summaryrefslogtreecommitdiff
path: root/compile.c
AgeCommit message (Collapse)Author
2023-03-11Rename builtin attr :inline to :leafTakashi Kokubun
2023-03-11Support multiple attributes with Primitive.attr!Takashi Kokubun
2023-03-10rename `defined_ivar` to `definedivar`Koichi Sasada
because non-opt instructions should contain `_` char. Notes: Merged: https://github.com/ruby/ruby/pull/7485
2023-03-08Add defined_ivar instructionOle Friis Østergaard
This is a variation of the `defined` instruction, for use when we are checking for an instance variable. Splitting this out as a separate instruction lets us skip some checks, and it also allows us to use an instance variable cache, letting shape analysis speed up the operation further. Notes: Merged: https://github.com/ruby/ruby/pull/7433
2023-03-08Constify function tablesNobuyoshi Nakada
Notes: Merged: https://github.com/ruby/ruby/pull/7473
2023-03-06Stop exporting symbols for MJITTakashi Kokubun
Notes: Merged: https://github.com/ruby/ruby/pull/7459
2023-03-06Change bytecode of `f(*a, **kw)`Koichi Sasada
`f(*a, **kw)` is compiled to `f([*a, kw])` but it makes an dummy array, so change it to pass two arguments `a` and `kw` with calling flags. ``` ruby 3.2.0 (2022-12-29 revision a7d467a792) [x86_64-linux] Calculating ------------------------------------- foo() 15.354M (± 4.2%) i/s - 77.295M in 5.043650s dele() 13.439M (± 3.9%) i/s - 67.109M in 5.001974s dele(*) 6.265M (± 4.5%) i/s - 31.730M in 5.075649s dele(*a) 6.286M (± 3.3%) i/s - 31.719M in 5.051516s dele(*a, **kw) 1.926M (± 4.5%) i/s - 9.753M in 5.076487s dele(*, **) 1.927M (± 4.2%) i/s - 9.710M in 5.048224s dele(...) 5.871M (± 3.9%) i/s - 29.471M in 5.028023s forwardable 4.969M (± 4.1%) i/s - 25.233M in 5.087498s ruby 3.3.0dev (2023-01-13T01:28:00Z master 7e8802fa5b) [x86_64-linux] Calculating ------------------------------------- foo() 16.354M (± 4.7%) i/s - 81.799M in 5.014561s dele() 14.256M (± 3.5%) i/s - 71.656M in 5.032883s dele(*) 6.701M (± 3.8%) i/s - 33.948M in 5.074938s dele(*a) 6.681M (± 3.3%) i/s - 33.578M in 5.031720s dele(*a, **kw) 4.200M (± 4.4%) i/s - 21.258M in 5.072583s dele(*, **) 4.197M (± 5.3%) i/s - 21.322M in 5.096684s dele(...) 6.039M (± 6.8%) i/s - 30.355M in 5.052662s forwardable 4.788M (± 3.2%) i/s - 24.033M in 5.024875s ```
2023-02-27Fix spelling (#7389)John Bampton
Notes: Merged-By: k0kubun <takashikkbn@gmail.com>
2023-02-24Fix incorrect line numbers in GC hookPeter Zhu
If the previous instruction is not a leaf instruction, then the PC was incremented before the instruction was ran (meaning the currently executing instruction is actually the previous instruction), so we should not increment the PC otherwise we will calculate the source line for the next instruction. This bug can be reproduced in the following script: ``` require "objspace" ObjectSpace.trace_object_allocations_start a = 1.0 / 0.0 p [ObjectSpace.allocation_sourceline(a), ObjectSpace.allocation_sourcefile(a)] ``` Which outputs: [4, "test.rb"] This is incorrect because the object was allocated on line 10 and not line 4. The behaviour is correct when we use a leaf instruction (e.g. if we replaced `1.0 / 0.0` with `"hello"`), then the output is: [10, "test.rb"]. [Bug #19456] Notes: Merged: https://github.com/ruby/ruby/pull/7357
2023-02-21Use `ERROR_ARGS_AT`Nobuyoshi Nakada
2023-02-20compile.c: eliminate getinstancevariable -> pop sequencesJean Boussier
This case wasn't eliminated before because `getinstancevariable` could emit a warning, but that's no longer the case since Ruby 3.0. Notes: Merged: https://github.com/ruby/ruby/pull/7342
2023-02-14Add utility macros `DECIMAL_SIZE_OF` and `DECIMAL_SIZE_OF_BYTES`Nobuyoshi Nakada
Notes: Merged: https://github.com/ruby/ruby/pull/7299
2023-02-13Remove ibf_dumper's WB_PROTECTED statusAlan Wu
It doesn't have the right write barriers in place. For example, there is rb_mark_set(dump->global_buffer.obj_table); in the mark function, but there is no corresponding write barrier when adding to the table in the `ibf_dump_object() -> ibf_table_find_or_insert() -> st_insert()` code path. To insert write barrier correctly, we need to store the T_STRUCT VALUE inside `struct ibf_dump`. Instead of doing that, let's just demote it to WB unproected for correctness. These dumper object are ephemeral so there is not a huge benefit for having them WB protected. Users of the bootsnap gem ran into crashes due to this issue: https://github.com/Shopify/bootsnap/issues/436 Fixes [Bug #19419] Notes: Merged: https://github.com/ruby/ruby/pull/7296
2023-02-09Merge gc.h and internal/gc.hMatt Valentine-House
[Feature #19425] Notes: Merged: https://github.com/ruby/ruby/pull/7273
2023-02-08Rename iseq_mark_and_update to iseq_mark_and_movePeter Zhu
The new name is more consistent.
2023-01-20Make all of the references of iseq movablePeter Zhu
Notes: Merged: https://github.com/ruby/ruby/pull/7156
2023-01-17Avoid checking interrupt when loading iseqStan Lo
The interrupt check will unintentionally release the VM lock when loading an iseq. And this will cause issues with the `debug` gem's [`ObjectSpace.each_iseq` method](https://github.com/ruby/debug/blob/0fcfc28acae33ec1c08068fb7c33703cfa681fa7/ext/debug/iseq_collector.c#L61-L67), which wraps iseqs with a wrapper and exposes their internal states when they're actually not ready to be used. And when that happens, errors like this would occur and kill the `debug` gem's thread: ``` DEBUGGER: ReaderThreadError: uninitialized InstructionSequence ┃ DEBUGGER: Disconnected. ┃ ["/opt/rubies/ruby-3.2.0/lib/ruby/gems/3.2.0/gems/debug-1.7.1/lib/debug/breakpoint.rb:247:in `absolute_path'", ┃ "/opt/rubies/ruby-3.2.0/lib/ruby/gems/3.2.0/gems/debug-1.7.1/lib/debug/breakpoint.rb:247:in `block in iterate_iseq'", ┃ "/opt/rubies/ruby-3.2.0/lib/ruby/gems/3.2.0/gems/debug-1.7.1/lib/debug/breakpoint.rb:246:in `each_iseq'", ... ``` A way to reproduce the issue is to satisfy these conditions at the same time: 1. `debug` gem calling `ObjectSpace.each_iseq` (e.g. [activating a `LineBreakpoint`](https://github.com/ruby/debug/blob/0fcfc28acae33ec1c08068fb7c33703cfa681fa7/lib/debug/breakpoint.rb#L246)). 2. A large amount of iseq being loaded from another thread (possibly through the `bootsnap` gem). 3. 1 and 2 iterating through the same iseq(s) at the same time. Because this issue requires external dependencies and a rather complicated timing setup to reproduce, I wasn't able to write a test case for it. But here's some pseudo code to help reproduce it: ```rb require "debug/session" Thread.new do 100.times do ObjectSpace.each_iseq do |iseq| iseq.absolute_path end end end sleep 0.1 load_a_bunch_of_iseq possibly_through_bootsnap ``` [Bug #19348] Co-authored-by: Peter Zhu <peter@peterzhu.ca>
2022-12-15Disallow mixed usage of ... and */**Shugo Maeda
[Feature #19134] Notes: Merged: https://github.com/ruby/ruby/pull/6934
2022-12-06Set max_iv_count (used for object shapes) based on inline cachesJemma Issroff
With this change, we're storing the iv name on an inline cache on setinstancevariable instructions. This allows us to check the inline cache to count instance variables set in initialize and give us an estimate of iv capacity for an object. For the purpose of estimating the number of instance variables required for an object, we're assuming that all initialize methods will call `super`. This change allows us to estimate the number of instance variables required without disassembling instruction sequences. Co-Authored-By: Aaron Patterson <tenderlove@ruby-lang.org> Notes: Merged: https://github.com/ruby/ruby/pull/6870
2022-11-29Remove ruby2_keywords related to args forwardingyui-knk
This was introduced by b609bdeb5307e280137b4b2838af0fe4e4b46f1c to suppress warnings. However these warngins were deleted by beae6cbf0fd8b6619e5212552de98022d4c4d4d4. Therefore these codes are not needed anymore. Notes: Merged: https://github.com/ruby/ruby/pull/6826
2022-11-16Using UNDEF_P macroS-H-GAMELINKS
Notes: Merged: https://github.com/ruby/ruby/pull/6721
2022-11-08Fix false LocalJumpError when branch coverage is enabledYusuke Endoh
`throw TAG_BREAK` instruction makes a jump only if the continuation of catch of TAG_BREAK exactly matches the instruction immediately following the "send" instruction that is currently being executed. Otherwise, it seems to determine break from proc-closure. Branch coverage may insert some recording instructions after "send" instruction, which broke the conditions for TAG_BREAK to work properly. This change forces to set the continuation of catch of TAG_BREAK immediately after "send" (or "invokesuper") instruction. [Bug #18991] Notes: Merged: https://github.com/ruby/ruby/pull/6688
2022-10-20push dummy frame for loading processKoichi Sasada
This patch pushes dummy frames when loading code for the profiling purpose. The following methods push a dummy frame: * `Kernel#require` * `Kernel#load` * `RubyVM::InstructionSequence.compile_file` * `RubyVM::InstructionSequence.load_from_binary` https://bugs.ruby-lang.org/issues/18559 Notes: Merged: https://github.com/ruby/ruby/pull/6572
2022-10-11Revert "Revert "This commit implements the Object Shapes technique in CRuby.""Jemma Issroff
This reverts commit 9a6803c90b817f70389cae10d60b50ad752da48f.
2022-09-30Revert "This commit implements the Object Shapes technique in CRuby."Aaron Patterson
This reverts commit 68bc9e2e97d12f80df0d113e284864e225f771c2.
2022-09-28This commit implements the Object Shapes technique in CRuby.Jemma Issroff
Object Shapes is used for accessing instance variables and representing the "frozenness" of objects. Object instances have a "shape" and the shape represents some attributes of the object (currently which instance variables are set and the "frozenness"). Shapes form a tree data structure, and when a new instance variable is set on an object, that object "transitions" to a new shape in the shape tree. Each shape has an ID that is used for caching. The shape structure is independent of class, so objects of different types can have the same shape. For example: ```ruby class Foo def initialize # Starts with shape id 0 @a = 1 # transitions to shape id 1 @b = 1 # transitions to shape id 2 end end class Bar def initialize # Starts with shape id 0 @a = 1 # transitions to shape id 1 @b = 1 # transitions to shape id 2 end end foo = Foo.new # `foo` has shape id 2 bar = Bar.new # `bar` has shape id 2 ``` Both `foo` and `bar` instances have the same shape because they both set instance variables of the same name in the same order. This technique can help to improve inline cache hits as well as generate more efficient machine code in JIT compilers. This commit also adds some methods for debugging shapes on objects. See `RubyVM::Shape` for more details. For more context on Object Shapes, see [Feature: #18776] Co-Authored-By: Aaron Patterson <tenderlove@ruby-lang.org> Co-Authored-By: Eileen M. Uchitelle <eileencodes@gmail.com> Co-Authored-By: John Hawthorn <john@hawthorn.email>
2022-09-26Revert this until we can figure out WB issues or remove shapes from GCAaron Patterson
Revert "* expand tabs. [ci skip]" This reverts commit 830b5b5c351c5c6efa5ad461ae4ec5085e5f0275. Revert "This commit implements the Object Shapes technique in CRuby." This reverts commit 9ddfd2ca004d1952be79cf1b84c52c79a55978f4.
2022-09-27* expand tabs. [ci skip]git
Tabs were expanded because the file did not have any tab indentation in unedited lines. Please update your editor config, and use misc/expand_tabs.rb in the pre-commit hook.
2022-09-26This commit implements the Object Shapes technique in CRuby.Jemma Issroff
Object Shapes is used for accessing instance variables and representing the "frozenness" of objects. Object instances have a "shape" and the shape represents some attributes of the object (currently which instance variables are set and the "frozenness"). Shapes form a tree data structure, and when a new instance variable is set on an object, that object "transitions" to a new shape in the shape tree. Each shape has an ID that is used for caching. The shape structure is independent of class, so objects of different types can have the same shape. For example: ```ruby class Foo def initialize # Starts with shape id 0 @a = 1 # transitions to shape id 1 @b = 1 # transitions to shape id 2 end end class Bar def initialize # Starts with shape id 0 @a = 1 # transitions to shape id 1 @b = 1 # transitions to shape id 2 end end foo = Foo.new # `foo` has shape id 2 bar = Bar.new # `bar` has shape id 2 ``` Both `foo` and `bar` instances have the same shape because they both set instance variables of the same name in the same order. This technique can help to improve inline cache hits as well as generate more efficient machine code in JIT compilers. This commit also adds some methods for debugging shapes on objects. See `RubyVM::Shape` for more details. For more context on Object Shapes, see [Feature: #18776] Co-Authored-By: Aaron Patterson <tenderlove@ruby-lang.org> Co-Authored-By: Eileen M. Uchitelle <eileencodes@gmail.com> Co-Authored-By: John Hawthorn <john@hawthorn.email> Notes: Merged: https://github.com/ruby/ruby/pull/6386
2022-09-25[Bug #19021] Fix safe call w/ conditional assignJohn Hawthorn
As of fbaac837cfba23a9d34dc7ee144d7940248222a2, when we were performing a safe call (`o&.x=`) with a conditional assign (`||= 1`) and discarding the result the stack would end up in a bad state due to a missing pop. This commit fixes that by adjusting the target label of the branchnil to be before a pop in that case (as was previously done in the non-conditional assignment case). Notes: Merged: https://github.com/ruby/ruby/pull/6437
2022-09-26Use `int first_lineno` for binary format.Samuel Williams
Notes: Merged: https://github.com/ruby/ruby/pull/6430
2022-09-26Rework vm_core to use `int first_lineno` struct member.Samuel Williams
Notes: Merged: https://github.com/ruby/ruby/pull/6430
2022-09-26Rework `first_lineno` to be `int`.Samuel Williams
Notes: Merged: https://github.com/ruby/ruby/pull/6430
2022-09-22avoid extra dup and pop in compile_op_asgn2HParker
Co-authored-by: John Hawthorn <jhawthorn@github.com> Notes: Merged: https://github.com/ruby/ruby/pull/6414
2022-09-22avoid extra dup and pop in compile_op_logHParker
Co-authored-by: John Hawthorn <jhawthorn@github.com> Notes: Merged: https://github.com/ruby/ruby/pull/6414
2022-09-22Enable coverage for eval.Samuel Williams
Notes: Merged: https://github.com/ruby/ruby/pull/6396
2022-09-12Add comments for some peephole optimizations [ci skip]Maple Ong
Notes: Merged: https://github.com/ruby/ruby/pull/6357 Merged-By: nobu <nobu@ruby-lang.org>
2022-09-02Adjust styles [ci skip]Nobuyoshi Nakada
2022-09-01Use getblockparamproxy with branchJohn Hawthorn
A common pattern when the block is an explicit parameter is to branch based on the block parameter instead of using `block_given?`, for example `block.call if block`. This commit checks in the peephole optimizer for that case and uses the getblockparamproxy optimization, which avoids allocating a proc for simple cases, whenever a getblockparam instruction is followed immediately by branchif or branchunless. ./miniruby --dump=insns -e 'def foo(&block); 123 if block; end' == disasm: #<ISeq:foo@-e:1 (1,0)-(1,34)> (catch: FALSE) local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: 0, kw: -1@-1, kwrest: -1]) [ 1] block@0<Block> 0000 getblockparamproxy block@0, 0 ( 1)[LiCa] 0003 branchunless 8 0005 putobject 123 0007 leave [Re] 0008 putnil 0009 leave [Re] Notes: Merged: https://github.com/ruby/ruby/pull/6286
2022-09-02* expand tabs. [ci skip]git
Tabs were expanded because the file did not have any tab indentation in unedited lines. Please update your editor config, and use misc/expand_tabs.rb in the pre-commit hook.
2022-09-01New constant caching insn: opt_getconstant_pathJohn Hawthorn
Previously YARV bytecode implemented constant caching by having a pair of instructions, opt_getinlinecache and opt_setinlinecache, wrapping a series of getconstant calls (with putobject providing supporting arguments). This commit replaces that pattern with a new instruction, opt_getconstant_path, handling both getting/setting the inline cache and fetching the constant on a cache miss. This is implemented by storing the full constant path as a null-terminated array of IDs inside of the IC structure. idNULL is used to signal an absolute constant reference. $ ./miniruby --dump=insns -e '::Foo::Bar::Baz' == disasm: #<ISeq:<main>@-e:1 (1,0)-(1,13)> (catch: FALSE) 0000 opt_getconstant_path <ic:0 ::Foo::Bar::Baz> ( 1)[Li] 0002 leave The motivation for this is that we had increasingly found the need to disassemble the instructions between the opt_getinlinecache and opt_setinlinecache in order to determine the constant we are fetching, or otherwise store metadata. This disassembly was done: * In opt_setinlinecache, to register the IC against the constant names it is using for granular invalidation. * In rb_iseq_free, to unregister the IC from the invalidation table. * In YJIT to find the position of a opt_getinlinecache instruction to invalidate it when the cache is populated * In YJIT to register the constant names being used for invalidation. With this change we no longe need disassemly for these (in fact rb_iseq_each is now unused), as the list of constant names being referenced is held in the IC. This should also make it possible to make more optimizations in the future. This may also reduce the size of iseqs, as previously each segment required 32 bytes (on 64-bit platforms) for each constant segment. This implementation only stores one ID per-segment. There should be no significant performance change between this and the previous implementation. Previously opt_getinlinecache was a "leaf" instruction, but it included a jump (almost always to a separate cache line). Now opt_getconstant_path is a non-leaf (it may raise/autoload/call const_missing) but it does not jump. These seem to even out. Notes: Merged: https://github.com/ruby/ruby/pull/6187
2022-08-25Convert catch_except_t to stdboolTakashi Kokubun
catch_excep_t is a field that exists for MJIT. In the process of rewriting MJIT in Ruby, I added API to convert 1/0 of _Bool to true/false, and it seemed confusing and hard to maintain if you don't use _Bool for *_p fields.
2022-08-09Optimize duparray/expandarray -> putobject/expandarrayJeremy Evans
There's no point in making a copy of an array just to expand it. Saves an unnecessary array allocation in the multiple assignment case, with a 35-84% improvement in affected cases in benchmark/masgn.yml. Notes: Merged: https://github.com/ruby/ruby/pull/6158
2022-08-09Expand newarray/expandarray optimization for unequal operandsJeremy Evans
This optimizes unbalanced multiple assignment cases such as: ```ruby a.b, c.d = e, f, g a.b, c.d, e.f = g, h ``` Previously, this would use: ``` newarray(3) expandarray(2, 0) newarray(2) expandarray(3, 0) ``` These would both allocate arrays. This switches to opt_reverse with either pop or putnil: ``` pop opt_reverse(2) putnil opt_reverse(3) ``` This avoids an unnecessary array allocation, and results in a 35-76% performance increase in these types of unbalanced cases (tested with benchmark/masgn.yml). Notes: Merged: https://github.com/ruby/ruby/pull/6158
2022-08-09Add peephole optimizer for newarray(X)/expandarray(X, 0) -> opt_reverse(X)Jeremy Evans
This renames the reverse instruction to opt_reverse, since now it is only added by the optimizer. Then it uses as a more general form of swap. This optimizes multiple assignment in the popped case with more than two elements. Notes: Merged: https://github.com/ruby/ruby/pull/6158
2022-08-09Add peephole optimizer for newarray(2)/expandarray(2, 0) -> swapJeremy Evans
An optimization for multiple assignment in the popped case to avoid array allocation was lost in my fix to make multiple assignment follow left-to-right evaluation (50c54d40a81bb2a4794a6be5f1861152900b4fed). Before, in the two element case, swap was used. Afterward, newarray(2) and expandarray(2, 0) were used, which is the same as swap, with the addition of an unnecessary allocation. Because this issue is not specific to multiple assignment, and the multiple assignment code is complex enough as it is, this updates the peephole optimizer to do the newarray(2)/expandarray(2, 0) -> swap conversion. A more general optimization pass for newarray(X)/expandarray(X, 0) -> reverse(X) will follow, but that requires readding the reverse instruction. Notes: Merged: https://github.com/ruby/ruby/pull/6158
2022-07-27Adjust styles [ci skip]Nobuyoshi Nakada
2022-07-26Rename rb_ary_tmp_new to rb_ary_hidden_newPeter Zhu
rb_ary_tmp_new suggests that the array is temporary in some way, but that's not true, it just creates an array that's hidden and not on the transient heap. This commit renames it to rb_ary_hidden_new. Notes: Merged: https://github.com/ruby/ruby/pull/6180
2022-07-23Remove duplicate code for internal arraysNobuyoshi Nakada
Internal arrays are now created hidden from the start.
2022-07-22Use rb_ary_tmp_new only for internal arraysPeter Zhu
rb_ary_tmp_new sets the klass to 0, so it should only be used for internal arrays.