Commit graph

547 commits

Author SHA1 Message Date
Takashi Kokubun
a677220aba
ZJIT: Stop duplicating context-less side exits (#14215) 2025-08-14 08:31:23 -07:00
Takashi Kokubun
cb281653ad
ZJIT: Enable or remove comments from YJIT (#14214) 2025-08-13 17:32:29 -07:00
Stan Lo
549a326f86
ZJIT: Implement StringIntern codegen (#14207)
* ZJIT: Add test and implement display for StringIntern HIR

Co-authored-by: Emily Samp <emily.samp@shopify.com>

* ZJIT: Implement StringIntern codegen

Co-authored-by: Emily Samp <emily.samp@shopify.com>

* ZJIT: Fix StringIntern's return type

---------

Co-authored-by: Emily Samp <emily.samp@shopify.com>
2025-08-13 13:04:01 -07:00
Stan Lo
2b16f27a35
ZJIT: Fix ObjToString rewrite (#14196)
ZJIT: Fix ObjToString rewrite

Currently, the rewrite for `ObjToString` always replaces it with a
`SendWithoutBlock(to_s)` instruction when the receiver is not a
string literal. This is incorrect because it calls `to_s` on the
receiver even if it's already a string.

This change fixes it by:
- Avoiding the `SendWithoutBlock(to_s)` rewrite
- Implement codegen for `ObjToString`
2025-08-13 13:03:26 -07:00
Max Bernstein
943d9f828d ZJIT: Don't eliminate NewHash with operands
Hashing and checking operands for equality is re-entrant. We could later
optimize this to check for hash/eq methods on operands and eliminate if
they don't have side effects, but this is fine for now.
2025-08-13 14:01:34 -04:00
Max Bernstein
ad12db4b3d ZJIT: Only validate HIR in debug mode 2025-08-13 13:52:41 -04:00
Stan Lo
df7d9812cc
ZJIT: Prepare non-leaf calls for SetGlobal (#14197)
Some checks failed
Windows / Windows 11-arm/Visual C++ (btest test-basic test-tool) (push) Waiting to run
Windows / Windows 2022/Visual C++ 2022 (check) (push) Waiting to run
Windows / Windows 2025/Visual C++ 2022 (check) (push) Waiting to run
Windows / Windows 2025/Visual C++ 2022 (test-bundled-gems) (push) Waiting to run
Windows / result (push) Blocked by required conditions
Ubuntu on WSL / wsl (push) Waiting to run
Annocheck / test-annocheck (push) Failing after 59s
Check Dependencies / Dependency checks (push) Failing after 56s
Misc / Miscellaneous checks (push) Failing after 1m4s
CodeQL / Analyze (push) Failing after 56s
Compilations / omnibus compilations, trigger (push) Failing after 52s
Update default gems list / Update default gems list (push) Has been skipped
parse.y / make (check) (push) Failing after 56s
parse.y / make (test-bundled-gems) (push) Failing after 56s
parse.y / make (test-bundler-parallel) (push) Failing after 57s
WebAssembly / make (map[debugflags: name:O2 optflags:-O2 wasmoptflags:-O2]) (push) Failing after 1m1s
Compilations / omnibus compilations, #5 (push) Has been skipped
Compilations / omnibus compilations, #6 (push) Has been skipped
Compilations / omnibus compilations, #8 (push) Has been skipped
Compilations / omnibus compilations, #10 (push) Has been skipped
Compilations / omnibus compilations, #11 (push) Has been skipped
BASERUBY Check / BASERUBY (push) Failing after 52s
Compilations / omnibus compilations, #1 (push) Has been skipped
Compilations / omnibus compilations, #2 (push) Has been skipped
Compilations / omnibus compilations, #3 (push) Has been skipped
Compilations / omnibus compilations, #4 (push) Has been skipped
Compilations / omnibus compilations, #7 (push) Has been skipped
Compilations / omnibus compilations, #9 (push) Has been skipped
Compilations / omnibus compilations, #12 (push) Has been skipped
Compilations / omnibus compilations, result (push) Successful in 1m14s
When trace_var is used, setting a global variable can cause exceptions
to be raised. We need to prepare for that.
2025-08-12 17:39:46 -07:00
Takashi Kokubun
231407c251
ZJIT: Avoid compiling failed ISEQs repeatedly (#14195) 2025-08-12 13:40:42 -07:00
Max Bernstein
998be6b3a4
ZJIT: Add flag to disable the HIR optimizer (#14181)
Also add a check in the bisect script that can assign blame to the HIR
optimizer.
2025-08-12 13:00:22 -04:00
Takashi Kokubun
e26ab5dbf2
ZJIT: Avoid splitting add_into/sub_into for x86_64 (#14177)
* ZJIT: Avoid splitting add_into/sub_into

* Require add_into/sub_into to take a Reg
2025-08-12 09:54:50 -07:00
Alan Wu
8b1afbc6ed CI: Surface Rust warnings on PRs that touch any Rust code
Rust PRs will have a failed CI step if they trigger any warnings.
This helps us stay on top of warnings from new Rust releases and
also ones we accidentally write.

Fix a typo for demo, since this only runs when Rust files are changed.
2025-08-11 20:12:25 -04:00
Takashi Kokubun
9fb34f4f16
ZJIT: Add --zjit-exec-mem-size (#14175)
* ZJIT: Add --zjit-exec-mem-size

* Add a comment about the limit
2025-08-11 15:36:37 -07:00
Stan Lo
e29d333454
ZJIT: Implement concatstrings insn (#14154)
Co-authored-by: Alexander Momchilov <alexander.momchilov@shopify.com>
2025-08-11 15:07:26 -07:00
Takashi Kokubun
319550527f
ZJIT: Add compile/profile/GC/invalidation time stats (#14158)
Co-authored-by: Stan Lo <stan001212@gmail.com>
2025-08-11 13:21:45 -07:00
Alan Wu
5b956fbf60 ZJIT: Fix mismatched_lifetime_syntaxes, new in Rust 1.89.0 2025-08-11 15:49:14 -04:00
Alan Wu
0ba488d7f5
ZJIT: Avoid compiling and direct sends to forwardable ISEQs
These `...` ISEQs have a special calling convention in the interpreter
and our stubs and JIT calling convention don't deal well. Reject for now.
Debugged with help from `@tekknolagi` and `tool/zjit_bisect.rb`.

Merely avoiding direct sends is enough to pass the attached test, but also
avoid compiling ISEQs with `...` parameter to limit exposure for now.

`SendWithoutBlock`, which does dynamic dispatch using interpreter code,
seems to handle calling into forwardable ISEQs correctly, so they are
fine -- we can't predict where these dynamic sends land anyways.
2025-08-08 18:54:53 +00:00
Takashi Kokubun
eb931a09c5
ZJIT: Fix "memory operand with non-register base" (#14153) 2025-08-08 11:24:39 -07:00
Max Bernstein
8eb26ebf91
ZJIT: Add a graphviz dumper for HIR (#14117)
This is moderately useful just in stdout (copy and paste into a renderer) but potentially more useful alongside a tool that parses stdout looking for `digraph G { ... }` and renders those automatically.
2025-08-08 13:56:19 -04:00
Takashi Kokubun
4fef87588a
ZJIT: Remove the need for unwrap() on with_num_bits() (#14144)
* ZJIT: Remove the need for unwrap() on with_num_bits()

* Fix arm64 tests

* Track the caller of with_num_bits

Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>

---------

Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
2025-08-07 16:56:27 -07:00
Stan Lo
2edc944702
ZJIT: Implement defined? codegen for non-yield calls (#14101) 2025-08-07 15:41:05 -07:00
Stan Lo
d25eb1eb5c
ZJIT: Optimize class guards by directly reading klass field (#14136)
Replace `rb_yarv_class_of` call with:
- a constant check for special constants (nil, fixnums, symbols, etc)
- a check for false
- direct memory read at offset 8 for regular heap objects for the class check
2025-08-07 15:38:02 -07:00
Takashi Kokubun
96c9e1e93a
ZJIT: Remove GC offsets overwritten by invalidation (#14102)
ZJIT: Remove GC offsts overwritten by invalidation
2025-08-07 15:30:02 -07:00
Max Bernstein
363ad0ad17
ZJIT: Create HeapObject Type (#14140)
This is a counterpoint to the Immediate type and it represents all BasicObject subclasses except for the several immediate objects.

If we know something is a HeapObject, we know we can treat it as an RBasic pointer.
2025-08-07 15:11:55 -04:00
Max Bernstein
a260bbc550
ZJIT: Set PC before StringCopy (#14141)
ZJIT: Set PC before StringCopy

This function allocates.
2025-08-07 18:28:10 +00:00
Max Bernstein
ba4a36e226
ZJIT: Inline attr_reader/attr_accessor (#14126)
We can rewrite SendWithoutBlock to GetIvar.
2025-08-06 16:56:01 -04:00
Stan Lo
4a70f946a7
ZJIT: Implement SingleRactorMode invalidation (#14121)
* ZJIT: Implement SingleRactorMode invalidation

* ZJIT: Add macro for compiling jumps

* ZJIT: Fix typo in comment

* YJIT: Fix typo in comment

* ZJIT: Avoid using unexported types in zjit.h

`enum ruby_vminsn_type` is declared in `insns.inc` and is not exported.
Using it in `zjit.h` would cause build errors when the file including it
doesn't include `insns.inc`.
2025-08-06 13:51:41 -07:00
Alan Wu
21cb1c9e92 ZJIT: x86: split: Fix live ranges index-out-of-range panic
Previously we crashed panicked due to index bounds check running
test_fixnum.rb.

On ARM and in other places in the x86 backend, this isn't a problem
because they inspect the output of instructions which is never replaced.
2025-08-06 16:26:14 -04:00
Takashi Kokubun
ebb775be8d
ZJIT: Fix "immediate value too large" on cmp for x86_64 (#14125)
Co-authored-by: Alan Wu <alansi.xingwu@shopify.com>
2025-08-06 10:05:20 -07:00
Stan Lo
e60e1952a4
ZJIT: Fix Kernel#Float's annotation (#14123)
As pointed out in https://github.com/ruby/ruby/pull/14078#discussion_r2255427676, the return type should be `Float` instead.
2025-08-05 22:52:59 -04:00
Stan Lo
9c0ebff2cd
ZJIT: Avoid matching built-in iseq's HIR line numbers in tests (#14124)
ZJIT: Avoid matching built-in ISEQs' HIR line numbers in tests

Co-authored-by: Author: Takashi Kokubun <takashi.kokubun@shopify.com>
2025-08-05 17:00:04 -07:00
Max Bernstein
ef95e5ba3d
ZJIT: Profile type+shape distributions (#13901)
ZJIT uses the interpreter to take type profiles of what objects pass through
the code. It stores a compressed record of the history per opcode for the
opcodes we select.

Before this change, we re-used the HIR Type data-structure, a shallow type
lattice, to store historical type information. This was quick for bringup but
is quite lossy as profiles go: we get one bit per built-in type seen, and if we
see a non-built-in type in addition, we end up with BasicObject. Not very
helpful. Additionally, it does not give us any notion of cardinality: how many
of each type did we see?

This change brings with it a much more interesting slice of type history: a
histogram. A Distribution holds a record of the top-N (where N is fixed at Ruby
compile-time) `(Class, ShapeId)` pairs and their counts. It also holds an
*other* count in case we see more than N pairs.

Using this distribution, we can make more informed decisions about when we
should use type information. We can determine if we are strictly monomorphic,
very nearly monomorphic, or something else. Maybe the call-site is polymorphic,
so we should have a polymorphic inline cache. Exciting stuff.

I also plumb this new distribution into the HIR part of the compilation
pipeline.
2025-08-05 16:56:04 -04:00
Takashi Kokubun
53b0462841
ZJIT: Add helpers to prepare for C calls (#14100) 2025-08-04 14:44:51 -07:00
Stan Lo
30a20bc166 ZJIT: Reject builtin annotation if its iseq has multiple invokebuiltin insns 2025-08-01 17:44:39 -07:00
Stan Lo
44dee185aa ZJIT: Annotate Kernel#class 2025-08-01 17:44:39 -07:00
Stan Lo
3c1ca509b8 ZJIT: Improve builtin function annotation collection 2025-08-01 17:44:39 -07:00
Stan Lo
85510fc2ff ZJIT: Support annotating builtin functions
This allows us to annotate builtin functions with their return type.
2025-08-01 17:44:39 -07:00
Takashi Kokubun
19cbf8406a
ZJIT: Enable IncrCounter for arm64 (#14086) 2025-08-01 17:37:00 -07:00
Alan Wu
3ad6bba136 ZJIT: Refer to scratch registers in operands
Co-authored-by: Takashi Kokubun <takashi.kokubun@shopify.com>
2025-08-01 17:56:15 -04:00
Alan Wu
afac226478 ZJIT: Fix side-exit panicking when there's too many locals
Previously, ARM64 panicked due to compiled_side_exits() when the memory
displacement got large enough to exceed the 9 bits limit. Usually, we split
these kind of memory operands, but compiled_side_exits() runs after
split.

Using scratch registers, implement `Insn::Store` on ARM such that it can
handle large displacements without split(). Do this for x86 as well, and
remove arch specific code from compiled_side_exits(). We can now run
`TestKeywordArguments`.

Since `Insn::Store` doesn't need splitting now, users enjoy lower
register pressure.

Downside is, using `Assembler::SCRATCH_REG` as a base register is now
sometimes an error, depending on whether `Insn::Store` also needs to
use the register. It seems a fair trade off since `SCRATCH_REG` is
not often used, and we don't put it as a base register anywhere at the
moment.
2025-08-01 17:56:15 -04:00
Alan Wu
f58fca7de0 ZJIT: A64: Use MOVN for small negative immediates
Save a couple instructions to load a small negative constant into a
register. In fact MOVN is speced to alias as `mov` in the official
disassembly.
2025-08-01 17:32:01 -04:00
Takashi Kokubun
543f8dcad3
ZJIT: Add the ISEQ name to Block asm comments (#14070) 2025-07-31 14:28:08 -07:00
Takashi Kokubun
12306c0c6f
ZJIT: Stub JIT-to-JIT calls (#14052) 2025-07-31 12:57:59 -07:00
Alan Wu
da0de3cb87 ZJIT: A64: Fix splitting for large memory displacements
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-31 13:45:20 -04:00
Alan Wu
0aabbbe31d ZJIT: Remove false comment [ci skip] 2025-07-31 13:45:20 -04:00
Alan Wu
214d587a77 ZJIT: Only build the assembler for target_arch
Fixes test error from running the ARM assembler on x86, but then trying
to disassemble it as x86.
2025-07-31 13:45:20 -04:00
Alan Wu
dd352461da ZJIT: A64: Add add_extended() which can add a register to sp 2025-07-31 13:45:20 -04:00
Max Bernstein
75f25e5c49 ZJIT: Don't create owned Cow/String when printing 2025-07-30 10:36:15 -07:00
Max Bernstein
1b700c56d8 ZJIT: Don't make unnecessary Cow 2025-07-30 10:36:15 -07:00
Max Bernstein
8c73b103cd ZJIT: Don't write to String 2025-07-30 10:36:15 -07:00
Max Bernstein
0f7ee8e7a4 ZJIT: Get rid of CallInfo 2025-07-30 10:36:15 -07:00