From 8ee678179522f793317f8e3eb5c1e0a77d64b78e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=88=B1=E7=89=B9=E6=AF=8F=E7=BE=8A=E9=98=9F?= Date: Wed, 5 Aug 2026 01:49:21 +0800 Subject: [PATCH] refactor(compiler): finalize single pass compilation --- crates/oxide_compiler/src/class/emit.rs | 2 - crates/oxide_compiler/src/compiler.rs | 40 ++++++++++++------- crates/oxide_compiler/src/expr/call.rs | 13 ++++-- .../tests/compile_stmt_tests.rs | 6 +++ 4 files changed, 40 insertions(+), 21 deletions(-) diff --git a/crates/oxide_compiler/src/class/emit.rs b/crates/oxide_compiler/src/class/emit.rs index 66705ca..1958812 100644 --- a/crates/oxide_compiler/src/class/emit.rs +++ b/crates/oxide_compiler/src/class/emit.rs @@ -66,7 +66,6 @@ impl Compiler { false, &self_binding, FunctionBodyContext::ClassElement, - None::, Some(|compiler: &Compiler, field_ctx: &mut CompileCtx| -> Result<(), String> { for field in &instance_fields { if let PropertyKey::PrivateIdentifier(private) = &field.key { @@ -98,7 +97,6 @@ impl Compiler { false, &self_binding, FunctionBodyContext::ClassElement, - None::, Some(|compiler: &Compiler, field_ctx: &mut CompileCtx| -> Result<(), String> { for field in &instance_fields { if let PropertyKey::PrivateIdentifier(private) = &field.key { diff --git a/crates/oxide_compiler/src/compiler.rs b/crates/oxide_compiler/src/compiler.rs index 28eaab4..5b193fe 100644 --- a/crates/oxide_compiler/src/compiler.rs +++ b/crates/oxide_compiler/src/compiler.rs @@ -138,6 +138,12 @@ pub(crate) struct JumpFixup { pub(crate) rd: u8, } +pub(crate) struct FieldBuffer { + pub(crate) bytecode: Vec, + pub(crate) labels: Vec<(Label, usize)>, + pub(crate) fixups: Vec, +} + /// A labeled-statement scope active during emission. `break label` targets /// `break_label`; `continue label` targets `continue_label` (only set when the /// labeled statement directly wraps an iteration statement). @@ -158,7 +164,6 @@ pub(crate) struct CompileCtx { reserved_reg_start: u8, pub(crate) labels: LabelCtx, pub(crate) scopes: ScopeCtx, - pub(crate) projected_pc: usize, pub(crate) sub_modules: Vec, /// Register holding `this` in the enclosing function context. /// 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_static_method: bool, pub(crate) static_block_this_reg: Option, - pub(crate) after_super_insert: Option>, - pub(crate) after_super_inserted: bool, + pub(crate) field_buffer: Option, pub(crate) current_upvalue_captures: Vec, /// 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. @@ -237,15 +241,13 @@ impl CompileCtx { next_private_name_id: 1, cell_registry: Vec::new(), }, - projected_pc: 0, sub_modules: Vec::new(), enclosing_this_reg: 254, // conventional this register at top level in_derived_constructor: false, in_instance_method: false, in_static_method: false, static_block_this_reg: None, - after_super_insert: None, - after_super_inserted: false, + field_buffer: None, current_upvalue_captures: Vec::new(), reg_overflow: false, const_overflow: false, @@ -356,7 +358,6 @@ impl CompileCtx { pub(crate) fn reset_regs(&mut self) { self.next_reg = self.builtin_reg_floor().max(self.reserved_reg_start); - self.projected_pc = 0; self.labels.label_counter = 0; } @@ -906,7 +907,6 @@ impl Compiler { is_expression_body, extra_bindings, body_context, - None::, None:: Result<(), String>>, false, ) @@ -1022,13 +1022,12 @@ impl Compiler { } #[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, is_expression_body: bool, extra_bindings: &[(&str, u8)], body_context: FunctionBodyContext, - _count_fields: Option, mut emit_fields: Option, fields_after_super: bool, + mut emit_fields: Option, fields_after_super: bool, ) -> Result where - C: FnMut(&Compiler, &mut CompileCtx), E: FnMut(&Compiler, &mut CompileCtx) -> Result<(), String>, { let mut ctx = CompileCtx::new(); @@ -1128,11 +1127,22 @@ impl Compiler { if let Some(emit) = emit_fields.as_mut() { 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)?; - let field_code = ctx.bytecode.split_off(start); - ctx.after_super_insert = Some(field_code); - ctx.after_super_inserted = false; + let field_buffer = FieldBuffer { + bytecode: std::mem::take(&mut ctx.bytecode), + 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 { emit(self, &mut ctx)?; } diff --git a/crates/oxide_compiler/src/expr/call.rs b/crates/oxide_compiler/src/expr/call.rs index c7691b4..5264000 100644 --- a/crates/oxide_compiler/src/expr/call.rs +++ b/crates/oxide_compiler/src/expr/call.rs @@ -19,10 +19,15 @@ impl Compiler { let result_reg = ctx.alloc_reg(); ctx.emit(opcode::encode(OpCode::SUPER_CALL, result_reg, first_arg_reg, 0)); ctx.emit(arg_regs.len() as u32); - if !ctx.after_super_inserted { - if let Some(field_code) = ctx.after_super_insert.clone() { - ctx.bytecode.extend(field_code); - ctx.after_super_inserted = true; + if let Some(mut field_buffer) = ctx.field_buffer.take() { + let insert_pc = ctx.bytecode.len(); + ctx.bytecode.append(&mut field_buffer.bytecode); + 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); diff --git a/crates/oxide_compiler/tests/compile_stmt_tests.rs b/crates/oxide_compiler/tests/compile_stmt_tests.rs index 9138070..f3d56b6 100644 --- a/crates/oxide_compiler/tests/compile_stmt_tests.rs +++ b/crates/oxide_compiler/tests/compile_stmt_tests.rs @@ -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] fn compile_class_declaration_default_constructor_creates_submodule() { let module = compile_source("class A {}");