diff --git a/Cargo.lock b/Cargo.lock index 278c04db..31927dad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1160,7 +1160,7 @@ dependencies = [ [[package]] name = "oxide_builtins" -version = "0.19.35" +version = "0.19.36" dependencies = [ "chrono", "fast-float", @@ -1185,7 +1185,7 @@ dependencies = [ [[package]] name = "oxide_bytecode" -version = "0.19.35" +version = "0.19.36" dependencies = [ "num-bigint", "oxide_log", @@ -1193,7 +1193,7 @@ dependencies = [ [[package]] name = "oxide_cfg" -version = "0.19.35" +version = "0.19.36" dependencies = [ "oxide_bytecode", "oxide_emit", @@ -1204,7 +1204,7 @@ dependencies = [ [[package]] name = "oxide_cli" -version = "0.19.35" +version = "0.19.36" dependencies = [ "ansi_term", "bumpalo", @@ -1228,7 +1228,7 @@ dependencies = [ [[package]] name = "oxide_code_cache" -version = "0.19.35" +version = "0.19.36" dependencies = [ "lru", "oxide_bytecode", @@ -1237,7 +1237,7 @@ dependencies = [ [[package]] name = "oxide_compiler" -version = "0.19.35" +version = "0.19.36" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1258,7 +1258,7 @@ dependencies = [ [[package]] name = "oxide_dce" -version = "0.19.35" +version = "0.19.36" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1272,7 +1272,7 @@ dependencies = [ [[package]] name = "oxide_emit" -version = "0.19.35" +version = "0.19.36" dependencies = [ "num-bigint", "oxc_allocator", @@ -1288,7 +1288,7 @@ dependencies = [ [[package]] name = "oxide_engine" -version = "0.19.35" +version = "0.19.36" dependencies = [ "oxide_bytecode", "oxide_compiler", @@ -1300,7 +1300,7 @@ dependencies = [ [[package]] name = "oxide_fold" -version = "0.19.35" +version = "0.19.36" dependencies = [ "num-bigint", "oxide_bytecode", @@ -1312,7 +1312,7 @@ dependencies = [ [[package]] name = "oxide_ir" -version = "0.19.35" +version = "0.19.36" dependencies = [ "oxide_bytecode", "oxide_log", @@ -1321,7 +1321,7 @@ dependencies = [ [[package]] name = "oxide_kernel" -version = "0.19.35" +version = "0.19.36" dependencies = [ "bumpalo", "dashmap", @@ -1335,7 +1335,7 @@ dependencies = [ [[package]] name = "oxide_liveness" -version = "0.19.35" +version = "0.19.36" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1347,7 +1347,7 @@ dependencies = [ [[package]] name = "oxide_log" -version = "0.19.35" +version = "0.19.36" dependencies = [ "tracing", "tracing-appender", @@ -1356,11 +1356,11 @@ dependencies = [ [[package]] name = "oxide_net" -version = "0.19.35" +version = "0.19.36" [[package]] name = "oxide_parser" -version = "0.19.35" +version = "0.19.36" dependencies = [ "oxc_allocator", "oxc_ast", @@ -1375,7 +1375,7 @@ dependencies = [ [[package]] name = "oxide_regalloc" -version = "0.19.35" +version = "0.19.36" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1391,7 +1391,7 @@ dependencies = [ [[package]] name = "oxide_runtime_api" -version = "0.19.35" +version = "0.19.36" dependencies = [ "num-bigint", "num-traits", @@ -1404,7 +1404,7 @@ dependencies = [ [[package]] name = "oxide_test262" -version = "0.19.35" +version = "0.19.36" dependencies = [ "oxide_bytecode", "oxide_compiler", @@ -1424,7 +1424,7 @@ dependencies = [ [[package]] name = "oxide_types" -version = "0.19.35" +version = "0.19.36" dependencies = [ "bumpalo", "dashmap", @@ -1437,7 +1437,7 @@ dependencies = [ [[package]] name = "oxide_vm" -version = "0.19.35" +version = "0.19.36" dependencies = [ "bumpalo", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 677eafd7..de070c07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ members = [ ] [workspace.package] -version = "0.19.35" +version = "0.19.36" edition = "2021" license = "MIT" rust-version = "1.80" diff --git a/crates/oxide_emit/src/class/field.rs b/crates/oxide_emit/src/class/field.rs index c58e4bc0..dea4bded 100644 --- a/crates/oxide_emit/src/class/field.rs +++ b/crates/oxide_emit/src/class/field.rs @@ -14,10 +14,8 @@ impl Emitter { &self, elements: &[ClassElement], ctor_reg: u32, key_slots: &[Option], ctx: &mut CompileCtx, ) -> Result<(), String> { let saved_static_this = ctx.static_block_this_reg; - // static_block_this_reg 保留 u8(this 槽语义,254 特判),ctor_reg 超 u8 界时报错而非静默截断。 - ctx.static_block_this_reg = Some( - u8::try_from(ctor_reg).map_err(|_| format!("class constructor register {ctor_reg} exceeds u8 limit"))?, - ); + // ctor_reg 是 vreg 号(RegAlloc 期压缩到物理域),直接存 u32,不截断。 + ctx.static_block_this_reg = Some(ctor_reg); for (element, &key_slot) in elements.iter().zip(key_slots) { match element { ClassElement::PropertyDefinition(prop) => { diff --git a/crates/oxide_emit/src/compile_ctx.rs b/crates/oxide_emit/src/compile_ctx.rs index 6e79483e..cf5f3dc8 100644 --- a/crates/oxide_emit/src/compile_ctx.rs +++ b/crates/oxide_emit/src/compile_ctx.rs @@ -66,7 +66,9 @@ pub struct CompileCtx { /// 源码是否为 `source_escape` 产物(动态编译入口):正则字面量源文本切片 /// 的池键形态据此选择(见 [`Emitter::source_encoded`])。 pub(crate) source_encoded: bool, - pub(crate) static_block_this_reg: Option, + /// 静态块内 `this` 的构造器寄存器(vreg 号,无 u8 上限,RegAlloc 期压缩到物理域)。 + /// None 表示非静态块上下文,`this` 走常规 this 槽。 + pub(crate) static_block_this_reg: Option, pub(crate) field_buffer: Option, /// 类构造器模块中 `@@field_keys` upvalue 下标(实例字段 computed key 数组)。 /// 类定义期求值一次存入 cell,构造器经此 upvalue 读取。 diff --git a/crates/oxide_emit/src/expr/this.rs b/crates/oxide_emit/src/expr/this.rs index 82e5af80..9b665ee8 100644 --- a/crates/oxide_emit/src/expr/this.rs +++ b/crates/oxide_emit/src/expr/this.rs @@ -8,8 +8,12 @@ use oxide_ir::operand::Operand; impl Emitter { pub(crate) fn emit_this_expression(&self, ctx: &mut CompileCtx) -> Result { let r = ctx.alloc_reg(); - let src = ctx.static_block_this_reg.unwrap_or(254); - let src_op = if src == 254 { Operand::This } else { Operand::Reg(src as u32) }; + // None 是常规 this 槽;Some(reg) 是类构造器 vreg(vreg 号可越过 254, + // 按寄存器处理,不与 this 槽特判混淆)。 + let src_op = match ctx.static_block_this_reg { + None => Operand::This, + Some(reg) => Operand::Reg(reg), + }; ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(r), src_op, Operand::None)); Ok(r) } diff --git a/crates/oxide_emit/tests/emit_ir_tests.rs b/crates/oxide_emit/tests/emit_ir_tests.rs index 7d141431..47365402 100644 --- a/crates/oxide_emit/tests/emit_ir_tests.rs +++ b/crates/oxide_emit/tests/emit_ir_tests.rs @@ -576,3 +576,33 @@ fn private_field_read_captures_object() { let names: HashSet<&str> = inner.upvalue_captures.iter().map(|c| c.name.as_str()).collect(); assert!(names.contains("self"), "私有字段读路径目标对象须入捕获集"); } + +/// 面 21:顶层 vreg 号越过 255 后,类静态块 `this` 仍正确读类构造器 vreg—— +/// 构造器寄存器不截断、不与 this 槽(254)特判混淆。 +#[test] +fn static_block_this_reads_ctor_vreg_beyond_u8() { + // 大量顶层 var 把 vreg 号推过 255,再声明含静态块的类。 + let mut src = String::new(); + for i in 0..300 { + src.push_str(&format!("var v{i} = {i};\n")); + } + src.push_str("class C { static { this.x = 1; } }"); + // 修复前此源码 emit 报「class constructor register … exceeds u8 limit」, + // `emit_ir` 会 panic。 + let ir = emit_ir(&src); + // 静态块 `this` 应发 LOAD_VAR 读构造器 vreg(Operand::Reg),非 this 槽。 + let this_load = ir + .insts + .iter() + .filter(|i| i.op == OpCode::LOAD_VAR) + .find(|i| matches!(i.a, Operand::Reg(_))) + .expect("静态块 this 应发 LOAD_VAR Reg"); + let Operand::Reg(r) = this_load.a else { + unreachable!() + }; + assert!(r > 255, "静态块 this 的构造器 vreg 号应越过 255:{r}"); + assert!( + !ir.insts.iter().any(|i| i.op == OpCode::LOAD_VAR && matches!(i.a, Operand::This)), + "静态块 this 不应走 this 槽" + ); +}