fix: 对齐 class 体 counter/emitter 指令条数,修私有方法、计算键、派生构造器字段注入位置的跳转漂移

This commit is contained in:
2026-06-27 20:50:12 +08:00
parent 3794ae3fd5
commit 03c9809c30
5 changed files with 130 additions and 17 deletions
+18 -8
View File
@@ -160,6 +160,10 @@ pub(crate) struct CompileCtx {
pub(crate) static_block_this_reg: Option<u8>,
pub(crate) after_super_insert: Option<Vec<opcode::Instr>>,
pub(crate) after_super_inserted: bool,
/// Count-pass mirror of `after_super_insert`: the instruction count of a derived
/// constructor's instance-field code, added at the super() call site during body
/// counting so projected_pc matches where the emit pass splices the field bytecode.
pub(crate) after_super_count_words: Option<usize>,
/// 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.
pub(crate) reg_overflow: bool,
@@ -233,6 +237,7 @@ impl CompileCtx {
static_block_this_reg: None,
after_super_insert: None,
after_super_inserted: false,
after_super_count_words: None,
reg_overflow: false,
const_overflow: false,
jump_overflow: false,
@@ -731,20 +736,25 @@ impl Compiler {
}
}
// Count pass
if !fields_after_super {
if let Some(count) = count_fields.as_mut() {
// Count pass. For derived constructors the emit pass allocates/counts the instance
// fields up front but splices the field bytecode into the body right after SUPER_CALL.
// Mirror that: count the fields (allocating the same registers/constants), capture
// their instruction count, undo the position here, and re-add it at the super() call
// site during body counting so labels after super() line up with the emit pass.
if let Some(count) = count_fields.as_mut() {
if fields_after_super {
let before = ctx.projected_pc;
count(self, &mut ctx);
let field_words = ctx.projected_pc - before;
ctx.projected_pc = before;
ctx.after_super_count_words = Some(field_words);
} else {
count(self, &mut ctx);
}
}
for stmt in body_stmts {
self.count_statement(stmt, &mut ctx);
}
if fields_after_super {
if let Some(count) = count_fields.as_mut() {
count(self, &mut ctx);
}
}
ctx.max_regs = ctx.max_regs.max(1);
ctx.reg_overflow = false;
ctx.reset_regs();
@@ -13,6 +13,10 @@ impl Compiler {
}
ctx.alloc_reg();
ctx.count_call_instr_with_arg_ext(); // SUPER_CALL + arg_count ext word
// Mirror emit: derived-ctor instance fields are injected right after super().
if let Some(words) = ctx.after_super_count_words.take() {
ctx.projected_pc += words;
}
return;
}
@@ -35,15 +35,19 @@ impl Compiler {
continue;
}
if matches!(method.key, oxide_parser::PropertyKey::PrivateIdentifier(_)) {
if method.r#static {
ctx.count_load_const(); // private id
ctx.count_load_const(); // method
ctx.count_instr(); // INIT_PRIVATE
}
// Mirror emit_private_method_init for static AND non-static private
// methods: private-id LOAD_CONST + CREATE_CLOSURE + SET_HOME_OBJECT +
// INIT_PRIVATE.
ctx.count_load_const(); // private id reg
ctx.count_load_const(); // method closure (CREATE_CLOSURE)
ctx.count_instr(); // SET_HOME_OBJECT
ctx.count_instr(); // INIT_PRIVATE
continue;
}
ctx.count_load_const(); // key_reg
ctx.count_load_const(); // method_reg
// Computed method key emits the full key expression; a plain key is one
// LOAD_CONST. Mirror emit_class_key_reg via the shared count_class_key.
self.count_class_key(&method.key, method.computed, ctx);
ctx.count_load_const(); // method closure (CREATE_CLOSURE)
ctx.count_instr(); // SET_HOME_OBJECT
match method.kind {
MethodDefinitionKind::Method => {
@@ -59,7 +63,9 @@ impl Compiler {
ClassElement::PropertyDefinition(prop) => {
let prop = prop.as_ref();
if prop.r#static {
ctx.count_load_const(); // key_reg
// Computed static field key emits the full key expression; mirror
// emit_public_field_init via the shared count_class_key.
self.count_class_key(&prop.key, prop.computed, ctx);
if let Some(value) = &prop.value {
self.count_expression(value, ctx);
} else {
+1 -1
View File
@@ -247,7 +247,7 @@ impl Compiler {
self.emit_expression(key.to_expression(), ctx)
}
fn count_class_key(&self, key: &PropertyKey, computed: bool, ctx: &mut CompileCtx) {
pub(crate) fn count_class_key(&self, key: &PropertyKey, computed: bool, ctx: &mut CompileCtx) {
if computed {
self.count_expression(key.to_expression(), ctx);
} else {