mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 03:01:12 +08:00
568 lines
26 KiB
Rust
568 lines
26 KiB
Rust
//! ShadowRealm native 实现:构造器(建影子 realm 与实例对象)与 `evaluate` /
|
||
//! `importValue` 真实现(影子 realm 脚本执行、跨 realm 结果结算、WrappedFunction
|
||
//! 包装、模块文件加载)。
|
||
//!
|
||
//! 关键约定:
|
||
//! - 函数是 concrete `&mut Vm` 形态(同 `worker_constructor`),不挂 `VmHost`
|
||
//! trait:构造器要新建 Vm(影子 realm),`VmHost` 接口面表达不了。
|
||
//! - 实例对象是 PLAIN 对象(`[[Prototype]]` → ShadowRealm.prototype),主 Vm
|
||
//! 侧表 `shadow_realm_objects` 是 brand 校验依据(this 指针在侧表),不占
|
||
//! OBJ_TYPE 槽位。
|
||
//! - `evaluate` / `importValue` 真实现:在影子 realm 内编译执行(脚本 / 模块),
|
||
//! 结果经跨 realm 结算(原始值直返、函数包装为 WrappedFunction、非原始非函数
|
||
//! 抛 TypeError、符号按 realm 重映射)后返回。
|
||
//! - WrappedFunction 是调用方 realm 的函数对象(native 函数项),持有跨 realm
|
||
//! 逻辑边:原函数在属主 Vm 的保活表(`shadow_keepalive`,属主 Vm 的 GC 根)
|
||
//! 保活,包装方 Vm 经 `wrapped_function_state`(包装方 Vm 的 GC 根)反查。
|
||
//! 包装方向双向:evaluate 结果包装影子函数(包装在主 realm),包装函数实参
|
||
//! 包装主 realm 函数(包装在影子 realm),嵌套影子 realm 沿属主链上溯解析。
|
||
|
||
use std::sync::Arc;
|
||
|
||
use oxide_builtins::error;
|
||
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
|
||
use oxide_runtime_api::{to_integer_or_infinity, NativeResult, ProtoKind, VmHost};
|
||
use oxide_types::object::{JsObject, NativeFnPtr, PropAttributes};
|
||
use oxide_types::private_key::WELL_KNOWN_SYMBOL_COUNT;
|
||
use oxide_types::value::JsValue;
|
||
|
||
use crate::native::NativeFn;
|
||
use crate::vm::Vm;
|
||
|
||
/// `new ShadowRealm()`:建影子 realm(独立 Vm)与实例对象。
|
||
///
|
||
/// # 步骤
|
||
/// 1. 构造形态校验(规范无 `[[Call]]`:非构造调用抛 TypeError)。
|
||
/// 2. 建影子 Vm:复用主 Vm 的 `KernelCore`(共享 intern/shape/code 缓存)并
|
||
/// 注入同一动态编译服务。
|
||
/// 3. 建实例对象:PLAIN 对象,`[[Prototype]]` → ShadowRealm.prototype。
|
||
/// 4. 登记主 Vm 侧表:键 = 影子 realm 编号,值 = (实例对象,影子 Vm)。
|
||
/// 5. 返回实例对象。
|
||
///
|
||
/// # 边界与前提
|
||
/// - 影子 Vm 存主 Vm 侧表、不跨线程:`full_reset` 与 `Drop` 统一清理。
|
||
/// - 实例对象是 GC 根(侧表登记);影子 Vm 堆独立,主 Vm 的 GC 不触达。
|
||
///
|
||
/// # 副作用
|
||
/// - 新建一个影子 Vm(新 session 加全量 builtin world);登记一条侧表条目
|
||
/// (GC 根)。
|
||
pub(crate) fn shadow_realm_constructor(vm: &mut Vm, _args: &[u8]) -> NativeResult {
|
||
// 构造形态校验(规范只有 [[Construct]])。
|
||
if !vm.constructing_native {
|
||
return NativeResult::Err(error::create_type_error(vm, "ShadowRealm constructor requires new"));
|
||
}
|
||
|
||
// 建影子 Vm:共享主 Vm 的 KernelCore 与动态编译服务。
|
||
let mut shadow_vm = Vm::with_kernel_core(vm.kernel_core.clone());
|
||
shadow_vm.set_compiler_service(vm.compiler.clone());
|
||
// 属主链:影子 Vm 记录创建它的 Vm,跨 realm 结算沿链上溯解析远端 realm。
|
||
shadow_vm.owner_vm = vm as *mut Vm;
|
||
|
||
// 建实例对象:PLAIN 对象,[[Prototype]] → ShadowRealm.prototype。
|
||
let proto_val = shadow_realm_prototype_value(vm);
|
||
let obj = JsObject::new_empty(EMPTY_SHAPE_ID, proto_val);
|
||
let ptr = vm.alloc_object(obj);
|
||
|
||
// 登记主 Vm 侧表(键 = 影子 realm 编号,值 = 实例对象加影子 Vm)。
|
||
let realm_id = shadow_vm.realm_id() as u64;
|
||
vm.shadow_realm_objects
|
||
.insert(realm_id, (JsValue::from_js_object(ptr), shadow_vm));
|
||
|
||
NativeResult::Ok(JsValue::from_js_object(ptr))
|
||
}
|
||
|
||
/// `ShadowRealm.prototype.evaluate`:在影子 realm 内把 `source` 按普通脚本编译
|
||
/// 执行,结果经跨 realm 结算后返回。
|
||
///
|
||
/// # 步骤
|
||
/// 1. brand 校验(`this` 须是 ShadowRealm 实例)。
|
||
/// 2. `source` 非字符串抛 TypeError(规范只接受 String,不做 ToString)。
|
||
/// 3. 在影子 realm 内把 `source` 编译为普通脚本(编译期 SyntaxError 原样透传)。
|
||
/// 4. 执行脚本(运行期异常包 TypeError)。
|
||
/// 5. 结果结算:原始值直返、函数包装为 WrappedFunction、符号按 realm 重映射、
|
||
/// 非原始非函数抛 TypeError。
|
||
///
|
||
/// # 边界
|
||
/// - 编译期 SyntaxError 透传(规范把编译期异常暴露给调用方 realm)。
|
||
/// - 运行期异常(含影子 realm 内的 TypeError/ReferenceError 与原始值抛出)
|
||
/// 在调用方 realm 包装为 TypeError。
|
||
pub(crate) fn evaluate(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||
if let Err(e) = shadow_realm_brand_check(vm, this_val) {
|
||
return NativeResult::Err(e);
|
||
}
|
||
let realm_id = shadow_realm_id_of(vm, this_val.as_js_object_ptr());
|
||
|
||
// 实参 source(args[1]):非字符串抛 TypeError。
|
||
let source_val = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
let source = match vm.lookup_str(source_val) {
|
||
Some(s) => s,
|
||
None => {
|
||
return NativeResult::Err(error::create_type_error(
|
||
vm,
|
||
"ShadowRealm.prototype.evaluate source must be a string",
|
||
))
|
||
}
|
||
};
|
||
|
||
// 在影子 realm 内编译并执行:编译期 SyntaxError 原样透传,运行期异常包 TypeError。
|
||
let raw_result: Result<JsValue, String> = {
|
||
let shadow_vm = &mut vm.shadow_realm_objects.get_mut(&realm_id).unwrap().1;
|
||
let script = match shadow_vm.create_plain_dynamic_script(&source) {
|
||
Ok(s) => s,
|
||
Err(msg) => return NativeResult::Err(error::create_syntax_error(vm, &msg)),
|
||
};
|
||
let global = shadow_vm.global_object();
|
||
let global_val = JsValue::from_js_object(global.as_ptr() as *mut JsObject);
|
||
shadow_vm.call_function_sync(script, global_val, &[])
|
||
};
|
||
let value = match raw_result {
|
||
Ok(v) => v,
|
||
Err(_) => return NativeResult::Err(error::create_type_error(vm, "Error evaluating code in ShadowRealm")),
|
||
};
|
||
|
||
// 结果结算:GetWrappedValue(callerRealm, value)。
|
||
match settle_value(vm, vm.realm_id() as u64, realm_id, value) {
|
||
Ok(v) => NativeResult::Ok(v),
|
||
Err(e) => NativeResult::Err(e),
|
||
}
|
||
}
|
||
|
||
/// `ShadowRealm.prototype.importValue`:在影子 realm 内按 `specifier` 解析并加载
|
||
/// 模块文件,编译求值后取 `exportName` 的导出值,以 Promise 结算返回。
|
||
///
|
||
/// # 步骤
|
||
/// 1. brand 校验(`this` 须是 ShadowRealm 实例)。
|
||
/// 2. `ToString(specifier)`(abrupt completion 原值传播);`exportName` 须为
|
||
/// 字符串,非字符串抛 TypeError。
|
||
/// 3. 建 Promise 能力(调用方 realm)。
|
||
/// 4. 在影子 realm 内编译并求值模块(语法错误 / 求值抛错 / 导出缺失均 reject
|
||
/// TypeError)。
|
||
/// 5. 导出值结算(原始值直返、函数包装、符号重映射、对象 reject TypeError)。
|
||
/// 6. 返回 Promise 本体。
|
||
///
|
||
/// # 边界
|
||
/// - 模块解析失败(语法错误)与求值抛错以 TypeError reject。
|
||
/// - 导出值非原始非函数以 TypeError reject。
|
||
pub(crate) fn import_value(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||
if let Err(e) = shadow_realm_brand_check(vm, this_val) {
|
||
return NativeResult::Err(e);
|
||
}
|
||
let realm_id = shadow_realm_id_of(vm, this_val.as_js_object_ptr());
|
||
|
||
// ToString(specifier):abrupt completion 传播原异常。
|
||
let specifier_val = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
let specifier = match oxide_runtime_api::to_string_full(specifier_val, vm) {
|
||
Ok(s) => s,
|
||
Err(e) => {
|
||
let exc = vm.exception_value.take().unwrap_or_else(|| error::create_from_text(vm, &e));
|
||
return NativeResult::Err(exc);
|
||
}
|
||
};
|
||
// exportName 须为字符串(不走 ToString):非字符串抛 TypeError,不触发
|
||
// 目标值的 toString 调用。
|
||
let export_name_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||
let export_name = match vm.lookup_str(export_name_val) {
|
||
Some(s) => s,
|
||
None => {
|
||
return NativeResult::Err(error::create_type_error(
|
||
vm,
|
||
"ShadowRealm.prototype.importValue exportName must be a string",
|
||
))
|
||
}
|
||
};
|
||
|
||
// 建 Promise 能力(调用方 realm)。
|
||
let (promise, _resolve, _reject) = vm.new_promise_capability();
|
||
|
||
// 在影子 realm 内加载并求值模块,取导出值。
|
||
let result = (|| -> Result<JsValue, JsValue> {
|
||
// 解析模块路径(以当前工作目录为基准,test262 runner 以测试目录为工作目录)。
|
||
let current_dir = std::env::current_dir()
|
||
.map_err(|e| error::create_type_error(vm, &format!("cannot get current directory: {e}")))?;
|
||
let module_path = current_dir.join(&specifier);
|
||
let module_path = module_path
|
||
.canonicalize()
|
||
.map_err(|e| error::create_type_error(vm, &format!("cannot resolve module {specifier}: {e}")))?;
|
||
let module_path_str = module_path.to_string_lossy().to_string();
|
||
let source = std::fs::read_to_string(&module_path)
|
||
.map_err(|e| error::create_type_error(vm, &format!("cannot read module {specifier}: {e}")))?;
|
||
|
||
// 追加导出值提取语句(exportName 是模块作用域内的绑定名,追加语句可读)。
|
||
let source_with_result = format!("{source}\nglobalThis.__oxide_import_result = {export_name};");
|
||
|
||
// 编译并求值模块(语法错误 / 求值抛错 → TypeError)。
|
||
let mut loader = ImportValueLoader;
|
||
let module = {
|
||
let shadow_vm = &mut vm.shadow_realm_objects.get_mut(&realm_id).unwrap().1;
|
||
shadow_vm
|
||
.compiler
|
||
.compile_module(&source_with_result, &module_path_str, &mut loader)
|
||
}
|
||
.map_err(|msg| error::create_type_error(vm, &msg))?;
|
||
{
|
||
let shadow_vm = &mut vm.shadow_realm_objects.get_mut(&realm_id).unwrap().1;
|
||
shadow_vm
|
||
.run(&Arc::new(module))
|
||
.map_err(|msg| error::create_type_error(vm, &msg))?;
|
||
}
|
||
|
||
// 读导出值(追加语句在模块求值末执行,导出绑定已初始化)。
|
||
let export_value = {
|
||
let shadow_vm = &mut vm.shadow_realm_objects.get_mut(&realm_id).unwrap().1;
|
||
let global = shadow_vm.global_object();
|
||
let global_ptr = global.as_ptr() as *mut JsObject;
|
||
// SAFETY: global_ptr 是影子 realm 的 global 对象,存活。
|
||
let global_obj = unsafe { &*global_ptr };
|
||
let global_val = JsValue::from_js_object(global_ptr);
|
||
let result_si = shadow_vm.perm_intern("__oxide_import_result");
|
||
shadow_vm.ordinary_get(global_obj, result_si, global_val)
|
||
}
|
||
.map_err(|msg| error::create_type_error(vm, &msg))?;
|
||
|
||
// 导出值结算:GetWrappedValue(callerRealm, exportValue)。
|
||
settle_value(vm, vm.realm_id() as u64, realm_id, export_value)
|
||
})();
|
||
|
||
// 结算 Promise。
|
||
match result {
|
||
Ok(value) => {
|
||
let _ = vm.resolve_promise(promise, value);
|
||
}
|
||
Err(e) => {
|
||
let _ = vm.reject_promise(promise, e);
|
||
}
|
||
}
|
||
NativeResult::Ok(promise)
|
||
}
|
||
|
||
/// WrappedFunction 的 native 函数项:结算 this 与实参、调用属主 realm 原函数、
|
||
/// 结算返回值。
|
||
///
|
||
/// # 步骤
|
||
/// 1. 从 callee 反查状态(原函数属主 realm 编号、保活表下标)。
|
||
/// 2. this 与实参逐个结算进目标 realm(可调用对象包装为内层 WrappedFunction、
|
||
/// 非可调用对象抛 TypeError)。
|
||
/// 3. 调用原函数(经属主 Vm 路由,异常退出包 TypeError)。
|
||
/// 4. 返回值结算进调用方 realm。
|
||
fn wrapped_function_call(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let callee = vm.reg(254);
|
||
let callee_ptr = callee.as_js_object_ptr();
|
||
let (target_realm_id, keepalive_index) = match vm.wrapped_function_state.get(&callee_ptr) {
|
||
Some(state) => *state,
|
||
None => {
|
||
return NativeResult::Err(error::create_type_error(vm, "invalid WrappedFunction"));
|
||
}
|
||
};
|
||
let caller_realm_id = vm.realm_id() as u64;
|
||
|
||
// this 结算:GetWrappedValue(targetRealm, thisArgument)。native 调用协议把
|
||
// receiver 寄存器下标放在实参表首位(`args[0]`,即 253 槽)。
|
||
let this_val = vm.reg(args[0]);
|
||
let settled_this = match settle_value(vm, target_realm_id, caller_realm_id, this_val) {
|
||
Ok(v) => v,
|
||
Err(e) => return NativeResult::Err(e),
|
||
};
|
||
|
||
// 实参逐个结算:GetWrappedValue(targetRealm, arg)。
|
||
let arg_count = vm.native_arg_count(args);
|
||
let mut settled_args = Vec::with_capacity(arg_count);
|
||
for i in 0..arg_count {
|
||
let arg = vm.native_arg_at(args, i);
|
||
match settle_value(vm, target_realm_id, caller_realm_id, arg) {
|
||
Ok(v) => settled_args.push(v),
|
||
Err(e) => return NativeResult::Err(e),
|
||
}
|
||
}
|
||
|
||
// 调用原函数(经属主 Vm 路由,异常退出包 TypeError)。
|
||
let result = {
|
||
let target_vm = resolve_vm(vm, target_realm_id);
|
||
let target_fn = target_vm.shadow_keepalive[keepalive_index];
|
||
target_vm.call_function_sync(target_fn, settled_this, &settled_args)
|
||
};
|
||
let value = match result {
|
||
Ok(v) => v,
|
||
Err(_) => return NativeResult::Err(error::create_type_error(vm, "Error calling wrapped function")),
|
||
};
|
||
|
||
// 返回值结算:GetWrappedValue(callerRealm, result)。
|
||
match settle_value(vm, caller_realm_id, target_realm_id, value) {
|
||
Ok(v) => NativeResult::Ok(v),
|
||
Err(e) => NativeResult::Err(e),
|
||
}
|
||
}
|
||
|
||
/// 按 realm 编号解析属主 Vm:自身、直接子影子 realm,或沿属主链上溯。
|
||
///
|
||
/// # 边界与前提
|
||
/// - `realm_id` 从 `vm` 可达(自身、子影子 realm 或属主链祖先):状态表只登记
|
||
/// 可达 realm 编号,前提恒成立。
|
||
/// - 目标 Vm 与 `vm` 同线程且非当前执行中(调用方在 `vm` 的 native 调用内),
|
||
/// 返回的 `&mut` 安全。
|
||
fn resolve_vm(vm: &mut Vm, realm_id: u64) -> &mut Vm {
|
||
if vm.realm_id() as u64 == realm_id {
|
||
return vm;
|
||
}
|
||
if let Some(entry) = vm.shadow_realm_objects.get_mut(&realm_id) {
|
||
return &mut entry.1;
|
||
}
|
||
// 沿属主链上溯(影子 Vm → 属主 Vm → … → 主 Vm)。
|
||
let mut cur = vm.owner_vm;
|
||
while !cur.is_null() {
|
||
// SAFETY: 属主 Vm 与 vm 同线程存活且非当前执行中。
|
||
let owner = unsafe { &mut *cur };
|
||
if owner.realm_id() as u64 == realm_id {
|
||
return owner;
|
||
}
|
||
if let Some(entry) = owner.shadow_realm_objects.get_mut(&realm_id) {
|
||
return &mut entry.1;
|
||
}
|
||
cur = owner.owner_vm;
|
||
}
|
||
panic!("ShadowRealm: realm {realm_id} 不可从属主链解析")
|
||
}
|
||
|
||
/// 跨 realm 值结算:GetWrappedValue 语义(包装在 `wrapper_realm_id` realm,
|
||
/// 原函数属主在 `target_realm_id` realm)。
|
||
///
|
||
/// # 边界
|
||
/// - 可调用对象:包装为 `wrapper_realm_id` realm 的 WrappedFunction,原函数在
|
||
/// `target_realm_id` realm 的 Vm 保活表保活。
|
||
/// - 非可调用对象:抛 TypeError。
|
||
/// - 符号:按 realm 重映射(well-known 同下标、注册表符号按 key 复用 / 新建、
|
||
/// 普通符号按描述新建)。
|
||
/// - 其余原始值:直返。
|
||
fn settle_value(vm: &mut Vm, wrapper_realm_id: u64, target_realm_id: u64, value: JsValue) -> Result<JsValue, JsValue> {
|
||
if value.is_object() {
|
||
if oxide_builtins::iterator::is_callable(value) {
|
||
return settle_function(vm, wrapper_realm_id, target_realm_id, value);
|
||
}
|
||
return Err(error::create_type_error(vm, "ShadowRealm: cannot return non-primitive value"));
|
||
}
|
||
if value.is_symbol() {
|
||
return settle_symbol(vm, wrapper_realm_id, target_realm_id, value);
|
||
}
|
||
Ok(value)
|
||
}
|
||
|
||
/// 函数结算:WrappedFunctionCreate(wrapper_realm, target)。
|
||
///
|
||
/// # 步骤
|
||
/// 1. 目标侧:原函数入属主 Vm 保活表、读 name / length(getter 抛错包 TypeError)。
|
||
/// 2. 包装侧:计算 name / length、建函数对象、登记状态表。
|
||
fn settle_function(
|
||
vm: &mut Vm, wrapper_realm_id: u64, target_realm_id: u64, target_fn: JsValue,
|
||
) -> Result<JsValue, JsValue> {
|
||
// 目标侧:保活原函数、读 name / length。
|
||
let (keepalive_index, name_result, length_result, has_own_length) = {
|
||
let target_vm = resolve_vm(vm, target_realm_id);
|
||
let keepalive_index = target_vm.shadow_keepalive.len();
|
||
target_vm.shadow_keepalive.push(target_fn);
|
||
let target_ptr = target_fn.as_js_object_ptr();
|
||
// SAFETY: target_fn 是属主 Vm 的函数对象,存活。
|
||
let target_obj = unsafe { &*target_ptr };
|
||
let name_si = target_vm.perm_intern("name");
|
||
let length_si = target_vm.perm_intern("length");
|
||
// HasOwnProperty 代理感知:getOwnPropertyDescriptor trap 可抛(撤销代理
|
||
// 或抛错 trap),抛错包 TypeError(规范:CopyNameAndLength abrupt 抛 TypeError)。
|
||
let has_own_length = match oxide_builtins::object::own_descriptor_of(target_vm, target_obj, length_si) {
|
||
Ok(Some(_)) => true,
|
||
Ok(None) => false,
|
||
Err(_) => return Err(error::create_type_error(vm, "ShadowRealm: error checking function length")),
|
||
};
|
||
let name_result = target_vm.ordinary_get(target_obj, name_si, target_fn);
|
||
let length_result = if has_own_length {
|
||
target_vm.ordinary_get(target_obj, length_si, target_fn)
|
||
} else {
|
||
Ok(JsValue::undefined())
|
||
};
|
||
(keepalive_index, name_result, length_result, has_own_length)
|
||
};
|
||
|
||
// getter 抛错包 TypeError(规范:WrappedFunctionCreate 从调用方 realm 抛 TypeError)。
|
||
let target_name = match name_result {
|
||
Ok(v) => v,
|
||
Err(_) => return Err(error::create_type_error(vm, "ShadowRealm: error reading function name")),
|
||
};
|
||
let target_length = match length_result {
|
||
Ok(v) => v,
|
||
Err(_) => return Err(error::create_type_error(vm, "ShadowRealm: error reading function length")),
|
||
};
|
||
|
||
// 计算包装后的 name / length。
|
||
let wrapped_name = {
|
||
let wrapper_vm = resolve_vm(vm, wrapper_realm_id);
|
||
wrapper_vm.lookup_str(target_name).unwrap_or_default()
|
||
};
|
||
let wrapped_length = compute_wrapped_length(target_length, has_own_length);
|
||
|
||
// 包装侧:建 WrappedFunction。
|
||
let wrapper_vm = resolve_vm(vm, wrapper_realm_id);
|
||
Ok(create_wrapped_function(
|
||
wrapper_vm,
|
||
target_realm_id,
|
||
keepalive_index,
|
||
&wrapped_name,
|
||
wrapped_length,
|
||
))
|
||
}
|
||
|
||
/// 符号结算:按 realm 重映射到包装 realm。
|
||
///
|
||
/// # 步骤
|
||
/// 1. 目标侧:读符号描述与注册表 key。
|
||
/// 2. 包装侧:well-known 按同下标、注册表符号按 key 复用 / 新建、
|
||
/// 普通符号按描述新建(不入注册表)。
|
||
fn settle_symbol(vm: &mut Vm, wrapper_realm_id: u64, target_realm_id: u64, value: JsValue) -> Result<JsValue, JsValue> {
|
||
let local_index = value.as_symbol_local_index();
|
||
// 目标侧:读符号描述与注册表 key。
|
||
let (description, registry_key) = {
|
||
let target_vm = resolve_vm(vm, target_realm_id);
|
||
(target_vm.symbol_description(local_index), target_vm.symbol_key_for_id(local_index))
|
||
};
|
||
|
||
// 包装侧:建 / 复用。
|
||
let wrapper_vm = resolve_vm(vm, wrapper_realm_id);
|
||
let wrapper_realm_id = wrapper_vm.realm_id();
|
||
if local_index < WELL_KNOWN_SYMBOL_COUNT {
|
||
// well-known 符号:跨 realm 同下标。
|
||
return Ok(JsValue::symbol_realm(wrapper_realm_id, local_index));
|
||
}
|
||
if let Some(key) = registry_key {
|
||
// 注册表符号:包装 realm 已有则复用,否则新建并登记。
|
||
if let Some(idx) = wrapper_vm.symbol_lookup_global(&key) {
|
||
return Ok(JsValue::symbol_realm(wrapper_realm_id, idx));
|
||
}
|
||
let idx = wrapper_vm.symbol_intern(description);
|
||
wrapper_vm.symbol_register_global(key, idx);
|
||
return Ok(JsValue::symbol_realm(wrapper_realm_id, idx));
|
||
}
|
||
// 普通符号:按描述新建(不入注册表)。
|
||
let idx = wrapper_vm.symbol_intern(description);
|
||
Ok(JsValue::symbol_realm(wrapper_realm_id, idx))
|
||
}
|
||
|
||
/// 建 WrappedFunction:包装 realm 的函数对象(native 函数项),登记状态表。
|
||
///
|
||
/// # 副作用
|
||
/// - 包装 realm 新建函数对象(session 分配);状态表登记一条(GC 根)。
|
||
fn create_wrapped_function(
|
||
vm: &mut Vm, target_realm_id: u64, keepalive_index: usize, name: &str, length: JsValue,
|
||
) -> JsValue {
|
||
let native_fn: NativeFn = wrapped_function_call;
|
||
let fn_proto = vm.realm.session.borrow().builtin_world().fn_proto_val();
|
||
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
|
||
func.set_function(true);
|
||
// SAFETY: wrapped_function_call 是 NativeFn 函数项。
|
||
func.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(native_fn as *const ()) }));
|
||
let ptr = vm.alloc_object(func);
|
||
// SAFETY: alloc_object 返回非空 session 对象指针;借出期间无别名。
|
||
let obj = unsafe { &mut *ptr };
|
||
let attrs = PropAttributes::new(false, false, true);
|
||
let length_si = vm.kernel_core.perm_interner().intern("length").0;
|
||
let name_si = vm.kernel_core.perm_interner().intern("name").0;
|
||
let _ = vm.define_data_property(obj, length_si, length, attrs);
|
||
let name_val = vm.new_string(name);
|
||
let _ = vm.define_data_property(obj, name_si, name_val, attrs);
|
||
vm.wrapped_function_state.insert(ptr, (target_realm_id, keepalive_index));
|
||
JsValue::from_js_object(ptr)
|
||
}
|
||
|
||
/// CopyNameAndLength 的 length 规则:无自身 length 归 0、非 Number 归 0、
|
||
/// +Infinity 归 +Infinity、-Infinity / NaN 归 0、有限数归 max(ToIntegerOrInfinity, 0)。
|
||
fn compute_wrapped_length(target_length: JsValue, has_own_length: bool) -> JsValue {
|
||
if !has_own_length || !target_length.is_number() {
|
||
return JsValue::float(0.0);
|
||
}
|
||
let n = oxide_runtime_api::to_number(target_length);
|
||
if n == f64::INFINITY {
|
||
return JsValue::float(f64::INFINITY);
|
||
}
|
||
if n == f64::NEG_INFINITY || n.is_nan() {
|
||
return JsValue::float(0.0);
|
||
}
|
||
let len = to_integer_or_infinity(target_length);
|
||
JsValue::float(len.max(0.0))
|
||
}
|
||
|
||
/// brand 校验:`this` 须是对象且指针在主 Vm 侧表内(实例对象注册表)。
|
||
fn shadow_realm_brand_check(vm: &mut Vm, this_val: JsValue) -> Result<(), JsValue> {
|
||
if !this_val.is_object() {
|
||
return Err(error::create_type_error(vm, "ShadowRealm method called on non-object"));
|
||
}
|
||
let this_ptr = this_val.as_js_object_ptr();
|
||
let in_table = vm
|
||
.shadow_realm_objects
|
||
.values()
|
||
.any(|(obj, _)| obj.as_js_object_ptr() == this_ptr);
|
||
if !in_table {
|
||
return Err(error::create_type_error(vm, "not a ShadowRealm instance"));
|
||
}
|
||
Ok(())
|
||
}
|
||
|
||
/// 据实例对象指针反查影子 realm 编号(brand 校验已保证存在)。
|
||
fn shadow_realm_id_of(vm: &Vm, this_ptr: *mut JsObject) -> u64 {
|
||
vm.shadow_realm_objects
|
||
.iter()
|
||
.find(|(_, (obj, _))| obj.as_js_object_ptr() == this_ptr)
|
||
.map(|(id, _)| *id)
|
||
.unwrap()
|
||
}
|
||
|
||
/// 读全局 `ShadowRealm` 构造器的 `prototype` 属性(ShadowRealm.prototype)。
|
||
///
|
||
/// # 边界
|
||
/// - 全局 `ShadowRealm` 槽缺失或构造器无 `prototype` 属性时回退到
|
||
/// `%Object.prototype%`(防御性兜底,正常路径 `bind_shadow_realm` 已安装)。
|
||
fn shadow_realm_prototype_value(vm: &mut Vm) -> JsValue {
|
||
let object_proto = JsValue::from_js_object(vm.builtin_proto(ProtoKind::ObjectProto));
|
||
let global = vm.global_object();
|
||
let global_ptr = global.as_ptr() as *mut JsObject;
|
||
// SAFETY: global_ptr 是当前 session 的 global 对象,存活。
|
||
let global_obj = unsafe { &*global_ptr };
|
||
let si_shadow_realm = vm.perm_intern("ShadowRealm");
|
||
let Some(store) = vm.get_own_property_slot(global_obj, si_shadow_realm) else {
|
||
return object_proto;
|
||
};
|
||
let ctor_val = global_obj.get_prop_at(store);
|
||
if !ctor_val.is_object() {
|
||
return object_proto;
|
||
}
|
||
let ctor_ptr = ctor_val.as_js_object_ptr();
|
||
// SAFETY: ctor_ptr 是 ShadowRealm 构造器对象,存活。
|
||
let ctor_obj = unsafe { &*ctor_ptr };
|
||
let si_prototype = vm.perm_intern("prototype");
|
||
let Some(proto_store) = vm.get_own_property_slot(ctor_obj, si_prototype) else {
|
||
return object_proto;
|
||
};
|
||
let proto_val = ctor_obj.get_prop_at(proto_store);
|
||
if proto_val.is_object() {
|
||
proto_val
|
||
} else {
|
||
object_proto
|
||
}
|
||
}
|
||
|
||
/// importValue 的模块加载器:以 `base_dir` 为基准解析相对导入,读磁盘 fixture 源码。
|
||
struct ImportValueLoader;
|
||
|
||
impl oxide_runtime_api::ModuleSourceLoader for ImportValueLoader {
|
||
fn resolve(&mut self, base_dir: &str, specifier: &str) -> Result<(String, String), String> {
|
||
let base = std::path::Path::new(base_dir);
|
||
let full = if specifier.starts_with('/') {
|
||
std::path::PathBuf::from(specifier.trim_start_matches('/'))
|
||
} else {
|
||
base.join(specifier)
|
||
};
|
||
let canonical = full
|
||
.canonicalize()
|
||
.map_err(|e| format!("cannot resolve module {specifier}: {e}"))?;
|
||
let content =
|
||
std::fs::read_to_string(&canonical).map_err(|e| format!("cannot read module {specifier}: {e}"))?;
|
||
Ok((content, canonical.to_string_lossy().to_string()))
|
||
}
|
||
}
|