feat: 落地 ShadowRealm 构造器原型与实例及 not supported 桩

This commit is contained in:
2026-10-19 02:01:17 +00:00
parent 8307480485
commit 866c8d1fb1
9 changed files with 415 additions and 25 deletions
Generated
+21 -21
View File
@@ -1160,7 +1160,7 @@ dependencies = [
[[package]]
name = "oxide_builtins"
version = "0.21.2"
version = "0.21.3"
dependencies = [
"chrono",
"fast-float",
@@ -1185,7 +1185,7 @@ dependencies = [
[[package]]
name = "oxide_bytecode"
version = "0.21.2"
version = "0.21.3"
dependencies = [
"num-bigint",
"oxide_log",
@@ -1193,7 +1193,7 @@ dependencies = [
[[package]]
name = "oxide_cfg"
version = "0.21.2"
version = "0.21.3"
dependencies = [
"oxide_bytecode",
"oxide_emit",
@@ -1204,7 +1204,7 @@ dependencies = [
[[package]]
name = "oxide_cli"
version = "0.21.2"
version = "0.21.3"
dependencies = [
"ansi_term",
"bumpalo",
@@ -1228,7 +1228,7 @@ dependencies = [
[[package]]
name = "oxide_code_cache"
version = "0.21.2"
version = "0.21.3"
dependencies = [
"lru",
"oxide_bytecode",
@@ -1237,7 +1237,7 @@ dependencies = [
[[package]]
name = "oxide_compiler"
version = "0.21.2"
version = "0.21.3"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1258,7 +1258,7 @@ dependencies = [
[[package]]
name = "oxide_dce"
version = "0.21.2"
version = "0.21.3"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1272,7 +1272,7 @@ dependencies = [
[[package]]
name = "oxide_emit"
version = "0.21.2"
version = "0.21.3"
dependencies = [
"num-bigint",
"oxc_allocator",
@@ -1288,7 +1288,7 @@ dependencies = [
[[package]]
name = "oxide_engine"
version = "0.21.2"
version = "0.21.3"
dependencies = [
"oxide_bytecode",
"oxide_compiler",
@@ -1300,7 +1300,7 @@ dependencies = [
[[package]]
name = "oxide_fold"
version = "0.21.2"
version = "0.21.3"
dependencies = [
"num-bigint",
"oxide_bytecode",
@@ -1312,7 +1312,7 @@ dependencies = [
[[package]]
name = "oxide_ir"
version = "0.21.2"
version = "0.21.3"
dependencies = [
"oxide_bytecode",
"oxide_log",
@@ -1321,7 +1321,7 @@ dependencies = [
[[package]]
name = "oxide_kernel"
version = "0.21.2"
version = "0.21.3"
dependencies = [
"bumpalo",
"dashmap",
@@ -1335,7 +1335,7 @@ dependencies = [
[[package]]
name = "oxide_liveness"
version = "0.21.2"
version = "0.21.3"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1347,7 +1347,7 @@ dependencies = [
[[package]]
name = "oxide_log"
version = "0.21.2"
version = "0.21.3"
dependencies = [
"tracing",
"tracing-appender",
@@ -1356,11 +1356,11 @@ dependencies = [
[[package]]
name = "oxide_net"
version = "0.21.2"
version = "0.21.3"
[[package]]
name = "oxide_parser"
version = "0.21.2"
version = "0.21.3"
dependencies = [
"oxc_allocator",
"oxc_ast",
@@ -1375,7 +1375,7 @@ dependencies = [
[[package]]
name = "oxide_regalloc"
version = "0.21.2"
version = "0.21.3"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1391,7 +1391,7 @@ dependencies = [
[[package]]
name = "oxide_runtime_api"
version = "0.21.2"
version = "0.21.3"
dependencies = [
"num-bigint",
"num-traits",
@@ -1404,7 +1404,7 @@ dependencies = [
[[package]]
name = "oxide_test262"
version = "0.21.2"
version = "0.21.3"
dependencies = [
"oxide_bytecode",
"oxide_compiler",
@@ -1424,7 +1424,7 @@ dependencies = [
[[package]]
name = "oxide_types"
version = "0.21.2"
version = "0.21.3"
dependencies = [
"bumpalo",
"dashmap",
@@ -1437,7 +1437,7 @@ dependencies = [
[[package]]
name = "oxide_vm"
version = "0.21.2"
version = "0.21.3"
dependencies = [
"bumpalo",
"chrono",
+1 -1
View File
@@ -25,7 +25,7 @@ members = [
]
[workspace.package]
version = "0.21.2"
version = "0.21.3"
edition = "2021"
license = "MIT"
rust-version = "1.80"
@@ -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
);
}
+5
View File
@@ -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);
+2
View File
@@ -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;
+197
View File
@@ -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
}
}
+9 -3
View File
@@ -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 已剪其条目)。
+8
View File
@@ -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 {
+5
View File
@@ -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;