fix: BigInt64Array/BigUint64Array 与 DataView BigInt 存取走真 BigInt 语义

TA 元素读写按 kind 分流:BigInt 类型走 ToBigInt(Number 入参抛 TypeError、
写入 mod 2^64 截断、读出为真 BigInt 值),数值类型走 ToNumber 且显式拒绝
BigInt 值;消除 64 位整数经 f64 中转的静默精度丢失。

- runtime_api 新增公共 to_bigint_full / string_to_bigint_full,bigint 构造器
  与 asIntN/asUintN 改调公共版消除双实现
- sort/toSorted 默认序对 BigInt 类型按 i64/u64 值比较;reverse/copyWithin/
  filter/toReversed/with 消除无谓数值中转
- 构造器第一参数非对象统一走 ToIndex(bool/null/BigInt/字符串),Symbol 抛
  TypeError
- DataView get/setBigInt64/getBigUint64 返回 BigInt 值、入参按 ToBigInt 校验
- 测试:精度往返 / TypeError / mod 2^64 / 字节序 / 排序 / 回调值类型断言
This commit is contained in:
2026-08-15 20:04:48 +08:00
parent f63b41454f
commit 1b9974fe7f
6 changed files with 525 additions and 211 deletions
+33 -12
View File
@@ -2,6 +2,9 @@ use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
use oxide_types::object::{JsObject, NativeFnPtr, PropAttributes};
use oxide_types::value::JsValue;
use num_bigint::BigInt;
use num_traits::ToPrimitive;
use crate::array_buffer::array_buffer_data_ptr;
use oxide_runtime_api::{NativeResult, VmHost};
@@ -323,7 +326,8 @@ pub fn data_view_get_float64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
NativeResult::Ok(JsValue::float(n))
}
/// `DataView.prototype.getBigInt64(byteOffset, littleEndian)`:读取 8 字节有符号 64 位整数。
/// `DataView.prototype.getBigInt64(byteOffset, littleEndian)`:读取 8 字节有符号 64 位
/// 整数并返回 BigInt 值。
pub fn data_view_get_big_int64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let bytes = native_try!(read_bytes::<8, H>(vm, args));
let n = if is_little_endian(vm, args, 2) {
@@ -331,10 +335,11 @@ pub fn data_view_get_big_int64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResu
} else {
i64::from_be_bytes(bytes)
};
NativeResult::Ok(JsValue::float(n as f64))
NativeResult::Ok(vm.new_bigint(BigInt::from(n)))
}
/// `DataView.prototype.getBigUint64(byteOffset, littleEndian)`:读取 8 字节无符号 64 位整数。
/// `DataView.prototype.getBigUint64(byteOffset, littleEndian)`:读取 8 字节无符号
/// 64 位整数并返回 BigInt 值。
pub fn data_view_get_big_uint64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let bytes = native_try!(read_bytes::<8, H>(vm, args));
let n = if is_little_endian(vm, args, 2) {
@@ -342,7 +347,7 @@ pub fn data_view_get_big_uint64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeRes
} else {
u64::from_be_bytes(bytes)
};
NativeResult::Ok(JsValue::float(n as f64))
NativeResult::Ok(vm.new_bigint(BigInt::from(n)))
}
/// `DataView.prototype.setInt8(byteOffset, value)`:写入 1 字节有符号整数。
@@ -431,30 +436,46 @@ pub fn data_view_set_float64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
NativeResult::Ok(JsValue::undefined())
}
/// `DataView.prototype.setBigInt64(byteOffset, value, littleEndian)`:写入 8 字节有符号 64 位整数。
/// `DataView.prototype.setBigInt64(byteOffset, value, littleEndian)`:按 ToBigInt
/// 语义接收值(Number 入参抛 TypeError),取低 64 位位模式写入 8 字节有符号整数。
pub fn data_view_set_big_int64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let value = numeric_arg(vm, args, 2) as i64;
let value = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
let b =
native_try!(oxide_runtime_api::to_bigint_full(value, vm).map_err(|e| crate::iterator::engine_error(vm, &e)));
let low = low64(vm, b) as i64;
let bytes = if is_little_endian(vm, args, 3) {
value.to_le_bytes()
low.to_le_bytes()
} else {
value.to_be_bytes()
low.to_be_bytes()
};
native_try!(write_bytes(vm, args, bytes));
NativeResult::Ok(JsValue::undefined())
}
/// `DataView.prototype.setBigUint64(byteOffset, value, littleEndian)`:写入 8 字节无符号 64 位整数。
/// `DataView.prototype.setBigUint64(byteOffset, value, littleEndian)`:按 ToBigInt
/// 语义接收值(Number 入参抛 TypeError),取低 64 位位模式写入 8 字节无符号整数。
pub fn data_view_set_big_uint64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let value = numeric_arg(vm, args, 2) as u64;
let value = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
let b =
native_try!(oxide_runtime_api::to_bigint_full(value, vm).map_err(|e| crate::iterator::engine_error(vm, &e)));
let low = low64(vm, b);
let bytes = if is_little_endian(vm, args, 3) {
value.to_le_bytes()
low.to_le_bytes()
} else {
value.to_be_bytes()
low.to_be_bytes()
};
native_try!(write_bytes(vm, args, bytes));
NativeResult::Ok(JsValue::undefined())
}
/// 取 BigInt 值低 64 位位模式:与 2^64-1 掩码后恒非负且可转 u64。
fn low64<H: VmHost>(vm: &mut H, val: JsValue) -> u64 {
let v = vm.bigint_value(val);
(v & (BigInt::from(u64::MAX)))
.to_u64()
.expect("与 u64::MAX 掩码后恒在 u64 范围")
}
/// `DataView.prototype.toString`:校验 receiver 后返回 `[object DataView]`。
pub fn data_view_to_string<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });