Mid rewrite
This commit is contained in:
@@ -1,59 +1,136 @@
|
||||
use super::{ENV_ARG, PROTO_FIELD, pusher};
|
||||
//! Process instrs that are a simple sequence of other instrs
|
||||
//!
|
||||
//! Useless instrs are replaced with `nop` since simply dropping instrs can break jump targets
|
||||
|
||||
use super::{ENV_ARG, PROTO_FIELD};
|
||||
|
||||
use crate::{
|
||||
libqjs::parse::{Atom, ImmOperand, Instr, JsValue, opcodes::OpCode},
|
||||
libqjs::parse::{Atom, ImmOperand as Imm, Instr, JsValue, opcodes::OpCode},
|
||||
native,
|
||||
};
|
||||
|
||||
/// Replace ops that are a fixed sequence of simpler ones
|
||||
///
|
||||
/// A sequence is never empty: jumps find their target by its pc (see regify),
|
||||
/// so every instr must keep at least one instr at its pc
|
||||
pub fn replace_expansion(instr: &Instr, out: &mut Vec<Instr>) -> bool {
|
||||
#[allow(non_snake_case)]
|
||||
pub fn try_replace_expansion(instr: &Instr, out: &mut Vec<Instr>) -> bool {
|
||||
use OpCode::*;
|
||||
|
||||
let none = ImmOperand::None;
|
||||
let imm = instr.imm;
|
||||
|
||||
// A plain call has no `this`, so it passes `undefined`. It is pushed last,
|
||||
// on top of the args, and the call pops it as one more arg (see regify)
|
||||
let plain_call = |n: u16| [(Undefined, none), (Call, ImmOperand::Npop(n + 1))];
|
||||
let tail_call = |n: u16| [(Undefined, none), (Call, ImmOperand::Npop(n + 1)), (Return, none)];
|
||||
|
||||
let seq: &[(OpCode, ImmOperand)] = match (instr.op, imm) {
|
||||
(Call0, _) => &plain_call(0),
|
||||
(Call1, _) => &plain_call(1),
|
||||
(Call2, _) => &plain_call(2),
|
||||
(Call3, _) => &plain_call(3),
|
||||
(Call, ImmOperand::Npop(n)) => &plain_call(n),
|
||||
(TailCall, ImmOperand::Npop(n)) => &tail_call(n),
|
||||
(TailCallMethod, _) => &[(CallMethod, imm), (Return, none)],
|
||||
(GetField2, _) => &[(Dup, none), (GetField, imm)],
|
||||
(GetLoc0Loc1, _) => &[(GetLoc0, none), (GetLoc1, none)],
|
||||
(IncLoc, _) => &[(GetLoc, imm), (Inc, none), (PutLoc, imm)],
|
||||
(DecLoc, _) => &[(GetLoc, imm), (Dec, none), (PutLoc, imm)],
|
||||
let seq = match (instr.op, instr.imm) {
|
||||
(Call0, _) => [
|
||||
(Nop, Imm::None),
|
||||
(Nop, Imm::None),
|
||||
(Undefined, Imm::None),
|
||||
(Call, Imm::Npop(1)),
|
||||
],
|
||||
(Call1, _) => [
|
||||
(Nop, Imm::None),
|
||||
(Nop, Imm::None),
|
||||
(Undefined, Imm::None),
|
||||
(Call, Imm::Npop(2)),
|
||||
],
|
||||
(Call2, _) => [
|
||||
(Nop, Imm::None),
|
||||
(Nop, Imm::None),
|
||||
(Undefined, Imm::None),
|
||||
(Call, Imm::Npop(3)),
|
||||
],
|
||||
(Call3, _) => [
|
||||
(Nop, Imm::None),
|
||||
(Nop, Imm::None),
|
||||
(Undefined, Imm::None),
|
||||
(Call, Imm::Npop(4)),
|
||||
],
|
||||
(Call, Imm::Npop(n)) => [
|
||||
(Nop, Imm::None),
|
||||
(Nop, Imm::None),
|
||||
(Undefined, Imm::None),
|
||||
(Call, Imm::Npop(n + 1)),
|
||||
],
|
||||
(TailCall, Imm::Npop(n)) => [
|
||||
(Nop, Imm::None),
|
||||
(Undefined, Imm::None),
|
||||
(Call, Imm::Npop(n + 1)),
|
||||
(Return, Imm::None),
|
||||
],
|
||||
(TailCallMethod, imm) => [
|
||||
(Nop, Imm::None),
|
||||
(Nop, Imm::None),
|
||||
(CallMethod, imm),
|
||||
(Return, Imm::None),
|
||||
],
|
||||
(GetField2, imm) => [
|
||||
(Nop, Imm::None),
|
||||
(Nop, Imm::None),
|
||||
(Dup, Imm::None),
|
||||
(GetField, imm),
|
||||
],
|
||||
(GetLoc0Loc1, _) => [
|
||||
(Nop, Imm::None),
|
||||
(Nop, Imm::None),
|
||||
(GetLoc0, Imm::None),
|
||||
(GetLoc1, Imm::None),
|
||||
],
|
||||
(IncLoc, imm) => [
|
||||
(Nop, Imm::None),
|
||||
(GetLoc, imm),
|
||||
(Inc, Imm::None),
|
||||
(PutLoc, imm),
|
||||
],
|
||||
(DecLoc, imm) => [
|
||||
(Nop, Imm::None),
|
||||
(GetLoc, imm),
|
||||
(Dec, Imm::None),
|
||||
(PutLoc, imm),
|
||||
],
|
||||
// The added value is on the stack, the local is the left operand
|
||||
(AddLoc, _) => &[(GetLoc, imm), (Swap, none), (Add, none), (PutLoc, imm)],
|
||||
(SetProto, _) => &[(DefineField, ImmOperand::Atom(PROTO_FIELD))],
|
||||
// The low two bits of `arg`: 0 method, 1 getter, 2 setter
|
||||
(DefineMethod, ImmOperand::AtomU8 { atom, arg }) => {
|
||||
(AddLoc, imm) => [
|
||||
(GetLoc, imm),
|
||||
(Swap, Imm::None),
|
||||
(Add, Imm::None),
|
||||
(PutLoc, imm),
|
||||
],
|
||||
(SetProto, _) => [
|
||||
(Nop, Imm::None),
|
||||
(Nop, Imm::None),
|
||||
(Nop, Imm::None),
|
||||
(DefineField, Imm::Atom(PROTO_FIELD)),
|
||||
],
|
||||
(DefineMethod, Imm::AtomU8 { atom, arg }) => {
|
||||
assert!(arg & 3 == 0, "getters and setters are not supported");
|
||||
&[(DefineField, ImmOperand::Atom(atom))]
|
||||
[
|
||||
(Nop, Imm::None),
|
||||
(Nop, Imm::None),
|
||||
(Nop, Imm::None),
|
||||
(DefineField, Imm::Atom(atom)),
|
||||
]
|
||||
}
|
||||
// The fn itself, which is its env
|
||||
(SpecialObject, ImmOperand::U8(2)) => &[(GetArg, ImmOperand::Arg(ENV_ARG))],
|
||||
(SpecialObject, Imm::U8(2)) => [
|
||||
(Nop, Imm::None),
|
||||
(Nop, Imm::None),
|
||||
(Nop, Imm::None),
|
||||
(GetArg, Imm::Arg(ENV_ARG)),
|
||||
],
|
||||
// [[HomeObject]], which only `super` reads. `super` is not supported
|
||||
// (see set_home_object in regify)
|
||||
(SpecialObject, ImmOperand::U8(4)) => &[(Undefined, none)],
|
||||
// A class constructor called without `new` throws. That is not
|
||||
// checked
|
||||
(CheckCtor, _) => &[(Nop, none)],
|
||||
(SpecialObject, Imm::U8(4)) => unimplemented!(),
|
||||
// A class constructor called without `new` throws. That is not checked for the moment
|
||||
(CheckCtor, _) => [
|
||||
(Nop, Imm::None),
|
||||
(Nop, Imm::None),
|
||||
(Nop, Imm::None),
|
||||
(Nop, Imm::None),
|
||||
],
|
||||
// arguments, new.target, import.meta
|
||||
(SpecialObject, _) => unimplemented!("special_object {imm:?}"),
|
||||
(SpecialObject, _) => unimplemented!(),
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
let mut push = pusher(instr.pc, out);
|
||||
seq.iter().for_each(|&(op, imm)| push(op, imm));
|
||||
for (op, imm) in seq {
|
||||
out.push(Instr {
|
||||
pc: instr.pc,
|
||||
op,
|
||||
imm,
|
||||
});
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
@@ -69,6 +146,12 @@ pub fn replace_get_var(
|
||||
}
|
||||
|
||||
cpool.push(native::global(instr.imm.atom(), atoms));
|
||||
pusher(instr.pc, out)(OpCode::PushConst, ImmOperand::Const(cpool.len() as u32 - 1));
|
||||
|
||||
out.push(Instr {
|
||||
pc: instr.pc,
|
||||
op: OpCode::PushConst,
|
||||
imm: Imm::Const(cpool.len() as u32 - 1),
|
||||
});
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user