feat: 绑定 Atomics 全局对象方法并接入 test262

This commit is contained in:
2026-09-23 19:08:35 +00:00
parent c5589c98c2
commit a7fa12e588
9 changed files with 267 additions and 46 deletions
+28 -26
View File
@@ -65,10 +65,10 @@ fn is_bigint_kind(kind: TypedArrayKind) -> bool {
/// # 步骤
/// 1. `get_typed_array_data` 品牌校验(非 TA 对象抛 TypeError)。
/// 2. 整数宽度守卫(浮点/clamped 视图抛 TypeError)。
/// 3. 索引经 ToIntegerOrInfinity(valueOf/toString 抛错原值上抛,先于越界判)。
/// 4. 相对字节偏移 = view.byte_offset + index·bpe(f64 运算);越界
/// 3. 写族加查写守卫(immutable/detach 抛 TypeError),先于索引/值 coercion。
/// 4. 索引经 ToIntegerOrInfinity(valueOf/toString 抛错原值上抛,先于越界判)。
/// 5. 相对字节偏移 = view.byte_offset + index·bpe(f64 运算);越界
/// (`< 0` 或 `>= buffer 字节长`)抛 RangeError,detach 视同越界。
/// 5. 写族加查写守卫(immutable/detach 抛 TypeError)。
///
/// # 边界与前提
/// - 返回的载荷指针、视图与偏移在 session 独占期内有效,调用方同一语句内消费。
@@ -83,6 +83,11 @@ fn resolve_atomic_access<H: VmHost>(
if !is_integer_kind(view.kind) {
return Err(type_error(vm, "Atomics operations require an integer TypedArray type"));
}
// 写守卫(不可变缓冲 TypeError)先于索引/值 coercion 求值:守卫抛错时
// index/value 的 valueOf 不得被调用(语料 calls 序列口径)。
if writable {
ta_validate(vm, view, true)?;
}
let index = ta_to_integer_or_infinity(vm, index_val)?;
// 缓冲字节长:AB/SAB 双认(buffer_payload_ptr),载荷缺失视同越界。
@@ -102,9 +107,6 @@ fn resolve_atomic_access<H: VmHost>(
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))
}
@@ -161,18 +163,18 @@ fn arithmetic_write_value<H: VmHost>(
/// `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));
let ta_val = arg_at(vm, args, 1);
let index_val = arg_at(vm, args, 2);
let (payload_ptr, view, offset) = native_try!(resolve_atomic_access(vm, ta_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 ta_val = arg_at(vm, args, 1);
let index_val = arg_at(vm, args, 2);
let value_val = arg_at(vm, args, 3);
let (payload_ptr, view, offset) = native_try!(resolve_atomic_access(vm, ta_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))
@@ -180,10 +182,10 @@ pub fn atomics_store<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
/// `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 ta_val = arg_at(vm, args, 1);
let index_val = arg_at(vm, args, 2);
let value_val = arg_at(vm, args, 3);
let (payload_ptr, view, offset) = native_try!(resolve_atomic_access(vm, ta_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);
@@ -217,10 +219,10 @@ pub fn atomics_xor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
/// 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 ta_val = arg_at(vm, args, 1);
let index_val = arg_at(vm, args, 2);
let value_val = arg_at(vm, args, 3);
let (payload_ptr, view, offset) = native_try!(resolve_atomic_access(vm, ta_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);
@@ -231,11 +233,11 @@ fn atomic_arithmetic<H: VmHost>(vm: &mut H, args: &[u8], op: &str) -> NativeResu
/// `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 ta_val = arg_at(vm, args, 1);
let index_val = arg_at(vm, args, 2);
let expected_val = arg_at(vm, args, 3);
let replacement_val = arg_at(vm, args, 4);
let (payload_ptr, view, offset) = native_try!(resolve_atomic_access(vm, ta_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) {
-4
View File
@@ -25,7 +25,3 @@ pub fn weakref_stub<H: VmHost>(vm: &mut H, _args: &[u8]) -> NativeResult {
pub fn finalization_registry_stub<H: VmHost>(vm: &mut H, _args: &[u8]) -> NativeResult {
stub_error(vm, "FinalizationRegistry")
}
/// `Atomics` 全局占位:始终抛 TypeError。按设计延后实现。
pub fn atomics_stub<H: VmHost>(vm: &mut H, _args: &[u8]) -> NativeResult {
stub_error(vm, "Atomics")
}