refactor: 内置八文件内核访问器调用改经 VmHost 能力方法

This commit is contained in:
2026-10-08 07:23:24 +00:00
parent 583175d174
commit 376a2a1e9e
10 changed files with 376 additions and 420 deletions
Generated
+19 -19
View File
@@ -1160,7 +1160,7 @@ dependencies = [
[[package]]
name = "oxide_builtins"
version = "0.8.72"
version = "0.8.73"
dependencies = [
"chrono",
"fast-float",
@@ -1185,7 +1185,7 @@ dependencies = [
[[package]]
name = "oxide_bytecode"
version = "0.8.72"
version = "0.8.73"
dependencies = [
"num-bigint",
"oxide_log",
@@ -1193,7 +1193,7 @@ dependencies = [
[[package]]
name = "oxide_cfg"
version = "0.8.72"
version = "0.8.73"
dependencies = [
"oxide_bytecode",
"oxide_emit",
@@ -1204,7 +1204,7 @@ dependencies = [
[[package]]
name = "oxide_cli"
version = "0.8.72"
version = "0.8.73"
dependencies = [
"ansi_term",
"bumpalo",
@@ -1226,7 +1226,7 @@ dependencies = [
[[package]]
name = "oxide_code_cache"
version = "0.8.72"
version = "0.8.73"
dependencies = [
"lru",
"oxide_bytecode",
@@ -1235,7 +1235,7 @@ dependencies = [
[[package]]
name = "oxide_compiler"
version = "0.8.72"
version = "0.8.73"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1255,7 +1255,7 @@ dependencies = [
[[package]]
name = "oxide_dce"
version = "0.8.72"
version = "0.8.73"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1269,7 +1269,7 @@ dependencies = [
[[package]]
name = "oxide_emit"
version = "0.8.72"
version = "0.8.73"
dependencies = [
"num-bigint",
"oxc_allocator",
@@ -1284,7 +1284,7 @@ dependencies = [
[[package]]
name = "oxide_engine"
version = "0.8.72"
version = "0.8.73"
dependencies = [
"oxide_bytecode",
"oxide_compiler",
@@ -1296,7 +1296,7 @@ dependencies = [
[[package]]
name = "oxide_ir"
version = "0.8.72"
version = "0.8.73"
dependencies = [
"oxide_bytecode",
"oxide_log",
@@ -1305,7 +1305,7 @@ dependencies = [
[[package]]
name = "oxide_kernel"
version = "0.8.72"
version = "0.8.73"
dependencies = [
"bumpalo",
"dashmap",
@@ -1319,7 +1319,7 @@ dependencies = [
[[package]]
name = "oxide_liveness"
version = "0.8.72"
version = "0.8.73"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1331,7 +1331,7 @@ dependencies = [
[[package]]
name = "oxide_log"
version = "0.8.72"
version = "0.8.73"
dependencies = [
"tracing",
"tracing-appender",
@@ -1340,7 +1340,7 @@ dependencies = [
[[package]]
name = "oxide_parser"
version = "0.8.72"
version = "0.8.73"
dependencies = [
"oxc_allocator",
"oxc_ast",
@@ -1355,7 +1355,7 @@ dependencies = [
[[package]]
name = "oxide_regalloc"
version = "0.8.72"
version = "0.8.73"
dependencies = [
"oxide_bytecode",
"oxide_cfg",
@@ -1371,7 +1371,7 @@ dependencies = [
[[package]]
name = "oxide_runtime_api"
version = "0.8.72"
version = "0.8.73"
dependencies = [
"num-bigint",
"num-traits",
@@ -1384,7 +1384,7 @@ dependencies = [
[[package]]
name = "oxide_test262"
version = "0.8.72"
version = "0.8.73"
dependencies = [
"oxide_bytecode",
"oxide_compiler",
@@ -1402,7 +1402,7 @@ dependencies = [
[[package]]
name = "oxide_types"
version = "0.8.72"
version = "0.8.73"
dependencies = [
"bumpalo",
"dashmap",
@@ -1415,7 +1415,7 @@ dependencies = [
[[package]]
name = "oxide_vm"
version = "0.8.72"
version = "0.8.73"
dependencies = [
"bumpalo",
"chrono",
+1 -1
View File
@@ -23,7 +23,7 @@ members = [
]
[workspace.package]
version = "0.8.72"
version = "0.8.73"
edition = "2021"
license = "MIT"
rust-version = "1.80"
+37 -50
View File
@@ -1,8 +1,5 @@
use std::sync::Arc;
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
use oxide_runtime_api::{to_string_full, NativeResult, VmHost};
use oxide_types::mem::P;
use oxide_runtime_api::{to_string_full, NativeResult, ProtoKind, VmHost};
use oxide_types::object::{JsObject, PropAttributes};
use oxide_types::value::JsValue;
@@ -25,10 +22,8 @@ fn set_own_message<H: VmHost>(host: &mut H, this: *mut JsObject, args: &[u8]) ->
return NativeResult::Err(create_type_error(host, "Cannot convert value to a string"));
}
};
let sf = Arc::clone(host.kernel_core().perm_interner());
let sh = Arc::clone(host.kernel_core().shape_forge());
let si = sf.intern("message").0;
let new_shape = sh.make_shape(EMPTY_SHAPE_ID, si);
let si = host.perm_intern("message");
let new_shape = host.make_shape(EMPTY_SHAPE_ID, si);
let perm_val = host.new_string(&msg_str);
unsafe {
(*this).set_shape_id(new_shape);
@@ -43,20 +38,18 @@ fn set_own_message<H: VmHost>(host: &mut H, this: *mut JsObject, args: &[u8]) ->
/// 这是引擎内部构造错误的统一入口,供 VM/native 层抛错使用。
pub fn create_kind_error<H: VmHost>(host: &mut H, kind: &str, msg: &str) -> JsValue {
let proto_ptr = match kind {
"TypeError" => P::as_ptr(&host.session().builtin_world().type_error_proto) as *mut JsObject,
"RangeError" => P::as_ptr(&host.session().builtin_world().range_error_proto) as *mut JsObject,
"ReferenceError" => P::as_ptr(&host.session().builtin_world().reference_error_proto) as *mut JsObject,
"SyntaxError" => P::as_ptr(&host.session().builtin_world().syntax_error_proto) as *mut JsObject,
"URIError" => P::as_ptr(&host.session().builtin_world().uri_error_proto) as *mut JsObject,
"EvalError" => P::as_ptr(&host.session().builtin_world().eval_error_proto) as *mut JsObject,
_ => P::as_ptr(&host.session().builtin_world().error_proto) as *mut JsObject,
"TypeError" => host.builtin_proto(ProtoKind::TypeErrorProto),
"RangeError" => host.builtin_proto(ProtoKind::RangeErrorProto),
"ReferenceError" => host.builtin_proto(ProtoKind::ReferenceErrorProto),
"SyntaxError" => host.builtin_proto(ProtoKind::SyntaxErrorProto),
"URIError" => host.builtin_proto(ProtoKind::UriErrorProto),
"EvalError" => host.builtin_proto(ProtoKind::EvalErrorProto),
_ => host.builtin_proto(ProtoKind::ErrorProto),
};
let obj = host.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto_ptr)));
let sf = Arc::clone(host.kernel_core().perm_interner());
let sh = Arc::clone(host.kernel_core().shape_forge());
if !msg.is_empty() {
let si_msg = sf.intern("message").0;
let shape = sh.make_shape(EMPTY_SHAPE_ID, si_msg);
let si_msg = host.perm_intern("message");
let shape = host.make_shape(EMPTY_SHAPE_ID, si_msg);
let msg_val = host.new_string(msg);
unsafe {
(*obj).set_shape_id(shape);
@@ -160,7 +153,7 @@ pub fn create_uri_error<H: VmHost>(host: &mut H, msg: &str) -> JsValue {
}
macro_rules! error_ctor {
($name:ident, $proto_field:ident) => {
($name:ident, $proto_kind:ident) => {
/// 对应 Error 子类(如 `TypeError`)的构造函数:接收第一个实参作为 message,
/// 返回携带 Error 家族标签(`[[ErrorData]]` 谓词)的实例。
///
@@ -172,7 +165,7 @@ macro_rules! error_ctor {
pub fn $name<H: VmHost>(host: &mut H, args: &[u8]) -> NativeResult {
let this_val = host.reg(if args.is_empty() { 0 } else { args[0] });
let new_target = host.reg(255);
let proto_ptr = P::as_ptr(&host.session().builtin_world().$proto_field) as *mut JsObject;
let proto_ptr = host.builtin_proto(ProtoKind::$proto_kind);
let this = if this_val.is_object() && new_target.is_object() {
this_val.as_js_object_ptr()
} else {
@@ -195,21 +188,19 @@ macro_rules! error_ctor {
};
}
error_ctor!(error_constructor, error_proto);
error_ctor!(type_error_constructor, type_error_proto);
error_ctor!(reference_error_constructor, reference_error_proto);
error_ctor!(range_error_constructor, range_error_proto);
error_ctor!(syntax_error_constructor, syntax_error_proto);
error_ctor!(uri_error_constructor, uri_error_proto);
error_ctor!(eval_error_constructor, eval_error_proto);
error_ctor!(error_constructor, ErrorProto);
error_ctor!(type_error_constructor, TypeErrorProto);
error_ctor!(reference_error_constructor, ReferenceErrorProto);
error_ctor!(range_error_constructor, RangeErrorProto);
error_ctor!(syntax_error_constructor, SyntaxErrorProto);
error_ctor!(uri_error_constructor, UriErrorProto);
error_ctor!(eval_error_constructor, EvalErrorProto);
/// 在对象上追加一个非枚举数据属性(writable/configurable=true,enumerable=false),
/// 与 `CreateNonEnumerableDataPropertyOrThrow` 语义一致。
fn set_own_data_prop<H: VmHost>(host: &mut H, obj: *mut JsObject, key: &str, val: JsValue) {
let sf = Arc::clone(host.kernel_core().perm_interner());
let sh = Arc::clone(host.kernel_core().shape_forge());
let si = sf.intern(key).0;
let new_shape = sh.make_shape(unsafe { (*obj).shape_id() }, si);
let si = host.perm_intern(key);
let new_shape = host.make_shape(unsafe { (*obj).shape_id() }, si);
unsafe {
(*obj).set_shape_id(new_shape);
let pos = (*obj).push_prop(val);
@@ -229,7 +220,7 @@ pub fn install_error_cause<H: VmHost>(host: &mut H, obj: *mut JsObject, options:
}
// SAFETY: is_object 保证指针非空且对象本 session 存活。
let opts = unsafe { &*options.as_js_object_ptr() };
let si = host.kernel_core().perm_interner().intern("cause").0;
let si = host.perm_intern("cause");
if host.resolve_property(opts, si).is_none() {
return NativeResult::Ok(JsValue::undefined());
}
@@ -257,7 +248,7 @@ pub fn install_error_cause<H: VmHost>(host: &mut H, obj: *mut JsObject, options:
pub fn suppressed_error_constructor<H: VmHost>(host: &mut H, args: &[u8]) -> NativeResult {
let this_val = host.reg(if args.is_empty() { 0 } else { args[0] });
let new_target = host.reg(255);
let proto_ptr = P::as_ptr(&host.session().builtin_world().suppressed_error_proto) as *mut JsObject;
let proto_ptr = host.builtin_proto(ProtoKind::SuppressedErrorProto);
let obj = if this_val.is_object() && new_target.is_object() {
this_val.as_js_object_ptr()
} else {
@@ -302,7 +293,7 @@ pub fn suppressed_error_constructor<H: VmHost>(host: &mut H, args: &[u8]) -> Nat
/// - 错误值/suppressed 值原样存储,不做任何转换;
/// - 返回对象 proto = suppressed_error_proto,标记 OBJ_TYPE_ERROR。
pub fn create_suppressed_error<H: VmHost>(host: &mut H, error_val: JsValue, suppressed_val: JsValue) -> JsValue {
let proto_ptr = P::as_ptr(&host.session().builtin_world().suppressed_error_proto) as *mut JsObject;
let proto_ptr = host.builtin_proto(ProtoKind::SuppressedErrorProto);
let obj = host.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto_ptr)));
set_own_data_prop(host, obj, "error", error_val);
set_own_data_prop(host, obj, "suppressed", suppressed_val);
@@ -332,9 +323,8 @@ pub fn error_to_string<H: VmHost>(host: &mut H, args: &[u8]) -> NativeResult {
return NativeResult::Err(err);
}
let obj = unsafe { &*this_val.as_js_object_ptr() };
let sf = Arc::clone(host.kernel_core().perm_interner());
let si_name = sf.intern("name").0;
let si_msg = sf.intern("message").0;
let si_name = host.perm_intern("name");
let si_msg = host.perm_intern("message");
let name_str = match host.ordinary_get(obj, si_name, this_val) {
Ok(v) if v.is_undefined() => "Error".to_string(),
@@ -383,9 +373,8 @@ pub fn error_stack_getter<H: VmHost>(host: &mut H, args: &[u8]) -> NativeResult
if !obj.is_error_obj() {
return NativeResult::Ok(JsValue::undefined());
}
let sf = Arc::clone(host.kernel_core().perm_interner());
let si_name = sf.intern("name").0;
let si_msg = sf.intern("message").0;
let si_name = host.perm_intern("name");
let si_msg = host.perm_intern("message");
let n = host
.resolve_property(obj, si_name)
.and_then(|v| host.lookup_str(v))
@@ -421,7 +410,7 @@ pub fn error_stack_setter<H: VmHost>(host: &mut H, args: &[u8]) -> NativeResult
if !this_val.is_object() {
return NativeResult::Err(create_type_error(host, "Error.prototype.stack setter called on non-object"));
}
let home = P::as_ptr(&host.session().builtin_world().error_proto) as *mut JsObject;
let home = host.builtin_proto(ProtoKind::ErrorProto);
if std::ptr::eq(this_val.as_js_object_ptr(), home) {
return NativeResult::Err(create_type_error(host, "cannot assign to read only property of Error prototype"));
}
@@ -431,7 +420,7 @@ pub fn error_stack_setter<H: VmHost>(host: &mut H, args: &[u8]) -> NativeResult
}
// SAFETY: is_object 保证指针非空且对象本 session 存活;写入路径对象不搬移。
let this_obj = unsafe { &mut *this_val.as_js_object_ptr() };
let si = host.kernel_core().perm_interner().intern("stack").0;
let si = host.perm_intern("stack");
match host.get_own_property_slot(this_obj, si) {
None => match host.define_data_property(this_obj, si, val, PropAttributes::new(true, true, true)) {
Ok(()) => NativeResult::Ok(JsValue::undefined()),
@@ -477,9 +466,8 @@ pub fn error_to_json<H: VmHost>(host: &mut H, args: &[u8]) -> NativeResult {
}
// SAFETY: is_object 保证指针非空且对象本 session 存活;读取期间不搬移。
let obj = unsafe { &*this_val.as_js_object_ptr() };
let sf = Arc::clone(host.kernel_core().perm_interner());
let si_name = sf.intern("name").0;
let si_msg = sf.intern("message").0;
let si_name = host.perm_intern("name");
let si_msg = host.perm_intern("message");
let name_val = match host.ordinary_get(obj, si_name, this_val) {
Ok(v) => v,
@@ -517,16 +505,15 @@ pub fn error_to_json<H: VmHost>(host: &mut H, args: &[u8]) -> NativeResult {
}
// 新对象:proto = %Object.prototype%,name/message 为可枚举数据属性。
let object_proto = P::as_ptr(&host.session().builtin_world().object_proto) as *mut JsObject;
let object_proto = host.builtin_proto(ProtoKind::ObjectProto);
let ptr = host.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(object_proto)));
// SAFETY: ptr 由 alloc_object 新建,非空 arena 指针;后续 shape/属性分配不改对象地址,无别名。
let obj_ref = unsafe { &mut *ptr };
let sh = Arc::clone(host.kernel_core().shape_forge());
let name_shape = sh.make_shape(EMPTY_SHAPE_ID, si_name);
let name_shape = host.make_shape(EMPTY_SHAPE_ID, si_name);
obj_ref.set_shape_id(name_shape);
let name_pos = obj_ref.push_prop(host.new_string(&name_str));
obj_ref.set_data_meta(name_pos, PropAttributes::new(true, true, true));
let msg_shape = sh.make_shape(obj_ref.shape_id(), si_msg);
let msg_shape = host.make_shape(obj_ref.shape_id(), si_msg);
obj_ref.set_shape_id(msg_shape);
let msg_pos = obj_ref.push_prop(host.new_string(&msg_str));
obj_ref.set_data_meta(msg_pos, PropAttributes::new(true, true, true));
+90 -98
View File
@@ -1,9 +1,10 @@
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
use oxide_types::object::{JsObject, PropAttributes};
use oxide_types::private_key::{encode_symbol_key, make_int_key};
use oxide_types::string_forge::PermInterner;
use oxide_types::value::JsValue;
use oxide_runtime_api::{to_object, NativeResult, VmHost};
use oxide_runtime_api::{to_object, NativeResult, ProtoKind, VmHost};
const INNER_PROP: &str = "__inner__";
const INDEX_PROP: &str = "__index__";
@@ -47,7 +48,7 @@ pub fn iterator_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
if proto.is_object() {
let proto_ptr = proto.as_js_object_ptr();
if !proto_ptr.is_null() {
let home = vm.session().builtin_world().iterator_proto.as_ptr() as *mut JsObject;
let home = vm.builtin_proto(ProtoKind::IteratorProto);
if std::ptr::eq(proto_ptr, home) {
return NativeResult::Err(crate::error::create_type_error(vm, "Iterator is not a constructor"));
}
@@ -68,12 +69,11 @@ pub fn iterator_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
/// lookup 失败(极端:global 无 `Iterator`)返回 undefined,不 panic。
pub fn iterator_constructor_getter<H: VmHost>(vm: &mut H, _args: &[u8]) -> NativeResult {
let (shape_id, global_ptr) = {
let session = vm.session();
let global = session.global_object();
let global = vm.global_object();
(global.shape_id(), global.as_ptr() as *mut JsObject)
};
let si = vm.kernel_core().perm_interner().intern("Iterator").0;
let Some(pos) = vm.kernel_core().shape_forge().lookup_position(shape_id, si) else {
let si = vm.perm_intern("Iterator");
let Some(pos) = vm.lookup_position(shape_id, si) else {
return NativeResult::Ok(JsValue::undefined());
};
NativeResult::Ok(unsafe { &*global_ptr }.get_prop_at(pos))
@@ -81,8 +81,9 @@ pub fn iterator_constructor_getter<H: VmHost>(vm: &mut H, _args: &[u8]) -> Nativ
/// `%IteratorPrototype%` 上 `Symbol.toStringTag` 访问器的 getter:返回 `"Iterator"`。
pub fn iterator_to_string_tag_getter<H: VmHost>(vm: &mut H, _args: &[u8]) -> NativeResult {
let sf = vm.kernel_core().perm_interner().as_ref();
NativeResult::Ok(JsValue::perm_string(sf.string_ptr(sf.intern("Iterator").0)))
// SAFETY: perm interner 随 VM 存活,本表达式内只读即时消费。
let sf = vm.perm_interner_ptr() as *const PermInterner;
NativeResult::Ok(JsValue::perm_string(unsafe { &*sf }.string_ptr(vm.perm_intern("Iterator"))))
}
/// 忽略原型属性的 setter 的共享实现(对应规范 SetterThatIgnoresPrototypeProperties):
@@ -100,7 +101,7 @@ fn iterator_setter_ignore_proto_props<H: VmHost>(vm: &mut H, args: &[u8], key: u
if !this_val.is_object() {
return NativeResult::Err(crate::error::create_type_error(vm, "Iterator property setter called on non-object"));
}
let home = vm.session().builtin_world().iterator_proto.as_ptr() as *mut JsObject;
let home = vm.builtin_proto(ProtoKind::IteratorProto);
if std::ptr::eq(this_val.as_js_object_ptr(), home) {
return NativeResult::Err(crate::error::create_type_error(
vm,
@@ -109,12 +110,7 @@ fn iterator_setter_ignore_proto_props<H: VmHost>(vm: &mut H, args: &[u8], key: u
}
let val = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
let this_obj = unsafe { &mut *this_val.as_js_object_ptr() };
if vm
.kernel_core()
.shape_forge()
.lookup_position(this_obj.shape_id(), key)
.is_none()
{
if vm.lookup_position(this_obj.shape_id(), key).is_none() {
match vm.define_data_property(this_obj, key, val, PropAttributes::new(true, true, true)) {
Ok(()) => NativeResult::Ok(JsValue::undefined()),
Err(err) => NativeResult::Err(crate::error::create_type_error(vm, &err)),
@@ -129,7 +125,7 @@ fn iterator_setter_ignore_proto_props<H: VmHost>(vm: &mut H, args: &[u8], key: u
/// `constructor` 访问器的 setter(键 = "constructor")。
pub fn iterator_constructor_setter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let key = vm.kernel_core().perm_interner().intern("constructor").0;
let key = vm.perm_intern("constructor");
iterator_setter_ignore_proto_props(vm, args, key)
}
@@ -154,7 +150,7 @@ pub fn iterator_dispose<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
));
}
let obj = unsafe { &*this_val.as_js_object_ptr() };
let return_si = vm.kernel_core().perm_interner().intern("return").0;
let return_si = vm.perm_intern("return");
let return_fn = match vm.ordinary_get(obj, return_si, this_val) {
Ok(f) if is_callable(f) => f,
Ok(_) => JsValue::undefined(),
@@ -203,7 +199,7 @@ pub(crate) fn validate_terminal_and_get_direct<H: VmHost>(
/// - `next` getter 抛错时透传原异常值。
pub(crate) fn get_iterator_direct<H: VmHost>(vm: &mut H, this_val: JsValue) -> Result<(JsValue, JsValue), JsValue> {
let iter_obj = unsafe { &*this_val.as_js_object_ptr() };
let next_si = vm.kernel_core().perm_interner().intern("next").0;
let next_si = vm.perm_intern("next");
let next = vm.ordinary_get(iter_obj, next_si, this_val).map_err(|e| engine_error(vm, &e))?;
Ok((this_val, next))
}
@@ -222,12 +218,12 @@ pub(crate) fn iterator_record_step<H: VmHost>(
return Err(crate::error::create_type_error(vm, "iterator result is not an object"));
}
let result_obj = unsafe { &*result.as_js_object_ptr() };
let done_si = vm.kernel_core().perm_interner().intern("done").0;
let done_si = vm.perm_intern("done");
let done = vm.ordinary_get(result_obj, done_si, result).map_err(|e| engine_error(vm, &e))?;
if oxide_runtime_api::to_boolean(done) {
return Ok(None);
}
let value_si = vm.kernel_core().perm_interner().intern("value").0;
let value_si = vm.perm_intern("value");
let value = vm
.ordinary_get(result_obj, value_si, result)
.map_err(|e| engine_error(vm, &e))?;
@@ -248,7 +244,7 @@ pub(crate) fn iterator_close_record<H: VmHost>(
vm: &mut H, iterated: JsValue, completion_err: Option<JsValue>,
) -> Result<(), JsValue> {
let iter_obj = unsafe { &*iterated.as_js_object_ptr() };
let return_si = vm.kernel_core().perm_interner().intern("return").0;
let return_si = vm.perm_intern("return");
let return_fn = match vm.ordinary_get(iter_obj, return_si, iterated) {
Ok(f) if is_callable(f) => f,
Ok(_) => {
@@ -439,17 +435,17 @@ fn get_iterator_flattenable<H: VmHost>(vm: &mut H, value: JsValue) -> Result<(Js
fn make_iterator_helper<H: VmHost>(
vm: &mut H, inner: JsValue, next: JsValue, kind: IteratorHelperKind, callback: JsValue, counter: JsValue,
) -> JsValue {
let helper_proto = vm.session().builtin_world().iterator_helper_proto.as_ptr() as *mut JsObject;
let helper_proto = vm.builtin_proto(ProtoKind::IteratorHelperProto);
let wrapper = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(helper_proto)));
let wrapper_obj = unsafe { &mut *wrapper };
let inner_si = vm.kernel_core().perm_interner().intern(INNER_PROP).0;
let next_si = vm.kernel_core().perm_interner().intern(NEXT_CACHE_PROP).0;
let kind_si = vm.kernel_core().perm_interner().intern(KIND_PROP).0;
let state_si = vm.kernel_core().perm_interner().intern(STATE_PROP).0;
let counter_si = vm.kernel_core().perm_interner().intern(COUNTER_PROP).0;
let callback_si = vm.kernel_core().perm_interner().intern(CALLBACK_PROP).0;
let inner_iter_si = vm.kernel_core().perm_interner().intern(INNER_ITER_PROP).0;
let inner_next_si = vm.kernel_core().perm_interner().intern(INNER_NEXT_PROP).0;
let inner_si = vm.perm_intern(INNER_PROP);
let next_si = vm.perm_intern(NEXT_CACHE_PROP);
let kind_si = vm.perm_intern(KIND_PROP);
let state_si = vm.perm_intern(STATE_PROP);
let counter_si = vm.perm_intern(COUNTER_PROP);
let callback_si = vm.perm_intern(CALLBACK_PROP);
let inner_iter_si = vm.perm_intern(INNER_ITER_PROP);
let inner_next_si = vm.perm_intern(INNER_NEXT_PROP);
vm.set_or_create_prop_value(wrapper_obj, inner_si, inner);
vm.set_or_create_prop_value(wrapper_obj, next_si, next);
vm.set_or_create_prop_value(wrapper_obj, kind_si, JsValue::int(kind as i32));
@@ -471,7 +467,7 @@ fn validate_helper_this<H: VmHost>(vm: &mut H, this_val: JsValue, method: &str)
return Err(crate::error::create_type_error(vm, &format!("{method} called on non-object")));
}
let obj = unsafe { &*this_val.as_js_object_ptr() };
let inner_si = vm.kernel_core().perm_interner().intern(INNER_PROP).0;
let inner_si = vm.perm_intern(INNER_PROP);
let inner = vm.ordinary_get(obj, inner_si, this_val).map_err(|e| engine_error(vm, &e))?;
if !inner.is_object() {
return Err(crate::error::create_type_error(vm, &format!("{method} called on non-iterator-helper")));
@@ -709,7 +705,7 @@ pub fn iterator_to_array<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
/// 按元素列表构造普通数组,以 Array.prototype 为原型(对应规范 CreateArrayFromList)。
fn make_array_from_list<H: VmHost>(vm: &mut H, items: &[JsValue]) -> JsValue {
let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let array_proto = vm.builtin_proto(ProtoKind::ArrayProto);
let arr = vm.alloc_object(JsObject::new_array(
EMPTY_SHAPE_ID,
JsValue::from_js_object(array_proto),
@@ -863,7 +859,7 @@ pub fn iterator_helper_next<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
Err(v) => return NativeResult::Err(v),
};
let helper = unsafe { &mut *this_val.as_js_object_ptr() };
let state_si = vm.kernel_core().perm_interner().intern(STATE_PROP).0;
let state_si = vm.perm_intern(STATE_PROP);
let state = read_slot_int(vm, helper, state_si, 2);
if state == 2 {
return NativeResult::Ok(make_iter_result(vm, JsValue::undefined(), true));
@@ -871,10 +867,10 @@ pub fn iterator_helper_next<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
if state == 1 {
return NativeResult::Err(crate::error::create_type_error(vm, "Iterator helper is already executing"));
}
let kind_si = vm.kernel_core().perm_interner().intern(KIND_PROP).0;
let kind_si = vm.perm_intern(KIND_PROP);
let kind = IteratorHelperKind::from_i32(read_slot_int(vm, helper, kind_si, 0));
vm.set_or_create_prop_value(helper, state_si, JsValue::int(1));
let next_si = vm.kernel_core().perm_interner().intern(NEXT_CACHE_PROP).0;
let next_si = vm.perm_intern(NEXT_CACHE_PROP);
let next = vm.ordinary_get(helper, next_si, this_val).unwrap_or(JsValue::undefined());
let step = match kind {
IteratorHelperKind::Map => helper_step_map(vm, this_val, helper, inner, next),
@@ -914,7 +910,7 @@ pub fn iterator_helper_return<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResul
Err(v) => return NativeResult::Err(v),
};
let helper = unsafe { &mut *this_val.as_js_object_ptr() };
let state_si = vm.kernel_core().perm_interner().intern(STATE_PROP).0;
let state_si = vm.perm_intern(STATE_PROP);
let state = read_slot_int(vm, helper, state_si, 2);
if state == 2 {
return NativeResult::Ok(make_iter_result(vm, JsValue::undefined(), true));
@@ -923,9 +919,9 @@ pub fn iterator_helper_return<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResul
return NativeResult::Err(crate::error::create_type_error(vm, "Iterator helper is already executing"));
}
vm.set_or_create_prop_value(helper, state_si, JsValue::int(2));
let kind_si = vm.kernel_core().perm_interner().intern(KIND_PROP).0;
let kind_si = vm.perm_intern(KIND_PROP);
if IteratorHelperKind::from_i32(read_slot_int(vm, helper, kind_si, 0)) == IteratorHelperKind::FlatMap {
let inner_iter_si = vm.kernel_core().perm_interner().intern(INNER_ITER_PROP).0;
let inner_iter_si = vm.perm_intern(INNER_ITER_PROP);
if let Ok(inner_iter) = vm.ordinary_get(helper, inner_iter_si, this_val) {
if inner_iter.is_object() {
// 内层关闭出错:以该错误关外层(外层 return 错误被吞),传播内层错误。
@@ -956,7 +952,7 @@ pub fn iterator_helper_throw<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
Err(v) => return NativeResult::Err(v),
};
let helper = unsafe { &mut *this_val.as_js_object_ptr() };
let state_si = vm.kernel_core().perm_interner().intern(STATE_PROP).0;
let state_si = vm.perm_intern(STATE_PROP);
let state = read_slot_int(vm, helper, state_si, 2);
if state == 2 {
return NativeResult::Err(value);
@@ -965,9 +961,9 @@ pub fn iterator_helper_throw<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
return NativeResult::Err(crate::error::create_type_error(vm, "Iterator helper is already executing"));
}
vm.set_or_create_prop_value(helper, state_si, JsValue::int(2));
let kind_si = vm.kernel_core().perm_interner().intern(KIND_PROP).0;
let kind_si = vm.perm_intern(KIND_PROP);
if IteratorHelperKind::from_i32(read_slot_int(vm, helper, kind_si, 0)) == IteratorHelperKind::FlatMap {
let inner_iter_si = vm.kernel_core().perm_interner().intern(INNER_ITER_PROP).0;
let inner_iter_si = vm.perm_intern(INNER_ITER_PROP);
if let Ok(inner_iter) = vm.ordinary_get(helper, inner_iter_si, this_val) {
if inner_iter.is_object() {
// throw 语义:原值胜出,内层/外层关闭错误均被吞。
@@ -984,8 +980,8 @@ pub fn iterator_helper_throw<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
fn helper_step_map<H: VmHost>(
vm: &mut H, this_val: JsValue, helper: &mut JsObject, inner: JsValue, next: JsValue,
) -> Result<Option<JsValue>, JsValue> {
let counter_si = vm.kernel_core().perm_interner().intern(COUNTER_PROP).0;
let callback_si = vm.kernel_core().perm_interner().intern(CALLBACK_PROP).0;
let counter_si = vm.perm_intern(COUNTER_PROP);
let callback_si = vm.perm_intern(CALLBACK_PROP);
let mapper = vm.ordinary_get(helper, callback_si, this_val).unwrap_or(JsValue::undefined());
let counter = read_counter(vm, helper, counter_si);
let value = match iterator_record_step(vm, next, inner) {
@@ -1012,8 +1008,8 @@ fn helper_step_map<H: VmHost>(
fn helper_step_filter<H: VmHost>(
vm: &mut H, this_val: JsValue, helper: &mut JsObject, inner: JsValue, next: JsValue,
) -> Result<Option<JsValue>, JsValue> {
let counter_si = vm.kernel_core().perm_interner().intern(COUNTER_PROP).0;
let callback_si = vm.kernel_core().perm_interner().intern(CALLBACK_PROP).0;
let counter_si = vm.perm_intern(COUNTER_PROP);
let callback_si = vm.perm_intern(CALLBACK_PROP);
let predicate = vm.ordinary_get(helper, callback_si, this_val).unwrap_or(JsValue::undefined());
let mut counter = read_counter(vm, helper, counter_si);
loop {
@@ -1045,7 +1041,7 @@ fn helper_step_filter<H: VmHost>(
fn helper_step_take<H: VmHost>(
vm: &mut H, helper: &mut JsObject, inner: JsValue, next: JsValue,
) -> Result<Option<JsValue>, JsValue> {
let counter_si = vm.kernel_core().perm_interner().intern(COUNTER_PROP).0;
let counter_si = vm.perm_intern(COUNTER_PROP);
let remaining = read_slot_double(vm, helper, counter_si, f64::INFINITY);
if remaining == 0.0 {
// remaining 归零:正常完成形态关底层(return 错误胜出)。
@@ -1068,7 +1064,7 @@ fn helper_step_take<H: VmHost>(
fn helper_step_drop<H: VmHost>(
vm: &mut H, helper: &mut JsObject, inner: JsValue, next: JsValue,
) -> Result<Option<JsValue>, JsValue> {
let counter_si = vm.kernel_core().perm_interner().intern(COUNTER_PROP).0;
let counter_si = vm.perm_intern(COUNTER_PROP);
let mut remaining = read_slot_double(vm, helper, counter_si, 0.0);
while remaining > 0.0 {
if remaining != f64::INFINITY {
@@ -1096,10 +1092,10 @@ fn helper_step_drop<H: VmHost>(
fn helper_step_flat_map<H: VmHost>(
vm: &mut H, this_val: JsValue, helper: &mut JsObject, outer: JsValue, outer_next: JsValue,
) -> Result<Option<JsValue>, JsValue> {
let counter_si = vm.kernel_core().perm_interner().intern(COUNTER_PROP).0;
let callback_si = vm.kernel_core().perm_interner().intern(CALLBACK_PROP).0;
let inner_iter_si = vm.kernel_core().perm_interner().intern(INNER_ITER_PROP).0;
let inner_next_si = vm.kernel_core().perm_interner().intern(INNER_NEXT_PROP).0;
let counter_si = vm.perm_intern(COUNTER_PROP);
let callback_si = vm.perm_intern(CALLBACK_PROP);
let inner_iter_si = vm.perm_intern(INNER_ITER_PROP);
let inner_next_si = vm.perm_intern(INNER_NEXT_PROP);
let mapper = vm.ordinary_get(helper, callback_si, this_val).unwrap_or(JsValue::undefined());
let mut counter = read_counter(vm, helper, counter_si);
loop {
@@ -1246,13 +1242,13 @@ pub(crate) fn build_iterator_wrapper<H: VmHost>(
) -> JsValue {
let iterator_proto = match wrapper_proto {
Some(proto) => proto,
None => vm.session().builtin_world().iterator_proto.as_ptr() as *mut JsObject,
None => vm.builtin_proto(ProtoKind::IteratorProto),
};
let wrapper = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(iterator_proto)));
let inner_si = vm.kernel_core().perm_interner().intern(INNER_PROP).0;
let index_si = vm.kernel_core().perm_interner().intern(INDEX_PROP).0;
let next_si = vm.kernel_core().perm_interner().intern("next").0;
let inner_si = vm.perm_intern(INNER_PROP);
let index_si = vm.perm_intern(INDEX_PROP);
let next_si = vm.perm_intern("next");
let wrapper_obj = unsafe { &mut *wrapper };
vm.set_or_create_prop_value(wrapper_obj, inner_si, inner);
vm.set_or_create_prop_value(wrapper_obj, index_si, JsValue::int(0));
@@ -1261,7 +1257,7 @@ pub(crate) fn build_iterator_wrapper<H: VmHost>(
// "只读一次"同模式),消费期直读槽不重触发 getter;非鸭子路径无槽,wrapper next
// 回退重读内层 next(既有行为)。
if let Some(next_fn) = cached_next {
let next_cache_si = vm.kernel_core().perm_interner().intern(NEXT_CACHE_PROP).0;
let next_cache_si = vm.perm_intern(NEXT_CACHE_PROP);
vm.set_or_create_prop_value(wrapper_obj, next_cache_si, next_fn);
}
@@ -1270,7 +1266,7 @@ pub(crate) fn build_iterator_wrapper<H: VmHost>(
// for-of/解构的 IteratorClose 需要 return 方法:条件暴露(内层有可调用 return 时)。
// `yield*` 委托(bind_return=false)不绑定,转发时对内层延迟 GetMethod。
let return_si = vm.kernel_core().perm_interner().intern("return").0;
let return_si = vm.perm_intern("return");
if bind_return && inner.is_object() {
let inner_obj = unsafe { &*inner.as_js_object_ptr() };
if let Ok(return_fn) = vm.ordinary_get(inner_obj, return_si, inner) {
@@ -1290,14 +1286,14 @@ fn iterator_wrapper_return<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
return NativeResult::Ok(JsValue::undefined());
}
let wrapper = unsafe { &*this_val.as_js_object_ptr() };
let inner_si = vm.kernel_core().perm_interner().intern(INNER_PROP).0;
let inner_si = vm.perm_intern(INNER_PROP);
let inner = match vm.ordinary_get(wrapper, inner_si, this_val) {
Ok(inner) if inner.is_object() => inner,
_ => return NativeResult::Ok(JsValue::undefined()),
};
// 延迟 GetMethod:内层无 return 方法时返回 undefined(IteratorClose 跳过)。
let inner_obj = unsafe { &*inner.as_js_object_ptr() };
let return_si = vm.kernel_core().perm_interner().intern("return").0;
let return_si = vm.perm_intern("return");
let return_fn = match vm.ordinary_get(inner_obj, return_si, inner) {
Ok(f) if is_callable(f) => f,
_ => return NativeResult::Ok(JsValue::undefined()),
@@ -1323,8 +1319,8 @@ pub fn iterator_wrapper_next<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
}
let wrapper = unsafe { &mut *this_val.as_js_object_ptr() };
let inner_si = vm.kernel_core().perm_interner().intern(INNER_PROP).0;
let index_si = vm.kernel_core().perm_interner().intern(INDEX_PROP).0;
let inner_si = vm.perm_intern(INNER_PROP);
let index_si = vm.perm_intern(INDEX_PROP);
let inner = match vm.ordinary_get(wrapper, inner_si, this_val) {
Ok(inner) if !inner.is_undefined() => inner,
_ => return NativeResult::Err(crate::error::create_type_error(vm, "Iterator wrapper has no inner iterator")),
@@ -1340,7 +1336,7 @@ pub fn iterator_wrapper_next<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
// 鸭子回退包装器优先读 `__next__` 槽(from() 时只读一次的缓存闭包,
// 消费期不重触发 getter);槽缺失或不可调用时回退重读内层 next
// (非鸭子路径既有行为)。
let next_cache_si = vm.kernel_core().perm_interner().intern(NEXT_CACHE_PROP).0;
let next_cache_si = vm.perm_intern(NEXT_CACHE_PROP);
let cached = match vm.ordinary_get(wrapper, next_cache_si, this_val) {
Ok(c) => c,
Err(err) => {
@@ -1355,7 +1351,7 @@ pub fn iterator_wrapper_next<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
cached
} else {
let inner_obj = unsafe { &*inner.as_js_object_ptr() };
let next_si = vm.kernel_core().perm_interner().intern("next").0;
let next_si = vm.perm_intern("next");
match vm.ordinary_get(inner_obj, next_si, inner) {
Ok(n) => n,
Err(err) => {
@@ -1405,7 +1401,7 @@ pub(crate) fn peek_iterator_method<H: VmHost>(vm: &mut H, value: JsValue) -> Res
// (与 get_iterator 的 String 臂同口径)。默认迭代器被删除/置 null 时须落
// array-like,而非按"String 恒可迭代"放行迭代路径。
if value.is_string() {
let proto_ptr = vm.session().builtin_world().string_proto.as_ptr() as *mut JsObject;
let proto_ptr = vm.builtin_proto(ProtoKind::StringProto);
// SAFETY: string_proto 是 BuiltinWorld 长驻原型对象,进程内有效且不被 GC 搬移。
let proto_obj = unsafe { &*proto_ptr };
let sym_iter_si = encode_symbol_key(vm.realm_id(), 0);
@@ -1465,7 +1461,7 @@ pub(crate) fn peek_iterator_method<H: VmHost>(vm: &mut H, value: JsValue) -> Res
// 装箱串不套用:get_iterator 的 String 臂无 duck-next 回退,规范也只看
// @@iterator(Array.from/%TypedArray%.from 应落 array-like)。
if !obj.is_string_obj() {
let next_si = vm.kernel_core().perm_interner().intern("next").0;
let next_si = vm.perm_intern("next");
if let Ok(next) = vm.ordinary_get(obj, next_si, value) {
if is_callable(next) {
return Ok(true);
@@ -1490,21 +1486,17 @@ fn builtin_iterator_default_intact<H: VmHost>(vm: &mut H, value: JsValue, method
if !method.is_object() {
return false;
}
let (anchor_ptr, anchor_name) = {
let session = vm.session();
let world = session.builtin_world();
if is_array_value(value) {
(world.array_proto.as_ptr() as *mut JsObject, "values")
} else if is_typed_array_value(value) {
(world.typed_array_proto.as_ptr() as *mut JsObject, "values")
} else if is_map_value(value) {
(world.map_proto.as_ptr() as *mut JsObject, "entries")
} else {
(world.set_proto.as_ptr() as *mut JsObject, "values")
}
let (anchor_ptr, anchor_name) = if is_array_value(value) {
(vm.builtin_proto(ProtoKind::ArrayProto), "values")
} else if is_typed_array_value(value) {
(vm.builtin_proto(ProtoKind::TypedArrayProto), "values")
} else if is_map_value(value) {
(vm.builtin_proto(ProtoKind::MapProto), "entries")
} else {
(vm.builtin_proto(ProtoKind::SetProto), "values")
};
let anchor_obj = unsafe { &*anchor_ptr };
let anchor_si = vm.kernel_core().perm_interner().intern(anchor_name).0;
let anchor_si = vm.perm_intern(anchor_name);
let Ok(anchor) = vm.ordinary_get(anchor_obj, anchor_si, JsValue::from_js_object(anchor_ptr)) else {
return false;
};
@@ -1539,7 +1531,7 @@ fn get_iterator<H: VmHost>(vm: &mut H, value: JsValue) -> Result<Option<(JsValue
let read_ptr = if value_is_string_box {
value.as_js_object_ptr()
} else {
vm.session().builtin_world().string_proto.as_ptr() as *mut JsObject
vm.builtin_proto(ProtoKind::StringProto)
};
let read_obj = unsafe { &*read_ptr };
let sym_iter_si = encode_symbol_key(vm.realm_id(), 0);
@@ -1567,7 +1559,7 @@ fn get_iterator<H: VmHost>(vm: &mut H, value: JsValue) -> Result<Option<(JsValue
};
// 默认迭代器(自别名:即 @@iterator 槽本身)走码元快速路径、不调方法——
// 调默认函数会递归回本 String 臂。指针未捕获(绑定前瞬时)亦回退快速路径。
let default_ptr = vm.session().builtin_world().string_default_iterator.get();
let default_ptr = vm.string_default_iterator();
if !default_ptr.is_null()
&& is_callable(method)
&& std::ptr::eq(method.as_js_object_ptr() as *const JsObject, default_ptr)
@@ -1657,7 +1649,7 @@ fn get_iterator<H: VmHost>(vm: &mut H, value: JsValue) -> Result<Option<(JsValue
}
// 鸭子回退:对象自身有可调用 next(Map/Set 迭代器包装等既有用法)。
// getter 抛错透传原值(不落入"不可迭代"),读到的闭包随 inner 回传供缓存。
let next_si = vm.kernel_core().perm_interner().intern("next").0;
let next_si = vm.perm_intern("next");
let next = match vm.ordinary_get(obj, next_si, value) {
Ok(n) => n,
Err(err) => {
@@ -1743,7 +1735,7 @@ pub fn builtin_iter_kind<H: VmHost>(vm: &mut H, wrapper: JsValue) -> Option<(Bui
}
// SAFETY: wrapper 刚判定为对象。
let wrapper_obj = unsafe { &*wrapper.as_js_object_ptr() };
let inner_si = vm.kernel_core().perm_interner().intern(INNER_PROP).0;
let inner_si = vm.perm_intern(INNER_PROP);
let inner = match vm.ordinary_get(wrapper_obj, inner_si, wrapper) {
Ok(inner) if !inner.is_undefined() => inner,
_ => return None,
@@ -1900,10 +1892,10 @@ fn current_index<H: VmHost>(vm: &mut H, wrapper: &JsObject, index_si: u32) -> us
/// 构造迭代器结果对象 `{value, done}`(生成器 next/return 结果复用)。
pub fn make_iter_result<H: VmHost>(vm: &mut H, value: JsValue, done: bool) -> JsValue {
let object_proto = vm.session().builtin_world().object_proto.as_ptr() as *mut JsObject;
let object_proto = vm.builtin_proto(ProtoKind::ObjectProto);
let obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(object_proto)));
let value_si = vm.kernel_core().perm_interner().intern("value").0;
let done_si = vm.kernel_core().perm_interner().intern("done").0;
let value_si = vm.perm_intern("value");
let done_si = vm.perm_intern("done");
let obj_ref = unsafe { &mut *obj };
vm.set_or_create_prop_value(obj_ref, value_si, value);
vm.set_or_create_prop_value(obj_ref, done_si, JsValue::bool(done));
@@ -1913,14 +1905,14 @@ pub fn make_iter_result<H: VmHost>(vm: &mut H, value: JsValue, done: bool) -> Js
/// 构造 native 函数对象并返回:设置函数标记、native 函数项、参数个数与 `name`
/// 属性。供迭代器包装器把自己的 next/return 方法装到包装对象上,不经绑定层注册。
pub(crate) fn make_native_function<H: VmHost>(vm: &mut H, name: &str, native_fn: *const (), arg_count: u8) -> JsValue {
let function_proto = vm.session().builtin_world().function_proto.as_ptr() as *mut JsObject;
let function_proto = vm.builtin_proto(ProtoKind::FunctionProto);
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(function_proto));
func.set_function(true);
// SAFETY: native_fn 来自 NativeFn 函数项。
func.set_native_fn(Some(unsafe { oxide_types::object::NativeFnPtr::from_raw(native_fn) }));
func.set_native_arg_count(arg_count);
let func = vm.alloc_object(func);
let name_si = vm.kernel_core().perm_interner().intern("name").0;
let name_si = vm.perm_intern("name");
let value = vm.new_string(name);
let func_ref = unsafe { &mut *func };
vm.set_or_create_prop_value(func_ref, name_si, value);
@@ -1966,7 +1958,7 @@ pub(crate) fn close_iterator<H: VmHost>(vm: &mut H, iterator: JsValue) {
return;
}
let iter_obj = unsafe { &*iterator.as_js_object_ptr() };
let return_si = vm.kernel_core().perm_interner().intern("return").0;
let return_si = vm.perm_intern("return");
if let Ok(ret) = vm.ordinary_get(iter_obj, return_si, iterator) {
if is_callable(ret) {
// return() 的抛错被忽略,其值不得外泄进槽覆盖在途异常。
@@ -2004,9 +1996,9 @@ pub fn iterate_iterator<H: VmHost, F>(vm: &mut H, iterator: JsValue, mut on_elem
where
F: FnMut(&mut H, JsValue) -> Result<(), JsValue>,
{
let next_si = vm.kernel_core().perm_interner().intern("next").0;
let done_si = vm.kernel_core().perm_interner().intern("done").0;
let value_si = vm.kernel_core().perm_interner().intern("value").0;
let next_si = vm.perm_intern("next");
let done_si = vm.perm_intern("done");
let value_si = vm.perm_intern("value");
let run: Result<(), JsValue> = (|| {
loop {
let iter_obj = unsafe { &*iterator.as_js_object_ptr() };
@@ -2052,7 +2044,7 @@ fn is_set_value(value: JsValue) -> bool {
}
fn make_map_set_pair<H: VmHost>(vm: &mut H, a: JsValue, b: JsValue) -> JsValue {
let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let array_proto = vm.builtin_proto(ProtoKind::ArrayProto);
let pair = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(array_proto), 2));
// SAFETY: pair 是刚经统一入口分配的数组 JsObject。
unsafe {
@@ -2176,9 +2168,9 @@ pub fn map_set_iterator_next<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
return NativeResult::Err(crate::error::create_type_error(vm, "iterator next called on non-object"));
}
let wrapper = unsafe { &mut *this_val.as_js_object_ptr() };
let inner_si = vm.kernel_core().perm_interner().intern(INNER_PROP).0;
let index_si = vm.kernel_core().perm_interner().intern(INDEX_PROP).0;
let mode_si = vm.kernel_core().perm_interner().intern(MODE_PROP).0;
let inner_si = vm.perm_intern(INNER_PROP);
let index_si = vm.perm_intern(INDEX_PROP);
let mode_si = vm.perm_intern(MODE_PROP);
let inner = match vm.ordinary_get(wrapper, inner_si, this_val) {
Ok(inner) if !inner.is_undefined() => inner,
_ => return NativeResult::Err(crate::error::create_type_error(vm, "iterator has no inner collection")),
@@ -2204,9 +2196,9 @@ pub(crate) fn make_collection_iterator<H: VmHost>(
std::ptr::null_mut()
};
let wrapper = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto_ptr)));
let inner_si = vm.kernel_core().perm_interner().intern(INNER_PROP).0;
let index_si = vm.kernel_core().perm_interner().intern(INDEX_PROP).0;
let mode_si = vm.kernel_core().perm_interner().intern(MODE_PROP).0;
let inner_si = vm.perm_intern(INNER_PROP);
let index_si = vm.perm_intern(INDEX_PROP);
let mode_si = vm.perm_intern(MODE_PROP);
let wrapper_obj = unsafe { &mut *wrapper };
vm.set_or_create_prop_value(wrapper_obj, inner_si, inner);
vm.set_or_create_prop_value(wrapper_obj, index_si, JsValue::int(0));
+18 -20
View File
@@ -7,7 +7,7 @@ use oxide_types::value::JsValue;
use crate::object::walk_own_keys;
use oxide_runtime_api::{NativeResult, VmHost};
use oxide_runtime_api::{NativeResult, ProtoKind, VmHost};
/// `JSON.parse(text, reviver)`:解析 JSON 文本为 JS 值(递归下降解析器,
/// 逐原始值记录精确源文本切片)。提供 reviver 时以后序遍历逐属性调用
@@ -49,7 +49,7 @@ pub fn json_parse<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
if reviver_val.is_object() {
let rptr = reviver_val.as_js_object_ptr();
if !rptr.is_null() && unsafe { (*rptr).is_function() } {
let empty_si = vm.kernel_core().perm_interner().intern("").0;
let empty_si = vm.perm_intern("");
let holder = create_wrapper(vm, result);
let holder_ptr = holder.as_js_object_ptr();
result = match walk_reviver(vm, holder_ptr, empty_si, reviver_val, Some(&parsed)) {
@@ -121,8 +121,8 @@ pub fn json_raw_json<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
// 建 null 原型对象:rawJSON 属性为唯一自身属性,frozen 形态收尾。
let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null());
obj.type_tag = JsObject::OBJ_TYPE_RAW_JSON;
let raw_si = vm.kernel_core().perm_interner().intern("rawJSON").0;
let new_shape = vm.kernel_core().shape_forge().make_shape(obj.shape_id(), raw_si);
let raw_si = vm.perm_intern("rawJSON");
let new_shape = vm.make_shape(obj.shape_id(), raw_si);
obj.set_shape_id(new_shape);
obj.ensure_hash_props().push(text_val);
let obj_ptr = vm.alloc_object(obj);
@@ -576,13 +576,13 @@ fn walk_reviver<H: VmHost>(
/// 属性(w/e/c 全 true)——被 reviver 前向替换的值、array/object 节点
/// 与无节点处一律空 context。
fn build_context<H: VmHost>(vm: &mut H, val: JsValue, node: Option<&JsonNode>) -> JsValue {
let object_proto = vm.session().builtin_world().object_proto.as_ptr() as *mut JsObject;
let object_proto = vm.builtin_proto(ProtoKind::ObjectProto);
let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(object_proto));
if let Some(n) = node {
if let Some(src) = n.source.as_ref() {
if same_value_as(vm, val, n) {
let source_si = vm.kernel_core().perm_interner().intern("source").0;
let new_shape = vm.kernel_core().shape_forge().make_shape(obj.shape_id(), source_si);
let source_si = vm.perm_intern("source");
let new_shape = vm.make_shape(obj.shape_id(), source_si);
obj.set_shape_id(new_shape);
obj.ensure_hash_props().push(vm.new_string(src));
}
@@ -647,7 +647,7 @@ fn build_js_value<H: VmHost>(vm: &mut H, node: &JsonNode) -> JsValue {
JsonKind::Number(n) => JsValue::float(*n),
JsonKind::String(s) => vm.new_string(s),
JsonKind::Array(items) => {
let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let array_proto = vm.builtin_proto(ProtoKind::ArrayProto);
let n = items.len();
let array_obj =
vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(array_proto), n));
@@ -670,13 +670,13 @@ fn build_js_value<H: VmHost>(vm: &mut H, node: &JsonNode) -> JsValue {
}
unique.sort_by(|a, b| a.0.cmp(b.0));
let object_proto = vm.session().builtin_world().object_proto.as_ptr() as *mut JsObject;
let object_proto = vm.builtin_proto(ProtoKind::ObjectProto);
let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(object_proto));
for (key, val) in unique {
// 键经字符串规范化:规范数字串("0"/"5")映射整数键,与属性访问统一。
let si = vm.string_key_si(key);
let jsv = build_js_value(vm, val);
let new_shape = vm.kernel_core().shape_forge().make_shape(obj.shape_id(), si);
let new_shape = vm.make_shape(obj.shape_id(), si);
obj.set_shape_id(new_shape);
obj.ensure_hash_props().push(jsv);
}
@@ -687,10 +687,10 @@ fn build_js_value<H: VmHost>(vm: &mut H, node: &JsonNode) -> JsValue {
}
fn create_wrapper<H: VmHost>(vm: &mut H, value: JsValue) -> JsValue {
let object_proto = vm.session().builtin_world().object_proto.as_ptr() as *mut JsObject;
let empty_si = vm.kernel_core().perm_interner().intern("").0;
let object_proto = vm.builtin_proto(ProtoKind::ObjectProto);
let empty_si = vm.perm_intern("");
let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(object_proto));
let new_shape = vm.kernel_core().shape_forge().make_shape(obj.shape_id(), empty_si);
let new_shape = vm.make_shape(obj.shape_id(), empty_si);
obj.set_shape_id(new_shape);
obj.ensure_hash_props().push(value);
let obj_ptr = vm.alloc_object(obj);
@@ -764,9 +764,7 @@ fn key_si_to_units<H: VmHost>(vm: &H, si: u32) -> Vec<u16> {
if is_int_key(si) {
int_key_value(si).to_string().encode_utf16().collect()
} else {
vm.kernel_core()
.perm_interner()
.lookup(si)
vm.perm_lookup(si)
.map(oxide_kernel::string_forge::decode_key)
.unwrap_or_default()
}
@@ -797,8 +795,8 @@ fn whitelist_element_name<H: VmHost>(vm: &mut H, elem: JsValue) -> Result<Option
}
// ToPrimitive string hint:toString 优先,valueOf 兜底。
let to_string_si = vm.kernel_core().perm_interner().intern("toString").0;
let value_of_si = vm.kernel_core().perm_interner().intern("valueOf").0;
let to_string_si = vm.perm_intern("toString");
let value_of_si = vm.perm_intern("valueOf");
for m_si in [to_string_si, value_of_si] {
let m = vm.ordinary_get(obj, m_si, elem).map_err(|msg| {
vm.take_uncaught_value()
@@ -835,9 +833,9 @@ fn call_to_json<H: VmHost>(vm: &mut H, obj_val: JsValue, key: &[u16]) -> Result<
}
p
} else {
vm.session().builtin_world().bigint_proto.as_ptr() as *mut JsObject
vm.builtin_proto(ProtoKind::BigIntProto)
};
let tojson_si = vm.kernel_core().perm_interner().intern("toJSON").0;
let tojson_si = vm.perm_intern("toJSON");
// Get 语义查表:访问器形 toJSON 触发 getter(receiver = 原值,BigInt 原语
// 以自身作 this),getter 异常传播原始抛出值。
let fn_val = match vm.ordinary_get(unsafe { &*obj_ptr }, tojson_si, obj_val) {
+47 -54
View File
@@ -7,7 +7,7 @@ use oxide_types::private_key::{
};
use oxide_types::value::JsValue;
use oxide_runtime_api::{NativeResult, VmHost};
use oxide_runtime_api::{NativeResult, ProtoKind, VmHost};
use crate::builtins_debug;
@@ -53,7 +53,7 @@ pub fn walk_own_keys<H: VmHost>(vm: &H, obj: &JsObject) -> Vec<(u32, u32)> {
if id == EMPTY_SHAPE_ID {
break;
}
if let Some(shape) = vm.kernel_core().shape_forge().get_shape(id) {
if let Some(shape) = vm.get_shape(id) {
cursor = shape.parent;
// Symbol 键/私有名键非字符串属性名,排除在字符串枚举之外(但仍占 shape
// 槽位,pos 计数须含它们才能与物理存储对齐)。
@@ -65,7 +65,7 @@ pub fn walk_own_keys<H: VmHost>(vm: &H, obj: &JsObject) -> Vec<(u32, u32)> {
}
}
for id in shape_ids.iter().rev() {
if let Some(shape) = vm.kernel_core().shape_forge().get_shape(*id) {
if let Some(shape) = vm.get_shape(*id) {
if !is_symbol_key(shape.property_name) && !is_private_name_key(shape.property_name) {
// 绝对存储索引:数组命名属性位于元素区之后。
let store = if obj.is_array() { obj.array_prop_count + pos } else { pos };
@@ -77,7 +77,6 @@ pub fn walk_own_keys<H: VmHost>(vm: &H, obj: &JsObject) -> Vec<(u32, u32)> {
// 类构造器属性序修正:shape 链构建序为 prototype→length→name(叶→根),
// 规范要求的插入序为 length→name→prototype。按规范重排字符串键。
if obj.is_class_constructor() {
let perm = vm.kernel_core().perm_interner();
let canonical = ["length", "name", "prototype"];
let mut canonical_map: std::collections::HashMap<&str, usize> = std::collections::HashMap::new();
for (i, &name) in canonical.iter().enumerate() {
@@ -93,8 +92,8 @@ pub fn walk_own_keys<H: VmHost>(vm: &H, obj: &JsObject) -> Vec<(u32, u32)> {
(None, Some(_)) => std::cmp::Ordering::Greater,
(None, None) => {
// 两者均为字符串键:查规范序。
let a_name = perm.lookup(*a_si).unwrap_or("");
let b_name = perm.lookup(*b_si).unwrap_or("");
let a_name = vm.perm_lookup(*a_si).unwrap_or("");
let b_name = vm.perm_lookup(*b_si).unwrap_or("");
let a_rank = canonical_map.get(a_name).copied().unwrap_or(usize::MAX);
let b_rank = canonical_map.get(b_name).copied().unwrap_or(usize::MAX);
// 规范键按序排,其余保持原序。
@@ -124,7 +123,7 @@ fn int_or_string_index<H: VmHost>(vm: &H, si: u32) -> Option<u32> {
if is_int_key(si) {
return Some(int_key_value(si));
}
let key = vm.kernel_core().perm_interner().lookup(si)?;
let key = vm.perm_lookup(si)?;
is_integer_index(key).then(|| key.parse::<u32>().ok()).flatten()
}
@@ -136,9 +135,7 @@ pub fn key_si_to_js_value<H: VmHost>(vm: &mut H, si: u32) -> JsValue {
return vm.new_string(&int_key_value(si).to_string());
}
let units = vm
.kernel_core()
.perm_interner()
.lookup(si)
.perm_lookup(si)
.map(oxide_kernel::string_forge::decode_key)
.unwrap_or_default();
vm.new_string_units_owned(units)
@@ -157,7 +154,7 @@ pub(crate) fn walk_own_symbol_keys<H: VmHost>(vm: &H, obj: &JsObject) -> Vec<(u3
if id == EMPTY_SHAPE_ID {
break;
}
if let Some(shape) = vm.kernel_core().shape_forge().get_shape(id) {
if let Some(shape) = vm.get_shape(id) {
cursor = shape.parent;
if shape.property_name != u32::MAX {
shape_ids.push(id);
@@ -167,7 +164,7 @@ pub(crate) fn walk_own_symbol_keys<H: VmHost>(vm: &H, obj: &JsObject) -> Vec<(u3
}
}
for (pos, id) in (0_u32..).zip(shape_ids.iter().rev()) {
if let Some(shape) = vm.kernel_core().shape_forge().get_shape(*id) {
if let Some(shape) = vm.get_shape(*id) {
// Symbol 键节点按绝对槽位回传(数组命名属性位于元素区之后)。
let store = if obj.is_array() { obj.array_prop_count + pos } else { pos };
if is_symbol_key(shape.property_name) {
@@ -233,7 +230,7 @@ pub fn sort_namespace_exports<H: VmHost>(vm: &mut H, obj: &mut JsObject) {
obj.set_shape_id(EMPTY_SHAPE_ID);
obj.clear_props();
for (si, value, meta) in entries.into_iter().chain(symbols) {
let shape = vm.kernel_core().shape_forge().make_shape(obj.shape_id(), si);
let shape = vm.make_shape(obj.shape_id(), si);
obj.set_shape_id(shape);
let pos = obj.push_prop(value);
if let Some(meta) = meta {
@@ -252,11 +249,7 @@ fn namespace_key_units<H: VmHost>(vm: &H, si: u32) -> Vec<u16> {
if is_int_key(si) {
return int_key_value(si).to_string().encode_utf16().collect();
}
vm.kernel_core()
.perm_interner()
.lookup(si)
.map(|key| key.encode_utf16().collect())
.unwrap_or_default()
vm.perm_lookup(si).map(|key| key.encode_utf16().collect()).unwrap_or_default()
}
/// `Object.getOwnPropertySymbols(obj)`:返回全部自身 Symbol 键数组。
@@ -272,7 +265,7 @@ pub fn object_get_own_property_symbols<H: VmHost>(vm: &mut H, args: &[u8]) -> Na
};
let n = symbols.len();
let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let array_proto = vm.builtin_proto(ProtoKind::ArrayProto);
let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(array_proto), n));
for (i, v) in symbols.iter().enumerate() {
unsafe {
@@ -290,7 +283,7 @@ fn array_index_of<H: VmHost>(vm: &H, key_si: u32) -> Option<u32> {
if is_int_key(key_si) {
return Some(int_key_value(key_si));
}
let key = vm.kernel_core().perm_interner().lookup(key_si)?;
let key = vm.perm_lookup(key_si)?;
if key.is_empty() || (key.len() > 1 && key.starts_with('0')) {
return None;
}
@@ -375,7 +368,7 @@ pub fn delete_own_property_outcome<H: VmHost>(vm: &mut H, obj: &mut JsObject, ke
}
// 非下标键:length 是虚拟属性(无 shape 槽、不在元素区),但描述符声明
// configurable:false,删除恒失败。
if key_si == vm.kernel_core().perm_interner().intern("length").0 {
if key_si == vm.perm_intern("length") {
return DeleteOutcome::NonConfigurable;
}
}
@@ -430,7 +423,7 @@ pub fn delete_own_property_outcome<H: VmHost>(vm: &mut H, obj: &mut JsObject, ke
obj.set_shape_id(EMPTY_SHAPE_ID);
obj.clear_props();
for (si, value, meta) in retained {
let shape = vm.kernel_core().shape_forge().make_shape(obj.shape_id(), si);
let shape = vm.make_shape(obj.shape_id(), si);
obj.set_shape_id(shape);
let pos = obj.push_prop(value);
if let Some(meta) = meta {
@@ -475,7 +468,7 @@ pub fn delete_own_property<H: VmHost>(vm: &mut H, obj: &mut JsObject, key_si: u3
/// JS `Object()` 构造逻辑:创建空对象(prototype 为 null,由 VM 补装内置原型)。
pub fn object_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let val = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
let object_proto = vm.session().builtin_world().object_proto.as_ptr() as *mut JsObject;
let object_proto = vm.builtin_proto(ProtoKind::ObjectProto);
// 对象参数原样返回;原始值参数创建对应 boxed 对象(规范 ToObject)。
if val.is_object() {
return NativeResult::Ok(val);
@@ -485,7 +478,7 @@ pub fn object_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
return NativeResult::Ok(JsValue::from_js_object(obj));
}
if val.is_int() || val.is_double() {
let proto = vm.session().builtin_world().number_proto.as_ptr() as *mut JsObject;
let proto = vm.builtin_proto(ProtoKind::NumberProto);
let obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto)));
let obj_ref = unsafe { &mut *obj };
obj_ref.type_tag = JsObject::OBJ_TYPE_NUMBER_OBJ;
@@ -493,7 +486,7 @@ pub fn object_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
return NativeResult::Ok(JsValue::from_js_object(obj));
}
if val.is_string() {
let proto = vm.session().builtin_world().string_proto.as_ptr() as *mut JsObject;
let proto = vm.builtin_proto(ProtoKind::StringProto);
let obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto)));
let obj_ref = unsafe { &mut *obj };
obj_ref.type_tag = JsObject::OBJ_TYPE_STRING_OBJ;
@@ -502,7 +495,7 @@ pub fn object_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
return NativeResult::Ok(JsValue::from_js_object(obj));
}
if val.is_bool() {
let proto = vm.session().builtin_world().boolean_proto.as_ptr() as *mut JsObject;
let proto = vm.builtin_proto(ProtoKind::BooleanProto);
let obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto)));
let obj_ref = unsafe { &mut *obj };
obj_ref.type_tag = JsObject::OBJ_TYPE_BOOLEAN_OBJ;
@@ -510,7 +503,7 @@ pub fn object_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
return NativeResult::Ok(JsValue::from_js_object(obj));
}
if val.is_symbol() {
let proto = vm.session().builtin_world().symbol_proto.as_ptr() as *mut JsObject;
let proto = vm.builtin_proto(ProtoKind::SymbolProto);
let obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto)));
let obj_ref = unsafe { &mut *obj };
obj_ref.type_tag = JsObject::OBJ_TYPE_SYMBOL_OBJ;
@@ -518,7 +511,7 @@ pub fn object_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
return NativeResult::Ok(JsValue::from_js_object(obj));
}
if val.is_bigint() {
let proto = vm.session().builtin_world().bigint_proto.as_ptr() as *mut JsObject;
let proto = vm.builtin_proto(ProtoKind::BigIntProto);
let obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto)));
let obj_ref = unsafe { &mut *obj };
obj_ref.set_boxed_value(val);
@@ -602,7 +595,7 @@ pub fn object_keys<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
}
}
let n = owned_keys.len();
let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let array_proto = vm.builtin_proto(ProtoKind::ArrayProto);
let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(array_proto), n));
for (i, (si, _offset)) in owned_keys.iter().enumerate() {
let key_val = key_si_to_js_value(vm, *si);
@@ -780,12 +773,12 @@ pub(crate) fn define_from_descriptor<H: VmHost>(
return Err(DefineDescFailure::Engine("Property description must be an object".to_string()));
}
let value_si = vm.kernel_core().perm_interner().intern("value").0;
let get_si = vm.kernel_core().perm_interner().intern("get").0;
let set_si = vm.kernel_core().perm_interner().intern("set").0;
let writable_si = vm.kernel_core().perm_interner().intern("writable").0;
let enumerable_si = vm.kernel_core().perm_interner().intern("enumerable").0;
let configurable_si = vm.kernel_core().perm_interner().intern("configurable").0;
let value_si = vm.perm_intern("value");
let get_si = vm.perm_intern("get");
let set_si = vm.perm_intern("set");
let writable_si = vm.perm_intern("writable");
let enumerable_si = vm.perm_intern("enumerable");
let configurable_si = vm.perm_intern("configurable");
// 六字段按规范序逐个 GetV,读取期异常原值传播(ReturnIfAbrupt)。
let value_field = own_field(vm, desc_val, value_si)?;
@@ -798,7 +791,7 @@ pub(crate) fn define_from_descriptor<H: VmHost>(
// 数组 length 是无 shape 槽的虚拟数据属性:需与普通已有属性一样参与描述符
// 缺省回填(writable 保持当前值、value 保持当前长度),其当前描述符由元素
// 计数与独立可写位虚拟构造;enumerable/configurable 恒为 false。
let length_si = vm.kernel_core().perm_interner().intern("length").0;
let length_si = vm.perm_intern("length");
let is_array_length = unsafe { &*obj_ptr }.is_array() && key_si == length_si;
let existing_pos = if is_array_length {
@@ -1075,8 +1068,8 @@ fn own_descriptor_of<H: VmHost>(vm: &mut H, obj: &JsObject, key_si: u32) -> Resu
{
let value = crate::typed_array::typed_array_element_get(vm, obj, index).unwrap_or(JsValue::undefined());
let desc = alloc_desc_object(vm);
let sh_ptr = vm.kernel_core().shape_forge().as_ref() as *const ShapeForge;
let sf_ptr = vm.kernel_core().perm_interner().as_ref() as *const PermInterner;
let sh_ptr = vm.shape_forge_ptr() as *const ShapeForge;
let sf_ptr = vm.perm_interner_ptr() as *const PermInterner;
// SAFETY: desc 为本函数刚分配的 epoch 对象;sh/sf 为 kernel 永久引用。
let d: &mut JsObject = unsafe { &mut *desc };
let sh = unsafe { &*sh_ptr };
@@ -1092,11 +1085,11 @@ fn own_descriptor_of<H: VmHost>(vm: &mut H, obj: &JsObject, key_si: u32) -> Resu
// 数组 length 是虚拟属性(无 shape 槽,ordinary_get 直接返回逻辑长度):
// 描述符 {value: len, writable: !frozen && 非显式收窄, enumerable: false,
// configurable: false}。冻结数组与经 defineProperty 收窄的数组 writable=false。
let length_si = vm.kernel_core().perm_interner().intern("length").0;
let length_si = vm.perm_intern("length");
if obj.is_array() && key_si == length_si {
let desc = alloc_desc_object(vm);
let sh_ptr = vm.kernel_core().shape_forge().as_ref() as *const ShapeForge;
let sf_ptr = vm.kernel_core().perm_interner().as_ref() as *const PermInterner;
let sh_ptr = vm.shape_forge_ptr() as *const ShapeForge;
let sf_ptr = vm.perm_interner_ptr() as *const PermInterner;
let d: &mut JsObject = unsafe { &mut *desc };
let sh = unsafe { &*sh_ptr };
let sf = unsafe { &*sf_ptr };
@@ -1119,8 +1112,8 @@ fn own_descriptor_of<H: VmHost>(vm: &mut H, obj: &JsObject, key_si: u32) -> Resu
let found_meta = obj.prop_meta_at(offset);
let desc = alloc_desc_object(vm);
let sh_ptr = vm.kernel_core().shape_forge().as_ref() as *const ShapeForge;
let sf_ptr = vm.kernel_core().perm_interner().as_ref() as *const PermInterner;
let sh_ptr = vm.shape_forge_ptr() as *const ShapeForge;
let sf_ptr = vm.perm_interner_ptr() as *const PermInterner;
let d: &mut JsObject = unsafe { &mut *desc };
let sh = unsafe { &*sh_ptr };
let sf = unsafe { &*sf_ptr };
@@ -1141,7 +1134,7 @@ fn own_descriptor_of<H: VmHost>(vm: &mut H, obj: &JsObject, key_si: u32) -> Resu
/// 分配空描述符对象(proto = %Object.prototype%)。
fn alloc_desc_object<H: VmHost>(vm: &mut H) -> *mut JsObject {
let desc_proto = vm.session().builtin_world().object_proto.as_ptr() as *mut JsObject;
let desc_proto = vm.builtin_proto(ProtoKind::ObjectProto);
vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(desc_proto)))
}
@@ -1207,7 +1200,7 @@ pub fn object_get_own_property_descriptors<H: VmHost>(vm: &mut H, args: &[u8]) -
keys.extend(walk_own_symbol_keys(vm, obj));
// 结果对象:proto = %Object.prototype%。
let desc_proto = vm.session().builtin_world().object_proto.as_ptr() as *mut JsObject;
let desc_proto = vm.builtin_proto(ProtoKind::ObjectProto);
let result = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(desc_proto)));
let result_val = JsValue::from_js_object(result);
@@ -1509,7 +1502,7 @@ pub fn object_get_own_property_names<H: VmHost>(vm: &mut H, args: &[u8]) -> Nati
let obj = unsafe { &*obj_ptr };
let keys = walk_own_keys(vm, obj);
let n = keys.len();
let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let array_proto = vm.builtin_proto(ProtoKind::ArrayProto);
let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(array_proto), n));
for (i, (si, _)) in keys.iter().enumerate() {
let key_val = key_si_to_js_value(vm, *si);
@@ -1566,7 +1559,7 @@ pub fn object_from_entries<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
if entries_ptr.is_null() {
return NativeResult::Err(crate::error::create_type_error(vm, "Object.fromEntries: argument must be iterable"));
}
let proto_ptr = vm.session().builtin_world().object_proto.as_ptr() as *mut JsObject;
let proto_ptr = vm.builtin_proto(ProtoKind::ObjectProto);
let obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto_ptr)));
let target_val = JsValue::from_js_object(obj);
// entry 数组的元素存元素区(元素区之外才是命名属性区),按元素区长度迭代。
@@ -1740,7 +1733,7 @@ pub fn object_proto_to_locale_string<H: VmHost>(vm: &mut H, args: &[u8]) -> Nati
Err(msg) => return NativeResult::Err(crate::error::create_type_error(vm, &msg)),
};
let obj = unsafe { &*obj_val.as_js_object_ptr() };
let si_to_string = vm.kernel_core().perm_interner().intern("toString").0;
let si_to_string = vm.perm_intern("toString");
let to_str = match vm.ordinary_get(obj, si_to_string, this_val) {
Ok(v) => v,
Err(e) => return NativeResult::Err(crate::iterator::engine_error(vm, &e)),
@@ -2138,7 +2131,7 @@ pub fn object_entries<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
})
.collect();
let n = owned_keys.len();
let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let array_proto = vm.builtin_proto(ProtoKind::ArrayProto);
let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(array_proto), n));
let obj_val = JsValue::from_js_object(obj_ptr);
for (i, (si, offset)) in owned_keys.iter().enumerate() {
@@ -2205,7 +2198,7 @@ pub fn object_group_by<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
return NativeResult::Err(crate::error::create_type_error(vm, "Object.groupBy: iterator is not an object"));
}
let iter_obj = unsafe { &*iter_val.as_js_object_ptr() };
let next_si = vm.kernel_core().perm_interner().intern("next").0;
let next_si = vm.perm_intern("next");
let next_fn = match vm.ordinary_get(iter_obj, next_si, iter_val) {
Ok(f) => f,
Err(e) => return NativeResult::Err(crate::iterator::engine_error(vm, &e)),
@@ -2231,7 +2224,7 @@ pub fn object_group_by<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
));
}
let nr = unsafe { &*next_result.as_js_object_ptr() };
let done_si = vm.kernel_core().perm_interner().intern("done").0;
let done_si = vm.perm_intern("done");
let done = match vm.ordinary_get(nr, done_si, next_result) {
Ok(v) => oxide_runtime_api::to_boolean(v),
Err(e) => return NativeResult::Err(crate::iterator::engine_error(vm, &e)),
@@ -2239,7 +2232,7 @@ pub fn object_group_by<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
if done {
break;
}
let value_si = vm.kernel_core().perm_interner().intern("value").0;
let value_si = vm.perm_intern("value");
let element = match vm.ordinary_get(nr, value_si, next_result) {
Ok(v) => v,
Err(e) => return NativeResult::Err(crate::iterator::engine_error(vm, &e)),
@@ -2280,7 +2273,7 @@ pub fn object_group_by<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let arr_val = if let Some(existing) = existing {
existing
} else {
let arr_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let arr_proto = vm.builtin_proto(ProtoKind::ArrayProto);
let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(arr_proto), 0));
let new_arr_val = JsValue::from_js_object(arr);
let result_ref_mut = unsafe { &mut *result };
@@ -2313,7 +2306,7 @@ pub fn object_values<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
})
.collect();
let n = owned_keys.len();
let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let array_proto = vm.builtin_proto(ProtoKind::ArrayProto);
let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(array_proto), n));
let obj_val = JsValue::from_js_object(obj_ptr);
for (i, (si, offset)) in owned_keys.iter().enumerate() {
+30 -32
View File
@@ -2,7 +2,7 @@ use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
use oxide_types::object::{JsObject, NativeFnPtr};
use oxide_types::value::JsValue;
use oxide_runtime_api::{NativeResult, VmHost};
use oxide_runtime_api::{NativeResult, ProtoKind, VmHost};
use crate::string::{make_units_array, MatchText, OwnedText};
@@ -20,7 +20,7 @@ pub(crate) fn build_groups_object<H: VmHost>(vm: &mut H, m: &regress::Match, tex
// 遍历所有命名捕获组,按名称设置属性(重复名称取首个已定义的出现)。
for (name, range) in named {
let name_si = vm.kernel_core().perm_interner().intern(name).0;
let name_si = vm.perm_intern(name);
let value = match range {
Some(r) => vm.new_string_units_owned(text.slice(r.start, r.end).into_owned()),
None => JsValue::undefined(),
@@ -37,7 +37,7 @@ pub(crate) fn build_groups_object<H: VmHost>(vm: &mut H, m: &regress::Match, tex
pub(crate) fn build_indices_array<H: VmHost>(vm: &mut H, m: &regress::Match, text: &MatchText) -> JsValue {
let group_count = m.captures.len();
let n = 1 + group_count;
let proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let proto = vm.builtin_proto(ProtoKind::ArrayProto);
let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(proto), n));
unsafe {
let range = m.range();
@@ -52,14 +52,14 @@ pub(crate) fn build_indices_array<H: VmHost>(vm: &mut H, m: &regress::Match, tex
(*arr).set_prop_count(n);
}
let groups_val = build_indices_groups_object(vm, m, text);
let groups_si = vm.kernel_core().perm_interner().intern("groups").0;
let groups_si = vm.perm_intern("groups");
vm.set_or_create_prop_value(unsafe { &mut *arr }, groups_si, groups_val);
JsValue::from_js_object(arr)
}
/// 单个 [start, end] 码元对数组(数组原型,两个自身元素)。
fn index_pair<H: VmHost>(vm: &mut H, start: usize, end: usize) -> JsValue {
let proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let proto = vm.builtin_proto(ProtoKind::ArrayProto);
let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(proto), 2));
unsafe {
(*arr).set_prop_at(0, JsValue::int(start as i32));
@@ -79,7 +79,7 @@ fn build_indices_groups_object<H: VmHost>(vm: &mut H, m: &regress::Match, text:
let groups_obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null()));
let groups_ptr = unsafe { &mut *groups_obj };
for (name, range) in named {
let name_si = vm.kernel_core().perm_interner().intern(name).0;
let name_si = vm.perm_intern(name);
let value = match range {
Some(r) => index_pair(vm, text.unit_pos(r.start), text.unit_pos(r.end)),
None => JsValue::undefined(),
@@ -145,7 +145,7 @@ pub(crate) fn to_length_value<H: VmHost>(vm: &mut H, val: JsValue) -> Result<usi
fn set_last_index<H: VmHost>(
vm: &mut H, re_ptr: *mut JsObject, this_val: JsValue, index: usize,
) -> Result<(), JsValue> {
let li_si = vm.kernel_core().perm_interner().intern("lastIndex").0;
let li_si = vm.perm_intern("lastIndex");
// setter 抛错优先恢复 uncaught 原异常值(与 rx_set_prop 同口径)。
match vm.ordinary_set(unsafe { &mut *re_ptr }, li_si, JsValue::int(index as i32), this_val, true) {
Ok(()) => Ok(()),
@@ -158,7 +158,7 @@ fn set_last_index<H: VmHost>(
pub(crate) fn rx_get_prop<H: VmHost>(
vm: &mut H, obj: *mut JsObject, name: &str, this_val: JsValue,
) -> Result<JsValue, JsValue> {
let si = vm.kernel_core().perm_interner().intern(name).0;
let si = vm.perm_intern(name);
match vm.ordinary_get(unsafe { &*obj }, si, this_val) {
Ok(v) => Ok(v),
Err(_) => Err(crate::iterator::engine_error(vm, "cannot read property")),
@@ -181,7 +181,7 @@ pub(crate) fn rx_get_index<H: VmHost>(
pub(crate) fn rx_set_prop<H: VmHost>(
vm: &mut H, obj: *mut JsObject, name: &str, val: JsValue, this_val: JsValue,
) -> Result<(), JsValue> {
let si = vm.kernel_core().perm_interner().intern(name).0;
let si = vm.perm_intern(name);
// setter 抛错时原异常值留在 uncaught 槽(优先恢复);写保护失败无
// uncaught,经格式化文本的 "TypeError: " 前缀恢复种类。
match vm.ordinary_set(unsafe { &mut *obj }, si, val, this_val, true) {
@@ -311,7 +311,7 @@ pub(crate) fn get_substitution_units<H: VmHost>(
(Some(end), Some(obj)) => {
let name_units = &rest[2..2 + end];
let name_str = String::from_utf16_lossy(name_units);
let si = vm.kernel_core().perm_interner().intern(&name_str).0;
let si = vm.perm_intern(&name_str);
// 真 Get 走完整原型链;getter 抛错恢复原异常上抛。
let cap = match vm.ordinary_get(
obj,
@@ -372,12 +372,12 @@ pub(crate) fn get_substitution_units<H: VmHost>(
}
fn set_prop<H: VmHost>(obj: &mut JsObject, name: &str, val: JsValue, vm: &H) {
let si = vm.kernel_core().perm_interner().intern(name).0;
let si = vm.perm_intern(name);
set_prop_by_si(obj, si, val, vm);
}
fn set_prop_by_si<H: VmHost>(obj: &mut JsObject, prop_name_si: u32, val: JsValue, vm: &H) {
let shape_id = vm.kernel_core().shape_forge().make_shape(obj.shape_id(), prop_name_si);
let shape_id = vm.make_shape(obj.shape_id(), prop_name_si);
obj.set_shape_id(shape_id);
obj.ensure_hash_props().push(val);
}
@@ -490,10 +490,8 @@ pub fn regexp_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
));
}
let mut obj = JsObject::new_empty(
EMPTY_SHAPE_ID,
JsValue::from_js_object(vm.session().builtin_world().regexp_proto.as_ptr() as *mut JsObject),
);
let mut obj =
JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(vm.builtin_proto(ProtoKind::RegExpProto)));
// regress 用 JS flag 字符串编译:g/i/m/s/y/u/v 原样透传(vendored fork
// 原生识别 v 标志,u/v 互斥已在上方前置校验)。
@@ -632,7 +630,7 @@ pub(crate) fn rx_search<H: VmHost>(
// lastIndex 读无条件执行(规范先读后在非 global/sticky 臂丢弃);
// 读走 Get + ToLength:完整属性解析,读异常传播原异常。
let last_index = {
let li_si = vm.kernel_core().perm_interner().intern("lastIndex").0;
let li_si = vm.perm_intern("lastIndex");
match vm.ordinary_get(unsafe { &*re_ptr }, li_si, this_val) {
Ok(val) => to_length_value(vm, val)?,
Err(_) => {
@@ -746,7 +744,7 @@ pub fn regexp_exec<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let range = m.range();
let group_count = m.captures.len();
let n = 1 + group_count;
let proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let proto = vm.builtin_proto(ProtoKind::ArrayProto);
let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(proto), n));
unsafe {
(*arr).set_prop_at(0, vm.new_string_units_owned(text.slice(range.start, range.end).into_owned()));
@@ -760,19 +758,19 @@ pub fn regexp_exec<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
(*arr).set_prop_count(n);
}
let index_si = vm.kernel_core().perm_interner().intern("index").0;
let index_si = vm.perm_intern("index");
vm.set_or_create_prop_value(unsafe { &mut *arr }, index_si, JsValue::int(text.unit_pos(range.start) as i32));
let input_val = haystack.to_value(vm);
let input_si = vm.kernel_core().perm_interner().intern("input").0;
let input_si = vm.perm_intern("input");
vm.set_or_create_prop_value(unsafe { &mut *arr }, input_si, input_val);
let groups_val = build_groups_object(vm, &m, &text);
let groups_si = vm.kernel_core().perm_interner().intern("groups").0;
let groups_si = vm.perm_intern("groups");
vm.set_or_create_prop_value(unsafe { &mut *arr }, groups_si, groups_val);
// d 标志:挂 indices 属性(逐组 [start, end] 码元对 + indices.groups 同构对象)。
if has_indices {
let indices_val = build_indices_array(vm, &m, &text);
let indices_si = vm.kernel_core().perm_interner().intern("indices").0;
let indices_si = vm.perm_intern("indices");
vm.set_or_create_prop_value(unsafe { &mut *arr }, indices_si, indices_val);
}
@@ -921,7 +919,7 @@ fn regexp_flag_of<H: VmHost>(vm: &mut H, args: &[u8], unit: char) -> NativeResul
let this_val = vm.reg(args[0]);
if this_val.is_object() {
let this_ptr = this_val.as_js_object_ptr();
let proto_ptr = vm.session().builtin_world().regexp_proto.as_ptr() as *mut JsObject;
let proto_ptr = vm.builtin_proto(ProtoKind::RegExpProto);
if !this_ptr.is_null() && this_ptr == proto_ptr {
return NativeResult::Ok(JsValue::undefined());
}
@@ -1027,7 +1025,7 @@ pub fn regexp_get_source<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
// proto 恒等判定:规范对 prototype 本身返回 "(?:)"(无 [[OriginalFlags]] 槽时)。
if this_val.is_object() {
let this_ptr = this_val.as_js_object_ptr();
let proto_ptr = vm.session().builtin_world().regexp_proto.as_ptr() as *mut JsObject;
let proto_ptr = vm.builtin_proto(ProtoKind::RegExpProto);
if !this_ptr.is_null() && this_ptr == proto_ptr {
return NativeResult::Ok(vm.new_string_units_owned(vec!['(' as u16, '?' as u16, ':' as u16, ')' as u16]));
}
@@ -1684,7 +1682,7 @@ pub fn regexp_symbol_split<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
}
// 物种构造 + y 标志:splitter 是后续唯一匹配面。
let regexp_ctor = vm.session().builtin_world().regexp_constructor.as_ptr() as *mut JsObject;
let regexp_ctor = vm.builtin_proto(ProtoKind::RegExpConstructor);
let regexp_ctor_val = JsValue::from_js_object(regexp_ctor);
let c = match species_constructor(vm, re_ptr, this_val, regexp_ctor_val) {
Ok(c) => c,
@@ -1841,7 +1839,7 @@ pub fn regexp_symbol_match_all<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResu
_ => true,
};
let regexp_ctor = vm.session().builtin_world().regexp_constructor.as_ptr() as *mut JsObject;
let regexp_ctor = vm.builtin_proto(ProtoKind::RegExpConstructor);
let regexp_ctor_val = JsValue::from_js_object(regexp_ctor);
let matcher_val = if is_regexp {
let c = match species_constructor(vm, re_ptr, this_val, regexp_ctor_val) {
@@ -1879,14 +1877,14 @@ pub fn regexp_symbol_match_all<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResu
}
// 迭代器包装:五槽(input/re/done/global/unicode),next 由原型提供。
let regexp_iter_proto = vm.session().builtin_world().regexp_string_iterator_proto.as_ptr() as *mut JsObject;
let regexp_iter_proto = vm.builtin_proto(ProtoKind::RegExpStringIteratorProto);
let wrapper = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(regexp_iter_proto)));
let wrapper_obj = unsafe { &mut *wrapper };
let input_si = vm.kernel_core().perm_interner().intern(crate::string::MALL_INPUT).0;
let re_si = vm.kernel_core().perm_interner().intern(crate::string::MALL_RE).0;
let done_si = vm.kernel_core().perm_interner().intern(crate::string::MALL_DONE).0;
let global_si = vm.kernel_core().perm_interner().intern(crate::string::MALL_GLOBAL).0;
let unicode_si = vm.kernel_core().perm_interner().intern(crate::string::MALL_UNICODE).0;
let input_si = vm.perm_intern(crate::string::MALL_INPUT);
let re_si = vm.perm_intern(crate::string::MALL_RE);
let done_si = vm.perm_intern(crate::string::MALL_DONE);
let global_si = vm.perm_intern(crate::string::MALL_GLOBAL);
let unicode_si = vm.perm_intern(crate::string::MALL_UNICODE);
// [[Global]]/[[Unicode]] 由 flags 串判定(u/v 均码点口径);input 属性存
// 完整转换后的字符串值(单元保真),游标归匹配器 lastIndex(已写入)。
vm.set_or_create_prop_value(wrapper_obj, input_si, s_val);
+29 -33
View File
@@ -2,7 +2,7 @@ use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
use oxide_types::object::JsObject;
use oxide_types::value::JsValue;
use oxide_runtime_api::{NativeResult, VmHost};
use oxide_runtime_api::{NativeResult, ProtoKind, VmHost};
use crate::builtins_debug;
use crate::builtins_error;
@@ -54,7 +54,7 @@ fn is_regexp_obj<H: VmHost>(val: JsValue, vm: &H) -> bool {
if proto_ptr.is_null() {
return false;
}
let rp = vm.session().builtin_world().regexp_proto.as_ptr() as *mut JsObject;
let rp = vm.builtin_proto(ProtoKind::RegExpProto);
std::ptr::eq(proto_ptr, rp)
}
@@ -347,11 +347,7 @@ fn string_replace_impl<H: VmHost>(vm: &mut H, args: &[u8], all: bool) -> NativeR
// ToString 须含 "g"(转换异常传播)。
let re_ptr = pattern_val.as_js_object_ptr();
// SAFETY: pattern_val 已校验为非空对象值。
let flags_val = match vm.ordinary_get(
unsafe { &*re_ptr },
vm.kernel_core().perm_interner().intern("flags").0,
pattern_val,
) {
let flags_val = match vm.ordinary_get(unsafe { &*re_ptr }, vm.perm_intern("flags"), pattern_val) {
Ok(v) => v,
Err(_) => {
if let Some(exc) = vm.take_uncaught_value() {
@@ -545,7 +541,7 @@ pub fn string_match_fn<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
// 非对象 / matcher undefined:Construct %RegExp%(undefined → 空模式、其余
// 经 ToString),再 GetMethod(rx, @@match) + Invoke;转换抛错(含 Symbol)
// 原样传播。
let regexp_ctor = vm.session().builtin_world().regexp_constructor.as_ptr() as *mut JsObject;
let regexp_ctor = vm.builtin_proto(ProtoKind::RegExpConstructor);
let rx_val = match vm.construct_ctor(JsValue::from_js_object(regexp_ctor), &[pattern_val]) {
Ok(v) => v,
Err(e) => return NativeResult::Err(e),
@@ -656,7 +652,7 @@ pub fn string_search<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
// 非对象 / searcher undefined:Construct %RegExp% + GetMethod(rx, @@search)
// + Invoke(rx, «string»);转换抛错(含 Symbol)原样传播。
let regexp_ctor = vm.session().builtin_world().regexp_constructor.as_ptr() as *mut JsObject;
let regexp_ctor = vm.builtin_proto(ProtoKind::RegExpConstructor);
let rx_val = match vm.construct_ctor(JsValue::from_js_object(regexp_ctor), &[pattern_val]) {
Ok(v) => v,
Err(e) => return NativeResult::Err(e),
@@ -814,7 +810,7 @@ pub fn string_match_all<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let re_ptr = pattern_val.as_js_object_ptr();
// SAFETY: pattern_val 已校验为非空对象值。
let re_obj = unsafe { &*re_ptr };
let flags_si = vm.kernel_core().perm_interner().intern("flags").0;
let flags_si = vm.perm_intern("flags");
let flags_val = match vm.ordinary_get(re_obj, flags_si, pattern_val) {
Ok(v) => v,
Err(e) => return NativeResult::err(crate::iterator::engine_error(vm, &e)),
@@ -883,7 +879,7 @@ pub fn string_match_all<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
return NativeResult::Err(crate::error::create_syntax_error(vm, &format!("Invalid regex: {}", e)));
}
};
let object_proto = vm.session().builtin_world().object_proto.as_ptr() as *mut JsObject;
let object_proto = vm.builtin_proto(ProtoKind::ObjectProto);
let mut stub = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(object_proto));
// 载体专型标签:native_fn 槽的 Box 经 RegExp 同一守卫释放/深拷贝,
// 避免每次 matchAll 泄漏一个已编译正则。
@@ -931,7 +927,7 @@ fn match_all_construct_invoke<H: VmHost>(vm: &mut H, this_val: JsValue, pattern_
// regexp = RegExpCreate(pattern, "g")。
let g_str = vm.new_string("g");
let ctor_ptr = vm.session().builtin_world().regexp_constructor.as_ptr() as *mut JsObject;
let ctor_ptr = vm.builtin_proto(ProtoKind::RegExpConstructor);
let rx_val = match vm.construct_ctor(JsValue::from_js_object(ctor_ptr), &[pattern_val, g_str]) {
Ok(v) => v,
Err(e) => return NativeResult::Err(e),
@@ -973,15 +969,15 @@ fn match_all_construct_invoke<H: VmHost>(vm: &mut H, this_val: JsValue, pattern_
fn builder_wrapper<H: VmHost>(vm: &mut H, input_val: JsValue, re_obj: JsValue) -> NativeResult {
// matchAll 迭代器挂 %RegExpStringIteratorPrototype%(链到 %IteratorPrototype%),
// next 由原型提供(不挂实例 own)。
let regexp_iter_proto = vm.session().builtin_world().regexp_string_iterator_proto.as_ptr() as *mut JsObject;
let regexp_iter_proto = vm.builtin_proto(ProtoKind::RegExpStringIteratorProto);
let wrapper = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(regexp_iter_proto)));
let wrapper_obj = unsafe { &mut *wrapper };
let input_si = vm.kernel_core().perm_interner().intern(MALL_INPUT).0;
let re_si = vm.kernel_core().perm_interner().intern(MALL_RE).0;
let done_si = vm.kernel_core().perm_interner().intern(MALL_DONE).0;
let global_si = vm.kernel_core().perm_interner().intern(MALL_GLOBAL).0;
let unicode_si = vm.kernel_core().perm_interner().intern(MALL_UNICODE).0;
let input_si = vm.perm_intern(MALL_INPUT);
let re_si = vm.perm_intern(MALL_RE);
let done_si = vm.perm_intern(MALL_DONE);
let global_si = vm.perm_intern(MALL_GLOBAL);
let unicode_si = vm.perm_intern(MALL_UNICODE);
vm.set_or_create_prop_value(wrapper_obj, input_si, input_val);
vm.set_or_create_prop_value(wrapper_obj, re_si, re_obj);
@@ -1023,7 +1019,7 @@ pub fn string_symbol_iterator<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResul
// 直构 String 迭代器:内层即 ToString 结果,不再回读 @@iterator。本函数语义
// 只由 this 决定,属性表被删除/置 null/被覆盖均不影响已保存引用的直调。
// 迭代器挂 %StringIteratorPrototype%(链到 %IteratorPrototype%);串内层不暴露 return。
let string_iter_proto = vm.session().builtin_world().string_iterator_proto.as_ptr() as *mut JsObject;
let string_iter_proto = vm.builtin_proto(ProtoKind::StringIteratorProto);
NativeResult::Ok(crate::iterator::build_iterator_wrapper(vm, s_val, None, true, Some(string_iter_proto)))
}
@@ -1057,11 +1053,11 @@ pub fn string_match_all_next<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
return NativeResult::Err(crate::error::create_type_error(vm, "matchAll next called on non-object"));
}
let wrapper = unsafe { &mut *this_val.as_js_object_ptr() };
let input_si = vm.kernel_core().perm_interner().intern(MALL_INPUT).0;
let re_si = vm.kernel_core().perm_interner().intern(MALL_RE).0;
let done_si = vm.kernel_core().perm_interner().intern(MALL_DONE).0;
let global_si = vm.kernel_core().perm_interner().intern(MALL_GLOBAL).0;
let unicode_si = vm.kernel_core().perm_interner().intern(MALL_UNICODE).0;
let input_si = vm.perm_intern(MALL_INPUT);
let re_si = vm.perm_intern(MALL_RE);
let done_si = vm.perm_intern(MALL_DONE);
let global_si = vm.perm_intern(MALL_GLOBAL);
let unicode_si = vm.perm_intern(MALL_UNICODE);
// 内部槽守卫:五槽同批写入,查一槽即全查;缺失即 TypeError。
if vm.get_own_property_slot(wrapper, done_si).is_none() {
@@ -1221,21 +1217,21 @@ fn make_match_result_array<H: VmHost>(
let arr = make_string_array_values(vm, parts);
let arr_ptr = arr.as_js_object_ptr();
let arr_obj = unsafe { &mut *arr_ptr };
let index_si = vm.kernel_core().perm_interner().intern("index").0;
let index_si = vm.perm_intern("index");
vm.set_or_create_prop_value(arr_obj, index_si, JsValue::int(match_index));
let input_si = vm.kernel_core().perm_interner().intern("input").0;
let input_si = vm.perm_intern("input");
vm.set_or_create_prop_value(arr_obj, input_si, input_val);
let groups_val = match m {
Some(m) => build_groups_object(vm, m, text),
None => JsValue::undefined(),
};
let groups_si = vm.kernel_core().perm_interner().intern("groups").0;
let groups_si = vm.perm_intern("groups");
vm.set_or_create_prop_value(arr_obj, groups_si, groups_val);
// d 标志:挂 indices 属性(与 exec 结果同口径的码元对数组族)。
if has_indices {
if let Some(m) = m {
let indices_val = crate::regexp::build_indices_array(vm, m, text);
let indices_si = vm.kernel_core().perm_interner().intern("indices").0;
let indices_si = vm.perm_intern("indices");
vm.set_or_create_prop_value(arr_obj, indices_si, indices_val);
}
}
@@ -1245,10 +1241,10 @@ fn make_match_result_array<H: VmHost>(
/// 构造迭代器结果对象 `{value, done}`(done 仅在 value 为 undefined 时为 true)。
fn make_match_done_result<H: VmHost>(vm: &mut H, value: JsValue) -> NativeResult {
let done = value.is_undefined();
let object_proto = vm.session().builtin_world().object_proto.as_ptr() as *mut JsObject;
let object_proto = vm.builtin_proto(ProtoKind::ObjectProto);
let obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(object_proto)));
let value_si = vm.kernel_core().perm_interner().intern("value").0;
let done_si = vm.kernel_core().perm_interner().intern("done").0;
let value_si = vm.perm_intern("value");
let done_si = vm.perm_intern("done");
let obj_ref = unsafe { &mut *obj };
vm.set_or_create_prop_value(obj_ref, value_si, value);
vm.set_or_create_prop_value(obj_ref, done_si, JsValue::bool(done));
@@ -1286,7 +1282,7 @@ pub fn string_raw<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let template_ptr = template_val.as_js_object_ptr();
// Step 2: 取 template.raw 属性。
let raw_si = vm.kernel_core().perm_interner().intern("raw").0;
let raw_si = vm.perm_intern("raw");
let template_obj = unsafe { &*template_ptr };
let raw_val = match vm.ordinary_get(template_obj, raw_si, template_val) {
Ok(v) => v,
@@ -1303,7 +1299,7 @@ pub fn string_raw<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let raw_ptr = raw_val.as_js_object_ptr();
// Step 3: 取 raw.length(ToLength,Symbol 抛 TypeError)。
let length_si = vm.kernel_core().perm_interner().intern("length").0;
let length_si = vm.perm_intern("length");
let raw_obj = unsafe { &*raw_ptr };
let raw_len = match vm.ordinary_get(raw_obj, length_si, raw_val) {
Ok(v) => {
+65 -66
View File
@@ -26,11 +26,10 @@ use std::collections::HashMap;
use std::sync::Arc;
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
use oxide_types::mem::P;
use oxide_types::object::{JsObject, NativeFnPtr, PropAttributes};
use oxide_types::value::JsValue;
use oxide_runtime_api::{to_string_full, NativeResult, VmHost};
use oxide_runtime_api::{to_string_full, NativeResult, ProtoKind, VmHost};
use crate::array::create_new_array;
use crate::map::MapInner;
@@ -111,7 +110,7 @@ fn parse_transfer_list<H: VmHost>(vm: &mut H, options: JsValue, state: &mut Clon
let opt_ptr = options.as_js_object_ptr();
// SAFETY: is_object 保证非空指针(入口已过滤);对象在 native 执行期间被根保持、不被回收。
let opt = unsafe { &*opt_ptr };
let si_transfer = vm.kernel_core().perm_interner().intern("transfer").0;
let si_transfer = vm.perm_intern("transfer");
let transfer_val = match vm.ordinary_get(opt, si_transfer, options) {
Ok(v) => v,
Err(e) => {
@@ -289,7 +288,7 @@ fn fill_error<H: VmHost>(
vm: &mut H, state: &mut CloneState, src: &JsObject, clone_ptr: *mut JsObject,
) -> Result<(), JsValue> {
let src_val = JsValue::from_js_object(src as *const JsObject as *mut JsObject);
let si_msg = vm.kernel_core().perm_interner().intern("message").0;
let si_msg = vm.perm_intern("message");
if let Some(store) = vm.get_own_property_slot(src, si_msg) {
// message 仅数据描述符复制:访问器不触发 getter、不复制。
let is_accessor = src.prop_meta_at(store).is_some_and(|m| m.is_accessor);
@@ -308,7 +307,7 @@ fn fill_error<H: VmHost>(
define_on_clone(vm, clone_ptr, si_msg, msg_val, PropAttributes::new(true, false, true))?;
}
}
let si_cause = vm.kernel_core().perm_interner().intern("cause").0;
let si_cause = vm.perm_intern("cause");
if let Some(store) = vm.get_own_property_slot(src, si_cause) {
let val = read_own_value(vm, src, src_val, si_cause, store)?;
let cloned = clone_value(vm, state, val)?;
@@ -443,7 +442,7 @@ fn fill_set<H: VmHost>(
/// 分配 plain 对象克隆(proto = %Object.prototype%)。
fn alloc_plain_clone<H: VmHost>(vm: &mut H) -> *mut JsObject {
let proto = vm.session().builtin_world().object_proto.as_ptr() as *mut JsObject;
let proto = vm.builtin_proto(ProtoKind::ObjectProto);
vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto)))
}
@@ -468,7 +467,7 @@ fn alloc_array_clone<H: VmHost>(vm: &mut H, src: &JsObject) -> *mut JsObject {
/// 分配 Map 克隆(空 `MapInner`,proto = %Map.prototype%)。
fn alloc_map_clone<H: VmHost>(vm: &mut H) -> *mut JsObject {
let map_proto = vm.session().builtin_world().map_proto.as_ptr() as *mut JsObject;
let map_proto = vm.builtin_proto(ProtoKind::MapProto);
let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(map_proto));
obj.set_map(true);
let inner = Box::into_raw(Box::new(MapInner::new()));
@@ -478,7 +477,7 @@ fn alloc_map_clone<H: VmHost>(vm: &mut H) -> *mut JsObject {
/// 分配 Set 克隆(空 `SetInner`,proto = %Set.prototype%)。
fn alloc_set_clone<H: VmHost>(vm: &mut H) -> *mut JsObject {
let set_proto = vm.session().builtin_world().set_proto.as_ptr() as *mut JsObject;
let set_proto = vm.builtin_proto(ProtoKind::SetProto);
let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(set_proto));
obj.set_set(true);
let inner = Box::into_raw(Box::new(SetInner::new()));
@@ -488,7 +487,7 @@ fn alloc_set_clone<H: VmHost>(vm: &mut H) -> *mut JsObject {
/// 分配 Date 克隆(同时间戳,proto = %Date.prototype%)。
fn alloc_date_clone<H: VmHost>(vm: &mut H, src: &JsObject) -> *mut JsObject {
let proto = vm.session().builtin_world().date_proto.as_ptr() as *mut JsObject;
let proto = vm.builtin_proto(ProtoKind::DateProto);
let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto));
obj.type_tag = JsObject::OBJ_TYPE_DATE;
obj.set_prop_at(0, src.get_prop_at(0));
@@ -501,7 +500,7 @@ fn alloc_date_clone<H: VmHost>(vm: &mut H, src: &JsObject) -> *mut JsObject {
/// - 源模式非法(理论上不发生,源已是合法 RegExp)时抛 SyntaxError;
/// - lastIndex 初始化为 0(writable / 非枚举 / 非可配置)。
fn alloc_regexp_clone<H: VmHost>(vm: &mut H, src: &JsObject) -> Result<*mut JsObject, JsValue> {
let proto = vm.session().builtin_world().regexp_proto.as_ptr() as *mut JsObject;
let proto = vm.builtin_proto(ProtoKind::RegExpProto);
let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto));
let source_val = src.get_regexp_source();
let flags_val = src.get_regexp_flags();
@@ -521,7 +520,7 @@ fn alloc_regexp_clone<H: VmHost>(vm: &mut H, src: &JsObject) -> Result<*mut JsOb
obj.type_tag = JsObject::OBJ_TYPE_REGEXP;
obj.set_regexp_source(source_val);
obj.set_regexp_flags(flags_val);
let si_lastindex = vm.kernel_core().perm_interner().intern("lastIndex").0;
let si_lastindex = vm.perm_intern("lastIndex");
let _ = vm.define_data_property(&mut obj, si_lastindex, JsValue::int(0), PropAttributes::new(true, false, false));
Ok(vm.alloc_object(obj))
}
@@ -534,7 +533,7 @@ fn alloc_regexp_clone<H: VmHost>(vm: &mut H, src: &JsObject) -> Result<*mut JsOb
/// - 克隆原型与源原型解耦(源子类原型丢弃,按规范反序列化口径回落标准原型)。
fn alloc_error_clone<H: VmHost>(vm: &mut H, src: &JsObject) -> Result<*mut JsObject, JsValue> {
let src_val = JsValue::from_js_object(src as *const JsObject as *mut JsObject);
let si_name = vm.kernel_core().perm_interner().intern("name").0;
let si_name = vm.perm_intern("name");
let name_val = match vm.ordinary_get(src, si_name, src_val) {
Ok(v) => v,
Err(e) => {
@@ -546,13 +545,13 @@ fn alloc_error_clone<H: VmHost>(vm: &mut H, src: &JsObject) -> Result<*mut JsObj
};
// 归一化:七标准名取对应标准原型,其余(非字符串或自定义名)取 %Error.prototype%。
let proto = match vm.lookup_str(name_val).as_deref() {
Some("EvalError") => P::as_ptr(&vm.session().builtin_world().eval_error_proto) as *mut JsObject,
Some("RangeError") => P::as_ptr(&vm.session().builtin_world().range_error_proto) as *mut JsObject,
Some("ReferenceError") => P::as_ptr(&vm.session().builtin_world().reference_error_proto) as *mut JsObject,
Some("SyntaxError") => P::as_ptr(&vm.session().builtin_world().syntax_error_proto) as *mut JsObject,
Some("TypeError") => P::as_ptr(&vm.session().builtin_world().type_error_proto) as *mut JsObject,
Some("URIError") => P::as_ptr(&vm.session().builtin_world().uri_error_proto) as *mut JsObject,
_ => P::as_ptr(&vm.session().builtin_world().error_proto) as *mut JsObject,
Some("EvalError") => vm.builtin_proto(ProtoKind::EvalErrorProto),
Some("RangeError") => vm.builtin_proto(ProtoKind::RangeErrorProto),
Some("ReferenceError") => vm.builtin_proto(ProtoKind::ReferenceErrorProto),
Some("SyntaxError") => vm.builtin_proto(ProtoKind::SyntaxErrorProto),
Some("TypeError") => vm.builtin_proto(ProtoKind::TypeErrorProto),
Some("URIError") => vm.builtin_proto(ProtoKind::UriErrorProto),
_ => vm.builtin_proto(ProtoKind::ErrorProto),
};
let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto));
obj.type_tag = JsObject::OBJ_TYPE_ERROR;
@@ -659,7 +658,7 @@ fn alloc_data_view_clone<H: VmHost>(
// SAFETY: data_ptr 经对象类型标签校验为存活状态盒;Copy 语义,不跨 JS 调用持借用。
let data = unsafe { *data_ptr };
let cloned_buffer = clone_value(vm, state, data.buffer)?;
let proto = JsValue::from_js_object(vm.session().builtin_world().data_view_proto.as_ptr() as *mut JsObject);
let proto = JsValue::from_js_object(vm.builtin_proto(ProtoKind::DataViewProto));
let mut obj = JsObject::new_empty(EMPTY_SHAPE_ID, proto);
obj.type_tag = JsObject::OBJ_TYPE_DATA_VIEW;
let new_data = Box::into_raw(Box::new(crate::data_view::DataViewData {
@@ -701,7 +700,7 @@ fn is_boxed_cloneable(src: &JsObject) -> bool {
/// 供同 crate 的跨 realm 值传递抽象(`message_value`)复用。
pub(crate) fn data_clone_error<H: VmHost>(vm: &mut H, msg: &str) -> JsValue {
let err = crate::error::create_kind_error(vm, "DataCloneError", msg);
let si_name = vm.kernel_core().perm_interner().intern("name").0;
let si_name = vm.perm_intern("name");
let name_val = vm.new_string("DataCloneError");
// 新建错误对象形状为空,define 恒成功;失败忽略(不影响异常值身份)。
let _ = vm.define_data_property(
@@ -745,7 +744,7 @@ mod tests {
/// 读对象自身属性值(按名称),无则 undefined。
fn obj_prop(vm: &Vm, obj: &JsObject, name: &str) -> JsValue {
let si = vm.kernel_core().perm_interner().intern(name).0;
let si = vm.perm_intern(name);
match vm.get_own_property_slot(obj, si) {
Some(idx) => obj.get_prop_at(idx),
None => JsValue::undefined(),
@@ -860,8 +859,8 @@ mod tests {
let (mut vm, v) = eval("var a = {x: 1}; var b = {ref: a, ref2: a}; b").unwrap();
let c = clone(&mut vm, v).unwrap();
let cl = unsafe { &*c.as_js_object_ptr() };
let si_ref = vm.kernel_core().perm_interner().intern("ref").0;
let si_ref2 = vm.kernel_core().perm_interner().intern("ref2").0;
let si_ref = vm.perm_intern("ref");
let si_ref2 = vm.perm_intern("ref2");
let ref1 = cl.get_prop_at(vm.get_own_property_slot(cl, si_ref).unwrap());
let ref2 = cl.get_prop_at(vm.get_own_property_slot(cl, si_ref2).unwrap());
assert!(ref1.is_object() && ref2.is_object());
@@ -873,7 +872,7 @@ mod tests {
let (mut vm, v) = eval("var a = {}; a.self = a; a").unwrap();
let c = clone(&mut vm, v).unwrap();
let cl = unsafe { &*c.as_js_object_ptr() };
let si_self = vm.kernel_core().perm_interner().intern("self").0;
let si_self = vm.perm_intern("self");
let self_ref = cl.get_prop_at(vm.get_own_property_slot(cl, si_self).unwrap());
assert!(std::ptr::eq(self_ref.as_js_object_ptr(), c.as_js_object_ptr()), "循环引用应指向克隆自身");
}
@@ -935,8 +934,8 @@ mod tests {
eval("var ab = new Uint8Array([9, 8, 7]).buffer; var opts = {transfer: [ab]}; ({ab: ab, opts: opts})")
.unwrap();
let holder = unsafe { &*v.as_js_object_ptr() };
let si_ab = vm.kernel_core().perm_interner().intern("ab").0;
let si_opts = vm.kernel_core().perm_interner().intern("opts").0;
let si_ab = vm.perm_intern("ab");
let si_opts = vm.perm_intern("opts");
let ab = holder.get_prop_at(vm.get_own_property_slot(holder, si_ab).unwrap());
let opts = holder.get_prop_at(vm.get_own_property_slot(holder, si_opts).unwrap());
let c = clone_with_options(&mut vm, ab, opts).unwrap();
@@ -971,8 +970,8 @@ mod tests {
eval("var ta = new Uint8Array([1, 2, 3]); var opts = {transfer: [ta.buffer]}; ({ta: ta, opts: opts})")
.unwrap();
let holder = unsafe { &*v.as_js_object_ptr() };
let si_ta = vm.kernel_core().perm_interner().intern("ta").0;
let si_opts = vm.kernel_core().perm_interner().intern("opts").0;
let si_ta = vm.perm_intern("ta");
let si_opts = vm.perm_intern("opts");
let ta = holder.get_prop_at(vm.get_own_property_slot(holder, si_ta).unwrap());
let opts = holder.get_prop_at(vm.get_own_property_slot(holder, si_opts).unwrap());
let c = clone_with_options(&mut vm, ta, opts).unwrap();
@@ -1026,8 +1025,8 @@ mod tests {
let (mut vm, v) =
eval("var sab = new SharedArrayBuffer(4); var opts = {transfer: [sab]}; ({v: sab, opts: opts})").unwrap();
let holder = unsafe { &*v.as_js_object_ptr() };
let si_v = vm.kernel_core().perm_interner().intern("v").0;
let si_opts = vm.kernel_core().perm_interner().intern("opts").0;
let si_v = vm.perm_intern("v");
let si_opts = vm.perm_intern("opts");
let val = holder.get_prop_at(vm.get_own_property_slot(holder, si_v).unwrap());
let opts = holder.get_prop_at(vm.get_own_property_slot(holder, si_opts).unwrap());
let e = clone_with_options(&mut vm, val, opts).unwrap_err();
@@ -1040,8 +1039,8 @@ mod tests {
let (mut vm, v) =
eval("var ab = new ArrayBuffer(4); var opts = {transfer: [ab, ab]}; ({v: ab, opts: opts})").unwrap();
let holder = unsafe { &*v.as_js_object_ptr() };
let si_v = vm.kernel_core().perm_interner().intern("v").0;
let si_opts = vm.kernel_core().perm_interner().intern("opts").0;
let si_v = vm.perm_intern("v");
let si_opts = vm.perm_intern("opts");
let val = holder.get_prop_at(vm.get_own_property_slot(holder, si_v).unwrap());
let opts = holder.get_prop_at(vm.get_own_property_slot(holder, si_opts).unwrap());
let e = clone_with_options(&mut vm, val, opts).unwrap_err();
@@ -1075,8 +1074,8 @@ mod tests {
// 字符串经 ToList 逐字符迭代,'x' 非 ArrayBuffer → DataCloneError。
let (mut vm, v) = eval("var opts = {transfer: 'x'}; ({v: 1, opts: opts})").unwrap();
let holder = unsafe { &*v.as_js_object_ptr() };
let si_v = vm.kernel_core().perm_interner().intern("v").0;
let si_opts = vm.kernel_core().perm_interner().intern("opts").0;
let si_v = vm.perm_intern("v");
let si_opts = vm.perm_intern("opts");
let val = holder.get_prop_at(vm.get_own_property_slot(holder, si_v).unwrap());
let opts = holder.get_prop_at(vm.get_own_property_slot(holder, si_opts).unwrap());
let e = clone_with_options(&mut vm, val, opts).unwrap_err();
@@ -1090,8 +1089,8 @@ mod tests {
// 不可迭代对象经 GetIterator 抛 TypeError。
let (mut vm, v) = eval("var opts = {transfer: {}}; ({v: 1, opts: opts})").unwrap();
let holder = unsafe { &*v.as_js_object_ptr() };
let si_v = vm.kernel_core().perm_interner().intern("v").0;
let si_opts = vm.kernel_core().perm_interner().intern("opts").0;
let si_v = vm.perm_intern("v");
let si_opts = vm.perm_intern("opts");
let val = holder.get_prop_at(vm.get_own_property_slot(holder, si_v).unwrap());
let opts = holder.get_prop_at(vm.get_own_property_slot(holder, si_opts).unwrap());
let e = clone_with_options(&mut vm, val, opts).unwrap_err();
@@ -1110,8 +1109,8 @@ mod tests {
)
.unwrap();
let holder = unsafe { &*v.as_js_object_ptr() };
let si_ab = vm.kernel_core().perm_interner().intern("ab").0;
let si_opts = vm.kernel_core().perm_interner().intern("opts").0;
let si_ab = vm.perm_intern("ab");
let si_opts = vm.perm_intern("opts");
let ab = holder.get_prop_at(vm.get_own_property_slot(holder, si_ab).unwrap());
let opts = holder.get_prop_at(vm.get_own_property_slot(holder, si_opts).unwrap());
let c = clone_with_options(&mut vm, ab, opts).unwrap();
@@ -1197,7 +1196,7 @@ mod tests {
let cl = unsafe { &*c.as_js_object_ptr() };
// 克隆是 plain 对象:原型链丢弃,回落 Object 原型,自有属性带过。
assert_eq!(cl.type_tag, JsObject::OBJ_TYPE_PLAIN);
let object_proto = vm.session().builtin_world().object_proto.as_ptr() as *const u8;
let object_proto = vm.builtin_proto(ProtoKind::ObjectProto) as *const u8;
assert!(std::ptr::eq(cl.proto().as_ptr(), object_proto));
assert_eq!(obj_prop(&vm, cl, "x"), JsValue::int(1));
}
@@ -1231,7 +1230,7 @@ mod tests {
let (mut vm, v) = eval("var o = {a: 1}; Object.freeze(o); o").unwrap();
let c = clone(&mut vm, v).unwrap();
let cl = unsafe { &*c.as_js_object_ptr() };
let si = vm.kernel_core().perm_interner().intern("a").0;
let si = vm.perm_intern("a");
let store = vm.get_own_property_slot(cl, si).unwrap();
let meta = cl.prop_meta_at(store).unwrap();
assert_eq!(meta.attributes, PropAttributes::DEFAULT_DATA, "克隆侧描述符应 w/e/c 全真");
@@ -1245,7 +1244,7 @@ mod tests {
let c = clone(&mut vm, v).unwrap();
let cl = unsafe { &*c.as_js_object_ptr() };
assert_eq!(obj_prop(&vm, cl, "a"), JsValue::int(1));
let si_b = vm.kernel_core().perm_interner().intern("b").0;
let si_b = vm.perm_intern("b");
assert!(vm.get_own_property_slot(cl, si_b).is_none(), "不可枚举自有属性不应复制");
}
@@ -1265,7 +1264,7 @@ mod tests {
let (mut vm, v) = eval("var e = new Error('boom'); e.cause = {x: 1}; e").unwrap();
let c = clone(&mut vm, v).unwrap();
let cl = unsafe { &*c.as_js_object_ptr() };
let si_cause = vm.kernel_core().perm_interner().intern("cause").0;
let si_cause = vm.perm_intern("cause");
let store = vm.get_own_property_slot(cl, si_cause).unwrap();
let meta = cl.prop_meta_at(store).unwrap();
assert_eq!(meta.attributes, PropAttributes::DEFAULT_DATA, "克隆侧 cause 应全真数据属性");
@@ -1279,7 +1278,7 @@ mod tests {
// 引擎给 Error 子类实例打 Error 家族标签,克隆走 Error 臂;name 归一
// "Error",原型回落 %Error.prototype%(源子类原型丢弃),message 带过。
assert!(cl.is_error_obj());
let error_proto = vm.session().builtin_world().error_proto.as_ptr() as *const u8;
let error_proto = vm.builtin_proto(ProtoKind::ErrorProto) as *const u8;
assert!(std::ptr::eq(cl.proto().as_ptr(), error_proto), "克隆原型应回落 %Error.prototype%");
assert_eq!(vm.lookup_str(obj_prop(&vm, cl, "message")).unwrap(), "msg");
}
@@ -1290,7 +1289,7 @@ mod tests {
let (mut vm, v) = eval("var e = new TypeError('boom'); e").unwrap();
let c = clone(&mut vm, v).unwrap();
let cl = unsafe { &*c.as_js_object_ptr() };
let type_proto = vm.session().builtin_world().type_error_proto.as_ptr() as *const u8;
let type_proto = vm.builtin_proto(ProtoKind::TypeErrorProto) as *const u8;
assert!(std::ptr::eq(cl.proto().as_ptr(), type_proto), "克隆原型应为 %TypeError.prototype%");
assert_eq!(vm.lookup_str(obj_prop(&vm, cl, "message")).unwrap(), "boom");
}
@@ -1318,8 +1317,8 @@ mod tests {
)
.unwrap();
let holder = unsafe { &*v.as_js_object_ptr() };
let si_ab = vm.kernel_core().perm_interner().intern("ab").0;
let si_opts = vm.kernel_core().perm_interner().intern("opts").0;
let si_ab = vm.perm_intern("ab");
let si_opts = vm.perm_intern("opts");
let ab = holder.get_prop_at(vm.get_own_property_slot(holder, si_ab).unwrap());
let opts = holder.get_prop_at(vm.get_own_property_slot(holder, si_opts).unwrap());
// 克隆持有者对象(含函数值,不可克隆)→ DataCloneError。
@@ -1338,9 +1337,9 @@ mod tests {
)
.unwrap();
let holder = unsafe { &*v.as_js_object_ptr() };
let si_v = vm.kernel_core().perm_interner().intern("v").0;
let si_ab = vm.kernel_core().perm_interner().intern("ab").0;
let si_opts = vm.kernel_core().perm_interner().intern("opts").0;
let si_v = vm.perm_intern("v");
let si_ab = vm.perm_intern("ab");
let si_opts = vm.perm_intern("opts");
let val = holder.get_prop_at(vm.get_own_property_slot(holder, si_v).unwrap());
let ab = holder.get_prop_at(vm.get_own_property_slot(holder, si_ab).unwrap());
let opts = holder.get_prop_at(vm.get_own_property_slot(holder, si_opts).unwrap());
@@ -1366,8 +1365,8 @@ mod tests {
)
.unwrap();
let holder = unsafe { &*v.as_js_object_ptr() };
let si_v = vm.kernel_core().perm_interner().intern("v").0;
let si_opts = vm.kernel_core().perm_interner().intern("opts").0;
let si_v = vm.perm_intern("v");
let si_opts = vm.perm_intern("opts");
let val = holder.get_prop_at(vm.get_own_property_slot(holder, si_v).unwrap());
let opts = holder.get_prop_at(vm.get_own_property_slot(holder, si_opts).unwrap());
let e = clone_with_options(&mut vm, val, opts).unwrap_err();
@@ -1387,7 +1386,7 @@ mod tests {
let key = &entries[0].0;
assert!(key.0.is_object());
let key_obj = unsafe { &*key.0.as_js_object_ptr() };
let si_m = vm.kernel_core().perm_interner().intern("m").0;
let si_m = vm.perm_intern("m");
let key_m = key_obj.get_prop_at(vm.get_own_property_slot(key_obj, si_m).unwrap());
assert!(std::ptr::eq(key_m.as_js_object_ptr(), c.as_js_object_ptr()), "克隆键应引用克隆的 map");
}
@@ -1408,10 +1407,10 @@ mod tests {
let (mut vm, v) = eval("var a = {}; var b = {}; a.b = b; b.a = a; a").unwrap();
let c = clone(&mut vm, v).unwrap();
let cl = unsafe { &*c.as_js_object_ptr() };
let si_b = vm.kernel_core().perm_interner().intern("b").0;
let si_b = vm.perm_intern("b");
let b_clone = cl.get_prop_at(vm.get_own_property_slot(cl, si_b).unwrap());
let b_obj = unsafe { &*b_clone.as_js_object_ptr() };
let si_a = vm.kernel_core().perm_interner().intern("a").0;
let si_a = vm.perm_intern("a");
let a_back = b_obj.get_prop_at(vm.get_own_property_slot(b_obj, si_a).unwrap());
assert!(std::ptr::eq(a_back.as_js_object_ptr(), c.as_js_object_ptr()), "深循环应指回克隆的 a");
}
@@ -1421,9 +1420,9 @@ mod tests {
let (mut vm, v) = eval("var a = {x: 1}; var b = {ref: a, ref2: a}; b.self = b; b").unwrap();
let c = clone(&mut vm, v).unwrap();
let cl = unsafe { &*c.as_js_object_ptr() };
let si_ref = vm.kernel_core().perm_interner().intern("ref").0;
let si_ref2 = vm.kernel_core().perm_interner().intern("ref2").0;
let si_self = vm.kernel_core().perm_interner().intern("self").0;
let si_ref = vm.perm_intern("ref");
let si_ref2 = vm.perm_intern("ref2");
let si_self = vm.perm_intern("self");
let ref1 = cl.get_prop_at(vm.get_own_property_slot(cl, si_ref).unwrap());
let ref2 = cl.get_prop_at(vm.get_own_property_slot(cl, si_ref2).unwrap());
let self_ref = cl.get_prop_at(vm.get_own_property_slot(cl, si_self).unwrap());
@@ -1439,8 +1438,8 @@ mod tests {
)
.unwrap();
let holder = unsafe { &*v.as_js_object_ptr() };
let si_ab = vm.kernel_core().perm_interner().intern("ab").0;
let si_opts = vm.kernel_core().perm_interner().intern("opts").0;
let si_ab = vm.perm_intern("ab");
let si_opts = vm.perm_intern("opts");
let ab = holder.get_prop_at(vm.get_own_property_slot(holder, si_ab).unwrap());
let opts = holder.get_prop_at(vm.get_own_property_slot(holder, si_opts).unwrap());
let c = clone_with_options(&mut vm, ab, opts).unwrap();
@@ -1460,8 +1459,8 @@ mod tests {
)
.unwrap();
let holder = unsafe { &*v.as_js_object_ptr() };
let si_ab = vm.kernel_core().perm_interner().intern("ab").0;
let si_opts = vm.kernel_core().perm_interner().intern("opts").0;
let si_ab = vm.perm_intern("ab");
let si_opts = vm.perm_intern("opts");
let ab = holder.get_prop_at(vm.get_own_property_slot(holder, si_ab).unwrap());
let opts = holder.get_prop_at(vm.get_own_property_slot(holder, si_opts).unwrap());
let c = clone_with_options(&mut vm, ab, opts).unwrap();
@@ -1493,7 +1492,7 @@ mod tests {
.unwrap();
let c = clone(&mut vm, v).unwrap();
let cl = unsafe { &*c.as_js_object_ptr() };
let si_msg = vm.kernel_core().perm_interner().intern("message").0;
let si_msg = vm.perm_intern("message");
assert!(vm.get_own_property_slot(cl, si_msg).is_none(), "访问器 message 不应复制");
}
@@ -1512,7 +1511,7 @@ mod tests {
let (mut vm, v) = eval("var e = new Error('base'); delete e.message; e").unwrap();
let c = clone(&mut vm, v).unwrap();
let cl = unsafe { &*c.as_js_object_ptr() };
let si_msg = vm.kernel_core().perm_interner().intern("message").0;
let si_msg = vm.perm_intern("message");
assert!(vm.get_own_property_slot(cl, si_msg).is_none());
}
@@ -1532,8 +1531,8 @@ mod tests {
// 全局绑定面:length 为 1、name 为 "structuredClone"(防绑定面回归)。
let (vm, v) = eval("({len: structuredClone.length, name: structuredClone.name})").unwrap();
let holder = unsafe { &*v.as_js_object_ptr() };
let si_len = vm.kernel_core().perm_interner().intern("len").0;
let si_name = vm.kernel_core().perm_interner().intern("name").0;
let si_len = vm.perm_intern("len");
let si_name = vm.perm_intern("name");
let len = holder.get_prop_at(vm.get_own_property_slot(holder, si_len).unwrap());
let name = holder.get_prop_at(vm.get_own_property_slot(holder, si_name).unwrap());
assert_eq!(len, JsValue::int(1));
+40 -47
View File
@@ -9,7 +9,7 @@ use crate::array_buffer::{
buffer_payload, buffer_payload_ptr, default_array_buffer_proto, new_array_buffer, MAX_ARRAY_BUFFER_LENGTH,
};
use oxide_runtime_api::{NativeResult, VmHost};
use oxide_runtime_api::{NativeResult, ProtoKind, VmHost};
#[derive(Clone, Copy)]
pub(crate) struct TypedArrayData {
@@ -58,23 +58,20 @@ fn to_index<H: VmHost>(vm: &mut H, value: JsValue, msg: &str) -> Result<usize, J
}
pub(crate) fn typed_array_proto_ptr<H: VmHost>(vm: &mut H, kind: TypedArrayKind) -> *mut JsObject {
{
let session = vm.session();
let world = session.builtin_world();
match kind {
TypedArrayKind::Int8 => world.int8array_proto.as_ptr() as *mut JsObject,
TypedArrayKind::Uint8 => world.uint8array_proto.as_ptr() as *mut JsObject,
TypedArrayKind::Uint8Clamped => world.uint8clampedarray_proto.as_ptr() as *mut JsObject,
TypedArrayKind::Int16 => world.int16array_proto.as_ptr() as *mut JsObject,
TypedArrayKind::Uint16 => world.uint16array_proto.as_ptr() as *mut JsObject,
TypedArrayKind::Int32 => world.int32array_proto.as_ptr() as *mut JsObject,
TypedArrayKind::Uint32 => world.uint32array_proto.as_ptr() as *mut JsObject,
TypedArrayKind::Float32 => world.float32array_proto.as_ptr() as *mut JsObject,
TypedArrayKind::Float64 => world.float64array_proto.as_ptr() as *mut JsObject,
TypedArrayKind::BigInt64 => world.bigint64array_proto.as_ptr() as *mut JsObject,
TypedArrayKind::BigUint64 => world.biguint64array_proto.as_ptr() as *mut JsObject,
}
}
let kind = match kind {
TypedArrayKind::Int8 => ProtoKind::Int8ArrayProto,
TypedArrayKind::Uint8 => ProtoKind::Uint8ArrayProto,
TypedArrayKind::Uint8Clamped => ProtoKind::Uint8ClampedArrayProto,
TypedArrayKind::Int16 => ProtoKind::Int16ArrayProto,
TypedArrayKind::Uint16 => ProtoKind::Uint16ArrayProto,
TypedArrayKind::Int32 => ProtoKind::Int32ArrayProto,
TypedArrayKind::Uint32 => ProtoKind::Uint32ArrayProto,
TypedArrayKind::Float32 => ProtoKind::Float32ArrayProto,
TypedArrayKind::Float64 => ProtoKind::Float64ArrayProto,
TypedArrayKind::BigInt64 => ProtoKind::BigInt64ArrayProto,
TypedArrayKind::BigUint64 => ProtoKind::BigUint64ArrayProto,
};
vm.builtin_proto(kind)
}
/// 取指定类型的内建构造器值(`[[TypedArrayName]]` → world 槽),species 默认臂
@@ -95,7 +92,7 @@ fn ta_gpf_proto<H: VmHost>(vm: &mut H, kind: TypedArrayKind) -> Result<JsValue,
let nt_ptr = new_target.as_js_object_ptr();
// SAFETY: is_object 保证指针非空且对象本 session 存活。
let nt_obj = unsafe { &*nt_ptr };
let proto_si = vm.kernel_core().perm_interner().intern("prototype").0;
let proto_si = vm.perm_intern("prototype");
match vm.ordinary_get(nt_obj, proto_si, new_target) {
Ok(v) => Ok(if v.is_object() { v } else { default_proto }),
Err(err) => Err(crate::iterator::engine_error(vm, &err)),
@@ -103,24 +100,20 @@ fn ta_gpf_proto<H: VmHost>(vm: &mut H, kind: TypedArrayKind) -> Result<JsValue,
}
fn typed_array_ctor_value<H: VmHost>(vm: &mut H, kind: TypedArrayKind) -> JsValue {
let ctor = {
let session = vm.session();
let world = session.builtin_world();
match kind {
TypedArrayKind::Int8 => world.int8array_constructor.clone(),
TypedArrayKind::Uint8 => world.uint8array_constructor.clone(),
TypedArrayKind::Uint8Clamped => world.uint8clampedarray_constructor.clone(),
TypedArrayKind::Int16 => world.int16array_constructor.clone(),
TypedArrayKind::Uint16 => world.uint16array_constructor.clone(),
TypedArrayKind::Int32 => world.int32array_constructor.clone(),
TypedArrayKind::Uint32 => world.uint32array_constructor.clone(),
TypedArrayKind::Float32 => world.float32array_constructor.clone(),
TypedArrayKind::Float64 => world.float64array_constructor.clone(),
TypedArrayKind::BigInt64 => world.bigint64array_constructor.clone(),
TypedArrayKind::BigUint64 => world.biguint64array_constructor.clone(),
}
let kind = match kind {
TypedArrayKind::Int8 => ProtoKind::Int8ArrayConstructor,
TypedArrayKind::Uint8 => ProtoKind::Uint8ArrayConstructor,
TypedArrayKind::Uint8Clamped => ProtoKind::Uint8ClampedArrayConstructor,
TypedArrayKind::Int16 => ProtoKind::Int16ArrayConstructor,
TypedArrayKind::Uint16 => ProtoKind::Uint16ArrayConstructor,
TypedArrayKind::Int32 => ProtoKind::Int32ArrayConstructor,
TypedArrayKind::Uint32 => ProtoKind::Uint32ArrayConstructor,
TypedArrayKind::Float32 => ProtoKind::Float32ArrayConstructor,
TypedArrayKind::Float64 => ProtoKind::Float64ArrayConstructor,
TypedArrayKind::BigInt64 => ProtoKind::BigInt64ArrayConstructor,
TypedArrayKind::BigUint64 => ProtoKind::BigUint64ArrayConstructor,
};
JsValue::from_js_object(ctor.as_ptr() as *mut JsObject)
JsValue::from_js_object(vm.builtin_proto(kind))
}
/// 把 TypedArray 实例数据(类型标签 + 视图内部槽)写入指定对象;构造调用与
@@ -402,7 +395,7 @@ pub fn ta_index_gate<H: VmHost>(vm: &H, obj: &JsObject, key_si: u32) -> TaIndexG
if is_int_key(key_si) {
return ta_index_gate_int(int_key_value(key_si), length);
}
let Some(key) = vm.kernel_core().perm_interner().lookup(key_si) else {
let Some(key) = vm.perm_lookup(key_si) else {
return TaIndexGate::Ordinary;
};
ta_index_gate_from_text(key, length)
@@ -699,8 +692,8 @@ pub fn element_error_text<H: VmHost>(vm: &mut H, err: JsValue) -> String {
}
if err.is_object() {
let obj = unsafe { &*err.as_js_object_ptr() };
let name_si = vm.kernel_core().perm_interner().intern("name").0;
let message_si = vm.kernel_core().perm_interner().intern("message").0;
let name_si = vm.perm_intern("name");
let message_si = vm.perm_intern("message");
let name = vm
.resolve_property(obj, name_si)
.and_then(|v| vm.lookup_str(v))
@@ -825,7 +818,7 @@ fn collect_array_like<H: VmHost>(
return Ok(values);
}
let length_si = vm.kernel_core().perm_interner().intern("length").0;
let length_si = vm.perm_intern("length");
let len_val = vm
.ordinary_get(obj, length_si, value)
.map_err(|e| crate::iterator::engine_error(vm, &e))?;
@@ -1141,7 +1134,7 @@ fn typed_array_species_create<H: VmHost>(
) -> Result<JsValue, JsValue> {
let o_ptr = o_val.as_js_object_ptr();
let o_obj = unsafe { &*o_ptr };
let ctor_key = vm.kernel_core().perm_interner().intern("constructor").0;
let ctor_key = vm.perm_intern("constructor");
let c = match vm.ordinary_get(o_obj, ctor_key, o_val) {
Ok(v) => v,
Err(msg) => return Err(crate::iterator::engine_error(vm, &msg)),
@@ -1371,7 +1364,7 @@ enum SetSourceKind {
/// array-like 源的 `length` 属性读 + ToLength 收敛(NaN/负取 0,上限 2^53-1)。
fn set_array_like_length<H: VmHost>(vm: &mut H, source: JsValue) -> Result<usize, JsValue> {
let si = vm.kernel_core().perm_interner().intern("length").0;
let si = vm.perm_intern("length");
let ptr = source.as_js_object_ptr();
let len_val = unsafe { vm.ordinary_get(&*ptr, si, source) }.map_err(|e| crate::iterator::engine_error(vm, &e))?;
let n = oxide_runtime_api::to_number_full(len_val, vm).map_err(|e| crate::iterator::engine_error(vm, &e))?;
@@ -2229,7 +2222,7 @@ pub fn typed_array_copy_within<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResu
fn invoke_element_to_locale_string<H: VmHost>(vm: &mut H, element: JsValue) -> Result<JsValue, JsValue> {
let obj_val = oxide_runtime_api::to_object(element, vm).map_err(|e| crate::iterator::engine_error(vm, &e))?;
let obj = unsafe { &*obj_val.as_js_object_ptr() };
let method_si = vm.kernel_core().perm_interner().intern("toLocaleString").0;
let method_si = vm.perm_intern("toLocaleString");
let method = vm
.ordinary_get(obj, method_si, element)
.map_err(|e| crate::iterator::engine_error(vm, &e))?;
@@ -2446,7 +2439,7 @@ pub fn typed_array_from<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
Err(err) => return NativeResult::Err(crate::error::create_type_error(vm, &err)),
};
let obj = unsafe { &*obj_val.as_js_object_ptr() };
let length_si = vm.kernel_core().perm_interner().intern("length").0;
let length_si = vm.perm_intern("length");
let len_val = match vm.ordinary_get(obj, length_si, obj_val) {
Ok(v) => v,
Err(e) => return NativeResult::Err(crate::iterator::engine_error(vm, &e)),
@@ -2604,10 +2597,10 @@ fn ta_decode_base64<H: VmHost>(
/// setFrom* 结果对象 `{ read, written }`:普通对象 + 两数据属性。
fn ta_read_written_result<H: VmHost>(vm: &mut H, read: usize, written: usize) -> JsValue {
let object_proto = vm.session().builtin_world().object_proto.as_ptr() as *mut JsObject;
let object_proto = vm.builtin_proto(ProtoKind::ObjectProto);
let obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(object_proto)));
let read_si = vm.kernel_core().perm_interner().intern("read").0;
let written_si = vm.kernel_core().perm_interner().intern("written").0;
let read_si = vm.perm_intern("read");
let written_si = vm.perm_intern("written");
let obj_ref = unsafe { &mut *obj };
vm.set_or_create_prop_value(obj_ref, read_si, JsValue::int(read as i32));
vm.set_or_create_prop_value(obj_ref, written_si, JsValue::int(written as i32));