perf: for-of 快路径快照 inner 与游标入条目,免每步槽协议

This commit is contained in:
2026-10-04 22:44:05 +00:00
parent b77f75b237
commit fce50e3f64
10 changed files with 132 additions and 105 deletions
+2
View File
@@ -117,6 +117,8 @@ fn gc_roots_contains_registers_frames_and_root_roots() {
is_async: false,
fast: None,
fast_value: JsValue::undefined(),
fast_inner: JsValue::from_js_object(child_session),
fast_cursor: 0,
});
let mut roots = Vec::new();
+1
View File
@@ -208,6 +208,7 @@ impl SuspendedFrame {
f(entry.iterator);
f(entry.last_result);
f(entry.fast_value);
f(entry.fast_inner);
}
if let Some(it) = self.delegated_iterator {
f(it);
+1
View File
@@ -80,6 +80,7 @@ impl Vm {
f(entry.iterator);
f(entry.last_result);
f(entry.fast_value);
f(entry.fast_inner);
}
// 微任务队列中的处理器/能力/值都是 GC 根。
for job in &self.job_queue {
+31 -18
View File
@@ -638,8 +638,12 @@ impl Vm {
match oxide_builtins::iterator::make_iterator_for_value(self, iterable) {
Ok(iterator) => {
// 内置包装器检测:Array/String/TA/Map/Set 走快路径(异步恒慢)。
let kind = oxide_builtins::iterator::builtin_iter_kind(self, iterator);
self.iters.push_for_of(iterator, false, kind);
// init 期把 inner 快照入条目,步内不重读 `__inner__` 槽。
let (kind, inner) = match oxide_builtins::iterator::builtin_iter_kind(self, iterator) {
Some((k, i)) => (Some(k), i),
None => (None, JsValue::undefined()),
};
self.iters.push_for_of(iterator, false, kind, inner);
Ok(())
}
Err(err) => {
@@ -657,7 +661,8 @@ impl Vm {
let iterable = self.regs[a];
match crate::async_from_sync::make_async_iterator(self, iterable) {
Ok(iterator) => {
self.iters.push_for_of(iterator, true, None);
// for-await-of 恒慢路径:无快路径快照,inner 传 undefined。
self.iters.push_for_of(iterator, true, None, JsValue::undefined());
Ok(())
}
Err(err) => {
@@ -770,26 +775,32 @@ impl Vm {
self.last_uncaught_value = None;
// 快路径:内置包装器(Array/String/TA/Map/Set)直步,跳过 native 调用帧、
// 结果对象分配与 done/value 两次读;kind 失配清标志,本迭代回落慢路径。
let fast_kind = self.iters.for_of_iters.last().and_then(|e| e.fast);
if let Some(kind) = fast_kind {
// SAFETY: iterator 刚判定为对象。
let iter_obj = unsafe { &mut *iterator.as_js_object_ptr() };
let step = oxide_builtins::iterator::builtin_iter_fast_step(self, iter_obj, kind);
// 元素 getter / __inner__ 访问器抛出:深度 0 的 raise_call_error 已就地
// unwind(跳转 catch),条目已弹出、异常值已入异常通道——直接返回,
// 派发循环自 catch 点续行,不得再触碰迭代器栈。
if !self.iters.for_of_iters.last().is_some_and(|e| e.iterator == iterator) {
// 结果对象分配与 done/value 两次读;inner 与游标取条目快照,步内不重跑槽协议。
if self.iters.for_of_iters.last().is_some_and(|e| e.fast.is_some()) {
// inner 与游标为 Copy 值:先拷出释放借用,再做步进核心的可变调用。
let (inner, cursor) = {
let e = self.iters.for_of_iters.last().unwrap();
(e.fast_inner, e.fast_cursor)
};
let stack_len = self.iters.for_of_iters.len();
let step = oxide_builtins::iterator::builtin_iter_fast_step(self, inner, cursor);
// 元素 getter / 访问器抛出:深度 0 的 raise_call_error 已就地 unwind
// (跳转 catch),条目已弹出、异常值已入异常通道——直接返回,派发循环
// 自 catch 点续行,不得再触碰迭代器栈。
// 判据须含栈深度:同迭代器两层嵌套时栈顶被外层条目顶替,仅凭 iterator
// 同一性会误判通过,须以步前深度不变作锚。
if self.iters.for_of_iters.len() != stack_len
|| !self.iters.for_of_iters.last().is_some_and(|e| e.iterator == iterator)
{
return Ok(());
}
match step {
Ok(Some((value, done))) => {
self.iters.for_of_iters.last_mut().unwrap().fast_value = value;
Ok((value, done, next_cursor)) => {
let entry = self.iters.for_of_iters.last_mut().unwrap();
entry.fast_value = value;
entry.fast_cursor = next_cursor;
self.regs[rd] = JsValue::bool(!done);
}
Ok(None) => {
self.iters.for_of_iters.last_mut().unwrap().fast = None;
}
Err(exc) => return self.throw_for_of_error_value(exc),
}
return Ok(());
@@ -1283,6 +1294,8 @@ mod tests {
is_async: false,
fast: None,
fast_value: JsValue::undefined(),
fast_inner: JsValue::undefined(),
fast_cursor: 0,
});
vm.run(&Arc::new(module))
+2
View File
@@ -943,6 +943,8 @@ mod tests {
is_async: false,
fast: None,
fast_value: JsValue::undefined(),
fast_inner: JsValue::undefined(),
fast_cursor: 0,
});
vm.spill_stack.push(JsValue::float(10.0));
vm.save_stack.push(JsValue::float(11.0));
+14 -3
View File
@@ -155,10 +155,16 @@ pub(crate) struct ForOfEntry {
/// 不得同步调用其 return()。
pub(crate) is_async: bool,
/// 内置包装器快路径:迭代器为 Array/String/TA/Map/Set 内置包装器时非 None,
/// DONE/NEXT 直步不经 native 调用;kind 失配清标志回落慢路径。
/// DONE/NEXT 直步不经 native 调用。
pub(crate) fast: Option<BuiltinIterKind>,
/// 快路径本迭代产出的元素值(仅 DONE→NEXT 之间有效,不跨迭代)。
pub(crate) fast_value: JsValue,
/// 快路径 inner 快照:init 期读 `__inner__` 槽后固化,步内不重读槽。
/// 是 GC 边(session 对象指针),须随 fast_value 接 mark。
pub(crate) fast_inner: JsValue,
/// 快路径游标:步内推进的迭代下标,替代每步读写 `__index__` 槽。
/// Map/Set 族耗尽哨兵为 i32::MAX(口径与慢路径槽一致)。
pub(crate) fast_cursor: usize,
}
/// for-in / for-of 的活跃迭代器状态。
@@ -203,14 +209,19 @@ impl IterState {
/// 压入新迭代器条目:`last_result` 初始为 undefined(尚未执行任何 next())。
/// `is_async` 标记 for-await-of 的异步迭代器(异步逃出关闭走独立机制);
/// `fast` 为内置包装器种类(None = 慢路径)。
pub(crate) fn push_for_of(&mut self, iterator: JsValue, is_async: bool, fast: Option<BuiltinIterKind>) {
/// `fast` 为内置包装器种类(None = 慢路径),`fast_inner` 为快路径 inner 快照
/// (慢路径传 undefined,游标恒 0)。
pub(crate) fn push_for_of(
&mut self, iterator: JsValue, is_async: bool, fast: Option<BuiltinIterKind>, fast_inner: JsValue,
) {
self.for_of_iters.push(ForOfEntry {
iterator,
last_result: JsValue::undefined(),
is_async,
fast,
fast_value: JsValue::undefined(),
fast_inner,
fast_cursor: 0,
});
}
+2
View File
@@ -792,6 +792,8 @@ fn reset_clears_runtime_state_like_rerun() {
is_async: false,
fast: None,
fast_value: JsValue::undefined(),
fast_inner: JsValue::undefined(),
fast_cursor: 0,
});
vm.saved_bytecode_stack.push(Arc::from(vec![oxide_bytecode::opcode::encode(
oxide_bytecode::opcode::OpCode::HALT,