mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 19:21:11 +08:00
feat: 调用实参 spread(f(...args) / new F(...args) / super(...args))
This commit is contained in:
@@ -18,7 +18,7 @@ impl Inst {
|
||||
pub fn def_reg(&self) -> Option<u32> {
|
||||
match self.op {
|
||||
// CALL 系:结果隐式写 reg 0,rd 是 callee 的 use
|
||||
OpCode::CALL | OpCode::CALL_NATIVE => Some(0),
|
||||
OpCode::CALL | OpCode::CALL_NATIVE | OpCode::CALL_SPREAD => Some(0),
|
||||
// GET_PROP 系:结果写 a/b 槽而非 rd
|
||||
OpCode::GET_PROP | OpCode::IC_GET_PROP => reg_of(&self.a),
|
||||
OpCode::GET_PROP_DYNAMIC => reg_of(&self.b),
|
||||
@@ -91,6 +91,25 @@ impl Inst {
|
||||
let nargs = self.ext.first().copied().unwrap_or(0);
|
||||
push_range(&mut uses, reg_of(&self.a), nargs);
|
||||
}
|
||||
// spread 调用系:ext 内嵌有序实参字(静态寄存器号 / `0x8000_0000|reg` spread 源)
|
||||
OpCode::CALL_SPREAD => {
|
||||
push_operand(&mut uses, &self.rd);
|
||||
push_operand(&mut uses, &self.a);
|
||||
for &w in self.ext.iter().skip(1) {
|
||||
uses.push(w & 0x7FFF_FFFF);
|
||||
}
|
||||
}
|
||||
OpCode::NEW_EXPRESSION_SPREAD => {
|
||||
push_operand(&mut uses, &self.a);
|
||||
for &w in self.ext.iter().skip(1) {
|
||||
uses.push(w & 0x7FFF_FFFF);
|
||||
}
|
||||
}
|
||||
OpCode::SUPER_CALL_SPREAD => {
|
||||
for &w in self.ext.iter().skip(1) {
|
||||
uses.push(w & 0x7FFF_FFFF);
|
||||
}
|
||||
}
|
||||
// GET_PROP 系:结果写 a/b 槽,rd=obj 是 use
|
||||
OpCode::GET_PROP => {
|
||||
push_operand(&mut uses, &self.rd);
|
||||
@@ -435,6 +454,24 @@ mod tests {
|
||||
assert_eq!(inst.use_regs().as_slice(), &[0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spread_call_def_and_uses() {
|
||||
// CALL_SPREAD:结果隐式写 reg 0;use = callee + this + ext 有序实参字(静态/spread 同编)
|
||||
let call = Inst::call_spread(Operand::Reg(0), Operand::Reg(1), &[5, 0x8000_0000 | 9, 300]);
|
||||
assert_eq!(call.def_reg(), Some(0));
|
||||
assert_eq!(call.use_regs().as_slice(), &[0, 1, 5, 9, 300]);
|
||||
|
||||
// NEW_EXPRESSION_SPREAD:rd 即 def;use = ctor + 实参字
|
||||
let ne = Inst::new_expression_spread(Operand::Reg(3), Operand::Reg(0), &[7, 0x8000_0000 | 12]);
|
||||
assert_eq!(ne.def_reg(), Some(3));
|
||||
assert_eq!(ne.use_regs().as_slice(), &[0, 7, 12]);
|
||||
|
||||
// SUPER_CALL_SPREAD:无 callee/this 槽
|
||||
let sc = Inst::super_call_spread(Operand::Reg(3), &[4, 0x8000_0000 | 8]);
|
||||
assert_eq!(sc.def_reg(), Some(3));
|
||||
assert_eq!(sc.use_regs().as_slice(), &[4, 8]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn void_defs_rd_no_use() {
|
||||
// VM 的 VOID handler 不读 a 槽
|
||||
@@ -630,6 +667,9 @@ mod tests {
|
||||
assert!(!Inst::call_native(Operand::Reg(0), Operand::Reg(1), Operand::Reg(2), 0).is_pure(&f));
|
||||
assert!(!Inst::new_expression(Operand::Reg(3), Operand::Reg(0), Operand::Reg(1), 0).is_pure(&f));
|
||||
assert!(!Inst::super_call(Operand::Reg(3), Operand::Reg(1), 0).is_pure(&f));
|
||||
assert!(!Inst::call_spread(Operand::Reg(0), Operand::Reg(1), &[3]).is_pure(&f));
|
||||
assert!(!Inst::new_expression_spread(Operand::Reg(3), Operand::Reg(0), &[2]).is_pure(&f));
|
||||
assert!(!Inst::super_call_spread(Operand::Reg(3), &[2]).is_pure(&f));
|
||||
assert!(!Inst::new(OpCode::CREATE_REGEXP, Operand::Reg(0), Operand::Reg(1), Operand::Reg(2)).is_pure(&f));
|
||||
assert!(!Inst::new(OpCode::RETURN, Operand::None, Operand::None, Operand::None).is_pure(&f));
|
||||
assert!(!Inst::new(OpCode::THROW, Operand::Reg(2), Operand::None, Operand::None).is_pure(&f));
|
||||
|
||||
@@ -116,6 +116,26 @@ impl Inst {
|
||||
Self::with_ext(OpCode::SUPER_CALL, result, first_arg, Operand::None, &[nargs as u32])
|
||||
}
|
||||
|
||||
/// spread 实参调用:rd=callee,a=this,b 槽未用。
|
||||
/// ext=[nstatic|(nspread<<8), 有序实参字…];每个实参字:静态实参为寄存器号,
|
||||
/// spread 源为 `0x8000_0000 | 寄存器号`(高位标记),按源码求值序排列。
|
||||
pub fn call_spread(callee: Operand, this: Operand, words: &[u32]) -> Self {
|
||||
let ext = spread_ext(words);
|
||||
Self::with_ext(OpCode::CALL_SPREAD, callee, this, Operand::None, &ext)
|
||||
}
|
||||
|
||||
/// spread 实参 `new`:结果写入 `result`,构造函数为 `constructor`。
|
||||
pub fn new_expression_spread(result: Operand, constructor: Operand, words: &[u32]) -> Self {
|
||||
let ext = spread_ext(words);
|
||||
Self::with_ext(OpCode::NEW_EXPRESSION_SPREAD, result, constructor, Operand::None, &ext)
|
||||
}
|
||||
|
||||
/// 派生类构造中的 `super(...spread)`:结果写入 `result`。
|
||||
pub fn super_call_spread(result: Operand, words: &[u32]) -> Self {
|
||||
let ext = spread_ext(words);
|
||||
Self::with_ext(OpCode::SUPER_CALL_SPREAD, result, Operand::None, Operand::None, &ext)
|
||||
}
|
||||
|
||||
// ── 其他带 ext 字 ──
|
||||
|
||||
/// 定义访问器属性:home 为宿主对象,get/set 为访问器函数寄存器,key_idx 为属性名常量下标。
|
||||
@@ -217,6 +237,17 @@ impl Inst {
|
||||
}
|
||||
}
|
||||
|
||||
/// spread 调用系 ext 构造:首字打包 `nstatic | (nspread << 8)`,后续按源码求值序排列
|
||||
/// 每个实参字(静态实参 = 寄存器号,spread 源 = `0x8000_0000 | 寄存器号`)。
|
||||
fn spread_ext(words: &[u32]) -> SmallVec<[u32; 4]> {
|
||||
let nspread = words.iter().filter(|w| *w >> 31 == 1).count() as u32;
|
||||
let nstatic = (words.len() as u32) - nspread;
|
||||
let mut ext = SmallVec::with_capacity(1 + words.len());
|
||||
ext.push(nstatic | (nspread << 8));
|
||||
ext.extend_from_slice(words);
|
||||
ext
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -282,6 +313,29 @@ mod tests {
|
||||
assert_eq!(rest.ext.as_slice(), &[7]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spread_call_constructors_carry_header_and_source_regs() {
|
||||
let call = Inst::call_spread(Operand::Reg(0), Operand::Reg(1), &[10, 0x8000_0000 | 300]);
|
||||
assert_eq!(call.op, OpCode::CALL_SPREAD);
|
||||
assert_eq!(call.rd, Operand::Reg(0));
|
||||
assert_eq!(call.a, Operand::Reg(1));
|
||||
assert_eq!(call.b, Operand::None);
|
||||
assert_eq!(call.ext.as_slice(), &[1 | (1 << 8), 10, 0x8000_0000 | 300]);
|
||||
|
||||
let ne = Inst::new_expression_spread(Operand::Reg(3), Operand::Reg(0), &[0x8000_0000 | 7]);
|
||||
assert_eq!(ne.op, OpCode::NEW_EXPRESSION_SPREAD);
|
||||
assert_eq!(ne.rd, Operand::Reg(3));
|
||||
assert_eq!(ne.a, Operand::Reg(0));
|
||||
assert_eq!(ne.ext.as_slice(), &[1 << 8, 0x8000_0000 | 7]);
|
||||
|
||||
let sc = Inst::super_call_spread(Operand::Reg(3), &[1, 0x8000_0000 | 5]);
|
||||
assert_eq!(sc.op, OpCode::SUPER_CALL_SPREAD);
|
||||
assert_eq!(sc.rd, Operand::Reg(3));
|
||||
assert_eq!(sc.a, Operand::None);
|
||||
assert_eq!(sc.b, Operand::None);
|
||||
assert_eq!(sc.ext.as_slice(), &[1 | (1 << 8), 1, 0x8000_0000 | 5]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn regalloc_constructors_carry_expected_slots() {
|
||||
let mov = Inst::inst_mov(Operand::Reg(3), Operand::Reg(7));
|
||||
|
||||
Reference in New Issue
Block a user