The `f(arg, *arg, **arg, **arg)` case was previously not optimized. The optimizer didn't optimize this case because of the multiple keyword splats, and the compiler didn't optimize it because the `f(*arg, **arg, **arg)` optimization added in 0ee3960685e283d8e75149a8777eb0109d41509a didn't apply. I found it difficult to apply this optimization without changing the `setup_args_core` API, since by the time you get to the ARGSCAT case, you don't know whether you were called recursively or directly, so I'm not sure if it was possible to know at that point whether the array allocation could be avoided. This changes the dup_rest argument in `setup_args_core` from an int to a pointer to int. This allows us to track whether we have allocated a caller side array for multiple splats or splat+post across recursive calls. Check the pointed value (*dup_rest) to determine the `splatarray` argument. If dup_rest is 1, then use `splatarray true` (caller-side array allocation), then set *dup_rest back to 0, ensuring only a single `splatarray true` per method call. Before calling `setup_args_core`, check whether the array allocation can be avoided safely using `splatarray false`. Optimizable cases are: ``` // f(*arg) SPLAT // f(1, *arg) ARGSCAT LIST // f(*arg, **arg) ARGSPUSH SPLAT HASH nd_brace=0 // f(1, *arg, **arg) ARGSPUSH ARGSCAT LIST HASH nd_brace=0 ``` If so, dup_rest is set to 0 instead of 1 to avoid the allocation. After calling `setup_args_core`, check the flag. If the flag includes `VM_CALL_ARGS_SPLAT`, and the pointed value has changed, indicating `splatarray true` was used, then also set `VM_CALL_ARGS_SPLAT_MUT` in the flag. My initial attempt at this broke the `f(*ary, &ary.pop)` test, because we were not duplicating the ary in the splat even though it was modified later (evaluation order issue). The initial attempt would also break `f(*ary, **ary.pop)` or `f(*ary, kw: ary.pop)` cases for the same reason. I added test cases for those evaluation order issues. Add setup_args_dup_rest_p static function that checks that a given node is safe. Call that on the block pass node to determine if the block pass node is safe. Also call it on each of the hash key/value nodes to test that they are safe. If any are not safe, then set dup_rest = 1 so that `splatarray true` will be used to avoid the evaluation order issue. This new approach has the affect of optimizing most cases of literal keywords after positional splats. Previously, only static keyword hashes after positional splats avoided array allocation for the splat. Now, most dynamic keyword hashes after positional splats also avoid array allocation. Add allocation tests for dynamic keyword keyword hashes after positional splats. setup_args_dup_rest_p is currently fairly conservative. It could definitely be expanded to handle additional node types to reduce allocations in additional cases.
What is Ruby?
Ruby is an interpreted object-oriented programming language often used for web development. It also offers many scripting features to process plain text and serialized files, or manage system tasks. It is simple, straightforward, and extensible.
Features of Ruby
- Simple Syntax
- Normal Object-oriented Features (e.g. class, method calls)
- Advanced Object-oriented Features (e.g. mix-in, singleton-method)
- Operator Overloading
- Exception Handling
- Iterators and Closures
- Garbage Collection
- Dynamic Loading of Object Files (on some architectures)
- Highly Portable (works on many Unix-like/POSIX compatible platforms as well as Windows, macOS, etc.) cf. https://docs.ruby-lang.org/en/master/maintainers_md.html#label-Platform+Maintainers
How to get Ruby
For a complete list of ways to install Ruby, including using third-party tools like rvm, see:
https://www.ruby-lang.org/en/downloads/
You can download release packages and the snapshot of the repository. If you want to download whole versions of Ruby, please visit https://www.ruby-lang.org/en/downloads/releases/.
Download with Git
The mirror of the Ruby source tree can be checked out with the following command:
$ git clone https://github.com/ruby/ruby.git
There are some other branches under development. Try the following command to see the list of branches:
$ git ls-remote https://github.com/ruby/ruby.git
You may also want to use https://git.ruby-lang.org/ruby.git (actual master of Ruby source) if you are a committer.
How to build
See Building Ruby
Ruby home page
Documentation
Mailing list
There is a mailing list to discuss Ruby. To subscribe to this list, please send the following phrase:
join
in the mail subject (not body) to the address ruby-talk-request@ml.ruby-lang.org.
Copying
See the file COPYING.
Feedback
Questions about the Ruby language can be asked on the Ruby-Talk mailing list or on websites like https://stackoverflow.com.
Bugs should be reported at https://bugs.ruby-lang.org. Read "Reporting Issues" for more information.
Contributing
See "Contributing to Ruby", which includes setup and build instructions.
The Author
Ruby was originally designed and developed by Yukihiro Matsumoto (Matz) in 1995.