diff --git a/Cargo.lock b/Cargo.lock index 81c29167..92cb6d61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1160,7 +1160,7 @@ dependencies = [ [[package]] name = "oxide_builtins" -version = "0.8.97" +version = "0.8.98" dependencies = [ "chrono", "fast-float", @@ -1185,7 +1185,7 @@ dependencies = [ [[package]] name = "oxide_bytecode" -version = "0.8.97" +version = "0.8.98" dependencies = [ "num-bigint", "oxide_log", @@ -1193,7 +1193,7 @@ dependencies = [ [[package]] name = "oxide_cfg" -version = "0.8.97" +version = "0.8.98" dependencies = [ "oxide_bytecode", "oxide_emit", @@ -1204,7 +1204,7 @@ dependencies = [ [[package]] name = "oxide_cli" -version = "0.8.97" +version = "0.8.98" dependencies = [ "ansi_term", "bumpalo", @@ -1226,7 +1226,7 @@ dependencies = [ [[package]] name = "oxide_code_cache" -version = "0.8.97" +version = "0.8.98" dependencies = [ "lru", "oxide_bytecode", @@ -1235,7 +1235,7 @@ dependencies = [ [[package]] name = "oxide_compiler" -version = "0.8.97" +version = "0.8.98" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1255,7 +1255,7 @@ dependencies = [ [[package]] name = "oxide_dce" -version = "0.8.97" +version = "0.8.98" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1269,7 +1269,7 @@ dependencies = [ [[package]] name = "oxide_emit" -version = "0.8.97" +version = "0.8.98" dependencies = [ "num-bigint", "oxc_allocator", @@ -1284,7 +1284,7 @@ dependencies = [ [[package]] name = "oxide_engine" -version = "0.8.97" +version = "0.8.98" dependencies = [ "oxide_bytecode", "oxide_compiler", @@ -1296,7 +1296,7 @@ dependencies = [ [[package]] name = "oxide_ir" -version = "0.8.97" +version = "0.8.98" dependencies = [ "oxide_bytecode", "oxide_log", @@ -1305,7 +1305,7 @@ dependencies = [ [[package]] name = "oxide_kernel" -version = "0.8.97" +version = "0.8.98" dependencies = [ "bumpalo", "dashmap", @@ -1319,7 +1319,7 @@ dependencies = [ [[package]] name = "oxide_liveness" -version = "0.8.97" +version = "0.8.98" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1331,7 +1331,7 @@ dependencies = [ [[package]] name = "oxide_log" -version = "0.8.97" +version = "0.8.98" dependencies = [ "tracing", "tracing-appender", @@ -1340,7 +1340,7 @@ dependencies = [ [[package]] name = "oxide_parser" -version = "0.8.97" +version = "0.8.98" dependencies = [ "oxc_allocator", "oxc_ast", @@ -1355,7 +1355,7 @@ dependencies = [ [[package]] name = "oxide_regalloc" -version = "0.8.97" +version = "0.8.98" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1371,7 +1371,7 @@ dependencies = [ [[package]] name = "oxide_runtime_api" -version = "0.8.97" +version = "0.8.98" dependencies = [ "num-bigint", "num-traits", @@ -1384,7 +1384,7 @@ dependencies = [ [[package]] name = "oxide_test262" -version = "0.8.97" +version = "0.8.98" dependencies = [ "oxide_bytecode", "oxide_compiler", @@ -1402,7 +1402,7 @@ dependencies = [ [[package]] name = "oxide_types" -version = "0.8.97" +version = "0.8.98" dependencies = [ "bumpalo", "dashmap", @@ -1415,7 +1415,7 @@ dependencies = [ [[package]] name = "oxide_vm" -version = "0.8.97" +version = "0.8.98" dependencies = [ "bumpalo", "chrono", diff --git a/Cargo.toml b/Cargo.toml index dc18c2e9..55766950 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ members = [ ] [workspace.package] -version = "0.8.97" +version = "0.8.98" edition = "2021" license = "MIT" rust-version = "1.80" diff --git a/crates/oxide_emit/src/stmt/exception/try_catch.rs b/crates/oxide_emit/src/stmt/exception/try_catch.rs index d5614f1b..9eeb99fd 100644 --- a/crates/oxide_emit/src/stmt/exception/try_catch.rs +++ b/crates/oxide_emit/src/stmt/exception/try_catch.rs @@ -19,6 +19,10 @@ impl Emitter { let has_catch = ts.handler.is_some(); let has_finally = ts.finalizer.is_some(); let result_reg = ctx.alloc_reg(); + // try 语句整体是 `UpdateEmpty(_, undefined)` 站点:压边界帧,位于 + // try/catch/finally 三个体列表帧之外,非空内层列表值穿透、空内层体 + // 携值物化 undefined。 + ctx.push_completion_boundary(); if has_finally { // finally 域跨整个语句(try 体 + catch 体 + finally 体):期间 break/continue // 逃出语句时须穿越本 finally,词法上记录域深度供跨越计数。 @@ -144,6 +148,7 @@ impl Emitter { ctx.pop_finally_domain(); } ctx.labels.set_label_pos(try_end_label, ctx.insts.len()); + ctx.pop_completion_boundary(); Ok(Some(result_reg)) } } diff --git a/crates/oxide_vm/tests/eval_tests.rs b/crates/oxide_vm/tests/eval_tests.rs index e68a88f4..249a2330 100644 --- a/crates/oxide_vm/tests/eval_tests.rs +++ b/crates/oxide_vm/tests/eval_tests.rs @@ -328,6 +328,50 @@ fn compound_statement_completion_values() { assert_num(result, 5.0); let result = eval(&mut vm, "a: { try { throw 1; } catch (e) { 5; break a; } }").unwrap(); assert_num(result, 5.0); + // try 边界帧:空 catch/finally 体 break/continue 携值物化 undefined(无 if + // 守卫独立验收形),非空 finally 体值穿透。 + let result = eval( + &mut vm, + "for (var i = 0; i < 2; ++i) { try { throw null; } catch (e) { break; } 'bad completion'; }", + ) + .unwrap(); + assert_eq!(result, JsValue::undefined()); + let result = eval( + &mut vm, + "for (var i = 0; i < 2; ++i) { try { throw null; } catch (e) { continue; } 'bad completion'; }", + ) + .unwrap(); + assert_eq!(result, JsValue::undefined()); + let result = eval(&mut vm, "for (var i = 0; i < 2; ++i) { try {} finally { break; } 'bad completion'; }").unwrap(); + assert_eq!(result, JsValue::undefined()); + let result = + eval(&mut vm, "for (var i = 0; i < 2; ++i) { try {} finally { continue; } 'bad completion'; }").unwrap(); + assert_eq!(result, JsValue::undefined()); + let result = eval( + &mut vm, + "for (var i = 0; i < 2; ++i) { try { throw null; } catch (e) {} finally { break; } 'bad completion'; }", + ) + .unwrap(); + assert_eq!(result, JsValue::undefined()); + let result = eval( + &mut vm, + "for (var i = 0; i < 2; ++i) { try { throw null; } catch (e) {} finally { continue; } 'bad completion'; }", + ) + .unwrap(); + assert_eq!(result, JsValue::undefined()); + // 跨 finally 值通道守卫:非空 finally 体值穿透,空 finally 体物化 undefined。 + let result = eval( + &mut vm, + "99; do { -99; try { 39 } catch (e) { -1 } finally { 42; break; -2 }; } while (false);", + ) + .unwrap(); + assert_num(result, 42.0); + let result = eval( + &mut vm, + "99; do { -99; try { 39 } catch (e) { -1 } finally { break; -2 }; } while (false);", + ) + .unwrap(); + assert_eq!(result, JsValue::undefined()); // for 泄漏形完成值:体不读循环变量加常量尾,取末次迭代体值,前值不沿用。 let result = eval(&mut vm, "for (var i = 0; i < 2; ++i) { 42 }").unwrap(); assert_num(result, 42.0);