Граф коммитов

98 Коммитов

Автор SHA1 Сообщение Дата
Zack Deveau dea4238544
Port gen_concatstring to new backend IR (https://github.com/Shopify/ruby/pull/350)
* Port gen_concatstring to new backend IR

* Update yjit/src/codegen.rs

Co-authored-by: Maxime Chevalier-Boisvert <maximechevalierb@gmail.com>
2022-08-29 08:47:05 -07:00
Takashi Kokubun 330c9e9850
Port anytostring, intern, and toregexp (https://github.com/Shopify/ruby/pull/348)
* Port anytostring, intern, and toregexp

* Port getspecial to the new backend (#349)

PR: https://github.com/Shopify/ruby/pull/349
2022-08-29 08:47:05 -07:00
Takashi Kokubun 16307adf8f
Port only ATTRSET of opt_send_without_block (https://github.com/Shopify/ruby/pull/351) 2022-08-29 08:47:05 -07:00
Zack Deveau 6ab71a8598
Port gen_checktype to the new IR assembler backend (https://github.com/Shopify/ruby/pull/343) 2022-08-29 08:47:05 -07:00
Matthew Draper ab08a43ec5
YJIT: Teach getblockparamproxy to handle the no-block case without exiting (#6191)
Teach getblockparamproxy to handle the no-block case without exiting

Co-authored-by: John Hawthorn <john@hawthorn.email>

Co-authored-by: John Hawthorn <john@hawthorn.email>
2022-07-28 11:38:07 -04:00
Matt Valentine-House 6423d32e3b Replace use of double_heap in tests with expand_heap 2022-07-11 09:00:03 -04:00
Noah Gibbs (and/or Benchmark CI) 5da31b62b0 Make sure string-operation assertions happen inside a method to be sure YJIT will JIT them. 2022-06-27 09:26:18 -07:00
Alan Wu 333754ace8 YJIT: Add regression test for local type tracking
The test in [1] was removed because it stopped working when we limited
the power of Kernel#binding in [2]. However, the underlying issue could
still be reproduced using blocks. Add back a regression test.

I tested the test by commenting out the fix from [1].

[1]: 54c91042ed
[2]: 343ea9967e
2022-06-23 20:27:02 -04:00
Noah Gibbs 9ed9cc9852
Add tests for a variety of string-subclass operations (#5999)
This way YJIT has to match CRuby for each of them.
Remove unused string_p() Rust function
2022-06-10 13:52:43 -04:00
Noah Gibbs 1598c9458a
Add special-case code for the String unary plus operator (#5982) 2022-06-07 11:20:57 -04:00
Noah Gibbs 9d18661e1d
Revert incorrect string-guard optimisation. (#5969)
Also add jhawthorn's test to for this bug.
Fix String#to_s invalidation test
2022-06-01 10:22:08 -04:00
Noah Gibbs 50bad7159a
Special-case jit_guard_known_class for strings. This can remove (#5920)
runtime guard-checks for String#to_s, making some blocks too
short to invalidate later. Add NOPs in those cases to reserve space.
2022-05-20 19:39:37 -04:00
Alan Wu f90549cd38 Rust YJIT
In December 2021, we opened an [issue] to solicit feedback regarding the
porting of the YJIT codebase from C99 to Rust. There were some
reservations, but this project was given the go ahead by Ruby core
developers and Matz. Since then, we have successfully completed the port
of YJIT to Rust.

The new Rust version of YJIT has reached parity with the C version, in
that it passes all the CRuby tests, is able to run all of the YJIT
benchmarks, and performs similarly to the C version (because it works
the same way and largely generates the same machine code). We've even
incorporated some design improvements, such as a more fine-grained
constant invalidation mechanism which we expect will make a big
difference in Ruby on Rails applications.

Because we want to be careful, YJIT is guarded behind a configure
option:

```shell
./configure --enable-yjit # Build YJIT in release mode
./configure --enable-yjit=dev # Build YJIT in dev/debug mode
```

By default, YJIT does not get compiled and cargo/rustc is not required.
If YJIT is built in dev mode, then `cargo` is used to fetch development
dependencies, but when building in release, `cargo` is not required,
only `rustc`. At the moment YJIT requires Rust 1.60.0 or newer.

The YJIT command-line options remain mostly unchanged, and more details
about the build process are documented in `doc/yjit/yjit.md`.

The CI tests have been updated and do not take any more resources than
before.

The development history of the Rust port is available at the following
commit for interested parties:
1fd9573d8b

Our hope is that Rust YJIT will be compiled and included as a part of
system packages and compiled binaries of the Ruby 3.2 release. We do not
anticipate any major problems as Rust is well supported on every
platform which YJIT supports, but to make sure that this process works
smoothly, we would like to reach out to those who take care of building
systems packages before the 3.2 release is shipped and resolve any
issues that may come up.

[issue]: https://bugs.ruby-lang.org/issues/18481

Co-authored-by: Maxime Chevalier-Boisvert <maximechevalierb@gmail.com>
Co-authored-by: Noah Gibbs <the.codefolio.guy@gmail.com>
Co-authored-by: Kevin Newton <kddnewton@gmail.com>
2022-04-27 11:00:22 -04:00
Jeremy Evans 0b091fdac6
Raise RuntimeError if Kernel#binding is called from a non-Ruby frame
Check whether the current or previous frame is a Ruby frame in
call_trace_func and rb_tracearg_binding before attempting to
create a binding for the frame.

Fixes [Bug #18487]

Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
2022-04-06 19:14:03 -07:00
Jeremy Evans d1d48cb690 Revert "Raise RuntimeError if Kernel#binding is called from a non-Ruby frame"
This reverts commit 343ea9967e.

This causes an assertion failure with -DRUBY_DEBUG=1 -DRGENGC_CHECK_MODE=2
2022-04-01 07:22:49 -07:00
Jeremy Evans 343ea9967e Raise RuntimeError if Kernel#binding is called from a non-Ruby frame
Check whether the current or previous frame is a Ruby frame in
call_trace_func before attempting to create a binding for the frame.

Fixes [Bug #18487]

Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
2022-03-24 12:31:07 -07:00
John Hawthorn 930ebdd7ca YJIT: Support kwargs for cfunc
This adds support for passing keyword arguments to cfuncs. This is done
by calling a helper method to create the hash from the top N values on
the stack (determined by the callinfo) and then moving that value onto
the stack.
2022-01-10 10:53:31 -08:00
John Hawthorn 18b97eee5a YJIT: Add support for ruby array cfuncs (argc=-2)
This adds support for cfuncs which take variable arguments using a Ruby
array. This is specified with the method entry's argc == -2.
2022-01-08 11:40:55 -08:00
Alan Wu 54c91042ed YJIT: Discard local var type info on routine call
Routines that are called from YJIT's output code can call methods, and
calling methods mean they can capture and change the environment of the
calling frame.

Discard type info whenever we perform routine calls. This is more
conservative than strictly necessary as some routines need to perform GC
allocation but can never call methods and so should never be able to
change local variables. However, manually analyzing C functions for
whether they have code paths that call methods is error prone and can go
out of date as changes land in the codebase.

Closes: shopify/yjit#300
2022-01-07 19:29:03 -05:00
John Hawthorn 5414de4b6e YJIT: Fix SP index with optarg and unordered kwarg
Previously when we were calling a method with an optional argument and
multiple keywords arguments which weren't in the order the receiver
expected we would use the wrong SP index to rearrange them.

Fixes Bug #18453
2021-12-31 17:30:47 -08:00
John Hawthorn c2197bf821 YJIT: Fix check for required kwargs
Previously, YJIT would not check that all the required keywords were
specified in the case that there were optional arguments specified. In
this case YJIT would incorrectly call the method with invalid arguments.
2021-12-17 15:26:04 -08:00
John Hawthorn 83aa68447c YJIT: Allow iseq with both opt and kwargs
Previously we mirrored the fast paths the interpreter had for having
only one of kwargs or optional args. This commit aims to combine the
cases and reduce complexity.

Though this allows calling iseqs which have have both optional and
keyword arguments, it requires that all optional arguments are specified
when there are keyword arguments, since unspecified optional arguments
appear before the kwargs. Support for this can be added a in a future
PR.
2021-12-17 15:26:04 -08:00
Alan Wu ac5d6faea8
YJIT: Fix unexpected truncation when outputing VALUE
Previously, YJIT incorrectly discarded the upper 32 bits of the object
pointer when writing out VALUEs to setup default keyword arguments.

In addition to incorrectly truncating, the output pointers were not
properly tracked for handling GC compaction moving the referenced
objects.

YJIT previously attempted to encode a mov instruction with a memory
destination and a 64 bit immediate when there is no such encoding
possible in the ISA. Add an assert to mitigate not being able to
catch this at build time.
2021-12-14 19:47:42 -05:00
Alan Wu 82bb9cedd3 YJIT: Fix leak in compilation loop
Previously, when there are too many blocks in a batch, the last block in
the batch is not tracked in the array of batches and not freed.
2021-12-08 16:59:52 -05:00
Alan Wu 286c07f0dc YJIT: Remove guard_self_is_heap()
It's superseded by functionality added to jit_guard_known_klass().
In weird situations such as the ones in the included test,
guard_self_is_heap() triggered assertions.

Co-authored-by: Jemma Issroff <jemmaissroff@gmail.com>
2021-12-07 17:20:34 -05:00
Alan Wu b7ea66bc32 YJIT: Fix incomplete invalidation from opt_setinlinecache
As part of YJIT's strategy for promoting Ruby constant expressions into
constants in the output native code, the interpreter calls
rb_yjit_constant_ic_update() from opt_setinlinecache.

The block invalidation loop indirectly calls rb_darray_remove_unordered(),
which does a shuffle remove. Because of this, looping with an
incrementing counter like done previously can miss some elements in the
array. Repeatedly invalidate the first element instead.

The bug this commit resolves does not seem to cause crashes or divergent
behaviors.

Co-authored-by: Jemma Issroff <jemmaissroff@gmail.com>
2021-12-06 19:24:41 -05:00
Alan Wu 34b5e2566d YJIT: Enable out of memory tests
As of [1] and [2], YJIT has enough support for out of memory conditions
to pass these two basic tests.

OOM code paths are prone to bugs since they are rarely exercised in
common workloads. We might want to add CI runs that stress test these
code paths. Maybe outside of GitHub Actions for capacity reasons.

[1]: f41b4d44f9
[2]: b5b6ab4194
2021-12-04 11:35:37 -05:00
Alan Wu d0772632bf YJIT: Fail gracefully while OOM for new entry points
Previously, YJIT crashes with rb_bug() when asked to compile new methods
while out of executable memory.

To handle this situation gracefully, this change keeps track of all the
blocks compiled each invocation in case YJIT runs out of memory in the
middle of a compliation sequence. The list is used to free all blocks in
case compilation fails.

yjit_gen_block() is renamed to gen_single_block() to make it distinct from
gen_block_version(). Call to limit_block_version() and block_t
allocation is moved into the function to help tidy error checking in the
outer loop.

limit_block_version() now returns by value. I feel that an out parameter
with conditional mutation is unnecessarily hard to read in code that
does not need to go for last drop performance. There is a good chance
that the optimizer is able to output identical code anyways.
2021-12-01 12:25:28 -05:00
Alan Wu b5b6ab4194
YJIT: Add ability to exit to interpreter from stubs
Previously, YJIT assumed that it's always possible to generate a new
basic block when servicing a stub in branch_stub_hit(). When YJIT is out
of executable memory, for example, this assumption doesn't hold up.

Add handling to branch_stub_hit() for servicing stubs without consuming
more executable memory by adding a code path that exits to the
interpreter at the location the branch stub represents. The new code
path reconstructs interpreter state in branch_stub_hit() and then exits
with a new snippet called `code_for_exit_from_stub` that returns
`Qundef` from the YJIT native stack frame.

As this change adds another place where we regenerate code from
`branch_t`, extract the logic for it into a new function and call it
regenerate_branch(). While we are at it, make the branch shrinking code
path in branch_stub_hit() more explicit.

This new functionality is hard to test without full support for out of
memory conditions. To verify this change, I ran
`RUBY_YJIT_ENABLE=1 make check -j12` with the following patch to stress
test the new code path:

```diff
diff --git a/yjit_core.c b/yjit_core.c
index 4ab63d9806..5788b8c5ed 100644
--- a/yjit_core.c
+++ b/yjit_core.c
@@ -878,8 +878,12 @@ branch_stub_hit(branch_t *branch, const uint32_t target_idx, rb_execution_contex
                 cb_set_write_ptr(cb, branch->end_addr);
             }

+if (rand() < RAND_MAX/2) {
             // Compile the new block version
             p_block = gen_block_version(target, target_ctx, ec);
+}else{
+    p_block = NULL;
+}

             if (!p_block && branch_modified) {
                 // We couldn't generate a new block for the branch, but we modified the branch.
```

We can enable the new test along with other OOM tests once full support
lands.

Other small changes:
 * yjit_utils.c (print_str): Update to work with new native frame shape.
       Follow up for 8fa0ee4d40.
 * yjit_iface.c (rb_yjit_init): Run yjit_init_core() after
       yjit_init_codegen() so `cb` and `ocb` are available.
2021-11-26 18:00:42 -05:00
John Hawthorn de9a1e4a96
YJIT: Implement new struct accessors (#5161)
* YJIT: Implement optimized_method_struct_aref

* YJIT: Implement struct_aref without method call

Struct member reads can be compiled directly into a memory read (with
either one or two levels of indirection).

* YJIT: Implement optimized struct aset

* YJIT: Update tests for struct access

* YJIT: Add counters for remaining optimized methods

* Check for INT32_MAX overflow

It only takes a struct with 0x7fffffff/8+1 members. Also add some
cheap compile time checks.

* Add tests for non-embedded struct aref/aset

Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
2021-11-25 11:56:58 -08:00
Alan Wu 13d1ded253 YJIT: Make block invalidation more robust
This commit adds an entry_exit field to block_t for use in
invalidate_block_version(). By patching the start of the block while
invalidating it, invalidate_block_version() can function correctly
while there is no executable memory left for new branch stubs.

This change additionally fixes correctness for situations where we
cannot patch incoming jumps to the invalidated block. In situations
such as Shopify/yjit#226, the address to the start of the block
is saved and used later, possibly after the block is invalidated.

The assume_* family of function now generate block->entry_exit before
remembering blocks for invalidation.

RubyVM::YJIT.simulate_oom! is introduced for testing out of memory
conditions. The test for it is disabled for now because OOM triggers
other failure conditions not addressed by this commit.

Fixes Shopify/yjit#226
2021-11-22 18:23:28 -05:00
Adam Hess 73388aff5e
Add YJIT codegen for objtostring (#5149)
This is the minimal correct objtostring implementation in YJIT.
For correctness, it is important that to_string not get called on strings or subclasses of string.
There is a new test for this behavior.

A follow up should implement an optimized version for other types as performed in `vm_objtostring`.

Co-authored-by: John Hawthorn <jhawthorn@github.com>

Co-authored-by: John Hawthorn <jhawthorn@github.com>
2021-11-19 16:57:09 -05:00
John Hawthorn fbd6cc5856
YJIT: Support iseq sends with mixed kwargs (#5082)
* YJIT: Support iseq sends with mixed kwargs

Co-authored-by: Kevin Newton <kddnewton@gmail.com>

* Add additional comments to iseq sends

Co-authored-by: Kevin Newton <kddnewton@gmail.com>
2021-11-05 17:01:07 -04:00
John Hawthorn 2fa51c7068
YJIT: Support kwargs sends with all defaults (#5067)
* YJIT: Support kwargs sends with all defaults

Previously keyword argument methods were only compiled by YJIT when all
keywords were specified in the caller.

This adds support for calling methods with keyword arguments when no
keyword arguments are specified and all are filled with the defaults.

* Remove unused send_iseq_kwargs_none_passed
2021-11-01 10:54:59 -04:00
John Hawthorn a6104b392a
YJIT: Support newhash with values (#5029)
* YJIT: Implement newhash with values

* YJIT: Add test of duphash

* Fix compilation on macos/clang
2021-10-27 10:55:43 -04:00
Ian C. Anderson e943511455
YJIT: Implement duphash (#5009)
`duphash` showed up in the top-20 most frequent exit ops for @jhawthorn's benchmark that renders github.com/about

The implementation was almost exactly the same as `duparray`

Co-authored-by: John Hawthorn <john@hawthorn.email>

Co-authored-by: John Hawthorn <john@hawthorn.email>
2021-10-25 10:40:33 -04:00
Koichi Sasada acb23454e5 allow to access ivars of classes/modules
if an ivar of a class/module refer to a shareable object, this ivar
can be read from non-main Ractors.
2021-10-23 01:32:55 +09:00
Alan Wu ba4bf8a1e6
Fix simple test on platforms where compaction is not supported
844588f915 made it so that trying to call
gc_verify_compaction_references on unsupported platform result in an
exception rather than a crash. Rescue the exception in a YJIT btest
that uses gc_verify_compaction_references.
2021-10-22 10:53:42 -04:00
Alan Wu bdfc23cba9
YJIT: don't compile attr_accessor methods when tracing (#4998)
2d98593bf5 made it so that
attr_accessor methods fire C method tracing events.
Previously, we weren't checking for whether we are tracing before
compiling, leading to missed events.

Since global invalidation invalidates all code, and that attr_accessor
methods can never enable tracing while running, events are only dropped
when YJIT tries to compile when tracing is already enabled.

Factor out the code for checking tracing and check it before generating
code for attr_accessor methods.

This change fixes TestSetTraceFunc#test_tracepoint_attr when it's
ran in isolation.
2021-10-21 15:07:32 -04:00
Alan Wu cffa116275 Do kwarg shuffle after checking for interrupts
Previously, we were shuffling keyword arguments before checking for
interrupts. In the case that we side exit in the interrupt check,
we left the interpreter with an already-shuffled argument list for
the call, resulting in a double shuffle, leaving the locals in the
wrong order for the callee.

Do keyword shuffling after all the possible side exits.

Co-authored-by: Kevin Newton <kddnewton@gmail.com>
2021-10-20 18:19:43 -04:00
Alan Wu b74d6563a6 Extract yjit_force_iv_index and make it work when object is frozen
In an effort to simplify the logic YJIT generates for accessing instance
variable, YJIT ensures that a given name-to-index mapping exists at
compile time. In the case that the mapping doesn't exist, it was created
by using rb_ivar_set() with Qundef on the sample object we see at
compile time. This hack isn't fine if the sample object happens to be
frozen, in which case YJIT would raise a FrozenError unexpectedly.

To deal with this, make a new function that only reserves the mapping
but doesn't touch the object. This is rb_obj_ensure_iv_index_mapping().
This new function superceeds the functionality of rb_iv_index_tbl_lookup()
so it was removed.

Reported by and includes a test case from John Hawthorn <john@hawthorn.email>

Fixes: GH-282
2021-10-20 18:19:43 -04:00
Kevin Newton 13261f00fb More simple bootstrap tests for kwargs 2021-10-20 18:19:43 -04:00
Kevin Newton 56b1b93a0c Feedback, tests, and rebase for kwargs 2021-10-20 18:19:43 -04:00
Kevin Newton 2c0891be20 Get kwargs reordering working 2021-10-20 18:19:42 -04:00
Alan Wu a09adac2d7 Add specialization for String#to_s on plain strings
When calling "to_s" on an instance of String, the method simply returns
self. In this situation most of the work comes from setting up the
method call. It turns out that both railsbench and liquid-render do this
a lot.

When generating code for opt_send_without_block, we already generate a
known class guard, so we can detect when the receiver is a String
instance. Since gen_send_cfunc() is also used for gen_invokesuper(), and
gen_invokesuper() doesn't generate a known class guard, a new nullable
parameter for specialized codegen function is added.

Closes GH-245
2021-10-20 18:19:41 -04:00
Alan Wu 8edb29e5a0 Reconstruct interpreter state before calling rb_ivar_get()
It could raise ractor exceptions. The included test didn't run properly
before this change.
2021-10-20 18:19:41 -04:00
John Hawthorn 9951a9a8ec Implement invokebuiltin 2021-10-20 18:19:41 -04:00
John Hawthorn 2ff26b9ec2 Fix opt_aset comptime_key check 2021-10-20 18:19:41 -04:00
John Hawthorn 5092d6129a Fix opt_eq for overridden equality 2021-10-20 18:19:40 -04:00
John Hawthorn 9ebcd576f3 String and fixnum equality 2021-10-20 18:19:40 -04:00