for-of 迭代器栈条目化:迭代器与最近 next 结果配对存放
单一 last_for_of_result 槽被嵌套迭代覆盖,CLOSE 判定本迭代器是否 自然 done 时误读他者结果,导致数组解构/spread/嵌套 for-of 提前退出 漏调或误调 return()。改为栈条目 (iterator, last_result) 配对: - IterState.for_of_iters 元素改 ForOfEntry,删除 last_for_of_result - INIT 压条目,DONE 写本条目,NEXT/CLOSE 读本条目结果判 done - GC mark/rewrite、inline save/restore、挂起帧快照同步配对遍历 - for-await-of 数组解构提前 break 现正确触发 return()(任务 40 样例)
This commit is contained in:
@@ -839,8 +839,10 @@ mod tests {
|
||||
vm.regs[1] = JsValue::from_js_object(child_session);
|
||||
vm.exception_value = Some(JsValue::from_js_object(root_session));
|
||||
vm.pending_exception = Some(JsValue::from_js_object(child_session));
|
||||
vm.iters.for_of_iters.push(JsValue::from_js_object(child_session));
|
||||
vm.iters.last_for_of_result = JsValue::from_js_object(root_session);
|
||||
vm.iters.for_of_iters.push(crate::vm_state::ForOfEntry {
|
||||
iterator: JsValue::from_js_object(child_session),
|
||||
last_result: JsValue::from_js_object(root_session),
|
||||
});
|
||||
|
||||
let mut roots = Vec::new();
|
||||
vm.for_each_root(|v| roots.push(v));
|
||||
|
||||
@@ -13,6 +13,7 @@ use oxide_types::object::Cell;
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
use crate::vm::{CallFrame, Completion, ForInIter, TryHandler, Vm};
|
||||
use crate::vm_state::ForOfEntry;
|
||||
|
||||
/// 挂起执行上下文快照(三份状态结构体共享的执行核心)。
|
||||
pub(crate) struct SuspendedFrame {
|
||||
@@ -30,8 +31,7 @@ pub(crate) struct SuspendedFrame {
|
||||
pub cell_stack: Vec<Vec<*mut Cell>>,
|
||||
pub try_stack: Vec<TryHandler>,
|
||||
pub for_in_iters: Vec<*mut ForInIter<'static>>,
|
||||
pub for_of_iters: Vec<JsValue>,
|
||||
pub last_for_of_result: JsValue,
|
||||
pub for_of_iters: Vec<ForOfEntry>,
|
||||
/// `yield*` 委托中的内层迭代器;异步函数恒为 None。
|
||||
pub delegated_iterator: Option<JsValue>,
|
||||
pub saved_bytecode_stack: Vec<Arc<[opcode::Instr]>>,
|
||||
@@ -58,7 +58,6 @@ impl SuspendedFrame {
|
||||
try_stack: Vec::new(),
|
||||
for_in_iters: Vec::new(),
|
||||
for_of_iters: Vec::new(),
|
||||
last_for_of_result: JsValue::undefined(),
|
||||
delegated_iterator: None,
|
||||
saved_bytecode_stack: Vec::new(),
|
||||
saved_immutables_stack: Vec::new(),
|
||||
@@ -96,7 +95,6 @@ impl SuspendedFrame {
|
||||
self.try_stack = std::mem::take(&mut vm.try_stack);
|
||||
self.for_in_iters = std::mem::take(&mut vm.iters.for_in_iters);
|
||||
self.for_of_iters = std::mem::take(&mut vm.iters.for_of_iters);
|
||||
self.last_for_of_result = vm.iters.last_for_of_result;
|
||||
self.delegated_iterator = std::mem::take(&mut vm.delegated_iterator);
|
||||
self.saved_bytecode_stack = std::mem::take(&mut vm.saved_bytecode_stack);
|
||||
self.saved_immutables_stack = std::mem::take(&mut vm.saved_immutables_stack);
|
||||
@@ -134,7 +132,6 @@ impl SuspendedFrame {
|
||||
vm.try_stack = std::mem::take(&mut self.try_stack);
|
||||
vm.iters.for_in_iters = std::mem::take(&mut self.for_in_iters);
|
||||
vm.iters.for_of_iters = std::mem::take(&mut self.for_of_iters);
|
||||
vm.iters.last_for_of_result = self.last_for_of_result;
|
||||
vm.delegated_iterator = std::mem::take(&mut self.delegated_iterator);
|
||||
vm.saved_bytecode_stack = std::mem::take(&mut self.saved_bytecode_stack);
|
||||
vm.saved_immutables_stack = std::mem::take(&mut self.saved_immutables_stack);
|
||||
@@ -174,10 +171,10 @@ impl SuspendedFrame {
|
||||
f(unsafe { &*p }.value);
|
||||
}
|
||||
}
|
||||
for v in &self.for_of_iters {
|
||||
f(*v);
|
||||
for entry in &self.for_of_iters {
|
||||
f(entry.iterator);
|
||||
f(entry.last_result);
|
||||
}
|
||||
f(self.last_for_of_result);
|
||||
if let Some(it) = self.delegated_iterator {
|
||||
f(it);
|
||||
}
|
||||
@@ -228,10 +225,10 @@ impl SuspendedFrame {
|
||||
cell.value = rewrite(cell.value);
|
||||
}
|
||||
}
|
||||
for v in &mut self.for_of_iters {
|
||||
*v = rewrite(*v);
|
||||
for entry in &mut self.for_of_iters {
|
||||
entry.iterator = rewrite(entry.iterator);
|
||||
entry.last_result = rewrite(entry.last_result);
|
||||
}
|
||||
self.last_for_of_result = rewrite(self.last_for_of_result);
|
||||
self.delegated_iterator = self.delegated_iterator.map(&mut rewrite);
|
||||
self.exception_value = self.exception_value.map(&mut rewrite);
|
||||
self.pending_exception = self.pending_exception.map(&mut rewrite);
|
||||
@@ -291,8 +288,15 @@ impl SuspendedFrame {
|
||||
cell_stack: self.cell_stack.clone(),
|
||||
try_stack: self.try_stack.clone(),
|
||||
for_in_iters: self.for_in_iters.clone(),
|
||||
for_of_iters: self.for_of_iters.iter().copied().map(&mut rewrite).collect(),
|
||||
last_for_of_result: rewrite(self.last_for_of_result),
|
||||
for_of_iters: self
|
||||
.for_of_iters
|
||||
.iter()
|
||||
.copied()
|
||||
.map(|entry| ForOfEntry {
|
||||
iterator: rewrite(entry.iterator),
|
||||
last_result: rewrite(entry.last_result),
|
||||
})
|
||||
.collect(),
|
||||
delegated_iterator: self.delegated_iterator.map(&mut rewrite),
|
||||
saved_bytecode_stack: self.saved_bytecode_stack.clone(),
|
||||
saved_immutables_stack: self.saved_immutables_stack.clone(),
|
||||
@@ -314,7 +318,7 @@ impl SuspendedFrame {
|
||||
self.bytecode.len() as u64 * std::mem::size_of::<opcode::Instr>() as u64
|
||||
+ self.spill_stack.capacity() as u64 * std::mem::size_of::<JsValue>() as u64
|
||||
+ self.save_stack.capacity() as u64 * std::mem::size_of::<JsValue>() as u64
|
||||
+ self.for_of_iters.capacity() as u64 * std::mem::size_of::<JsValue>() as u64
|
||||
+ self.for_of_iters.capacity() as u64 * std::mem::size_of::<ForOfEntry>() as u64
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,8 +372,10 @@ mod tests {
|
||||
frame_depth: 0,
|
||||
for_of_depth: 0,
|
||||
});
|
||||
frame.for_of_iters.push(JsValue::float(6.0));
|
||||
frame.last_for_of_result = JsValue::float(7.0);
|
||||
frame.for_of_iters.push(ForOfEntry {
|
||||
iterator: JsValue::float(6.0),
|
||||
last_result: JsValue::float(7.0),
|
||||
});
|
||||
frame.delegated_iterator = Some(JsValue::float(8.0));
|
||||
frame.saved_bytecode_stack.push(Arc::from(vec![0u32]));
|
||||
frame.saved_immutables_stack.push(std::ptr::slice_from_raw_parts(std::ptr::null(), 0));
|
||||
|
||||
+17
-12
@@ -12,7 +12,7 @@ use smallvec::SmallVec;
|
||||
pub use crate::bindings::init_kernel_builtins;
|
||||
use crate::native::NativeFn;
|
||||
use crate::session_gc::SessionGc;
|
||||
use crate::vm_state::{GcState, IterState, ProfilingState, SymbolState};
|
||||
use crate::vm_state::{ForOfEntry, GcState, IterState, ProfilingState, SymbolState};
|
||||
use crate::{vm_debug, vm_error, vm_trace, vm_warn};
|
||||
use oxide_kernel::kernel::{KernelCore, KernelSession};
|
||||
use oxide_runtime_api as coercion;
|
||||
@@ -309,8 +309,7 @@ pub(crate) struct InlineSyncState {
|
||||
pub(crate) pending_error_kind: Option<&'static str>,
|
||||
pub(crate) pending_completion: Option<Completion>,
|
||||
pub(crate) for_in_iters: Vec<*mut ForInIter<'static>>,
|
||||
pub(crate) for_of_iters: Vec<JsValue>,
|
||||
pub(crate) last_for_of_result: JsValue,
|
||||
pub(crate) for_of_iters: Vec<ForOfEntry>,
|
||||
pub(crate) saved_bytecode_stack: Vec<Arc<[opcode::Instr]>>,
|
||||
pub(crate) saved_immutables_stack: Vec<*const [JsValue]>,
|
||||
pub(crate) save_stack: Vec<JsValue>,
|
||||
@@ -727,10 +726,10 @@ impl Vm {
|
||||
f(self.async_context.unwrap_or(JsValue::undefined()));
|
||||
f(self.async_gen_context.unwrap_or(JsValue::undefined()));
|
||||
f(self.inline_callee.unwrap_or(JsValue::undefined()));
|
||||
for &v in &self.iters.for_of_iters {
|
||||
f(v);
|
||||
for &entry in &self.iters.for_of_iters {
|
||||
f(entry.iterator);
|
||||
f(entry.last_result);
|
||||
}
|
||||
f(self.iters.last_for_of_result);
|
||||
// 微任务队列中的处理器/能力/值都是 GC 根。
|
||||
for job in &self.job_queue {
|
||||
crate::promise::for_each_job_value(job, &mut f);
|
||||
@@ -791,10 +790,10 @@ impl Vm {
|
||||
self.async_context = self.async_context.map(&mut rewrite);
|
||||
self.async_gen_context = self.async_gen_context.map(&mut rewrite);
|
||||
self.inline_callee = self.inline_callee.map(&mut rewrite);
|
||||
for v in &mut self.iters.for_of_iters {
|
||||
*v = rewrite(*v);
|
||||
for entry in &mut self.iters.for_of_iters {
|
||||
entry.iterator = rewrite(entry.iterator);
|
||||
entry.last_result = rewrite(entry.last_result);
|
||||
}
|
||||
self.iters.last_for_of_result = rewrite(self.iters.last_for_of_result);
|
||||
// 微任务队列中的值随 sweep 重写。
|
||||
for job in &mut self.job_queue {
|
||||
crate::promise::rewrite_job_values(job, &mut rewrite);
|
||||
@@ -2255,7 +2254,7 @@ fn rehome_subtree(module: &CompiledModule, base: u32, out: &mut Vec<Arc<Compiled
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{opcode, JsValue, TryHandler, Vm};
|
||||
use super::{opcode, ForOfEntry, JsValue, TryHandler, Vm};
|
||||
use oxide_bytecode::module::CompiledModule;
|
||||
use oxide_runtime_api::{NativeResult, VmHost};
|
||||
use oxide_types::object::NativeFnPtr;
|
||||
@@ -2381,7 +2380,10 @@ mod tests {
|
||||
vm.iters
|
||||
.for_in_iters
|
||||
.push(std::ptr::dangling_mut::<super::ForInIter<'static>>());
|
||||
vm.iters.for_of_iters.push(JsValue::undefined());
|
||||
vm.iters.for_of_iters.push(ForOfEntry {
|
||||
iterator: JsValue::undefined(),
|
||||
last_result: JsValue::undefined(),
|
||||
});
|
||||
vm.saved_bytecode_stack
|
||||
.push(Arc::from(vec![opcode::encode(opcode::OpCode::HALT, 0, 0, 0)]));
|
||||
vm.saved_immutables_stack
|
||||
@@ -2437,7 +2439,10 @@ mod tests {
|
||||
..CompiledModule::new()
|
||||
};
|
||||
let mut vm = Vm::new();
|
||||
vm.iters.for_of_iters.push(JsValue::undefined());
|
||||
vm.iters.for_of_iters.push(ForOfEntry {
|
||||
iterator: JsValue::undefined(),
|
||||
last_result: JsValue::undefined(),
|
||||
});
|
||||
|
||||
vm.run(&module).expect("FOR_OF_CLOSE should tolerate non-object sentinel");
|
||||
|
||||
|
||||
@@ -538,7 +538,6 @@ impl Vm {
|
||||
match oxide_builtins::iterator::make_iterator_for_value(self, iterable) {
|
||||
Ok(iterator) => {
|
||||
self.iters.push_for_of(iterator);
|
||||
self.iters.clear_last_for_of_result();
|
||||
Ok(())
|
||||
}
|
||||
Err(err) => {
|
||||
@@ -557,7 +556,6 @@ impl Vm {
|
||||
match crate::async_from_sync::make_async_iterator(self, iterable) {
|
||||
Ok(iterator) => {
|
||||
self.iters.push_for_of(iterator);
|
||||
self.iters.clear_last_for_of_result();
|
||||
Ok(())
|
||||
}
|
||||
Err(err) => {
|
||||
@@ -594,14 +592,14 @@ impl Vm {
|
||||
}
|
||||
|
||||
/// for-await-of 步进完成检查:读取 `AWAIT` 恢复值(a 槽,即迭代器结果对象)的
|
||||
/// `done`,写入 last_for_of_result 并把 `!done` 写 rd(供 JMP_IF_FALSE 分支)。
|
||||
/// `done`,写入本迭代器条目结果并把 `!done` 写 rd(供 JMP_IF_FALSE 分支)。
|
||||
pub(crate) fn dispatch_for_await_of_done(&mut self, rd: usize, a: usize) -> Result<(), String> {
|
||||
vm_trace!("FOR_AWAIT_OF_DONE rd={} r{}={:?}", rd, a, self.regs[a]);
|
||||
let result = self.regs[a];
|
||||
if !result.is_object() {
|
||||
return self.raise_type_error("iterator result is not an object");
|
||||
}
|
||||
self.iters.set_last_for_of_result(result);
|
||||
self.iters.set_last_result(result);
|
||||
let result_obj = unsafe { &*result.as_js_object_ptr() };
|
||||
let done_si = self.kernel_core.perm_interner().intern("done").0;
|
||||
let done_val = match self.ordinary_get(result_obj, done_si, result) {
|
||||
@@ -616,10 +614,11 @@ impl Vm {
|
||||
/// 调用 `return()`,其返回的 promise 经 await 挂起,恢复后继续循环后的指令。
|
||||
pub(crate) fn dispatch_for_await_of_close(&mut self) -> Result<(), String> {
|
||||
vm_trace!("FOR_AWAIT_OF_CLOSE");
|
||||
let Some(iterator) = self.iters.pop_for_of() else {
|
||||
let Some(entry) = self.iters.pop_for_of() else {
|
||||
return Ok(());
|
||||
};
|
||||
let result = self.iters.last_for_of_result();
|
||||
let iterator = entry.iterator;
|
||||
let result = entry.last_result;
|
||||
if result.is_object() {
|
||||
let result_obj = unsafe { &*result.as_js_object_ptr() };
|
||||
let done_si = self.kernel_core.perm_interner().intern("done").0;
|
||||
@@ -678,7 +677,7 @@ impl Vm {
|
||||
Err(e) => return self.throw_for_of_error(e),
|
||||
};
|
||||
let done = to_boolean(done_val);
|
||||
self.iters.set_last_for_of_result(result);
|
||||
self.iters.set_last_result(result);
|
||||
self.regs[rd] = JsValue::bool(!done);
|
||||
Ok(())
|
||||
}
|
||||
@@ -686,7 +685,7 @@ impl Vm {
|
||||
pub(crate) fn dispatch_for_of_next(&mut self, rd: usize) -> Result<(), String> {
|
||||
vm_trace!("FOR_OF_NEXT rd={}", rd);
|
||||
self.last_uncaught_value = None;
|
||||
let result = self.iters.last_for_of_result();
|
||||
let result = self.iters.last_result();
|
||||
if !result.is_object() {
|
||||
self.regs[rd] = JsValue::undefined();
|
||||
return Ok(());
|
||||
@@ -716,12 +715,13 @@ impl Vm {
|
||||
|
||||
pub(crate) fn dispatch_for_of_close(&mut self) -> Result<(), String> {
|
||||
vm_trace!("FOR_OF_CLOSE");
|
||||
let Some(iterator) = self.iters.pop_for_of() else {
|
||||
let Some(entry) = self.iters.pop_for_of() else {
|
||||
return Ok(());
|
||||
};
|
||||
let iterator = entry.iterator;
|
||||
let result = entry.last_result;
|
||||
// 迭代已自然结束(最后一次 next 返回 done:true)时不调 return();
|
||||
// 仅当元素耗尽但迭代器未 done(提前退出)才执行 IteratorClose。
|
||||
let result = self.iters.last_for_of_result();
|
||||
if result.is_object() {
|
||||
let result_obj = unsafe { &*result.as_js_object_ptr() };
|
||||
let done_si = self.kernel_core.perm_interner().intern("done").0;
|
||||
@@ -789,10 +789,10 @@ impl Vm {
|
||||
/// 路径(它已弹出自己的迭代器)。
|
||||
pub(crate) fn close_for_of_above(&mut self, depth: usize) {
|
||||
while self.iters.for_of_iters.len() > depth {
|
||||
let Some(iterator) = self.iters.pop_for_of() else {
|
||||
let Some(entry) = self.iters.pop_for_of() else {
|
||||
break;
|
||||
};
|
||||
let _ = self.close_for_of_iterator(iterator, true);
|
||||
let _ = self.close_for_of_iterator(entry.iterator, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,6 @@ macro_rules! inline_save_field {
|
||||
($recv:ident, $window_regs:ident, pending_completion, opt_copy) => { $recv.pending_completion };
|
||||
($recv:ident, $window_regs:ident, for_in_iters, for_in_keys) => { std::mem::take(&mut $recv.iters.for_in_iters) };
|
||||
($recv:ident, $window_regs:ident, for_of_iters, iter_take) => { std::mem::take(&mut $recv.iters.for_of_iters) };
|
||||
($recv:ident, $window_regs:ident, last_for_of_result, iter_copy) => { $recv.iters.last_for_of_result };
|
||||
($recv:ident, $window_regs:ident, saved_bytecode_stack, move_field) => { std::mem::take(&mut $recv.saved_bytecode_stack) };
|
||||
($recv:ident, $window_regs:ident, saved_immutables_stack, move_field) => { std::mem::take(&mut $recv.saved_immutables_stack) };
|
||||
($recv:ident, $window_regs:ident, save_stack, move_field) => { std::mem::take(&mut $recv.save_stack) };
|
||||
@@ -83,7 +82,6 @@ macro_rules! inline_restore_field {
|
||||
($recv:ident, $saved:ident, pending_completion, opt_copy) => { $recv.pending_completion = $saved.pending_completion };
|
||||
($recv:ident, $saved:ident, for_in_iters, for_in_keys) => { $recv.iters.for_in_iters = $saved.for_in_iters };
|
||||
($recv:ident, $saved:ident, for_of_iters, iter_take) => { $recv.iters.for_of_iters = $saved.for_of_iters };
|
||||
($recv:ident, $saved:ident, last_for_of_result, iter_copy) => { $recv.iters.last_for_of_result = $saved.last_for_of_result };
|
||||
($recv:ident, $saved:ident, saved_bytecode_stack, move_field) => { $recv.saved_bytecode_stack = $saved.saved_bytecode_stack };
|
||||
($recv:ident, $saved:ident, saved_immutables_stack, move_field) => { $recv.saved_immutables_stack = $saved.saved_immutables_stack };
|
||||
($recv:ident, $saved:ident, save_stack, move_field) => { $recv.save_stack = $saved.save_stack };
|
||||
@@ -117,7 +115,6 @@ macro_rules! inline_core_fields {
|
||||
(pending_completion, opt_copy), // V M
|
||||
(for_in_iters, for_in_keys), // V M
|
||||
(for_of_iters, iter_take), // V M
|
||||
(last_for_of_result, iter_copy), // V M
|
||||
(saved_bytecode_stack, move_field), // M
|
||||
(saved_immutables_stack, move_field), // M
|
||||
(save_stack, move_field), // V M
|
||||
@@ -195,7 +192,6 @@ impl Vm {
|
||||
self.try_stack.clear();
|
||||
self.iters.for_in_iters.clear();
|
||||
self.iters.for_of_iters.clear();
|
||||
self.iters.last_for_of_result = JsValue::undefined();
|
||||
self.spill_stack.clear();
|
||||
self.save_stack.clear();
|
||||
self.saved_bytecode_stack.clear();
|
||||
@@ -480,7 +476,10 @@ mod tests {
|
||||
value: JsValue::float(8.0),
|
||||
remaining_finally: 1,
|
||||
});
|
||||
vm.iters.last_for_of_result = JsValue::float(9.0);
|
||||
vm.iters.for_of_iters.push(crate::vm_state::ForOfEntry {
|
||||
iterator: JsValue::float(8.5),
|
||||
last_result: JsValue::float(9.0),
|
||||
});
|
||||
vm.spill_stack.push(JsValue::float(10.0));
|
||||
vm.save_stack.push(JsValue::float(11.0));
|
||||
vm.inline_callee = Some(JsValue::float(12.0));
|
||||
@@ -506,7 +505,9 @@ mod tests {
|
||||
vm.pending_completion,
|
||||
Some(Completion::Return { value, remaining_finally: 1 }) if value == JsValue::float(8.0)
|
||||
));
|
||||
assert_eq!(vm.iters.last_for_of_result, JsValue::float(9.0));
|
||||
assert_eq!(vm.iters.for_of_iters.len(), 1);
|
||||
assert_eq!(vm.iters.for_of_iters[0].iterator, JsValue::float(8.5));
|
||||
assert_eq!(vm.iters.for_of_iters[0].last_result, JsValue::float(9.0));
|
||||
assert_eq!(vm.spill_stack, vec![JsValue::float(10.0)]);
|
||||
assert_eq!(vm.save_stack, vec![JsValue::float(11.0)]);
|
||||
assert_eq!(vm.inline_callee, Some(JsValue::float(12.0)));
|
||||
|
||||
@@ -116,18 +116,29 @@ impl SymbolState {
|
||||
}
|
||||
}
|
||||
|
||||
/// for-of 迭代器栈条目:迭代器对象与其最近一次 `next()` 结果对象配对存放。
|
||||
///
|
||||
/// `last_result` 只属于本迭代器(嵌套 for-of / 数组解构 / spread 各自持有自己的
|
||||
/// 结果),`FOR_OF_CLOSE`/`FOR_AWAIT_OF_CLOSE` 据此判定本迭代器是否自然 done,
|
||||
/// 避免共享单槽被其它迭代器覆盖导致漏调/多调 `return()`。
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) struct ForOfEntry {
|
||||
/// 迭代器对象(同步迭代器 / 异步迭代器 / AsyncFromSyncIterator 包装)。
|
||||
pub(crate) iterator: JsValue,
|
||||
/// 本迭代器最近一次 DONE 返回的结果对象(CLOSE 判 done 用)。
|
||||
pub(crate) last_result: JsValue,
|
||||
}
|
||||
|
||||
/// for-in / for-of 的活跃迭代器状态。
|
||||
pub(crate) struct IterState {
|
||||
pub(crate) for_in_iters: Vec<*mut ForInIter<'static>>,
|
||||
pub(crate) for_of_iters: Vec<JsValue>,
|
||||
pub(crate) last_for_of_result: JsValue,
|
||||
pub(crate) for_of_iters: Vec<ForOfEntry>,
|
||||
}
|
||||
|
||||
impl IterState {
|
||||
pub(crate) fn reset(&mut self) {
|
||||
self.for_in_iters.clear();
|
||||
self.for_of_iters.clear();
|
||||
self.last_for_of_result = JsValue::undefined();
|
||||
}
|
||||
|
||||
pub(crate) fn push_for_in(&mut self, iter: *mut ForInIter<'static>) {
|
||||
@@ -142,28 +153,32 @@ impl IterState {
|
||||
self.for_in_iters.last().copied().unwrap_or(std::ptr::null_mut())
|
||||
}
|
||||
|
||||
pub(crate) fn push_for_of(&mut self, val: JsValue) {
|
||||
self.for_of_iters.push(val);
|
||||
/// 压入新迭代器条目:`last_result` 初始为 undefined(尚未执行任何 next())。
|
||||
pub(crate) fn push_for_of(&mut self, iterator: JsValue) {
|
||||
self.for_of_iters.push(ForOfEntry {
|
||||
iterator,
|
||||
last_result: JsValue::undefined(),
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn last_for_of(&self) -> Option<JsValue> {
|
||||
self.for_of_iters.last().copied()
|
||||
self.for_of_iters.last().map(|e| e.iterator)
|
||||
}
|
||||
|
||||
pub(crate) fn pop_for_of(&mut self) -> Option<JsValue> {
|
||||
pub(crate) fn pop_for_of(&mut self) -> Option<ForOfEntry> {
|
||||
self.for_of_iters.pop()
|
||||
}
|
||||
|
||||
pub(crate) fn last_for_of_result(&self) -> JsValue {
|
||||
self.last_for_of_result
|
||||
/// 栈顶条目最近一次 DONE 结果;栈空时返回 undefined(防御)。
|
||||
pub(crate) fn last_result(&self) -> JsValue {
|
||||
self.for_of_iters.last().map(|e| e.last_result).unwrap_or(JsValue::undefined())
|
||||
}
|
||||
|
||||
pub(crate) fn set_last_for_of_result(&mut self, val: JsValue) {
|
||||
self.last_for_of_result = val;
|
||||
}
|
||||
|
||||
pub(crate) fn clear_last_for_of_result(&mut self) {
|
||||
self.last_for_of_result = JsValue::undefined();
|
||||
/// 写入栈顶条目的 DONE 结果(本迭代器自身的结果,不跨迭代器覆盖)。
|
||||
pub(crate) fn set_last_result(&mut self, val: JsValue) {
|
||||
if let Some(entry) = self.for_of_iters.last_mut() {
|
||||
entry.last_result = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -108,7 +108,6 @@ impl Vm {
|
||||
iters: IterState {
|
||||
for_in_iters: Vec::new(),
|
||||
for_of_iters: Vec::new(),
|
||||
last_for_of_result: JsValue::undefined(),
|
||||
},
|
||||
profiling: ProfilingState {
|
||||
ic_hits: std::cell::Cell::new(0),
|
||||
@@ -213,7 +212,6 @@ impl Vm {
|
||||
iters: IterState {
|
||||
for_in_iters: Vec::new(),
|
||||
for_of_iters: Vec::new(),
|
||||
last_for_of_result: JsValue::undefined(),
|
||||
},
|
||||
profiling: ProfilingState {
|
||||
ic_hits: std::cell::Cell::new(0),
|
||||
|
||||
Reference in New Issue
Block a user