Files
OxideJS-New/crates/oxide_vm/src/vm/vmhost.rs
T

252 lines
10 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! `oxide_runtime_api::VmHost` 委托实现:宿主接口各项委托到 `Vm` 同名固有方法。
use std::sync::Arc;
use oxide_kernel::kernel::{KernelCore, KernelSession};
use oxide_types::mem::Epoch;
use oxide_types::object::{Cell, JsObject, PropAttributes};
use oxide_types::value::JsValue;
use super::Vm;
impl oxide_runtime_api::VmHost for Vm {
fn reg(&self, idx: u8) -> JsValue {
self.reg(idx)
}
fn set_reg(&mut self, idx: u8, val: JsValue) {
self.set_reg(idx, val);
}
fn native_overflow_count(&self) -> usize {
self.native_overflow_count
}
fn native_overflow_at(&self, i: usize) -> JsValue {
self.spill_stack[self.native_overflow_base + i]
}
fn constructing_native(&self) -> bool {
self.constructing_native
}
fn alloc_object(&mut self, obj: JsObject) -> *mut JsObject {
self.alloc_object(obj)
}
fn new_string(&mut self, s: &str) -> JsValue {
self.new_string(s)
}
fn new_string_owned(&mut self, s: String) -> JsValue {
Vm::new_string_owned(self, s)
}
fn new_bigint(&mut self, v: num_bigint::BigInt) -> JsValue {
Vm::new_bigint(self, v)
}
fn bigint_value(&mut self, val: JsValue) -> &num_bigint::BigInt {
Vm::bigint_value(self, val)
}
fn kernel_core(&self) -> &Arc<KernelCore> {
self.kernel_core()
}
fn session(&self) -> &KernelSession {
self.session()
}
fn epoch(&self) -> &Epoch {
self.epoch()
}
fn pc(&self) -> usize {
self.pc
}
fn take_uncaught_value(&mut self) -> Option<JsValue> {
self.last_uncaught_value.take()
}
fn restore_uncaught_value(&mut self, value: Option<JsValue>) {
self.last_uncaught_value = value;
}
fn take_pending_length_exception(&mut self) -> Option<JsValue> {
self.pending_length_exception.take()
}
fn clear_uncaught_value(&mut self) {
self.last_uncaught_value = None;
}
fn move_uncaught_to_pending_length(&mut self) {
self.pending_length_exception = self.last_uncaught_value.take();
}
fn property_key_si(&mut self, val: JsValue) -> u32 {
// 对象键转换(to_string_full)失败时降级为空键:本 trait 路径供不传播
// 键转换异常的内置站点(Object defineProperty/fromEntries/hasOwn、
// 数值串内部键等)使用;按规范须传播异常的站点用返回 Result 的
// `to_property_key_si`,转换异常原样保留。
self.property_key_si(val)
.unwrap_or_else(|_| self.kernel_core.perm_interner().intern("").0)
}
fn to_property_key_si(&mut self, val: JsValue) -> Result<u32, String> {
// ToPropertyKey 完整路径:转换异常(对象 ToPrimitive 抛错 / Symbol 处理)
// 原样返回,供需传播异常的 builtins(groupBy / __defineGetter__ 等)使用。
self.property_key_si(val)
}
fn string_key_si(&mut self, s: &str) -> u32 {
// 与运行时字符串键同口径:含 FFFD 的键文本按 encode_key 形态入键空间
// (FFFD 键的 JSON.parse 键与字面量/拼接构造的运行时键身份一致)。
self.string_key_text(s)
}
fn string_units(&self, val: JsValue) -> std::borrow::Cow<'_, [u16]> {
// SAFETY: 调用方保证 val 为字符串值。perm 串由内核持有永不释放;session
// 串仅经 &mut self 路径(new_string/GC)释放,&self 借用期间编译器强制
// 不存在 &mut 存续,字符串不会在借用期内回收。
unsafe { (*val.as_string_ptr()).units() }
}
fn new_string_units(&mut self, units: &[u16]) -> JsValue {
Vm::new_string_units(self, units)
}
fn new_string_units_owned(&mut self, units: Vec<u16>) -> JsValue {
Vm::new_string_units_owned(self, units)
}
fn resolve_property(&self, obj: &JsObject, prop_name_si: u32) -> Option<JsValue> {
self.resolve_property(obj, prop_name_si)
}
fn has_property(&self, obj: &JsObject, prop_name_si: u32) -> bool {
self.has_property(obj, prop_name_si)
}
fn get_own_property_slot(&self, obj: &JsObject, prop_name_si: u32) -> Option<u32> {
self.get_own_property_slot(obj, prop_name_si)
}
fn ordinary_get(&mut self, obj: &JsObject, prop_name_si: u32, receiver: JsValue) -> Result<JsValue, String> {
self.ordinary_get(obj, prop_name_si, receiver)
}
fn ordinary_set(
&mut self, obj: &mut JsObject, prop_name_si: u32, val: JsValue, receiver: JsValue, strict: bool,
) -> Result<(), String> {
// builtin 调用边界:写失败返回格式化 Err,不就地展开(见 ordinary_set_builtin)。
self.ordinary_set_builtin(obj, prop_name_si, val, receiver, strict)
}
fn define_data_property(
&mut self, obj: &mut JsObject, prop_name_si: u32, val: JsValue, attributes: PropAttributes,
) -> Result<(), String> {
self.define_data_property(obj, prop_name_si, val, attributes)
}
fn define_accessor_property(
&mut self, obj: &mut JsObject, prop_name_si: u32, get: JsValue, set: JsValue, attributes: PropAttributes,
) -> Result<(), String> {
self.define_accessor_property(obj, prop_name_si, get, set, attributes)
}
fn set_or_create_prop_value(&mut self, obj: &mut JsObject, prop_name_si: u32, val: JsValue) {
self.set_or_create_prop_value(obj, prop_name_si, val)
}
fn sync_global_builtin_mirror(&mut self, obj: &JsObject, key_si: u32, val: JsValue) {
self.sync_global_builtin_mirror(obj, key_si, val)
}
fn lookup_str(&self, val: JsValue) -> Option<String> {
self.lookup_str(val)
}
fn coerce_primitive_bounded(&mut self, value: JsValue, prefer_string: bool) -> Result<JsValue, String> {
self.coerce_primitive_bounded(value, prefer_string)
}
fn coerce_number_bounded(&mut self, value: JsValue) -> Result<f64, String> {
self.coerce_number_bounded(value)
}
fn call_function_sync(&mut self, callee: JsValue, receiver: JsValue, args: &[JsValue]) -> Result<JsValue, String> {
self.call_function_sync(callee, receiver, args)
}
fn construct_ctor(&mut self, ctor: JsValue, args: &[JsValue]) -> Result<JsValue, JsValue> {
Vm::construct_ctor(self, ctor, args)
}
fn construct_ctor_nt(&mut self, ctor: JsValue, new_target: JsValue, args: &[JsValue]) -> Result<JsValue, JsValue> {
Vm::construct_with(self, ctor, new_target, args)
}
fn checked_object_ptr(&mut self, val: JsValue, error_msg: &str) -> Result<Option<*mut JsObject>, String> {
self.checked_object_ptr(val, error_msg)
}
fn raise_type_error(&mut self, msg: &str) -> Result<(), String> {
self.raise_type_error(msg)
}
fn raise_captured(&mut self, exc: JsValue) -> Result<(), String> {
self.raise_captured(exc)
}
fn error_message_text(&self, kind: &str, msg: &str) -> String {
self.error_message_text(kind, msg)
}
fn call_stack_function_names(&self) -> Vec<String> {
self.frames
.iter()
.rev()
.map(|f| {
self.kernel_core
.perm_interner()
.lookup(f.function_name)
.unwrap_or("<anonymous>")
.to_string()
})
.collect()
}
fn function_is_strict(&self, obj: &JsObject) -> bool {
// native 函数(sub_module_index == 0)无子模块,callee_module 返回 None,
// 按严格处理(受限访问器对其抛错)。
self.callee_module(obj).map(|m| m.is_strict).unwrap_or(true)
}
fn function_is_restricted(&self, obj: &JsObject) -> bool {
// 严格函数对象,或 [[Prototype]] 为三个动态函数原型之一(生成器 /
// 异步 / 异步生成器函数):caller/arguments 访问一律受限。
if self.function_is_strict(obj) {
return true;
}
let proto = obj.proto();
if !proto.is_object() {
return false;
}
let p = proto.as_js_object_ptr() as *const JsObject;
std::ptr::eq(p, self.generator_function_proto.as_ptr())
|| std::ptr::eq(p, self.async_function_proto.as_ptr())
|| std::ptr::eq(p, self.async_generator_function_proto.as_ptr())
}
fn promote_if_needed_for_write_ptr(&mut self, _target_ptr: *mut JsObject, value: JsValue) -> JsValue {
value
}
fn step_rng(&mut self) {
self.step_rng()
}
fn math_rng_value(&self) -> f64 {
self.math_rng_value()
}
fn sub_module_function_name(&self, gen: u32, sub_idx: u16) -> String {
self.tables
.get(&gen)
.and_then(|t| t.modules.get(sub_idx as usize))
.and_then(|m| m.function_name.clone())
.unwrap_or_default()
}
fn module_frame_cell(&self, cell_idx: u32) -> Option<*mut Cell> {
self.cell_stack
.last()
.and_then(|cells| cells.get(cell_idx as usize).copied())
.filter(|p| !p.is_null())
}
fn create_dynamic_function(
&mut self, params: &[String], body: &str, is_generator: bool, is_async: bool,
) -> Result<JsValue, String> {
self.create_dynamic_function(params, body, is_generator, is_async)
}
fn create_dynamic_script(&mut self, code: &str) -> Result<JsValue, String> {
self.create_dynamic_script(code)
}
fn symbol_intern(&mut self, desc: Option<String>) -> u32 {
self.symbols.intern(desc)
}
fn symbol_description(&self, idx: u32) -> Option<&str> {
self.symbols.description(idx)
}
fn symbol_lookup_global(&self, key: &str) -> Option<u32> {
self.symbols.lookup_global(key)
}
fn symbol_register_global(&mut self, key: String, idx: u32) {
self.symbols.register_global(key, idx)
}
fn symbol_key_for_id(&self, idx: u32) -> Option<String> {
self.symbols.key_for_id(idx)
}
fn atomics_new_waiter_promise(&mut self) -> JsValue {
self.atomics_new_waiter_promise()
}
fn atomics_register_waiter(&mut self, buffer: *mut JsObject, offset: usize, promise: JsValue) {
self.atomics_register_waiter(buffer, offset, promise)
}
fn atomics_wake_waiters(&mut self, buffer: *mut JsObject, offset: usize, count: f64) -> usize {
self.atomics_wake_waiters(buffer, offset, count)
}
}