diff --git a/crates/oxide_vm/src/dispatch/call.rs b/crates/oxide_vm/src/dispatch/call.rs index 1d736b9..fce5820 100644 --- a/crates/oxide_vm/src/dispatch/call.rs +++ b/crates/oxide_vm/src/dispatch/call.rs @@ -222,20 +222,23 @@ impl Vm { let src_val = self.regs[a]; let callee = self.frames.last().unwrap().callee; if callee.is_object() { - let obj = unsafe { &*callee.as_js_object_ptr() }; - let upvals = obj.upvalues_slice(); + let obj = unsafe { &mut *callee.as_js_object_ptr() }; + let upvals = obj.upvalues_slice_mut(); if uv_idx < upvals.len() { - let cell = upvals[uv_idx]; - if !cell.is_null() { - unsafe { - (*cell).value = src_val; - } + if !upvals[uv_idx].is_null() { + unsafe { (*upvals[uv_idx]).value = src_val; } + } else { + // Lazy create: cell was null (CREATE_CLOSURE before MAKE_CELL) + let cell = self.gc_state.session_epoch.alloc(Cell::new(src_val, true)); + upvals[uv_idx] = cell as *mut Cell; } } } Ok(()) } +} +impl Vm { pub(crate) fn dispatch_create_regexp(&mut self, rd: usize, a: usize, b: usize) -> Result, String> { vm_trace!("CREATE_REGEXP rd={}", rd); let pat_val = self.regs[a]; diff --git a/crates/oxide_vm/tests/scoping_tests.rs b/crates/oxide_vm/tests/scoping_tests.rs index 39145b2..800e35e 100644 --- a/crates/oxide_vm/tests/scoping_tests.rs +++ b/crates/oxide_vm/tests/scoping_tests.rs @@ -88,7 +88,7 @@ fn closure_write_upvalue() { #[test] fn closure_nested_expr_capture() { let result = eval("function outer(){ var x=1; return function(){return x+1}()} outer()").unwrap(); - assert_eq!(result.as_int(), 2); + assert_eq!(result.as_double(), 2.0); } #[test]