From 2920c77148a5b884de380ae81492534ba3dd0562 Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Thu, 24 Sep 2026 22:36:54 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=A1=A5=E9=BD=90=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E6=9E=84=E9=80=A0=E5=99=A8=E6=97=8F=E4=B8=8E?= =?UTF-8?q?=E5=8E=9F=E5=9E=8B=E5=AF=B9=E8=B1=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_builtins/src/function.rs | 39 +++++++++++-- crates/oxide_runtime_api/src/host.rs | 15 ++++- crates/oxide_vm/src/async_func.rs | 61 +++++++++++++------- crates/oxide_vm/src/async_generator.rs | 67 +++++++++++++++------- crates/oxide_vm/src/generator.rs | 77 ++++++++++++++++++-------- crates/oxide_vm/src/vm/dynamic.rs | 19 ++++++- crates/oxide_vm/src/vm/vmhost.rs | 21 ++++++- crates/oxide_vm/src/vm_support.rs | 3 +- 8 files changed, 224 insertions(+), 78 deletions(-) diff --git a/crates/oxide_builtins/src/function.rs b/crates/oxide_builtins/src/function.rs index a1ff1e93..708d58dd 100644 --- a/crates/oxide_builtins/src/function.rs +++ b/crates/oxide_builtins/src/function.rs @@ -19,7 +19,34 @@ fn invoke_target(vm: &mut H, target_val: JsValue, this_val: JsValue, /// 实参转单元序列后经 `source_escape` 源码域转义再动态编译。 /// 编译成功返回函数对象,语法错误抛 SyntaxError,实参 ToPrimitive 失败抛 TypeError。 pub fn function_constructor(vm: &mut H, args: &[u8]) -> NativeResult { - let arg_regs = &args[1..]; + dynamic_function_core(vm, &args[1..], false, false) +} + +/// `GeneratorFunction(...)` / `new GeneratorFunction(...)` 构造器:动态编译 +/// 一个匿名生成器函数(`function*` 形态)。 +pub fn generator_function_constructor(vm: &mut H, args: &[u8]) -> NativeResult { + dynamic_function_core(vm, &args[1..], true, false) +} + +/// `AsyncFunction(...)` / `new AsyncFunction(...)` 构造器:动态编译一个匿名 +/// 异步函数(`async function` 形态)。 +pub fn async_function_constructor(vm: &mut H, args: &[u8]) -> NativeResult { + dynamic_function_core(vm, &args[1..], false, true) +} + +/// `AsyncGeneratorFunction(...)` / `new AsyncGeneratorFunction(...)` 构造器: +/// 动态编译一个匿名异步生成器函数(`async function*` 形态)。 +pub fn async_generator_function_constructor(vm: &mut H, args: &[u8]) -> NativeResult { + dynamic_function_core(vm, &args[1..], true, true) +} + +/// 四个动态函数构造器的公共体:除最后一个实参为函数体外,其余实参为形参名; +/// 无实参时函数体为空串。实参转单元序列后经 `source_escape` 源码域转义再 +/// 动态编译(`is_generator` / `is_async` 决定 wrap 源码函数形态)。 +/// 编译成功返回函数对象,语法错误抛 SyntaxError,实参 ToPrimitive 失败抛 TypeError。 +fn dynamic_function_core( + vm: &mut H, arg_regs: &[u8], is_generator: bool, is_async: bool, +) -> NativeResult { let (param_regs, body_reg) = if arg_regs.is_empty() { (vec![], None) } else { @@ -44,7 +71,7 @@ pub fn function_constructor(vm: &mut H, args: &[u8]) -> NativeResult None => String::new(), }; - match vm.create_dynamic_function(¶ms, &body) { + match vm.create_dynamic_function(¶ms, &body, is_generator, is_async) { Ok(func) => NativeResult::Ok(func), Err(msg) => NativeResult::Err(crate::error::create_syntax_error(vm, &msg)), } @@ -344,9 +371,9 @@ fn bound_restricted_thrower(vm: &mut H, _args: &[u8]) -> NativeResult /// %ThrowTypeError%:Function.prototype 的 caller/arguments 受限访问器共用。 /// -/// 按接收者严格性分流:严格函数对象与 native 函数(含 Function.prototype 本身) -/// 的 get/set 一律抛 TypeError;非严格函数对象读不抛、返回 undefined(写不抛、 -/// 丢弃写入),与规范"非严格函数 caller 可读"的残面一致。 +/// 按接收者受限性分流:严格函数对象与生成器 / 异步 / 异步生成器函数对象 +/// 的 get/set 一律抛 TypeError;非严格普通函数对象读不抛、返回 undefined +/// (写不抛、丢弃写入),与规范"非严格函数 caller 可读"的残面一致。 pub fn function_restricted_thrower(vm: &mut H, args: &[u8]) -> NativeResult { let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); let obj = match vm.checked_object_ptr(this_val, "restricted property access") { @@ -354,7 +381,7 @@ pub fn function_restricted_thrower(vm: &mut H, args: &[u8]) -> Native Ok(None) => return NativeResult::Err(crate::error::create_type_error(vm, "restricted property access")), Err(e) => return NativeResult::Err(crate::error::create_type_error(vm, &e)), }; - if !vm.function_is_strict(unsafe { &*obj }) { + if !vm.function_is_restricted(unsafe { &*obj }) { return NativeResult::Ok(JsValue::undefined()); } NativeResult::Err(crate::error::create_type_error(vm, "restricted property access")) diff --git a/crates/oxide_runtime_api/src/host.rs b/crates/oxide_runtime_api/src/host.rs index a6d76e36..c55785b3 100644 --- a/crates/oxide_runtime_api/src/host.rs +++ b/crates/oxide_runtime_api/src/host.rs @@ -224,6 +224,9 @@ pub trait VmHost { /// 函数对象是否为严格模式函数(经子模块 `is_strict` 判定);native 函数 /// (无子模块)视为严格。供 caller/arguments 受限访问器按严格性分流抛错。 fn function_is_strict(&self, obj: &JsObject) -> bool; + /// caller/arguments 访问是否受限:严格函数对象,或生成器 / 异步 / + /// 异步生成器函数对象([[Prototype]] 为三个动态函数原型之一)。 + fn function_is_restricted(&self, obj: &JsObject) -> bool; fn promote_if_needed_for_write_ptr(&mut self, target_ptr: *mut JsObject, value: JsValue) -> JsValue; fn step_rng(&mut self); fn math_rng_value(&self) -> f64; @@ -234,9 +237,15 @@ pub trait VmHost { /// - 仅在同一 VM 世代的字节码帧执行期读取:native 调用不压 `cell_stack`,故 /// builtin 内读到的是调用方模块帧;`cell_idx` 越界或槽为空返回 `None`。 fn module_frame_cell(&self, cell_idx: u32) -> Option<*mut Cell>; - /// 动态编译一个函数体(`Function` 构造器用):把参数列表与函数体编译为可调用 - /// 函数对象。编译或解析失败返回 `Err`,由调用方转为 `SyntaxError`。 - fn create_dynamic_function(&mut self, params: &[String], body: &str) -> Result; + /// 动态编译一个函数体(`Function` / `GeneratorFunction` / `AsyncFunction` / + /// `AsyncGeneratorFunction` 构造器用):把参数列表与函数体编译为可调用 + /// 函数对象。`is_generator` / `is_async` 决定 wrap 源码的函数形态 + /// (`function` / `function*` / `async function` / `async function*`), + /// 函数对象原型与 `prototype` 属性面按编译标志自动分流。 + /// 编译或解析失败返回 `Err`,由调用方转为 `SyntaxError`。 + fn create_dynamic_function( + &mut self, params: &[String], body: &str, is_generator: bool, is_async: bool, + ) -> Result; /// 动态编译脚本(`eval` 字符串模式):按脚本模式编译,var/函数声明落全局对象。 /// 编译或解析失败返回 `Err`,由调用方转为 `SyntaxError`。 fn create_dynamic_script(&mut self, code: &str) -> Result; diff --git a/crates/oxide_vm/src/async_func.rs b/crates/oxide_vm/src/async_func.rs index bccd8d30..6c5c8ac5 100644 --- a/crates/oxide_vm/src/async_func.rs +++ b/crates/oxide_vm/src/async_func.rs @@ -399,28 +399,42 @@ pub(crate) fn init_async_intrinsics(vm: &mut Vm) { let sh = vm.kernel_core.shape_forge().as_ref(); let fn_proto_val = vm.session.builtin_world().fn_proto_val(); - // %AsyncFunction% 占位构造器:proto = Function.prototype,调用抛错(动态 - // 创建未实现)。选择性重建复用:前轮占位构造器按键迁移(prototype 槽在 - // 下方 P 槽换入后重指新原型),不再每轮新建对象。 + // %AsyncFunction% 构造器:proto = Function.prototype,动态编译异步函数。 + // 选择性重建复用:前轮构造器按键迁移(prototype 槽在下方 P 槽换入后重指 + // 新原型),不再每轮新建对象。 let af_ctor_label = sf.intern("AsyncFunctionCtor").0; let af_reuse_key = oxide_kernel::builtin::FnWrapperKey::new(0, af_ctor_label, 0, 0); - // SAFETY: async_function_stub 是 NativeFn 函数项。 - let af_stub_ptr = unsafe { NativeFnPtr::from_raw(async_function_stub as *const ()) }; - let (af_ctor_ptr, af_ctor_is_new) = match vm.session.builtin_world().find_fn_wrapper(af_reuse_key, af_stub_ptr, 1) { + // SAFETY: async_function_constructor 是 NativeFn 函数项。 + let af_ctor_fn_ptr = unsafe { + NativeFnPtr::from_raw(oxide_builtins::function::async_function_constructor:: as *const ()) + }; + let (af_ctor_ptr, af_ctor_is_new) = match vm.session.builtin_world().find_fn_wrapper(af_reuse_key, af_ctor_fn_ptr, 1) { Some(ptr) => (ptr, false), None => { - let mut af_ctor = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto_val)); + // [[Prototype]] = Function 构造器本体(与 Function 构造器同链, + // `Object.getPrototypeOf(AsyncFunction) === Function` 语义)。 + let fn_ctor_val = + JsValue::from_js_object(vm.session.builtin_world().function_constructor.as_ptr() as *mut JsObject); + let mut af_ctor = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, fn_ctor_val)); af_ctor.set_function(true); af_ctor.set_native_arg_count(1); - af_ctor.set_native_fn(Some(af_stub_ptr)); + af_ctor.set_native_fn(Some(af_ctor_fn_ptr)); + // 构造器 tag:IsConstructor 判定与 new 表达式派发据此放行。 + af_ctor.type_tag = JsObject::OBJ_TYPE_CONSTRUCTOR; + // 自身属性序:length、name、prototype、@@toStringTag(CreateBuiltinFunction 序)。 + let length_si = sf.intern("length").0; + let length_shape = sh.make_shape(EMPTY_SHAPE_ID, length_si); + af_ctor.set_shape_id(length_shape); let name_si = sf.intern("name").0; - let ctor_shape = sh.make_shape(af_ctor.shape_id(), name_si); - af_ctor.set_shape_id(ctor_shape); - let npos = af_ctor.push_prop(JsValue::perm_string(sf.string_ptr(sf.intern("AsyncFunction").0))); - af_ctor.set_data_meta(npos, PropAttributes::new(false, false, true)); + let name_shape = sh.make_shape(af_ctor.shape_id(), name_si); + af_ctor.set_shape_id(name_shape); let proto_si = sf.intern("prototype").0; - let ctor_shape2 = sh.make_shape(af_ctor.shape_id(), proto_si); - af_ctor.set_shape_id(ctor_shape2); + let proto_shape = sh.make_shape(af_ctor.shape_id(), proto_si); + af_ctor.set_shape_id(proto_shape); + let tag_key = + oxide_types::private_key::make_well_known_symbol_key(oxide_types::private_key::WELL_KNOWN_SYMBOL_TO_STRING_TAG); + let tag_shape = sh.make_shape(af_ctor.shape_id(), tag_key); + af_ctor.set_shape_id(tag_shape); let af_ctor_ptr = Box::into_raw(af_ctor); // 登记进 world 释放表(带复用键):session 收尾统一释放构造器本体与属性区。 vm.session.builtin_world().track_fn_wrapper(af_ctor_ptr, af_reuse_key); @@ -445,26 +459,33 @@ pub(crate) fn init_async_intrinsics(vm: &mut Vm) { af_proto.set_data_meta(tag_pos, PropAttributes::new(false, false, true)); // proto 本体只存在于 P 槽(Arc 副本,原 Box 随函数结束释放):装入 P 槽后再把 - // 构造器 prototype 属性指向 P 槽实例,使其与动态异步函数使用的 [[Prototype]] - // 同一对象,保证 `AsyncFunction.prototype === (async () => {}).__proto__`。 + // 构造器 length/name/prototype/@@toStringTag 属性(按形状序)指向 P 槽实例, + // 使其与动态异步函数使用的 [[Prototype]] 同一对象,保证 + // `AsyncFunction.prototype === (async () => {}).__proto__`。 // 复用构造器 prototype 槽原位改指新 P 原型(旧原型已随 P 换出释放)。 Vm::swap_intrinsic_proto(&mut vm.async_function_proto, *af_proto); // SAFETY: af_ctor_ptr 为 Box 原分配(已登记释放表、生命周期覆盖 session),本 Vm 独占。 unsafe { let ctor_mut = &mut *af_ctor_ptr; let proto_val = JsValue::from_js_object(vm.async_function_proto.as_ptr() as *mut JsObject); + let name_val = JsValue::perm_string(sf.string_ptr(sf.intern("AsyncFunction").0)); if af_ctor_is_new { + let lpos = ctor_mut.push_prop(JsValue::int(1)); + ctor_mut.set_data_meta(lpos, PropAttributes::new(false, false, true)); + let npos = ctor_mut.push_prop(name_val); + ctor_mut.set_data_meta(npos, PropAttributes::new(false, false, true)); let ppos = ctor_mut.push_prop(proto_val); ctor_mut.set_data_meta(ppos, PropAttributes::new(false, false, false)); + let tag_val = JsValue::perm_string(sf.string_ptr(sf.intern("Function").0)); + let tpos = ctor_mut.push_prop(tag_val); + ctor_mut.set_data_meta(tpos, PropAttributes::new(false, false, true)); } else if let Some(pos) = sh.lookup_position(ctor_mut.shape_id(), sf.intern("prototype").0) { ctor_mut.set_prop_at(pos, proto_val); } } -} -/// `%AsyncFunction%` 占位:动态异步函数创建未实现,调用抛错。 -fn async_function_stub(vm: &mut Vm, _args: &[u8]) -> NativeResult { - NativeResult::Err(oxide_builtins::error::create_type_error(vm, "AsyncFunction constructor is not supported")) + // 绑定 global:按规范 AsyncFunction 不是全局绑定(is-not-a-global 语义), + // 仅经 `async function` 实例的 constructor 链可达。 } // ── session GC 支撑:状态快照中的 JsValues 作为异步上下文对象边追踪 ── diff --git a/crates/oxide_vm/src/async_generator.rs b/crates/oxide_vm/src/async_generator.rs index 3968e54c..1887b295 100644 --- a/crates/oxide_vm/src/async_generator.rs +++ b/crates/oxide_vm/src/async_generator.rs @@ -930,22 +930,35 @@ pub(crate) fn init_async_generator_intrinsics(vm: &mut Vm) { // 槽在下方 P 槽换入后重指新原型),不再每轮新建对象。 let agf_ctor_label = sf.intern("AsyncGeneratorFunctionCtor").0; let agf_reuse_key = oxide_kernel::builtin::FnWrapperKey::new(0, agf_ctor_label, 0, 0); - // SAFETY: async_generator_function_stub 是 NativeFn 函数项。 - let agf_stub_ptr = unsafe { NativeFnPtr::from_raw(async_generator_function_stub as *const ()) }; - let (agf_ctor_ptr, agf_ctor_is_new) = match world.find_fn_wrapper(agf_reuse_key, agf_stub_ptr, 1) { + // SAFETY: async_generator_function_constructor 是 NativeFn 函数项。 + let agf_ctor_fn_ptr = unsafe { + NativeFnPtr::from_raw( + oxide_builtins::function::async_generator_function_constructor:: as *const (), + ) + }; + let (agf_ctor_ptr, agf_ctor_is_new) = match world.find_fn_wrapper(agf_reuse_key, agf_ctor_fn_ptr, 1) { Some(ptr) => (ptr, false), None => { let mut agf_ctor = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto_val)); agf_ctor.set_function(true); agf_ctor.set_native_arg_count(1); - agf_ctor.set_native_fn(Some(agf_stub_ptr)); - // prototype/name 属性(构造器形状 [prototype, name])。 - let proto_si = sf.intern("prototype").0; - let ctor_shape = sh.make_shape(EMPTY_SHAPE_ID, proto_si); - agf_ctor.set_shape_id(ctor_shape); + agf_ctor.set_native_fn(Some(agf_ctor_fn_ptr)); + // 构造器 tag:IsConstructor 判定与 new 表达式派发据此放行。 + agf_ctor.type_tag = JsObject::OBJ_TYPE_CONSTRUCTOR; + // 自身属性序:length、name、prototype、@@toStringTag(CreateBuiltinFunction 序)。 + let length_si = sf.intern("length").0; + let length_shape = sh.make_shape(EMPTY_SHAPE_ID, length_si); + agf_ctor.set_shape_id(length_shape); let name_si = sf.intern("name").0; let name_shape = sh.make_shape(agf_ctor.shape_id(), name_si); agf_ctor.set_shape_id(name_shape); + let proto_si = sf.intern("prototype").0; + let proto_shape = sh.make_shape(agf_ctor.shape_id(), proto_si); + agf_ctor.set_shape_id(proto_shape); + let tag_key = + oxide_types::private_key::make_well_known_symbol_key(oxide_types::private_key::WELL_KNOWN_SYMBOL_TO_STRING_TAG); + let tag_shape = sh.make_shape(agf_ctor.shape_id(), tag_key); + agf_ctor.set_shape_id(tag_shape); let agf_ctor_ptr = Box::into_raw(agf_ctor); // 登记进 world 释放表(带复用键):session 收尾统一释放构造器本体与属性区。 world.track_fn_wrapper(agf_ctor_ptr, agf_reuse_key); @@ -964,7 +977,7 @@ pub(crate) fn init_async_generator_intrinsics(vm: &mut Vm) { let proto2_shape = sh.make_shape(agf_proto.shape_id(), proto2_si); agf_proto.set_shape_id(proto2_shape); let ppos2 = agf_proto.push_prop(JsValue::from_js_object(vm.async_generator_proto.as_ptr() as *mut JsObject)); - agf_proto.set_data_meta(ppos2, PropAttributes::new(false, false, false)); + agf_proto.set_data_meta(ppos2, PropAttributes::new(false, false, true)); // agf_proto[Symbol.toStringTag] = "AsyncGeneratorFunction"(数据属性,w/e/c = false/false/true)。 let tag2_key = oxide_types::private_key::make_well_known_symbol_key(oxide_types::private_key::WELL_KNOWN_SYMBOL_TO_STRING_TAG); @@ -974,7 +987,7 @@ pub(crate) fn init_async_generator_intrinsics(vm: &mut Vm) { agf_proto.set_data_meta(tag2_pos, PropAttributes::new(false, false, true)); // proto 本体只存在于 P 槽(Arc 副本,原 Box 随函数结束释放):装入 P 槽后再写 - // 构造器 prototype/name 属性(按模板序 prototype 在前),prototype 指向 P 槽实例, + // 构造器 length/name/prototype/@@toStringTag 属性(按形状序),prototype 指向 P 槽实例, // 使其与动态异步生成器函数使用的 [[Prototype]] 同一对象。复用构造器槽位已填充, // prototype 原位改指新 P 原型(旧原型已随 P 换出释放)。 Vm::swap_intrinsic_proto(&mut vm.async_generator_function_proto, *agf_proto); @@ -984,10 +997,15 @@ pub(crate) fn init_async_generator_intrinsics(vm: &mut Vm) { let proto_val = JsValue::from_js_object(vm.async_generator_function_proto.as_ptr() as *mut JsObject); let name_val = JsValue::perm_string(sf.string_ptr(sf.intern("AsyncGeneratorFunction").0)); if agf_ctor_is_new { - let ppos = ctor_mut.push_prop(proto_val); - ctor_mut.set_data_meta(ppos, PropAttributes::new(false, false, false)); + let lpos = ctor_mut.push_prop(JsValue::int(1)); + ctor_mut.set_data_meta(lpos, PropAttributes::new(false, false, true)); let npos = ctor_mut.push_prop(name_val); ctor_mut.set_data_meta(npos, PropAttributes::new(false, false, true)); + let ppos = ctor_mut.push_prop(proto_val); + ctor_mut.set_data_meta(ppos, PropAttributes::new(false, false, false)); + let tag_val = JsValue::perm_string(sf.string_ptr(sf.intern("Function").0)); + let tpos = ctor_mut.push_prop(tag_val); + ctor_mut.set_data_meta(tpos, PropAttributes::new(false, false, true)); } else { let si_prototype = sf.intern("prototype").0; if let Some(pos) = sh.lookup_position(ctor_mut.shape_id(), si_prototype) { @@ -999,14 +1017,25 @@ pub(crate) fn init_async_generator_intrinsics(vm: &mut Vm) { } } } -} -/// `%AsyncGeneratorFunction%` 占位:动态异步生成器函数创建未实现,调用抛错。 -fn async_generator_function_stub(vm: &mut Vm, _args: &[u8]) -> NativeResult { - NativeResult::Err(oxide_builtins::error::create_type_error( - vm, - "AsyncGeneratorFunction constructor is not supported", - )) + // 绑定 global:AsyncGeneratorFunction 槽已存在则原位更新(full_reset 未重建 + // global 时旧槽指向已弃 ctor),不存在则开新槽。 + let global_ptr = vm.session.global_object().as_ptr() as *mut JsObject; + // SAFETY: global 由 session 持有存活整个 session;本函数内只改其 shape/属性区, + // 期间无 reset 或对象搬移。 + let global = unsafe { &mut *global_ptr }; + let si = sf.intern("AsyncGeneratorFunction").0; + let ctor_val = JsValue::from_js_object(agf_ctor_ptr); + if let Some(pos) = sh.lookup_position(global.shape_id(), si) { + global.set_prop_at(pos, ctor_val); + } else { + let shape = sh.make_shape(global.shape_id(), si); + global.set_shape_id(shape); + let pos = global.push_prop(ctor_val); + // global 数据属性:writable:true、enumerable:false、configurable:true。 + global.set_data_meta(pos, PropAttributes::new(true, false, true)); + global.bump_generation(); + } } // ── session GC 支撑:状态快照中的 JsValues 作为异步生成器对象边追踪 ── diff --git a/crates/oxide_vm/src/generator.rs b/crates/oxide_vm/src/generator.rs index 03256231..9e876188 100644 --- a/crates/oxide_vm/src/generator.rs +++ b/crates/oxide_vm/src/generator.rs @@ -766,27 +766,40 @@ pub(crate) fn init_generator_intrinsics(vm: &mut Vm) { // %GeneratorFunction.prototype%:proto = Function.prototype,constructor = %GeneratorFunction%。 let mut gf_proto = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto_val)); - // %GeneratorFunction% 占位构造器:动态生成器函数创建未实现,调用抛 - // TypeError。选择性重建复用:前轮占位构造器按键迁移(prototype 槽在 - // 下方 P 槽换入后重指新原型),不再每轮新建对象。 + // %GeneratorFunction% 构造器:proto = Function.prototype,动态编译生成器 + // 函数。选择性重建复用:前轮构造器按键迁移(prototype 槽在下方 P 槽换入后 + // 重指新原型),不再每轮新建对象。 let gf_ctor_label = sf.intern("GeneratorFunctionCtor").0; let gf_reuse_key = oxide_kernel::builtin::FnWrapperKey::new(0, gf_ctor_label, 0, 0); - // SAFETY: generator_function_stub 是 NativeFn 函数项。 - let gf_stub_ptr = unsafe { NativeFnPtr::from_raw(generator_function_stub as *const ()) }; - let (gf_ctor_ptr, gf_ctor_is_new) = match world.find_fn_wrapper(gf_reuse_key, gf_stub_ptr, 1) { + // SAFETY: generator_function_constructor 是 NativeFn 函数项。 + let gf_ctor_fn_ptr = unsafe { + NativeFnPtr::from_raw( + oxide_builtins::function::generator_function_constructor:: as *const (), + ) + }; + let (gf_ctor_ptr, gf_ctor_is_new) = match world.find_fn_wrapper(gf_reuse_key, gf_ctor_fn_ptr, 1) { Some(ptr) => (ptr, false), None => { let mut gf_ctor = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto_val)); gf_ctor.set_function(true); gf_ctor.set_native_arg_count(1); - gf_ctor.set_native_fn(Some(gf_stub_ptr)); - // prototype/name 属性(构造器形状 [prototype, name])。 - let proto_si = sf.intern("prototype").0; - let ctor_shape = sh.make_shape(EMPTY_SHAPE_ID, proto_si); - gf_ctor.set_shape_id(ctor_shape); + gf_ctor.set_native_fn(Some(gf_ctor_fn_ptr)); + // 构造器 tag:IsConstructor 判定与 new 表达式派发据此放行。 + gf_ctor.type_tag = JsObject::OBJ_TYPE_CONSTRUCTOR; + // 自身属性序:length、name、prototype、@@toStringTag(CreateBuiltinFunction 序)。 + let length_si = sf.intern("length").0; + let length_shape = sh.make_shape(EMPTY_SHAPE_ID, length_si); + gf_ctor.set_shape_id(length_shape); let name_si = sf.intern("name").0; let name_shape = sh.make_shape(gf_ctor.shape_id(), name_si); gf_ctor.set_shape_id(name_shape); + let proto_si = sf.intern("prototype").0; + let proto_shape = sh.make_shape(gf_ctor.shape_id(), proto_si); + gf_ctor.set_shape_id(proto_shape); + let tag_key = + oxide_types::private_key::make_well_known_symbol_key(oxide_types::private_key::WELL_KNOWN_SYMBOL_TO_STRING_TAG); + let tag_shape = sh.make_shape(gf_ctor.shape_id(), tag_key); + gf_ctor.set_shape_id(tag_shape); let gf_ctor_ptr = Box::into_raw(gf_ctor); // 登记进 world 释放表(带复用键):session 收尾统一释放构造器本体与属性区。 world.track_fn_wrapper(gf_ctor_ptr, gf_reuse_key); @@ -804,7 +817,7 @@ pub(crate) fn init_generator_intrinsics(vm: &mut Vm) { let proto2_shape = sh.make_shape(gf_proto.shape_id(), proto2_si); gf_proto.set_shape_id(proto2_shape); let ppos2 = gf_proto.push_prop(JsValue::from_js_object(vm.generator_proto.as_ptr() as *mut JsObject)); - gf_proto.set_data_meta(ppos2, oxide_types::object::PropAttributes::new(false, false, false)); + gf_proto.set_data_meta(ppos2, oxide_types::object::PropAttributes::new(false, false, true)); // gf_proto[Symbol.toStringTag] = "GeneratorFunction"(数据属性,w/e/c = false/false/true)。 let tag2_key = oxide_types::private_key::make_well_known_symbol_key(oxide_types::private_key::WELL_KNOWN_SYMBOL_TO_STRING_TAG); @@ -814,9 +827,9 @@ pub(crate) fn init_generator_intrinsics(vm: &mut Vm) { gf_proto.set_data_meta(tag2_pos, oxide_types::object::PropAttributes::new(false, false, true)); // proto 本体只存在于 P 槽(Arc 副本,原 Box 随函数结束释放):装入 P 槽后再写 - // 构造器 prototype/name 属性(按模板序 prototype 在前),prototype 指向 P 槽实例, - // 使其与动态生成器函数使用的 [[Prototype]] 同一对象。复用构造器槽位已填充, - // prototype 原位改指新 P 原型(旧原型已随 P 换出释放)。 + // 构造器 length/name/prototype/@@toStringTag 属性(按形状序),prototype 指向 + // P 槽实例,使其与动态生成器函数使用的 [[Prototype]] 同一对象。复用构造器槽位 + // 已填充,prototype 原位改指新 P 原型(旧原型已随 P 换出释放)。 Vm::swap_intrinsic_proto(&mut vm.generator_function_proto, *gf_proto); // SAFETY: gf_ctor_ptr 为 Box 原分配(已登记释放表、生命周期覆盖 session),本 Vm 独占。 unsafe { @@ -824,10 +837,15 @@ pub(crate) fn init_generator_intrinsics(vm: &mut Vm) { let proto_val = JsValue::from_js_object(vm.generator_function_proto.as_ptr() as *mut JsObject); let name_val = JsValue::perm_string(sf.string_ptr(sf.intern("GeneratorFunction").0)); if gf_ctor_is_new { - let ppos = ctor_mut.push_prop(proto_val); - ctor_mut.set_data_meta(ppos, oxide_types::object::PropAttributes::new(false, false, false)); + let lpos = ctor_mut.push_prop(JsValue::int(1)); + ctor_mut.set_data_meta(lpos, oxide_types::object::PropAttributes::new(false, false, true)); let npos = ctor_mut.push_prop(name_val); ctor_mut.set_data_meta(npos, oxide_types::object::PropAttributes::new(false, false, true)); + let ppos = ctor_mut.push_prop(proto_val); + ctor_mut.set_data_meta(ppos, oxide_types::object::PropAttributes::new(false, false, false)); + let tag_val = JsValue::perm_string(sf.string_ptr(sf.intern("Function").0)); + let tpos = ctor_mut.push_prop(tag_val); + ctor_mut.set_data_meta(tpos, oxide_types::object::PropAttributes::new(false, false, true)); } else { let si_prototype = sf.intern("prototype").0; if let Some(pos) = sh.lookup_position(ctor_mut.shape_id(), si_prototype) { @@ -839,14 +857,25 @@ pub(crate) fn init_generator_intrinsics(vm: &mut Vm) { } } } -} -/// `%GeneratorFunction%` 占位:动态生成器函数创建未实现,调用抛错。 -fn generator_function_stub(vm: &mut Vm, _args: &[u8]) -> NativeResult { - NativeResult::Err(oxide_builtins::error::create_type_error( - vm, - "GeneratorFunction constructor is not supported", - )) + // 绑定 global:GeneratorFunction 槽已存在则原位更新(full_reset 未重建 global + // 时旧槽指向已弃 ctor),不存在则开新槽。 + let global_ptr = vm.session.global_object().as_ptr() as *mut JsObject; + // SAFETY: global 由 session 持有存活整个 session;本函数内只改其 shape/属性区, + // 期间无 reset 或对象搬移。 + let global = unsafe { &mut *global_ptr }; + let si = sf.intern("GeneratorFunction").0; + let ctor_val = JsValue::from_js_object(gf_ctor_ptr); + if let Some(pos) = sh.lookup_position(global.shape_id(), si) { + global.set_prop_at(pos, ctor_val); + } else { + let shape = sh.make_shape(global.shape_id(), si); + global.set_shape_id(shape); + let pos = global.push_prop(ctor_val); + // global 数据属性:writable:true、enumerable:false、configurable:true。 + global.set_data_meta(pos, oxide_types::object::PropAttributes::new(true, false, true)); + global.bump_generation(); + } } // ── session GC 支撑:状态快照中的 JsValues 作为生成器对象边追踪 ── diff --git a/crates/oxide_vm/src/vm/dynamic.rs b/crates/oxide_vm/src/vm/dynamic.rs index ff88fe26..70cecb00 100644 --- a/crates/oxide_vm/src/vm/dynamic.rs +++ b/crates/oxide_vm/src/vm/dynamic.rs @@ -19,7 +19,9 @@ impl Vm { /// 原样透传。 /// /// # 步骤 - /// 1. wrap 源码 `function anonymous(p...) { body }`,parse + compile。 + /// 1. wrap 源码 `{prefix} anonymous(p...) { body }`(prefix 按生成器 / + /// 异步标志取 `function` / `function*` / `async function` / + /// `async function*`),parse + compile。 /// 2. 取 `sub_modules[0]`(匿名函数模块),把其子树 flat_id 重编号到平表末尾 /// 并重写子树内每条 `CREATE_CLOSURE` 的 imm16。 /// 3. 同步扩容当前代际的常量缓存,建函数对象并设置 name/length。 @@ -33,12 +35,23 @@ impl Vm { /// /// # 副作用 /// - 扩展当前代际平表(`tables[current_gen]`)与常量缓存。 - pub fn create_dynamic_function(&mut self, params: &[String], body: &str) -> Result { + pub fn create_dynamic_function( + &mut self, params: &[String], body: &str, is_generator: bool, is_async: bool, + ) -> Result { // wrap 源码:body 两端换行防止以行注释结尾吞掉右花括号;形参串后补 // 换行,使形参以 HTML 注释(``)结尾时注释在行末终止、 // 右括号不被吞(规范按形参串与体串各自独立解析,此处以换行等价)。 + // 函数形态按生成器 / 异步标志分流,编译标志(is_generator / is_async) + // 由 emit 层从 AST 读回,函数对象原型与 prototype 属性面随之自动分流。 + let prefix = if is_async { + if is_generator { "async function*" } else { "async function" } + } else if is_generator { + "function*" + } else { + "function" + }; let params_str = params.join(", "); - let source = format!("function anonymous({params_str}\n) {{\n{body}\n}}"); + let source = format!("{prefix} anonymous({params_str}\n) {{\n{body}\n}}"); let allocator = oxide_parser::Allocator::default(); let program = oxide_parser::parse(&allocator, &source) diff --git a/crates/oxide_vm/src/vm/vmhost.rs b/crates/oxide_vm/src/vm/vmhost.rs index 05e47e29..3b8ab048 100644 --- a/crates/oxide_vm/src/vm/vmhost.rs +++ b/crates/oxide_vm/src/vm/vmhost.rs @@ -179,6 +179,21 @@ impl oxide_runtime_api::VmHost for Vm { // 按严格处理(受限访问器对其抛错)。 self.callee_module(obj).map(|m| m.is_strict).unwrap_or(true) } + fn function_is_restricted(&self, obj: &JsObject) -> bool { + // 严格函数对象,或 [[Prototype]] 为三个动态函数原型之一(生成器 / + // 异步 / 异步生成器函数):caller/arguments 访问一律受限。 + if self.function_is_strict(obj) { + return true; + } + let proto = obj.proto(); + if !proto.is_object() { + return false; + } + let p = proto.as_js_object_ptr(); + p == self.generator_function_proto.as_ptr() as *mut JsObject + || p == self.async_function_proto.as_ptr() as *mut JsObject + || p == self.async_generator_function_proto.as_ptr() as *mut JsObject + } fn promote_if_needed_for_write_ptr(&mut self, target_ptr: *mut JsObject, value: JsValue) -> JsValue { self.promote_if_needed_for_write_ptr(target_ptr, value) } @@ -201,8 +216,10 @@ impl oxide_runtime_api::VmHost for Vm { .and_then(|cells| cells.get(cell_idx as usize).copied()) .filter(|p| !p.is_null()) } - fn create_dynamic_function(&mut self, params: &[String], body: &str) -> Result { - self.create_dynamic_function(params, body) + fn create_dynamic_function( + &mut self, params: &[String], body: &str, is_generator: bool, is_async: bool, + ) -> Result { + self.create_dynamic_function(params, body, is_generator, is_async) } fn create_dynamic_script(&mut self, code: &str) -> Result { self.create_dynamic_script(code) diff --git a/crates/oxide_vm/src/vm_support.rs b/crates/oxide_vm/src/vm_support.rs index 242cc585..2ef72c23 100644 --- a/crates/oxide_vm/src/vm_support.rs +++ b/crates/oxide_vm/src/vm_support.rs @@ -781,8 +781,9 @@ impl Vm { + crate::session_gc::SessionGc::object_heap_data_bytes(unsafe { &*obj_ptr }) as usize; let func_val = JsValue::object(obj_ptr as *mut u8); - if !is_arrow { + if !is_arrow && !(is_async && !is_generator) { // 原型对象自身的 [[Prototype]]:生成器为 %GeneratorPrototype%,普通函数为 Object.prototype。 + // 纯异步函数(非生成器)无 `prototype` 属性:规范不为其建 prototype 子对象。 let proto_of_proto = if is_async_generator { JsValue::from_js_object(self.async_generator_proto.as_ptr() as *mut JsObject) } else if is_generator {