fix: 顶层 count pass 镜像 emit 的函数提升顺序,消除跳转目标漂移导致的死循环
This commit is contained in:
@@ -866,8 +866,19 @@ impl Compiler {
|
|||||||
let mut ctx = CompileCtx::new();
|
let mut ctx = CompileCtx::new();
|
||||||
ctx.pre_register_builtins();
|
ctx.pre_register_builtins();
|
||||||
|
|
||||||
|
// The emit pass below hoists FunctionDeclarations to the front. The count pass
|
||||||
|
// must walk in that same order: counting in source order would record jump-target
|
||||||
|
// labels at source-order PCs while emit places code at hoisted-order PCs, drifting
|
||||||
|
// every jump that sits after a hoisted function declaration (infinite loops at run).
|
||||||
for stmt in &program.body {
|
for stmt in &program.body {
|
||||||
self.count_statement(stmt, &mut ctx);
|
if matches!(stmt, Statement::FunctionDeclaration(_)) {
|
||||||
|
self.count_statement(stmt, &mut ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for stmt in &program.body {
|
||||||
|
if !matches!(stmt, Statement::FunctionDeclaration(_)) {
|
||||||
|
self.count_statement(stmt, &mut ctx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
crate::compiler_debug!("counter: {} instructions estimated", ctx.projected_pc);
|
crate::compiler_debug!("counter: {} instructions estimated", ctx.projected_pc);
|
||||||
ctx.max_regs = ctx.max_regs.max(1);
|
ctx.max_regs = ctx.max_regs.max(1);
|
||||||
|
|||||||
@@ -38,6 +38,26 @@ fn coalesce_nonsimple_then_while() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A jump-bearing construct (if/loop) followed by a hoisted function declaration:
|
||||||
|
// the count pass must walk in the same function-hoisting order as the emit pass,
|
||||||
|
// otherwise the construct's jump targets drift past the hoisted body and the
|
||||||
|
// program loops forever at run time.
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn if_then_hoisted_function() {
|
||||||
|
assert_eq!(eval("if(false){} function f(){return 1} f()"), "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_of_then_hoisted_function() {
|
||||||
|
assert_eq!(eval("var r=0; for(const x of [1,2,3]) r+=x; function f(){return 100} r + f()"), "106");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn while_then_hoisted_function() {
|
||||||
|
assert_eq!(eval("var n=0; while(n<3){n=n+1;} function f(){return 100} n + f()"), "103");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn coalesce_nonsimple_then_for() {
|
fn coalesce_nonsimple_then_for() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
Reference in New Issue
Block a user