| Age | Commit message (Collapse) | Author |
|
Fixes [Bug #21266].
Backport of 9168cad4d63a5d281d443bde4edea6be213b0b25 to 3.3
|
|
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]
|
|
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>
|
|
Don't call `Warning.warn` unless the category is enabled
The warning category should be enabled if we want to call
`Warning.warn`.
This commit speeds up the following benchmark:
```ruby
eval "def test; " +
1000.times.map { "' '.chomp!" }.join(";") + "; end"
def run_benchmark count
i = 0
while i < count
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
yield
ms = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
puts "itr ##{i}: #{(ms * 1000).to_i}ms"
i += 1
end
end
run_benchmark(25) do
250.times do
test
end
end
```
On `master` this runs at about 92ms per iteration. With this patch, it
is 7ms per iteration.
[Bug #20573]
|
|
Improve YJIT performance warning regression test
[Bug #20522]
|
|
(#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>
|
|
This is a backport of 6c8ae44a388e5c03b7db90376af3652007b574e8 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]
|
|
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]
|
|
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]
|
|
#20192] (#10249)
* merge revision(s) bbd249e351af7e4929b518a5de73a832b5617273: [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
|
|
[[Bug #20214]](https://bugs.ruby-lang.org/issues/20214)
|
|
|
|
in bootstrap tests so that `make btest-bruby` skips the right tests.
|
|
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.
|
|
|
|
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)
|
|
YJIT: Avoid register allocation conflict
with a higher stack_idx
|
|
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.
|
|
|
|
Following Jean Boussier's comment that some shape bugs were not
caught by our tests, I'm trying to improve our test coverage a
tiny bit.
|
|
* YJIT: Inline basic Ruby methods
* YJIT: Fix "InsnOut operand made it past register allocation"
checktype should not generate a useless instruction.
|
|
Previously, for block argument callsites with some specific argument
count and callee local variable count combinations, YJIT ended up
writing over arguments that are supposed to be collected into a rest
parameter array unmodified.
Detect when clobbering would happen and avoid it. Also, place the block
handler after the stack overflow check, since it writes to new stack
space.
Reported-by: Takashi Kokubun <takashikkbn@gmail.com>
|
|
* YJIT: Chain-guard opt_mult overflow
* YJIT: Support regenerating Jo after Mul
|
|
Since the compile-time iseq used in the guard was not marked and updated
during compaction, a runtime value reusing the address could falsely pass
the guard.
Co-authored-by: Takashi Kokubun <takashikkbn@gmail.com>
|
|
* Add getbyte JIT implementation
Adds an implementation for String#getbyte for YJIT, along with a
bootstrap test. This should be helpful for pure Ruby implementations
and to avoid unneeded allocations.
Co-authored-by: John Hawthorn <jhawthorn@github.com>
* Skip the getbyte test for RJIT for now
---------
Co-authored-by: John Hawthorn <jhawthorn@github.com>
Co-authored-by: Takashi Kokubun <takashikkbn@gmail.com>
Notes:
Merged-By: maximecb <maximecb@ruby-lang.org>
|
|
These types are essentially claims about what `RBASIC_CLASS(obj)`
returns. The field changes with singleton class creation, but we didn't
consider so previously and elided guards where we actually needed them.
Found running ruby/spec with --yjit-verify-ctx. The assertion interface
makes extensive use of singleton classes.
Notes:
Merged: https://github.com/ruby/ruby/pull/8299
|
|
Issue found by running ruby/spec with `--yjit-verify-ctx`. Thanks!
Notes:
Merged: https://github.com/ruby/ruby/pull/8250
|
|
* YJIT: implement fast path for integer multiplication in opt_mult
* Update yjit/src/codegen.rs
Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
* Implement mul with overflow checking on arm64
* Fix missing semicolon
* Add arm splitting for lshift, rshift, urshift
---------
Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
Notes:
Merged-By: maximecb <maximecb@ruby-lang.org>
|
|
We previously falsely asserted that String#<< always returns a ::String
instance. Issue was discovered on CI with `--yjit-verify-ctx`.
https://github.com/ruby/ruby/actions/runs/5893760435/job/15986002531
Notes:
Merged: https://github.com/ruby/ruby/pull/8240
|
|
* YJIT: Fix splatting empty array with rest param
* YJIT: Rework optional parameter handling to fix corner case
The old code had a few unintuitive parts. The starting PC of the callee
was set in different places; `num_param`, which one would assume to be
static for a particular callee seemingly tallied to different amounts
depending on the what the caller passed; `opts_filled_with_splat` was
greater than zero even when the opts were not filled by items in the
splat array. Functionally, the bits that lets the callee know which
keyword parameters are unspecified were not passed properly when there
are optional parameters and a rest parameter, and then optional
parameters are all filled.
Make `num_param` non-mut and use parameter information in the callee
iseq as-is. Move local variable nil fill and placing of the rest array
out of `gen_push_frame()` as they are only ever relevant for iseq calls.
Always place the rest array at `lead_num + opt_num` to fix the
previously buggy situation.
* YJIT: Compile splat calls to iseqs with rest params
Test interactions with optional parameters.
Notes:
Merged-By: maximecb <maximecb@ruby-lang.org>
|
|
Notes:
Merged-By: k0kubun <takashikkbn@gmail.com>
|
|
Co-authored-by: Maxime Chevalier-Boisvert <maximechevalierb@gmail.com>
Notes:
Merged-By: k0kubun <takashikkbn@gmail.com>
|
|
* YJIT: handle expandarray_rhs_too_small case
YJIT: fix csel bug in x86 backend, add test
Remove commented out lines
Refactor expandarray to use chain guards
Propagate Type::Nil when known
Update yjit/src/codegen.rs
Co-authored-by: Takashi Kokubun <takashikkbn@gmail.com>
* Add missing counter, use get_array_ptr() in expandarray
* Make change suggested by Kokubun to reuse loop
---------
Co-authored-by: Takashi Kokubun <takashikkbn@gmail.com>
Notes:
Merged-By: maximecb <maximecb@ruby-lang.org>
|
|
Implement gen_opt_aref_with
Vm opt_aref_with is available
Test opt_aref_with
Stats for opt_aref_with
Co-authored-by: jhawthorn <jhawthorn@github.com>
Notes:
Merged-By: maximecb <maximecb@ruby-lang.org>
|
|
* Revert "Revert "YJIT: Break register cycles for C arguments (#7918)""
This reverts commit 78ca085785460de46bfc4851a898d525c1698ef8.
* Use shfited_live_ranges for the last-insn check
Notes:
Merged-By: maximecb <maximecb@ruby-lang.org>
|
|
* YJIT: Fix autosplat miscomp for blocks with optionals
When passing an array as the sole argument to `yield`, and the yieldee
takes more than 1 optional parameter, the array is expanded similar
to `*array` splat calls. This is called "autosplat" in
`setup_parameters_complex()`.
Previously, YJIT did not detect this autosplat condition. It passed the
array without expanding it, deviating from interpreter behavior.
Detect this conditon and refuse to compile it.
Fixes: Shopify/yjit#313
* RJIT: Fix autosplat miscomp for blocks with optionals
This is mirrors the same issue as YJIT. See previous commit.
Notes:
Merged-By: maximecb <maximecb@ruby-lang.org>
|
|
SystemStackError
Originally, when 2e7bceb34ea858649e1f975a934ce1894d1f06a6 fixed cfuncs to no
longer use the VM stack for large array splats, it was thought to have fully
fixed Bug #4040, since the issue was fixed for methods defined in Ruby (iseqs)
back in Ruby 2.2.
After additional research, I determined that same issue affects almost all
types of method calls, not just iseq and cfunc calls. There were two main
types of remaining issues, important cases (where large array splat should
work) and pedantic cases (where large array splat raised SystemStackError
instead of ArgumentError).
Important cases:
```ruby
define_method(:a){|*a|}
a(*1380888.times)
def b(*a); end
send(:b, *1380888.times)
:b.to_proc.call(self, *1380888.times)
def d; yield(*1380888.times) end
d(&method(:b))
def self.method_missing(*a); end
not_a_method(*1380888.times)
```
Pedantic cases:
```ruby
def a; end
a(*1380888.times)
def b(_); end
b(*1380888.times)
def c(_=nil); end
c(*1380888.times)
c = Class.new do
attr_accessor :a
alias b a=
end.new
c.a(*1380888.times)
c.b(*1380888.times)
c = Struct.new(:a) do
alias b a=
end.new
c.a(*1380888.times)
c.b(*1380888.times)
```
This patch fixes all usage of CALLER_SETUP_ARG with splatting a large
number of arguments, and required similar fixes to use a temporary
hidden array in three other cases where the VM would use the VM stack
for handling a large number of arguments. However, it is possible
there may be additional cases where splatting a large number
of arguments still causes a SystemStackError.
This has a measurable performance impact, as it requires additional
checks for a large number of arguments in many additional cases.
This change is fairly invasive, as there were many different VM
functions that needed to be modified to support this. To avoid
too much API change, I modified struct rb_calling_info to add a
heap_argv member for storing the array, so I would not have to
thread it through many functions. This struct is always stack
allocated, which helps ensure sure GC doesn't collect it early.
Because of how invasive the changes are, and how rarely large
arrays are actually splatted in Ruby code, the existing test/spec
suites are not great at testing for correct behavior. To try to
find and fix all issues, I tested this in CI with
VM_ARGC_STACK_MAX to -1, ensuring that a temporary array is used
for all array splat method calls. This was very helpful in
finding breaking cases, especially ones involving flagged keyword
hashes.
Fixes [Bug #4040]
Co-authored-by: Jimmy Miller <jimmy.miller@shopify.com>
Notes:
Merged: https://github.com/ruby/ruby/pull/7522
|
|
Notes:
Merged-By: maximecb <maximecb@ruby-lang.org>
|
|
Despite applying a fix to RJIT similar to the YJIT fix, this test still
crashes RJIT.
Notes:
Merged: https://github.com/ruby/ruby/pull/7718
|
|
Previously, setinstancevariable could generate code that calls
`rb_ensure_iv_list_size()` without first updating `cfp->sp`. This means
in the event that a GC start from within said routine the top few
objects would not be marked, causing them to be falsly collected.
Call `jit_prepare_routine_call()` first.
[Bug #19601]
Notes:
Merged: https://github.com/ruby/ruby/pull/7718
|
|
Notes:
Merged-By: k0kubun <takashikkbn@gmail.com>
|
|
Previously we were missing a compile-time check that the known cfuncs
receive the correct number of arguments.
We noticied this because in particular when using ARGS_SPLAT, which also
wasn't checked, YJIT would crash on code which was otherwise correct
(didn't raise exceptions in the VM).
This still supports vararg (argc == -1) cfuncs. I added an additional
assertion that when we use the specialized codegen for one of these
known functions that the argc are popped off the stack correctly, which
should help ensure they're implemented correctly (previously the crash
was usually observed on a future `leave` insn).
[Bug #19595]
Notes:
Merged: https://github.com/ruby/ruby/pull/7697
|
|
Fix [Bug #19586]
Notes:
Merged-By: k0kubun <takashikkbn@gmail.com>
|
|
* YJIT: Add codegen for Integer methods
* YJIT: Update dependencies
* YJIT: Fix Integer#[] for argc=2
Notes:
Merged-By: k0kubun <takashikkbn@gmail.com>
|
|
Notes:
Merged: https://github.com/ruby/ruby/pull/7628
|
|
* YJIT: Rest and keyword (non-supplying)
* Update yjit/src/codegen.rs
---------
Co-authored-by: Maxime Chevalier-Boisvert <maximechevalierb@gmail.com>
Notes:
Merged-By: maximecb <maximecb@ruby-lang.org>
|
|
Notes:
Merged-By: maximecb <maximecb@ruby-lang.org>
|
|
Notes:
Merged-By: maximecb <maximecb@ruby-lang.org>
|
|
* Use shape information in YJIT's definedivar implementation
* Handle complex shape for definedivar
Notes:
Merged-By: maximecb <maximecb@ruby-lang.org>
|
|
We crashed in some edge cases due to the recent change to not compile
encoded iseqs that are larger than `u16::MAX`.
- Match the C signature of rb_yjit_constant_ic_update() and clamp down
to `IseqIdx` size
- Return failure instead of panicking with `unwrap()` in codegen when
the iseq is too large
Co-authored-by: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@shopify.com>
Co-authored-by: Noah Gibbs <noah.gibbs@shopify.com>
Notes:
Merged-By: maximecb <maximecb@ruby-lang.org>
|