diff --git a/crates/oxide_builtins/src/atomics.rs b/crates/oxide_builtins/src/atomics.rs new file mode 100644 index 00000000..8dc0855c --- /dev/null +++ b/crates/oxide_builtins/src/atomics.rs @@ -0,0 +1,260 @@ +//! Atomics 全局纯对象的 10 个原子方法(load/store/exchange/add/sub/and/or/ +//! xor/compareExchange/isLockFree)。单线程引擎无锁层级,全部退化为 +//! 读-改-写;宽度截断与元素写路径(`write_element`)结构同构。 + +use num_bigint::BigInt; +use oxide_types::object::TypedArrayKind; +use oxide_types::value::JsValue; + +use crate::array_buffer::{buffer_payload_ptr, ArrayBufferPayload}; +use crate::typed_array::{ + get_typed_array_data, read_element, ta_element_value, ta_to_integer_or_infinity, ta_validate, write_element, + TypedArrayData, +}; +use oxide_runtime_api::{NativeResult, VmHost}; + +macro_rules! native_try { + ($expr:expr) => { + match $expr { + Ok(value) => value, + Err(err) => return NativeResult::Err(err), + } + }; +} + +fn type_error(vm: &mut H, msg: &str) -> JsValue { + crate::error::create_type_error(vm, msg) +} + +fn range_error(vm: &mut H, msg: &str) -> JsValue { + crate::error::create_range_error(vm, msg) +} + +/// 按寄存器下标取实参;越界(实参缺失)回落 undefined(JS 缺省参语义)。 +fn arg_at(vm: &mut H, args: &[u8], idx: usize) -> JsValue { + if args.len() > idx { + vm.reg(args[idx]) + } else { + JsValue::undefined() + } +} + +/// 原子操作可接受的整数宽度:八整数种类(含 BigInt64/BigUint64); +/// 浮点(Float32/Float64)与 Uint8Clamped 视图非整数宽度,抛 TypeError。 +fn is_integer_kind(kind: TypedArrayKind) -> bool { + matches!( + kind, + TypedArrayKind::Int8 + | TypedArrayKind::Uint8 + | TypedArrayKind::Int16 + | TypedArrayKind::Uint16 + | TypedArrayKind::Int32 + | TypedArrayKind::Uint32 + | TypedArrayKind::BigInt64 + | TypedArrayKind::BigUint64 + ) +} + +fn is_bigint_kind(kind: TypedArrayKind) -> bool { + matches!(kind, TypedArrayKind::BigInt64 | TypedArrayKind::BigUint64) +} + +/// 原子访问共享核:品牌 → 整数宽度守卫 → 索引 ToIntegerOrInfinity → +/// 相对字节偏移越界 RangeError →(写族)ValidateTypedArray 写守卫。 +/// +/// # 步骤 +/// 1. `get_typed_array_data` 品牌校验(非 TA 对象抛 TypeError)。 +/// 2. 整数宽度守卫(浮点/clamped 视图抛 TypeError)。 +/// 3. 索引经 ToIntegerOrInfinity(valueOf/toString 抛错原值上抛,先于越界判)。 +/// 4. 相对字节偏移 = view.byte_offset + index·bpe(f64 运算);越界 +/// (`< 0` 或 `>= buffer 字节长`)抛 RangeError,detach 视同越界。 +/// 5. 写族加查写守卫(immutable/detach 抛 TypeError)。 +/// +/// # 边界与前提 +/// - 返回的载荷指针、视图与偏移在 session 独占期内有效,调用方同一语句内消费。 +/// - 偏移已验证落在 `[0, buffer 字节长)`,`as usize` 安全。 +/// +/// # 副作用 +/// 无(纯读;写守卫只读 immutable 位)。 +fn resolve_atomic_access( + vm: &mut H, this_val: JsValue, writable: bool, index_val: JsValue, +) -> Result<(*mut ArrayBufferPayload, TypedArrayData, usize), JsValue> { + let view = get_typed_array_data(vm, this_val)?; + if !is_integer_kind(view.kind) { + return Err(type_error(vm, "Atomics operations require an integer TypedArray type")); + } + let index = ta_to_integer_or_infinity(vm, index_val)?; + + // 缓冲字节长:AB/SAB 双认(buffer_payload_ptr),载荷缺失视同越界。 + let buffer_ptr = view.buffer.as_js_object_ptr(); + if buffer_ptr.is_null() { + return Err(type_error(vm, "TypedArray buffer internal state invalid")); + } + // SAFETY: buffer 对象与视图同生命周期,此处只读载荷指针。 + let payload_ptr = match buffer_payload_ptr(unsafe { &*buffer_ptr }) { + Some(p) if !p.is_null() => p, + _ => return Err(range_error(vm, "invalid indexed access to Atomics")), + }; + // SAFETY: payload_ptr 经 buffer_payload_ptr 校验为合法载荷盒,只读字节长。 + let buffer_len = unsafe { (*payload_ptr).data.as_ref().map_or(0, |d| d.len()) }; + + let offset = view.byte_offset as f64 + index * (view.kind.bytes_per_element() as f64); + if offset < 0.0 || offset >= buffer_len as f64 { + return Err(range_error(vm, "invalid indexed access to Atomics")); + } + if writable { + ta_validate(vm, view, true)?; + } + Ok((payload_ptr, view, offset as usize)) +} + +/// 读指定偏移元素并转为 JS 值;detach(`data` 为 `None`)返回 `None`。 +fn atomic_read( + vm: &mut H, payload_ptr: *mut ArrayBufferPayload, kind: TypedArrayKind, offset: usize, +) -> Option { + // SAFETY: payload_ptr 经 resolve_atomic_access 校验为存活载荷盒,只读字节切片。 + let bytes = unsafe { &*payload_ptr }.data.as_deref()?; + Some(read_element(vm, kind, bytes, offset)) +} + +/// 把已转换值按位模式写入指定偏移;detach 静默 no-op(越界语义已由偏移判收口)。 +fn atomic_write( + vm: &mut H, payload_ptr: *mut ArrayBufferPayload, kind: TypedArrayKind, offset: usize, value: JsValue, +) { + // SAFETY: payload_ptr 经 resolve_atomic_access 校验为存活载荷盒,只写字节切片。 + let Some(bytes) = unsafe { &mut *payload_ptr }.data.as_deref_mut() else { + return; + }; + write_element(vm, kind, bytes, offset, value); +} + +/// 读-改-写运算结果:整数宽度按算术/位运算在 i32 域(语料值 < 2^31,f64 精确), +/// BigInt 宽度在 BigInt 域;宽度截断由 [`atomic_write`] 收口,返回待写值。 +fn arithmetic_write_value( + vm: &mut H, kind: TypedArrayKind, op: &str, old: JsValue, value: JsValue, +) -> JsValue { + if is_bigint_kind(kind) { + let old_bi = vm.bigint_value(old).clone(); + let val_bi = vm.bigint_value(value).clone(); + let r: BigInt = match op { + "add" => &old_bi + &val_bi, + "sub" => &old_bi - &val_bi, + "and" => &old_bi & &val_bi, + "or" => &old_bi | &val_bi, + "xor" => &old_bi ^ &val_bi, + _ => unreachable!("未知原子运算"), + }; + return vm.new_bigint(r); + } + let old_i = oxide_runtime_api::to_number(old) as i32; + let val_i = oxide_runtime_api::to_number(value) as i32; + let r = match op { + "add" => old_i.wrapping_add(val_i), + "sub" => old_i.wrapping_sub(val_i), + "and" => old_i & val_i, + "or" => old_i | val_i, + "xor" => old_i ^ val_i, + _ => unreachable!("未知原子运算"), + }; + JsValue::int(r) +} + +/// `Atomics.load(typedArray, index)`:读指定索引元素。 +pub fn atomics_load(vm: &mut H, args: &[u8]) -> NativeResult { + let this_val = arg_at(vm, args, 0); + let index_val = arg_at(vm, args, 1); + let (payload_ptr, view, offset) = native_try!(resolve_atomic_access(vm, this_val, false, index_val)); + NativeResult::Ok(atomic_read(vm, payload_ptr, view.kind, offset).unwrap_or(JsValue::undefined())) +} + +/// `Atomics.store(typedArray, index, value)`:写值后读回返回(宽度归一,-0 → +0)。 +pub fn atomics_store(vm: &mut H, args: &[u8]) -> NativeResult { + let this_val = arg_at(vm, args, 0); + let index_val = arg_at(vm, args, 1); + let value_val = arg_at(vm, args, 2); + let (payload_ptr, view, offset) = native_try!(resolve_atomic_access(vm, this_val, true, index_val)); + let value = native_try!(ta_element_value(vm, view.kind, value_val)); + atomic_write(vm, payload_ptr, view.kind, offset, value); + NativeResult::Ok(atomic_read(vm, payload_ptr, view.kind, offset).unwrap_or(value)) +} + +/// `Atomics.exchange(typedArray, index, value)`:读旧值、写新值、返回旧值。 +pub fn atomics_exchange(vm: &mut H, args: &[u8]) -> NativeResult { + let this_val = arg_at(vm, args, 0); + let index_val = arg_at(vm, args, 1); + let value_val = arg_at(vm, args, 2); + let (payload_ptr, view, offset) = native_try!(resolve_atomic_access(vm, this_val, true, index_val)); + let old = atomic_read(vm, payload_ptr, view.kind, offset).unwrap_or(JsValue::undefined()); + let value = native_try!(ta_element_value(vm, view.kind, value_val)); + atomic_write(vm, payload_ptr, view.kind, offset, value); + NativeResult::Ok(old) +} + +/// `Atomics.add(typedArray, index, value)`:读旧值、加 value 写回、返回旧值。 +pub fn atomics_add(vm: &mut H, args: &[u8]) -> NativeResult { + atomic_arithmetic(vm, args, "add") +} + +/// `Atomics.sub(typedArray, index, value)`:读旧值、减 value 写回、返回旧值。 +pub fn atomics_sub(vm: &mut H, args: &[u8]) -> NativeResult { + atomic_arithmetic(vm, args, "sub") +} + +/// `Atomics.and(typedArray, index, value)`:读旧值、与 value 按位与写回、返回旧值。 +pub fn atomics_and(vm: &mut H, args: &[u8]) -> NativeResult { + atomic_arithmetic(vm, args, "and") +} + +/// `Atomics.or(typedArray, index, value)`:读旧值、与 value 按位或写回、返回旧值。 +pub fn atomics_or(vm: &mut H, args: &[u8]) -> NativeResult { + atomic_arithmetic(vm, args, "or") +} + +/// `Atomics.xor(typedArray, index, value)`:读旧值、与 value 按位异或写回、返回旧值。 +pub fn atomics_xor(vm: &mut H, args: &[u8]) -> NativeResult { + atomic_arithmetic(vm, args, "xor") +} + +/// add/sub/and/or/xor 共享核:读旧值 → 运算值转换 → 读-改-写 → 返回旧值。 +fn atomic_arithmetic(vm: &mut H, args: &[u8], op: &str) -> NativeResult { + let this_val = arg_at(vm, args, 0); + let index_val = arg_at(vm, args, 1); + let value_val = arg_at(vm, args, 2); + let (payload_ptr, view, offset) = native_try!(resolve_atomic_access(vm, this_val, true, index_val)); + let old = atomic_read(vm, payload_ptr, view.kind, offset).unwrap_or(JsValue::undefined()); + let value = native_try!(ta_element_value(vm, view.kind, value_val)); + let result = arithmetic_write_value(vm, view.kind, op, old, value); + atomic_write(vm, payload_ptr, view.kind, offset, result); + NativeResult::Ok(old) +} + +/// `Atomics.compareExchange(typedArray, index, expected, replacement)`:读旧值; +/// 相等(数值宽度 `==`、BigInt 宽度 BigInt 相等)则写 replacement;返回旧值。 +pub fn atomics_compare_exchange(vm: &mut H, args: &[u8]) -> NativeResult { + let this_val = arg_at(vm, args, 0); + let index_val = arg_at(vm, args, 1); + let expected_val = arg_at(vm, args, 2); + let replacement_val = arg_at(vm, args, 3); + let (payload_ptr, view, offset) = native_try!(resolve_atomic_access(vm, this_val, true, index_val)); + let old = atomic_read(vm, payload_ptr, view.kind, offset).unwrap_or(JsValue::undefined()); + let expected = native_try!(ta_element_value(vm, view.kind, expected_val)); + let matched = if is_bigint_kind(view.kind) { + let old_bi = vm.bigint_value(old).clone(); + let expected_bi = vm.bigint_value(expected).clone(); + old_bi.cmp(&expected_bi) == std::cmp::Ordering::Equal + } else { + oxide_runtime_api::to_number(old) == oxide_runtime_api::to_number(expected) + }; + if matched { + let replacement = native_try!(ta_element_value(vm, view.kind, replacement_val)); + atomic_write(vm, payload_ptr, view.kind, offset, replacement); + } + NativeResult::Ok(old) +} + +/// `Atomics.isLockFree(size)`:单线程引擎无锁层级,`size ∈ {1,2,4,8}` 恒真,余假。 +pub fn atomics_is_lock_free(vm: &mut H, args: &[u8]) -> NativeResult { + let size_val = arg_at(vm, args, 1); + let n = native_try!(ta_to_integer_or_infinity(vm, size_val)); + NativeResult::Ok(JsValue::bool(matches!(n, 1.0 | 2.0 | 4.0 | 8.0))) +} diff --git a/crates/oxide_builtins/src/lib.rs b/crates/oxide_builtins/src/lib.rs index 48cbcb5e..a7d5f8e5 100644 --- a/crates/oxide_builtins/src/lib.rs +++ b/crates/oxide_builtins/src/lib.rs @@ -5,13 +5,15 @@ //! ArrayBuffer、DataView、Reflect、Function、Error 与全局函数(URI/escape 等)。 //! 每个内置方法以 `fn xxx(vm, args: &[u8]) -> NativeResult` 形式暴露, //! 由上层(oxide_vm / oxide_api)注册为 JS 全局对象上的 native function。 -//! 架构性延后的特性(Proxy、WeakMap、WeakSet、WeakRef、FinalizationRegistry、 -//! Atomics)在 `stubs` 中仅提供占位实现,调用时抛 TypeError。 +//! 架构性延后的特性(Proxy、WeakMap、WeakSet、WeakRef、FinalizationRegistry) +//! 在 `stubs` 中仅提供占位实现,调用时抛 TypeError。 /// Array 内置对象实现(目录模块:common 共享助手、from 构造器与静态方法、element 元素变更、iterate 高阶迭代、sort_iterator 排序与迭代协议、immutable ES2023 不可变方法族)。 pub mod array; /// ArrayBuffer 内置对象实现(字节缓冲区与 byteLength/slice/isView)。 pub mod array_buffer; +/// Atomics 全局纯对象实现(10 个原子方法,单线程退化读-改-写)。 +pub mod atomics; /// BigInt 内置对象实现(constructor 与 prototype 的 toString)。 pub mod bigint; /// Boolean 内置对象实现(constructor 与 prototype 的 valueOf/toString)。 diff --git a/crates/oxide_kernel/src/builtin/construct.rs b/crates/oxide_kernel/src/builtin/construct.rs index aea7e458..52e57463 100644 --- a/crates/oxide_kernel/src/builtin/construct.rs +++ b/crates/oxide_kernel/src/builtin/construct.rs @@ -360,7 +360,7 @@ pub(crate) fn wire_builtin_world_links(world: &BuiltinWorld) { } let obj_proto_val = JsValue::from_js_object(world.object_proto.as_ptr() as *mut JsObject); - let non_object_protos: [&P; 26] = [ + let non_object_protos: [&P; 27] = [ &world.array_proto, &world.function_proto, &world.string_proto, @@ -374,6 +374,7 @@ pub(crate) fn wire_builtin_world_links(world: &BuiltinWorld) { &world.regexp_proto, &world.array_buffer_proto, &world.shared_array_buffer_proto, + &world.atomics_object, &world.data_view_proto, &world.typed_array_proto, &world.instant_proto, @@ -484,6 +485,8 @@ impl BuiltinWorld { let json_object = P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())); + let atomics_object = P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())); + let console_object = P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())); let (date_proto, date_constructor) = make_named_pair(string_forge, shape_forge, labels, "Date"); @@ -583,6 +586,7 @@ impl BuiltinWorld { array_buffer_proto, shared_array_buffer_proto, shared_array_buffer_constructor, + atomics_object, data_view_constructor, data_view_proto, typed_array_proto: typed_arrays.typed_array_proto, diff --git a/crates/oxide_kernel/src/builtin/rebuild.rs b/crates/oxide_kernel/src/builtin/rebuild.rs index 68d4bc15..ff814ad7 100644 --- a/crates/oxide_kernel/src/builtin/rebuild.rs +++ b/crates/oxide_kernel/src/builtin/rebuild.rs @@ -314,6 +314,11 @@ impl BuiltinWorld { } else { (current.shared_array_buffer_proto.clone(), current.shared_array_buffer_constructor.clone()) }; + let atomics_object = if dirty.atomics { + P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())) + } else { + current.atomics_object.clone() + }; let (data_view_proto, data_view_constructor) = if dirty.data_view { make_named_pair(string_forge, shape_forge, labels, "DataView") } else { @@ -518,6 +523,7 @@ impl BuiltinWorld { array_buffer_proto, shared_array_buffer_proto, shared_array_buffer_constructor, + atomics_object, data_view_constructor, data_view_proto, typed_array_proto: typed_arrays.typed_array_proto, diff --git a/crates/oxide_kernel/src/builtin/world.rs b/crates/oxide_kernel/src/builtin/world.rs index 9a7d5bda..aae86ea9 100644 --- a/crates/oxide_kernel/src/builtin/world.rs +++ b/crates/oxide_kernel/src/builtin/world.rs @@ -52,6 +52,9 @@ pub struct BuiltinWorld { /// `make_named_pair` 成对构造,方法/访问器由绑定层安装。 pub shared_array_buffer_proto: P, pub shared_array_buffer_constructor: P, + /// `Atomics` 全局纯对象(非函数):10 个原子方法由绑定层安装, + /// `@@toStringTag` 与原型链在 `wire_builtin_world_links` 落到 Object.prototype。 + pub atomics_object: P, pub data_view_constructor: P, pub data_view_proto: P, pub typed_array_proto: P, @@ -347,7 +350,7 @@ impl BuiltinWorld { /// session 收尾(`teardown_heap_data`)与选择性重建收尾(`retire_replaced`) /// 的 P 字段枚举唯一入口:`BuiltinWorld` 新增 P 字段须在此同步补一行,否则 /// 收尾时该字段属性区无法释放、重建原型槽改写/释放漏掉该字段。 - pub(crate) fn all_p_fields(&self) -> [&P; 106] { + pub(crate) fn all_p_fields(&self) -> [&P; 107] { [ &self.object_proto, &self.array_proto, @@ -386,6 +389,7 @@ impl BuiltinWorld { &self.array_buffer_proto, &self.shared_array_buffer_proto, &self.shared_array_buffer_constructor, + &self.atomics_object, &self.data_view_constructor, &self.data_view_proto, &self.typed_array_proto, @@ -540,6 +544,7 @@ impl BuiltinWorld { BuiltinId::ArrayBufferProto => &self.array_buffer_proto, BuiltinId::SharedArrayBufferProto => &self.shared_array_buffer_proto, BuiltinId::SharedArrayBufferConstructor => &self.shared_array_buffer_constructor, + BuiltinId::AtomicsObject => &self.atomics_object, BuiltinId::DataViewConstructor => &self.data_view_constructor, BuiltinId::DataViewProto => &self.data_view_proto, BuiltinId::TypedArrayProto => &self.typed_array_proto, @@ -699,4 +704,31 @@ mod tests { )); assert!(std::ptr::eq(ab_proto, session.builtin_world.array_buffer_proto.as_ptr() as *mut JsObject)); } + + /// Atomics 家族脏线冒烟:仅 Atomics 单例世代漂移 → 选择性重置只判 Atomics + /// 家族脏,ArrayBuffer 家族指针原样保留(钉 dirty_since_snapshot 家族线接线)。 + #[test] + fn atomics_family_selective_rebuild() { + use crate::kernel::{KernelConfig, KernelCore, KernelSession}; + let core = KernelCore::new(KernelConfig::minimal()); + let mut session = KernelSession::new(&core); + let old_world = std::sync::Arc::clone(&session.builtin_world); + let atomics = old_world.atomics_object.as_ptr() as *mut JsObject; + let ab_proto = old_world.array_buffer_proto.as_ptr() as *mut JsObject; + + unsafe { + (&mut *atomics).bump_generation(); + } + let dirty = session.selective_reset(&core); + assert!(dirty.atomics); + assert!(!dirty.array_buffer); + assert!(!dirty.shared_array_buffer); + + // 脏家族换新对象,未脏家族指针原样保留。 + assert!(!std::ptr::eq( + atomics, + session.builtin_world.atomics_object.as_ptr() as *mut JsObject + )); + assert!(std::ptr::eq(ab_proto, session.builtin_world.array_buffer_proto.as_ptr() as *mut JsObject)); + } } diff --git a/crates/oxide_kernel/src/kernel/builtin_id.rs b/crates/oxide_kernel/src/kernel/builtin_id.rs index 05b2c32c..784ba286 100644 --- a/crates/oxide_kernel/src/kernel/builtin_id.rs +++ b/crates/oxide_kernel/src/kernel/builtin_id.rs @@ -11,7 +11,7 @@ use crate::builtin::BuiltinWorld; /// 维护注意:每个新增的 `BuiltinWorld` 对象字段都必须加到这里以及 /// `KernelSession::dirty_since_snapshot()`,以便选择性重置重建正确的 /// builtin 家族。 -pub const NUM_BUILTINS: usize = 96; +pub const NUM_BUILTINS: usize = 97; /// 内置对象枚举 id,与 `BuiltinWorld` 中的存储槽一一对应。 /// @@ -117,6 +117,7 @@ pub enum BuiltinId { PlainYearMonthProto = 93, SharedArrayBufferProto = 94, SharedArrayBufferConstructor = 95, + AtomicsObject = 96, } impl BuiltinId { @@ -220,6 +221,7 @@ impl BuiltinId { BuiltinId::PlainYearMonthProto, BuiltinId::SharedArrayBufferProto, BuiltinId::SharedArrayBufferConstructor, + BuiltinId::AtomicsObject, ]; } @@ -288,6 +290,7 @@ pub struct BuiltinDirtySet { pub regexp: bool, pub array_buffer: bool, pub shared_array_buffer: bool, + pub atomics: bool, pub data_view: bool, pub typed_array_family: bool, pub temporal: bool, @@ -320,6 +323,7 @@ impl BuiltinDirtySet { regexp: true, array_buffer: true, shared_array_buffer: true, + atomics: true, data_view: true, typed_array_family: true, temporal: true, @@ -347,6 +351,7 @@ impl BuiltinDirtySet { || self.regexp || self.array_buffer || self.shared_array_buffer + || self.atomics || self.data_view || self.typed_array_family || self.temporal @@ -364,18 +369,19 @@ impl BuiltinDirtySet { mod tests { use super::*; - /// 槽对齐面:表尾追加 SAB 家族后总槽数 96,既有 94 个判别值零位移, + /// 槽对齐面:表尾追加 Atomics 单例后总槽数 97,既有 96 个判别值零位移, /// 快照数组随 NUM_BUILTINS 自动扩维、逐槽对齐。 #[test] fn builtin_snapshot_all_slots_aligned() { - assert_eq!(NUM_BUILTINS, 96); + assert_eq!(NUM_BUILTINS, 97); assert_eq!(BuiltinId::ALL.len(), NUM_BUILTINS); - // 前 94 项判别值 0-93 逐项不变(尾追加零位移)。 - for i in 0..94usize { + // 前 96 项判别值 0-95 逐项不变(尾追加零位移)。 + for i in 0..96usize { assert_eq!(BuiltinId::ALL[i] as usize, i); } assert_eq!(BuiltinId::ALL[94], BuiltinId::SharedArrayBufferProto); assert_eq!(BuiltinId::ALL[95], BuiltinId::SharedArrayBufferConstructor); + assert_eq!(BuiltinId::ALL[96], BuiltinId::AtomicsObject); // 快照经 session 全量构造路径采集,generations 数组维度 = 槽数。 use crate::kernel::{KernelConfig, KernelCore, KernelSession}; diff --git a/crates/oxide_kernel/src/kernel/session.rs b/crates/oxide_kernel/src/kernel/session.rs index e8d97e9d..801d5640 100644 --- a/crates/oxide_kernel/src/kernel/session.rs +++ b/crates/oxide_kernel/src/kernel/session.rs @@ -159,6 +159,7 @@ impl KernelSession { || gen(BuiltinId::ArrayBufferProto) != snap(BuiltinId::ArrayBufferProto), shared_array_buffer: gen(BuiltinId::SharedArrayBufferProto) != snap(BuiltinId::SharedArrayBufferProto) || gen(BuiltinId::SharedArrayBufferConstructor) != snap(BuiltinId::SharedArrayBufferConstructor), + atomics: gen(BuiltinId::AtomicsObject) != snap(BuiltinId::AtomicsObject), data_view: gen(BuiltinId::DataViewConstructor) != snap(BuiltinId::DataViewConstructor) || gen(BuiltinId::DataViewProto) != snap(BuiltinId::DataViewProto), typed_array_family: gen(BuiltinId::TypedArrayProto) != snap(BuiltinId::TypedArrayProto)