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
8 changes: 1 addition & 7 deletions crates/perry-codegen/src/function/precise_roots.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,7 @@ fn lower_roots_for_rs4gc(lines: &[&str], root_ptrs: &[String]) -> Option<String>
if is_call && trimmed.ends_with(')') && !trimmed.contains(" asm ") {
if let Some(callee) = direct_callee_name(line) {
let leaf = match crate::gc_call_effects::classify_direct_callee(callee) {
crate::gc_call_effects::GcCallEffect::CannotCollect
| crate::gc_call_effects::GcCallEffect::NeverReturns => true,
crate::gc_call_effects::GcCallEffect::CannotCollect => true,
crate::gc_call_effects::GcCallEffect::AllocNoReentry => {
crate::codegen::helpers::gc_safepoint_only_contract_enabled()
}
Expand Down Expand Up @@ -712,7 +711,6 @@ pub(super) fn lower_precise_roots_to_native_stack(
matches!(
crate::gc_call_effects::classify_direct_callee(c),
crate::gc_call_effects::GcCallEffect::CannotCollect
| crate::gc_call_effects::GcCallEffect::NeverReturns
)
});
if let Some(report) = report.as_mut() {
Expand Down Expand Up @@ -757,10 +755,6 @@ pub(super) fn lower_precise_roots_to_native_stack(
let cannot_collect = direct_callee.is_some_and(|callee| {
match crate::gc_call_effects::classify_direct_callee(callee) {
crate::gc_call_effects::GcCallEffect::CannotCollect => true,
// Control never returns here: no relocation is consumed and
// the frame's roots are dead past the call. Deeper frames
// carry their own records.
crate::gc_call_effects::GcCallEffect::NeverReturns => true,
// Under the explicit-safepoint contract the runtime
// guarantees these helpers' triggers never consume this
// frame's precise roots (they defer to a declared safepoint
Expand Down
17 changes: 6 additions & 11 deletions crates/perry-codegen/src/gc_call_effects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,6 @@ pub(crate) enum GcCallEffect {
/// consumed at this call site and it needs no statepoint. Without the
/// contract these remain safepoints.
AllocNoReentry,
/// The callee never returns to this call site (audited 2026-08-01: every
/// `js_throw*` helper funnels into `exception::js_throw`, which is
/// `-> !` — the `f64` results are unreachable ABI shape). No relocation
/// can ever be consumed downstream and the frame's roots are dead past
/// the call, so the site needs no metadata in ANY mode. Values the
/// helper itself holds are its own frame's responsibility
/// (`RuntimeHandleScope`/temp roots), exactly as for every helper call.
NeverReturns,
Unknown,
}

Expand Down Expand Up @@ -113,9 +105,12 @@ pub(crate) fn classify_direct_callee(name: &str) -> GcCallEffect {
| "js_validate_array_comparator"
| "js_validate_array_map_callback" => GcCallEffect::AllocNoReentry,
// NO `js_throw*` prefix arm. It used to classify the whole family
// `NeverReturns`, which suppresses the safepoint in every mode — the
// strongest classification in this table, and the only one applied by
// prefix rather than exact name.
// a `NeverReturns` classification that suppressed the safepoint in
// every mode — the strongest possible, and the only one that would be
// applied by prefix rather than exact name. That variant is DELETED,
// not merely unused: it was never constructed, so its three match arms
// in `precise_roots.rs` were dead, and the kill-policy in CLAUDE.md
// says an unexercised mode is a decision nobody has made.
//
// Two things make that unsafe. The audit it rested on is already
// false: `js_throw_reference_error_tdz`, `js_throw_not_a_constructor`
Expand Down
Loading