mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 19:21:11 +08:00
feat: SharedArrayBuffer 原型对象与构造器 meta 正式绑定
This commit is contained in:
@@ -159,9 +159,15 @@ pub fn drop_array_buffer_native(obj: &mut JsObject) -> u64 {
|
|||||||
bytes
|
bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 分配定长 SharedArrayBuffer 对象(零填充字节缓冲,`max_byte_length` 存 0)。
|
/// 默认缓冲区原型 %SharedArrayBuffer.prototype%(构造器回落路径与各定长建点共用)。
|
||||||
pub(crate) fn new_shared_array_buffer<H: VmHost>(vm: &mut H, data: Vec<u8>) -> *mut JsObject {
|
pub(crate) fn default_shared_array_buffer_proto<H: VmHost>(vm: &H) -> JsValue {
|
||||||
let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null());
|
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 {
|
||||||
|
let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, proto);
|
||||||
obj.type_tag = JsObject::OBJ_TYPE_SHARED_ARRAY_BUFFER;
|
obj.type_tag = JsObject::OBJ_TYPE_SHARED_ARRAY_BUFFER;
|
||||||
let payload = ArrayBufferPayload {
|
let payload = ArrayBufferPayload {
|
||||||
data: Some(data),
|
data: Some(data),
|
||||||
@@ -227,8 +233,16 @@ pub fn clone_shared_array_buffer_native(old_obj: &JsObject, new_obj: &mut JsObje
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// `SharedArrayBuffer(length)`:构造语义仅 `new`;length 缺省 0,经 ToIndex
|
/// `SharedArrayBuffer(length)`:构造语义仅 `new`;length 缺省 0,经 ToIndex
|
||||||
/// 传播式(强转副作用原值上抛),超引擎上界 → RangeError。最小实现:字节
|
/// 传播式(强转副作用原值上抛),超引擎上界 → RangeError。
|
||||||
/// 缓冲零填充定长,无 resizable 选项面与 `[[ArrayBufferMaxByteLength]]`。
|
///
|
||||||
|
/// # 步骤
|
||||||
|
/// 1. 非构造形态(普通调用,new.target 缺失)→ TypeError。
|
||||||
|
/// 2. length = ToIndex(length) 传播式;undefined/缺省 → 0。
|
||||||
|
/// 3. 分配期上界校验(超引擎上限 → RangeError)。
|
||||||
|
/// 4. GetPrototypeFromConstructor:经 ordinary_get 读 new.target 的
|
||||||
|
/// "prototype"(访问器触发,异常原值传播);非对象结果回落
|
||||||
|
/// %SharedArrayBuffer.prototype%。
|
||||||
|
/// 5. 对象创建(零填充定长,无 resizable 选项面)。
|
||||||
pub fn shared_array_buffer_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn shared_array_buffer_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
if !vm.constructing_native() {
|
if !vm.constructing_native() {
|
||||||
return NativeResult::Err(crate::error::create_type_error(vm, "SharedArrayBuffer must be called with new"));
|
return NativeResult::Err(crate::error::create_type_error(vm, "SharedArrayBuffer must be called with new"));
|
||||||
@@ -237,10 +251,92 @@ pub fn shared_array_buffer_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> Na
|
|||||||
if length > MAX_ARRAY_BUFFER_LENGTH {
|
if length > MAX_ARRAY_BUFFER_LENGTH {
|
||||||
return NativeResult::Err(crate::error::create_range_error(vm, "invalid SharedArrayBuffer length"));
|
return NativeResult::Err(crate::error::create_range_error(vm, "invalid SharedArrayBuffer length"));
|
||||||
}
|
}
|
||||||
let obj_ptr = new_shared_array_buffer(vm, vec![0; length]);
|
// GetPrototypeFromConstructor:prototype getter 可抛错,异常原值传播;
|
||||||
|
// 结果非对象时回落默认原型。
|
||||||
|
let default_proto = default_shared_array_buffer_proto(vm);
|
||||||
|
let new_target = vm.reg(255);
|
||||||
|
let proto = if new_target.is_object() {
|
||||||
|
let nt_ptr = new_target.as_js_object_ptr();
|
||||||
|
// SAFETY: is_object 保证指针非空且对象本 session 存活。
|
||||||
|
let nt_obj = unsafe { &*nt_ptr };
|
||||||
|
let proto_si = vm.kernel_core().perm_interner().intern("prototype").0;
|
||||||
|
let proto_val = match vm.ordinary_get(nt_obj, proto_si, new_target) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(err) => return NativeResult::Err(crate::iterator::engine_error(vm, &err)),
|
||||||
|
};
|
||||||
|
if proto_val.is_object() {
|
||||||
|
proto_val
|
||||||
|
} else {
|
||||||
|
default_proto
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
default_proto
|
||||||
|
};
|
||||||
|
let obj_ptr = new_shared_array_buffer(vm, vec![0; length], proto);
|
||||||
NativeResult::Ok(JsValue::from_js_object(obj_ptr))
|
NativeResult::Ok(JsValue::from_js_object(obj_ptr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 读入口:校验 receiver 为 SharedArrayBuffer 并取载荷指针。SAB 无 detach
|
||||||
|
/// 生产路径,载荷 `data` 恒在场(`map_or` 兜底与 AB 读入口同形)。
|
||||||
|
pub(crate) fn shared_array_buffer_payload<H: VmHost>(
|
||||||
|
vm: &mut H, this_val: JsValue,
|
||||||
|
) -> Result<*mut ArrayBufferPayload, JsValue> {
|
||||||
|
if !this_val.is_object() {
|
||||||
|
return Err(crate::error::create_type_error(
|
||||||
|
vm,
|
||||||
|
"SharedArrayBuffer method called on incompatible receiver",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let obj_ptr = this_val.as_js_object_ptr();
|
||||||
|
if obj_ptr.is_null() {
|
||||||
|
return Err(crate::error::create_type_error(vm, "SharedArrayBuffer internal state invalid"));
|
||||||
|
}
|
||||||
|
let obj = unsafe { &*obj_ptr };
|
||||||
|
if !obj.is_shared_array_buffer_obj() {
|
||||||
|
return Err(crate::error::create_type_error(
|
||||||
|
vm,
|
||||||
|
"SharedArrayBuffer method called on incompatible receiver",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let Some(payload_ptr) = obj.native_fn() else {
|
||||||
|
return Err(crate::error::create_type_error(vm, "SharedArrayBuffer internal state invalid"));
|
||||||
|
};
|
||||||
|
let payload_ptr = payload_ptr.as_ptr() as *mut ArrayBufferPayload;
|
||||||
|
if payload_ptr.is_null() {
|
||||||
|
return Err(crate::error::create_type_error(vm, "SharedArrayBuffer internal state invalid"));
|
||||||
|
}
|
||||||
|
Ok(payload_ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `SharedArrayBuffer.prototype.byteLength` getter:返回缓冲区字节数
|
||||||
|
/// (定长臂读载荷 len;growable 臂归后续面)。
|
||||||
|
pub fn shared_array_buffer_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 len = unsafe { &*payload_ptr }.data.as_ref().map_or(0, |d| d.len());
|
||||||
|
NativeResult::Ok(JsValue::int(len as i32))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `SharedArrayBuffer.prototype.growable` getter:定长臂恒 false
|
||||||
|
/// (载荷存储态上限 0;growable 真值臂归后续面)。
|
||||||
|
/// 非 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))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `SharedArrayBuffer.prototype.maxByteLength` getter:非 growable
|
||||||
|
/// (载荷存储态上限 0)返回当前字节数;growable 臂归后续面。
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
|
||||||
/// 读入口:校验 receiver 为 ArrayBuffer 并取载荷指针。detach(载荷 `data` 为
|
/// 读入口:校验 receiver 为 ArrayBuffer 并取载荷指针。detach(载荷 `data` 为
|
||||||
/// `None`)不在此分叉,由消费方现读 `data` 时按既有错误形态处理。
|
/// `None`)不在此分叉,由消费方现读 `data` 时按既有错误形态处理。
|
||||||
pub(crate) fn array_buffer_payload<H: VmHost>(
|
pub(crate) fn array_buffer_payload<H: VmHost>(
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
//! 每个内置方法以 `fn xxx<H: VmHost>(vm, args: &[u8]) -> NativeResult` 形式暴露,
|
//! 每个内置方法以 `fn xxx<H: VmHost>(vm, args: &[u8]) -> NativeResult` 形式暴露,
|
||||||
//! 由上层(oxide_vm / oxide_api)注册为 JS 全局对象上的 native function。
|
//! 由上层(oxide_vm / oxide_api)注册为 JS 全局对象上的 native function。
|
||||||
//! 架构性延后的特性(Proxy、WeakMap、WeakSet、WeakRef、FinalizationRegistry、
|
//! 架构性延后的特性(Proxy、WeakMap、WeakSet、WeakRef、FinalizationRegistry、
|
||||||
//! SharedArrayBuffer、Atomics)在 `stubs` 中仅提供占位实现,调用时抛 TypeError。
|
//! Atomics)在 `stubs` 中仅提供占位实现,调用时抛 TypeError。
|
||||||
|
|
||||||
/// Array 内置对象实现(目录模块:common 共享助手、from 构造器与静态方法、element 元素变更、iterate 高阶迭代、sort_iterator 排序与迭代协议、immutable ES2023 不可变方法族)。
|
/// Array 内置对象实现(目录模块:common 共享助手、from 构造器与静态方法、element 元素变更、iterate 高阶迭代、sort_iterator 排序与迭代协议、immutable ES2023 不可变方法族)。
|
||||||
pub mod array;
|
pub mod array;
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::bind_constructor;
|
||||||
|
use crate::bindings::{bind_accessor_getter, configure_native_constructor};
|
||||||
|
use oxide_kernel::kernel::{KernelCore, KernelSession};
|
||||||
|
use oxide_types::object::JsObject;
|
||||||
|
|
||||||
|
/// 把 SharedArrayBuffer 构造器与原型访问器绑定到 global。
|
||||||
|
pub fn bind_shared_array_buffer(core: &Arc<KernelCore>, session: &KernelSession, global: &mut JsObject) {
|
||||||
|
let ctor_ptr = session.builtin_world().shared_array_buffer_constructor.as_ptr() as *mut JsObject;
|
||||||
|
let ctor = unsafe { &mut *ctor_ptr };
|
||||||
|
let proto_ptr = session.builtin_world().shared_array_buffer_proto.as_ptr() as *mut JsObject;
|
||||||
|
let proto = unsafe { &mut *proto_ptr };
|
||||||
|
|
||||||
|
configure_native_constructor(
|
||||||
|
ctor,
|
||||||
|
oxide_builtins::array_buffer::shared_array_buffer_constructor::<crate::vm::Vm> as *const (),
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
|
||||||
|
// SAB 原型当前无静态方法(grow/growable 臂与 slice 归后续面);
|
||||||
|
// byteLength/maxByteLength 两枚访问器(set 恒 undefined)读载荷字节数。
|
||||||
|
bind_accessor_getter(
|
||||||
|
core,
|
||||||
|
session,
|
||||||
|
proto,
|
||||||
|
"byteLength",
|
||||||
|
oxide_builtins::array_buffer::shared_array_buffer_byte_length::<crate::vm::Vm> as *const (),
|
||||||
|
);
|
||||||
|
|
||||||
|
bind_accessor_getter(
|
||||||
|
core,
|
||||||
|
session,
|
||||||
|
proto,
|
||||||
|
"maxByteLength",
|
||||||
|
oxide_builtins::array_buffer::shared_array_buffer_max_byte_length::<crate::vm::Vm> as *const (),
|
||||||
|
);
|
||||||
|
|
||||||
|
// growable 定长臂:恒 false,品牌校验抛 TypeError(proto 自身访问即抛)。
|
||||||
|
bind_accessor_getter(
|
||||||
|
core,
|
||||||
|
session,
|
||||||
|
proto,
|
||||||
|
"growable",
|
||||||
|
oxide_builtins::array_buffer::shared_array_buffer_growable::<crate::vm::Vm> as *const (),
|
||||||
|
);
|
||||||
|
|
||||||
|
bind_constructor!(
|
||||||
|
core,
|
||||||
|
global,
|
||||||
|
"SharedArrayBuffer",
|
||||||
|
ctor_ptr,
|
||||||
|
oxide_builtins::array_buffer::shared_array_buffer_constructor::<crate::vm::Vm>,
|
||||||
|
1,
|
||||||
|
hash: true
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ use oxide_types::value::JsValue;
|
|||||||
|
|
||||||
use crate::bindings::{bind_global_value, configure_native_constructor};
|
use crate::bindings::{bind_global_value, configure_native_constructor};
|
||||||
|
|
||||||
const STUBS: [(&str, *const (), u8); 7] = [
|
const STUBS: [(&str, *const (), u8); 6] = [
|
||||||
("Proxy", oxide_builtins::stubs::proxy_stub::<crate::vm::Vm> as *const (), 2),
|
("Proxy", oxide_builtins::stubs::proxy_stub::<crate::vm::Vm> as *const (), 2),
|
||||||
("WeakMap", oxide_builtins::stubs::weakmap_stub::<crate::vm::Vm> as *const (), 0),
|
("WeakMap", oxide_builtins::stubs::weakmap_stub::<crate::vm::Vm> as *const (), 0),
|
||||||
("WeakSet", oxide_builtins::stubs::weakset_stub::<crate::vm::Vm> as *const (), 0),
|
("WeakSet", oxide_builtins::stubs::weakset_stub::<crate::vm::Vm> as *const (), 0),
|
||||||
@@ -18,15 +18,10 @@ const STUBS: [(&str, *const (), u8); 7] = [
|
|||||||
oxide_builtins::stubs::finalization_registry_stub::<crate::vm::Vm> as *const (),
|
oxide_builtins::stubs::finalization_registry_stub::<crate::vm::Vm> as *const (),
|
||||||
1,
|
1,
|
||||||
),
|
),
|
||||||
(
|
|
||||||
"SharedArrayBuffer",
|
|
||||||
oxide_builtins::array_buffer::shared_array_buffer_constructor::<crate::vm::Vm> as *const (),
|
|
||||||
1,
|
|
||||||
),
|
|
||||||
("Atomics", oxide_builtins::stubs::atomics_stub::<crate::vm::Vm> as *const (), 0),
|
("Atomics", oxide_builtins::stubs::atomics_stub::<crate::vm::Vm> as *const (), 0),
|
||||||
];
|
];
|
||||||
|
|
||||||
/// 把未实现内置(Proxy/WeakMap/WeakSet/WeakRef/FinalizationRegistry/SharedArrayBuffer/Atomics)
|
/// 把未实现内置(Proxy/WeakMap/WeakSet/WeakRef/FinalizationRegistry/Atomics)
|
||||||
/// 的 stub 构造器绑定到 global,并登记到 `stub_objects` 供快照跟踪。
|
/// 的 stub 构造器绑定到 global,并登记到 `stub_objects` 供快照跟踪。
|
||||||
pub fn bind_stubs(core: &Arc<KernelCore>, session: &mut KernelSession, global: &mut JsObject) {
|
pub fn bind_stubs(core: &Arc<KernelCore>, session: &mut KernelSession, global: &mut JsObject) {
|
||||||
let builtin_world = Arc::get_mut(&mut session.builtin_world)
|
let builtin_world = Arc::get_mut(&mut session.builtin_world)
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ pub mod bind_reflect;
|
|||||||
pub mod bind_regexp;
|
pub mod bind_regexp;
|
||||||
/// Set 构造器与原型的 native 方法绑定。
|
/// Set 构造器与原型的 native 方法绑定。
|
||||||
pub mod bind_set;
|
pub mod bind_set;
|
||||||
|
/// SharedArrayBuffer 构造器与原型的 native 方法绑定。
|
||||||
|
pub mod bind_shared_array_buffer;
|
||||||
/// String 构造器与原型的 native 方法绑定。
|
/// String 构造器与原型的 native 方法绑定。
|
||||||
pub mod bind_string;
|
pub mod bind_string;
|
||||||
/// 未实现内置(Proxy/BigInt/WeakMap 等)的 stub 构造器绑定。
|
/// 未实现内置(Proxy/BigInt/WeakMap 等)的 stub 构造器绑定。
|
||||||
@@ -632,9 +634,10 @@ fn install_to_string_tags(core: &Arc<KernelCore>, session: &KernelSession) {
|
|||||||
let sh = core.shape_forge().as_ref();
|
let sh = core.shape_forge().as_ref();
|
||||||
let tag_id = oxide_types::private_key::WELL_KNOWN_SYMBOL_TO_STRING_TAG;
|
let tag_id = oxide_types::private_key::WELL_KNOWN_SYMBOL_TO_STRING_TAG;
|
||||||
let tag_key = oxide_types::private_key::make_well_known_symbol_key(tag_id);
|
let tag_key = oxide_types::private_key::make_well_known_symbol_key(tag_id);
|
||||||
let cases: [(*mut JsObject, &str); 12] = [
|
let cases: [(*mut JsObject, &str); 13] = [
|
||||||
(world.map_proto.as_ptr() as *mut JsObject, "Map"),
|
(world.map_proto.as_ptr() as *mut JsObject, "Map"),
|
||||||
(world.array_buffer_proto.as_ptr() as *mut JsObject, "ArrayBuffer"),
|
(world.array_buffer_proto.as_ptr() as *mut JsObject, "ArrayBuffer"),
|
||||||
|
(world.shared_array_buffer_proto.as_ptr() as *mut JsObject, "SharedArrayBuffer"),
|
||||||
(world.set_proto.as_ptr() as *mut JsObject, "Set"),
|
(world.set_proto.as_ptr() as *mut JsObject, "Set"),
|
||||||
(world.data_view_proto.as_ptr() as *mut JsObject, "DataView"),
|
(world.data_view_proto.as_ptr() as *mut JsObject, "DataView"),
|
||||||
(world.array_iterator_proto.as_ptr() as *mut JsObject, "Array Iterator"),
|
(world.array_iterator_proto.as_ptr() as *mut JsObject, "Array Iterator"),
|
||||||
@@ -884,11 +887,6 @@ fn bind_stub_globals(core: &Arc<KernelCore>, session: &KernelSession, global: &m
|
|||||||
oxide_builtins::stubs::finalization_registry_stub::<crate::vm::Vm> as *const (),
|
oxide_builtins::stubs::finalization_registry_stub::<crate::vm::Vm> as *const (),
|
||||||
1,
|
1,
|
||||||
),
|
),
|
||||||
(
|
|
||||||
"SharedArrayBuffer",
|
|
||||||
oxide_builtins::array_buffer::shared_array_buffer_constructor::<crate::vm::Vm> as *const (),
|
|
||||||
1,
|
|
||||||
),
|
|
||||||
("Atomics", oxide_builtins::stubs::atomics_stub::<crate::vm::Vm> as *const (), 0),
|
("Atomics", oxide_builtins::stubs::atomics_stub::<crate::vm::Vm> as *const (), 0),
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -923,6 +921,11 @@ pub fn bind_global_builtin_slots(core: &Arc<KernelCore>, session: &KernelSession
|
|||||||
oxide_builtins::array_buffer::array_buffer_constructor::<crate::vm::Vm> as *const (),
|
oxide_builtins::array_buffer::array_buffer_constructor::<crate::vm::Vm> as *const (),
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
|
configure_existing_ctor(
|
||||||
|
&world.shared_array_buffer_constructor,
|
||||||
|
oxide_builtins::array_buffer::shared_array_buffer_constructor::<crate::vm::Vm> as *const (),
|
||||||
|
1,
|
||||||
|
);
|
||||||
configure_existing_ctor(
|
configure_existing_ctor(
|
||||||
&world.data_view_constructor,
|
&world.data_view_constructor,
|
||||||
oxide_builtins::data_view::data_view_constructor::<crate::vm::Vm> as *const (),
|
oxide_builtins::data_view::data_view_constructor::<crate::vm::Vm> as *const (),
|
||||||
@@ -976,6 +979,10 @@ pub fn bind_global_builtin_slots(core: &Arc<KernelCore>, session: &KernelSession
|
|||||||
"ArrayBuffer",
|
"ArrayBuffer",
|
||||||
JsValue::from_js_object(world.array_buffer_constructor.as_ptr() as *mut JsObject),
|
JsValue::from_js_object(world.array_buffer_constructor.as_ptr() as *mut JsObject),
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
"SharedArrayBuffer",
|
||||||
|
JsValue::from_js_object(world.shared_array_buffer_constructor.as_ptr() as *mut JsObject),
|
||||||
|
),
|
||||||
("DataView", JsValue::from_js_object(world.data_view_constructor.as_ptr() as *mut JsObject)),
|
("DataView", JsValue::from_js_object(world.data_view_constructor.as_ptr() as *mut JsObject)),
|
||||||
("Error", JsValue::from_js_object(world.error_constructor.as_ptr() as *mut JsObject)),
|
("Error", JsValue::from_js_object(world.error_constructor.as_ptr() as *mut JsObject)),
|
||||||
("String", JsValue::from_js_object(world.string_constructor.as_ptr() as *mut JsObject)),
|
("String", JsValue::from_js_object(world.string_constructor.as_ptr() as *mut JsObject)),
|
||||||
@@ -1160,6 +1167,9 @@ pub fn rebind_dirty_builtins(core: &Arc<KernelCore>, session: &mut KernelSession
|
|||||||
if dirty.map_or(true, |d| d.array_buffer) {
|
if dirty.map_or(true, |d| d.array_buffer) {
|
||||||
bind_array_buffer::bind_array_buffer(core, session, global);
|
bind_array_buffer::bind_array_buffer(core, session, global);
|
||||||
}
|
}
|
||||||
|
if dirty.map_or(true, |d| d.shared_array_buffer) {
|
||||||
|
bind_shared_array_buffer::bind_shared_array_buffer(core, session, global);
|
||||||
|
}
|
||||||
if dirty.map_or(true, |d| d.data_view) {
|
if dirty.map_or(true, |d| d.data_view) {
|
||||||
bind_data_view::bind_data_view(core, session, global);
|
bind_data_view::bind_data_view(core, session, global);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1158,3 +1158,167 @@ fn sab_constructor_and_brand_rejection() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(result.as_bool());
|
assert!(result.as_bool());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 构造器 meta 面钉:length 值 1 描述符 {f,f,t},prototype {f,f,f} 值恒等,
|
||||||
|
/// prototype.constructor 互指 {1,0,1},proto 链挂 Object.prototype。
|
||||||
|
#[test]
|
||||||
|
fn sab_ctor_meta_descriptors() {
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval(
|
||||||
|
&mut vm,
|
||||||
|
"(function () { \
|
||||||
|
var l = Object.getOwnPropertyDescriptor(SharedArrayBuffer, 'length'); \
|
||||||
|
var p = Object.getOwnPropertyDescriptor(SharedArrayBuffer, 'prototype'); \
|
||||||
|
var c = Object.getOwnPropertyDescriptor(SharedArrayBuffer.prototype, 'constructor'); \
|
||||||
|
return l.value === 1 && l.writable === false && l.enumerable === false && l.configurable === true \
|
||||||
|
&& p.value === SharedArrayBuffer.prototype \
|
||||||
|
&& p.writable === false && p.enumerable === false && p.configurable === false \
|
||||||
|
&& SharedArrayBuffer.prototype.constructor === SharedArrayBuffer \
|
||||||
|
&& c.writable === true && c.enumerable === false && c.configurable === true \
|
||||||
|
&& Object.getPrototypeOf(SharedArrayBuffer.prototype) === Object.prototype; })()",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert!(result.as_bool());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 原型 @@toStringTag 钉:值 "SharedArrayBuffer"、{f,f,t},Object.prototype
|
||||||
|
/// toString 经标签链读出 "[object SharedArrayBuffer]"。
|
||||||
|
#[test]
|
||||||
|
fn sab_proto_to_string_tag() {
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval(
|
||||||
|
&mut vm,
|
||||||
|
"(function () { \
|
||||||
|
var d = Object.getOwnPropertyDescriptor(SharedArrayBuffer.prototype, Symbol.toStringTag); \
|
||||||
|
return d.value === 'SharedArrayBuffer' \
|
||||||
|
&& d.writable === false && d.enumerable === false && d.configurable === true \
|
||||||
|
&& Object.prototype.toString.call(new SharedArrayBuffer(0)) === '[object SharedArrayBuffer]'; })()",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert!(result.as_bool());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 实例 proto 挂回钉:getPrototypeOf === proto,无 own byteLength 数据属性,
|
||||||
|
/// 构造长度经原型访问器读回,访问器描述符 {get,set 缺,e:false,c:true}。
|
||||||
|
#[test]
|
||||||
|
fn sab_instance_proto_and_readback() {
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval(
|
||||||
|
&mut vm,
|
||||||
|
"(function () { \
|
||||||
|
var sab = new SharedArrayBuffer(42); \
|
||||||
|
var own = Object.getOwnPropertyDescriptor(sab, 'byteLength'); \
|
||||||
|
var d = Object.getOwnPropertyDescriptor(SharedArrayBuffer.prototype, 'byteLength'); \
|
||||||
|
return Object.getPrototypeOf(sab) === SharedArrayBuffer.prototype \
|
||||||
|
&& SharedArrayBuffer.prototype.constructor === SharedArrayBuffer \
|
||||||
|
&& own === undefined \
|
||||||
|
&& sab.byteLength === 42 \
|
||||||
|
&& typeof d.get === 'function' && d.set === undefined \
|
||||||
|
&& d.enumerable === false && d.configurable === true; })()",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert!(result.as_bool());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// receiver 品牌校验钉:get.call(undefined/{} / ArrayBuffer 实例) 均 TypeError。
|
||||||
|
#[test]
|
||||||
|
fn sab_bytelength_this_checks() {
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval(
|
||||||
|
&mut vm,
|
||||||
|
"(function () { \
|
||||||
|
var d = Object.getOwnPropertyDescriptor(SharedArrayBuffer.prototype, 'byteLength'); \
|
||||||
|
var undef_threw = false, obj_threw = false, ab_threw = false; \
|
||||||
|
try { d.get.call(undefined); } catch (e) { undef_threw = e instanceof TypeError; } \
|
||||||
|
try { d.get.call({}); } catch (e) { obj_threw = e instanceof TypeError; } \
|
||||||
|
try { d.get.call(new ArrayBuffer(4)); } catch (e) { ab_threw = e instanceof TypeError; } \
|
||||||
|
return undef_threw && obj_threw && ab_threw; })()",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert!(result.as_bool());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// maxByteLength 非 growable 臂钉:值同字节数,描述符 {get,set 缺,e:false,c:true},
|
||||||
|
/// getter name/length 元数据。
|
||||||
|
#[test]
|
||||||
|
fn sab_max_bytelength_descriptor_and_values() {
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval(
|
||||||
|
&mut vm,
|
||||||
|
"(function () { \
|
||||||
|
var sab8 = new SharedArrayBuffer(8); \
|
||||||
|
var sab0 = new SharedArrayBuffer(0); \
|
||||||
|
var d = Object.getOwnPropertyDescriptor(SharedArrayBuffer.prototype, 'maxByteLength'); \
|
||||||
|
return sab8.maxByteLength === 8 && sab0.maxByteLength === 0 \
|
||||||
|
&& typeof d.get === 'function' && d.set === undefined \
|
||||||
|
&& d.enumerable === false && d.configurable === true \
|
||||||
|
&& d.get.name === 'get maxByteLength' && d.get.length === 0; })()",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert!(result.as_bool());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// GetPrototypeFromConstructor 钉:newTarget.prototype 为对象时实例挂其原型;
|
||||||
|
/// prototype 属性非对象时回落 %SharedArrayBuffer.prototype%;getter 抛错原值传播。
|
||||||
|
#[test]
|
||||||
|
fn sab_new_target_proto_and_fallback() {
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval(
|
||||||
|
&mut vm,
|
||||||
|
"(function () { \
|
||||||
|
var c = Reflect.construct(SharedArrayBuffer, [8], Object); \
|
||||||
|
if (Object.getPrototypeOf(c) !== Object.prototype) { return false; } \
|
||||||
|
var D = function () {}; \
|
||||||
|
D.prototype = null; \
|
||||||
|
var d = Reflect.construct(SharedArrayBuffer, [4], D); \
|
||||||
|
if (Object.getPrototypeOf(d) !== SharedArrayBuffer.prototype) { return false; } \
|
||||||
|
var E = function () {}; \
|
||||||
|
Object.defineProperty(E, 'prototype', { get: function () { throw new RangeError('x'); } }); \
|
||||||
|
var threw = false; \
|
||||||
|
try { Reflect.construct(SharedArrayBuffer, [1], E); } catch (e) { threw = e instanceof RangeError; } \
|
||||||
|
return threw; })()",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert!(result.as_bool());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// full_reset(dirty 重建)重绑钉:重建后构造、实例读回、proto 互指、
|
||||||
|
/// toStringTag 标签全部存活。
|
||||||
|
#[test]
|
||||||
|
fn sab_full_reset_rebinds() {
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
eval(&mut vm, "new SharedArrayBuffer(4).byteLength; 0").expect("run1");
|
||||||
|
vm.full_reset();
|
||||||
|
let result = eval(
|
||||||
|
&mut vm,
|
||||||
|
"(function () { \
|
||||||
|
var sab = new SharedArrayBuffer(4); \
|
||||||
|
return (sab instanceof SharedArrayBuffer) + '|' \
|
||||||
|
+ (sab.byteLength === 4) + '|' \
|
||||||
|
+ (SharedArrayBuffer.prototype.constructor === SharedArrayBuffer) + '|' \
|
||||||
|
+ (sab[Symbol.toStringTag] === 'SharedArrayBuffer'); })()",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let text = vm.lookup_str(result).unwrap_or_default().to_string();
|
||||||
|
assert_eq!(text, "true|true|true|true");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// STUBS 表收缩钉:剩余 6 枚 stub 全局仍为 function 且 Atomics 调用仍抛
|
||||||
|
/// TypeError(占位行为未随 SAB 移出而漂移)。
|
||||||
|
#[test]
|
||||||
|
fn sab_stubs_shrunk_six_remain() {
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval(
|
||||||
|
&mut vm,
|
||||||
|
"(function () { \
|
||||||
|
var names = ['Proxy', 'WeakMap', 'WeakSet', 'WeakRef', 'FinalizationRegistry', 'Atomics']; \
|
||||||
|
for (var i = 0; i < names.length; i++) { \
|
||||||
|
if (typeof globalThis[names[i]] !== 'function') { return false; } \
|
||||||
|
} \
|
||||||
|
var threw = false; \
|
||||||
|
try { Atomics.add(new SharedArrayBuffer(4), 0, 1); } catch (e) { threw = e instanceof TypeError; } \
|
||||||
|
return threw; })()",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert!(result.as_bool());
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user