fix: IC 快速路径 symbol 原始值走 Symbol.prototype 链

This commit is contained in:
2026-08-16 10:31:34 +08:00
parent a8378694be
commit 8ac26fc01f
6 changed files with 130 additions and 13 deletions
+10 -1
View File
@@ -1,6 +1,6 @@
use std::sync::Arc;
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_types::object::JsObject;
use oxide_types::value::JsValue;
@@ -36,6 +36,15 @@ pub fn bind_symbol(core: &Arc<KernelCore>, session: &KernelSession, global: &mut
],
);
// description 是访问器 getter(Symbol 原始值成员访问经 Symbol.prototype 链命中)。
bind_accessor_getter(
core,
session,
proto,
"description",
oxide_builtins::symbol::symbol_description_getter::<crate::vm::Vm> as *const (),
);
for (name, val) in [
(
"match",
+5
View File
@@ -70,6 +70,11 @@ impl Vm {
let proto = unsafe { &*proto_ptr };
return self.ordinary_get(proto, prop_name_si, val).map(Some);
}
if val.is_symbol() {
let proto_ptr = self.session.builtin_world().symbol_proto.as_ptr() as *mut JsObject;
let proto = unsafe { &*proto_ptr };
return self.ordinary_get(proto, prop_name_si, val).map(Some);
}
Ok(None)
}
@@ -283,3 +283,69 @@ fn symbol_key_read_via_get_own_property_symbols_index() {
.unwrap();
assert!(result.as_bool());
}
// --- Symbol 原始值成员访问走 Symbol.prototype 链 ---
#[test]
fn symbol_primitive_to_string_via_symbol_proto() {
let mut vm = Vm::new();
let result = eval(&mut vm, "Symbol('66').toString()").unwrap();
assert_eq!(to_str(&vm, result), "Symbol(66)");
}
#[test]
fn symbol_primitive_value_of_via_symbol_proto() {
let mut vm = Vm::new();
let result = eval(&mut vm, "var s = Symbol('x'); s.valueOf() === s").unwrap();
assert!(result.as_bool());
}
#[test]
fn symbol_primitive_chain_reaches_object_proto_method() {
let mut vm = Vm::new();
let result = eval(&mut vm, "Symbol('x').hasOwnProperty('description')").unwrap();
assert!(!result.as_bool());
}
#[test]
fn symbol_primitive_description_getter() {
let mut vm = Vm::new();
let result = eval(&mut vm, "Symbol('desc').description").unwrap();
assert_eq!(to_str(&vm, result), "desc");
}
#[test]
fn symbol_without_description_returns_undefined() {
let mut vm = Vm::new();
let result = eval(&mut vm, "Symbol().description").unwrap();
assert!(result.is_undefined());
}
#[test]
fn symbol_wrapper_object_description_unboxes() {
let mut vm = Vm::new();
let result = eval(&mut vm, "Object(Symbol('w')).description").unwrap();
assert_eq!(to_str(&vm, result), "w");
}
#[test]
fn symbol_description_non_symbol_receiver_throws_type_error() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"try { Object.getOwnPropertyDescriptor(Symbol.prototype, 'description').get.call(42); false } catch (e) { e instanceof TypeError }",
)
.unwrap();
assert!(result.as_bool());
}
#[test]
fn symbol_proto_direct_description_access_throws_type_error() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"try { Symbol.prototype.description; false } catch (e) { e instanceof TypeError }",
)
.unwrap();
assert!(result.as_bool());
}
@@ -181,3 +181,18 @@ fn primitive_receiver_skips_ic_ext_words() {
);
assert_eq!(r, "303", "字符串 length 经 primitive 分支返回 3,扩展字跳越无错位");
}
/// 非对象 receiver(symbol)经 IC primitive 分支走 Symbol.prototype 链:
/// toString/description 均经原型解析,扩展字跳越无错位。
#[test]
fn symbol_primitive_receiver_walks_symbol_proto() {
let (r, _hits, _misses) = run_once(
r#"var s = Symbol('x');
var ok = 0;
for (var i = 0; i < 100; i++) {
ok += (s.toString() === 'Symbol(x)') ? 1 : 0;
}
ok + ((s.description === 'x') ? 1 : 0)"#,
);
assert_eq!(r, "101", "symbol 原始值 toString/description 经 Symbol.prototype 解析");
}