Felix Bünemann 80cb94bcd6 YJIT (arm64): fix off-by-one in the single-branch range check
jmp_ptr_bytes() reserves room for a patchable jump -- it sets
page_end_reserve and bounds conditional jump width. A single `b` suffices
when every branch in the code region is in imm26 range; otherwise it
reserves 5 instructions for an absolute load-address plus br.

The range test was `virtual_region_size() / 4`, but two instructions in an
S-byte region are at most S-4 bytes apart. At exactly 128MiB, S/4 is 2^25
while the widest imm26 offset is 2^25-1, so the check gave up one
instruction early and took the 5-instruction fallback -- despite the comment
right above it saying <= 128 should work.

That boundary is the default. exec_mem_size falls back to mem_size in
CodegenGlobals::init and mem_size defaults to 128MiB, so every arm64 run
without an explicit --yjit-exec-mem-size reserved 20 bytes per patchable
jump where 4 would do. On a branch-heavy method that is the difference
between 1336 and 956 bytes of inline code.

Test (S-4)/4 instead. The decision moves into a small jmp_ptr_bytes_for_region()
so a unit test can pin both sides of the boundary without allocating a region
that large. --yjit-exec-mem-size=129 still takes the fallback, as before.

Checked with `make yjit-check` on arm64 macOS and on Linux/Graviton 4: 374
cargo tests, all bootstraptest at --yjit-call-threshold=1, and test_yjit.rb
(142 tests, 0 failures). Since the default size is the boundary case, the
whole suite ran on the tightened reservation.
2026-07-27 14:01:46 -07:00
..
2026-07-15 15:43:28 +02:00