mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
fix: 修复嵌套函数调用并接通闭包捕获链路
This commit is contained in:
@@ -1089,10 +1089,13 @@ impl Compiler {
|
||||
is_class_constructor: false,
|
||||
is_derived_constructor: false,
|
||||
needs_home_object: false,
|
||||
upvalue_captures: Vec::new(),
|
||||
cells_needed: ctx.scopes.symbols.scopes[0]
|
||||
.bindings
|
||||
.values()
|
||||
upvalue_captures: ctx.current_upvalue_captures.clone(),
|
||||
cells_needed: ctx
|
||||
.scopes
|
||||
.symbols
|
||||
.scopes
|
||||
.iter()
|
||||
.flat_map(|s| s.bindings.values())
|
||||
.filter(|b| b.is_captured.get())
|
||||
.count() as u8,
|
||||
})
|
||||
@@ -1193,10 +1196,13 @@ impl Compiler {
|
||||
is_class_constructor: false,
|
||||
is_derived_constructor: false,
|
||||
needs_home_object: false,
|
||||
upvalue_captures: Vec::new(),
|
||||
cells_needed: ctx.scopes.symbols.scopes[0]
|
||||
.bindings
|
||||
.values()
|
||||
upvalue_captures: ctx.current_upvalue_captures.clone(),
|
||||
cells_needed: ctx
|
||||
.scopes
|
||||
.symbols
|
||||
.scopes
|
||||
.iter()
|
||||
.flat_map(|s| s.bindings.values())
|
||||
.filter(|b| b.is_captured.get())
|
||||
.count() as u8,
|
||||
})
|
||||
|
||||
@@ -356,9 +356,6 @@ impl Compiler {
|
||||
) -> Result<(), String> {
|
||||
let var_reg = ctx.alloc_reg();
|
||||
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) {
|
||||
Ok(()) => var_reg,
|
||||
Err(_) => ctx.lookup(name).unwrap_or(var_reg),
|
||||
@@ -367,7 +364,13 @@ impl Compiler {
|
||||
ctx.declare(name, var_reg, kind, is_const)?;
|
||||
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);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ impl Compiler {
|
||||
if is_captured {
|
||||
let cell_idx = ctx.scopes.cell_registry.len() as u8;
|
||||
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 {
|
||||
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 needs_home_object = sub.needs_home_object;
|
||||
let upvalue_captures = sub.upvalue_captures.clone();
|
||||
let cells_needed = sub.cells_needed;
|
||||
let result = self.create_function_object(
|
||||
sub_idx,
|
||||
is_arrow,
|
||||
@@ -104,7 +103,7 @@ impl Vm {
|
||||
is_derived_constructor,
|
||||
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() {
|
||||
let mut upvals = Box::new(Vec::with_capacity(upvalue_captures.len()));
|
||||
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> {
|
||||
let cell_idx = opcode::imm16(instr) as usize;
|
||||
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 current = self.cell_stack.last_mut().unwrap();
|
||||
while current.len() <= cell_idx {
|
||||
@@ -137,19 +136,18 @@ impl Vm {
|
||||
}
|
||||
|
||||
#[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 current = self.cell_stack.last().unwrap();
|
||||
if cell_idx >= current.len() {
|
||||
self.regs[rd] = JsValue::undefined();
|
||||
return Ok(());
|
||||
let current = self.cell_stack.last_mut().unwrap();
|
||||
while current.len() <= cell_idx {
|
||||
current.push(std::ptr::null_mut());
|
||||
}
|
||||
let cell_ptr = current[cell_idx];
|
||||
if cell_ptr.is_null() {
|
||||
self.regs[rd] = JsValue::undefined();
|
||||
return Ok(());
|
||||
if current[cell_idx].is_null() {
|
||||
let val = self.regs[a];
|
||||
let cell = self.gc_state.session_epoch.alloc(Cell::new(val, true));
|
||||
current[cell_idx] = cell as *mut Cell;
|
||||
}
|
||||
self.regs[rd] = unsafe { (*cell_ptr).value };
|
||||
self.regs[rd] = unsafe { (*current[cell_idx]).value };
|
||||
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();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -769,7 +769,6 @@ impl Vm {
|
||||
self.sub_modules = Arc::new(callee_subs.clone());
|
||||
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.pc = 0;
|
||||
|
||||
Reference in New Issue
Block a user