diff --git a/crates/oxide_kernel/src/kernel/mod.rs b/crates/oxide_kernel/src/kernel/mod.rs index e69d8f27..1556a148 100644 --- a/crates/oxide_kernel/src/kernel/mod.rs +++ b/crates/oxide_kernel/src/kernel/mod.rs @@ -1,263 +1,11 @@ #![allow(clippy::arc_with_non_send_sync)] -use std::sync::Arc; - -use oxide_types::mem::P; -use oxide_types::object::JsObject; -use oxide_types::value::JsValue; - -use crate::builtin::BuiltinWorld; -use crate::shape_forge::EMPTY_SHAPE_ID; - mod builtin_id; mod config; mod core; +mod session; pub use builtin_id::{BuiltinDirtySet, BuiltinId, BuiltinSnapshot, NUM_BUILTINS}; pub use config::KernelConfig; pub use core::KernelCore; - -/// 每会话可变状态:内置原型对象与全局对象。 -/// 在 full_reset() 时重建,实现 JS 执行之间的完全隔离。 -pub struct KernelSession { - pub builtin_world: Arc, - pub global_object: P, - pub builtin_snapshot: BuiltinSnapshot, -} - -impl KernelSession { - fn new_global_object(core: &KernelCore) -> P { - let mut global_obj = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null()); - - let si_nan = core.perm_interner.intern("NaN").0; - let si_undef = core.perm_interner.intern("undefined").0; - let si_infinity = core.perm_interner.intern("Infinity").0; - - // 全局三常量描述符:{ writable:false, enumerable:false, configurable:false }。 - // e:false 是枚举面守卫(Object.keys / for-in 由 enumerable 决定); - // c:false 是 delete / defineProperty 可观察的规范值(delete globalThis.undefined - // 返回 false、属性不可删,后续声明/定义均不得 reconfigure)。 - let nan_shape = core.shape_forge.make_shape(EMPTY_SHAPE_ID, si_nan); - global_obj.set_shape_id(nan_shape); - global_obj.ensure_hash_props().push(JsValue::float(f64::NAN)); - global_obj.set_data_meta( - global_obj.prop_vec_len().saturating_sub(1) as u32, - oxide_types::object::PropAttributes::new(false, false, false), - ); - - let undef_shape = core.shape_forge.make_shape(nan_shape, si_undef); - global_obj.set_shape_id(undef_shape); - global_obj.ensure_hash_props().push(JsValue::undefined()); - global_obj.set_data_meta( - global_obj.prop_vec_len().saturating_sub(1) as u32, - oxide_types::object::PropAttributes::new(false, false, false), - ); - - let inf_shape = core.shape_forge.make_shape(undef_shape, si_infinity); - global_obj.set_shape_id(inf_shape); - global_obj.ensure_hash_props().push(JsValue::float(f64::INFINITY)); - global_obj.set_data_meta( - global_obj.prop_vec_len().saturating_sub(1) as u32, - oxide_types::object::PropAttributes::new(false, false, false), - ); - - P::new(global_obj) - } - - /// 从 KernelCore 构建一个全新 session。所有 string/shape intern 调用在 - /// 第二次及后续调用时命中缓存——净开销 < 0.5 ms。 - pub fn new(core: &KernelCore) -> Self { - let builtin_world = Arc::new(BuiltinWorld::new(&core.perm_interner, &core.shape_forge)); - let global_object = Self::new_global_object(core); - let builtin_snapshot = BuiltinSnapshot::new(&builtin_world, &global_object); - - Self { - builtin_world, - global_object, - builtin_snapshot, - } - } - - /// 只读访问当前 session 的 builtin world。 - pub fn builtin_world(&self) -> &Arc { - &self.builtin_world - } - - /// 只读访问当前 session 的 global object。 - pub fn global_object(&self) -> &P { - &self.global_object - } - - /// 重新采集内置对象世代快照,作为下一次脏检查的基准。 - pub fn record_snapshot(&mut self) { - self.builtin_snapshot = BuiltinSnapshot::new(&self.builtin_world, &self.global_object); - } - - /// 对比当前世代与最近快照,返回各 builtin 家族是否被污染。 - pub fn dirty_since_snapshot(&self) -> BuiltinDirtySet { - let world = self.builtin_world.as_ref(); - let snapshot = &self.builtin_snapshot; - let stub_generations_dirty = world - .stub_objects - .iter() - .zip(snapshot.stub_object_generations.iter()) - .any(|(obj, generation)| BuiltinSnapshot::gen(obj) != *generation); - let gen = |id: BuiltinId| BuiltinSnapshot::gen(world.get_by_id(id)); - let snap = |id: BuiltinId| snapshot.generations[id as usize]; - - BuiltinDirtySet { - object: gen(BuiltinId::ObjectProto) != snap(BuiltinId::ObjectProto) - || gen(BuiltinId::ObjectConstructor) != snap(BuiltinId::ObjectConstructor), - array: gen(BuiltinId::ArrayProto) != snap(BuiltinId::ArrayProto) - || gen(BuiltinId::ArrayConstructor) != snap(BuiltinId::ArrayConstructor), - function: gen(BuiltinId::FunctionProto) != snap(BuiltinId::FunctionProto) - || gen(BuiltinId::FunctionConstructor) != snap(BuiltinId::FunctionConstructor), - string: gen(BuiltinId::StringProto) != snap(BuiltinId::StringProto) - || gen(BuiltinId::StringConstructor) != snap(BuiltinId::StringConstructor), - number: gen(BuiltinId::NumberProto) != snap(BuiltinId::NumberProto) - || gen(BuiltinId::NumberConstructor) != snap(BuiltinId::NumberConstructor), - boolean: gen(BuiltinId::BooleanProto) != snap(BuiltinId::BooleanProto) - || gen(BuiltinId::BooleanConstructor) != snap(BuiltinId::BooleanConstructor), - error_family: gen(BuiltinId::ErrorProto) != snap(BuiltinId::ErrorProto) - || gen(BuiltinId::ErrorConstructor) != snap(BuiltinId::ErrorConstructor) - || gen(BuiltinId::TypeErrorProto) != snap(BuiltinId::TypeErrorProto) - || gen(BuiltinId::ReferenceErrorProto) != snap(BuiltinId::ReferenceErrorProto) - || gen(BuiltinId::RangeErrorProto) != snap(BuiltinId::RangeErrorProto) - || gen(BuiltinId::SyntaxErrorProto) != snap(BuiltinId::SyntaxErrorProto) - || gen(BuiltinId::UriErrorProto) != snap(BuiltinId::UriErrorProto) - || gen(BuiltinId::EvalErrorProto) != snap(BuiltinId::EvalErrorProto) - || gen(BuiltinId::SuppressedErrorProto) != snap(BuiltinId::SuppressedErrorProto), - symbol_family: gen(BuiltinId::SymbolProto) != snap(BuiltinId::SymbolProto) - || gen(BuiltinId::SymbolConstructor) != snap(BuiltinId::SymbolConstructor) - || gen(BuiltinId::SymMatch) != snap(BuiltinId::SymMatch) - || gen(BuiltinId::SymReplace) != snap(BuiltinId::SymReplace) - || gen(BuiltinId::SymSearch) != snap(BuiltinId::SymSearch) - || gen(BuiltinId::SymSplit) != snap(BuiltinId::SymSplit) - || gen(BuiltinId::SymIterator) != snap(BuiltinId::SymIterator) - || gen(BuiltinId::SymToPrimitive) != snap(BuiltinId::SymToPrimitive) - || gen(BuiltinId::SymHasInstance) != snap(BuiltinId::SymHasInstance) - || gen(BuiltinId::SymMatchAll) != snap(BuiltinId::SymMatchAll) - || gen(BuiltinId::SymAsyncIterator) != snap(BuiltinId::SymAsyncIterator) - || gen(BuiltinId::SymToStringTag) != snap(BuiltinId::SymToStringTag) - || gen(BuiltinId::SymSpecies) != snap(BuiltinId::SymSpecies) - || gen(BuiltinId::SymAsyncDispose) != snap(BuiltinId::SymAsyncDispose) - || gen(BuiltinId::SymDispose) != snap(BuiltinId::SymDispose), - math: gen(BuiltinId::MathObject) != snap(BuiltinId::MathObject), - json: gen(BuiltinId::JsonObject) != snap(BuiltinId::JsonObject), - date: gen(BuiltinId::DateConstructor) != snap(BuiltinId::DateConstructor) - || gen(BuiltinId::DateProto) != snap(BuiltinId::DateProto), - set: gen(BuiltinId::SetConstructor) != snap(BuiltinId::SetConstructor) - || gen(BuiltinId::SetProto) != snap(BuiltinId::SetProto), - map: gen(BuiltinId::MapConstructor) != snap(BuiltinId::MapConstructor) - || gen(BuiltinId::MapProto) != snap(BuiltinId::MapProto), - regexp: gen(BuiltinId::RegExpConstructor) != snap(BuiltinId::RegExpConstructor) - || gen(BuiltinId::RegExpProto) != snap(BuiltinId::RegExpProto), - array_buffer: gen(BuiltinId::ArrayBufferConstructor) != snap(BuiltinId::ArrayBufferConstructor) - || gen(BuiltinId::ArrayBufferProto) != snap(BuiltinId::ArrayBufferProto), - data_view: gen(BuiltinId::DataViewConstructor) != snap(BuiltinId::DataViewConstructor) - || gen(BuiltinId::DataViewProto) != snap(BuiltinId::DataViewProto), - typed_array_family: gen(BuiltinId::TypedArrayProto) != snap(BuiltinId::TypedArrayProto) - || gen(BuiltinId::Int8ArrayConstructor) != snap(BuiltinId::Int8ArrayConstructor) - || gen(BuiltinId::Int8ArrayProto) != snap(BuiltinId::Int8ArrayProto) - || gen(BuiltinId::Uint8ArrayConstructor) != snap(BuiltinId::Uint8ArrayConstructor) - || gen(BuiltinId::Uint8ArrayProto) != snap(BuiltinId::Uint8ArrayProto) - || gen(BuiltinId::Uint8ClampedArrayConstructor) != snap(BuiltinId::Uint8ClampedArrayConstructor) - || gen(BuiltinId::Uint8ClampedArrayProto) != snap(BuiltinId::Uint8ClampedArrayProto) - || gen(BuiltinId::Int16ArrayConstructor) != snap(BuiltinId::Int16ArrayConstructor) - || gen(BuiltinId::Int16ArrayProto) != snap(BuiltinId::Int16ArrayProto) - || gen(BuiltinId::Uint16ArrayConstructor) != snap(BuiltinId::Uint16ArrayConstructor) - || gen(BuiltinId::Uint16ArrayProto) != snap(BuiltinId::Uint16ArrayProto) - || gen(BuiltinId::Int32ArrayConstructor) != snap(BuiltinId::Int32ArrayConstructor) - || gen(BuiltinId::Int32ArrayProto) != snap(BuiltinId::Int32ArrayProto) - || gen(BuiltinId::Uint32ArrayConstructor) != snap(BuiltinId::Uint32ArrayConstructor) - || gen(BuiltinId::Uint32ArrayProto) != snap(BuiltinId::Uint32ArrayProto) - || gen(BuiltinId::Float32ArrayConstructor) != snap(BuiltinId::Float32ArrayConstructor) - || gen(BuiltinId::Float32ArrayProto) != snap(BuiltinId::Float32ArrayProto) - || gen(BuiltinId::Float64ArrayConstructor) != snap(BuiltinId::Float64ArrayConstructor) - || gen(BuiltinId::Float64ArrayProto) != snap(BuiltinId::Float64ArrayProto) - || gen(BuiltinId::BigInt64ArrayConstructor) != snap(BuiltinId::BigInt64ArrayConstructor) - || gen(BuiltinId::BigInt64ArrayProto) != snap(BuiltinId::BigInt64ArrayProto) - || gen(BuiltinId::BigUint64ArrayConstructor) != snap(BuiltinId::BigUint64ArrayConstructor) - || gen(BuiltinId::BigUint64ArrayProto) != snap(BuiltinId::BigUint64ArrayProto), - temporal: gen(BuiltinId::TemporalObject) != snap(BuiltinId::TemporalObject) - || gen(BuiltinId::TemporalNowObject) != snap(BuiltinId::TemporalNowObject) - || gen(BuiltinId::InstantConstructor) != snap(BuiltinId::InstantConstructor) - || gen(BuiltinId::InstantProto) != snap(BuiltinId::InstantProto) - || gen(BuiltinId::PlainDateConstructor) != snap(BuiltinId::PlainDateConstructor) - || gen(BuiltinId::PlainDateProto) != snap(BuiltinId::PlainDateProto) - || gen(BuiltinId::PlainTimeConstructor) != snap(BuiltinId::PlainTimeConstructor) - || gen(BuiltinId::PlainTimeProto) != snap(BuiltinId::PlainTimeProto) - || gen(BuiltinId::DurationConstructor) != snap(BuiltinId::DurationConstructor) - || gen(BuiltinId::DurationProto) != snap(BuiltinId::DurationProto) - || gen(BuiltinId::ZonedDateTimeConstructor) != snap(BuiltinId::ZonedDateTimeConstructor) - || gen(BuiltinId::ZonedDateTimeProto) != snap(BuiltinId::ZonedDateTimeProto) - || gen(BuiltinId::PlainDateTimeConstructor) != snap(BuiltinId::PlainDateTimeConstructor) - || gen(BuiltinId::PlainDateTimeProto) != snap(BuiltinId::PlainDateTimeProto) - || gen(BuiltinId::PlainMonthDayConstructor) != snap(BuiltinId::PlainMonthDayConstructor) - || gen(BuiltinId::PlainMonthDayProto) != snap(BuiltinId::PlainMonthDayProto) - || gen(BuiltinId::PlainYearMonthConstructor) != snap(BuiltinId::PlainYearMonthConstructor) - || gen(BuiltinId::PlainYearMonthProto) != snap(BuiltinId::PlainYearMonthProto), - stubs: world.stub_objects.len() != snapshot.stub_objects_len - || stub_generations_dirty - || gen(BuiltinId::BigIntConstructor) != snap(BuiltinId::BigIntConstructor) - || gen(BuiltinId::BigIntProto) != snap(BuiltinId::BigIntProto), - global: BuiltinSnapshot::gen(&self.global_object) != snapshot.global_object_generation, - console: gen(BuiltinId::Console) != snap(BuiltinId::Console), - } - } - - /// 是否自上次快照以来存在任何污染。 - pub fn is_dirty_since_snapshot(&self) -> bool { - self.dirty_since_snapshot().any() - } - - /// 收尾释放 session 拥有的手工堆数据:builtin world(方法 wrapper 登记表 + - /// 全部 P 对象属性区)与 global 对象属性区。对象本体随 Arc 引用归零释放。 - /// - /// # 注意事项 - /// 幂等(登记表按值取走、属性区释放后置空),session 生命周期内可安全重入; - /// 仅应在 session 真正终止时调用——选择性重置换出的旧 world/global 不走本路径。 - pub fn teardown_builtins(&mut self) { - self.builtin_world.teardown_heap_data(); - // SAFETY: global 归本 session 所有,收尾时恰好释放其属性区一次。 - let global = unsafe { &mut *(self.global_object.as_ptr() as *mut JsObject) }; - global.release_raw_heap(); - } - - /// 选择性重置:只重建被污染的对象(global 或相应 builtin 家族),并返回脏集合。 - /// - /// 相比全量重建,可保留未污染的内置对象指针与世代,减少隔离成本。 - pub fn selective_reset(&mut self, core: &Arc) -> BuiltinDirtySet { - let dirty = self.dirty_since_snapshot(); - if dirty.global { - // 旧 global 的属性区在替换前释放,避免随旧引用永久泄漏。 - let old_global = unsafe { &mut *(self.global_object.as_ptr() as *mut JsObject) }; - old_global.release_raw_heap(); - self.global_object = Self::new_global_object(core); - } - if dirty.any_builtin_dirty() { - let old_world = self.builtin_world.clone(); - let new_world = BuiltinWorld::rebuild_with_dirty( - &old_world, - core.perm_interner.as_ref(), - core.shape_forge.as_ref(), - &dirty, - ); - // 旧 world 的登记表并入新 world:存活 wrapper(未污染家族别名)仍须在 - // session 收尾统一释放;已弃 wrapper 随之恰好释放一次,不二次持有。 - new_world.inherit_leaked_objects(&old_world); - // 重建收尾:保留对象(登记表 wrapper + 共用保留 P 字段)proto 槽 - // 重指新指针,随后被替换旧对象属性区恰好释放一次(含保活钉住 - // 对的属性区,本体钉保留);重指须先于释放、先于换出完成。 - new_world.retire_replaced(&old_world); - self.builtin_world = Arc::new(new_world); - } - dirty - } -} - -impl Drop for KernelSession { - fn drop(&mut self) { - self.teardown_builtins(); - } -} +pub use session::KernelSession; diff --git a/crates/oxide_kernel/src/kernel/session.rs b/crates/oxide_kernel/src/kernel/session.rs new file mode 100644 index 00000000..dbc49050 --- /dev/null +++ b/crates/oxide_kernel/src/kernel/session.rs @@ -0,0 +1,257 @@ +//! 每会话可变状态:内置原型对象(BuiltinWorld)与全局对象,full_reset 时 +//! 重建;世代快照 + 家族位脏集合计算,selective_reset 只重建脏家族。 + +use std::sync::Arc; + +use oxide_types::mem::P; +use oxide_types::object::JsObject; +use oxide_types::value::JsValue; + +use crate::builtin::BuiltinWorld; +use crate::shape_forge::EMPTY_SHAPE_ID; + +use super::{BuiltinDirtySet, BuiltinId, BuiltinSnapshot, KernelCore}; +/// 每会话可变状态:内置原型对象与全局对象。 +/// 在 full_reset() 时重建,实现 JS 执行之间的完全隔离。 +pub struct KernelSession { + pub builtin_world: Arc, + pub global_object: P, + pub builtin_snapshot: BuiltinSnapshot, +} + +impl KernelSession { + fn new_global_object(core: &KernelCore) -> P { + let mut global_obj = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null()); + + let si_nan = core.perm_interner.intern("NaN").0; + let si_undef = core.perm_interner.intern("undefined").0; + let si_infinity = core.perm_interner.intern("Infinity").0; + + // 全局三常量描述符:{ writable:false, enumerable:false, configurable:false }。 + // e:false 是枚举面守卫(Object.keys / for-in 由 enumerable 决定); + // c:false 是 delete / defineProperty 可观察的规范值(delete globalThis.undefined + // 返回 false、属性不可删,后续声明/定义均不得 reconfigure)。 + let nan_shape = core.shape_forge.make_shape(EMPTY_SHAPE_ID, si_nan); + global_obj.set_shape_id(nan_shape); + global_obj.ensure_hash_props().push(JsValue::float(f64::NAN)); + global_obj.set_data_meta( + global_obj.prop_vec_len().saturating_sub(1) as u32, + oxide_types::object::PropAttributes::new(false, false, false), + ); + + let undef_shape = core.shape_forge.make_shape(nan_shape, si_undef); + global_obj.set_shape_id(undef_shape); + global_obj.ensure_hash_props().push(JsValue::undefined()); + global_obj.set_data_meta( + global_obj.prop_vec_len().saturating_sub(1) as u32, + oxide_types::object::PropAttributes::new(false, false, false), + ); + + let inf_shape = core.shape_forge.make_shape(undef_shape, si_infinity); + global_obj.set_shape_id(inf_shape); + global_obj.ensure_hash_props().push(JsValue::float(f64::INFINITY)); + global_obj.set_data_meta( + global_obj.prop_vec_len().saturating_sub(1) as u32, + oxide_types::object::PropAttributes::new(false, false, false), + ); + + P::new(global_obj) + } + + /// 从 KernelCore 构建一个全新 session。所有 string/shape intern 调用在 + /// 第二次及后续调用时命中缓存——净开销 < 0.5 ms。 + pub fn new(core: &KernelCore) -> Self { + let builtin_world = Arc::new(BuiltinWorld::new(&core.perm_interner, &core.shape_forge)); + let global_object = Self::new_global_object(core); + let builtin_snapshot = BuiltinSnapshot::new(&builtin_world, &global_object); + + Self { + builtin_world, + global_object, + builtin_snapshot, + } + } + + /// 只读访问当前 session 的 builtin world。 + pub fn builtin_world(&self) -> &Arc { + &self.builtin_world + } + + /// 只读访问当前 session 的 global object。 + pub fn global_object(&self) -> &P { + &self.global_object + } + + /// 重新采集内置对象世代快照,作为下一次脏检查的基准。 + pub fn record_snapshot(&mut self) { + self.builtin_snapshot = BuiltinSnapshot::new(&self.builtin_world, &self.global_object); + } + + /// 对比当前世代与最近快照,返回各 builtin 家族是否被污染。 + pub fn dirty_since_snapshot(&self) -> BuiltinDirtySet { + let world = self.builtin_world.as_ref(); + let snapshot = &self.builtin_snapshot; + let stub_generations_dirty = world + .stub_objects + .iter() + .zip(snapshot.stub_object_generations.iter()) + .any(|(obj, generation)| BuiltinSnapshot::gen(obj) != *generation); + let gen = |id: BuiltinId| BuiltinSnapshot::gen(world.get_by_id(id)); + let snap = |id: BuiltinId| snapshot.generations[id as usize]; + + BuiltinDirtySet { + object: gen(BuiltinId::ObjectProto) != snap(BuiltinId::ObjectProto) + || gen(BuiltinId::ObjectConstructor) != snap(BuiltinId::ObjectConstructor), + array: gen(BuiltinId::ArrayProto) != snap(BuiltinId::ArrayProto) + || gen(BuiltinId::ArrayConstructor) != snap(BuiltinId::ArrayConstructor), + function: gen(BuiltinId::FunctionProto) != snap(BuiltinId::FunctionProto) + || gen(BuiltinId::FunctionConstructor) != snap(BuiltinId::FunctionConstructor), + string: gen(BuiltinId::StringProto) != snap(BuiltinId::StringProto) + || gen(BuiltinId::StringConstructor) != snap(BuiltinId::StringConstructor), + number: gen(BuiltinId::NumberProto) != snap(BuiltinId::NumberProto) + || gen(BuiltinId::NumberConstructor) != snap(BuiltinId::NumberConstructor), + boolean: gen(BuiltinId::BooleanProto) != snap(BuiltinId::BooleanProto) + || gen(BuiltinId::BooleanConstructor) != snap(BuiltinId::BooleanConstructor), + error_family: gen(BuiltinId::ErrorProto) != snap(BuiltinId::ErrorProto) + || gen(BuiltinId::ErrorConstructor) != snap(BuiltinId::ErrorConstructor) + || gen(BuiltinId::TypeErrorProto) != snap(BuiltinId::TypeErrorProto) + || gen(BuiltinId::ReferenceErrorProto) != snap(BuiltinId::ReferenceErrorProto) + || gen(BuiltinId::RangeErrorProto) != snap(BuiltinId::RangeErrorProto) + || gen(BuiltinId::SyntaxErrorProto) != snap(BuiltinId::SyntaxErrorProto) + || gen(BuiltinId::UriErrorProto) != snap(BuiltinId::UriErrorProto) + || gen(BuiltinId::EvalErrorProto) != snap(BuiltinId::EvalErrorProto) + || gen(BuiltinId::SuppressedErrorProto) != snap(BuiltinId::SuppressedErrorProto), + symbol_family: gen(BuiltinId::SymbolProto) != snap(BuiltinId::SymbolProto) + || gen(BuiltinId::SymbolConstructor) != snap(BuiltinId::SymbolConstructor) + || gen(BuiltinId::SymMatch) != snap(BuiltinId::SymMatch) + || gen(BuiltinId::SymReplace) != snap(BuiltinId::SymReplace) + || gen(BuiltinId::SymSearch) != snap(BuiltinId::SymSearch) + || gen(BuiltinId::SymSplit) != snap(BuiltinId::SymSplit) + || gen(BuiltinId::SymIterator) != snap(BuiltinId::SymIterator) + || gen(BuiltinId::SymToPrimitive) != snap(BuiltinId::SymToPrimitive) + || gen(BuiltinId::SymHasInstance) != snap(BuiltinId::SymHasInstance) + || gen(BuiltinId::SymMatchAll) != snap(BuiltinId::SymMatchAll) + || gen(BuiltinId::SymAsyncIterator) != snap(BuiltinId::SymAsyncIterator) + || gen(BuiltinId::SymToStringTag) != snap(BuiltinId::SymToStringTag) + || gen(BuiltinId::SymSpecies) != snap(BuiltinId::SymSpecies) + || gen(BuiltinId::SymAsyncDispose) != snap(BuiltinId::SymAsyncDispose) + || gen(BuiltinId::SymDispose) != snap(BuiltinId::SymDispose), + math: gen(BuiltinId::MathObject) != snap(BuiltinId::MathObject), + json: gen(BuiltinId::JsonObject) != snap(BuiltinId::JsonObject), + date: gen(BuiltinId::DateConstructor) != snap(BuiltinId::DateConstructor) + || gen(BuiltinId::DateProto) != snap(BuiltinId::DateProto), + set: gen(BuiltinId::SetConstructor) != snap(BuiltinId::SetConstructor) + || gen(BuiltinId::SetProto) != snap(BuiltinId::SetProto), + map: gen(BuiltinId::MapConstructor) != snap(BuiltinId::MapConstructor) + || gen(BuiltinId::MapProto) != snap(BuiltinId::MapProto), + regexp: gen(BuiltinId::RegExpConstructor) != snap(BuiltinId::RegExpConstructor) + || gen(BuiltinId::RegExpProto) != snap(BuiltinId::RegExpProto), + array_buffer: gen(BuiltinId::ArrayBufferConstructor) != snap(BuiltinId::ArrayBufferConstructor) + || gen(BuiltinId::ArrayBufferProto) != snap(BuiltinId::ArrayBufferProto), + data_view: gen(BuiltinId::DataViewConstructor) != snap(BuiltinId::DataViewConstructor) + || gen(BuiltinId::DataViewProto) != snap(BuiltinId::DataViewProto), + typed_array_family: gen(BuiltinId::TypedArrayProto) != snap(BuiltinId::TypedArrayProto) + || gen(BuiltinId::Int8ArrayConstructor) != snap(BuiltinId::Int8ArrayConstructor) + || gen(BuiltinId::Int8ArrayProto) != snap(BuiltinId::Int8ArrayProto) + || gen(BuiltinId::Uint8ArrayConstructor) != snap(BuiltinId::Uint8ArrayConstructor) + || gen(BuiltinId::Uint8ArrayProto) != snap(BuiltinId::Uint8ArrayProto) + || gen(BuiltinId::Uint8ClampedArrayConstructor) != snap(BuiltinId::Uint8ClampedArrayConstructor) + || gen(BuiltinId::Uint8ClampedArrayProto) != snap(BuiltinId::Uint8ClampedArrayProto) + || gen(BuiltinId::Int16ArrayConstructor) != snap(BuiltinId::Int16ArrayConstructor) + || gen(BuiltinId::Int16ArrayProto) != snap(BuiltinId::Int16ArrayProto) + || gen(BuiltinId::Uint16ArrayConstructor) != snap(BuiltinId::Uint16ArrayConstructor) + || gen(BuiltinId::Uint16ArrayProto) != snap(BuiltinId::Uint16ArrayProto) + || gen(BuiltinId::Int32ArrayConstructor) != snap(BuiltinId::Int32ArrayConstructor) + || gen(BuiltinId::Int32ArrayProto) != snap(BuiltinId::Int32ArrayProto) + || gen(BuiltinId::Uint32ArrayConstructor) != snap(BuiltinId::Uint32ArrayConstructor) + || gen(BuiltinId::Uint32ArrayProto) != snap(BuiltinId::Uint32ArrayProto) + || gen(BuiltinId::Float32ArrayConstructor) != snap(BuiltinId::Float32ArrayConstructor) + || gen(BuiltinId::Float32ArrayProto) != snap(BuiltinId::Float32ArrayProto) + || gen(BuiltinId::Float64ArrayConstructor) != snap(BuiltinId::Float64ArrayConstructor) + || gen(BuiltinId::Float64ArrayProto) != snap(BuiltinId::Float64ArrayProto) + || gen(BuiltinId::BigInt64ArrayConstructor) != snap(BuiltinId::BigInt64ArrayConstructor) + || gen(BuiltinId::BigInt64ArrayProto) != snap(BuiltinId::BigInt64ArrayProto) + || gen(BuiltinId::BigUint64ArrayConstructor) != snap(BuiltinId::BigUint64ArrayConstructor) + || gen(BuiltinId::BigUint64ArrayProto) != snap(BuiltinId::BigUint64ArrayProto), + temporal: gen(BuiltinId::TemporalObject) != snap(BuiltinId::TemporalObject) + || gen(BuiltinId::TemporalNowObject) != snap(BuiltinId::TemporalNowObject) + || gen(BuiltinId::InstantConstructor) != snap(BuiltinId::InstantConstructor) + || gen(BuiltinId::InstantProto) != snap(BuiltinId::InstantProto) + || gen(BuiltinId::PlainDateConstructor) != snap(BuiltinId::PlainDateConstructor) + || gen(BuiltinId::PlainDateProto) != snap(BuiltinId::PlainDateProto) + || gen(BuiltinId::PlainTimeConstructor) != snap(BuiltinId::PlainTimeConstructor) + || gen(BuiltinId::PlainTimeProto) != snap(BuiltinId::PlainTimeProto) + || gen(BuiltinId::DurationConstructor) != snap(BuiltinId::DurationConstructor) + || gen(BuiltinId::DurationProto) != snap(BuiltinId::DurationProto) + || gen(BuiltinId::ZonedDateTimeConstructor) != snap(BuiltinId::ZonedDateTimeConstructor) + || gen(BuiltinId::ZonedDateTimeProto) != snap(BuiltinId::ZonedDateTimeProto) + || gen(BuiltinId::PlainDateTimeConstructor) != snap(BuiltinId::PlainDateTimeConstructor) + || gen(BuiltinId::PlainDateTimeProto) != snap(BuiltinId::PlainDateTimeProto) + || gen(BuiltinId::PlainMonthDayConstructor) != snap(BuiltinId::PlainMonthDayConstructor) + || gen(BuiltinId::PlainMonthDayProto) != snap(BuiltinId::PlainMonthDayProto) + || gen(BuiltinId::PlainYearMonthConstructor) != snap(BuiltinId::PlainYearMonthConstructor) + || gen(BuiltinId::PlainYearMonthProto) != snap(BuiltinId::PlainYearMonthProto), + stubs: world.stub_objects.len() != snapshot.stub_objects_len + || stub_generations_dirty + || gen(BuiltinId::BigIntConstructor) != snap(BuiltinId::BigIntConstructor) + || gen(BuiltinId::BigIntProto) != snap(BuiltinId::BigIntProto), + global: BuiltinSnapshot::gen(&self.global_object) != snapshot.global_object_generation, + console: gen(BuiltinId::Console) != snap(BuiltinId::Console), + } + } + + /// 是否自上次快照以来存在任何污染。 + pub fn is_dirty_since_snapshot(&self) -> bool { + self.dirty_since_snapshot().any() + } + + /// 收尾释放 session 拥有的手工堆数据:builtin world(方法 wrapper 登记表 + + /// 全部 P 对象属性区)与 global 对象属性区。对象本体随 Arc 引用归零释放。 + /// + /// # 注意事项 + /// 幂等(登记表按值取走、属性区释放后置空),session 生命周期内可安全重入; + /// 仅应在 session 真正终止时调用——选择性重置换出的旧 world/global 不走本路径。 + pub fn teardown_builtins(&mut self) { + self.builtin_world.teardown_heap_data(); + // SAFETY: global 归本 session 所有,收尾时恰好释放其属性区一次。 + let global = unsafe { &mut *(self.global_object.as_ptr() as *mut JsObject) }; + global.release_raw_heap(); + } + + /// 选择性重置:只重建被污染的对象(global 或相应 builtin 家族),并返回脏集合。 + /// + /// 相比全量重建,可保留未污染的内置对象指针与世代,减少隔离成本。 + pub fn selective_reset(&mut self, core: &Arc) -> BuiltinDirtySet { + let dirty = self.dirty_since_snapshot(); + if dirty.global { + // 旧 global 的属性区在替换前释放,避免随旧引用永久泄漏。 + let old_global = unsafe { &mut *(self.global_object.as_ptr() as *mut JsObject) }; + old_global.release_raw_heap(); + self.global_object = Self::new_global_object(core); + } + if dirty.any_builtin_dirty() { + let old_world = self.builtin_world.clone(); + let new_world = BuiltinWorld::rebuild_with_dirty( + &old_world, + core.perm_interner.as_ref(), + core.shape_forge.as_ref(), + &dirty, + ); + // 旧 world 的登记表并入新 world:存活 wrapper(未污染家族别名)仍须在 + // session 收尾统一释放;已弃 wrapper 随之恰好释放一次,不二次持有。 + new_world.inherit_leaked_objects(&old_world); + // 重建收尾:保留对象(登记表 wrapper + 共用保留 P 字段)proto 槽 + // 重指新指针,随后被替换旧对象属性区恰好释放一次(含保活钉住 + // 对的属性区,本体钉保留);重指须先于释放、先于换出完成。 + new_world.retire_replaced(&old_world); + self.builtin_world = Arc::new(new_world); + } + dirty + } +} + +impl Drop for KernelSession { + fn drop(&mut self) { + self.teardown_builtins(); + } +}