Age | Commit message (Collapse) | Author |
|
... then, new_insn_core extracts nd_line(node).
Also, if a macro "EXPERIMENTAL_ISEQ_NODE_ID" is defined, this changeset
keeps nd_node_id(node) for each instruction. This is intended for
TypeProf to identify what AST::Node corresponds to each instruction.
This patch is originally authored by @yui-knk for showing which column a
NoMethodError occurred.
https://github.com/ruby/ruby/compare/master...yui-knk:feature/node_id
Co-Authored-By: Yuichiro Kaneko <yui-knk@ruby-lang.org>
Notes:
Merged: https://github.com/ruby/ruby/pull/4470
|
|
add_ensure_iseq() adds ensure block to the end of
jump such as next/redo/return. However, if the rescue
cause are in the body, this rescue catches the exception
in ensure clause.
iter do
next
rescue
R
ensure
raise
end
In this case, R should not be executed, but executed without this patch.
Fixes [Bug #13930]
Fixes [Bug #16618]
A part of tests are written by @jeremyevans https://github.com/ruby/ruby/pull/4291
Notes:
Merged: https://github.com/ruby/ruby/pull/4399
|
|
In regular assignment, Ruby evaluates the left hand side before
the right hand side. For example:
```ruby
foo[0] = bar
```
Calls `foo`, then `bar`, then `[]=` on the result of `foo`.
Previously, multiple assignment didn't work this way. If you did:
```ruby
abc.def, foo[0] = bar, baz
```
Ruby would previously call `bar`, then `baz`, then `abc`, then
`def=` on the result of `abc`, then `foo`, then `[]=` on the
result of `foo`.
This change makes multiple assignment similar to single assignment,
changing the evaluation order of the above multiple assignment code
to calling `abc`, then `foo`, then `bar`, then `baz`, then `def=` on
the result of `abc`, then `[]=` on the result of `foo`.
Implementing this is challenging with the stack-based virtual machine.
We need to keep track of all of the left hand side attribute setter
receivers and setter arguments, and then keep track of the stack level
while handling the assignment processing, so we can issue the
appropriate topn instructions to get the receiver. Here's an example
of how the multiple assignment is executed, showing the stack and
instructions:
```
self # putself
abc # send
abc, self # putself
abc, foo # send
abc, foo, 0 # putobject 0
abc, foo, 0, [bar, baz] # evaluate RHS
abc, foo, 0, [bar, baz], baz, bar # expandarray
abc, foo, 0, [bar, baz], baz, bar, abc # topn 5
abc, foo, 0, [bar, baz], baz, abc, bar # swap
abc, foo, 0, [bar, baz], baz, def= # send
abc, foo, 0, [bar, baz], baz # pop
abc, foo, 0, [bar, baz], baz, foo # topn 3
abc, foo, 0, [bar, baz], baz, foo, 0 # topn 3
abc, foo, 0, [bar, baz], baz, foo, 0, baz # topn 2
abc, foo, 0, [bar, baz], baz, []= # send
abc, foo, 0, [bar, baz], baz # pop
abc, foo, 0, [bar, baz] # pop
[bar, baz], foo, 0, [bar, baz] # setn 3
[bar, baz], foo, 0 # pop
[bar, baz], foo # pop
[bar, baz] # pop
```
As multiple assignment must deal with splats, post args, and any level
of nesting, it gets quite a bit more complex than this in non-trivial
cases. To handle this, struct masgn_state is added to keep
track of the overall state of the mass assignment, which stores a linked
list of struct masgn_attrasgn, one for each assigned attribute.
This adds a new optimization that replaces a topn 1/pop instruction
combination with a single swap instruction for multiple assignment
to non-aref attributes.
This new approach isn't compatible with one of the optimizations
previously used, in the case where the multiple assignment return value
was not needed, there was no lhs splat, and one of the left hand side
used an attribute setter. This removes that optimization. Removing
the optimization allowed for removing the POP_ELEMENT and adjust_stack
functions.
This adds a benchmark to measure how much slower multiple
assignment is with the correct evaluation order.
This benchmark shows:
* 4-9% decrease for attribute sets
* 14-23% decrease for array member sets
* Basically same speed for local variable sets
Importantly, it shows no significant difference between the popped
(where return value of the multiple assignment is not needed) and
!popped (where return value of the multiple assignment is needed)
cases for attribute and array member sets. This indicates the
previous optimization, which was dropped in the evaluation
order fix and only affected the popped case, is not important to
performance.
Fixes [Bug #4443]
Notes:
Merged: https://github.com/ruby/ruby/pull/4390
Merged-By: jeremyevans <code@jeremyevans.net>
|
|
Previously, defined? could result in many more method calls than
the code it was checking. `defined? a.b.c.d.e.f` generated 15 calls,
with `a` called 5 times, `b` called 4 times, etc.. This was due to
the fact that defined works in a recursive manner, but it previously
did not cache results. So for `defined? a.b.c.d.e.f`, the logic was
similar to
```ruby
return nil unless defined? a
return nil unless defined? a.b
return nil unless defined? a.b.c
return nil unless defined? a.b.c.d
return nil unless defined? a.b.c.d.e
return nil unless defined? a.b.c.d.e.f
"method"
```
With this change, the logic is similar to the following, without
the creation of a local variable:
```ruby
return nil unless defined? a
_ = a
return nil unless defined? _.b
_ = _.b
return nil unless defined? _.c
_ = _.c
return nil unless defined? _.d
_ = _.d
return nil unless defined? _.e
_ = _.e
return nil unless defined? _.f
"method"
```
In addition to eliminating redundant method calls for defined
statements, this greatly simplifies the instruction sequences by
eliminating duplication. Previously:
```
0000 putnil ( 1)[Li]
0001 putself
0002 defined func, :a, false
0006 branchunless 73
0008 putself
0009 opt_send_without_block <calldata!mid:a, argc:0, FCALL|VCALL|ARGS_SIMPLE>
0011 defined method, :b, false
0015 branchunless 73
0017 putself
0018 opt_send_without_block <calldata!mid:a, argc:0, FCALL|VCALL|ARGS_SIMPLE>
0020 opt_send_without_block <calldata!mid:b, argc:0, ARGS_SIMPLE>
0022 defined method, :c, false
0026 branchunless 73
0028 putself
0029 opt_send_without_block <calldata!mid:a, argc:0, FCALL|VCALL|ARGS_SIMPLE>
0031 opt_send_without_block <calldata!mid:b, argc:0, ARGS_SIMPLE>
0033 opt_send_without_block <calldata!mid:c, argc:0, ARGS_SIMPLE>
0035 defined method, :d, false
0039 branchunless 73
0041 putself
0042 opt_send_without_block <calldata!mid:a, argc:0, FCALL|VCALL|ARGS_SIMPLE>
0044 opt_send_without_block <calldata!mid:b, argc:0, ARGS_SIMPLE>
0046 opt_send_without_block <calldata!mid:c, argc:0, ARGS_SIMPLE>
0048 opt_send_without_block <calldata!mid:d, argc:0, ARGS_SIMPLE>
0050 defined method, :e, false
0054 branchunless 73
0056 putself
0057 opt_send_without_block <calldata!mid:a, argc:0, FCALL|VCALL|ARGS_SIMPLE>
0059 opt_send_without_block <calldata!mid:b, argc:0, ARGS_SIMPLE>
0061 opt_send_without_block <calldata!mid:c, argc:0, ARGS_SIMPLE>
0063 opt_send_without_block <calldata!mid:d, argc:0, ARGS_SIMPLE>
0065 opt_send_without_block <calldata!mid:e, argc:0, ARGS_SIMPLE>
0067 defined method, :f, true
0071 swap
0072 pop
0073 leave
```
After change:
```
0000 putnil ( 1)[Li]
0001 putself
0002 dup
0003 defined func, :a, false
0007 branchunless 52
0009 opt_send_without_block <calldata!mid:a, argc:0, FCALL|VCALL|ARGS_SIMPLE>
0011 dup
0012 defined method, :b, false
0016 branchunless 52
0018 opt_send_without_block <calldata!mid:b, argc:0, ARGS_SIMPLE>
0020 dup
0021 defined method, :c, false
0025 branchunless 52
0027 opt_send_without_block <calldata!mid:c, argc:0, ARGS_SIMPLE>
0029 dup
0030 defined method, :d, false
0034 branchunless 52
0036 opt_send_without_block <calldata!mid:d, argc:0, ARGS_SIMPLE>
0038 dup
0039 defined method, :e, false
0043 branchunless 52
0045 opt_send_without_block <calldata!mid:e, argc:0, ARGS_SIMPLE>
0047 defined method, :f, true
0051 swap
0052 pop
0053 leave
```
This fixes issues where for pathological small examples, Ruby would generate
huge instruction sequences.
Unfortunately, implementing this support is kind of a hack. This adds another
parameter to compile_call for whether we should assume the receiver is already
present on the stack, and has defined? set that parameter for the specific
case where it is compiling a method call where the receiver is also a method
call.
defined_expr0 also takes an additional parameter for whether it should leave
the results of the method call on the stack. If that argument is true, in
the case where the method isn't defined, we jump to the pop before the leave,
so the extra result is not left on the stack. This requires space for an
additional label, so lfinish now needs to be able to hold 3 labels.
Fixes [Bug #17649]
Fixes [Bug #13708]
Notes:
Merged: https://github.com/ruby/ruby/pull/4213
|
|
This commit is based on the patch by @nobu.
|
|
We can know the string used for "defined" calls at compile time, then
store the string in the instruction sequences
Notes:
Merged: https://github.com/ruby/ruby/pull/4279
|
|
Notes:
Merged: https://github.com/ruby/ruby/pull/4119
|
|
Notes:
Merged: https://github.com/ruby/ruby/pull/4119
|
|
Notes:
Merged: https://github.com/ruby/ruby/pull/4119
|
|
Notes:
Merged: https://github.com/ruby/ruby/pull/4119
|
|
Before this commit:
```
$ ruby --dump=insn -e '1.times { |x| puts x }'
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,22)> (catch: FALSE)
== catch table
| catch type: break st: 0000 ed: 0004 sp: 0000 cont: 0004
| == disasm: #<ISeq:block in <main>@-e:1 (1,8)-(1,22)> (catch: FALSE)
| == catch table
| | catch type: redo st: 0001 ed: 0006 sp: 0000 cont: 0001
| | catch type: next st: 0001 ed: 0006 sp: 0000 cont: 0006
| |------------------------------------------------------------------------
| local table (size: 1, argc: 1 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
| [ 1] x@0<Arg>
| 0000 nop ( 1)[Bc]
| 0001 putself [Li]
| 0002 getlocal_WC_0 x@0
| 0004 opt_send_without_block <calldata!mid:puts, argc:1, FCALL|ARGS_SIMPLE>
| 0006 leave [Br]
|------------------------------------------------------------------------
0000 putobject_INT2FIX_1_ ( 1)[Li]
0001 send <calldata!mid:times, argc:0>, block in <main>
0004 leave
```
After this commit:
```
> ruby --dump=insn -e '1.times { |x| puts x }'
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,22)> (catch: FALSE)
0000 putobject_INT2FIX_1_ ( 1)[Li]
0001 send <calldata!mid:times, argc:0>, block in <main>
0004 leave
== disasm: #<ISeq:block in <main>@-e:1 (1,8)-(1,22)> (catch: FALSE)
local table (size: 1, argc: 1 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 1] x@0<Arg>
0000 putself ( 1)[LiBc]
0001 getlocal_WC_0 x@0
0003 opt_send_without_block <calldata!mid:puts, argc:1, FCALL|ARGS_SIMPLE>
0005 leave
```
Fixes [ruby-core:102418] [Feature #17613]
Co-Authored-By: Alan Wu <XrXr@users.noreply.github.com>
Notes:
Merged: https://github.com/ruby/ruby/pull/4125
|
|
Peephole optimization doesn't play well with find pattern at
least. The only case when a pattern matching could have
unreachable patterns is when we have lasgn/dasgn node, which
shouldn't happen in real-life.
Fixes https://bugs.ruby-lang.org/issues/17534
|
|
The WB for callinfo needs to be executed *after* the reference is
written. Otherwise we get a WB miss.
|
|
Callinfo was being written in to an array and the GC would not see the
reference on the stack. `new_insn_send` creates a new callinfo object,
then it calls `new_insn_core`. `new_insn_core` allocates a new INSN
linked list item, which can end up calling `xmalloc` which will trigger
a GC:
https://github.com/ruby/ruby/blob/70cd351c7c71c48ee18d7c01e851a89614086f8f/compile.c#L968-L969
Since the callinfo object isn't on the stack, the GC won't see it, and
it can get collected. This patch just refactors `new_insn_send` to keep
the object on the stack
Co-authored-by: John Hawthorn <john@hawthorn.email>
Notes:
Merged: https://github.com/ruby/ruby/pull/4066
|
|
We don't need nop padding when the catch tables are only for break /
next / redo, so lets avoid them. This eliminates nop padding in
many lambdas.
Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
Notes:
Merged: https://github.com/ruby/ruby/pull/4055
|
|
constant cache `IC` is accessed by non-atomic manner and there are
thread-safety issues, so Ruby 3.0 disables to use const cache on
non-main ractors.
This patch enables it by introducing `imemo_constcache` and allocates
it by every re-fill of const cache like `imemo_callcache`.
[Bug #17510]
Now `IC` only has one entry `IC::entry` and it points to
`iseq_inline_constant_cache_entry`, managed by T_IMEMO object.
`IC` is atomic data structure so `rb_mjit_before_vm_ic_update()` and
`rb_mjit_after_vm_ic_update()` is not needed.
Notes:
Merged: https://github.com/ruby/ruby/pull/4022
|
|
|
|
Notes:
Merged: https://github.com/ruby/ruby/pull/4015
|
|
|
|
|
|
Previously we would add code to check if an ivar was defined when using
`@foo ||= 123`, which was slower than `@foo || (@foo = 123)` when `@foo`
was already defined.
Recently 01b7d5acc702df22d306ae95f1a9c3096e63e624 made it so that
accessing an undefined variable no longer generates a warning, making
the defined check unnecessary and both statements exactly equal.
This commit avoids emitting the defined instruction when compiling
NODE_OP_ASGN_OR with a NODE_IVAR.
Before:
$ ruby --dump=insn -e '@foo ||= 123'
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,12)> (catch: FALSE)
0000 putnil ( 1)[Li]
0001 defined instance-variable, :@foo, false
0005 branchunless 14
0007 getinstancevariable :@foo, <is:0>
0010 dup
0011 branchif 20
0013 pop
0014 putobject 123
0016 dup
0017 setinstancevariable :@foo, <is:0>
0020 leave
After:
$ ./ruby --dump=insn -e '@foo ||= 123'
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,12)> (catch: FALSE)
0000 getinstancevariable :@foo, <is:0> ( 1)[Li]
0003 dup
0004 branchif 13
0006 pop
0007 putobject 123
0009 dup
0010 setinstancevariable :@foo, <is:0>
0013 leave
This seems to be about 50% faster in this benchmark:
require "benchmark/ips"
class Foo
def initialize
@foo = nil
end
def test1
@foo ||= 123
end
def test2
@foo || (@foo = 123)
end
end
FOO = Foo.new
Benchmark.ips do |x|
x.report("test1", "FOO.test1")
x.report("test2", "FOO.test2")
end
Before:
$ ruby benchmark_ivar.rb
Warming up --------------------------------------
test1 1.957M i/100ms
test2 3.125M i/100ms
Calculating -------------------------------------
test1 20.030M (± 1.7%) i/s - 101.780M in 5.083040s
test2 31.227M (± 4.5%) i/s - 156.262M in 5.015936s
After:
$ ./ruby benchmark_ivar.rb
Warming up --------------------------------------
test1 3.205M i/100ms
test2 3.197M i/100ms
Calculating -------------------------------------
test1 32.066M (± 1.1%) i/s - 163.440M in 5.097581s
test2 31.438M (± 4.9%) i/s - 159.860M in 5.098961s
Notes:
Merged: https://github.com/ruby/ruby/pull/3904
|
|
Notes:
Merged: https://github.com/ruby/ruby/pull/3622
Merged-By: nobu <nobu@ruby-lang.org>
|
|
* `GC.auto_compact=`, `GC.auto_compact` can be used to control when
compaction runs. Setting `auto_compact=` to true will cause
compaction to occurr duing major collections. At the moment,
compaction adds significant overhead to major collections, so please
test first!
[Feature #17176]
|
|
`remove_unreachable_chunk()` after `iseq_set_sequence()`"
This reverts commit 3685ed7303fc08bf68cd3cc8d11e22a8ce63a067 and 5dc107b03f5cf32656a5308574b90458486c633c.
Because of some CI failures https://github.com/ruby/ruby/pull/3404#issuecomment-719868313.
|
|
|
|
Notes:
Merged: https://github.com/ruby/ruby/pull/3404
|
|
Notes:
Merged: https://github.com/ruby/ruby/pull/3404
|
|
|
|
Isolated Proc prohibit to access outer local variables, but it was
violated by binding and so on, so they should be error.
Notes:
Merged: https://github.com/ruby/ruby/pull/3721
|
|
Notes:
Merged-By: mrkn <mrkn@ruby-lang.org>
|
|
Notes:
Merged: https://github.com/ruby/ruby/pull/3589
|
|
iv_index_tbl manages instance variable indexes (ID -> index).
This data structure should be synchronized with other ractors
so introduce some VM locks.
This patch also introduced atomic ivar cache used by
set/getinlinecache instructions. To make updating ivar cache (IVC),
we changed iv_index_tbl data structure to manage (ID -> entry)
and an entry points serial and index. IVC points to this entry so
that cache update becomes atomically.
Notes:
Merged: https://github.com/ruby/ruby/pull/3662
|
|
Notes:
Merged: https://github.com/ruby/ruby/pull/3445
|
|
Notes:
Merged: https://github.com/ruby/ruby/pull/3445
|
|
The write barrier wasn't being called for this object, so add the
missing WB. Automatic compaction moved the reference because it didn't
know about the relationship (that's how I found the missing WB).
|
|
|
|
|
|
Range literal is now frozen so we can reuse same Range object if
the begin and the last are Numeric (frozen), such as `(1..2)`.
Notes:
Merged: https://github.com/ruby/ruby/pull/3587
|
|
[Feature #17104]
|
|
* Remove freezestring instruction since this was the only usage for it.
* [Feature #17104]
Notes:
Merged: https://github.com/ruby/ruby/pull/3488
|
|
This commit introduces Ractor mechanism to run Ruby program in
parallel. See doc/ractor.md for more details about Ractor.
See ticket [Feature #17100] to see the implementation details
and discussions.
[Feature #17100]
This commit does not complete the implementation. You can find
many bugs on using Ractor. Also the specification will be changed
so that this feature is experimental. You will see a warning when
you make the first Ractor with `Ractor.new`.
I hope this feature can help programmers from thread-safety issues.
Notes:
Merged: https://github.com/ruby/ruby/pull/3365
|
|
|
|
Just moved "case base" after allocating cache space.
|
|
This reverts commit 3a4be429b50062122d1616256de38649464d3146.
To fix following warning:
```
compiling ../compile.c
../compile.c:6336:20: warning: variable 'line' is uninitialized when used here [-Wuninitialized]
ADD_INSN(head, line, putnil); /* allocate stack for cached #deconstruct value */
^~~~
../compile.c:220:57: note: expanded from macro 'ADD_INSN'
ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line), BIN(insn), 0))
^~~~
../compile.c:6327:13: note: initialize the variable 'line' to silence this warning
int line;
^
= 0
1 warning generated.
```
|
|
|
|
Notes:
Merged: https://github.com/ruby/ruby/pull/3403
|
|
Notes:
Merged: https://github.com/ruby/ruby/pull/3403
|
|
Notes:
Merged: https://github.com/ruby/ruby/pull/3403
|
|
Notes:
Merged: https://github.com/ruby/ruby/pull/3403
|
|
Notes:
Merged: https://github.com/ruby/ruby/pull/3403
|