825 Commits
Author SHA1 Message Date
Randy Stauner 0cba8cf414 YJIT: Bail out if proc would be stored above stack top
Fixes [Bug #21266].

Backport of 9168cad4d6 to 3.3
2026-03-04 15:45:16 +09:00
nagachika c1c068e43c Follow up for 3809389984. The type of jump_to_next_insn() is Option<()> on ruby_3_3. 2025-05-24 18:12:02 +09:00
nagachika 7230a070e3 Follow up for 3809389984. jump_to_next_insn() require 3rd argument on ruby_3_3. 2025-05-24 17:27:33 +09:00
nagachika 3809389984 merge revision(s) cbf9c088f8: [Backport #21310]
YJIT: End the block after OPTIMIZE_METHOD_TYPE_CALL (#13245)
2025-05-24 16:38:32 +09:00
nagachika f57dd4470b merge revision(s) 80a1a1bb8a: [Backport #21257]
YJIT: Fix potential infinite loop when OOM (GH-13186)

	Avoid generating an infinite loop in the case where:
	1. Block `first` is adjacent to block `second`, and the branch from `first` to
	   `second` is a fallthrough, and
	2. Block `second` immediately exits to the interpreter, and
	3. Block `second` is invalidated and YJIT is OOM

	While pondering how to fix this, I think I've stumbled on another related edge case:
	1. Block `incoming_one` and `incoming_two` both branch to block `second`. Block
	   `incoming_one` has a fallthrough
	2. Block `second` immediately exits to the interpreter (so it starts with its exit)
	3. When Block `second` is invalidated, the incoming fallthrough branch from
	   `incoming_one` might be rewritten first, which overwrites the start of block
	   `second` with a jump to a new branch stub.
	4. YJIT runs of out memory
	5. The incoming branch from `incoming_two` is then rewritten, but because we're
	   OOM we can't generate a new stub, so we use `second`'s exit as the branch
	   target. However `second`'s exit was already overwritten with a jump to the
	   branch stub for `incoming_one`, so `incoming_two` will end up jumping to
	   `incoming_one`'s branch stub.

	Fixes [Bug #21257]
2025-05-18 16:25:01 +09:00
Takashi KokubunandAlan Wu e9f479d871 YJIT: Filter & calls from specialized C method codegen
Evident with the crash reported in [Bug #20997], the C replacement
codegen functions aren't authored to handle block arguments (nor
should they because the extra code from the complexity defeats
optimization). Filter sites with VM_CALL_ARGS_BLOCKARG.

Co-Authored-By: Alan Wu <alanwu@ruby-lang.org>
2025-01-14 21:16:37 -08:00
Alan Wu aa957546fa Bump shlex from 1.1.0 to 1.3.0 in /yjit/bindgen (#10985)
`yjit-bindgen` isn't run to build Ruby releases at all, but people might
be running security scanners on the source tarball. Upgrade this
dependency to calm the scanners.

Backport of <https://github.com/ruby/ruby/pull/9652>.
See: <https://github.com/ruby/ruby/pull/10980>
2024-06-13 10:02:02 -07:00
Jean byroot BoussierandJean Boussier d0327a7224 Don't add +YJIT to RUBY_DESCRIPTION until it's actually enabled (#10920)
If you start Ruby with `--yjit-disable`, the `+YJIT` shouldn't be
added until `RubyVM::YJIT.enable` is actually called. Otherwise
it's confusing in crash reports etc.

Co-authored-by: Jean Boussier <jean.boussier@gmail.com>
2024-06-05 14:54:24 -07:00
4f00d98b32 [3.3 backport] Do not emit shape transition warnings when YJIT is compiling (#10911)
Do not emit shape transition warnings when YJIT is compiling

[Bug #20522]

If `Warning.warn` is redefined in Ruby, emitting a warning would invoke
Ruby code, which can't safely be done when YJIT is compiling.

Co-authored-by: Jean Boussier <jean.boussier@gmail.com>
Co-authored-by: Takashi Kokubun <takashikkbn@gmail.com>
2024-06-04 13:21:58 -07:00
Alan Wu b74f669e2f YJIT: Fix out of bounds access when splatting empty array (#10905)
This is a backport of 6c8ae44a38 with a
test tailored to crash the 3.3.x branch (from GH-10904).

    Previously, we read the last element array even when the array was
    empty, doing an out-of-bounds access. This sometimes caused a SEGV.

    [Bug #20496]
2024-06-04 13:17:41 -07:00
Takashi Kokubun 6383d0afac merge revision(s) 015b0e2e1d312e2be60551587389c8da5c585e6f,ac1e9e443a0d6a4d4c0801c26d1d8bd33d9eb431: [Backport #20195]
YJIT: Fix unused warnings

	```
	warning: unused import: `condition::Condition`
	  --> src/asm/arm64/arg/mod.rs:13:9
	   |
	13 | pub use condition::Condition;
	   |         ^^^^^^^^^^^^^^^^^^^^
	   |
	   = note: `#[warn(unused_imports)]` on by default

	warning: unused import: `rb_yjit_fix_mul_fix as rb_fix_mul_fix`
	   --> src/cruby.rs:188:9
	    |
	188 | pub use rb_yjit_fix_mul_fix as rb_fix_mul_fix;
	    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

	warning: unused import: `rb_insn_len as raw_insn_len`
	   --> src/cruby.rs:142:9
	    |
	142 | pub use rb_insn_len as raw_insn_len;
	    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
	    |
	    = note: `#[warn(unused_imports)]` on by default
	```

	Make asm public so it stops warning about unused public stuff in there.

	YJIT: Fix ruby2_keywords splat+rest and drop bogus checks

	YJIT didn't guard for ruby2_keywords hash in case of splat calls that
	land in methods with a rest parameter, creating incorrect results.

	The compile-time checks didn't correspond to any actual effects of
	ruby2_keywords, so it was masking this bug and YJIT was needlessly
	refusing to compile some code. About 16% of fallback reasons in
	`lobsters` was due to the ISeq check.

	We already handle the tagging part with
	exit_if_supplying_kw_and_has_no_kw() and should now have a dynamic guard
	for all splat cases.

	Note for backporting: You also need 7f51959ff1.

	[Bug #20195]
2024-05-28 17:10:33 -07:00
Takashi Kokubun 9c81bbbbb7 merge revision(s) 7f51959ff1: [Backport #20204]
YJIT: Move guard up for a case of splat+rest

	Previously, YJIT put the guard for having enough items to extract from
	splat array at a place where the side exit is invalid, so if the guard
	fails, YJIT could raise something other than ArgumentError. Move the
	guard up to a place before any stack manipulation.

	[Bug #20204]
2024-05-28 16:55:49 -07:00
NARUSE, Yui 93d7bf5c5c merge revision(s) bbd249e351: [Backport #20192] (#10249)
* merge revision(s) bbd249e351: [Backport #20192]

	YJIT: Properly reject keyword splat with `yield`

	We don't have support for keyword splat anywhere, but we tried to
	compile these anyways in case of `invokeblock`. This led to bad things
	happening such as passing the wrong value and passing a hash into
	rb_yjit_array_len(), which raised in the middle of compilation.

	[Bug #20192]

* Skip a new test for RJIT
2024-05-28 14:52:47 -07:00
Alan Wu cdcabd8a44 Backport 3.3: YJIT memory leak fix with additional CI fixes (#9841)
merge revision(s) 2cc7a56e,b0711b1,db5d9429: [Backport #20209]

	YJIT: Avoid leaks by skipping objects with a singleton class

	For receiver with a singleton class, there are multiple vectors YJIT can
	end up retaining the object. There is a path in jit_guard_known_klass()
	that bakes the receiver into the code, and the object could also be kept
	alive indirectly through a path starting at the CME object baked into
	the code.

	To avoid these leaks, avoid compiling calls on objects with a singleton
	class.

	See: https://github.com/Shopify/ruby/issues/552

	[Bug #20209]
	---
	 yjit/bindgen/src/main.rs       |  1 +
	 yjit/src/codegen.rs            | 17 +++++++++++++++++
	 yjit/src/cruby_bindings.inc.rs |  1 +
	 yjit/src/stats.rs              |  2 ++
	 4 files changed, 21 insertions(+)

	YJIT: Fix tailcall and JIT entry eating up FINISH frames (#9729)

	Suppose YJIT runs a rb_vm_opt_send_without_block()
	fallback and the control frame stack looks like:

	```
	will_tailcall_bar [FINISH]
	caller_that_used_fallback
	```

	will_tailcall_bar() runs in the interpreter and sets up a tailcall.
	Right before JIT_EXEC() in the `send` instruction, the stack will look like:

	```
	bar [FINISH]
	caller_that_used_fallback
	```

	Previously, JIT_EXEC() ran bar() in JIT code, which caused the `FINISH`
	flag to return to the interpreter instead of to the JIT code running
	caller_that_used_fallback(), causing code to run twice and probably
	crash. Recent flaky failures on CI about "each stub expects a particular
	iseq" are probably due to leaving methods twice in
	`test_optimizations.rb`.

	Only run JIT code from the interpreter if a new frame is pushed.
	---
	 test/ruby/test_optimization.rb | 11 +++++++++++
	 vm_exec.h                      |  3 ++-
	 2 files changed, 13 insertions(+), 1 deletion(-)

	YJIT: No need to RESTORE_REG now that we reject tailcalls

	Thanks to Kokubun for noticing.

	Follow-up: b0711b1cf1
	---
	 vm_exec.h | 1 -
	 1 file changed, 1 deletion(-)
2024-03-14 16:26:02 +00:00
Takashi Kokubun 3f0e3ede02 YJIT: Fix exits on splatkw instruction (#9715)
[[Bug #20214]](https://bugs.ruby-lang.org/issues/20214)
2024-02-05 14:51:16 +00:00
Takashi Kokubun a065b68bd8 Backport #9415 to ruby_3_3 (#9424)
YJIT: Let RubyVM::YJIT.enable respect --yjit-stats
2024-02-04 05:37:33 +00:00
Maxime Chevalier-BoisvertandTakashi Kokubun ba16b34098 YJIT: reduce default exec mem size to 48MiB (#9692)
* YJIT: reduce default exec mem size to 48MiB based

Based on user feedback from @jhawthorn and others.
Better for small and memory-constrained deployments.

NOTE: This commit should be included in the next Ruby 3.3.x point
release. @xrxr should we tag someone specific?

* YJIT: Update yjit.md about mem size (#9687)

---------

Co-authored-by: Takashi Kokubun <takashikkbn@gmail.com>
2024-02-04 05:36:34 +00:00
Hiroshi SHIBATA 863ded45a1 Typofix under bootstraptest, spec and yjit directories 2023-12-25 13:50:23 +09:00
Takashi Kokubun bd91c5127f YJIT: Add stats option to RubyVM::YJIT.enable (#9297) 2023-12-19 11:47:27 -08:00
Takashi Kokubun b266890dab YJIT: Add --yjit-disable to help and reorder it (#9230) 2023-12-13 13:29:37 -08:00
Alan Wu d4bbee7475 YJIT: Fix off-by-one in Kernel#send type handling (#9212)
Previously, if the method ID argument happens to be on one below the top
of the stack, we didn't overwrite the type of the stack slot, which
leaves an incorrect type for the stack slot. The included script tripped
asserts both with and without --yjit-verify-ctx.
2023-12-12 22:10:14 +00:00
Alan Wu 9cb0ad863c YJIT: Fix missing arity check for splat calls to methods with optionals
Previously, for splat callsites that land in methods with optional
parameters, we didn't reject the case where the caller supplies too many
arguments. Accepting those calls previously caused YJIT to construct
corrupted control frames, which leads to crashes if the callee uses
certain stack walking methods such as Kernel#raise and String#gsub (for
setting up the frame-local `$~`).

Example crash in a debug build:

    Assertion Failed: ../vm_core.h:1375:VM_ENV_FLAGS:FIXNUM_P(flags)
2023-12-11 19:21:08 -05:00
Alan Wu 4755309474 YJIT: Rename helper function and correct counter name
Counter::guard_send_iseq_has_rest_and_splat_not_equal was using
jump-if-lesser-than, so wasn't checking for equality. Rename function
because moving is destructive in Rust, which is confusing for this function
which doesn't modify the array.
2023-12-11 19:21:08 -05:00
Jeremy Evans a950f23078 Ensure f(**kw, &block) calls kw.to_hash before block.to_proc
Previously, block.to_proc was called first, by vm_caller_setup_arg_block.
kw.to_hash was called later inside CALLER_SETUP_ARG or setup_parameters_complex.

This adds a splatkw instruction that is inserted before sends with
ARGS_BLOCKARG and KW_SPLAT and without KW_SPLAT_MUT. This is not needed in the
KW_SPLAT_MUT case, because then you know the value is a hash, and you don't
need to call to_hash on it.

The splatkw instruction checks whether the second to top block is a hash,
and if not, replaces it with the value of calling to_hash on it (using
rb_to_hash_type).  As it is always before a send with ARGS_BLOCKARG and
KW_SPLAT, second to top is the keyword splat, and top is the passed block.
2023-12-09 13:15:47 -08:00
Takashi Kokubun ac5fd58700 YJIT: Fix on-stack ISEQ comparison for auto_compact (#9164) 2023-12-07 22:53:05 +00:00
Alan Wu 9d9865d9bc YJIT: Add some object validity assertions
We've seen quite a few compaction bugs lately, and these assertions
should give clearer symptoms. We only call class_of() on
objects that the Ruby code can see.
2023-12-06 16:42:53 -05:00
Takashi Kokubun a439fc2f17 YJIT: Avoid register allocation conflict with a higher stack_idx (#9143)
YJIT: Avoid register allocation conflict

with a higher stack_idx
2023-12-06 15:19:43 -05:00
Alan Wu a063969ec1 YJIT: Assert code pages are not partially in-bounds
Helps understand page switching
2023-12-05 13:20:06 -05:00
Alan Wu 695e5c179e YJIT: Simplify code page switching logic, remove an assert
We have received a report of `assert!( !cb.has_dropped_bytes())` in
set_page() failing. The only explanation for this seems to be memory
allocation failing in write_byte(). The if condition implies that
`current_write_pos < dst_pos < mem_size`, which rules out failing to
encode the relative jump. The has_capacity() assert above not tripping
implies that we were in a place in the page where write_byte() did
attempt to write the byte and potentially made a syscall in the process.

Remove the assert, since memory allocation could fail. Also, return
failure if the destination is outside of the code region to detect that
out-of-memory situation quicker.
2023-12-05 13:20:06 -05:00
Alan Wu b5a62eb9ab YJIT: Mark and update stubs in invalidated blocks (#9104)
Like in the example given in delayed_deallocation(), stubs can be hit
even if the block housing it is invalidated. Mark them so we don't
work with invalidate ISeqs when hitting these stubs.
2023-12-04 10:13:40 -05:00
Takashi KokubunandAlan Wu ba1cdadfc8 YJIT: Cancel on-stack jit_return on invalidation (#9086)
* YJIT: Cancel on-stack jit_return on invalidation

Co-authored-by: Alan Wu <alansi.xingwu@shopify.com>

* Use RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P

---------

Co-authored-by: Alan Wu <alansi.xingwu@shopify.com>
2023-11-30 21:35:55 -05:00
Maxime Chevalier-Boisvert 73e6d8a0d0 YJIT: optimized codegen for rb_ary_length() (#9085)
YJIT: optimized codegen for rb_ary_length()
2023-11-30 17:14:53 -05:00
Takashi Kokubun d048bae96b YJIT: Bump ec->cfp after setting cfp->jit_return (#9072) 2023-11-30 11:23:25 -05:00
Maxime Chevalier-Boisvert 8d1138c1cf YJIT: edit yjit.md and bring it up to date (#9068)
Also make various minor edits to improve readability.
2023-11-29 18:09:55 -05:00
Maxime Chevalier-Boisvert ea3e17e430 YJIT: fix bug in top cfunc logging in --yjit-stats (#9056)
YJIT: correctly handle case where there are no cfunc calls

Fix bug in top cfunc logging in `--yjit-stats`
2023-11-28 22:27:11 +00:00
Maxime Chevalier-Boisvert 6310522a9a YJIT: reduce default exec-mem-size to 64MiB (#9054) 2023-11-28 20:04:33 +00:00
Takashi Kokubun 476a231e7e YJIT: Assert no patch overlap on pos_marker (#9048) 2023-11-28 10:41:14 -05:00
Maxime Chevalier-Boisvert 7f50c70574 YJIT: add top C function call counts to --yjit-stats (#9047)
* YJIT: gather call counts for individual cfuncs

Co-authored by Takashi Kokubun
2023-11-27 22:49:53 +00:00
Maxime Chevalier-Boisvert f05d586cc9 YJIT: record num_send_cfunc stat (#9022)
* YJIT: record num_send_cfunc stat

Also report num_send_known_cfunc as percentage of num_send_cfunc

* Rename num_send_known_cfunc => num_send_cfunc_inline

Name seems more descriptive of what we do with out custom codegen
2023-11-23 15:33:43 -05:00
Takashi Kokubun 440b59db10 YJIT: Apply patches ignoring page_end_reserve (#9015) 2023-11-23 10:53:12 -05:00
Takashi Kokubun 95369ac0a3 YJIT: Fix jmp_ptr_bytes on x86_64 (#9016) 2023-11-23 10:50:42 -05:00
Takashi Kokubun 926bfc3bc0 YJIT: Avoid a register spill on arm64 (#9014) 2023-11-22 15:13:32 -08:00
Takashi Kokubun 95d4a52b3a YJIT: Skip dump-disasm if it fails to create a file (#8968) 2023-11-21 10:28:45 -05:00
Aaron Patterson 6fce8c7980 Don't try compacting ivars on Classes that are "too complex"
Too complex classes use a hash table to store ivs, and should always pin
their IVs.  We shouldn't touch those classes in compaction.
2023-11-20 16:09:48 -08:00
Takashi Kokubun fa547cd702 YJIT: Print a disasm path to stderr (#8967)
YJIT: Print a perf map path to stderr
2023-11-20 14:51:54 -08:00
Maxime Chevalier-Boisvert f9628fb4be YJIT: make --yjit-max-versions=N option undocumented (#8962)
Not useful for the vast majority of end users to change
this option.
2023-11-20 21:26:18 +00:00
Maxime Chevalier-Boisvert c552a5f7b0 YJIT: shrink Context down to 15 bytes (#8911)
* WIP context refactoring

* Refactor to remove Context.temp_mapping
2023-11-13 17:14:24 -05:00
Alan Wu f5fa90fe0b YJIT: Fix clippy::useless_vec in a test 2023-11-10 16:55:56 -05:00
Alan Wu 8dfbfa15f6 YJIT: Take cargo --fix for unnecessary calls to into() 2023-11-10 16:55:56 -05:00
Alan Wu 408d5886cf YJIT: Auto fix for clippy::unnecessary_cast 2023-11-10 16:55:56 -05:00