feat: AsyncDisposableStack disposeAsync 状态机(needsAwait 微任务序 + 错误链合并 + 绑定三时机)

This commit is contained in:
2026-08-16 20:11:50 +08:00
parent 742897f319
commit 6c7bcdeed6
5 changed files with 488 additions and 1 deletions
+326
View File
@@ -0,0 +1,326 @@
//! AsyncDisposableStack.prototype.disposeAsync 的 VM 层实现。
//!
//! disposeAsync 返回 `%Promise%` 能力,逆序释放栈内条目。循环体以原生函数
//! 闭包实现(续链闭包),跨 await 的状态(游标/错误合并/needsAwait/hasAwaited)
//! 存函数对象属性槽;栈对象引用存入闭包槽保活状态盒(跨 await 不被 GC 回收)。
//! 2026 新版 DisposeResources 语义:null/undefined 型 async 条目的 Await 延迟到
//! 循环末单次执行;sync 条目遇待决 Await 先插队执行 Await;`@@dispose` 来源的
//! 方法(wrap_sync)返回值丢弃、同步异常异步化为拒绝再 await。
//!
//! 状态机仿 AsyncFromSync 续链模式:每次 await 经 `promise_resolve` +
//! `perform_promise_then` 注册同一 native(不同 reject_role 槽)的两个闭包实例,
//! 派生的中间 promise 不可观察。
use oxide_builtins::disposable_stack::{merge_dispose_error, require_dispose_capability, DisposeState};
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
use oxide_runtime_api::NativeResult;
use oxide_types::object::{JsObject, NativeFnPtr};
use oxide_types::value::JsValue;
use crate::vm::Vm;
/// 续链闭包上保存状态盒所在栈对象的属性名(保活状态盒)。
const STACK_PROP: &str = "__oxide_ads_stack__";
/// 续链闭包上保存能力 resolve 的属性名。
const RESOLVE_PROP: &str = "__oxide_ads_resolve__";
/// 续链闭包上保存能力 reject 的属性名。
const REJECT_PROP: &str = "__oxide_ads_reject__";
/// 续链闭包上保存下一 entry 下标的属性名(逆序遍历 0→len)。
const INDEX_PROP: &str = "__oxide_ads_index__";
/// 续链闭包上保存已合并错误值的属性名(无错时为 undefined)。
const COMPLETION_PROP: &str = "__oxide_ads_completion__";
/// 续链闭包上保存是否已有错误值的属性名(区分"无错"与"错误值为 undefined")。
const HAS_COMPLETION_PROP: &str = "__oxide_ads_has_completion__";
/// 续链闭包上保存 needsAwait 标志的属性名(末尾补 Await / sync 插队判断)。
const NEEDS_AWAIT_PROP: &str = "__oxide_ads_needs_await__";
/// 续链闭包上保存 hasAwaited 标志的属性名(真实 async 方法是否已 await)。
const HAS_AWAITED_PROP: &str = "__oxide_ads_has_awaited__";
/// 续链闭包上区分 reject 角色的属性名(reject 处理器先合并入参为错误)。
const REJECT_ROLE_PROP: &str = "__oxide_ads_reject_role__";
/// `AsyncDisposableStack.prototype.disposeAsync()`:逆序释放全部资源并返回能力。
///
/// # 步骤
/// 1. 新建 promise 能力;this 非 AsyncDisposableStack(type_tag=25)或无状态盒 →
/// reject 该能力(**reject 而非抛**)并返回。
/// 2. 已 Disposed → 同步 fulfill undefined(幂等,当前轮即入队反应)。
/// 3. 同步置 state=Disposed(防重入;执行中的二次调用命中步骤 2)。
/// 4. 建续链闭包并同步执行循环至首次 await 或完成:完成时 fulfill/reject 能力
/// 同步结算(空栈/纯 sync 满足微任务序断言);首次 await 注册续链后返回。
pub(crate) fn dispose_async(vm: &mut Vm, args: &[u8]) -> NativeResult {
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
let (promise, resolve, reject) = vm.new_promise_capability();
let cap = match require_dispose_capability(vm, this_val, JsObject::OBJ_TYPE_ASYNC_DISPOSABLE_STACK) {
Ok(c) => c,
Err(err) => {
let _ = vm.call_function_sync(reject, JsValue::undefined(), &[err]);
return NativeResult::Ok(promise);
}
};
// SAFETY: cap 由 require 校验,native 执行期间对象存活。
let state = unsafe { (*cap).state };
if state == DisposeState::Disposed {
let _ = vm.call_function_sync(resolve, JsValue::undefined(), &[JsValue::undefined()]);
return NativeResult::Ok(promise);
}
// 先置位再执行:执行中/后续调用 disposeAsync 均命中 Disposed 分支。
unsafe { (*cap).state = DisposeState::Disposed };
let entries_len = unsafe { (*cap).entries.len() };
let continue_fn = make_dispose_continue_fn(vm, this_val, resolve, reject, false, None);
// 逆序游标初始化为条目数:INDEX 槽表示下一待处理位置(len → 0 递减)。
let continue_obj = unsafe { &mut *continue_fn.as_js_object_ptr() };
write_prop(vm, continue_obj, INDEX_PROP, JsValue::int(entries_len as i32));
run_dispose_loop(vm, &continue_fn, JsValue::undefined(), false);
NativeResult::Ok(promise)
}
/// 构造 disposeAsync 续链闭包:native 函数对象,状态存属性槽。
///
/// # 步骤
/// 1. 以 `dispose_async_continue` 建原生函数对象(length=1)。
/// 2. 写栈对象/能力闭包/角色槽;`state_from` 给出当前循环状态(游标/错误合并/
/// await 标志)时逐槽复制,保证续链从上次让出点继续。
fn make_dispose_continue_fn(
vm: &mut Vm, stack: JsValue, resolve: JsValue, reject: JsValue, reject_role: bool, state_from: Option<&JsObject>,
) -> JsValue {
let fn_proto = vm.session.builtin_world().fn_proto_val();
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
func.set_function(true);
// SAFETY: dispose_async_continue 是 NativeFn 函数项。
func.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(dispose_async_continue as *const ()) }));
func.set_native_arg_count(1);
let ptr = vm.alloc_object(func);
let obj = unsafe { &mut *ptr };
let stack_si = vm.kernel_core.perm_interner().intern(STACK_PROP).0;
vm.set_or_create_prop_value(obj, stack_si, stack);
let resolve_si = vm.kernel_core.perm_interner().intern(RESOLVE_PROP).0;
vm.set_or_create_prop_value(obj, resolve_si, resolve);
let reject_si = vm.kernel_core.perm_interner().intern(REJECT_PROP).0;
vm.set_or_create_prop_value(obj, reject_si, reject);
if let Some(src) = state_from {
let index_si = vm.kernel_core.perm_interner().intern(INDEX_PROP).0;
if let Some(v) = vm.resolve_property(src, index_si) {
vm.set_or_create_prop_value(obj, index_si, v);
}
let completion_si = vm.kernel_core.perm_interner().intern(COMPLETION_PROP).0;
if let Some(v) = vm.resolve_property(src, completion_si) {
vm.set_or_create_prop_value(obj, completion_si, v);
}
let has_completion_si = vm.kernel_core.perm_interner().intern(HAS_COMPLETION_PROP).0;
if let Some(v) = vm.resolve_property(src, has_completion_si) {
vm.set_or_create_prop_value(obj, has_completion_si, v);
}
let needs_await_si = vm.kernel_core.perm_interner().intern(NEEDS_AWAIT_PROP).0;
if let Some(v) = vm.resolve_property(src, needs_await_si) {
vm.set_or_create_prop_value(obj, needs_await_si, v);
}
let has_awaited_si = vm.kernel_core.perm_interner().intern(HAS_AWAITED_PROP).0;
if let Some(v) = vm.resolve_property(src, has_awaited_si) {
vm.set_or_create_prop_value(obj, has_awaited_si, v);
}
} else {
let index_si = vm.kernel_core.perm_interner().intern(INDEX_PROP).0;
vm.set_or_create_prop_value(obj, index_si, JsValue::int(0));
let completion_si = vm.kernel_core.perm_interner().intern(COMPLETION_PROP).0;
vm.set_or_create_prop_value(obj, completion_si, JsValue::undefined());
let has_completion_si = vm.kernel_core.perm_interner().intern(HAS_COMPLETION_PROP).0;
vm.set_or_create_prop_value(obj, has_completion_si, JsValue::bool(false));
let needs_await_si = vm.kernel_core.perm_interner().intern(NEEDS_AWAIT_PROP).0;
vm.set_or_create_prop_value(obj, needs_await_si, JsValue::bool(false));
let has_awaited_si = vm.kernel_core.perm_interner().intern(HAS_AWAITED_PROP).0;
vm.set_or_create_prop_value(obj, has_awaited_si, JsValue::bool(false));
}
let role_si = vm.kernel_core.perm_interner().intern(REJECT_ROLE_PROP).0;
vm.set_or_create_prop_value(obj, role_si, JsValue::bool(reject_role));
vm.add_fn_name_length(obj, "", 1);
JsValue::from_js_object(ptr)
}
/// 续链闭包回调:读角色槽区分 fulfill/reject,把 await 结果交给循环主体。
fn dispose_async_continue(vm: &mut Vm, args: &[u8]) -> NativeResult {
let callee = vm.reg(254);
if !callee.is_object() {
return NativeResult::Err(oxide_builtins::error::create_type_error(
vm,
"disposeAsync continuation handler is invalid",
));
}
let callee_obj = unsafe { &*callee.as_js_object_ptr() };
let role_si = vm.kernel_core.perm_interner().intern(REJECT_ROLE_PROP).0;
let reject_role = vm
.resolve_property(callee_obj, role_si)
.map(|v| v.is_bool() && v.as_bool())
.unwrap_or(false);
let arg = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
run_dispose_loop(vm, &callee, arg, reject_role);
NativeResult::Ok(JsValue::undefined())
}
/// disposeAsync 循环主体:逆序遍历 entries,按 2026 DisposeResources 语义释放。
///
/// # 步骤
/// 1. 读全部状态槽;reject 角色先把 await 拒绝原因合并进完成记录。
/// 2. 逐条逆序处理:
/// - 游标越界:needsAwait 且未 await 过 → 末尾补一次 Await(undefined);
/// 否则清空 entries 并结算能力(有错 reject / 无错 fulfill)。
/// - sync 条目遇待决 needsAwait → 先插队 Await(undefined) 再执行。
/// - method 为 undefined(async-null 条目)→ 置 needsAwait,继续。
/// - 调用释放回调:sync 抛错 → 合并后继续;async 条目调用成功 → 记
/// hasAwaited 并 await(wrap_sync 丢弃返回值 await undefined);wrap_sync
/// 同步抛错 → 建 rejected promise 异步化后 await;真实 async 方法同步抛错
/// → 直接合并(规范不异步化)。
/// 3. 每次 await 前更新状态槽,注册同一 native 的 fulfill/reject 双闭包续链。
fn run_dispose_loop(vm: &mut Vm, callee: &JsValue, arg: JsValue, reject_role: bool) {
if !callee.is_object() {
return;
}
// SAFETY: callee 是当前 native 调用的函数对象,native 执行期间存活。
let callee_obj = unsafe { &mut *callee.as_js_object_ptr() };
let stack = read_prop(vm, callee_obj, STACK_PROP);
let resolve = read_prop(vm, callee_obj, RESOLVE_PROP);
let reject = read_prop(vm, callee_obj, REJECT_PROP);
if !stack.is_object() || resolve.is_undefined() || reject.is_undefined() {
return;
}
let mut index = read_int(vm, callee_obj, INDEX_PROP);
let mut completion = read_prop(vm, callee_obj, COMPLETION_PROP);
let mut has_completion = read_bool(vm, callee_obj, HAS_COMPLETION_PROP);
let mut needs_await = read_bool(vm, callee_obj, NEEDS_AWAIT_PROP);
let mut has_awaited = read_bool(vm, callee_obj, HAS_AWAITED_PROP);
if reject_role {
let merged = merge_dispose_error(vm, if has_completion { Some(completion) } else { None }, arg);
(completion, has_completion) = match merged {
Some(err) => (err, true),
None => (JsValue::undefined(), false),
};
write_prop(vm, callee_obj, HAS_COMPLETION_PROP, JsValue::bool(has_completion));
write_prop(vm, callee_obj, COMPLETION_PROP, completion);
}
loop {
let stack_ptr = stack.as_js_object_ptr();
if stack_ptr.is_null() {
return;
}
// SAFETY: stack 对象由闭包槽保活,native 执行期间 epoch 不重置。
let stack_obj = unsafe { &*stack_ptr };
if !stack_obj.is_async_disposable_stack_obj() {
return;
}
let cap = oxide_builtins::disposable_stack::get_capability_ptr(stack_obj);
if cap.is_null() {
return;
}
// SAFETY: cap 是构造时写入的有效 Box 指针,状态盒随栈对象存活。
let cap_ref = unsafe { &mut *cap };
if index == 0 {
if needs_await && !has_awaited {
needs_await = false;
write_prop(vm, callee_obj, NEEDS_AWAIT_PROP, JsValue::bool(needs_await));
try_await(vm, callee_obj, JsValue::undefined());
return;
}
cap_ref.entries.clear();
let _ = if has_completion {
vm.call_function_sync(reject, JsValue::undefined(), &[completion])
} else {
vm.call_function_sync(resolve, JsValue::undefined(), &[JsValue::undefined()])
};
return;
}
let entry = cap_ref.entries[index - 1];
if entry.hint == 0 && needs_await && !has_awaited {
// 插队 await:不推进游标,await 续链后重读同一位置执行该 sync 条目。
needs_await = false;
write_prop(vm, callee_obj, NEEDS_AWAIT_PROP, JsValue::bool(needs_await));
try_await(vm, callee_obj, JsValue::undefined());
return;
}
index -= 1;
write_prop(vm, callee_obj, INDEX_PROP, JsValue::int(index as i32));
if entry.method.is_undefined() {
needs_await = true;
write_prop(vm, callee_obj, NEEDS_AWAIT_PROP, JsValue::bool(needs_await));
continue;
}
match oxide_builtins::disposable_stack::call_entry_method(vm, &entry) {
Err(err) => {
if entry.hint == 1 && entry.wrap_sync {
has_awaited = true;
write_prop(vm, callee_obj, HAS_AWAITED_PROP, JsValue::bool(has_awaited));
let (rejected, _, _) = vm.new_promise_capability();
let _ = vm.reject_promise(rejected, err);
try_await(vm, callee_obj, rejected);
return;
}
let merged = merge_dispose_error(vm, if has_completion { Some(completion) } else { None }, err);
(completion, has_completion) = match merged {
Some(err_val) => (err_val, true),
None => (JsValue::undefined(), false),
};
write_prop(vm, callee_obj, HAS_COMPLETION_PROP, JsValue::bool(has_completion));
write_prop(vm, callee_obj, COMPLETION_PROP, completion);
}
Ok(value) => {
if entry.hint == 1 {
has_awaited = true;
write_prop(vm, callee_obj, HAS_AWAITED_PROP, JsValue::bool(has_awaited));
let awaited = if entry.wrap_sync { JsValue::undefined() } else { value };
try_await(vm, callee_obj, awaited);
return;
}
}
}
}
}
/// 读闭包对象属性槽的 bool 值(缺失回退 false)。
fn read_bool(vm: &Vm, obj: &JsObject, prop: &str) -> bool {
let v = read_prop(vm, obj, prop);
v.is_bool() && v.as_bool()
}
/// 读闭包对象属性槽的 int 值(缺失回退 0)。
fn read_int(vm: &Vm, obj: &JsObject, prop: &str) -> usize {
let v = read_prop(vm, obj, prop);
if v.is_int() && v.as_int() >= 0 {
v.as_int() as usize
} else {
0
}
}
/// 读闭包对象属性槽值(缺失回退 undefined)。
fn read_prop(vm: &Vm, obj: &JsObject, prop: &str) -> JsValue {
let si = vm.kernel_core.perm_interner().intern(prop).0;
vm.resolve_property(obj, si).unwrap_or(JsValue::undefined())
}
/// 写闭包对象属性槽值。
fn write_prop(vm: &mut Vm, obj: &mut JsObject, prop: &str, val: JsValue) {
let si = vm.kernel_core.perm_interner().intern(prop).0;
vm.set_or_create_prop_value(obj, si, val);
}
/// 等待 `value`:PromiseResolve 包装后注册续链;失败(constructor getter 抛错)
/// 直接拒绝能力(规范 Await abrupt → IfAbruptRejectPromise)。
///
/// # 副作用
/// - 注册的 fulfill/reject 续链闭包持全套状态槽;派生 promise 不可观察。
fn try_await(vm: &mut Vm, callee_obj: &JsObject, value: JsValue) {
let promise = match vm.promise_resolve(value) {
Ok(p) => p,
Err(exc) => {
let reject = read_prop(vm, callee_obj, REJECT_PROP);
let _ = vm.call_function_sync(reject, JsValue::undefined(), &[exc]);
return;
}
};
let stack = read_prop(vm, callee_obj, STACK_PROP);
let resolve = read_prop(vm, callee_obj, RESOLVE_PROP);
let reject = read_prop(vm, callee_obj, REJECT_PROP);
let fulfill_fn = make_dispose_continue_fn(vm, stack, resolve, reject, false, Some(callee_obj));
let reject_fn = make_dispose_continue_fn(vm, stack, resolve, reject, true, Some(callee_obj));
let _ = vm.perform_promise_then(promise, fulfill_fn, reject_fn);
}
@@ -0,0 +1,154 @@
use std::sync::Arc;
use oxide_kernel::kernel::{KernelCore, KernelSession};
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
use oxide_types::object::{JsObject, PropAttributes};
use oxide_types::value::JsValue;
use crate::async_disposable::dispose_async;
use crate::bindings::{
apply_binding_table, bind_accessor_getter, bind_disposable_stack::write_proto_constructor, bind_global_value,
bind_well_known_data_property, bind_well_known_method_alias, configure_native_constructor,
};
/// 在 `AsyncDisposableStack.prototype` 上安装方法/别名/访问器/@@toStringTag。
///
/// 幂等:proto 上已有 `use` 方法(全新 proto 或已完整绑定)时整组跳过,
/// 保留原型经 dirty reset 重复经过时安全。`@@asyncDispose` 别名须在
/// `disposeAsync` 绑定之后调用(读源槽 lookup_position,顺序敏感)。
pub fn bind_async_disposable_stack_protos(core: &Arc<KernelCore>, session: &KernelSession) {
let world = session.builtin_world();
let proto_ptr = world.async_disposable_stack_proto.as_ptr() as *mut JsObject;
let proto = unsafe { &mut *proto_ptr };
let si_use = core.perm_interner().intern("use").0;
if core.shape_forge().lookup_position(proto.shape_id(), si_use).is_some() {
return;
}
apply_binding_table(
world,
proto,
core,
&[
(
"use",
oxide_builtins::disposable_stack::async_disposable_stack_use::<crate::vm::Vm> as *const (),
1,
),
(
"adopt",
oxide_builtins::disposable_stack::async_disposable_stack_adopt::<crate::vm::Vm> as *const (),
2,
),
(
"defer",
oxide_builtins::disposable_stack::async_disposable_stack_defer::<crate::vm::Vm> as *const (),
1,
),
(
"move",
oxide_builtins::disposable_stack::async_disposable_stack_move::<crate::vm::Vm> as *const (),
0,
),
("disposeAsync", dispose_async as *const (), 0),
],
);
bind_accessor_getter(
core,
session,
proto,
"disposed",
oxide_builtins::disposable_stack::async_disposable_stack_disposed_getter::<crate::vm::Vm> as *const (),
);
// @@asyncDispose 与 disposeAsync 为同一函数对象(先绑 disposeAsync 再取源槽)。
bind_well_known_method_alias(core, proto, "disposeAsync", 11);
let sf = core.perm_interner().as_ref();
let tag = JsValue::perm_string(sf.string_ptr(sf.intern("AsyncDisposableStack").0));
bind_well_known_data_property(core, proto, 9, tag, PropAttributes::new(false, false, true));
}
/// 把 `AsyncDisposableStack` 构造器绑定到 global(init 与 full_reset global 重建共用)。
///
/// proto.constructor 已有则复用(dirty reset 保留路径);否则 Box 自建构造器
/// (proto=Function.prototype,prototype 槽=AsyncDisposableStack.prototype,
/// 描述符按规范)。幂等:protos 安装与 global 槽写入均自带重复跳过。
pub fn bind_async_disposable_stack(core: &Arc<KernelCore>, session: &KernelSession, global: &mut JsObject) {
let world = session.builtin_world();
let proto_ptr = world.async_disposable_stack_proto.as_ptr() as *mut JsObject;
let proto = unsafe { &mut *proto_ptr };
let si_constructor = core.perm_interner().intern("constructor").0;
let ctor_val = match core.shape_forge().lookup_position(proto.shape_id(), si_constructor) {
Some(pos) => {
let existing = proto.get_prop_at(pos);
if existing.is_object() {
existing
} else {
JsValue::undefined()
}
}
None => JsValue::undefined(),
};
let ctor_val = if ctor_val.is_object() {
ctor_val
} else {
// Box 自建:[[Prototype]] 指向 Function.prototype,prototype/name 描述符按规范。
let function_proto = world.function_proto.as_ptr() as *mut JsObject;
let mut ctor = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(function_proto)));
ctor.set_function(true);
configure_native_constructor(
&mut ctor,
oxide_builtins::disposable_stack::async_disposable_stack_constructor::<crate::vm::Vm> as *const (),
0,
);
let sf = core.perm_interner().as_ref();
let sh = core.shape_forge().as_ref();
let si_prototype = sf.intern("prototype").0;
let si_name = sf.intern("name").0;
let si_length = sf.intern("length").0;
let ctor_shape1 = sh.make_shape(EMPTY_SHAPE_ID, si_prototype);
let ctor_shape2 = sh.make_shape(ctor_shape1, si_name);
let ctor_shape3 = sh.make_shape(ctor_shape2, si_length);
ctor.set_shape_id(ctor_shape3);
ctor.ensure_hash_props()
.push(JsValue::from_js_object(world.async_disposable_stack_proto.as_ptr() as *mut JsObject));
ctor.ensure_hash_props()
.push(JsValue::perm_string(sf.string_ptr(sf.intern("AsyncDisposableStack").0)));
ctor.ensure_hash_props().push(JsValue::int(0));
ctor.set_data_meta(0u32, PropAttributes::new(false, false, false));
ctor.set_data_meta(1u32, PropAttributes::new(false, false, true));
ctor.set_data_meta(2u32, PropAttributes::new(false, false, true));
JsValue::from_js_object(Box::into_raw(ctor))
};
write_proto_constructor(core, proto, ctor_val);
bind_async_disposable_stack_protos(core, session);
bind_global_value(core, global, "AsyncDisposableStack", ctor_val);
}
/// 对齐保留 global 上 `AsyncDisposableStack` 函数对象的 `prototype` 属性:object
/// 家族重建会产生新的 `AsyncDisposableStack.prototype`,保留的构造器须指向新
/// 原型,否则 reset 后 `instanceof` 沿旧原型链恒 false。
///
/// global 同时重建(global dirty)或初始化时无 `AsyncDisposableStack` 属性,
/// 直接跳过——彼时由 `bind_async_disposable_stack` 以新原型创建函数对象。
pub fn sync_async_disposable_stack_ctor(core: &Arc<KernelCore>, session: &KernelSession, global: &mut JsObject) {
let si_stack = core.perm_interner().intern("AsyncDisposableStack").0;
let Some(pos) = core.shape_forge().lookup_position(global.shape_id(), si_stack) else {
return;
};
let stack_val = global.get_prop_at(pos);
if !stack_val.is_object() {
return;
}
let ctor = unsafe { &mut *stack_val.as_js_object_ptr() };
let si_prototype = core.perm_interner().intern("prototype").0;
let Some(proto_pos) = core.shape_forge().lookup_position(ctor.shape_id(), si_prototype) else {
return;
};
let new_proto =
JsValue::from_js_object(session.builtin_world().async_disposable_stack_proto.as_ptr() as *mut JsObject);
ctor.set_prop_at(proto_pos, new_proto);
let proto_ptr = session.builtin_world().async_disposable_stack_proto.as_ptr() as *mut JsObject;
write_proto_constructor(core, unsafe { &mut *proto_ptr }, stack_val);
}
@@ -71,7 +71,7 @@ pub fn bind_disposable_stack_protos(core: &Arc<KernelCore>, session: &KernelSess
}
/// 在 proto 上写 `constructor` 数据属性(非枚举,描述符 {t,f,t})。
fn write_proto_constructor(core: &Arc<KernelCore>, proto: &mut JsObject, ctor_val: JsValue) {
pub(crate) fn write_proto_constructor(core: &Arc<KernelCore>, proto: &mut JsObject, ctor_val: JsValue) {
let sf = core.perm_interner().as_ref();
let sh = core.shape_forge().as_ref();
let si_constructor = sf.intern("constructor").0;
+6
View File
@@ -6,6 +6,8 @@
pub mod bind_array;
/// ArrayBuffer 构造器与原型的 native 方法绑定。
pub mod bind_array_buffer;
/// AsyncDisposableStack 构造器与原型的 native 方法绑定(含 dirty reset 同步)。
pub mod bind_async_disposable_stack;
/// BigInt 构造器与原型的 native 方法绑定。
pub mod bind_bigint;
/// Boolean 构造器与原型的 native 方法绑定。
@@ -975,6 +977,7 @@ pub fn bind_global_builtin_slots(core: &Arc<KernelCore>, session: &KernelSession
bind_reflect_global(core, session, global);
bind_iterator_global(core, session, global);
bind_disposable_stack::bind_disposable_stack(core, session, global);
bind_async_disposable_stack::bind_async_disposable_stack(core, session, global);
bind_stub_globals(core, session, global);
bind_bigint::bind_bigint(core, session, global);
bind_global_functions(core, session, global);
@@ -1000,6 +1003,8 @@ pub fn rebind_dirty_builtins(core: &Arc<KernelCore>, session: &mut KernelSession
sync_iterator_function_prototype(core, session, global);
bind_disposable_stack::bind_disposable_stack_protos(core, session);
bind_disposable_stack::sync_disposable_stack_ctor(core, session, global);
bind_async_disposable_stack::bind_async_disposable_stack_protos(core, session);
bind_async_disposable_stack::sync_async_disposable_stack_ctor(core, session, global);
}
if dirty.map_or(true, |d| d.array) {
bind_array::bind_array(core, session, global);
@@ -1067,6 +1072,7 @@ pub fn init_kernel_builtins(core: &Arc<KernelCore>, session: &mut KernelSession)
let global = unsafe { &mut *global_ptr };
bind_iterator::bind_iterator(core, session, global);
bind_disposable_stack::bind_disposable_stack(core, session, global);
bind_async_disposable_stack::bind_async_disposable_stack(core, session, global);
bind_reflect::bind_reflect(core, session, global);
bind_global::bind_global(core, session, global);
bind_global_value(core, global, "globalThis", JsValue::from_js_object(global_ptr));
+1
View File
@@ -7,6 +7,7 @@
//! 核心入口为 [`vm::Vm`];`VmPool` 负责 VM 实例的复用;`session_gc` 提供
//! session 内存回收;`bindings` 把内置对象绑定到每个 session 的 global 上。
mod async_disposable;
mod async_from_sync;
mod async_func;
mod async_generator;