diff --git a/crates/oxide_bytecode/src/module.rs b/crates/oxide_bytecode/src/module.rs index 892d9552..7d547676 100644 --- a/crates/oxide_bytecode/src/module.rs +++ b/crates/oxide_bytecode/src/module.rs @@ -2,7 +2,9 @@ //! //! [`CompiledModule`] 是编译器输出的字节码函数单元:指令序列、常量池、 //! 寄存器布局元信息、子函数(嵌套函数)与 upvalue 捕获描述;随 VM 解释执行 -//! 或由其它模块克隆复制。`Display` 输出可读的反汇编文本,供调试用。 +//! 或由其它模块克隆复制。`Display` 输出可读的反汇编文本,供调试用: +//! 扩展字并入其指令行不单独成行,offset 列为字序号(与 VM 的 pc 同单位), +//! 子模块(嵌套函数体)递归渲染。 use std::fmt; use std::sync::Arc; @@ -151,39 +153,271 @@ impl Clone for CompiledModule { impl fmt::Display for CompiledModule { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!(f, "; n_registers = {}", self.n_registers)?; - writeln!(f, "; constants:")?; - for (i, c) in self.constants.iter().enumerate() { - writeln!(f, "; [{i}] = {c:?}")?; + Self::render(f, self, 0, None) + } +} + +impl CompiledModule { + /// 渲染一个模块单元:头部元信息 + 指令行 + 递归子模块。 + /// + /// `depth` 控制指令行缩进(顶层 0,每层 +2 空格);`sub_index` 为子模块序号 + /// (顶层 None)。指令行按 `1 + ext_word_count` 推进 offset,扩展字并入其 + /// 指令行,不单独成行;offset 列即字序号(与 VM 的 pc 同单位)。 + fn render( + f: &mut fmt::Formatter<'_>, module: &CompiledModule, depth: usize, sub_index: Option, + ) -> fmt::Result { + // 子模块头:序号 + 全局 flat_id + 函数名(嵌套函数体调试入口)。 + if let Some(i) = sub_index { + let name = module.function_name.as_deref().unwrap_or(""); + writeln!(f, "\n; sub_module[{i}] (flat_id={flat_id}, \"{name}\"):", flat_id = module.flat_id)?; + } + // 头部元信息(顶层 2 空格缩进,子模块 4 空格)。 + let p1 = if depth == 0 { "; " } else { "; " }; + let p2 = if depth == 0 { "; " } else { "; " }; + writeln!(f, "{p1}n_registers = {}", module.n_registers)?; + writeln!(f, "{p1}constants:")?; + for (i, c) in module.constants.iter().enumerate() { + writeln!(f, "{p2}[{i}] = {c:?}")?; } writeln!(f)?; - writeln!(f, "; upvalue_captures: {:?}", self.upvalue_captures)?; + writeln!(f, "{p1}upvalue_captures: {:?}", module.upvalue_captures)?; writeln!(f)?; - for (offset, &instr) in self.bytecode.iter().enumerate() { + // 指令行:逐指令按 ext 字数推进,扩展字并入本行。 + let indent = " ".repeat(depth + 1); + let mut offset = 0usize; + while offset < module.bytecode.len() { + let instr = module.bytecode[offset]; let op = opcode::opcode(instr); - let rd = opcode::rd(instr); - let a = opcode::a(instr); - let b = opcode::b(instr); - write!(f, " {offset:04} {op}")?; - match op { - OpCode::LOAD_CONST => { - write!(f, " r{rd}, const[{}]", opcode::imm16(instr))?; - } - OpCode::JMP | OpCode::JMP_IF_FALSE | OpCode::JMP_IF_TRUE => { - write!(f, " r{rd}, {offset:+}", offset = opcode::offset16(instr))?; - } - OpCode::RETURN | OpCode::HALT | OpCode::NOP => { - write!(f, " r{rd}")?; - } - OpCode::NEG => { - write!(f, " r{rd}, r{a}")?; - } - _ => { - write!(f, " r{rd}, r{a}, r{b}")?; - } - } + write!(f, "{indent}{offset:04} {op}")?; + render_operands(f, op, instr, &module.bytecode, offset)?; writeln!(f)?; + offset += 1 + opcode::ext_word_count(&module.bytecode, offset); + } + // 递归渲染子模块(嵌套函数体)。 + for (i, sub) in module.sub_modules.iter().enumerate() { + Self::render(f, sub, depth + 1, Some(i))?; } Ok(()) } } + +/// 指令操作数渲染:按 opcode 语义把 rd/a/b/imm16/ext 字渲染为可读文本。 +/// +/// 常量池下标族渲染 `const[N]`,upvalue 下标族 `uv[N]`,闭包模块下标 +/// `module[N]`,跳转族渲染相对偏移(单位 = 指令字,含 ext 字);ext 字并入 +/// 本行。ext 字越界回退 0(Display 面不 panic)。 +fn render_operands( + f: &mut fmt::Formatter<'_>, op: OpCode, instr: opcode::Instr, bytecode: &[opcode::Instr], offset: usize, +) -> fmt::Result { + let rd = opcode::rd(instr); + let a = opcode::a(instr); + let b = opcode::b(instr); + // ext 字安全读取(越界回退 0)。 + let ext = |i: usize| bytecode.get(offset + 1 + i).copied().unwrap_or(0); + match op { + // 跳转族:offset16 相对偏移(单位 = 指令字,含 ext 字)。 + OpCode::JMP | OpCode::TRY_BEGIN | OpCode::TRY_FINALLY_BEGIN => { + write!(f, " +{} (rel)", opcode::offset16(instr)) + } + OpCode::JMP_IF_FALSE | OpCode::JMP_IF_TRUE | OpCode::JMP_IF_NULLISH | OpCode::BREAK | OpCode::CONTINUE => { + write!(f, " r{rd}, +{} (rel)", opcode::offset16(instr)) + } + // imm16 常量池/下标族。 + OpCode::LOAD_CONST | OpCode::LOAD_GLOBAL | OpCode::LOAD_GLOBAL_TYPEOF => { + write!(f, " r{rd}, const[{}]", opcode::imm16(instr)) + } + OpCode::LOAD_UPVALUE => write!(f, " r{rd}, uv[{}]", opcode::imm16(instr)), + OpCode::CREATE_CLOSURE => write!(f, " r{rd}, module[{}]", opcode::imm16(instr)), + OpCode::STORE_UPVALUE => write!(f, " r{a}, uv[{b}]"), + // 单 ext 字族。 + OpCode::SPILL | OpCode::UNSPILL => write!(f, " r{rd}, slot[{}]", ext(0)), + OpCode::CALL | OpCode::CALL_NATIVE | OpCode::NEW_EXPRESSION => { + write!(f, " r{rd}, r{a}, r{b}, nargs={}", ext(0) & 0xFF) + } + OpCode::SUPER_CALL => write!(f, " r{rd}, r{a}, nargs={}", ext(0) & 0xFF), + OpCode::DEFINE_ACCESSOR => write!(f, " r{rd}, r{a}, r{b}, const[{}]", ext(0)), + OpCode::DEFINE_ACCESSOR_DYNAMIC => write!(f, " r{rd}, r{a}, r{b}, key=r{}", ext(0) & 0x7FFF_FFFF), + OpCode::DEFINE_PROP_ATTRS => write!(f, " r{rd}, r{a}, r{b}, attrs={:#x}", ext(0)), + OpCode::DEFINE_GLOBAL_PROP_C | OpCode::DEFINE_GLOBAL_PROP_C_IF_ABSENT => { + write!(f, " r{a}, const[{}]", ext(0)) + } + OpCode::DELETE_GLOBAL_PROP_C => write!(f, " r{rd}, r{a}, const[{}]", ext(0)), + OpCode::DELETE_PROP_STATIC => write!(f, " r{rd}, r{a}, const[{}]", ext(0)), + OpCode::REST_OBJECT => write!(f, " r{rd}, r{a}, r{b}, excl=const[{}]", ext(0)), + OpCode::INIT_PRIVATE => write!(f, " r{rd}, r{a}, r{b}, method={}", ext(0)), + // 双 ext 字族。 + OpCode::DEFINE_ACCESSOR_ATTRS => { + write!(f, " r{rd}, r{a}, r{b}, const[{}], attrs={:#x}", ext(0), ext(1)) + } + OpCode::DEFINE_ACCESSOR_ATTRS_DYNAMIC => { + write!(f, " r{rd}, r{a}, r{b}, key=r{}, attrs={:#x}", ext(0) & 0x7FFF_FFFF, ext(1)) + } + OpCode::GET_PRIVATE | OpCode::SET_PRIVATE | OpCode::PRIVATE_BRAND_IN => { + write!(f, " r{rd}, r{a}, r{b}, brand=r{}, id={}", ext(0), ext(1)) + } + // IC 族:8 个多态槽扩展字。 + _ if op.has_ic_ext_words() => write!(f, " r{rd}, r{a}, r{b}, ic x{}", opcode::IC_EXT_WORDS), + // 变长 ext 族。 + OpCode::CALL_SPREAD | OpCode::NEW_EXPRESSION_SPREAD | OpCode::SUPER_CALL_SPREAD => { + // 首字 = nstatic | (nspread<<8);实参字:静态 = 寄存器号,spread 源带高位标记。 + let header = ext(0); + let n = ((header & 0xFF) + ((header >> 8) & 0xFF)) as usize; + write!(f, " r{rd}, r{a}, r{b}, args=[")?; + for i in 0..n { + if i > 0 { + write!(f, ", ")?; + } + let w = ext(i + 1); + if w & 0x8000_0000 != 0 { + write!(f, "...r{}", w & 0x7FFF_FFFF)?; + } else { + write!(f, "r{}", w)?; + } + } + write!(f, "]") + } + OpCode::TEMPLATE_STR => { + // 首字 = (segment_count<<16) | len_hint;段字:高位标记 = 表达式寄存器, + // 否则常量池下标。 + let header = ext(0); + let n = ((header >> 16) & 0xFFFF) as usize; + write!(f, " r{rd}, segs=[")?; + for i in 0..n { + if i > 0 { + write!(f, ", ")?; + } + let w = ext(i + 1); + if w & 0x8000_0000 != 0 { + write!(f, "r{}", w & 0x7FFF_FFFF)?; + } else { + write!(f, "c{}", w & 0x7FFF_FFFF)?; + } + } + write!(f, "]") + } + OpCode::GET_TEMPLATE_OBJECT => { + // ext[0]=quasis 段数 n,随后 2n 个交错 cooked/raw 字,末尾 site 序号。 + let n = ext(0) as usize; + write!(f, " r{rd}, {n} quasis, site={}", ext(1 + 2 * n)) + } + OpCode::CONCAT_N => { + // ext[0]=n=操作数总数,其余 n-1 字为操作数寄存器。 + let n = ext(0) as usize; + write!(f, " r{rd}, r{a}, ops=[")?; + for i in 0..n.saturating_sub(1) { + if i > 0 { + write!(f, ", ")?; + } + write!(f, "r{}", ext(i + 1) & 0x7FFF_FFFF)?; + } + write!(f, "]") + } + OpCode::NEW_OBJECT => { + // a 槽 = 属性数,ext = 每键常量池下标。 + let n = a as usize; + write!(f, " r{rd}, {n} keys [")?; + for i in 0..n { + if i > 0 { + write!(f, ", ")?; + } + write!(f, "const[{}]", ext(i))?; + } + write!(f, "]") + } + // 单操作数族。 + OpCode::NEG => write!(f, " r{rd}, r{a}"), + OpCode::RETURN | OpCode::HALT | OpCode::NOP => write!(f, " r{rd}"), + _ => write!(f, " r{rd}, r{a}, r{b}"), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// 手工构造反汇编夹具:顶层 5 条指令(NEW_OBJECT 1 字键表、CALL 1 ext 字、 + /// IC_GET_PROP 8 ext 字),子模块 1 个(3 条指令,RETURN 带 1 个逃出计数 ext 字)。 + fn fixture() -> CompiledModule { + let sub = CompiledModule { + function_name: Some("f".into()), + flat_id: 1, + n_registers: 2, + constants: vec![Constant::Int(42)], + bytecode: Arc::from([ + opcode::encode(OpCode::LOAD_CONST, 1, 0, 0), + opcode::encode(OpCode::RETURN, 1, 0, 0), + 0, // RETURN 逃出计数 ext 字 + opcode::encode(OpCode::HALT, 0, 0, 0), + ]), + ..Default::default() + }; + let mut m = CompiledModule::new(); + m.n_registers = 4; + m.constants = vec![Constant::Int(1), Constant::String("a".into())]; + m.bytecode = Arc::from([ + opcode::encode(OpCode::LOAD_CONST, 1, 0, 0), + opcode::encode(OpCode::NEW_OBJECT, 2, 1, 0), + 1, // NEW_OBJECT 键表:const[1] + opcode::encode(OpCode::CALL, 3, 0, 1), + 1, // CALL ext:nargs=1 + opcode::encode(OpCode::IC_GET_PROP, 0, 2, 3), + 0xAAAA_AAAA, + 0xBBBB_BBBB, + 0xCCCC_CCCC, + 0xDDDD_DDDD, + 0xEEEE_EEEE, + 0xFFFF_FFFF, + 0x1111_1111, + 0x2222_2222, + opcode::encode(OpCode::HALT, 0, 0, 0), + ]); + m.sub_modules = vec![Arc::new(sub)]; + m + } + + #[test] + fn disassembly_ext_words_merge_into_instruction_lines() { + let text = fixture().to_string(); + let lines: Vec<&str> = text.lines().collect(); + // 指令行数 = 真实指令数(顶层 5 + 子模块 3),ext 字不单独成行。 + let instr_lines = lines + .iter() + .filter(|l| l.trim_start().chars().next().is_some_and(|c| c.is_ascii_digit())); + assert_eq!(instr_lines.count(), 8, "指令行数 = 真实指令数\n{text}"); + // 逐行形态:offset 列 = 字序号(与 VM pc 同单位),操作数按语义渲染。 + let expected = [ + " 0000 LOAD_CONST r1, const[0]", + " 0001 NEW_OBJECT r2, 1 keys [const[1]]", + " 0003 CALL r3, r0, r1, nargs=1", + " 0005 IC_GET_PROP r0, r2, r3, ic x8", + " 0014 HALT r0", + " 0000 LOAD_CONST r1, const[0]", + " 0001 RETURN r1", + " 0003 HALT r0", + ]; + for line in &expected { + assert!(lines.contains(line), "missing line: {line}\n{text}"); + } + // 子模块头:序号 + flat_id + 函数名。 + assert!(lines.contains(&"; sub_module[0] (flat_id=1, \"f\"):")); + } + + #[test] + fn disassembly_imm16_and_ext_operand_rendering() { + let mut m = CompiledModule::new(); + m.constants = vec![Constant::String("x".into())]; + m.bytecode = Arc::from([ + opcode::encode(OpCode::LOAD_GLOBAL, 1, 0, 0), + opcode::encode(OpCode::CREATE_CLOSURE, 2, 0, 0), + opcode::encode(OpCode::DEFINE_GLOBAL_PROP_C, 0, 1, 0), + 3, // ext:键常量池下标 + opcode::encode(OpCode::JMP_IF_FALSE, 1, 12, 0), + ]); + let text = m.to_string(); + let lines: Vec<&str> = text.lines().collect(); + assert!(lines.contains(&" 0000 LOAD_GLOBAL r1, const[0]")); + assert!(lines.contains(&" 0001 CREATE_CLOSURE r2, module[0]")); + assert!(lines.contains(&" 0002 DEFINE_GLOBAL_PROP_C r1, const[3]")); + assert!(lines.contains(&" 0004 JMP_IF_FALSE r1, +12 (rel)")); + } +} diff --git a/crates/oxide_bytecode/src/opcode.rs b/crates/oxide_bytecode/src/opcode.rs index 9f215ab6..f055e754 100644 --- a/crates/oxide_bytecode/src/opcode.rs +++ b/crates/oxide_bytecode/src/opcode.rs @@ -773,6 +773,64 @@ pub fn offset16(instr: Instr) -> i16 { ((instr >> 16) & 0xFFFF) as i16 } +/// 计算 `pc` 处指令之后的扩展字个数(按 opcode 语义推进,逐指令字节序一致)。 +/// +/// 定长族返回固定字数;变长族依指令内容:spread 调用从首字读 nstatic|nspread、 +/// TEMPLATE_STR 从首字读 segment_count、GET_TEMPLATE_OBJECT 从首字读 quasis 段数、 +/// CONCAT_N 从首字读操作数总数、NEW_OBJECT 从 a 槽读属性数(键表)。 +/// 反汇编 Display 与 IC 清零扫描共用此表,任何新增变长 ext opcode 必须在此登记。 +pub fn ext_word_count(bytecode: &[Instr], pc: usize) -> usize { + let op = opcode(bytecode[pc]); + // IC 系固定 IC_EXT_WORDS 扩展字(多态槽组)。 + if op.has_ic_ext_words() { + return IC_EXT_WORDS; + } + match op { + OpCode::SPILL + | OpCode::UNSPILL + | OpCode::CALL + | OpCode::CALL_NATIVE + | OpCode::NEW_EXPRESSION + | OpCode::SUPER_CALL + | OpCode::DEFINE_ACCESSOR + | OpCode::DEFINE_ACCESSOR_DYNAMIC + | OpCode::DEFINE_PROP_ATTRS + | OpCode::DEFINE_GLOBAL_PROP_C + | OpCode::DEFINE_GLOBAL_PROP_C_IF_ABSENT + | OpCode::DELETE_GLOBAL_PROP_C + | OpCode::DELETE_PROP_STATIC + | OpCode::REST_OBJECT + | OpCode::INIT_PRIVATE => 1, + OpCode::DEFINE_ACCESSOR_ATTRS + | OpCode::DEFINE_ACCESSOR_ATTRS_DYNAMIC + | OpCode::GET_PRIVATE + | OpCode::SET_PRIVATE + | OpCode::PRIVATE_BRAND_IN => 2, + // 逃出计数 ext:BREAK/CONTINUE/RETURN 恒带 1 个 pack_escape_counts 字 + // (for-of/for-in 逃出层数打包);lower 对这三条无条件落 ext 字, + // dispatch 经 read_escape_counts 消费,扫描必须同步跳过以免错位。 + OpCode::BREAK | OpCode::CONTINUE | OpCode::RETURN => 1, + OpCode::CALL_SPREAD | OpCode::NEW_EXPRESSION_SPREAD | OpCode::SUPER_CALL_SPREAD => { + let header = bytecode.get(pc + 1).copied().unwrap_or(0); + 1 + (header & 0xFF) as usize + ((header >> 8) & 0xFF) as usize + } + OpCode::TEMPLATE_STR => { + let header = bytecode.get(pc + 1).copied().unwrap_or(0); + 1 + ((header >> 16) & 0xFFFF) as usize + } + // GET_TEMPLATE_OBJECT:ext[0]=quasis 段数 n,随后 2n 个交错 cooked/raw 字, + // 末尾 1 个 site 序号——总 ext 字数 = 2+2n,与 dispatch 逐字消费一致。 + OpCode::GET_TEMPLATE_OBJECT => { + let n = bytecode.get(pc + 1).copied().unwrap_or(0) as usize; + 2 + 2 * n + } + // CONCAT_N:ext[0]=n=操作数总数,ext 字数 = 1+(n-1) = n。 + OpCode::CONCAT_N => bytecode.get(pc + 1).copied().unwrap_or(0) as usize, + OpCode::NEW_OBJECT => a(bytecode[pc]) as usize, + _ => 0, + } +} + /// 发射无条件跳转指令(`JMP`,偏移以 16 位补码编码)。 pub fn encode_jmp(offset: i16) -> Instr { let lo = (offset as u16 & 0xFF) as u8; @@ -889,4 +947,27 @@ mod tests { let tbl: Vec = all_opcodes().filter(|op| op.has_ic_ext_words()).map(|op| op as u8).collect(); assert_eq!(tbl, legacy); } + + /// ext 字数表与 dispatch 逐字消费布局对齐(定长族 / 双字族 / 变长族)。 + #[test] + fn ext_word_count_matches_dispatch_layout() { + // IC 族固定 8 字。 + let ic = [encode(OpCode::IC_GET_PROP, 0, 0, 0); IC_EXT_WORDS + 1]; + assert_eq!(ext_word_count(&ic, 0), IC_EXT_WORDS); + // 1 字族(含 BREAK/CONTINUE/RETURN 逃出计数)。 + assert_eq!(ext_word_count(&[encode(OpCode::CALL, 0, 0, 0), 3], 0), 1); + assert_eq!(ext_word_count(&[encode(OpCode::BREAK, 0, 0, 0), 1], 0), 1); + assert_eq!(ext_word_count(&[encode(OpCode::RETURN, 0, 0, 0), 1], 0), 1); + // 2 字族。 + assert_eq!(ext_word_count(&[encode(OpCode::GET_PRIVATE, 0, 0, 0), 1, 2], 0), 2); + // 变长族:spread 首字 nstatic|nspread、TEMPLATE_STR 段数、GET_TEMPLATE_OBJECT 2+2n、 + // CONCAT_N=n、NEW_OBJECT=a 槽属性数。 + assert_eq!(ext_word_count(&[encode(OpCode::CALL_SPREAD, 0, 0, 0), 0x0201, 5, 6, 7], 0), 4); + assert_eq!(ext_word_count(&[encode(OpCode::TEMPLATE_STR, 0, 0, 0), 0x0002_0000, 1, 2], 0), 3); + assert_eq!(ext_word_count(&[encode(OpCode::GET_TEMPLATE_OBJECT, 0, 0, 0), 1, 2, 3, 4], 0), 4); + assert_eq!(ext_word_count(&[encode(OpCode::CONCAT_N, 0, 0, 0), 3, 1, 2], 0), 3); + assert_eq!(ext_word_count(&[encode(OpCode::NEW_OBJECT, 0, 2, 0), 7, 8], 0), 2); + // 无 ext 字。 + assert_eq!(ext_word_count(&[encode(OpCode::ADD, 0, 0, 0)], 0), 0); + } } diff --git a/crates/oxide_vm/src/ic_helper.rs b/crates/oxide_vm/src/ic_helper.rs index 82ad7b3a..aa74bb24 100644 --- a/crates/oxide_vm/src/ic_helper.rs +++ b/crates/oxide_vm/src/ic_helper.rs @@ -14,7 +14,7 @@ //! - 命中路径零写:只读扩展字 + Cell 计数,不触发 bytecode COW。 use crate::vm_trace; -use oxide_bytecode::opcode::{self, Instr, OpCode, IC_EXT_WORDS, IC_SLOTS}; +use oxide_bytecode::opcode::{self, ext_word_count, Instr, IC_EXT_WORDS, IC_SLOTS}; use oxide_types::object::JsObject; use oxide_types::value::JsValue; @@ -45,63 +45,6 @@ pub(crate) fn write_ic_back(bytecode: &mut [Instr], pc: usize, shape_id: u32, sl bytecode[base..pc].copy_from_slice(&new_words); } -/// 计算 `pc` 处指令之后的扩展字个数(按 opcode 语义推进,逐指令字节序一致)。 -/// -/// 定长族返回固定字数;变长族依指令内容:spread 调用从首字读 nstatic|nspread、 -/// TEMPLATE_STR 从首字读 segment_count、NEW_OBJECT 从 a 槽读属性数(键表)。 -/// `clear_ic_caches` 依赖此函数逐指令定位,任何新增变长 ext opcode 必须在此登记。 -fn ext_word_count(bytecode: &[Instr], pc: usize) -> usize { - let op = opcode::opcode(bytecode[pc]); - // IC 系固定 IC_EXT_WORDS 扩展字(多态槽组)。 - if op.has_ic_ext_words() { - return IC_EXT_WORDS; - } - match op { - OpCode::SPILL - | OpCode::UNSPILL - | OpCode::CALL - | OpCode::CALL_NATIVE - | OpCode::NEW_EXPRESSION - | OpCode::SUPER_CALL - | OpCode::DEFINE_ACCESSOR - | OpCode::DEFINE_ACCESSOR_DYNAMIC - | OpCode::DEFINE_PROP_ATTRS - | OpCode::DEFINE_GLOBAL_PROP_C - | OpCode::DEFINE_GLOBAL_PROP_C_IF_ABSENT - | OpCode::DELETE_GLOBAL_PROP_C - | OpCode::DELETE_PROP_STATIC - | OpCode::REST_OBJECT - | OpCode::INIT_PRIVATE => 1, - OpCode::DEFINE_ACCESSOR_ATTRS - | OpCode::DEFINE_ACCESSOR_ATTRS_DYNAMIC - | OpCode::GET_PRIVATE - | OpCode::SET_PRIVATE - | OpCode::PRIVATE_BRAND_IN => 2, - // 逃出计数 ext:BREAK/CONTINUE/RETURN 恒带 1 个 pack_escape_counts 字 - // (for-of/for-in 逃出层数打包);lower 对这三条无条件落 ext 字, - // dispatch 经 read_escape_counts 消费,扫描必须同步跳过以免错位。 - OpCode::BREAK | OpCode::CONTINUE | OpCode::RETURN => 1, - OpCode::CALL_SPREAD | OpCode::NEW_EXPRESSION_SPREAD | OpCode::SUPER_CALL_SPREAD => { - let header = bytecode.get(pc + 1).copied().unwrap_or(0); - 1 + (header & 0xFF) as usize + ((header >> 8) & 0xFF) as usize - } - OpCode::TEMPLATE_STR => { - let header = bytecode.get(pc + 1).copied().unwrap_or(0); - 1 + ((header >> 16) & 0xFFFF) as usize - } - // GET_TEMPLATE_OBJECT:ext[0]=quasis 段数 n,随后 2n 个交错 cooked/raw 字, - // 末尾 1 个 site 序号——总 ext 字数 = 2+2n,与 dispatch 逐字消费一致。 - OpCode::GET_TEMPLATE_OBJECT => { - let n = bytecode.get(pc + 1).copied().unwrap_or(0) as usize; - 2 + 2 * n - } - // CONCAT_N:ext[0]=n=操作数总数,ext 字数 = 1+(n-1) = n。 - OpCode::CONCAT_N => bytecode.get(pc + 1).copied().unwrap_or(0) as usize, - OpCode::NEW_OBJECT => opcode::a(bytecode[pc]) as usize, - _ => 0, - } -} - /// 把流中所有 IC 扩展字清零,使全部缓存 shape 失效。 /// /// 逐指令按 opcode 的 ext 字数推进,避开变长 ext opcode(CALL_SPREAD/TEMPLATE_STR/ @@ -310,6 +253,7 @@ fn ic_set_hit_own_poly(obj: &mut JsObject, bytecode: &[Instr], ext_pc: usize, va #[cfg(test)] mod tests { use super::*; + use oxide_bytecode::opcode::OpCode; #[test] fn concat_n_ext_word_count_advances_by_n() {