From 710c8c8a2cf443b70a2a96eafac1826dc766bce1 Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Fri, 7 Aug 2026 14:38:47 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E9=97=AD=E5=8C=85=20upvalue=20cell=20?= =?UTF-8?q?=E5=8D=A0=E4=BD=8D=E7=A8=B3=E5=AE=9A=E5=8C=96=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E9=94=99=E8=AF=BB=E8=B0=83=E7=94=A8=E6=96=B9=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 2 +- crates/oxide_log/Cargo.toml | 2 +- crates/oxide_log/src/init.rs | 3 ++- crates/oxide_test262/src/main.rs | 9 +++++++- crates/oxide_vm/src/dispatch/call.rs | 34 ++++++++++++++++++++-------- crates/oxide_vm/src/vm.rs | 28 +++++++++++++++++++++++ crates/oxide_vm/src/vm_runtime.rs | 10 ++++++++ 7 files changed, 74 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8ddfdd01..a4544aac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,7 +57,7 @@ lru = "0.18" smallvec = { version = "1", features = ["union"] } chrono = { version = "0.4", default-features = false, features = ["clock"] } unicode-normalization = "0.1" -tracing = { version = "0.1.44", features = ["max_level_trace", "release_max_level_info"] } +tracing = { version = "0.1.44", features = ["max_level_trace", "release_max_level_debug"] } tracing-subscriber = { version = "0.3.23", features = ["env-filter", "registry"] } tracing-appender = "0.2.5" diff --git a/crates/oxide_log/Cargo.toml b/crates/oxide_log/Cargo.toml index 0f0194b3..4c6fc6da 100644 --- a/crates/oxide_log/Cargo.toml +++ b/crates/oxide_log/Cargo.toml @@ -7,6 +7,6 @@ rust-version.workspace = true description = "OxideJS - Structured logging subsystem (tracing-based)" [dependencies] -tracing = { workspace = true, features = ["max_level_trace", "release_max_level_info"] } +tracing = { workspace = true, features = ["max_level_trace", "release_max_level_debug"] } tracing-subscriber = { workspace = true, features = ["env-filter", "registry"] } tracing-appender = "0.2.5" diff --git a/crates/oxide_log/src/init.rs b/crates/oxide_log/src/init.rs index 636956de..a31c569d 100644 --- a/crates/oxide_log/src/init.rs +++ b/crates/oxide_log/src/init.rs @@ -85,7 +85,8 @@ pub fn init(config: &LogConfig) { } SUBSYSTEM.set(filter.clone()).ok(); - let env_filter = EnvFilter::try_from_env("OXIDE_LOG").unwrap_or_else(|_| EnvFilter::new("oxide=off")); + let env_filter = EnvFilter::try_from_env("OXIDE_LOG") + .unwrap_or_else(|_| EnvFilter::new("oxide=trace")); subsystem::apply_env_levels(); diff --git a/crates/oxide_test262/src/main.rs b/crates/oxide_test262/src/main.rs index 28c192b4..3e3f2f08 100644 --- a/crates/oxide_test262/src/main.rs +++ b/crates/oxide_test262/src/main.rs @@ -1135,9 +1135,16 @@ fn run_tests() -> bool { } }; + let mut log_level = Level::Info; + if let Ok(s) = std::env::var("OXIDE_TEST262_LOG_LEVEL") { + if let Some(l) = oxide_log::subsystem::parse_level(&s) { + log_level = l; + } + } + eprintln!("[LOG] level={log_level:?}"); oxide_log::init(&LogConfig { output: Output::Stderr, - levels: [Level::Info; SUBSYSTEM_COUNT], + levels: [log_level; SUBSYSTEM_COUNT], }); let test262_root = if let Some(root) = config.test262_root.clone() { diff --git a/crates/oxide_vm/src/dispatch/call.rs b/crates/oxide_vm/src/dispatch/call.rs index dc47a561..6b4debbd 100644 --- a/crates/oxide_vm/src/dispatch/call.rs +++ b/crates/oxide_vm/src/dispatch/call.rs @@ -133,15 +133,21 @@ impl Vm { let name_val = function_name.as_deref().map(|n| self.new_string(n)).unwrap_or_else(|| self.new_string("")); self.set_or_create_prop_value(func_obj, name_si, name_val); if !upvalue_captures.is_empty() { - if let Some(current_cells) = self.cell_stack.last() { + if let Some(current_cells) = self.cell_stack.last_mut() { let mut upvals = Box::new(Vec::with_capacity(upvalue_captures.len())); for capture in &upvalue_captures { - let cell_ptr = if (capture.cell_idx as usize) < current_cells.len() { - current_cells[capture.cell_idx as usize] - } else { - std::ptr::null_mut() - }; - upvals.push(cell_ptr); + let cell_idx = capture.cell_idx as usize; + if cell_idx >= current_cells.len() { + current_cells.resize(cell_idx + 1, std::ptr::null_mut()); + } + // cell 可能尚未 MAKE_CELL(hoisting 顺序:CREATE_CLOSURE 先于 + // MAKE_CELL)——建占位 Cell,后续 MAKE_CELL 更新同一 Cell 的值, + // 保证 upvalue 始终指向定义方表里的稳定 cell(而非调用方表)。 + if current_cells[cell_idx].is_null() { + let cell = self.gc_state.session_epoch.alloc(Cell::new(JsValue::undefined(), true)); + current_cells[cell_idx] = cell as *mut Cell; + } + upvals.push(current_cells[cell_idx]); } let func_obj = unsafe { &mut *result.as_js_object_ptr() }; func_obj.set_upvalues(upvals); @@ -155,13 +161,21 @@ impl Vm { pub(crate) fn dispatch_make_cell(&mut self, rd: usize, instr: u32) -> Result<(), String> { let cell_idx = opcode::imm16(instr) as usize; let value = self.regs[rd]; - let cell = self.gc_state.session_epoch.alloc(Cell::new(value, true)); - let cell_ptr = cell as *mut Cell; let current = self.cell_stack.last_mut().unwrap(); while current.len() <= cell_idx { current.push(std::ptr::null_mut()); } - current[cell_idx] = cell_ptr; + if current[cell_idx].is_null() { + // 无占位 cell:新建。 + let cell = self.gc_state.session_epoch.alloc(Cell::new(value, true)); + current[cell_idx] = cell as *mut Cell; + } else { + // 更新占位 cell(CREATE_CLOSURE 已建),使闭包 upvalue 指向的 + // cell 值跟随初始化。 + unsafe { + (*current[cell_idx]).value = value; + } + } Ok(()) } diff --git a/crates/oxide_vm/src/vm.rs b/crates/oxide_vm/src/vm.rs index 34ca1167..78ada42d 100644 --- a/crates/oxide_vm/src/vm.rs +++ b/crates/oxide_vm/src/vm.rs @@ -856,6 +856,34 @@ impl Vm { } } if self.pc >= self.bytecode.len() { + let tail: Vec = self + .bytecode + .iter() + .enumerate() + .rev() + .take(5) + .map(|(i, &instr)| format!("{i}:{:?}", opcode::opcode(instr))) + .collect(); + let fn_names: Vec = self + .frames + .iter() + .map(|f| { + self.kernel_core + .perm_interner() + .lookup(f.function_name) + .map(|s| s.to_string()) + .unwrap_or_else(|| "?".into()) + }) + .collect(); + vm_error!( + "dispatch: program counter out of bounds pc={} len={} frames={} cell_stack={} tail={:?} fns={:?}", + self.pc, + self.bytecode.len(), + self.frames.len(), + self.cell_stack.len(), + tail, + fn_names + ); vm_error!("dispatch: program counter out of bounds pc={} len={}", self.pc, self.bytecode.len()); self.profiling.instruction_count = steps; return Err("program counter out of bounds".into()); diff --git a/crates/oxide_vm/src/vm_runtime.rs b/crates/oxide_vm/src/vm_runtime.rs index 73a589a6..8e5d7511 100644 --- a/crates/oxide_vm/src/vm_runtime.rs +++ b/crates/oxide_vm/src/vm_runtime.rs @@ -149,6 +149,16 @@ impl Vm { if let Some(saved_bc) = self.saved_bytecode_stack.pop() { self.bytecode = saved_bc; } + vm_debug!( + "restore_frame: return_addr={} bc_len={} saved_stack={} fn={:?}", + frame.return_addr, + self.bytecode.len(), + self.saved_bytecode_stack.len(), + self.kernel_core + .perm_interner() + .lookup(frame.function_name) + .map(|s| s.to_string()) + ); if let Some(saved_imm) = self.saved_immutables_stack.pop() { self.active_immutables = saved_imm; }