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

1434 Коммитов

Автор SHA1 Сообщение Дата
Jemma Issroff 8f71a5c530 [PRISM] Move scope_node itself to CRuby, create prism_compile.h 2023-10-25 18:18:35 -03:00
yui-knk 08e25985d1 Expand OP_ASGN1 nd_args to nd_index and nd_rvalue
ARGSCAT has been used for nd_args to hold index and rvalue,
because there was limitation on the number of members for Node.
We can easily change structure of node now, let's expand it.
2023-10-20 07:56:20 +09:00
Nobuyoshi Nakada c2d4c92a98
Extract a local variable 2023-10-19 17:28:41 +09:00
Jemma Issroff 10c5063704 Address PR comments 2023-10-18 17:16:11 -07:00
Jemma Issroff ba3a99acaf Remove pm_compile_context_t, move the context onto ScopeNode
We changed ScopeNodes to point to their parent (previous) ScopeNodes.
Accordingly, we can remove pm_compile_context_t, and store all
necessary context in ScopeNodes, allowing us to access locals from
outer scopes.
2023-10-18 17:16:11 -07:00
Alan Wu d2b0c9da2e
YJIT: Add a live ISeq counter
It's an estimator for application size and could be used as a
compilation heuristic later.

Co-authored-by: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@shopify.com>
Co-authored-by: Takashi Kokubun <takashikkbn@gmail.com>
2023-10-18 23:46:35 +00:00
Nobuyoshi Nakada 8e6a251138
Remove unnecessary and misleading casts 2023-10-18 18:52:05 +09:00
Nobuyoshi Nakada 380c25f89f
Adjust indent [ci skip] 2023-10-11 19:42:07 +09:00
yui-knk f9fe7aeef4 Extract NODE_FL_NEWLINE access to macro 2023-10-11 19:22:34 +09:00
yui-knk 8c2a493233 Fix cast node type 2023-10-09 19:08:23 +09:00
yui-knk fbd534679f Correctly casting node for accessing nd_value and nd_vid in compile.c 2023-10-07 17:54:35 +09:00
yui-knk 5c779dc45d Remove not used fields from MATCH3 2023-10-06 15:32:33 +09:00
Nobuyoshi Nakada a5cc6341c0
Remove `NODE_VALUES`
This node type was added for the multi-value experiment back in 2004.
The feature itself was removed after a few years, but this is its
remnant.
2023-10-06 03:39:58 +09:00
yui-knk 45350a0460 Correctly casting node for accessing COLON node nd_mid in compile.c 2023-10-05 13:19:09 +09:00
Yuichiro Kaneko 1ed6fd8997 Check the result of get_nd_recv before node type check for safety
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
2023-10-02 09:41:45 +09:00
yui-knk b1131851e0 Correctly casting node for accessing nd_recv, nd_mid and nd_args in compile.c 2023-10-02 09:41:45 +09:00
HParker c74dc8b4af Use reference counting to avoid memory leak in kwargs
Tracks other callinfo that references the same kwargs and frees them when all references are cleared.

[bug #19906]

Co-authored-by: Peter Zhu <peter@peterzhu.ca>
2023-10-01 10:55:19 -04:00
yui-knk 08239fd6af Use rb_node_args_t and rb_node_args_aux_t instead of NODE 2023-10-01 19:38:03 +09:00
yui-knk cecd1de2eb Use rb_node_opt_arg_t and rb_node_kw_arg_t instead of NODE 2023-10-01 09:19:42 +09:00
yui-knk d293d9e191 Expand pattern_info struct into ARYPTN Node and FNDPTN Node 2023-09-30 13:11:32 +09:00
yui-knk 129d006852 Remove not used fields from argument nodes 2023-09-30 12:29:29 +09:00
yui-knk 37a783a30c Merge RNode_OP_ASGN2 and RNode_OP_ASGN22 2023-09-29 08:36:39 +09:00
Kevin Newton a213d21448 Move CRuby-specific prism files to top level 2023-09-28 09:44:16 -04:00
yui-knk 74c6781153 Change RNode structure from union to struct
All kind of AST nodes use same struct RNode, which has u1, u2, u3 union members
for holding different kind of data.
This has two problems.

1. Low flexibility of data structure

Some nodes, for example NODE_TRUE, don’t use u1, u2, u3. On the other hand,
NODE_OP_ASGN2 needs more than three union members. However they use same
structure definition, need to allocate three union members for NODE_TRUE and
need to separate NODE_OP_ASGN2 into another node.
This change removes the restriction so make it possible to
change data structure by each node type.

2. No compile time check for union member access

It’s developer’s responsibility for using correct member for each node type when it’s union.
This change clarifies which node has which type of fields and enables compile time check.

This commit also changes node_buffer_elem_struct buf management to handle
different size data with alignment.
2023-09-28 11:58:10 +09:00
Kevin Newton 175ac32c62 Use new constant pool layout for prism 2023-09-27 15:41:05 -04:00
Kevin Newton 3d0a46796b Rename YARP symbols to prism 2023-09-27 13:57:38 -04:00
Aaron Patterson f08cac066e Don't call malloc with 0
It seems not-uncommon for methods to have no IV, ISE, or ICVARC caches.
Calling malloc with 0 will actually allocate something, so if there
aren't any caches (`ISEQ_IS_SIZE(body) == 0`), then we can avoid
allocating memory by not calling malloc.  If there are no caches, then
theoretically nobody should be reading from the buffer anyway.

This saves about 1MB on Lobsters benchmark.
2023-09-14 16:15:53 -07:00
Nobuyoshi Nakada 6e64d43704 [Bug #19862] Skip compiled result of never reachable expression 2023-09-13 08:30:37 +09:00
yui-knk b5914a72a9 Refactor to use same logic with other assignment nodes 2023-09-10 19:45:33 +09:00
Peter Zhu b3b57f70cc Fix missing write barrier in iseq instruction list
There's a missing write barrier for operands in the iseq instruction
list, which can cause crashes.

It can be reproduced when Ruby is compiled with `-DRUBY_DEBUG_ENV=1`.
Using the following command:

```
RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR=0 RUBY_DEBUG=gc_stress ruby -w --disable=gems -Itool/lib -W0 test.rb
```

The following script crashes:

```
require "test/unit"
```
2023-09-06 11:18:50 -04:00
Yusuke Endoh 4f4c1170bc Revert "Don't reset line coverage for evaled code. (#8330)"
This reverts commit 7e0f5df2f9.

https://bugs.ruby-lang.org/issues/19857#note-7
2023-09-04 19:52:08 +09:00
Samuel Williams 7e0f5df2f9
Don't reset line coverage for evaled code. (#8330)
* Add failing test.
2023-09-04 13:31:25 +12:00
Kevin Newton 49dff732e8
Update YARP APIs to handle uint8_t 2023-08-30 14:41:39 -04:00
Jemma Issroff 535045ab3b
[YARP] Compile basic types (#8311)
* Add a compile_context arg to yp_compile_node

The compile_context will allow us to pass around the parser, and
the constants and lookup table (to be used in future commits).

* Compile yp_program_node_t and yp_statements_node_t

Add the compilation for program and statements node so that we can
successfully compile an empty program with YARP.

* Helper functions for parsing numbers, strings, and symbols

* Compile basic numeric / boolean node types in YARP

* Compile StringNode and SymbolNodes in YARP

* Compile several basic node types in YARP

* Added error return for missing node
2023-08-29 09:27:00 -07:00
Jemma Issroff 3b815ed7da
Add yarp/yarp_compiler.c (#8042)
* Add yarp/yarp_compiler.c as stencil for compiling YARP

This commit adds yarp/yarp_compiler.c, and changes the sync script
to ensure that yarp/yarp_compiler.c will not get overwritten

* [Misc #119772] Create and expose RubyVM::InstructionSequence.compile_yarp

This commit creates the stencil for a compile_yarp function, which
we will continue to fill out. It allows us to check the output
of compiled YARP code against compiled code without using YARP.
2023-08-28 13:55:58 -07:00
yui-knk 00054de6b5 Remove nd_entry from NODE_GASGN and NODE_GVAR
After a0f12a0258 NODE_GASGN and
NODE_GVAR hold same value on both nd_vid and nd_entry.
This commit stops setting value to nd_entry and makes to use only
nd_vid.
2023-08-23 07:59:54 +09:00
Takashi Kokubun e210b899dc
Move the PC regardless of the leaf flag (#8232)
Co-authored-by: Alan Wu <alansi.xingwu@shopify.com>
2023-08-16 20:28:33 -07:00
Koichi Sasada d68c01fd31 support `rescue` event for TracePoint
fix [Feature #19572]
2023-08-01 22:46:17 +09:00
Takashi Kokubun 38be9a9b72
Clean up OPT_STACK_CACHING (#8132) 2023-07-27 17:27:05 -07:00
Peter Zhu 3223181284 Remove RARRAY_CONST_PTR_TRANSIENT
RARRAY_CONST_PTR now does the same things as RARRAY_CONST_PTR_TRANSIENT.
2023-07-13 14:48:14 -04:00
Nobuyoshi Nakada 0d0841ad4c
Compile code for lazy ISeq loding always 2023-06-30 23:59:05 +09:00
yui-knk 19c62b400d Replace parser & node compile_option from Hash to bit field
This commit reduces dependency to CRuby object.
2023-06-17 16:41:08 +09:00
yui-knk 5f65e8c5d5 Rename `rb_node_name` to the original name
98637d421d changes the name of
the function. However this function is exported as global,
then change the name to origin one for keeping compatibility.
2023-05-24 20:54:48 +09:00
yui-knk 98637d421d Move `ruby_node_name` to node.c and rename prefix of the function 2023-05-23 18:05:35 +09:00
Nobuyoshi Nakada c7bacf84f0 [Bug #19611] Remove never-reachable branch in logical expression 2023-04-27 14:52:22 +09:00
Nobuyoshi Nakada 8023da746c
Adjust indent [ci skip] 2023-04-19 09:23:28 +09:00
git 21082eac50 * expand tabs. [ci skip]
Please consider using misc/expand_tabs.rb as a pre-commit hook.
2023-04-19 00:16:36 +00:00
Aaron Patterson c5fc1ce975 Emit special instruction for array literal + .(hash|min|max)
This commit introduces a new instruction `opt_newarray_send` which is
used when there is an array literal followed by either the `hash`,
`min`, or `max` method.

```
[a, b, c].hash
```

Will emit an `opt_newarray_send` instruction.  This instruction falls
back to a method call if the "interested" method has been monkey
patched.

Here are some examples of the instructions generated:

```
$ ./miniruby --dump=insns -e '[@a, @b].max'
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,12)> (catch: FALSE)
0000 getinstancevariable                    :@a, <is:0>               (   1)[Li]
0003 getinstancevariable                    :@b, <is:1>
0006 opt_newarray_send                      2, :max
0009 leave
$ ./miniruby --dump=insns -e '[@a, @b].min'
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,12)> (catch: FALSE)
0000 getinstancevariable                    :@a, <is:0>               (   1)[Li]
0003 getinstancevariable                    :@b, <is:1>
0006 opt_newarray_send                      2, :min
0009 leave
$ ./miniruby --dump=insns -e '[@a, @b].hash'
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,13)> (catch: FALSE)
0000 getinstancevariable                    :@a, <is:0>               (   1)[Li]
0003 getinstancevariable                    :@b, <is:1>
0006 opt_newarray_send                      2, :hash
0009 leave
```

[Feature #18897] [ruby-core:109147]

Co-authored-by: John Hawthorn <jhawthorn@github.com>
2023-04-18 17:16:22 -07:00
eileencodes ce99e50ede Move `catch_except_p` to `compile_data`
The `catch_except_p` flag is used for communicating between parent and
child iseq's that a throw instruction was emitted. So for example if a
child iseq has a throw in it and the parent wants to catch the throw, we
use this flag to communicate to the parent iseq that a throw instruction
was emitted.

This flag is only useful at compile time, it only impacts the
compilation process so it seems to be fine to move it from the iseq body
to the compile_data struct.

Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
2023-04-11 10:47:58 -07:00
Koichi Sasada c9fd81b860 `vm_call_single_noarg_inline_builtin`
If the iseq only contains `opt_invokebuiltin_delegate_leave` insn and
the builtin-function (bf) is inline-able, the caller doesn't need to
build a method frame.

`vm_call_single_noarg_inline_builtin` is fast path for such cases.
2023-03-23 14:03:12 +09:00
Koichi Sasada e5a5e43c36 should not restore builtin_inline_index
`builtin_inline_index` is restored because THEN clause on
`Primitive.mandatory_only?` was compiled twice.

However, f29c9d6d36 skips to compile THEN clause so we don't
need to restore `builtin_inline_index`.
2023-03-23 14:03:12 +09:00
Koichi Sasada f29c9d6d36 compile branch body if needed
```ruby
if true
  THEN
else
  ELSE
end
```

On this case, ELSE is not needed so that only compile THEN part.
2023-03-17 09:50:41 +09:00
Koichi Sasada 6462c1a042 `Hash#dup` for kwsplat arguments
On `f(*a, **kw)` method calls, a rest keyword parameter is identically
same Hash object is passed and it should make `#dup`ed Hahs.

fix https://bugs.ruby-lang.org/issues/19526
2023-03-15 18:05:13 +09:00
Takashi Kokubun 70ba310212
YJIT: Introduce no_gc attribute (#7511) 2023-03-14 15:38:58 -07:00
Takashi Kokubun 94da5f7c36 Rename builtin attr :inline to :leaf 2023-03-11 14:25:12 -08:00
Takashi Kokubun 0c0c88d383 Support multiple attributes with Primitive.attr! 2023-03-11 14:19:46 -08:00
Koichi Sasada 262254dc7d rename `defined_ivar` to `definedivar`
because non-opt instructions should contain `_` char.
2023-03-10 00:37:11 +09:00
Ole Friis Østergaard 1a3f8e1c9f Add defined_ivar instruction
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.
2023-03-08 09:34:31 -08:00
Nobuyoshi Nakada 5889cbd7de Constify function tables 2023-03-08 13:59:21 +09:00
Takashi Kokubun 233ddfac54 Stop exporting symbols for MJIT 2023-03-06 21:59:23 -08:00
Koichi Sasada e87d088291 Change bytecode of `f(*a, **kw)`
`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-03-06 15:03:06 +09:00
John Bampton 2f7270c681
Fix spelling (#7389) 2023-02-27 09:56:06 -08:00
Peter Zhu 3e09822407 Fix incorrect line numbers in GC hook
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]
2023-02-24 14:10:09 -05:00
Nobuyoshi Nakada cb40432c74
Use `ERROR_ARGS_AT` 2023-02-21 18:40:03 +09:00
Jean Boussier 0459eaec95 compile.c: eliminate getinstancevariable -> pop sequences
This case wasn't eliminated before because `getinstancevariable`
could emit a warning, but that's no longer the case since Ruby
3.0.
2023-02-20 19:04:04 +01:00
Nobuyoshi Nakada 2490b2e121 Add utility macros `DECIMAL_SIZE_OF` and `DECIMAL_SIZE_OF_BYTES` 2023-02-14 15:18:21 +09:00
Alan Wu 86de48e9f6 Remove ibf_dumper's WB_PROTECTED status
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]
2023-02-13 11:42:58 -05:00
Matt Valentine-House 72aba64fff Merge gc.h and internal/gc.h
[Feature #19425]
2023-02-09 10:32:29 -05:00
Peter Zhu 861d70e383 Rename iseq_mark_and_update to iseq_mark_and_move
The new name is more consistent.
2023-02-08 12:43:25 -05:00
Peter Zhu 056e7a0154 Make all of the references of iseq movable 2023-01-20 08:51:39 -05:00
Stan Lo df6b72b8ff Avoid checking interrupt when loading iseq
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](0fcfc28aca/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`](0fcfc28aca/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>
2023-01-17 08:01:19 -05:00
Shugo Maeda 2581de112c Disallow mixed usage of ... and */**
[Feature #19134]
2022-12-15 18:56:24 +09:00
Jemma Issroff 40a9964b89 Set max_iv_count (used for object shapes) based on inline caches
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>
2022-12-06 13:43:42 -08:00
yui-knk 8be62f06c8 Remove ruby2_keywords related to args forwarding
This was introduced by b609bdeb53
to suppress warnings. However these warngins were deleted by
beae6cbf0f. Therefore these codes
are not needed anymore.
2022-11-29 15:39:56 +09:00
S-H-GAMELINKS 1f4f6c9832 Using UNDEF_P macro 2022-11-16 18:58:33 +09:00
Yusuke Endoh 4a7d6c2852 Fix false LocalJumpError when branch coverage is enabled
`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]
2022-11-08 14:37:08 +09:00
Koichi Sasada e35c528d72 push dummy frame for loading process
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
2022-10-20 17:38:28 +09:00
Jemma Issroff ad63b668e2
Revert "Revert "This commit implements the Object Shapes technique in CRuby.""
This reverts commit 9a6803c90b.
2022-10-11 08:40:56 -07:00
Aaron Patterson 9a6803c90b
Revert "This commit implements the Object Shapes technique in CRuby."
This reverts commit 68bc9e2e97d12f80df0d113e284864e225f771c2.
2022-09-30 16:01:50 -07:00
Jemma Issroff d594a5a8bd
This commit implements the Object Shapes technique in CRuby.
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-28 08:26:21 -07:00
Aaron Patterson 06abfa5be6
Revert this until we can figure out WB issues or remove shapes from GC
Revert "* expand tabs. [ci skip]"

This reverts commit 830b5b5c35.

Revert "This commit implements the Object Shapes technique in CRuby."

This reverts commit 9ddfd2ca00.
2022-09-26 16:10:11 -07:00
git 830b5b5c35 * expand tabs. [ci skip]
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-27 01:21:58 +09:00
Jemma Issroff 9ddfd2ca00 This commit implements the Object Shapes technique in CRuby.
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-26 09:21:30 -07:00
John Hawthorn b361bdc200 [Bug #19021] Fix safe call w/ conditional assign
As of fbaac837cf, 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).
2022-09-25 20:44:54 -07:00
Samuel Williams 85cc0ce5c8 Use `int first_lineno` for binary format. 2022-09-26 00:41:16 +13:00
Samuel Williams 22af2e9084 Rework vm_core to use `int first_lineno` struct member. 2022-09-26 00:41:16 +13:00
Samuel Williams 75cf29f60d Rework `first_lineno` to be `int`. 2022-09-26 00:41:16 +13:00
HParker fbaac837cf avoid extra dup and pop in compile_op_asgn2
Co-authored-by: John Hawthorn <jhawthorn@github.com>
2022-09-22 09:47:13 -07:00
HParker aafbc9068f avoid extra dup and pop in compile_op_log
Co-authored-by: John Hawthorn <jhawthorn@github.com>
2022-09-22 09:47:13 -07:00
Samuel Williams 9434a7333c Enable coverage for eval. 2022-09-22 22:19:12 +12:00
Maple Ong 89077b4c5a
Add comments for some peephole optimizations [ci skip] 2022-09-12 07:50:55 +09:00
Nobuyoshi Nakada 92d2476208
Adjust styles [ci skip] 2022-09-02 14:49:42 +09:00
John Hawthorn fc2d9fedc2 Use getblockparamproxy with branch
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]
2022-09-01 17:36:20 -07:00
git 3401e58f23 * expand tabs. [ci skip]
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-02 07:21:12 +09:00
John Hawthorn 679ef34586 New constant caching insn: opt_getconstant_path
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.
2022-09-01 15:20:49 -07:00
Takashi Kokubun d6f21b308b
Convert catch_except_t to stdbool
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-25 23:00:19 -07:00
Jeremy Evans 9363b0423a Optimize duparray/expandarray -> putobject/expandarray
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.
2022-08-09 22:19:46 -07:00
Jeremy Evans fc4b4f2e8d Expand newarray/expandarray optimization for unequal operands
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).
2022-08-09 22:19:46 -07:00
Jeremy Evans 5089b6acc7 Add peephole optimizer for newarray(X)/expandarray(X, 0) -> opt_reverse(X)
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.
2022-08-09 22:19:46 -07:00
Jeremy Evans 9f8abd28ba Add peephole optimizer for newarray(2)/expandarray(2, 0) -> swap
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 (50c54d40a8).

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.
2022-08-09 22:19:46 -07:00