1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/test
Jeremy Evans 50c54d40a8
Evaluate multiple assignment left hand side before right hand side
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]
2021-04-21 10:49:19 -07:00
..
-ext- rb_enc_interned_str: handle autoloaded encodings 2021-03-22 21:37:48 +09:00
base64
benchmark [ruby/benchmark] Adds Tms#to_h 2021-02-07 23:06:17 -05:00
bigdecimal [ruby/bigdecimal] Fix for the coerce cases in divide and DoDivmod 2021-01-16 00:09:26 +09:00
cgi
coverage
csv Rename RubyVM::MJIT to RubyVM::JIT 2021-01-13 22:46:51 -08:00
date [ruby/date] Make Ractor-compatible 2020-12-22 03:12:51 -05:00
dbm
did_you_mean
digest [digest] Make digest Ractor safe 2020-12-19 15:08:01 +09:00
drb test/drb/test_drb.rb: Specify the host of DRbServer 2021-04-07 16:34:19 +09:00
dtrace
erb [ruby/erb] Warn safe_level and later args even without -w 2021-01-21 13:52:02 +09:00
etc Fix leaked file descriptor in passwd test 2021-03-24 13:02:54 +09:00
excludes
fiber Test incorrect behaviour of rb_io_wait_readable/writable. 2021-03-30 23:16:59 +13:00
fiddle Oops! Add another test and fix to_proc implementation 2021-02-26 10:06:56 -08:00
fileutils Try to test with rake-13.0.2 again. 2020-12-19 16:53:18 +09:00
fixtures/fake_sorted_set_gem Import set 1.0.1 2020-12-22 21:41:44 +09:00
gdbm
io [ruby/io-wait] Declare as Ractor-safe 2021-03-07 09:54:35 +09:00
irb [ruby/irb] Suppress verbose messages in the parallel test 2021-04-05 14:00:21 +09:00
json Prepare to release json-2.5.0 2020-12-22 19:44:27 +09:00
lib Rename RubyVM::MJIT to RubyVM::JIT 2021-01-13 22:46:51 -08:00
logger [ruby/logger] Consider cygwin a Windows platform 2020-12-04 20:16:00 +09:00
matrix [ruby/matrix] Add Matrix#rotate_entries [#19] 2021-01-21 13:22:25 -05:00
mkmf mkmf: fixed install directories of header files in extension libraries [Bug #17761] 2021-03-30 23:28:49 +09:00
monitor
net Fix a warning 2021-01-23 10:52:17 +09:00
nkf
objspace Use EnvUtil.under_gc_stress 2021-03-31 22:14:15 +09:00
open-uri
openssl [ruby/openssl] pkcs7: keep private key when duplicating PKCS7_SIGNER_INFO 2021-03-31 18:05:07 +09:00
optparse [ruby/optparse] Fixed error message of unparsed non-option 2021-03-29 19:37:24 +09:00
ostruct Fix method protection for modules in the ancestry chain. 2021-01-12 23:29:39 -05:00
pathname [ruby/pathname] Fix segfault of Pathname#split 2021-03-28 14:04:10 +09:00
psych [ruby/psych] Skip test_ractor.rb with ruby/psych repo 2020-12-23 19:45:54 +09:00
racc [ruby/racc] skip the failing test with JRuby 2020-11-10 21:21:07 +09:00
rdoc [ruby/rdoc] Links to document texts without "rdoc-ref:" prefix 2021-04-03 01:22:09 +09:00
readline [ruby/readline-ext] Use omit 2021-02-18 21:17:42 +09:00
reline [ruby/reline] Separate keystrokes each editing mode 2021-04-08 21:41:00 +09:00
resolv fe80 should be case insensitive too 2020-11-09 16:16:30 +09:00
rinda Rename RubyVM::MJIT to RubyVM::JIT 2021-01-13 22:46:51 -08:00
ripper Pattern matching pin operator against expression [Feature #17411] 2021-03-21 15:14:31 +09:00
ruby Evaluate multiple assignment left hand side before right hand side 2021-04-21 10:49:19 -07:00
rubygems Merge the master branch of RubyGems 2021-04-15 15:36:15 +09:00
socket Fixed FD leaks 2021-03-08 10:08:40 +09:00
stringio [ruby/stringio] Check if closed in loop 2021-03-08 10:13:29 +09:00
strscan [strscan] Make strscan Ractor safe (#17) 2020-12-18 14:25:41 +09:00
syslog
uri
win32ole
yaml
zlib test/zlib/test_zlib.rb: Set binmode to test output file 2021-04-08 14:26:42 +09:00
runner.rb No codesign in tests 2021-03-27 10:15:01 +09:00
test_abbrev.rb
test_delegate.rb
test_extlibs.rb Removed win32api 2020-11-11 09:27:36 +09:00
test_find.rb
test_forwardable.rb
test_ipaddr.rb
test_mutex_m.rb [ruby/mutex_m] Fix Mutex_m#initialize when the super's initialize has kwargs 2020-12-04 19:53:16 +09:00
test_observer.rb
test_open3.rb
test_pp.rb
test_prettyprint.rb
test_prime.rb [ruby/prime] Optimize Integer#prime? 2020-12-09 00:40:09 -05:00
test_pstore.rb
test_pty.rb
test_rbconfig.rb
test_securerandom.rb
test_set.rb Avoid rehashing in Hash#replace/dup/initialize_copy [Bug #16996] 2021-03-18 07:34:40 -04:00
test_shellwords.rb
test_singleton.rb
test_sorted_set.rb Import set 1.0.1 2020-12-22 21:41:44 +09:00
test_syslog.rb
test_tempfile.rb
test_time.rb
test_timeout.rb
test_tmpdir.rb [ruby/tmpdir] Make usable chars more strict 2021-04-05 21:08:57 +09:00
test_tracer.rb
test_trick.rb test/test_trick.rb: fixed the position to add timeout 2020-12-25 22:23:53 +09:00
test_tsort.rb
test_unicode_normalize.rb
test_weakref.rb