mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 11:11:11 +08:00
fix: DataView 原型访问器与 ToNumber 强转序位收口
This commit is contained in:
@@ -233,6 +233,9 @@ pub(crate) fn clamp_relative(rel: f64, n_f: f64, n: usize) -> usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// IsConstructor 的近似判定(与 construct_array_from_result 保持一致)。
|
/// IsConstructor 的近似判定(与 construct_array_from_result 保持一致)。
|
||||||
|
///
|
||||||
|
/// native 函数须带构造器 tag;bound 包装恒接受(target 可构造性在
|
||||||
|
/// `dispatch_new_bound` 入口复核,此处仅判值形态)。
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn is_constructor_value(c: JsValue) -> bool {
|
pub(crate) fn is_constructor_value(c: JsValue) -> bool {
|
||||||
if !c.is_object() {
|
if !c.is_object() {
|
||||||
@@ -241,7 +244,9 @@ pub(crate) fn is_constructor_value(c: JsValue) -> bool {
|
|||||||
let c_obj = unsafe { &*c.as_js_object_ptr() };
|
let c_obj = unsafe { &*c.as_js_object_ptr() };
|
||||||
c_obj.is_function()
|
c_obj.is_function()
|
||||||
&& !c_obj.is_arrow()
|
&& !c_obj.is_arrow()
|
||||||
&& !(c_obj.native_fn().is_some() && c_obj.type_tag != JsObject::OBJ_TYPE_CONSTRUCTOR)
|
&& !(c_obj.native_fn().is_some()
|
||||||
|
&& c_obj.type_tag != JsObject::OBJ_TYPE_CONSTRUCTOR
|
||||||
|
&& c_obj.type_tag != JsObject::OBJ_TYPE_BOUND)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 校验回调参数为可调用函数对象(判空与 is_function 均须通过),不是则抛 TypeError。
|
/// 校验回调参数为可调用函数对象(判空与 is_function 均须通过),不是则抛 TypeError。
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
|
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
|
||||||
use oxide_types::object::{JsObject, NativeFnPtr, PropAttributes};
|
use oxide_types::object::{JsObject, NativeFnPtr};
|
||||||
use oxide_types::value::JsValue;
|
use oxide_types::value::JsValue;
|
||||||
|
|
||||||
use num_bigint::BigInt;
|
use num_bigint::BigInt;
|
||||||
@@ -25,15 +25,28 @@ macro_rules! native_try {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ToIndex(ECMA-262 §7.1.19):ToNumber → NaN 归 0 → 非有限抛 RangeError → trunc →
|
||||||
|
/// 负值抛 RangeError。
|
||||||
|
///
|
||||||
|
/// # 边界与前提
|
||||||
|
/// - 序位按规范步序:trunc 先于判负(-0.99999 归 0,不抛)。
|
||||||
|
/// - 强转失败(对象 valueOf/toString 抛错、Symbol、BigInt)以 `Err` 传播原异常值,
|
||||||
|
/// 调用方不得吞成 NaN。
|
||||||
fn to_index<H: VmHost>(vm: &mut H, value: JsValue, msg: &str) -> Result<usize, JsValue> {
|
fn to_index<H: VmHost>(vm: &mut H, value: JsValue, msg: &str) -> Result<usize, JsValue> {
|
||||||
let n = vm.coerce_number_bounded(value).unwrap_or(f64::NAN);
|
let n = vm
|
||||||
|
.coerce_number_bounded(value)
|
||||||
|
.map_err(|e| crate::iterator::engine_error(vm, &e))?;
|
||||||
if n.is_nan() {
|
if n.is_nan() {
|
||||||
return Ok(0);
|
return Ok(0);
|
||||||
}
|
}
|
||||||
if !n.is_finite() || n < 0.0 {
|
if !n.is_finite() {
|
||||||
return Err(crate::error::create_range_error(vm, msg));
|
return Err(crate::error::create_range_error(vm, msg));
|
||||||
}
|
}
|
||||||
Ok(n.trunc() as usize)
|
let truncated = n.trunc();
|
||||||
|
if truncated < 0.0 {
|
||||||
|
return Err(crate::error::create_range_error(vm, msg));
|
||||||
|
}
|
||||||
|
Ok(truncated as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_little_endian<H: VmHost>(vm: &mut H, args: &[u8], idx: usize) -> bool {
|
fn is_little_endian<H: VmHost>(vm: &mut H, args: &[u8], idx: usize) -> bool {
|
||||||
@@ -42,15 +55,33 @@ fn is_little_endian<H: VmHost>(vm: &mut H, args: &[u8], idx: usize) -> bool {
|
|||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn numeric_arg<H: VmHost>(vm: &mut H, args: &[u8], idx: usize) -> f64 {
|
/// 可选 byteOffset 实参的 ToIndex(缺省 → 0),强转失败传播。
|
||||||
args.get(idx)
|
fn to_index_arg<H: VmHost>(vm: &mut H, args: &[u8], idx: usize) -> Result<usize, JsValue> {
|
||||||
.map(|reg| vm.coerce_number_bounded(vm.reg(*reg)).unwrap_or(f64::NAN))
|
if args.len() > idx {
|
||||||
.unwrap_or(0.0)
|
to_index(vm, vm.reg(args[idx]), "DataView offset out of bounds")
|
||||||
|
} else {
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_named_prop<H: VmHost>(vm: &mut H, obj: &mut JsObject, name: &str, value: JsValue, attributes: PropAttributes) {
|
/// value 实参的 ToNumber(缺省 → undefined → NaN),强转失败传播。
|
||||||
let si = vm.kernel_core().perm_interner().intern(name).0;
|
fn coerce_value_arg<H: VmHost>(vm: &mut H, args: &[u8], idx: usize) -> Result<f64, JsValue> {
|
||||||
let _ = vm.define_data_property(obj, si, value, attributes);
|
let value = if args.len() > idx { vm.reg(args[idx]) } else { JsValue::undefined() };
|
||||||
|
vm.coerce_number_bounded(value)
|
||||||
|
.map_err(|e| crate::iterator::engine_error(vm, &e))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ToInt32 回卷:0/±Infinity 归 0,trunc 后对 2^32 取模再按符号解释(位模式口径)。
|
||||||
|
fn to_int32(n: f64) -> i32 {
|
||||||
|
if n == 0.0 || !n.is_finite() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
let int = n.trunc().rem_euclid(4_294_967_296.0) as u32;
|
||||||
|
if int > i32::MAX as u32 {
|
||||||
|
(int as i64 - 4_294_967_296i64) as i32
|
||||||
|
} else {
|
||||||
|
int as i32
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_data_view_data<H: VmHost>(vm: &mut H, this_val: JsValue) -> Result<DataViewData, JsValue> {
|
fn get_data_view_data<H: VmHost>(vm: &mut H, this_val: JsValue) -> Result<DataViewData, JsValue> {
|
||||||
@@ -87,14 +118,8 @@ fn checked_absolute_offset<H: VmHost>(
|
|||||||
Ok(view.byte_offset + offset)
|
Ok(view.byte_offset + offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_bytes<const N: usize, H: VmHost>(vm: &mut H, args: &[u8]) -> Result<[u8; N], JsValue> {
|
/// GetViewValue 后半:按已校验的视图与偏移读 N 字节(越界抛 RangeError)。
|
||||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
fn read_bytes_at<const N: usize, H: VmHost>(vm: &mut H, view: DataViewData, offset: usize) -> Result<[u8; N], JsValue> {
|
||||||
let view = get_data_view_data(vm, this_val)?;
|
|
||||||
let offset = if args.len() > 1 {
|
|
||||||
to_index(vm, vm.reg(args[1]), "DataView offset out of bounds")?
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
let abs = checked_absolute_offset(vm, view, offset, N)?;
|
let abs = checked_absolute_offset(vm, view, offset, N)?;
|
||||||
let buffer_ptr = array_buffer_data_ptr(vm, view.buffer)?;
|
let buffer_ptr = array_buffer_data_ptr(vm, view.buffer)?;
|
||||||
let buffer = unsafe { &*buffer_ptr };
|
let buffer = unsafe { &*buffer_ptr };
|
||||||
@@ -106,14 +131,10 @@ fn read_bytes<const N: usize, H: VmHost>(vm: &mut H, args: &[u8]) -> Result<[u8;
|
|||||||
Ok(out)
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_bytes<const N: usize, H: VmHost>(vm: &mut H, args: &[u8], bytes: [u8; N]) -> Result<(), JsValue> {
|
/// SetViewValue 后半:按已校验的视图与偏移写 N 字节(越界抛 RangeError)。
|
||||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
fn write_bytes<const N: usize, H: VmHost>(
|
||||||
let view = get_data_view_data(vm, this_val)?;
|
vm: &mut H, view: DataViewData, offset: usize, bytes: [u8; N],
|
||||||
let offset = if args.len() > 1 {
|
) -> Result<(), JsValue> {
|
||||||
to_index(vm, vm.reg(args[1]), "DataView offset out of bounds")?
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
let abs = checked_absolute_offset(vm, view, offset, N)?;
|
let abs = checked_absolute_offset(vm, view, offset, N)?;
|
||||||
let buffer_ptr = array_buffer_data_ptr(vm, view.buffer)?;
|
let buffer_ptr = array_buffer_data_ptr(vm, view.buffer)?;
|
||||||
let buffer = unsafe { &mut *buffer_ptr };
|
let buffer = unsafe { &mut *buffer_ptr };
|
||||||
@@ -124,8 +145,52 @@ fn write_bytes<const N: usize, H: VmHost>(vm: &mut H, args: &[u8], bytes: [u8; N
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 校验 receiver 原型链含 `%DataView.prototype%`(`new DataView` 构造出的实例
|
||||||
|
/// 特征,普通调用面 this = globalThis 不满足)。
|
||||||
|
fn has_data_view_proto<H: VmHost>(vm: &mut H, this_val: JsValue) -> bool {
|
||||||
|
if !this_val.is_object() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let target = vm.session().builtin_world().data_view_proto.as_ptr() as *mut JsObject;
|
||||||
|
let mut cursor = this_val;
|
||||||
|
for _ in 0..1024 {
|
||||||
|
if !cursor.is_object() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let ptr = cursor.as_js_object_ptr();
|
||||||
|
if ptr.is_null() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if std::ptr::eq(ptr, target) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
cursor = unsafe { &*ptr }.proto();
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
/// `DataView(buffer, byteOffset, byteLength)` 构造逻辑:在 ArrayBuffer 上建立定点字节视图。
|
/// `DataView(buffer, byteOffset, byteLength)` 构造逻辑:在 ArrayBuffer 上建立定点字节视图。
|
||||||
|
///
|
||||||
|
/// # 步骤
|
||||||
|
/// 1. receiver 原型链不含 %DataView.prototype% → TypeError(普通调用面:
|
||||||
|
/// this = globalThis 不满足;构造路径恒传 DataView 原型链上的 receiver)。
|
||||||
|
/// 2. buffer 品牌校验(ArrayBufferData)。
|
||||||
|
/// 3. offset = ToIndex(byteOffset) 传播式;offset > bufferLen → RangeError。
|
||||||
|
/// 4. byteLength 缺省/undefined → bufferLen - offset,否则 ToIndex 传播式;
|
||||||
|
/// offset + byteLength > bufferLen → RangeError。
|
||||||
|
/// 5. GetPrototypeFromConstructor:经 `ordinary_get` 读 NewTarget(regs[255])
|
||||||
|
/// 的 `prototype`(触发访问器,读期异常原值传播);非对象回落 %DataView.prototype%。
|
||||||
|
/// 6. 分配 OBJ_TYPE_DATA_VIEW 对象并挂 DataViewData 状态盒。
|
||||||
|
///
|
||||||
|
/// # 边界与前提
|
||||||
|
/// - 原型读取在全部校验之后:越界 RangeError 先于抛错的 prototype getter。
|
||||||
|
/// - NewTarget 非对象(直调/缺省面)时直接回落默认原型,不抛错。
|
||||||
pub fn data_view_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn data_view_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
if !has_data_view_proto(vm, this_val) {
|
||||||
|
return NativeResult::Err(crate::error::create_type_error(vm, "DataView must be called with new"));
|
||||||
|
}
|
||||||
|
let new_target = vm.reg(255);
|
||||||
if args.len() < 2 {
|
if args.len() < 2 {
|
||||||
return NativeResult::Err(crate::error::create_type_error(vm, "DataView requires an ArrayBuffer"));
|
return NativeResult::Err(crate::error::create_type_error(vm, "DataView requires an ArrayBuffer"));
|
||||||
}
|
}
|
||||||
@@ -141,8 +206,14 @@ pub fn data_view_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
|||||||
return NativeResult::Err(crate::error::create_range_error(vm, "DataView byteOffset out of bounds"));
|
return NativeResult::Err(crate::error::create_range_error(vm, "DataView byteOffset out of bounds"));
|
||||||
}
|
}
|
||||||
let default_len = buffer_len - byte_offset;
|
let default_len = buffer_len - byte_offset;
|
||||||
|
// byteLength 显式 undefined 视同缺省(ToIndex(undefined) = 0 会吞掉视图长度)。
|
||||||
let byte_length = if args.len() > 3 {
|
let byte_length = if args.len() > 3 {
|
||||||
native_try!(to_index(vm, vm.reg(args[3]), "DataView byteLength out of bounds"))
|
let bl_val = vm.reg(args[3]);
|
||||||
|
if bl_val.is_undefined() {
|
||||||
|
default_len
|
||||||
|
} else {
|
||||||
|
native_try!(to_index(vm, bl_val, "DataView byteLength out of bounds"))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
default_len
|
default_len
|
||||||
};
|
};
|
||||||
@@ -150,8 +221,28 @@ pub fn data_view_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
|||||||
return NativeResult::Err(crate::error::create_range_error(vm, "DataView byteLength out of bounds"));
|
return NativeResult::Err(crate::error::create_range_error(vm, "DataView byteLength out of bounds"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let proto = vm.session().builtin_world().data_view_proto.as_ptr() as *mut JsObject;
|
// GetPrototypeFromConstructor:普通读触发原型链上的访问器 getter,
|
||||||
let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto));
|
// 读期用户异常经原值槽恢复后重抛。NewTarget 非对象(直调/缺省面)时
|
||||||
|
// 回落默认原型,不抛错。
|
||||||
|
let default_proto = JsValue::from_js_object(vm.session().builtin_world().data_view_proto.as_ptr() as *mut JsObject);
|
||||||
|
let proto = if new_target.is_object() {
|
||||||
|
let nt_ptr = new_target.as_js_object_ptr();
|
||||||
|
let nt_obj = unsafe { &*nt_ptr };
|
||||||
|
let proto_si = vm.kernel_core().perm_interner().intern("prototype").0;
|
||||||
|
let proto_val = match vm.ordinary_get(nt_obj, proto_si, new_target) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => return NativeResult::Err(crate::iterator::engine_error(vm, &e)),
|
||||||
|
};
|
||||||
|
if proto_val.is_object() {
|
||||||
|
proto_val
|
||||||
|
} else {
|
||||||
|
default_proto
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
default_proto
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, proto);
|
||||||
obj.type_tag = JsObject::OBJ_TYPE_DATA_VIEW;
|
obj.type_tag = JsObject::OBJ_TYPE_DATA_VIEW;
|
||||||
let data = Box::into_raw(Box::new(DataViewData {
|
let data = Box::into_raw(Box::new(DataViewData {
|
||||||
buffer,
|
buffer,
|
||||||
@@ -161,21 +252,6 @@ pub fn data_view_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
|||||||
// SAFETY: DataView 对象不可调用,native_fn 存不透明 `Box<DataViewData>` 指针,
|
// SAFETY: DataView 对象不可调用,native_fn 存不透明 `Box<DataViewData>` 指针,
|
||||||
// 与 ArrayBuffer / RegExp 的类型化存储模式一致。
|
// 与 ArrayBuffer / RegExp 的类型化存储模式一致。
|
||||||
obj.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(data as *const ()) }));
|
obj.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(data as *const ()) }));
|
||||||
set_named_prop(vm, &mut obj, "buffer", buffer, PropAttributes::new(false, false, false));
|
|
||||||
set_named_prop(
|
|
||||||
vm,
|
|
||||||
&mut obj,
|
|
||||||
"byteOffset",
|
|
||||||
JsValue::int(byte_offset as i32),
|
|
||||||
PropAttributes::new(false, false, false),
|
|
||||||
);
|
|
||||||
set_named_prop(
|
|
||||||
vm,
|
|
||||||
&mut obj,
|
|
||||||
"byteLength",
|
|
||||||
JsValue::int(byte_length as i32),
|
|
||||||
PropAttributes::new(false, false, false),
|
|
||||||
);
|
|
||||||
NativeResult::Ok(JsValue::from_js_object(vm.alloc_object(obj)))
|
NativeResult::Ok(JsValue::from_js_object(vm.alloc_object(obj)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,19 +339,28 @@ pub fn drop_data_view_native(obj: &mut JsObject) -> u64 {
|
|||||||
|
|
||||||
/// `DataView.prototype.getInt8(byteOffset)`:读取 1 字节有符号整数。
|
/// `DataView.prototype.getInt8(byteOffset)`:读取 1 字节有符号整数。
|
||||||
pub fn data_view_get_int8<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn data_view_get_int8<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
let bytes = native_try!(read_bytes::<1, H>(vm, args));
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||||
|
let bytes = native_try!(read_bytes_at::<1, H>(vm, view, offset));
|
||||||
NativeResult::Ok(JsValue::int(i8::from_ne_bytes(bytes) as i32))
|
NativeResult::Ok(JsValue::int(i8::from_ne_bytes(bytes) as i32))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `DataView.prototype.getUint8(byteOffset)`:读取 1 字节无符号整数。
|
/// `DataView.prototype.getUint8(byteOffset)`:读取 1 字节无符号整数。
|
||||||
pub fn data_view_get_uint8<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn data_view_get_uint8<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
let bytes = native_try!(read_bytes::<1, H>(vm, args));
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||||
|
let bytes = native_try!(read_bytes_at::<1, H>(vm, view, offset));
|
||||||
NativeResult::Ok(JsValue::int(bytes[0] as i32))
|
NativeResult::Ok(JsValue::int(bytes[0] as i32))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `DataView.prototype.getInt16(byteOffset, littleEndian)`:读取 2 字节有符号整数。
|
/// `DataView.prototype.getInt16(byteOffset, littleEndian)`:读取 2 字节有符号整数。
|
||||||
pub fn data_view_get_int16<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn data_view_get_int16<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
let bytes = native_try!(read_bytes::<2, H>(vm, args));
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||||
|
let bytes = native_try!(read_bytes_at::<2, H>(vm, view, offset));
|
||||||
let n = if is_little_endian(vm, args, 2) {
|
let n = if is_little_endian(vm, args, 2) {
|
||||||
i16::from_le_bytes(bytes)
|
i16::from_le_bytes(bytes)
|
||||||
} else {
|
} else {
|
||||||
@@ -286,7 +371,10 @@ pub fn data_view_get_int16<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
|
|
||||||
/// `DataView.prototype.getUint16(byteOffset, littleEndian)`:读取 2 字节无符号整数。
|
/// `DataView.prototype.getUint16(byteOffset, littleEndian)`:读取 2 字节无符号整数。
|
||||||
pub fn data_view_get_uint16<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn data_view_get_uint16<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
let bytes = native_try!(read_bytes::<2, H>(vm, args));
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||||
|
let bytes = native_try!(read_bytes_at::<2, H>(vm, view, offset));
|
||||||
let n = if is_little_endian(vm, args, 2) {
|
let n = if is_little_endian(vm, args, 2) {
|
||||||
u16::from_le_bytes(bytes)
|
u16::from_le_bytes(bytes)
|
||||||
} else {
|
} else {
|
||||||
@@ -297,7 +385,10 @@ pub fn data_view_get_uint16<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
|||||||
|
|
||||||
/// `DataView.prototype.getInt32(byteOffset, littleEndian)`:读取 4 字节有符号整数。
|
/// `DataView.prototype.getInt32(byteOffset, littleEndian)`:读取 4 字节有符号整数。
|
||||||
pub fn data_view_get_int32<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn data_view_get_int32<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
let bytes = native_try!(read_bytes::<4, H>(vm, args));
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||||
|
let bytes = native_try!(read_bytes_at::<4, H>(vm, view, offset));
|
||||||
let n = if is_little_endian(vm, args, 2) {
|
let n = if is_little_endian(vm, args, 2) {
|
||||||
i32::from_le_bytes(bytes)
|
i32::from_le_bytes(bytes)
|
||||||
} else {
|
} else {
|
||||||
@@ -308,7 +399,10 @@ pub fn data_view_get_int32<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
|
|
||||||
/// `DataView.prototype.getUint32(byteOffset, littleEndian)`:读取 4 字节无符号整数。
|
/// `DataView.prototype.getUint32(byteOffset, littleEndian)`:读取 4 字节无符号整数。
|
||||||
pub fn data_view_get_uint32<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn data_view_get_uint32<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
let bytes = native_try!(read_bytes::<4, H>(vm, args));
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||||
|
let bytes = native_try!(read_bytes_at::<4, H>(vm, view, offset));
|
||||||
let n = if is_little_endian(vm, args, 2) {
|
let n = if is_little_endian(vm, args, 2) {
|
||||||
u32::from_le_bytes(bytes)
|
u32::from_le_bytes(bytes)
|
||||||
} else {
|
} else {
|
||||||
@@ -319,7 +413,10 @@ pub fn data_view_get_uint32<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
|||||||
|
|
||||||
/// `DataView.prototype.getFloat32(byteOffset, littleEndian)`:读取 4 字节单精度浮点。
|
/// `DataView.prototype.getFloat32(byteOffset, littleEndian)`:读取 4 字节单精度浮点。
|
||||||
pub fn data_view_get_float32<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn data_view_get_float32<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
let bytes = native_try!(read_bytes::<4, H>(vm, args));
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||||
|
let bytes = native_try!(read_bytes_at::<4, H>(vm, view, offset));
|
||||||
let n = if is_little_endian(vm, args, 2) {
|
let n = if is_little_endian(vm, args, 2) {
|
||||||
f32::from_le_bytes(bytes)
|
f32::from_le_bytes(bytes)
|
||||||
} else {
|
} else {
|
||||||
@@ -330,7 +427,10 @@ pub fn data_view_get_float32<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
|||||||
|
|
||||||
/// `DataView.prototype.getFloat16(byteOffset, littleEndian)`:读取 2 字节半精度浮点。
|
/// `DataView.prototype.getFloat16(byteOffset, littleEndian)`:读取 2 字节半精度浮点。
|
||||||
pub fn data_view_get_float16<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn data_view_get_float16<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
let bytes = native_try!(read_bytes::<2, H>(vm, args));
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||||
|
let bytes = native_try!(read_bytes_at::<2, H>(vm, view, offset));
|
||||||
let bits = if is_little_endian(vm, args, 2) {
|
let bits = if is_little_endian(vm, args, 2) {
|
||||||
u16::from_le_bytes(bytes)
|
u16::from_le_bytes(bytes)
|
||||||
} else {
|
} else {
|
||||||
@@ -341,7 +441,10 @@ pub fn data_view_get_float16<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
|||||||
|
|
||||||
/// `DataView.prototype.getFloat64(byteOffset, littleEndian)`:读取 8 字节双精度浮点。
|
/// `DataView.prototype.getFloat64(byteOffset, littleEndian)`:读取 8 字节双精度浮点。
|
||||||
pub fn data_view_get_float64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn data_view_get_float64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
let bytes = native_try!(read_bytes::<8, H>(vm, args));
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||||
|
let bytes = native_try!(read_bytes_at::<8, H>(vm, view, offset));
|
||||||
let n = if is_little_endian(vm, args, 2) {
|
let n = if is_little_endian(vm, args, 2) {
|
||||||
f64::from_le_bytes(bytes)
|
f64::from_le_bytes(bytes)
|
||||||
} else {
|
} else {
|
||||||
@@ -353,7 +456,10 @@ pub fn data_view_get_float64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
|||||||
/// `DataView.prototype.getBigInt64(byteOffset, littleEndian)`:读取 8 字节有符号 64 位
|
/// `DataView.prototype.getBigInt64(byteOffset, littleEndian)`:读取 8 字节有符号 64 位
|
||||||
/// 整数并返回 BigInt 值。
|
/// 整数并返回 BigInt 值。
|
||||||
pub fn data_view_get_big_int64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
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 this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||||
|
let bytes = native_try!(read_bytes_at::<8, H>(vm, view, offset));
|
||||||
let n = if is_little_endian(vm, args, 2) {
|
let n = if is_little_endian(vm, args, 2) {
|
||||||
i64::from_le_bytes(bytes)
|
i64::from_le_bytes(bytes)
|
||||||
} else {
|
} else {
|
||||||
@@ -365,7 +471,10 @@ pub fn data_view_get_big_int64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResu
|
|||||||
/// `DataView.prototype.getBigUint64(byteOffset, littleEndian)`:读取 8 字节无符号
|
/// `DataView.prototype.getBigUint64(byteOffset, littleEndian)`:读取 8 字节无符号
|
||||||
/// 64 位整数并返回 BigInt 值。
|
/// 64 位整数并返回 BigInt 值。
|
||||||
pub fn data_view_get_big_uint64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
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 this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||||
|
let bytes = native_try!(read_bytes_at::<8, H>(vm, view, offset));
|
||||||
let n = if is_little_endian(vm, args, 2) {
|
let n = if is_little_endian(vm, args, 2) {
|
||||||
u64::from_le_bytes(bytes)
|
u64::from_le_bytes(bytes)
|
||||||
} else {
|
} else {
|
||||||
@@ -375,108 +484,138 @@ pub fn data_view_get_big_uint64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeRes
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// `DataView.prototype.setInt8(byteOffset, value)`:写入 1 字节有符号整数。
|
/// `DataView.prototype.setInt8(byteOffset, value)`:写入 1 字节有符号整数。
|
||||||
|
///
|
||||||
|
/// 步序:品牌 → ToIndex(byteOffset) → ToInt32(value) 回卷 → 越界 RangeError → 写。
|
||||||
pub fn data_view_set_int8<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn data_view_set_int8<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
let value = numeric_arg(vm, args, 2) as i32 as u8 as i8;
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
native_try!(write_bytes(vm, args, value.to_ne_bytes()));
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||||
|
let n = to_int32(native_try!(coerce_value_arg(vm, args, 2)));
|
||||||
|
native_try!(write_bytes::<1, H>(vm, view, offset, [n as u8]));
|
||||||
NativeResult::Ok(JsValue::undefined())
|
NativeResult::Ok(JsValue::undefined())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `DataView.prototype.setUint8(byteOffset, value)`:写入 1 字节无符号整数。
|
/// `DataView.prototype.setUint8(byteOffset, value)`:写入 1 字节无符号整数。
|
||||||
pub fn data_view_set_uint8<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn data_view_set_uint8<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
let value = numeric_arg(vm, args, 2) as i32 as u8;
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
native_try!(write_bytes(vm, args, [value]));
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||||
|
let n = to_int32(native_try!(coerce_value_arg(vm, args, 2)));
|
||||||
|
native_try!(write_bytes::<1, H>(vm, view, offset, [n as u8]));
|
||||||
NativeResult::Ok(JsValue::undefined())
|
NativeResult::Ok(JsValue::undefined())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `DataView.prototype.setInt16(byteOffset, value, littleEndian)`:写入 2 字节有符号整数。
|
/// `DataView.prototype.setInt16(byteOffset, value, littleEndian)`:写入 2 字节有符号整数。
|
||||||
pub fn data_view_set_int16<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn data_view_set_int16<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
let value = numeric_arg(vm, args, 2) as i32 as u16 as i16;
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||||
|
let n = to_int32(native_try!(coerce_value_arg(vm, args, 2)));
|
||||||
let bytes = if is_little_endian(vm, args, 3) {
|
let bytes = if is_little_endian(vm, args, 3) {
|
||||||
value.to_le_bytes()
|
(n as u16).to_le_bytes()
|
||||||
} else {
|
} else {
|
||||||
value.to_be_bytes()
|
(n as u16).to_be_bytes()
|
||||||
};
|
};
|
||||||
native_try!(write_bytes(vm, args, bytes));
|
native_try!(write_bytes::<2, H>(vm, view, offset, bytes));
|
||||||
NativeResult::Ok(JsValue::undefined())
|
NativeResult::Ok(JsValue::undefined())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `DataView.prototype.setUint16(byteOffset, value, littleEndian)`:写入 2 字节无符号整数。
|
/// `DataView.prototype.setUint16(byteOffset, value, littleEndian)`:写入 2 字节无符号整数。
|
||||||
pub fn data_view_set_uint16<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn data_view_set_uint16<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
let value = numeric_arg(vm, args, 2) as i32 as u16;
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||||
|
let n = to_int32(native_try!(coerce_value_arg(vm, args, 2)));
|
||||||
let bytes = if is_little_endian(vm, args, 3) {
|
let bytes = if is_little_endian(vm, args, 3) {
|
||||||
value.to_le_bytes()
|
(n as u16).to_le_bytes()
|
||||||
} else {
|
} else {
|
||||||
value.to_be_bytes()
|
(n as u16).to_be_bytes()
|
||||||
};
|
};
|
||||||
native_try!(write_bytes(vm, args, bytes));
|
native_try!(write_bytes::<2, H>(vm, view, offset, bytes));
|
||||||
NativeResult::Ok(JsValue::undefined())
|
NativeResult::Ok(JsValue::undefined())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `DataView.prototype.setInt32(byteOffset, value, littleEndian)`:写入 4 字节有符号整数。
|
/// `DataView.prototype.setInt32(byteOffset, value, littleEndian)`:写入 4 字节有符号整数。
|
||||||
pub fn data_view_set_int32<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn data_view_set_int32<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
let value = numeric_arg(vm, args, 2) as i32;
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
let bytes = if is_little_endian(vm, args, 3) {
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
value.to_le_bytes()
|
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||||
} else {
|
let n = to_int32(native_try!(coerce_value_arg(vm, args, 2)));
|
||||||
value.to_be_bytes()
|
let bytes = if is_little_endian(vm, args, 3) { n.to_le_bytes() } else { n.to_be_bytes() };
|
||||||
};
|
native_try!(write_bytes::<4, H>(vm, view, offset, bytes));
|
||||||
native_try!(write_bytes(vm, args, bytes));
|
|
||||||
NativeResult::Ok(JsValue::undefined())
|
NativeResult::Ok(JsValue::undefined())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `DataView.prototype.setUint32(byteOffset, value, littleEndian)`:写入 4 字节无符号整数。
|
/// `DataView.prototype.setUint32(byteOffset, value, littleEndian)`:写入 4 字节无符号整数。
|
||||||
pub fn data_view_set_uint32<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn data_view_set_uint32<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
let value = numeric_arg(vm, args, 2) as u32;
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||||
|
let n = to_int32(native_try!(coerce_value_arg(vm, args, 2)));
|
||||||
let bytes = if is_little_endian(vm, args, 3) {
|
let bytes = if is_little_endian(vm, args, 3) {
|
||||||
value.to_le_bytes()
|
(n as u32).to_le_bytes()
|
||||||
} else {
|
} else {
|
||||||
value.to_be_bytes()
|
(n as u32).to_be_bytes()
|
||||||
};
|
};
|
||||||
native_try!(write_bytes(vm, args, bytes));
|
native_try!(write_bytes::<4, H>(vm, view, offset, bytes));
|
||||||
NativeResult::Ok(JsValue::undefined())
|
NativeResult::Ok(JsValue::undefined())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `DataView.prototype.setFloat32(byteOffset, value, littleEndian)`:写入单精度浮点。
|
/// `DataView.prototype.setFloat32(byteOffset, value, littleEndian)`:写入单精度浮点。
|
||||||
pub fn data_view_set_float32<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn data_view_set_float32<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
let value = numeric_arg(vm, args, 2) as f32;
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||||
|
let value = native_try!(coerce_value_arg(vm, args, 2)) as f32;
|
||||||
let bytes = if is_little_endian(vm, args, 3) {
|
let bytes = if is_little_endian(vm, args, 3) {
|
||||||
value.to_le_bytes()
|
value.to_le_bytes()
|
||||||
} else {
|
} else {
|
||||||
value.to_be_bytes()
|
value.to_be_bytes()
|
||||||
};
|
};
|
||||||
native_try!(write_bytes(vm, args, bytes));
|
native_try!(write_bytes::<4, H>(vm, view, offset, bytes));
|
||||||
NativeResult::Ok(JsValue::undefined())
|
NativeResult::Ok(JsValue::undefined())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `DataView.prototype.setFloat16(byteOffset, value, littleEndian)`:按 IEEE 754
|
/// `DataView.prototype.setFloat16(byteOffset, value, littleEndian)`:按 IEEE 754
|
||||||
/// binary16 舍入写入 2 字节半精度浮点(NaN 规范化由 `f64_to_f16_bits` 处理)。
|
/// binary16 舍入写入 2 字节半精度浮点(NaN 规范化由 `f64_to_f16_bits` 处理)。
|
||||||
pub fn data_view_set_float16<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn data_view_set_float16<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
let value = numeric_arg(vm, args, 2);
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||||
|
let value = native_try!(coerce_value_arg(vm, args, 2));
|
||||||
let bits = crate::math::f64_to_f16_bits(value);
|
let bits = crate::math::f64_to_f16_bits(value);
|
||||||
let bytes = if is_little_endian(vm, args, 3) {
|
let bytes = if is_little_endian(vm, args, 3) {
|
||||||
bits.to_le_bytes()
|
bits.to_le_bytes()
|
||||||
} else {
|
} else {
|
||||||
bits.to_be_bytes()
|
bits.to_be_bytes()
|
||||||
};
|
};
|
||||||
native_try!(write_bytes(vm, args, bytes));
|
native_try!(write_bytes::<2, H>(vm, view, offset, bytes));
|
||||||
NativeResult::Ok(JsValue::undefined())
|
NativeResult::Ok(JsValue::undefined())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `DataView.prototype.setFloat64(byteOffset, value, littleEndian)`:写入双精度浮点。
|
/// `DataView.prototype.setFloat64(byteOffset, value, littleEndian)`:写入双精度浮点。
|
||||||
pub fn data_view_set_float64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn data_view_set_float64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
let value = numeric_arg(vm, args, 2);
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||||
|
let value = native_try!(coerce_value_arg(vm, args, 2));
|
||||||
let bytes = if is_little_endian(vm, args, 3) {
|
let bytes = if is_little_endian(vm, args, 3) {
|
||||||
value.to_le_bytes()
|
value.to_le_bytes()
|
||||||
} else {
|
} else {
|
||||||
value.to_be_bytes()
|
value.to_be_bytes()
|
||||||
};
|
};
|
||||||
native_try!(write_bytes(vm, args, bytes));
|
native_try!(write_bytes::<8, H>(vm, view, offset, bytes));
|
||||||
NativeResult::Ok(JsValue::undefined())
|
NativeResult::Ok(JsValue::undefined())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `DataView.prototype.setBigInt64(byteOffset, value, littleEndian)`:按 ToBigInt
|
/// `DataView.prototype.setBigInt64(byteOffset, value, littleEndian)`:按 ToBigInt
|
||||||
/// 语义接收值(Number 入参抛 TypeError),取低 64 位位模式写入 8 字节有符号整数。
|
/// 语义接收值(Number 入参抛 TypeError),取低 64 位位模式写入 8 字节有符号整数。
|
||||||
|
///
|
||||||
|
/// 步序:品牌 → ToIndex(byteOffset) → ToBigInt(value) → 越界 RangeError → 写。
|
||||||
pub fn data_view_set_big_int64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn data_view_set_big_int64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||||
let value = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
let value = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||||
let b =
|
let b =
|
||||||
native_try!(oxide_runtime_api::to_bigint_full(value, vm).map_err(|e| crate::iterator::engine_error(vm, &e)));
|
native_try!(oxide_runtime_api::to_bigint_full(value, vm).map_err(|e| crate::iterator::engine_error(vm, &e)));
|
||||||
@@ -486,13 +625,16 @@ pub fn data_view_set_big_int64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResu
|
|||||||
} else {
|
} else {
|
||||||
low.to_be_bytes()
|
low.to_be_bytes()
|
||||||
};
|
};
|
||||||
native_try!(write_bytes(vm, args, bytes));
|
native_try!(write_bytes::<8, H>(vm, view, offset, bytes));
|
||||||
NativeResult::Ok(JsValue::undefined())
|
NativeResult::Ok(JsValue::undefined())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `DataView.prototype.setBigUint64(byteOffset, value, littleEndian)`:按 ToBigInt
|
/// `DataView.prototype.setBigUint64(byteOffset, value, littleEndian)`:按 ToBigInt
|
||||||
/// 语义接收值(Number 入参抛 TypeError),取低 64 位位模式写入 8 字节无符号整数。
|
/// 语义接收值(Number 入参抛 TypeError),取低 64 位位模式写入 8 字节无符号整数。
|
||||||
pub fn data_view_set_big_uint64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn data_view_set_big_uint64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||||
let value = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
let value = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||||
let b =
|
let b =
|
||||||
native_try!(oxide_runtime_api::to_bigint_full(value, vm).map_err(|e| crate::iterator::engine_error(vm, &e)));
|
native_try!(oxide_runtime_api::to_bigint_full(value, vm).map_err(|e| crate::iterator::engine_error(vm, &e)));
|
||||||
@@ -502,7 +644,7 @@ pub fn data_view_set_big_uint64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeRes
|
|||||||
} else {
|
} else {
|
||||||
low.to_be_bytes()
|
low.to_be_bytes()
|
||||||
};
|
};
|
||||||
native_try!(write_bytes(vm, args, bytes));
|
native_try!(write_bytes::<8, H>(vm, view, offset, bytes));
|
||||||
NativeResult::Ok(JsValue::undefined())
|
NativeResult::Ok(JsValue::undefined())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -518,3 +660,24 @@ pub fn data_view_to_string<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
native_try!(get_data_view_data(vm, this_val));
|
native_try!(get_data_view_data(vm, this_val));
|
||||||
NativeResult::Ok(vm.new_string("[object DataView]"))
|
NativeResult::Ok(vm.new_string("[object DataView]"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `DataView.prototype.buffer` getter:返回该视图所锚定的 ArrayBuffer 对象。
|
||||||
|
pub fn data_view_buffer_getter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
NativeResult::Ok(view.buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `DataView.prototype.byteOffset` getter:返回视图起始字节在 buffer 内的偏移。
|
||||||
|
pub fn data_view_byte_offset_getter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
NativeResult::Ok(JsValue::float(view.byte_offset as f64))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `DataView.prototype.byteLength` getter:返回视图覆盖的字节长度。
|
||||||
|
pub fn data_view_byte_length_getter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
|
let view = native_try!(get_data_view_data(vm, this_val));
|
||||||
|
NativeResult::Ok(JsValue::float(view.byte_length as f64))
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,15 +6,29 @@ use oxide_runtime_api::{NativeResult, VmHost};
|
|||||||
/// 普通调用返回原始 number(整数走 int 表示);new 语义返回 `[[NumberData]]` 包装对象。
|
/// 普通调用返回原始 number(整数走 int 表示);new 语义返回 `[[NumberData]]` 包装对象。
|
||||||
pub fn number_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn number_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
let n = if args.len() > 1 {
|
let n = if args.len() > 1 {
|
||||||
match vm.coerce_number_bounded(vm.reg(args[1])) {
|
let raw = vm.reg(args[1]);
|
||||||
Ok(n) => n,
|
// ToPrimitive 先解盒:BigInt 原始值走 lossy 转换(BigIntToNumber 不抛错,
|
||||||
|
// 显式 `Number(bigint)` 是规范唯一合法入口);其余经 bounded ToNumber
|
||||||
|
// 入口(Symbol 抛 TypeError)。
|
||||||
|
let prim = match vm.coerce_primitive_bounded(raw, false) {
|
||||||
|
Ok(p) => p,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
// 对象经 ToNumber 转换时 toString/valueOf 可抛异常,须原样传播原始异常。
|
// 对象经 ToPrimitive 转换时 toString/valueOf 可抛异常,须原样传播原始异常。
|
||||||
if let Some(exc) = vm.take_uncaught_value() {
|
if let Some(exc) = vm.take_uncaught_value() {
|
||||||
return NativeResult::Err(exc);
|
return NativeResult::Err(exc);
|
||||||
}
|
}
|
||||||
return NativeResult::Err(crate::error::create_type_error(vm, "Cannot convert value to a number"));
|
return NativeResult::Err(crate::error::create_type_error(vm, "Cannot convert value to a number"));
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
if prim.is_bigint() {
|
||||||
|
oxide_runtime_api::bigint_to_f64(unsafe { oxide_runtime_api::bigint_data(prim) })
|
||||||
|
} else if prim.is_symbol() {
|
||||||
|
if let Some(exc) = vm.take_uncaught_value() {
|
||||||
|
return NativeResult::Err(exc);
|
||||||
|
}
|
||||||
|
return NativeResult::Err(crate::error::create_type_error(vm, "Cannot convert a Symbol value to a number"));
|
||||||
|
} else {
|
||||||
|
oxide_runtime_api::to_number(prim)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
0.0
|
0.0
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::bind_constructor;
|
use crate::bind_constructor;
|
||||||
use crate::bindings::{apply_binding_table, configure_native_constructor};
|
use crate::bindings::{apply_binding_table, bind_accessor_getter, configure_native_constructor};
|
||||||
use oxide_kernel::kernel::{KernelCore, KernelSession};
|
use oxide_kernel::kernel::{KernelCore, KernelSession};
|
||||||
use oxide_types::object::JsObject;
|
use oxide_types::object::{JsObject, PropAttributes};
|
||||||
|
|
||||||
/// 把 DataView 构造器与原型方法绑定到 global。
|
/// 把 DataView 构造器与原型方法绑定到 global。
|
||||||
pub fn bind_data_view(core: &Arc<KernelCore>, session: &KernelSession, global: &mut JsObject) {
|
pub fn bind_data_view(core: &Arc<KernelCore>, session: &KernelSession, global: &mut JsObject) {
|
||||||
@@ -15,7 +15,7 @@ pub fn bind_data_view(core: &Arc<KernelCore>, session: &KernelSession, global: &
|
|||||||
configure_native_constructor(
|
configure_native_constructor(
|
||||||
ctor,
|
ctor,
|
||||||
oxide_builtins::data_view::data_view_constructor::<crate::vm::Vm> as *const (),
|
oxide_builtins::data_view::data_view_constructor::<crate::vm::Vm> as *const (),
|
||||||
3,
|
1,
|
||||||
);
|
);
|
||||||
|
|
||||||
apply_binding_table(
|
apply_binding_table(
|
||||||
@@ -133,5 +133,36 @@ pub fn bind_data_view(core: &Arc<KernelCore>, session: &KernelSession, global: &
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
bind_constructor!(core, global, "DataView", ctor_ptr, oxide_builtins::data_view::data_view_constructor::<crate::vm::Vm>, 3, hash: true);
|
bind_constructor!(core, global, "DataView", ctor_ptr, oxide_builtins::data_view::data_view_constructor::<crate::vm::Vm>, 1, hash: true);
|
||||||
|
// length 属性描述符补 { writable:false, enumerable:false, configurable:true }
|
||||||
|
// (bind_constructor! 宏的通用缺省 meta 不可写回,此处理仅覆盖 DataView)。
|
||||||
|
{
|
||||||
|
let length_si = core.perm_interner().intern("length").0;
|
||||||
|
if let Some(pos) = core.shape_forge().lookup_position(ctor.shape_id(), length_si) {
|
||||||
|
ctor.set_data_meta(pos, PropAttributes::new(false, false, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// buffer/byteOffset/byteLength 只读访问器(set 恒 undefined,getter 读视图状态盒)。
|
||||||
|
bind_accessor_getter(
|
||||||
|
core,
|
||||||
|
session,
|
||||||
|
proto,
|
||||||
|
"buffer",
|
||||||
|
oxide_builtins::data_view::data_view_buffer_getter::<crate::vm::Vm> as *const (),
|
||||||
|
);
|
||||||
|
bind_accessor_getter(
|
||||||
|
core,
|
||||||
|
session,
|
||||||
|
proto,
|
||||||
|
"byteOffset",
|
||||||
|
oxide_builtins::data_view::data_view_byte_offset_getter::<crate::vm::Vm> as *const (),
|
||||||
|
);
|
||||||
|
bind_accessor_getter(
|
||||||
|
core,
|
||||||
|
session,
|
||||||
|
proto,
|
||||||
|
"byteLength",
|
||||||
|
oxide_builtins::data_view::data_view_byte_length_getter::<crate::vm::Vm> as *const (),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -972,8 +972,13 @@ impl Vm {
|
|||||||
let new_obj_val = JsValue::object(new_obj as *mut u8);
|
let new_obj_val = JsValue::object(new_obj as *mut u8);
|
||||||
|
|
||||||
if ctor_obj.native_fn().is_some() {
|
if ctor_obj.native_fn().is_some() {
|
||||||
// native 构造器:receiver 为新对象,值传递调用。
|
// native 构造器:receiver 为新对象,值传递调用。newTarget 快照后置入
|
||||||
match self.call_function_sync(constructor, new_obj_val, &args) {
|
// reg(255) 暴露给 native 构造器(调用后恢复原值)。
|
||||||
|
let saved_new_target = self.regs[255];
|
||||||
|
self.regs[255] = constructor;
|
||||||
|
let result = self.call_function_sync(constructor, new_obj_val, &args);
|
||||||
|
self.regs[255] = saved_new_target;
|
||||||
|
match result {
|
||||||
Ok(v) => {
|
Ok(v) => {
|
||||||
self.regs[rd] = if v.is_object() { v } else { new_obj_val };
|
self.regs[rd] = if v.is_object() { v } else { new_obj_val };
|
||||||
Ok(false)
|
Ok(false)
|
||||||
|
|||||||
@@ -74,9 +74,28 @@ impl Vm {
|
|||||||
let nt_obj = unsafe { &*new_target.as_js_object_ptr() };
|
let nt_obj = unsafe { &*new_target.as_js_object_ptr() };
|
||||||
// native 构造器:receiver 为新对象(this 取 newTarget.prototype),值传递调用。
|
// native 构造器:receiver 为新对象(this 取 newTarget.prototype),值传递调用。
|
||||||
if ctor_obj.native_fn().is_some() {
|
if ctor_obj.native_fn().is_some() {
|
||||||
let this_ptr = self.alloc_ctor_this(nt_obj)?;
|
// DataView 构造器不预分配 this:其体内先做全部校验、后读 newTarget.prototype
|
||||||
let this_val = JsValue::from_js_object(this_ptr);
|
// (抛错的 prototype getter 不得先于越界 RangeError 触发),占位 receiver
|
||||||
return match self.call_function_sync(ctor, this_val, args) {
|
// 不可观测(构造器恒返回自建对象);原型取 %DataView.prototype% 使构造器
|
||||||
|
// 的 receiver 原型链判定通过。
|
||||||
|
let is_data_view = std::ptr::eq(
|
||||||
|
ctor.as_js_object_ptr(),
|
||||||
|
self.session.builtin_world().data_view_constructor.as_ptr() as *mut JsObject,
|
||||||
|
);
|
||||||
|
let this_val = if is_data_view {
|
||||||
|
let data_view_proto_val =
|
||||||
|
JsValue::from_js_object(self.session.builtin_world().data_view_proto.as_ptr() as *mut JsObject);
|
||||||
|
JsValue::from_js_object(self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, data_view_proto_val)))
|
||||||
|
} else {
|
||||||
|
let this_ptr = self.alloc_ctor_this(nt_obj)?;
|
||||||
|
JsValue::from_js_object(this_ptr)
|
||||||
|
};
|
||||||
|
// newTarget 经 reg(255) 暴露给 native 构造器(快照/恢复:call 窗口不触及 255)。
|
||||||
|
let saved_nt = self.regs[255];
|
||||||
|
self.regs[255] = new_target;
|
||||||
|
let result = self.call_function_sync(ctor, this_val, args);
|
||||||
|
self.regs[255] = saved_nt;
|
||||||
|
return match result {
|
||||||
Ok(ret) if ret.is_object() => Ok(ret),
|
Ok(ret) if ret.is_object() => Ok(ret),
|
||||||
Ok(_) => Ok(this_val),
|
Ok(_) => Ok(this_val),
|
||||||
Err(e) => Err(self
|
Err(e) => Err(self
|
||||||
|
|||||||
@@ -121,7 +121,8 @@ enum AggregateKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// IsConstructor 近似判定:可调用、非 arrow,且 native 函数须带构造器 tag
|
/// IsConstructor 近似判定:可调用、非 arrow,且 native 函数须带构造器 tag
|
||||||
/// (与 `construct_ctor` 的校验一致)。
|
/// (与 `construct_ctor` 的校验一致);bound 包装恒接受(target 可构造性在
|
||||||
|
/// `dispatch_new_bound` 入口复核)。
|
||||||
fn is_constructor_value(c: JsValue) -> bool {
|
fn is_constructor_value(c: JsValue) -> bool {
|
||||||
if !c.is_object() {
|
if !c.is_object() {
|
||||||
return false;
|
return false;
|
||||||
@@ -130,7 +131,9 @@ fn is_constructor_value(c: JsValue) -> bool {
|
|||||||
let c_obj = unsafe { &*c.as_js_object_ptr() };
|
let c_obj = unsafe { &*c.as_js_object_ptr() };
|
||||||
c_obj.is_function()
|
c_obj.is_function()
|
||||||
&& !c_obj.is_arrow()
|
&& !c_obj.is_arrow()
|
||||||
&& !(c_obj.native_fn().is_some() && c_obj.type_tag != JsObject::OBJ_TYPE_CONSTRUCTOR)
|
&& !(c_obj.native_fn().is_some()
|
||||||
|
&& c_obj.type_tag != JsObject::OBJ_TYPE_CONSTRUCTOR
|
||||||
|
&& c_obj.type_tag != JsObject::OBJ_TYPE_BOUND)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── session GC 支撑:状态盒中的 JsValues 作为 Promise 对象边追踪 ──
|
// ── session GC 支撑:状态盒中的 JsValues 作为 Promise 对象边追踪 ──
|
||||||
|
|||||||
@@ -325,6 +325,20 @@ fn map_this(vm: &mut Vm, reg: u8) -> JsValue {
|
|||||||
val
|
val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 分配一个原型指向 DataView.prototype 的占位对象并写入寄存器,作为构造器调用的 `this`。
|
||||||
|
fn data_view_this(vm: &mut Vm, reg: u8) -> JsValue {
|
||||||
|
let proto = vm.session.builtin_world().data_view_proto.as_ptr() as *mut JsObject;
|
||||||
|
let obj = vm.epoch.alloc(JsObject::new_empty(
|
||||||
|
oxide_kernel::shape_forge::EMPTY_SHAPE_ID,
|
||||||
|
JsValue::from_js_object(proto),
|
||||||
|
));
|
||||||
|
// 测试辅助函数绕过 alloc_object,需手动置位 EPOCH_BIT。
|
||||||
|
unsafe { (*obj).set_is_epoch(true) };
|
||||||
|
let val = JsValue::from_js_object(obj);
|
||||||
|
vm.regs[reg as usize] = val;
|
||||||
|
val
|
||||||
|
}
|
||||||
|
|
||||||
/// 分配一个原型指向 Set.prototype 的占位对象并写入寄存器,作为构造器调用的 `this`。
|
/// 分配一个原型指向 Set.prototype 的占位对象并写入寄存器,作为构造器调用的 `this`。
|
||||||
fn set_this(vm: &mut Vm, reg: u8) -> JsValue {
|
fn set_this(vm: &mut Vm, reg: u8) -> JsValue {
|
||||||
let proto = vm.session.builtin_world().set_proto.as_ptr() as *mut JsObject;
|
let proto = vm.session.builtin_world().set_proto.as_ptr() as *mut JsObject;
|
||||||
@@ -735,6 +749,7 @@ fn session_gc_keeps_shared_array_buffer_alive_through_view_native_edges() {
|
|||||||
let typed = native_ok(typed_array::int32array_constructor(&mut vm, &[0, 1]));
|
let typed = native_ok(typed_array::int32array_constructor(&mut vm, &[0, 1]));
|
||||||
|
|
||||||
vm.regs[1] = buffer;
|
vm.regs[1] = buffer;
|
||||||
|
data_view_this(&mut vm, 0);
|
||||||
let view = native_ok(data_view::data_view_constructor(&mut vm, &[0, 1]));
|
let view = native_ok(data_view::data_view_constructor(&mut vm, &[0, 1]));
|
||||||
|
|
||||||
vm.regs[0] = view;
|
vm.regs[0] = view;
|
||||||
@@ -790,6 +805,7 @@ fn session_gc_rewrites_buffer_retained_only_by_data_view_native_edge() {
|
|||||||
vm.regs[1] = JsValue::int(8);
|
vm.regs[1] = JsValue::int(8);
|
||||||
let buffer = native_ok(array_buffer::array_buffer_constructor(&mut vm, &[0, 1]));
|
let buffer = native_ok(array_buffer::array_buffer_constructor(&mut vm, &[0, 1]));
|
||||||
vm.regs[1] = buffer;
|
vm.regs[1] = buffer;
|
||||||
|
data_view_this(&mut vm, 0);
|
||||||
let view = native_ok(data_view::data_view_constructor(&mut vm, &[0, 1]));
|
let view = native_ok(data_view::data_view_constructor(&mut vm, &[0, 1]));
|
||||||
|
|
||||||
vm.regs[0] = view;
|
vm.regs[0] = view;
|
||||||
|
|||||||
@@ -147,14 +147,20 @@ impl Vm {
|
|||||||
/// ToNumber 有界版:先按 number hint 做 ToPrimitive,再转 `f64`。
|
/// ToNumber 有界版:先按 number hint 做 ToPrimitive,再转 `f64`。
|
||||||
///
|
///
|
||||||
/// # 边界与前提
|
/// # 边界与前提
|
||||||
/// 原始值为 Symbol 时按规范(ECMA-262 §7.1.4)抛 `TypeError`,不落入
|
/// 原始值为 Symbol 或 BigInt 时抛 `TypeError`,不落入
|
||||||
/// [`coercion::to_number`] 的宽松快路径(后者对该输入返回 `NaN`)。
|
/// [`coercion::to_number`] 的宽松快路径(后者对 Symbol 返回 `NaN`、
|
||||||
|
/// 对 BigInt 做 lossy 转换)。BigInt 入口语义:显式 lossy 站点
|
||||||
|
/// (`Number` 构造器)先解盒自行转换,不经本入口。
|
||||||
pub(crate) fn coerce_number_bounded(&mut self, value: JsValue) -> Result<f64, String> {
|
pub(crate) fn coerce_number_bounded(&mut self, value: JsValue) -> Result<f64, String> {
|
||||||
let primitive = self.coerce_primitive_bounded(value, false)?;
|
let primitive = self.coerce_primitive_bounded(value, false)?;
|
||||||
if primitive.is_symbol() {
|
if primitive.is_symbol() {
|
||||||
self.conversion_error("Cannot convert a Symbol value to a number")?;
|
self.conversion_error("Cannot convert a Symbol value to a number")?;
|
||||||
return Ok(f64::NAN);
|
return Ok(f64::NAN);
|
||||||
}
|
}
|
||||||
|
if primitive.is_bigint() {
|
||||||
|
self.conversion_error("Cannot convert a BigInt value to a number")?;
|
||||||
|
return Ok(f64::NAN);
|
||||||
|
}
|
||||||
Ok(coercion::to_number(primitive))
|
Ok(coercion::to_number(primitive))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,8 +87,13 @@ impl Vm {
|
|||||||
// native 构造器:收口到 call_function_sync(与 spread / bound 变体一致)。
|
// native 构造器:收口到 call_function_sync(与 spread / bound 变体一致)。
|
||||||
// 该入口统一保存/恢复调用窗口与 253/254 槽且不触碰 255,调用方
|
// 该入口统一保存/恢复调用窗口与 253/254 槽且不触碰 255,调用方
|
||||||
// new.target 与 this 跨 native 构造不被污染;receiver 经 arg0 打包,
|
// new.target 与 this 跨 native 构造不被污染;receiver 经 arg0 打包,
|
||||||
// native 侧经 reg(args[0]) 读取,构造语义不变。
|
// native 侧经 reg(args[0]) 读取,构造语义不变。newTarget 快照后置入
|
||||||
match self.call_function_sync(constructor, new_obj_val, &args) {
|
// reg(255) 暴露给 native 构造器(调用后恢复原值)。
|
||||||
|
let saved_new_target = self.regs[255];
|
||||||
|
self.regs[255] = constructor;
|
||||||
|
let result = self.call_function_sync(constructor, new_obj_val, &args);
|
||||||
|
self.regs[255] = saved_new_target;
|
||||||
|
match result {
|
||||||
Ok(v) => {
|
Ok(v) => {
|
||||||
self.regs[rd] = if v.is_object() { v } else { new_obj_val };
|
self.regs[rd] = if v.is_object() { v } else { new_obj_val };
|
||||||
Ok(false)
|
Ok(false)
|
||||||
@@ -224,7 +229,13 @@ impl Vm {
|
|||||||
|
|
||||||
if target_obj.native_fn().is_some() {
|
if target_obj.native_fn().is_some() {
|
||||||
// native 构造器:receiver = 新对象,值传递调用(错误原值恢复后展开)。
|
// native 构造器:receiver = 新对象,值传递调用(错误原值恢复后展开)。
|
||||||
match self.call_function_sync(target_val, new_obj_val, &call_args) {
|
// new.target 按 bound [[Construct]] 语义取最外层 bound 包装(wrapper_val),
|
||||||
|
// 快照后置入 reg(255) 暴露给 native 构造器(调用后恢复原值)。
|
||||||
|
let saved_new_target = self.regs[255];
|
||||||
|
self.regs[255] = wrapper_val;
|
||||||
|
let result = self.call_function_sync(target_val, new_obj_val, &call_args);
|
||||||
|
self.regs[255] = saved_new_target;
|
||||||
|
match result {
|
||||||
Ok(v) => {
|
Ok(v) => {
|
||||||
self.regs[rd] = if v.is_object() { v } else { new_obj_val };
|
self.regs[rd] = if v.is_object() { v } else { new_obj_val };
|
||||||
Ok(false)
|
Ok(false)
|
||||||
|
|||||||
Reference in New Issue
Block a user