mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 02:31:13 +08:00
feat: 内核与内置层增 Atomics 对象槽位与十方法
This commit is contained in:
@@ -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<H: VmHost>(vm: &mut H, msg: &str) -> JsValue {
|
||||
crate::error::create_type_error(vm, msg)
|
||||
}
|
||||
|
||||
fn range_error<H: VmHost>(vm: &mut H, msg: &str) -> JsValue {
|
||||
crate::error::create_range_error(vm, msg)
|
||||
}
|
||||
|
||||
/// 按寄存器下标取实参;越界(实参缺失)回落 undefined(JS 缺省参语义)。
|
||||
fn arg_at<H: VmHost>(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<H: VmHost>(
|
||||
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<H: VmHost>(
|
||||
vm: &mut H, payload_ptr: *mut ArrayBufferPayload, kind: TypedArrayKind, offset: usize,
|
||||
) -> Option<JsValue> {
|
||||
// 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<H: VmHost>(
|
||||
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<H: VmHost>(
|
||||
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<H: VmHost>(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<H: VmHost>(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<H: VmHost>(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<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
atomic_arithmetic(vm, args, "add")
|
||||
}
|
||||
|
||||
/// `Atomics.sub(typedArray, index, value)`:读旧值、减 value 写回、返回旧值。
|
||||
pub fn atomics_sub<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
atomic_arithmetic(vm, args, "sub")
|
||||
}
|
||||
|
||||
/// `Atomics.and(typedArray, index, value)`:读旧值、与 value 按位与写回、返回旧值。
|
||||
pub fn atomics_and<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
atomic_arithmetic(vm, args, "and")
|
||||
}
|
||||
|
||||
/// `Atomics.or(typedArray, index, value)`:读旧值、与 value 按位或写回、返回旧值。
|
||||
pub fn atomics_or<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
atomic_arithmetic(vm, args, "or")
|
||||
}
|
||||
|
||||
/// `Atomics.xor(typedArray, index, value)`:读旧值、与 value 按位异或写回、返回旧值。
|
||||
pub fn atomics_xor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
atomic_arithmetic(vm, args, "xor")
|
||||
}
|
||||
|
||||
/// add/sub/and/or/xor 共享核:读旧值 → 运算值转换 → 读-改-写 → 返回旧值。
|
||||
fn atomic_arithmetic<H: VmHost>(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<H: VmHost>(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<H: VmHost>(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)))
|
||||
}
|
||||
@@ -5,13 +5,15 @@
|
||||
//! ArrayBuffer、DataView、Reflect、Function、Error 与全局函数(URI/escape 等)。
|
||||
//! 每个内置方法以 `fn xxx<H: VmHost>(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)。
|
||||
|
||||
@@ -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<JsObject>; 26] = [
|
||||
let non_object_protos: [&P<JsObject>; 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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -52,6 +52,9 @@ pub struct BuiltinWorld {
|
||||
/// `make_named_pair` 成对构造,方法/访问器由绑定层安装。
|
||||
pub shared_array_buffer_proto: P<JsObject>,
|
||||
pub shared_array_buffer_constructor: P<JsObject>,
|
||||
/// `Atomics` 全局纯对象(非函数):10 个原子方法由绑定层安装,
|
||||
/// `@@toStringTag` 与原型链在 `wire_builtin_world_links` 落到 Object.prototype。
|
||||
pub atomics_object: P<JsObject>,
|
||||
pub data_view_constructor: P<JsObject>,
|
||||
pub data_view_proto: P<JsObject>,
|
||||
pub typed_array_proto: P<JsObject>,
|
||||
@@ -347,7 +350,7 @@ impl BuiltinWorld {
|
||||
/// session 收尾(`teardown_heap_data`)与选择性重建收尾(`retire_replaced`)
|
||||
/// 的 P 字段枚举唯一入口:`BuiltinWorld` 新增 P 字段须在此同步补一行,否则
|
||||
/// 收尾时该字段属性区无法释放、重建原型槽改写/释放漏掉该字段。
|
||||
pub(crate) fn all_p_fields(&self) -> [&P<JsObject>; 106] {
|
||||
pub(crate) fn all_p_fields(&self) -> [&P<JsObject>; 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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user