feat: TA toStringTag 访问器收窄并补 ArrayBuffer tag

This commit is contained in:
2026-09-22 17:23:15 +00:00
parent 72f9a063a4
commit 44f6f6e55b
4 changed files with 60 additions and 5 deletions
+10 -3
View File
@@ -768,11 +768,18 @@ pub fn typed_array_length_getter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeRe
NativeResult::Ok(JsValue::int(view.length as i32))
}
/// `%TypedArray%.prototype[@@toStringTag]` 访问器:返回具体类型名(如 `Int16Array`),
/// 供 `Object.prototype.toString` 区分类型。
/// `%TypedArray%.prototype[@@toStringTag]` 访问器:返回具体类型名(如
/// `Int16Array`),供 `Object.prototype.toString` 区分类型。
///
/// # 边界与前提
/// - this 非对象、无 `[[TypedArrayName]]` 内部槽(如原型自身)或内部状态无效时
/// 返回 undefined(规范语义,不抛错)。
pub fn typed_array_to_string_tag_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_typed_array_data(vm, this_val));
let view = match get_typed_array_data(vm, this_val) {
Ok(view) => view,
Err(_) => return NativeResult::Ok(JsValue::undefined()),
};
NativeResult::Ok(vm.new_string(view.kind.name()))
}
@@ -250,7 +250,7 @@ pub fn bind_typed_array(core: &Arc<KernelCore>, session: &KernelSession, global:
session,
shared_proto,
oxide_types::private_key::make_well_known_symbol_key(oxide_types::private_key::WELL_KNOWN_SYMBOL_TO_STRING_TAG),
"get @@toStringTag",
"get [Symbol.toStringTag]",
oxide_builtins::typed_array::typed_array_to_string_tag_getter::<crate::vm::Vm> as *const (),
);
+2 -1
View File
@@ -628,8 +628,9 @@ fn install_to_string_tags(core: &Arc<KernelCore>, session: &KernelSession) {
let sh = core.shape_forge().as_ref();
let tag_id = oxide_types::private_key::WELL_KNOWN_SYMBOL_TO_STRING_TAG;
let tag_key = oxide_types::private_key::make_well_known_symbol_key(tag_id);
let cases: [(*mut JsObject, &str); 11] = [
let cases: [(*mut JsObject, &str); 12] = [
(world.map_proto.as_ptr() as *mut JsObject, "Map"),
(world.array_buffer_proto.as_ptr() as *mut JsObject, "ArrayBuffer"),
(world.set_proto.as_ptr() as *mut JsObject, "Set"),
(world.data_view_proto.as_ptr() as *mut JsObject, "DataView"),
(world.array_iterator_proto.as_ptr() as *mut JsObject, "Array Iterator"),
@@ -406,3 +406,50 @@ fn typed_array_bigint_methods_receive_bigint_values() {
.unwrap();
assert!(result.as_bool());
}
#[test]
fn typed_array_to_string_tag_undefined_for_non_ta_this() {
// 原型自身(无 [[TypedArrayName]] 内部槽)与基元/非 TA 对象 this 读值均为
// undefined,规范语义不抛错。
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var g = Object.getOwnPropertyDescriptor(TypedArray.prototype, Symbol.toStringTag).get; \
g.call(TypedArray.prototype) === undefined && \
g.call(null) === undefined && g.call(42) === undefined && \
g.call('x') === undefined && g.call({}) === undefined && g.call([]) === undefined",
)
.unwrap();
assert!(result.as_bool());
}
#[test]
fn typed_array_to_string_tag_accessor_name_label() {
// getter 的 name/length/set 描述符面按规范钉。
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var d = Object.getOwnPropertyDescriptor(TypedArray.prototype, Symbol.toStringTag); \
d.set === undefined && d.enumerable === false && d.configurable === true && \
d.get.name === 'get [Symbol.toStringTag]' && d.get.length === 0",
)
.unwrap();
assert!(result.as_bool());
}
#[test]
fn typed_array_instance_tag_and_arraybuffer_proto_tag() {
// 实例读类型名(经 Object.prototype.toString 与直读两面);
// ArrayBuffer.prototype 的 tag 为数据属性。
let mut vm = Vm::new();
let result = eval(
&mut vm,
"new Int16Array(2)[Symbol.toStringTag] === 'Int16Array' && \
Object.prototype.toString.call(new BigUint64Array(1)) === '[object BigUint64Array]' && \
Object.prototype.toString.call(new ArrayBuffer(4)) === '[object ArrayBuffer]' && \
ArrayBuffer.prototype[Symbol.toStringTag] === 'ArrayBuffer' && \
Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, Symbol.toStringTag).writable === false",
)
.unwrap();
assert!(result.as_bool());
}