test: 钉住 SAB 构造器预分配账目与 grow 语义族及无 detach 面

This commit is contained in:
2026-10-09 02:54:57 +00:00
parent c5c1d470fb
commit ff31e5bfd7
3 changed files with 153 additions and 20 deletions
Generated
+19 -19
View File
@@ -1160,7 +1160,7 @@ dependencies = [
[[package]]
name = "oxide_builtins"
version = "0.8.82"
version = "0.8.83"
dependencies = [
"chrono",
"fast-float",
@@ -1185,7 +1185,7 @@ dependencies = [
[[package]]
name = "oxide_bytecode"
version = "0.8.82"
version = "0.8.83"
dependencies = [
"num-bigint",
"oxide_log",
@@ -1193,7 +1193,7 @@ dependencies = [
[[package]]
name = "oxide_cfg"
version = "0.8.82"
version = "0.8.83"
dependencies = [
"oxide_bytecode",
"oxide_emit",
@@ -1204,7 +1204,7 @@ dependencies = [
[[package]]
name = "oxide_cli"
version = "0.8.82"
version = "0.8.83"
dependencies = [
"ansi_term",
"bumpalo",
@@ -1226,7 +1226,7 @@ dependencies = [
[[package]]
name = "oxide_code_cache"
version = "0.8.82"
version = "0.8.83"
dependencies = [
"lru",
"oxide_bytecode",
@@ -1235,7 +1235,7 @@ dependencies = [
[[package]]
name = "oxide_compiler"
version = "0.8.82"
version = "0.8.83"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1255,7 +1255,7 @@ dependencies = [
[[package]]
name = "oxide_dce"
version = "0.8.82"
version = "0.8.83"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1269,7 +1269,7 @@ dependencies = [
[[package]]
name = "oxide_emit"
version = "0.8.82"
version = "0.8.83"
dependencies = [
"num-bigint",
"oxc_allocator",
@@ -1284,7 +1284,7 @@ dependencies = [
[[package]]
name = "oxide_engine"
version = "0.8.82"
version = "0.8.83"
dependencies = [
"oxide_bytecode",
"oxide_compiler",
@@ -1296,7 +1296,7 @@ dependencies = [
[[package]]
name = "oxide_ir"
version = "0.8.82"
version = "0.8.83"
dependencies = [
"oxide_bytecode",
"oxide_log",
@@ -1305,7 +1305,7 @@ dependencies = [
[[package]]
name = "oxide_kernel"
version = "0.8.82"
version = "0.8.83"
dependencies = [
"bumpalo",
"dashmap",
@@ -1319,7 +1319,7 @@ dependencies = [
[[package]]
name = "oxide_liveness"
version = "0.8.82"
version = "0.8.83"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1331,7 +1331,7 @@ dependencies = [
[[package]]
name = "oxide_log"
version = "0.8.82"
version = "0.8.83"
dependencies = [
"tracing",
"tracing-appender",
@@ -1340,7 +1340,7 @@ dependencies = [
[[package]]
name = "oxide_parser"
version = "0.8.82"
version = "0.8.83"
dependencies = [
"oxc_allocator",
"oxc_ast",
@@ -1355,7 +1355,7 @@ dependencies = [
[[package]]
name = "oxide_regalloc"
version = "0.8.82"
version = "0.8.83"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1371,7 +1371,7 @@ dependencies = [
[[package]]
name = "oxide_runtime_api"
version = "0.8.82"
version = "0.8.83"
dependencies = [
"num-bigint",
"num-traits",
@@ -1384,7 +1384,7 @@ dependencies = [
[[package]]
name = "oxide_test262"
version = "0.8.82"
version = "0.8.83"
dependencies = [
"oxide_bytecode",
"oxide_compiler",
@@ -1402,7 +1402,7 @@ dependencies = [
[[package]]
name = "oxide_types"
version = "0.8.82"
version = "0.8.83"
dependencies = [
"bumpalo",
"dashmap",
@@ -1415,7 +1415,7 @@ dependencies = [
[[package]]
name = "oxide_vm"
version = "0.8.82"
version = "0.8.83"
dependencies = [
"bumpalo",
"chrono",
+1 -1
View File
@@ -23,7 +23,7 @@ members = [
]
[workspace.package]
version = "0.8.82"
version = "0.8.83"
edition = "2021"
license = "MIT"
rust-version = "1.80"
+133
View File
@@ -1457,4 +1457,137 @@ mod tests {
.unwrap();
assert_eq!(vm.lookup_str(r).unwrap(), "TypeError");
}
/// growable 构造器预分配账目钉:byteLength 读活长、maxByteLength 读真实
/// 上限、growable 为真;核的 `shared_buffer_bytes` 增量等于真实上限
/// (预分配一次性到位),而非初始活长。定长对照臂:增量即活长、
/// growable 为假、maxByteLength 解码取活长。
#[test]
fn growable_constructor_preallocates_to_max() {
let mut vm = Vm::new();
let before = vm.kernel_core().shared_buffer_bytes();
let r = eval_ab(
&mut vm,
"var sab = new SharedArrayBuffer(2, {maxByteLength: 8}); \
globalThis.__sab = sab; \
[sab.byteLength, sab.maxByteLength, sab.growable].join(',')",
)
.unwrap();
assert_eq!(vm.lookup_str(r).unwrap(), "2,8,true");
assert_eq!(
vm.kernel_core().shared_buffer_bytes() - before,
8,
"growable 预分配账目是真实上限而非初始活长"
);
// 定长对照臂:账目即活长,growable 为假,maxByteLength 解码取活长。
let before_fixed = vm.kernel_core().shared_buffer_bytes();
let r = eval_ab(
&mut vm,
"var fixed = new SharedArrayBuffer(4); \
globalThis.__fixed = fixed; \
[fixed.byteLength, fixed.maxByteLength, fixed.growable].join(',')",
)
.unwrap();
assert_eq!(vm.lookup_str(r).unwrap(), "4,4,false");
assert_eq!(vm.kernel_core().shared_buffer_bytes() - before_fixed, 4);
}
/// grow 前缀保留与零填充钉:写入前缀后 grow,前缀字节不变、增补区
/// 全零、活长推进到目标值。
#[test]
fn grow_preserves_prefix_and_zero_fills() {
let mut vm = Vm::new();
let r = eval_ab(
&mut vm,
"(function () { var sab = new SharedArrayBuffer(2, {maxByteLength: 8}); \
var v = new Uint8Array(sab); v[0] = 0xAA; v[1] = 0xBB; \
sab.grow(6); \
var v2 = new Uint8Array(sab); \
return v2[0] === 0xAA && v2[1] === 0xBB && v2[2] === 0 && v2[3] === 0 \
&& v2[4] === 0 && v2[5] === 0 && sab.byteLength === 6; })()",
)
.unwrap();
assert!(r.as_bool());
}
/// grow-only 与超上限 RangeError 钉:缩长(当前活长以下任意值)与超
/// 真实上限各抛 RangeError,恰好到上限成功;恰好等于当前活长是 no-op
/// 成功(只增不缩,相等放行)。
#[test]
fn grow_only_and_over_max_range_errors() {
let mut vm = Vm::new();
let r = eval_ab(
&mut vm,
"(function () { var sab = new SharedArrayBuffer(4, {maxByteLength: 8}); \
var out = ''; \
try { sab.grow(3); out += 'no-throw'; } \
catch (e) { out += (e.name === 'RangeError' ? 'R' : 'X'); } \
try { sab.grow(4); out += 'ok'; } \
catch (e) { out += 'X'; } \
try { sab.grow(9); out += 'no-throw'; } \
catch (e) { out += (e.name === 'RangeError' ? 'R' : 'X'); } \
try { sab.grow(8); out += 'ok'; } \
catch (e) { out += 'X'; } \
return out + '|' + sab.byteLength; })()",
)
.unwrap();
assert_eq!(vm.lookup_str(r).unwrap(), "RokRok|8");
}
/// grow 非 growable 守卫钉:定长 SAB 调 grow 抛 TypeError,守卫先于
/// 参数强转(valueOf 副作用不运行)。
#[test]
fn grow_non_growable_guard_before_coercion() {
let mut vm = Vm::new();
let r = eval_ab(
&mut vm,
"(function () { var calls = 0; \
var sab = new SharedArrayBuffer(4); \
try { sab.grow({ valueOf() { calls++; return 8; } }); \
return 'no-throw' + calls; } \
catch (err) { return (err.name === 'TypeError' ? 'T' : 'X') + calls; } })()",
)
.unwrap();
assert_eq!(vm.lookup_str(r).unwrap(), "T0");
}
/// grow 强转窗口重取钉:界判消费强转后重取的活长——valueOf 内先
/// grow 推进活长,外层 grow 到重取活长之下抛 RangeError(若消费
/// 求值前快照则会成功)。
#[test]
fn grow_coercion_window_refetch() {
let mut vm = Vm::new();
let r = eval_ab(
&mut vm,
"(function () { var sab = new SharedArrayBuffer(4, {maxByteLength: 8}); \
try { sab.grow({ valueOf() { sab.grow(6); return 5; } }); \
return 'no-throw|' + sab.byteLength; } \
catch (e) { return (e.name === 'RangeError' ? 'R' : 'X') + '|' + sab.byteLength; } })()",
)
.unwrap();
assert_eq!(vm.lookup_str(r).unwrap(), "R|6");
}
/// SAB 无 detach 面钉:$262.detachArrayBuffer 对 SAB 抛 TypeError
/// (读入口标签校验臂),SAB 原型无 AB 专属方法(transfer / resize /
/// markImmutable / sliceToImmutable 均 undefined),detach 失败后缓冲
/// 状态不变。
#[test]
fn sab_has_no_detach_surface() {
let mut vm = Vm::new();
let r = eval_ab(
&mut vm,
"(function () { var sab = new SharedArrayBuffer(4, {maxByteLength: 8}); \
var out = ''; \
try { $262.detachArrayBuffer(sab); out += 'no-throw'; } \
catch (e) { out += (e.name === 'TypeError' ? 'T' : 'X'); } \
out += ',' + (sab.transfer === undefined ? 'u' : 'x') \
+ '|' + (sab.resize === undefined ? 'u' : 'x') \
+ '|' + (sab.markImmutable === undefined ? 'u' : 'x') \
+ '|' + (sab.sliceToImmutable === undefined ? 'u' : 'x'); \
return out + '|' + sab.byteLength + '|' + sab.growable; })()",
)
.unwrap();
assert_eq!(vm.lookup_str(r).unwrap(), "T,u|u|u|u|4|true");
}
}