mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: 落地 ShadowRealm 构造器原型与实例及 not supported 桩
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
//! ShadowRealm 构造器绑定:Box 分配构造器(不占 `BuiltinWorld` P 字段、不新增
|
||||
//! `BuiltinId`、不占 `BuiltinDirtySet` 脏位)加 prototype 与全局槽,全槽
|
||||
//! `lookup_position` 幂等守卫。
|
||||
//!
|
||||
//! 与 `bind_worker` 同型:构造器经 `Box::into_raw` 登记 world 释放
|
||||
//! 登记表(session 收尾统一释放),全局 `ShadowRealm` 槽经 `bind_constructor!`
|
||||
//! 原位安装(既有槽更新槽值、无槽新开)。
|
||||
|
||||
use crate::bind_constructor;
|
||||
use crate::bindings::{
|
||||
apply_binding_table, bind_well_known_data_property, configure_native_constructor, BindEnv,
|
||||
};
|
||||
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
|
||||
use oxide_types::object::{JsObject, PropAttributes};
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
/// 把 ShadowRealm 构造器(Box 分配)与 prototype 方法绑定到 global。
|
||||
///
|
||||
/// # 幂等
|
||||
/// 本函数从三条路径到达:`init_kernel_builtins`(初始)、`rebind_dirty_builtins`
|
||||
/// 的无条件分支(构造器不在脏体系内)、global-dirty 路径
|
||||
/// (`bind_global_builtin_slots`)。构造器本体经 `lookup_position` 守卫复用(有
|
||||
/// 槽即不新建);原型槽位经 `lookup_position` 守卫(有槽即跳过);
|
||||
/// `bind_constructor!` 的全局槽臂自带既有槽原位更新。
|
||||
///
|
||||
/// # 副作用
|
||||
/// - 构造器与原型对象经 `Box::into_raw` 登记 world 释放登记表(session 收尾统一
|
||||
/// 释放);全局 `ShadowRealm` 槽经 `bind_constructor!` 原位安装。
|
||||
/// - prototype 上装 `constructor` 指回构造器、`@@toStringTag` 数据属性
|
||||
/// "ShadowRealm" 与 `evaluate` / `importValue` 方法(not supported 桩)。
|
||||
///
|
||||
/// `realm_id` 经 `@@toStringTag` 符号键编码使用(well-known 符号键按
|
||||
/// (realm 编号,局部下标)编码)。
|
||||
pub fn bind_shadow_realm(env: BindEnv<'_>, global: &mut JsObject) {
|
||||
let world = env.world();
|
||||
let sf = env.string_forge();
|
||||
let sh = env.shape_forge();
|
||||
|
||||
// ---- 构造器本体(Box 分配,不占 P 字段)----
|
||||
// 幂等:全局 `ShadowRealm` 槽已有构造器时复用(不新建)。
|
||||
let si_shadow_realm = sf.intern("ShadowRealm").0;
|
||||
let ctor_ptr: *mut JsObject = match sh.lookup_position(global.shape_id(), si_shadow_realm) {
|
||||
Some(pos) if global.get_prop_at(pos).is_object() => global.get_prop_at(pos).as_js_object_ptr(),
|
||||
_ => {
|
||||
let function_proto = world.function_proto.as_ptr() as *mut JsObject;
|
||||
let mut ctor = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(function_proto));
|
||||
ctor.set_function(true);
|
||||
configure_native_constructor(
|
||||
&mut ctor,
|
||||
crate::shadow_realm::shadow_realm_constructor as *const (),
|
||||
0,
|
||||
);
|
||||
let ptr = Box::into_raw(Box::new(ctor));
|
||||
world.track_leaked_object(ptr);
|
||||
ptr
|
||||
}
|
||||
};
|
||||
|
||||
// 构造器 name 槽(描述符 { f,f,t }),幂等守卫。
|
||||
let si_name = sf.intern("name").0;
|
||||
{
|
||||
let ctor = unsafe { &mut *ctor_ptr };
|
||||
if sh.lookup_position(ctor.shape_id(), si_name).is_none() {
|
||||
let shape = sh.make_shape(ctor.shape_id(), si_name);
|
||||
ctor.set_shape_id(shape);
|
||||
ctor.ensure_hash_props()
|
||||
.push(JsValue::perm_string(sf.string_ptr(sf.intern("ShadowRealm").0)));
|
||||
let pos = ctor.hash_props_vec().map_or(0, |v| v.len() as u32).saturating_sub(1);
|
||||
ctor.set_data_meta(pos, PropAttributes::new(false, false, true));
|
||||
ctor.bump_generation();
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 原型占位 ----
|
||||
// 幂等:构造器 prototype 槽已有原型时复用(不新建)。
|
||||
let si_prototype = sf.intern("prototype").0;
|
||||
let proto_ptr: *mut JsObject = {
|
||||
let ctor = unsafe { &*ctor_ptr };
|
||||
match sh.lookup_position(ctor.shape_id(), si_prototype) {
|
||||
Some(pos) if ctor.get_prop_at(pos).is_object() => ctor.get_prop_at(pos).as_js_object_ptr(),
|
||||
_ => {
|
||||
// ShadowRealm.prototype 的 [[Prototype]] 指向 Object.prototype。
|
||||
let object_proto = world.object_proto.as_ptr() as *mut JsObject;
|
||||
let proto = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(object_proto));
|
||||
let ptr = Box::into_raw(Box::new(proto));
|
||||
world.track_leaked_object(ptr);
|
||||
// 回填构造器 prototype 槽(描述符 { f,f,f })。
|
||||
let ctor = unsafe { &mut *ctor_ptr };
|
||||
let shape = sh.make_shape(ctor.shape_id(), si_prototype);
|
||||
ctor.set_shape_id(shape);
|
||||
ctor.ensure_hash_props().push(JsValue::from_js_object(ptr));
|
||||
let pos = ctor.hash_props_vec().map_or(0, |v| v.len() as u32).saturating_sub(1);
|
||||
ctor.set_data_meta(pos, PropAttributes::new(false, false, false));
|
||||
ctor.bump_generation();
|
||||
ptr
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
let proto = unsafe { &mut *proto_ptr };
|
||||
|
||||
// constructor 槽 → 构造器对象(描述符 { t,f,t }),幂等守卫。
|
||||
let si_constructor = sf.intern("constructor").0;
|
||||
if sh.lookup_position(proto.shape_id(), si_constructor).is_none() {
|
||||
let shape = sh.make_shape(proto.shape_id(), si_constructor);
|
||||
proto.set_shape_id(shape);
|
||||
let pos = proto.push_prop(JsValue::from_js_object(ctor_ptr));
|
||||
proto.set_data_meta(pos, PropAttributes::new(true, false, true));
|
||||
proto.bump_generation();
|
||||
}
|
||||
|
||||
// @@toStringTag 数据属性 "ShadowRealm"(描述符 { f,f,t }),幂等守卫。
|
||||
let tag_key = oxide_types::private_key::encode_symbol_key(
|
||||
env.realm_id(),
|
||||
oxide_types::private_key::WELL_KNOWN_SYMBOL_TO_STRING_TAG,
|
||||
);
|
||||
if sh.lookup_position(proto.shape_id(), tag_key).is_none() {
|
||||
let tag_val = JsValue::perm_string(sf.string_ptr(sf.intern("ShadowRealm").0));
|
||||
bind_well_known_data_property(
|
||||
env.core,
|
||||
proto,
|
||||
oxide_types::private_key::WELL_KNOWN_SYMBOL_TO_STRING_TAG,
|
||||
tag_val,
|
||||
PropAttributes::new(false, false, true),
|
||||
env.realm_id(),
|
||||
);
|
||||
}
|
||||
|
||||
// evaluate / importValue 方法(not supported 桩,幂等守卫)。
|
||||
let si_evaluate = sf.intern("evaluate").0;
|
||||
if sh.lookup_position(proto.shape_id(), si_evaluate).is_none() {
|
||||
apply_binding_table(
|
||||
env,
|
||||
proto,
|
||||
&[(
|
||||
"evaluate",
|
||||
crate::shadow_realm::evaluate_stub as *const (),
|
||||
1,
|
||||
)],
|
||||
);
|
||||
}
|
||||
let si_import_value = sf.intern("importValue").0;
|
||||
if sh.lookup_position(proto.shape_id(), si_import_value).is_none() {
|
||||
apply_binding_table(
|
||||
env,
|
||||
proto,
|
||||
&[(
|
||||
"importValue",
|
||||
crate::shadow_realm::import_value_stub as *const (),
|
||||
2,
|
||||
)],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 全局 `ShadowRealm` 槽(bind_constructor! 自带既有槽原位更新、无槽新开)。
|
||||
bind_constructor!(
|
||||
env,
|
||||
global,
|
||||
"ShadowRealm",
|
||||
ctor_ptr,
|
||||
crate::shadow_realm::shadow_realm_constructor,
|
||||
0,
|
||||
hash: true
|
||||
);
|
||||
}
|
||||
@@ -53,6 +53,8 @@ pub mod bind_object;
|
||||
pub mod bind_reflect;
|
||||
/// RegExp 构造器与原型的 native 方法绑定。
|
||||
pub mod bind_regexp;
|
||||
/// ShadowRealm 构造器绑定(Box 分配,不占 BuiltinWorld P 字段)。
|
||||
pub mod bind_shadow_realm;
|
||||
/// Set 构造器与原型的 native 方法绑定。
|
||||
pub mod bind_set;
|
||||
/// SharedArrayBuffer 构造器与原型的 native 方法绑定。
|
||||
@@ -1326,6 +1328,7 @@ pub fn bind_global_builtin_slots(
|
||||
bind_reflect_global(env, global);
|
||||
bind_iterator_global(env, global);
|
||||
bind_worker::bind_worker(env, global);
|
||||
bind_shadow_realm::bind_shadow_realm(env, global);
|
||||
bind_disposable_stack::bind_disposable_stack(env, global);
|
||||
bind_async_disposable_stack::bind_async_disposable_stack(env, global);
|
||||
bind_stub_globals(env, global);
|
||||
@@ -1461,6 +1464,8 @@ pub fn rebind_dirty_builtins(
|
||||
// worker 构造器是 Box 分配对象(不在 BuiltinWorld 快照内),不占脏位:
|
||||
// 无条件重绑(构造器经 lookup_position 守卫复用,幂等)。
|
||||
bind_worker::bind_worker(env, global);
|
||||
// ShadowRealm 构造器同为 Box 分配对象(不占脏位),无条件重绑,幂等。
|
||||
bind_shadow_realm::bind_shadow_realm(env, global);
|
||||
// tag 目标横跨多个脏分组(Map/Set/DataView/Math/JSON/迭代器原型),
|
||||
// 各组各自重绑后统一补装;安装点自带幂等检查。
|
||||
install_to_string_tags(env);
|
||||
|
||||
@@ -33,6 +33,8 @@ mod proxy;
|
||||
mod realm;
|
||||
/// session 级 mark-sweep GC:标记-清扫 session arena 对象与 session 字符串。
|
||||
pub mod session_gc;
|
||||
/// ShadowRealm native 实现(构造器建影子 realm 与实例对象、evaluate / importValue 桩)。
|
||||
mod shadow_realm;
|
||||
mod suspended;
|
||||
/// test262 宿主对象 `$262` 的最小实现(非标准全局,供 test262 套件使用)。
|
||||
pub mod test262_host;
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
//! ShadowRealm native 实现:构造器(建影子 realm 与实例对象)与 `evaluate` /
|
||||
//! `importValue` 的 not supported 桩。
|
||||
//!
|
||||
//! 关键约定:
|
||||
//! - 函数是 concrete `&mut Vm` 形态(同 `worker_constructor`),不挂 `VmHost`
|
||||
//! trait:构造器要新建 Vm(影子 realm),`VmHost` 接口面表达不了。
|
||||
//! - 实例对象是 PLAIN 对象(`[[Prototype]]` → ShadowRealm.prototype),主 Vm
|
||||
//! 侧表 `shadow_realm_objects` 是 brand 校验依据(this 指针在侧表),不占
|
||||
//! OBJ_TYPE 槽位。
|
||||
//! - `evaluate` / `importValue` 现为 not supported 桩(抛含 `not supported`
|
||||
//! 子串的 TypeError),真实现是后续任务。
|
||||
|
||||
use oxide_builtins::error;
|
||||
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
|
||||
use oxide_runtime_api::{NativeResult, ProtoKind, VmHost};
|
||||
use oxide_types::object::JsObject;
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
use crate::vm::Vm;
|
||||
|
||||
/// `new ShadowRealm()`:建影子 realm(独立 Vm)与实例对象。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. 构造形态校验(规范无 `[[Call]]`:非构造调用抛 TypeError)。
|
||||
/// 2. 建影子 Vm:复用主 Vm 的 `KernelCore`(共享 intern/shape/code 缓存)并
|
||||
/// 注入同一动态编译服务。
|
||||
/// 3. 建实例对象:PLAIN 对象,`[[Prototype]]` → ShadowRealm.prototype。
|
||||
/// 4. 登记主 Vm 侧表:键 = 影子 realm 编号,值 = (实例对象,影子 Vm)。
|
||||
/// 5. 返回实例对象。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 影子 Vm 存主 Vm 侧表、不跨线程:`full_reset` 与 `Drop` 统一清理。
|
||||
/// - 实例对象是 GC 根(侧表登记);影子 Vm 堆独立,主 Vm 的 GC 不触达。
|
||||
///
|
||||
/// # 副作用
|
||||
/// - 新建一个影子 Vm(新 session 加全量 builtin world);登记一条侧表条目
|
||||
/// (GC 根)。
|
||||
pub(crate) fn shadow_realm_constructor(vm: &mut Vm, _args: &[u8]) -> NativeResult {
|
||||
// 构造形态校验(规范只有 [[Construct]])。
|
||||
if !vm.constructing_native {
|
||||
return NativeResult::Err(error::create_type_error(
|
||||
vm,
|
||||
"ShadowRealm constructor requires new",
|
||||
));
|
||||
}
|
||||
|
||||
// 建影子 Vm:共享主 Vm 的 KernelCore 与动态编译服务。
|
||||
let mut shadow_vm = Vm::with_kernel_core(vm.kernel_core.clone());
|
||||
shadow_vm.set_compiler_service(vm.compiler.clone());
|
||||
|
||||
// 建实例对象:PLAIN 对象,[[Prototype]] → ShadowRealm.prototype。
|
||||
let proto_val = shadow_realm_prototype_value(vm);
|
||||
let obj = JsObject::new_empty(EMPTY_SHAPE_ID, proto_val);
|
||||
let ptr = vm.alloc_object(obj);
|
||||
|
||||
// 登记主 Vm 侧表(键 = 影子 realm 编号,值 = 实例对象加影子 Vm)。
|
||||
let realm_id = shadow_vm.realm_id() as u64;
|
||||
vm.shadow_realm_objects
|
||||
.insert(realm_id, (JsValue::from_js_object(ptr), shadow_vm));
|
||||
|
||||
NativeResult::Ok(JsValue::from_js_object(ptr))
|
||||
}
|
||||
|
||||
/// `ShadowRealm.prototype.evaluate` 桩:按规范前置步骤校验后抛 not supported。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. brand 校验(`this` 须是 ShadowRealm 实例)。
|
||||
/// 2. 实参 `source` 非字符串抛 TypeError(规范只接受 String,不做 ToString)。
|
||||
/// 3. 编译 `source`(编译期 SyntaxError 原样透传;语法判定与 realm 无关,
|
||||
/// 经调用方编译服务完成)。
|
||||
/// 4. 抛 not supported。
|
||||
///
|
||||
/// # 边界
|
||||
/// - 桩消息含 `not supported` 子串(test262 判定器据此判能力缺失)。
|
||||
pub(crate) fn evaluate_stub(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
if let Err(e) = shadow_realm_brand_check(vm, this_val) {
|
||||
return NativeResult::Err(e);
|
||||
}
|
||||
|
||||
// 实参 source(args[1]):非字符串抛 TypeError。
|
||||
let source_val = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||||
let source = match vm.lookup_str(source_val) {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
return NativeResult::Err(error::create_type_error(
|
||||
vm,
|
||||
"ShadowRealm.prototype.evaluate source must be a string",
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
// 编译期语法错误原样透传(SyntaxError)。
|
||||
if let Err(msg) = vm.compiler.compile_script(&source) {
|
||||
return NativeResult::Err(error::create_syntax_error(vm, &msg));
|
||||
}
|
||||
|
||||
NativeResult::Err(error::create_type_error(
|
||||
vm,
|
||||
"ShadowRealm.prototype.evaluate is not supported",
|
||||
))
|
||||
}
|
||||
|
||||
/// `ShadowRealm.prototype.importValue` 桩:按规范前置步骤校验后抛 not supported。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. brand 校验(`this` 须是 ShadowRealm 实例)。
|
||||
/// 2. `ToString(specifier)`(abrupt completion 原值传播)。
|
||||
/// 3. 实参 `exportName` 非字符串抛 TypeError(规范只接受 String,不做 ToString)。
|
||||
/// 4. 抛 not supported。
|
||||
///
|
||||
/// # 边界
|
||||
/// - 桩消息含 `not supported` 子串(test262 判定器据此判能力缺失)。
|
||||
pub(crate) fn import_value_stub(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
if let Err(e) = shadow_realm_brand_check(vm, this_val) {
|
||||
return NativeResult::Err(e);
|
||||
}
|
||||
|
||||
// ToString(specifier):abrupt completion 传播原异常(native 重入点原值已物化
|
||||
// 入异常通道)。
|
||||
let specifier_val = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||||
if let Err(e) = oxide_runtime_api::to_string_full(specifier_val, vm) {
|
||||
let exc = vm
|
||||
.exception_value
|
||||
.take()
|
||||
.unwrap_or_else(|| error::create_from_text(vm, &e));
|
||||
return NativeResult::Err(exc);
|
||||
}
|
||||
|
||||
// 实参 exportName(args[2]):非字符串抛 TypeError。
|
||||
let export_name_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
if !export_name_val.is_string() {
|
||||
return NativeResult::Err(error::create_type_error(
|
||||
vm,
|
||||
"ShadowRealm.prototype.importValue exportName must be a string",
|
||||
));
|
||||
}
|
||||
|
||||
NativeResult::Err(error::create_type_error(
|
||||
vm,
|
||||
"ShadowRealm.prototype.importValue is not supported",
|
||||
))
|
||||
}
|
||||
|
||||
/// brand 校验:`this` 须是对象且指针在主 Vm 侧表内(实例对象注册表)。
|
||||
fn shadow_realm_brand_check(vm: &mut Vm, this_val: JsValue) -> Result<(), JsValue> {
|
||||
if !this_val.is_object() {
|
||||
return Err(error::create_type_error(
|
||||
vm,
|
||||
"ShadowRealm method called on non-object",
|
||||
));
|
||||
}
|
||||
let this_ptr = this_val.as_js_object_ptr();
|
||||
let in_table = vm
|
||||
.shadow_realm_objects
|
||||
.values()
|
||||
.any(|(obj, _)| obj.as_js_object_ptr() == this_ptr);
|
||||
if !in_table {
|
||||
return Err(error::create_type_error(vm, "not a ShadowRealm instance"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 读全局 `ShadowRealm` 构造器的 `prototype` 属性(ShadowRealm.prototype)。
|
||||
///
|
||||
/// # 边界
|
||||
/// - 全局 `ShadowRealm` 槽缺失或构造器无 `prototype` 属性时回退到
|
||||
/// `%Object.prototype%`(防御性兜底,正常路径 `bind_shadow_realm` 已安装)。
|
||||
fn shadow_realm_prototype_value(vm: &mut Vm) -> JsValue {
|
||||
let object_proto = JsValue::from_js_object(vm.builtin_proto(ProtoKind::ObjectProto));
|
||||
let global = vm.global_object();
|
||||
let global_ptr = global.as_ptr() as *mut JsObject;
|
||||
// SAFETY: global_ptr 是当前 session 的 global 对象,存活。
|
||||
let global_obj = unsafe { &*global_ptr };
|
||||
let si_shadow_realm = vm.perm_intern("ShadowRealm");
|
||||
let Some(store) = vm.get_own_property_slot(global_obj, si_shadow_realm) else {
|
||||
return object_proto;
|
||||
};
|
||||
let ctor_val = global_obj.get_prop_at(store);
|
||||
if !ctor_val.is_object() {
|
||||
return object_proto;
|
||||
}
|
||||
let ctor_ptr = ctor_val.as_js_object_ptr();
|
||||
// SAFETY: ctor_ptr 是 ShadowRealm 构造器对象,存活。
|
||||
let ctor_obj = unsafe { &*ctor_ptr };
|
||||
let si_prototype = vm.perm_intern("prototype");
|
||||
let Some(proto_store) = vm.get_own_property_slot(ctor_obj, si_prototype) else {
|
||||
return object_proto;
|
||||
};
|
||||
let proto_val = ctor_obj.get_prop_at(proto_store);
|
||||
if proto_val.is_object() {
|
||||
proto_val
|
||||
} else {
|
||||
object_proto
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ use super::frames::Completion;
|
||||
use super::Vm;
|
||||
use crate::session_gc::SessionGc;
|
||||
|
||||
/// GC 根组来源:`for_each_value` 枚举的 29 个根组,变体顺序与根清单
|
||||
/// GC 根组来源:`for_each_value` 枚举的 30 个根组,变体顺序与根清单
|
||||
/// 的枚举顺序一致。
|
||||
///
|
||||
/// 变体下标是逐组计数数组(`SessionGc::root_counts`)的下标;`COUNT` 与
|
||||
@@ -41,6 +41,7 @@ pub(crate) enum RootGroup {
|
||||
ForInIters,
|
||||
Global,
|
||||
WorkerObjects,
|
||||
ShadowRealmObjects,
|
||||
DisposeStack,
|
||||
EventTargets,
|
||||
ModuleEvalStates,
|
||||
@@ -48,7 +49,7 @@ pub(crate) enum RootGroup {
|
||||
|
||||
impl RootGroup {
|
||||
/// 根组总数(与变体数同源,绑定逐组计数数组的长度)。
|
||||
pub const COUNT: usize = 29;
|
||||
pub const COUNT: usize = 30;
|
||||
}
|
||||
|
||||
impl Vm {
|
||||
@@ -56,7 +57,7 @@ impl Vm {
|
||||
/// 覆盖执行核心的全部 JsValue 持有点:regs/帧/各栈段/cell/在途异常与完成/
|
||||
/// 挂起信号/迭代器/微任务/global/Worker 对象注册表。
|
||||
///
|
||||
/// 闭包接收根组来源(`RootGroup`)与根值:组是枚举顺序中的 29 根组之一,
|
||||
/// 闭包接收根组来源(`RootGroup`)与根值:组是枚举顺序中的 30 根组之一,
|
||||
/// 调用方按组计数(如 `SessionGc` 的逐组计数)。
|
||||
pub(crate) fn for_each_value(&self, mut f: impl FnMut(RootGroup, JsValue)) {
|
||||
for value in &self.regs {
|
||||
@@ -186,6 +187,11 @@ impl Vm {
|
||||
for &worker_obj in self.worker_objects.values() {
|
||||
f(RootGroup::WorkerObjects, worker_obj);
|
||||
}
|
||||
// ShadowRealm 实例注册表:实例对象是 GC 根(注册表保活至 full_reset
|
||||
// 清表),漏根 → sweep 释放 → brand 校验解引用悬垂。
|
||||
for (instance_obj, _) in self.shadow_realm_objects.values() {
|
||||
f(RootGroup::ShadowRealmObjects, *instance_obj);
|
||||
}
|
||||
// EventTarget 监听器注册表:监听器回调是 GC 根(存活目标的回调随目标存活,
|
||||
// 漏根 → 回调被 sweep 释放 → 派发解引用悬垂)。弱键剪枝见 sweep;此处
|
||||
// 无条件标活全部回调(死目标的回调多活一轮收集,非泄漏,sweep 已剪其条目)。
|
||||
|
||||
@@ -477,6 +477,10 @@ pub struct Vm {
|
||||
/// 是 GC 根(`for_each_value` 遍历),注册表保活至 `worker_terminate` /
|
||||
/// `full_reset` 清表,无悬垂风险。
|
||||
pub(crate) worker_objects: std::collections::HashMap<u64, JsValue>,
|
||||
/// ShadowRealm 实例注册表:键 = 影子 realm 编号,值 = (实例对象,影子
|
||||
/// Vm)。实例对象是 GC 根(`for_each_value` 遍历);影子 Vm 不跨线程,
|
||||
/// 随主 Vm 整体迁移,在 `full_reset` / `Drop` 清表时统一释放。
|
||||
pub(crate) shadow_realm_objects: std::collections::HashMap<u64, (JsValue, Vm)>,
|
||||
}
|
||||
|
||||
impl Drop for Vm {
|
||||
@@ -534,6 +538,10 @@ impl Drop for Vm {
|
||||
// 条目自持模块 Arc 与常量 BigInt 存储(Vec<BigInt>),存储随 Vm 整体迁移
|
||||
// (同不变量 1 条款:Vm 独占分配、地址稳定、跨线程移动不悬垂);键是
|
||||
// Arc 指针身份,条目自持 Arc 保证键指针在条目存活期内不被分配器复用。
|
||||
//
|
||||
// 8. shadow_realm_objects 字段(HashMap<u64, (JsValue, Vm)>):实例对象指针
|
||||
// 归不变量 1 覆盖;影子 Vm 各持独立 session 堆、不跨线程共享(同不变量 1
|
||||
// 与 3 条款),随主 Vm 整体迁移、地址稳定不悬垂。
|
||||
unsafe impl Send for Vm {}
|
||||
|
||||
impl Vm {
|
||||
|
||||
@@ -257,6 +257,7 @@ impl Vm {
|
||||
worker_registry: std::collections::HashMap::new(),
|
||||
worker_next_id: 0,
|
||||
worker_objects: std::collections::HashMap::new(),
|
||||
shadow_realm_objects: std::collections::HashMap::new(),
|
||||
};
|
||||
vm.init_generator_intrinsics();
|
||||
vm.init_promise_intrinsics();
|
||||
@@ -426,6 +427,7 @@ impl Vm {
|
||||
worker_registry: std::collections::HashMap::new(),
|
||||
worker_next_id: 0,
|
||||
worker_objects: std::collections::HashMap::new(),
|
||||
shadow_realm_objects: std::collections::HashMap::new(),
|
||||
};
|
||||
vm.init_generator_intrinsics();
|
||||
vm.init_promise_intrinsics();
|
||||
@@ -562,6 +564,9 @@ impl Vm {
|
||||
// Worker 对象注册表持 session 对象指针:teardown 释放全部 session 对象
|
||||
// 前须清表,否则残留悬垂指针。
|
||||
self.worker_objects.clear();
|
||||
// ShadowRealm 实例注册表同持 session 对象指针(实例对象):teardown
|
||||
// 释放全部 session 对象前须清表,影子 Vm 随条目 drop 统一释放。
|
||||
self.shadow_realm_objects.clear();
|
||||
self.realm.teardown_session_heap_data();
|
||||
self.realm.gc.borrow_mut().session_bytes_allocated = 0;
|
||||
self.realm.gc.borrow_mut().session_bytes_peak = 0;
|
||||
|
||||
Reference in New Issue
Block a user