fix(vm): inline 回调支持 upvalue 闭包上下文
This commit is contained in:
@@ -169,18 +169,25 @@ impl Vm {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 当前执行函数的闭包对象:普通路径取 frames 栈顶帧,inline(sync 回调)路径
|
||||||
|
/// frames 被隔离为空,取 `inline_callee`。
|
||||||
|
fn current_callee(&self) -> Option<JsValue> {
|
||||||
|
self.frames.last().map(|f| f.callee).or(self.inline_callee)
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) fn dispatch_load_upvalue(&mut self, rd: usize, instr: u32) -> Result<(), String> {
|
pub(crate) fn dispatch_load_upvalue(&mut self, rd: usize, instr: u32) -> Result<(), String> {
|
||||||
let uv_idx = opcode::imm16(instr) as usize;
|
let uv_idx = opcode::imm16(instr) as usize;
|
||||||
let callee = self.frames.last().unwrap().callee;
|
if let Some(callee) = self.current_callee() {
|
||||||
if callee.is_object() {
|
if callee.is_object() {
|
||||||
let obj = unsafe { &*callee.as_js_object_ptr() };
|
let obj = unsafe { &*callee.as_js_object_ptr() };
|
||||||
let upvals = obj.upvalues_slice();
|
let upvals = obj.upvalues_slice();
|
||||||
if uv_idx < upvals.len() {
|
if uv_idx < upvals.len() {
|
||||||
let cell = upvals[uv_idx];
|
let cell = upvals[uv_idx];
|
||||||
if !cell.is_null() {
|
if !cell.is_null() {
|
||||||
self.regs[rd] = unsafe { (*cell).value };
|
self.regs[rd] = unsafe { (*cell).value };
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -190,26 +197,27 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn lazy_create_upvalue_cell(&mut self, rd: usize, uv_idx: usize) -> Result<(), String> {
|
fn lazy_create_upvalue_cell(&mut self, rd: usize, uv_idx: usize) -> Result<(), String> {
|
||||||
let callee = self.frames.last().unwrap().callee;
|
if let Some(callee) = self.current_callee() {
|
||||||
if callee.is_object() {
|
if callee.is_object() {
|
||||||
let obj = unsafe { &mut *callee.as_js_object_ptr() };
|
let obj = unsafe { &mut *callee.as_js_object_ptr() };
|
||||||
let upvals = obj.upvalues_slice_mut();
|
let upvals = obj.upvalues_slice_mut();
|
||||||
if uv_idx < upvals.len() {
|
if uv_idx < upvals.len() {
|
||||||
// 尝试从调用方 cell 表取初值(MAKE_CELL 在 CREATE_CLOSURE 之后执行)。
|
// 尝试从调用方 cell 表取初值(MAKE_CELL 在 CREATE_CLOSURE 之后执行)。
|
||||||
let val = if self.cell_stack.len() >= 2 {
|
let val = if self.cell_stack.len() >= 2 {
|
||||||
let caller_cells = &self.cell_stack[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() {
|
if uv_idx < caller_cells.len() && !caller_cells[uv_idx].is_null() {
|
||||||
unsafe { (*caller_cells[uv_idx]).value }
|
unsafe { (*caller_cells[uv_idx]).value }
|
||||||
|
} else {
|
||||||
|
self.regs[rd]
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.regs[rd]
|
self.regs[rd]
|
||||||
}
|
};
|
||||||
} else {
|
let cell = self.gc_state.session_epoch.alloc(Cell::new(val, true));
|
||||||
self.regs[rd]
|
upvals[uv_idx] = cell as *mut Cell;
|
||||||
};
|
self.regs[rd] = cell.value;
|
||||||
let cell = self.gc_state.session_epoch.alloc(Cell::new(val, true));
|
return Ok(());
|
||||||
upvals[uv_idx] = cell as *mut Cell;
|
}
|
||||||
self.regs[rd] = cell.value;
|
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.regs[rd] = JsValue::undefined();
|
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> {
|
pub(crate) fn dispatch_store_upvalue(&mut self, a: usize, b: usize) -> Result<(), String> {
|
||||||
let uv_idx = b;
|
let uv_idx = b;
|
||||||
let src_val = self.regs[a];
|
let src_val = self.regs[a];
|
||||||
let callee = self.frames.last().unwrap().callee;
|
if let Some(callee) = self.current_callee() {
|
||||||
if callee.is_object() {
|
if callee.is_object() {
|
||||||
let obj = unsafe { &mut *callee.as_js_object_ptr() };
|
let obj = unsafe { &mut *callee.as_js_object_ptr() };
|
||||||
let upvals = obj.upvalues_slice_mut();
|
let upvals = obj.upvalues_slice_mut();
|
||||||
if uv_idx < upvals.len() {
|
if uv_idx < upvals.len() {
|
||||||
if !upvals[uv_idx].is_null() {
|
if !upvals[uv_idx].is_null() {
|
||||||
unsafe {
|
unsafe {
|
||||||
(*upvals[uv_idx]).value = src_val;
|
(*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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ pub(crate) struct InlineSyncState {
|
|||||||
pub(crate) save_stack: Vec<JsValue>,
|
pub(crate) save_stack: Vec<JsValue>,
|
||||||
pub(crate) spill_stack: Vec<JsValue>,
|
pub(crate) spill_stack: Vec<JsValue>,
|
||||||
pub(crate) cell_stack: Vec<Vec<*mut Cell>>,
|
pub(crate) cell_stack: Vec<Vec<*mut Cell>>,
|
||||||
|
pub(crate) inline_callee: Option<JsValue>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 基于寄存器的 JS 虚拟机:持有执行状态、寄存器文件、调用栈与 session 内存。
|
/// 基于寄存器的 JS 虚拟机:持有执行状态、寄存器文件、调用栈与 session 内存。
|
||||||
@@ -212,6 +213,10 @@ pub struct Vm {
|
|||||||
/// 调度循环检查该标志,跳过用调用结果写 `regs[target_reg]` —— 值改由 RETURN
|
/// 调度循环检查该标志,跳过用调用结果写 `regs[target_reg]` —— 值改由 RETURN
|
||||||
/// 处理器交付。
|
/// 处理器交付。
|
||||||
pub(crate) accessor_frame_target_reg: Option<u8>,
|
pub(crate) accessor_frame_target_reg: Option<u8>,
|
||||||
|
/// `call_bytecode_function_inline` 执行期间当前回调闭包;LOAD/STORE_UPVALUE 在
|
||||||
|
/// frames 为空(inline 隔离状态)时由此取闭包 upvalues。嵌套 inline 由
|
||||||
|
/// InlineSyncState 保存/恢复。
|
||||||
|
pub(crate) inline_callee: Option<JsValue>,
|
||||||
/// 分组保存 session arena / GC 簿记状态。
|
/// 分组保存 session arena / GC 簿记状态。
|
||||||
pub(crate) gc_state: GcState,
|
pub(crate) gc_state: GcState,
|
||||||
/// 分组保存 `Symbol` intern 状态。
|
/// 分组保存 `Symbol` intern 状态。
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ impl Vm {
|
|||||||
save_stack: std::mem::take(&mut self.save_stack),
|
save_stack: std::mem::take(&mut self.save_stack),
|
||||||
spill_stack: std::mem::take(&mut self.spill_stack),
|
spill_stack: std::mem::take(&mut self.spill_stack),
|
||||||
cell_stack: std::mem::take(&mut self.cell_stack),
|
cell_stack: std::mem::take(&mut self.cell_stack),
|
||||||
|
inline_callee: self.inline_callee,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.regs = [JsValue::undefined(); 256];
|
self.regs = [JsValue::undefined(); 256];
|
||||||
@@ -70,6 +71,8 @@ impl Vm {
|
|||||||
self.activate_immutables(sub_idx + 1, &sub.constants);
|
self.activate_immutables(sub_idx + 1, &sub.constants);
|
||||||
self.active_reg_limit = sub.n_registers.max(1);
|
self.active_reg_limit = sub.n_registers.max(1);
|
||||||
self.root_reg_limit = self.active_reg_limit;
|
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 {
|
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());
|
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.save_stack = saved.save_stack;
|
||||||
self.spill_stack = saved.spill_stack;
|
self.spill_stack = saved.spill_stack;
|
||||||
self.cell_stack = saved.cell_stack;
|
self.cell_stack = saved.cell_stack;
|
||||||
|
self.inline_callee = saved.inline_callee;
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ impl Vm {
|
|||||||
active_reg_limit: 0,
|
active_reg_limit: 0,
|
||||||
native_call_depth: 0,
|
native_call_depth: 0,
|
||||||
accessor_frame_target_reg: None,
|
accessor_frame_target_reg: None,
|
||||||
|
inline_callee: None,
|
||||||
gc_state: GcState {
|
gc_state: GcState {
|
||||||
session_epoch: bumpalo::Bump::new(),
|
session_epoch: bumpalo::Bump::new(),
|
||||||
session_gc: crate::session_gc::SessionGc::new(),
|
session_gc: crate::session_gc::SessionGc::new(),
|
||||||
@@ -111,6 +112,7 @@ impl Vm {
|
|||||||
active_reg_limit: 0,
|
active_reg_limit: 0,
|
||||||
native_call_depth: 0,
|
native_call_depth: 0,
|
||||||
accessor_frame_target_reg: None,
|
accessor_frame_target_reg: None,
|
||||||
|
inline_callee: None,
|
||||||
gc_state: GcState {
|
gc_state: GcState {
|
||||||
session_epoch: bumpalo::Bump::new(),
|
session_epoch: bumpalo::Bump::new(),
|
||||||
session_gc: crate::session_gc::SessionGc::new(),
|
session_gc: crate::session_gc::SessionGc::new(),
|
||||||
|
|||||||
Reference in New Issue
Block a user