refactor: 提取 Realm 组合类型,session 与 GC 及原型槽归 realm

This commit is contained in:
2026-10-07 00:10:27 +00:00
parent add910a504
commit 14ef287a75
31 changed files with 598 additions and 567 deletions
Generated
+18 -18
View File
@@ -1160,7 +1160,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_builtins" name = "oxide_builtins"
version = "0.8.46" version = "0.8.47"
dependencies = [ dependencies = [
"chrono", "chrono",
"fast-float", "fast-float",
@@ -1185,7 +1185,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_bytecode" name = "oxide_bytecode"
version = "0.8.46" version = "0.8.47"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"oxide_log", "oxide_log",
@@ -1193,7 +1193,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_cfg" name = "oxide_cfg"
version = "0.8.46" version = "0.8.47"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_emit", "oxide_emit",
@@ -1204,7 +1204,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_cli" name = "oxide_cli"
version = "0.8.46" version = "0.8.47"
dependencies = [ dependencies = [
"ansi_term", "ansi_term",
"bumpalo", "bumpalo",
@@ -1225,7 +1225,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_code_cache" name = "oxide_code_cache"
version = "0.8.46" version = "0.8.47"
dependencies = [ dependencies = [
"lru", "lru",
"oxide_bytecode", "oxide_bytecode",
@@ -1234,7 +1234,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_compiler" name = "oxide_compiler"
version = "0.8.46" version = "0.8.47"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1253,7 +1253,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_dce" name = "oxide_dce"
version = "0.8.46" version = "0.8.47"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1267,7 +1267,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_emit" name = "oxide_emit"
version = "0.8.46" version = "0.8.47"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"oxc_allocator", "oxc_allocator",
@@ -1282,7 +1282,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_ir" name = "oxide_ir"
version = "0.8.46" version = "0.8.47"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_log", "oxide_log",
@@ -1291,7 +1291,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_kernel" name = "oxide_kernel"
version = "0.8.46" version = "0.8.47"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"dashmap", "dashmap",
@@ -1306,7 +1306,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_liveness" name = "oxide_liveness"
version = "0.8.46" version = "0.8.47"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1318,7 +1318,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_log" name = "oxide_log"
version = "0.8.46" version = "0.8.47"
dependencies = [ dependencies = [
"tracing", "tracing",
"tracing-appender", "tracing-appender",
@@ -1327,7 +1327,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_parser" name = "oxide_parser"
version = "0.8.46" version = "0.8.47"
dependencies = [ dependencies = [
"oxc_allocator", "oxc_allocator",
"oxc_ast", "oxc_ast",
@@ -1342,7 +1342,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_regalloc" name = "oxide_regalloc"
version = "0.8.46" version = "0.8.47"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1358,7 +1358,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_runtime_api" name = "oxide_runtime_api"
version = "0.8.46" version = "0.8.47"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"num-traits", "num-traits",
@@ -1370,7 +1370,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_test262" name = "oxide_test262"
version = "0.8.46" version = "0.8.47"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_compiler", "oxide_compiler",
@@ -1387,7 +1387,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_types" name = "oxide_types"
version = "0.8.46" version = "0.8.47"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"hashbrown 0.14.5", "hashbrown 0.14.5",
@@ -1399,7 +1399,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_vm" name = "oxide_vm"
version = "0.8.46" version = "0.8.47"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"chrono", "chrono",
+1 -1
View File
@@ -22,7 +22,7 @@ members = [
] ]
[workspace.package] [workspace.package]
version = "0.8.46" version = "0.8.47"
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
rust-version = "1.80" rust-version = "1.80"
+1 -1
View File
@@ -83,7 +83,7 @@ pub(crate) fn dispose_async(vm: &mut Vm, args: &[u8]) -> NativeResult {
fn make_dispose_continue_fn( fn make_dispose_continue_fn(
vm: &mut Vm, stack: JsValue, resolve: JsValue, reject: JsValue, reject_role: bool, state_from: Option<&JsObject>, vm: &mut Vm, stack: JsValue, resolve: JsValue, reject: JsValue, reject_role: bool, state_from: Option<&JsObject>,
) -> JsValue { ) -> JsValue {
let fn_proto = vm.session.builtin_world().fn_proto_val(); let fn_proto = vm.realm.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto); let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true); func.set_function(true);
// SAFETY: dispose_async_continue 是 NativeFn 函数项。 // SAFETY: dispose_async_continue 是 NativeFn 函数项。
+4 -4
View File
@@ -81,7 +81,7 @@ impl Vm {
let return_fn = make_wrapper_fn(self, async_from_sync_return as *const ()); let return_fn = make_wrapper_fn(self, async_from_sync_return as *const ());
let throw_fn = make_wrapper_fn(self, async_from_sync_throw as *const ()); let throw_fn = make_wrapper_fn(self, async_from_sync_throw as *const ());
let self_fn = make_wrapper_fn(self, async_from_sync_symbol_async_iterator as *const ()); let self_fn = make_wrapper_fn(self, async_from_sync_symbol_async_iterator as *const ());
let object_proto = self.session.builtin_world().object_proto.as_ptr() as *mut JsObject; let object_proto = self.realm.session.builtin_world().object_proto.as_ptr() as *mut JsObject;
let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(object_proto))); let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(object_proto)));
let obj = unsafe { &mut *ptr }; let obj = unsafe { &mut *ptr };
let inner_si = self.kernel_core.perm_interner().intern(INNER_PROP).0; let inner_si = self.kernel_core.perm_interner().intern(INNER_PROP).0;
@@ -100,7 +100,7 @@ impl Vm {
/// 构造包装器方法 native 函数对象(name/length 属性由 `add_fn_name_length` 补全)。 /// 构造包装器方法 native 函数对象(name/length 属性由 `add_fn_name_length` 补全)。
fn make_wrapper_fn(vm: &mut Vm, native_fn: *const ()) -> JsValue { fn make_wrapper_fn(vm: &mut Vm, native_fn: *const ()) -> JsValue {
let fn_proto = vm.session.builtin_world().fn_proto_val(); let fn_proto = vm.realm.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto); let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true); func.set_function(true);
// SAFETY: native_fn 来自 NativeFn 函数项。 // SAFETY: native_fn 来自 NativeFn 函数项。
@@ -235,7 +235,7 @@ fn close_sync_iterator(vm: &mut Vm, inner: JsValue) {
/// 构造 valueWrapper 拒绝时关闭迭代器的闭包:携带目标 reject 与内层同步迭代器。 /// 构造 valueWrapper 拒绝时关闭迭代器的闭包:携带目标 reject 与内层同步迭代器。
fn make_reject_close_fn(vm: &mut Vm, reject: JsValue, inner: JsValue) -> JsValue { fn make_reject_close_fn(vm: &mut Vm, reject: JsValue, inner: JsValue) -> JsValue {
let fn_proto = vm.session.builtin_world().fn_proto_val(); let fn_proto = vm.realm.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto); let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true); func.set_function(true);
// SAFETY: async_from_sync_reject_close 是 NativeFn 函数项。 // SAFETY: async_from_sync_reject_close 是 NativeFn 函数项。
@@ -271,7 +271,7 @@ fn async_from_sync_reject_close(vm: &mut Vm, args: &[u8]) -> NativeResult {
/// 构造 AsyncFromSyncIteratorContinuation 的 value unwrap 闭包:携带目标 resolve 与 /// 构造 AsyncFromSyncIteratorContinuation 的 value unwrap 闭包:携带目标 resolve 与
/// done 标志,valueWrapper settle 后把解开值包成 `{value, done}` 结算。 /// done 标志,valueWrapper settle 后把解开值包成 `{value, done}` 结算。
fn make_unwrap_fn(vm: &mut Vm, resolve: JsValue, done: bool) -> JsValue { fn make_unwrap_fn(vm: &mut Vm, resolve: JsValue, done: bool) -> JsValue {
let fn_proto = vm.session.builtin_world().fn_proto_val(); let fn_proto = vm.realm.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto); let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true); func.set_function(true);
// SAFETY: async_from_sync_unwrap 是 NativeFn 函数项。 // SAFETY: async_from_sync_unwrap 是 NativeFn 函数项。
+9 -9
View File
@@ -88,7 +88,7 @@ impl Vm {
&mut self, callee: JsValue, this_value: JsValue, args: &[JsValue], promise: JsValue, resolve: JsValue, &mut self, callee: JsValue, this_value: JsValue, args: &[JsValue], promise: JsValue, resolve: JsValue,
reject: JsValue, reject: JsValue,
) -> JsValue { ) -> JsValue {
let proto_val = JsValue::from_js_object(self.session.builtin_world().object_proto.as_ptr() as *mut JsObject); let proto_val = JsValue::from_js_object(self.realm.session.builtin_world().object_proto.as_ptr() as *mut JsObject);
let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val)); let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val));
let obj = unsafe { &mut *ptr }; let obj = unsafe { &mut *ptr };
obj.type_tag = JsObject::OBJ_TYPE_ASYNC; obj.type_tag = JsObject::OBJ_TYPE_ASYNC;
@@ -342,7 +342,7 @@ impl Vm {
/// 构造 await 恢复闭包:携带目标异步上下文对象,区分 fulfill/reject 角色。 /// 构造 await 恢复闭包:携带目标异步上下文对象,区分 fulfill/reject 角色。
fn make_async_await_resume_fn(&mut self, ctx: JsValue, reject_role: bool) -> JsValue { fn make_async_await_resume_fn(&mut self, ctx: JsValue, reject_role: bool) -> JsValue {
let fn_proto = self.session.builtin_world().fn_proto_val(); let fn_proto = self.realm.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto); let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true); func.set_function(true);
// SAFETY: async_await_resume_closure 是 NativeFn 函数项。 // SAFETY: async_await_resume_closure 是 NativeFn 函数项。
@@ -361,7 +361,7 @@ impl Vm {
/// 构造逃出关闭结算闭包:携带目标异步上下文对象与 return() promise,区分 /// 构造逃出关闭结算闭包:携带目标异步上下文对象与 return() promise,区分
/// fulfill/reject 角色。 /// fulfill/reject 角色。
pub(crate) fn make_async_escape_close_fn(&mut self, ctx: JsValue, promise: JsValue, reject_role: bool) -> JsValue { pub(crate) fn make_async_escape_close_fn(&mut self, ctx: JsValue, promise: JsValue, reject_role: bool) -> JsValue {
let fn_proto = self.session.builtin_world().fn_proto_val(); let fn_proto = self.realm.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto); let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true); func.set_function(true);
// SAFETY: async_escape_close_closure 是 NativeFn 函数项。 // SAFETY: async_escape_close_closure 是 NativeFn 函数项。
@@ -596,7 +596,7 @@ fn async_escape_close_closure(vm: &mut Vm, args: &[u8]) -> NativeResult {
pub(crate) fn init_async_intrinsics(vm: &mut Vm) { pub(crate) fn init_async_intrinsics(vm: &mut Vm) {
let sf = vm.kernel_core.perm_interner().as_ref(); let sf = vm.kernel_core.perm_interner().as_ref();
let sh = vm.kernel_core.shape_forge().as_ref(); let sh = vm.kernel_core.shape_forge().as_ref();
let fn_proto_val = vm.session.builtin_world().fn_proto_val(); let fn_proto_val = vm.realm.session.builtin_world().fn_proto_val();
// %AsyncFunction% 构造器:proto = Function.prototype,动态编译异步函数。 // %AsyncFunction% 构造器:proto = Function.prototype,动态编译异步函数。
// 选择性重建复用:前轮构造器按键迁移(prototype 槽在下方 P 槽换入后重指 // 选择性重建复用:前轮构造器按键迁移(prototype 槽在下方 P 槽换入后重指
@@ -607,13 +607,13 @@ pub(crate) fn init_async_intrinsics(vm: &mut Vm) {
let af_ctor_fn_ptr = let af_ctor_fn_ptr =
unsafe { NativeFnPtr::from_raw(oxide_builtins::function::async_function_constructor::<Vm> as *const ()) }; unsafe { NativeFnPtr::from_raw(oxide_builtins::function::async_function_constructor::<Vm> as *const ()) };
let (af_ctor_ptr, af_ctor_is_new) = let (af_ctor_ptr, af_ctor_is_new) =
match vm.session.builtin_world().find_fn_wrapper(af_reuse_key, af_ctor_fn_ptr, 1) { match vm.realm.session.builtin_world().find_fn_wrapper(af_reuse_key, af_ctor_fn_ptr, 1) {
Some(ptr) => (ptr, false), Some(ptr) => (ptr, false),
None => { None => {
// [[Prototype]] = Function 构造器本体(与 Function 构造器同链, // [[Prototype]] = Function 构造器本体(与 Function 构造器同链,
// `Object.getPrototypeOf(AsyncFunction) === Function` 语义)。 // `Object.getPrototypeOf(AsyncFunction) === Function` 语义)。
let fn_ctor_val = let fn_ctor_val =
JsValue::from_js_object(vm.session.builtin_world().function_constructor.as_ptr() as *mut JsObject); JsValue::from_js_object(vm.realm.session.builtin_world().function_constructor.as_ptr() as *mut JsObject);
let mut af_ctor = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, fn_ctor_val)); let mut af_ctor = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, fn_ctor_val));
af_ctor.set_function(true); af_ctor.set_function(true);
af_ctor.set_native_arg_count(1); af_ctor.set_native_arg_count(1);
@@ -637,7 +637,7 @@ pub(crate) fn init_async_intrinsics(vm: &mut Vm) {
af_ctor.set_shape_id(tag_shape); af_ctor.set_shape_id(tag_shape);
let af_ctor_ptr = Box::into_raw(af_ctor); let af_ctor_ptr = Box::into_raw(af_ctor);
// 登记进 world 释放表(带复用键):session 收尾统一释放构造器本体与属性区。 // 登记进 world 释放表(带复用键):session 收尾统一释放构造器本体与属性区。
vm.session.builtin_world().track_fn_wrapper(af_ctor_ptr, af_reuse_key); vm.realm.session.builtin_world().track_fn_wrapper(af_ctor_ptr, af_reuse_key);
(af_ctor_ptr, true) (af_ctor_ptr, true)
} }
}; };
@@ -663,11 +663,11 @@ pub(crate) fn init_async_intrinsics(vm: &mut Vm) {
// 使其与动态异步函数使用的 [[Prototype]] 同一对象,保证 // 使其与动态异步函数使用的 [[Prototype]] 同一对象,保证
// `AsyncFunction.prototype === (async () => {}).__proto__`。 // `AsyncFunction.prototype === (async () => {}).__proto__`。
// 复用构造器 prototype 槽原位改指新 P 原型(旧原型已随 P 换出释放)。 // 复用构造器 prototype 槽原位改指新 P 原型(旧原型已随 P 换出释放)。
Vm::swap_intrinsic_proto(&mut vm.async_function_proto, *af_proto); Vm::swap_intrinsic_proto(&mut vm.realm.async_function_proto, *af_proto);
// SAFETY: af_ctor_ptr 为 Box 原分配(已登记释放表、生命周期覆盖 session),本 Vm 独占。 // SAFETY: af_ctor_ptr 为 Box 原分配(已登记释放表、生命周期覆盖 session),本 Vm 独占。
unsafe { unsafe {
let ctor_mut = &mut *af_ctor_ptr; let ctor_mut = &mut *af_ctor_ptr;
let proto_val = JsValue::from_js_object(vm.async_function_proto.as_ptr() as *mut JsObject); let proto_val = JsValue::from_js_object(vm.realm.async_function_proto.as_ptr() as *mut JsObject);
let name_val = JsValue::perm_string(sf.string_ptr(sf.intern("AsyncFunction").0)); let name_val = JsValue::perm_string(sf.string_ptr(sf.intern("AsyncFunction").0));
if af_ctor_is_new { if af_ctor_is_new {
let lpos = ctor_mut.push_prop(JsValue::int(1)); let lpos = ctor_mut.push_prop(JsValue::int(1));
+15 -15
View File
@@ -103,7 +103,7 @@ impl Vm {
pub(crate) fn create_async_generator_object( pub(crate) fn create_async_generator_object(
&mut self, callee: JsValue, this_value: JsValue, args: &[JsValue], &mut self, callee: JsValue, this_value: JsValue, args: &[JsValue],
) -> Result<JsValue, String> { ) -> Result<JsValue, String> {
let gen_proto_val = JsValue::from_js_object(self.async_generator_proto.as_ptr() as *mut JsObject); let gen_proto_val = JsValue::from_js_object(self.realm.async_generator_proto.as_ptr() as *mut JsObject);
let obj = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, gen_proto_val)); let obj = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, gen_proto_val));
let obj_ref = unsafe { &mut *obj }; let obj_ref = unsafe { &mut *obj };
obj_ref.type_tag = JsObject::OBJ_TYPE_ASYNC_GENERATOR; obj_ref.type_tag = JsObject::OBJ_TYPE_ASYNC_GENERATOR;
@@ -681,7 +681,7 @@ impl Vm {
/// 构造 await 恢复闭包:携带目标异步生成器上下文对象,区分 fulfill/reject 角色。 /// 构造 await 恢复闭包:携带目标异步生成器上下文对象,区分 fulfill/reject 角色。
pub(crate) fn make_async_gen_await_resume_fn(&mut self, ctx: JsValue, reject_role: bool) -> JsValue { pub(crate) fn make_async_gen_await_resume_fn(&mut self, ctx: JsValue, reject_role: bool) -> JsValue {
let fn_proto = self.session.builtin_world().fn_proto_val(); let fn_proto = self.realm.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto); let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true); func.set_function(true);
// SAFETY: async_gen_await_resume_closure 是 NativeFn 函数项。 // SAFETY: async_gen_await_resume_closure 是 NativeFn 函数项。
@@ -702,7 +702,7 @@ impl Vm {
fn make_async_gen_yield_unwrap_fn( fn make_async_gen_yield_unwrap_fn(
&mut self, ctx: JsValue, promise: JsValue, raw: bool, reject_role: bool, &mut self, ctx: JsValue, promise: JsValue, raw: bool, reject_role: bool,
) -> JsValue { ) -> JsValue {
let fn_proto = self.session.builtin_world().fn_proto_val(); let fn_proto = self.realm.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto); let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true); func.set_function(true);
// SAFETY: async_gen_yield_unwrap_closure 是 NativeFn 函数项。 // SAFETY: async_gen_yield_unwrap_closure 是 NativeFn 函数项。
@@ -726,7 +726,7 @@ impl Vm {
pub(crate) fn make_delegate_step_closure( pub(crate) fn make_delegate_step_closure(
&mut self, ctx: JsValue, step: DelegateStep, reject_role: bool, &mut self, ctx: JsValue, step: DelegateStep, reject_role: bool,
) -> JsValue { ) -> JsValue {
let fn_proto = self.session.builtin_world().fn_proto_val(); let fn_proto = self.realm.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto); let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true); func.set_function(true);
// SAFETY: async_gen_delegate_step_closure 是 NativeFn 函数项。 // SAFETY: async_gen_delegate_step_closure 是 NativeFn 函数项。
@@ -747,7 +747,7 @@ impl Vm {
/// 构造委托 return 请求值 Await 恢复闭包:携带目标异步生成器上下文与 /// 构造委托 return 请求值 Await 恢复闭包:携带目标异步生成器上下文与
/// fulfill/reject 角色,结算后以展开值完成生成器(拒绝时以拒绝原因终止)。 /// fulfill/reject 角色,结算后以展开值完成生成器(拒绝时以拒绝原因终止)。
fn make_delegate_return_await_closure(&mut self, ctx: JsValue, reject_role: bool) -> JsValue { fn make_delegate_return_await_closure(&mut self, ctx: JsValue, reject_role: bool) -> JsValue {
let fn_proto = self.session.builtin_world().fn_proto_val(); let fn_proto = self.realm.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto); let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true); func.set_function(true);
// SAFETY: async_gen_delegate_return_await_closure 是 NativeFn 函数项。 // SAFETY: async_gen_delegate_return_await_closure 是 NativeFn 函数项。
@@ -770,7 +770,7 @@ impl Vm {
pub(crate) fn make_async_gen_escape_close_fn( pub(crate) fn make_async_gen_escape_close_fn(
&mut self, ctx: JsValue, promise: JsValue, reject_role: bool, &mut self, ctx: JsValue, promise: JsValue, reject_role: bool,
) -> JsValue { ) -> JsValue {
let fn_proto = self.session.builtin_world().fn_proto_val(); let fn_proto = self.realm.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto); let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true); func.set_function(true);
// SAFETY: async_gen_escape_closure 是 NativeFn 函数项。 // SAFETY: async_gen_escape_closure 是 NativeFn 函数项。
@@ -1469,7 +1469,7 @@ fn async_dispose_settle_closure(vm: &mut Vm, args: &[u8]) -> NativeResult {
impl Vm { impl Vm {
/// 构造 `@@asyncDispose` 的 unwrap 闭包(无捕获状态,恒返回 undefined)。 /// 构造 `@@asyncDispose` 的 unwrap 闭包(无捕获状态,恒返回 undefined)。
fn make_async_dispose_unwrap_fn(&mut self) -> JsValue { fn make_async_dispose_unwrap_fn(&mut self) -> JsValue {
let fn_proto = self.session.builtin_world().fn_proto_val(); let fn_proto = self.realm.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto); let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true); func.set_function(true);
// SAFETY: async_dispose_unwrap_closure 是 NativeFn 函数项。 // SAFETY: async_dispose_unwrap_closure 是 NativeFn 函数项。
@@ -1483,7 +1483,7 @@ impl Vm {
/// 构造 `@@asyncDispose` 结算闭包:捕获能力 promise 与结算角色, /// 构造 `@@asyncDispose` 结算闭包:捕获能力 promise 与结算角色,
/// 反应触发时以反应值结算能力 promise。 /// 反应触发时以反应值结算能力 promise。
fn make_async_dispose_settle_fn(&mut self, promise: JsValue, reject_role: bool) -> JsValue { fn make_async_dispose_settle_fn(&mut self, promise: JsValue, reject_role: bool) -> JsValue {
let fn_proto = self.session.builtin_world().fn_proto_val(); let fn_proto = self.realm.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto); let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true); func.set_function(true);
// SAFETY: async_dispose_settle_closure 是 NativeFn 函数项。 // SAFETY: async_dispose_settle_closure 是 NativeFn 函数项。
@@ -1507,8 +1507,8 @@ impl Vm {
pub(crate) fn init_async_generator_intrinsics(vm: &mut Vm) { pub(crate) fn init_async_generator_intrinsics(vm: &mut Vm) {
let sf = vm.kernel_core.perm_interner().as_ref(); let sf = vm.kernel_core.perm_interner().as_ref();
let sh = vm.kernel_core.shape_forge().as_ref(); let sh = vm.kernel_core.shape_forge().as_ref();
let fn_proto_val = vm.session.builtin_world().fn_proto_val(); let fn_proto_val = vm.realm.session.builtin_world().fn_proto_val();
let world = vm.session.builtin_world(); let world = vm.realm.session.builtin_world();
// %AsyncGeneratorPrototype% 链到 %AsyncIteratorPrototype%(规范原型链), // %AsyncGeneratorPrototype% 链到 %AsyncIteratorPrototype%(规范原型链),
// 方法 next/return/throw 挂其自身。 // 方法 next/return/throw 挂其自身。
let async_iterator_proto_val = JsValue::from_js_object(world.async_iterator_proto.as_ptr() as *mut JsObject); let async_iterator_proto_val = JsValue::from_js_object(world.async_iterator_proto.as_ptr() as *mut JsObject);
@@ -1547,7 +1547,7 @@ pub(crate) fn init_async_generator_intrinsics(vm: &mut Vm) {
world, world,
ag_label, ag_label,
); );
Vm::swap_intrinsic_proto(&mut vm.async_generator_proto, *ag_proto); Vm::swap_intrinsic_proto(&mut vm.realm.async_generator_proto, *ag_proto);
// %AsyncGeneratorFunction.prototype%:proto = Function.prototype, // %AsyncGeneratorFunction.prototype%:proto = Function.prototype,
// constructor = %AsyncGeneratorFunction%。占位构造器动态创建未实现, // constructor = %AsyncGeneratorFunction%。占位构造器动态创建未实现,
@@ -1600,7 +1600,7 @@ pub(crate) fn init_async_generator_intrinsics(vm: &mut Vm) {
let proto2_si = sf.intern("prototype").0; let proto2_si = sf.intern("prototype").0;
let proto2_shape = sh.make_shape(agf_proto.shape_id(), proto2_si); let proto2_shape = sh.make_shape(agf_proto.shape_id(), proto2_si);
agf_proto.set_shape_id(proto2_shape); agf_proto.set_shape_id(proto2_shape);
let ppos2 = agf_proto.push_prop(JsValue::from_js_object(vm.async_generator_proto.as_ptr() as *mut JsObject)); let ppos2 = agf_proto.push_prop(JsValue::from_js_object(vm.realm.async_generator_proto.as_ptr() as *mut JsObject));
agf_proto.set_data_meta(ppos2, PropAttributes::new(false, false, true)); agf_proto.set_data_meta(ppos2, PropAttributes::new(false, false, true));
// agf_proto[Symbol.toStringTag] = "AsyncGeneratorFunction"(数据属性,w/e/c = false/false/true)。 // agf_proto[Symbol.toStringTag] = "AsyncGeneratorFunction"(数据属性,w/e/c = false/false/true)。
let tag2_key = let tag2_key =
@@ -1614,11 +1614,11 @@ pub(crate) fn init_async_generator_intrinsics(vm: &mut Vm) {
// 构造器 length/name/prototype/@@toStringTag 属性(按形状序),prototype 指向 P 槽实例, // 构造器 length/name/prototype/@@toStringTag 属性(按形状序),prototype 指向 P 槽实例,
// 使其与动态异步生成器函数使用的 [[Prototype]] 同一对象。复用构造器槽位已填充, // 使其与动态异步生成器函数使用的 [[Prototype]] 同一对象。复用构造器槽位已填充,
// prototype 原位改指新 P 原型(旧原型已随 P 换出释放)。 // prototype 原位改指新 P 原型(旧原型已随 P 换出释放)。
Vm::swap_intrinsic_proto(&mut vm.async_generator_function_proto, *agf_proto); Vm::swap_intrinsic_proto(&mut vm.realm.async_generator_function_proto, *agf_proto);
// SAFETY: agf_ctor_ptr 为 Box 原分配(已登记释放表、生命周期覆盖 session),本 Vm 独占。 // SAFETY: agf_ctor_ptr 为 Box 原分配(已登记释放表、生命周期覆盖 session),本 Vm 独占。
unsafe { unsafe {
let ctor_mut = &mut *agf_ctor_ptr; let ctor_mut = &mut *agf_ctor_ptr;
let proto_val = JsValue::from_js_object(vm.async_generator_function_proto.as_ptr() as *mut JsObject); let proto_val = JsValue::from_js_object(vm.realm.async_generator_function_proto.as_ptr() as *mut JsObject);
let name_val = JsValue::perm_string(sf.string_ptr(sf.intern("AsyncGeneratorFunction").0)); let name_val = JsValue::perm_string(sf.string_ptr(sf.intern("AsyncGeneratorFunction").0));
if agf_ctor_is_new { if agf_ctor_is_new {
let lpos = ctor_mut.push_prop(JsValue::int(1)); let lpos = ctor_mut.push_prop(JsValue::int(1));
@@ -1644,7 +1644,7 @@ pub(crate) fn init_async_generator_intrinsics(vm: &mut Vm) {
// 绑定 global:AsyncGeneratorFunction 槽已存在则原位更新(full_reset 未重建 // 绑定 global:AsyncGeneratorFunction 槽已存在则原位更新(full_reset 未重建
// global 时旧槽指向已弃 ctor),不存在则开新槽。 // global 时旧槽指向已弃 ctor),不存在则开新槽。
let global_ptr = vm.session.global_object().as_ptr() as *mut JsObject; let global_ptr = vm.realm.session.global_object().as_ptr() as *mut JsObject;
// SAFETY: global 由 session 持有存活整个 session;本函数内只改其 shape/属性区, // SAFETY: global 由 session 持有存活整个 session;本函数内只改其 shape/属性区,
// 期间无 reset 或对象搬移。 // 期间无 reset 或对象搬移。
let global = unsafe { &mut *global_ptr }; let global = unsafe { &mut *global_ptr };
+10 -10
View File
@@ -230,7 +230,7 @@ impl Vm {
if current_cells[cell_idx].is_null() { if current_cells[cell_idx].is_null() {
// 占位 Cell 保持未初始化(TDZ)直到 MAKE_CELL 置位; // 占位 Cell 保持未初始化(TDZ)直到 MAKE_CELL 置位;
// 若绑定为 var 则其初始化 MAKE_CELL 在函数序言先于任何读取执行。 // 若绑定为 var 则其初始化 MAKE_CELL 在函数序言先于任何读取执行。
current_cells[cell_idx] = self.gc_state.alloc_cell(JsValue::undefined(), false); current_cells[cell_idx] = self.realm.gc.alloc_cell(JsValue::undefined(), false);
} }
current_cells[cell_idx] current_cells[cell_idx]
}; };
@@ -275,14 +275,14 @@ impl Vm {
} }
if current[cell_idx].is_null() { if current[cell_idx].is_null() {
// 无占位 cell:新建。 // 无占位 cell:新建。
current[cell_idx] = self.gc_state.alloc_cell(value, initialized); current[cell_idx] = self.realm.gc.alloc_cell(value, initialized);
} else { } else {
let existing_initialized = unsafe { &*current[cell_idx] }.is_initialized(); let existing_initialized = unsafe { &*current[cell_idx] }.is_initialized();
if !initialized && existing_initialized { if !initialized && existing_initialized {
// TDZ 占位而槽内是已初始化 cell:新建替换。循环体每迭代重执行 // TDZ 占位而槽内是已初始化 cell:新建替换。循环体每迭代重执行
// 的 TDZ 占位不得原位翻新迭代 cell(已被本迭代前闭包捕获); // 的 TDZ 占位不得原位翻新迭代 cell(已被本迭代前闭包捕获);
// 已初始化 cell 保持身份,闭包 upvalue 保值。 // 已初始化 cell 保持身份,闭包 upvalue 保值。
current[cell_idx] = self.gc_state.alloc_cell(value, initialized); current[cell_idx] = self.realm.gc.alloc_cell(value, initialized);
} else { } else {
// 更新占位 cell(CREATE_CLOSURE 已建),使闭包 upvalue 指向的 // 更新占位 cell(CREATE_CLOSURE 已建),使闭包 upvalue 指向的
// cell 值跟随初始化;初始化标志随指令 b 槽。 // cell 值跟随初始化;初始化标志随指令 b 槽。
@@ -309,7 +309,7 @@ impl Vm {
while current.len() <= cell_idx { while current.len() <= cell_idx {
current.push(std::ptr::null_mut()); current.push(std::ptr::null_mut());
} }
current[cell_idx] = self.gc_state.alloc_cell(value, true); current[cell_idx] = self.realm.gc.alloc_cell(value, true);
Ok(()) Ok(())
} }
@@ -334,7 +334,7 @@ impl Vm {
} }
if current[cell_idx].is_null() { if current[cell_idx].is_null() {
let val = self.regs[a]; let val = self.regs[a];
current[cell_idx] = self.gc_state.alloc_cell(val, true); current[cell_idx] = self.realm.gc.alloc_cell(val, true);
} }
let c = unsafe { &*current[cell_idx] }; let c = unsafe { &*current[cell_idx] };
if !c.is_initialized() { if !c.is_initialized() {
@@ -478,7 +478,7 @@ impl Vm {
} else { } else {
self.regs[rd] self.regs[rd]
}; };
upvals[uv_idx] = self.gc_state.alloc_cell(val, true); upvals[uv_idx] = self.realm.gc.alloc_cell(val, true);
self.regs[rd] = unsafe { (*upvals[uv_idx]).value }; self.regs[rd] = unsafe { (*upvals[uv_idx]).value };
return Ok(()); return Ok(());
} }
@@ -532,7 +532,7 @@ impl Vm {
} }
vm_debug!("STORE_UPVALUE len={} wrote existing", upvals.len()); vm_debug!("STORE_UPVALUE len={} wrote existing", upvals.len());
} else { } else {
upvals[uv_idx] = self.gc_state.alloc_cell(src_val, true); upvals[uv_idx] = self.realm.gc.alloc_cell(src_val, true);
} }
} }
Ok(()) Ok(())
@@ -544,7 +544,7 @@ impl Vm {
vm_trace!("CREATE_REGEXP rd={}", rd); vm_trace!("CREATE_REGEXP rd={}", rd);
let pat_val = self.regs[a]; let pat_val = self.regs[a];
let flags_val = self.regs[b]; let flags_val = self.regs[b];
let ctor_ptr = self.session.builtin_world().regexp_constructor.as_ptr() as *mut JsObject; let ctor_ptr = self.realm.session.builtin_world().regexp_constructor.as_ptr() as *mut JsObject;
let ctor = unsafe { &*ctor_ptr }; let ctor = unsafe { &*ctor_ptr };
let Some(native_fn) = ctor.native_fn() else { let Some(native_fn) = ctor.native_fn() else {
self.raise_error_kind("TypeError", "RegExp constructor unavailable")?; self.raise_error_kind("TypeError", "RegExp constructor unavailable")?;
@@ -1004,7 +1004,7 @@ impl Vm {
// bound 包装:解包链后转发到最内层 target([[Construct]] 语义)。 // bound 包装:解包链后转发到最内层 target([[Construct]] 语义)。
if ctor_obj.type_tag == oxide_types::object::JsObject::OBJ_TYPE_BOUND { if ctor_obj.type_tag == oxide_types::object::JsObject::OBJ_TYPE_BOUND {
let proto_ptr = &*self.object_prototype as *const JsObject as *mut JsObject; let proto_ptr = &*self.realm.object_prototype as *const JsObject as *mut JsObject;
let new_obj = self.alloc_object(JsObject::new_empty( let new_obj = self.alloc_object(JsObject::new_empty(
oxide_kernel::shape_forge::EMPTY_SHAPE_ID, oxide_kernel::shape_forge::EMPTY_SHAPE_ID,
JsValue::from_js_object(proto_ptr), JsValue::from_js_object(proto_ptr),
@@ -1012,7 +1012,7 @@ impl Vm {
return self.dispatch_new_bound(rd, constructor, new_obj, args, 0); return self.dispatch_new_bound(rd, constructor, new_obj, args, 0);
} }
let proto_ptr = &*self.object_prototype as *const JsObject as *mut JsObject; let proto_ptr = &*self.realm.object_prototype as *const JsObject as *mut JsObject;
let new_obj = self.alloc_object(JsObject::new_empty( let new_obj = self.alloc_object(JsObject::new_empty(
oxide_kernel::shape_forge::EMPTY_SHAPE_ID, oxide_kernel::shape_forge::EMPTY_SHAPE_ID,
JsValue::from_js_object(proto_ptr), JsValue::from_js_object(proto_ptr),
+9 -9
View File
@@ -39,7 +39,7 @@ impl Vm {
return Err(format!("LOAD_GLOBAL constant index {idx} is not a string key")); return Err(format!("LOAD_GLOBAL constant index {idx} is not a string key"));
} }
let si = self.property_key_si(key_val)?; let si = self.property_key_si(key_val)?;
let global = self.session.global_object(); let global = self.realm.session.global_object();
if let Some(val) = self.resolve_property(global, si) { if let Some(val) = self.resolve_property(global, si) {
self.regs[rd] = val; self.regs[rd] = val;
Ok(false) Ok(false)
@@ -67,7 +67,7 @@ impl Vm {
return Err(format!("LOAD_GLOBAL_TYPEOF constant index {idx} is not a string key")); return Err(format!("LOAD_GLOBAL_TYPEOF constant index {idx} is not a string key"));
} }
let si = self.property_key_si(key_val)?; let si = self.property_key_si(key_val)?;
let global = self.session.global_object(); let global = self.realm.session.global_object();
self.regs[rd] = self.resolve_property(global, si).unwrap_or(JsValue::undefined()); self.regs[rd] = self.resolve_property(global, si).unwrap_or(JsValue::undefined());
Ok(()) Ok(())
} }
@@ -215,7 +215,7 @@ impl Vm {
pub(crate) fn dispatch_new_object(&mut self, rd: usize, instr: u32) -> Result<(), String> { pub(crate) fn dispatch_new_object(&mut self, rd: usize, instr: u32) -> Result<(), String> {
let nprops = opcode::a(instr) as usize; let nprops = opcode::a(instr) as usize;
vm_trace!("NEW_OBJECT rd={} nprops={}", rd, nprops); vm_trace!("NEW_OBJECT rd={} nprops={}", rd, nprops);
let proto_ptr = &*self.object_prototype as *const JsObject as *mut JsObject; let proto_ptr = &*self.realm.object_prototype as *const JsObject as *mut JsObject;
let mut shape_id = EMPTY_SHAPE_ID; let mut shape_id = EMPTY_SHAPE_ID;
if nprops > 0 { if nprops > 0 {
let key_idxs: Vec<u32> = self.bytecode[self.pc..self.pc + nprops].to_vec(); let key_idxs: Vec<u32> = self.bytecode[self.pc..self.pc + nprops].to_vec();
@@ -258,7 +258,7 @@ impl Vm {
/// - 登记 session 对象表并计入堆账目;回收由 session GC mark/sweep 承担。 /// - 登记 session 对象表并计入堆账目;回收由 session GC mark/sweep 承担。
pub(crate) fn dispatch_new_session_object(&mut self, rd: usize) -> Result<(), String> { pub(crate) fn dispatch_new_session_object(&mut self, rd: usize) -> Result<(), String> {
vm_trace!("NEW_SESSION_OBJECT rd={}", rd); vm_trace!("NEW_SESSION_OBJECT rd={}", rd);
let proto_ptr = &*self.object_prototype as *const JsObject as *mut JsObject; let proto_ptr = &*self.realm.object_prototype as *const JsObject as *mut JsObject;
let obj = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto_ptr)); let obj = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto_ptr));
let obj_ptr = self.alloc_session_object(obj); let obj_ptr = self.alloc_session_object(obj);
self.regs[rd] = JsValue::object(obj_ptr as *mut u8); self.regs[rd] = JsValue::object(obj_ptr as *mut u8);
@@ -278,7 +278,7 @@ impl Vm {
Some(frame) => (frame.arguments_base, frame.arguments_count), Some(frame) => (frame.arguments_base, frame.arguments_count),
None => (self.inline_args_base, self.inline_args_count), None => (self.inline_args_base, self.inline_args_count),
}; };
let proto_ptr = &*self.object_prototype as *const JsObject as *mut JsObject; let proto_ptr = &*self.realm.object_prototype as *const JsObject as *mut JsObject;
let obj_ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto_ptr))); let obj_ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto_ptr)));
let obj = unsafe { &mut *obj_ptr }; let obj = unsafe { &mut *obj_ptr };
obj.type_tag = JsObject::OBJ_TYPE_ARGUMENTS; obj.type_tag = JsObject::OBJ_TYPE_ARGUMENTS;
@@ -312,7 +312,7 @@ impl Vm {
let simple = self.active_module().is_some_and(|m| m.has_simple_params); let simple = self.active_module().is_some_and(|m| m.has_simple_params);
if strict || !simple { if strict || !simple {
// SAFETY: 指针由绑定层在 session 构造期写入,session 存活期内有效。 // SAFETY: 指针由绑定层在 session 构造期写入,session 存活期内有效。
let thrower_ptr = self.session.builtin_world().throw_type_error.get(); let thrower_ptr = self.realm.session.builtin_world().throw_type_error.get();
if thrower_ptr.is_null() { if thrower_ptr.is_null() {
// 绑定层尚未写入共享对象(正常路径不出现):退化为数据属性保调用可用。 // 绑定层尚未写入共享对象(正常路径不出现):退化为数据属性保调用可用。
if let Err(msg) = if let Err(msg) =
@@ -367,7 +367,7 @@ impl Vm {
let sym_iter_si = make_well_known_symbol_key(0); let sym_iter_si = make_well_known_symbol_key(0);
// SAFETY: array_proto 是 perm 层内置对象(BuiltinWorld 持有),地址稳定且 // SAFETY: array_proto 是 perm 层内置对象(BuiltinWorld 持有),地址稳定且
// 跨 epoch/session 存活,本调用期间无 GC 搬移。 // 跨 epoch/session 存活,本调用期间无 GC 搬移。
let array_proto = self.session.builtin_world().array_proto.as_ptr(); let array_proto = self.realm.session.builtin_world().array_proto.as_ptr();
let iter_val = match self.ordinary_get(unsafe { &*array_proto }, sym_iter_si, JsValue::undefined()) { let iter_val = match self.ordinary_get(unsafe { &*array_proto }, sym_iter_si, JsValue::undefined()) {
Ok(v) => v, Ok(v) => v,
Err(msg) => return self.raise_error_kind("TypeError", &msg), Err(msg) => return self.raise_error_kind("TypeError", &msg),
@@ -397,7 +397,7 @@ impl Vm {
}; };
let n = count as usize; let n = count as usize;
let rest_len = n.saturating_sub(fixed_count); let rest_len = n.saturating_sub(fixed_count);
let proto_ptr = self.session.builtin_world().array_proto.as_ptr() as *mut JsObject; let proto_ptr = self.realm.session.builtin_world().array_proto.as_ptr() as *mut JsObject;
let obj_ptr = let obj_ptr =
self.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(proto_ptr), rest_len)); self.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(proto_ptr), rest_len));
let obj = unsafe { &mut *obj_ptr }; let obj = unsafe { &mut *obj_ptr };
@@ -417,7 +417,7 @@ impl Vm {
pub(crate) fn dispatch_new_array(&mut self, rd: usize, instr: u32) { pub(crate) fn dispatch_new_array(&mut self, rd: usize, instr: u32) {
let n = opcode::imm16(instr) as usize; let n = opcode::imm16(instr) as usize;
vm_trace!("NEW_ARRAY rd={} n={}", rd, n); vm_trace!("NEW_ARRAY rd={} n={}", rd, n);
let proto_ptr = self.session.builtin_world().array_proto.as_ptr() as *mut JsObject; let proto_ptr = self.realm.session.builtin_world().array_proto.as_ptr() as *mut JsObject;
let obj = self.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(proto_ptr), n)); let obj = self.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(proto_ptr), n));
self.regs[rd] = JsValue::object(obj as *mut u8); self.regs[rd] = JsValue::object(obj as *mut u8);
} }
+6 -6
View File
@@ -88,27 +88,27 @@ impl Vm {
} }
return Ok(Some(JsValue::undefined())); return Ok(Some(JsValue::undefined()));
} }
let proto_ptr = self.session.builtin_world().string_proto.as_ptr() as *mut JsObject; let proto_ptr = self.realm.session.builtin_world().string_proto.as_ptr() as *mut JsObject;
let proto = unsafe { &*proto_ptr }; let proto = unsafe { &*proto_ptr };
return self.ordinary_get(proto, prop_name_si, val).map(Some); return self.ordinary_get(proto, prop_name_si, val).map(Some);
} }
if val.is_int() || val.is_double() { if val.is_int() || val.is_double() {
let proto_ptr = self.session.builtin_world().number_proto.as_ptr() as *mut JsObject; let proto_ptr = self.realm.session.builtin_world().number_proto.as_ptr() as *mut JsObject;
let proto = unsafe { &*proto_ptr }; let proto = unsafe { &*proto_ptr };
return self.ordinary_get(proto, prop_name_si, val).map(Some); return self.ordinary_get(proto, prop_name_si, val).map(Some);
} }
if val.is_bool() { if val.is_bool() {
let proto_ptr = self.session.builtin_world().boolean_proto.as_ptr() as *mut JsObject; let proto_ptr = self.realm.session.builtin_world().boolean_proto.as_ptr() as *mut JsObject;
let proto = unsafe { &*proto_ptr }; let proto = unsafe { &*proto_ptr };
return self.ordinary_get(proto, prop_name_si, val).map(Some); return self.ordinary_get(proto, prop_name_si, val).map(Some);
} }
if val.is_bigint() { if val.is_bigint() {
let proto_ptr = self.session.builtin_world().bigint_proto.as_ptr() as *mut JsObject; let proto_ptr = self.realm.session.builtin_world().bigint_proto.as_ptr() as *mut JsObject;
let proto = unsafe { &*proto_ptr }; let proto = unsafe { &*proto_ptr };
return self.ordinary_get(proto, prop_name_si, val).map(Some); return self.ordinary_get(proto, prop_name_si, val).map(Some);
} }
if val.is_symbol() { if val.is_symbol() {
let proto_ptr = self.session.builtin_world().symbol_proto.as_ptr() as *mut JsObject; let proto_ptr = self.realm.session.builtin_world().symbol_proto.as_ptr() as *mut JsObject;
let proto = unsafe { &*proto_ptr }; let proto = unsafe { &*proto_ptr };
return self.ordinary_get(proto, prop_name_si, val).map(Some); return self.ordinary_get(proto, prop_name_si, val).map(Some);
} }
@@ -790,7 +790,7 @@ impl Vm {
return Err(format!("DELETE_GLOBAL_PROP_C constant index {idx} is not a string key")); return Err(format!("DELETE_GLOBAL_PROP_C constant index {idx} is not a string key"));
} }
let si = self.property_key_si(key_val)?; let si = self.property_key_si(key_val)?;
let global_ptr = self.session.global_object().as_ptr() as *mut JsObject; let global_ptr = self.realm.session.global_object().as_ptr() as *mut JsObject;
// SAFETY: 全局对象钉在 session 永久区,指针在 VM 生命周期内有效。 // SAFETY: 全局对象钉在 session 永久区,指针在 VM 生命周期内有效。
let obj = unsafe { &mut *global_ptr }; let obj = unsafe { &mut *global_ptr };
// 统一走共享删除逻辑(与 Reflect.deleteProperty 同源);不可配置返回 // 统一走共享删除逻辑(与 Reflect.deleteProperty 同源);不可配置返回
+9 -9
View File
@@ -102,7 +102,7 @@ impl Vm {
pub(crate) fn create_generator_object( pub(crate) fn create_generator_object(
&mut self, callee: JsValue, this_value: JsValue, args: &[JsValue], &mut self, callee: JsValue, this_value: JsValue, args: &[JsValue],
) -> Result<JsValue, String> { ) -> Result<JsValue, String> {
let gen_proto_val = JsValue::from_js_object(self.generator_proto.as_ptr() as *mut JsObject); let gen_proto_val = JsValue::from_js_object(self.realm.generator_proto.as_ptr() as *mut JsObject);
let obj = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, gen_proto_val)); let obj = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, gen_proto_val));
let obj_ref = unsafe { &mut *obj }; let obj_ref = unsafe { &mut *obj };
obj_ref.type_tag = JsObject::OBJ_TYPE_GENERATOR; obj_ref.type_tag = JsObject::OBJ_TYPE_GENERATOR;
@@ -797,12 +797,12 @@ fn generator_step_result(vm: &mut Vm, step: Result<GeneratorStep, String>) -> Na
pub(crate) fn init_generator_intrinsics(vm: &mut Vm) { pub(crate) fn init_generator_intrinsics(vm: &mut Vm) {
let sf = vm.kernel_core.perm_interner().as_ref(); let sf = vm.kernel_core.perm_interner().as_ref();
let sh = vm.kernel_core.shape_forge().as_ref(); let sh = vm.kernel_core.shape_forge().as_ref();
let fn_proto_val = vm.session.builtin_world().fn_proto_val(); let fn_proto_val = vm.realm.session.builtin_world().fn_proto_val();
let world = vm.session.builtin_world(); let world = vm.realm.session.builtin_world();
// %GeneratorPrototype%:proto = %IteratorPrototype%(生成器是迭代器,继承 // %GeneratorPrototype%:proto = %IteratorPrototype%(生成器是迭代器,继承
// @@iterator 与 Iterator helper 方法),方法 next/return/throw。 // @@iterator 与 Iterator helper 方法),方法 next/return/throw。
let iterator_proto_val = let iterator_proto_val =
JsValue::from_js_object(vm.session.builtin_world().iterator_proto.as_ptr() as *mut JsObject); JsValue::from_js_object(vm.realm.session.builtin_world().iterator_proto.as_ptr() as *mut JsObject);
let mut gen_proto = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, iterator_proto_val)); let mut gen_proto = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, iterator_proto_val));
// 站点标签:与 AsyncGenerator 原型的同名方法槽(next/return/throw)区分复用键。 // 站点标签:与 AsyncGenerator 原型的同名方法槽(next/return/throw)区分复用键。
let gen_label = sf.intern("GeneratorPrototype").0; let gen_label = sf.intern("GeneratorPrototype").0;
@@ -836,7 +836,7 @@ pub(crate) fn init_generator_intrinsics(vm: &mut Vm) {
world, world,
gen_label, gen_label,
); );
Vm::swap_intrinsic_proto(&mut vm.generator_proto, *gen_proto); Vm::swap_intrinsic_proto(&mut vm.realm.generator_proto, *gen_proto);
// %GeneratorFunction.prototype%:proto = Function.prototype,constructor = %GeneratorFunction%。 // %GeneratorFunction.prototype%:proto = Function.prototype,constructor = %GeneratorFunction%。
let mut gf_proto = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto_val)); let mut gf_proto = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto_val));
@@ -888,7 +888,7 @@ pub(crate) fn init_generator_intrinsics(vm: &mut Vm) {
let proto2_si = sf.intern("prototype").0; let proto2_si = sf.intern("prototype").0;
let proto2_shape = sh.make_shape(gf_proto.shape_id(), proto2_si); let proto2_shape = sh.make_shape(gf_proto.shape_id(), proto2_si);
gf_proto.set_shape_id(proto2_shape); gf_proto.set_shape_id(proto2_shape);
let ppos2 = gf_proto.push_prop(JsValue::from_js_object(vm.generator_proto.as_ptr() as *mut JsObject)); let ppos2 = gf_proto.push_prop(JsValue::from_js_object(vm.realm.generator_proto.as_ptr() as *mut JsObject));
gf_proto.set_data_meta(ppos2, oxide_types::object::PropAttributes::new(false, false, true)); gf_proto.set_data_meta(ppos2, oxide_types::object::PropAttributes::new(false, false, true));
// gf_proto[Symbol.toStringTag] = "GeneratorFunction"(数据属性,w/e/c = false/false/true)。 // gf_proto[Symbol.toStringTag] = "GeneratorFunction"(数据属性,w/e/c = false/false/true)。
let tag2_key = let tag2_key =
@@ -902,11 +902,11 @@ pub(crate) fn init_generator_intrinsics(vm: &mut Vm) {
// 构造器 length/name/prototype/@@toStringTag 属性(按形状序),prototype 指向 // 构造器 length/name/prototype/@@toStringTag 属性(按形状序),prototype 指向
// P 槽实例,使其与动态生成器函数使用的 [[Prototype]] 同一对象。复用构造器槽位 // P 槽实例,使其与动态生成器函数使用的 [[Prototype]] 同一对象。复用构造器槽位
// 已填充,prototype 原位改指新 P 原型(旧原型已随 P 换出释放)。 // 已填充,prototype 原位改指新 P 原型(旧原型已随 P 换出释放)。
Vm::swap_intrinsic_proto(&mut vm.generator_function_proto, *gf_proto); Vm::swap_intrinsic_proto(&mut vm.realm.generator_function_proto, *gf_proto);
// SAFETY: gf_ctor_ptr 为 Box 原分配(已登记释放表、生命周期覆盖 session),本 Vm 独占。 // SAFETY: gf_ctor_ptr 为 Box 原分配(已登记释放表、生命周期覆盖 session),本 Vm 独占。
unsafe { unsafe {
let ctor_mut = &mut *gf_ctor_ptr; let ctor_mut = &mut *gf_ctor_ptr;
let proto_val = JsValue::from_js_object(vm.generator_function_proto.as_ptr() as *mut JsObject); let proto_val = JsValue::from_js_object(vm.realm.generator_function_proto.as_ptr() as *mut JsObject);
let name_val = JsValue::perm_string(sf.string_ptr(sf.intern("GeneratorFunction").0)); let name_val = JsValue::perm_string(sf.string_ptr(sf.intern("GeneratorFunction").0));
if gf_ctor_is_new { if gf_ctor_is_new {
let lpos = ctor_mut.push_prop(JsValue::int(1)); let lpos = ctor_mut.push_prop(JsValue::int(1));
@@ -932,7 +932,7 @@ pub(crate) fn init_generator_intrinsics(vm: &mut Vm) {
// 绑定 global:GeneratorFunction 槽已存在则原位更新(full_reset 未重建 global // 绑定 global:GeneratorFunction 槽已存在则原位更新(full_reset 未重建 global
// 时旧槽指向已弃 ctor),不存在则开新槽。 // 时旧槽指向已弃 ctor),不存在则开新槽。
let global_ptr = vm.session.global_object().as_ptr() as *mut JsObject; let global_ptr = vm.realm.session.global_object().as_ptr() as *mut JsObject;
// SAFETY: global 由 session 持有存活整个 session;本函数内只改其 shape/属性区, // SAFETY: global 由 session 持有存活整个 session;本函数内只改其 shape/属性区,
// 期间无 reset 或对象搬移。 // 期间无 reset 或对象搬移。
let global = unsafe { &mut *global_ptr }; let global = unsafe { &mut *global_ptr };
+2
View File
@@ -23,6 +23,8 @@ pub mod native;
mod native_box_dispatch; mod native_box_dispatch;
/// Promise 运行时(状态盒 + 微任务队列 + 构造器/方法实现)。 /// Promise 运行时(状态盒 + 微任务队列 + 构造器/方法实现)。
pub mod promise; pub mod promise;
/// 每 VM 的 realm 组合:内核会话、session GC 簿记与 10 个内建原型槽。
mod realm;
/// session 级 mark-sweep GC:标记-清扫 session arena 对象与 session 字符串。 /// session 级 mark-sweep GC:标记-清扫 session arena 对象与 session 字符串。
pub mod session_gc; pub mod session_gc;
mod suspended; mod suspended;
+21 -21
View File
@@ -28,7 +28,7 @@ impl Vm {
/// 创建聚合静态方法(all/race/allSettled/any)的共享记录对象:剩余计数 /// 创建聚合静态方法(all/race/allSettled/any)的共享记录对象:剩余计数
/// 初始 1,结果数组(race 无)与能力 resolve/reject 闭包全部存为自身属性。 /// 初始 1,结果数组(race 无)与能力 resolve/reject 闭包全部存为自身属性。
fn make_agg_record(&mut self, values: JsValue, resolve: JsValue, reject: JsValue) -> JsValue { fn make_agg_record(&mut self, values: JsValue, resolve: JsValue, reject: JsValue) -> JsValue {
let proto_val = JsValue::from_js_object(self.session.builtin_world().object_proto.as_ptr() as *mut JsObject); let proto_val = JsValue::from_js_object(self.realm.session.builtin_world().object_proto.as_ptr() as *mut JsObject);
let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val)); let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val));
// SAFETY: ptr 由 alloc_object 新建,返回非空 arena 指针;本次 native 调用内不搬移,借出期间无别名。 // SAFETY: ptr 由 alloc_object 新建,返回非空 arena 指针;本次 native 调用内不搬移,借出期间无别名。
let obj = unsafe { &mut *ptr }; let obj = unsafe { &mut *ptr };
@@ -46,7 +46,7 @@ impl Vm {
/// 创建 keyed 聚合静态方法的共享记录对象:剩余计数(初始 1)、结果平行数组、 /// 创建 keyed 聚合静态方法的共享记录对象:剩余计数(初始 1)、结果平行数组、
/// 键平行数组与能力 resolve/reject 闭包存为自身属性。 /// 键平行数组与能力 resolve/reject 闭包存为自身属性。
fn make_agg_record_keyed(&mut self, values: JsValue, keys: JsValue, resolve: JsValue, reject: JsValue) -> JsValue { fn make_agg_record_keyed(&mut self, values: JsValue, keys: JsValue, resolve: JsValue, reject: JsValue) -> JsValue {
let proto_val = JsValue::from_js_object(self.session.builtin_world().object_proto.as_ptr() as *mut JsObject); let proto_val = JsValue::from_js_object(self.realm.session.builtin_world().object_proto.as_ptr() as *mut JsObject);
let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val)); let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val));
// SAFETY: ptr 由 alloc_object 新建,返回非空 arena 指针;本次 native 调用内不搬移,借出期间无别名。 // SAFETY: ptr 由 alloc_object 新建,返回非空 arena 指针;本次 native 调用内不搬移,借出期间无别名。
let obj = unsafe { &mut *ptr }; let obj = unsafe { &mut *ptr };
@@ -67,7 +67,7 @@ impl Vm {
/// 初始 false。内部状态属性非枚举且追加在 length/name 之后,保持内建函数 /// 初始 false。内部状态属性非枚举且追加在 length/name 之后,保持内建函数
/// "length 先于 name" 的属性序。 /// "length 先于 name" 的属性序。
fn make_agg_element_fn(&mut self, native_fn: NativeFn, record: JsValue, index: i32) -> JsValue { fn make_agg_element_fn(&mut self, native_fn: NativeFn, record: JsValue, index: i32) -> JsValue {
let fn_proto = self.session.builtin_world().fn_proto_val(); let fn_proto = self.realm.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto); let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true); func.set_function(true);
// SAFETY: native_fn 是 NativeFn 函数项。 // SAFETY: native_fn 是 NativeFn 函数项。
@@ -99,7 +99,7 @@ impl Vm {
/// 构造 allSettled 的结算记录 `{status, <value_field>: value}` 普通对象。 /// 构造 allSettled 的结算记录 `{status, <value_field>: value}` 普通对象。
fn make_settled_record(&mut self, status: &str, value_field: &str, value: JsValue) -> JsValue { fn make_settled_record(&mut self, status: &str, value_field: &str, value: JsValue) -> JsValue {
let proto_val = JsValue::from_js_object(self.session.builtin_world().object_proto.as_ptr() as *mut JsObject); let proto_val = JsValue::from_js_object(self.realm.session.builtin_world().object_proto.as_ptr() as *mut JsObject);
let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val)); let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val));
// SAFETY: ptr 由 alloc_object 新建,返回非空 arena 指针;写 status/value 属性(含 new_string 分配)期间不搬移,借出期间无别名。 // SAFETY: ptr 由 alloc_object 新建,返回非空 arena 指针;写 status/value 属性(含 new_string 分配)期间不搬移,借出期间无别名。
let obj = unsafe { &mut *ptr }; let obj = unsafe { &mut *ptr };
@@ -114,7 +114,7 @@ impl Vm {
/// 构造 AggregateError 实例(proto = %AggregateError.prototype%):message 非 /// 构造 AggregateError 实例(proto = %AggregateError.prototype%):message 非
/// undefined 时 ToString 建自身属性,errors 存为数据属性。 /// undefined 时 ToString 建自身属性,errors 存为数据属性。
fn make_aggregate_error(&mut self, errors: JsValue, message: JsValue) -> JsValue { fn make_aggregate_error(&mut self, errors: JsValue, message: JsValue) -> JsValue {
let proto_val = JsValue::from_js_object(self.aggregate_error_proto.as_ptr() as *mut JsObject); let proto_val = JsValue::from_js_object(self.realm.aggregate_error_proto.as_ptr() as *mut JsObject);
let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val)); let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val));
// SAFETY: ptr 由 alloc_object 新建,返回非空 arena 指针;写 message/errors 数据属性期间不搬移,借出期间无别名。 // SAFETY: ptr 由 alloc_object 新建,返回非空 arena 指针;写 message/errors 数据属性期间不搬移,借出期间无别名。
let obj = unsafe { &mut *ptr }; let obj = unsafe { &mut *ptr };
@@ -135,7 +135,7 @@ impl Vm {
/// 把 errors 可迭代值收集为新数组(IterableToList)。不可迭代抛 TypeError。 /// 把 errors 可迭代值收集为新数组(IterableToList)。不可迭代抛 TypeError。
fn aggregate_errors_to_list(&mut self, errors: JsValue) -> Result<JsValue, JsValue> { fn aggregate_errors_to_list(&mut self, errors: JsValue) -> Result<JsValue, JsValue> {
let array_proto = JsValue::from_js_object(self.session.builtin_world().array_proto.as_ptr() as *mut JsObject); let array_proto = JsValue::from_js_object(self.realm.session.builtin_world().array_proto.as_ptr() as *mut JsObject);
let ptr = self.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, array_proto, 0)); let ptr = self.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, array_proto, 0));
let list = JsValue::from_js_object(ptr); let list = JsValue::from_js_object(ptr);
let mut index = 0usize; let mut index = 0usize;
@@ -151,7 +151,7 @@ impl Vm {
/// 建普通数组对象并依次写入元素(Promise.try 转发实参的承载)。 /// 建普通数组对象并依次写入元素(Promise.try 转发实参的承载)。
fn make_plain_array(&mut self, elements: Vec<JsValue>) -> JsValue { fn make_plain_array(&mut self, elements: Vec<JsValue>) -> JsValue {
let array_proto = JsValue::from_js_object(self.session.builtin_world().array_proto.as_ptr() as *mut JsObject); let array_proto = JsValue::from_js_object(self.realm.session.builtin_world().array_proto.as_ptr() as *mut JsObject);
let ptr = self.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, array_proto, 0)); let ptr = self.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, array_proto, 0));
// SAFETY: ptr 由 alloc_object 新建,返回非空 arena 指针;元素写入不搬移对象。 // SAFETY: ptr 由 alloc_object 新建,返回非空 arena 指针;元素写入不搬移对象。
let obj = unsafe { &mut *ptr }; let obj = unsafe { &mut *ptr };
@@ -165,7 +165,7 @@ impl Vm {
/// 自身属性(GC 边走属性区,免 native_data 接线);W 被构造器以 /// 自身属性(GC 边走属性区,免 native_data 接线);W 被构造器以
/// (resolve, reject) 实参调用。 /// (resolve, reject) 实参调用。
fn make_try_wrapper(&mut self, executor: JsValue, call_args: Vec<JsValue>) -> JsValue { fn make_try_wrapper(&mut self, executor: JsValue, call_args: Vec<JsValue>) -> JsValue {
let fn_proto = self.session.builtin_world().fn_proto_val(); let fn_proto = self.realm.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto); let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true); func.set_function(true);
// SAFETY: promise_try_wrapper 是 NativeFn 函数项。 // SAFETY: promise_try_wrapper 是 NativeFn 函数项。
@@ -192,7 +192,7 @@ impl Vm {
let sf = self.kernel_core.perm_interner().as_ref(); let sf = self.kernel_core.perm_interner().as_ref();
let sh = self.kernel_core.shape_forge().as_ref(); let sh = self.kernel_core.shape_forge().as_ref();
let error_proto_val = let error_proto_val =
JsValue::from_js_object(self.session.builtin_world().error_proto.as_ptr() as *mut JsObject); JsValue::from_js_object(self.realm.session.builtin_world().error_proto.as_ptr() as *mut JsObject);
// %AggregateError.prototype%:proto = %Error.prototype%,constructor/name/message 数据属性。 // %AggregateError.prototype%:proto = %Error.prototype%,constructor/name/message 数据属性。
let mut proto = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, error_proto_val)); let mut proto = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, error_proto_val));
@@ -214,7 +214,7 @@ impl Vm {
// %AggregateError% 构造器:proto = %Error%(NativeError 构造器继承 Error 构造器),length 2。 // %AggregateError% 构造器:proto = %Error%(NativeError 构造器继承 Error 构造器),length 2。
let error_ctor_val = let error_ctor_val =
JsValue::from_js_object(self.session.builtin_world().error_constructor.as_ptr() as *mut JsObject); JsValue::from_js_object(self.realm.session.builtin_world().error_constructor.as_ptr() as *mut JsObject);
let mut ctor = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, error_ctor_val)); let mut ctor = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, error_ctor_val));
ctor.set_function(true); ctor.set_function(true);
ctor.type_tag = JsObject::OBJ_TYPE_CONSTRUCTOR; ctor.type_tag = JsObject::OBJ_TYPE_CONSTRUCTOR;
@@ -238,22 +238,22 @@ impl Vm {
ctor.set_data_meta(2u32, PropAttributes::new(false, false, false)); ctor.set_data_meta(2u32, PropAttributes::new(false, false, false));
// 固定地址后互相接线:proto.constructor ↔ ctor.prototype。 // 固定地址后互相接线:proto.constructor ↔ ctor.prototype。
Self::swap_intrinsic_proto(&mut self.aggregate_error_proto, *proto); Self::swap_intrinsic_proto(&mut self.realm.aggregate_error_proto, *proto);
Self::swap_intrinsic_proto(&mut self.aggregate_error_constructor, *ctor); Self::swap_intrinsic_proto(&mut self.realm.aggregate_error_constructor, *ctor);
// SAFETY: aggregate_error_proto 为堆址固定的 P<JsObject>(Arc 透明包装),本行前刚经 swap_intrinsic_proto 落地;与 ctor_mut 分属不同对象,无别名。 // SAFETY: aggregate_error_proto 为堆址固定的 P<JsObject>(Arc 透明包装),本行前刚经 swap_intrinsic_proto 落地;与 ctor_mut 分属不同对象,无别名。
let proto_mut = unsafe { &mut *self.aggregate_error_proto.as_mut_ptr() }; let proto_mut = unsafe { &mut *self.realm.aggregate_error_proto.as_mut_ptr() };
proto_mut proto_mut
.set_prop_at(0u32, JsValue::from_js_object(self.aggregate_error_constructor.as_ptr() as *mut JsObject)); .set_prop_at(0u32, JsValue::from_js_object(self.realm.aggregate_error_constructor.as_ptr() as *mut JsObject));
// SAFETY: aggregate_error_constructor 同为堆址固定的 P<JsObject>(Arc 透明包装);此处写 prototype 槽位(下标 2),与 proto_mut 分属不同对象,无别名。 // SAFETY: aggregate_error_constructor 同为堆址固定的 P<JsObject>(Arc 透明包装);此处写 prototype 槽位(下标 2),与 proto_mut 分属不同对象,无别名。
let ctor_mut = unsafe { &mut *self.aggregate_error_constructor.as_mut_ptr() }; let ctor_mut = unsafe { &mut *self.realm.aggregate_error_constructor.as_mut_ptr() };
ctor_mut.set_prop_at(2u32, JsValue::from_js_object(self.aggregate_error_proto.as_ptr() as *mut JsObject)); ctor_mut.set_prop_at(2u32, JsValue::from_js_object(self.realm.aggregate_error_proto.as_ptr() as *mut JsObject));
// 绑定 global(槽已存在则更新)。 // 绑定 global(槽已存在则更新)。
let global_ptr = self.session.global_object().as_ptr() as *mut JsObject; let global_ptr = self.realm.session.global_object().as_ptr() as *mut JsObject;
// SAFETY: global 对象由 session 持有,存活整个 session;本函数内只改其 shape/属性区,期间无 reset 或对象搬移。 // SAFETY: global 对象由 session 持有,存活整个 session;本函数内只改其 shape/属性区,期间无 reset 或对象搬移。
let global = unsafe { &mut *global_ptr }; let global = unsafe { &mut *global_ptr };
let si = self.kernel_core.perm_interner().intern("AggregateError").0; let si = self.kernel_core.perm_interner().intern("AggregateError").0;
let ctor_val = JsValue::from_js_object(self.aggregate_error_constructor.as_ptr() as *mut JsObject); let ctor_val = JsValue::from_js_object(self.realm.aggregate_error_constructor.as_ptr() as *mut JsObject);
if let Some(pos) = self.kernel_core.shape_forge().lookup_position(global.shape_id(), si) { if let Some(pos) = self.kernel_core.shape_forge().lookup_position(global.shape_id(), si) {
global.set_prop_at(pos, ctor_val); global.set_prop_at(pos, ctor_val);
} else { } else {
@@ -356,7 +356,7 @@ pub(super) fn promise_static_with_resolvers(vm: &mut Vm, args: &[u8]) -> NativeR
Ok(t) => t, Ok(t) => t,
Err(err) => return NativeResult::Err(err), Err(err) => return NativeResult::Err(err),
}; };
let object_proto = JsValue::from_js_object(vm.session.builtin_world().object_proto.as_ptr() as *mut JsObject); let object_proto = JsValue::from_js_object(vm.realm.session.builtin_world().object_proto.as_ptr() as *mut JsObject);
let ptr = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, object_proto)); let ptr = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, object_proto));
// SAFETY: ptr 由 alloc_object 新建,返回非空 arena 指针;写 promise/resolve/reject 属性期间不搬移,借出期间无别名。 // SAFETY: ptr 由 alloc_object 新建,返回非空 arena 指针;写 promise/resolve/reject 属性期间不搬移,借出期间无别名。
let obj = unsafe { &mut *ptr }; let obj = unsafe { &mut *ptr };
@@ -481,7 +481,7 @@ fn perform_promise_combine(
let values = if kind == AggregateKind::Race { let values = if kind == AggregateKind::Race {
JsValue::undefined() JsValue::undefined()
} else { } else {
let array_proto = JsValue::from_js_object(vm.session.builtin_world().array_proto.as_ptr() as *mut JsObject); let array_proto = JsValue::from_js_object(vm.realm.session.builtin_world().array_proto.as_ptr() as *mut JsObject);
let ptr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, array_proto, 0)); let ptr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, array_proto, 0));
JsValue::from_js_object(ptr) JsValue::from_js_object(ptr)
}; };
@@ -1049,7 +1049,7 @@ fn aggregate_error_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult {
let this = if this_val.is_object() && new_target.is_object() { let this = if this_val.is_object() && new_target.is_object() {
this_val.as_js_object_ptr() this_val.as_js_object_ptr()
} else { } else {
let proto_val = JsValue::from_js_object(vm.aggregate_error_proto.as_ptr() as *mut JsObject); let proto_val = JsValue::from_js_object(vm.realm.aggregate_error_proto.as_ptr() as *mut JsObject);
vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val)) vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val))
}; };
// SAFETY: this 来自构造路径预分配或 alloc_object 新建,均存活且本段无别名。 // SAFETY: this 来自构造路径预分配或 alloc_object 新建,均存活且本段无别名。
+17 -17
View File
@@ -22,7 +22,7 @@ use super::{is_constructor_value, PromiseState, PromiseStateKind};
impl Vm { impl Vm {
/// 创建空 Promise 对象(proto = `%Promise.prototype%`),状态盒为 Pending。 /// 创建空 Promise 对象(proto = `%Promise.prototype%`),状态盒为 Pending。
pub(super) fn create_promise_object(&mut self) -> JsValue { pub(super) fn create_promise_object(&mut self) -> JsValue {
let proto_val = JsValue::from_js_object(self.promise_proto.as_ptr() as *mut JsObject); let proto_val = JsValue::from_js_object(self.realm.promise_proto.as_ptr() as *mut JsObject);
let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val)); let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val));
// SAFETY: `alloc_object` 返回非空 arena 指针;此处写 type_tag 与 native_data // SAFETY: `alloc_object` 返回非空 arena 指针;此处写 type_tag 与 native_data
// (Box<PromiseState> 由 Box::into_raw 分配,随对象释放),无别名。 // (Box<PromiseState> 由 Box::into_raw 分配,随对象释放),无别名。
@@ -114,11 +114,11 @@ impl Vm {
// 的 receiver 原型链判定通过。 // 的 receiver 原型链判定通过。
let is_data_view = std::ptr::eq( let is_data_view = std::ptr::eq(
ctor.as_js_object_ptr(), ctor.as_js_object_ptr(),
self.session.builtin_world().data_view_constructor.as_ptr() as *mut JsObject, self.realm.session.builtin_world().data_view_constructor.as_ptr() as *mut JsObject,
); );
let this_val = if is_data_view { let this_val = if is_data_view {
let data_view_proto_val = let data_view_proto_val =
JsValue::from_js_object(self.session.builtin_world().data_view_proto.as_ptr() as *mut JsObject); JsValue::from_js_object(self.realm.session.builtin_world().data_view_proto.as_ptr() as *mut JsObject);
JsValue::from_js_object(self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, data_view_proto_val))) JsValue::from_js_object(self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, data_view_proto_val)))
} else { } else {
let this_ptr = self.alloc_ctor_this(nt_obj, ctor_obj, new_target)?; let this_ptr = self.alloc_ctor_this(nt_obj, ctor_obj, new_target)?;
@@ -156,7 +156,7 @@ impl Vm {
&mut self, nt_obj: &JsObject, ctor_obj: &JsObject, nt_val: JsValue, &mut self, nt_obj: &JsObject, ctor_obj: &JsObject, nt_val: JsValue,
) -> Result<*mut JsObject, JsValue> { ) -> Result<*mut JsObject, JsValue> {
let proto_si = self.kernel_core.perm_interner().intern("prototype").0; let proto_si = self.kernel_core.perm_interner().intern("prototype").0;
let object_proto = JsValue::from_js_object(self.session.builtin_world().object_proto.as_ptr() as *mut JsObject); let object_proto = JsValue::from_js_object(self.realm.session.builtin_world().object_proto.as_ptr() as *mut JsObject);
let is_native_ctor = ctor_obj.native_fn().is_some() && ctor_obj.type_tag == JsObject::OBJ_TYPE_CONSTRUCTOR; let is_native_ctor = ctor_obj.native_fn().is_some() && ctor_obj.type_tag == JsObject::OBJ_TYPE_CONSTRUCTOR;
let proto_val = if is_native_ctor { let proto_val = if is_native_ctor {
match self.resolve_property(nt_obj, proto_si) { match self.resolve_property(nt_obj, proto_si) {
@@ -257,10 +257,10 @@ impl Vm {
pub(crate) fn init_promise_intrinsics(&mut self) { pub(crate) fn init_promise_intrinsics(&mut self) {
let sf = self.kernel_core.perm_interner().as_ref(); let sf = self.kernel_core.perm_interner().as_ref();
let sh = self.kernel_core.shape_forge().as_ref(); let sh = self.kernel_core.shape_forge().as_ref();
let fn_proto_val = self.session.builtin_world().fn_proto_val(); let fn_proto_val = self.realm.session.builtin_world().fn_proto_val();
let world = self.session.builtin_world(); let world = self.realm.session.builtin_world();
let object_proto_val = let object_proto_val =
JsValue::from_js_object(self.session.builtin_world().object_proto.as_ptr() as *mut JsObject); JsValue::from_js_object(self.realm.session.builtin_world().object_proto.as_ptr() as *mut JsObject);
// %Promise.prototype%:proto = Object.prototype,方法 then/catch/finally + @@toStringTag。 // %Promise.prototype%:proto = Object.prototype,方法 then/catch/finally + @@toStringTag。
let mut proto = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, object_proto_val)); let mut proto = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, object_proto_val));
@@ -327,23 +327,23 @@ impl Vm {
); );
// 固定地址后互相接线:proto.constructor ↔ ctor.prototype。 // 固定地址后互相接线:proto.constructor ↔ ctor.prototype。
Self::swap_intrinsic_proto(&mut self.promise_proto, *proto); Self::swap_intrinsic_proto(&mut self.realm.promise_proto, *proto);
Self::swap_intrinsic_proto(&mut self.promise_constructor, *ctor); Self::swap_intrinsic_proto(&mut self.realm.promise_constructor, *ctor);
// SAFETY: `promise_proto` 为 `P<JsObject>`(Arc 透明包装),堆址固定且本行前刚经 // SAFETY: `promise_proto` 为 `P<JsObject>`(Arc 透明包装),堆址固定且本行前刚经
// swap_intrinsic_proto 落地;与下一处 ctor_mut 指向不同对象,无别名。 // swap_intrinsic_proto 落地;与下一处 ctor_mut 指向不同对象,无别名。
let proto_mut = unsafe { &mut *self.promise_proto.as_mut_ptr() }; let proto_mut = unsafe { &mut *self.realm.promise_proto.as_mut_ptr() };
proto_mut.set_prop_at(0u32, JsValue::from_js_object(self.promise_constructor.as_ptr() as *mut JsObject)); proto_mut.set_prop_at(0u32, JsValue::from_js_object(self.realm.promise_constructor.as_ptr() as *mut JsObject));
// SAFETY: `promise_constructor` 同为堆址固定的存活 `P<JsObject>`(Arc 透明包装); // SAFETY: `promise_constructor` 同为堆址固定的存活 `P<JsObject>`(Arc 透明包装);
// 此处写 prototype 槽位(下标 2),与 proto_mut 分属不同对象,无别名。 // 此处写 prototype 槽位(下标 2),与 proto_mut 分属不同对象,无别名。
let ctor_mut = unsafe { &mut *self.promise_constructor.as_mut_ptr() }; let ctor_mut = unsafe { &mut *self.realm.promise_constructor.as_mut_ptr() };
// prototype 槽位在 length/name 之后(下标 2)。 // prototype 槽位在 length/name 之后(下标 2)。
ctor_mut.set_prop_at(2u32, JsValue::from_js_object(self.promise_proto.as_ptr() as *mut JsObject)); ctor_mut.set_prop_at(2u32, JsValue::from_js_object(self.realm.promise_proto.as_ptr() as *mut JsObject));
// Promise[Symbol.species] 访问器:getter 返回 receiver,派生类沿静态原型链 // Promise[Symbol.species] 访问器:getter 返回 receiver,派生类沿静态原型链
// 解析 @@species 得自身构造器。ctor 经本函数每次调用全新构造,同键槽不累积。 // 解析 @@species 得自身构造器。ctor 经本函数每次调用全新构造,同键槽不累积。
crate::bindings::bind_accessor_getter_key( crate::bindings::bind_accessor_getter_key(
&self.kernel_core, &self.kernel_core,
&self.session, &self.realm.session,
ctor_mut, ctor_mut,
oxide_types::private_key::make_well_known_symbol_key(oxide_types::private_key::WELL_KNOWN_SYMBOL_SPECIES), oxide_types::private_key::make_well_known_symbol_key(oxide_types::private_key::WELL_KNOWN_SYMBOL_SPECIES),
"get [Symbol.species]", "get [Symbol.species]",
@@ -351,12 +351,12 @@ impl Vm {
); );
// 绑定 global:槽已存在则更新(full_reset 未重建 global 时旧槽指向已弃 ctor)。 // 绑定 global:槽已存在则更新(full_reset 未重建 global 时旧槽指向已弃 ctor)。
let global_ptr = self.session.global_object().as_ptr() as *mut JsObject; let global_ptr = self.realm.session.global_object().as_ptr() as *mut JsObject;
// SAFETY: global 对象由 session 持有,存活整个 session;本函数内只改其 // SAFETY: global 对象由 session 持有,存活整个 session;本函数内只改其
// shape/属性区,期间无 reset 或对象搬移。 // shape/属性区,期间无 reset 或对象搬移。
let global = unsafe { &mut *global_ptr }; let global = unsafe { &mut *global_ptr };
let si = self.kernel_core.perm_interner().intern("Promise").0; let si = self.kernel_core.perm_interner().intern("Promise").0;
let ctor_val = JsValue::from_js_object(self.promise_constructor.as_ptr() as *mut JsObject); let ctor_val = JsValue::from_js_object(self.realm.promise_constructor.as_ptr() as *mut JsObject);
if let Some(pos) = self.kernel_core.shape_forge().lookup_position(global.shape_id(), si) { if let Some(pos) = self.kernel_core.shape_forge().lookup_position(global.shape_id(), si) {
global.set_prop_at(pos, ctor_val); global.set_prop_at(pos, ctor_val);
} else { } else {
@@ -392,7 +392,7 @@ fn promise_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult {
return NativeResult::Err(oxide_builtins::error::create_type_error(vm, "Promise executor is not a function")); return NativeResult::Err(oxide_builtins::error::create_type_error(vm, "Promise executor is not a function"));
} }
// GetPrototypeFromConstructor:异常原值上抛;非对象结果回落内建原型。 // GetPrototypeFromConstructor:异常原值上抛;非对象结果回落内建原型。
let promise_proto_val = JsValue::from_js_object(vm.promise_proto.as_ptr() as *mut JsObject); let promise_proto_val = JsValue::from_js_object(vm.realm.promise_proto.as_ptr() as *mut JsObject);
let new_target = vm.reg(255); let new_target = vm.reg(255);
let proto = if new_target.is_object() { let proto = if new_target.is_object() {
let nt_ptr = new_target.as_js_object_ptr(); let nt_ptr = new_target.as_js_object_ptr();
+4 -4
View File
@@ -145,7 +145,7 @@ impl Vm {
} }
}; };
if ctor.is_undefined() { if ctor.is_undefined() {
return Ok(JsValue::from_js_object(self.promise_constructor.as_ptr() as *mut JsObject)); return Ok(JsValue::from_js_object(self.realm.promise_constructor.as_ptr() as *mut JsObject));
} }
if !ctor.is_object() { if !ctor.is_object() {
return Err(oxide_builtins::error::create_type_error( return Err(oxide_builtins::error::create_type_error(
@@ -287,7 +287,7 @@ impl Vm {
/// 调 onFinally 后经 PromiseResolve(ctor, 返回值) 解包,再以直通 thunk /// 调 onFinally 后经 PromiseResolve(ctor, 返回值) 解包,再以直通 thunk
/// 调 Invoke(p, "then")——fulfill 角色透传原值,reject 角色重抛原拒绝原因。 /// 调 Invoke(p, "then")——fulfill 角色透传原值,reject 角色重抛原拒绝原因。
fn make_finally_handler(&mut self, on_finally: JsValue, ctor: JsValue, reject_role: bool) -> JsValue { fn make_finally_handler(&mut self, on_finally: JsValue, ctor: JsValue, reject_role: bool) -> JsValue {
let fn_proto = self.session.builtin_world().fn_proto_val(); let fn_proto = self.realm.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto); let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true); func.set_function(true);
// SAFETY: promise_finally_handler 是 NativeFn 函数项。 // SAFETY: promise_finally_handler 是 NativeFn 函数项。
@@ -309,7 +309,7 @@ impl Vm {
/// 构造 finally 直通 thunk(CreateBuiltinFunction(closure, 0, "")): /// 构造 finally 直通 thunk(CreateBuiltinFunction(closure, 0, "")):
/// fulfill 角色返回携带值,reject 角色抛携带的拒绝原因。 /// fulfill 角色返回携带值,reject 角色抛携带的拒绝原因。
fn make_finally_thunk(&mut self, reject_role: bool, value: JsValue) -> JsValue { fn make_finally_thunk(&mut self, reject_role: bool, value: JsValue) -> JsValue {
let fn_proto = self.session.builtin_world().fn_proto_val(); let fn_proto = self.realm.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto); let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true); func.set_function(true);
// SAFETY: finally_thunk 是 NativeFn 函数项。 // SAFETY: finally_thunk 是 NativeFn 函数项。
@@ -360,7 +360,7 @@ fn promise_finally_handler(vm: &mut Vm, args: &[u8]) -> NativeResult {
let c_si = vm.kernel_core.perm_interner().intern(FINALLY_CTOR_PROP).0; let c_si = vm.kernel_core.perm_interner().intern(FINALLY_CTOR_PROP).0;
let ctor = vm let ctor = vm
.resolve_property(callee_obj, c_si) .resolve_property(callee_obj, c_si)
.unwrap_or_else(|| JsValue::from_js_object(vm.promise_constructor.as_ptr() as *mut JsObject)); .unwrap_or_else(|| JsValue::from_js_object(vm.realm.promise_constructor.as_ptr() as *mut JsObject));
let rj_si = vm.kernel_core.perm_interner().intern(FINALLY_REJECT_PROP).0; let rj_si = vm.kernel_core.perm_interner().intern(FINALLY_REJECT_PROP).0;
let is_reject = vm let is_reject = vm
.resolve_property(callee_obj, rj_si) .resolve_property(callee_obj, rj_si)
+4 -4
View File
@@ -36,7 +36,7 @@ impl Vm {
pub(super) fn new_promise_capability_with_ctor( pub(super) fn new_promise_capability_with_ctor(
&mut self, ctor: JsValue, &mut self, ctor: JsValue,
) -> Result<(JsValue, JsValue, JsValue), JsValue> { ) -> Result<(JsValue, JsValue, JsValue), JsValue> {
let intrinsic = JsValue::from_js_object(self.promise_constructor.as_ptr() as *mut JsObject); let intrinsic = JsValue::from_js_object(self.realm.promise_constructor.as_ptr() as *mut JsObject);
if oxide_runtime_api::same_value(ctor, intrinsic) { if oxide_runtime_api::same_value(ctor, intrinsic) {
return Ok(self.new_promise_capability()); return Ok(self.new_promise_capability());
} }
@@ -71,7 +71,7 @@ impl Vm {
/// 构造 GetCapabilitiesExecutor:调用时把 resolve/reject 存入自身 prop。 /// 构造 GetCapabilitiesExecutor:调用时把 resolve/reject 存入自身 prop。
fn make_capability_executor(&mut self) -> JsValue { fn make_capability_executor(&mut self) -> JsValue {
let fn_proto = self.session.builtin_world().fn_proto_val(); let fn_proto = self.realm.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto); let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true); func.set_function(true);
// SAFETY: capability_executor 是 NativeFn 函数项。 // SAFETY: capability_executor 是 NativeFn 函数项。
@@ -90,7 +90,7 @@ impl Vm {
/// 仍阻止二次结算。 /// 仍阻止二次结算。
pub(super) fn make_resolve_reject_fn(&mut self, promise: JsValue, reject_role: bool, delegated: bool) -> JsValue { pub(super) fn make_resolve_reject_fn(&mut self, promise: JsValue, reject_role: bool, delegated: bool) -> JsValue {
let native_fn: NativeFn = if reject_role { promise_reject_closure } else { promise_resolve_closure }; let native_fn: NativeFn = if reject_role { promise_reject_closure } else { promise_resolve_closure };
let fn_proto = self.session.builtin_world().fn_proto_val(); let fn_proto = self.realm.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto); let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true); func.set_function(true);
// SAFETY: native_fn 是 NativeFn 函数项。 // SAFETY: native_fn 是 NativeFn 函数项。
@@ -314,7 +314,7 @@ impl Vm {
return Err(exc); return Err(exc);
} }
}; };
let intrinsic = JsValue::from_js_object(self.promise_constructor.as_ptr() as *mut JsObject); let intrinsic = JsValue::from_js_object(self.realm.promise_constructor.as_ptr() as *mut JsObject);
if oxide_runtime_api::same_value(ctor, intrinsic) { if oxide_runtime_api::same_value(ctor, intrinsic) {
return Ok(value); return Ok(value);
} }
+44
View File
@@ -0,0 +1,44 @@
//! 每 VM 的 realm 组合:内核会话(builtin world 与 global 对象)、
//! session GC 簿记与 10 个内建原型槽。
//!
//! `Vm` 以单个 `realm: Realm` 字段持有本组合。`kernel_core`
//! 留在 `Vm` 上不进 Realm(`active_vms` 边界守卫计数是 per-VM 语义,
//! `KernelCore` 是跨 realm 共享结构,多 realm 共享同一 kernel)。
use oxide_kernel::kernel::KernelSession;
use oxide_types::mem::P;
use oxide_types::object::JsObject;
use crate::vm_state::GcState;
/// 每 VM 的 realm 组合:内核会话(builtin world 与 global 对象)、
/// session GC 簿记与 10 个内建原型槽。
///
/// 字段顺序按原 `Vm` 声明顺序(session 先、10 个 P 字段次之、gc 最后),
/// 保 Drop 相对顺序。
pub(crate) struct Realm {
pub(crate) session: KernelSession,
/// `%Object.prototype%`:session 的 Object 原型(global 的 `[[Prototype]]` 挂它)。
pub(crate) object_prototype: P<JsObject>,
/// `%GeneratorPrototype%`:生成器实例的原型(next/return/throw 方法挂此)。
pub(crate) generator_proto: P<JsObject>,
/// `%GeneratorFunction.prototype%`:生成器函数对象的原型(`constructor` 指向
/// `%GeneratorFunction%`,使 `g.constructor.name` 解析为 "GeneratorFunction")。
pub(crate) generator_function_proto: P<JsObject>,
/// `%Promise%` 构造器(resolve/reject 静态方法挂此,global 的 Promise 槽指向它)。
pub(crate) promise_constructor: P<JsObject>,
/// `%Promise.prototype%`:Promise 实例的原型(then/catch/finally 方法挂此)。
pub(crate) promise_proto: P<JsObject>,
/// `%AggregateError%` 构造器(Promise.any 拒绝时构造 AggregateError 用)。
pub(crate) aggregate_error_constructor: P<JsObject>,
/// `%AggregateError.prototype%`(proto = %Error.prototype%)。
pub(crate) aggregate_error_proto: P<JsObject>,
/// `%AsyncFunction.prototype%`:异步函数对象的原型(`constructor` 指向 `%AsyncFunction%`)。
pub(crate) async_function_proto: P<JsObject>,
/// `%AsyncGeneratorPrototype%`:异步生成器实例的原型(next/return/throw/@@asyncIterator)。
pub(crate) async_generator_proto: P<JsObject>,
/// `%AsyncGeneratorFunction.prototype%`:异步生成器函数对象的原型。
pub(crate) async_generator_function_proto: P<JsObject>,
/// session 堆与 GC 簿记(对象/字符串/BigInt/cell 四表 + 水位与账目)。
pub(crate) gc: GcState,
}
+29 -29
View File
@@ -50,7 +50,7 @@ impl SessionGc {
/// 清空 session 对象表的 GC mark 位。置位不随表清位消失,残留位会让下一次 /// 清空 session 对象表的 GC mark 位。置位不随表清位消失,残留位会让下一次
/// `mark` 的 DFS 在已标对象处短路,漏扫其新增引用边。 /// `mark` 的 DFS 在已标对象处短路,漏扫其新增引用边。
pub(crate) fn clear_all_marks(&mut self, vm: &mut Vm) { pub(crate) fn clear_all_marks(&mut self, vm: &mut Vm) {
vm_debug!("[GC] clear_all_marks: {} session objects", vm.gc_state.session_object_ptrs.len()); vm_debug!("[GC] clear_all_marks: {} session objects", vm.realm.gc.session_object_ptrs.len());
self.clear_session_marks(vm); self.clear_session_marks(vm);
} }
@@ -59,7 +59,7 @@ impl SessionGc {
/// 与收集前历史残留——残留 true 会让下一次 `mark` 的 DFS 在已标对象处 /// 与收集前历史残留——残留 true 会让下一次 `mark` 的 DFS 在已标对象处
/// 短路,漏扫其新增引用边。 /// 短路,漏扫其新增引用边。
pub(crate) fn clear_session_marks(&mut self, vm: &mut Vm) { pub(crate) fn clear_session_marks(&mut self, vm: &mut Vm) {
for &ptr in &vm.gc_state.session_object_ptrs { for &ptr in &vm.realm.gc.session_object_ptrs {
if ptr.is_null() { if ptr.is_null() {
continue; continue;
} }
@@ -650,7 +650,7 @@ impl SessionGc {
/// `sweep`(完整收集)与 `collect_in_run`(执行期收集)共用,保证两条 /// `sweep`(完整收集)与 `collect_in_run`(执行期收集)共用,保证两条
/// 收集路径的弱键定夺口径一致。返回 (存活数, 死数, 释放字节)。 /// 收集路径的弱键定夺口径一致。返回 (存活数, 死数, 释放字节)。
fn sweep_in_place(&mut self, vm: &mut Vm) -> (u64, u64, u64) { fn sweep_in_place(&mut self, vm: &mut Vm) -> (u64, u64, u64) {
let old_ptrs = std::mem::take(&mut vm.gc_state.session_object_ptrs); let old_ptrs = std::mem::take(&mut vm.realm.gc.session_object_ptrs);
let mut survivors = Vec::with_capacity(old_ptrs.len()); let mut survivors = Vec::with_capacity(old_ptrs.len());
// 弱键定夺先于死对象释放:键对象(含死键)此刻全部仍分配, // 弱键定夺先于死对象释放:键对象(含死键)此刻全部仍分配,
@@ -689,12 +689,12 @@ impl SessionGc {
} }
} }
let live = survivors.len() as u64; let live = survivors.len() as u64;
vm.gc_state.session_object_ptrs = survivors; vm.realm.gc.session_object_ptrs = survivors;
// 对象口径重算:存活对象头 + 堆数据求和(串/BigInt/cell 分量不在此口径, // 对象口径重算:存活对象头 + 堆数据求和(串/BigInt/cell 分量不在此口径,
// 由各清扫路径按存活补回,与完整收集的最终账目一致)。 // 由各清扫路径按存活补回,与完整收集的最终账目一致)。
vm.gc_state.session_bytes_allocated = vm vm.realm.gc.session_bytes_allocated = vm
.gc_state .realm.gc
.session_object_ptrs .session_object_ptrs
.iter() .iter()
.filter(|&&ptr| !ptr.is_null()) .filter(|&&ptr| !ptr.is_null())
@@ -737,8 +737,8 @@ impl SessionGc {
/// `session_bytes_allocated` 重置为仅对象),再补回存活字符串字节。 /// `session_bytes_allocated` 重置为仅对象),再补回存活字符串字节。
/// 返回释放的字节数。 /// 返回释放的字节数。
pub(crate) fn sweep_session_strings(&mut self, vm: &mut Vm) -> u64 { pub(crate) fn sweep_session_strings(&mut self, vm: &mut Vm) -> u64 {
vm_debug!("[GC] sweep strings: {} string ptrs", vm.gc_state.session_string_ptrs.len()); vm_debug!("[GC] sweep strings: {} string ptrs", vm.realm.gc.session_string_ptrs.len());
let old = std::mem::take(&mut vm.gc_state.session_string_ptrs); let old = std::mem::take(&mut vm.realm.gc.session_string_ptrs);
let mut freed = 0u64; let mut freed = 0u64;
let mut live_bytes = 0usize; let mut live_bytes = 0usize;
let mut live = Vec::with_capacity(old.len()); let mut live = Vec::with_capacity(old.len());
@@ -756,8 +756,8 @@ impl SessionGc {
freed += unsafe { Self::drop_dead_session_string(ptr) }; freed += unsafe { Self::drop_dead_session_string(ptr) };
} }
} }
vm.gc_state.session_string_ptrs = live; vm.realm.gc.session_string_ptrs = live;
vm.gc_state.session_bytes_allocated = vm.gc_state.session_bytes_allocated.saturating_add(live_bytes); vm.realm.gc.session_bytes_allocated = vm.realm.gc.session_bytes_allocated.saturating_add(live_bytes);
self.total_bytes_freed = self.total_bytes_freed.saturating_add(freed); self.total_bytes_freed = self.total_bytes_freed.saturating_add(freed);
self.last_collection_bytes_freed = self.last_collection_bytes_freed.saturating_add(freed); self.last_collection_bytes_freed = self.last_collection_bytes_freed.saturating_add(freed);
@@ -769,7 +769,7 @@ impl SessionGc {
/// forwarding 表与根指针重写。在字符串清扫之后运行。 /// forwarding 表与根指针重写。在字符串清扫之后运行。
/// 返回释放的字节数。 /// 返回释放的字节数。
pub(crate) fn sweep_session_bigints(&mut self, vm: &mut Vm) -> u64 { pub(crate) fn sweep_session_bigints(&mut self, vm: &mut Vm) -> u64 {
let old = vm.gc_state.session_bigint_ptrs.borrow_mut().drain(..).collect::<Vec<_>>(); let old = vm.realm.gc.session_bigint_ptrs.borrow_mut().drain(..).collect::<Vec<_>>();
let mut freed = 0u64; let mut freed = 0u64;
let mut live = Vec::with_capacity(old.len()); let mut live = Vec::with_capacity(old.len());
for ptr in old { for ptr in old {
@@ -788,7 +788,7 @@ impl SessionGc {
} }
} }
} }
*vm.gc_state.session_bigint_ptrs.borrow_mut() = live; *vm.realm.gc.session_bigint_ptrs.borrow_mut() = live;
self.total_bytes_freed = self.total_bytes_freed.saturating_add(freed); self.total_bytes_freed = self.total_bytes_freed.saturating_add(freed);
self.last_collection_bytes_freed = self.last_collection_bytes_freed.saturating_add(freed); self.last_collection_bytes_freed = self.last_collection_bytes_freed.saturating_add(freed);
@@ -804,7 +804,7 @@ impl SessionGc {
/// 统计、不重算存活账目。 /// 统计、不重算存活账目。
/// 返回释放的字节数。 /// 返回释放的字节数。
pub(crate) fn sweep_session_cells(&mut self, vm: &mut Vm) -> u64 { pub(crate) fn sweep_session_cells(&mut self, vm: &mut Vm) -> u64 {
let old = vm.gc_state.session_cell_ptrs.borrow_mut().drain(..).collect::<Vec<_>>(); let old = vm.realm.gc.session_cell_ptrs.borrow_mut().drain(..).collect::<Vec<_>>();
let mut freed = 0u64; let mut freed = 0u64;
let mut live = Vec::with_capacity(old.len()); let mut live = Vec::with_capacity(old.len());
for ptr in old { for ptr in old {
@@ -822,7 +822,7 @@ impl SessionGc {
} }
} }
} }
*vm.gc_state.session_cell_ptrs.borrow_mut() = live; *vm.realm.gc.session_cell_ptrs.borrow_mut() = live;
self.total_bytes_freed = self.total_bytes_freed.saturating_add(freed); self.total_bytes_freed = self.total_bytes_freed.saturating_add(freed);
self.last_collection_bytes_freed = self.last_collection_bytes_freed.saturating_add(freed); self.last_collection_bytes_freed = self.last_collection_bytes_freed.saturating_add(freed);
@@ -831,10 +831,10 @@ impl SessionGc {
/// 完整收集的触发判断:对象、字符串或 BigInt 表非空,且字节账目已达阈值。 /// 完整收集的触发判断:对象、字符串或 BigInt 表非空,且字节账目已达阈值。
pub(crate) fn should_collect(&self, vm: &Vm) -> bool { pub(crate) fn should_collect(&self, vm: &Vm) -> bool {
(!vm.gc_state.session_object_ptrs.is_empty() (!vm.realm.gc.session_object_ptrs.is_empty()
|| !vm.gc_state.session_string_ptrs.is_empty() || !vm.realm.gc.session_string_ptrs.is_empty()
|| !vm.gc_state.session_bigint_ptrs.borrow().is_empty()) || !vm.realm.gc.session_bigint_ptrs.borrow().is_empty())
&& vm.gc_state.session_bytes_allocated >= vm.kernel_core().config().session_gc_threshold && vm.realm.gc.session_bytes_allocated >= vm.kernel_core().config().session_gc_threshold
} }
/// 执行期字符串回收的触发判断:账目须超过水位(上次收集后的存活字节 + /// 执行期字符串回收的触发判断:账目须超过水位(上次收集后的存活字节 +
@@ -842,10 +842,10 @@ impl SessionGc {
/// 保证死对象超阈值即被 reset 回收;执行期走增量水位,活串超阈值时不每指令 /// 保证死对象超阈值即被 reset 回收;执行期走增量水位,活串超阈值时不每指令
/// 重复触发无死串可回收的白跑。 /// 重复触发无死串可回收的白跑。
pub(crate) fn should_collect_strings(&self, vm: &Vm) -> bool { pub(crate) fn should_collect_strings(&self, vm: &Vm) -> bool {
(!vm.gc_state.session_object_ptrs.is_empty() (!vm.realm.gc.session_object_ptrs.is_empty()
|| !vm.gc_state.session_string_ptrs.is_empty() || !vm.realm.gc.session_string_ptrs.is_empty()
|| !vm.gc_state.session_bigint_ptrs.borrow().is_empty()) || !vm.realm.gc.session_bigint_ptrs.borrow().is_empty())
&& vm.gc_state.session_bytes_allocated >= vm.gc_state.string_gc_watermark && vm.realm.gc.session_bytes_allocated >= vm.realm.gc.string_gc_watermark
} }
/// debug 兜底:mark 之后断言所有存活对象持有的字符串边都已登记进 /// debug 兜底:mark 之后断言所有存活对象持有的字符串边都已登记进
@@ -853,7 +853,7 @@ impl SessionGc {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
fn debug_assert_marked_object_strings_live(&self, vm: &Vm) { fn debug_assert_marked_object_strings_live(&self, vm: &Vm) {
let mut live = HashSet::with_hasher(FxBuildHasher); let mut live = HashSet::with_hasher(FxBuildHasher);
for &ptr in &vm.gc_state.session_object_ptrs { for &ptr in &vm.realm.gc.session_object_ptrs {
if ptr.is_null() { if ptr.is_null() {
continue; continue;
} }
@@ -942,7 +942,7 @@ impl SessionGc {
// 扣减字符串账目(保留对象账目),再补回存活串字节。 // 扣减字符串账目(保留对象账目),再补回存活串字节。
let object_bytes: usize = vm let object_bytes: usize = vm
.gc_state .realm.gc
.session_object_ptrs .session_object_ptrs
.iter() .iter()
.filter(|&&ptr| !ptr.is_null()) .filter(|&&ptr| !ptr.is_null())
@@ -951,7 +951,7 @@ impl SessionGc {
size_of::<JsObject>() as u64 + Self::object_heap_data_bytes(obj) size_of::<JsObject>() as u64 + Self::object_heap_data_bytes(obj)
}) })
.sum::<u64>() as usize; .sum::<u64>() as usize;
vm.gc_state.session_bytes_allocated = object_bytes; vm.realm.gc.session_bytes_allocated = object_bytes;
let mut freed_bytes = self.sweep_session_strings(vm); let mut freed_bytes = self.sweep_session_strings(vm);
freed_bytes += self.sweep_session_bigints(vm); freed_bytes += self.sweep_session_bigints(vm);
freed_bytes += self.sweep_session_cells(vm); freed_bytes += self.sweep_session_cells(vm);
@@ -964,7 +964,7 @@ impl SessionGc {
// 抬高下次触发水位:本次存活字节 + 阈值增量,避免活串超阈值时每指令重复 // 抬高下次触发水位:本次存活字节 + 阈值增量,避免活串超阈值时每指令重复
// 触发无死串可回收的完整 mark + 串清扫。 // 触发无死串可回收的完整 mark + 串清扫。
let threshold = vm.kernel_core().config().session_gc_threshold; let threshold = vm.kernel_core().config().session_gc_threshold;
vm.gc_state.string_gc_watermark = vm.gc_state.session_bytes_allocated.saturating_add(threshold); vm.realm.gc.string_gc_watermark = vm.realm.gc.session_bytes_allocated.saturating_add(threshold);
let elapsed = start.elapsed(); let elapsed = start.elapsed();
self.total_collections += 1; self.total_collections += 1;
@@ -1034,18 +1034,18 @@ impl SessionGc {
// 串,串表整体计入,与 strings-only 口径一致;BigInt/cell 不在手工 // 串,串表整体计入,与 strings-only 口径一致;BigInt/cell 不在手工
// 账目内,由 `run_alloc_bytes` 公式按表长单列)。 // 账目内,由 `run_alloc_bytes` 公式按表长单列)。
let mut string_bytes: usize = 0; let mut string_bytes: usize = 0;
for &ptr in &vm.gc_state.session_string_ptrs { for &ptr in &vm.realm.gc.session_string_ptrs {
if ptr.is_null() { if ptr.is_null() {
continue; continue;
} }
// SAFETY: ptr 在字符串表登记,收尾前有效。 // SAFETY: ptr 在字符串表登记,收尾前有效。
string_bytes += size_of::<JsString>() + unsafe { (*ptr).payload_bytes() }; string_bytes += size_of::<JsString>() + unsafe { (*ptr).payload_bytes() };
} }
vm.gc_state.session_bytes_allocated = vm.gc_state.session_bytes_allocated.saturating_add(string_bytes); vm.realm.gc.session_bytes_allocated = vm.realm.gc.session_bytes_allocated.saturating_add(string_bytes);
// 抬高下次触发水位:当前分配包络 + 阈值增量——存活包络超阈值时不每指令 // 抬高下次触发水位:当前分配包络 + 阈值增量——存活包络超阈值时不每指令
// 重复触发无死对象可回收的白跑。 // 重复触发无死对象可回收的白跑。
vm.gc_state.gc_watermark = vm.run_alloc_bytes().saturating_add(vm.gc_state.gc_threshold_cached); vm.realm.gc.gc_watermark = vm.run_alloc_bytes().saturating_add(vm.realm.gc.gc_threshold_cached);
let elapsed = start.elapsed(); let elapsed = start.elapsed();
self.total_collections += 1; self.total_collections += 1;
+127 -127
View File
@@ -14,7 +14,7 @@ use oxide_emit::module::{ModuleKind, ModuleSourceLoader, ResolvedModule};
use oxide_runtime_api::NativeResult; use oxide_runtime_api::NativeResult;
fn plain_object(vm: &mut Vm) -> *mut JsObject { fn plain_object(vm: &mut Vm) -> *mut JsObject {
let proto_ptr = vm.session.builtin_world().object_proto.as_ptr() as *mut JsObject; let proto_ptr = vm.realm.session.builtin_world().object_proto.as_ptr() as *mut JsObject;
vm.alloc_object(JsObject::new_empty( vm.alloc_object(JsObject::new_empty(
oxide_kernel::shape_forge::EMPTY_SHAPE_ID, oxide_kernel::shape_forge::EMPTY_SHAPE_ID,
JsValue::from_js_object(proto_ptr), JsValue::from_js_object(proto_ptr),
@@ -127,7 +127,7 @@ fn gc_roots_contains_registers_frames_and_root_roots() {
assert!(has_ptr(&roots, frame_session)); assert!(has_ptr(&roots, frame_session));
assert!(has_ptr(&roots, this_session)); assert!(has_ptr(&roots, this_session));
assert!(has_ptr(&roots, child_session)); assert!(has_ptr(&roots, child_session));
assert!(has_ptr(&roots, vm.session.global_object().as_ptr() as *mut JsObject)); assert!(has_ptr(&roots, vm.realm.session.global_object().as_ptr() as *mut JsObject));
assert!(!roots.is_empty()); assert!(!roots.is_empty());
assert!(roots.contains(&JsValue::from_js_object(root_session))); assert!(roots.contains(&JsValue::from_js_object(root_session)));
assert_eq!(vm.exception_value, Some(JsValue::from_js_object(root_session))); assert_eq!(vm.exception_value, Some(JsValue::from_js_object(root_session)));
@@ -149,9 +149,9 @@ fn mark_phase_reaches_cycles_and_unreachable_are_unmarked() {
let unreachable_session = unreachable; let unreachable_session = unreachable;
vm.regs[0] = JsValue::from_js_object(root_session); vm.regs[0] = JsValue::from_js_object(root_session);
let mut gc = std::mem::take(&mut vm.gc_state.session_gc); let mut gc = std::mem::take(&mut vm.realm.gc.session_gc);
gc.mark(&vm); gc.mark(&vm);
vm.gc_state.session_gc = gc; vm.realm.gc.session_gc = gc;
assert!(unsafe { (*root_session).is_gc_marked() }); assert!(unsafe { (*root_session).is_gc_marked() });
assert!(unsafe { (*reachable_session).is_gc_marked() }); assert!(unsafe { (*reachable_session).is_gc_marked() });
@@ -173,17 +173,17 @@ fn sweep_preserves_cycle_and_collects_unreachable() {
let root_session = root; let root_session = root;
vm.regs[0] = JsValue::from_js_object(root_session); vm.regs[0] = JsValue::from_js_object(root_session);
let dead_session = dead; let dead_session = dead;
let mut gc = std::mem::take(&mut vm.gc_state.session_gc); let mut gc = std::mem::take(&mut vm.realm.gc.session_gc);
gc.mark(&vm); gc.mark(&vm);
let _ = gc.sweep(&mut vm); let _ = gc.sweep(&mut vm);
vm.gc_state.session_gc = gc; vm.realm.gc.session_gc = gc;
assert_eq!(vm.gc_state.session_object_ptrs.len(), 2); assert_eq!(vm.realm.gc.session_object_ptrs.len(), 2);
// 原地 sweep 不搬移存活对象:根与子保持原址(克隆体即原对象),死对象出表。 // 原地 sweep 不搬移存活对象:根与子保持原址(克隆体即原对象),死对象出表。
assert!(vm.gc_state.session_object_ptrs.contains(&root_session)); assert!(vm.realm.gc.session_object_ptrs.contains(&root_session));
assert!(!vm.gc_state.session_object_ptrs.contains(&dead_session)); assert!(!vm.realm.gc.session_object_ptrs.contains(&dead_session));
assert!(!vm assert!(!vm
.gc_state .realm.gc
.session_object_ptrs .session_object_ptrs
.iter() .iter()
.any(|ptr| unsafe { (*(*ptr)).is_gc_marked() })); .any(|ptr| unsafe { (*(*ptr)).is_gc_marked() }));
@@ -192,7 +192,7 @@ fn sweep_preserves_cycle_and_collects_unreachable() {
#[test] #[test]
fn sweep_preserves_array_elements_and_collects_dead_element_object() { fn sweep_preserves_array_elements_and_collects_dead_element_object() {
let mut vm = Vm::new(); let mut vm = Vm::new();
let array_proto = vm.session.builtin_world().array_proto.as_ptr() as *mut JsObject; let array_proto = vm.realm.session.builtin_world().array_proto.as_ptr() as *mut JsObject;
let arr = vm.alloc_object(JsObject::new_array( let arr = vm.alloc_object(JsObject::new_array(
oxide_kernel::shape_forge::EMPTY_SHAPE_ID, oxide_kernel::shape_forge::EMPTY_SHAPE_ID,
JsValue::from_js_object(array_proto), JsValue::from_js_object(array_proto),
@@ -212,10 +212,10 @@ fn sweep_preserves_array_elements_and_collects_dead_element_object() {
} }
vm.regs[0] = JsValue::from_js_object(arr_session); vm.regs[0] = JsValue::from_js_object(arr_session);
let mut gc = std::mem::take(&mut vm.gc_state.session_gc); let mut gc = std::mem::take(&mut vm.realm.gc.session_gc);
gc.mark(&vm); gc.mark(&vm);
let _ = gc.sweep(&mut vm); let _ = gc.sweep(&mut vm);
vm.gc_state.session_gc = gc; vm.realm.gc.session_gc = gc;
// 原地 sweep 不搬移存活对象:数组保持原址、根指针不变,死元素对象 // 原地 sweep 不搬移存活对象:数组保持原址、根指针不变,死元素对象
// 原地释放并出表,存活集合只剩数组与元素 0 的对象。 // 原地释放并出表,存活集合只剩数组与元素 0 的对象。
@@ -227,7 +227,7 @@ fn sweep_preserves_array_elements_and_collects_dead_element_object() {
assert_eq!(unsafe { (*arr_addr).get_prop_at(0).as_js_object_ptr() }, live_session); assert_eq!(unsafe { (*arr_addr).get_prop_at(0).as_js_object_ptr() }, live_session);
// 元素 1 引用已断开:死元素对象被回收。 // 元素 1 引用已断开:死元素对象被回收。
assert_eq!(unsafe { (*arr_addr).get_prop_at(1) }, JsValue::undefined()); assert_eq!(unsafe { (*arr_addr).get_prop_at(1) }, JsValue::undefined());
assert_eq!(vm.gc_state.session_object_ptrs.len(), 2); assert_eq!(vm.realm.gc.session_object_ptrs.len(), 2);
} }
fn vm_with_low_threshold() -> Vm { fn vm_with_low_threshold() -> Vm {
@@ -247,7 +247,7 @@ fn native_ok(result: NativeResult) -> JsValue {
/// 分配一个原型指向 Map.prototype 的占位对象并写入寄存器,作为构造器调用的 `this`。 /// 分配一个原型指向 Map.prototype 的占位对象并写入寄存器,作为构造器调用的 `this`。
fn map_this(vm: &mut Vm, reg: u8) -> JsValue { fn map_this(vm: &mut Vm, reg: u8) -> JsValue {
let proto = vm.session.builtin_world().map_proto.as_ptr() as *mut JsObject; let proto = vm.realm.session.builtin_world().map_proto.as_ptr() as *mut JsObject;
let obj = vm.alloc_object(JsObject::new_empty( let obj = vm.alloc_object(JsObject::new_empty(
oxide_kernel::shape_forge::EMPTY_SHAPE_ID, oxide_kernel::shape_forge::EMPTY_SHAPE_ID,
JsValue::from_js_object(proto), JsValue::from_js_object(proto),
@@ -259,7 +259,7 @@ fn map_this(vm: &mut Vm, reg: u8) -> JsValue {
/// 分配一个原型指向 DataView.prototype 的占位对象并写入寄存器,作为构造器调用的 `this`。 /// 分配一个原型指向 DataView.prototype 的占位对象并写入寄存器,作为构造器调用的 `this`。
fn data_view_this(vm: &mut Vm, reg: u8) -> JsValue { fn data_view_this(vm: &mut Vm, reg: u8) -> JsValue {
let proto = vm.session.builtin_world().data_view_proto.as_ptr() as *mut JsObject; let proto = vm.realm.session.builtin_world().data_view_proto.as_ptr() as *mut JsObject;
let obj = vm.alloc_object(JsObject::new_empty( let obj = vm.alloc_object(JsObject::new_empty(
oxide_kernel::shape_forge::EMPTY_SHAPE_ID, oxide_kernel::shape_forge::EMPTY_SHAPE_ID,
JsValue::from_js_object(proto), JsValue::from_js_object(proto),
@@ -271,7 +271,7 @@ fn data_view_this(vm: &mut Vm, reg: u8) -> JsValue {
/// 分配一个原型指向 Set.prototype 的占位对象并写入寄存器,作为构造器调用的 `this`。 /// 分配一个原型指向 Set.prototype 的占位对象并写入寄存器,作为构造器调用的 `this`。
fn set_this(vm: &mut Vm, reg: u8) -> JsValue { fn set_this(vm: &mut Vm, reg: u8) -> JsValue {
let proto = vm.session.builtin_world().set_proto.as_ptr() as *mut JsObject; let proto = vm.realm.session.builtin_world().set_proto.as_ptr() as *mut JsObject;
let obj = vm.alloc_object(JsObject::new_empty( let obj = vm.alloc_object(JsObject::new_empty(
oxide_kernel::shape_forge::EMPTY_SHAPE_ID, oxide_kernel::shape_forge::EMPTY_SHAPE_ID,
JsValue::from_js_object(proto), JsValue::from_js_object(proto),
@@ -284,7 +284,7 @@ fn set_this(vm: &mut Vm, reg: u8) -> JsValue {
/// 分配一个原型指向 DisposableStack.prototype 的占位对象并写入寄存器, /// 分配一个原型指向 DisposableStack.prototype 的占位对象并写入寄存器,
/// 作为构造器调用的 `this`。 /// 作为构造器调用的 `this`。
fn dispose_stack_this(vm: &mut Vm, reg: u8) -> JsValue { fn dispose_stack_this(vm: &mut Vm, reg: u8) -> JsValue {
let proto = vm.session.builtin_world().disposable_stack_proto.as_ptr() as *mut JsObject; let proto = vm.realm.session.builtin_world().disposable_stack_proto.as_ptr() as *mut JsObject;
let obj = vm.alloc_object(JsObject::new_empty( let obj = vm.alloc_object(JsObject::new_empty(
oxide_kernel::shape_forge::EMPTY_SHAPE_ID, oxide_kernel::shape_forge::EMPTY_SHAPE_ID,
JsValue::from_js_object(proto), JsValue::from_js_object(proto),
@@ -297,7 +297,7 @@ fn dispose_stack_this(vm: &mut Vm, reg: u8) -> JsValue {
/// 置函数位标志的占位对象(通过 `is_callable` 判定),供 adopt 的 /// 置函数位标志的占位对象(通过 `is_callable` 判定),供 adopt 的
/// onDispose 槽使用;测试不调用它。 /// onDispose 槽使用;测试不调用它。
fn function_placeholder(vm: &mut Vm) -> JsValue { fn function_placeholder(vm: &mut Vm) -> JsValue {
let proto = vm.session.builtin_world().object_proto.as_ptr() as *mut JsObject; let proto = vm.realm.session.builtin_world().object_proto.as_ptr() as *mut JsObject;
let obj = vm.alloc_object(JsObject::new_empty( let obj = vm.alloc_object(JsObject::new_empty(
oxide_kernel::shape_forge::EMPTY_SHAPE_ID, oxide_kernel::shape_forge::EMPTY_SHAPE_ID,
JsValue::from_js_object(proto), JsValue::from_js_object(proto),
@@ -312,16 +312,16 @@ fn function_placeholder(vm: &mut Vm) -> JsValue {
fn reset_maybe_collect_collects_after_threshold() { fn reset_maybe_collect_collects_after_threshold() {
let mut vm = vm_with_low_threshold(); let mut vm = vm_with_low_threshold();
plain_object(&mut vm); plain_object(&mut vm);
assert!(!vm.gc_state.session_object_ptrs.is_empty()); assert!(!vm.realm.gc.session_object_ptrs.is_empty());
let tracked_before = vm.gc_state.session_object_ptrs.len(); let tracked_before = vm.realm.gc.session_object_ptrs.len();
vm.regs[0] = JsValue::undefined(); vm.regs[0] = JsValue::undefined();
vm.regs[1] = JsValue::undefined(); vm.regs[1] = JsValue::undefined();
vm.reset(); vm.reset();
assert!(vm.gc_state.session_object_ptrs.len() <= tracked_before); assert!(vm.realm.gc.session_object_ptrs.len() <= tracked_before);
assert_eq!(vm.gc_state.session_object_ptrs.len(), 0); assert_eq!(vm.realm.gc.session_object_ptrs.len(), 0);
assert_eq!(vm.gc_state.session_bytes_allocated, 0); assert_eq!(vm.realm.gc.session_bytes_allocated, 0);
} }
#[test] #[test]
@@ -330,7 +330,7 @@ fn gc_stats_summary_includes_collection() {
plain_object(&mut vm); plain_object(&mut vm);
vm.regs[0] = JsValue::undefined(); vm.regs[0] = JsValue::undefined();
vm.maybe_collect_session_gc(); vm.maybe_collect_session_gc();
let summary = vm.gc_state.session_gc.stats_summary(); let summary = vm.realm.gc.session_gc.stats_summary();
assert!(summary.contains("[GC] collection")); assert!(summary.contains("[GC] collection"));
} }
@@ -343,7 +343,7 @@ fn full_collect_keeps_global_root_edges_in_place() {
} }
let old_ptr = obj; let old_ptr = obj;
let key = vm.kernel_core.perm_interner().intern("gcRoot").0; let key = vm.kernel_core.perm_interner().intern("gcRoot").0;
let global_ptr = vm.session.global_object().as_ptr() as *mut JsObject; let global_ptr = vm.realm.session.global_object().as_ptr() as *mut JsObject;
unsafe { unsafe {
let global = &mut *global_ptr; let global = &mut *global_ptr;
vm.set_or_create_prop_value(global, key, JsValue::from_js_object(old_ptr)); vm.set_or_create_prop_value(global, key, JsValue::from_js_object(old_ptr));
@@ -351,7 +351,7 @@ fn full_collect_keeps_global_root_edges_in_place() {
vm.maybe_collect_session_gc(); vm.maybe_collect_session_gc();
let global = vm.session.global_object(); let global = vm.realm.session.global_object();
let pos = vm let pos = vm
.kernel_core .kernel_core
.shape_forge() .shape_forge()
@@ -401,15 +401,15 @@ fn session_gc_traces_map_object_key_and_value() {
let map_session = map_value.as_js_object_ptr(); let map_session = map_value.as_js_object_ptr();
vm.regs.fill(JsValue::undefined()); vm.regs.fill(JsValue::undefined());
vm.regs[0] = JsValue::from_js_object(map_session); vm.regs[0] = JsValue::from_js_object(map_session);
let mut gc = std::mem::take(&mut vm.gc_state.session_gc); let mut gc = std::mem::take(&mut vm.realm.gc.session_gc);
gc.collect(&mut vm); gc.collect(&mut vm);
vm.gc_state.session_gc = gc; vm.realm.gc.session_gc = gc;
let live_map = unsafe { &*vm.regs[0].as_js_object_ptr() }; let live_map = unsafe { &*vm.regs[0].as_js_object_ptr() };
let edges = map::map_native_edges(live_map); let edges = map::map_native_edges(live_map);
assert_eq!(edges.len(), 2); assert_eq!(edges.len(), 2);
assert!(edges.iter().all(|value| vm.is_session_ptr(value.as_js_object_ptr()))); assert!(edges.iter().all(|value| vm.is_session_ptr(value.as_js_object_ptr())));
assert_eq!(vm.gc_state.session_object_ptrs.len(), 3); assert_eq!(vm.realm.gc.session_object_ptrs.len(), 3);
} }
#[test] #[test]
@@ -425,15 +425,15 @@ fn session_gc_traces_set_object_key() {
let set_session = set_value.as_js_object_ptr(); let set_session = set_value.as_js_object_ptr();
vm.regs.fill(JsValue::undefined()); vm.regs.fill(JsValue::undefined());
vm.regs[0] = JsValue::from_js_object(set_session); vm.regs[0] = JsValue::from_js_object(set_session);
let mut gc = std::mem::take(&mut vm.gc_state.session_gc); let mut gc = std::mem::take(&mut vm.realm.gc.session_gc);
gc.collect(&mut vm); gc.collect(&mut vm);
vm.gc_state.session_gc = gc; vm.realm.gc.session_gc = gc;
let live_set = unsafe { &*vm.regs[0].as_js_object_ptr() }; let live_set = unsafe { &*vm.regs[0].as_js_object_ptr() };
let edges = set::set_native_edges(live_set); let edges = set::set_native_edges(live_set);
assert_eq!(edges.len(), 1); assert_eq!(edges.len(), 1);
assert!(vm.is_session_ptr(edges[0].as_js_object_ptr())); assert!(vm.is_session_ptr(edges[0].as_js_object_ptr()));
assert_eq!(vm.gc_state.session_object_ptrs.len(), 2); assert_eq!(vm.realm.gc.session_object_ptrs.len(), 2);
} }
/// 造带条目盒的 WeakMap 形 session 对象(构造体落地前的单测代用形态)。 /// 造带条目盒的 WeakMap 形 session 对象(构造体落地前的单测代用形态)。
@@ -470,9 +470,9 @@ fn weak_map_entry_survives_promotion_with_live_key() {
let value_root = let value_root =
oxide_builtins::weak_map::weak_map_probe_get(unsafe { &*wm_session }, JsValue::from_js_object(key)); oxide_builtins::weak_map::weak_map_probe_get(unsafe { &*wm_session }, JsValue::from_js_object(key));
vm.regs[2] = value_root; vm.regs[2] = value_root;
let mut gc = std::mem::take(&mut vm.gc_state.session_gc); let mut gc = std::mem::take(&mut vm.realm.gc.session_gc);
gc.collect(&mut vm); gc.collect(&mut vm);
vm.gc_state.session_gc = gc; vm.realm.gc.session_gc = gc;
let live_wm = unsafe { &*vm.regs[0].as_js_object_ptr() }; let live_wm = unsafe { &*vm.regs[0].as_js_object_ptr() };
assert_eq!(oxide_builtins::weak_map::weak_map_entry_count(live_wm), 1, "强可达键的条目须在收集后存活"); assert_eq!(oxide_builtins::weak_map::weak_map_entry_count(live_wm), 1, "强可达键的条目须在收集后存活");
@@ -503,9 +503,9 @@ fn weak_map_entry_dropped_when_key_unrooted() {
vm.regs.fill(JsValue::undefined()); vm.regs.fill(JsValue::undefined());
vm.regs[0] = JsValue::from_js_object(wm_session); vm.regs[0] = JsValue::from_js_object(wm_session);
vm.regs[2] = JsValue::from_js_object(value); vm.regs[2] = JsValue::from_js_object(value);
let mut gc = std::mem::take(&mut vm.gc_state.session_gc); let mut gc = std::mem::take(&mut vm.realm.gc.session_gc);
gc.collect(&mut vm); gc.collect(&mut vm);
vm.gc_state.session_gc = gc; vm.realm.gc.session_gc = gc;
let live_wm = unsafe { &*vm.regs[0].as_js_object_ptr() }; let live_wm = unsafe { &*vm.regs[0].as_js_object_ptr() };
assert_eq!(oxide_builtins::weak_map::weak_map_entry_count(live_wm), 0, "死键条目须在收集时丢弃"); assert_eq!(oxide_builtins::weak_map::weak_map_entry_count(live_wm), 0, "死键条目须在收集时丢弃");
@@ -535,9 +535,9 @@ fn weak_map_value_edge_keeps_value_alive() {
vm.regs.fill(JsValue::undefined()); vm.regs.fill(JsValue::undefined());
vm.regs[0] = JsValue::from_js_object(wm_session); vm.regs[0] = JsValue::from_js_object(wm_session);
vm.regs[1] = JsValue::from_js_object(key); vm.regs[1] = JsValue::from_js_object(key);
let mut gc = std::mem::take(&mut vm.gc_state.session_gc); let mut gc = std::mem::take(&mut vm.realm.gc.session_gc);
gc.collect(&mut vm); gc.collect(&mut vm);
vm.gc_state.session_gc = gc; vm.realm.gc.session_gc = gc;
let live_wm = unsafe { &*vm.regs[0].as_js_object_ptr() }; let live_wm = unsafe { &*vm.regs[0].as_js_object_ptr() };
// 原地 sweep 不搬移对象:键与值边原地保留,按原键读回同一对象。 // 原地 sweep 不搬移对象:键与值边原地保留,按原键读回同一对象。
@@ -547,7 +547,7 @@ fn weak_map_value_edge_keeps_value_alive() {
assert!(vm.is_session_ptr(stored.as_js_object_ptr())); assert!(vm.is_session_ptr(stored.as_js_object_ptr()));
// key、value、wm 三对象均存活(key/value 经寄存器根、wm 经寄存器根), // key、value、wm 三对象均存活(key/value 经寄存器根、wm 经寄存器根),
// 原地保留原址。 // 原地保留原址。
assert_eq!(vm.gc_state.session_object_ptrs.len(), 3); assert_eq!(vm.realm.gc.session_object_ptrs.len(), 3);
} }
/// in-run 原地 sweep·死键面:无强根的 session 键在原地 sweep 按 mark 位判死, /// in-run 原地 sweep·死键面:无强根的 session 键在原地 sweep 按 mark 位判死,
@@ -560,7 +560,7 @@ fn weak_map_dead_key_freed_by_in_run_sweep() {
// 键无强根:仅表内弱边引用。 // 键无强根:仅表内弱边引用。
let key = plain_object(&mut vm); let key = plain_object(&mut vm);
// P 键(builtin 原型,不可死):对照条目须保留。 // P 键(builtin 原型,不可死):对照条目须保留。
let p_key = JsValue::from_js_object(vm.session.builtin_world().object_proto.as_ptr() as *mut JsObject); let p_key = JsValue::from_js_object(vm.realm.session.builtin_world().object_proto.as_ptr() as *mut JsObject);
unsafe { unsafe {
oxide_builtins::weak_map::weak_map_insert( oxide_builtins::weak_map::weak_map_insert(
&mut *wm, &mut *wm,
@@ -574,7 +574,7 @@ fn weak_map_dead_key_freed_by_in_run_sweep() {
vm.maybe_collect_in_run(); vm.maybe_collect_in_run();
assert_eq!(vm.session_gc_stats().total_collections, 1, "in-run 收集应跑一轮"); assert_eq!(vm.session_gc_stats().total_collections, 1, "in-run 收集应跑一轮");
assert!(!vm.gc_state.session_object_ptrs.contains(&key), "死键对象须出表"); assert!(!vm.realm.gc.session_object_ptrs.contains(&key), "死键对象须出表");
let live_wm = unsafe { &*vm.regs[0].as_js_object_ptr() }; let live_wm = unsafe { &*vm.regs[0].as_js_object_ptr() };
assert_eq!( assert_eq!(
oxide_builtins::weak_map::weak_map_entry_count(live_wm), oxide_builtins::weak_map::weak_map_entry_count(live_wm),
@@ -645,8 +645,8 @@ fn session_gc_traces_map_string_and_bigint_value() {
collect(&mut vm); collect(&mut vm);
// 只断言表成员——sweep 已释放的指针解引用即 UB。 // 只断言表成员——sweep 已释放的指针解引用即 UB。
assert!(vm.gc_state.session_string_ptrs.contains(&str_ptr)); assert!(vm.realm.gc.session_string_ptrs.contains(&str_ptr));
assert!(vm.gc_state.session_bigint_ptrs.borrow().contains(&bi_ptr)); assert!(vm.realm.gc.session_bigint_ptrs.borrow().contains(&bi_ptr));
} }
/// 盒持唯一引用的 session 串与 BigInt 经 Set native 边进入存活集: /// 盒持唯一引用的 session 串与 BigInt 经 Set native 边进入存活集:
@@ -672,8 +672,8 @@ fn session_gc_traces_set_string_and_bigint_value() {
collect(&mut vm); collect(&mut vm);
// 只断言表成员——sweep 已释放的指针解引用即 UB。 // 只断言表成员——sweep 已释放的指针解引用即 UB。
assert!(vm.gc_state.session_string_ptrs.contains(&str_ptr)); assert!(vm.realm.gc.session_string_ptrs.contains(&str_ptr));
assert!(vm.gc_state.session_bigint_ptrs.borrow().contains(&bi_ptr)); assert!(vm.realm.gc.session_bigint_ptrs.borrow().contains(&bi_ptr));
} }
/// 盒持唯一引用的 session 串与 BigInt 经资源栈条目边进入存活集: /// 盒持唯一引用的 session 串与 BigInt 经资源栈条目边进入存活集:
@@ -702,8 +702,8 @@ fn session_gc_traces_dispose_stack_string_and_bigint_value() {
collect(&mut vm); collect(&mut vm);
// 只断言表成员——sweep 已释放的指针解引用即 UB。 // 只断言表成员——sweep 已释放的指针解引用即 UB。
assert!(vm.gc_state.session_string_ptrs.contains(&str_ptr)); assert!(vm.realm.gc.session_string_ptrs.contains(&str_ptr));
assert!(vm.gc_state.session_bigint_ptrs.borrow().contains(&bi_ptr)); assert!(vm.realm.gc.session_bigint_ptrs.borrow().contains(&bi_ptr));
} }
/// 挂起帧内期望值 BigInt 查找:挂起点唯一持有期望值(帧内死槽残留的 /// 挂起帧内期望值 BigInt 查找:挂起点唯一持有期望值(帧内死槽残留的
@@ -740,8 +740,8 @@ fn session_gc_traces_promise_string_and_bigint_result() {
collect(&mut vm); collect(&mut vm);
// 只断言表成员——sweep 已释放的指针解引用即 UB。 // 只断言表成员——sweep 已释放的指针解引用即 UB。
assert!(vm.gc_state.session_string_ptrs.contains(&str_ptr)); assert!(vm.realm.gc.session_string_ptrs.contains(&str_ptr));
assert!(vm.gc_state.session_bigint_ptrs.borrow().contains(&bi_ptr)); assert!(vm.realm.gc.session_bigint_ptrs.borrow().contains(&bi_ptr));
} }
/// 挂起生成器帧寄存器持唯一引用 session BigInt:yield 挂起时 b 存活 /// 挂起生成器帧寄存器持唯一引用 session BigInt:yield 挂起时 b 存活
@@ -771,7 +771,7 @@ fn session_gc_traces_suspended_generator_bigint_value() {
collect(&mut vm); collect(&mut vm);
// 只断言表成员——sweep 已释放的指针解引用即 UB。 // 只断言表成员——sweep 已释放的指针解引用即 UB。
assert!(vm.gc_state.session_bigint_ptrs.borrow().contains(&bi_ptr)); assert!(vm.realm.gc.session_bigint_ptrs.borrow().contains(&bi_ptr));
} }
/// 挂起异步函数帧持唯一引用 session BigInt:body await 永不结算的 promise, /// 挂起异步函数帧持唯一引用 session BigInt:body await 永不结算的 promise,
@@ -815,7 +815,7 @@ fn session_gc_traces_suspended_async_function_bigint_value() {
collect(&mut vm); collect(&mut vm);
// 只断言表成员——sweep 已释放的指针解引用即 UB。 // 只断言表成员——sweep 已释放的指针解引用即 UB。
assert!(vm.gc_state.session_bigint_ptrs.borrow().contains(&bi_ptr)); assert!(vm.realm.gc.session_bigint_ptrs.borrow().contains(&bi_ptr));
} }
/// 挂起异步生成器帧持唯一引用 session BigInt:首次 next() 挂起于 yield, /// 挂起异步生成器帧持唯一引用 session BigInt:首次 next() 挂起于 yield,
@@ -844,7 +844,7 @@ fn session_gc_traces_suspended_async_generator_bigint_value() {
collect(&mut vm); collect(&mut vm);
// 只断言表成员——sweep 已释放的指针解引用即 UB。 // 只断言表成员——sweep 已释放的指针解引用即 UB。
assert!(vm.gc_state.session_bigint_ptrs.borrow().contains(&bi_ptr)); assert!(vm.realm.gc.session_bigint_ptrs.borrow().contains(&bi_ptr));
} }
#[test] #[test]
@@ -883,9 +883,9 @@ fn session_gc_keeps_shared_array_buffer_alive_through_view_native_edges() {
let root_session = root; let root_session = root;
vm.regs.fill(JsValue::undefined()); vm.regs.fill(JsValue::undefined());
vm.regs[0] = JsValue::from_js_object(root_session); vm.regs[0] = JsValue::from_js_object(root_session);
let mut gc = std::mem::take(&mut vm.gc_state.session_gc); let mut gc = std::mem::take(&mut vm.realm.gc.session_gc);
gc.collect(&mut vm); gc.collect(&mut vm);
vm.gc_state.session_gc = gc; vm.realm.gc.session_gc = gc;
let live_root = unsafe { &*vm.regs[0].as_js_object_ptr() }; let live_root = unsafe { &*vm.regs[0].as_js_object_ptr() };
let live_typed = live_root.get_prop_at(0); let live_typed = live_root.get_prop_at(0);
@@ -936,16 +936,16 @@ fn session_gc_rewrites_buffer_retained_only_by_data_view_native_edge() {
let view_session = view.as_js_object_ptr(); let view_session = view.as_js_object_ptr();
vm.regs.fill(JsValue::undefined()); vm.regs.fill(JsValue::undefined());
vm.regs[0] = JsValue::from_js_object(view_session); vm.regs[0] = JsValue::from_js_object(view_session);
let mut gc = std::mem::take(&mut vm.gc_state.session_gc); let mut gc = std::mem::take(&mut vm.realm.gc.session_gc);
gc.collect(&mut vm); gc.collect(&mut vm);
vm.gc_state.session_gc = gc; vm.realm.gc.session_gc = gc;
let live_view = vm.regs[0]; let live_view = vm.regs[0];
let live_view_obj = unsafe { &*live_view.as_js_object_ptr() }; let live_view_obj = unsafe { &*live_view.as_js_object_ptr() };
let edges = data_view::data_view_native_edges(live_view_obj); let edges = data_view::data_view_native_edges(live_view_obj);
assert_eq!(edges.len(), 1); assert_eq!(edges.len(), 1);
assert!(vm.is_session_ptr(edges[0].as_js_object_ptr())); assert!(vm.is_session_ptr(edges[0].as_js_object_ptr()));
assert_eq!(vm.gc_state.session_object_ptrs.len(), 2); assert_eq!(vm.realm.gc.session_object_ptrs.len(), 2);
vm.regs[0] = live_view; vm.regs[0] = live_view;
vm.regs[1] = JsValue::int(0); vm.regs[1] = JsValue::int(0);
@@ -953,9 +953,9 @@ fn session_gc_rewrites_buffer_retained_only_by_data_view_native_edge() {
} }
fn collect(vm: &mut Vm) { fn collect(vm: &mut Vm) {
let mut gc = std::mem::take(&mut vm.gc_state.session_gc); let mut gc = std::mem::take(&mut vm.realm.gc.session_gc);
gc.collect(vm); gc.collect(vm);
vm.gc_state.session_gc = gc; vm.realm.gc.session_gc = gc;
} }
#[test] #[test]
@@ -963,12 +963,12 @@ fn session_string_collected_when_dead() {
let mut vm = Vm::new(); let mut vm = Vm::new();
let dead = vm.new_string("dead-string"); let dead = vm.new_string("dead-string");
let dead_ptr = dead.as_string_ptr_mut(); let dead_ptr = dead.as_string_ptr_mut();
assert!(vm.gc_state.session_string_ptrs.contains(&dead_ptr)); assert!(vm.realm.gc.session_string_ptrs.contains(&dead_ptr));
// 没有根引用 `dead`(它只作为值包装存在于 Rust 栈上)。 // 没有根引用 `dead`(它只作为值包装存在于 Rust 栈上)。
collect(&mut vm); collect(&mut vm);
assert!(!vm.gc_state.session_string_ptrs.contains(&dead_ptr)); assert!(!vm.realm.gc.session_string_ptrs.contains(&dead_ptr));
} }
#[test] #[test]
@@ -980,7 +980,7 @@ fn session_string_survives_when_in_register() {
collect(&mut vm); collect(&mut vm);
assert!(vm.gc_state.session_string_ptrs.contains(&live_ptr)); assert!(vm.realm.gc.session_string_ptrs.contains(&live_ptr));
// 存活字符串永不搬移——寄存器仍指向同一 box。 // 存活字符串永不搬移——寄存器仍指向同一 box。
assert_eq!(vm.regs[0].as_string_ptr_mut(), live_ptr); assert_eq!(vm.regs[0].as_string_ptr_mut(), live_ptr);
assert_eq!(unsafe { (*live_ptr).as_str() }, "live-in-reg"); assert_eq!(unsafe { (*live_ptr).as_str() }, "live-in-reg");
@@ -1003,7 +1003,7 @@ fn session_string_survives_via_object_property() {
collect(&mut vm); collect(&mut vm);
assert!(vm.gc_state.session_string_ptrs.contains(&s_ptr)); assert!(vm.realm.gc.session_string_ptrs.contains(&s_ptr));
assert_eq!(unsafe { (*s_ptr).as_str() }, "prop-string"); assert_eq!(unsafe { (*s_ptr).as_str() }, "prop-string");
} }
@@ -1013,13 +1013,13 @@ fn permanent_string_untouched_by_sweep() {
let perm = vm.perm_string("perm"); let perm = vm.perm_string("perm");
let perm_ptr = perm.as_string_ptr_mut(); let perm_ptr = perm.as_string_ptr_mut();
// 永久字符串位于 PermInterner,绝不在 session 集合中。 // 永久字符串位于 PermInterner,绝不在 session 集合中。
assert!(!vm.gc_state.session_string_ptrs.contains(&perm_ptr)); assert!(!vm.realm.gc.session_string_ptrs.contains(&perm_ptr));
vm.regs[0] = perm; vm.regs[0] = perm;
collect(&mut vm); collect(&mut vm);
// 绝不被 session 清扫释放(仍可读,仍不在 session 集合中)。 // 绝不被 session 清扫释放(仍可读,仍不在 session 集合中)。
assert!(!vm.gc_state.session_string_ptrs.contains(&perm_ptr)); assert!(!vm.realm.gc.session_string_ptrs.contains(&perm_ptr));
assert_eq!(unsafe { (*perm_ptr).as_str() }, "perm"); assert_eq!(unsafe { (*perm_ptr).as_str() }, "perm");
} }
@@ -1030,11 +1030,11 @@ fn string_sweep_byte_accounting() {
let _ = dead.as_string_ptr_mut(); let _ = dead.as_string_ptr_mut();
let expected = (size_of::<JsString>() + "0123456789".len()) as u64; let expected = (size_of::<JsString>() + "0123456789".len()) as u64;
let mut gc = std::mem::take(&mut vm.gc_state.session_gc); let mut gc = std::mem::take(&mut vm.realm.gc.session_gc);
let before = gc.total_bytes_freed; let before = gc.total_bytes_freed;
gc.collect(&mut vm); gc.collect(&mut vm);
let after = gc.total_bytes_freed; let after = gc.total_bytes_freed;
vm.gc_state.session_gc = gc; vm.realm.gc.session_gc = gc;
assert!(after >= before + expected); assert!(after >= before + expected);
} }
@@ -1055,7 +1055,7 @@ fn compile(source: &str) -> oxide_bytecode::module::CompiledModule {
} }
fn global_prop_opt(vm: &Vm, name: &str) -> Option<JsValue> { fn global_prop_opt(vm: &Vm, name: &str) -> Option<JsValue> {
let global = vm.session.global_object(); let global = vm.realm.session.global_object();
let si = vm.kernel_core().perm_interner().intern(name).0; let si = vm.kernel_core().perm_interner().intern(name).0;
vm.resolve_property(global, si) vm.resolve_property(global, si)
} }
@@ -1071,7 +1071,7 @@ fn closure_cell_survives_object_sweep() {
"function outer() { var counter = 0; function inc() { return ++counter; } globalThis.inc = inc; return 0; } outer(); 0", "function outer() { var counter = 0; function inc() { return ++counter; } globalThis.inc = inc; return 0; } outer(); 0",
))) )))
.expect("run1"); .expect("run1");
assert!(!vm.gc_state.session_cell_ptrs.borrow().is_empty(), "run1 应分配 upvalue cell"); assert!(!vm.realm.gc.session_cell_ptrs.borrow().is_empty(), "run1 应分配 upvalue cell");
// reset 触发对象 sweep:存活对象原地保留,死对象原地释放。 // reset 触发对象 sweep:存活对象原地保留,死对象原地释放。
vm.reset(); vm.reset();
@@ -1126,10 +1126,10 @@ fn cells_freed_by_full_reset_and_reallocatable() {
"function outer() { var x = 1; function f() { return x; } globalThis.f = f; return f(); } outer()", "function outer() { var x = 1; function f() { return x; } globalThis.f = f; return f(); } outer()",
))) )))
.expect("run1"); .expect("run1");
assert!(!vm.gc_state.session_cell_ptrs.borrow().is_empty()); assert!(!vm.realm.gc.session_cell_ptrs.borrow().is_empty());
vm.full_reset(); vm.full_reset();
assert!(vm.gc_state.session_cell_ptrs.borrow().is_empty(), "full_reset 应释放全部 cell"); assert!(vm.realm.gc.session_cell_ptrs.borrow().is_empty(), "full_reset 应释放全部 cell");
let result = vm let result = vm
.run(&Arc::new(compile( .run(&Arc::new(compile(
@@ -1186,13 +1186,13 @@ fn live_closure_cell_survives_full_collect() {
let cells = obj.upvalues_slice(); let cells = obj.upvalues_slice();
assert_eq!(cells.len(), 1, "inc 应捕获 counter 一个 cell"); assert_eq!(cells.len(), 1, "inc 应捕获 counter 一个 cell");
let cell_ptr = cells[0]; let cell_ptr = cells[0];
assert!(vm.gc_state.session_cell_ptrs.borrow().contains(&cell_ptr), "活 cell 应登记在表"); assert!(vm.realm.gc.session_cell_ptrs.borrow().contains(&cell_ptr), "活 cell 应登记在表");
vm.regs.fill(JsValue::undefined()); vm.regs.fill(JsValue::undefined());
collect(&mut vm); collect(&mut vm);
// 只断言表成员——sweep 已释放的指针解引用即 UB。 // 只断言表成员——sweep 已释放的指针解引用即 UB。
assert!(vm.gc_state.session_cell_ptrs.borrow().contains(&cell_ptr), "活 cell 应跨完整收集存活"); assert!(vm.realm.gc.session_cell_ptrs.borrow().contains(&cell_ptr), "活 cell 应跨完整收集存活");
} }
/// 活跃帧 cell_stack 根:内层函数 upvalue cell 在活跃帧 cell_stack 上(低阈值使 /// 活跃帧 cell_stack 根:内层函数 upvalue cell 在活跃帧 cell_stack 上(低阈值使
@@ -1245,14 +1245,14 @@ fn suspended_state_box_cell_root_survives_collect() {
.copied() .copied()
.find(|p| !p.is_null()) .find(|p| !p.is_null())
.expect("挂起帧应持有 x cell"); .expect("挂起帧应持有 x cell");
assert!(vm.gc_state.session_cell_ptrs.borrow().contains(&cell_ptr), "cell 应登记在表"); assert!(vm.realm.gc.session_cell_ptrs.borrow().contains(&cell_ptr), "cell 应登记在表");
vm.regs.fill(JsValue::undefined()); vm.regs.fill(JsValue::undefined());
vm.regs[0] = JsValue::from_js_object(g_session); vm.regs[0] = JsValue::from_js_object(g_session);
collect(&mut vm); collect(&mut vm);
// 只断言表成员——sweep 已释放的指针解引用即 UB。 // 只断言表成员——sweep 已释放的指针解引用即 UB。
assert!(vm.gc_state.session_cell_ptrs.borrow().contains(&cell_ptr), "挂起帧 cell 应跨完整收集存活"); assert!(vm.realm.gc.session_cell_ptrs.borrow().contains(&cell_ptr), "挂起帧 cell 应跨完整收集存活");
// 恢复后读值:cell 未被误释放。 // 恢复后读值:cell 未被误释放。
let read = vm.run(&Arc::new(compile("globalThis.g.next().value"))).expect("read"); let read = vm.run(&Arc::new(compile("globalThis.g.next().value"))).expect("read");
@@ -1312,7 +1312,7 @@ fn module_ns_cell_root_survives_collect() {
.into_iter() .into_iter()
.next() .next()
.expect("依赖 ns 应持有 x 的 cell"); .expect("依赖 ns 应持有 x 的 cell");
assert!(vm.gc_state.session_cell_ptrs.borrow().contains(&cell_ptr), "cell 应登记在表"); assert!(vm.realm.gc.session_cell_ptrs.borrow().contains(&cell_ptr), "cell 应登记在表");
vm.regs.fill(JsValue::undefined()); vm.regs.fill(JsValue::undefined());
vm.regs[0] = ns_val; vm.regs[0] = ns_val;
@@ -1320,7 +1320,7 @@ fn module_ns_cell_root_survives_collect() {
// 只断言表成员——sweep 已释放的指针解引用即 UB。 // 只断言表成员——sweep 已释放的指针解引用即 UB。
assert!( assert!(
vm.gc_state.session_cell_ptrs.borrow().contains(&cell_ptr), vm.realm.gc.session_cell_ptrs.borrow().contains(&cell_ptr),
"模块 ns cell 应跨完整收集存活" "模块 ns cell 应跨完整收集存活"
); );
@@ -1346,16 +1346,16 @@ fn allocation_does_not_trigger_gc_before_safe_point() {
let seed_ptr = seed.as_string_ptr_mut(); let seed_ptr = seed.as_string_ptr_mut();
let returned = vm.new_string_owned("returned".repeat(16)); let returned = vm.new_string_owned("returned".repeat(16));
assert_eq!(vm.gc_state.session_gc.total_collections, 0); assert_eq!(vm.realm.gc.session_gc.total_collections, 0);
assert!(vm.gc_state.session_string_ptrs.contains(&seed_ptr)); assert!(vm.realm.gc.session_string_ptrs.contains(&seed_ptr));
assert!(vm.gc_state.session_string_ptrs.contains(&returned.as_string_ptr_mut())); assert!(vm.realm.gc.session_string_ptrs.contains(&returned.as_string_ptr_mut()));
// 显式触发后:无根引用的 seed 被回收,入根的 returned 存活(安全点语义)。 // 显式触发后:无根引用的 seed 被回收,入根的 returned 存活(安全点语义)。
vm.regs[0] = returned; vm.regs[0] = returned;
vm.maybe_collect_session_strings(); vm.maybe_collect_session_strings();
assert!(vm.gc_state.session_gc.total_collections >= 1); assert!(vm.realm.gc.session_gc.total_collections >= 1);
assert!(!vm.gc_state.session_string_ptrs.contains(&seed_ptr)); assert!(!vm.realm.gc.session_string_ptrs.contains(&seed_ptr));
assert!(vm.gc_state.session_string_ptrs.contains(&returned.as_string_ptr_mut())); assert!(vm.realm.gc.session_string_ptrs.contains(&returned.as_string_ptr_mut()));
} }
#[test] #[test]
@@ -1388,10 +1388,10 @@ fn strings_only_collection_preserves_all_root_kinds() {
vm.maybe_collect_session_strings(); vm.maybe_collect_session_strings();
assert!(vm.gc_state.session_string_ptrs.contains(&reg_str.as_string_ptr_mut())); assert!(vm.realm.gc.session_string_ptrs.contains(&reg_str.as_string_ptr_mut()));
assert!(vm.gc_state.session_string_ptrs.contains(&prop_str.as_string_ptr_mut())); assert!(vm.realm.gc.session_string_ptrs.contains(&prop_str.as_string_ptr_mut()));
assert!(vm.gc_state.session_string_ptrs.contains(&epoch_str.as_string_ptr_mut())); assert!(vm.realm.gc.session_string_ptrs.contains(&epoch_str.as_string_ptr_mut()));
assert!(!vm.gc_state.session_string_ptrs.contains(&dead_ptr)); assert!(!vm.realm.gc.session_string_ptrs.contains(&dead_ptr));
// 存活串内容可读,地址稳定。 // 存活串内容可读,地址稳定。
assert_eq!(unsafe { (*reg_str.as_string_ptr_mut()).as_str() }, "reg-root".repeat(16)); assert_eq!(unsafe { (*reg_str.as_string_ptr_mut()).as_str() }, "reg-root".repeat(16));
assert_eq!(unsafe { (*prop_str.as_string_ptr_mut()).as_str() }, "prop-root".repeat(16)); assert_eq!(unsafe { (*prop_str.as_string_ptr_mut()).as_str() }, "prop-root".repeat(16));
@@ -1404,7 +1404,7 @@ fn strings_only_collection_does_not_move_objects() {
let obj = plain_object(&mut vm); let obj = plain_object(&mut vm);
let obj_session = obj; let obj_session = obj;
vm.regs[0] = JsValue::from_js_object(obj_session); vm.regs[0] = JsValue::from_js_object(obj_session);
let before: Vec<_> = vm.gc_state.session_object_ptrs.clone(); let before: Vec<_> = vm.realm.gc.session_object_ptrs.clone();
let s = vm.new_string_owned("x".repeat(64)); let s = vm.new_string_owned("x".repeat(64));
vm.regs[1] = s; vm.regs[1] = s;
@@ -1412,7 +1412,7 @@ fn strings_only_collection_does_not_move_objects() {
vm.maybe_collect_session_strings(); vm.maybe_collect_session_strings();
// 对象指针逐一相同:不搬移、不重写根。 // 对象指针逐一相同:不搬移、不重写根。
assert_eq!(vm.gc_state.session_object_ptrs, before); assert_eq!(vm.realm.gc.session_object_ptrs, before);
assert_eq!(vm.regs[0].as_js_object_ptr(), obj_session); assert_eq!(vm.regs[0].as_js_object_ptr(), obj_session);
assert_eq!(vm.session_object_count(), 1); assert_eq!(vm.session_object_count(), 1);
} }
@@ -1435,10 +1435,10 @@ fn multiple_strings_only_cycles_keep_objects_alive() {
} }
// 分配不自动触发,每轮显式触发一次回收。 // 分配不自动触发,每轮显式触发一次回收。
vm.maybe_collect_session_strings(); vm.maybe_collect_session_strings();
assert!(vm.gc_state.session_object_ptrs.contains(&obj_session)); assert!(vm.realm.gc.session_object_ptrs.contains(&obj_session));
assert_eq!(unsafe { (*obj_session).get_prop_at(0) }, live); assert_eq!(unsafe { (*obj_session).get_prop_at(0) }, live);
} }
assert!(vm.gc_state.session_string_ptrs.contains(&live.as_string_ptr_mut())); assert!(vm.realm.gc.session_string_ptrs.contains(&live.as_string_ptr_mut()));
} }
#[test] #[test]
@@ -1458,15 +1458,15 @@ fn strings_only_then_full_collect_keeps_object_strings_live() {
// 第一轮 strings-only:对象被 mark 置位。收尾清残留,否则该位残留至完整 // 第一轮 strings-only:对象被 mark 置位。收尾清残留,否则该位残留至完整
// 收集会使 mark DFS 在对象处短路、漏标其属性中的串;随后校验串跨完整收集存活。 // 收集会使 mark DFS 在对象处短路、漏标其属性中的串;随后校验串跨完整收集存活。
vm.maybe_collect_session_strings(); vm.maybe_collect_session_strings();
assert!(vm.gc_state.session_string_ptrs.contains(&s_ptr)); assert!(vm.realm.gc.session_string_ptrs.contains(&s_ptr));
// 完整收集(reset 的 maybe_collect 路径):对象搬移、字符串地址稳定。 // 完整收集(reset 的 maybe_collect 路径):对象搬移、字符串地址稳定。
let mut gc = std::mem::take(&mut vm.gc_state.session_gc); let mut gc = std::mem::take(&mut vm.realm.gc.session_gc);
gc.collect(&mut vm); gc.collect(&mut vm);
vm.gc_state.session_gc = gc; vm.realm.gc.session_gc = gc;
// 存活对象经重写仍可达其串:串未被误释放,内容可读。 // 存活对象经重写仍可达其串:串未被误释放,内容可读。
assert!(vm.gc_state.session_string_ptrs.contains(&s_ptr)); assert!(vm.realm.gc.session_string_ptrs.contains(&s_ptr));
assert_eq!(unsafe { (*s_ptr).as_str() }, "kept".repeat(8)); assert_eq!(unsafe { (*s_ptr).as_str() }, "kept".repeat(8));
assert_eq!(unsafe { (*vm.regs[0].as_js_object_ptr()).get_prop_at(0) }, s); assert_eq!(unsafe { (*vm.regs[0].as_js_object_ptr()).get_prop_at(0) }, s);
} }
@@ -1487,8 +1487,8 @@ fn strings_only_collection_byte_accounting_matches_survivors() {
// 账目 = 对象头 + 存活串(size_of::<JsString>() + len),死串不再计入。 // 账目 = 对象头 + 存活串(size_of::<JsString>() + len),死串不再计入。
let expected = size_of::<JsObject>() + (size_of::<JsString>() + unsafe { (*live_ptr).payload_bytes() }); let expected = size_of::<JsObject>() + (size_of::<JsString>() + unsafe { (*live_ptr).payload_bytes() });
assert_eq!(vm.gc_state.session_bytes_allocated, expected); assert_eq!(vm.realm.gc.session_bytes_allocated, expected);
assert!(!vm.gc_state.session_string_ptrs.contains(&dead.as_string_ptr_mut())); assert!(!vm.realm.gc.session_string_ptrs.contains(&dead.as_string_ptr_mut()));
} }
#[test] #[test]
@@ -1500,7 +1500,7 @@ fn run_alloc_formula_lists_bigint_and_cell_via_tables() {
// 下不成立,钉向量面互不相交。 // 下不成立,钉向量面互不相交。
let arr = vm.alloc_object(JsObject::new_array( let arr = vm.alloc_object(JsObject::new_array(
oxide_kernel::shape_forge::EMPTY_SHAPE_ID, oxide_kernel::shape_forge::EMPTY_SHAPE_ID,
JsValue::from_js_object(vm.session.builtin_world().array_proto.as_ptr() as *mut JsObject), JsValue::from_js_object(vm.realm.session.builtin_world().array_proto.as_ptr() as *mut JsObject),
2, 2,
)); ));
vm.regs[3] = JsValue::from_js_object(arr); vm.regs[3] = JsValue::from_js_object(arr);
@@ -1509,30 +1509,30 @@ fn run_alloc_formula_lists_bigint_and_cell_via_tables() {
let b = vm.new_bigint(num_bigint::BigInt::from(7_i128)); let b = vm.new_bigint(num_bigint::BigInt::from(7_i128));
vm.regs[2] = b; vm.regs[2] = b;
// 未根 cell:收集后不可达,随 sweep 出表。 // 未根 cell:收集后不可达,随 sweep 出表。
vm.gc_state.alloc_cell(JsValue::int(9), true); vm.realm.gc.alloc_cell(JsValue::int(9), true);
// 公式 = 手工账目 + BigInt 表长 × 尺寸 + cell 表长 × 尺寸,三分量两两不相交。 // 公式 = 手工账目 + BigInt 表长 × 尺寸 + cell 表长 × 尺寸,三分量两两不相交。
assert_eq!( assert_eq!(
vm.run_alloc_bytes(), vm.run_alloc_bytes(),
vm.gc_state.session_bytes_allocated vm.realm.gc.session_bytes_allocated
+ vm.gc_state.session_bigint_ptrs.borrow().len() * size_of::<num_bigint::BigInt>() + vm.realm.gc.session_bigint_ptrs.borrow().len() * size_of::<num_bigint::BigInt>()
+ vm.gc_state.session_cell_ptrs.borrow().len() * size_of::<Cell>() + vm.realm.gc.session_cell_ptrs.borrow().len() * size_of::<Cell>()
); );
// BigInt 不在手工账目内:账目 = 两对象(头 + 堆数据)+ 串,数组带元素向量。 // BigInt 不在手工账目内:账目 = 两对象(头 + 堆数据)+ 串,数组带元素向量。
let string_bytes = size_of::<JsString>() + unsafe { (*s.as_string_ptr_mut()).payload_bytes() }; let string_bytes = size_of::<JsString>() + unsafe { (*s.as_string_ptr_mut()).payload_bytes() };
let arr_heap_bytes = SessionGc::object_heap_data_bytes(unsafe { &*arr }); let arr_heap_bytes = SessionGc::object_heap_data_bytes(unsafe { &*arr });
assert!(arr_heap_bytes > 0, "数组元素向量应计入对象堆数据"); assert!(arr_heap_bytes > 0, "数组元素向量应计入对象堆数据");
assert_eq!( assert_eq!(
vm.gc_state.session_bytes_allocated, vm.realm.gc.session_bytes_allocated,
2 * size_of::<JsObject>() + arr_heap_bytes as usize + string_bytes 2 * size_of::<JsObject>() + arr_heap_bytes as usize + string_bytes
); );
// 完整收集后:死 cell 出表、存活 BigInt 留表,账目保持对象 + 串口径。 // 完整收集后:死 cell 出表、存活 BigInt 留表,账目保持对象 + 串口径。
vm.collect_session_gc(); vm.collect_session_gc();
assert_eq!(vm.gc_state.session_cell_ptrs.borrow().len(), 0); assert_eq!(vm.realm.gc.session_cell_ptrs.borrow().len(), 0);
assert_eq!(vm.gc_state.session_bigint_ptrs.borrow().len(), 1); assert_eq!(vm.realm.gc.session_bigint_ptrs.borrow().len(), 1);
assert_eq!( assert_eq!(
vm.gc_state.session_bytes_allocated, vm.realm.gc.session_bytes_allocated,
2 * size_of::<JsObject>() + arr_heap_bytes as usize + string_bytes 2 * size_of::<JsObject>() + arr_heap_bytes as usize + string_bytes
); );
// 深采样全量重算与轻层公式零增长下逐位相等:存活对象带堆区(元素向量), // 深采样全量重算与轻层公式零增长下逐位相等:存活对象带堆区(元素向量),
@@ -1546,8 +1546,8 @@ fn runtime_collection_below_threshold_is_noop() {
let s = vm.new_string_owned("small".repeat(4)); let s = vm.new_string_owned("small".repeat(4));
vm.regs[0] = s; vm.regs[0] = s;
assert_eq!(vm.gc_state.session_gc.total_collections, 0); assert_eq!(vm.realm.gc.session_gc.total_collections, 0);
assert!(vm.gc_state.session_string_ptrs.contains(&s.as_string_ptr_mut())); assert!(vm.realm.gc.session_string_ptrs.contains(&s.as_string_ptr_mut()));
} }
// ── rope(Cons)GC 传播闭包 ── // ── rope(Cons)GC 传播闭包 ──
@@ -1570,9 +1570,9 @@ fn rope_survives_collection_with_children_propagated() {
// 父(寄存器根)+ 子节点(经传播闭包)全部存活,内容可读。 // 父(寄存器根)+ 子节点(经传播闭包)全部存活,内容可读。
let parent_ptr = parent.as_string_ptr_mut(); let parent_ptr = parent.as_string_ptr_mut();
assert!(vm.gc_state.session_string_ptrs.contains(&parent_ptr)); assert!(vm.realm.gc.session_string_ptrs.contains(&parent_ptr));
assert!(vm.gc_state.session_string_ptrs.contains(&l_ptr)); assert!(vm.realm.gc.session_string_ptrs.contains(&l_ptr));
assert!(vm.gc_state.session_string_ptrs.contains(&r_ptr)); assert!(vm.realm.gc.session_string_ptrs.contains(&r_ptr));
assert_eq!(unsafe { (*parent_ptr).as_lossy_str() }, "left-partright-part"); assert_eq!(unsafe { (*parent_ptr).as_lossy_str() }, "left-partright-part");
} }
@@ -1581,14 +1581,14 @@ fn rope_children_swept_when_parent_dead() {
let mut vm = Vm::new(); let mut vm = Vm::new();
let (parent, l_ptr, r_ptr) = make_cons_pair(&mut vm, "left", "right"); let (parent, l_ptr, r_ptr) = make_cons_pair(&mut vm, "left", "right");
let parent_ptr = parent.as_string_ptr_mut(); let parent_ptr = parent.as_string_ptr_mut();
assert!(vm.gc_state.session_string_ptrs.contains(&parent_ptr)); assert!(vm.realm.gc.session_string_ptrs.contains(&parent_ptr));
// 父与子均无根引用 → 整树回收。 // 父与子均无根引用 → 整树回收。
collect(&mut vm); collect(&mut vm);
assert!(!vm.gc_state.session_string_ptrs.contains(&parent_ptr)); assert!(!vm.realm.gc.session_string_ptrs.contains(&parent_ptr));
assert!(!vm.gc_state.session_string_ptrs.contains(&l_ptr)); assert!(!vm.realm.gc.session_string_ptrs.contains(&l_ptr));
assert!(!vm.gc_state.session_string_ptrs.contains(&r_ptr)); assert!(!vm.realm.gc.session_string_ptrs.contains(&r_ptr));
} }
#[test] #[test]
@@ -1605,8 +1605,8 @@ fn rope_product_freed_with_parent() {
// 父死 → 连带释放产物(不 double-free、不泄漏;产物从不进 session 表)。 // 父死 → 连带释放产物(不 double-free、不泄漏;产物从不进 session 表)。
let flat_mut = flat_ptr as *mut JsString; let flat_mut = flat_ptr as *mut JsString;
assert!(!vm.gc_state.session_string_ptrs.contains(&parent_ptr)); assert!(!vm.realm.gc.session_string_ptrs.contains(&parent_ptr));
assert!(!vm.gc_state.session_string_ptrs.contains(&flat_mut)); assert!(!vm.realm.gc.session_string_ptrs.contains(&flat_mut));
} }
#[test] #[test]
@@ -1623,7 +1623,7 @@ fn rope_deep_chain_mark_iterative() {
collect(&mut vm); collect(&mut vm);
assert!(vm.gc_state.session_string_ptrs.contains(&chain_ptr)); assert!(vm.realm.gc.session_string_ptrs.contains(&chain_ptr));
assert_eq!(unsafe { (*chain_ptr).as_lossy_str() }, format!("root{}", "x".repeat(1024))); assert_eq!(unsafe { (*chain_ptr).as_lossy_str() }, format!("root{}", "x".repeat(1024)));
} }
@@ -1640,8 +1640,8 @@ fn rope_perm_child_untouched_by_sweep() {
collect(&mut vm); collect(&mut vm);
// perm 子节点永不释放(不在 session 表);session 子节点随父存活。 // perm 子节点永不释放(不在 session 表);session 子节点随父存活。
assert!(!vm.gc_state.session_string_ptrs.contains(&perm_ptr)); assert!(!vm.realm.gc.session_string_ptrs.contains(&perm_ptr));
assert!(vm.gc_state.session_string_ptrs.contains(&session_ptr)); assert!(vm.realm.gc.session_string_ptrs.contains(&session_ptr));
assert_eq!(unsafe { (*parent.as_string_ptr_mut()).as_lossy_str() }, "perm-leafsession-leaf"); assert_eq!(unsafe { (*parent.as_string_ptr_mut()).as_lossy_str() }, "perm-leafsession-leaf");
} }
@@ -1655,7 +1655,7 @@ fn full_reset_frees_rope_and_product() {
// full_reset 清空全部 session 字符串(连带产物):无泄漏、无 double-free。 // full_reset 清空全部 session 字符串(连带产物):无泄漏、无 double-free。
vm.full_reset(); vm.full_reset();
assert!(vm.gc_state.session_string_ptrs.is_empty()); assert!(vm.realm.gc.session_string_ptrs.is_empty());
} }
// ── 执行期两档收集 ────────────────────────────────────────────────────── // ── 执行期两档收集 ──────────────────────────────────────────────────────
@@ -1708,7 +1708,7 @@ fn active_and_suspended_for_in_do_not_block_in_run_collection() {
vm.maybe_collect_in_run(); vm.maybe_collect_in_run();
assert_eq!(vm.session_gc_stats().total_collections, 1, "无门控:活跃 for-in 存在时收集照常执行"); assert_eq!(vm.session_gc_stats().total_collections, 1, "无门控:活跃 for-in 存在时收集照常执行");
assert!(!vm.gc_state.session_object_ptrs.contains(&dead), "死 session 对象应被原地释放并出表"); assert!(!vm.realm.gc.session_object_ptrs.contains(&dead), "死 session 对象应被原地释放并出表");
// 挂起形:生成器在 for-in 内 yield 后 run 结束,迭代器经状态盒持有 // 挂起形:生成器在 for-in 内 yield 后 run 结束,迭代器经状态盒持有
// (vm.iters 已空)——键经状态盒边入根收集标活,收集照常执行。 // (vm.iters 已空)——键经状态盒边入根收集标活,收集照常执行。
@@ -1725,7 +1725,7 @@ fn active_and_suspended_for_in_do_not_block_in_run_collection() {
assert_eq!(vm.session_gc_stats().total_collections, 1, "挂起 for-in:收集照常执行"); assert_eq!(vm.session_gc_stats().total_collections, 1, "挂起 for-in:收集照常执行");
// 挂起生成器对象保持原址(未释放):状态盒与迭代器一体存活。 // 挂起生成器对象保持原址(未释放):状态盒与迭代器一体存活。
let gen_in_session = vm let gen_in_session = vm
.gc_state .realm.gc
.session_object_ptrs .session_object_ptrs
.iter() .iter()
.any(|&p| !p.is_null() && unsafe { (*p).type_tag == JsObject::OBJ_TYPE_GENERATOR }); .any(|&p| !p.is_null() && unsafe { (*p).type_tag == JsObject::OBJ_TYPE_GENERATOR });
@@ -1900,11 +1900,11 @@ fn promise_promote_migrates_reject_reactions_to_clone() {
fn mark_counts_roots_by_group() { fn mark_counts_roots_by_group() {
let mut vm = Vm::new(); let mut vm = Vm::new();
vm.regs[0] = JsValue::from_js_object(plain_object(&mut vm)); vm.regs[0] = JsValue::from_js_object(plain_object(&mut vm));
let mut gc = std::mem::take(&mut vm.gc_state.session_gc); let mut gc = std::mem::take(&mut vm.realm.gc.session_gc);
gc.mark(&vm); gc.mark(&vm);
vm.gc_state.session_gc = gc; vm.realm.gc.session_gc = gc;
let counts = &vm.gc_state.session_gc.root_counts; let counts = &vm.realm.gc.session_gc.root_counts;
assert_eq!(counts[RootGroup::Regs as usize], 256, "寄存器组应计满 256 槽"); assert_eq!(counts[RootGroup::Regs as usize], 256, "寄存器组应计满 256 槽");
assert_eq!(counts[RootGroup::Global as usize], 1, "global 组应计 global 对象"); assert_eq!(counts[RootGroup::Global as usize], 1, "global 组应计 global 对象");
// 9 个单槽侧通道:空 VM 时各经 unwrap_or(undefined) 产出一个未定义根值。 // 9 个单槽侧通道:空 VM 时各经 unwrap_or(undefined) 产出一个未定义根值。
+2 -2
View File
@@ -47,7 +47,7 @@ pub fn eval_script(vm: &mut Vm, args: &[u8]) -> NativeResult {
let code = oxide_kernel::string_forge::source_escape(&units); let code = oxide_kernel::string_forge::source_escape(&units);
match vm.create_plain_dynamic_script(&code) { match vm.create_plain_dynamic_script(&code) {
Ok(func) => { Ok(func) => {
let global = JsValue::from_js_object(vm.session().global_object().as_ptr() as *mut JsObject); let global = JsValue::from_js_object(vm.realm.session.global_object().as_ptr() as *mut JsObject);
match vm.call_function_sync(func, global, &[]) { match vm.call_function_sync(func, global, &[]) {
Ok(val) => NativeResult::Ok(val), Ok(val) => NativeResult::Ok(val),
Err(e) => NativeResult::Err(oxide_builtins::error::create_from_text(vm, &e)), Err(e) => NativeResult::Err(oxide_builtins::error::create_from_text(vm, &e)),
@@ -82,7 +82,7 @@ pub fn create_realm(vm: &mut Vm, _args: &[u8]) -> NativeResult {
/// - 置强制收集旗标;下一个顶层指令边界执行 mark + 移动式 sweep + /// - 置强制收集旗标;下一个顶层指令边界执行 mark + 移动式 sweep +
/// 字符串/BigInt 清扫,重写 session 对象指针。 /// 字符串/BigInt 清扫,重写 session 对象指针。
pub fn gc(vm: &mut Vm, _args: &[u8]) -> NativeResult { pub fn gc(vm: &mut Vm, _args: &[u8]) -> NativeResult {
vm.gc_state.pending_forced_collect = true; vm.realm.gc.pending_forced_collect = true;
NativeResult::Ok(JsValue::undefined()) NativeResult::Ok(JsValue::undefined())
} }
+4 -4
View File
@@ -47,9 +47,9 @@ impl Vm {
obj.set_session_epoch(true); obj.set_session_epoch(true);
obj.set_heap_alloc(true); obj.set_heap_alloc(true);
let ptr = Box::into_raw(Box::new(obj)); let ptr = Box::into_raw(Box::new(obj));
self.gc_state.session_object_ptrs.push(ptr); self.realm.gc.session_object_ptrs.push(ptr);
// 直 session 分配计入堆账目(与 promote 同式:对象头 + 对象堆数据)。 // 直 session 分配计入堆账目(与 promote 同式:对象头 + 对象堆数据)。
self.gc_state.session_bytes_allocated += std::mem::size_of::<JsObject>() self.realm.gc.session_bytes_allocated += std::mem::size_of::<JsObject>()
+ crate::session_gc::SessionGc::object_heap_data_bytes(unsafe { &*ptr }) as usize; + crate::session_gc::SessionGc::object_heap_data_bytes(unsafe { &*ptr }) as usize;
ptr ptr
} }
@@ -296,7 +296,7 @@ impl Vm {
self.regs[254] = if sub_is_arrow { self.regs[254] = if sub_is_arrow {
obj.captured_this() obj.captured_this()
} else if !sub_is_strict && this_value.is_nullish() { } else if !sub_is_strict && this_value.is_nullish() {
JsValue::from_js_object(self.session.global_object().as_ptr() as *mut JsObject) JsValue::from_js_object(self.realm.session.global_object().as_ptr() as *mut JsObject)
} else if sub_is_strict { } else if sub_is_strict {
this_value this_value
} else { } else {
@@ -402,7 +402,7 @@ mod tests {
} }
fn native_function(vm: &mut Vm, f: crate::native::NativeFn) -> JsValue { fn native_function(vm: &mut Vm, f: crate::native::NativeFn) -> JsValue {
let proto = vm.session.builtin_world().function_proto.as_ptr() as *mut JsObject; let proto = vm.realm.session.builtin_world().function_proto.as_ptr() as *mut JsObject;
let mut obj = JsObject::new_empty(oxide_kernel::shape_forge::EMPTY_SHAPE_ID, JsValue::from_js_object(proto)); let mut obj = JsObject::new_empty(oxide_kernel::shape_forge::EMPTY_SHAPE_ID, JsValue::from_js_object(proto));
obj.set_function(true); obj.set_function(true);
// SAFETY: f 是 NativeFn 函数项,可作为 NativeFnPtr 存储。 // SAFETY: f 是 NativeFn 函数项,可作为 NativeFnPtr 存储。
+9 -9
View File
@@ -128,29 +128,29 @@ impl Vm {
// 宿主 `$262.gc()` 置位的强制收集与压力模式收集在此边界消费: // 宿主 `$262.gc()` 置位的强制收集与压力模式收集在此边界消费:
// 完整收集唯一安全点(无在途 dispatch 局部值),与正常触发路径 // 完整收集唯一安全点(无在途 dispatch 局部值),与正常触发路径
// 同一入口。压力模式开启后每个顶层边界做一次完整收集。 // 同一入口。压力模式开启后每个顶层边界做一次完整收集。
if self.gc_state.pending_forced_collect || self.gc_state.gc_pressure_mode { if self.realm.gc.pending_forced_collect || self.realm.gc.gc_pressure_mode {
self.gc_state.pending_forced_collect = false; self.realm.gc.pending_forced_collect = false;
self.collect_session_gc(); self.collect_session_gc();
} }
// 峰值高水位:同一边界采样 session 堆账目上界 // 峰值高水位:同一边界采样 session 堆账目上界
let bytes = self.gc_state.session_bytes_allocated; let bytes = self.realm.gc.session_bytes_allocated;
if bytes > self.gc_state.session_bytes_peak { if bytes > self.realm.gc.session_bytes_peak {
self.gc_state.session_bytes_peak = bytes; self.realm.gc.session_bytes_peak = bytes;
} }
// 单 run 分配包络高水位:O(1) 读(手工账目 + BigInt/cell 表长)。 // 单 run 分配包络高水位:O(1) 读(手工账目 + BigInt/cell 表长)。
let alloc = self.run_alloc_bytes(); let alloc = self.run_alloc_bytes();
if alloc > self.gc_state.run_alloc_peak { if alloc > self.realm.gc.run_alloc_peak {
self.gc_state.run_alloc_peak = alloc; self.realm.gc.run_alloc_peak = alloc;
} }
// 压力模式开启时跳过两档水位收集:完整收集已涵盖其全部工作, // 压力模式开启时跳过两档水位收集:完整收集已涵盖其全部工作,
// 同边界双触发只会多一轮空转 mark。 // 同边界双触发只会多一轮空转 mark。
if bytes >= self.gc_state.string_gc_watermark && !self.gc_state.gc_pressure_mode { if bytes >= self.realm.gc.string_gc_watermark && !self.realm.gc.gc_pressure_mode {
self.maybe_collect_session_strings(); self.maybe_collect_session_strings();
} }
// 执行期原地 sweep 收集:O(1) 包络超触发水位 → 收集(无门控: // 执行期原地 sweep 收集:O(1) 包络超触发水位 → 收集(无门控:
// 迭代器键引用经根收集标活,原地释放不搬移存活对象; // 迭代器键引用经根收集标活,原地释放不搬移存活对象;
// 边界契约见 maybe_collect_in_run)。 // 边界契约见 maybe_collect_in_run)。
if alloc >= self.gc_state.gc_watermark && !self.gc_state.gc_pressure_mode { if alloc >= self.realm.gc.gc_watermark && !self.realm.gc.gc_pressure_mode {
self.maybe_collect_in_run(); self.maybe_collect_in_run();
} }
} }
+21 -21
View File
@@ -150,7 +150,7 @@ impl Vm {
} }
} }
} }
f(RootGroup::Global, JsValue::from_js_object(self.session.global_object().as_ptr() as *mut JsObject)); f(RootGroup::Global, JsValue::from_js_object(self.realm.session.global_object().as_ptr() as *mut JsObject));
} }
/// GC 根统一枚举入口:遍历的字段清单与 `for_each_value` 相同。 /// GC 根统一枚举入口:遍历的字段清单与 `for_each_value` 相同。
@@ -163,17 +163,17 @@ impl Vm {
/// `session_gc` 经 `mem::take` 借出后再放回:收集需要 `&mut Vm`,而 /// `session_gc` 经 `mem::take` 借出后再放回:收集需要 `&mut Vm`,而
/// `SessionGc` 是 `Vm` 的内部字段,借出以避开借用冲突。 /// `SessionGc` 是 `Vm` 的内部字段,借出以避开借用冲突。
pub(crate) fn maybe_collect_session_gc(&mut self) { pub(crate) fn maybe_collect_session_gc(&mut self) {
let mut session_gc = std::mem::take(&mut self.gc_state.session_gc); let mut session_gc = std::mem::take(&mut self.realm.gc.session_gc);
session_gc.maybe_collect(self); session_gc.maybe_collect(self);
self.gc_state.session_gc = session_gc; self.realm.gc.session_gc = session_gc;
} }
/// 执行期字符串阈值回收:仅回收 session 字符串(跳过对象搬移)。热路径只在 /// 执行期字符串阈值回收:仅回收 session 字符串(跳过对象搬移)。热路径只在
/// 超阈值后进入,`mem::take` 不承担每次分配的开销。 /// 超阈值后进入,`mem::take` 不承担每次分配的开销。
pub(crate) fn maybe_collect_session_strings(&mut self) { pub(crate) fn maybe_collect_session_strings(&mut self) {
let mut session_gc = std::mem::take(&mut self.gc_state.session_gc); let mut session_gc = std::mem::take(&mut self.realm.gc.session_gc);
session_gc.maybe_collect_strings_only(self); session_gc.maybe_collect_strings_only(self);
self.gc_state.session_gc = session_gc; self.realm.gc.session_gc = session_gc;
} }
/// 执行期原地 sweep 收集的 dispatch 安全点入口:仅在循环顶 /// 执行期原地 sweep 收集的 dispatch 安全点入口:仅在循环顶
@@ -187,35 +187,35 @@ impl Vm {
/// - 无对象可回收时仍跑一轮(mark + 原地清扫),水位同点抬高, /// - 无对象可回收时仍跑一轮(mark + 原地清扫),水位同点抬高,
/// 触发间距由包络增量控制。 /// 触发间距由包络增量控制。
pub(crate) fn maybe_collect_in_run(&mut self) { pub(crate) fn maybe_collect_in_run(&mut self) {
let mut session_gc = std::mem::take(&mut self.gc_state.session_gc); let mut session_gc = std::mem::take(&mut self.realm.gc.session_gc);
session_gc.collect_in_run(self); session_gc.collect_in_run(self);
self.gc_state.session_gc = session_gc; self.realm.gc.session_gc = session_gc;
} }
/// 只读访问 session GC 的统计(回收次数、存活/死亡对象数、释放字节等)。 /// 只读访问 session GC 的统计(回收次数、存活/死亡对象数、释放字节等)。
pub fn session_gc_stats(&self) -> &SessionGc { pub fn session_gc_stats(&self) -> &SessionGc {
&self.gc_state.session_gc &self.realm.gc.session_gc
} }
/// 当前 session arena 中存活(已晋升)的对象数量。 /// 当前 session arena 中存活(已晋升)的对象数量。
pub fn session_object_count(&self) -> usize { pub fn session_object_count(&self) -> usize {
self.gc_state.session_object_ptrs.len() self.realm.gc.session_object_ptrs.len()
} }
/// session 当前分配的字节数(对象 + 存活字符串)。 /// session 当前分配的字节数(对象 + 存活字符串)。
pub fn session_bytes_allocated(&self) -> usize { pub fn session_bytes_allocated(&self) -> usize {
self.gc_state.session_bytes_allocated self.realm.gc.session_bytes_allocated
} }
/// 执行期 session 堆账目的峰值高水位(顶层指令边界采样,全量重置清零)。 /// 执行期 session 堆账目的峰值高水位(顶层指令边界采样,全量重置清零)。
pub fn session_bytes_peak(&self) -> usize { pub fn session_bytes_peak(&self) -> usize {
self.gc_state.session_bytes_peak self.realm.gc.session_bytes_peak
} }
/// 本 run 累计分配字节的高水位:`run_alloc_bytes` 的顶层指令边界 /// 本 run 累计分配字节的高水位:`run_alloc_bytes` 的顶层指令边界
/// 采样上界,run 边界(reset/full_reset)重起算。留存内存观测锚。 /// 采样上界,run 边界(reset/full_reset)重起算。留存内存观测锚。
pub fn run_alloc_peak(&self) -> usize { pub fn run_alloc_peak(&self) -> usize {
self.gc_state.run_alloc_peak self.realm.gc.run_alloc_peak
} }
/// 本 run 累计分配字节:session 手工堆账目(session 对象及其属性向量 + /// 本 run 累计分配字节:session 手工堆账目(session 对象及其属性向量 +
@@ -228,9 +228,9 @@ impl Vm {
/// 属性区(元素/属性向量扩容)增长对其不可见——上限判定须配合 /// 属性区(元素/属性向量扩容)增长对其不可见——上限判定须配合
/// [`Self::run_alloc_bytes_full`] 的深采样层。 /// [`Self::run_alloc_bytes_full`] 的深采样层。
pub(crate) fn run_alloc_bytes(&self) -> usize { pub(crate) fn run_alloc_bytes(&self) -> usize {
self.gc_state.session_bytes_allocated self.realm.gc.session_bytes_allocated
+ self.gc_state.session_bigint_ptrs.borrow().len() * std::mem::size_of::<num_bigint::BigInt>() + self.realm.gc.session_bigint_ptrs.borrow().len() * std::mem::size_of::<num_bigint::BigInt>()
+ self.gc_state.session_cell_ptrs.borrow().len() * std::mem::size_of::<Cell>() + self.realm.gc.session_cell_ptrs.borrow().len() * std::mem::size_of::<Cell>()
} }
/// 本 run 累计分配字节(O(1) 读)。 /// 本 run 累计分配字节(O(1) 读)。
@@ -248,7 +248,7 @@ impl Vm {
/// 与 [`Self::run_alloc_bytes`] 的轻层公式逐位相等。 /// 与 [`Self::run_alloc_bytes`] 的轻层公式逐位相等。
pub(crate) fn run_alloc_bytes_full(&self) -> u64 { pub(crate) fn run_alloc_bytes_full(&self) -> u64 {
let mut bytes = 0u64; let mut bytes = 0u64;
for &ptr in self.gc_state.session_object_ptrs.iter() { for &ptr in self.realm.gc.session_object_ptrs.iter() {
if ptr.is_null() { if ptr.is_null() {
continue; continue;
} }
@@ -256,15 +256,15 @@ impl Vm {
let obj = unsafe { &*ptr }; let obj = unsafe { &*ptr };
bytes += std::mem::size_of::<JsObject>() as u64 + SessionGc::object_heap_data_bytes(obj); bytes += std::mem::size_of::<JsObject>() as u64 + SessionGc::object_heap_data_bytes(obj);
} }
for &ptr in &self.gc_state.session_string_ptrs { for &ptr in &self.realm.gc.session_string_ptrs {
if ptr.is_null() { if ptr.is_null() {
continue; continue;
} }
// SAFETY: ptr 在字符串表登记,收尾前有效。 // SAFETY: ptr 在字符串表登记,收尾前有效。
bytes += (std::mem::size_of::<JsString>() + unsafe { (*ptr).payload_bytes() }) as u64; bytes += (std::mem::size_of::<JsString>() + unsafe { (*ptr).payload_bytes() }) as u64;
} }
bytes += (self.gc_state.session_bigint_ptrs.borrow().len() * std::mem::size_of::<num_bigint::BigInt>()) as u64; bytes += (self.realm.gc.session_bigint_ptrs.borrow().len() * std::mem::size_of::<num_bigint::BigInt>()) as u64;
bytes += (self.gc_state.session_cell_ptrs.borrow().len() * std::mem::size_of::<Cell>()) as u64; bytes += (self.realm.gc.session_cell_ptrs.borrow().len() * std::mem::size_of::<Cell>()) as u64;
bytes bytes
} }
@@ -278,9 +278,9 @@ impl Vm {
/// - 须在执行外的安全点调用(无在途 builtin 局部裸指针、dispatch 未重入); /// - 须在执行外的安全点调用(无在途 builtin 局部裸指针、dispatch 未重入);
/// 执行期触发仍走水位路径,本入口供事后观测(如基准测 workload 后留存堆)。 /// 执行期触发仍走水位路径,本入口供事后观测(如基准测 workload 后留存堆)。
pub fn collect_session_gc(&mut self) { pub fn collect_session_gc(&mut self) {
let mut session_gc = std::mem::take(&mut self.gc_state.session_gc); let mut session_gc = std::mem::take(&mut self.realm.gc.session_gc);
session_gc.collect(self); session_gc.collect(self);
self.gc_state.session_gc = session_gc; self.realm.gc.session_gc = session_gc;
} }
/// 当前 epoch 中已分配并跟踪的对象数量。对象分配统一入口 Box 化后 /// 当前 epoch 中已分配并跟踪的对象数量。对象分配统一入口 Box 化后
+7 -27
View File
@@ -17,11 +17,11 @@ use smallvec::SmallVec;
/// 初始化一个 session 的内置对象(global 槽位、各构造器与原型、IC 预热)。 /// 初始化一个 session 的内置对象(global 槽位、各构造器与原型、IC 预热)。
pub use crate::bindings::init_kernel_builtins; pub use crate::bindings::init_kernel_builtins;
use crate::native::NativeFn; use crate::native::NativeFn;
use crate::realm::Realm;
use crate::vm_debug; use crate::vm_debug;
use crate::vm_state::{GcState, IterState, ProfilingState, SampleState, SymbolState}; use crate::vm_state::{IterState, ProfilingState, SampleState, SymbolState};
use oxide_kernel::kernel::{KernelCore, KernelSession}; use oxide_kernel::kernel::{KernelCore, KernelSession};
use oxide_types::error::JsErrorKind; use oxide_types::error::JsErrorKind;
use oxide_types::mem::P;
use oxide_types::object::{Cell, JsObject, JsString, NativeFnPtr}; use oxide_types::object::{Cell, JsObject, JsString, NativeFnPtr};
use oxide_types::private_key::INT_KEY_COUNT; use oxide_types::private_key::INT_KEY_COUNT;
use oxide_types::value::JsValue; use oxide_types::value::JsValue;
@@ -175,7 +175,9 @@ pub struct Vm {
pub(crate) active_immutables: *const [JsValue], pub(crate) active_immutables: *const [JsValue],
pub(crate) frames: SmallVec<[CallFrame; 16]>, pub(crate) frames: SmallVec<[CallFrame; 16]>,
pub(crate) kernel_core: Arc<KernelCore>, pub(crate) kernel_core: Arc<KernelCore>,
pub(crate) session: KernelSession, /// 每 VM 的 realm 组合:内核会话(builtin world 与 global 对象)、
/// session GC 簿记与 10 个内建原型槽(见 `realm` 模块)。
pub(crate) realm: Realm,
/// `"length"` 属性键的 intern id 缓存:进程内稳定(PermInterner append-only、 /// `"length"` 属性键的 intern id 缓存:进程内稳定(PermInterner append-only、
/// KernelCore 不重建),属性 get/set 热路径免每次 intern(hash64 + DashMap + /// KernelCore 不重建),属性 get/set 热路径免每次 intern(hash64 + DashMap +
/// RwLock 读锁)。 /// RwLock 读锁)。
@@ -190,26 +192,6 @@ pub struct Vm {
/// f64→string 十六槽 last-value 缓存的值(session 串,经 `for_each_value` /// f64→string 十六槽 last-value 缓存的值(session 串,经 `for_each_value`
/// 登记为 GC 根;`full_reset` 在 session 串释放前清空)。 /// 登记为 GC 根;`full_reset` 在 session 串释放前清空)。
pub(crate) number_to_string_cache_vals: [JsValue; 16], pub(crate) number_to_string_cache_vals: [JsValue; 16],
pub object_prototype: P<JsObject>,
/// `%GeneratorPrototype%`:生成器实例的原型(next/return/throw 方法挂此)。
pub generator_proto: P<JsObject>,
/// `%GeneratorFunction.prototype%`:生成器函数对象的原型(`constructor` 指向
/// `%GeneratorFunction%`,使 `g.constructor.name` 解析为 "GeneratorFunction")。
pub generator_function_proto: P<JsObject>,
/// `%Promise%` 构造器(resolve/reject 静态方法挂此,global 的 Promise 槽指向它)。
pub promise_constructor: P<JsObject>,
/// `%Promise.prototype%`:Promise 实例的原型(then/catch/finally 方法挂此)。
pub promise_proto: P<JsObject>,
/// `%AggregateError%` 构造器(Promise.any 拒绝时构造 AggregateError 用)。
pub aggregate_error_constructor: P<JsObject>,
/// `%AggregateError.prototype%`(proto = %Error.prototype%)。
pub aggregate_error_proto: P<JsObject>,
/// `%AsyncFunction.prototype%`:异步函数对象的原型(`constructor` 指向 `%AsyncFunction%`)。
pub async_function_proto: P<JsObject>,
/// `%AsyncGeneratorPrototype%`:异步生成器实例的原型(next/return/throw/@@asyncIterator)。
pub async_generator_proto: P<JsObject>,
/// `%AsyncGeneratorFunction.prototype%`:异步生成器函数对象的原型。
pub async_generator_function_proto: P<JsObject>,
/// 微任务队列(Promise reactions / thenable 委托),`run()` 末尾 FIFO drain。 /// 微任务队列(Promise reactions / thenable 委托),`run()` 末尾 FIFO drain。
pub(crate) job_queue: VecDeque<crate::promise::Microtask>, pub(crate) job_queue: VecDeque<crate::promise::Microtask>,
/// Atomics.waitAsync waiter 表:键 = (缓冲对象指针, 元素字节偏移),值 = /// Atomics.waitAsync waiter 表:键 = (缓冲对象指针, 元素字节偏移),值 =
@@ -357,8 +339,6 @@ pub struct Vm {
/// 异步生成器 body `dispatch()` 的 AWAIT 让出信号:置 true 表示挂起在 await, /// 异步生成器 body `dispatch()` 的 AWAIT 让出信号:置 true 表示挂起在 await,
/// 恢复方(异步生成器内嵌 dispatch 循环)据此快照挂起状态。 /// 恢复方(异步生成器内嵌 dispatch 循环)据此快照挂起状态。
pub(crate) async_gen_suspended: bool, pub(crate) async_gen_suspended: bool,
/// 分组保存 session arena / GC 簿记状态。
pub(crate) gc_state: GcState,
/// 分组保存 `Symbol` intern 状态。 /// 分组保存 `Symbol` intern 状态。
pub(crate) symbols: SymbolState, pub(crate) symbols: SymbolState,
/// 分组保存活跃的 for-in / for-of 迭代器状态。 /// 分组保存活跃的 for-in / for-of 迭代器状态。
@@ -440,12 +420,12 @@ impl Vm {
/// 只读访问当前 session(builtin world 与 global object)。 /// 只读访问当前 session(builtin world 与 global object)。
pub fn session(&self) -> &KernelSession { pub fn session(&self) -> &KernelSession {
&self.session &self.realm.session
} }
/// 判定裸指针是否指向当前 session 的 `%Object.prototype%`。 /// 判定裸指针是否指向当前 session 的 `%Object.prototype%`。
pub(crate) fn is_object_prototype(&self, ptr: *const JsObject) -> bool { pub(crate) fn is_object_prototype(&self, ptr: *const JsObject) -> bool {
let proto_ptr = self.session.builtin_world().object_proto.as_ptr(); let proto_ptr = self.realm.session.builtin_world().object_proto.as_ptr();
std::ptr::eq(ptr, proto_ptr) std::ptr::eq(ptr, proto_ptr)
} }
+4 -4
View File
@@ -46,7 +46,7 @@ impl oxide_runtime_api::VmHost for Vm {
self.kernel_core() self.kernel_core()
} }
fn session(&self) -> &KernelSession { fn session(&self) -> &KernelSession {
self.session() &self.realm.session
} }
fn pc(&self) -> usize { fn pc(&self) -> usize {
self.pc self.pc
@@ -189,9 +189,9 @@ impl oxide_runtime_api::VmHost for Vm {
return false; return false;
} }
let p = proto.as_js_object_ptr() as *const JsObject; let p = proto.as_js_object_ptr() as *const JsObject;
std::ptr::eq(p, self.generator_function_proto.as_ptr()) std::ptr::eq(p, self.realm.generator_function_proto.as_ptr())
|| std::ptr::eq(p, self.async_function_proto.as_ptr()) || std::ptr::eq(p, self.realm.async_function_proto.as_ptr())
|| std::ptr::eq(p, self.async_generator_function_proto.as_ptr()) || std::ptr::eq(p, self.realm.async_generator_function_proto.as_ptr())
} }
fn step_rng(&mut self) { fn step_rng(&mut self) {
self.step_rng() self.step_rng()
+2 -2
View File
@@ -387,7 +387,7 @@ impl Vm {
} }
let si = self.property_key_si(key_val)?; let si = self.property_key_si(key_val)?;
let value = self.regs[a]; let value = self.regs[a];
let global_ptr = self.session.global_object().as_ptr() as *mut JsObject; let global_ptr = self.realm.session.global_object().as_ptr() as *mut JsObject;
// SAFETY: 全局对象钉在 session 永久区,指针在 VM 生命周期内有效。 // SAFETY: 全局对象钉在 session 永久区,指针在 VM 生命周期内有效。
let obj = unsafe { &mut *global_ptr }; let obj = unsafe { &mut *global_ptr };
// 属性已存在:accessor 形走 Set 语义(有 setter 调用之、无 setter // 属性已存在:accessor 形走 Set 语义(有 setter 调用之、无 setter
@@ -483,7 +483,7 @@ impl Vm {
} }
let si = self.property_key_si(key_val)?; let si = self.property_key_si(key_val)?;
let value = self.regs[a]; let value = self.regs[a];
let global_ptr = self.session.global_object().as_ptr() as *mut JsObject; let global_ptr = self.realm.session.global_object().as_ptr() as *mut JsObject;
// SAFETY: 全局对象钉在 session 永久区,指针在 VM 生命周期内有效。 // SAFETY: 全局对象钉在 session 永久区,指针在 VM 生命周期内有效。
let obj = unsafe { &mut *global_ptr }; let obj = unsafe { &mut *global_ptr };
// 既有属性:CreateGlobalVarBinding 零动作。 // 既有属性:CreateGlobalVarBinding 零动作。
+5 -5
View File
@@ -55,7 +55,7 @@ impl Vm {
for i in 0..arg_count.min(256) { for i in 0..arg_count.min(256) {
args.push(self.regs[first_arg_reg.wrapping_add(i as u8) as usize]); args.push(self.regs[first_arg_reg.wrapping_add(i as u8) as usize]);
} }
let proto_ptr = &*self.object_prototype as *const JsObject as *mut JsObject; let proto_ptr = &*self.realm.object_prototype as *const JsObject as *mut JsObject;
let new_obj = self.alloc_object(JsObject::new_empty( let new_obj = self.alloc_object(JsObject::new_empty(
oxide_kernel::shape_forge::EMPTY_SHAPE_ID, oxide_kernel::shape_forge::EMPTY_SHAPE_ID,
JsValue::from_js_object(proto_ptr), JsValue::from_js_object(proto_ptr),
@@ -63,7 +63,7 @@ impl Vm {
return self.dispatch_new_bound(rd, constructor, new_obj, args, call_window); return self.dispatch_new_bound(rd, constructor, new_obj, args, call_window);
} }
let proto_ptr = &*self.object_prototype as *const JsObject as *mut JsObject; let proto_ptr = &*self.realm.object_prototype as *const JsObject as *mut JsObject;
let new_obj = self.alloc_object(JsObject::new_empty( let new_obj = self.alloc_object(JsObject::new_empty(
oxide_kernel::shape_forge::EMPTY_SHAPE_ID, oxide_kernel::shape_forge::EMPTY_SHAPE_ID,
JsValue::from_js_object(proto_ptr), JsValue::from_js_object(proto_ptr),
@@ -998,7 +998,7 @@ impl Vm {
if src.is_null() || src.is_undefined() { if src.is_null() || src.is_undefined() {
return self.raise_type_error("Cannot destructure property of null/undefined"); return self.raise_type_error("Cannot destructure property of null/undefined");
} }
let proto_ptr = self.session.builtin_world().object_proto.as_ptr() as *mut JsObject; let proto_ptr = self.realm.session.builtin_world().object_proto.as_ptr() as *mut JsObject;
let rest_ptr = self.alloc_object(JsObject::new_empty( let rest_ptr = self.alloc_object(JsObject::new_empty(
oxide_kernel::shape_forge::EMPTY_SHAPE_ID, oxide_kernel::shape_forge::EMPTY_SHAPE_ID,
JsValue::from_js_object(proto_ptr), JsValue::from_js_object(proto_ptr),
@@ -1088,7 +1088,7 @@ impl Vm {
} }
// 提交到 rest 对象。 // 提交到 rest 对象。
let proto_ptr = self.session.builtin_world().object_proto.as_ptr() as *mut JsObject; let proto_ptr = self.realm.session.builtin_world().object_proto.as_ptr() as *mut JsObject;
let rest_ptr = self.alloc_object(JsObject::new_empty( let rest_ptr = self.alloc_object(JsObject::new_empty(
oxide_kernel::shape_forge::EMPTY_SHAPE_ID, oxide_kernel::shape_forge::EMPTY_SHAPE_ID,
JsValue::from_js_object(proto_ptr), JsValue::from_js_object(proto_ptr),
@@ -1210,7 +1210,7 @@ impl Vm {
return Ok(()); return Ok(());
} }
let proto_ptr = self.session.builtin_world().array_proto.as_ptr() as *mut JsObject; let proto_ptr = self.realm.session.builtin_world().array_proto.as_ptr() as *mut JsObject;
let proto_val = JsValue::from_js_object(proto_ptr); let proto_val = JsValue::from_js_object(proto_ptr);
// 模板对象直接分配为 session 对象:写入 session 根(存进 global/数组) // 模板对象直接分配为 session 对象:写入 session 根(存进 global/数组)
// 时对象地址稳定,缓存指针不失效——分配档不同则首次写入触发搬移, // 时对象地址稳定,缓存指针不失效——分配档不同则首次写入触发搬移,
+6 -6
View File
@@ -239,7 +239,7 @@ impl Vm {
/// - 只可挂在真实 A 侧写发生之后;写失败路径(只读 no-op / 抛错)不得 /// - 只可挂在真实 A 侧写发生之后;写失败路径(只读 no-op / 抛错)不得
/// 调用,否则污染镜像槽。 /// 调用,否则污染镜像槽。
pub(crate) fn sync_global_builtin_mirror(&mut self, obj: &JsObject, key_si: u32, val: JsValue) { pub(crate) fn sync_global_builtin_mirror(&mut self, obj: &JsObject, key_si: u32, val: JsValue) {
if !std::ptr::eq(obj as *const JsObject, self.session.global_object().as_ptr()) { if !std::ptr::eq(obj as *const JsObject, self.realm.session.global_object().as_ptr()) {
return; return;
} }
let Some(module) = self.active_module() else { let Some(module) = self.active_module() else {
@@ -264,7 +264,7 @@ impl Vm {
pub(crate) fn sync_global_builtin_mirror_slot( pub(crate) fn sync_global_builtin_mirror_slot(
&mut self, obj: &JsObject, shape_id: u32, slot: u32, depth: u8, val: JsValue, &mut self, obj: &JsObject, shape_id: u32, slot: u32, depth: u8, val: JsValue,
) { ) {
if !std::ptr::eq(obj as *const JsObject, self.session.global_object().as_ptr()) { if !std::ptr::eq(obj as *const JsObject, self.realm.session.global_object().as_ptr()) {
return; return;
} }
if depth != 0 || shape_id != obj.shape_id() { if depth != 0 || shape_id != obj.shape_id() {
@@ -305,7 +305,7 @@ impl Vm {
if map.is_empty() { if map.is_empty() {
return; return;
} }
let global = self.session.global_object(); let global = self.realm.session.global_object();
for (name, reg) in map { for (name, reg) in map {
if (*reg as usize) < pack_end { if (*reg as usize) < pack_end {
continue; continue;
@@ -1543,7 +1543,7 @@ mod tests {
} }
fn native_function(vm: &mut Vm, f: crate::native::NativeFn) -> JsValue { fn native_function(vm: &mut Vm, f: crate::native::NativeFn) -> JsValue {
let proto = vm.session.builtin_world().function_proto.as_ptr() as *mut JsObject; let proto = vm.realm.session.builtin_world().function_proto.as_ptr() as *mut JsObject;
let mut obj = JsObject::new_empty(oxide_kernel::shape_forge::EMPTY_SHAPE_ID, JsValue::from_js_object(proto)); let mut obj = JsObject::new_empty(oxide_kernel::shape_forge::EMPTY_SHAPE_ID, JsValue::from_js_object(proto));
obj.set_function(true); obj.set_function(true);
// SAFETY: f 是 NativeFn 函数项,可作为 NativeFnPtr 存储。 // SAFETY: f 是 NativeFn 函数项,可作为 NativeFnPtr 存储。
@@ -1552,7 +1552,7 @@ mod tests {
} }
fn plain_object(vm: &mut Vm) -> JsValue { fn plain_object(vm: &mut Vm) -> JsValue {
let proto = vm.session.builtin_world().object_proto.as_ptr() as *mut JsObject; let proto = vm.realm.session.builtin_world().object_proto.as_ptr() as *mut JsObject;
let obj = JsObject::new_empty(oxide_kernel::shape_forge::EMPTY_SHAPE_ID, JsValue::from_js_object(proto)); let obj = JsObject::new_empty(oxide_kernel::shape_forge::EMPTY_SHAPE_ID, JsValue::from_js_object(proto));
JsValue::object(vm.alloc_object(obj) as *mut u8) JsValue::object(vm.alloc_object(obj) as *mut u8)
} }
@@ -1681,7 +1681,7 @@ mod tests {
// ===== 大索引(越稠密上限)写降级命名属性的行为钉 ===== // ===== 大索引(越稠密上限)写降级命名属性的行为钉 =====
fn new_array_val(vm: &mut Vm, n: u32) -> JsValue { fn new_array_val(vm: &mut Vm, n: u32) -> JsValue {
let proto = vm.session.builtin_world().array_proto.as_ptr() as *mut JsObject; let proto = vm.realm.session.builtin_world().array_proto.as_ptr() as *mut JsObject;
let arr = let arr =
JsObject::new_array(oxide_kernel::shape_forge::EMPTY_SHAPE_ID, JsValue::from_js_object(proto), n as usize); JsObject::new_array(oxide_kernel::shape_forge::EMPTY_SHAPE_ID, JsValue::from_js_object(proto), n as usize);
JsValue::object(vm.alloc_object(arr) as *mut u8) JsValue::object(vm.alloc_object(arr) as *mut u8)
+3 -3
View File
@@ -502,7 +502,7 @@ impl Vm {
self.regs[254] = if sub.is_arrow { self.regs[254] = if sub.is_arrow {
callee_obj.captured_this() callee_obj.captured_this()
} else if !sub.is_strict && receiver.is_nullish() { } else if !sub.is_strict && receiver.is_nullish() {
JsValue::from_js_object(self.session.global_object().as_ptr() as *mut JsObject) JsValue::from_js_object(self.realm.session.global_object().as_ptr() as *mut JsObject)
} else if sub.is_strict { } else if sub.is_strict {
receiver receiver
} else { } else {
@@ -632,7 +632,7 @@ impl Vm {
// 存活代际集:函数对象只经创建点直落 session 对象表登记(或晋升克隆 // 存活代际集:函数对象只经创建点直落 session 对象表登记(或晋升克隆
// 随行),扫全表即完备;native 函数哨兵 sub_module_index == 0 不计数。 // 随行),扫全表即完备;native 函数哨兵 sub_module_index == 0 不计数。
let mut live_gens: Vec<u32> = Vec::new(); let mut live_gens: Vec<u32> = Vec::new();
for &ptr in &self.gc_state.session_object_ptrs { for &ptr in &self.realm.gc.session_object_ptrs {
if ptr.is_null() { if ptr.is_null() {
continue; continue;
} }
@@ -692,7 +692,7 @@ impl Vm {
// 顶层 this:脚本为全局对象(ECMA-262 全局执行上下文); // 顶层 this:脚本为全局对象(ECMA-262 全局执行上下文);
// ES module 顶层环境 GetThisBinding 返回 undefined。记录到 // ES module 顶层环境 GetThisBinding 返回 undefined。记录到
// top_level_this:rerun 清空寄存器文件后按此恢复顶层 this。 // top_level_this:rerun 清空寄存器文件后按此恢复顶层 this。
let global = self.session.global_object(); let global = self.realm.session.global_object();
let this_val = if module.is_es_module { let this_val = if module.is_es_module {
JsValue::undefined() JsValue::undefined()
} else { } else {
+1 -1
View File
@@ -1,6 +1,6 @@
//! `Vm` 的状态子结构分组。 //! `Vm` 的状态子结构分组。
//! //!
//! `Vm` 以字段持有这些子结构(`gc_state`、`symbols`、`iters`、`profiling`), //! `Vm` 以字段持有这些子结构(`realm` 内的 `gc`、`symbols`、`iters`、`profiling`),
//! 使各子系统维护者只需改动一个结构而非庞大的 `Vm` 主结构。约定: //! 使各子系统维护者只需改动一个结构而非庞大的 `Vm` 主结构。约定:
//! Symbol/Iter/Profiling 为完整子模块(逻辑自包含);`GcState` 仅做字段分类—— //! Symbol/Iter/Profiling 为完整子模块(逻辑自包含);`GcState` 仅做字段分类——
//! GC 的 mark/sweep/alloc_object 需要扫描跨全部子结构的根(regs、frames、 //! GC 的 mark/sweep/alloc_object 需要扫描跨全部子结构的根(regs、frames、
+105 -100
View File
@@ -6,6 +6,7 @@ use std::sync::Arc;
use oxide_bytecode::module::Constant; use oxide_bytecode::module::Constant;
use crate::bindings; use crate::bindings;
use crate::realm::Realm;
use crate::vm::{TableGen, Vm}; use crate::vm::{TableGen, Vm};
use crate::vm_info; use crate::vm_info;
use crate::vm_state::{GcState, IterState, ProfilingState, SampleState, SymbolState}; use crate::vm_state::{GcState, IterState, ProfilingState, SampleState, SymbolState};
@@ -63,21 +64,38 @@ impl Vm {
active_immutables: std::ptr::slice_from_raw_parts(std::ptr::null(), 0), active_immutables: std::ptr::slice_from_raw_parts(std::ptr::null(), 0),
frames: smallvec::SmallVec::new(), frames: smallvec::SmallVec::new(),
kernel_core: core, kernel_core: core,
session, realm: Realm {
session,
object_prototype: obj_proto,
generator_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
generator_function_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
promise_constructor: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
promise_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
aggregate_error_constructor: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
aggregate_error_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
async_function_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
async_generator_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
async_generator_function_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
gc: GcState {
session_gc: crate::session_gc::SessionGc::new(),
session_object_ptrs: Vec::new(),
session_string_ptrs: Vec::new(),
session_bigint_ptrs: std::cell::RefCell::new(Vec::new()),
session_cell_ptrs: std::cell::RefCell::new(Vec::new()),
session_bytes_allocated: 0,
session_bytes_peak: 0,
run_alloc_peak: 0,
string_gc_watermark: gc_threshold,
gc_threshold_cached: gc_threshold,
gc_watermark: gc_threshold,
pending_forced_collect: false,
gc_pressure_mode: gc_pressure_mode_from_env(),
},
},
length_si, length_si,
length_perm_ptr, length_perm_ptr,
number_to_string_cache_keys: [0u64; 16], number_to_string_cache_keys: [0u64; 16],
number_to_string_cache_vals: [JsValue::undefined(); 16], number_to_string_cache_vals: [JsValue::undefined(); 16],
object_prototype: obj_proto,
generator_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
generator_function_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
promise_constructor: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
promise_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
aggregate_error_constructor: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
aggregate_error_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
async_function_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
async_generator_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
async_generator_function_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
job_queue: VecDeque::new(), job_queue: VecDeque::new(),
atomics_waiters: std::collections::HashMap::new(), atomics_waiters: std::collections::HashMap::new(),
math_rng_state: 0, math_rng_state: 0,
@@ -134,21 +152,6 @@ impl Vm {
async_gen_context: None, async_gen_context: None,
async_gen_dispatch: false, async_gen_dispatch: false,
async_gen_suspended: false, async_gen_suspended: false,
gc_state: GcState {
session_gc: crate::session_gc::SessionGc::new(),
session_object_ptrs: Vec::new(),
session_string_ptrs: Vec::new(),
session_bigint_ptrs: std::cell::RefCell::new(Vec::new()),
session_cell_ptrs: std::cell::RefCell::new(Vec::new()),
session_bytes_allocated: 0,
session_bytes_peak: 0,
run_alloc_peak: 0,
string_gc_watermark: gc_threshold,
gc_threshold_cached: gc_threshold,
gc_watermark: gc_threshold,
pending_forced_collect: false,
gc_pressure_mode: gc_pressure_mode_from_env(),
},
symbols: SymbolState { symbols: SymbolState {
symbol_counter: 0, symbol_counter: 0,
symbol_descriptions: Vec::new(), symbol_descriptions: Vec::new(),
@@ -183,7 +186,7 @@ impl Vm {
vm.init_async_intrinsics(); vm.init_async_intrinsics();
vm.init_async_generator_intrinsics(); vm.init_async_generator_intrinsics();
// Promise 全局绑定发生在快照采集之后,重录快照避免首次 full_reset 误判脏。 // Promise 全局绑定发生在快照采集之后,重录快照避免首次 full_reset 误判脏。
vm.session.record_snapshot(); vm.realm.session.record_snapshot();
// 边界守卫计数:VM 完整构造后登记,与 `Drop for Vm` 的注销恰好配对。 // 边界守卫计数:VM 完整构造后登记,与 `Drop for Vm` 的注销恰好配对。
vm.kernel_core.note_vm_started(); vm.kernel_core.note_vm_started();
vm_info!("Vm created"); vm_info!("Vm created");
@@ -208,21 +211,38 @@ impl Vm {
active_immutables: std::ptr::slice_from_raw_parts(std::ptr::null(), 0), active_immutables: std::ptr::slice_from_raw_parts(std::ptr::null(), 0),
frames: smallvec::SmallVec::new(), frames: smallvec::SmallVec::new(),
kernel_core: core, kernel_core: core,
session, realm: Realm {
session,
object_prototype: obj_proto,
generator_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
generator_function_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
promise_constructor: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
promise_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
aggregate_error_constructor: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
aggregate_error_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
async_function_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
async_generator_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
async_generator_function_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
gc: GcState {
session_gc: crate::session_gc::SessionGc::new(),
session_object_ptrs: Vec::new(),
session_string_ptrs: Vec::new(),
session_bigint_ptrs: std::cell::RefCell::new(Vec::new()),
session_cell_ptrs: std::cell::RefCell::new(Vec::new()),
session_bytes_allocated: 0,
session_bytes_peak: 0,
run_alloc_peak: 0,
string_gc_watermark: gc_threshold,
gc_threshold_cached: gc_threshold,
gc_watermark: gc_threshold,
pending_forced_collect: false,
gc_pressure_mode: gc_pressure_mode_from_env(),
},
},
length_si, length_si,
length_perm_ptr, length_perm_ptr,
number_to_string_cache_keys: [0u64; 16], number_to_string_cache_keys: [0u64; 16],
number_to_string_cache_vals: [JsValue::undefined(); 16], number_to_string_cache_vals: [JsValue::undefined(); 16],
object_prototype: obj_proto,
generator_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
generator_function_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
promise_constructor: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
promise_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
aggregate_error_constructor: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
aggregate_error_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
async_function_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
async_generator_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
async_generator_function_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
job_queue: VecDeque::new(), job_queue: VecDeque::new(),
atomics_waiters: std::collections::HashMap::new(), atomics_waiters: std::collections::HashMap::new(),
math_rng_state: 0, math_rng_state: 0,
@@ -279,21 +299,6 @@ impl Vm {
async_gen_context: None, async_gen_context: None,
async_gen_dispatch: false, async_gen_dispatch: false,
async_gen_suspended: false, async_gen_suspended: false,
gc_state: GcState {
session_gc: crate::session_gc::SessionGc::new(),
session_object_ptrs: Vec::new(),
session_string_ptrs: Vec::new(),
session_bigint_ptrs: std::cell::RefCell::new(Vec::new()),
session_cell_ptrs: std::cell::RefCell::new(Vec::new()),
session_bytes_allocated: 0,
session_bytes_peak: 0,
run_alloc_peak: 0,
string_gc_watermark: gc_threshold,
gc_threshold_cached: gc_threshold,
gc_watermark: gc_threshold,
pending_forced_collect: false,
gc_pressure_mode: gc_pressure_mode_from_env(),
},
symbols: SymbolState { symbols: SymbolState {
symbol_counter: 0, symbol_counter: 0,
symbol_descriptions: Vec::new(), symbol_descriptions: Vec::new(),
@@ -328,7 +333,7 @@ impl Vm {
vm.init_async_intrinsics(); vm.init_async_intrinsics();
vm.init_async_generator_intrinsics(); vm.init_async_generator_intrinsics();
// Promise 全局绑定发生在快照采集之后,重录快照避免首次 full_reset 误判脏。 // Promise 全局绑定发生在快照采集之后,重录快照避免首次 full_reset 误判脏。
vm.session.record_snapshot(); vm.realm.session.record_snapshot();
// 边界守卫计数:VM 完整构造后登记,与 `Drop for Vm` 的注销恰好配对。 // 边界守卫计数:VM 完整构造后登记,与 `Drop for Vm` 的注销恰好配对。
vm.kernel_core.note_vm_started(); vm.kernel_core.note_vm_started();
vm_info!("Vm created (pool)"); vm_info!("Vm created (pool)");
@@ -365,26 +370,26 @@ impl Vm {
// 防御兜底:属性值写原语已推进 generation,常规覆盖写由快照对比发现; // 防御兜底:属性值写原语已推进 generation,常规覆盖写由快照对比发现;
// 若未来出现绕过属性写原语的裸属性区改写,session 对象会被 session GC 回收, // 若未来出现绕过属性写原语的裸属性区改写,session 对象会被 session GC 回收,
// 保留 global 将持悬垂指针,故带 session 对象时强制 bump 保证 global 重建。 // 保留 global 将持悬垂指针,故带 session 对象时强制 bump 保证 global 重建。
if !self.gc_state.session_object_ptrs.is_empty() { if !self.realm.gc.session_object_ptrs.is_empty() {
let global_ptr = self.session.global_object().as_ptr() as *mut JsObject; let global_ptr = self.realm.session.global_object().as_ptr() as *mut JsObject;
unsafe { &mut *global_ptr }.bump_generation(); unsafe { &mut *global_ptr }.bump_generation();
} }
let dirty = self.session.selective_reset(&self.kernel_core); let dirty = self.realm.session.selective_reset(&self.kernel_core);
if dirty.any_builtin_dirty() { if dirty.any_builtin_dirty() {
bindings::rebind_dirty_builtins(&self.kernel_core, &mut self.session, Some(&dirty)); bindings::rebind_dirty_builtins(&self.kernel_core, &mut self.realm.session, Some(&dirty));
} }
if dirty.global { if dirty.global {
let global_ptr = self.session.global_object().as_ptr() as *mut JsObject; let global_ptr = self.realm.session.global_object().as_ptr() as *mut JsObject;
let global = unsafe { &mut *global_ptr }; let global = unsafe { &mut *global_ptr };
bindings::bind_global_builtin_slots(&self.kernel_core, &self.session, global); bindings::bind_global_builtin_slots(&self.kernel_core, &self.realm.session, global);
} }
self.object_prototype = P::clone(&self.session.builtin_world().object_proto); self.realm.object_prototype = P::clone(&self.realm.session.builtin_world().object_proto);
self.init_generator_intrinsics(); self.init_generator_intrinsics();
self.init_promise_intrinsics(); self.init_promise_intrinsics();
self.init_async_intrinsics(); self.init_async_intrinsics();
self.init_async_generator_intrinsics(); self.init_async_generator_intrinsics();
// 快照须在 Promise 全局绑定之后采集:绑定会修改 global 世代。 // 快照须在 Promise 全局绑定之后采集:绑定会修改 global 世代。
self.session.record_snapshot(); self.realm.session.record_snapshot();
self.clear_full_reset_state(); self.clear_full_reset_state();
vm_info!("full_reset completed"); vm_info!("full_reset completed");
} }
@@ -392,14 +397,14 @@ impl Vm {
/// benchmark 专用重置路径:总是丢弃并重建整个 session 与内置对象。 /// benchmark 专用重置路径:总是丢弃并重建整个 session 与内置对象。
#[doc(hidden)] #[doc(hidden)]
pub fn full_reset_legacy_for_bench(&mut self) { pub fn full_reset_legacy_for_bench(&mut self) {
self.session = KernelSession::new(&self.kernel_core); self.realm.session = KernelSession::new(&self.kernel_core);
bindings::init_kernel_builtins(&self.kernel_core, &mut self.session); bindings::init_kernel_builtins(&self.kernel_core, &mut self.realm.session);
self.object_prototype = P::clone(&self.session.builtin_world().object_proto); self.realm.object_prototype = P::clone(&self.realm.session.builtin_world().object_proto);
self.init_generator_intrinsics(); self.init_generator_intrinsics();
self.init_promise_intrinsics(); self.init_promise_intrinsics();
self.init_async_intrinsics(); self.init_async_intrinsics();
self.init_async_generator_intrinsics(); self.init_async_generator_intrinsics();
self.session.record_snapshot(); self.realm.session.record_snapshot();
self.clear_full_reset_state(); self.clear_full_reset_state();
} }
@@ -431,14 +436,14 @@ impl Vm {
self.number_to_string_cache_keys = [0u64; 16]; self.number_to_string_cache_keys = [0u64; 16];
self.number_to_string_cache_vals = [JsValue::undefined(); 16]; self.number_to_string_cache_vals = [JsValue::undefined(); 16];
self.teardown_session_heap_data(); self.teardown_session_heap_data();
self.gc_state.session_bytes_allocated = 0; self.realm.gc.session_bytes_allocated = 0;
self.gc_state.session_bytes_peak = 0; self.realm.gc.session_bytes_peak = 0;
self.gc_state.run_alloc_peak = 0; self.realm.gc.run_alloc_peak = 0;
self.gc_state.string_gc_watermark = self.kernel_core.config().session_gc_threshold; self.realm.gc.string_gc_watermark = self.kernel_core.config().session_gc_threshold;
// 执行期收集水位同点复位(同式:阈值增量起算):旧 run 的存活包络 // 执行期收集水位同点复位(同式:阈值增量起算):旧 run 的存活包络
// 不延续到新 run 的触发判定。 // 不延续到新 run 的触发判定。
self.gc_state.gc_watermark = self.gc_state.gc_threshold_cached; self.realm.gc.gc_watermark = self.realm.gc.gc_threshold_cached;
self.gc_state.session_gc = crate::session_gc::SessionGc::new(); self.realm.gc.session_gc = crate::session_gc::SessionGc::new();
self.symbols.reset(); self.symbols.reset();
self.root_reg_limit = 0; self.root_reg_limit = 0;
self.active_reg_limit = 0; self.active_reg_limit = 0;
@@ -459,7 +464,7 @@ impl Vm {
self.iters.reset(); self.iters.reset();
// 对象逐条独占释放:本体 + 堆数据 + upvalue 列表,顺序由 // 对象逐条独占释放:本体 + 堆数据 + upvalue 列表,顺序由
// drop_dead_session_object 收口。 // drop_dead_session_object 收口。
for ptr in self.gc_state.session_object_ptrs.drain(..) { for ptr in self.realm.gc.session_object_ptrs.drain(..) {
if ptr.is_null() { if ptr.is_null() {
continue; continue;
} }
@@ -469,7 +474,7 @@ impl Vm {
} }
self.free_session_string_heap_data(); self.free_session_string_heap_data();
self.free_session_bigint_heap_data(); self.free_session_bigint_heap_data();
self.gc_state.free_cells(); self.realm.gc.free_cells();
} }
/// 释放 VM 内建原型 P 对象(生成器/Promise/异步族与 Object 原型)的堆外属性区。 /// 释放 VM 内建原型 P 对象(生成器/Promise/异步族与 Object 原型)的堆外属性区。
@@ -481,16 +486,16 @@ impl Vm {
/// world 引用同一对象,其属性区归 session 收尾(`teardown_builtins`)释放。 /// world 引用同一对象,其属性区归 session 收尾(`teardown_builtins`)释放。
pub(crate) fn teardown_intrinsic_protos(&mut self) { pub(crate) fn teardown_intrinsic_protos(&mut self) {
for p in [ for p in [
&self.object_prototype, &self.realm.object_prototype,
&self.generator_proto, &self.realm.generator_proto,
&self.generator_function_proto, &self.realm.generator_function_proto,
&self.promise_constructor, &self.realm.promise_constructor,
&self.promise_proto, &self.realm.promise_proto,
&self.aggregate_error_constructor, &self.realm.aggregate_error_constructor,
&self.aggregate_error_proto, &self.realm.aggregate_error_proto,
&self.async_function_proto, &self.realm.async_function_proto,
&self.async_generator_proto, &self.realm.async_generator_proto,
&self.async_generator_function_proto, &self.realm.async_generator_function_proto,
] { ] {
if p.strong_count() != 1 { if p.strong_count() != 1 {
continue; continue;
@@ -565,7 +570,7 @@ impl Vm {
self.sampling.clear_records(); self.sampling.clear_records();
// GC 统计同属执行期状态:池化 Vm 跨 run 复用,不清零则 per-run // GC 统计同属执行期状态:池化 Vm 跨 run 复用,不清零则 per-run
// 指标(gc_trigger_count)跨文件累积,报告失真。 // 指标(gc_trigger_count)跨文件累积,报告失真。
let gc = &mut self.gc_state.session_gc; let gc = &mut self.realm.gc.session_gc;
gc.total_collections = 0; gc.total_collections = 0;
gc.total_bytes_freed = 0; gc.total_bytes_freed = 0;
gc.total_objects_scanned = 0; gc.total_objects_scanned = 0;
@@ -590,9 +595,9 @@ impl Vm {
// 指针作废,下次 run 重装。 // 指针作废,下次 run 重装。
self.active_immutables = std::ptr::slice_from_raw_parts(std::ptr::null(), 0); self.active_immutables = std::ptr::slice_from_raw_parts(std::ptr::null(), 0);
// 单 run 分配包络按 run 边界重起算(与 run_alloc_bytes 起算口径同源)。 // 单 run 分配包络按 run 边界重起算(与 run_alloc_bytes 起算口径同源)。
self.gc_state.run_alloc_peak = 0; self.realm.gc.run_alloc_peak = 0;
// 执行期收集水位与包络同起算:旧 run 的存活包络不延续到新 run 的触发判定。 // 执行期收集水位与包络同起算:旧 run 的存活包络不延续到新 run 的触发判定。
self.gc_state.gc_watermark = self.gc_state.gc_threshold_cached; self.realm.gc.gc_watermark = self.realm.gc.gc_threshold_cached;
self.root_reg_limit = 0; self.root_reg_limit = 0;
self.active_reg_limit = 0; self.active_reg_limit = 0;
} }
@@ -664,8 +669,8 @@ impl Vm {
/// 水位触发(此时 builtin 局部值已落地为执行根,分配点触发会误释放 /// 水位触发(此时 builtin 局部值已落地为执行根,分配点触发会误释放
/// 仅存于局部/构造中的活串)。 /// 仅存于局部/构造中的活串)。
fn register_session_string(&mut self, ptr: *mut JsString, bytes: usize) -> JsValue { fn register_session_string(&mut self, ptr: *mut JsString, bytes: usize) -> JsValue {
self.gc_state.session_string_ptrs.push(ptr); self.realm.gc.session_string_ptrs.push(ptr);
self.gc_state.session_bytes_allocated += std::mem::size_of::<JsString>() + bytes; self.realm.gc.session_bytes_allocated += std::mem::size_of::<JsString>() + bytes;
JsValue::string(ptr) JsValue::string(ptr)
} }
@@ -737,7 +742,7 @@ impl Vm {
/// (`full_reset` / `clear_full_reset_state`)时调用,此时没有存活的 session 对象 /// (`full_reset` / `clear_full_reset_state`)时调用,此时没有存活的 session 对象
/// 会引用它们。较轻量的 `reset()` 刻意保留它们,与 session 对象跨 eval 存活一致。 /// 会引用它们。较轻量的 `reset()` 刻意保留它们,与 session 对象跨 eval 存活一致。
fn free_session_string_heap_data(&mut self) { fn free_session_string_heap_data(&mut self) {
for ptr in self.gc_state.session_string_ptrs.drain(..) { for ptr in self.realm.gc.session_string_ptrs.drain(..) {
// SAFETY: 每个指针来自 new_string/new_cons_string 的 Box::into_raw, // SAFETY: 每个指针来自 new_string/new_cons_string 的 Box::into_raw,
// 且只在这里(或 sweep)恰好释放一次;内部连带释放 rope 扁平化产物。 // 且只在这里(或 sweep)恰好释放一次;内部连带释放 rope 扁平化产物。
unsafe { unsafe {
@@ -767,13 +772,13 @@ impl Vm {
// 异步生成器(`async function*`)函数对象:原型为 %AsyncGeneratorFunction.prototype%。 // 异步生成器(`async function*`)函数对象:原型为 %AsyncGeneratorFunction.prototype%。
let is_async_generator = is_generator && is_async; let is_async_generator = is_generator && is_async;
let proto_val = if is_async_generator { let proto_val = if is_async_generator {
JsValue::from_js_object(self.async_generator_function_proto.as_ptr() as *mut JsObject) JsValue::from_js_object(self.realm.async_generator_function_proto.as_ptr() as *mut JsObject)
} else if is_generator { } else if is_generator {
JsValue::from_js_object(self.generator_function_proto.as_ptr() as *mut JsObject) JsValue::from_js_object(self.realm.generator_function_proto.as_ptr() as *mut JsObject)
} else if is_async { } else if is_async {
JsValue::from_js_object(self.async_function_proto.as_ptr() as *mut JsObject) JsValue::from_js_object(self.realm.async_function_proto.as_ptr() as *mut JsObject)
} else { } else {
JsValue::from_js_object(self.session.builtin_world().function_proto.as_ptr() as *mut JsObject) JsValue::from_js_object(self.realm.session.builtin_world().function_proto.as_ptr() as *mut JsObject)
}; };
let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, proto_val); let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, proto_val);
obj.set_function(true); obj.set_function(true);
@@ -798,11 +803,11 @@ impl Vm {
// 原型对象自身的 [[Prototype]]:生成器为 %GeneratorPrototype%,普通函数为 Object.prototype。 // 原型对象自身的 [[Prototype]]:生成器为 %GeneratorPrototype%,普通函数为 Object.prototype。
// 纯异步函数(非生成器)无 `prototype` 属性:规范不为其建 prototype 子对象。 // 纯异步函数(非生成器)无 `prototype` 属性:规范不为其建 prototype 子对象。
let proto_of_proto = if is_async_generator { let proto_of_proto = if is_async_generator {
JsValue::from_js_object(self.async_generator_proto.as_ptr() as *mut JsObject) JsValue::from_js_object(self.realm.async_generator_proto.as_ptr() as *mut JsObject)
} else if is_generator { } else if is_generator {
JsValue::from_js_object(self.generator_proto.as_ptr() as *mut JsObject) JsValue::from_js_object(self.realm.generator_proto.as_ptr() as *mut JsObject)
} else { } else {
JsValue::from_js_object(self.session.builtin_world().object_proto.as_ptr() as *mut JsObject) JsValue::from_js_object(self.realm.session.builtin_world().object_proto.as_ptr() as *mut JsObject)
}; };
// prototype 子对象与函数本体同走 session 分配:`f.prototype === // prototype 子对象与函数本体同走 session 分配:`f.prototype ===
// globalThis.f.prototype` 要求两侧同一对象,逃逸写不会克隆出第二份。 // globalThis.f.prototype` 要求两侧同一对象,逃逸写不会克隆出第二份。
@@ -864,11 +869,11 @@ impl Vm {
/// 分配一个 BigInt 值:把 `i128` 堆分配为 box 并返回携带指针的 `JsValue`。 /// 分配一个 BigInt 值:把 `i128` 堆分配为 box 并返回携带指针的 `JsValue`。
/// ///
/// box 指针登记进 `gc_state.session_bigint_ptrs`,在 `full_reset` 统一释放。 /// box 指针登记进 `realm.gc.session_bigint_ptrs`,在 `full_reset` 统一释放。
/// `&self` 使 `convert_immutables`(常量池 → JsValue)也能分配。 /// `&self` 使 `convert_immutables`(常量池 → JsValue)也能分配。
pub fn new_bigint(&self, v: num_bigint::BigInt) -> JsValue { pub fn new_bigint(&self, v: num_bigint::BigInt) -> JsValue {
let ptr = Box::into_raw(Box::new(v)); let ptr = Box::into_raw(Box::new(v));
self.gc_state.session_bigint_ptrs.borrow_mut().push(ptr); self.realm.gc.session_bigint_ptrs.borrow_mut().push(ptr);
JsValue::bigint(ptr) JsValue::bigint(ptr)
} }
@@ -881,7 +886,7 @@ impl Vm {
/// 释放全部 session 堆 BigInt box。仅在完全隔离重置(`full_reset`)时调用, /// 释放全部 session 堆 BigInt box。仅在完全隔离重置(`full_reset`)时调用,
/// 此时没有存活的 session 对象/寄存器会引用它们。 /// 此时没有存活的 session 对象/寄存器会引用它们。
fn free_session_bigint_heap_data(&mut self) { fn free_session_bigint_heap_data(&mut self) {
for ptr in self.gc_state.session_bigint_ptrs.borrow_mut().drain(..) { for ptr in self.realm.gc.session_bigint_ptrs.borrow_mut().drain(..) {
// SAFETY: 每个指针来自 new_bigint 的 Box::into_raw(Box::new(BigInt)), // SAFETY: 每个指针来自 new_bigint 的 Box::into_raw(Box::new(BigInt)),
// 且只在这里恰好释放一次。 // 且只在这里恰好释放一次。
unsafe { unsafe {
+99 -99
View File
@@ -6,7 +6,7 @@ fn global_prop(vm: &Vm, name: &str) -> JsValue {
} }
fn global_prop_opt(vm: &Vm, name: &str) -> Option<JsValue> { fn global_prop_opt(vm: &Vm, name: &str) -> Option<JsValue> {
let global = vm.session.global_object(); let global = vm.realm.session.global_object();
let si = vm.kernel_core.perm_interner().intern(name).0; let si = vm.kernel_core.perm_interner().intern(name).0;
vm.kernel_core vm.kernel_core
.shape_forge() .shape_forge()
@@ -68,17 +68,17 @@ fn full_reset_with_session_objects_forces_global_rebuild() {
unsafe { (&*written.as_js_object_ptr()).is_session_epoch() }, unsafe { (&*written.as_js_object_ptr()).is_session_epoch() },
"覆盖值应为 session 对象(统一入口 Box 化)" "覆盖值应为 session 对象(统一入口 Box 化)"
); );
let old_global = vm.session.global_object.as_ptr(); let old_global = vm.realm.session.global_object.as_ptr();
vm.full_reset(); vm.full_reset();
// global 必须重建:旧 global 与其 session 子引用随 session 释放,Array 恢复内置构造器。 // global 必须重建:旧 global 与其 session 子引用随 session 释放,Array 恢复内置构造器。
assert!(!std::ptr::eq(old_global, vm.session.global_object.as_ptr())); assert!(!std::ptr::eq(old_global, vm.realm.session.global_object.as_ptr()));
assert!(std::ptr::eq( assert!(std::ptr::eq(
global_prop(&vm, "Array").as_js_object_ptr(), global_prop(&vm, "Array").as_js_object_ptr(),
vm.session.builtin_world().array_constructor.as_ptr() as *mut JsObject vm.realm.session.builtin_world().array_constructor.as_ptr() as *mut JsObject
)); ));
assert!(!vm.session.is_dirty_since_snapshot()); assert!(!vm.realm.session.is_dirty_since_snapshot());
} }
/// P 原型上方法槽的 wrapper 对象原始指针(rebuild 跨轮复用验证用)。 /// P 原型上方法槽的 wrapper 对象原始指针(rebuild 跨轮复用验证用)。
@@ -98,7 +98,7 @@ fn method_wrapper_ptr(vm: &Vm, proto_ptr: *const JsObject, name: &str) -> *const
/// global 属性槽数(槽位原位更新跨轮不追加验证用)。 /// global 属性槽数(槽位原位更新跨轮不追加验证用)。
fn global_slot_count(vm: &Vm) -> usize { fn global_slot_count(vm: &Vm) -> usize {
let g = vm.session.global_object.as_ptr() as *mut JsObject; let g = vm.realm.session.global_object.as_ptr() as *mut JsObject;
// SAFETY: global 是本 session 对象,安全点内无并发读者。 // SAFETY: global 是本 session 对象,安全点内无并发读者。
unsafe { (*g).prop_vec_len() } unsafe { (*g).prop_vec_len() }
} }
@@ -110,9 +110,9 @@ fn global_slot_count(vm: &Vm) -> usize {
fn full_reset_rebuild_reuses_method_wrappers_across_rounds() { fn full_reset_rebuild_reuses_method_wrappers_across_rounds() {
let mut vm = Vm::new(); let mut vm = Vm::new();
let _ = run_source(&mut vm, "0"); let _ = run_source(&mut vm, "0");
let push_before = method_wrapper_ptr(&vm, vm.session.builtin_world().array_proto.as_ptr(), "push"); let push_before = method_wrapper_ptr(&vm, vm.realm.session.builtin_world().array_proto.as_ptr(), "push");
let push_shape_before = unsafe { &*push_before }.shape_id(); let push_shape_before = unsafe { &*push_before }.shape_id();
let registry_before = vm.session.builtin_world().leaked_object_count(); let registry_before = vm.realm.session.builtin_world().leaked_object_count();
let slots_before = global_slot_count(&vm); let slots_before = global_slot_count(&vm);
for i in 0..3u32 { for i in 0..3u32 {
@@ -126,10 +126,10 @@ fn full_reset_rebuild_reuses_method_wrappers_across_rounds() {
vm.full_reset(); vm.full_reset();
} }
let push_after = method_wrapper_ptr(&vm, vm.session.builtin_world().array_proto.as_ptr(), "push"); let push_after = method_wrapper_ptr(&vm, vm.realm.session.builtin_world().array_proto.as_ptr(), "push");
assert!(std::ptr::eq(push_before, push_after), "存活方法 wrapper 应复用(同 raw 指针)"); assert!(std::ptr::eq(push_before, push_after), "存活方法 wrapper 应复用(同 raw 指针)");
assert_eq!(push_shape_before, unsafe { &*push_after }.shape_id(), "wrapper shape 应稳定"); assert_eq!(push_shape_before, unsafe { &*push_after }.shape_id(), "wrapper shape 应稳定");
let registry_after = vm.session.builtin_world().leaked_object_count(); let registry_after = vm.realm.session.builtin_world().leaked_object_count();
assert!( assert!(
registry_after <= registry_before, registry_after <= registry_before,
"释放表计数跨轮不应增长: {registry_before} -> {registry_after}" "释放表计数跨轮不应增长: {registry_before} -> {registry_after}"
@@ -161,7 +161,7 @@ fn full_reset_rebuild_keeps_global_slot_count_flat() {
// Error 槽应指向本轮重建的构造器(非滞留旧指针)。 // Error 槽应指向本轮重建的构造器(非滞留旧指针)。
assert!(std::ptr::eq( assert!(std::ptr::eq(
global_prop(&vm, "Error").as_js_object_ptr(), global_prop(&vm, "Error").as_js_object_ptr(),
vm.session.builtin_world().error_constructor.as_ptr() as *mut JsObject vm.realm.session.builtin_world().error_constructor.as_ptr() as *mut JsObject
)); ));
assert!(global_prop(&vm, "TypeError").is_object()); assert!(global_prop(&vm, "TypeError").is_object());
assert_eq!(run_source(&mut vm, "new TypeError('x') instanceof TypeError"), JsValue::bool(true)); assert_eq!(run_source(&mut vm, "new TypeError('x') instanceof TypeError"), JsValue::bool(true));
@@ -279,74 +279,74 @@ fn generator_captured_upvalue_survives_sweep() {
#[test] #[test]
fn full_reset_clean_keeps_session_objects() { fn full_reset_clean_keeps_session_objects() {
let mut vm = Vm::new(); let mut vm = Vm::new();
let world_ptr = Arc::as_ptr(&vm.session.builtin_world); let world_ptr = Arc::as_ptr(&vm.realm.session.builtin_world);
let global_ptr = vm.session.global_object.as_ptr(); let global_ptr = vm.realm.session.global_object.as_ptr();
let object_proto_ptr = vm.session.builtin_world().object_proto.as_ptr(); let object_proto_ptr = vm.realm.session.builtin_world().object_proto.as_ptr();
vm.full_reset(); vm.full_reset();
assert!(std::ptr::eq(world_ptr, Arc::as_ptr(&vm.session.builtin_world))); assert!(std::ptr::eq(world_ptr, Arc::as_ptr(&vm.realm.session.builtin_world)));
assert!(std::ptr::eq(global_ptr, vm.session.global_object.as_ptr())); assert!(std::ptr::eq(global_ptr, vm.realm.session.global_object.as_ptr()));
assert!(std::ptr::eq(object_proto_ptr, vm.session.builtin_world().object_proto.as_ptr())); assert!(std::ptr::eq(object_proto_ptr, vm.realm.session.builtin_world().object_proto.as_ptr()));
assert!(!vm.session.is_dirty_since_snapshot()); assert!(!vm.realm.session.is_dirty_since_snapshot());
} }
#[test] #[test]
fn full_reset_global_dirty_rebuilds_global_and_restores_slots() { fn full_reset_global_dirty_rebuilds_global_and_restores_slots() {
let mut vm = Vm::new(); let mut vm = Vm::new();
let world_ptr = Arc::as_ptr(&vm.session.builtin_world); let world_ptr = Arc::as_ptr(&vm.realm.session.builtin_world);
let global_ptr = vm.session.global_object.as_ptr(); let global_ptr = vm.realm.session.global_object.as_ptr();
let global = unsafe { &mut *(vm.session.global_object.as_ptr() as *mut JsObject) }; let global = unsafe { &mut *(vm.realm.session.global_object.as_ptr() as *mut JsObject) };
bindings::bind_global_value(&vm.kernel_core, global, "userGlobal", JsValue::int(99)); bindings::bind_global_value(&vm.kernel_core, global, "userGlobal", JsValue::int(99));
unsafe { &mut *(vm.session.global_object.as_ptr() as *mut JsObject) }.bump_generation(); unsafe { &mut *(vm.realm.session.global_object.as_ptr() as *mut JsObject) }.bump_generation();
vm.full_reset(); vm.full_reset();
assert!(std::ptr::eq(world_ptr, Arc::as_ptr(&vm.session.builtin_world))); assert!(std::ptr::eq(world_ptr, Arc::as_ptr(&vm.realm.session.builtin_world)));
assert!(!std::ptr::eq(global_ptr, vm.session.global_object.as_ptr())); assert!(!std::ptr::eq(global_ptr, vm.realm.session.global_object.as_ptr()));
assert!(global_prop_opt(&vm, "userGlobal").is_none()); assert!(global_prop_opt(&vm, "userGlobal").is_none());
assert!(std::ptr::eq( assert!(std::ptr::eq(
global_prop(&vm, "Array").as_js_object_ptr(), global_prop(&vm, "Array").as_js_object_ptr(),
vm.session.builtin_world().array_constructor.as_ptr() as *mut JsObject vm.realm.session.builtin_world().array_constructor.as_ptr() as *mut JsObject
)); ));
assert!(std::ptr::eq( assert!(std::ptr::eq(
global_prop(&vm, "globalThis").as_js_object_ptr(), global_prop(&vm, "globalThis").as_js_object_ptr(),
vm.session.global_object.as_ptr() as *mut JsObject vm.realm.session.global_object.as_ptr() as *mut JsObject
)); ));
assert!(!vm.session.is_dirty_since_snapshot()); assert!(!vm.realm.session.is_dirty_since_snapshot());
} }
#[test] #[test]
fn full_reset_dirty_builtin_rebinds_global_slot() { fn full_reset_dirty_builtin_rebinds_global_slot() {
let mut vm = Vm::new(); let mut vm = Vm::new();
let old_object_proto = vm.session.builtin_world().object_proto.as_ptr(); let old_object_proto = vm.realm.session.builtin_world().object_proto.as_ptr();
let old_array_proto = vm.session.builtin_world().array_proto.as_ptr(); let old_array_proto = vm.realm.session.builtin_world().array_proto.as_ptr();
unsafe { &mut *(old_array_proto as *mut JsObject) }.bump_generation(); unsafe { &mut *(old_array_proto as *mut JsObject) }.bump_generation();
vm.full_reset(); vm.full_reset();
assert!(std::ptr::eq(old_object_proto, vm.session.builtin_world().object_proto.as_ptr())); assert!(std::ptr::eq(old_object_proto, vm.realm.session.builtin_world().object_proto.as_ptr()));
assert!(!std::ptr::eq(old_array_proto, vm.session.builtin_world().array_proto.as_ptr())); assert!(!std::ptr::eq(old_array_proto, vm.realm.session.builtin_world().array_proto.as_ptr()));
assert!(std::ptr::eq( assert!(std::ptr::eq(
global_prop(&vm, "Array").as_js_object_ptr(), global_prop(&vm, "Array").as_js_object_ptr(),
vm.session.builtin_world().array_constructor.as_ptr() as *mut JsObject vm.realm.session.builtin_world().array_constructor.as_ptr() as *mut JsObject
)); ));
let constructor_si = vm.kernel_core.perm_interner().intern("constructor").0; let constructor_si = vm.kernel_core.perm_interner().intern("constructor").0;
let array_proto = &*vm.session.builtin_world().array_proto; let array_proto = &*vm.realm.session.builtin_world().array_proto;
let constructor = vm let constructor = vm
.resolve_property(array_proto, constructor_si) .resolve_property(array_proto, constructor_si)
.expect("Array.prototype.constructor"); .expect("Array.prototype.constructor");
assert!(std::ptr::eq( assert!(std::ptr::eq(
constructor.as_js_object_ptr(), constructor.as_js_object_ptr(),
vm.session.builtin_world().array_constructor.as_ptr() as *mut JsObject vm.realm.session.builtin_world().array_constructor.as_ptr() as *mut JsObject
)); ));
assert!(!vm.session.is_dirty_since_snapshot()); assert!(!vm.realm.session.is_dirty_since_snapshot());
} }
#[test] #[test]
fn full_reset_dirty_function_keeps_call_working() { fn full_reset_dirty_function_keeps_call_working() {
let mut vm = Vm::new(); let mut vm = Vm::new();
let function_proto = vm.session.builtin_world().function_proto.as_ptr(); let function_proto = vm.realm.session.builtin_world().function_proto.as_ptr();
unsafe { &mut *(function_proto as *mut JsObject) }.bump_generation(); unsafe { &mut *(function_proto as *mut JsObject) }.bump_generation();
vm.full_reset(); vm.full_reset();
@@ -366,7 +366,7 @@ fn full_reset_dirty_function_keeps_call_working() {
assert_eq!(in_map, JsValue::bool(true)); assert_eq!(in_map, JsValue::bool(true));
let mapped = run_source(&mut vm, "Array.prototype.map.call([1, 2], function(x){ return x + 1; }).join(',')"); let mapped = run_source(&mut vm, "Array.prototype.map.call([1, 2], function(x){ return x + 1; }).join(',')");
assert_eq!(vm.lookup_str(mapped).as_deref(), Some("2,3")); assert_eq!(vm.lookup_str(mapped).as_deref(), Some("2,3"));
assert!(!vm.session.is_dirty_since_snapshot()); assert!(!vm.realm.session.is_dirty_since_snapshot());
} }
/// Function 家族脏重建:未重建家族的方法 wrapper 是跨重置存活对象,其 proto /// Function 家族脏重建:未重建家族的方法 wrapper 是跨重置存活对象,其 proto
@@ -374,9 +374,9 @@ fn full_reset_dirty_function_keeps_call_working() {
#[test] #[test]
fn full_reset_dirty_function_repoints_retained_wrapper_proto() { fn full_reset_dirty_function_repoints_retained_wrapper_proto() {
let mut vm = Vm::new(); let mut vm = Vm::new();
let old_fn_proto = vm.session.builtin_world().function_proto.as_ptr() as *mut JsObject; let old_fn_proto = vm.realm.session.builtin_world().function_proto.as_ptr() as *mut JsObject;
// 保留方法 wrapper:array 家族不重建,wrapper 对象与其 proto 槽跨重置存活。 // 保留方法 wrapper:array 家族不重建,wrapper 对象与其 proto 槽跨重置存活。
let array_proto = vm.session.builtin_world().array_proto.as_ptr() as *mut JsObject; let array_proto = vm.realm.session.builtin_world().array_proto.as_ptr() as *mut JsObject;
let push_si = vm.kernel_core.perm_interner().intern("push").0; let push_si = vm.kernel_core.perm_interner().intern("push").0;
let push = vm let push = vm
.resolve_property(unsafe { &*array_proto }, push_si) .resolve_property(unsafe { &*array_proto }, push_si)
@@ -388,12 +388,12 @@ fn full_reset_dirty_function_repoints_retained_wrapper_proto() {
vm.full_reset(); vm.full_reset();
let new_fn_proto = vm.session.builtin_world().function_proto.as_ptr() as *mut JsObject; let new_fn_proto = vm.realm.session.builtin_world().function_proto.as_ptr() as *mut JsObject;
assert!(!std::ptr::eq(new_fn_proto, old_fn_proto)); assert!(!std::ptr::eq(new_fn_proto, old_fn_proto));
// 保留 wrapper proto 槽已重指新 fn_proto,call 链走新原型。 // 保留 wrapper proto 槽已重指新 fn_proto,call 链走新原型。
assert!(std::ptr::eq(unsafe { (*push_ptr).proto().as_js_object_ptr() }, new_fn_proto)); assert!(std::ptr::eq(unsafe { (*push_ptr).proto().as_js_object_ptr() }, new_fn_proto));
assert_eq!(run_source(&mut vm, "Array.prototype.push.call([1], 2)"), JsValue::int(2)); assert_eq!(run_source(&mut vm, "Array.prototype.push.call([1], 2)"), JsValue::int(2));
assert!(!vm.session.is_dirty_since_snapshot()); assert!(!vm.realm.session.is_dirty_since_snapshot());
} }
/// 新键写脏 object/array/string/function 四家族(S2 脏源形态):full_reset 后 /// 新键写脏 object/array/string/function 四家族(S2 脏源形态):full_reset 后
@@ -406,7 +406,7 @@ fn full_reset_dirty_four_families_cross_family_reads() {
&mut vm, &mut vm,
"Object.prototype['d'] = 1; Array.prototype['d'] = 2; String.prototype['d'] = 3; Function.prototype['d'] = 4;", "Object.prototype['d'] = 1; Array.prototype['d'] = 2; String.prototype['d'] = 3; Function.prototype['d'] = 4;",
); );
assert!(vm.session.is_dirty_since_snapshot()); assert!(vm.realm.session.is_dirty_since_snapshot());
vm.full_reset(); vm.full_reset();
@@ -420,7 +420,7 @@ fn full_reset_dirty_four_families_cross_family_reads() {
JsValue::bool(true) JsValue::bool(true)
); );
assert_eq!(run_source(&mut vm, "Array.prototype.constructor === Array"), JsValue::bool(true)); assert_eq!(run_source(&mut vm, "Array.prototype.constructor === Array"), JsValue::bool(true));
assert!(!vm.session.is_dirty_since_snapshot()); assert!(!vm.realm.session.is_dirty_since_snapshot());
} }
/// 未捕获异常侧通道是执行期状态:原生错误后可能残留原值,reset/full_reset /// 未捕获异常侧通道是执行期状态:原生错误后可能残留原值,reset/full_reset
@@ -592,32 +592,32 @@ fn dynamic_function_rethrows_to_string_exception() {
#[test] #[test]
fn full_reset_refreshes_object_prototype_after_object_dirty() { fn full_reset_refreshes_object_prototype_after_object_dirty() {
let mut vm = Vm::new(); let mut vm = Vm::new();
let old_object_proto = vm.session.builtin_world().object_proto.as_ptr(); let old_object_proto = vm.realm.session.builtin_world().object_proto.as_ptr();
unsafe { &mut *(old_object_proto as *mut JsObject) }.bump_generation(); unsafe { &mut *(old_object_proto as *mut JsObject) }.bump_generation();
vm.full_reset(); vm.full_reset();
assert!(!std::ptr::eq(old_object_proto, vm.session.builtin_world().object_proto.as_ptr())); assert!(!std::ptr::eq(old_object_proto, vm.realm.session.builtin_world().object_proto.as_ptr()));
assert!(std::ptr::eq( assert!(std::ptr::eq(
vm.object_prototype.as_ptr(), vm.realm.object_prototype.as_ptr(),
vm.session.builtin_world().object_proto.as_ptr() vm.realm.session.builtin_world().object_proto.as_ptr()
)); ));
assert!(!vm.session.is_dirty_since_snapshot()); assert!(!vm.realm.session.is_dirty_since_snapshot());
} }
#[test] #[test]
fn full_reset_object_dirty_rebinds_iterator_family() { fn full_reset_object_dirty_rebinds_iterator_family() {
let mut vm = Vm::new(); let mut vm = Vm::new();
let old_object_proto = vm.session.builtin_world().object_proto.as_ptr(); let old_object_proto = vm.realm.session.builtin_world().object_proto.as_ptr();
let old_iterator_proto = vm.session.builtin_world().iterator_proto.as_ptr(); let old_iterator_proto = vm.realm.session.builtin_world().iterator_proto.as_ptr();
// 用户修改 Object.prototype:object 家族世代递增,global 未动。 // 用户修改 Object.prototype:object 家族世代递增,global 未动。
unsafe { &mut *(old_object_proto as *mut JsObject) }.bump_generation(); unsafe { &mut *(old_object_proto as *mut JsObject) }.bump_generation();
vm.full_reset(); vm.full_reset();
// object 家族与迭代器原型全部重建(新原型链到新 Object.prototype)。 // object 家族与迭代器原型全部重建(新原型链到新 Object.prototype)。
assert!(!std::ptr::eq(old_object_proto, vm.session.builtin_world().object_proto.as_ptr())); assert!(!std::ptr::eq(old_object_proto, vm.realm.session.builtin_world().object_proto.as_ptr()));
assert!(!std::ptr::eq(old_iterator_proto, vm.session.builtin_world().iterator_proto.as_ptr())); assert!(!std::ptr::eq(old_iterator_proto, vm.realm.session.builtin_world().iterator_proto.as_ptr()));
// global 保留(dirty.global=false):其 Iterator 函数对象的 prototype // global 保留(dirty.global=false):其 Iterator 函数对象的 prototype
// 属性须对齐到重建后的 %IteratorPrototype%。 // 属性须对齐到重建后的 %IteratorPrototype%。
let iter_val = global_prop(&vm, "Iterator"); let iter_val = global_prop(&vm, "Iterator");
@@ -630,10 +630,10 @@ fn full_reset_object_dirty_rebinds_iterator_family() {
.expect("Iterator should have prototype slot"); .expect("Iterator should have prototype slot");
assert!(std::ptr::eq( assert!(std::ptr::eq(
iter_obj.get_prop_at(proto_pos).as_js_object_ptr(), iter_obj.get_prop_at(proto_pos).as_js_object_ptr(),
vm.session.builtin_world().iterator_proto.as_ptr() as *mut JsObject vm.realm.session.builtin_world().iterator_proto.as_ptr() as *mut JsObject
)); ));
// full_reset 后 session 干净;此后 run_source 执行才重新累积世代变化。 // full_reset 后 session 干净;此后 run_source 执行才重新累积世代变化。
assert!(!vm.session.is_dirty_since_snapshot()); assert!(!vm.realm.session.is_dirty_since_snapshot());
// 迭代器家族功能完整:原型 next 就位,for-of/spread/Array.from/Iterator.from/ // 迭代器家族功能完整:原型 next 就位,for-of/spread/Array.from/Iterator.from/
// Map/Set/String/yield* 全部可用,原型链与 Iterator.prototype 一致。 // Map/Set/String/yield* 全部可用,原型链与 Iterator.prototype 一致。
let r = run_source(&mut vm, "[...[1,2,3]].join(',')"); let r = run_source(&mut vm, "[...[1,2,3]].join(',')");
@@ -662,19 +662,19 @@ fn full_reset_object_dirty_rebinds_iterator_family() {
#[test] #[test]
fn full_reset_global_dirty_keeps_iterator_proto_slots_stable() { fn full_reset_global_dirty_keeps_iterator_proto_slots_stable() {
let mut vm = Vm::new(); let mut vm = Vm::new();
let arr_iter_proto = vm.session.builtin_world().array_iterator_proto.as_ptr() as *mut JsObject; let arr_iter_proto = vm.realm.session.builtin_world().array_iterator_proto.as_ptr() as *mut JsObject;
let slots_before = unsafe { &*arr_iter_proto }.hash_props_vec().map_or(0, |v| v.len()); let slots_before = unsafe { &*arr_iter_proto }.hash_props_vec().map_or(0, |v| v.len());
// global 世代递增(用户写 global),builtin 家族未动。 // global 世代递增(用户写 global),builtin 家族未动。
unsafe { &mut *(vm.session.global_object.as_ptr() as *mut JsObject) }.bump_generation(); unsafe { &mut *(vm.realm.session.global_object.as_ptr() as *mut JsObject) }.bump_generation();
vm.full_reset(); vm.full_reset();
// builtin 未脏 → 迭代器原型保留原对象且属性槽不膨胀(重复 full_reset 不再追加)。 // builtin 未脏 → 迭代器原型保留原对象且属性槽不膨胀(重复 full_reset 不再追加)。
let arr_iter_proto_after = vm.session.builtin_world().array_iterator_proto.as_ptr() as *mut JsObject; let arr_iter_proto_after = vm.realm.session.builtin_world().array_iterator_proto.as_ptr() as *mut JsObject;
assert!(std::ptr::eq(arr_iter_proto, arr_iter_proto_after)); assert!(std::ptr::eq(arr_iter_proto, arr_iter_proto_after));
let slots_after = unsafe { &*arr_iter_proto_after }.hash_props_vec().map_or(0, |v| v.len()); let slots_after = unsafe { &*arr_iter_proto_after }.hash_props_vec().map_or(0, |v| v.len());
assert_eq!(slots_before, slots_after); assert_eq!(slots_before, slots_after);
assert!(!vm.session.is_dirty_since_snapshot()); assert!(!vm.realm.session.is_dirty_since_snapshot());
// 迭代器功能经保留原型仍完整(run_source 起再次累积世代变化)。 // 迭代器功能经保留原型仍完整(run_source 起再次累积世代变化)。
let r = run_source(&mut vm, "[...[1,2,3]].join(',')"); let r = run_source(&mut vm, "[...[1,2,3]].join(',')");
assert_eq!(vm.lookup_str(r).as_deref(), Some("1,2,3")); assert_eq!(vm.lookup_str(r).as_deref(), Some("1,2,3"));
@@ -862,19 +862,19 @@ fn inline_for_in_escape_restores_snapshot_and_releases_residual_body() {
fn full_reset_value_overwrite_on_builtin_proto_rebuilds_family() { fn full_reset_value_overwrite_on_builtin_proto_rebuilds_family() {
let mut vm = Vm::new(); let mut vm = Vm::new();
let _ = run_source(&mut vm, "0"); let _ = run_source(&mut vm, "0");
let old_array_proto = vm.session.builtin_world().array_proto.as_ptr(); let old_array_proto = vm.realm.session.builtin_world().array_proto.as_ptr();
assert_eq!(run_source(&mut vm, "Array.prototype.push = 9"), JsValue::int(9)); assert_eq!(run_source(&mut vm, "Array.prototype.push = 9"), JsValue::int(9));
assert_eq!(run_source(&mut vm, "Array.prototype.push"), JsValue::int(9)); assert_eq!(run_source(&mut vm, "Array.prototype.push"), JsValue::int(9));
assert!(vm.session.is_dirty_since_snapshot(), "值覆盖应推进世代被脏检测捕获"); assert!(vm.realm.session.is_dirty_since_snapshot(), "值覆盖应推进世代被脏检测捕获");
vm.full_reset(); vm.full_reset();
assert!(!std::ptr::eq(old_array_proto, vm.session.builtin_world().array_proto.as_ptr())); assert!(!std::ptr::eq(old_array_proto, vm.realm.session.builtin_world().array_proto.as_ptr()));
let t = run_source(&mut vm, "typeof Array.prototype.push"); let t = run_source(&mut vm, "typeof Array.prototype.push");
assert_eq!(vm.lookup_str(t).as_deref(), Some("function")); assert_eq!(vm.lookup_str(t).as_deref(), Some("function"));
assert_eq!(run_source(&mut vm, "[1, 2].push(3)"), JsValue::int(3)); assert_eq!(run_source(&mut vm, "[1, 2].push(3)"), JsValue::int(3));
assert!(!vm.session.is_dirty_since_snapshot()); assert!(!vm.realm.session.is_dirty_since_snapshot());
} }
/// 对象值形态的既有槽覆盖同样须被发现:epoch 对象写入 builtin P 对象不被晋升, /// 对象值形态的既有槽覆盖同样须被发现:epoch 对象写入 builtin P 对象不被晋升,
@@ -883,17 +883,17 @@ fn full_reset_value_overwrite_on_builtin_proto_rebuilds_family() {
fn full_reset_value_overwrite_with_object_value_drops_stale_pointer() { fn full_reset_value_overwrite_with_object_value_drops_stale_pointer() {
let mut vm = Vm::new(); let mut vm = Vm::new();
let _ = run_source(&mut vm, "0"); let _ = run_source(&mut vm, "0");
let old_array_proto = vm.session.builtin_world().array_proto.as_ptr(); let old_array_proto = vm.realm.session.builtin_world().array_proto.as_ptr();
let _ = run_source(&mut vm, "Array.prototype.push = {}; 0"); let _ = run_source(&mut vm, "Array.prototype.push = {}; 0");
assert!(vm.session.is_dirty_since_snapshot(), "对象值覆盖应被脏检测捕获"); assert!(vm.realm.session.is_dirty_since_snapshot(), "对象值覆盖应被脏检测捕获");
vm.full_reset(); vm.full_reset();
assert!(!std::ptr::eq(old_array_proto, vm.session.builtin_world().array_proto.as_ptr())); assert!(!std::ptr::eq(old_array_proto, vm.realm.session.builtin_world().array_proto.as_ptr()));
let t = run_source(&mut vm, "typeof Array.prototype.push"); let t = run_source(&mut vm, "typeof Array.prototype.push");
assert_eq!(vm.lookup_str(t).as_deref(), Some("function")); assert_eq!(vm.lookup_str(t).as_deref(), Some("function"));
assert!(!vm.session.is_dirty_since_snapshot()); assert!(!vm.realm.session.is_dirty_since_snapshot());
} }
/// 零 session 对象的全局内置值覆盖:`globalThis.Array = 9` 不触发 promote, /// 零 session 对象的全局内置值覆盖:`globalThis.Array = 9` 不触发 promote,
@@ -905,17 +905,17 @@ fn full_reset_global_builtin_value_overwrite_restores_constructor() {
let _ = run_source(&mut vm, "0"); let _ = run_source(&mut vm, "0");
let _ = run_source(&mut vm, "globalThis.Array = 9; 0"); let _ = run_source(&mut vm, "globalThis.Array = 9; 0");
assert!(vm.gc_state.session_object_ptrs.is_empty(), "原始值覆盖不产生 session 对象"); assert!(vm.realm.gc.session_object_ptrs.is_empty(), "原始值覆盖不产生 session 对象");
assert!(vm.session.is_dirty_since_snapshot(), "全局值覆盖应推进世代"); assert!(vm.realm.session.is_dirty_since_snapshot(), "全局值覆盖应推进世代");
vm.full_reset(); vm.full_reset();
assert!(std::ptr::eq( assert!(std::ptr::eq(
global_prop(&vm, "Array").as_js_object_ptr(), global_prop(&vm, "Array").as_js_object_ptr(),
vm.session.builtin_world().array_constructor.as_ptr() as *mut JsObject vm.realm.session.builtin_world().array_constructor.as_ptr() as *mut JsObject
)); ));
assert_eq!(run_source(&mut vm, "[1].push(2)"), JsValue::int(2)); assert_eq!(run_source(&mut vm, "[1].push(2)"), JsValue::int(2));
assert!(!vm.session.is_dirty_since_snapshot()); assert!(!vm.realm.session.is_dirty_since_snapshot());
} }
/// IC 二次写(miss 落既有槽 + 命中直写)与复合赋值(set_member_prop 既有槽) /// IC 二次写(miss 落既有槽 + 命中直写)与复合赋值(set_member_prop 既有槽)
@@ -927,19 +927,19 @@ fn full_reset_value_overwrite_via_ic_and_compound_marks_dirty() {
// IC 首写 miss 落既有槽、二次写经缓存命中,两次都须 bump。 // IC 首写 miss 落既有槽、二次写经缓存命中,两次都须 bump。
let _ = run_source(&mut vm, "Array.prototype.push = 9; Array.prototype.push = 8; 0"); let _ = run_source(&mut vm, "Array.prototype.push = 9; Array.prototype.push = 8; 0");
assert!(vm.session.is_dirty_since_snapshot(), "IC 二次写应被脏检测捕获"); assert!(vm.realm.session.is_dirty_since_snapshot(), "IC 二次写应被脏检测捕获");
vm.full_reset(); vm.full_reset();
let t = run_source(&mut vm, "typeof Array.prototype.push"); let t = run_source(&mut vm, "typeof Array.prototype.push");
assert_eq!(vm.lookup_str(t).as_deref(), Some("function")); assert_eq!(vm.lookup_str(t).as_deref(), Some("function"));
// 复合赋值读改写走 set_member_prop 既有槽路径,同样须 bump。 // 复合赋值读改写走 set_member_prop 既有槽路径,同样须 bump。
let _ = run_source(&mut vm, "Array.prototype.push = 9; Array.prototype.push += 1; 0"); let _ = run_source(&mut vm, "Array.prototype.push = 9; Array.prototype.push += 1; 0");
assert!(vm.session.is_dirty_since_snapshot(), "复合赋值应被脏检测捕获"); assert!(vm.realm.session.is_dirty_since_snapshot(), "复合赋值应被脏检测捕获");
vm.full_reset(); vm.full_reset();
let t = run_source(&mut vm, "typeof Array.prototype.push"); let t = run_source(&mut vm, "typeof Array.prototype.push");
assert_eq!(vm.lookup_str(t).as_deref(), Some("function")); assert_eq!(vm.lookup_str(t).as_deref(), Some("function"));
assert_eq!(run_source(&mut vm, "[1, 2, 3].push(4)"), JsValue::int(4)); assert_eq!(run_source(&mut vm, "[1, 2, 3].push(4)"), JsValue::int(4));
assert!(!vm.session.is_dirty_since_snapshot()); assert!(!vm.realm.session.is_dirty_since_snapshot());
} }
/// wrapper 本体新增 own 属性:写入的是方法 wrapper 自身而非所属 P 对象, /// wrapper 本体新增 own 属性:写入的是方法 wrapper 自身而非所属 P 对象,
@@ -949,20 +949,20 @@ fn full_reset_value_overwrite_via_ic_and_compound_marks_dirty() {
fn full_reset_wrapper_own_property_does_not_survive() { fn full_reset_wrapper_own_property_does_not_survive() {
let mut vm = Vm::new(); let mut vm = Vm::new();
let _ = run_source(&mut vm, "0"); let _ = run_source(&mut vm, "0");
let push_before = method_wrapper_ptr(&vm, vm.session.builtin_world().array_proto.as_ptr(), "push"); let push_before = method_wrapper_ptr(&vm, vm.realm.session.builtin_world().array_proto.as_ptr(), "push");
let _ = run_source(&mut vm, "Array.prototype.push.custom = 1; 0"); let _ = run_source(&mut vm, "Array.prototype.push.custom = 1; 0");
assert!(vm.session.is_dirty_since_snapshot(), "wrapper 本体写应被脏检测捕获"); assert!(vm.realm.session.is_dirty_since_snapshot(), "wrapper 本体写应被脏检测捕获");
vm.full_reset(); vm.full_reset();
assert_eq!(run_source(&mut vm, "Array.prototype.push.custom"), JsValue::undefined()); assert_eq!(run_source(&mut vm, "Array.prototype.push.custom"), JsValue::undefined());
assert_eq!(run_source(&mut vm, "'custom' in Array.prototype.push"), JsValue::bool(false)); assert_eq!(run_source(&mut vm, "'custom' in Array.prototype.push"), JsValue::bool(false));
assert_eq!(run_source(&mut vm, "typeof Array.prototype.push === 'function'"), JsValue::bool(true)); assert_eq!(run_source(&mut vm, "typeof Array.prototype.push === 'function'"), JsValue::bool(true));
let push_after = method_wrapper_ptr(&vm, vm.session.builtin_world().array_proto.as_ptr(), "push"); let push_after = method_wrapper_ptr(&vm, vm.realm.session.builtin_world().array_proto.as_ptr(), "push");
assert!(!std::ptr::eq(push_before, push_after), "被写的 wrapper 不应被复用"); assert!(!std::ptr::eq(push_before, push_after), "被写的 wrapper 不应被复用");
assert_eq!(run_source(&mut vm, "[1, 2].push(3)"), JsValue::int(3)); assert_eq!(run_source(&mut vm, "[1, 2].push(3)"), JsValue::int(3));
assert!(!vm.session.is_dirty_since_snapshot()); assert!(!vm.realm.session.is_dirty_since_snapshot());
} }
/// wrapper 本体写 epoch 对象值:epoch 对象不晋升、不登记,若 wrapper 跨轮 /// wrapper 本体写 epoch 对象值:epoch 对象不晋升、不登记,若 wrapper 跨轮
@@ -973,13 +973,13 @@ fn full_reset_wrapper_object_property_does_not_dangle() {
let _ = run_source(&mut vm, "0"); let _ = run_source(&mut vm, "0");
let _ = run_source(&mut vm, "Array.prototype.push.custom = {}; 0"); let _ = run_source(&mut vm, "Array.prototype.push.custom = {}; 0");
assert!(vm.session.is_dirty_since_snapshot(), "wrapper 对象值写应被脏检测捕获"); assert!(vm.realm.session.is_dirty_since_snapshot(), "wrapper 对象值写应被脏检测捕获");
vm.full_reset(); vm.full_reset();
assert_eq!(run_source(&mut vm, "Array.prototype.push.custom"), JsValue::undefined()); assert_eq!(run_source(&mut vm, "Array.prototype.push.custom"), JsValue::undefined());
assert_eq!(run_source(&mut vm, "[1, 2].push(3)"), JsValue::int(3)); assert_eq!(run_source(&mut vm, "[1, 2].push(3)"), JsValue::int(3));
assert!(!vm.session.is_dirty_since_snapshot()); assert!(!vm.realm.session.is_dirty_since_snapshot());
} }
/// wrapper 既有 own 槽的值覆盖:首次写已建槽后重录快照,第二次写走 /// wrapper 既有 own 槽的值覆盖:首次写已建槽后重录快照,第二次写走
@@ -989,16 +989,16 @@ fn full_reset_wrapper_existing_slot_overwrite_marks_dirty() {
let mut vm = Vm::new(); let mut vm = Vm::new();
let _ = run_source(&mut vm, "0"); let _ = run_source(&mut vm, "0");
let _ = run_source(&mut vm, "Array.prototype.push.custom = 1; 0"); let _ = run_source(&mut vm, "Array.prototype.push.custom = 1; 0");
vm.session.record_snapshot(); vm.realm.session.record_snapshot();
let _ = run_source(&mut vm, "Array.prototype.push.custom = 2; 0"); let _ = run_source(&mut vm, "Array.prototype.push.custom = 2; 0");
assert!(vm.session.is_dirty_since_snapshot(), "wrapper 既有槽覆盖应被脏检测捕获"); assert!(vm.realm.session.is_dirty_since_snapshot(), "wrapper 既有槽覆盖应被脏检测捕获");
vm.full_reset(); vm.full_reset();
assert_eq!(run_source(&mut vm, "Array.prototype.push.custom"), JsValue::undefined()); assert_eq!(run_source(&mut vm, "Array.prototype.push.custom"), JsValue::undefined());
assert_eq!(run_source(&mut vm, "typeof Array.prototype.push === 'function'"), JsValue::bool(true)); assert_eq!(run_source(&mut vm, "typeof Array.prototype.push === 'function'"), JsValue::bool(true));
assert!(!vm.session.is_dirty_since_snapshot()); assert!(!vm.realm.session.is_dirty_since_snapshot());
} }
/// 不可复用宿主对象(`Reflect`)的属性写:登记面无复用键,脏时靠 global /// 不可复用宿主对象(`Reflect`)的属性写:登记面无复用键,脏时靠 global
@@ -1009,13 +1009,13 @@ fn full_reset_keyless_leaked_object_property_does_not_survive() {
let _ = run_source(&mut vm, "0"); let _ = run_source(&mut vm, "0");
let _ = run_source(&mut vm, "Reflect.custom = 1; 0"); let _ = run_source(&mut vm, "Reflect.custom = 1; 0");
assert!(vm.session.is_dirty_since_snapshot(), "keyless 宿主对象写应被脏检测捕获"); assert!(vm.realm.session.is_dirty_since_snapshot(), "keyless 宿主对象写应被脏检测捕获");
vm.full_reset(); vm.full_reset();
assert_eq!(run_source(&mut vm, "'custom' in Reflect"), JsValue::bool(false)); assert_eq!(run_source(&mut vm, "'custom' in Reflect"), JsValue::bool(false));
assert_eq!(run_source(&mut vm, "typeof Reflect.apply === 'function'"), JsValue::bool(true)); assert_eq!(run_source(&mut vm, "typeof Reflect.apply === 'function'"), JsValue::bool(true));
assert!(!vm.session.is_dirty_since_snapshot()); assert!(!vm.realm.session.is_dirty_since_snapshot());
} }
/// global 函数 wrapper(`parseInt`)的属性写:global 函数 wrapper 无 P 家族 /// global 函数 wrapper(`parseInt`)的属性写:global 函数 wrapper 无 P 家族
@@ -1026,13 +1026,13 @@ fn full_reset_global_function_wrapper_property_does_not_survive() {
let _ = run_source(&mut vm, "0"); let _ = run_source(&mut vm, "0");
let _ = run_source(&mut vm, "parseInt.custom = 1; 0"); let _ = run_source(&mut vm, "parseInt.custom = 1; 0");
assert!(vm.session.is_dirty_since_snapshot(), "global 函数 wrapper 写应被脏检测捕获"); assert!(vm.realm.session.is_dirty_since_snapshot(), "global 函数 wrapper 写应被脏检测捕获");
vm.full_reset(); vm.full_reset();
assert_eq!(run_source(&mut vm, "'custom' in parseInt"), JsValue::bool(false)); assert_eq!(run_source(&mut vm, "'custom' in parseInt"), JsValue::bool(false));
assert_eq!(run_source(&mut vm, "parseInt('42')"), JsValue::int(42)); assert_eq!(run_source(&mut vm, "parseInt('42')"), JsValue::int(42));
assert!(!vm.session.is_dirty_since_snapshot()); assert!(!vm.realm.session.is_dirty_since_snapshot());
} }
/// wrapper 写重建后基线已刷新:后续仅 P 对象脏写的轮次复用新 wrapper、 /// wrapper 写重建后基线已刷新:后续仅 P 对象脏写的轮次复用新 wrapper、
@@ -1044,8 +1044,8 @@ fn wrapper_write_rebuild_then_p_writes_reuse_fresh_wrapper() {
let _ = run_source(&mut vm, "Array.prototype.push.custom = 1; 0"); let _ = run_source(&mut vm, "Array.prototype.push.custom = 1; 0");
vm.full_reset(); vm.full_reset();
let push_after = method_wrapper_ptr(&vm, vm.session.builtin_world().array_proto.as_ptr(), "push"); let push_after = method_wrapper_ptr(&vm, vm.realm.session.builtin_world().array_proto.as_ptr(), "push");
let registry_after = vm.session.builtin_world().leaked_object_count(); let registry_after = vm.realm.session.builtin_world().leaked_object_count();
for i in 0..3u32 { for i in 0..3u32 {
let source = format!("Array.prototype['w{i}'] = 1; Object.prototype['w{i}'] = 2; 0"); let source = format!("Array.prototype['w{i}'] = 1; Object.prototype['w{i}'] = 2; 0");
@@ -1053,15 +1053,15 @@ fn wrapper_write_rebuild_then_p_writes_reuse_fresh_wrapper() {
vm.full_reset(); vm.full_reset();
} }
let push_final = method_wrapper_ptr(&vm, vm.session.builtin_world().array_proto.as_ptr(), "push"); let push_final = method_wrapper_ptr(&vm, vm.realm.session.builtin_world().array_proto.as_ptr(), "push");
assert!(std::ptr::eq(push_after, push_final), "P 写轮应复用 wrapper,不应每轮失效重建"); assert!(std::ptr::eq(push_after, push_final), "P 写轮应复用 wrapper,不应每轮失效重建");
assert_eq!( assert_eq!(
vm.session.builtin_world().leaked_object_count(), vm.realm.session.builtin_world().leaked_object_count(),
registry_after, registry_after,
"P 写轮释放登记表不应增长" "P 写轮释放登记表不应增长"
); );
assert_eq!(run_source(&mut vm, "[1, 2].push(3)"), JsValue::int(3)); assert_eq!(run_source(&mut vm, "[1, 2].push(3)"), JsValue::int(3));
assert!(!vm.session.is_dirty_since_snapshot()); assert!(!vm.realm.session.is_dirty_since_snapshot());
} }
/// 假阳性护栏:只写用户对象的良性运行不得误判 wrapper 脏——wrapper 世代 /// 假阳性护栏:只写用户对象的良性运行不得误判 wrapper 脏——wrapper 世代
@@ -1070,16 +1070,16 @@ fn wrapper_write_rebuild_then_p_writes_reuse_fresh_wrapper() {
fn benign_user_object_writes_do_not_dirty_leaked_objects() { fn benign_user_object_writes_do_not_dirty_leaked_objects() {
let mut vm = Vm::new(); let mut vm = Vm::new();
let _ = run_source(&mut vm, "0"); let _ = run_source(&mut vm, "0");
let world_ptr = Arc::as_ptr(&vm.session.builtin_world); let world_ptr = Arc::as_ptr(&vm.realm.session.builtin_world);
let result = run_source(&mut vm, "(function () { var a = {}; a.x = 1; a.x = 2; return a.x; })()"); let result = run_source(&mut vm, "(function () { var a = {}; a.x = 1; a.x = 2; return a.x; })()");
assert_eq!(result, JsValue::int(2)); assert_eq!(result, JsValue::int(2));
assert!(!vm.session.is_dirty_since_snapshot(), "只写用户对象不应误判 wrapper 脏"); assert!(!vm.realm.session.is_dirty_since_snapshot(), "只写用户对象不应误判 wrapper 脏");
vm.full_reset(); vm.full_reset();
assert!(std::ptr::eq(world_ptr, Arc::as_ptr(&vm.session.builtin_world)), "无污染不应重建 world"); assert!(std::ptr::eq(world_ptr, Arc::as_ptr(&vm.realm.session.builtin_world)), "无污染不应重建 world");
assert!(!vm.session.is_dirty_since_snapshot()); assert!(!vm.realm.session.is_dirty_since_snapshot());
} }
/// 假阳性护栏:只写用户对象的良性运行不得误判 builtin 脏。 /// 假阳性护栏:只写用户对象的良性运行不得误判 builtin 脏。
@@ -1091,16 +1091,16 @@ fn benign_user_object_writes_do_not_dirty_leaked_objects() {
fn benign_run_does_not_falsely_dirty_builtins() { fn benign_run_does_not_falsely_dirty_builtins() {
let mut vm = Vm::new(); let mut vm = Vm::new();
let _ = run_source(&mut vm, "0"); let _ = run_source(&mut vm, "0");
let world_ptr = Arc::as_ptr(&vm.session.builtin_world); let world_ptr = Arc::as_ptr(&vm.realm.session.builtin_world);
run_source(&mut vm, "({ x: 1 }).x + [1, 2].length"); run_source(&mut vm, "({ x: 1 }).x + [1, 2].length");
assert_eq!(vm.session_object_count(), 2, "良性表达式应产生两枚临时对象(对象字面量 + 数组字面量)"); assert_eq!(vm.session_object_count(), 2, "良性表达式应产生两枚临时对象(对象字面量 + 数组字面量)");
assert!(!vm.session.is_dirty_since_snapshot(), "良性运行不应误判 builtin 脏"); assert!(!vm.realm.session.is_dirty_since_snapshot(), "良性运行不应误判 builtin 脏");
vm.full_reset(); vm.full_reset();
assert!(std::ptr::eq(world_ptr, Arc::as_ptr(&vm.session.builtin_world)), "builtin world 不应重建"); assert!(std::ptr::eq(world_ptr, Arc::as_ptr(&vm.realm.session.builtin_world)), "builtin world 不应重建");
assert!(!vm.session.is_dirty_since_snapshot()); assert!(!vm.realm.session.is_dirty_since_snapshot());
} }
#[test] #[test]