Broken site based impl
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
use super::{ENV_ARG, PROTO_FIELD, pusher};
|
||||
use crate::{
|
||||
libqjs::parse::{Atom, ImmOperand, 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 {
|
||||
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)],
|
||||
// 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 }) => {
|
||||
assert!(arg & 3 == 0, "getters and setters are not supported");
|
||||
&[(DefineField, ImmOperand::Atom(atom))]
|
||||
}
|
||||
// The fn itself, which is its env
|
||||
(SpecialObject, ImmOperand::U8(2)) => &[(GetArg, ImmOperand::Arg(ENV_ARG))],
|
||||
// [[HomeObject]], which only `super` reads. `super` is not supported
|
||||
// (see set_home_object in regify)
|
||||
(SpecialObject, ImmOperand::U8(4)) => &[(Undefined, none)],
|
||||
// arguments, new.target, import.meta
|
||||
(SpecialObject, _) => unimplemented!("special_object {imm:?}"),
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
let mut push = pusher(instr.pc, out);
|
||||
seq.iter().for_each(|&(op, imm)| push(op, imm));
|
||||
true
|
||||
}
|
||||
|
||||
/// Replace a read of a global with the constant it is (see `native`)
|
||||
pub fn replace_get_var(
|
||||
instr: &Instr,
|
||||
atoms: &[Atom],
|
||||
cpool: &mut Vec<JsValue>,
|
||||
out: &mut Vec<Instr>,
|
||||
) -> bool {
|
||||
if instr.op != OpCode::GetVar {
|
||||
return false;
|
||||
}
|
||||
|
||||
cpool.push(native::global(instr.imm.atom(), atoms));
|
||||
pusher(instr.pc, out)(OpCode::PushConst, ImmOperand::Const(cpool.len() as u32 - 1));
|
||||
true
|
||||
}
|
||||
Reference in New Issue
Block a user