use crate::vm::{ Completion, ConstructArgs, DisposeResumeKind, ForInIter, FrameArgs, FrameContinuation, PendingAsyncDispose, TryHandler, Vm, MAX_PROTO_CHAIN_DEPTH, }; use crate::vm_trace; use oxide_builtins::iterator::is_callable; use oxide_runtime_api::{push_units_to, to_boolean, to_units_full, VmHost}; use oxide_types::object::{JsObject, PropAttributes}; use oxide_types::private_key::{ encode_symbol_key, int_key_value, is_int_key, is_private_name_key, is_symbol_key, make_int_key, INT_KEY_COUNT, WELL_KNOWN_SYMBOL_ASYNC_DISPOSE, WELL_KNOWN_SYMBOL_DISPOSE, WELL_KNOWN_SYMBOL_HAS_INSTANCE, }; use oxide_types::value::JsValue; /// 单资源释放结局(规范 Dispose 语义):`Done` = 释放成功;`NoMethod` = 无释放方法 /// (非对象 / 方法未定义 / 不可调用,跳过);`Err(v)` = 释放方法抛错(v 为原始异常值); /// `Suspended(promise)` = 异步释放已挂起(promise 为释放方法结果经 PromiseResolve 包装 /// 后登记的结算 promise,调用方据此登记 `PendingAsyncDispose`)。 enum DisposeOutcome { Done, NoMethod, Err(JsValue), Suspended(JsValue), } /// 批量释放(`dispose_above` / `dispose_top_n`)结局:`Clean` = 全部正常; /// `Threw` = 有释放方法抛错(合并错误已写入 `exception_value`);`Suspended` = /// 异步挂起已登记(`PendingAsyncDispose` 已置,调用方须快照并早退)。 pub(crate) enum DisposePhase { Clean, Threw, Suspended, } impl Vm { pub(crate) fn dispatch_new_expression(&mut self, rd: usize, a: usize, b: usize) -> Result { let constructor_reg = a; let first_arg_reg = b as u8; vm_trace!("NEW_EXPRESSION rd={}", rd); let constructor = self.regs[constructor_reg]; if !constructor.is_object() { return self .raise_type_error("NEW_EXPRESSION: constructor is not an object") .map(|_| true); } let ctor_ptr = constructor.as_js_object_ptr(); if ctor_ptr.is_null() { return self.raise_type_error("NEW_EXPRESSION: constructor is null").map(|_| true); } let ctor_obj = unsafe { &*ctor_ptr }; if !ctor_obj.is_function() { return self .raise_type_error("NEW_EXPRESSION: constructor is not a function") .map(|_| true); } if ctor_obj.is_arrow() { return self .raise_type_error("arrow functions cannot be used as constructors") .map(|_| true); } // native 方法(非构造器)不可 new;bound 包装除外(其构造语义转发到 target)。 if ctor_obj.native_fn().is_some() && ctor_obj.type_tag != oxide_types::object::JsObject::OBJ_TYPE_CONSTRUCTOR && ctor_obj.type_tag != oxide_types::object::JsObject::OBJ_TYPE_BOUND { return self.raise_type_error("object is not a constructor").map(|_| true); } let ext = self.bytecode[self.pc]; self.pc += 1; let arg_count = (ext & 0xFF) as usize; // ext 高 8 位 = 调用点存活上界(0 = 未编码/全量),压帧窗口按此截断。 let call_window = (ext >> 8) as u8; // bound 包装:解包链后转发到最内层 target([[Construct]] 语义)。 if ctor_obj.type_tag == oxide_types::object::JsObject::OBJ_TYPE_BOUND { let mut args = Vec::with_capacity(arg_count); for i in 0..arg_count.min(256) { args.push(self.regs[first_arg_reg.wrapping_add(i as u8) as usize]); } let proto_ptr = self.realm.object_prototype.borrow().as_ptr() as *mut JsObject; let new_obj = self.alloc_object(JsObject::new_empty( oxide_kernel::shape_forge::EMPTY_SHAPE_ID, JsValue::from_js_object(proto_ptr), )); return self.dispatch_new_bound(rd, constructor, new_obj, args, call_window); } let proto_ptr = self.realm.object_prototype.borrow().as_ptr() as *mut JsObject; let new_obj = self.alloc_object(JsObject::new_empty( oxide_kernel::shape_forge::EMPTY_SHAPE_ID, JsValue::from_js_object(proto_ptr), )); // GpFC 按构造器种类分读形:native 构造器体(native_fn + CONSTRUCTOR // tag)保持裸存储读(占位 receiver 的原型不可观测,可观测面由构造体 // 自重读覆盖);字节码构造器走传播读(Ordinary [[Construct]] 的 GpFC // 先于函数体求值,访问器 getter 的异常须原值上抛,非对象结果回落 // Object.prototype)。bound 包装已在上方转发臂返回,不到达此处。 let proto_si = self.kernel_core.perm_interner().intern("prototype").0; let proto_val = if ctor_obj.native_fn().is_some() { self.resolve_property(ctor_obj, proto_si) } else { let pc_before = self.pc; match self.ordinary_get(ctor_obj, proto_si, constructor) { Ok(v) if self.pc == pc_before => Some(v), Ok(_) => { // getter 抛且已有 catch/finally 接手:展开已跳到落点,停构造流。 return Ok(true); } Err(err) => { // 无处理器(或重入在途异常):恢复原值走异常通道。 let exc = self .last_uncaught_value .take() .unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &err)); self.exception_value = Some(exc); self.pending_error_kind = Some(self.thrown_error_kind(exc)); return self.unwind().map(|_| true); } } }; if let Some(v) = proto_val { if v.is_object() { let new_obj_mut = unsafe { &mut *new_obj }; let proto_obj_ptr = v.as_js_object_ptr(); let _ = new_obj_mut.set_proto(JsValue::from_js_object(proto_obj_ptr)); } } if ctor_obj.native_fn().is_some() { let new_obj_val = JsValue::object(new_obj as *mut u8); let mut args = Vec::with_capacity(arg_count); for i in 0..arg_count.min(256) { args.push(self.regs[first_arg_reg.wrapping_add(i as u8) as usize]); } // native 构造器:收口到 call_function_sync(与 spread / bound 变体一致)。 // 该入口统一保存/恢复调用窗口与 253/254 槽且不触碰 255,调用方 // new.target 与 this 跨 native 构造不被污染;receiver 经 arg0 打包, // native 侧经 reg(args[0]) 读取,构造语义不变。newTarget 快照后置入 // reg(255) 暴露给 native 构造器(调用后恢复原值);构造形态标记同窗 // 夹持(调用后恢复)。 let saved_new_target = self.regs[255]; let saved_constructing = self.constructing_native; self.regs[255] = constructor; self.constructing_native = true; let result = self.call_function_sync(constructor, new_obj_val, &args); self.constructing_native = saved_constructing; self.regs[255] = saved_new_target; match result { Ok(v) => { self.regs[rd] = if v.is_object() { v } else { new_obj_val }; Ok(false) } Err(_) => { let exc = self .last_uncaught_value .take() .unwrap_or_else(|| oxide_builtins::error::create_from_text(self, "constructor call failed")); self.exception_value = Some(exc); self.pending_error_kind = Some(self.thrown_error_kind(exc)); self.unwind().map(|_| true) } } } else if ctor_obj.sub_module_index() > 0 { let sub_idx = ctor_obj.sub_module_index() as usize; let sub = match self.callee_module(ctor_obj) { Some(m) => m, None => { // 上界取构造器自身代际平表长度(跨 run 调用时可异于当前代际)。 return Err(format!( "NEW_EXPRESSION: sub_module_index {} out of bounds (max {})", sub_idx, self.tables.get(&ctor_obj.table_gen()).map(|t| t.modules.len()).unwrap_or(0) )); } }; // 生成器函数不是构造器:`new g()` 抛 TypeError。 if sub.is_generator { return self.raise_type_error("g is not a constructor").map(|_| true); } // 异步函数不是构造器:`new f()` 抛 TypeError。 if sub.is_async { return self.raise_type_error("g is not a constructor").map(|_| true); } let new_obj_val = JsValue::object(new_obj as *mut u8); // 收敛到统一压帧入口:derived 构造器在 super() 前 this 为 undefined, // 基类构造器 this = 新对象;new.target = 构造器本身。 let this_value = if ctor_obj.is_derived_constructor() { JsValue::undefined() } else { new_obj_val }; self.push_bytecode_frame( constructor, this_value, FrameArgs::RegRange { first: first_arg_reg, count: arg_count, }, ConstructArgs::new(rd as u8, new_obj_val, constructor), FrameContinuation::None, call_window, )?; Ok(true) } else { // 无函数体的函数对象(如 Function.prototype):IsConstructor 为假, // 按规范抛 TypeError(此前该分支不可达,报普通 Error 属内部错误)。 self.raise_type_error("NEW_EXPRESSION: constructor is not a constructor") .map(|_| true) } } /// bound 函数构造分支:按 bound [[Construct]] 语义解包链后转发到最内层 target。 /// /// # 步骤 /// 1. 逐层解包 [[BoundTargetFunction]]:每层绑定实参(状态对象存储槽 2+) /// 拼到调用实参之前(外层先解包 → 最终顺序为内层绑定实参先、外层后、 /// 调用实参尾) /// 2. 校验最内层 target 可构造(native 须 CONSTRUCTOR 标记;字节码须非 /// arrow/async/generator),否则抛 TypeError /// 3. 新对象原型取 target.prototype(new 表达式路径 newTarget 恒等于构造器, /// 规范 SameValue 替换后 newTarget = target) /// 4. 构造调用:native target 值传递(receiver = 新对象);字节码 target 压 /// 构造帧(this = 新对象,派生 target 为 undefined,new.target = target) /// /// # 边界与前提 /// - `call_args` 为调用点实参(寄存器连续区或 spread 物化),绑定实参前置拼接 /// - 原型属性非对象时保持 object_proto 默认(OrdinaryCreateFromConstructor 回退) pub(crate) fn dispatch_new_bound( &mut self, rd: usize, wrapper_val: JsValue, new_obj: *mut JsObject, mut call_args: Vec, call_window: u8, ) -> Result { // 逐层解包 bound 链,绑定实参前置拼接。 let mut target_val = wrapper_val; loop { let wrapper_obj = unsafe { &*target_val.as_js_object_ptr() }; // 绑定状态对象 [target, thisArg, ...boundArgs](oxide_builtins::function // 固定第 4 号 shape 属性):target 取存储槽 0,绑定实参取存储槽 2+。 let state = oxide_builtins::function::bound_state_values(wrapper_obj); let target = state.first().copied().unwrap_or(JsValue::undefined()); let mut combined: Vec = state.iter().skip(2).copied().collect(); combined.extend_from_slice(&call_args); call_args = combined; let is_bound = target.is_object() && !target.as_js_object_ptr().is_null() && unsafe { &*target.as_js_object_ptr() }.type_tag == JsObject::OBJ_TYPE_BOUND; target_val = target; if !is_bound { break; } } // 校验最内层 target 可构造。 if !target_val.is_object() || target_val.as_js_object_ptr().is_null() { return self.raise_type_error("object is not a constructor").map(|_| true); } let target_obj = unsafe { &*target_val.as_js_object_ptr() }; if !target_obj.is_function() || target_obj.is_arrow() { return self.raise_type_error("object is not a constructor").map(|_| true); } if target_obj.native_fn().is_some() && target_obj.type_tag != JsObject::OBJ_TYPE_CONSTRUCTOR { return self.raise_type_error("object is not a constructor").map(|_| true); } // 按 target 自身记录的表代际解析:生成器/异步函数不是构造器。 if matches!(self.callee_module(target_obj), Some(sub) if sub.is_generator || sub.is_async) { return self.raise_type_error("object is not a constructor").map(|_| true); } // 新对象原型取最内层 target 的 prototype(bound 包装自身无 prototype)。 // 读形与 NEW 读体同构:native target 裸读,字节码 target 传播读 // (getter 异常原值上抛,非对象回落 Object.prototype)。 let proto_si = self.kernel_core.perm_interner().intern("prototype").0; let proto_val = if target_obj.native_fn().is_some() { self.resolve_property(target_obj, proto_si) } else { let pc_before = self.pc; match self.ordinary_get(target_obj, proto_si, target_val) { Ok(v) if self.pc == pc_before => Some(v), Ok(_) => { return Ok(true); } Err(err) => { let exc = self .last_uncaught_value .take() .unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &err)); self.exception_value = Some(exc); self.pending_error_kind = Some(self.thrown_error_kind(exc)); return self.unwind().map(|_| true); } } }; if let Some(v) = proto_val { if v.is_object() { let new_obj_mut = unsafe { &mut *new_obj }; let proto_obj_ptr = v.as_js_object_ptr(); let _ = new_obj_mut.set_proto(JsValue::from_js_object(proto_obj_ptr)); } } let new_obj_val = JsValue::object(new_obj as *mut u8); if target_obj.native_fn().is_some() { // native 构造器:receiver = 新对象,值传递调用(错误原值恢复后展开)。 // new.target 按 bound [[Construct]] 语义取最外层 bound 包装(wrapper_val), // 快照后置入 reg(255) 暴露给 native 构造器(调用后恢复原值);构造 // 形态标记同窗夹持(调用后恢复)。 let saved_new_target = self.regs[255]; let saved_constructing = self.constructing_native; self.regs[255] = wrapper_val; self.constructing_native = true; let result = self.call_function_sync(target_val, new_obj_val, &call_args); self.constructing_native = saved_constructing; self.regs[255] = saved_new_target; match result { Ok(v) => { self.regs[rd] = if v.is_object() { v } else { new_obj_val }; Ok(false) } Err(_) => { let exc = self .last_uncaught_value .take() .unwrap_or_else(|| oxide_builtins::error::create_from_text(self, "constructor call failed")); self.exception_value = Some(exc); self.pending_error_kind = Some(self.thrown_error_kind(exc)); self.unwind().map(|_| true) } } } else if target_obj.sub_module_index() > 0 { // 字节码构造器:this = 新对象(派生 target 为 undefined,super() 装配), // new.target = 最内层 target。 let this_value = if target_obj.is_derived_constructor() { JsValue::undefined() } else { new_obj_val }; self.push_bytecode_frame( target_val, this_value, FrameArgs::Slice(&call_args), ConstructArgs::new(rd as u8, new_obj_val, target_val), FrameContinuation::None, call_window, )?; Ok(true) } else { self.raise_type_error("object is not a constructor").map(|_| true) } } pub(crate) fn dispatch_template_str(&mut self, rd: usize) -> Result<(), String> { vm_trace!("TEMPLATE_STR rd={}", rd); let header = self.bytecode[self.pc]; self.pc += 1; let segment_count = (header >> 16) as usize; let len_hint = (header & 0xFFFF) as usize; // 单元缓冲:字符串操作数按单元序列展开(lone surrogate 保真), // len_hint 为单元数口径(emit 侧同口径)。 let mut units: Vec = Vec::with_capacity(len_hint.max(16)); for _ in 0..segment_count { let seg = self.bytecode[self.pc]; self.pc += 1; if (seg >> 31) == 1 { let reg = (seg & 0x7FFF_FFFF) as usize; let val = self.regs[reg]; if val.is_string() { // SAFETY: val 是字符串值;借用仅在本次展开内消费,不跨分配点。 let s = unsafe { &*val.as_string_ptr() }; units.extend_from_slice(s.units().as_ref()); } else if val.is_object() || val.is_symbol() { // 对象走完整 ToString(ToPrimitive 副作用顺序,结果保单元); // Symbol 抛 TypeError(to_units_full 无 symbol 直写分支)。 units.extend(to_units_full(val, self)?); } else { // 原始值直写结果缓冲,免中间 String。 push_units_to(val, &mut units); } } else { let const_idx = (seg & 0x7FFF_FFFF) as usize; let imm = self.immutables(); if const_idx < imm.len() { let val = imm[const_idx]; if val.is_string() { // SAFETY: val 是字符串值;借用仅在本次展开内消费,不跨分配点。 let s = unsafe { &*val.as_string_ptr() }; units.extend_from_slice(s.units().as_ref()); } } } } self.regs[rd] = self.new_string_units_owned(units); Ok(()) } pub(crate) fn dispatch_instanceof(&mut self, rd: usize, a: usize, b: usize) -> Result<(), String> { vm_trace!("INSTANCEOF rd={}", rd); let lhs_val = self.regs[a]; let rhs_val = self.regs[b]; if !rhs_val.is_object() { return self.raise_type_error("INSTANCEOF right-hand side is not callable"); } let has_instance_si = encode_symbol_key(self.realm_id(), WELL_KNOWN_SYMBOL_HAS_INSTANCE); let ctor_obj = unsafe { &*rhs_val.as_js_object_ptr() }; // 传播读触发 getter;getter 抛错且外围 catch 接手时 ordinary_get 返回 // catch 参数值(pc 已改写),按 pc 变化感知并停流,异常由展开送达。 let pc_before = self.pc; let has_instance_val = match self.ordinary_get(ctor_obj, has_instance_si, rhs_val) { Ok(v) if self.pc == pc_before => v, Ok(_) => return Ok(()), Err(e) => return self.raise_call_error(&e).map(|_| ()), }; // 仅 undefined 视为无 handler;null 非 undefined,须调用,Call(null) 抛 // TypeError。handler 在场须可调用;调用异常原值上抛(外围 try/catch 可捕获)。 if !has_instance_val.is_undefined() { if !is_callable(has_instance_val) { return self.raise_type_error("instanceof: @@hasInstance handler is not callable"); } let result = match self.call_function_sync(has_instance_val, rhs_val, &[lhs_val]) { Ok(v) => v, Err(e) => return self.raise_call_error(&e).map(|_| ()), }; self.regs[rd] = JsValue::bool(to_boolean(result)); return Ok(()); } // 无 handler 时 RHS 不可调用即 TypeError(先于左操作数类型检查)。 if !is_callable(rhs_val) { return self.raise_type_error("INSTANCEOF right-hand side is not callable"); } if !lhs_val.is_object() { self.regs[rd] = JsValue::bool(false); return Ok(()); } let rhs_obj = unsafe { &*rhs_val.as_js_object_ptr() }; let proto_si = self.kernel_core.perm_interner().intern("prototype").0; // 传播读:getter 异常原值上抛(深度 0 已就地展开的由 pc 变化感知)。 let pc_before = self.pc; let ctor_proto = match self.ordinary_get(rhs_obj, proto_si, rhs_val) { Ok(v) if self.pc == pc_before => v, Ok(_) => return Ok(()), Err(e) => return self.raise_call_error(&e).map(|_| ()), }; // prototype 非对象 → TypeError。 if !ctor_proto.is_object() { return self.raise_type_error("instanceof: prototype is not an object"); } let ctor_proto_ptr = ctor_proto.as_js_object_ptr(); let mut proto = unsafe { &*lhs_val.as_js_object_ptr() }.proto(); let mut depth = 0usize; loop { if !proto.is_object() { self.regs[rd] = JsValue::bool(false); break; } if depth >= MAX_PROTO_CHAIN_DEPTH { self.regs[rd] = JsValue::bool(false); break; } depth += 1; let proto_ptr = proto.as_js_object_ptr(); if proto_ptr == ctor_proto_ptr { self.regs[rd] = JsValue::bool(true); break; } proto = unsafe { &*proto_ptr }.proto(); } Ok(()) } pub(crate) fn dispatch_in(&mut self, rd: usize, a: usize, b: usize) -> Result<(), String> { vm_trace!("IN rd={}", rd); let key_val = self.regs[a]; let obj_ptr = self.regs[b].as_object_ptr() as *mut JsObject; if obj_ptr.is_null() { return self.raise_type_error("IN right-hand side is not an object"); } let obj = unsafe { &*obj_ptr }; let prop_name_si = self.property_key_si(key_val)?; // `in` 即 HasProperty:原型链各层都要看数组元素区与 TypedArray 整数索引, // 读值解析不覆盖这两处。deferred namespace 目标先触发求值(cyclic 抛错)。 let found = self.has_property(obj, prop_name_si)?; self.regs[rd] = JsValue::bool(found); Ok(()) } pub(crate) fn dispatch_for_in_init(&mut self, a: usize) -> Result<(), String> { vm_trace!("FOR_IN_INIT r{}={:?}", a, self.regs[a]); let mut obj_val = self.regs[a]; if obj_val.is_null() || obj_val.is_undefined() { // null/undefined 枚举不到任何键——是空 for-in,而非 TypeError。 let iter = Box::into_raw(Box::new(ForInIter { keys: Vec::new(), index: 0 })); self.iters.push_for_in(iter); return Ok(()); } if !obj_val.is_object() { // ToObject:字符串盒构造期已物化索引属性面,其余原始值盒无自身可枚举属性。 obj_val = oxide_runtime_api::to_object(obj_val, self)?; } // [[OwnPropertyKeys]] 触发(for-in 枚举源):deferred namespace 先求值, // cyclic 守卫抛 TypeError,触发失败走可捕获异常展开。 let obj_ptr = obj_val.as_js_object_ptr(); if !obj_ptr.is_null() { let obj = unsafe { &*obj_ptr }; if let Err(msg) = self.ensure_deferred_ns_evaluation(obj, None) { self.raise_call_error(&msg)?; return Ok(()); } } let mut keys_vec: Vec<(JsValue, u32)> = Vec::new(); let mut seen = std::collections::HashSet::new(); let mut current = obj_val; // 数组把整型下标元素存在 prop_vec,而 prop_vec 不属于 shape 链。 // 单独枚举它们(ES:数组下标是可枚举字符串键,按升序排在其它自有键之前)。 // hole(删除标记)跳过——for-in 不枚举数组稀疏空洞。 if current.is_object() { let arr = unsafe { &*current.as_js_object_ptr() }; if arr.is_array() { for i in 0..arr.array_prop_count { if arr.prop_meta_at(i).is_some_and(|m| m.is_hole()) { continue; } let is_enum = arr .prop_meta_at(i) .map(|m| m.attributes.enumerable()) .unwrap_or(PropAttributes::DEFAULT_DATA.enumerable()); if is_enum { // 整数下标编码为整数键(免 intern + 防永久泄漏);枚举值 // 物化为数字字符串,排序时由 array_index_from_property_key // 直接反解。 let idx = make_int_key(i); keys_vec.push((self.new_string(&i.to_string()), idx)); } } } // TA 元素键:整数下标 0..live 长升序排前(尾稳定排序负责序); // 越界(含 detach)live 长 0 零枚;元素住 buffer,不在形状链。 if arr.is_typed_array_obj() { let len = oxide_builtins::typed_array::ta_view_length(self, arr) as u32; for i in 0..len.min(INT_KEY_COUNT) { keys_vec.push((self.new_string(&i.to_string()), make_int_key(i))); } } } let mut depth = 0usize; loop { if !current.is_object() { break; } if depth >= MAX_PROTO_CHAIN_DEPTH { break; } depth += 1; let cur = unsafe { &*current.as_js_object_ptr() }; let obj_start = keys_vec.len(); let mut cursor = Some(cur.shape_id()); while let Some(id) = cursor { if id == oxide_kernel::shape_forge::EMPTY_SHAPE_ID { break; } if let Some(shape) = self.kernel_core.shape_forge().get_shape(id) { // Symbol 键/私有名键不参与 for-in 枚举。 if shape.property_name != u32::MAX && !is_symbol_key(shape.property_name) && !is_private_name_key(shape.property_name) && seen.insert(shape.property_name) { let enumerable = self .kernel_core .shape_forge() .lookup_position(cur.shape_id(), shape.property_name) // 数组命名属性存储下标 = 元素区偏移加 shape 槽位; // 普通对象槽位即下标,空数组偏移为零。 .and_then(|pos| { cur.prop_meta_at(if cur.is_array() { cur.array_prop_count + pos } else { pos }) }) .map(|meta| meta.attributes.enumerable()) .unwrap_or(PropAttributes::DEFAULT_DATA.enumerable()); if enumerable { // 整数键不在 interner:物化为数字字符串;其余键取永久串。 let key_val = if is_int_key(shape.property_name) { self.new_string(&int_key_value(shape.property_name).to_string()) } else { JsValue::perm_string(self.kernel_core.perm_interner().string_ptr(shape.property_name)) }; keys_vec.push((key_val, shape.property_name)); } } cursor = shape.parent; } else { break; } } // shape 链按叶→根遍历(与插入序相反);在接上原型前把本对象的切片 // 翻转为插入序。 keys_vec[obj_start..].reverse(); current = cur.proto(); } // 模块命名空间 exotic:EnumerateObjectProperties 构建键表时逐键走 // `? [[GetOwnProperty]]`,未初始化导出抛 ReferenceError。校验须在排序与 // 迭代器建立之前(INIT 期),不遗留 for-in 迭代器;非 live ns 无条目表, // `module_ns_export` 返回 None,落普通路径零行为变化。deferred 对象求值后 // 校验按真实 ns 条目表(deferred 自身槽位是预注册占位)。 if obj_val.is_object() { let ns_obj = unsafe { &*obj_val.as_js_object_ptr() }; if ns_obj.is_module_namespace() { for (_key_val, si) in &keys_vec { if is_symbol_key(*si) { continue; } let target = oxide_builtins::module::deferred_ns_read_target(ns_obj); if let Some(oxide_builtins::module::ModuleNsQuery::Uninitialized) = oxide_builtins::module::module_ns_export(target, *si) { return self .raise_error_kind("ReferenceError", oxide_builtins::module::NS_UNINITIALIZED_MESSAGE); } } } } // ES 枚举序:整型下标键升序,其余按插入序。稳定排序保持非下标键间的插入序。 keys_vec.sort_by(|(_, a_si), (_, b_si)| { match (self.array_index_from_property_key(*a_si), self.array_index_from_property_key(*b_si)) { (Some(ai), Some(bi)) => ai.cmp(&bi), (Some(_), None) => std::cmp::Ordering::Less, (None, Some(_)) => std::cmp::Ordering::Greater, (None, None) => std::cmp::Ordering::Equal, } }); // std Vec 直接作为迭代器体;体是堆上 Box,生命周期随迭代器表与 // 挂起状态盒,出表/状态盒释放时逐条释放。 let iter = Box::into_raw(Box::new(ForInIter { keys: keys_vec, index: 0 })); self.iters.push_for_in(iter); Ok(()) } pub(crate) fn dispatch_for_in_next(&mut self, rd: usize) -> Result<(), String> { vm_trace!("FOR_IN_NEXT rd={}", rd); let iter_ptr = self.iters.last_for_in(); if iter_ptr.is_null() { return Err("FOR_IN_NEXT without active iterator".into()); } let iter = unsafe { &mut *iter_ptr }; if iter.index < iter.keys.len() { self.regs[rd] = iter.keys[iter.index].0; iter.index += 1; } else { self.regs[rd] = JsValue::undefined(); } Ok(()) } pub(crate) fn dispatch_for_in_done(&mut self, rd: usize) { vm_trace!("FOR_IN_DONE rd={}", rd); let iter_ptr = self.iters.last_for_in(); if iter_ptr.is_null() { self.regs[rd] = JsValue::bool(true); } else { let iter = unsafe { &*iter_ptr }; self.regs[rd] = JsValue::bool(iter.index >= iter.keys.len()); } } pub(crate) fn dispatch_for_in_cleanup(&mut self) { vm_trace!("FOR_IN_CLEANUP"); self.iters.pop_for_in(); } /// using/await using 声明登记:把资源值(rd 槽)与释放提示(a 槽)压入释放栈。 /// /// 释放提示 0 = 同步、1 = 异步,登记期原样保留供释放点分派; /// 本指令只登记,释放时机由作用域出口点决定。 /// /// # 副作用 /// - 释放栈增长(栈内 JsValue 是 GC 根,run 边界清空)。 pub(crate) fn dispatch_dispose_register(&mut self, rd: usize, a: usize) { vm_trace!("DISPOSE_REGISTER rd={} hint={}", rd, a); self.dispose_stack.push((self.regs[rd], a as u16)); } /// 作用域入口水位:把当前释放栈深度压入水位栈(DISPOSE_POP 的配对入口)。 /// /// # 副作用 /// - 水位栈增长。 pub(crate) fn dispatch_dispose_mark(&mut self) { vm_trace!("DISPOSE_MARK depth={}", self.dispose_stack.len()); self.dispose_marks.push(self.dispose_stack.len()); } /// 作用域出口:弹出水位,逆序释放水位以上资源并截断释放栈(规范 /// DisposeResources)。多个释放方法抛错时按规范折叠成 SuppressedError 链 /// (后抛为 error、前值为 suppressed),循环不因错中断;收尾有合并错误时 /// 写入在途异常并展开到最近处理器。 /// /// # 边界与前提 /// - 正常完成穿越:completion 初值为 None(无在途异常)。 /// /// # 副作用 /// - 释放栈截断到水位、水位栈弹出;释放方法是任意 JS 调用(可再入, /// 嵌套 using 声明会在其内再压释放栈)。 /// - 有合并错误时改写 `exception_value`/`pending_error_kind` 并触发 `unwind`。 pub(crate) fn dispatch_dispose_pop(&mut self) -> Result<(), String> { // 重入守卫:释放方法抛错触发的嵌套 unwind 会重入本函数,置位时直接返回, // 防重复释放与合并(先于弹水位,防重入误弹外层水位)。 if self.disposing { return Ok(()); } let mark = match self.dispose_marks.pop() { Some(m) => m, None => return Ok(()), }; vm_trace!("DISPOSE_POP mark={} depth={}", mark, self.dispose_stack.len()); self.disposing = true; let mut completion: Option = None; while self.dispose_stack.len() > mark { let (value, hint) = self.dispose_stack.pop().expect("水位以上必有条目"); match self.dispose_value(value, hint)? { DisposeOutcome::Done | DisposeOutcome::NoMethod => {} DisposeOutcome::Err(exc) => { completion = oxide_builtins::disposable_stack::merge_dispose_error(self, completion, exc); } DisposeOutcome::Suspended(promise) => { // 异步挂起:登记在途状态(水位已在循环前弹出,恢复后续循环不 // 重复弹),置挂起信号让派发循环退出由恢复方快照。 self.pending_async_dispose = Some(PendingAsyncDispose { dispose_promise: promise, mark, completion, kind: DisposeResumeKind::Pop, }); self.disposing = false; return Ok(()); } } } self.disposing = false; if let Some(exc) = completion { self.exception_value = Some(exc); self.pending_error_kind = Some(self.thrown_error_kind(exc)); self.unwind()?; } Ok(()) } /// 批量释放核心:逆序释放 `depth` 以上条目并截断释放栈到 `depth`,同步弹出 /// 水位栈中 `>= depth` 的基线条目(保两栈一致,防异常路径基线泄漏)。 /// /// # 步骤 /// 1. 在途异常作 completion 种子(`seed`,异常穿越时被折叠进 suppressed)。 /// 2. 逐条弹出并释放(`dispose_value`);多个释放方法抛错时按规范折叠成 /// SuppressedError 链(后抛为 error、前值为 suppressed),循环不因错中断。 /// 3. 异步挂起时登记 `PendingAsyncDispose`(携给定 `kind` 与在途合并错误)并 /// 返回 `Suspended`。 /// 4. 收尾写回 completion:有合并错误则替代在途异常并更新错误类型;无合并 /// 错误则还原在途异常(类型不变)。 /// 5. 截断释放栈后,弹出水位栈中 `>= depth` 的基线条目。 /// /// # 边界与前提 /// - 重入守卫:释放方法抛错触发的嵌套 unwind 会重入本函数,`disposing` 置位时 /// 直接返回(防重复释放与合并,合并链会被二次折叠)。 /// - 挂起路径基线水位暂不弹(恢复续循环后统一弹)。 pub(crate) fn dispose_above_core( &mut self, depth: usize, kind: DisposeResumeKind, seed: Option, ) -> Result { if self.disposing { return Ok(DisposePhase::Clean); } self.disposing = true; let mut completion: Option = seed; let mut threw = false; let truncated = self.dispose_stack.len() > depth; while self.dispose_stack.len() > depth { let (value, hint) = self.dispose_stack.pop().expect("水位以上必有条目"); match self.dispose_value(value, hint)? { DisposeOutcome::Done | DisposeOutcome::NoMethod => {} DisposeOutcome::Err(exc) => { completion = oxide_builtins::disposable_stack::merge_dispose_error(self, completion, exc); threw = true; } DisposeOutcome::Suspended(promise) => { // 异步挂起:登记在途状态,基线水位暂不弹(恢复续循环后统一弹)。 self.pending_async_dispose = Some(PendingAsyncDispose { dispose_promise: promise, mark: depth, completion, kind, }); self.disposing = false; return Ok(DisposePhase::Suspended); } } } if let Some(exc) = completion { self.exception_value = Some(exc); if threw { self.pending_error_kind = Some(self.thrown_error_kind(exc)); } } // 仅在实际截断释放栈时同步弹基线,防 no-op 调用(如 dispose_top_n(0)) // 误弹外层作用域的水位。 if truncated { while self.dispose_marks.last().is_some_and(|&m| m >= depth) { self.dispose_marks.pop(); } } self.disposing = false; Ok(if threw { DisposePhase::Threw } else { DisposePhase::Clean }) } /// 异常穿越释放:逆序释放 `depth` 以上资源。在途异常作 completion 种子(被折叠 /// 进 suppressed)。挂起时携 `Unwind(handler)`(handler 已弹出,恢复时重压再入 /// unwind)。 pub(crate) fn dispose_above(&mut self, depth: usize, handler: Option) -> Result { self.dispose_above_core(depth, DisposeResumeKind::Unwind(handler), self.exception_value) } /// 释放栈顶部 `n` 条资源(逃出释放:return/break/continue 完成值逃出作用域时 /// 逆序释放被逃出的资源)。`n` 超过栈长时按全量释放。在途 completion 初值为 /// None(完成值非 throw),挂起时携 `Escape(completion)` 供恢复后执行。 pub(crate) fn dispose_top_n(&mut self, n: usize, completion: Completion) -> Result { let depth = self.dispose_stack.len().saturating_sub(n); self.dispose_above_core(depth, DisposeResumeKind::Escape(completion), None) } /// 单资源释放(规范 Dispose 语义):按释放提示取方法(同步只取 Symbol.dispose; /// 异步先取 Symbol.asyncDispose,未定义回退 Symbol.dispose),以资源自身为 this /// 零参调用。 /// /// # 返回值 /// `Done` = 释放成功;`NoMethod` = 无释放方法(跳过);`Err(v)` = 释放方法抛错 /// (v 为原始异常值,经 `last_uncaught_value` 恢复,无则按错误文本建普通 Error); /// `Suspended(promise)` = 异步释放已挂起(promise 为释放方法结果经 PromiseResolve /// 包装后登记的结算 promise,调用方据此登记 `PendingAsyncDispose`)。 /// /// # 边界与前提 /// - 取方法 / 调用方法任一步抛错均归入 `Err`(getter 抛错与调用抛错同处置)。 /// - 异步提示恒挂起:方法未定义时结果取 undefined,仍经 PromiseResolve 包成新 /// promise 让出一次微任务(规范 `await using` 的 Await 步无条件执行)。 fn dispose_value(&mut self, value: JsValue, hint: u16) -> Result { // 取方法抛错(getter 抛错)归入 Err 结局(合并进链)。 let method = match self.lookup_dispose_method(value, hint) { Ok(m) => m, Err(exc) => return Ok(DisposeOutcome::Err(exc)), }; // 异步提示且有异步上下文:调用方法(未定义时结果取 undefined),结果无条件 // Await 挂起。无异步上下文(顶层 await using)回退同步释放。 if hint == 1 && (self.async_context.is_some() || self.async_gen_context.is_some()) { let result = if is_callable(method) { match self.call_function_sync(method, value, &[]) { Ok(v) => v, Err(e) => return Ok(DisposeOutcome::Err(self.dispose_exc(e))), } } else { JsValue::undefined() }; let promise = match self.promise_resolve(result) { Ok(p) => p, Err(exc) => { let (p, _, _) = self.new_promise_capability(); let _ = self.reject_promise(p, exc); p } }; self.register_dispose_suspend(promise)?; return Ok(DisposeOutcome::Suspended(promise)); } // 同步(或无异步上下文的异步提示):不可调用跳过;调用成功 Done,抛错 Err。 if !is_callable(method) { return Ok(DisposeOutcome::NoMethod); } match self.call_function_sync(method, value, &[]) { Ok(_) => Ok(DisposeOutcome::Done), Err(e) => Ok(DisposeOutcome::Err(self.dispose_exc(e))), } } /// 取释放方法:异步提示先取 Symbol.asyncDispose,未定义回退 Symbol.dispose; /// 同步提示只取 Symbol.dispose。非对象取 undefined。getter 抛错时返回原始 /// 异常值(经 `last_uncaught_value` 恢复,无则按错误文本建普通 Error)。 fn lookup_dispose_method(&mut self, value: JsValue, hint: u16) -> Result { if !value.is_object() { return Ok(JsValue::undefined()); } let val_obj = unsafe { &*value.as_js_object_ptr() }; let dispose_key = encode_symbol_key(self.realm_id(), WELL_KNOWN_SYMBOL_DISPOSE); let method = if hint == 1 { let async_key = encode_symbol_key(self.realm_id(), WELL_KNOWN_SYMBOL_ASYNC_DISPOSE); let async_method = self.ordinary_get(val_obj, async_key, value).map_err(|e| self.dispose_exc(e))?; if async_method.is_undefined() { self.ordinary_get(val_obj, dispose_key, value) .map_err(|e| self.dispose_exc(e))? } else { async_method } } else { self.ordinary_get(val_obj, dispose_key, value) .map_err(|e| self.dispose_exc(e))? }; Ok(method) } /// 登记异步释放挂起:按派发上下文(异步生成器 / 普通异步函数)构造结算闭包, /// 登记 fulfill/reject 恢复反应并置挂起信号。 /// /// # 边界与前提 /// - 异步生成器派发(`async_gen_dispatch`)走异步生成器状态盒与结算闭包,置 /// `async_gen_suspended`;普通异步函数走异步上下文,置 `async_suspended`。 /// - 无对应上下文(非异步上下文内的异步释放)返回 Err,不静默降级。 fn register_dispose_suspend(&mut self, promise: JsValue) -> Result<(), String> { if self.async_gen_dispatch { let Some(ctx) = self.async_gen_context else { return Err("async dispose in async generator without context".into()); }; let fulfill_fn = self.make_async_gen_dispose_resume_fn(ctx, promise, false); let reject_fn = self.make_async_gen_dispose_resume_fn(ctx, promise, true); let _ = self.perform_promise_then(promise, fulfill_fn, reject_fn); self.async_gen_suspended = true; return Ok(()); } let Some(ctx) = self.async_context else { return Err("async dispose outside async function".into()); }; let fulfill_fn = self.make_async_dispose_resume_fn(ctx, promise, false); let reject_fn = self.make_async_dispose_resume_fn(ctx, promise, true); let _ = self.perform_promise_then(promise, fulfill_fn, reject_fn); self.async_suspended = true; Ok(()) } /// 释放路径抛错时恢复原始异常值(经 `last_uncaught_value`,无则按错误文本建 /// 普通 Error)。 fn dispose_exc(&mut self, e: String) -> JsValue { self.last_uncaught_value .take() .unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e)) } pub(crate) fn dispatch_for_of_init(&mut self, a: usize) -> Result<(), String> { vm_trace!("FOR_OF_INIT r{}={:?}", a, self.regs[a]); let iterable = self.regs[a]; match oxide_builtins::iterator::make_iterator_for_value(self, iterable) { Ok(iterator) => { // 内置包装器检测:Array/String/TA/Map/Set 走快路径(异步恒慢)。 // init 期把 inner 快照入条目,步内不重读 `__inner__` 槽。 let (kind, inner) = match oxide_builtins::iterator::builtin_iter_kind(self, iterator) { Some((k, i)) => (Some(k), i), None => (None, JsValue::undefined()), }; self.iters.push_for_of(iterator, false, kind, inner); Ok(()) } Err(err) => { self.exception_value = Some(err); self.pending_error_kind = Some(self.thrown_error_kind(err)); self.unwind() } } } /// for-await-of 初始化:按 GetAsyncIterator 协议取异步迭代器(缺失 `@@asyncIterator` /// 时回退同步迭代器并包 AsyncFromSyncIterator),压入 for-of 迭代器栈。 pub(crate) fn dispatch_for_await_of_init(&mut self, a: usize) -> Result<(), String> { vm_trace!("FOR_AWAIT_OF_INIT r{}={:?}", a, self.regs[a]); let iterable = self.regs[a]; match crate::async_from_sync::make_async_iterator(self, iterable) { Ok(iterator) => { // for-await-of 恒慢路径:无快路径快照,inner 传 undefined。 self.iters.push_for_of(iterator, true, None, JsValue::undefined()); Ok(()) } Err(err) => { self.exception_value = Some(err); self.pending_error_kind = Some(self.thrown_error_kind(err)); self.unwind() } } } /// for-await-of 步进:调用迭代器 `next()`,把返回的 promise 写入 rd。 /// 随后的 `AWAIT` 负责挂起等待;next() 抛出时弹出迭代器并透传(与同步 for-of 一致)。 pub(crate) fn dispatch_for_await_of_next(&mut self, rd: usize) -> Result<(), String> { vm_trace!("FOR_AWAIT_OF_NEXT rd={}", rd); self.last_uncaught_value = None; let Some(iterator) = self.iters.last_for_of() else { return Err("FOR_AWAIT_OF_NEXT without active iterator".into()); }; if !iterator.is_object() { return Err("FOR_AWAIT_OF_NEXT iterator is not an object".into()); } let iter_obj = unsafe { &*iterator.as_js_object_ptr() }; let next_si = self.kernel_core.perm_interner().intern("next").0; let next_fn = match self.ordinary_get(iter_obj, next_si, iterator) { Ok(v) => v, Err(e) => return self.throw_for_of_error(e), }; let result = match self.call_function_sync(next_fn, iterator, &[]) { Ok(v) => v, Err(e) => return self.throw_for_of_error(e), }; self.regs[rd] = result; Ok(()) } /// for-await-of 步进完成检查:读取 `AWAIT` 恢复值(a 槽,即迭代器结果对象)的 /// `done`,写入本迭代器条目结果并把 `!done` 写 rd(供 JMP_IF_FALSE 分支)。 pub(crate) fn dispatch_for_await_of_done(&mut self, rd: usize, a: usize) -> Result<(), String> { vm_trace!("FOR_AWAIT_OF_DONE rd={} r{}={:?}", rd, a, self.regs[a]); let result = self.regs[a]; if !result.is_object() { return self.raise_type_error("iterator result is not an object"); } self.iters.set_last_result(result); let result_obj = unsafe { &*result.as_js_object_ptr() }; let done_si = self.kernel_core.perm_interner().intern("done").0; let done_val = match self.ordinary_get(result_obj, done_si, result) { Ok(v) => v, Err(e) => return self.throw_for_of_error(e), }; self.regs[rd] = JsValue::bool(!to_boolean(done_val)); Ok(()) } /// for-await-of 收尾:迭代器自然 done 时跳过;否则执行异步 IteratorClose—— /// 调用 `return()`,其返回的 promise 经 await 挂起,恢复后继续循环后的指令。 pub(crate) fn dispatch_for_await_of_close(&mut self) -> Result<(), String> { vm_trace!("FOR_AWAIT_OF_CLOSE"); let Some(entry) = self.iters.pop_for_of() else { return Ok(()); }; let iterator = entry.iterator; let result = entry.last_result; if result.is_object() { let result_obj = unsafe { &*result.as_js_object_ptr() }; let done_si = self.kernel_core.perm_interner().intern("done").0; if let Ok(done_val) = self.ordinary_get(result_obj, done_si, result) { if to_boolean(done_val) { return Ok(()); } } } if !iterator.is_object() { return Ok(()); } let iter_obj = unsafe { &*iterator.as_js_object_ptr() }; let return_si = self.kernel_core.perm_interner().intern("return").0; let return_fn = match self.ordinary_get(iter_obj, return_si, iterator) { Ok(v) => v, // return getter 抛出:恢复原始异常值并就地展开,使外围 try/catch 可捕获。 Err(e) => return self.throw_for_of_close_error(&e), }; if !return_fn.is_object() { return Ok(()); } if !unsafe { &*return_fn.as_js_object_ptr() }.is_function() { return Ok(()); } let inner = match self.call_function_sync(return_fn, iterator, &[]) { Ok(v) => v, // return() 抛出:恢复原始异常值并就地展开,使外围 try/catch 可捕获。 Err(e) => return self.throw_for_of_close_error(&e), }; if !inner.is_object() { return self.raise_type_error("iterator return() result is not an object"); } self.perform_await(inner) } pub(crate) fn dispatch_for_of_done(&mut self, rd: usize) -> Result<(), String> { vm_trace!("FOR_OF_DONE rd={}", rd); let Some(iterator) = self.iters.last_for_of() else { return Err("FOR_OF_DONE without active iterator".into()); }; if !iterator.is_object() { return Err("FOR_OF_DONE iterator is not an object".into()); } // 调用 next()/读 done 前清空异常值槽:跨调用残留不得污染本指令的取槽。 self.last_uncaught_value = None; // 快路径:内置包装器(Array/String/TA/Map/Set)直步,跳过 native 调用帧、 // 结果对象分配与 done/value 两次读;inner 与游标取条目快照,步内不重跑槽协议。 if self.iters.for_of_iters.last().is_some_and(|e| e.fast.is_some()) { // inner 与游标为 Copy 值:先拷出释放借用,再做步进核心的可变调用。 let (inner, cursor) = { let e = self.iters.for_of_iters.last().unwrap(); (e.fast_inner, e.fast_cursor) }; let stack_len = self.iters.for_of_iters.len(); let step = oxide_builtins::iterator::builtin_iter_fast_step(self, inner, cursor); // 元素 getter / 访问器抛出:深度 0 的 raise_call_error 已就地 unwind // (跳转 catch),条目已弹出、异常值已入异常通道——直接返回,派发循环 // 自 catch 点续行,不得再触碰迭代器栈。 // 判据须含栈深度:同迭代器两层嵌套时栈顶被外层条目顶替,仅凭 iterator // 同一性会误判通过,须以步前深度不变作锚。 if self.iters.for_of_iters.len() != stack_len || !self.iters.for_of_iters.last().is_some_and(|e| e.iterator == iterator) { return Ok(()); } match step { Ok((value, done, next_cursor)) => { let entry = self.iters.for_of_iters.last_mut().unwrap(); entry.fast_value = value; entry.fast_cursor = next_cursor; self.regs[rd] = JsValue::bool(!done); } Err(exc) => return self.throw_for_of_error_value(exc), } return Ok(()); } let iter_obj = unsafe { &*iterator.as_js_object_ptr() }; let next_si = self.kernel_core.perm_interner().intern("next").0; let next_fn = match self.ordinary_get(iter_obj, next_si, iterator) { Ok(v) => v, // 错误路径只经 throw_for_of_error 传播,不写 rd(rd 保持循环决策位, // 异常展开后指令流离开循环,残留值无效)。 Err(e) => return self.throw_for_of_error(e), }; let result = match self.call_function_sync(next_fn, iterator, &[]) { Ok(v) => v, Err(e) => return self.throw_for_of_error(e), }; if !result.is_object() { return self.raise_type_error("iterator result is not an object"); } let result_obj = unsafe { &*result.as_js_object_ptr() }; let done_si = self.kernel_core.perm_interner().intern("done").0; let done_val = match self.ordinary_get(result_obj, done_si, result) { Ok(v) => v, Err(e) => return self.throw_for_of_error(e), }; let done = to_boolean(done_val); self.iters.set_last_result(result); self.regs[rd] = JsValue::bool(!done); Ok(()) } pub(crate) fn dispatch_for_of_next(&mut self, rd: usize) -> Result<(), String> { vm_trace!("FOR_OF_NEXT rd={}", rd); 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(); if !result.is_object() { self.regs[rd] = JsValue::undefined(); return Ok(()); } let result_obj = unsafe { &*result.as_js_object_ptr() }; let value_si = self.kernel_core.perm_interner().intern("value").0; self.regs[rd] = match self.ordinary_get(result_obj, value_si, result) { Ok(v) => v, // 错误路径只经 throw_for_of_error 传播,不写 rd(同上)。 Err(e) => return self.throw_for_of_error(e), }; Ok(()) } /// next()/value 访问抛出:经 unwind 走异常展开,使外围 try/catch 能捕获,并尽可能 /// 重新抛出原始值。按 ECMA-262,next() 抛出时不会经 return() 关闭迭代器—— /// 先弹出它,使展开时的 IteratorClose 遍历跳过该迭代器。 fn throw_for_of_error(&mut self, msg: String) -> Result<(), String> { let exc = match self.last_uncaught_value.take() { Some(v) => v, 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.pending_error_kind = Some(self.thrown_error_kind(exc)); // 无论取到原值还是重建错误对象,异常必须展开传播,不得静默返回 Ok—— // 否则 for-of 循环继续推进形成不终止。 self.unwind() } /// for-await-of 收尾抛错(return getter 或 return() 调用):恢复原始异常值并就地 /// 展开,使外围 try/catch 可捕获。本函数入口已弹出本迭代器条目,故展开路径不得 /// 再弹 for-of 栈(与 throw_for_of_error_value 的唯一区别)。 /// /// 直接 unwind 而非经 raise_call_error:后者以 native_call_depth 门控展开, /// 异步函数恢复期深度恒大于零会误判为不展开,使异常绕过循环内 catch 直接 /// 拒绝 capability promise。 fn throw_for_of_close_error(&mut self, msg: &str) -> Result<(), String> { let exc = self .last_uncaught_value .take() .unwrap_or_else(|| oxide_builtins::error::create_from_text(self, msg)); self.exception_value = Some(exc); self.pending_error_kind = Some(self.thrown_error_kind(exc)); self.unwind() } pub(crate) fn dispatch_for_of_close(&mut self) -> Result<(), String> { vm_trace!("FOR_OF_CLOSE"); let Some(entry) = self.iters.pop_for_of() else { return Ok(()); }; let iterator = entry.iterator; let result = entry.last_result; // 迭代已自然结束(最后一次 next 返回 done:true)时不调 return(); // 仅当元素耗尽但迭代器未 done(提前退出)才执行 IteratorClose。 if result.is_object() { let result_obj = unsafe { &*result.as_js_object_ptr() }; let done_si = self.kernel_core.perm_interner().intern("done").0; if let Ok(done_val) = self.ordinary_get(result_obj, done_si, result) { if to_boolean(done_val) { return Ok(()); } } } // 正常 / break / return 退出:此前无进行中的突然完成,return() 自身的抛出直接传播。 self.close_for_of_iterator(iterator, false) } /// 调用 `iterator.return()`(IteratorClose)。 /// /// # 边界与前提 /// - `suppress_return_error` 为 true 时表示正在展开某个外围突然完成:return() 的 /// 自身结果被丢弃,并保留在途异常跨调用存活。 /// - 为 false 时(正常 for-of 退出)return() 的错误向外传播。 pub(crate) fn close_for_of_iterator( &mut self, iterator: JsValue, suppress_return_error: bool, ) -> Result<(), String> { if !iterator.is_object() { return Ok(()); } let iter_obj = unsafe { &*iterator.as_js_object_ptr() }; let return_si = self.kernel_core.perm_interner().intern("return").0; let return_fn = match self.ordinary_get(iter_obj, return_si, iterator) { Ok(v) => v, Err(e) => { if suppress_return_error { return Ok(()); } return Err(e); } }; if return_fn.is_object() { let return_obj = unsafe { &*return_fn.as_js_object_ptr() }; if return_obj.is_function() { if suppress_return_error { let saved_exc = self.exception_value; let saved_kind = self.pending_error_kind; // 忽略调用期间的原始异常值一并暂存:return() 自身抛错按契约被在途 // 异常替代,其值不得外泄进槽供后续 take 误取。 let saved_uncaught = self.last_uncaught_value.take(); let _ = self.call_function_sync(return_fn, iterator, &[]); self.exception_value = saved_exc; self.pending_error_kind = saved_kind; self.last_uncaught_value = saved_uncaught; } else { let inner = match self.call_function_sync(return_fn, iterator, &[]) { Ok(v) => v, // return() 抛出:恢复原始异常值并展开,使外围 try/catch 可捕获。 Err(e) => return self.raise_call_error(&e).map(|_| ()), }; // IteratorClose 要求 return() 返回值是对象,否则抛 TypeError。 if !inner.is_object() { self.raise_type_error("iterator return() result is not an object")?; return Ok(()); } } } } Ok(()) } /// 对 `depth` 以上的所有活跃 for-of 迭代器执行 IteratorClose,供 `unwind()` 关闭 /// 被异常中断的循环。先弹出再关闭,防止重入调用重复关闭,同时跳过 next()-throw /// 路径(它已弹出自己的迭代器)。 pub(crate) fn close_for_of_above(&mut self, depth: usize) { while self.iters.for_of_iters.len() > depth { let Some(entry) = self.iters.pop_for_of() else { break; }; let _ = self.close_for_of_iterator(entry.iterator, true); } } pub(crate) fn dispatch_rest_object(&mut self, rd: usize, a: usize, b: usize) -> Result<(), String> { vm_trace!("REST_OBJECT rd={}", rd); // ext 字(excluded 常量下标)在任何路径都先消费,防止 ToObject 早返回后 // pc 错位把 ext 字当下一条指令解码(曾误读成 UNSPILL slot)。 let excluded_idx = self.bytecode[self.pc] as usize; self.pc += 1; let src = self.regs[a]; if !src.is_object() { // ToObject:null/undefined 抛;number/boolean/symbol 无自有属性 → 空对象; // string 的索引字符(UTF-16 code unit)是可枚举自有属性。 if src.is_null() || src.is_undefined() { return self.raise_type_error("Cannot destructure property of null/undefined"); } let proto_ptr = self.realm.session.borrow().builtin_world().object_proto.as_ptr() as *mut JsObject; let rest_ptr = self.alloc_object(JsObject::new_empty( oxide_kernel::shape_forge::EMPTY_SHAPE_ID, JsValue::from_js_object(proto_ptr), )); if src.is_string() { // SAFETY: src 是字符串值;单元序列展开(lone surrogate 保真)。 let code_units: Vec = unsafe { (*src.as_string_ptr()).units().into_owned() }; for (i, unit) in code_units.iter().enumerate() { let si = make_int_key(i as u32); let ch_val = self.unit_char_value(*unit); let rest = unsafe { &mut *rest_ptr }; self.set_or_create_prop_value(rest, si, ch_val); } } self.regs[rd] = JsValue::from_js_object(rest_ptr); return Ok(()); } // 排除名单常量按单元序列展开(lone surrogate 名保真),0x0000 分隔。 let excluded_const = self .immutables() .get(excluded_idx) .and_then(|v| { if v.is_string() { // SAFETY: v 是字符串常量值。 Some(unsafe { (*v.as_string_ptr()).units().into_owned() }) } else { None } }) .unwrap_or_default(); let mut excluded: std::collections::HashSet = std::collections::HashSet::new(); let mut seg: Vec = Vec::new(); for &u in excluded_const.iter() { if u == 0x0000 { if !seg.is_empty() { excluded.insert(self.string_key_units(&seg)); seg.clear(); } continue; } seg.push(u); } if !seg.is_empty() { excluded.insert(self.string_key_units(&seg)); } // 运行时 excluded:b 槽数组(computed key 求值结果)的元素 ToPropertyKey 后排除。 if b != 0 { let arr_val = self.regs[b]; if arr_val.is_object() { let arr_obj = unsafe { &*arr_val.as_js_object_ptr() }; if arr_obj.is_array() { for i in 0..arr_obj.array_prop_count { let v = arr_obj.get_prop_at(i); let si = self.property_key_si(v)?; excluded.insert(si); } } } } let src_obj = unsafe { &*src.as_js_object_ptr() }; // 收集-提交:先取齐 (键, 值),取值阶段触发 getter(可能抛异常),再统一写 // 目标对象,避免提交写与取值互相交错。只复制可枚举自有属性(CopyDataProperties)。 // 字符串包装对象的索引字符是构造期物化的可枚举自有属性,走同一 walk 路径。 let mut assignments: Vec<(u32, JsValue)> = Vec::new(); // 自身属性:walk_own_keys 已合并数组元素区(hole 跳过)并返回绝对存储索引, // 仅可枚举,跳过 pattern 已绑定的键。 let keys = oxide_builtins::object::walk_own_keys(self, src_obj); for (si, pos) in keys { let enumerable = src_obj .prop_meta_at(pos) .map(|m| m.attributes.enumerable()) .unwrap_or(PropAttributes::DEFAULT_DATA.enumerable()); if !enumerable { continue; } if excluded.contains(&si) { continue; } let val = match self.ordinary_get(src_obj, si, src) { Ok(v) => v, Err(e) => return self.raise_call_error(&e).map(|_| ()), }; assignments.push((si, val)); } // 提交到 rest 对象。 let proto_ptr = self.realm.session.borrow().builtin_world().object_proto.as_ptr() as *mut JsObject; let rest_ptr = self.alloc_object(JsObject::new_empty( oxide_kernel::shape_forge::EMPTY_SHAPE_ID, JsValue::from_js_object(proto_ptr), )); let rest = unsafe { &mut *rest_ptr }; for (si, val) in assignments { self.set_or_create_prop_value(rest, si, val); } self.regs[rd] = JsValue::from_js_object(rest_ptr); Ok(()) } /// SPREAD_OBJECT:对象字面量 `...` 展开,把源的可枚举自有属性写入目标对象(原地改)。 /// /// 语义 = CopyDataProperties 的"非 null/undefined 源"分支:`{...null}` / `{...undefined}` /// 合法(产出空展开),与 REST_OBJECT 对 null/undefined 抛 TypeError 不同。 /// /// # 步骤 /// 1. null/undefined 源直接返回(空展开) /// 2. 字符串源按 UTF-16 code unit 下标复制为可枚举索引属性 /// 3. 对象源先收集可枚举自有属性(数组元素区 + shape 链),取值经 ordinary_get /// 触发访问器 getter,再统一写入目标 /// /// # 边界与前提 /// - 其它原始值(number/boolean/symbol)无自有可枚举属性 → 空展开 /// - 目标已有同名属性被覆盖(后定义/后展开者胜) /// /// # 副作用 /// - 原地修改 rd 指向的对象;取值可能触发 getter 并抛异常(异常传播) pub(crate) fn dispatch_spread_object(&mut self, rd: usize, a: usize) -> Result<(), String> { vm_trace!("SPREAD_OBJECT rd={}", rd); let target_val = self.regs[rd]; let src = self.regs[a]; // null/undefined 源合法:展开为空,直接返回。 if src.is_null() || src.is_undefined() { return Ok(()); } // 字符串源:按单元下标复制(可枚举索引属性,lone surrogate 保真)。 if src.is_string() { let target = unsafe { &mut *target_val.as_js_object_ptr() }; // SAFETY: src 是字符串值。 let code_units: Vec = unsafe { (*src.as_string_ptr()).units().into_owned() }; for (i, unit) in code_units.iter().enumerate() { let si = make_int_key(i as u32); let ch_val = self.unit_char_value(*unit); self.set_or_create_prop_value(target, si, ch_val); } return Ok(()); } // 其它原始值无自有可枚举属性 → 空展开。 if !src.is_object() { return Ok(()); } let src_obj = unsafe { &*src.as_js_object_ptr() }; // 收集-提交:先取齐 (键, 值),取值阶段触发 getter(可能抛异常), // 再统一写目标,避免提交写与取值互相交错。 let mut assignments: Vec<(u32, JsValue)> = Vec::new(); // 自身属性:walk_own_keys 已合并数组元素区(hole 跳过)并返回绝对存储索引, // 仅可枚举;取值经 ordinary_get 触发访问器 getter。 let keys = oxide_builtins::object::walk_own_keys(self, src_obj); for (si, pos) in keys { let enumerable = src_obj .prop_meta_at(pos) .map(|m| m.attributes.enumerable()) .unwrap_or(PropAttributes::DEFAULT_DATA.enumerable()); if !enumerable { continue; } let val = self.ordinary_get(src_obj, si, src)?; assignments.push((si, val)); } // 提交:覆盖目标已有同名属性(从左到右求值,后展开者胜)。 let target = unsafe { &mut *target_val.as_js_object_ptr() }; for (si, val) in assignments { self.set_or_create_prop_value(target, si, val); } Ok(()) } /// GET_TEMPLATE_OBJECT:GetTemplateObject 语义——按 (模块 flat_id, site 序号) /// 查缓存,未命中则构建模板对象(cooked/raw 数组 + raw 属性)并冻结。 /// /// # ext 布局(紧跟指令后的扩展字) /// - `n`:quasis 段数; /// - 每段两个字:cooked 字(高位 `0x8000_0000` 标记非法转义 → undefined, /// 低 31 位为常量池下标)、raw 字(常量池下标); /// - 末尾:site 序号。 /// /// # 副作用 /// - 首次构建时分配 cooked/raw 数组并写入 `template_objects` 缓存(GC 根); /// 缓存命中时零分配。 pub(crate) fn dispatch_get_template_object(&mut self, rd: usize) -> Result<(), String> { vm_trace!("GET_TEMPLATE_OBJECT rd={}", rd); let n = self.bytecode[self.pc] as usize; self.pc += 1; let mut cooked_words = Vec::with_capacity(n); let mut raw_idxs = Vec::with_capacity(n); for _ in 0..n { cooked_words.push(self.bytecode[self.pc]); self.pc += 1; raw_idxs.push(self.bytecode[self.pc]); self.pc += 1; } let site_no = self.bytecode[self.pc]; self.pc += 1; // 键含表代际:跨 run 调用的旧代模块与当前 run 模块 flat_id 重编号, // 无代际维度会误命中他代同 (flat_id, site) 的模板对象。 let key = (self.active_table_gen, self.active_flat_id, site_no); if let Some(&cached) = self.template_objects.get(&key) { self.regs[rd] = cached; return Ok(()); } let proto_ptr = self.realm.session.borrow().builtin_world().array_proto.as_ptr() as *mut JsObject; let proto_val = JsValue::from_js_object(proto_ptr); // 模板对象直接分配为 session 对象:写入 session 根(存进 global/数组) // 时对象地址稳定,缓存指针不失效——分配档不同则首次写入触发搬移, // 缓存旧指针与新实例分叉,同一 site 两次取值将返回不同对象。 let mut alloc_session_array = |n: usize| { let clone = JsObject::new_array(oxide_kernel::shape_forge::EMPTY_SHAPE_ID, proto_val, n); self.alloc_session_object(clone) }; let cooked = alloc_session_array(n); let raw = alloc_session_array(n); let cooked_val = JsValue::from_js_object(cooked); let raw_val = JsValue::from_js_object(raw); // 元素:可枚举、不可写、不可配置(模板对象属性恒只读,禁止改写元素)。 let elem_attrs = PropAttributes::new(false, true, false); for i in 0..n { let (c_val, r_val) = { // immutables 借用限于本块:先取出本段两值,再放行借用。 let imm = self.immutables(); let c_val = if cooked_words[i] & 0x8000_0000 != 0 { JsValue::undefined() } else { imm.get(cooked_words[i] as usize).copied().unwrap_or(JsValue::undefined()) }; let r_val = imm.get(raw_idxs[i] as usize).copied().unwrap_or(JsValue::undefined()); (c_val, r_val) }; // SAFETY: cooked/raw 为本函数刚分配的 epoch 对象,借用仅在本循环内消费。 unsafe { (*cooked).set_prop_at(i, c_val); (*cooked).set_data_meta(i, elem_attrs); (*raw).set_prop_at(i, r_val); (*raw).set_data_meta(i, elem_attrs); } } // raw 属性:不可枚举、不可写、不可配置(规范 desc 无 writable/enumerable // 键,DefinePropertyOrThrow 默认 false)。先于冻结定义(冻结后不可扩展, // 新增属性会被拒)。 let raw_si = self.kernel_core.perm_interner().intern("raw").0; // SAFETY: cooked 为本函数分配的 epoch 对象,借用仅在本次 define 内消费。 self.define_data_property(unsafe { &mut *cooked }, raw_si, raw_val, PropAttributes::new(false, false, false))?; // 冻结两个数组:不可扩展 + length writable=false(is_frozen 使 length // 赋值与元素写入经 ordinary_set 拒绝);length {e:false,w:false,c:false} // 由 getOwnPropertyDescriptor 的数组 length 特判表达。 // SAFETY: cooked/raw 为本函数分配的 session 对象。 unsafe { (*cooked).set_frozen(true); (*cooked).set_extensible(false); (*raw).set_frozen(true); (*raw).set_extensible(false); } self.template_objects.insert(key, cooked_val); self.regs[rd] = cooked_val; Ok(()) } } #[cfg(test)] mod tests { use super::*; use std::sync::Arc; use oxide_bytecode::module::CompiledModule; use oxide_bytecode::opcode; use crate::vm_state::ForOfEntry; use crate::vm_support::FunctionFlags; #[test] fn for_of_close_pops_iterator_stack() { let module = CompiledModule { bytecode: Arc::from(vec![ opcode::encode(opcode::OpCode::FOR_OF_CLOSE, 0, 0, 0), opcode::encode(opcode::OpCode::HALT, 0, 0, 0), ]), n_registers: 1, ..CompiledModule::new() }; let mut vm = Vm::new(); vm.iters.for_of_iters.push(ForOfEntry { iterator: JsValue::undefined(), last_result: JsValue::undefined(), is_async: false, fast: None, fast_value: JsValue::undefined(), fast_inner: JsValue::undefined(), fast_cursor: 0, }); vm.run(&Arc::new(module)) .expect("FOR_OF_CLOSE should tolerate non-object sentinel"); assert!(vm.iters.for_of_iters.is_empty()); } #[test] fn dispatch_new_expression_param_overlap_reads_spill_first() { // NEW 收敛路径同款重叠几何(实参源 regs[1..3) 与 callee 形参写入区 regs[2..4) // 重叠,first < param_base):经 NEW_EXPRESSION 入口压帧,形参与 spill 实参区 // (arguments 对象源)必须取原始实参值,不得先写后读串值。 let mut vm = Vm::new(); // sub_modules[1] = 构造器:2 个形参,param_base=2(与调用方实参槽 2 重叠) let mut ctor_mod = CompiledModule::new(); ctor_mod.n_args = 2; ctor_mod.param_base = 2; ctor_mod.n_registers = 5; ctor_mod.bytecode = Arc::from(vec![opcode::encode(opcode::OpCode::RETURN, 0, 0, 0)]); vm.install_module_table_for_test(Arc::new(vec![Arc::new(CompiledModule::new()), Arc::new(ctor_mod)])); vm.active_reg_limit = 8; // NEW_EXPRESSION 指令:ext 低 8 位 = 实参个数 2,高 8 位 = 窗口 0(全量) vm.bytecode = Arc::from(vec![opcode::encode(opcode::OpCode::NEW_EXPRESSION, 0, 0, 0), 2]); vm.pc = 0; // 调用方实参区 regs[1..3):arg0=10, arg1=20;regs[2] 同时是 callee 形参槽(param_base=2) vm.regs[1] = JsValue::int(10); vm.regs[2] = JsValue::int(20); vm.regs[5] = vm.create_function_object(1, vm.current_gen, FunctionFlags::none()); vm.dispatch_new_expression(0, 5, 1).expect("NEW 压帧成功"); let frame = vm.frames.last().expect("压帧后应有帧"); // 形参从 spill 实参区取源:regs[2]=arg0=10,regs[3]=arg1=20(不得被先写覆盖) assert_eq!(vm.regs[2], JsValue::int(10), "形参 a 应为实参 arg0"); assert_eq!(vm.regs[3], JsValue::int(20), "形参 b 应为实参 arg1(不受先写覆盖)"); // spill 实参区(arguments 对象源)保持原实参值 let base = frame.arguments_base as usize; assert_eq!(vm.spill_stack[base], JsValue::int(10), "spill 实参区 arg0"); assert_eq!(vm.spill_stack[base + 1], JsValue::int(20), "spill 实参区 arg1"); // NEW 帧契约:构造结果寄存器与 constructed_this 随帧携带 assert_eq!(frame.construct_result_reg, Some(0), "构造结果写回 regs[0]"); assert!( frame.has_constructed_this && frame.constructed_this.is_object(), "基类构造路径 constructed_this 应为新对象" ); assert!(!frame.is_derived_constructor, "普通函数非 derived 构造器"); } }