mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
fix: 可抛算术比较位 opcode 纯标翻转,DCE 不再删副作用指令
This commit is contained in:
@@ -159,22 +159,22 @@ define_opcodes! {
|
||||
// ── Arithmetic (0x00-0x0F) ──
|
||||
ADD = 0x00 => "ADD",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
SUB = 0x01 => "SUB",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
MUL = 0x02 => "MUL",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
DIV = 0x03 => "DIV",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
MOD = 0x04 => "MOD",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
NEG = 0x05 => "NEG",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A)],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
COMPOUND_ADD = 0x06 => "COMPOUND_ADD",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::Rd), SlotSpec::Slot(Slot::A)],
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
@@ -196,7 +196,7 @@ define_opcodes! {
|
||||
// 二元幂运算 `a ** b`(三寄存器,与 SUB/MUL 同族;0x00-0x0F 已满,值用空闲槽 0x94)。
|
||||
EXP = 0x94 => "EXP",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
MOV = 0x0C => "MOV", // rd=dst, a=src(寄存器复制,区间拆分搬值)
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A)],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
@@ -213,22 +213,22 @@ define_opcodes! {
|
||||
// ── 比较 (0x10-0x1F) ──
|
||||
EQ = 0x10 => "EQ",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
NEQ = 0x11 => "NEQ",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
LT = 0x12 => "LT",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
GT = 0x13 => "GT",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
LTE = 0x14 => "LTE",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
GTE = 0x15 => "GTE",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
IN = 0x16 => "IN",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
@@ -249,7 +249,7 @@ define_opcodes! {
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
UNARY_PLUS = 0x1D => "UNARY_PLUS",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A)],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
|
||||
// ── 控制流 (0x1E-0x2F) ──
|
||||
BREAK = 0x1E => "BREAK",
|
||||
@@ -330,7 +330,7 @@ define_opcodes! {
|
||||
// ── 模板字符串 (0x38) ──
|
||||
TEMPLATE_STR = 0x38 => "TEMPLATE_STR",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::TemplateExprs],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
|
||||
// ── 标签模板对象 (0x97) ──
|
||||
// GetTemplateObject:按 site 缓存模板对象(同一编译树同 site 恒返回同一对象),
|
||||
@@ -473,10 +473,10 @@ define_opcodes! {
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
// 多操作数拼接(连续 `+` 左结合链摊平):rd=结果,a=首操作数,ext=[n, op2..opn],
|
||||
// n=操作数总数,ext 字数 = 1+(n-1) = n;op 字无高位标记(纯 vreg,≤255),
|
||||
// SpreadArgs 直接解析。与 ADD 同标纯(含 ToPrimitive 副作用仍静态可删,语义同 ADD)。
|
||||
// SpreadArgs 直接解析。含 ToPrimitive 副作用,不可删。
|
||||
CONCAT_N = 0x93 => "CONCAT_N",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::SpreadArgs],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
|
||||
// ── 成员更新 (0x59-0x62) ──
|
||||
MEMBER_INC = 0x59 => "MEMBER_INC", // 结果写 a 槽(val 槽原地更新)
|
||||
@@ -668,25 +668,25 @@ define_opcodes! {
|
||||
// ── 位运算 (0x80-0x8F) ──
|
||||
BIT_AND = 0x80 => "BIT_AND",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
BIT_OR = 0x81 => "BIT_OR",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
BIT_XOR = 0x82 => "BIT_XOR",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
SHL = 0x83 => "SHL",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
SHR = 0x84 => "SHR",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
USHR = 0x85 => "USHR",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A), SlotSpec::Slot(Slot::B)],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
BIT_NOT = 0x86 => "BIT_NOT",
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::A)],
|
||||
pure = true, jump = false, term = false, ic = false,
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
TO_OBJECT = 0x87 => "TO_OBJECT", // rd 原地转换(读且写)
|
||||
def = Some(SlotSpec::Slot(Slot::Rd)), uses = [SlotSpec::Slot(Slot::Rd)],
|
||||
pure = false, jump = false, term = false, ic = false,
|
||||
|
||||
@@ -792,3 +792,12 @@ fn compile_delete_new_instanceof_in() {
|
||||
);
|
||||
assert!(module.bytecode.iter().any(|&i| opcode::opcode(i) == OpCode::IN), "in should emit IN");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compile_nonfinal_relational_comparison_kept() {
|
||||
let module = compile_source("let s = 1; s <= 1; s + 1;");
|
||||
assert!(
|
||||
module.bytecode.iter().any(|&i| opcode::opcode(i) == OpCode::LTE),
|
||||
"非末语句形 s <= 1 应保留 LTE 指令(结果虽未用,ToPrimitive 副作用不可删)"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -107,13 +107,12 @@ mod tests {
|
||||
use oxide_ir::inst::Inst;
|
||||
use oxide_ir::operand::Operand;
|
||||
|
||||
/// 线性死链:LOAD_CONST→ADD→结果丢弃,全删(剩 RETURN)。
|
||||
/// 线性死链:LOAD_CONST→MOV→结果丢弃,全删(剩 RETURN)。
|
||||
#[test]
|
||||
fn linear_dead_chain_deleted() {
|
||||
let mut f = IRFunction::new();
|
||||
f.insts.push(Inst::load_const(Operand::Reg(0), 0)); // 0: r0 = const
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::ADD, Operand::Reg(1), Operand::Reg(0), Operand::Reg(0))); // 1: r1 = r0 + r0
|
||||
f.insts.push(Inst::inst_mov(Operand::Reg(1), Operand::Reg(0))); // 1: r1 = r0
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::RETURN, Operand::Reg(2), Operand::None, Operand::None)); // 2: return r2
|
||||
let mut keep = vec![true; f.insts.len()];
|
||||
@@ -175,13 +174,12 @@ mod tests {
|
||||
assert_eq!(keep, vec![false, true], "死 CREATE_CLOSURE 删,RETURN 保留");
|
||||
}
|
||||
|
||||
/// 连锁迭代:写链 LOAD_CONST→ADD→LOAD_CONST 全死,逐轮删除至不动点。
|
||||
/// 连锁迭代:写链 LOAD_CONST→MOV→LOAD_CONST 全死,逐轮删除至不动点。
|
||||
#[test]
|
||||
fn chained_dead_writes_deleted_iteratively() {
|
||||
let mut f = IRFunction::new();
|
||||
f.insts.push(Inst::load_const(Operand::Reg(0), 0)); // 0: r0(ADD 读,轮 2 删)
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::ADD, Operand::Reg(1), Operand::Reg(0), Operand::Reg(0))); // 1: r1(轮 1 删)
|
||||
f.insts.push(Inst::load_const(Operand::Reg(0), 0)); // 0: r0(MOV 读,轮 2 删)
|
||||
f.insts.push(Inst::inst_mov(Operand::Reg(1), Operand::Reg(0))); // 1: r1(轮 1 删)
|
||||
f.insts.push(Inst::load_const(Operand::Reg(2), 2)); // 2: r2 无人读(轮 1 删)
|
||||
f.insts
|
||||
.push(Inst::new(OpCode::RETURN, Operand::Reg(5), Operand::None, Operand::None)); // 3
|
||||
|
||||
@@ -31,18 +31,8 @@ fn run_precise(f: &mut IRFunction, after: &[&[u32]], reg_count: usize) {
|
||||
#[test]
|
||||
fn reuse_killed_dead_write_deleted() {
|
||||
let mut f = IRFunction::new();
|
||||
f.insts.push(Inst::new(
|
||||
oxide_bytecode::opcode::OpCode::ADD,
|
||||
Operand::Reg(5),
|
||||
Operand::Reg(1),
|
||||
Operand::Reg(2),
|
||||
));
|
||||
f.insts.push(Inst::new(
|
||||
oxide_bytecode::opcode::OpCode::ADD,
|
||||
Operand::Reg(5),
|
||||
Operand::Reg(3),
|
||||
Operand::Reg(4),
|
||||
));
|
||||
f.insts.push(Inst::inst_mov(Operand::Reg(5), Operand::Reg(1)));
|
||||
f.insts.push(Inst::inst_mov(Operand::Reg(5), Operand::Reg(3)));
|
||||
f.insts.push(Inst::new(
|
||||
oxide_bytecode::opcode::OpCode::RETURN,
|
||||
Operand::Reg(5),
|
||||
@@ -51,7 +41,7 @@ fn reuse_killed_dead_write_deleted() {
|
||||
));
|
||||
// inst_live_after = [{3,4}, {5}, {}]:inst0 def 5 在 live_after[0] 无 5(后写杀死)
|
||||
run_precise(&mut f, &[&[3, 4], &[5], &[]], 5);
|
||||
assert_eq!(f.insts.len(), 2, "死写(前一个 ADD)应被删");
|
||||
assert_eq!(f.insts.len(), 2, "死写(前一个 MOV)应被删");
|
||||
}
|
||||
|
||||
/// 局部死 STORE_VAR 删除(四条件全满足)。
|
||||
|
||||
@@ -252,16 +252,8 @@ fn regalloc_opcodes_def_use_contract() {
|
||||
#[test]
|
||||
fn pure_ops_are_deletable() {
|
||||
let f = IRFunction::new();
|
||||
// 算术 / 比较 / 位 / 逻辑
|
||||
assert!(Inst::new(OpCode::ADD, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
|
||||
assert!(Inst::new(OpCode::SUB, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
|
||||
assert!(Inst::new(OpCode::MUL, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
|
||||
assert!(Inst::new(OpCode::NEG, Operand::Reg(0), Operand::Reg(1), Operand::None).is_pure(&f));
|
||||
assert!(Inst::new(OpCode::EQ, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
|
||||
// 逻辑 / 严格相等(不抛,纯)
|
||||
assert!(Inst::new(OpCode::STRICT_EQ, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
|
||||
assert!(Inst::new(OpCode::LT, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
|
||||
assert!(Inst::new(OpCode::BIT_AND, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
|
||||
assert!(Inst::new(OpCode::BIT_NOT, Operand::Reg(0), Operand::Reg(1), Operand::None).is_pure(&f));
|
||||
assert!(Inst::new(OpCode::AND, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
|
||||
assert!(Inst::new(OpCode::OR, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
|
||||
assert!(Inst::new(OpCode::NOT, Operand::Reg(0), Operand::Reg(1), Operand::None).is_pure(&f));
|
||||
@@ -277,8 +269,6 @@ fn pure_ops_are_deletable() {
|
||||
assert!(Inst::create_closure(Operand::Reg(1), 0).is_pure(&f));
|
||||
assert!(Inst::new(OpCode::LOAD_UPVALUE, Operand::Reg(1), Operand::Imm(0), Operand::None).is_pure(&f));
|
||||
assert!(Inst::new(OpCode::CELL_GET, Operand::Reg(0), Operand::Reg(1), Operand::Imm(0)).is_pure(&f));
|
||||
// 模板字符串
|
||||
assert!(Inst::template_str(Operand::Reg(1), 1, 10, &[0x1234]).is_pure(&f));
|
||||
// RegAlloc 辅助:MOV 纯
|
||||
assert!(Inst::inst_mov(Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
|
||||
// LOAD_VAR 普通(a=Reg)纯
|
||||
@@ -292,6 +282,16 @@ fn pure_ops_are_deletable() {
|
||||
#[test]
|
||||
fn impure_ops_are_not_deletable() {
|
||||
let f = IRFunction::new();
|
||||
// 算术 / 比较 / 位 / 模板字符串(ToNumber/ToPrimitive 可抛,不可删)
|
||||
assert!(!Inst::new(OpCode::ADD, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
|
||||
assert!(!Inst::new(OpCode::SUB, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
|
||||
assert!(!Inst::new(OpCode::MUL, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
|
||||
assert!(!Inst::new(OpCode::NEG, Operand::Reg(0), Operand::Reg(1), Operand::None).is_pure(&f));
|
||||
assert!(!Inst::new(OpCode::EQ, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
|
||||
assert!(!Inst::new(OpCode::LT, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
|
||||
assert!(!Inst::new(OpCode::BIT_AND, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
|
||||
assert!(!Inst::new(OpCode::BIT_NOT, Operand::Reg(0), Operand::Reg(1), Operand::None).is_pure(&f));
|
||||
assert!(!Inst::template_str(Operand::Reg(1), 1, 10, &[0x1234]).is_pure(&f));
|
||||
// getter / 写对象属性
|
||||
assert!(!Inst::ic_get(Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
|
||||
assert!(!Inst::new(OpCode::GET_PROP, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
|
||||
@@ -440,7 +440,14 @@ fn assert_group(ops: &[OpCode], def: Option<u32>, uses: &[u32], pure: bool) {
|
||||
/// 每个 opcode 的 def/use/pure 与现有语义表一致(canonical rd=1, a=2, b=3)。
|
||||
#[test]
|
||||
fn opcode_semantics_golden_table() {
|
||||
// 二元运算:def=rd, uses=[a,b],纯
|
||||
// 二元运算:def=rd, uses=[a,b],纯(逻辑/严格相等不抛)
|
||||
assert_group(
|
||||
&[OpCode::AND, OpCode::OR, OpCode::STRICT_EQ, OpCode::STRICT_NEQ, OpCode::NULLISH],
|
||||
Some(1),
|
||||
&[2, 3],
|
||||
true,
|
||||
);
|
||||
// 二元但不可删:ToNumber/ToPrimitive 可抛,或 coerce 有观察路径
|
||||
assert_group(
|
||||
&[
|
||||
OpCode::ADD,
|
||||
@@ -454,31 +461,24 @@ fn opcode_semantics_golden_table() {
|
||||
OpCode::GT,
|
||||
OpCode::LTE,
|
||||
OpCode::GTE,
|
||||
OpCode::AND,
|
||||
OpCode::OR,
|
||||
OpCode::STRICT_EQ,
|
||||
OpCode::STRICT_NEQ,
|
||||
OpCode::BIT_AND,
|
||||
OpCode::BIT_OR,
|
||||
OpCode::BIT_XOR,
|
||||
OpCode::SHL,
|
||||
OpCode::SHR,
|
||||
OpCode::USHR,
|
||||
OpCode::NULLISH,
|
||||
OpCode::IN,
|
||||
OpCode::INSTANCEOF,
|
||||
OpCode::CREATE_REGEXP,
|
||||
],
|
||||
Some(1),
|
||||
&[2, 3],
|
||||
true,
|
||||
);
|
||||
// 二元但不可删:coerce 有观察路径
|
||||
assert_group(&[OpCode::IN, OpCode::INSTANCEOF, OpCode::CREATE_REGEXP], Some(1), &[2, 3], false);
|
||||
// 一元:def=rd, uses=[a]
|
||||
assert_group(
|
||||
&[OpCode::NEG, OpCode::NOT, OpCode::UNARY_PLUS, OpCode::BIT_NOT, OpCode::TYPEOF],
|
||||
Some(1),
|
||||
&[2],
|
||||
true,
|
||||
false,
|
||||
);
|
||||
// 一元:def=rd, uses=[a],纯(NOT/TYPEOF 不抛)
|
||||
assert_group(&[OpCode::NOT, OpCode::TYPEOF], Some(1), &[2], true);
|
||||
// 一元但不可删:ToNumber/ToPrimitive 可抛
|
||||
assert_group(&[OpCode::NEG, OpCode::UNARY_PLUS, OpCode::BIT_NOT], Some(1), &[2], false);
|
||||
// 复合赋值:def=rd, uses=[rd,a],不可删
|
||||
assert_group(
|
||||
&[
|
||||
@@ -551,10 +551,10 @@ fn opcode_semantics_golden_table() {
|
||||
assert_contract(OpCode::THROW, None, &[1], false);
|
||||
assert_contract(OpCode::RETURN, None, &[1], false);
|
||||
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);
|
||||
// 模板字符串:表达式寄存器来自 ext;ToPrimitive 可抛,不可删
|
||||
assert_contract(OpCode::TEMPLATE_STR, Some(1), &[5], false);
|
||||
// 多操作数拼接:a 槽首操作数 + ext[1..] 后续操作数(SpreadArgs 解析);ToPrimitive 可抛,不可删
|
||||
assert_contract(OpCode::CONCAT_N, Some(1), &[2, 5, 9], false);
|
||||
// 小语言特性
|
||||
assert_contract(OpCode::DELETE_PROP_STATIC, None, &[1], false);
|
||||
assert_contract(OpCode::DELETE_PROP_DYNAMIC, None, &[1, 3], false);
|
||||
|
||||
Reference in New Issue
Block a user