mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
docs: 改写虚拟机核心域注释并清除英文残留
- error.rs:补 coerce_primitive_bounded / coerce_number/int32/uint32_bounded / checked_object_ptr / raise_error_kind / raise_js_error / raise_type_error / error_message_text / thrown_error_kind 共 10 项文档;@@toPrimitive 英文块译中。 - dispatch_loop.rs:补 dispatch 主循环五段式文档。 - vmhost.rs:property_key_si trait 臂英文块译中(Reflect/Object 不传播键转换异常)。
This commit is contained in:
@@ -55,6 +55,34 @@ macro_rules! binary_arith {
|
||||
}
|
||||
|
||||
impl Vm {
|
||||
/// 主 dispatch 循环:逐指令解码并分派到各 `dispatch_*` 处理器,直到返回、
|
||||
/// 异常逃出或触发步数/分配上限。
|
||||
///
|
||||
/// # 约定
|
||||
/// - 完成值:HALT 与 RETURN 类指令把结果写回寄存器(顶层承载于 `regs[0]`),
|
||||
/// 循环以 `Ok(value)` 返回。
|
||||
/// - 异常:可捕获异常经 `unwind` 改写 pc/寄存器后就地继续;无 handler 时
|
||||
/// 返回 `Err`,异常值由 `last_uncaught_value` 上交调用方。
|
||||
/// - 寄存器镜像槽允许裸读:热点路径直接索引 `self.regs` 取模块 builtin 名集
|
||||
/// 槽,槽值仅在 run/帧入口重载,进入循环前须保证已重载。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. 循环前缓存 `max_steps`/`max_alloc_bytes`,嵌套重入按 hop 计数兜底采样。
|
||||
/// 2. 指令边界采执行期 GC 安全点(仅顶层 `native_call_depth == 0`)。
|
||||
/// 3. 检查步数上限、单 run 分配上限与 pc 越界,超限按错误返回。
|
||||
/// 4. 解码当前指令、递增 pc,按 OpCode 分派到处理器。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 嵌套 dispatch(原生 builtin 重入执行 JS)不推进顶层 `steps`,靠重入
|
||||
/// hop 计数每 64 跳强制一次轻采样兜底分配上限。
|
||||
/// - `pc` 越过 `bytecode.len()` 视为内部错误,返回 `Err`(不抛 JS 异常)。
|
||||
///
|
||||
/// # 副作用
|
||||
/// - 改写 `pc`、寄存器、帧栈与 GC 状态;可能触发字符串/两档 session 收集。
|
||||
///
|
||||
/// # 注意事项
|
||||
/// - GC 安全点不得下移到嵌套 dispatch:调用方寄存器窗口副本存于 inline
|
||||
/// 状态、非 GC 根,此时回收会把调用方 regs 中的活值当死值释放。
|
||||
pub(crate) fn dispatch(&mut self) -> Result<JsValue, String> {
|
||||
// config.max_steps / max_alloc_bytes 逐指令只读且循环内不变:提到循环外,
|
||||
// 免每次经 kernel_core Arc 指针追寻读取(热点内仅有的 config 访问)。
|
||||
|
||||
@@ -11,6 +11,30 @@ use super::{format_error_message, js_error_kind, js_error_kind_name, Vm};
|
||||
use crate::vm_debug;
|
||||
|
||||
impl Vm {
|
||||
/// ToPrimitive 有界版:按规范序把对象转为原始值,失败统一抛 `TypeError`。
|
||||
///
|
||||
/// 对象自身的 `Symbol.toPrimitive` 优先;不存在时按 `prefer_string` 定序尝试
|
||||
/// `toString`/`valueOf`,等价于 OrdinaryToPrimitive。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. 非对象或空指针原样返回。
|
||||
/// 2. 读 `@@toPrimitive`:存在则必须可调用(否则抛 `TypeError`),以
|
||||
/// `"string"`/`"number"` hint 调用;返回对象再抛 `TypeError`。
|
||||
/// 3. 回退方法族:按 hint 顺序试 `toString`/`valueOf`,不可调用者跳过,
|
||||
/// 首个返回非对象的结果即采用。
|
||||
/// 4. 两条路径都不产出原始值时抛 `TypeError`。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - `prefer_string` 为 `true` 时先试 `toString`,否则先试 `valueOf`。
|
||||
/// - 方法调用经 `call_function_sync`;调用错误转 `raise_call_error` 恢复
|
||||
/// 原始异常。
|
||||
///
|
||||
/// # 副作用
|
||||
/// - 执行用户代码(getter / 方法调用),可能抛异常并触发 GC 安全点。
|
||||
///
|
||||
/// # 注意事项
|
||||
/// - 主 dispatch 下就地展开异常;原生 builtin 内部只返回格式化 `Err`,
|
||||
/// 由其调用边界恢复(见 `conversion_error`)。
|
||||
pub(crate) fn coerce_primitive_bounded(&mut self, value: JsValue, prefer_string: bool) -> Result<JsValue, String> {
|
||||
if !value.is_object() {
|
||||
return Ok(value);
|
||||
@@ -21,9 +45,9 @@ impl Vm {
|
||||
return Ok(value);
|
||||
}
|
||||
|
||||
// ECMA-262 §7.1.1 step 1: an exotic obj[Symbol.toPrimitive] takes precedence
|
||||
// over OrdinaryToPrimitive. well-known symbol 键经 property_key_si 映射为
|
||||
// 固定 Symbol 键,读键路径与写键路径一致。
|
||||
// ECMA-262 §7.1.1 step 1:exotic 对象自身的 Symbol.toPrimitive 优先于
|
||||
// OrdinaryToPrimitive。well-known symbol 键经 property_key_si 映射为固定
|
||||
// Symbol 键,读键路径与写键路径一致。
|
||||
let sym_key = {
|
||||
let sym_ptr = self.session.builtin_world().sym_to_primitive.as_ptr() as *mut JsObject;
|
||||
JsValue::from_js_object(sym_ptr)
|
||||
@@ -124,11 +148,13 @@ impl Vm {
|
||||
Err(err.to_string())
|
||||
}
|
||||
|
||||
/// ToNumber 有界版:先按 number hint 做 ToPrimitive,再转 `f64`。
|
||||
pub(crate) fn coerce_number_bounded(&mut self, value: JsValue) -> Result<f64, String> {
|
||||
let primitive = self.coerce_primitive_bounded(value, false)?;
|
||||
Ok(coercion::to_number(primitive))
|
||||
}
|
||||
|
||||
/// ToInt32 有界版:整数直通;其余先 ToNumber,再取模 2^32 后按符号回卷。
|
||||
pub(crate) fn coerce_int32_bounded(&mut self, value: JsValue) -> Result<i32, String> {
|
||||
if value.is_int() {
|
||||
return Ok(value.as_int());
|
||||
@@ -145,6 +171,7 @@ impl Vm {
|
||||
}
|
||||
}
|
||||
|
||||
/// ToUint32 有界版:整数直通;其余先 ToNumber,再取模 2^32。
|
||||
pub(crate) fn coerce_uint32_bounded(&mut self, value: JsValue) -> Result<u32, String> {
|
||||
if value.is_int() {
|
||||
return Ok(value.as_int() as u32);
|
||||
@@ -156,6 +183,13 @@ impl Vm {
|
||||
Ok(n.trunc().rem_euclid(4_294_967_296.0) as u32)
|
||||
}
|
||||
|
||||
/// 校验 `JsValue` 为合法非空对象指针,成功时返回对象裸指针。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 非对象、空指针、地址低于 `0x10000` 或未按 `JsObject` 对齐:抛
|
||||
/// `TypeError`(消息由调用方给出)并返回 `Ok(None)`,调用方据此短路
|
||||
/// (错误已进异常通道,后续由 dispatch 继续展开)。
|
||||
/// - 本函数不做语义检查(可调用/可构造等能力由调用方判定)。
|
||||
pub(crate) fn checked_object_ptr(
|
||||
&mut self, val: JsValue, error_msg: &str,
|
||||
) -> Result<Option<*mut JsObject>, String> {
|
||||
@@ -172,10 +206,17 @@ impl Vm {
|
||||
Ok(Some(ptr))
|
||||
}
|
||||
|
||||
/// 按 kind 名构造 `JsError` 并转 `raise_js_error` 抛出。
|
||||
pub(crate) fn raise_error_kind(&mut self, kind: &'static str, msg: &str) -> Result<(), String> {
|
||||
self.raise_js_error(JsError::new(js_error_kind(kind), msg))
|
||||
}
|
||||
|
||||
/// 构造错误对象、写入异常通道并展开到最近的 try 处理器。
|
||||
///
|
||||
/// - `exception_value` 存错误对象、`pending_error_kind` 存 kind 名,供外围
|
||||
/// try/catch 与错误通道查询。
|
||||
/// - 展开失败(无 handler)时 `unwind` 返回 `Err`,异常逃出 run 边界经
|
||||
/// `last_uncaught_value` 上交调用方。
|
||||
pub(crate) fn raise_js_error(&mut self, err: JsError) -> Result<(), String> {
|
||||
let kind = js_error_kind_name(err.kind);
|
||||
vm_debug!("raise_js_error: {} \"{}\"", kind, err.message);
|
||||
@@ -185,14 +226,20 @@ impl Vm {
|
||||
self.unwind()
|
||||
}
|
||||
|
||||
/// 抛 `TypeError` 的便捷入口,等价于以 kind 名 `"TypeError"` 调
|
||||
/// `raise_error_kind`。
|
||||
pub(crate) fn raise_type_error(&mut self, msg: &str) -> Result<(), String> {
|
||||
self.raise_error_kind("TypeError", msg)
|
||||
}
|
||||
|
||||
/// 格式化错误文本,供原生 builtin 调用边界恢复异常时使用。
|
||||
pub(crate) fn error_message_text(&self, kind: &str, msg: &str) -> String {
|
||||
format_error_message(kind, msg)
|
||||
}
|
||||
|
||||
/// 从异常对象读 `name` 属性并映射为错误 kind 名。
|
||||
///
|
||||
/// 非对象、无 `name`、name 非字符串或未知名称一律回退 `"Error"`。
|
||||
pub(crate) fn thrown_error_kind(&self, val: JsValue) -> &'static str {
|
||||
if !val.is_object() {
|
||||
return "Error";
|
||||
|
||||
@@ -53,9 +53,9 @@ impl oxide_runtime_api::VmHost for Vm {
|
||||
self.last_uncaught_value = value;
|
||||
}
|
||||
fn property_key_si(&mut self, val: JsValue) -> u32 {
|
||||
// Object-key conversion (to_string_full) failures degrade to the empty key here:
|
||||
// this trait path is used by Reflect/Object builtins; computed property access
|
||||
// uses the inherent Result-returning version to preserve the full exception.
|
||||
// 对象键转换(to_string_full)失败时降级为空键:本 trait 路径供
|
||||
// Reflect/Object 内置使用,这些内置按规范不传播键转换异常;计算属性
|
||||
// 访问走返回 Result 的 inherent 版本,转换异常原样保留。
|
||||
self.property_key_si(val)
|
||||
.unwrap_or_else(|_| self.kernel_core.perm_interner().intern("").0)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user