Skip to content

jit: dispatch float residual calls through the float return register - #990

Merged
youknowone merged 3 commits into
mainfrom
rewrite-tracer
Aug 3, 2026
Merged

youknowone merged 3 commits into
mainfrom
rewrite-tracer

Conversation

@youknowone

@youknowone youknowone commented Aug 2, 2026 •

Copy link
Copy Markdown
Collaborator

Follow-up to #963, which landed a result_type() == Float decline in
try_fold_pure_call_via_executor rather than fixing the ABI underneath it.
This removes the decline by fixing the ABI.

The defect

execute_pure_call and execute_residual_call routed a Type::Float result
through call_int_function, an extern "C" fn(..) -> i64 transmute. The C ABI
returns f64 in xmm0 / d0, so the result was read from the integer return
register — which still held an argument. Float arguments were wrong in the
same way, passed in the integer register file rather than the FP one.

executor.py:66-68 dispatches FLOAT through cpu.bh_call_f, whose backend
implementation calls a per-descr stub built from the descr's own signature
(llmodel.py:828 → descr.py:598-612 create_call_stub). pyre has already
ported that
as majit_backend::call_stub::bh_call_f_by_classes /
bh_call_f_dispatch, and two of the three residual-call consumers already use
it on this exact operand — the blackhole's bhimpl_residual_call_irf_f and the
metainterp's own BC_RESIDUAL_CALL_IRF_F dispatcher. executor.rs was the lone
outlier.

Why the decline could not just be extended

The decline covered only the pure path. The non-pure sibling
try_execute_residual_call_via_executor admits CallF / CallLoopinvariantF /
CallMayForceF with no such guard, runs the same integer read via
execute_residual_call, and stamps Value::Float(f64::from_bits(..)).

Copying the guard there is not available: its Declined arm runs
fbw_abort_nested_unjournaled_residual + fbw_mark_unjournaled_effect, so a
decline trades a wrong value for an unjournaled walk whose region the caller
then replays. Fixing the ABI closes both seams; declining can only ever close
one.

The change

call_float_function(func_ptr, args, arg_types) -> f64 — the bh_call_f
sibling of call_int_function. It splits the positional args into the int/float
banks bh_call_f_dispatch expects, keeps the wasm32 host-trampoline path, and
returns the f64. Float slots carry raw f64::to_bits in both directions
(longlong float-storage parity). Both walker seams use it; the decline is
deleted.

bh_call_f_dispatch's arity table is fn(I × ints, F × floats) — all
integer/ref parameters precede all floats. Interleaved signatures assert rather
than shuffle registers. Every float-returning helper in the tree is
non-interleaved: jit_bigint_to_f64_or_inf(ref) -> f64,
jit_float_abs(f64) -> f64, jit_float_fmod(f64, f64) -> f64.

Why this is safe: operand 0's ABI is set by REGISTRATION, not by emitter

#963's comment said the split was "codewriter vs the *_canonical_via_target
family". That is wrong —
residual_call_float_canonical_via_target_with_effect_info bakes
target.concrete_ptr for every producer. The discriminator is the
JitCallTarget registration site:

registration concrete_ptr is float return
add_fn_ptr(ptr) = add_call_target(ptr, ptr) the raw callee address real f64 register
macro add_call_target_with_save_err(trace, concrete) #[jit_module]'s _concrete wrapper, extern "C" fn(i64,..) -> i64 with f64::to_bits i64 bits
LLBC codewriter plain ConstInt(fnaddr_for_target) — no JitCallTarget at all real f64 register

pyre's own codewriter registers via add_fn_ptr / add_fn_ptr_with_slot, so
its concrete_ptr is the raw address.

The i64-packing wrapper reaches a residual call only through the explicit
*_float_wrapped call policies — the macro's HelperCallKind::Float arm emits
an UNSUPPORTED policy byte for every attribute otherwise. No crate declares
one:

$ rg -n 'float_wrapped' --type rust -g '!target' -g '!majit/majit-macros/**' .
(no matches)

So every live float residual-call funcbox is a raw callee address. This is a
compile-time fact, so it needed no instrumented build.

The first commit corrects those comments in place, including two stale line
citations (jitcode/assembler.rs:3343, codegen.rs:909).

Deliberately unchanged

  • execute_varargs's Float arm keeps call_int_function — its caller set
    includes do_recursive_call's portal runner (bh_portal_runner -> i64), and
    that convention was not verified here.
  • The CALL_ASSEMBLER arms (pyjitpl/dispatch.rs, blackhole.rs) genuinely do
    want the i64 wrapper and are a separate opcode family.

Verification

cargo test -p majit-metainterp -p pyre-jit-trace: 1428 + 322 + siblings, 0
failed.

pyre/check.py --backend dynasm,cranelift,wasm: 2 failed each, byte-identical
to the pre-change run on the same base
— exception_args_virtual (all three),
list_length_hint_validate (dynasm/cranelift), pickle_terminal_raise_resume
(wasm). All three are inherited from main; the last was attributed by building
origin/main itself with none of these commits and measuring the same
loops_aborted = 59.

The corpus is neutral because no synth fixture drives a float residual call
through the walker executor (math_sqrt_hot / math_log_trig_hot short-circuit
in the walker specializers). The evidence is in the unit tests instead:

  • the walker test now folds halve_f64_for_walker_test(7) to 3.5; an
    integer-register read stamps the argument 7;
  • the two executor float tests use real extern "C" fn(f64) -> f64 and
    fn(i64) -> f64 callees, replacing hand-packed i64 helpers that had pinned
    the broken convention.

Codex parity review disposition

Section 1: none. Sections 2–4 were checked against the cited upstream lines
before acting; both section-2 findings are reclassified, and the section-3
finding is a structural adaptation. The third commit records each reason in
code rather than changing behaviour.

2.1 — the interleaved-signature assert! vs create_call_stub's arbitrary
arg_classes order.
Reclassified. bh_call_*_dispatch recovers the callee
signature from the bucketed (int, float) arity, so fn(f64, i64) would be
dispatched as fn(i64, f64). That is register-preserving under SysV and AAPCS,
which fill the integer and floating-point files in independent relative order,
and wrong under the Microsoft x64 convention, whose first four argument slots
are positional — fn(f64, i64) takes xmm0/rdx where fn(i64, f64) takes
rcx/xmm1. Upstream needs no such restriction because create_call_stub
generates a stub carrying the descr's real signature; the convergence path for
pyre is the libffi dispatch already named in dispatch_arity_body!'s catch-all
arm. The assertion is kept and its rationale restated in those terms.

Reviewing this did surface a real gap Codex did not flag: collect_call_args
performs the same reordering on the bank-fed path (bh_call_{i,f,v}_by_classes)
with no check at all. Not changed here — a blanket rejection would panic on
calls that are ABI-correct under SysV/AAPCS on the blackhole and backend hot
paths, and the correct fix is the same libffi dispatch. The gap is now stated
at the function.

2.2 — Type::Float treated as f64, losing 'L' (SignedLongLong) and
'S' (SingleFloat).
Reclassified as unreachable at this seam. The bank-fed
collect_call_args does carry both arms ('L' → integer register file, 'S'
→ explicit panic). call_float_function is fed by descr.arg_types(), and
CallDescr::arg_classes maps Type onto 'i'/'r'/'f'/'v' exhaustively,
so a Type::Float slot is always class 'f'. Documented at the seam so that
teaching Type those classes extends both sites.

3 — the NULL-Ref fold refusal vs record_result_of_call_pure. Structural
adaptation, not pre-existing debt. Upstream's weaker test ("every argbox is a
Const", admitting ConstPtr(NULL)) is reached only after the call has already
executed for real, on constants the interpreter itself produced. Pyre's walker
folds from a different source: getfield_gc_r propagates pointer-valued field
reads as concrete whenever the parent struct is concrete-known, so a top-level
frame stamps Value::Ref(GcRef(0)) where upstream still holds a symbolic box
guarded by the guard_nonnull its optimizer inserts ahead of a pointer-deref
residual call. Executing helper(NULL) before that guard exists dereferences
NULL. The comment now names the upstream test and where the divergence in
constant provenance comes from.

4 — both items accepted as documented adaptations. The to_bits() as i64
result is the longlong float-storage equivalent; the shared dispatch table
stands in for translation-time per-descr stub generation, and 2.2 above is the
descriptor-class semantics that entry asks it to retain.

cargo test -p majit-metainterp -p majit-backend -p pyre-jit-trace: 1428 + 325

  • siblings, 0 failed. The third commit changes doc comments and one assertion
    message only, so the measured corpus results above still stand.

— authored by Claude

Summary by CodeRabbit

  • New Features

    • Improved support for executing calls that return floating-point values.
    • Floating-point arguments and results are now handled correctly across supported calling conventions.
    • Pure floating-point calls can now be evaluated and folded during optimization.
  • Bug Fixes

    • Corrected mixed integer-and-floating-point call handling.
    • Added safeguards for unsupported argument layouts to prevent incorrect dispatch behavior.
  • Documentation

    • Clarified calling-convention compatibility and dispatch limitations.

@coderabbitai

coderabbitai Bot commented Aug 2, 2026 •

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The change adds ABI-aware floating-point call dispatch. Pure and residual float-returning calls now execute through the floating-point path and can fold concrete results. Tests cover mixed argument classes, floating-point registers, and Float(3.5) folding.

Changes

Floating-point call dispatch

Layer / File(s) Summary
Floating-point dispatcher and ABI contract
majit/majit-backend/src/call_stub.rs, majit/majit-metainterp/src/pyjitpl/dispatch.rs, majit/majit-metainterp/src/pyjitpl.rs
Adds call_float_function, exports it through pyjitpl, and documents ABI restrictions for bucketed argument dispatch.
Executor float-result integration
majit/majit-metainterp/src/executor.rs
Routes pure and residual float results through floating-point dispatch and adds ABI-focused tests.
Residual pure-call folding
pyre/pyre-jit-trace/src/jitcode_dispatch/residual_call.rs, pyre/pyre-jit-trace/src/jitcode_dispatch/tests.rs
Allows float-result pure calls to fold through the executor and updates expectations to Float(3.5). NULL-reference handling remains unchanged.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Executor
  participant call_float_function
  participant HostTrampoline
  participant bh_call_f_dispatch
  Executor->>call_float_function: typed arguments and raw float bits
  alt host trampoline available
    call_float_function->>HostTrampoline: dispatch classified arguments
  else host trampoline unavailable
    call_float_function->>bh_call_f_dispatch: dispatch classified arguments
  end
  call_float_function-->>Executor: f64 return value
Loading

Possibly related PRs

Poem

A rabbit packed the floats just right,
Through register banks they took their flight.
Pure calls folded, crisp and clean,
Float(3.5) now can be seen.
ABI paths hop safely bright.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: routing float residual calls through the floating-point return register.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rewrite-tracer

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 2, 2026 •

Copy link
Copy Markdown

🤖 Codex parity review

Static analysis of this diff vs the local RPython/PyPy sources (commit 4fb34e2).
Updated: 2026-08-03T01:25:13.307Z

Files in the reviewed diff
majit/majit-backend/src/call_stub.rs
majit/majit-metainterp/src/executor.rs
majit/majit-metainterp/src/pyjitpl.rs
majit/majit-metainterp/src/pyjitpl/dispatch.rs
pyre/pyre-jit-trace/src/jitcode_dispatch/residual_call.rs
pyre/pyre-jit-trace/src/jitcode_dispatch/tests.rs

1. Regressions to PyPy parity introduced by this patch

None.

2. Other mismatches introduced by this patch

  • majit/majit-metainterp/src/pyjitpl/dispatch.rs:8487 ↔ rpython/jit/backend/llsupport/descr.py:573-605 — the new Float dispatcher rejects a positional signature with an integer/ref after a Float (fn(f64, i64) -> f64) instead of constructing that exact signature. PyPy preserves arg_classes order in ARGS and supports all interleavings; this path panics.

3. Pre-existing mismatches (already present before this patch)

  • majit/majit-backend/src/call_stub.rs:501-514 ↔ rpython/jit/backend/llsupport/descr.py:551-569 — 'S' / SingleFloat calls panic because pyre has only f64 dispatch arms; PyPy converts with int2singlefloat and emits an lltype.SingleFloat parameter.

  • pyre/pyre-jit-trace/src/jitcode_dispatch/residual_call.rs:1618-1623 ↔ rpython/jit/backend/llsupport/descr.py:604-605 — pure-call folding declines above 16 arguments due to MAX_HOST_CALL_ARITY; PyPy builds FUNC from the full descriptor argument list without this ceiling.

4. Structural adaptations

  • majit/majit-metainterp/src/executor.rs:829-831 ↔ rpython/jit/metainterp/executor.py:66-72 — returning the Float result as f64::to_bits() as i64 is a Rust register-bank/storage adaptation. It is semantically equivalent to PyPy’s bh_call_f followed by Float storage conversion.

  • majit/majit-metainterp/src/pyjitpl/dispatch.rs:8475-8479 ↔ rpython/jit/backend/llsupport/descr.py:599-605 — wasm uses a host trampoline with positional raw-bit arguments because wasm indirect calls require the exact function type; PyPy instead creates a typed per-descriptor stub.

  • pyre/pyre-jit-trace/src/jitcode_dispatch/residual_call.rs:1644-1667 ↔ rpython/jit/metainterp/pyjitpl.py:3586-3603 — pyre declines concrete NULL-Ref pure-call folding to avoid dereferencing a walker-propagated null before a guard exists. PyPy’s execution/recording ordering permits its all-constant path.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 83a5197618

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +8469 to +8473
assert!(
float_args.is_empty(),
"call_float_function: interleaved int/float parameters are \
outside `bh_call_f_dispatch`'s `fn(I.., F..)` arity table"
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Accept mixed argument order for float residuals

On native targets, a CallPureF/CallF descriptor such as [Float, Int] reaches this assertion and panics instead of executing; this is a valid signature already used by jit_math_ldexp_raw(f64, i64) -> f64 and its descriptor in specialize.rs:6092-6096. The existing bh_call_f_by_classes path accepts interleaving by separating the ABI register banks, so this new executor path should do likewise (or retain the pure-call decline for unsupported layouts) rather than aborting tracing.

AGENTS.md reference: AGENTS.md:L194-L196

Useful? React with 👍 / 👎.

Operand 0's float ABI is set by how its `JitCallTarget` was registered,
not by which emitter ran: `add_fn_ptr(ptr)` is `add_call_target(ptr, ptr)`
(`jitcode/assembler.rs:4617`) so `concrete_ptr` is the raw callee address,
while the policy-macro lowering registers `#[jit_module]`'s `_concrete`
i64-packing wrapper; the LLBC codewriter mints no `JitCallTarget` at all.
`residual_call_float_canonical_via_target_with_effect_info` bakes
`target.concrete_ptr` for all of them.

Also records that `pyjitpl/dispatch.rs:6539` calls the same `concrete_ptr`
through `bh_call_f_by_classes` as a real f64 return, the opposite of what
`execute_pure_call`'s Float arm assumes, and fixes two stale line
citations (`jitcode/assembler.rs:3343`, `codegen.rs:909`).

Comments only.

Assisted-by: Claude
`execute_pure_call` and `execute_residual_call` routed a `Type::Float`
result through `call_int_function`, an `extern "C" fn(..) -> i64`
transmute, so the result was read from the integer return register and
float arguments were passed in the integer register file.

Adds `call_float_function(func_ptr, args, arg_types)`, the `bh_call_f`
sibling of `call_int_function` (`executor.py:66-68`, `llmodel.py:828`):
it splits the positional args into the int/float banks
`bh_call_f_dispatch` expects and returns the `f64`. Float slots carry
raw `f64::to_bits` in both directions. Interleaved int/float parameters
are outside the arity table and assert rather than shuffle registers.

Both walker seams now use it, replacing the `result_type() == Float`
decline in `try_fold_pure_call_via_executor`. The decline covered only
the pure path; `try_execute_residual_call_via_executor` admits `CallF` /
`CallLoopinvariantF` / `CallMayForceF` with no such guard and stamped
`Value::Float(f64::from_bits(..))` from the same integer read. Extending
the decline there was not available: its `Declined` arm runs
`fbw_abort_nested_unjournaled_residual` + `fbw_mark_unjournaled_effect`.

The funcbox reaching these seams is the callee's own address on every
live path — `add_fn_ptr(ptr)` is `add_call_target(ptr, ptr)`, which is
what pyre's codewriter registers, and the LLBC path bakes a plain
`ConstInt` fnaddr with no `JitCallTarget`. The `f64::to_bits`-packing
`_concrete` wrapper reaches a residual call only through the
`*_float_wrapped` call policies, which no crate declares. The
CALL_ASSEMBLER arms that do want that wrapper keep `call_int_function`.
`execute_varargs`'s Float arm is unchanged; its caller set includes the
i64-returning portal runner.

Tests: the two executor float tests now use real `extern "C" fn(f64)
-> f64` and `fn(i64) -> f64` callees instead of hand-packed i64 helpers,
and the walker test asserts the fold produces 3.5 rather than asserting
the decline; an integer-register read would stamp the argument 7.

check.py dynasm/cranelift/wasm: 2 failed each, byte-identical to the
pre-change run (all three inherited from main).

Assisted-by: Claude
…old refusal

`dispatch_arity_body!` recovers a callee signature from the bucketed
(int, float) arity, which reorders an interleaved signature. Record that
this preserves register assignment on SysV/AAPCS, where the two register
files are filled in independent relative order, but not on the Microsoft
x64 convention, where the first four argument slots are positional.
`collect_call_args` states that it does not reject interleaving and why.

`call_float_function`: restate the panic's rationale in those terms, note
that libffi is the recorded convergence path, and record that `descr.py`'s
'L'/'S' argument classes cannot reach the `arg_types()` seam because
`CallDescr::arg_classes` maps `Type` onto 'i'/'r'/'f'/'v'.

`try_fold_pure_call_via_executor`: name the upstream test being deviated
from (`record_result_of_call_pure` folds on all-Const, admitting
`ConstPtr(NULL)`) and where pyre's concrete NULL comes from that upstream
would still hold symbolically.

Assisted-by: Claude

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4fb34e214b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +829 to +830
majit_ir::Type::Float => {
crate::pyjitpl::call_float_function(func_ptr, args, descr.arg_types()).to_bits() as i64

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve the integer-return ABI for wrapped float helpers

When a native dynasm/cranelift trace uses an explicit float-wrapped policy such as elidable_float_cannot_raise_wrapped, the macro registers distinct trace and concrete targets, and residual_call_float_canonical_via_target_with_effect_info bakes target.concrete_ptr into the funcbox; that generated _concrete wrapper returns i64 containing f64::to_bits. Calling it here through an extern "C" fn(...) -> f64 ABI reads the floating-point return register instead, so pure folding can stamp an arbitrary float into the trace. Preserve the target discriminator/use the trace target, or decline folding when the funcbox is the integer-return wrapper.

AGENTS.md reference: AGENTS.md:L194-L195

Useful? React with 👍 / 👎.

Comment on lines +8498 to +8499
unsafe {
majit_backend::call_stub::bh_call_f_dispatch(func_ptr as usize, &int_args, &float_args)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Decline float folds outside the dispatch arity table

For a valid constant CallPureF signature within MAX_HOST_CALL_ARITY but outside dispatch_arity_body!—for example five Float arguments—this newly reachable call falls into the backend catch-all and panics while tracing; before this change, every float-result pure call remained symbolic for the backend to execute. Either check that the (int, float) counts are represented before invoking this dispatcher or implement the general per-signature dispatch, rather than turning an otherwise valid residual call into a tracer panic.

AGENTS.md reference: AGENTS.md:L194-L195

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@majit/majit-metainterp/src/pyjitpl/dispatch.rs`:
- Around line 8474-8501: Add a focused #[should_panic] test for
call_float_function that passes interleaved argument types such as [Type::Float,
Type::Int] and matching arguments, exercising the assertion that rejects
integer/ref parameters after floating-point parameters. Keep the test scoped to
validating this panic contract.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9b054696-097b-4af4-8e87-0db81d7d9cee

📥 Commits

Reviewing files that changed from the base of the PR and between b44c30b and 4fb34e2.

📒 Files selected for processing (6)
  • majit/majit-backend/src/call_stub.rs
  • majit/majit-metainterp/src/executor.rs
  • majit/majit-metainterp/src/pyjitpl.rs
  • majit/majit-metainterp/src/pyjitpl/dispatch.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/residual_call.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/tests.rs

Comment on lines +8474 to +8501
pub fn call_float_function(func_ptr: *const (), args: &[i64], arg_types: &[Type]) -> f64 {
// Where a backend cannot build a `call_indirect` whose type matches the
// callee's real signature (wasm32), route through the host trampoline,
// which reflects the signature and returns an f64 result as its raw bits.
if let Some(hook) = majit_backend::call_stub::residual_host_call() {
return f64::from_bits(hook(func_ptr as usize, args) as u64);
}
let mut int_args: Vec<i64> = Vec::with_capacity(args.len());
let mut float_args: Vec<f64> = Vec::new();
for (i, &a) in args.iter().enumerate() {
match arg_types.get(i) {
Some(Type::Float) => float_args.push(f64::from_bits(a as u64)),
_ => {
assert!(
float_args.is_empty(),
"call_float_function: an integer/ref parameter after a float \
one cannot be bucketed into `bh_call_f_dispatch`'s \
`fn(I.., F..)` signature without changing which register \
each argument lands in on a positional-slot ABI"
);
int_args.push(a);
}
}
}
unsafe {
majit_backend::call_stub::bh_call_f_dispatch(func_ptr as usize, &int_args, &float_args)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a test for the interleaved-signature rejection.

The assert! at Line 8487 is the safety mechanism that prevents silent register corruption for interleaved int/float signatures. No test in the provided diff exercises this panic path. Add a #[should_panic] test that calls call_float_function with arg_types such as [Type::Float, Type::Int] to lock in this contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@majit/majit-metainterp/src/pyjitpl/dispatch.rs` around lines 8474 - 8501, Add
a focused #[should_panic] test for call_float_function that passes interleaved
argument types such as [Type::Float, Type::Int] and matching arguments,
exercising the assertion that rejects integer/ref parameters after
floating-point parameters. Keep the test scoped to validating this panic
contract.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant