style: 全 workspace 格式订正,消除 fmt 漂移

This commit is contained in:
2026-10-09 23:58:34 +00:00
parent dbdc5556c6
commit c7f7588b81
23 changed files with 172 additions and 218 deletions
+1 -2
View File
@@ -191,8 +191,7 @@ pub(crate) fn unit_string_value<H: VmHost>(vm: &mut H, unit: u16) -> JsValue {
pub(crate) fn arraylike_index_present<H: VmHost>(vm: &mut H, ptr: *mut JsObject, i: usize) -> bool {
// SAFETY: ptr 来自 this/参数对象,指向存活对象。
let key_si = vm.string_key_si(&i.to_string());
vm.has_property(unsafe { &*ptr }, key_si)
.unwrap_or(false)
vm.has_property(unsafe { &*ptr }, key_si).unwrap_or(false)
}
/// 元素读取失败时直接把异常作为 NativeResult::Err 返回。
+1 -9
View File
@@ -1042,15 +1042,7 @@ pub fn date_set_year<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let full_year = if (0..=99).contains(&y_int) { y_int + 1900 } else { y_int };
finish_local_setter(
obj,
make_local_timestamp(
full_year as f64,
dm as f64,
dd as f64,
dh as f64,
dmin as f64,
dsec as f64,
dms as f64,
),
make_local_timestamp(full_year as f64, dm as f64, dd as f64, dh as f64, dmin as f64, dsec as f64, dms as f64),
)
}
+2 -9
View File
@@ -23,11 +23,7 @@ fn escape_units(input: &[u16]) -> Vec<u16> {
continue;
}
// 转义序列恒为全 ASCII,按码元推入。
let text = if u <= 0xFF {
format!("%{u:02X}")
} else {
format!("%u{u:04X}")
};
let text = if u <= 0xFF { format!("%{u:02X}") } else { format!("%u{u:04X}") };
out.extend(text.encode_utf16());
}
out
@@ -42,10 +38,7 @@ fn unescape_units(input: &[u16]) -> Vec<u16> {
while i < input.len() {
if input[i] == b'%' as u16 {
// %uXXXX:后跟 4 位十六进制。
if i + 6 <= input.len()
&& input[i + 1] == b'u' as u16
&& (2..6).all(|k| hex_val(input[i + k]).is_some())
{
if i + 6 <= input.len() && input[i + 1] == b'u' as u16 && (2..6).all(|k| hex_val(input[i + k]).is_some()) {
let v = (0..4).fold(0u16, |acc, k| acc * 16 + hex_val(input[i + 2 + k]).unwrap());
out.push(v);
i += 6;
+2 -7
View File
@@ -946,8 +946,7 @@ pub fn module_defer_object<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let fn_val = vm.reg(args[1]);
let ns_val = vm.reg(args[2]);
// fn 为函数或 undefined(哨兵);其余抛 TypeError。
let fn_is_function = fn_val.is_object()
&& {
let fn_is_function = fn_val.is_object() && {
let ptr = fn_val.as_js_object_ptr();
!ptr.is_null() && unsafe { (*ptr).is_function() }
};
@@ -1165,11 +1164,7 @@ mod tests {
// 再收集一次:若 error 边漏登,err 被回收、计数回落。
vm.collect_session_gc();
assert_eq!(
vm.session_object_count(),
steady_count,
"失败缓存错误应跨收集存活(GC 边已登记)"
);
assert_eq!(vm.session_object_count(), steady_count, "失败缓存错误应跨收集存活(GC 边已登记)");
// 原地 sweep 不搬移:ns 与状态盒原地保留,error 指针稳定。
let ns_obj = unsafe { &*ns_val.as_js_object_ptr() };
let state = deferred_state(ns_obj).expect("deferred state 应存活");
+8 -2
View File
@@ -842,12 +842,18 @@ pub fn regexp_compile<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
return NativeResult::Err(crate::error::create_type_error(vm, "null object"));
}
if !unsafe { &*this_ptr }.is_regexp_obj() {
return NativeResult::Err(crate::error::create_type_error(vm, "RegExp.prototype.compile called on non-RegExp object"));
return NativeResult::Err(crate::error::create_type_error(
vm,
"RegExp.prototype.compile called on non-RegExp object",
));
}
// proto 精确恒等:子类实例(proto = 子类 prototype)抛 TypeError。
let proto_ptr = vm.builtin_proto(ProtoKind::RegExpProto);
if unsafe { &*this_ptr }.proto() != JsValue::from_js_object(proto_ptr) {
return NativeResult::Err(crate::error::create_type_error(vm, "RegExp.prototype.compile called on subclass instance"));
return NativeResult::Err(crate::error::create_type_error(
vm,
"RegExp.prototype.compile called on subclass instance",
));
}
// 第 2 / 3 步:pattern / flags 取参。
@@ -914,80 +914,57 @@ fn test_filter_boxed_string_this() {
// 引擎钉:reduce 装箱串 this——从左到右累计,初值空串。
#[test]
fn test_reduce_boxed_string_this() {
let out = eval_str(
"(() => { return Array.prototype.reduce.call('ab', (a, b) => a + b, ''); })()",
)
.unwrap();
let out = eval_str("(() => { return Array.prototype.reduce.call('ab', (a, b) => a + b, ''); })()").unwrap();
assert_eq!(out, "ab");
}
// 引擎钉:reduceRight 装箱串 this——从右到左累计。
#[test]
fn test_reduce_right_boxed_string_this() {
let out = eval_str(
"(() => { return Array.prototype.reduceRight.call('ab', (a, b) => a + b, ''); })()",
)
.unwrap();
let out = eval_str("(() => { return Array.prototype.reduceRight.call('ab', (a, b) => a + b, ''); })()").unwrap();
assert_eq!(out, "ba");
}
// 引擎钉:find 装箱串 this——返回首个真值单元。
#[test]
fn test_find_boxed_string_this() {
let out = eval_str(
"(() => { return Array.prototype.find.call('ab', c => c === 'b'); })()",
)
.unwrap();
let out = eval_str("(() => { return Array.prototype.find.call('ab', c => c === 'b'); })()").unwrap();
assert_eq!(out, "b");
}
// 引擎钉:findIndex 装箱串 this——返回首个真值下标。
#[test]
fn test_find_index_boxed_string_this() {
let out = eval_str(
"(() => { return String(Array.prototype.findIndex.call('ab', c => c === 'a')); })()",
)
.unwrap();
let out = eval_str("(() => { return String(Array.prototype.findIndex.call('ab', c => c === 'a')); })()").unwrap();
assert_eq!(out, "0");
}
// 引擎钉:findLast 装箱串 this——返回末个真值单元。
#[test]
fn test_find_last_boxed_string_this() {
let out = eval_str(
"(() => { return Array.prototype.findLast.call('ab', c => c === 'b'); })()",
)
.unwrap();
let out = eval_str("(() => { return Array.prototype.findLast.call('ab', c => c === 'b'); })()").unwrap();
assert_eq!(out, "b");
}
// 引擎钉:findLastIndex 装箱串 this——返回末个真值下标。
#[test]
fn test_find_last_index_boxed_string_this() {
let out = eval_str(
"(() => { return String(Array.prototype.findLastIndex.call('ab', c => c === 'b')); })()",
)
.unwrap();
let out =
eval_str("(() => { return String(Array.prototype.findLastIndex.call('ab', c => c === 'b')); })()").unwrap();
assert_eq!(out, "1");
}
// 引擎钉:some 装箱串 this——任一单元真值即 true。
#[test]
fn test_some_boxed_string_this() {
let out = eval_str(
"(() => { return String(Array.prototype.some.call('ab', c => c === 'b')); })()",
)
.unwrap();
let out = eval_str("(() => { return String(Array.prototype.some.call('ab', c => c === 'b')); })()").unwrap();
assert_eq!(out, "true");
}
// 引擎钉:every 装箱串 this——全单元真值才 true。
#[test]
fn test_every_boxed_string_this() {
let out = eval_str(
"(() => { return String(Array.prototype.every.call('ab', c => c !== 'x')); })()",
)
.unwrap();
let out = eval_str("(() => { return String(Array.prototype.every.call('ab', c => c !== 'x')); })()").unwrap();
assert_eq!(out, "true");
}
+1 -4
View File
@@ -974,10 +974,7 @@ impl CompileCtx {
) -> IRFunction {
// 编译期不变式:每个 DISPOSE_MARK 都有配对的 DISPOSE_POP,函数体收尾
// 释放作用域全部关闭(早 return 跳过 POP 归穿越面,不在此列)。
debug_assert!(
self.labels.dispose_depth == 0,
"函数体收尾释放作用域深度须归零(mark/pop 未配对)"
);
debug_assert!(self.labels.dispose_depth == 0, "函数体收尾释放作用域深度须归零(mark/pop 未配对)");
let upvalue_captures = self
.current_upvalue_captures
.iter()
+2 -1
View File
@@ -120,7 +120,8 @@ impl Emitter {
// 被捕获参数经 visible_cell 回退命中 CELL_GET,判定后置即漏判。
if ctx.param_tdz_names.contains(name) {
let _ = self.emit_tdz_throw(&format!("Cannot access '{name}' before initialization"), ctx);
} else if let Some((uv_idx, _)) = ctx.current_upvalue_captures.iter().enumerate().find(|(_, u)| u.name == name) {
} else if let Some((uv_idx, _)) = ctx.current_upvalue_captures.iter().enumerate().find(|(_, u)| u.name == name)
{
ctx.inst(Inst::new(
OpCode::LOAD_UPVALUE,
Operand::Reg(result_reg),
+15 -14
View File
@@ -163,8 +163,8 @@ impl Emitter {
/// 编译函数体并显式指定生成器标志(`function*` 走此入口)。
pub(crate) fn compile_generator_body<'a>(
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
own_strict: bool, name: Option<&str>,
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx, own_strict: bool,
name: Option<&str>,
) -> Result<IRFunction, String> {
self.compile_function_body_with_flags(
param_specs,
@@ -183,11 +183,19 @@ impl Emitter {
/// 同时标记 `is_generator` 与 `is_async`,VM 调用时按异步生成器协议执行
/// (next 返回 Promise,yield 挂起与 await 挂起共存)。
pub(crate) fn compile_async_generator_body<'a>(
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
own_strict: bool, name: Option<&str>,
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx, own_strict: bool,
name: Option<&str>,
) -> Result<IRFunction, String> {
self.compile_function_body_with_flags(
param_specs, body_stmts, parent_ctx, false, false, true, true, own_strict, name,
param_specs,
body_stmts,
parent_ctx,
false,
false,
true,
true,
own_strict,
name,
)
}
@@ -300,8 +308,7 @@ impl Emitter {
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
is_expression_body: bool, extra_bindings: &[(&str, u32)], body_context: FunctionBodyContext,
mut emit_fields: Option<E>, fields_after_super: bool, extra_capture_exprs: &[&'a Expression<'a>],
extra_upvalue_names: &[(&str, u8)], is_generator: bool, is_async: bool, own_strict: bool,
name: Option<&str>,
extra_upvalue_names: &[(&str, u8)], is_generator: bool, is_async: bool, own_strict: bool, name: Option<&str>,
) -> Result<IRFunction, String>
where
E: FnMut(&Emitter, &mut CompileCtx) -> Result<(), String>,
@@ -708,13 +715,7 @@ impl Emitter {
|| (fn_name == "arguments" && arguments_reg.is_some());
if !suppressed {
let reg = ctx.alloc_reg();
ctx.scopes
.symbols
.scopes
.last_mut()
.expect("函数作用域已压入")
.bindings
.insert(
ctx.scopes.symbols.scopes.last_mut().expect("函数作用域已压入").bindings.insert(
fn_name.to_string(),
Binding {
reg,
+7 -7
View File
@@ -24,8 +24,7 @@ use oxide_ir::operand::Operand;
use oxide_ir::{IRFunction, ParamLayout};
use oxide_parser::{
BindingPattern, Declaration, ExportDefaultDeclarationKind, Expression, ImportAttributeKey,
ImportDeclarationSpecifier, ImportPhase, ModuleExportName, Statement, VariableDeclarationKind,
WithClause,
ImportDeclarationSpecifier, ImportPhase, ModuleExportName, Statement, VariableDeclarationKind, WithClause,
};
use oxide_types::MODULE_NAMESPACE_BINDING;
@@ -501,9 +500,11 @@ impl Emitter {
_ => continue,
};
let is_new = !phase_map.contains_key(&spec);
let entry = phase_map
.entry(spec.clone())
.or_insert_with(|| DepPhase { eager: false, defer: false, attrs });
let entry = phase_map.entry(spec.clone()).or_insert_with(|| DepPhase {
eager: false,
defer: false,
attrs,
});
if is_new {
defer_order.push(spec.clone());
}
@@ -772,8 +773,7 @@ impl Emitter {
);
}
let bind_reg = if is_defer {
*ctx
.module_defer_ns_regs
*ctx.module_defer_ns_regs
.get(&dep_spec)
.ok_or_else(|| format!("module dependency missing: {dep_spec}"))?
} else {
@@ -87,8 +87,9 @@ impl Emitter {
pub(crate) fn emit_continue_statement(
&self, stmt: &oxide_parser::ContinueStatement, ctx: &mut CompileCtx,
) -> Result<Option<u32>, String> {
let (continue_label, fd_at_open, fod_at_open, fid_at_open, dd_at_open, target_v_reg) =
if let Some(label) = &stmt.label {
let (continue_label, fd_at_open, fod_at_open, fid_at_open, dd_at_open, target_v_reg) = if let Some(label) =
&stmt.label
{
let name = label.name.as_str();
let scope = ctx
.find_label(name)
@@ -6,8 +6,7 @@ use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_parser::{
BindingPattern, ForStatementInit, ForStatementLeft, Statement, VariableDeclaration,
VariableDeclarationKind,
BindingPattern, ForStatementInit, ForStatementLeft, Statement, VariableDeclaration, VariableDeclarationKind,
};
impl Emitter {
@@ -137,9 +136,7 @@ impl Emitter {
/// using/await using 声明登记释放栈:把资源值(val_reg)压入释放栈。非
/// using/await using 声明不登记。a 槽为释放提示(0 = 同步、1 = 异步)。
pub(crate) fn emit_dispose_register(
&self, val_reg: u32, kind: VariableDeclarationKind, ctx: &mut CompileCtx,
) {
pub(crate) fn emit_dispose_register(&self, val_reg: u32, kind: VariableDeclarationKind, ctx: &mut CompileCtx) {
if !matches!(kind, VariableDeclarationKind::Using | VariableDeclarationKind::AwaitUsing) {
return;
}
+1 -4
View File
@@ -446,10 +446,7 @@ fn ancestor_defer_back_edge_sentinel() {
let (ir, _) = emit_module(
main_src,
"./main.js",
&[
("./main.js", ModuleKind::Js, main_src),
("./dep.js", ModuleKind::Js, dep_src),
],
&[("./main.js", ModuleKind::Js, main_src), ("./dep.js", ModuleKind::Js, dep_src)],
)
.expect("祖先 defer 回边应编译成功");
// main:1 个 eager 依赖(dep)求值。
+32 -8
View File
@@ -574,9 +574,8 @@ impl Vm {
/// 续 dispatch 并结算:运行 body 到下一个 AWAIT/RETURN/异常,挂起则快照新状态,
/// 完成/异常则结算 capability。恢复调用方状态。
fn dispatch_and_finish_async(
&mut self, state_ptr: *mut AsyncState, saved: Box<InlineSyncState>,
prev_ctx: Option<JsValue>, prev_dispatch: bool, prev_gen_ctx: Option<JsValue>,
prev_gen_dispatch: bool,
&mut self, state_ptr: *mut AsyncState, saved: Box<InlineSyncState>, prev_ctx: Option<JsValue>,
prev_dispatch: bool, prev_gen_ctx: Option<JsValue>, prev_gen_dispatch: bool,
) -> Result<(), String> {
let result = self.dispatch();
if std::mem::take(&mut self.async_suspended) {
@@ -695,7 +694,12 @@ impl Vm {
return Ok(());
}
self.dispatch_and_finish_async(
state_ptr, saved, prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch,
state_ptr,
saved,
prev_ctx,
prev_dispatch,
prev_gen_ctx,
prev_gen_dispatch,
)
}
DisposeResumeKind::Unwind(handler) => {
@@ -712,7 +716,12 @@ impl Vm {
return Ok(());
}
self.dispatch_and_finish_async(
state_ptr, saved, prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch,
state_ptr,
saved,
prev_ctx,
prev_dispatch,
prev_gen_ctx,
prev_gen_dispatch,
)
}
DisposeResumeKind::Escape(completion_val) => {
@@ -727,7 +736,12 @@ impl Vm {
return Ok(());
}
self.dispatch_and_finish_async(
state_ptr, saved, prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch,
state_ptr,
saved,
prev_ctx,
prev_dispatch,
prev_gen_ctx,
prev_gen_dispatch,
)
} else {
// 无合并错误:执行完成。
@@ -742,13 +756,23 @@ impl Vm {
return Ok(());
}
self.dispatch_and_finish_async(
state_ptr, saved, prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch,
state_ptr,
saved,
prev_ctx,
prev_dispatch,
prev_gen_ctx,
prev_gen_dispatch,
)
}
Completion::Break { target_pc, .. } | Completion::Continue { target_pc, .. } => {
self.pc = target_pc;
self.dispatch_and_finish_async(
state_ptr, saved, prev_ctx, prev_dispatch, prev_gen_ctx, prev_gen_dispatch,
state_ptr,
saved,
prev_ctx,
prev_dispatch,
prev_gen_ctx,
prev_gen_dispatch,
)
}
}
+15 -15
View File
@@ -1,8 +1,8 @@
use std::sync::Arc;
use crate::bindings::{
apply_binding_table, bind_accessor_getter, bind_accessor_getset, bind_accessor_getter_key,
bind_well_known_method, configure_native_constructor,
apply_binding_table, bind_accessor_getset, bind_accessor_getter, bind_accessor_getter_key, bind_well_known_method,
configure_native_constructor,
};
use oxide_kernel::kernel::{KernelCore, KernelSession};
use oxide_types::object::JsObject;
@@ -50,16 +50,7 @@ pub fn bind_regexp(core: &Arc<KernelCore>, session: &KernelSession, global: &mut
let sf = core.perm_interner().as_ref();
let mut bind_getset = |name: &str, getter: *const (), setter: *const ()| {
let key = sf.intern(name).0;
bind_accessor_getset(
core,
session,
ctor,
key,
&format!("get {name}"),
&format!("set {name}"),
getter,
setter,
);
bind_accessor_getset(core, session, ctor, key, &format!("get {name}"), &format!("set {name}"), getter, setter);
};
// input/$_:get+set 对(唯一带 setter 的遗留访问器)。
bind_getset(
@@ -74,9 +65,15 @@ pub fn bind_regexp(core: &Arc<KernelCore>, session: &KernelSession, global: &mut
);
// 其余 18 个 getter(set 恒 undefined)。
for (name, getter) in [
("lastMatch", oxide_builtins::regexp::regexp_legacy_get_last_match::<crate::vm::Vm> as *const ()),
(
"lastMatch",
oxide_builtins::regexp::regexp_legacy_get_last_match::<crate::vm::Vm> as *const (),
),
("$&", oxide_builtins::regexp::regexp_legacy_get_last_match::<crate::vm::Vm> as *const ()),
("lastParen", oxide_builtins::regexp::regexp_legacy_get_last_paren::<crate::vm::Vm> as *const ()),
(
"lastParen",
oxide_builtins::regexp::regexp_legacy_get_last_paren::<crate::vm::Vm> as *const (),
),
("$+", oxide_builtins::regexp::regexp_legacy_get_last_paren::<crate::vm::Vm> as *const ()),
(
"leftContext",
@@ -87,7 +84,10 @@ pub fn bind_regexp(core: &Arc<KernelCore>, session: &KernelSession, global: &mut
"rightContext",
oxide_builtins::regexp::regexp_legacy_get_right_context::<crate::vm::Vm> as *const (),
),
("$'", oxide_builtins::regexp::regexp_legacy_get_right_context::<crate::vm::Vm> as *const ()),
(
"$'",
oxide_builtins::regexp::regexp_legacy_get_right_context::<crate::vm::Vm> as *const (),
),
("index", oxide_builtins::regexp::regexp_legacy_get_index::<crate::vm::Vm> as *const ()),
("$1", oxide_builtins::regexp::regexp_legacy_get_dollar_1::<crate::vm::Vm> as *const ()),
("$2", oxide_builtins::regexp::regexp_legacy_get_dollar_2::<crate::vm::Vm> as *const ()),
+5 -16
View File
@@ -45,11 +45,7 @@ pub fn bind_worker(core: &Arc<KernelCore>, session: &KernelSession, global: &mut
let function_proto = world.function_proto.as_ptr() as *mut JsObject;
let mut ctor = JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(function_proto));
ctor.set_function(true);
configure_native_constructor(
&mut ctor,
crate::worker::bindings::worker_constructor as *const (),
1,
);
configure_native_constructor(&mut ctor, crate::worker::bindings::worker_constructor as *const (), 1);
let ptr = Box::into_raw(Box::new(ctor));
world.track_leaked_object(ptr);
ptr
@@ -63,7 +59,8 @@ pub fn bind_worker(core: &Arc<KernelCore>, session: &KernelSession, global: &mut
if sh.lookup_position(ctor.shape_id(), si_name).is_none() {
let shape = sh.make_shape(ctor.shape_id(), si_name);
ctor.set_shape_id(shape);
ctor.ensure_hash_props().push(JsValue::perm_string(sf.string_ptr(sf.intern("Worker").0)));
ctor.ensure_hash_props()
.push(JsValue::perm_string(sf.string_ptr(sf.intern("Worker").0)));
let pos = ctor.hash_props_vec().map_or(0, |v| v.len() as u32).saturating_sub(1);
ctor.set_data_meta(pos, PropAttributes::new(false, false, true));
ctor.bump_generation();
@@ -116,11 +113,7 @@ pub fn bind_worker(core: &Arc<KernelCore>, session: &KernelSession, global: &mut
proto,
core,
&[
(
"postMessage",
crate::worker::bindings::worker_post_message as *const (),
1,
),
("postMessage", crate::worker::bindings::worker_post_message as *const (), 1),
("terminate", crate::worker::bindings::worker_terminate as *const (), 0),
],
);
@@ -147,11 +140,7 @@ pub fn bind_worker(core: &Arc<KernelCore>, session: &KernelSession, global: &mut
global,
core,
&[
(
"postMessage",
crate::worker::bindings::self_post_message as *const (),
1,
),
("postMessage", crate::worker::bindings::self_post_message as *const (), 1),
("close", crate::worker::bindings::self_close as *const (), 0),
],
);
+2 -2
View File
@@ -56,8 +56,6 @@ pub mod bind_shared_array_buffer;
pub mod bind_string;
/// 未实现内置(Proxy/BigInt/WeakMap 等)的 stub 构造器绑定。
pub mod bind_stubs;
/// Worker 构造器绑定(Box 分配,不占 BuiltinWorld P 字段)。
pub mod bind_worker;
/// Symbol 构造器与原型的 native 方法绑定。
pub mod bind_symbol;
/// Temporal 命名空间对象(Now/Instant/PlainDate/PlainTime)绑定。
@@ -66,6 +64,8 @@ pub mod bind_temporal;
pub mod bind_typed_array;
/// WeakMap 构造器与原型四方法的 native 绑定(弱族不占 BuiltinWorld 槽)。
pub mod bind_weak;
/// Worker 构造器绑定(Box 分配,不占 BuiltinWorld P 字段)。
pub mod bind_worker;
use std::sync::Arc;
+9 -13
View File
@@ -1,6 +1,6 @@
use crate::vm::{
Completion, DisposeResumeKind, ForInIter, FrameArgs, FrameContinuation, PendingAsyncDispose,
TryHandler, Vm, MAX_PROTO_CHAIN_DEPTH,
Completion, DisposeResumeKind, ForInIter, FrameArgs, FrameContinuation, PendingAsyncDispose, TryHandler, Vm,
MAX_PROTO_CHAIN_DEPTH,
};
use crate::vm_trace;
use oxide_builtins::iterator::is_callable;
@@ -817,18 +817,14 @@ impl Vm {
/// 异常穿越释放:逆序释放 `depth` 以上资源。在途异常作 completion 种子(被折叠
/// 进 suppressed)。挂起时携 `Unwind(handler)`(handler 已弹出,恢复时重压再入
/// unwind)。
pub(crate) fn dispose_above(
&mut self, depth: usize, handler: Option<TryHandler>,
) -> Result<DisposePhase, String> {
pub(crate) fn dispose_above(&mut self, depth: usize, handler: Option<TryHandler>) -> Result<DisposePhase, String> {
self.dispose_above_core(depth, DisposeResumeKind::Unwind(handler), self.exception_value)
}
/// 释放栈顶部 `n` 条资源(逃出释放:return/break/continue 完成值逃出作用域时
/// 逆序释放被逃出的资源)。`n` 超过栈长时按全量释放。在途 completion 初值为
/// None(完成值非 throw),挂起时携 `Escape(completion)` 供恢复后执行。
pub(crate) fn dispose_top_n(
&mut self, n: usize, completion: Completion,
) -> Result<DisposePhase, String> {
pub(crate) fn dispose_top_n(&mut self, n: usize, completion: Completion) -> Result<DisposePhase, String> {
let depth = self.dispose_stack.len().saturating_sub(n);
self.dispose_above_core(depth, DisposeResumeKind::Escape(completion), None)
}
@@ -896,16 +892,16 @@ impl Vm {
let dispose_key = encode_symbol_key(self.realm_id(), WELL_KNOWN_SYMBOL_DISPOSE);
let method = if hint == 1 {
let async_key = encode_symbol_key(self.realm_id(), WELL_KNOWN_SYMBOL_ASYNC_DISPOSE);
let async_method = self
.ordinary_get(val_obj, async_key, value)
.map_err(|e| self.dispose_exc(e))?;
let async_method = self.ordinary_get(val_obj, async_key, value).map_err(|e| self.dispose_exc(e))?;
if async_method.is_undefined() {
self.ordinary_get(val_obj, dispose_key, value).map_err(|e| self.dispose_exc(e))?
self.ordinary_get(val_obj, dispose_key, value)
.map_err(|e| self.dispose_exc(e))?
} else {
async_method
}
} else {
self.ordinary_get(val_obj, dispose_key, value).map_err(|e| self.dispose_exc(e))?
self.ordinary_get(val_obj, dispose_key, value)
.map_err(|e| self.dispose_exc(e))?
};
Ok(method)
}
+1 -4
View File
@@ -876,10 +876,7 @@ impl Vm {
// 异常穿越释放:逆序释放该作用域内登记的资源(规范序 IteratorClose 先、
// DisposeResources 后)。释放方法抛错时新错误替代在途异常继续向外展开;
// 异步释放挂起时登记在途状态并让出(恢复方重压 handler 再入本函数)。
if matches!(
self.dispose_above(handler.dispose_depth, Some(handler))?,
DisposePhase::Suspended
) {
if matches!(self.dispose_above(handler.dispose_depth, Some(handler))?, DisposePhase::Suspended) {
return Ok(());
}
if let Some(finally_pc) = handler.finally_pc {
+11 -9
View File
@@ -86,12 +86,7 @@ pub(crate) fn worker_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult {
let url_val = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
let url = match vm.lookup_str(url_val) {
Some(u) => u,
None => {
return NativeResult::Err(oxide_builtins::error::create_type_error(
vm,
"Worker url must be a string",
))
}
None => return NativeResult::Err(oxide_builtins::error::create_type_error(vm, "Worker url must be a string")),
};
// 主线程侧读 url 文件(worker 脚本源码)。
@@ -120,9 +115,11 @@ pub(crate) fn worker_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult {
// onmessage / onerror / onmessageerror:普通 own 数据属性(非枚举),初值 undefined。
let si_onmessage = vm.perm_intern("onmessage");
let _ = vm.define_data_property(worker_obj, si_onmessage, JsValue::undefined(), PropAttributes::new(true, false, true));
let _ =
vm.define_data_property(worker_obj, si_onmessage, JsValue::undefined(), PropAttributes::new(true, false, true));
let si_onerror = vm.perm_intern("onerror");
let _ = vm.define_data_property(worker_obj, si_onerror, JsValue::undefined(), PropAttributes::new(true, false, true));
let _ =
vm.define_data_property(worker_obj, si_onerror, JsValue::undefined(), PropAttributes::new(true, false, true));
let si_onmessageerror = vm.perm_intern("onmessageerror");
let _ = vm.define_data_property(
worker_obj,
@@ -133,7 +130,12 @@ pub(crate) fn worker_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult {
// workerId:非枚举数据属性(值为 worker 编号,数值表示无 GC 边)。
let si_worker_id = vm.perm_intern("workerId");
let _ = vm.define_data_property(worker_obj, si_worker_id, JsValue::float(id as f64), PropAttributes::new(true, false, true));
let _ = vm.define_data_property(
worker_obj,
si_worker_id,
JsValue::float(id as f64),
PropAttributes::new(true, false, true),
);
// 登记 Worker 对象进注册表(GC 根,主线程事件循环据编号反查 onmessage)。
vm.worker_objects.insert(id, JsValue::from_js_object(ptr));
@@ -420,11 +420,8 @@ fn function_call_apply_bind_async_target_returns_promise() {
fn function_call_async_target_rejection_keeps_value() {
// 异步目标抛错:Promise 以原值拒绝,.then 的拒绝臂收到原值。
let mut vm = Vm::new();
let result = eval_drain(
&mut vm,
"async function f(){ throw 42; } f.call(null).then(v => 'ok:'+v, e => 'err:'+e)",
)
.unwrap();
let result =
eval_drain(&mut vm, "async function f(){ throw 42; } f.call(null).then(v => 'ok:'+v, e => 'err:'+e)").unwrap();
assert_eq!(vm.lookup_str(result).unwrap_or_default(), "err:42");
}
@@ -168,11 +168,7 @@ fn strict_ctx_indirect_eval_catch_arguments_throws() {
#[test]
fn sloppy_eval_completion_value_unaffected() {
// 守卫:sloppy 上下文 eval 完成值不受严格性判定影响。
assert_eq!(
eval("eval(\"1+2\")"),
"3",
"sloppy context eval completion value is unaffected"
);
assert_eq!(eval("eval(\"1+2\")"), "3", "sloppy context eval completion value is unaffected");
}
#[test]
+1 -4
View File
@@ -291,10 +291,7 @@ fn fn_name_recursive_call() {
/// 断言运行期抛出未捕获 ReferenceError(默认参数 TDZ 守卫的期望形态)。
fn assert_dflt_tdz_reference_error(source: &str, msg: &str) {
let err = eval(&mut Vm::new(), source).unwrap_err();
assert!(
err.contains("ReferenceError"),
"{msg}: expected an uncaught ReferenceError, got: {err}"
);
assert!(err.contains("ReferenceError"), "{msg}: expected an uncaught ReferenceError, got: {err}");
}
#[test]