Big progress by Claude
This commit is contained in:
+43
-1
@@ -1,4 +1,6 @@
|
||||
use crate::libqjs::parse::{Atom, AtomRef, ClosureVar, Function, Instr, JsValue, QuickJSBinary};
|
||||
use crate::libqjs::parse::{
|
||||
Atom, AtomRef, ClosureVar, Function, ImmOperand, Instr, JsValue, QuickJSBinary, opcodes::OpCode,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FlatFn {
|
||||
@@ -13,9 +15,49 @@ pub fn flatten(bin: QuickJSBinary) -> (Vec<FlatFn>, Vec<Vec<ClosureVar>>, Vec<At
|
||||
let mut fns = vec![];
|
||||
let mut captures = vec![];
|
||||
walk(bin.root_mod.root_fn, &mut fns, &mut captures);
|
||||
append_entry(&mut fns, &mut captures);
|
||||
(fns, captures, bin.atoms)
|
||||
}
|
||||
|
||||
/// Append the synthetic program entry, the host the runtime would provide,
|
||||
/// written in the IR so the ordinary passes handle it. It drives the module
|
||||
/// body `<eval>` (fn 0): build its environment record, run the link phase
|
||||
/// (`this = true`), then the evaluate phase (`this = false`).
|
||||
///
|
||||
/// `fclosure8` of fn 0 lets `declosure` build the record from `<eval>`'s own
|
||||
/// captures — the module bindings — so no stage needs bespoke module knowledge.
|
||||
/// The closure is made once and kept in local 0, so both phases run on the one
|
||||
/// record and the link phase's writes reach the evaluate phase. `call_method`
|
||||
/// carries the phase flag as the receiver (`this`); a plain call could not set
|
||||
/// it.
|
||||
fn append_entry(fns: &mut Vec<FlatFn>, captures: &mut Vec<Vec<ClosureVar>>) {
|
||||
let mk = |pc, op, imm| Instr { pc, op, imm };
|
||||
let code = vec![
|
||||
mk(0, OpCode::Fclosure8, ImmOperand::Const(0)),
|
||||
mk(1, OpCode::PutLoc, ImmOperand::Loc(0)),
|
||||
mk(2, OpCode::PushTrue, ImmOperand::None),
|
||||
mk(3, OpCode::GetLoc, ImmOperand::Loc(0)),
|
||||
mk(4, OpCode::CallMethod, ImmOperand::Npop(0)),
|
||||
mk(5, OpCode::Drop, ImmOperand::None),
|
||||
mk(6, OpCode::PushFalse, ImmOperand::None),
|
||||
mk(7, OpCode::GetLoc, ImmOperand::Loc(0)),
|
||||
mk(8, OpCode::CallMethod, ImmOperand::Npop(0)),
|
||||
mk(9, OpCode::Drop, ImmOperand::None),
|
||||
mk(10, OpCode::ReturnUndef, ImmOperand::None),
|
||||
];
|
||||
|
||||
fns.push(FlatFn {
|
||||
name: AtomRef::Predefined(0),
|
||||
arg_count: 0,
|
||||
// Local 0 holds the closure of `<eval>`.
|
||||
var_count: 1,
|
||||
cpool: vec![JsValue::FnById(0)],
|
||||
code,
|
||||
});
|
||||
|
||||
captures.push(vec![]);
|
||||
}
|
||||
|
||||
fn walk(func: Function, flat_fns: &mut Vec<FlatFn>, captures: &mut Vec<Vec<ClosureVar>>) -> usize {
|
||||
let id = flat_fns.len();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user