Age | Commit message (Collapse) | Author |
---|
| 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: Optimize defined?(yield) * Remove an irrelevant comment * s/get/gen/ |
| ``` 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. |
| Right now the `rb_shape_get_next` shape caller need to first check if there is capacity left, and if not call `rb_shape_transition_shape_capa` before it can call `rb_shape_get_next`. And on each of these it needs to checks if we got a TOO_COMPLEX back. All this logic is duplicated in the interpreter, YJIT and RJIT. Instead we can have `rb_shape_get_next` do the capacity transition when needed. The caller can compare the old and new shapes capacity to know if resizing is needed. It also can check for TOO_COMPLEX only once. |
| Previously, the version-controlled `cruby_bindings.inc.rs` file contained the build-time artifact `id.h`, which nobu mentioned hinders the goal of having fewer magic numbers in the repository. Lookup the IDs YJIT needs on boot. It costs cycles, but it's fine since YJIT only uses a handful of IDs at the moment. No perceptible degradation to boot time found in my testing. |
| |
| Previously, TestStack#test_machine_stack_size failed pretty consistently on ARM64 macOS, with Rust code and part of the interpreter used for per-instruction fallback (rb_vm_invokeblock() and friends) touching the stack guard page and crashing with SEGV. I've also seen the same test fail on x64 Linux, though with a different symptom. Notes: Merged: https://.com/ruby/ruby/pull/8443 Merged-By: XrXr |
| * YJIT: implement side chain fallback for setlocal to avoid exiting * Update yjit/src/codegen.rs Co-authored-by: Takashi Kokubun <[email protected]> --------- Co-authored-by: Takashi Kokubun <[email protected]> Notes: Merged-By: maximecb <[email protected]> |
| Notes: Merged-By: maximecb <[email protected]> |
| * YJIT: Count throw instructions for each tag * Show % of each throw type Notes: Merged-By: k0kubun <[email protected]> |
| Co-authored-by: Maxime Chevalier-Boisvert <[email protected]> Notes: Merged-By: k0kubun <[email protected]> |
| Notes: Merged-By: maximecb <[email protected]> |
| Notes: Merged: https://.com/ruby/ruby/pull/8124 |
| Notes: Merged-By: k0kubun <[email protected]> |
| * YJIT: refactoring to allow for fancier call threshold logic * Avoid potentially compiling functions multiple times. * Update vm.c Co-authored-by: Alan Wu <[email protected]> --------- Co-authored-by: Alan Wu <[email protected]> Notes: Merged-By: maximecb <[email protected]> |
| Notes: Merged-By: maximecb <[email protected]> |
| `IO#reopen` is very special in that it is able to change the class and singleton class of IO instances. In its presence, it is not correct to assume that IO instances has a stable class/singleton class and guard by comparing identity. Notes: Merged-By: maximecb <[email protected]> |
| * YJIT: Add codegen for Integer methods * YJIT: Update dependencies * YJIT: Fix Integer#[] for argc=2 Notes: Merged-By: k0kubun <[email protected]> |
| Remove !USE_RVARGC code [Feature #19579] The Variable Width Allocation feature was turned on by default in Ruby 3.2. Since then, we haven't received bug reports or backports to the non-Variable Width Allocation code paths, so we assume that nobody is using it. We also don't plan on maintaining the non-Variable Width Allocation code, so we are going to remove it. Notes: Merged-By: maximecb <[email protected]> |
| Notes: Merged-By: k0kubun <[email protected]> |
| |
| Notes: Merged: https://.com/ruby/ruby/pull/7535 Merged-By: k0kubun <[email protected]> |
| Somewhat important because having the lock is a key part of the soundness reasoning for the `unsafe` usage here. Notes: Merged: https://.com/ruby/ruby/pull/7530 |
| Notes: Merged-By: k0kubun <[email protected]> |
| Notes: Merged-By: maximecb <[email protected]> |
| This works much like the existing `defined` implementation, but calls out to rb_ivar_defined instead of the more general rb_vm_defined. Other difference to the existing `defined` implementation is that this new instruction has to take the same operands as the CRuby `defined_ivar` instruction. Notes: Merged: https://.com/ruby/ruby/pull/7433 |
| For example: ```ruby def my_func(x, y, *rest) p [x, y, rest] end my_func(1, 2, 3, *[4, 5]) ``` Notes: Merged-By: maximecb <[email protected]> |
| If you have a method that takes rest arguments and a splat call that happens to line up perfectly with that rest, you can just dupe the array rather than move anything around. We still have to dupe, because people could have a custom to_a method or something like that which means it is hard to guarantee we have exclusive access to that array. Example: ```ruby def foo(a, b, *rest) end foo(1, 2, *[3, 4]) ``` Notes: Merged-By: maximecb <[email protected]> |
| Notes: Merged: https://.com/ruby/ruby/pull/7330 |
| Given that signleton classes don't have an allocator, we can re-use these bytes to store the attached object in `rb_classext_struct` without making it larger. Notes: Merged: https://.com/ruby/ruby/pull/7309 |
| Co-authored-by: Maxime Chevalier-Boisvert <[email protected]> Co-authored-by: Alan Wu <[email protected]> Notes: Merged: https://.com/ruby/ruby/pull/7297 Merged-By: XrXr |
| Notes: Merged-By: maximecb <[email protected]> |
| * YJIT: log the names of methods we call to in disasm * Assert that pointer is not null * Handle case where UTF8 conversion not possible Notes: Merged-By: maximecb <[email protected]> |
| Helps with getting good bug reports in the wild. Intended to be backported to the 3.2.x series. Notes: Merged: https://.com/ruby/ruby/pull/7232 |
| * YJIT: Handle splat with opt more fully * Update yjit/src/codegen.rs --------- Co-authored-by: Maxime Chevalier-Boisvert <[email protected]> Notes: Merged-By: maximecb <[email protected]> |
| are exiting (#6929) YJIT: Implement splat for cfuncs. Split exit cases This also implements a new check for ruby2keywords as the last argument of a splat. This does mean that we generate more code, but in actual benchmarks where we gained speed from this (binarytrees) I don't see any significant slow down. I did have to struggle here with the register allocator to find code that didn't allocate too many registers. It's a bit hard when everything is implicit. But I think I got to the minimal amount of copying and stuff given our current allocation strategy. Notes: Merged-By: maximecb <[email protected]> |
| YJIT: implement codegen for String#empty? Notes: Merged-By: maximecb <[email protected]> |
| * YJIT: Make iseq_get_location consistent with iseq.c * YJIT: Call it "YJIT entry point" Co-authored-by: Maxime Chevalier-Boisvert <[email protected]> Co-authored-by: Maxime Chevalier-Boisvert <[email protected]> Notes: Merged-By: k0kubun <[email protected]> |
| When an object becomes "too complex" (in other words it has too many variations in the shape tree), we transition it to use a "too complex" shape and use a hash for storing instance variables. Without this , there were rare cases where shape tree growth could "explode" and cause performance degradation on what would otherwise have been cached fast paths. This puts a limit on shape tree growth, and gracefully degrades in the rare case where there could be a factorial growth in the shape tree. For example: ```ruby class NG; end HUGE_NUMBER.times do NG.new.instance_variable_set(:"@unique_ivar_#{_1}", 1) end ``` We consider objects to be "too complex" when the object's class has more than SHAPE_MAX_VARIATIONS (currently 8) leaf nodes in the shape tree and the object introduces a new variation (a new leaf node) associated with that class. For example, new variations on instances of the following class would be considered "too complex" because those instances create more than 8 leaves in the shape tree: ```ruby class Foo; end 9.times { Foo.new.instance_variable_set(":@uniq_#{_1}", 1) } ``` However, the following class is *not* too complex because it only has one leaf in the shape tree: ```ruby class Foo def initialize @a = @b = @c = @d = @e = @f = @g = @h = @i = nil end end 9.times { Foo.new } `` This case is rare, so we don't expect this change to impact performance of most applications, but it needs to be handled. Co-Authored-By: Aaron Patterson <[email protected]> Notes: Merged: https://.com/ruby/ruby/pull/6931 |
| The new version has an option to merge everything into a big `extern "C"` block and it's nicer. More importantly, this upgrade fixes an issue where Ubuntu with Clang 12 and macOS with Clang 14 gave a one line diff for `rb_shape_t`. It was slightly annoying because we use macOS locally. Notes: Merged: https://.com/ruby/ruby/pull/6887 |
| Notes: Merged-By: k0kubun <[email protected]> |
| Notes: Merged: https://.com/ruby/ruby/pull/6767 |
| Notes: Merged: https://.com/ruby/ruby/pull/6767 |
| Notes: Merged: https://.com/ruby/ruby/pull/6767 |
| Notes: Merged: https://.com/ruby/ruby/pull/6767 |
| * YJIT: Make case-when optimization respect === redefinition Even when a fixnum key is in the dis hash, if there is a case such that its basic operations for === is redefined, we need to fall back to checking each case like the interpreter. Semantically we're always checking each case by calling === in order, it's just that this is not observable when basic operations are intact. When all the keys are fixnums, though, we can do the optimization we're doing right now. Check for this condition. * Update yjit/src/cruby_bindings.inc.rs Co-authored-by: Takashi Kokubun <[email protected]> Co-authored-by: Takashi Kokubun <[email protected]> Notes: Merged-By: maximecb <[email protected]> |
| * YJIT: Reorder branches for Fixnum opt_case_dis Co-authored-by: Maxime Chevalier-Boisvert <[email protected]> Co-authored-by: Alan Wu <[email protected]> * YJIT: Don't support too large values Co-authored-by: Maxime Chevalier-Boisvert <[email protected]> Co-authored-by: Alan Wu <[email protected]> Notes: Merged-By: maximecb <[email protected]> |
| This commit changes the shape id comparisons to use a 32 bit comparison rather than 64 bit. That means we don't need to load the shape id to a register on x86 machines. Given the following program: ```ruby class Foo def initialize @foo = 1 @bar = 1 end def read [@foo, @bar] end end foo = Foo.new foo.read foo.read foo.read foo.read foo.read puts RubyVM::YJIT.disasm(Foo.instance_method(:read)) ``` The machine code we generated _before_ this change is like this: ``` == BLOCK 1/4, ISEQ RANGE [0,3), 65 bytes ====================== # getinstancevariable 0x559a18623023: mov rax, qword ptr [r13 + 0x18] # guard object is heap 0x559a18623027: test al, 7 0x559a1862302a: jne 0x559a1862502d 0x559a18623030: cmp rax, 4 0x559a18623034: jbe 0x559a1862502d # guard shape, embedded, and T_OBJECT 0x559a1862303a: mov rcx, qword ptr [rax] 0x559a1862303d: movabs r11, 0xffff00000000201f 0x559a18623047: and rcx, r11 0x559a1862304a: movabs r11, 0xb000000002001 0x559a18623054: cmp rcx, r11 0x559a18623057: jne 0x559a18625046 0x559a1862305d: mov rax, qword ptr [rax + 0x18] 0x559a18623061: mov qword ptr [rbx], rax == BLOCK 2/4, ISEQ RANGE [3,6), 0 bytes ======================= == BLOCK 3/4, ISEQ RANGE [3,6), 47 bytes ====================== # gen_direct_jmp: fallthrough # getinstancevariable # regenerate_branch # getinstancevariable # regenerate_branch 0x559a18623064: mov rax, qword ptr [r13 + 0x18] # guard shape, embedded, and T_OBJECT 0x559a18623068: mov rcx, qword ptr [rax] 0x559a1862306b: movabs r11, 0xffff00000000201f 0x559a18623075: and rcx, r11 0x559a18623078: movabs r11, 0xb000000002001 0x559a18623082: cmp rcx, r11 0x559a18623085: jne 0x559a18625099 0x559a1862308b: mov rax, qword ptr [rax + 0x20] 0x559a1862308f: mov qword ptr [rbx + 8], rax ``` After this change, it's like this: ``` == BLOCK 1/4, ISEQ RANGE [0,3), 41 bytes ====================== # getinstancevariable 0x5560c986d023: mov rax, qword ptr [r13 + 0x18] # guard object is heap 0x5560c986d027: test al, 7 0x5560c986d02a: jne 0x5560c986f02d 0x5560c986d030: cmp rax, 4 0x5560c986d034: jbe 0x5560c986f02d # guard shape 0x5560c986d03a: cmp word ptr [rax + 6], 0x19 0x5560c986d03f: jne 0x5560c986f046 0x5560c986d045: mov rax, qword ptr [rax + 0x10] 0x5560c986d049: mov qword ptr [rbx], rax == BLOCK 2/4, ISEQ RANGE [3,6), 0 bytes ======================= == BLOCK 3/4, ISEQ RANGE [3,6), 23 bytes ====================== # gen_direct_jmp: fallthrough # getinstancevariable # regenerate_branch # getinstancevariable # regenerate_branch 0x5560c986d04c: mov rax, qword ptr [r13 + 0x18] # guard shape 0x5560c986d050: cmp word ptr [rax + 6], 0x19 0x5560c986d055: jne 0x5560c986f099 0x5560c986d05b: mov rax, qword ptr [rax + 0x18] 0x5560c986d05f: mov qword ptr [rbx + 8], rax ``` The first ivar read is a bit more complex, but the second ivar read is much simpler. I think eventually we could teach the context about the shape, then emit only one shape guard. Notes: Merged: https://.com/ruby/ruby/pull/6737 |
| We don't need this constant to be exposed anymore, so remove it Notes: Merged: https://.com/ruby/ruby/pull/6728 |
| This dises to a c func for doing the dynamic lookup. I experimented with chain on the proc but wasn't able to detect which call sites would be monomorphic vs polymorphic. There is definitely room for optimization here, but it does reduce exits. Notes: Merged-By: maximecb <[email protected]> |