refactor(compiler): finalize single pass compilation

This commit is contained in:
爱特每羊队
2026-08-05 01:49:21 +08:00
parent 0f78f341fa
commit 8ee6781795
4 changed files with 40 additions and 21 deletions
-2
View File
@@ -66,7 +66,6 @@ impl Compiler {
false, false,
&self_binding, &self_binding,
FunctionBodyContext::ClassElement, FunctionBodyContext::ClassElement,
None::<fn(&Compiler, &mut CompileCtx)>,
Some(|compiler: &Compiler, field_ctx: &mut CompileCtx| -> Result<(), String> { Some(|compiler: &Compiler, field_ctx: &mut CompileCtx| -> Result<(), String> {
for field in &instance_fields { for field in &instance_fields {
if let PropertyKey::PrivateIdentifier(private) = &field.key { if let PropertyKey::PrivateIdentifier(private) = &field.key {
@@ -98,7 +97,6 @@ impl Compiler {
false, false,
&self_binding, &self_binding,
FunctionBodyContext::ClassElement, FunctionBodyContext::ClassElement,
None::<fn(&Compiler, &mut CompileCtx)>,
Some(|compiler: &Compiler, field_ctx: &mut CompileCtx| -> Result<(), String> { Some(|compiler: &Compiler, field_ctx: &mut CompileCtx| -> Result<(), String> {
for field in &instance_fields { for field in &instance_fields {
if let PropertyKey::PrivateIdentifier(private) = &field.key { if let PropertyKey::PrivateIdentifier(private) = &field.key {
+25 -15
View File
@@ -138,6 +138,12 @@ pub(crate) struct JumpFixup {
pub(crate) rd: u8, pub(crate) rd: u8,
} }
pub(crate) struct FieldBuffer {
pub(crate) bytecode: Vec<opcode::Instr>,
pub(crate) labels: Vec<(Label, usize)>,
pub(crate) fixups: Vec<JumpFixup>,
}
/// A labeled-statement scope active during emission. `break label` targets /// A labeled-statement scope active during emission. `break label` targets
/// `break_label`; `continue label` targets `continue_label` (only set when the /// `break_label`; `continue label` targets `continue_label` (only set when the
/// labeled statement directly wraps an iteration statement). /// labeled statement directly wraps an iteration statement).
@@ -158,7 +164,6 @@ pub(crate) struct CompileCtx {
reserved_reg_start: u8, reserved_reg_start: u8,
pub(crate) labels: LabelCtx, pub(crate) labels: LabelCtx,
pub(crate) scopes: ScopeCtx, pub(crate) scopes: ScopeCtx,
pub(crate) projected_pc: usize,
pub(crate) sub_modules: Vec<CompiledModule>, pub(crate) sub_modules: Vec<CompiledModule>,
/// Register holding `this` in the enclosing function context. /// Register holding `this` in the enclosing function context.
/// Used by arrow functions to capture lexical `this`. /// Used by arrow functions to capture lexical `this`.
@@ -168,8 +173,7 @@ pub(crate) struct CompileCtx {
pub(crate) in_instance_method: bool, pub(crate) in_instance_method: bool,
pub(crate) in_static_method: bool, pub(crate) in_static_method: bool,
pub(crate) static_block_this_reg: Option<u8>, pub(crate) static_block_this_reg: Option<u8>,
pub(crate) after_super_insert: Option<Vec<opcode::Instr>>, pub(crate) field_buffer: Option<FieldBuffer>,
pub(crate) after_super_inserted: bool,
pub(crate) current_upvalue_captures: Vec<UpvalueCapture>, pub(crate) current_upvalue_captures: Vec<UpvalueCapture>,
/// Set when alloc_reg() overflows into the reserved this/new.target range (≥254). /// Set when alloc_reg() overflows into the reserved this/new.target range (≥254).
/// Checked after each emit phase to produce a compile error rather than silent corruption. /// Checked after each emit phase to produce a compile error rather than silent corruption.
@@ -237,15 +241,13 @@ impl CompileCtx {
next_private_name_id: 1, next_private_name_id: 1,
cell_registry: Vec::new(), cell_registry: Vec::new(),
}, },
projected_pc: 0,
sub_modules: Vec::new(), sub_modules: Vec::new(),
enclosing_this_reg: 254, // conventional this register at top level enclosing_this_reg: 254, // conventional this register at top level
in_derived_constructor: false, in_derived_constructor: false,
in_instance_method: false, in_instance_method: false,
in_static_method: false, in_static_method: false,
static_block_this_reg: None, static_block_this_reg: None,
after_super_insert: None, field_buffer: None,
after_super_inserted: false,
current_upvalue_captures: Vec::new(), current_upvalue_captures: Vec::new(),
reg_overflow: false, reg_overflow: false,
const_overflow: false, const_overflow: false,
@@ -356,7 +358,6 @@ impl CompileCtx {
pub(crate) fn reset_regs(&mut self) { pub(crate) fn reset_regs(&mut self) {
self.next_reg = self.builtin_reg_floor().max(self.reserved_reg_start); self.next_reg = self.builtin_reg_floor().max(self.reserved_reg_start);
self.projected_pc = 0;
self.labels.label_counter = 0; self.labels.label_counter = 0;
} }
@@ -906,7 +907,6 @@ impl Compiler {
is_expression_body, is_expression_body,
extra_bindings, extra_bindings,
body_context, body_context,
None::<fn(&Compiler, &mut CompileCtx)>,
None::<fn(&Compiler, &mut CompileCtx) -> Result<(), String>>, None::<fn(&Compiler, &mut CompileCtx) -> Result<(), String>>,
false, false,
) )
@@ -1022,13 +1022,12 @@ impl Compiler {
} }
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub(crate) fn compile_function_body_with_field_hooks<'a, C, E>( pub(crate) fn compile_function_body_with_field_hooks<'a, E>(
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx, &self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
is_expression_body: bool, extra_bindings: &[(&str, u8)], body_context: FunctionBodyContext, is_expression_body: bool, extra_bindings: &[(&str, u8)], body_context: FunctionBodyContext,
_count_fields: Option<C>, mut emit_fields: Option<E>, fields_after_super: bool, mut emit_fields: Option<E>, fields_after_super: bool,
) -> Result<CompiledModule, String> ) -> Result<CompiledModule, String>
where where
C: FnMut(&Compiler, &mut CompileCtx),
E: FnMut(&Compiler, &mut CompileCtx) -> Result<(), String>, E: FnMut(&Compiler, &mut CompileCtx) -> Result<(), String>,
{ {
let mut ctx = CompileCtx::new(); let mut ctx = CompileCtx::new();
@@ -1128,11 +1127,22 @@ impl Compiler {
if let Some(emit) = emit_fields.as_mut() { if let Some(emit) = emit_fields.as_mut() {
if fields_after_super { if fields_after_super {
let start = ctx.bytecode.len(); let mut parent_bytecode = Vec::new();
let mut parent_labels = HashMap::new();
let mut parent_fixups = Vec::new();
std::mem::swap(&mut ctx.bytecode, &mut parent_bytecode);
std::mem::swap(&mut ctx.labels.label_map, &mut parent_labels);
std::mem::swap(&mut ctx.fixups, &mut parent_fixups);
emit(self, &mut ctx)?; emit(self, &mut ctx)?;
let field_code = ctx.bytecode.split_off(start); let field_buffer = FieldBuffer {
ctx.after_super_insert = Some(field_code); bytecode: std::mem::take(&mut ctx.bytecode),
ctx.after_super_inserted = false; labels: std::mem::take(&mut ctx.labels.label_map).into_iter().collect(),
fixups: std::mem::take(&mut ctx.fixups),
};
ctx.bytecode = parent_bytecode;
ctx.labels.label_map = parent_labels;
ctx.fixups = parent_fixups;
ctx.field_buffer = Some(field_buffer);
} else { } else {
emit(self, &mut ctx)?; emit(self, &mut ctx)?;
} }
+9 -4
View File
@@ -19,10 +19,15 @@ impl Compiler {
let result_reg = ctx.alloc_reg(); let result_reg = ctx.alloc_reg();
ctx.emit(opcode::encode(OpCode::SUPER_CALL, result_reg, first_arg_reg, 0)); ctx.emit(opcode::encode(OpCode::SUPER_CALL, result_reg, first_arg_reg, 0));
ctx.emit(arg_regs.len() as u32); ctx.emit(arg_regs.len() as u32);
if !ctx.after_super_inserted { if let Some(mut field_buffer) = ctx.field_buffer.take() {
if let Some(field_code) = ctx.after_super_insert.clone() { let insert_pc = ctx.bytecode.len();
ctx.bytecode.extend(field_code); ctx.bytecode.append(&mut field_buffer.bytecode);
ctx.after_super_inserted = true; for (label, relative_pc) in field_buffer.labels {
ctx.labels.label_map.insert(label, insert_pc + relative_pc);
}
for mut fixup in field_buffer.fixups {
fixup.pc += insert_pc;
ctx.fixups.push(fixup);
} }
} }
return Ok(result_reg); return Ok(result_reg);
@@ -284,6 +284,12 @@ fn compile_class_declaration_emits_constructor_and_prototype_setup() {
); );
} }
#[test]
fn compile_derived_constructor_inserts_instance_fields_after_super() {
let module = compile_source("class Base {} class Derived extends Base { value = 1; constructor() { super(); } }");
assert!(!module.sub_modules.is_empty(), "derived class should compile its constructor");
}
#[test] #[test]
fn compile_class_declaration_default_constructor_creates_submodule() { fn compile_class_declaration_default_constructor_creates_submodule() {
let module = compile_source("class A {}"); let module = compile_source("class A {}");