mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
fix: 修复块级闭包 TDZ 占位与调用窗口踩踏及 for-of 迭代器展开
This commit is contained in:
Generated
+21
-21
@@ -1160,7 +1160,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_builtins"
|
||||
version = "0.21.0"
|
||||
version = "0.21.1"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"fast-float",
|
||||
@@ -1185,7 +1185,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_bytecode"
|
||||
version = "0.21.0"
|
||||
version = "0.21.1"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxide_log",
|
||||
@@ -1193,7 +1193,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cfg"
|
||||
version = "0.21.0"
|
||||
version = "0.21.1"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_emit",
|
||||
@@ -1204,7 +1204,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cli"
|
||||
version = "0.21.0"
|
||||
version = "0.21.1"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"bumpalo",
|
||||
@@ -1228,7 +1228,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_code_cache"
|
||||
version = "0.21.0"
|
||||
version = "0.21.1"
|
||||
dependencies = [
|
||||
"lru",
|
||||
"oxide_bytecode",
|
||||
@@ -1237,7 +1237,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_compiler"
|
||||
version = "0.21.0"
|
||||
version = "0.21.1"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1258,7 +1258,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_dce"
|
||||
version = "0.21.0"
|
||||
version = "0.21.1"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1272,7 +1272,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_emit"
|
||||
version = "0.21.0"
|
||||
version = "0.21.1"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxc_allocator",
|
||||
@@ -1288,7 +1288,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_engine"
|
||||
version = "0.21.0"
|
||||
version = "0.21.1"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1300,7 +1300,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_fold"
|
||||
version = "0.21.0"
|
||||
version = "0.21.1"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxide_bytecode",
|
||||
@@ -1312,7 +1312,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_ir"
|
||||
version = "0.21.0"
|
||||
version = "0.21.1"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_log",
|
||||
@@ -1321,7 +1321,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_kernel"
|
||||
version = "0.21.0"
|
||||
version = "0.21.1"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1335,7 +1335,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_liveness"
|
||||
version = "0.21.0"
|
||||
version = "0.21.1"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1347,7 +1347,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_log"
|
||||
version = "0.21.0"
|
||||
version = "0.21.1"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
"tracing-appender",
|
||||
@@ -1356,11 +1356,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_net"
|
||||
version = "0.21.0"
|
||||
version = "0.21.1"
|
||||
|
||||
[[package]]
|
||||
name = "oxide_parser"
|
||||
version = "0.21.0"
|
||||
version = "0.21.1"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast",
|
||||
@@ -1375,7 +1375,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_regalloc"
|
||||
version = "0.21.0"
|
||||
version = "0.21.1"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1391,7 +1391,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_runtime_api"
|
||||
version = "0.21.0"
|
||||
version = "0.21.1"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
@@ -1404,7 +1404,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_test262"
|
||||
version = "0.21.0"
|
||||
version = "0.21.1"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1424,7 +1424,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_types"
|
||||
version = "0.21.0"
|
||||
version = "0.21.1"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1437,7 +1437,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_vm"
|
||||
version = "0.21.0"
|
||||
version = "0.21.1"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"chrono",
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.21.0"
|
||||
version = "0.21.1"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
rust-version = "1.80"
|
||||
|
||||
@@ -2420,6 +2420,7 @@ fn get_iterator<H: VmHost>(vm: &mut H, value: JsValue) -> Result<Option<(JsValue
|
||||
// 迭代协议:GetIterator 先取 value[Symbol.iterator] 并调用;装箱对象仅作查找
|
||||
// 起点与鸭子回退 inner,receiver/this 用原始 value(GetV / GetIteratorFromMethod)。
|
||||
let sym_iter_si = encode_symbol_key(vm.realm_id(), 0);
|
||||
let pc_before = vm.pc();
|
||||
let method = match vm.ordinary_get(obj, sym_iter_si, value) {
|
||||
Ok(m) => m,
|
||||
Err(err) => {
|
||||
@@ -2430,6 +2431,11 @@ fn get_iterator<H: VmHost>(vm: &mut H, value: JsValue) -> Result<Option<(JsValue
|
||||
return Err(exc);
|
||||
}
|
||||
};
|
||||
// 取 @@iterator 期间源 getter 抛出:深度 0 的 raise_call_error 已就地 unwind
|
||||
//(跳转 catch),pc 必已变化——须立即停止,不得落入鸭子回退二次触源 getter。
|
||||
if vm.pc() != pc_before {
|
||||
return Ok(None);
|
||||
}
|
||||
if builtin_value && builtin_iterator_default_intact(vm, value, method) {
|
||||
return Ok(Some((value, None)));
|
||||
}
|
||||
|
||||
@@ -115,6 +115,11 @@ pub struct CompileCtx {
|
||||
/// 0..n-1 占满),块级遮蔽绑定预声明追加、catch 参数就地声明与合成 cell 经
|
||||
/// `alloc_cell_idx` 递增取号,保证与函数级名字排序索引及历次追加互不碰撞。
|
||||
pub(crate) next_cell_idx: u8,
|
||||
/// 块入口已发每迭代 TDZ 占位 MAKE_CELL 的 cell 索引集:被捕获的块级
|
||||
/// let/const 在块入口每迭代新建未初始化 cell(循环体重执行即新 cell),
|
||||
/// 声明点据此改发原位 MAKE_CELL(闭包捕获占位 cell 后跟随初始化),
|
||||
/// 不发 MAKE_CELL_FRESH(替换会孤儿化声明前创建的闭包)。
|
||||
pub(crate) per_iter_predeclared_cells: HashSet<u8>,
|
||||
/// 词法循环头(C-for / for-in / for-of)名集:头名索引由 ForHeadEnv 覆盖
|
||||
/// 捕获映射分配(TDZ 占位与体区 fresh cell),声明点据此走映射回退而非
|
||||
/// 就地追加新索引。begin 时并入、restore 时移除,嵌套循环成对。
|
||||
@@ -304,6 +309,7 @@ impl CompileCtx {
|
||||
block_fn_entry_mats: Vec::new(),
|
||||
captured_bindings: BTreeMap::new(),
|
||||
next_cell_idx: 0,
|
||||
per_iter_predeclared_cells: HashSet::new(),
|
||||
for_head_env_names: HashSet::new(),
|
||||
pending_for_head_names: HashSet::new(),
|
||||
global_tier_names: HashSet::new(),
|
||||
|
||||
@@ -425,6 +425,11 @@ impl Emitter {
|
||||
{
|
||||
let idx = ctx.alloc_cell_idx();
|
||||
ctx.set_binding_cell_idx(bi.name.as_str(), idx);
|
||||
// 登记每迭代 TDZ 占位:循环体内块重执行时该 MAKE_CELL 每迭代
|
||||
// 新建未初始化 cell,声明点据此改发原位 MAKE_CELL(闭包捕获
|
||||
// 占位 cell 后跟随初始化),替换式 fresh 会孤儿化声明前创建的
|
||||
// 闭包(提升函数声明)致 TDZ 误报。
|
||||
ctx.per_iter_predeclared_cells.insert(idx);
|
||||
let undef_reg = self.emit_undefined(ctx);
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::MAKE_CELL,
|
||||
|
||||
@@ -101,7 +101,15 @@ impl Emitter {
|
||||
// 绑定走回填索引,块级遮蔽绑定走预声明追加索引,catch 参数等块作用域
|
||||
// 就地声明现场追加;词法循环头名走捕获映射回退。
|
||||
if let Some(cell_idx) = ctx.resolve_bind_cell_idx(name) {
|
||||
let op = if fresh_cell { OpCode::MAKE_CELL_FRESH } else { OpCode::MAKE_CELL };
|
||||
// 每迭代 TDZ 占位已建(块入口预声明)时改发原位 MAKE_CELL:占位
|
||||
// cell 是本迭代新 cell,声明前创建的闭包(提升函数声明)已捕获它,
|
||||
// 原位更新使其跟随初始化;仅体区 fresh cell 场景(循环头绑定,占位
|
||||
// 一次性)发替换式 MAKE_CELL_FRESH。
|
||||
let op = if fresh_cell && !ctx.per_iter_predeclared_cells.contains(&cell_idx) {
|
||||
OpCode::MAKE_CELL_FRESH
|
||||
} else {
|
||||
OpCode::MAKE_CELL
|
||||
};
|
||||
ctx.inst(Inst::new(op, Operand::Reg(src_reg), Operand::Imm(cell_idx as u16), Operand::None));
|
||||
// C 风格 for 头绑定:cell 之外补写绑定寄存器——循环体/test/update 读寄存器,
|
||||
// 每迭代 fresh 拷贝的源也是寄存器(见 `CompileCtx::for_head_store_registers`)。
|
||||
|
||||
@@ -79,8 +79,13 @@ impl Emitter {
|
||||
// 被捕获绑定的 cell 在函数入口已实例化(undefined);声明语句
|
||||
// 不赋值,仅首次声明刷新初值,已绑定的 cell 保留现值。
|
||||
if !already_bound {
|
||||
// 重执行迭代取新 cell,与 with-init 臂同一门控。
|
||||
let op = if reexec { OpCode::MAKE_CELL_FRESH } else { OpCode::MAKE_CELL };
|
||||
// 重执行迭代取新 cell,与 with-init 臂同一门控:块入口每迭代
|
||||
// TDZ 占位已建时原位更新,防孤儿化声明前创建的闭包。
|
||||
let op = if reexec && !ctx.per_iter_predeclared_cells.contains(&cell_idx) {
|
||||
OpCode::MAKE_CELL_FRESH
|
||||
} else {
|
||||
OpCode::MAKE_CELL
|
||||
};
|
||||
ctx.inst(Inst::new(op, Operand::Reg(tmp), Operand::Imm(cell_idx as u16), Operand::None));
|
||||
}
|
||||
} else if !already_bound {
|
||||
|
||||
@@ -303,8 +303,16 @@ impl Vm {
|
||||
// 窗口 = min(调用方活动寄存器, 存活上界);call_window=0 表示调用方全量
|
||||
// (运行时发起路径 / 未编码的旧模块)。恢复按窗口回拷,active_reg_limit
|
||||
// 仍还原为调用方真实值(caller_active_reg_limit)。
|
||||
// native 调用在飞(native_call_depth > 0)时窗口扩到全量 254:native 实参
|
||||
// 暂存在调用点参数窗口(物理槽 252/253 一带),内层字节码调用复用同一
|
||||
// 参数窗口会踩掉外层 native 实参;窗口截断不覆盖参数窗口时 restore
|
||||
// 不还原,外层 builtin 后续读实参得踩值。
|
||||
let caller_active_reg_limit = self.active_reg_limit.max(1);
|
||||
let caller_reg_limit = self.call_window_limit(caller_active_reg_limit, call_window);
|
||||
let caller_reg_limit = if self.native_call_depth > 0 {
|
||||
254
|
||||
} else {
|
||||
self.call_window_limit(caller_active_reg_limit, call_window)
|
||||
};
|
||||
let saved_reg_offset = self.save_stack.len() as u32;
|
||||
self.save_stack.extend_from_slice(&self.regs[..caller_reg_limit as usize]);
|
||||
let saved_this = self.regs[254];
|
||||
|
||||
@@ -1032,8 +1032,15 @@ impl Vm {
|
||||
pub(crate) fn dispatch_for_of_init(&mut self, a: usize) -> Result<(), String> {
|
||||
vm_trace!("FOR_OF_INIT r{}={:?}", a, self.regs[a]);
|
||||
let iterable = self.regs[a];
|
||||
let pc_before = self.pc;
|
||||
match oxide_builtins::iterator::make_iterator_for_value(self, iterable) {
|
||||
Ok(iterator) => {
|
||||
// 取迭代器期间源 getter 抛出:深度 0 的 raise_call_error 已就地
|
||||
// unwind(跳转 catch),pc 已改写——迭代器值无效,直接返回,
|
||||
// 派发循环自 catch 点续行,不得再触碰迭代器栈。
|
||||
if self.pc != pc_before {
|
||||
return Ok(());
|
||||
}
|
||||
// 内置包装器检测:Array/String/TA/Map/Set 走快路径(异步恒慢)。
|
||||
// init 期把 inner 快照入条目,步内不重读 `__inner__` 槽。
|
||||
let (kind, inner) = match oxide_builtins::iterator::builtin_iter_kind(self, iterator) {
|
||||
@@ -1044,6 +1051,12 @@ impl Vm {
|
||||
Ok(())
|
||||
}
|
||||
Err(err) => {
|
||||
// 取迭代器期间源 getter 抛出:深度 0 的 raise_call_error 已就地
|
||||
// unwind(跳转 catch),pc 已改写、handler 已弹出——不得再 unwind
|
||||
//(二次展开无 handler 必报未捕获),派发循环自 catch 点续行。
|
||||
if self.pc != pc_before {
|
||||
return Ok(());
|
||||
}
|
||||
self.exception_value = Some(err);
|
||||
self.pending_error_kind = Some(self.thrown_error_kind(err));
|
||||
self.unwind()
|
||||
|
||||
@@ -466,7 +466,15 @@ impl Vm {
|
||||
vm_trace!("call_bytecode: saving state pc={} depth={}", self.pc, self.frames.len());
|
||||
// 窗口 = max(调用方活跃寄存器, callee 寄存器数):restore 只回拷窗口,正好
|
||||
// 覆盖 callee 写入区(regs[0..n_registers] + 254/255)与调用方活动区。
|
||||
let window = self.active_reg_limit.max(sub.n_registers).max(1) as usize;
|
||||
// native 调用在飞(native_call_depth > 0)时窗口扩到全量 254:native 实参
|
||||
// 暂存在调用点参数窗口(物理槽 252/253 一带,arg_window_base = 254 − max_nargs),
|
||||
// 内层字节码调用复用同一参数窗口会踩掉外层 native 实参;窗口截断不覆盖
|
||||
// 参数窗口时 restore 不还原,外层 builtin 后续读实参得踩值。
|
||||
let window = if self.native_call_depth > 0 {
|
||||
254
|
||||
} else {
|
||||
self.active_reg_limit.max(sub.n_registers).max(1) as usize
|
||||
};
|
||||
let saved = self.save_inline_state(window);
|
||||
|
||||
// 只零填 callee 读区 regs[0..n_registers];高位残留调用方旧值无害
|
||||
|
||||
Reference in New Issue
Block a user