mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 18:51:13 +08:00
feat: DataView 活界判与构造器 proto 读后终校验落地
This commit is contained in:
@@ -5,15 +5,19 @@ use oxide_types::value::JsValue;
|
||||
use num_bigint::BigInt;
|
||||
use num_traits::ToPrimitive;
|
||||
|
||||
use crate::array_buffer::array_buffer_payload;
|
||||
use crate::array_buffer::{array_buffer_payload, ArrayBufferPayload};
|
||||
|
||||
use oxide_runtime_api::{NativeResult, VmHost};
|
||||
|
||||
/// DataView 视图状态盒。`byte_length` 语义随 `length_is_auto` 分流:
|
||||
/// 定长视图存静态长;auto 视图(构造时 byteLength 缺省且构造期缓冲可 resize)
|
||||
/// 存构造期 live − offset 初值,活读一律现算 live − offset。
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) struct DataViewData {
|
||||
buffer: JsValue,
|
||||
byte_offset: usize,
|
||||
byte_length: usize,
|
||||
length_is_auto: bool,
|
||||
}
|
||||
|
||||
macro_rules! native_try {
|
||||
@@ -106,50 +110,91 @@ fn get_data_view_data<H: VmHost>(vm: &mut H, this_val: JsValue) -> Result<DataVi
|
||||
Ok(unsafe { *data_ptr })
|
||||
}
|
||||
|
||||
fn checked_absolute_offset<H: VmHost>(
|
||||
vm: &mut H, view: DataViewData, offset: usize, width: usize,
|
||||
/// 视图界判核(规范 IsViewOutOfBounds 与 GetViewByteLength 合一):缓冲已
|
||||
/// detach(载荷 `data` 为 `None`)、auto 视图 offset 超 live、定长视图
|
||||
/// offset + 静态长超 live(含溢出)→ TypeError;通过时返回视图长
|
||||
/// (auto 视图现算 live − offset,定长视图返静态长)。
|
||||
fn dv_view_bounds<H: VmHost>(
|
||||
vm: &mut H, payload_ptr: *mut ArrayBufferPayload, view: DataViewData,
|
||||
) -> Result<usize, JsValue> {
|
||||
let Some(end) = offset.checked_add(width) else {
|
||||
return Err(crate::error::create_range_error(vm, "DataView offset out of bounds"));
|
||||
// SAFETY: payload_ptr 经 array_buffer_payload 校验为合法 ArrayBuffer 载荷。
|
||||
let Some(data) = unsafe { &*payload_ptr }.data.as_deref() else {
|
||||
return Err(crate::error::create_type_error(vm, "ArrayBuffer internal state invalid"));
|
||||
};
|
||||
if end > view.byte_length {
|
||||
return Err(crate::error::create_range_error(vm, "DataView offset out of bounds"));
|
||||
let live = data.len();
|
||||
if view.length_is_auto {
|
||||
if view.byte_offset > live {
|
||||
return Err(crate::error::create_type_error(vm, "ArrayBuffer internal state invalid"));
|
||||
}
|
||||
return Ok(live - view.byte_offset);
|
||||
}
|
||||
match view.byte_offset.checked_add(view.byte_length) {
|
||||
Some(end) if end <= live => Ok(view.byte_length),
|
||||
_ => Err(crate::error::create_type_error(vm, "ArrayBuffer internal state invalid")),
|
||||
}
|
||||
Ok(view.byte_offset + offset)
|
||||
}
|
||||
|
||||
/// GetViewValue 后半:按已校验的视图与偏移读 N 字节(越界抛 RangeError)。
|
||||
/// detach 守卫先于范围校验(规范序:IsDetachedBuffer 检查先于越界判定,
|
||||
/// detach 后越界偏移也抛 TypeError 而非 RangeError)。
|
||||
/// set 面入口写守卫:immutable 缓冲 → TypeError(先于一切实参强转)。
|
||||
fn dv_buffer_writable<H: VmHost>(vm: &mut H, view: DataViewData) -> Result<(), JsValue> {
|
||||
let payload_ptr = array_buffer_payload(vm, view.buffer)?;
|
||||
// SAFETY: payload_ptr 经 array_buffer_payload 校验为合法 ArrayBuffer 载荷。
|
||||
if unsafe { &*payload_ptr }.immutable {
|
||||
return Err(crate::error::create_type_error(vm, "ArrayBuffer is immutable"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// JS 调用点后的缓冲重取纪律:重读寄存器再重取载荷(epoch 晋升改写
|
||||
/// 寄存器,旧 JsValue 滞留 epoch 克隆旧盒);detached → TypeError。
|
||||
/// 返回(寄存器重读值、live 长、存储上限)。
|
||||
fn revalidate_buffer<H: VmHost>(vm: &mut H, buf_reg: u8) -> Result<(JsValue, usize, usize), JsValue> {
|
||||
let buffer = vm.reg(buf_reg);
|
||||
let payload_ptr = array_buffer_payload(vm, buffer)?;
|
||||
// SAFETY: payload_ptr 经 array_buffer_payload 校验为合法 ArrayBuffer 载荷。
|
||||
let payload = unsafe { &*payload_ptr };
|
||||
let Some(data) = payload.data.as_deref() else {
|
||||
return Err(crate::error::create_type_error(vm, "ArrayBuffer internal state invalid"));
|
||||
};
|
||||
Ok((buffer, data.len(), payload.max_byte_length))
|
||||
}
|
||||
|
||||
/// GetViewValue 后半:按已校验的视图与偏移读 N 字节。界判核先
|
||||
/// (detach/OOB → TypeError,live 长口径),后视图相对越界
|
||||
/// (→ RangeError,判活视图长)。
|
||||
fn read_bytes_at<const N: usize, H: VmHost>(vm: &mut H, view: DataViewData, offset: usize) -> Result<[u8; N], JsValue> {
|
||||
let payload_ptr = array_buffer_payload(vm, view.buffer)?;
|
||||
// SAFETY: payload_ptr 经 array_buffer_payload 校验为合法 ArrayBuffer 载荷。
|
||||
let Some(buffer) = unsafe { &*payload_ptr }.data.as_deref() else {
|
||||
return Err(crate::error::create_type_error(vm, "ArrayBuffer internal state invalid"));
|
||||
};
|
||||
let abs = checked_absolute_offset(vm, view, offset, N)?;
|
||||
if abs + N > buffer.len() {
|
||||
return Err(crate::error::create_range_error(vm, "DataView offset out of bounds"));
|
||||
let view_len = dv_view_bounds(vm, payload_ptr, view)?;
|
||||
match offset.checked_add(N) {
|
||||
Some(end) if end <= view_len => {}
|
||||
_ => return Err(crate::error::create_range_error(vm, "DataView offset out of bounds")),
|
||||
}
|
||||
let abs = view.byte_offset + offset;
|
||||
let mut out = [0u8; N];
|
||||
out.copy_from_slice(&buffer[abs..abs + N]);
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
/// SetViewValue 后半:按已校验的视图与偏移写 N 字节(越界抛 RangeError)。
|
||||
/// detach 守卫先于范围校验(规范序同读路径)。
|
||||
/// SetViewValue 后半:按已校验的视图与偏移写 N 字节(读路径同序)。
|
||||
fn write_bytes<const N: usize, H: VmHost>(
|
||||
vm: &mut H, view: DataViewData, offset: usize, bytes: [u8; N],
|
||||
) -> Result<(), JsValue> {
|
||||
let payload_ptr = array_buffer_payload(vm, view.buffer)?;
|
||||
// SAFETY: payload_ptr 经 array_buffer_payload 校验为合法 ArrayBuffer 载荷。
|
||||
// 界判核共享借用先于可变借用建立,避免活别名。
|
||||
let view_len = dv_view_bounds(vm, payload_ptr, view)?;
|
||||
// SAFETY: payload_ptr 经 array_buffer_payload 校验为合法 ArrayBuffer 载荷;
|
||||
// 界判核已证 data 在场,下方守卫为结构性兜底。
|
||||
let Some(buffer) = unsafe { &mut *payload_ptr }.data.as_deref_mut() else {
|
||||
return Err(crate::error::create_type_error(vm, "ArrayBuffer internal state invalid"));
|
||||
};
|
||||
let abs = checked_absolute_offset(vm, view, offset, N)?;
|
||||
if abs + N > buffer.len() {
|
||||
return Err(crate::error::create_range_error(vm, "DataView offset out of bounds"));
|
||||
match offset.checked_add(N) {
|
||||
Some(end) if end <= view_len => {}
|
||||
_ => return Err(crate::error::create_range_error(vm, "DataView offset out of bounds")),
|
||||
}
|
||||
let abs = view.byte_offset + offset;
|
||||
buffer[abs..abs + N].copy_from_slice(&bytes);
|
||||
Ok(())
|
||||
}
|
||||
@@ -183,18 +228,26 @@ fn has_data_view_proto<H: VmHost>(vm: &mut H, this_val: JsValue) -> bool {
|
||||
/// # 步骤
|
||||
/// 1. receiver 原型链不含 %DataView.prototype% → TypeError(普通调用面:
|
||||
/// this = globalThis 不满足;构造路径恒传 DataView 原型链上的 receiver)。
|
||||
/// 2. buffer 品牌校验(ArrayBufferData)。
|
||||
/// 3. offset = ToIndex(byteOffset) 传播式;detached 缓冲 → TypeError(在
|
||||
/// 偏移强转之后);offset > bufferLen → RangeError。
|
||||
/// 4. byteLength 缺省/undefined → bufferLen - offset,否则 ToIndex 传播式;
|
||||
/// offset + byteLength > bufferLen → RangeError。
|
||||
/// 2. buffer 品牌校验(ArrayBufferData);首个载荷取用后即弃指针,
|
||||
/// 不持借用跨 JS 调用。
|
||||
/// 3. offset = ToIndex(byteOffset) 传播式;其后重取(重读寄存器 + 载荷重取):
|
||||
/// detached 缓冲 → TypeError(在偏移强转之后);offset > live → RangeError。
|
||||
/// 4. byteLength 缺省/undefined → 缺省长 live − offset,auto 位按构造期缓冲
|
||||
/// resizable 定;否则 ToIndex 传播式,其后重取按新 live 复验
|
||||
/// offset + byteLength → RangeError。
|
||||
/// 5. GetPrototypeFromConstructor:经 `ordinary_get` 读 NewTarget(regs[255])
|
||||
/// 的 `prototype`(触发访问器,读期异常原值传播);非对象回落 %DataView.prototype%。
|
||||
/// 6. 分配 OBJ_TYPE_DATA_VIEW 对象并挂 DataViewData 状态盒。
|
||||
/// 6. 终校验(proto 读后再重取一次):detached → TypeError;offset > live' →
|
||||
/// RangeError;显式长 offset + byteLength > live' → RangeError;auto 视图
|
||||
/// 存储长按 live' − offset 重算。
|
||||
/// 7. 分配 OBJ_TYPE_DATA_VIEW 对象并挂 DataViewData 状态盒(终校验先于
|
||||
/// 分配,raise 路径无半成品对象)。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 原型读取在全部校验之后:越界 RangeError 先于抛错的 prototype getter。
|
||||
/// - 原型读取在全部初校验之后:越界 RangeError 先于抛错的 prototype getter。
|
||||
/// - NewTarget 非对象(直调/缺省面)时直接回落默认原型,不抛错。
|
||||
/// - 每个 JS 调用点后重取缓冲(重读寄存器 + 载荷重取):晋升改写寄存器,
|
||||
/// 旧值滞留 epoch 克隆旧盒。
|
||||
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) {
|
||||
@@ -205,37 +258,34 @@ pub fn data_view_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, "DataView requires an ArrayBuffer"));
|
||||
}
|
||||
let buffer = vm.reg(args[1]);
|
||||
let payload_ptr = native_try!(array_buffer_payload(vm, buffer));
|
||||
// SAFETY: payload_ptr 经 array_buffer_payload 校验为合法 ArrayBuffer 载荷。
|
||||
let buf = unsafe { &*payload_ptr }.data.as_deref();
|
||||
let buffer_len = buf.map_or(0, |d| d.len());
|
||||
// 首个载荷取用只做品牌校验,指针即弃,不持借用跨 JS 调用。
|
||||
native_try!(array_buffer_payload(vm, buffer));
|
||||
|
||||
let byte_offset = if args.len() > 2 {
|
||||
native_try!(to_index(vm, vm.reg(args[2]), "DataView byteOffset out of bounds"))
|
||||
} else {
|
||||
0
|
||||
};
|
||||
// detach 守卫在偏移强转之后、越界判定之前(规范序:detached 缓冲构造
|
||||
// 抛 TypeError,且偏移的 ToNumber 已恰好发生一次)。
|
||||
if buf.is_none() {
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, "ArrayBuffer internal state invalid"));
|
||||
}
|
||||
if byte_offset > buffer_len {
|
||||
|
||||
// 偏移强转后的重取:detached 缓冲构造抛 TypeError,且偏移的 ToNumber
|
||||
// 已恰好发生一次(规范序)。
|
||||
let (_, live, max_byte_length) = native_try!(revalidate_buffer(vm, args[1]));
|
||||
if byte_offset > live {
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "DataView byteOffset out of bounds"));
|
||||
}
|
||||
let default_len = buffer_len - byte_offset;
|
||||
// byteLength 显式 undefined 视同缺省(ToIndex(undefined) = 0 会吞掉视图长度)。
|
||||
let byte_length = if args.len() > 3 {
|
||||
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"))
|
||||
|
||||
// byteLength 显式 undefined 视同缺省(ToIndex(undefined) = 0 会吞掉视图长度);
|
||||
// 缺省臂 auto 位按构造期缓冲 resizable 判定。
|
||||
let explicit = args.len() > 3 && !vm.reg(args[3]).is_undefined();
|
||||
let length_is_auto = !explicit && max_byte_length != 0;
|
||||
let mut byte_length = live - byte_offset;
|
||||
if explicit {
|
||||
byte_length = native_try!(to_index(vm, vm.reg(args[3]), "DataView byteLength out of bounds"));
|
||||
// byteLength 强转后的重取,按新 live 复验。
|
||||
let (_, live, _) = native_try!(revalidate_buffer(vm, args[1]));
|
||||
if byte_offset + byte_length > live {
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "DataView byteLength out of bounds"));
|
||||
}
|
||||
} else {
|
||||
default_len
|
||||
};
|
||||
if byte_offset + byte_length > buffer_len {
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "DataView byteLength out of bounds"));
|
||||
}
|
||||
|
||||
// GetPrototypeFromConstructor:普通读触发原型链上的访问器 getter,
|
||||
@@ -259,12 +309,24 @@ pub fn data_view_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
||||
default_proto
|
||||
};
|
||||
|
||||
// 终校验:proto getter 是用户代码窗(detach/resize 可发生),再重取一次,
|
||||
// 全部判定用 live';auto 视图存储长按 live' − offset 重算。
|
||||
let (buffer, live, _) = native_try!(revalidate_buffer(vm, args[1]));
|
||||
if byte_offset > live {
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "DataView byteOffset out of bounds"));
|
||||
}
|
||||
if !length_is_auto && byte_offset + byte_length > live {
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "DataView byteLength out of bounds"));
|
||||
}
|
||||
let byte_length = if length_is_auto { live - byte_offset } else { byte_length };
|
||||
|
||||
let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, proto);
|
||||
obj.type_tag = JsObject::OBJ_TYPE_DATA_VIEW;
|
||||
let data = Box::into_raw(Box::new(DataViewData {
|
||||
buffer,
|
||||
byte_offset,
|
||||
byte_length,
|
||||
length_is_auto,
|
||||
}));
|
||||
// SAFETY: DataView 对象不可调用,native_fn 存不透明 `Box<DataViewData>` 指针,
|
||||
// 与 ArrayBuffer / RegExp 的类型化存储模式一致。
|
||||
@@ -502,10 +564,12 @@ pub fn data_view_get_big_uint64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeRes
|
||||
|
||||
/// `DataView.prototype.setInt8(byteOffset, value)`:写入 1 字节有符号整数。
|
||||
///
|
||||
/// 步序:品牌 → ToIndex(byteOffset) → ToInt32(value) 回卷 → 越界 RangeError → 写。
|
||||
/// 步序:品牌 → immutable 写守卫 → ToIndex(byteOffset) → ToInt32(value)
|
||||
/// 回卷 → 越界 RangeError → 写。
|
||||
pub fn data_view_set_int8<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));
|
||||
native_try!(dv_buffer_writable(vm, view));
|
||||
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]));
|
||||
@@ -516,6 +580,7 @@ pub fn data_view_set_int8<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
pub fn data_view_set_uint8<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));
|
||||
native_try!(dv_buffer_writable(vm, view));
|
||||
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]));
|
||||
@@ -526,6 +591,7 @@ pub fn data_view_set_uint8<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
pub fn data_view_set_int16<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));
|
||||
native_try!(dv_buffer_writable(vm, view));
|
||||
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) {
|
||||
@@ -541,6 +607,7 @@ pub fn data_view_set_int16<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
pub fn data_view_set_uint16<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));
|
||||
native_try!(dv_buffer_writable(vm, view));
|
||||
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) {
|
||||
@@ -556,6 +623,7 @@ pub fn data_view_set_uint16<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
||||
pub fn data_view_set_int32<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));
|
||||
native_try!(dv_buffer_writable(vm, view));
|
||||
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) { n.to_le_bytes() } else { n.to_be_bytes() };
|
||||
@@ -567,6 +635,7 @@ pub fn data_view_set_int32<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
pub fn data_view_set_uint32<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));
|
||||
native_try!(dv_buffer_writable(vm, view));
|
||||
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) {
|
||||
@@ -582,6 +651,7 @@ pub fn data_view_set_uint32<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
||||
pub fn data_view_set_float32<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));
|
||||
native_try!(dv_buffer_writable(vm, view));
|
||||
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) {
|
||||
@@ -598,6 +668,7 @@ pub fn data_view_set_float32<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
||||
pub fn data_view_set_float16<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));
|
||||
native_try!(dv_buffer_writable(vm, view));
|
||||
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);
|
||||
@@ -614,6 +685,7 @@ pub fn data_view_set_float16<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
||||
pub fn data_view_set_float64<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));
|
||||
native_try!(dv_buffer_writable(vm, view));
|
||||
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) {
|
||||
@@ -628,10 +700,12 @@ pub fn data_view_set_float64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
||||
/// `DataView.prototype.setBigInt64(byteOffset, value, littleEndian)`:按 ToBigInt
|
||||
/// 语义接收值(Number 入参抛 TypeError),取低 64 位位模式写入 8 字节有符号整数。
|
||||
///
|
||||
/// 步序:品牌 → ToIndex(byteOffset) → ToBigInt(value) → 越界 RangeError → 写。
|
||||
/// 步序:品牌 → immutable 写守卫 → ToIndex(byteOffset) → ToBigInt(value)
|
||||
/// → 越界 RangeError → 写。
|
||||
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));
|
||||
native_try!(dv_buffer_writable(vm, view));
|
||||
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||
let value = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
let b =
|
||||
@@ -651,6 +725,7 @@ pub fn data_view_set_big_int64<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResu
|
||||
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));
|
||||
native_try!(dv_buffer_writable(vm, view));
|
||||
let offset = native_try!(to_index_arg(vm, args, 1));
|
||||
let value = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
let b =
|
||||
@@ -686,21 +761,22 @@ pub fn data_view_buffer_getter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResu
|
||||
}
|
||||
|
||||
/// `DataView.prototype.byteOffset` getter:返回视图起始字节在 buffer 内的偏移。
|
||||
/// 缓冲已 detach 或视图越界(live 长口径)→ TypeError。
|
||||
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));
|
||||
let payload_ptr = native_try!(array_buffer_payload(vm, view.buffer));
|
||||
native_try!(dv_view_bounds(vm, payload_ptr, view));
|
||||
NativeResult::Ok(JsValue::float(view.byte_offset as f64))
|
||||
}
|
||||
|
||||
/// `DataView.prototype.byteLength` getter:返回视图覆盖的字节长度。
|
||||
/// 缓冲已 detach → TypeError(规范序:IsDetachedBuffer 检查先于返回值)。
|
||||
/// 缓冲已 detach 或视图越界 → TypeError;auto 视图返 live − offset 活读
|
||||
/// (存储值仅构造期语义)。
|
||||
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));
|
||||
let payload_ptr = native_try!(array_buffer_payload(vm, view.buffer));
|
||||
// SAFETY: payload_ptr 经 array_buffer_payload 校验为合法 ArrayBuffer 载荷。
|
||||
if unsafe { &*payload_ptr }.data.is_none() {
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, "ArrayBuffer internal state invalid"));
|
||||
}
|
||||
NativeResult::Ok(JsValue::float(view.byte_length as f64))
|
||||
let view_len = native_try!(dv_view_bounds(vm, payload_ptr, view));
|
||||
NativeResult::Ok(JsValue::float(view_len as f64))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user