Big progress by Claude

This commit is contained in:
2026-09-25 19:31:15 +00:00
parent 183c4e35c9
commit e93ce94ac7
15 changed files with 1577 additions and 470 deletions
+43 -1
View File
@@ -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();