Age | Commit message (Collapse) | Author |
|
On non RUBY_DEBUG builds, assert() compiles to nothing and the compiler
warns about uninitialized variables in those code paths. Replace
those asserts with rb_bug() to fix the warnings and do the assert in
all builds. Since yjit_asm_tests.c compiles outside of Ruby, it needed
a distinct version of rb_bug().
Also put YJIT_STATS check for function delcaration that is only defined
in YJIT_STATS builds.
|
|
For upstreaming, we want functions we export either prefixed with "rb_"
or made static. Historically we haven't been following this rule, so we
were "leaking" a lot of symbols as `make leak-globals` would tell us.
This change unifies everything YJIT into a single compilation unit,
yjit.o, and makes everything unprefixed static to pass `make leak-globals`.
This manual "unified build" setup is similar to that of vm.o.
Having everything in one compilation unit allows static functions to
be visible across YJIT files and removes the need for declarations in
headers in some cases. Unnecessary declarations were removed.
Other changes of note:
- switched to MJIT_SYMBOL_EXPORT_BEGIN which indicates stuff as being
off limits for native extensions
- the first include of each YJIT file is change to be "internal.h"
- undefined MAP_STACK before explicitly redefining it since it
collide's with a definition in system headers. Consider renaming?
|
|
|
|
|
|
This is so we know the specific reason we're exiting this instruction.
Co-authored-by: Aaron Patterson tenderlove@ruby-lang.org
|
|
|
|
I noticed that there were two st_table iterators that do exactly the
same thing so I merged them into one.
|
|
|
|
Before this change, when we encounter a constant cache that is specific
to a lexical scope, we unconditionally exit. This change falls back to
the interpreter's cache in this situation.
This should help constant expressions in `class << self`, which is popular
at Shopify due to the style guide.
This change relies on the cache being warm while compiling to detect the
need for checking the lexical scope for simplicity.
|
|
|
|
|
|
Checked on default build, RUBY_DEBUG build, and YJIT_STATS build.
|
|
Follow up for ecb5b383a0c17550b9b27663005049ddac871edb. Now that
YJIT_STATS is defined in yjit.h, it shoudl be the only place that
defines it.
|
|
This fixes and re-enables invokesuper, replacing the existing guards
with a guard on the method entry for the EP.
|
|
This change fixes some cases where YJIT fails to fire tracing events.
Most of the situations YJIT did not handle correctly involves enabling
tracing while running inside generated code.
A new operation to invalidate all generated code is added, which uses
patching to make generated code exit at the next VM instruction
boundary. A new routine called `jit_prepare_routine_call()` is
introduced to facilitate this and should be used when generating code
that could allocate, or could otherwise use `RB_VM_LOCK_ENTER()`.
The `c_return` event is fired in the middle of an instruction as opposed
to at an instruction boundary, so it requires special handling. C method
call return points are patched to go to a fucntion which does everything
the interpreter does, including firing the `c_return` event. The
generated code for C method calls normally does not fire the event.
Invalided code should not change after patching so the exits are not
clobbered. A new variable is introduced to track the region of code that
should not change.
|
|
|
|
RUBY_DEBUG have a very significant performance overhead. Enough that
YJIT with RUBY_DEBUG is noticeably slower than the interpreter without
RUBY_DEBUG.
This makes it hard to collect yjit-stats in production environments.
By allowing to collect JIT statistics without the RUBy_DEBUG overhead,
I hope to make such use cases smoother.
|
|
|
|
Now that we're using the jit function entry point, we don't need the
scraper. Thank you for your service, scraper. ❤️
|
|
Methods with optional parameters don't always start executing at the
first PC, but we compile all methods assuming that they do. This commit
adds a guard to ensure that we're actually starting at the first PC for
methods with optional params
|
|
Always using `ret` to return to the interpreter means that we never have
to check the VM_FRAME_FLAG_FINISH flag.
In the case that we return `Qundef`, the interpreter will execute the
cfp. We can take advantage of this by setting the PC to the instruction
we can't handle, and let the interpreter pick up the ball from there.
If we return a value other than Qundef, the interpreter will take that
value as the "return value" from the JIT and push that to the SP of the
caller
The leave instruction puts the return value on the top of the calling
frame's stack. YJIT does the same thing for leave instructions.
However, when we're returning back to the interpreter, the leave
instruction _should not_ put the return value on the top of the stack,
but put it in RAX and use RET. This commit pops the last value from the
stack pointer and puts it in RAX so that the interpreter is happy with
SP.
|
|
|
|
|
|
|
|
|
|
For use in development for writing `test.rb` and running with `make
run`.
|
|
* Use builtin_inline_p to skip a frame of C methods
* Fix bugs in primitive cfunc call code
* Remove if (push_frame) {}
* Remove if (push_frame) {}
* Push Aaron's fix to avoid hardcoding insn lengths
Co-authored-by: Takashi Kokubun <takashikkbn@gmail.com>
|
|
* Implement send with blocks
Not that much extra work compared to `opt_send_without_block`.
Moved the stack over flow check because it could've exited after changes
are made to cfp.
* rename oswb counters
* Might as well implement sending block to cfuncs
* Disable sending blocks to cfuncs for now
* Reconstruct interpreter sp before calling into cfuncs
In case the callee cfunc calls a method or delegates to a block.
This also has the side benefit of letting call sites that sometimes are
iseq calls and sometimes cfunc call share the same successor.
* only sync with interpreter sp when passing a block
Co-authored-by: Maxime Chevalier-Boisvert <maximechevalierb@gmail.com>
Co-authored-by: Aaron Patterson <aaron.patterson@shopify.com>
|
|
* Implement calls to methods with simple optional params
* Remove unnecessary MJIT_STATIC
See comment for MJIT_STATIC. I added it not knowing whether it's
required because the function next to it has it. Don't use it and wait
for problems to come up instead.
* Better naming, some comments
* Count bailing on kw only iseqs
On railsbench:
```
opt_send_without_block exit reasons:
bmethod 59729 (27.7%)
optimized_method 59137 (27.5%)
iseq_complex_callee 41362 (19.2%)
alias_method 33346 (15.5%)
callsite_not_simple 19170 ( 8.9%)
iseq_only_keywords 1300 ( 0.6%)
kw_splat 1299 ( 0.6%)
cfunc_ruby_array_varg 18 ( 0.0%)
```
|
|
This commit improves the set ivar implementation.
|
|
YJIT: Avoid adding duplicate code comments
|
|
|
|
Make sure `opt_getinlinecache` is in a block all on its own, and
invalidate it from the interpreter when `opt_setinlinecache`.
It will recompile with a filled cache the second time around.
This lets YJIT runs well when the IC for constant is cold.
|
|
Introduce a new macro `ADD_COMMENT(cb, comment)` that records a comment
for the current write position in the code block.
Co-authored-by: Maxime Chevalier-Boisvert <maximechevalierb@gmail.com>
Co-authored-by: Aaron Patterson <aaron.patterson@shopify.com>
|
|
This commit collects statistics about how many binding objects are
allocated as well as the number of local variables set on bindings.
Statistics are output along with other YJIT stats. Here is an example
of the output:
```
***YJIT: Printing runtime counters from yjit.rb***
Number of Bindings Allocated: 195
Number of locals modified through binding: 0
opt_send_without_block exit reasons:
ivar_get_method 7515891 (40.4%)
se_cc_klass_differ 3081330 (16.6%)
iseq_argc_mismatch 1564578 ( 8.4%)
se_receiver_not_heap 1557663 ( 8.4%)
ic_empty 1407064 ( 7.6%)
optimized_method 995823 ( 5.4%)
iseq_not_simple 819413 ( 4.4%)
alias_method 706972 ( 3.8%)
bmethod 685253 ( 3.7%)
callsite_not_simple 225983 ( 1.2%)
kw_splat 25999 ( 0.1%)
ivar_set_method 902 ( 0.0%)
cfunc_toomany_args 394 ( 0.0%)
refined_method 42 ( 0.0%)
cfunc_ruby_array_varg 29 ( 0.0%)
invalid_cme 4 ( 0.0%)
leave exit reasons:
se_finish_frame 4067107 (100.0%)
se_interrupt 24 ( 0.0%)
getinstancevariable exit reasons:
undef 121177 (100.0%)
idx_out_of_range 5 ( 0.0%)
opt_aref exit reasons:
(all relevant counters are zero)
compiled_iseq_count: 3944
main_block_code_size: 1.1 MiB
side_block_code_size: 0.6 MiB
vm_insns_count: 1137268516
yjit_exec_insns_count: 414015644
ratio_in_yjit: 26.7%
avg_len_in_yjit: 7.5
total_exit_count: 55491789
most frequent exit op:
opt_send_without_block: 18587628 (33.5%)
opt_getinlinecache: 11075822 (20.0%)
send: 4949300 (8.9%)
leave: 4067131 (7.3%)
defined: 3975196 (7.2%)
setinstancevariable: 3567315 (6.4%)
invokesuper: 2982163 (5.4%)
getblockparamproxy: 2168852 (3.9%)
opt_nil_p: 2104524 (3.8%)
opt_aref: 2013858 (3.6%)
```
Running RailsBench allocates 195 binding objects but doesn't set any
local variables.
|
|
Mostly unused and uninitialized warnings here and there
|
|
|
|
|
|
|
|
Make it lazy and add a hash specialization in addition to the array
specialization.
|
|
|
|
Lazily compile out a chain of checks for different known classes and
whether `self` embeds its ivars or not.
* Remove trailing whitespaces
* Get proper addresss in Capstone disassembly
* Lowercase address in Capstone disassembly
Capstone uses lowercase for jump targets in generated listings. Let's
match it.
* Use the same successor in getivar guard chains
Cuts down on duplication
* Address reviews
* Fix copypasta error
* Add a comment
|
|
This is how vm.c does it, and if we don't follow it in yjit
compilation units, rb_vm_t would have a conflicting size.
|
|
When a BOP is redefined, the BOP redefinition callback will invalidate
any blocks that depend on BOPS. This allows us to eliminate runtime
checks for BOP redefinition.
|
|
Renaming uJIT to YJIT. AKA s/ujit/yjit/g.
|