From 991e6040e5dd2a0ad8fc9f6ae2232515791b08f3 Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Tue, 30 Jun 2026 22:52:25 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=97=AD=E5=8C=85?= =?UTF-8?q?=E5=80=BC=E4=BC=A0=E9=80=92=E9=93=BE=E8=B7=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_compiler/src/compiler.rs | 27 +++++++++++++++++++-------- crates/oxide_vm/src/dispatch/call.rs | 13 ++++++++++++- crates/oxide_vm/src/vm.rs | 1 - crates/oxide_vm/src/vm_runtime.rs | 2 ++ crates/oxide_vm/src/vm_support.rs | 1 + 5 files changed, 34 insertions(+), 10 deletions(-) diff --git a/crates/oxide_compiler/src/compiler.rs b/crates/oxide_compiler/src/compiler.rs index e1e9c962..176f54ec 100644 --- a/crates/oxide_compiler/src/compiler.rs +++ b/crates/oxide_compiler/src/compiler.rs @@ -700,10 +700,15 @@ impl Compiler { match expr { Expression::Identifier(ident) => { let name = ident.name.as_str(); - // Only skip if name is in the nested function's OWN scopes (not inherited scopes[0]) - let is_local = nested_symbols.scopes.iter().skip(1).any(|s| s.bindings.contains_key(name)); - if is_local { - return; + if nested_symbols.lookup_any_binding(name).is_some() { + // Check if this is a parent function-scope binding (real upvalue) + let is_parent_func_var = parent_ctx.scopes.symbols.scopes.iter() + .skip(1) + .any(|s| s.bindings.contains_key(name)); + if !is_parent_func_var { + return; // true local or global, not upvalue + } + // falls through to capture } if let Some((binding, _)) = parent_ctx.scopes.symbols.lookup_any_binding(name) { if seen.contains_key(name) { @@ -721,8 +726,11 @@ impl Compiler { Expression::AssignmentExpression(ae) => { if let oxide_parser::AssignmentTarget::AssignmentTargetIdentifier(ati) = &ae.left { let name = ati.name.as_str(); - let is_local = nested_symbols.scopes.iter().skip(1).any(|s| s.bindings.contains_key(name)); - if !is_local { +let in_nested = nested_symbols.lookup_any_binding(name).is_some(); +let is_parent_func_var = parent_ctx.scopes.symbols.scopes.iter() + .skip(1) + .any(|s| s.bindings.contains_key(name)); +if !in_nested || is_parent_func_var { if let Some((binding, _)) = parent_ctx.scopes.symbols.lookup_any_binding(name) { if !seen.contains_key(name) { let cell_idx = captures.len() as u8; @@ -748,8 +756,11 @@ impl Compiler { Expression::UpdateExpression(ue) => { if let oxide_parser::SimpleAssignmentTarget::AssignmentTargetIdentifier(ati) = &ue.argument { let name = ati.name.as_str(); - let is_local = nested_symbols.scopes.iter().skip(1).any(|s| s.bindings.contains_key(name)); - if !is_local { +let in_nested = nested_symbols.lookup_any_binding(name).is_some(); +let is_parent_func_var = parent_ctx.scopes.symbols.scopes.iter() + .skip(1) + .any(|s| s.bindings.contains_key(name)); +if !in_nested || is_parent_func_var { if let Some((binding, _)) = parent_ctx.scopes.symbols.lookup_any_binding(name) { if !seen.contains_key(name) { let cell_idx = captures.len() as u8; diff --git a/crates/oxide_vm/src/dispatch/call.rs b/crates/oxide_vm/src/dispatch/call.rs index 5c94607f..1d736b95 100644 --- a/crates/oxide_vm/src/dispatch/call.rs +++ b/crates/oxide_vm/src/dispatch/call.rs @@ -195,7 +195,18 @@ impl Vm { let obj = unsafe { &mut *callee.as_js_object_ptr() }; let upvals = obj.upvalues_slice_mut(); if uv_idx < upvals.len() { - let cell = self.gc_state.session_epoch.alloc(Cell::new(self.regs[rd], true)); + // Try to get value from caller's cell table (MAKE_CELL ran after CREATE_CLOSURE) + let val = if self.cell_stack.len() >= 2 { + let caller_cells = &self.cell_stack[self.cell_stack.len() - 2]; + if uv_idx < caller_cells.len() && !caller_cells[uv_idx].is_null() { + unsafe { (*caller_cells[uv_idx]).value } + } else { + self.regs[rd] + } + } else { + self.regs[rd] + }; + let cell = self.gc_state.session_epoch.alloc(Cell::new(val, true)); upvals[uv_idx] = cell as *mut Cell; self.regs[rd] = cell.value; return Ok(()); diff --git a/crates/oxide_vm/src/vm.rs b/crates/oxide_vm/src/vm.rs index 87e3b420..83975ef2 100644 --- a/crates/oxide_vm/src/vm.rs +++ b/crates/oxide_vm/src/vm.rs @@ -767,7 +767,6 @@ impl Vm { let callee_subs = &subs[sub_idx].sub_modules; if !callee_subs.is_empty() { self.sub_modules = Arc::new(callee_subs.clone()); - self.immutables_cache = (0..=callee_subs.len()).map(|_| OnceLock::new()).collect(); } self.active_reg_limit = sub_n_registers.max(1); diff --git a/crates/oxide_vm/src/vm_runtime.rs b/crates/oxide_vm/src/vm_runtime.rs index 34746348..4ed2f8eb 100644 --- a/crates/oxide_vm/src/vm_runtime.rs +++ b/crates/oxide_vm/src/vm_runtime.rs @@ -152,6 +152,8 @@ impl Vm { pub fn run(&mut self, module: &CompiledModule) -> Result { vm_debug!("run: starting bytecode execution, {} instructions", module.bytecode.len()); self.clear_execution_state(); + self.cell_stack.clear(); + self.cell_stack.push(Vec::new()); self.sub_modules = Arc::new(module.sub_modules.clone()); self.immutables_cache = (0..=self.sub_modules.len()).map(|_| OnceLock::new()).collect(); self.bytecode = module.bytecode.clone(); diff --git a/crates/oxide_vm/src/vm_support.rs b/crates/oxide_vm/src/vm_support.rs index 11f755a9..4b9d3314 100644 --- a/crates/oxide_vm/src/vm_support.rs +++ b/crates/oxide_vm/src/vm_support.rs @@ -205,6 +205,7 @@ impl Vm { self.saved_bytecode_stack.clear(); self.saved_immutables_stack.clear(); self.save_stack.clear(); + self.cell_stack.clear(); self.try_stack.clear(); self.exception_value = None; self.pending_exception = None;