mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
perf: for-of 内置迭代器快路径直步,跳过 native 调用帧
This commit is contained in:
@@ -1693,9 +1693,67 @@ fn str_iter_step(units: &[u16], at: usize) -> (usize, Option<StrIterElem>) {
|
|||||||
(at + 1, Some(StrIterElem::One(u)))
|
(at + 1, Some(StrIterElem::One(u)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_array_like<H: VmHost>(
|
/// 内置包装器的内层值种类:for-of 内置包装器(Array/String/TA/Map/Set)的
|
||||||
|
/// 内层类型五判据(与 `next_array_like` 臂分派同判据)。快路径按 kind 直步,
|
||||||
|
/// kind 失配时回落慢路径。
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum BuiltinIterKind {
|
||||||
|
Array,
|
||||||
|
String,
|
||||||
|
TypedArray,
|
||||||
|
MapEntries,
|
||||||
|
SetValues,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 按五判据分类内层值(臂序与 `next_array_like` 一致),非内置类型返回 None。
|
||||||
|
fn classify_inner(inner: JsValue) -> Option<BuiltinIterKind> {
|
||||||
|
if is_array_value(inner) {
|
||||||
|
Some(BuiltinIterKind::Array)
|
||||||
|
} else if inner.is_string() {
|
||||||
|
Some(BuiltinIterKind::String)
|
||||||
|
} else if is_typed_array_value(inner) {
|
||||||
|
Some(BuiltinIterKind::TypedArray)
|
||||||
|
} else if is_map_value(inner) {
|
||||||
|
Some(BuiltinIterKind::MapEntries)
|
||||||
|
} else if is_set_value(inner) {
|
||||||
|
Some(BuiltinIterKind::SetValues)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 检测内置包装器种类:读 `__inner__` 槽后按五判据分类。
|
||||||
|
///
|
||||||
|
/// # 边界
|
||||||
|
/// - 包装器非对象 / `__inner__` 缺失(undefined)/ 非内置类型 → None(调用方走慢路径)。
|
||||||
|
///
|
||||||
|
/// # 注意事项
|
||||||
|
/// - `__inner__` 是用户可观察槽,随时可能被改写;检测结果只是 init 期提示,
|
||||||
|
/// 快路径每步重读复判(见 `builtin_iter_fast_step`)。
|
||||||
|
pub fn builtin_iter_kind<H: VmHost>(vm: &mut H, wrapper: JsValue) -> Option<BuiltinIterKind> {
|
||||||
|
if !wrapper.is_object() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
// SAFETY: wrapper 刚判定为对象。
|
||||||
|
let wrapper_obj = unsafe { &*wrapper.as_js_object_ptr() };
|
||||||
|
let inner_si = vm.kernel_core().perm_interner().intern(INNER_PROP).0;
|
||||||
|
let inner = match vm.ordinary_get(wrapper_obj, inner_si, wrapper) {
|
||||||
|
Ok(inner) if !inner.is_undefined() => inner,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
classify_inner(inner)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 内置包装器步进核心:按内层类型产出元素值与 done 标志,并把新游标写回
|
||||||
|
/// 包装器 `__index__` 槽(用户可观察槽,每步直读直写、不跨步缓存)。
|
||||||
|
///
|
||||||
|
/// # 返回值
|
||||||
|
/// - `Ok(None)`:内层非内置类型(调用方落慢路径);
|
||||||
|
/// - `Ok(Some((value, done)))`:本步元素值与 done 标志;
|
||||||
|
/// - `Err`:原始异常值(元素 getter 抛出、TA detach/越界等)。
|
||||||
|
fn step_builtin_inner<H: VmHost>(
|
||||||
vm: &mut H, wrapper: &mut JsObject, inner: JsValue, index_si: u32,
|
vm: &mut H, wrapper: &mut JsObject, inner: JsValue, index_si: u32,
|
||||||
) -> Result<Option<JsValue>, JsValue> {
|
) -> Result<Option<(JsValue, bool)>, JsValue> {
|
||||||
if is_array_value(inner) {
|
if is_array_value(inner) {
|
||||||
let index = current_index(vm, wrapper, index_si);
|
let index = current_index(vm, wrapper, index_si);
|
||||||
let arr = unsafe { &*inner.as_js_object_ptr() };
|
let arr = unsafe { &*inner.as_js_object_ptr() };
|
||||||
@@ -1713,9 +1771,9 @@ fn next_array_like<H: VmHost>(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
vm.set_or_create_prop_value(wrapper, index_si, JsValue::int((index + 1) as i32));
|
vm.set_or_create_prop_value(wrapper, index_si, JsValue::int((index + 1) as i32));
|
||||||
return Ok(Some(make_iter_result(vm, value, false)));
|
return Ok(Some((value, false)));
|
||||||
}
|
}
|
||||||
return Ok(Some(make_iter_result(vm, JsValue::undefined(), true)));
|
return Ok(Some((JsValue::undefined(), true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if inner.is_string() {
|
if inner.is_string() {
|
||||||
@@ -1761,9 +1819,9 @@ fn next_array_like<H: VmHost>(
|
|||||||
},
|
},
|
||||||
StrIterElem::Pair(hi, lo) => vm.new_string_units(&[hi, lo]),
|
StrIterElem::Pair(hi, lo) => vm.new_string_units(&[hi, lo]),
|
||||||
};
|
};
|
||||||
return Ok(Some(make_iter_result(vm, value, false)));
|
return Ok(Some((value, false)));
|
||||||
}
|
}
|
||||||
return Ok(Some(make_iter_result(vm, JsValue::undefined(), true)));
|
return Ok(Some((JsValue::undefined(), true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_typed_array_value(inner) {
|
if is_typed_array_value(inner) {
|
||||||
@@ -1779,22 +1837,57 @@ fn next_array_like<H: VmHost>(
|
|||||||
Err(e) => return Err(crate::error::create_type_error(vm, &e)),
|
Err(e) => return Err(crate::error::create_type_error(vm, &e)),
|
||||||
};
|
};
|
||||||
vm.set_or_create_prop_value(wrapper, index_si, JsValue::int((index + 1) as i32));
|
vm.set_or_create_prop_value(wrapper, index_si, JsValue::int((index + 1) as i32));
|
||||||
return Ok(Some(make_iter_result(vm, value, false)));
|
return Ok(Some((value, false)));
|
||||||
}
|
}
|
||||||
return Ok(Some(make_iter_result(vm, JsValue::undefined(), true)));
|
return Ok(Some((JsValue::undefined(), true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// for-of 循环默认迭代:Map 产出 [key, value] 对,Set 产出值。
|
// for-of 循环默认迭代:Map 产出 [key, value] 对,Set 产出值。
|
||||||
if is_map_value(inner) {
|
if is_map_value(inner) {
|
||||||
return Ok(Some(map_set_step(vm, wrapper, inner, index_si, MapSetMode::MapEntries)));
|
let (value, done) = map_set_step_core(vm, wrapper, inner, index_si, MapSetMode::MapEntries);
|
||||||
|
return Ok(Some((value, done)));
|
||||||
}
|
}
|
||||||
if is_set_value(inner) {
|
if is_set_value(inner) {
|
||||||
return Ok(Some(map_set_step(vm, wrapper, inner, index_si, MapSetMode::SetValues)));
|
let (value, done) = map_set_step_core(vm, wrapper, inner, index_si, MapSetMode::SetValues);
|
||||||
|
return Ok(Some((value, done)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 内置包装器步进一步(for-of 快路径入口):重读 `__inner__` 槽并复判 kind,
|
||||||
|
/// 失配 / 缺失 / 非对象时以 `None` 信号回落慢路径(调用方清快标志)。
|
||||||
|
///
|
||||||
|
/// # 返回值
|
||||||
|
/// - `Ok(None)`:kind 失配或 `__inner__` 缺失(非内置包装器);
|
||||||
|
/// - `Ok(Some((value, done)))`:本步元素值与 done 标志;
|
||||||
|
/// - `Err`:原始异常值。
|
||||||
|
pub fn builtin_iter_fast_step<H: VmHost>(
|
||||||
|
vm: &mut H, wrapper: &mut JsObject, kind: BuiltinIterKind,
|
||||||
|
) -> Result<Option<(JsValue, bool)>, JsValue> {
|
||||||
|
let inner_si = vm.kernel_core().perm_interner().intern(INNER_PROP).0;
|
||||||
|
let index_si = vm.kernel_core().perm_interner().intern(INDEX_PROP).0;
|
||||||
|
let inner = match vm.ordinary_get(wrapper, inner_si, JsValue::undefined()) {
|
||||||
|
Ok(inner) if !inner.is_undefined() => inner,
|
||||||
|
_ => return Ok(None),
|
||||||
|
};
|
||||||
|
match classify_inner(inner) {
|
||||||
|
Some(actual) if actual == kind => step_builtin_inner(vm, wrapper, inner, index_si),
|
||||||
|
_ => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 内置包装器的 `next` 步进(慢路径):步进核心产出元素后包成 `{value, done}`
|
||||||
|
/// 结果对象;慢路径行为与抽提前逐位一致。
|
||||||
|
fn next_array_like<H: VmHost>(
|
||||||
|
vm: &mut H, wrapper: &mut JsObject, inner: JsValue, index_si: u32,
|
||||||
|
) -> Result<Option<JsValue>, JsValue> {
|
||||||
|
match step_builtin_inner(vm, wrapper, inner, index_si)? {
|
||||||
|
Some((value, done)) => Ok(Some(make_iter_result(vm, value, done))),
|
||||||
|
None => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn current_index<H: VmHost>(vm: &mut H, wrapper: &JsObject, index_si: u32) -> usize {
|
fn current_index<H: VmHost>(vm: &mut H, wrapper: &JsObject, index_si: u32) -> usize {
|
||||||
match vm.ordinary_get(wrapper, index_si, JsValue::undefined()) {
|
match vm.ordinary_get(wrapper, index_si, JsValue::undefined()) {
|
||||||
Ok(value) if value.is_int() => value.as_int().max(0) as usize,
|
Ok(value) if value.is_int() => value.as_int().max(0) as usize,
|
||||||
@@ -1999,13 +2092,15 @@ impl MapSetMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 把 Map/Set 迭代器包装器推进一步,按指定模式产出 `{value, done}` 结果。
|
/// Map/Set 迭代步进核心:按模式产出元素值与 done 标志,并把新下标写回
|
||||||
|
/// 包装器 `__index__` 槽。
|
||||||
|
///
|
||||||
/// 条目存放在集合 native-data 槽中(Map 为槽表:空槽跳过、下标口径为"下一待检槽";
|
/// 条目存放在集合 native-data 槽中(Map 为槽表:空槽跳过、下标口径为"下一待检槽";
|
||||||
/// Set 为插入序表);(a, b) 对在任意分配之前拷出,使对 native 集合的借用不会
|
/// Set 为插入序表);(a, b) 对在任意分配之前拷出,使对 native 集合的借用不会
|
||||||
/// 跨越 `vm` 调用保持。
|
/// 跨越 `vm` 调用保持。
|
||||||
fn map_set_step<H: VmHost>(
|
fn map_set_step_core<H: VmHost>(
|
||||||
vm: &mut H, wrapper: &mut JsObject, inner: JsValue, index_si: u32, mode: MapSetMode,
|
vm: &mut H, wrapper: &mut JsObject, inner: JsValue, index_si: u32, mode: MapSetMode,
|
||||||
) -> JsValue {
|
) -> (JsValue, bool) {
|
||||||
let index = current_index(vm, wrapper, index_si);
|
let index = current_index(vm, wrapper, index_si);
|
||||||
let is_map = matches!(mode, MapSetMode::MapEntries | MapSetMode::MapValues | MapSetMode::MapKeys);
|
let is_map = matches!(mode, MapSetMode::MapEntries | MapSetMode::MapValues | MapSetMode::MapKeys);
|
||||||
let (entry, next_index): (Option<(JsValue, JsValue)>, usize) = unsafe {
|
let (entry, next_index): (Option<(JsValue, JsValue)>, usize) = unsafe {
|
||||||
@@ -2056,17 +2151,25 @@ fn map_set_step<H: VmHost>(
|
|||||||
MapSetMode::MapValues => b,
|
MapSetMode::MapValues => b,
|
||||||
MapSetMode::MapKeys | MapSetMode::SetValues => a,
|
MapSetMode::MapKeys | MapSetMode::SetValues => a,
|
||||||
};
|
};
|
||||||
make_iter_result(vm, value, false)
|
(value, false)
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// 迭代器已耗尽:把下标推进到永不匹配的哨兵值,使后续 next() 恒返回 done,
|
// 迭代器已耗尽:把下标推进到永不匹配的哨兵值,使后续 next() 恒返回 done,
|
||||||
// 即使集合之后又新增元素也不会"复活"。
|
// 即使集合之后又新增元素也不会"复活"。
|
||||||
vm.set_or_create_prop_value(wrapper, index_si, JsValue::int(i32::MAX));
|
vm.set_or_create_prop_value(wrapper, index_si, JsValue::int(i32::MAX));
|
||||||
make_iter_result(vm, JsValue::undefined(), true)
|
(JsValue::undefined(), true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 把 Map/Set 迭代器包装器推进一步,按指定模式产出 `{value, done}` 结果。
|
||||||
|
fn map_set_step<H: VmHost>(
|
||||||
|
vm: &mut H, wrapper: &mut JsObject, inner: JsValue, index_si: u32, mode: MapSetMode,
|
||||||
|
) -> JsValue {
|
||||||
|
let (value, done) = map_set_step_core(vm, wrapper, inner, index_si, mode);
|
||||||
|
make_iter_result(vm, value, done)
|
||||||
|
}
|
||||||
|
|
||||||
/// Map/Set 迭代器 `next`:模式从 wrapper `__mode__` 槽读取后按模式推进。
|
/// Map/Set 迭代器 `next`:模式从 wrapper `__mode__` 槽读取后按模式推进。
|
||||||
///
|
///
|
||||||
/// %MapIteratorPrototype%/%SetIteratorPrototype% 绑定同一实现——家族与模式
|
/// %MapIteratorPrototype%/%SetIteratorPrototype% 绑定同一实现——家族与模式
|
||||||
|
|||||||
@@ -117,6 +117,8 @@ fn gc_roots_contains_registers_frames_and_root_roots() {
|
|||||||
iterator: JsValue::from_js_object(child_session),
|
iterator: JsValue::from_js_object(child_session),
|
||||||
last_result: JsValue::from_js_object(root_session),
|
last_result: JsValue::from_js_object(root_session),
|
||||||
is_async: false,
|
is_async: false,
|
||||||
|
fast: None,
|
||||||
|
fast_value: JsValue::undefined(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut roots = Vec::new();
|
let mut roots = Vec::new();
|
||||||
|
|||||||
@@ -194,6 +194,7 @@ impl SuspendedFrame {
|
|||||||
for entry in &self.for_of_iters {
|
for entry in &self.for_of_iters {
|
||||||
f(entry.iterator);
|
f(entry.iterator);
|
||||||
f(entry.last_result);
|
f(entry.last_result);
|
||||||
|
f(entry.fast_value);
|
||||||
}
|
}
|
||||||
if let Some(it) = self.delegated_iterator {
|
if let Some(it) = self.delegated_iterator {
|
||||||
f(it);
|
f(it);
|
||||||
@@ -248,6 +249,7 @@ impl SuspendedFrame {
|
|||||||
for entry in &mut self.for_of_iters {
|
for entry in &mut self.for_of_iters {
|
||||||
entry.iterator = rewrite(entry.iterator);
|
entry.iterator = rewrite(entry.iterator);
|
||||||
entry.last_result = rewrite(entry.last_result);
|
entry.last_result = rewrite(entry.last_result);
|
||||||
|
entry.fast_value = rewrite(entry.fast_value);
|
||||||
}
|
}
|
||||||
self.delegated_iterator = self.delegated_iterator.map(&mut rewrite);
|
self.delegated_iterator = self.delegated_iterator.map(&mut rewrite);
|
||||||
self.exception_value = self.exception_value.map(&mut rewrite);
|
self.exception_value = self.exception_value.map(&mut rewrite);
|
||||||
@@ -324,6 +326,8 @@ impl SuspendedFrame {
|
|||||||
iterator: rewrite(entry.iterator),
|
iterator: rewrite(entry.iterator),
|
||||||
last_result: rewrite(entry.last_result),
|
last_result: rewrite(entry.last_result),
|
||||||
is_async: entry.is_async,
|
is_async: entry.is_async,
|
||||||
|
fast: entry.fast,
|
||||||
|
fast_value: rewrite(entry.fast_value),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
delegated_iterator: self.delegated_iterator.map(&mut rewrite),
|
delegated_iterator: self.delegated_iterator.map(&mut rewrite),
|
||||||
@@ -413,6 +417,8 @@ mod tests {
|
|||||||
iterator: JsValue::float(6.0),
|
iterator: JsValue::float(6.0),
|
||||||
last_result: JsValue::float(7.0),
|
last_result: JsValue::float(7.0),
|
||||||
is_async: false,
|
is_async: false,
|
||||||
|
fast: None,
|
||||||
|
fast_value: JsValue::undefined(),
|
||||||
});
|
});
|
||||||
frame.delegated_iterator = Some(JsValue::float(8.0));
|
frame.delegated_iterator = Some(JsValue::float(8.0));
|
||||||
frame.saved_bytecode_stack.push(Arc::from(vec![0u32]));
|
frame.saved_bytecode_stack.push(Arc::from(vec![0u32]));
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ impl Vm {
|
|||||||
for &entry in &self.iters.for_of_iters {
|
for &entry in &self.iters.for_of_iters {
|
||||||
f(entry.iterator);
|
f(entry.iterator);
|
||||||
f(entry.last_result);
|
f(entry.last_result);
|
||||||
|
f(entry.fast_value);
|
||||||
}
|
}
|
||||||
// 微任务队列中的处理器/能力/值都是 GC 根。
|
// 微任务队列中的处理器/能力/值都是 GC 根。
|
||||||
for job in &self.job_queue {
|
for job in &self.job_queue {
|
||||||
@@ -151,6 +152,7 @@ impl Vm {
|
|||||||
for entry in &mut self.iters.for_of_iters {
|
for entry in &mut self.iters.for_of_iters {
|
||||||
entry.iterator = rewrite(entry.iterator);
|
entry.iterator = rewrite(entry.iterator);
|
||||||
entry.last_result = rewrite(entry.last_result);
|
entry.last_result = rewrite(entry.last_result);
|
||||||
|
entry.fast_value = rewrite(entry.fast_value);
|
||||||
}
|
}
|
||||||
// 微任务队列中的值随 sweep 重写。
|
// 微任务队列中的值随 sweep 重写。
|
||||||
for job in &mut self.job_queue {
|
for job in &mut self.job_queue {
|
||||||
|
|||||||
@@ -641,7 +641,9 @@ impl Vm {
|
|||||||
let iterable = self.regs[a];
|
let iterable = self.regs[a];
|
||||||
match oxide_builtins::iterator::make_iterator_for_value(self, iterable) {
|
match oxide_builtins::iterator::make_iterator_for_value(self, iterable) {
|
||||||
Ok(iterator) => {
|
Ok(iterator) => {
|
||||||
self.iters.push_for_of(iterator, false);
|
// 内置包装器检测:Array/String/TA/Map/Set 走快路径(异步恒慢)。
|
||||||
|
let kind = oxide_builtins::iterator::builtin_iter_kind(self, iterator);
|
||||||
|
self.iters.push_for_of(iterator, false, kind);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -659,7 +661,7 @@ impl Vm {
|
|||||||
let iterable = self.regs[a];
|
let iterable = self.regs[a];
|
||||||
match crate::async_from_sync::make_async_iterator(self, iterable) {
|
match crate::async_from_sync::make_async_iterator(self, iterable) {
|
||||||
Ok(iterator) => {
|
Ok(iterator) => {
|
||||||
self.iters.push_for_of(iterator, true);
|
self.iters.push_for_of(iterator, true, None);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -762,6 +764,33 @@ impl Vm {
|
|||||||
|
|
||||||
// 调用 next()/读 done 前清空异常值槽:跨调用残留不得污染本指令的取槽。
|
// 调用 next()/读 done 前清空异常值槽:跨调用残留不得污染本指令的取槽。
|
||||||
self.last_uncaught_value = None;
|
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) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
match step {
|
||||||
|
Ok(Some((value, done))) => {
|
||||||
|
self.iters.for_of_iters.last_mut().unwrap().fast_value = value;
|
||||||
|
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(());
|
||||||
|
}
|
||||||
|
|
||||||
let iter_obj = unsafe { &*iterator.as_js_object_ptr() };
|
let iter_obj = unsafe { &*iterator.as_js_object_ptr() };
|
||||||
let next_si = self.kernel_core.perm_interner().intern("next").0;
|
let next_si = self.kernel_core.perm_interner().intern("next").0;
|
||||||
let next_fn = match self.ordinary_get(iter_obj, next_si, iterator) {
|
let next_fn = match self.ordinary_get(iter_obj, next_si, iterator) {
|
||||||
@@ -792,6 +821,11 @@ impl Vm {
|
|||||||
pub(crate) fn dispatch_for_of_next(&mut self, rd: usize) -> Result<(), String> {
|
pub(crate) fn dispatch_for_of_next(&mut self, rd: usize) -> Result<(), String> {
|
||||||
vm_trace!("FOR_OF_NEXT rd={}", rd);
|
vm_trace!("FOR_OF_NEXT rd={}", rd);
|
||||||
self.last_uncaught_value = None;
|
self.last_uncaught_value = None;
|
||||||
|
// 快路径:元素值由前一次 DONE 快步产出,直写寄存器。
|
||||||
|
if self.iters.for_of_iters.last().is_some_and(|e| e.fast.is_some()) {
|
||||||
|
self.regs[rd] = self.iters.for_of_iters.last().unwrap().fast_value;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
let result = self.iters.last_result();
|
let result = self.iters.last_result();
|
||||||
if !result.is_object() {
|
if !result.is_object() {
|
||||||
self.regs[rd] = JsValue::undefined();
|
self.regs[rd] = JsValue::undefined();
|
||||||
@@ -811,11 +845,16 @@ impl Vm {
|
|||||||
/// 重新抛出原始值。按 ECMA-262,next() 抛出时不会经 return() 关闭迭代器——
|
/// 重新抛出原始值。按 ECMA-262,next() 抛出时不会经 return() 关闭迭代器——
|
||||||
/// 先弹出它,使展开时的 IteratorClose 遍历跳过该迭代器。
|
/// 先弹出它,使展开时的 IteratorClose 遍历跳过该迭代器。
|
||||||
fn throw_for_of_error(&mut self, msg: String) -> Result<(), String> {
|
fn throw_for_of_error(&mut self, msg: String) -> Result<(), String> {
|
||||||
self.iters.pop_for_of();
|
|
||||||
let exc = match self.last_uncaught_value.take() {
|
let exc = match self.last_uncaught_value.take() {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => oxide_builtins::error::create_from_text(self, &msg),
|
None => oxide_builtins::error::create_from_text(self, &msg),
|
||||||
};
|
};
|
||||||
|
self.throw_for_of_error_value(exc)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 以指定异常值展开(慢路径文本重建与快路径原值透传共用)。
|
||||||
|
fn throw_for_of_error_value(&mut self, exc: JsValue) -> Result<(), String> {
|
||||||
|
self.iters.pop_for_of();
|
||||||
self.exception_value = Some(exc);
|
self.exception_value = Some(exc);
|
||||||
self.pending_error_kind = Some(self.thrown_error_kind(exc));
|
self.pending_error_kind = Some(self.thrown_error_kind(exc));
|
||||||
// 无论取到原值还是重建错误对象,异常必须展开传播,不得静默返回 Ok——
|
// 无论取到原值还是重建错误对象,异常必须展开传播,不得静默返回 Ok——
|
||||||
@@ -1234,6 +1273,8 @@ mod tests {
|
|||||||
iterator: JsValue::undefined(),
|
iterator: JsValue::undefined(),
|
||||||
last_result: JsValue::undefined(),
|
last_result: JsValue::undefined(),
|
||||||
is_async: false,
|
is_async: false,
|
||||||
|
fast: None,
|
||||||
|
fast_value: JsValue::undefined(),
|
||||||
});
|
});
|
||||||
|
|
||||||
vm.run(&Arc::new(module))
|
vm.run(&Arc::new(module))
|
||||||
|
|||||||
@@ -828,6 +828,8 @@ mod tests {
|
|||||||
iterator: JsValue::float(8.5),
|
iterator: JsValue::float(8.5),
|
||||||
last_result: JsValue::float(9.0),
|
last_result: JsValue::float(9.0),
|
||||||
is_async: false,
|
is_async: false,
|
||||||
|
fast: None,
|
||||||
|
fast_value: JsValue::undefined(),
|
||||||
});
|
});
|
||||||
vm.spill_stack.push(JsValue::float(10.0));
|
vm.spill_stack.push(JsValue::float(10.0));
|
||||||
vm.save_stack.push(JsValue::float(11.0));
|
vm.save_stack.push(JsValue::float(11.0));
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ use rustc_hash::FxBuildHasher;
|
|||||||
|
|
||||||
use crate::session_gc::SessionGc;
|
use crate::session_gc::SessionGc;
|
||||||
use crate::vm::ForInIter;
|
use crate::vm::ForInIter;
|
||||||
|
use oxide_builtins::iterator::BuiltinIterKind;
|
||||||
use oxide_types::object::{Cell as UpvalueCell, JsObject, JsString};
|
use oxide_types::object::{Cell as UpvalueCell, JsObject, JsString};
|
||||||
use oxide_types::private_key::WELL_KNOWN_SYMBOL_COUNT;
|
use oxide_types::private_key::WELL_KNOWN_SYMBOL_COUNT;
|
||||||
use oxide_types::value::JsValue;
|
use oxide_types::value::JsValue;
|
||||||
@@ -165,6 +166,11 @@ pub(crate) struct ForOfEntry {
|
|||||||
/// promise(独立异步机制),同步逃出路径(break/continue/return 计数关闭)
|
/// promise(独立异步机制),同步逃出路径(break/continue/return 计数关闭)
|
||||||
/// 不得同步调用其 return()。
|
/// 不得同步调用其 return()。
|
||||||
pub(crate) is_async: bool,
|
pub(crate) is_async: bool,
|
||||||
|
/// 内置包装器快路径:迭代器为 Array/String/TA/Map/Set 内置包装器时非 None,
|
||||||
|
/// DONE/NEXT 直步不经 native 调用;kind 失配清标志回落慢路径。
|
||||||
|
pub(crate) fast: Option<BuiltinIterKind>,
|
||||||
|
/// 快路径本迭代产出的元素值(仅 DONE→NEXT 之间有效,不跨迭代)。
|
||||||
|
pub(crate) fast_value: JsValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// for-in / for-of 的活跃迭代器状态。
|
/// for-in / for-of 的活跃迭代器状态。
|
||||||
@@ -192,12 +198,15 @@ impl IterState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 压入新迭代器条目:`last_result` 初始为 undefined(尚未执行任何 next())。
|
/// 压入新迭代器条目:`last_result` 初始为 undefined(尚未执行任何 next())。
|
||||||
/// `is_async` 标记 for-await-of 的异步迭代器(异步逃出关闭走独立机制)。
|
/// `is_async` 标记 for-await-of 的异步迭代器(异步逃出关闭走独立机制);
|
||||||
pub(crate) fn push_for_of(&mut self, iterator: JsValue, is_async: bool) {
|
/// `fast` 为内置包装器种类(None = 慢路径)。
|
||||||
|
pub(crate) fn push_for_of(&mut self, iterator: JsValue, is_async: bool, fast: Option<BuiltinIterKind>) {
|
||||||
self.for_of_iters.push(ForOfEntry {
|
self.for_of_iters.push(ForOfEntry {
|
||||||
iterator,
|
iterator,
|
||||||
last_result: JsValue::undefined(),
|
last_result: JsValue::undefined(),
|
||||||
is_async,
|
is_async,
|
||||||
|
fast,
|
||||||
|
fast_value: JsValue::undefined(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -853,6 +853,8 @@ fn reset_clears_runtime_state_like_rerun() {
|
|||||||
iterator: JsValue::undefined(),
|
iterator: JsValue::undefined(),
|
||||||
last_result: JsValue::undefined(),
|
last_result: JsValue::undefined(),
|
||||||
is_async: false,
|
is_async: false,
|
||||||
|
fast: None,
|
||||||
|
fast_value: JsValue::undefined(),
|
||||||
});
|
});
|
||||||
vm.saved_bytecode_stack.push(Arc::from(vec![oxide_bytecode::opcode::encode(
|
vm.saved_bytecode_stack.push(Arc::from(vec![oxide_bytecode::opcode::encode(
|
||||||
oxide_bytecode::opcode::OpCode::HALT,
|
oxide_bytecode::opcode::OpCode::HALT,
|
||||||
|
|||||||
Reference in New Issue
Block a user