feat: Promise 静态方法(all/race/allSettled/any + AggregateError)+ async test262 解锁

- Promise.all/race/allSettled/any:共享聚合核心,逐元素 C.resolve + Invoke(then),
  共享记录对象承载剩余计数/结果数组/能力闭包,元素处理器按模式结算
- AggregateError 内建(构造器 + prototype,Promise.any 拒绝路径依赖)
- 修复 capability_executor:能力已持有非 undefined 值时二次调用抛 TypeError
- test262 runner:移除 async flag 无条件 skip;解锁 asyncHelpers/promiseHelper/
  doneprintHandle harness;注入 print 捕获 + ,run() 后按 marker 判定
- 排除 await-dictionary(Promise.allKeyed/allSettledKeyed 2025 proposal)特性
- iterator 遍历辅助改 pub 供 oxide_vm 复用
This commit is contained in:
2026-08-09 23:25:36 +08:00
parent fd47cd56d0
commit 5a9a46483d
8 changed files with 798 additions and 61 deletions
Generated
+1
View File
@@ -1302,6 +1302,7 @@ dependencies = [
"oxide_kernel",
"oxide_log",
"oxide_parser",
"oxide_types",
"oxide_vm",
"serde",
"serde_yaml",
+2 -2
View File
@@ -437,7 +437,7 @@ pub(crate) fn close_iterator<H: VmHost>(vm: &mut H, iterator: JsValue) {
/// # 返回值
/// - `Ok(())`:迭代完成;
/// - `Err`:迭代或回调抛出的原异常值(任意类型)。
pub(crate) fn iterate_elements<H: VmHost, F>(vm: &mut H, iterable: JsValue, mut on_elem: F) -> Result<(), JsValue>
pub fn iterate_elements<H: VmHost, F>(vm: &mut H, iterable: JsValue, mut on_elem: F) -> Result<(), JsValue>
where
F: FnMut(&mut H, JsValue) -> Result<(), JsValue>,
{
@@ -451,7 +451,7 @@ where
///
/// # 副作用
/// 迭代或回调抛错时调用迭代器的 `return()`(IteratorClose)后透传原异常。
pub(crate) fn iterate_iterator<H: VmHost, F>(vm: &mut H, iterator: JsValue, mut on_elem: F) -> Result<(), JsValue>
pub fn iterate_iterator<H: VmHost, F>(vm: &mut H, iterator: JsValue, mut on_elem: F) -> Result<(), JsValue>
where
F: FnMut(&mut H, JsValue) -> Result<(), JsValue>,
{
+1
View File
@@ -86,6 +86,7 @@ const BUILTIN_GLOBALS: &[&str] = &[
"Math",
"JSON",
"Promise",
"AggregateError",
"Date",
"Set",
"Map",
+1
View File
@@ -16,6 +16,7 @@ oxide_compiler = { path = "../oxide_compiler" }
oxide_vm = { path = "../oxide_vm" }
oxide_parser = { path = "../oxide_parser" }
oxide_kernel = { path = "../oxide_kernel" }
oxide_types = { path = "../oxide_types" }
oxide_log = { path = "../oxide_log" }
serde = { version = "1", features = ["derive"] }
serde_yaml = "0.9"
+141 -56
View File
@@ -2,6 +2,7 @@
use oxide_compiler::compiler::Compiler;
use oxide_kernel::kernel::{KernelConfig, KernelCore};
use oxide_types::value::JsValue;
use oxide_vm::vm::Vm;
use serde::Deserialize;
use std::collections::HashMap;
@@ -213,6 +214,9 @@ impl HarnessSources {
sources.insert("typeCoercion.js", include_str!("../../../tests/test262/harness/typeCoercion.js"));
sources.insert("deepEqual.js", include_str!("../../../tests/test262/harness/deepEqual.js"));
sources.insert("testTypedArray.js", include_str!("../../../tests/test262/harness/testTypedArray.js"));
sources.insert("asyncHelpers.js", include_str!("../../../tests/test262/harness/asyncHelpers.js"));
sources.insert("doneprintHandle.js", include_str!("../../../tests/test262/harness/doneprintHandle.js"));
sources.insert("promiseHelper.js", include_str!("../../../tests/test262/harness/promiseHelper.js"));
Self { sources }
}
@@ -234,14 +238,11 @@ fn is_blacklisted_harness(name: &str) -> bool {
| "proxyTrapsHelper.js"
| "temporalHelpers.js"
| "tcoHelper.js"
| "asyncHelpers.js"
| "promiseHelper.js"
| "detachArrayBuffer.js"
| "resizableArrayBufferUtils.js"
| "byteConversionValues.js"
| "compareIterator.js"
| "iteratorZipUtils.js"
| "doneprintHandle.js"
)
}
@@ -388,7 +389,6 @@ fn is_skipped(meta: &TestMeta) -> Option<String> {
for flag in &meta.flags {
match flag.as_str() {
"module" => return Some("module tests excluded".into()),
"async" => return Some("async tests excluded".into()),
"raw" => return Some("raw tests excluded".into()),
// noStrict 测试放行——很多在严格模式下仍可通过;运行时跳过逻辑会捕获失败。
_ => {}
@@ -407,6 +407,8 @@ fn is_skipped(meta: &TestMeta) -> Option<String> {
"Atomics",
"SharedArrayBuffer",
"cross-realm",
// await-dictionary(Promise.allKeyed/allSettledKeyed)是 2025 proposal,未实现。
"await-dictionary",
];
for feat in &meta.features {
@@ -448,9 +450,25 @@ fn run_test_inner(
) -> TestResult {
let start = std::time::Instant::now();
let is_async = meta.flags.iter().any(|f| f == "async");
let code = match get_harness_prefix(meta, harness, harness_cache) {
Ok(prefix) => {
let mut code = prefix;
if is_async {
// 异步测试:注入 print 捕获 + $DONE(asyncTests 用 $DONE 报告结果)。
// 结果写入 globalThis 全局字符串,run() 结束后由 runner 读取并按 marker 判定。
// (顶层 var 不落 global 对象,须显式写 globalThis。)
append_source_chunk(
&mut code,
"async capture",
"globalThis.$__test262_async_result = \"\";\n\
function print(msg) { globalThis.$__test262_async_result += String(msg) + \"\\n\"; }",
);
if let Some(done_src) = harness.get("doneprintHandle.js") {
append_source_chunk(&mut code, "doneprintHandle.js", done_src);
}
}
append_source_chunk(&mut code, "test source", strip_meta(source));
code
}
@@ -505,10 +523,15 @@ fn run_test_inner(
};
let mut vm = Vm::with_kernel_core(Arc::clone(kernel));
let run_result = vm.run(&module);
let dur = start.elapsed().as_millis() as u64;
match vm.run(&module) {
if is_async {
return judge_async_result(path, run_result, &mut vm, meta, dur, no_skip);
}
match run_result {
Ok(result) => {
let dur = start.elapsed().as_millis() as u64;
if let Some(neg) = meta.negative.as_ref() {
return TestResult::fail(
path.to_path_buf(),
@@ -518,58 +541,120 @@ fn run_test_inner(
}
TestResult::pass(path.to_path_buf(), dur, format!("ok: {result}"))
}
Err(e) => {
let dur = start.elapsed().as_millis() as u64;
if let Some(neg) = meta.negative.as_ref() {
if e.contains("TypeError") && neg.error_type == "TypeError" {
return TestResult::pass(path.to_path_buf(), dur, format!("expected: {e}"));
}
if e.contains("ReferenceError") && neg.error_type == "ReferenceError" {
return TestResult::pass(path.to_path_buf(), dur, format!("expected: {e}"));
}
if e.contains("SyntaxError") && neg.error_type == "SyntaxError" {
return TestResult::pass(path.to_path_buf(), dur, format!("expected: {e}"));
}
if e.contains(&neg.error_type) {
return TestResult::pass(path.to_path_buf(), dur, format!("expected: {e}"));
}
TestResult::fail(path.to_path_buf(), dur, format!("expected {} error, got: {e}", neg.error_type))
} else if e.contains("not yet implemented")
|| e.contains("not yet supported")
|| e.contains("not supported")
|| e.contains("unsupported")
|| e.contains("step limit")
|| e.contains("is not defined")
|| e.contains("NEW_EXPRESSION")
|| e.contains("IC_GET_PROP on non-object")
|| e.contains("GET_PROP_DYNAMIC on non-object")
|| e.contains("SET_PROP_DYNAMIC on non-object")
|| e.contains("private field brand check")
|| e.contains("CALL_NATIVE target")
|| e.contains("call stack size exceeded")
|| e.contains("is not implemented")
|| e.contains("unexpected tail call")
|| e.contains("not callable")
|| e.contains("Cannot convert object to primitive")
|| e.contains("Cannot create property on non-object")
|| e.contains("Property description must be an object")
|| e.contains("method called on incompatible")
|| e.contains("called on non-Set")
|| e.contains("called on non-Map")
|| e.contains("called on non-ArrayBuffer")
|| e.contains("called on non-TypedArray")
|| e.contains("Array.prototype method called on null")
|| e.contains("__proto__ must be an object")
// 私有字段未实现。
{
if no_skip {
return TestResult::fail(path.to_path_buf(), dur, format!("vm error: {e}"));
}
TestResult::skip(path.to_path_buf(), format!("vm: {e}"))
} else {
TestResult::fail(path.to_path_buf(), dur, format!("vm error: {e}"))
Err(e) => judge_vm_error(path, &e, meta, dur, no_skip),
}
}
/// 异步测试判定:`$DONE` 把结果写入捕获串,run() 结束时微任务队列已 drain。
///
/// 失败 marker 优先(`Test262:AsyncTestFailure:<name>: <msg>`);其次成功 marker
/// (`Test262:AsyncTestComplete`);两者都无则测试未在 run() 内同步完成
/// (需 setTimeout 等异步 runner 的测试在此失败),回退到 run 结果判定。
fn judge_async_result(
path: &Path, run_result: Result<JsValue, String>, vm: &mut Vm, meta: &TestMeta, dur: u64, no_skip: bool,
) -> TestResult {
let output = read_async_output(vm);
if let Some(pos) = output.find("Test262:AsyncTestFailure:") {
let detail = output[pos..].trim();
if let Some(neg) = meta.negative.as_ref() {
let name = detail
.strip_prefix("Test262:AsyncTestFailure:")
.and_then(|rest| rest.split(':').next())
.unwrap_or("");
if name == neg.error_type {
return TestResult::pass(path.to_path_buf(), dur, format!("expected: {detail}"));
}
return TestResult::fail(
path.to_path_buf(),
dur,
format!("expected {} error, got: {detail}", neg.error_type),
);
}
return TestResult::fail(path.to_path_buf(), dur, detail);
}
if output.contains("Test262:AsyncTestComplete") {
if meta.negative.is_some() {
return TestResult::fail(
path.to_path_buf(),
dur,
format!("expected runtime error ({}), got: async complete", meta.negative.as_ref().unwrap().error_type),
);
}
return TestResult::pass(path.to_path_buf(), dur, "async ok");
}
// $DONE 未被调用:run() 结果决定成败(顶层抛错走普通判定,未抛错视为未完成)。
match run_result {
Ok(_) => TestResult::fail(path.to_path_buf(), dur, "async test did not call $DONE synchronously"),
Err(e) => judge_vm_error(path, &e, meta, dur, no_skip),
}
}
/// 读取异步测试捕获的 `$DONE` 输出字符串。
fn read_async_output(vm: &Vm) -> String {
let si = vm.kernel_core().perm_interner().intern("$__test262_async_result").0;
let global = vm.session().global_object();
let val = vm
.kernel_core()
.shape_forge()
.lookup_position(global.shape_id(), si)
.map(|pos| global.get_prop_at(pos))
.unwrap_or(JsValue::undefined());
vm.lookup_str(val).unwrap_or_default()
}
/// 运行期错误的判定(negative 匹配 + 未实现特性跳过分类)。
fn judge_vm_error(path: &Path, e: &str, meta: &TestMeta, dur: u64, no_skip: bool) -> TestResult {
if let Some(neg) = meta.negative.as_ref() {
if e.contains("TypeError") && neg.error_type == "TypeError" {
return TestResult::pass(path.to_path_buf(), dur, format!("expected: {e}"));
}
if e.contains("ReferenceError") && neg.error_type == "ReferenceError" {
return TestResult::pass(path.to_path_buf(), dur, format!("expected: {e}"));
}
if e.contains("SyntaxError") && neg.error_type == "SyntaxError" {
return TestResult::pass(path.to_path_buf(), dur, format!("expected: {e}"));
}
if e.contains(&neg.error_type) {
return TestResult::pass(path.to_path_buf(), dur, format!("expected: {e}"));
}
return TestResult::fail(path.to_path_buf(), dur, format!("expected {} error, got: {e}", neg.error_type));
}
if e.contains("not yet implemented")
|| e.contains("not yet supported")
|| e.contains("not supported")
|| e.contains("unsupported")
|| e.contains("step limit")
|| e.contains("is not defined")
|| e.contains("NEW_EXPRESSION")
|| e.contains("IC_GET_PROP on non-object")
|| e.contains("GET_PROP_DYNAMIC on non-object")
|| e.contains("SET_PROP_DYNAMIC on non-object")
|| e.contains("private field brand check")
|| e.contains("CALL_NATIVE target")
|| e.contains("call stack size exceeded")
|| e.contains("is not implemented")
|| e.contains("unexpected tail call")
|| e.contains("not callable")
|| e.contains("Cannot convert object to primitive")
|| e.contains("Cannot create property on non-object")
|| e.contains("Property description must be an object")
|| e.contains("method called on incompatible")
|| e.contains("called on non-Set")
|| e.contains("called on non-Map")
|| e.contains("called on non-ArrayBuffer")
|| e.contains("called on non-TypedArray")
|| e.contains("Array.prototype method called on null")
|| e.contains("__proto__ must be an object")
// 私有字段未实现。
{
if no_skip {
return TestResult::fail(path.to_path_buf(), dur, format!("vm error: {e}"));
}
TestResult::skip(path.to_path_buf(), format!("vm: {e}"))
} else {
TestResult::fail(path.to_path_buf(), dur, format!("vm error: {e}"))
}
}
+644 -3
View File
@@ -77,6 +77,31 @@ const FINALLY_REJECT_PROP: &str = "__oxide_finally_reject__";
const CAP_RESOLVE_PROP: &str = "__oxide_cap_resolve__";
const CAP_REJECT_PROP: &str = "__oxide_cap_reject__";
// ── 聚合静态方法(all/race/allSettled/any)内部状态属性 ──
/// 元素处理器函数上存共享记录对象的属性名。
const AGG_RECORD_PROP: &str = "__oxide_agg_record__";
/// 元素处理器函数上存元素下标的属性名。
const AGG_INDEX_PROP: &str = "__oxide_agg_index__";
/// 元素处理器函数上存"已调用一次"标志的属性名。
const AGG_ALREADY_PROP: &str = "__oxide_agg_already__";
/// 记录对象上存剩余未结算元素计数(含尾部哨兵 1)。
const AGG_REMAINING_PROP: &str = "__oxide_agg_remaining__";
/// 记录对象上存结果数组(all/allSettled 的 values,any 的 errors)。
const AGG_VALUES_PROP: &str = "__oxide_agg_values__";
/// 记录对象上存能力 resolve 闭包。
const AGG_RESOLVE_PROP: &str = "__oxide_agg_resolve__";
/// 记录对象上存能力 reject 闭包。
const AGG_REJECT_PROP: &str = "__oxide_agg_reject__";
/// 聚合静态方法的语义模式(决定元素处理器与结算方式)。
#[derive(Clone, Copy, PartialEq, Eq)]
enum AggregateKind {
All,
Race,
AllSettled,
Any,
}
impl Vm {
/// 创建空 Promise 对象(proto = `%Promise.prototype%`),状态盒为 Pending。
fn create_promise_object(&mut self) -> JsValue {
@@ -548,6 +573,10 @@ impl Vm {
fn_proto_val,
("resolve", promise_static_resolve as *const (), 1),
("reject", promise_static_reject as *const (), 1),
("all", promise_static_all as *const (), 1),
("race", promise_static_race as *const (), 1),
("allSettled", promise_static_all_settled as *const (), 1),
("any", promise_static_any as *const (), 1),
);
// 固定地址后互相接线:proto.constructor ↔ ctor.prototype。
@@ -574,6 +603,9 @@ impl Vm {
global.set_data_meta(pos, PropAttributes::new(true, false, true));
global.bump_generation();
}
// Promise.any 的拒绝路径依赖 AggregateError 内建。
self.init_aggregate_error_intrinsics();
}
}
@@ -761,6 +793,183 @@ impl Vm {
let npos = obj.push_prop(JsValue::perm_string(sf.string_ptr(sf.intern(name).0)));
obj.set_data_meta(npos, attrs);
}
/// 创建聚合静态方法(all/race/allSettled/any)的共享记录对象:剩余计数
/// 初始 1,结果数组(race 无)与能力 resolve/reject 闭包全部存为自身属性。
fn make_agg_record(&mut self, values: JsValue, resolve: JsValue, reject: JsValue) -> JsValue {
let proto_val = JsValue::from_js_object(self.session.builtin_world().object_proto.as_ptr() as *mut JsObject);
let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val));
let obj = unsafe { &mut *ptr };
let rem_si = self.kernel_core.perm_interner().intern(AGG_REMAINING_PROP).0;
self.set_or_create_prop_value(obj, rem_si, JsValue::int(1));
let val_si = self.kernel_core.perm_interner().intern(AGG_VALUES_PROP).0;
self.set_or_create_prop_value(obj, val_si, values);
let res_si = self.kernel_core.perm_interner().intern(AGG_RESOLVE_PROP).0;
self.set_or_create_prop_value(obj, res_si, resolve);
let rej_si = self.kernel_core.perm_interner().intern(AGG_REJECT_PROP).0;
self.set_or_create_prop_value(obj, rej_si, reject);
JsValue::from_js_object(ptr)
}
/// 创建聚合静态方法的元素处理器闭包:携带共享记录与元素下标,`already` 标志
/// 初始 false。内部状态属性非枚举且追加在 length/name 之后,保持内建函数
/// "length 先于 name" 的属性序。
fn make_agg_element_fn(&mut self, native_fn: NativeFn, record: JsValue, index: i32) -> JsValue {
let fn_proto = self.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true);
// SAFETY: native_fn 是 NativeFn 函数项。
func.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(native_fn as *const ()) }));
func.set_native_arg_count(1);
let ptr = self.alloc_object(func);
let obj = unsafe { &mut *ptr };
self.add_fn_name_length(obj, "", 1);
let sh = self.kernel_core.shape_forge().as_ref();
let attrs = PropAttributes::new(false, false, false);
let rec_si = self.kernel_core.perm_interner().intern(AGG_RECORD_PROP).0;
let rec_shape = sh.make_shape(obj.shape_id(), rec_si);
obj.set_shape_id(rec_shape);
let rec_pos = obj.push_prop(record);
obj.set_data_meta(rec_pos, attrs);
let idx_si = self.kernel_core.perm_interner().intern(AGG_INDEX_PROP).0;
let idx_shape = sh.make_shape(obj.shape_id(), idx_si);
obj.set_shape_id(idx_shape);
let idx_pos = obj.push_prop(JsValue::int(index));
obj.set_data_meta(idx_pos, attrs);
let al_si = self.kernel_core.perm_interner().intern(AGG_ALREADY_PROP).0;
let al_shape = sh.make_shape(obj.shape_id(), al_si);
obj.set_shape_id(al_shape);
let al_pos = obj.push_prop(JsValue::bool(false));
obj.set_data_meta(al_pos, attrs);
JsValue::from_js_object(ptr)
}
/// 构造 allSettled 的结算记录 `{status, <value_field>: value}` 普通对象。
fn make_settled_record(&mut self, status: &str, value_field: &str, value: JsValue) -> JsValue {
let proto_val = JsValue::from_js_object(self.session.builtin_world().object_proto.as_ptr() as *mut JsObject);
let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val));
let obj = unsafe { &mut *ptr };
let status_si = self.kernel_core.perm_interner().intern("status").0;
let status_val = self.new_string(status);
self.set_or_create_prop_value(obj, status_si, status_val);
let field_si = self.kernel_core.perm_interner().intern(value_field).0;
self.set_or_create_prop_value(obj, field_si, value);
JsValue::from_js_object(ptr)
}
/// 构造 AggregateError 实例(proto = %AggregateError.prototype%):message 非
/// undefined 时 ToString 建自身属性,errors 存为数据属性。
fn make_aggregate_error(&mut self, errors: JsValue, message: JsValue) -> JsValue {
let proto_val = JsValue::from_js_object(self.aggregate_error_proto.as_ptr() as *mut JsObject);
let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val));
let obj = unsafe { &mut *ptr };
// message/errors 为数据属性:writable、非枚举、configurable(CreateMethodProperty)。
let attrs = PropAttributes::new(true, false, true);
if !message.is_undefined() {
let msg_str = oxide_runtime_api::to_string_full(message, self).unwrap_or_default();
let msg_si = self.kernel_core.perm_interner().intern("message").0;
let msg_val = self.new_string(&msg_str);
let _ = self.define_data_property(obj, msg_si, msg_val, attrs);
}
let err_si = self.kernel_core.perm_interner().intern("errors").0;
let _ = self.define_data_property(obj, err_si, errors, attrs);
JsValue::from_js_object(ptr)
}
/// 把 errors 可迭代值收集为新数组(IterableToList)。不可迭代抛 TypeError。
fn aggregate_errors_to_list(&mut self, errors: JsValue) -> Result<JsValue, JsValue> {
let array_proto = JsValue::from_js_object(self.session.builtin_world().array_proto.as_ptr() as *mut JsObject);
let ptr = self.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, array_proto, 0, self.epoch.bump()));
let list = JsValue::from_js_object(ptr);
let mut index = 0usize;
oxide_builtins::iterator::iterate_elements(self, errors, |_vm, elem| {
// SAFETY: list 是本函数新建的存活数组对象。
let list_obj = unsafe { &mut *list.as_js_object_ptr() };
list_obj.set_prop_at(index, elem);
index += 1;
Ok(())
})?;
Ok(list)
}
/// 初始化/重建 AggregateError 内建对象:`%AggregateError%` 构造器与
/// `%AggregateError.prototype%`(proto = %Error.prototype%),绑定 global 槽。
///
/// 与 `init_promise_intrinsics` 同生命周期(VM 创建 + full_reset),
/// `Promise.any` 的拒绝路径依赖此内建。
pub(crate) fn init_aggregate_error_intrinsics(&mut self) {
let sf = self.kernel_core.perm_interner().as_ref();
let sh = self.kernel_core.shape_forge().as_ref();
let fn_proto_val = self.session.builtin_world().fn_proto_val();
let error_proto_val = JsValue::from_js_object(self.session.builtin_world().error_proto.as_ptr() as *mut JsObject);
// %AggregateError.prototype%:proto = %Error.prototype%,constructor/name/message 数据属性。
let mut proto = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, error_proto_val));
let ctor_si = sf.intern("constructor").0;
let ctor_shape = sh.make_shape(proto.shape_id(), ctor_si);
proto.set_shape_id(ctor_shape);
proto.push_prop(JsValue::undefined());
proto.set_data_meta(0u32, PropAttributes::new(true, false, true));
let name_si = sf.intern("name").0;
let name_shape = sh.make_shape(proto.shape_id(), name_si);
proto.set_shape_id(name_shape);
let name_pos = proto.push_prop(JsValue::perm_string(sf.string_ptr(sf.intern("AggregateError").0)));
proto.set_data_meta(name_pos, PropAttributes::new(true, false, true));
let msg_si = sf.intern("message").0;
let msg_shape = sh.make_shape(proto.shape_id(), msg_si);
proto.set_shape_id(msg_shape);
let msg_pos = proto.push_prop(JsValue::perm_string(sf.string_ptr(sf.intern("").0)));
proto.set_data_meta(msg_pos, PropAttributes::new(true, false, true));
// %AggregateError% 构造器:proto = %Function.prototype%,length 2。
let mut ctor = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto_val));
ctor.set_function(true);
ctor.type_tag = JsObject::OBJ_TYPE_CONSTRUCTOR;
// SAFETY: aggregate_error_constructor 是 NativeFn 函数项。
ctor.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(aggregate_error_constructor as *const ()) }));
ctor.set_native_arg_count(2);
let length_si = sf.intern("length").0;
let ctor_shape1 = sh.make_shape(ctor.shape_id(), length_si);
ctor.set_shape_id(ctor_shape1);
let lpos = ctor.push_prop(JsValue::int(2));
ctor.set_data_meta(lpos, PropAttributes::new(false, false, true));
let name2_si = sf.intern("name").0;
let ctor_shape2 = sh.make_shape(ctor.shape_id(), name2_si);
ctor.set_shape_id(ctor_shape2);
let npos = ctor.push_prop(JsValue::perm_string(sf.string_ptr(sf.intern("AggregateError").0)));
ctor.set_data_meta(npos, PropAttributes::new(false, false, true));
let proto2_si = sf.intern("prototype").0;
let ctor_shape3 = sh.make_shape(ctor.shape_id(), proto2_si);
ctor.set_shape_id(ctor_shape3);
ctor.push_prop(JsValue::undefined());
ctor.set_data_meta(2u32, PropAttributes::new(false, false, false));
// 固定地址后互相接线:proto.constructor ↔ ctor.prototype。
self.aggregate_error_proto = P::new(*proto);
self.aggregate_error_constructor = P::new(*ctor);
let proto_mut = unsafe { &mut *self.aggregate_error_proto.as_mut_ptr() };
proto_mut.set_prop_at(
0u32,
JsValue::from_js_object(self.aggregate_error_constructor.as_ptr() as *mut JsObject),
);
let ctor_mut = unsafe { &mut *self.aggregate_error_constructor.as_mut_ptr() };
ctor_mut.set_prop_at(2u32, JsValue::from_js_object(self.aggregate_error_proto.as_ptr() as *mut JsObject));
// 绑定 global(槽已存在则更新)。
let global_ptr = self.session.global_object().as_ptr() as *mut JsObject;
let global = unsafe { &mut *global_ptr };
let si = self.kernel_core.perm_interner().intern("AggregateError").0;
let ctor_val = JsValue::from_js_object(self.aggregate_error_constructor.as_ptr() as *mut JsObject);
if let Some(pos) = self.kernel_core.shape_forge().lookup_position(global.shape_id(), si) {
global.set_prop_at(pos, ctor_val);
} else {
let shape = self.kernel_core.shape_forge().make_shape(global.shape_id(), si);
global.set_shape_id(shape);
let pos = global.push_prop(ctor_val);
global.set_data_meta(pos, PropAttributes::new(true, false, true));
global.bump_generation();
}
}
}
/// finally 处理器闭包:读自身 prop 的 onFinally 与角色,调用后透传/重抛。
@@ -854,7 +1063,437 @@ fn promise_static_reject(vm: &mut Vm, args: &[u8]) -> NativeResult {
}
}
/// GetCapabilitiesExecutor:捕获 resolve/reject 到自身 prop,重复调用抛 TypeError。
/// `Promise.all(iterable)`:全部元素结算后以结果数组完成,任一拒绝则拒绝。
fn promise_static_all(vm: &mut Vm, args: &[u8]) -> NativeResult {
let ctor = vm.reg(if args.is_empty() { 0 } else { args[0] });
let iterable = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
match perform_promise_combine(vm, ctor, iterable, AggregateKind::All) {
Ok(promise) => NativeResult::Ok(promise),
Err(err) => NativeResult::Err(err),
}
}
/// `Promise.race(iterable)`:任一元素先结算即按该结果完成/拒绝。
fn promise_static_race(vm: &mut Vm, args: &[u8]) -> NativeResult {
let ctor = vm.reg(if args.is_empty() { 0 } else { args[0] });
let iterable = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
match perform_promise_combine(vm, ctor, iterable, AggregateKind::Race) {
Ok(promise) => NativeResult::Ok(promise),
Err(err) => NativeResult::Err(err),
}
}
/// `Promise.allSettled(iterable)`:全部元素结算后以 `{status, value|reason}` 数组完成。
fn promise_static_all_settled(vm: &mut Vm, args: &[u8]) -> NativeResult {
let ctor = vm.reg(if args.is_empty() { 0 } else { args[0] });
let iterable = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
match perform_promise_combine(vm, ctor, iterable, AggregateKind::AllSettled) {
Ok(promise) => NativeResult::Ok(promise),
Err(err) => NativeResult::Err(err),
}
}
/// `Promise.any(iterable)`:任一元素完成即完成;全部拒绝则以 AggregateError(errors) 拒绝。
fn promise_static_any(vm: &mut Vm, args: &[u8]) -> NativeResult {
let ctor = vm.reg(if args.is_empty() { 0 } else { args[0] });
let iterable = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
match perform_promise_combine(vm, ctor, iterable, AggregateKind::Any) {
Ok(promise) => NativeResult::Ok(promise),
Err(err) => NativeResult::Err(err),
}
}
/// 聚合静态方法的共享核心:迭代可迭代输入,逐元素调 `C.resolve` 建 promise 并注册反应,
/// 按模式在全部/任一结算后交付能力 promise。
///
/// # 步骤
/// 1. 建能力(NewPromiseCapability(C) 抛错同步上抛),取 C.resolve 一次(不可调用 → 拒绝)。
/// 2. 建共享记录(剩余计数 = 1 + 元素数,结果数组,能力 resolve/reject)。
/// 3. 迭代元素:逐元素 `Call(C.resolve, C, «elem»)` 后 `Invoke(promise.then, 元素处理器)`。
/// 4. 迭代完成时哨兵计数递减;为 0 时结算(all/allSettled 完成数组,any 拒绝 AggregateError)。
///
/// # 边界与前提
/// - 迭代异常按来源区分是否 IteratorClose:next 调用与 then 注册抛错关闭迭代器,
/// 迭代结果对象的 done/value 读取抛错按规范直接拒绝(不关闭)。
/// - 元素处理器同步触发时(thenable 直接调 onFulfilled),剩余计数先 +1 再注册,
/// 保证中途结算仍能等齐全部元素。
fn perform_promise_combine(
vm: &mut Vm, ctor: JsValue, iterable: JsValue, kind: AggregateKind,
) -> Result<JsValue, JsValue> {
let (promise, resolve, reject) = vm.new_promise_capability_with_ctor(ctor)?;
// 取 C.resolve 一次(getter 抛错或不可调用 → 拒绝能力)。
let resolve_si = vm.kernel_core.perm_interner().intern("resolve").0;
let promise_resolve = if ctor.is_object() {
// SAFETY: ctor 是存活对象。
let ctor_obj = unsafe { &*ctor.as_js_object_ptr() };
match vm.ordinary_get(ctor_obj, resolve_si, ctor) {
Ok(v) => v,
Err(e) => {
let exc = vm
.last_uncaught_value
.take()
.unwrap_or_else(|| oxide_builtins::error::create_error(vm, &e));
let _ = vm.call_function_sync(reject, JsValue::undefined(), &[exc]);
return Ok(promise);
}
}
} else {
JsValue::undefined()
};
if !oxide_builtins::iterator::is_callable(promise_resolve) {
let exc = oxide_builtins::error::create_type_error(vm, "resolve is not a function");
let _ = vm.call_function_sync(reject, JsValue::undefined(), &[exc]);
return Ok(promise);
}
// 结果数组(race 不需要)。
let values = if kind == AggregateKind::Race {
JsValue::undefined()
} else {
let array_proto = JsValue::from_js_object(vm.session.builtin_world().array_proto.as_ptr() as *mut JsObject);
let ptr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, array_proto, 0, vm.epoch.bump()));
JsValue::from_js_object(ptr)
};
let record = vm.make_agg_record(values, resolve, reject);
// GetIterator 失败 → 拒绝(尚无迭代器可关闭)。
let iterator = match oxide_builtins::iterator::make_iterator_for_value(vm, iterable) {
Ok(it) => it,
Err(err) => {
let _ = vm.call_function_sync(reject, JsValue::undefined(), &[err]);
return Ok(promise);
}
};
enum IterAbrupt {
Close(JsValue),
NoClose(JsValue),
}
let mut index: i32 = 0;
let result: Result<(), IterAbrupt> = (|| {
let next_si = vm.kernel_core.perm_interner().intern("next").0;
let done_si = vm.kernel_core.perm_interner().intern("done").0;
let value_si = vm.kernel_core.perm_interner().intern("value").0;
// SAFETY: iterator 是存活对象。
let iter_obj = unsafe { &*iterator.as_js_object_ptr() };
let next_fn = vm
.ordinary_get(iter_obj, next_si, iterator)
.map_err(|e| IterAbrupt::Close(agg_engine_error(vm, &e)))?;
loop {
let step = vm
.call_function_sync(next_fn, iterator, &[])
.map_err(|e| IterAbrupt::Close(agg_engine_error(vm, &e)))?;
if !step.is_object() {
return Err(IterAbrupt::NoClose(oxide_builtins::error::create_type_error(
vm,
"iterator result is not an object",
)));
}
// SAFETY: step 是存活对象。
let step_obj = unsafe { &*step.as_js_object_ptr() };
let done = vm
.ordinary_get(step_obj, done_si, step)
.map_err(|e| IterAbrupt::NoClose(agg_engine_error(vm, &e)))?;
if oxide_runtime_api::to_boolean(done) {
return Ok(());
}
let elem = vm
.ordinary_get(step_obj, value_si, step)
.map_err(|e| IterAbrupt::NoClose(agg_engine_error(vm, &e)))?;
let next_promise = vm
.call_function_sync(promise_resolve, ctor, &[elem])
.map_err(|e| IterAbrupt::Close(agg_engine_error(vm, &e)))?;
// 剩余计数先 +1 再注册:thenable 同步结算时 handler 依赖该计数已含自身。
let cur = agg_read_remaining(vm, record);
agg_write_remaining(vm, record, cur + 1);
match kind {
AggregateKind::All => {
let re = vm.make_agg_element_fn(promise_all_resolve_element, record, index);
vm.invoke_then(next_promise, &[re, reject]).map_err(IterAbrupt::Close)?;
}
AggregateKind::Race => {
// race 直接把能力 resolve/reject 作为反应处理器(规范无元素函数包装,
// 能力结算一次后其余调用为 no-op)。
vm.invoke_then(next_promise, &[resolve, reject]).map_err(IterAbrupt::Close)?;
}
AggregateKind::AllSettled => {
let re = vm.make_agg_element_fn(promise_all_settled_resolve_element, record, index);
let rj = vm.make_agg_element_fn(promise_all_settled_reject_element, record, index);
vm.invoke_then(next_promise, &[re, rj]).map_err(IterAbrupt::Close)?;
}
AggregateKind::Any => {
// any 的完成侧直接用能力 resolve;拒绝侧用带 AlreadyCalled 的 reject 元素。
let rj = vm.make_agg_element_fn(promise_any_reject_element, record, index);
vm.invoke_then(next_promise, &[resolve, rj]).map_err(IterAbrupt::Close)?;
}
}
index += 1;
}
})();
match result {
Ok(()) => {
// 迭代完成:哨兵 1 递减;为 0 时结算(race 无计数语义)。
let remaining = agg_read_remaining(vm, record) - 1;
agg_write_remaining(vm, record, remaining); match kind {
AggregateKind::All | AggregateKind::AllSettled => {
if remaining == 0 {
let values = agg_record_val(vm, record, AGG_VALUES_PROP);
agg_call_resolve(vm, record, values);
}
}
AggregateKind::Any => {
if remaining == 0 {
let errors = agg_record_val(vm, record, AGG_VALUES_PROP);
let agg = vm.make_aggregate_error(errors, JsValue::undefined());
let rej = agg_record_val(vm, record, AGG_REJECT_PROP);
let _ = vm.call_function_sync(rej, JsValue::undefined(), &[agg]);
}
}
AggregateKind::Race => {}
}
}
Err(IterAbrupt::Close(e)) => {
close_agg_iterator(vm, iterator);
let rej = agg_record_val(vm, record, AGG_REJECT_PROP);
let _ = vm.call_function_sync(rej, JsValue::undefined(), &[e]);
}
Err(IterAbrupt::NoClose(e)) => {
let rej = agg_record_val(vm, record, AGG_REJECT_PROP);
let _ = vm.call_function_sync(rej, JsValue::undefined(), &[e]);
}
}
Ok(promise)
}
/// 聚合元素处理器的公共 prologue:取共享记录与下标;`already` 已置位返回 None
/// (元素函数只生效一次),否则置位后返回记录。
fn agg_element_state(vm: &mut Vm) -> Option<(JsValue, i32)> {
let callee = vm.reg(254);
if !callee.is_object() {
return None;
}
let callee_ptr = callee.as_js_object_ptr();
let rec_si = vm.kernel_core.perm_interner().intern(AGG_RECORD_PROP).0;
let idx_si = vm.kernel_core.perm_interner().intern(AGG_INDEX_PROP).0;
let al_si = vm.kernel_core.perm_interner().intern(AGG_ALREADY_PROP).0;
// SAFETY: callee 是当前调用的存活函数对象。
let callee_ref = unsafe { &*callee_ptr };
if vm.resolve_property(callee_ref, al_si).map_or(false, oxide_runtime_api::to_boolean) {
return None;
}
let record = vm.resolve_property(callee_ref, rec_si).unwrap_or(JsValue::undefined());
let index = vm
.resolve_property(callee_ref, idx_si)
.map_or(0, |v| if v.is_int() { v.as_int() } else { 0 });
// SAFETY: 同一 callee 对象,此处仅写 already 标志。
vm.set_or_create_prop_value(unsafe { &mut *callee_ptr }, al_si, JsValue::bool(true));
Some((record, index))
}
/// 读取记录对象属性(非对象/缺失返回 undefined)。
fn agg_record_val(vm: &Vm, record: JsValue, prop: &str) -> JsValue {
if !record.is_object() {
return JsValue::undefined();
}
let si = vm.kernel_core.perm_interner().intern(prop).0;
// SAFETY: record 是存活对象。
vm.resolve_property(unsafe { &*record.as_js_object_ptr() }, si)
.unwrap_or(JsValue::undefined())
}
/// 读取记录剩余计数。
fn agg_read_remaining(vm: &Vm, record: JsValue) -> i32 {
let v = agg_record_val(vm, record, AGG_REMAINING_PROP);
if v.is_int() {
v.as_int()
} else {
0
}
}
/// 写回记录剩余计数。
fn agg_write_remaining(vm: &mut Vm, record: JsValue, n: i32) {
if !record.is_object() {
return;
}
let si = vm.kernel_core.perm_interner().intern(AGG_REMAINING_PROP).0;
// SAFETY: record 是存活对象。
vm.set_or_create_prop_value(unsafe { &mut *record.as_js_object_ptr() }, si, JsValue::int(n));
}
/// 调用记录上的能力 resolve;抛错时改以能力 reject 拒绝(IfAbruptRejectPromise)。
fn agg_call_resolve(vm: &mut Vm, record: JsValue, arg: JsValue) {
let resolve = agg_record_val(vm, record, AGG_RESOLVE_PROP);
if let Err(e) = vm.call_function_sync(resolve, JsValue::undefined(), &[arg]) {
let exc = vm
.last_uncaught_value
.take()
.unwrap_or_else(|| oxide_builtins::error::create_error(vm, &e));
let reject = agg_record_val(vm, record, AGG_REJECT_PROP);
let _ = vm.call_function_sync(reject, JsValue::undefined(), &[exc]);
}
}
/// 把 `call_function_sync` 的错误文本恢复为原始异常值。
fn agg_engine_error(vm: &mut Vm, err: &str) -> JsValue {
vm.last_uncaught_value
.take()
.unwrap_or_else(|| oxide_builtins::error::create_error(vm, err))
}
/// IteratorClose:调用迭代器的 `return()`(可调用时),忽略其抛错。
fn close_agg_iterator(vm: &mut Vm, iterator: JsValue) {
if !iterator.is_object() {
return;
}
let return_si = vm.kernel_core.perm_interner().intern("return").0;
// SAFETY: iterator 是存活对象。
let iter_obj = unsafe { &*iterator.as_js_object_ptr() };
if let Ok(ret) = vm.ordinary_get(iter_obj, return_si, iterator) {
if oxide_builtins::iterator::is_callable(ret) {
let _ = vm.call_function_sync(ret, iterator, &[]);
}
}
}
/// `Promise.all` resolve 元素:写 `values[index]`,剩余计数归零时完成数组。
fn promise_all_resolve_element(vm: &mut Vm, args: &[u8]) -> NativeResult {
let Some((record, index)) = agg_element_state(vm) else {
return NativeResult::Ok(JsValue::undefined());
};
let value = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
let values = agg_record_val(vm, record, AGG_VALUES_PROP);
if values.is_object() {
let key_si = vm.kernel_core.perm_interner().intern(&index.to_string()).0;
// SAFETY: values 是存活数组对象;直写元素区不触发数组 setter。
vm.set_or_create_prop_value(unsafe { &mut *values.as_js_object_ptr() }, key_si, value);
}
let remaining = agg_read_remaining(vm, record) - 1;
agg_write_remaining(vm, record, remaining);
if remaining == 0 {
agg_call_resolve(vm, record, values);
}
NativeResult::Ok(JsValue::undefined())
}
/// `Promise.race` 使用能力 resolve/reject 直连,无独立元素函数。
/// `Promise.allSettled` resolve 元素:写 `{status:'fulfilled', value}` 记录。
fn promise_all_settled_resolve_element(vm: &mut Vm, args: &[u8]) -> NativeResult {
let Some((record, index)) = agg_element_state(vm) else {
return NativeResult::Ok(JsValue::undefined());
};
let value = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
let values = agg_record_val(vm, record, AGG_VALUES_PROP);
if values.is_object() {
let settled = vm.make_settled_record("fulfilled", "value", value);
let key_si = vm.kernel_core.perm_interner().intern(&index.to_string()).0;
// SAFETY: values 是存活数组对象。
vm.set_or_create_prop_value(unsafe { &mut *values.as_js_object_ptr() }, key_si, settled);
}
let remaining = agg_read_remaining(vm, record) - 1;
agg_write_remaining(vm, record, remaining);
if remaining == 0 {
agg_call_resolve(vm, record, values);
}
NativeResult::Ok(JsValue::undefined())
}
/// `Promise.allSettled` reject 元素:写 `{status:'rejected', reason}` 记录。
fn promise_all_settled_reject_element(vm: &mut Vm, args: &[u8]) -> NativeResult {
let Some((record, index)) = agg_element_state(vm) else {
return NativeResult::Ok(JsValue::undefined());
};
let reason = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
let values = agg_record_val(vm, record, AGG_VALUES_PROP);
if values.is_object() {
let settled = vm.make_settled_record("rejected", "reason", reason);
let key_si = vm.kernel_core.perm_interner().intern(&index.to_string()).0;
// SAFETY: values 是存活数组对象。
vm.set_or_create_prop_value(unsafe { &mut *values.as_js_object_ptr() }, key_si, settled);
}
let remaining = agg_read_remaining(vm, record) - 1;
agg_write_remaining(vm, record, remaining);
if remaining == 0 {
agg_call_resolve(vm, record, values);
}
NativeResult::Ok(JsValue::undefined())
}
/// `Promise.any` reject 元素:写 `errors[index]`,全部拒绝时以 AggregateError 拒绝。
fn promise_any_reject_element(vm: &mut Vm, args: &[u8]) -> NativeResult {
let Some((record, index)) = agg_element_state(vm) else {
return NativeResult::Ok(JsValue::undefined());
};
let reason = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
let errors = agg_record_val(vm, record, AGG_VALUES_PROP);
if errors.is_object() {
let key_si = vm.kernel_core.perm_interner().intern(&index.to_string()).0;
// SAFETY: errors 是存活数组对象。
vm.set_or_create_prop_value(unsafe { &mut *errors.as_js_object_ptr() }, key_si, reason);
}
let remaining = agg_read_remaining(vm, record) - 1;
agg_write_remaining(vm, record, remaining);
if remaining == 0 {
let agg = vm.make_aggregate_error(errors, JsValue::undefined());
let reject = agg_record_val(vm, record, AGG_REJECT_PROP);
let _ = vm.call_function_sync(reject, JsValue::undefined(), &[agg]);
}
NativeResult::Ok(JsValue::undefined())
}
/// `AggregateError(errors, message)` 构造器:message 非 undefined 时先 ToString 建
/// 自身属性,再把 errors 可迭代收集为 `errors` 数据属性。
fn aggregate_error_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult {
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
let errors = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
let message = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
let this = if this_val.is_object() {
this_val.as_js_object_ptr()
} else {
let proto_val = JsValue::from_js_object(vm.aggregate_error_proto.as_ptr() as *mut JsObject);
vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, proto_val))
};
if !message.is_undefined() {
let msg_str = match oxide_runtime_api::to_string_full(message, vm) {
Ok(s) => s,
Err(e) => {
let exc = vm
.last_uncaught_value
.take()
.unwrap_or_else(|| oxide_builtins::error::create_error(vm, &e));
return NativeResult::Err(exc);
}
};
let msg_si = vm.kernel_core.perm_interner().intern("message").0;
let msg_val = vm.new_string(&msg_str);
// SAFETY: this 是本次构造的存活对象。
let _ = vm.define_data_property(
unsafe { &mut *this },
msg_si,
msg_val,
PropAttributes::new(true, false, true),
);
}
let errors_list = match vm.aggregate_errors_to_list(errors) {
Ok(list) => list,
Err(err) => return NativeResult::Err(err),
};
let err_si = vm.kernel_core.perm_interner().intern("errors").0;
let _ = vm.define_data_property(
unsafe { &mut *this },
err_si,
errors_list,
PropAttributes::new(true, false, true),
);
NativeResult::Ok(JsValue::from_js_object(this))
}
/// GetCapabilitiesExecutor:捕获 resolve/reject 到自身 prop;能力已持有任一
/// 非 undefined 值时再次调用抛 TypeError。
fn capability_executor(vm: &mut Vm, args: &[u8]) -> NativeResult {
let callee = vm.reg(254);
if !callee.is_object() {
@@ -862,7 +1501,10 @@ fn capability_executor(vm: &mut Vm, args: &[u8]) -> NativeResult {
}
let obj = unsafe { &*callee.as_js_object_ptr() };
let res_si = vm.kernel_core.perm_interner().intern(CAP_RESOLVE_PROP).0;
if vm.resolve_property(obj, res_si).is_some_and(|v| v.is_object()) {
let rej_si = vm.kernel_core.perm_interner().intern(CAP_REJECT_PROP).0;
let held = vm.resolve_property(obj, res_si).map_or(false, |v| !v.is_undefined())
|| vm.resolve_property(obj, rej_si).map_or(false, |v| !v.is_undefined());
if held {
return NativeResult::Err(oxide_builtins::error::create_type_error(
vm,
"Promise capability executor has already been called",
@@ -871,7 +1513,6 @@ fn capability_executor(vm: &mut Vm, args: &[u8]) -> NativeResult {
let resolve = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
let reject = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
let obj = unsafe { &mut *callee.as_js_object_ptr() };
let rej_si = vm.kernel_core.perm_interner().intern(CAP_REJECT_PROP).0;
vm.set_or_create_prop_value(obj, res_si, resolve);
vm.set_or_create_prop_value(obj, rej_si, reject);
NativeResult::Ok(JsValue::undefined())
+4
View File
@@ -250,6 +250,10 @@ pub struct Vm {
pub promise_constructor: P<JsObject>,
/// `%Promise.prototype%`:Promise 实例的原型(then/catch/finally 方法挂此)。
pub promise_proto: P<JsObject>,
/// `%AggregateError%` 构造器(Promise.any 拒绝时构造 AggregateError 用)。
pub aggregate_error_constructor: P<JsObject>,
/// `%AggregateError.prototype%`(proto = %Error.prototype%)。
pub aggregate_error_proto: P<JsObject>,
/// `%AsyncFunction.prototype%`:异步函数对象的原型(`constructor` 指向 `%AsyncFunction%`)。
pub async_function_proto: P<JsObject>,
/// 微任务队列(Promise reactions / thenable 委托),`run()` 末尾 FIFO drain。
+4
View File
@@ -37,6 +37,8 @@ impl Vm {
generator_function_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
promise_constructor: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
promise_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
aggregate_error_constructor: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
aggregate_error_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
async_function_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
job_queue: VecDeque::new(),
math_rng_state: 0,
@@ -122,6 +124,8 @@ impl Vm {
generator_function_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
promise_constructor: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
promise_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
aggregate_error_constructor: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
aggregate_error_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
async_function_proto: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
job_queue: VecDeque::new(),
math_rng_state: 0,