Mid rewrite

This commit is contained in:
UditDey
2026-10-13 11:52:02 +00:00
parent 2f21347088
commit d0c2f291e9
24 changed files with 752 additions and 3527 deletions
+125 -42
View File
@@ -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
}