summaryrefslogtreecommitdiff
path: root/zjit/src
AgeCommit message (Collapse)Author
2025-07-31ZJIT: Stub JIT-to-JIT calls (#14052)Takashi Kokubun
2025-07-31ZJIT: A64: Fix splitting for large memory displacementsAlan Wu
On the ruby side, this fixes a crash for methods with 39 or more parameters. We used to miscomp those entry points due to Insn::Lea picking ADDS which cannot reference SP: # set method params: 40 mov x0, #0xfee8 movk x0, #0xffff, lsl #16 movk x0, #0xffff, lsl #32 movk x0, #0xffff, lsl #48 adds x0, xzr, x0 Have Lea work for all i32 displacements and avoid involving the split pass. Previously, direct use of Insn::Lea directly from the user (as opposed to generated by the split pass for some memory operations) wasn't split, so being able to handle the whole range in arm64_emit() was implicitly required. Also, not going through split reduces register pressure.
2025-07-31ZJIT: Remove false comment [ci skip]Alan Wu
2025-07-31ZJIT: Only build the assembler for `target_arch`Alan Wu
Fixes test error from running the ARM assembler on x86, but then trying to disassemble it as x86.
2025-07-31ZJIT: A64: Add add_extended() which can add a register to spAlan Wu
2025-07-30ZJIT: Don't create owned Cow/String when printingMax Bernstein
2025-07-30ZJIT: Don't make unnecessary CowMax Bernstein
2025-07-30ZJIT: Don't write to StringMax Bernstein
2025-07-30ZJIT: Get rid of CallInfoMax Bernstein
2025-07-30ZJIT: Deref struct in find()Max Bernstein
2025-07-30ZJIT: Remove catch-all case to make it clearer what's unimplementedMax Bernstein
2025-07-30ZJIT: Remove unused ArraySet instructionMax Bernstein
2025-07-30ZJIT: Prepare for sharing JIT hooks with ZJIT (#14044)Takashi Kokubun
2025-07-29ZJIT: Catch more failed recursive compilations (#14042)Max Bernstein
Untangle the logic a bit and specifically: * catch `gen_entry` failures * don't set `start_ptr` until all recursive calls succeed Co-authored-by: Alan Wu <alanwu@ruby-lang.org>
2025-07-29ZJIT: Create delta debugging script to narrow JIT failures (#14041)Max Bernstein
Add support for `--zjit-allowed-iseqs=SomeFile` and `--zjit-log-compiled-iseqs=SomeFile` so we can restrict and inspect which ISEQs get compiled. Then add `jit_bisect.rb` which we can run to try and narrow a failing script. For example: plum% ../tool/zjit_bisect.rb ../build-dev/miniruby "test.rb" I, [2025-07-29T12:41:18.657177 #96899] INFO -- : Starting with JIT list of 4 items. I, [2025-07-29T12:41:18.657229 #96899] INFO -- : Verifying items I, [2025-07-29T12:41:18.726213 #96899] INFO -- : step fixed[0] and items[4] I, [2025-07-29T12:41:18.726246 #96899] INFO -- : 4 candidates I, [2025-07-29T12:41:18.797212 #96899] INFO -- : 2 candidates Reduced JIT list: bar@test.rb:8 plum% We start with 4 compiled functions and shrink to just one.
2025-07-29ZJIT: Add --zjit-stats (#14034)Takashi Kokubun
2025-07-29Get rid of imemo_astJean Boussier
It has been marked as obsolete for a while and I see no reason to keep it.
2025-07-28ZJIT: Support invalidating constant patch points (#13998)Stan Lo
2025-07-28ZJIT: Fix land raceMax Bernstein
2025-07-28ZJIT: Mark Symbol, Float, NilClass, TrueClass, FalseClass as finalMax Bernstein
They can be subclassed but new instances cannot be created.
2025-07-28ZJIT: Remove Integer subclasses from latticeMax Bernstein
While Integer can technically be subclassed, instances of subclasses cannot be created. Remove it from the type lattice.
2025-07-28ZJIT: Inline guard type checks for some built-in types (#14017)Stan Lo
This implements similar fast-path guard type checks as YJIT.
2025-07-28ZJIT: Keep a frame pointer and use it for memory paramsAlan Wu
Previously, ZJIT miscompiled the following because of native SP interference. def a(n1,n2,n3,n4,n5,n6,n7,n8) = [n8] a(0,0,0,0,0,0,0, :ok) Commented problematic disassembly: ; call rb_ary_new_capa mov x0, #1 mov x16, #0x1278 movk x16, #0x4bc, lsl #16 movk x16, #1, lsl #32 blr x16 ; call rb_ary_push mov x1, x0 str x1, [sp, #-0x10]! ; c_push() from alloc_regs() mov x0, x1 ; arg0, the array ldur x1, [sp] ; meant to be arg1=n8, but sp just moved! mov x16, #0x3968 movk x16, #0x4bc, lsl #16 movk x16, #1, lsl #32 blr x16 Since the frame pointer stays constant in the body of the function, static offsets based on it don't run the risk of being invalidated by SP movements. Pass the registers to preserve through Insn::FrameSetup. This allows ARM to use STP and waste no gaps between EC, SP, and CFP. x86 now preserves and restores RBP since we use it as the frame pointer. Since all arches now have a frame pointer, remove offset based SP movement in the epilogue and restore registers using the frame pointer.
2025-07-24ZJIT: Re-enable some A64 assembler testsAlan Wu
Tweak for Condition to build when `cfg!(target = "x86_64")`.
2025-07-24ZJIT: DRY up underscore rexport anti-patternAlan Wu
Keeping the same name makes re-exporting more concise.
2025-07-24Remove unused imemo_parser_strtermPeter Zhu
2025-07-23ZJIT: Fix clobbering register for `self` in gen_entry_params()Alan Wu
Previously, for 8+ params we wound up clobbering the self param when putting the last param in memory in the JIT entry point: # ZJIT entry point: a@../test.rb:5 <snip> ldur x0, [x19, #0x18] # set method params: 8 ldur x1, [x21, #-0x58] ldur x2, [x21, #-0x50] ldur x3, [x21, #-0x48] ldur x4, [x21, #-0x40] ldur x5, [x21, #-0x38] ldur x11, [x21, #-0x30] ldur x12, [x21, #-0x28] ldur x0, [x21, #-0x20] stur x0, [sp, #-0x20] bl #0x11e17018c Doing the memcpys for parameters in memory first avoids this clobbering. # set method params: 8 ldur x0, [x21, #-0x20] stur x0, [sp, #-0x20] ldur x12, [x21, #-0x28] ldur x11, [x21, #-0x30] ldur x5, [x21, #-0x38] ldur x4, [x21, #-0x40] ldur x3, [x21, #-0x48] ldur x2, [x21, #-0x50] ldur x1, [x21, #-0x58] ldur x0, [x19, #0x18]
2025-07-22ZJIT: Use rb_vm_env_write() for `hir::Insn::SetLocal`Alan Wu
We weren't firing write barriers before when writing to imemo/env objects. Wbcheck caught this with test/ruby/test_refinement.rb: ruby -v: ruby 3.5.0dev (2025-07-22T17:05:58Z wbcheck 2569a80954) +ZJIT dev +PRISM +GC[wbcheck] [x86_64-linux] WBCHECK ERROR: Missed write barrier detected! Parent object: 0x558de9f4e6e0 (wb_protected: true) rb_obj_info_dump: 0x0000558de9f4e6e0 T_IMEMO/<env> Reference counts - snapshot: 3, writebarrier: 0, current: 4, missed: 1 Missing reference to: 0x558decf37c30 rb_obj_info_dump: 0x0000558decf37c30 method/UnboundMethod method WBCHECK SUMMARY: Found 1 objects with missed write barriers (1 total violations)
2025-07-21ZJIT: Load return value before frame teardownAlan Wu
Or else the following returns garbage since it loads after moving SP. Prior bad disassembly: def a(n1,n2,n3,n4,n5,n6,n7,n8) = n8 a(1,1,1,1,1,1,1,0) # Block: bb0(v0, v1, v2, v3, v4, v5, v6, v7, v8) stp x29, x30, [sp, #-0x10]! mov x29, sp # bump C stack pointer sub sp, sp, #0x10 # Insn: v10 Return v8 # pop stack frame adds x19, x19, #0x38 stur x19, [x20, #0x10] # restore C stack pointer add sp, sp, #0x10 mov sp, x29 ldp x29, x30, [sp], #0x10 ldur x0, [sp] ret
2025-07-21ZJIT: Remove no-op movs after register allocationAlan Wu
Previously `no_dead_mov_from_vreg` generated: 0x0: ldur x0, [x0] 0x4: mov x0, x0 0x8: ret Because of phase ordering. Split couldn't recognize that the no-op mov because at that point it sees a `VReg`.
2025-07-21ZJIT: Trim disassembly output from capstone-rsAlan Wu
It has a bad habit of leaving a trailing space, for example for ARM `ret`.
2025-07-18ZJIT: Support invalidating on method redefinition (#13875)Stan Lo
ZJIT: Support invalidating method redefinition This commit adds support for the MethodRedefined invariant to be invalidated when a method is redefined. Changes: - Added CME pointer to the MethodRedefined invariant in HIR - Updated all places where MethodRedefined invariants are created to include the CME pointer - Added handling for MethodRedefined invariants in gen_patch_point to call track_cme_assumption, which registers the patch point for invalidation when rb_zjit_cme_invalidate is called This ensures that when a method is redefined, all JIT code that depends on that method will be properly invalidated.
2025-07-17ZJIT: Fix fixnum folding for negative values (#13942)Stan Lo
Use `fixnum_from_isize` instead of `fixnum_from_usize` in `fold_fixnum_bop` to properly handle negative values. Casting negative `i64` to `usize` produces large unsigned values that exceed `RUBY_FIXNUM_MAX`.
2025-07-17ZJIT: Create perf map files for profilers (#13941)Max Bernstein
This lets us ZJIT compiled functions show up in the profiles of, say, perf, or samply. Fix https://github.com/Shopify/ruby/issues/634
2025-07-17ZJIT: Remove obsoleted exit_trampoline (#13943)Takashi Kokubun
2025-07-17ZJIT: Give up JIT-to-JIT calls for 6+ args (#13939)Takashi Kokubun
2025-07-17ZJIT: Precise GC writebarriersJohn Hawthorn
This issues writebarriers for objects added via gc_offsets or by profiling. This may be slower than writebarrier_remember, but we would like it to be more debuggable. Co-authored-by: Max Bernstein <ruby@bernsteinbear.com> Co-authored-by: Stan Lo <stan001212@gmail.com>
2025-07-17Tweak the comment on mark_all_executable() a little [ci skip]Takashi Kokubun
2025-07-17ZJIT: Mark the code region executable on partial failures (#13937)Takashi Kokubun
2025-07-16ZJIT: Add missing write barrier in profiling (GH-13922)Alan Wu
Fixes `TestZJIT::test_require_rubygems`. It was crashing locally due to false collection of a live object. See <https://alanwu.space/post/write-barrier/>. Co-authored-by: Max Bernstein <max@bernsteinbear.com> Co-authored-by: Takashi Kokubun <takashi.kokubun@shopify.com> Co-authored-by: Stan Lo <stan.lo@shopify.com>
2025-07-16ZJIT: Check if BOP is redefined before rewriting (#13916)Max Bernstein
Fix https://github.com/Shopify/ruby/issues/592
2025-07-16ZJIT: Eagerly infer types of rewritten Const instructions (#13917)Max Bernstein
This helps us rewrite more SendWithoutBlock into SendWithoutBlockDirect.
2025-07-16ZJIT: Split shift with immediate operand (#13914)Max Bernstein
Fix https://github.com/Shopify/ruby/issues/627
2025-07-16ZJIT: Remove dead have_two_fixnums function (#13913)Max Bernstein
2025-07-16ZJIT: A64: Fix bad operand swapping in `asm.sub(imm, reg)`Alan Wu
Previously, my buggy optimization would turn `asm.sub(imm, reg)` into `subs out, reg, imm` since it runs through the addition path which relies on the commutative property. Don't do that because subtraction does not commute. Good thing no one seems to use this form. Also, delete the 2 regs match arm for Add because it's already covered by the fallback arm -- both split_load_operand() and split_shifted_immediate() are no-op when the input is a register. Fixes: 1317377fa74 ("ZJIT: A64: Have add/sub to SP be single-instruction")
2025-07-16ZJIT: A64: Fix the optimization merging `asm.add(reg, imm)` with MovAlan Wu
The raw bytes didn't disassemble to the disassembly, but we missed this since CI didn't run `make zjit-test` with the disasm feature. Fixes: 1317377fa74 ("ZJIT: A64: Have add/sub to SP be single-instruction")
2025-07-16ZJIT: A64: Fix `asm.add_into(NATIVE_STACK_POINTER, ...)`Alan Wu
Previously, it issued CMN, which doesn't add to the stack pointer.
2025-07-16ZJIT: Profile each instruction at most num_profiles times (#13903)Takashi Kokubun
* ZJIT: Profile each instruction at most num_profiles times * Use saturating_add for num_profiles
2025-07-16Use a const blockTakashi Kokubun
Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
2025-07-16ZJIT: Restore SP on side-exit chainsTakashi Kokubun