Skip to content

Commit adf28be

Browse files
proggeramlugRalph Küpper
andauthored
fix(runtime): permit dynamic construct throws to unwind (#8873)
* fix(runtime): permit dynamic construct throws to unwind * test: retain dynamic construct ABI regression --------- Co-authored-by: Ralph Küpper <ralph@skelpo.com>
1 parent d354443 commit adf28be

3 files changed

Lines changed: 13 additions & 4 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix catchable dynamic-constructor TypeErrors aborting at the runtime construct boundary.

crates/perry-runtime/src/object/class_registry/construct.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,11 @@ pub(crate) unsafe fn nm_ctor_stream(
230230
}
231231

232232
#[no_mangle]
233-
pub unsafe extern "C" fn js_new_function_construct(
233+
// This is a generated-code boundary whose TypeError paths unwind to the
234+
// caller's JavaScript catch landing pad. A plain `extern "C"` installs an
235+
// abort-on-unwind guard in the debug/static runtime, so `new <primitive>()`
236+
// aborts instead of remaining catchable.
237+
pub unsafe extern "C-unwind" fn js_new_function_construct(
234238
func_value: f64,
235239
args_ptr: *const f64,
236240
args_len: usize,
@@ -1160,6 +1164,8 @@ pub unsafe extern "C" fn js_new_function_construct(
11601164
super::super::object_ops::throw_object_type_error(b"is not a constructor")
11611165
}
11621166

1167+
const _: unsafe extern "C-unwind" fn(f64, *const f64, usize) -> f64 = js_new_function_construct;
1168+
11631169
/// `new <callee>(...spread)` — spread-bearing construction. Codegen builds a
11641170
/// single JS array containing every argument in evaluation order (regular args
11651171
/// pushed, spread sources expanded via `js_array_like_to_array` + concat), then

crates/perry/tests/issue_5253_construct_reference_source_location.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,13 @@ fn run_fixture(fixture: &str, extra_args: &[&str]) -> String {
9898
let bin = root.join("main_bin");
9999
let run = Command::new(&bin).output().expect("run compiled binary");
100100
// Both fixtures catch the throw and log it, so the program must exit
101-
// cleanly. Preserve stderr here so an ABI abort cannot masquerade as an
102-
// empty-output assertion failure.
101+
// cleanly. This is also the ABI regression assertion: every runtime
102+
// boundary between the throw helper and generated code's catch landing
103+
// pad must permit unwinding. Preserve stderr so an ABI abort cannot
104+
// masquerade as an empty-output assertion failure.
103105
assert!(
104106
run.status.success(),
105-
"compiled binary must exit successfully; status: {:?}\nstdout:\n{}\nstderr:\n{}",
107+
"compiled binary must catch the runtime throw and exit successfully; status: {:?}\nstdout:\n{}\nstderr:\n{}",
106108
run.status,
107109
String::from_utf8_lossy(&run.stdout),
108110
String::from_utf8_lossy(&run.stderr),

0 commit comments

Comments
 (0)