From f5367ce32bcc161350de5be8b92e79dfcef31e89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Wed, 26 Aug 2026 16:54:38 +0200 Subject: [PATCH 1/3] fix: clear v0.5.1519 r19 release blockers --- changelog.d/8864-release-r19-blockers.md | 3 +++ crates/perry-runtime/src/closure/unbox.rs | 15 ++++++++++++--- .../expected/test_parity_native_value_profile.txt | 2 +- 3 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 changelog.d/8864-release-r19-blockers.md diff --git a/changelog.d/8864-release-r19-blockers.md b/changelog.d/8864-release-r19-blockers.md new file mode 100644 index 0000000000..20a4f93c3a --- /dev/null +++ b/changelog.d/8864-release-r19-blockers.md @@ -0,0 +1,3 @@ +### Fixed + +- Kept non-callable value-call errors catchable across the checked-unbox runtime boundary and refreshed the native-value-profile parity expectation for its intentional POD-copy coverage. diff --git a/crates/perry-runtime/src/closure/unbox.rs b/crates/perry-runtime/src/closure/unbox.rs index c365a0be1e..243eea3b3e 100644 --- a/crates/perry-runtime/src/closure/unbox.rs +++ b/crates/perry-runtime/src/closure/unbox.rs @@ -21,8 +21,13 @@ use super::dispatch::throw_not_callable; /// available. A callable value (closure, bound method/function, native /// handle) is always `POINTER_TAG`; numbers, strings, bigints, booleans, /// null and undefined are not, and throw here. +/// +/// `C-unwind` is required because `throw_not_callable` can raise a Perry +/// exception through the system unwinder to generated code's landing pad. +/// A plain `extern "C"` boundary turns that catchable throw into +/// `panic_cannot_unwind` and aborts the process. #[no_mangle] -pub extern "C" fn js_closure_unbox_callee_checked(callee: f64) -> i64 { +pub extern "C-unwind" fn js_closure_unbox_callee_checked(callee: f64) -> i64 { let bits = callee.to_bits(); if bits & crate::value::TAG_MASK != crate::value::POINTER_TAG { throw_not_callable(); @@ -48,7 +53,7 @@ pub extern "C" fn js_closure_unbox_callee_checked(callee: f64) -> i64 { /// `this` (plain functions, arrows), so receiverless shapes and the common /// own-method call (baked `this` == receiver) keep their exact behavior. #[no_mangle] -pub extern "C" fn js_closure_unbox_callee_checked_rebind(callee: f64, receiver: f64) -> i64 { +pub extern "C-unwind" fn js_closure_unbox_callee_checked_rebind(callee: f64, receiver: f64) -> i64 { let bits = callee.to_bits(); if bits & crate::value::TAG_MASK != crate::value::POINTER_TAG { throw_not_callable(); @@ -60,5 +65,9 @@ pub extern "C" fn js_closure_unbox_callee_checked_rebind(callee: f64, receiver: /// Keepalive: generated code is the only caller (#6475). #[cfg(feature = "keepalive-anchors")] #[used] -static KEEP_JS_CLOSURE_UNBOX_CALLEE_CHECKED_REBIND: extern "C" fn(f64, f64) -> i64 = +static KEEP_JS_CLOSURE_UNBOX_CALLEE_CHECKED_REBIND: extern "C-unwind" fn(f64, f64) -> i64 = js_closure_unbox_callee_checked_rebind; + +// Compile-time ABI guards for both throw-capable generated-code boundaries. +const _: extern "C-unwind" fn(f64) -> i64 = js_closure_unbox_callee_checked; +const _: extern "C-unwind" fn(f64, f64) -> i64 = js_closure_unbox_callee_checked_rebind; diff --git a/test-parity/expected/test_parity_native_value_profile.txt b/test-parity/expected/test_parity_native_value_profile.txt index 485980b450..9050e2bd0c 100644 --- a/test-parity/expected/test_parity_native_value_profile.txt +++ b/test-parity/expected/test_parity_native_value_profile.txt @@ -1 +1 @@ -size=24,align=8,sequence=8,length=1,flags=4294967295,sequenceValue=9007199254740991,gainRounded=true,tiny=2:1:255:255:7,narrow=16:2:4:8:-128:65535:-32768:-9007199254740991:-5:65535:-1024:-42,header=7:42:true,rejectedFraction=true,rejectedType=true,rejectedOctet=true,rejectedSignedByte=true,rejectedHalfWord=true,rejectedSignedHalfWord=true,rejectedSignedSize=true +size=24,align=8,sequence=8,length=1,flags=4294967295,sequenceValue=9007199254740991,gainRounded=true,tiny=2:1:255:255:7,narrow=16:2:4:8:-128:65535:-32768:-9007199254740991:-5:65535:-1024:-42,header=7:42:true,podCopy=7:9:513:-8,rejectedFraction=true,rejectedType=true,rejectedOctet=true,rejectedSignedByte=true,rejectedHalfWord=true,rejectedSignedHalfWord=true,rejectedSignedSize=true From 4ed0a51b7ff795dacfc5e4dc7858a6e1c0182196 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Wed, 26 Aug 2026 16:59:46 +0200 Subject: [PATCH 2/3] ci: retrigger release blocker checks From 0b053fa8ac353a0b7a0dca2db934a18a0233e161 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Wed, 26 Aug 2026 17:05:13 +0200 Subject: [PATCH 3/3] fix(stdlib): remove stale stdin close arm --- changelog.d/8864-release-r19-blockers.md | 2 +- crates/perry-stdlib/src/readline/mod.rs | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/changelog.d/8864-release-r19-blockers.md b/changelog.d/8864-release-r19-blockers.md index 20a4f93c3a..03145f39b7 100644 --- a/changelog.d/8864-release-r19-blockers.md +++ b/changelog.d/8864-release-r19-blockers.md @@ -1,3 +1,3 @@ ### Fixed -- Kept non-callable value-call errors catchable across the checked-unbox runtime boundary and refreshed the native-value-profile parity expectation for its intentional POD-copy coverage. +- Kept non-callable value-call errors catchable across the checked-unbox runtime boundary, refreshed the native-value-profile parity expectation for its intentional POD-copy coverage, and removed a duplicate stdin listener match arm that made current `main` fail the warnings gate. diff --git a/crates/perry-stdlib/src/readline/mod.rs b/crates/perry-stdlib/src/readline/mod.rs index c6bbc00a17..a0a0069c1b 100644 --- a/crates/perry-stdlib/src/readline/mod.rs +++ b/crates/perry-stdlib/src/readline/mod.rs @@ -1699,12 +1699,6 @@ pub extern "C" fn js_readline_stdin_remove_listener( v.retain(|registered| *registered != callback); } } - "end" | "close" => CLOSE_CALLBACK.with(|cb| { - let mut cb = cb.borrow_mut(); - if *cb == Some(callback) { - *cb = None; - } - }), _ => {} } js_nanbox_pointer(STDIN_READLINE_HANDLE)