diff --git a/crates/oxide_vm/src/dispatch/call.rs b/crates/oxide_vm/src/dispatch/call.rs index 477e087..c609477 100644 --- a/crates/oxide_vm/src/dispatch/call.rs +++ b/crates/oxide_vm/src/dispatch/call.rs @@ -169,18 +169,25 @@ impl Vm { Ok(()) } + /// 当前执行函数的闭包对象:普通路径取 frames 栈顶帧,inline(sync 回调)路径 + /// frames 被隔离为空,取 `inline_callee`。 + fn current_callee(&self) -> Option { + self.frames.last().map(|f| f.callee).or(self.inline_callee) + } + #[allow(dead_code)] pub(crate) fn dispatch_load_upvalue(&mut self, rd: usize, instr: u32) -> Result<(), String> { let uv_idx = opcode::imm16(instr) as usize; - let callee = self.frames.last().unwrap().callee; - if callee.is_object() { - let obj = unsafe { &*callee.as_js_object_ptr() }; - let upvals = obj.upvalues_slice(); - if uv_idx < upvals.len() { - let cell = upvals[uv_idx]; - if !cell.is_null() { - self.regs[rd] = unsafe { (*cell).value }; - return Ok(()); + if let Some(callee) = self.current_callee() { + if callee.is_object() { + let obj = unsafe { &*callee.as_js_object_ptr() }; + let upvals = obj.upvalues_slice(); + if uv_idx < upvals.len() { + let cell = upvals[uv_idx]; + if !cell.is_null() { + self.regs[rd] = unsafe { (*cell).value }; + return Ok(()); + } } } } @@ -190,26 +197,27 @@ impl Vm { } fn lazy_create_upvalue_cell(&mut self, rd: usize, uv_idx: usize) -> Result<(), String> { - let callee = self.frames.last().unwrap().callee; - if callee.is_object() { - let obj = unsafe { &mut *callee.as_js_object_ptr() }; - let upvals = obj.upvalues_slice_mut(); - if uv_idx < upvals.len() { - // 尝试从调用方 cell 表取初值(MAKE_CELL 在 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 } + if let Some(callee) = self.current_callee() { + if callee.is_object() { + let obj = unsafe { &mut *callee.as_js_object_ptr() }; + let upvals = obj.upvalues_slice_mut(); + if uv_idx < upvals.len() { + // 尝试从调用方 cell 表取初值(MAKE_CELL 在 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] - } - } 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(()); + }; + 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(()); + } } } self.regs[rd] = JsValue::undefined(); @@ -220,19 +228,20 @@ impl Vm { pub(crate) fn dispatch_store_upvalue(&mut self, a: usize, b: usize) -> Result<(), String> { let uv_idx = b; let src_val = self.regs[a]; - let callee = self.frames.last().unwrap().callee; - if callee.is_object() { - let obj = unsafe { &mut *callee.as_js_object_ptr() }; - let upvals = obj.upvalues_slice_mut(); - if uv_idx < upvals.len() { - if !upvals[uv_idx].is_null() { - unsafe { - (*upvals[uv_idx]).value = src_val; + if let Some(callee) = self.current_callee() { + if callee.is_object() { + let obj = unsafe { &mut *callee.as_js_object_ptr() }; + let upvals = obj.upvalues_slice_mut(); + if uv_idx < upvals.len() { + if !upvals[uv_idx].is_null() { + unsafe { + (*upvals[uv_idx]).value = src_val; + } + vm_debug!("STORE_UPVALUE len={} wrote existing", upvals.len()); + } else { + let cell = self.gc_state.session_epoch.alloc(Cell::new(src_val, true)); + upvals[uv_idx] = cell as *mut Cell; } - vm_debug!("STORE_UPVALUE len={} wrote existing", upvals.len()); - } else { - let cell = self.gc_state.session_epoch.alloc(Cell::new(src_val, true)); - upvals[uv_idx] = cell as *mut Cell; } } } diff --git a/crates/oxide_vm/src/vm.rs b/crates/oxide_vm/src/vm.rs index 7d6cf84..ce51d26 100644 --- a/crates/oxide_vm/src/vm.rs +++ b/crates/oxide_vm/src/vm.rs @@ -163,6 +163,7 @@ pub(crate) struct InlineSyncState { pub(crate) save_stack: Vec, pub(crate) spill_stack: Vec, pub(crate) cell_stack: Vec>, + pub(crate) inline_callee: Option, } /// 基于寄存器的 JS 虚拟机:持有执行状态、寄存器文件、调用栈与 session 内存。 @@ -212,6 +213,10 @@ pub struct Vm { /// 调度循环检查该标志,跳过用调用结果写 `regs[target_reg]` —— 值改由 RETURN /// 处理器交付。 pub(crate) accessor_frame_target_reg: Option, + /// `call_bytecode_function_inline` 执行期间当前回调闭包;LOAD/STORE_UPVALUE 在 + /// frames 为空(inline 隔离状态)时由此取闭包 upvalues。嵌套 inline 由 + /// InlineSyncState 保存/恢复。 + pub(crate) inline_callee: Option, /// 分组保存 session arena / GC 簿记状态。 pub(crate) gc_state: GcState, /// 分组保存 `Symbol` intern 状态。 diff --git a/crates/oxide_vm/src/vm_runtime.rs b/crates/oxide_vm/src/vm_runtime.rs index d465277..2a8f0e4 100644 --- a/crates/oxide_vm/src/vm_runtime.rs +++ b/crates/oxide_vm/src/vm_runtime.rs @@ -62,6 +62,7 @@ impl Vm { save_stack: std::mem::take(&mut self.save_stack), spill_stack: std::mem::take(&mut self.spill_stack), cell_stack: std::mem::take(&mut self.cell_stack), + inline_callee: self.inline_callee, }); self.regs = [JsValue::undefined(); 256]; @@ -70,6 +71,8 @@ impl Vm { self.activate_immutables(sub_idx + 1, &sub.constants); self.active_reg_limit = sub.n_registers.max(1); self.root_reg_limit = self.active_reg_limit; + self.cell_stack.push(Vec::with_capacity(sub.cells_needed as usize)); + self.inline_callee = Some(callee); for i in 0..sub.n_args as usize { self.regs[sub.param_base as usize + i] = args.get(i).copied().unwrap_or(JsValue::undefined()); } @@ -114,6 +117,7 @@ impl Vm { self.save_stack = saved.save_stack; self.spill_stack = saved.spill_stack; self.cell_stack = saved.cell_stack; + self.inline_callee = saved.inline_callee; result } diff --git a/crates/oxide_vm/src/vm_support.rs b/crates/oxide_vm/src/vm_support.rs index 74be700..a2bb605 100644 --- a/crates/oxide_vm/src/vm_support.rs +++ b/crates/oxide_vm/src/vm_support.rs @@ -47,6 +47,7 @@ impl Vm { active_reg_limit: 0, native_call_depth: 0, accessor_frame_target_reg: None, + inline_callee: None, gc_state: GcState { session_epoch: bumpalo::Bump::new(), session_gc: crate::session_gc::SessionGc::new(), @@ -111,6 +112,7 @@ impl Vm { active_reg_limit: 0, native_call_depth: 0, accessor_frame_target_reg: None, + inline_callee: None, gc_state: GcState { session_epoch: bumpalo::Bump::new(), session_gc: crate::session_gc::SessionGc::new(),