Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/8464-closure-unwind-family.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fix(runtime): the whole closure dispatch family is `extern "C-unwind"` now (#8463). #8416 let dynamic Function errors unwind but converted only `js_closure_call1`; every other edge (`call0`/`call3+`, `call2`'s inner transmute, `dispatch_with_arity`'s per-arity transmutes, `js_closure_call_array`/`_apply_with_spread`, the direct-call-site cache, `js_function_bind`) kept the abort-on-unwind shim, turning a deferred Function error into "panic in a function that cannot unwind" on Linux — the nightly `bun_ffi_stage1` abort. Registration entry points stay `extern "C"`.
4 changes: 2 additions & 2 deletions crates/perry-runtime/src/closure/dispatch/bound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ unsafe fn read_function_name_property(closure_ptr: usize) -> Option<String> {
/// `.name` is set to `"bound " + target.name` and `.length` to
/// `max(0, target.length - boundArgs.length)`, matching Node. Refs #2840.
#[no_mangle]
pub unsafe extern "C" fn js_function_bind(
pub unsafe extern "C-unwind" fn js_function_bind(
target_value: f64,
args_ptr: *const f64,
args_len: usize,
Expand Down Expand Up @@ -489,7 +489,7 @@ pub unsafe extern "C" fn js_function_bind(
/// survives the bitcode pipeline. See project_auto_optimize_keepalive_3320.
#[cfg(feature = "keepalive-anchors")]
#[used]
static KEEP_JS_FUNCTION_BIND: unsafe extern "C" fn(f64, *const f64, usize) -> f64 =
static KEEP_JS_FUNCTION_BIND: unsafe extern "C-unwind" fn(f64, *const f64, usize) -> f64 =
js_function_bind;

/// Reify a `Function.prototype.{bind,call,apply}` (or any function method)
Expand Down
73 changes: 41 additions & 32 deletions crates/perry-runtime/src/closure/dispatch/calln.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use super::*;

/// Call a closure with 0 arguments, returning f64
#[no_mangle]
pub extern "C" fn js_closure_call0(closure: *const ClosureHeader) -> f64 {
pub extern "C-unwind" fn js_closure_call0(closure: *const ClosureHeader) -> f64 {
let func_ptr = get_valid_func_ptr(closure);
if func_ptr.is_null() {
return dispatch_proxy_callee_or_throw(closure, &[]);
Expand All @@ -26,7 +26,7 @@ pub extern "C" fn js_closure_call0(closure: *const ClosureHeader) -> f64 {
dispatch_with_arity(closure, func_ptr, &[], declared)
},
_ => {
let func: extern "C" fn(*const ClosureHeader) -> f64 =
let func: extern "C-unwind" fn(*const ClosureHeader) -> f64 =
unsafe { std::mem::transmute(func_ptr) };
func(closure)
}
Expand Down Expand Up @@ -84,7 +84,7 @@ pub extern "C-unwind" fn js_closure_call2(
dispatch_with_arity(closure, func_ptr, &[arg0, arg1], declared)
},
_ => {
let func: extern "C" fn(*const ClosureHeader, f64, f64) -> f64 =
let func: extern "C-unwind" fn(*const ClosureHeader, f64, f64) -> f64 =
unsafe { std::mem::transmute(func_ptr) };
func(closure, arg0, arg1)
}
Expand All @@ -93,7 +93,7 @@ pub extern "C-unwind" fn js_closure_call2(

/// Call a closure with 3 arguments, returning f64
#[no_mangle]
pub extern "C" fn js_closure_call3(
pub extern "C-unwind" fn js_closure_call3(
closure: *const ClosureHeader,
arg0: f64,
arg1: f64,
Expand All @@ -117,7 +117,7 @@ pub extern "C" fn js_closure_call3(
dispatch_with_arity(closure, func_ptr, &[arg0, arg1, arg2], declared)
},
_ => {
let func: extern "C" fn(*const ClosureHeader, f64, f64, f64) -> f64 =
let func: extern "C-unwind" fn(*const ClosureHeader, f64, f64, f64) -> f64 =
unsafe { std::mem::transmute(func_ptr) };
func(closure, arg0, arg1, arg2)
}
Expand All @@ -126,7 +126,7 @@ pub extern "C" fn js_closure_call3(

/// Call a closure with 4 arguments, returning f64
#[no_mangle]
pub extern "C" fn js_closure_call4(
pub extern "C-unwind" fn js_closure_call4(
closure: *const ClosureHeader,
arg0: f64,
arg1: f64,
Expand Down Expand Up @@ -157,7 +157,7 @@ pub extern "C" fn js_closure_call4(
dispatch_with_arity(closure, func_ptr, &[arg0, arg1, arg2, arg3], declared)
},
_ => {
let func: extern "C" fn(*const ClosureHeader, f64, f64, f64, f64) -> f64 =
let func: extern "C-unwind" fn(*const ClosureHeader, f64, f64, f64, f64) -> f64 =
unsafe { std::mem::transmute(func_ptr) };
func(closure, arg0, arg1, arg2, arg3)
}
Expand All @@ -166,7 +166,7 @@ pub extern "C" fn js_closure_call4(

/// Call a closure with 5 arguments, returning f64
#[no_mangle]
pub extern "C" fn js_closure_call5(
pub extern "C-unwind" fn js_closure_call5(
closure: *const ClosureHeader,
arg0: f64,
arg1: f64,
Expand Down Expand Up @@ -202,14 +202,14 @@ pub extern "C" fn js_closure_call5(
};
}
}
let func: extern "C" fn(*const ClosureHeader, f64, f64, f64, f64, f64) -> f64 =
let func: extern "C-unwind" fn(*const ClosureHeader, f64, f64, f64, f64, f64) -> f64 =
unsafe { std::mem::transmute(func_ptr) };
func(closure, arg0, arg1, arg2, arg3, arg4)
}

/// Call a closure with 6 arguments, returning f64
#[no_mangle]
pub extern "C" fn js_closure_call6(
pub extern "C-unwind" fn js_closure_call6(
closure: *const ClosureHeader,
arg0: f64,
arg1: f64,
Expand Down Expand Up @@ -251,7 +251,7 @@ pub extern "C" fn js_closure_call6(
};
}
}
let func: extern "C" fn(*const ClosureHeader, f64, f64, f64, f64, f64, f64) -> f64 =
let func: extern "C-unwind" fn(*const ClosureHeader, f64, f64, f64, f64, f64, f64) -> f64 =
unsafe { std::mem::transmute(func_ptr) };
func(closure, arg0, arg1, arg2, arg3, arg4, arg5)
}
Expand Down Expand Up @@ -291,7 +291,7 @@ pub(crate) fn dispatch_rest_or_declared_arity(

/// Call a closure with 7 arguments, returning f64
#[no_mangle]
pub extern "C" fn js_closure_call7(
pub extern "C-unwind" fn js_closure_call7(
closure: *const ClosureHeader,
arg0: f64,
arg1: f64,
Expand All @@ -316,14 +316,14 @@ pub extern "C" fn js_closure_call7(
if let Some(result) = dispatch_rest_or_declared_arity(closure, func_ptr, &args, 7) {
return result;
}
let func: extern "C" fn(*const ClosureHeader, f64, f64, f64, f64, f64, f64, f64) -> f64 =
let func: extern "C-unwind" fn(*const ClosureHeader, f64, f64, f64, f64, f64, f64, f64) -> f64 =
unsafe { std::mem::transmute(func_ptr) };
func(closure, arg0, arg1, arg2, arg3, arg4, arg5, arg6)
}

/// Call a closure with 8 arguments, returning f64
#[no_mangle]
pub extern "C" fn js_closure_call8(
pub extern "C-unwind" fn js_closure_call8(
closure: *const ClosureHeader,
arg0: f64,
arg1: f64,
Expand All @@ -349,14 +349,23 @@ pub extern "C" fn js_closure_call8(
if let Some(result) = dispatch_rest_or_declared_arity(closure, func_ptr, &args, 8) {
return result;
}
let func: extern "C" fn(*const ClosureHeader, f64, f64, f64, f64, f64, f64, f64, f64) -> f64 =
unsafe { std::mem::transmute(func_ptr) };
let func: extern "C-unwind" fn(
*const ClosureHeader,
f64,
f64,
f64,
f64,
f64,
f64,
f64,
f64,
) -> f64 = unsafe { std::mem::transmute(func_ptr) };
func(closure, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
}

/// Call a closure with 9 arguments, returning f64
#[no_mangle]
pub extern "C" fn js_closure_call9(
pub extern "C-unwind" fn js_closure_call9(
closure: *const ClosureHeader,
arg0: f64,
arg1: f64,
Expand All @@ -383,7 +392,7 @@ pub extern "C" fn js_closure_call9(
if let Some(result) = dispatch_rest_or_declared_arity(closure, func_ptr, &args, 9) {
return result;
}
let func: extern "C" fn(
let func: extern "C-unwind" fn(
*const ClosureHeader,
f64,
f64,
Expand All @@ -402,7 +411,7 @@ pub extern "C" fn js_closure_call9(

/// Call a closure with 10 arguments, returning f64
#[no_mangle]
pub extern "C" fn js_closure_call10(
pub extern "C-unwind" fn js_closure_call10(
closure: *const ClosureHeader,
arg0: f64,
arg1: f64,
Expand Down Expand Up @@ -430,7 +439,7 @@ pub extern "C" fn js_closure_call10(
if let Some(result) = dispatch_rest_or_declared_arity(closure, func_ptr, &args, 10) {
return result;
}
let func: extern "C" fn(
let func: extern "C-unwind" fn(
*const ClosureHeader,
f64,
f64,
Expand All @@ -450,7 +459,7 @@ pub extern "C" fn js_closure_call10(

/// Call a closure with 11 arguments, returning f64
#[no_mangle]
pub extern "C" fn js_closure_call11(
pub extern "C-unwind" fn js_closure_call11(
closure: *const ClosureHeader,
arg0: f64,
arg1: f64,
Expand Down Expand Up @@ -485,7 +494,7 @@ pub extern "C" fn js_closure_call11(
if let Some(result) = dispatch_rest_or_declared_arity(closure, func_ptr, &args, 11) {
return result;
}
let func: extern "C" fn(
let func: extern "C-unwind" fn(
*const ClosureHeader,
f64,
f64,
Expand All @@ -506,7 +515,7 @@ pub extern "C" fn js_closure_call11(

/// Call a closure with 12 arguments, returning f64
#[no_mangle]
pub extern "C" fn js_closure_call12(
pub extern "C-unwind" fn js_closure_call12(
closure: *const ClosureHeader,
arg0: f64,
arg1: f64,
Expand Down Expand Up @@ -542,7 +551,7 @@ pub extern "C" fn js_closure_call12(
if let Some(result) = dispatch_rest_or_declared_arity(closure, func_ptr, &args, 12) {
return result;
}
let func: extern "C" fn(
let func: extern "C-unwind" fn(
*const ClosureHeader,
f64,
f64,
Expand All @@ -564,7 +573,7 @@ pub extern "C" fn js_closure_call12(

/// Call a closure with 13 arguments, returning f64
#[no_mangle]
pub extern "C" fn js_closure_call13(
pub extern "C-unwind" fn js_closure_call13(
closure: *const ClosureHeader,
arg0: f64,
arg1: f64,
Expand Down Expand Up @@ -601,7 +610,7 @@ pub extern "C" fn js_closure_call13(
if let Some(result) = dispatch_rest_or_declared_arity(closure, func_ptr, &args, 13) {
return result;
}
let func: extern "C" fn(
let func: extern "C-unwind" fn(
*const ClosureHeader,
f64,
f64,
Expand All @@ -624,7 +633,7 @@ pub extern "C" fn js_closure_call13(

/// Call a closure with 14 arguments, returning f64
#[no_mangle]
pub extern "C" fn js_closure_call14(
pub extern "C-unwind" fn js_closure_call14(
closure: *const ClosureHeader,
arg0: f64,
arg1: f64,
Expand Down Expand Up @@ -663,7 +672,7 @@ pub extern "C" fn js_closure_call14(
if let Some(result) = dispatch_rest_or_declared_arity(closure, func_ptr, &args, 14) {
return result;
}
let func: extern "C" fn(
let func: extern "C-unwind" fn(
*const ClosureHeader,
f64,
f64,
Expand All @@ -688,7 +697,7 @@ pub extern "C" fn js_closure_call14(

/// Call a closure with 15 arguments, returning f64
#[no_mangle]
pub extern "C" fn js_closure_call15(
pub extern "C-unwind" fn js_closure_call15(
closure: *const ClosureHeader,
arg0: f64,
arg1: f64,
Expand Down Expand Up @@ -730,7 +739,7 @@ pub extern "C" fn js_closure_call15(
if let Some(result) = dispatch_rest_or_declared_arity(closure, func_ptr, &args, 15) {
return result;
}
let func: extern "C" fn(
let func: extern "C-unwind" fn(
*const ClosureHeader,
f64,
f64,
Expand All @@ -756,7 +765,7 @@ pub extern "C" fn js_closure_call15(

/// Call a closure with 16 arguments, returning f64
#[no_mangle]
pub extern "C" fn js_closure_call16(
pub extern "C-unwind" fn js_closure_call16(
closure: *const ClosureHeader,
arg0: f64,
arg1: f64,
Expand Down Expand Up @@ -799,7 +808,7 @@ pub extern "C" fn js_closure_call16(
if let Some(result) = dispatch_rest_or_declared_arity(closure, func_ptr, &args, 16) {
return result;
}
let func: extern "C" fn(
let func: extern "C-unwind" fn(
*const ClosureHeader,
f64,
f64,
Expand Down
8 changes: 4 additions & 4 deletions crates/perry-runtime/src/closure/dispatch/direct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ macro_rules! define_direct_call_site {
) => {
$(#[$meta])*
#[derive(Clone, Copy)]
pub struct $site(Option<extern "C" fn(*const ClosureHeader, $(define_direct_call_site!(@f64 $arg)),+) -> f64>);
pub struct $site(Option<extern "C-unwind" fn(*const ClosureHeader, $(define_direct_call_site!(@f64 $arg)),+) -> f64>);

impl $site {
/// Resolve `closure` once, before the loop.
Expand All @@ -98,7 +98,7 @@ macro_rules! define_direct_call_site {
$site(resolve_direct_func_ptr(closure, $arity).map(|func_ptr| unsafe {
std::mem::transmute::<
*const u8,
extern "C" fn(*const ClosureHeader, $(define_direct_call_site!(@f64 $arg)),+) -> f64,
extern "C-unwind" fn(*const ClosureHeader, $(define_direct_call_site!(@f64 $arg)),+) -> f64,
>(func_ptr)
}))
}
Expand Down Expand Up @@ -174,11 +174,11 @@ mod tests {

// A capture-less body behind a real `ClosureHeader`, the same way
// `array/tests.rs` and `array/typed_array_receiver_tests.rs` build theirs.
extern "C" fn add3(_c: *const ClosureHeader, a: f64, b: f64, c: f64) -> f64 {
extern "C-unwind" fn add3(_c: *const ClosureHeader, a: f64, b: f64, c: f64) -> f64 {
a * 100.0 + b * 10.0 + c
}

extern "C" fn sum2(_c: *const ClosureHeader, a: f64, b: f64) -> f64 {
extern "C-unwind" fn sum2(_c: *const ClosureHeader, a: f64, b: f64) -> f64 {
a + b
}

Expand Down
4 changes: 2 additions & 2 deletions crates/perry-runtime/src/closure/dispatch/value_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ pub unsafe extern "C-unwind" fn js_native_call_value(
/// rather than xmm0 — matching the trampoline's `extern "C"` int-arg
/// expectation.
#[no_mangle]
pub unsafe extern "C" fn js_closure_call_array(
pub unsafe extern "C-unwind" fn js_closure_call_array(
closure_env: i64,
args_ptr: *const f64,
args_len: i64,
Expand Down Expand Up @@ -661,7 +661,7 @@ pub unsafe extern "C" fn js_closure_call_array(
/// `lower_expr` produces for a closure-typed expression). A null/undefined
/// box returns TAG_UNDEFINED.
#[no_mangle]
pub unsafe extern "C" fn js_closure_call_apply_with_spread(
pub unsafe extern "C-unwind" fn js_closure_call_apply_with_spread(
closure_box: f64,
regular_args: *const f64,
regular_count: i64,
Expand Down
5 changes: 3 additions & 2 deletions crates/perry-runtime/src/closure/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -954,14 +954,15 @@ pub unsafe fn dispatch_with_arity(
macro_rules! arm {
(@ty $i:tt) => { f64 };
($($i:tt),* $(,)?) => {{
let f: extern "C" fn(*const ClosureHeader $(, arm!(@ty $i))*) -> f64 =
let f: extern "C-unwind" fn(*const ClosureHeader $(, arm!(@ty $i))*) -> f64 =
std::mem::transmute(func_ptr);
f(closure $(, a!($i))*)
}};
}
match k {
0 => {
let f: extern "C" fn(*const ClosureHeader) -> f64 = std::mem::transmute(func_ptr);
let f: extern "C-unwind" fn(*const ClosureHeader) -> f64 =
std::mem::transmute(func_ptr);
f(closure)
}
1 => arm!(0),
Expand Down
6 changes: 6 additions & 0 deletions crates/perry/tests/bun_ffi_stage1.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
// #8463: these fixtures exercise JS exceptions unwinding through the closure
// dispatch family (`js_closure_call*`, `dispatch_with_arity`). After #8416 the
// whole family must be `extern "C-unwind"` — a single plain `extern "C"` edge
// turns a deferred Function error into `panic in a function that cannot
// unwind` and aborts the binary on Linux. Naming this file in a runtime diff
// also opts the suite into the PR tier's e2e-scoped job.
//! bun:ffi stages 1-2 (#6562) — e2e: compile TS that dlopens real C-ABI
//! dylibs and drive them through the typed call stubs.
//!
Expand Down
Loading