fix: 修复嵌套函数调用并接通闭包捕获链路
This commit is contained in:
@@ -1089,10 +1089,13 @@ impl Compiler {
|
|||||||
is_class_constructor: false,
|
is_class_constructor: false,
|
||||||
is_derived_constructor: false,
|
is_derived_constructor: false,
|
||||||
needs_home_object: false,
|
needs_home_object: false,
|
||||||
upvalue_captures: Vec::new(),
|
upvalue_captures: ctx.current_upvalue_captures.clone(),
|
||||||
cells_needed: ctx.scopes.symbols.scopes[0]
|
cells_needed: ctx
|
||||||
.bindings
|
.scopes
|
||||||
.values()
|
.symbols
|
||||||
|
.scopes
|
||||||
|
.iter()
|
||||||
|
.flat_map(|s| s.bindings.values())
|
||||||
.filter(|b| b.is_captured.get())
|
.filter(|b| b.is_captured.get())
|
||||||
.count() as u8,
|
.count() as u8,
|
||||||
})
|
})
|
||||||
@@ -1193,10 +1196,13 @@ impl Compiler {
|
|||||||
is_class_constructor: false,
|
is_class_constructor: false,
|
||||||
is_derived_constructor: false,
|
is_derived_constructor: false,
|
||||||
needs_home_object: false,
|
needs_home_object: false,
|
||||||
upvalue_captures: Vec::new(),
|
upvalue_captures: ctx.current_upvalue_captures.clone(),
|
||||||
cells_needed: ctx.scopes.symbols.scopes[0]
|
cells_needed: ctx
|
||||||
.bindings
|
.scopes
|
||||||
.values()
|
.symbols
|
||||||
|
.scopes
|
||||||
|
.iter()
|
||||||
|
.flat_map(|s| s.bindings.values())
|
||||||
.filter(|b| b.is_captured.get())
|
.filter(|b| b.is_captured.get())
|
||||||
.count() as u8,
|
.count() as u8,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -356,9 +356,6 @@ impl Compiler {
|
|||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let var_reg = ctx.alloc_reg();
|
let var_reg = ctx.alloc_reg();
|
||||||
let target_reg = if matches!(kind, VariableDeclarationKind::Var) {
|
let target_reg = if matches!(kind, VariableDeclarationKind::Var) {
|
||||||
// `var` is hoisted, so the count pass already registered the name. A redeclare
|
|
||||||
// here reuses that existing register instead of erroring; the freshly allocated
|
|
||||||
// reg matches it (count/emit allocate in lock-step) so either resolves the same.
|
|
||||||
match ctx.declare(name, var_reg, kind, is_const) {
|
match ctx.declare(name, var_reg, kind, is_const) {
|
||||||
Ok(()) => var_reg,
|
Ok(()) => var_reg,
|
||||||
Err(_) => ctx.lookup(name).unwrap_or(var_reg),
|
Err(_) => ctx.lookup(name).unwrap_or(var_reg),
|
||||||
@@ -367,7 +364,13 @@ impl Compiler {
|
|||||||
ctx.declare(name, var_reg, kind, is_const)?;
|
ctx.declare(name, var_reg, kind, is_const)?;
|
||||||
var_reg
|
var_reg
|
||||||
};
|
};
|
||||||
ctx.emit(opcode::encode(OpCode::STORE_VAR, target_reg, src_reg, if is_const { 1 } else { 0 }));
|
if ctx.scopes.symbols.lookup_is_captured(name) {
|
||||||
|
let cell_idx = ctx.scopes.cell_registry.len() as u8;
|
||||||
|
ctx.scopes.cell_registry.push((name.to_string(), cell_idx));
|
||||||
|
ctx.emit(opcode::encode(OpCode::MAKE_CELL, src_reg, cell_idx, 0));
|
||||||
|
} else {
|
||||||
|
ctx.emit(opcode::encode(OpCode::STORE_VAR, target_reg, src_reg, if is_const { 1 } else { 0 }));
|
||||||
|
}
|
||||||
ctx.init_var(name);
|
ctx.init_var(name);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ impl Compiler {
|
|||||||
if is_captured {
|
if is_captured {
|
||||||
let cell_idx = ctx.scopes.cell_registry.len() as u8;
|
let cell_idx = ctx.scopes.cell_registry.len() as u8;
|
||||||
ctx.scopes.cell_registry.push((bi.name.to_string(), cell_idx));
|
ctx.scopes.cell_registry.push((bi.name.to_string(), cell_idx));
|
||||||
ctx.emit(opcode::encode(OpCode::MAKE_CELL, var_reg, cell_idx, 0));
|
ctx.emit(opcode::encode(OpCode::MAKE_CELL, tmp, cell_idx, 0));
|
||||||
} else {
|
} else {
|
||||||
ctx.emit(opcode::encode(OpCode::STORE_VAR, var_reg, tmp, 0));
|
ctx.emit(opcode::encode(OpCode::STORE_VAR, var_reg, tmp, 0));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,7 +96,6 @@ impl Vm {
|
|||||||
let is_derived_constructor = sub.is_derived_constructor;
|
let is_derived_constructor = sub.is_derived_constructor;
|
||||||
let needs_home_object = sub.needs_home_object;
|
let needs_home_object = sub.needs_home_object;
|
||||||
let upvalue_captures = sub.upvalue_captures.clone();
|
let upvalue_captures = sub.upvalue_captures.clone();
|
||||||
let cells_needed = sub.cells_needed;
|
|
||||||
let result = self.create_function_object(
|
let result = self.create_function_object(
|
||||||
sub_idx,
|
sub_idx,
|
||||||
is_arrow,
|
is_arrow,
|
||||||
@@ -104,7 +103,7 @@ impl Vm {
|
|||||||
is_derived_constructor,
|
is_derived_constructor,
|
||||||
needs_home_object,
|
needs_home_object,
|
||||||
);
|
);
|
||||||
if !upvalue_captures.is_empty() && cells_needed > 0 {
|
if !upvalue_captures.is_empty() {
|
||||||
if let Some(current_cells) = self.cell_stack.last() {
|
if let Some(current_cells) = self.cell_stack.last() {
|
||||||
let mut upvals = Box::new(Vec::with_capacity(upvalue_captures.len()));
|
let mut upvals = Box::new(Vec::with_capacity(upvalue_captures.len()));
|
||||||
for capture in &upvalue_captures {
|
for capture in &upvalue_captures {
|
||||||
@@ -126,7 +125,7 @@ impl Vm {
|
|||||||
pub(crate) fn dispatch_make_cell(&mut self, rd: usize, instr: u32) -> Result<(), String> {
|
pub(crate) fn dispatch_make_cell(&mut self, rd: usize, instr: u32) -> Result<(), String> {
|
||||||
let cell_idx = opcode::imm16(instr) as usize;
|
let cell_idx = opcode::imm16(instr) as usize;
|
||||||
let value = self.regs[rd];
|
let value = self.regs[rd];
|
||||||
let cell = self.gc_state.session_epoch.alloc(Cell::new(value, false));
|
let cell = self.gc_state.session_epoch.alloc(Cell::new(value, true));
|
||||||
let cell_ptr = cell as *mut Cell;
|
let cell_ptr = cell as *mut Cell;
|
||||||
let current = self.cell_stack.last_mut().unwrap();
|
let current = self.cell_stack.last_mut().unwrap();
|
||||||
while current.len() <= cell_idx {
|
while current.len() <= cell_idx {
|
||||||
@@ -137,19 +136,18 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) fn dispatch_cell_get(&mut self, rd: usize, _a: usize, b: usize) -> Result<(), String> {
|
pub(crate) fn dispatch_cell_get(&mut self, rd: usize, a: usize, b: usize) -> Result<(), String> {
|
||||||
let cell_idx = b;
|
let cell_idx = b;
|
||||||
let current = self.cell_stack.last().unwrap();
|
let current = self.cell_stack.last_mut().unwrap();
|
||||||
if cell_idx >= current.len() {
|
while current.len() <= cell_idx {
|
||||||
self.regs[rd] = JsValue::undefined();
|
current.push(std::ptr::null_mut());
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
let cell_ptr = current[cell_idx];
|
if current[cell_idx].is_null() {
|
||||||
if cell_ptr.is_null() {
|
let val = self.regs[a];
|
||||||
self.regs[rd] = JsValue::undefined();
|
let cell = self.gc_state.session_epoch.alloc(Cell::new(val, true));
|
||||||
return Ok(());
|
current[cell_idx] = cell as *mut Cell;
|
||||||
}
|
}
|
||||||
self.regs[rd] = unsafe { (*cell_ptr).value };
|
self.regs[rd] = unsafe { (*current[cell_idx]).value };
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,6 +184,23 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Cell not yet created (hoisting order: CREATE_CLOSURE before MAKE_CELL).
|
||||||
|
// Create cell lazily with caller's register value.
|
||||||
|
self.lazy_create_upvalue_cell(rd, uv_idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
||||||
|
let cell = self.gc_state.session_epoch.alloc(Cell::new(self.regs[rd], true));
|
||||||
|
upvals[uv_idx] = cell as *mut Cell;
|
||||||
|
self.regs[rd] = cell.value;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
self.regs[rd] = JsValue::undefined();
|
self.regs[rd] = JsValue::undefined();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -769,7 +769,6 @@ impl Vm {
|
|||||||
self.sub_modules = Arc::new(callee_subs.clone());
|
self.sub_modules = Arc::new(callee_subs.clone());
|
||||||
self.immutables_cache = (0..=callee_subs.len()).map(|_| OnceLock::new()).collect();
|
self.immutables_cache = (0..=callee_subs.len()).map(|_| OnceLock::new()).collect();
|
||||||
}
|
}
|
||||||
self.cell_stack.push(Vec::with_capacity(subs[sub_idx].cells_needed as usize));
|
|
||||||
|
|
||||||
self.active_reg_limit = sub_n_registers.max(1);
|
self.active_reg_limit = sub_n_registers.max(1);
|
||||||
self.pc = 0;
|
self.pc = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user