perf: CONCAT_N 多操作数拼接单趟精确预分配替代逐次 ADD

新增 CONCAT_N opcode(0x93):连续加号左结合链摊平为单条指令,
字符串模式单趟精确总长预分配,消除 N-2 次中间串分配与逐次整串重拷贝。

- emit 只下钻 left 链、right 括号不拆(a+(b+c) 退化 ADD),求值序与
  f64 结合性保持左结合原义;摊平上限 14 防超长链寄存器压力
- dispatch 两阶段:数值前缀逐项复用 ADD 判定序列(int 溢出升 double、
  BigInt 混合 TypeError、对象 ToPrimitive 副作用序),遇字符串转入
  字符串模式单趟预分配拼接(concat_n_strings)
- RegAlloc graph/rewrite 登记 CONCAT_N ext 操作数(漏收集即错值);
  ic_helper ext_word_count 登记(clear_ic_caches 字节定位)
- contract golden 显式 CONCAT_N 分支(规避 canonical_inst _ 兜底)
This commit is contained in:
2026-08-15 09:08:05 +08:00
parent aa4c28cdf0
commit 38a4f20743
10 changed files with 423 additions and 0 deletions
+3
View File
@@ -556,6 +556,7 @@ mod tests {
Inst::compound_member_ushr(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3))
}
OpCode::TEMPLATE_STR => Inst::template_str(Operand::Reg(1), 2, 10, &[0x1234, 0x8000_0000 | 5]),
OpCode::CONCAT_N => Inst::concat_n(Operand::Reg(1), &[2, 5, 9]),
OpCode::GET_PRIVATE => {
Inst::get_private(Operand::Reg(1), Operand::Reg(2), Operand::Reg(3), 7, 99)
}
@@ -723,6 +724,8 @@ mod tests {
assert_contract(OpCode::HALT, None, &[0], false);
// 模板字符串:表达式寄存器来自 ext
assert_contract(OpCode::TEMPLATE_STR, Some(1), &[5], true);
// 多操作数拼接:a 槽首操作数 + ext[1..] 后续操作数(SpreadArgs 解析)
assert_contract(OpCode::CONCAT_N, Some(1), &[2, 5, 9], true);
// 小语言特性
assert_contract(OpCode::DELETE_PROP_STATIC, None, &[1], false);
assert_contract(OpCode::DELETE_PROP_DYNAMIC, None, &[1, 3], false);
+28
View File
@@ -258,6 +258,23 @@ impl Inst {
Self::new(OpCode::SET_PROP_BATCH, target, value, Operand::Imm(slot))
}
/// 多操作数拼接(连续 `+` 表达式摊平):rd=结果,首操作数放 a 槽,
/// ext=[n, op2..opn](n=操作数总数,ext 字数 = 1+(n-1) = n)。
/// 操作数按源码求值序排列,emit 层保证 ≥3 个(<3 退化 ADD);op 字无高位标记。
pub fn concat_n(dst: Operand, operands: &[u32]) -> Self {
debug_assert!(operands.len() >= 3, "CONCAT_N 仅用于 ≥3 操作数摊平");
let mut ext = SmallVec::with_capacity(operands.len());
ext.push(operands.len() as u32);
ext.extend_from_slice(&operands[1..]);
Self {
op: OpCode::CONCAT_N,
rd: dst,
a: Operand::Reg(operands[0]),
b: Operand::None,
ext,
}
}
/// TEMPLATE_STR:变长 ext。首字打包 `(segment_count<<16) | total_len_hint`,
/// 后续每 quasi 一项 `quasi_const_idx & 0x7FFF_FFFF`,其后若跟表达式再一项 `0x8000_0000 | expr_reg`。
pub fn template_str(dst: Operand, segment_count: u32, total_len_hint: u16, parts: &[u32]) -> Self {
@@ -591,4 +608,15 @@ mod tests {
assert_eq!(inst.ext[1], 0x1234);
assert_eq!(inst.ext[2], 0x8000_0000 | 5);
}
#[test]
fn concat_n_packs_n_header_and_operand_regs() {
// 6 操作数:a 槽=op1,ext=[6, op2..op6]
let inst = Inst::concat_n(Operand::Reg(1), &[2, 5, 9, 12, 300, 7]);
assert_eq!(inst.op, OpCode::CONCAT_N);
assert_eq!(inst.rd, Operand::Reg(1));
assert_eq!(inst.a, Operand::Reg(2));
assert_eq!(inst.b, Operand::None);
assert_eq!(inst.ext.as_slice(), &[6, 5, 9, 12, 300, 7]);
}
}