feat: 重构for-in为预计算+隐藏局部变量模式
ForInInit: 改为预计算所有迭代元素为数组 ForInNext: 接收items_slot+idx_slot操作数,从局部变量读取 编译器: for-in迭代器使用隐藏局部变量(items, idx),隔离于value stack 修复: for-in在函数调用嵌套场景下栈对齐问题 修复: break路径在for-in中正确弹出循环变量 修复: ForInNext退出时push Nil以保持栈平衡 修复: 跳转偏移计算(移除emit_loop_jump中错误的-3) 通过: 17/18 benchmark测试 (全部for-in相关测试通过) 已知限制: 3层嵌套闭包(10c)需传递式upvalue支持
This commit is contained in:
+27
-18
@@ -511,32 +511,41 @@ impl Vm {
|
||||
// --- For-in ---
|
||||
OpCode::ForInInit => {
|
||||
let iterable = self.stack.pop().unwrap();
|
||||
// Push iterator state: (collection, index)
|
||||
let iter = Value::Number(0.0);
|
||||
self.stack.push(iterable);
|
||||
self.stack.push(iter);
|
||||
let items = self.for_in_items(&iterable);
|
||||
self.stack.push(Value::Array(Rc::new(RefCell::new(items))));
|
||||
self.advance_ip(SIZE_OP);
|
||||
}
|
||||
OpCode::ForInNext => {
|
||||
let exit_offset = read_i16(code, ip) as isize;
|
||||
let exit_ip = ((ip as isize) + exit_offset) as usize;
|
||||
let iter_idx = self.stack.pop().unwrap(); // current index
|
||||
let collection = self.stack.pop().unwrap(); // the iterable
|
||||
// Encoding: opcode(1) + items_slot(1) + idx_slot(1) + exit_offset(2) = 5
|
||||
let items_slot = code[ip + 1] as usize;
|
||||
let idx_slot = code[ip + 2] as usize;
|
||||
let exit_offset = ((code[ip + 3] as u16) | ((code[ip + 4] as u16) << 8)) as i16;
|
||||
let exit_ip = ((ip as isize) + exit_offset as isize) as usize;
|
||||
let base = self.frames.last().unwrap().stack_base;
|
||||
|
||||
// Read index from local slot
|
||||
let idx_val = self.stack[base + idx_slot].clone();
|
||||
let idx = self.as_usize(&idx_val, "for-in index")?;
|
||||
let items_val = self.stack[base + items_slot].clone();
|
||||
|
||||
let items = match &items_val {
|
||||
Value::Array(arr) => arr.borrow(),
|
||||
_ => return Err(RuntimeError::RuntimeError {
|
||||
message: "ForInNext: items is not an array".into(),
|
||||
token: None,
|
||||
}),
|
||||
};
|
||||
|
||||
let idx = self.as_number(&iter_idx)? as usize;
|
||||
let items = self.for_in_items(&collection);
|
||||
if idx >= items.len() {
|
||||
// Done iterating — push back state and jump to exit
|
||||
self.stack.push(collection);
|
||||
self.stack.push(iter_idx);
|
||||
// Done: push Nil (keeps stack balanced for Pop at exit)
|
||||
self.stack.push(Value::Nil);
|
||||
self.advance_ip_to(exit_ip);
|
||||
} else {
|
||||
// Push back incremented state
|
||||
self.stack.push(collection);
|
||||
self.stack.push(Value::Number((idx + 1) as f64));
|
||||
// Push the current value for the loop body
|
||||
// Push current element for loop body
|
||||
self.stack.push(items[idx].clone());
|
||||
self.advance_ip(SIZE_U16);
|
||||
// Increment index in local slot
|
||||
self.stack[base + idx_slot] = Value::Number((idx + 1) as f64);
|
||||
self.advance_ip(5); // SIZE_FORIN_NEXT = 5
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user