mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: SAB 构造器 maxByteLength 选项面 grow 方法与访问器真值臂落地
This commit is contained in:
@@ -164,14 +164,17 @@ pub(crate) fn default_shared_array_buffer_proto<H: VmHost>(vm: &H) -> JsValue {
|
||||
JsValue::from_js_object(vm.session().builtin_world().shared_array_buffer_proto.as_ptr() as *mut JsObject)
|
||||
}
|
||||
|
||||
/// 分配携给定 proto 与载荷形态(`max_byte_length` 恒 0 定长)的
|
||||
/// SharedArrayBuffer 对象;byteLength 经原型访问器读(不写 own 数据属性)。
|
||||
pub(crate) fn new_shared_array_buffer<H: VmHost>(vm: &mut H, data: Vec<u8>, proto: JsValue) -> *mut JsObject {
|
||||
/// 分配携给定 proto 与载荷形态(`max_byte_length` 为存储态:0 定长,非 0 可
|
||||
/// grow)的 SharedArrayBuffer 对象;byteLength 经原型访问器读(不写 own 数据
|
||||
/// 属性)。
|
||||
pub(crate) fn new_shared_array_buffer<H: VmHost>(
|
||||
vm: &mut H, data: Vec<u8>, max_byte_length: usize, proto: JsValue,
|
||||
) -> *mut JsObject {
|
||||
let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, proto);
|
||||
obj.type_tag = JsObject::OBJ_TYPE_SHARED_ARRAY_BUFFER;
|
||||
let payload = ArrayBufferPayload {
|
||||
data: Some(data),
|
||||
max_byte_length: 0,
|
||||
max_byte_length,
|
||||
immutable: false,
|
||||
};
|
||||
let payload_ptr = Box::into_raw(Box::new(payload));
|
||||
@@ -242,24 +245,57 @@ pub fn clone_shared_array_buffer_native(old_obj: &JsObject, new_obj: &mut JsObje
|
||||
new_obj.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(cloned_ptr as *const ()) }));
|
||||
}
|
||||
|
||||
/// `SharedArrayBuffer(length)`:构造语义仅 `new`;length 缺省 0,经 ToIndex
|
||||
/// 传播式(强转副作用原值上抛),超引擎上界 → RangeError。
|
||||
/// `SharedArrayBuffer(length [, options])`:构造语义仅 `new`;length 缺省 0,
|
||||
/// 经 ToIndex 传播式(强转副作用原值上抛);`maxByteLength` 选项经传播式
|
||||
/// Get + ToIndex,`resizable` 键恒忽略(SAB 面不读);分配期上界校验在原型
|
||||
/// 读之后。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. 非构造形态(普通调用,new.target 缺失)→ TypeError。
|
||||
/// 2. length = ToIndex(length) 传播式;undefined/缺省 → 0。
|
||||
/// 3. 分配期上界校验(超引擎上限 → RangeError)。
|
||||
/// 4. GetPrototypeFromConstructor:经 ordinary_get 读 new.target 的
|
||||
/// 3. GetArrayBufferMaxByteLengthOption:options 非对象 → 定长;Get
|
||||
/// "maxByteLength" 传播式;undefined → 定长;否则 ToIndex 传播式。
|
||||
/// 4. length > max → RangeError(先于原型读与对象创建)。
|
||||
/// 5. GetPrototypeFromConstructor:经 ordinary_get 读 new.target 的
|
||||
/// "prototype"(访问器触发,异常原值传播);非对象结果回落
|
||||
/// %SharedArrayBuffer.prototype%。
|
||||
/// 5. 对象创建(零填充定长,无 resizable 选项面)。
|
||||
/// 6. 分配期上界校验(length 与 max 各一条,超引擎上限 → RangeError)。
|
||||
/// 7. 对象创建(零填充,定长/growable 由选项是否在场决定);不设 own
|
||||
/// maxByteLength 数据属性(ArrayBuffer 构造器有此步,SAB 面经原型访问器
|
||||
/// 读)。
|
||||
pub fn shared_array_buffer_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
if !vm.constructing_native() {
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, "SharedArrayBuffer must be called with new"));
|
||||
}
|
||||
let length = if args.len() > 1 { native_try!(to_index(vm, vm.reg(args[1]))) } else { 0 };
|
||||
if length > MAX_ARRAY_BUFFER_LENGTH {
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "invalid SharedArrayBuffer length"));
|
||||
// GetArrayBufferMaxByteLengthOption:None = 空(定长),Some(v) = 请求的
|
||||
// 上限(v 可为 0,与"空"语义相异:length > v 的界判须生效)。
|
||||
let max_opt = if args.len() > 2 {
|
||||
let options = vm.reg(args[2]);
|
||||
if !options.is_object() {
|
||||
None
|
||||
} else {
|
||||
let options_ptr = options.as_js_object_ptr();
|
||||
// SAFETY: is_object 保证指针非空且对象本 session 存活。
|
||||
let options_obj = unsafe { &*options_ptr };
|
||||
let si = vm.kernel_core().perm_interner().intern("maxByteLength").0;
|
||||
let max_val = match vm.ordinary_get(options_obj, si, options) {
|
||||
Ok(v) => v,
|
||||
Err(err) => return NativeResult::Err(crate::iterator::engine_error(vm, &err)),
|
||||
};
|
||||
if max_val.is_undefined() {
|
||||
None
|
||||
} else {
|
||||
Some(native_try!(to_index(vm, max_val)))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if let Some(max) = max_opt {
|
||||
if length > max {
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "invalid SharedArrayBuffer length"));
|
||||
}
|
||||
}
|
||||
// GetPrototypeFromConstructor:prototype getter 可抛错,异常原值传播;
|
||||
// 结果非对象时回落默认原型。
|
||||
@@ -282,7 +318,12 @@ pub fn shared_array_buffer_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> Na
|
||||
} else {
|
||||
default_proto
|
||||
};
|
||||
let obj_ptr = new_shared_array_buffer(vm, vec![0; length], proto);
|
||||
// 分配期上界:length 与 max 超引擎上限一律拒绝(ToIndex 阶段不校验)。
|
||||
if length > MAX_ARRAY_BUFFER_LENGTH || max_opt.is_some_and(|m| m > MAX_ARRAY_BUFFER_LENGTH) {
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "invalid SharedArrayBuffer length"));
|
||||
}
|
||||
// 存储态上限 = 请求上限 + 1(上限 0 与定长可分;定长存 0)。
|
||||
let obj_ptr = new_shared_array_buffer(vm, vec![0; length], max_opt.map_or(0, |m| m + 1), proto);
|
||||
NativeResult::Ok(JsValue::from_js_object(obj_ptr))
|
||||
}
|
||||
|
||||
@@ -328,23 +369,78 @@ pub fn shared_array_buffer_byte_length<H: VmHost>(vm: &mut H, args: &[u8]) -> Na
|
||||
NativeResult::Ok(JsValue::int(len as i32))
|
||||
}
|
||||
|
||||
/// `SharedArrayBuffer.prototype.growable` getter:定长臂恒 false
|
||||
/// (载荷存储态上限 0;growable 真值臂归后续面)。
|
||||
/// `SharedArrayBuffer.prototype.growable` getter:返回缓冲区是否 growable
|
||||
/// (载荷存储态上限非 0:0 = 定长,非 0 = 请求上限 + 1)。
|
||||
/// 非 SAB receiver 经品牌校验抛 TypeError(RequireInternalSlot 同语义)。
|
||||
pub fn shared_array_buffer_growable<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
native_try!(shared_array_buffer_payload(vm, this_val));
|
||||
NativeResult::Ok(JsValue::bool(false))
|
||||
let payload_ptr = native_try!(shared_array_buffer_payload(vm, this_val));
|
||||
// SAFETY: payload_ptr 经 shared_array_buffer_payload 校验为合法 SAB 载荷。
|
||||
NativeResult::Ok(JsValue::bool(unsafe { &*payload_ptr }.max_byte_length != 0))
|
||||
}
|
||||
|
||||
/// `SharedArrayBuffer.prototype.maxByteLength` getter:非 growable
|
||||
/// (载荷存储态上限 0)返回当前字节数;growable 臂归后续面。
|
||||
/// `SharedArrayBuffer.prototype.maxByteLength` getter:定长(存储态上限 0)
|
||||
/// 返回当前字节数;growable 返回真实上限(存储态 − 1 解码)。SAB 无
|
||||
/// detached 臂(载荷 `data` 恒在场)。
|
||||
pub fn shared_array_buffer_max_byte_length<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
let payload_ptr = native_try!(shared_array_buffer_payload(vm, this_val));
|
||||
// SAFETY: payload_ptr 经 shared_array_buffer_payload 校验为合法 SAB 载荷。
|
||||
let payload = unsafe { &*payload_ptr };
|
||||
NativeResult::Ok(JsValue::int(payload.data.as_ref().map_or(0, |d| d.len()) as i32))
|
||||
let value = if payload.max_byte_length == 0 {
|
||||
payload.data.as_ref().map_or(0, |d| d.len())
|
||||
} else {
|
||||
payload.max_byte_length - 1
|
||||
};
|
||||
NativeResult::Ok(JsValue::int(value as i32))
|
||||
}
|
||||
|
||||
/// `SharedArrayBuffer.prototype.grow(newLength)`:growable 缓冲区原地增长到
|
||||
/// newLength,前缀保留、增补零填;只增不缩(缩为 RangeError)。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. this 品牌校验(非对象/非 SAB → TypeError)。
|
||||
/// 2. 非 growable(存储态上限 0)→ TypeError,先于强转。
|
||||
/// 3. newByteLength = ToIntegerOrInfinity(newLength) 传播式(NaN → 0,
|
||||
/// ±Infinity 保留)。
|
||||
/// 4. 重取 this 寄存器 + 载荷指针(强转 JS 调用窗可晋升——AB resize 同式;
|
||||
/// SAB 无 detach 面,仅晋升面)。
|
||||
/// 5. 重读存储态上限 0 → TypeError。
|
||||
/// 6. newByteLength < 0 或 > 真实上限(重读存储态 − 1)或 < 当前字节数
|
||||
/// (grow-only)→ RangeError。
|
||||
/// 7. `Vec::resize` 一次调用收口目标长度。
|
||||
/// 8. 返回 undefined。
|
||||
pub fn shared_array_buffer_grow<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let this_reg = if args.is_empty() { 0 } else { args[0] };
|
||||
let this_val = vm.reg(this_reg);
|
||||
let payload_ptr = native_try!(shared_array_buffer_payload(vm, this_val));
|
||||
// SAFETY: payload_ptr 经 shared_array_buffer_payload 校验为合法 SAB 载荷;
|
||||
// 状态位拷出后本次借用即结束,不跨 JS 调用点。
|
||||
if unsafe { &*payload_ptr }.max_byte_length == 0 {
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, "SharedArrayBuffer is not growable"));
|
||||
}
|
||||
let new_val = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||||
let new_length = native_try!(to_integer_or_infinity(vm, new_val));
|
||||
// 强转调用可能已把本缓冲区晋升进 session:接收者寄存器与载荷指针均须
|
||||
// 重取重检,不得消费求值前快照。
|
||||
let this_val = vm.reg(this_reg);
|
||||
let payload_ptr = native_try!(shared_array_buffer_payload(vm, this_val));
|
||||
// SAFETY: 重取的 payload_ptr 指向存活载荷盒。
|
||||
let payload = unsafe { &mut *payload_ptr };
|
||||
if payload.max_byte_length == 0 {
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, "SharedArrayBuffer is not growable"));
|
||||
}
|
||||
let Some(data) = payload.data.as_mut() else {
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, "SharedArrayBuffer internal state invalid"));
|
||||
};
|
||||
// 存储态上限 +1 编码:真实上限 = max - 1(上限 0 的缓冲区只许 grow(0));
|
||||
// 当前长度之下拒缩。
|
||||
let real_max = payload.max_byte_length - 1;
|
||||
if new_length < 0.0 || new_length > real_max as f64 || new_length < data.len() as f64 {
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "invalid SharedArrayBuffer length"));
|
||||
}
|
||||
data.resize(new_length as usize, 0);
|
||||
NativeResult::Ok(JsValue::undefined())
|
||||
}
|
||||
|
||||
/// 读入口:校验 receiver 为 ArrayBuffer 并取载荷指针。detach(载荷 `data` 为
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::bind_constructor;
|
||||
use crate::bindings::{bind_accessor_getter, configure_native_constructor};
|
||||
use crate::bindings::{apply_binding_table, bind_accessor_getter, configure_native_constructor};
|
||||
use oxide_kernel::kernel::{KernelCore, KernelSession};
|
||||
use oxide_types::object::JsObject;
|
||||
|
||||
@@ -18,8 +18,20 @@ pub fn bind_shared_array_buffer(core: &Arc<KernelCore>, session: &KernelSession,
|
||||
1,
|
||||
);
|
||||
|
||||
// SAB 原型当前无静态方法(grow/growable 臂与 slice 归后续面);
|
||||
// byteLength/maxByteLength 两枚访问器(set 恒 undefined)读载荷字节数。
|
||||
// grow 方法(slice 归后续面):growable 缓冲区原地增长,只增不缩。
|
||||
apply_binding_table(
|
||||
session.builtin_world(),
|
||||
proto,
|
||||
core,
|
||||
&[(
|
||||
"grow",
|
||||
oxide_builtins::array_buffer::shared_array_buffer_grow::<crate::vm::Vm> as *const (),
|
||||
1,
|
||||
)],
|
||||
);
|
||||
|
||||
// byteLength/maxByteLength 两枚访问器(set 恒 undefined)读载荷字节数 /
|
||||
// 存储态上限,品牌校验抛 TypeError(proto 自身访问即抛)。
|
||||
bind_accessor_getter(
|
||||
core,
|
||||
session,
|
||||
@@ -36,7 +48,7 @@ pub fn bind_shared_array_buffer(core: &Arc<KernelCore>, session: &KernelSession,
|
||||
oxide_builtins::array_buffer::shared_array_buffer_max_byte_length::<crate::vm::Vm> as *const (),
|
||||
);
|
||||
|
||||
// growable 定长臂:恒 false,品牌校验抛 TypeError(proto 自身访问即抛)。
|
||||
// growable 真值臂:读载荷存储态上限(0 定长 false / 非 0 growable true)。
|
||||
bind_accessor_getter(
|
||||
core,
|
||||
session,
|
||||
|
||||
@@ -1303,6 +1303,177 @@ fn sab_full_reset_rebinds() {
|
||||
assert_eq!(text, "true|true|true|true");
|
||||
}
|
||||
|
||||
/// SAB 构造器 options 真值臂钉:maxByteLength 在场 → growable true 且
|
||||
/// maxByteLength 回请求上限;undefined / 非对象 options → 定长。
|
||||
#[test]
|
||||
fn sab_constructor_options_growable_and_fixed() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"(function () { \
|
||||
var g = new SharedArrayBuffer(4, { maxByteLength: 5 }); \
|
||||
var u = new SharedArrayBuffer(4, { maxByteLength: undefined }); \
|
||||
var n = new SharedArrayBuffer(0, 9); \
|
||||
return g.growable === true && g.maxByteLength === 5 \
|
||||
&& u.growable === false && u.maxByteLength === 4 \
|
||||
&& n.growable === false && n.maxByteLength === 0; })()",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
|
||||
/// SAB options 抛形钉:length > max / max 负值 / max 2^53−1(引擎上界)
|
||||
/// 均 RangeError;options getter 抛错原值传播。
|
||||
#[test]
|
||||
fn sab_constructor_options_errors() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"(function () { \
|
||||
var t1 = false; \
|
||||
try { new SharedArrayBuffer(1, { maxByteLength: 0 }); } catch (e) { t1 = e instanceof RangeError; } \
|
||||
var t2 = false; \
|
||||
try { new SharedArrayBuffer(0, { maxByteLength: -1 }); } catch (e) { t2 = e instanceof RangeError; } \
|
||||
var t3 = false; \
|
||||
try { new SharedArrayBuffer(0, { maxByteLength: 9007199254740991 }); } catch (e) { t3 = e instanceof RangeError; } \
|
||||
function Test262Error() {} \
|
||||
var t4 = false; \
|
||||
var options = { get maxByteLength() { throw new Test262Error(); } }; \
|
||||
try { new SharedArrayBuffer(0, options); } catch (e) { t4 = e instanceof Test262Error; } \
|
||||
return t1 && t2 && t3 && t4; })()",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
|
||||
/// SAB length>max 先于对象创建钉:max 在场且 length 超限时 RangeError 先出,
|
||||
/// 抛错 prototype getter 不得先出。
|
||||
#[test]
|
||||
fn sab_constructor_length_gt_max_before_gpfc() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"(function () { \
|
||||
function Test262Error() {} \
|
||||
var newTarget = function() {}.bind(null); \
|
||||
Object.defineProperty(newTarget, 'prototype', { get: function () { throw new Test262Error(); } }); \
|
||||
var t = false; \
|
||||
try { Reflect.construct(SharedArrayBuffer, [10, { maxByteLength: 0 }], newTarget); } catch (e) { t = e instanceof RangeError; } \
|
||||
return t; })()",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
|
||||
/// SAB 分配期上界移序钉:合法 length/max 下抛错 prototype getter 先出;
|
||||
/// 7 PiB length(超引擎上界)同样 prototype getter 先出(上界后移于原型读)。
|
||||
#[test]
|
||||
fn sab_constructor_gpfc_before_allocation_limit() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"(function () { \
|
||||
function DummyError() {} \
|
||||
var newTarget = function() {}.bind(null); \
|
||||
Object.defineProperty(newTarget, 'prototype', { get: function () { throw new DummyError(); } }); \
|
||||
var t1 = false; \
|
||||
try { Reflect.construct(SharedArrayBuffer, [8, { maxByteLength: 16 }], newTarget); } catch (e) { t1 = e instanceof DummyError; } \
|
||||
var t2 = false; \
|
||||
try { Reflect.construct(SharedArrayBuffer, [7 * 1125899906842624], newTarget); } catch (e) { t2 = e instanceof DummyError; } \
|
||||
return t1 && t2; })()",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
|
||||
/// SAB grow 守卫序钉:品牌 / 非 growable / receiver 类型均 TypeError;
|
||||
/// growable 界判 grow-only(超上限 / 负值 / 缩长均 RangeError)。
|
||||
#[test]
|
||||
fn sab_grow_guard_order() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"(function () { \
|
||||
var fixed = new SharedArrayBuffer(4); \
|
||||
var t1 = false; \
|
||||
try { fixed.grow(5); } catch (e) { t1 = e instanceof TypeError; } \
|
||||
var t2 = false; \
|
||||
try { SharedArrayBuffer.prototype.grow.call(new ArrayBuffer(4)); } catch (e) { t2 = e instanceof TypeError; } \
|
||||
var t3 = false; \
|
||||
try { SharedArrayBuffer.prototype.grow.call({}); } catch (e) { t3 = e instanceof TypeError; } \
|
||||
var g = new SharedArrayBuffer(4, { maxByteLength: 5 }); \
|
||||
var t4 = false; \
|
||||
try { g.grow(6); } catch (e) { t4 = e instanceof RangeError; } \
|
||||
var t5 = false; \
|
||||
try { g.grow(-1); } catch (e) { t5 = e instanceof RangeError; } \
|
||||
var t6 = false; \
|
||||
try { g.grow(3); } catch (e) { t6 = e instanceof RangeError; } \
|
||||
return t1 && t2 && t3 && t4 && t5 && t6; })()",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
|
||||
/// SAB grow 原地语义钉:grow(上限) 后 byteLength 更新且回 undefined;
|
||||
/// 同长 no-op;零长 growable 缓冲 grow(0)/grow(上限) 均合法。
|
||||
#[test]
|
||||
fn sab_grow_inplace_semantics() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"(function () { \
|
||||
var g = new SharedArrayBuffer(4, { maxByteLength: 5 }); \
|
||||
if (g.grow(5) !== undefined || g.byteLength !== 5) { return false; } \
|
||||
if (g.grow(5) !== undefined || g.byteLength !== 5) { return false; } \
|
||||
var z = new SharedArrayBuffer(0, { maxByteLength: 4 }); \
|
||||
if (z.grow(0) !== undefined || z.byteLength !== 0) { return false; } \
|
||||
if (z.grow(4) !== undefined || z.byteLength !== 4) { return false; } \
|
||||
return true; })()",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
|
||||
/// SAB grow NaN 归零钉:ToIntegerOrInfinity 将 NaN 折为 0——非零长 growable
|
||||
/// 经 grow-only 界判 RangeError,零长 growable 同长成功(node 20 同形)。
|
||||
#[test]
|
||||
fn sab_grow_nan_folds_to_zero() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"(function () { \
|
||||
var g = new SharedArrayBuffer(4, { maxByteLength: 5 }); \
|
||||
var t1 = false; \
|
||||
try { g.grow(NaN); } catch (e) { t1 = e instanceof RangeError; } \
|
||||
if (g.byteLength !== 4) { return false; } \
|
||||
var z = new SharedArrayBuffer(0, { maxByteLength: 4 }); \
|
||||
var r = z.grow(NaN); \
|
||||
return t1 && r === undefined && z.byteLength === 0; })()",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
|
||||
/// SAB growable / maxByteLength 访问器真值臂钉:growable 双形态、
|
||||
/// maxByteLength 0/23/42 三形态与语料同值。
|
||||
#[test]
|
||||
fn sab_growable_and_max_bytelength_truth_arms() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"(function () { \
|
||||
var s1 = new SharedArrayBuffer(1); \
|
||||
var s2 = new SharedArrayBuffer(1, { maxByteLength: 1 }); \
|
||||
var m0 = new SharedArrayBuffer(0, { maxByteLength: 0 }); \
|
||||
var m23 = new SharedArrayBuffer(0, { maxByteLength: 23 }); \
|
||||
var m42 = new SharedArrayBuffer(42, { maxByteLength: 42 }); \
|
||||
return s1.growable === false && s2.growable === true \
|
||||
&& m0.maxByteLength === 0 && m23.maxByteLength === 23 && m42.maxByteLength === 42; })()",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
|
||||
/// STUBS 表收缩钉:Atomics 移出 stub 后剩 5 枚 stub 全局仍为 function;
|
||||
/// Atomics 现为纯对象(typeof 'object'),对其调用抛 TypeError(非函数)。
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user