From 9a2579fe9cff4b62f2a40528a08c8ce74351aad5 Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Sat, 22 Aug 2026 11:30:03 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20GET=5FTEMPLATE=5FOBJECT=20=E6=BC=8F?= =?UTF-8?q?=E7=99=BB=20ext=5Fword=5Fcount=E2=80=94=E2=80=94ic=20=E7=BC=93?= =?UTF-8?q?=E5=AD=98=E6=89=AB=E6=8F=8F=E9=94=99=E4=BD=8D=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_vm/src/ic_helper.rs | 38 ++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/crates/oxide_vm/src/ic_helper.rs b/crates/oxide_vm/src/ic_helper.rs index 94058ba4..d59c1777 100644 --- a/crates/oxide_vm/src/ic_helper.rs +++ b/crates/oxide_vm/src/ic_helper.rs @@ -82,6 +82,12 @@ fn ext_word_count(bytecode: &[Instr], pc: usize) -> usize { 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, @@ -324,6 +330,38 @@ mod tests { assert_eq!(ext_word_count(&bytecode, 2), 1, "RETURN ext 字数 = 1"); } + #[test] + fn get_template_object_ext_word_count_is_2_plus_2n() { + // GET_TEMPLATE_OBJECT:ext=[n, cooked, raw, ..., site_no] 共 2+2n 个扩展字 + // (n=1 时 4 个字)。未登记时 clear_ic_caches 会把 ext 字当指令逐字扫描, + // 多跳/误清零导致后续 IC 扩展字漏清或误清,本用例可抓住该错位。 + let mut bytecode = vec![ + opcode::encode(OpCode::GET_TEMPLATE_OBJECT, 1, 0, 0), + 1, + 0x8000_0000, + 0x0000_0005, + 0x0000_0007, + opcode::encode(OpCode::IC_GET_PROP, 1, 2, 3), + 0xAAAA_AAAA, + 0xBBBB_BBBB, + 0xCCCC_CCCC, + 0xDDDD_DDDD, + 0xEEEE_EEEE, + 0xFFFF_FFFF, + 0x1111_1111, + 0x2222_2222, + ]; + assert_eq!(ext_word_count(&bytecode, 0), 4, "GET_TEMPLATE_OBJECT ext 字数 = 2+2n"); + + clear_ic_caches(&mut bytecode); + assert_eq!( + &bytecode[1..=4], + &[1, 0x8000_0000, 0x0000_0005, 0x0000_0007], + "GET_TEMPLATE_OBJECT ext 字保持原值" + ); + assert_eq!(&bytecode[6..=13], &[0; 8], "后续 IC 扩展字被清零"); + } + #[test] fn clear_ic_caches_skips_break_ext_word() { // BREAK 的逃出计数 ext 字必须原样保留;其低 8 位 = for_of_count,取 0x40