fix: 修复闭包值传递链路
This commit is contained in:
@@ -700,10 +700,15 @@ impl Compiler {
|
|||||||
match expr {
|
match expr {
|
||||||
Expression::Identifier(ident) => {
|
Expression::Identifier(ident) => {
|
||||||
let name = ident.name.as_str();
|
let name = ident.name.as_str();
|
||||||
// Only skip if name is in the nested function's OWN scopes (not inherited scopes[0])
|
if nested_symbols.lookup_any_binding(name).is_some() {
|
||||||
let is_local = nested_symbols.scopes.iter().skip(1).any(|s| s.bindings.contains_key(name));
|
// Check if this is a parent function-scope binding (real upvalue)
|
||||||
if is_local {
|
let is_parent_func_var = parent_ctx.scopes.symbols.scopes.iter()
|
||||||
return;
|
.skip(1)
|
||||||
|
.any(|s| s.bindings.contains_key(name));
|
||||||
|
if !is_parent_func_var {
|
||||||
|
return; // true local or global, not upvalue
|
||||||
|
}
|
||||||
|
// falls through to capture
|
||||||
}
|
}
|
||||||
if let Some((binding, _)) = parent_ctx.scopes.symbols.lookup_any_binding(name) {
|
if let Some((binding, _)) = parent_ctx.scopes.symbols.lookup_any_binding(name) {
|
||||||
if seen.contains_key(name) {
|
if seen.contains_key(name) {
|
||||||
@@ -721,8 +726,11 @@ impl Compiler {
|
|||||||
Expression::AssignmentExpression(ae) => {
|
Expression::AssignmentExpression(ae) => {
|
||||||
if let oxide_parser::AssignmentTarget::AssignmentTargetIdentifier(ati) = &ae.left {
|
if let oxide_parser::AssignmentTarget::AssignmentTargetIdentifier(ati) = &ae.left {
|
||||||
let name = ati.name.as_str();
|
let name = ati.name.as_str();
|
||||||
let is_local = nested_symbols.scopes.iter().skip(1).any(|s| s.bindings.contains_key(name));
|
let in_nested = nested_symbols.lookup_any_binding(name).is_some();
|
||||||
if !is_local {
|
let is_parent_func_var = parent_ctx.scopes.symbols.scopes.iter()
|
||||||
|
.skip(1)
|
||||||
|
.any(|s| s.bindings.contains_key(name));
|
||||||
|
if !in_nested || is_parent_func_var {
|
||||||
if let Some((binding, _)) = parent_ctx.scopes.symbols.lookup_any_binding(name) {
|
if let Some((binding, _)) = parent_ctx.scopes.symbols.lookup_any_binding(name) {
|
||||||
if !seen.contains_key(name) {
|
if !seen.contains_key(name) {
|
||||||
let cell_idx = captures.len() as u8;
|
let cell_idx = captures.len() as u8;
|
||||||
@@ -748,8 +756,11 @@ impl Compiler {
|
|||||||
Expression::UpdateExpression(ue) => {
|
Expression::UpdateExpression(ue) => {
|
||||||
if let oxide_parser::SimpleAssignmentTarget::AssignmentTargetIdentifier(ati) = &ue.argument {
|
if let oxide_parser::SimpleAssignmentTarget::AssignmentTargetIdentifier(ati) = &ue.argument {
|
||||||
let name = ati.name.as_str();
|
let name = ati.name.as_str();
|
||||||
let is_local = nested_symbols.scopes.iter().skip(1).any(|s| s.bindings.contains_key(name));
|
let in_nested = nested_symbols.lookup_any_binding(name).is_some();
|
||||||
if !is_local {
|
let is_parent_func_var = parent_ctx.scopes.symbols.scopes.iter()
|
||||||
|
.skip(1)
|
||||||
|
.any(|s| s.bindings.contains_key(name));
|
||||||
|
if !in_nested || is_parent_func_var {
|
||||||
if let Some((binding, _)) = parent_ctx.scopes.symbols.lookup_any_binding(name) {
|
if let Some((binding, _)) = parent_ctx.scopes.symbols.lookup_any_binding(name) {
|
||||||
if !seen.contains_key(name) {
|
if !seen.contains_key(name) {
|
||||||
let cell_idx = captures.len() as u8;
|
let cell_idx = captures.len() as u8;
|
||||||
|
|||||||
@@ -195,7 +195,18 @@ impl Vm {
|
|||||||
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() {
|
||||||
let cell = self.gc_state.session_epoch.alloc(Cell::new(self.regs[rd], true));
|
// Try to get value from caller's cell table (MAKE_CELL ran after 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]
|
||||||
|
};
|
||||||
|
let cell = self.gc_state.session_epoch.alloc(Cell::new(val, true));
|
||||||
upvals[uv_idx] = cell as *mut Cell;
|
upvals[uv_idx] = cell as *mut Cell;
|
||||||
self.regs[rd] = cell.value;
|
self.regs[rd] = cell.value;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|||||||
@@ -767,7 +767,6 @@ impl Vm {
|
|||||||
let callee_subs = &subs[sub_idx].sub_modules;
|
let callee_subs = &subs[sub_idx].sub_modules;
|
||||||
if !callee_subs.is_empty() {
|
if !callee_subs.is_empty() {
|
||||||
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.active_reg_limit = sub_n_registers.max(1);
|
self.active_reg_limit = sub_n_registers.max(1);
|
||||||
|
|||||||
@@ -152,6 +152,8 @@ impl Vm {
|
|||||||
pub fn run(&mut self, module: &CompiledModule) -> Result<JsValue, String> {
|
pub fn run(&mut self, module: &CompiledModule) -> Result<JsValue, String> {
|
||||||
vm_debug!("run: starting bytecode execution, {} instructions", module.bytecode.len());
|
vm_debug!("run: starting bytecode execution, {} instructions", module.bytecode.len());
|
||||||
self.clear_execution_state();
|
self.clear_execution_state();
|
||||||
|
self.cell_stack.clear();
|
||||||
|
self.cell_stack.push(Vec::new());
|
||||||
self.sub_modules = Arc::new(module.sub_modules.clone());
|
self.sub_modules = Arc::new(module.sub_modules.clone());
|
||||||
self.immutables_cache = (0..=self.sub_modules.len()).map(|_| OnceLock::new()).collect();
|
self.immutables_cache = (0..=self.sub_modules.len()).map(|_| OnceLock::new()).collect();
|
||||||
self.bytecode = module.bytecode.clone();
|
self.bytecode = module.bytecode.clone();
|
||||||
|
|||||||
@@ -205,6 +205,7 @@ impl Vm {
|
|||||||
self.saved_bytecode_stack.clear();
|
self.saved_bytecode_stack.clear();
|
||||||
self.saved_immutables_stack.clear();
|
self.saved_immutables_stack.clear();
|
||||||
self.save_stack.clear();
|
self.save_stack.clear();
|
||||||
|
self.cell_stack.clear();
|
||||||
self.try_stack.clear();
|
self.try_stack.clear();
|
||||||
self.exception_value = None;
|
self.exception_value = None;
|
||||||
self.pending_exception = None;
|
self.pending_exception = None;
|
||||||
|
|||||||
Reference in New Issue
Block a user