summaryrefslogtreecommitdiff
path: root/vm_args.c
AgeCommit message (Collapse)Author
2024-02-11Fix crash when passing large keyword splat to method accepting keywords and ↵Jeremy Evans
keyword splat The following code previously caused a crash: ```ruby h = {} 1000000.times{|i| h[i.to_s.to_sym] = i} def f(kw: 1, **kws) end f(**h) ``` Inside a thread or fiber, the size of the keyword splat could be much smaller and still cause a crash. I found this issue while optimizing method calling by reducing implicit allocations. Given the following code: ```ruby def f(kw: , **kws) end kw = {kw: 1} f(**kw) ``` The `f(**kw)` call previously allocated two hashes callee side instead of a single hash. This is because `setup_parameters_complex` would extract the keywords from the keyword splat hash to the C stack, to attempt to mirror the case when literal keywords are passed without a keyword splat. Then, `make_rest_kw_hash` would build a new hash based on the extracted keywords that weren't used for literal keywords. Switch the implementation so that if a keyword splat is passed, literal keywords are deleted from the keyword splat hash (or a copy of the hash if the hash is not mutable). In addition to avoiding the crash, this new approach is much more efficient in all cases. With the included benchmark: ``` 1 miniruby: 5247879.9 i/s miniruby-before: 2474050.2 i/s - 2.12x slower 1_mutable miniruby: 1797036.5 i/s miniruby-before: 1239543.3 i/s - 1.45x slower 10 miniruby: 1094750.1 i/s miniruby-before: 365529.6 i/s - 2.99x slower 10_mutable miniruby: 407781.7 i/s miniruby-before: 225364.0 i/s - 1.81x slower 100 miniruby: 100992.3 i/s miniruby-before: 32703.6 i/s - 3.09x slower 100_mutable miniruby: 40092.3 i/s miniruby-before: 21266.9 i/s - 1.89x slower 1000 miniruby: 21694.2 i/s miniruby-before: 4949.8 i/s - 4.38x slower 1000_mutable miniruby: 5819.5 i/s miniruby-before: 2995.0 i/s - 1.94x slower ```
2024-01-31Do not modify provided argument splat when using ruby2_keywords with ↵Jeremy Evans
anonymous splat Previously, this would push the provided keywords onto the argument splat. Add ruby2_keywords to the list of other checks for whether it is safe for treating a given splat as mutable when the called method accepts an anonymous splat.
2024-01-24Introduce Allocationless Anonymous Splat ForwardingJeremy Evans
Ruby makes it easy to delegate all arguments from one method to another: ```ruby def f(*args, **kw) g(*args, **kw) end ``` Unfortunately, this indirection decreases performance. One reason it decreases performance is that this allocates an array and a hash per call to `f`, even if `args` and `kw` are not modified. Due to Ruby's ability to modify almost anything at runtime, it's difficult to avoid the array allocation in the general case. For example, it's not safe to avoid the allocation in a case like this: ```ruby def f(*args, **kw) foo(bar) g(*args, **kw) end ``` Because `foo` may be `eval` and `bar` may be a string referencing `args` or `kw`. To fix this correctly, you need to perform something similar to escape analysis on the variables. However, there is a case where you can avoid the allocation without doing escape analysis, and that is when the splat variables are anonymous: ```ruby def f(*, **) g(*, **) end ``` When splat variables are anonymous, it is not possible to reference them directly, it is only possible to use them as splats to other methods. Since that is the case, if `f` is called with a regular splat and a keyword splat, it can pass the arguments directly to `g` without copying them, avoiding allocation. For example: ```ruby def g(a, b:) a + b end def f(*, **) g(*, **) end a = [1] kw = {b: 2} f(*a, **kw) ``` I call this technique: Allocationless Anonymous Splat Forwarding. This is implemented using a couple additional iseq param flags, anon_rest and anon_kwrest. If anon_rest is set, and an array splat is passed when calling the method when the array splat can be used without modification, `setup_parameters_complex` does not duplicate it. Similarly, if anon_kwest is set, and a keyword splat is passed when calling the method, `setup_parameters_complex` does not duplicate it.
2024-01-24Add VM_CALL_ARGS_SPLAT_MUT callinfo flagJeremy Evans
This flag is set when the caller has already created a new array to handle a splat, such as for `f(*a, b)` and `f(*a, *b)`. Previously, if `f` was defined as `def f(*a)`, these calls would create an extra array on the callee side, instead of using the new array created by the caller. This modifies `setup_args_core` to set the flag whenver it would add a `splatarray true` instruction. However, when `splatarray true` is changed to `splatarray false` in the peephole optimizer, to avoid unnecessary allocations on the caller side, the flag must be removed. Add `optimize_args_splat_no_copy` and have the peephole optimizer call that. This significantly simplifies the related peephole optimizer code. On the callee side, in `setup_parameters_complex`, set `args->rest_dupped` to true if the flag is set. This takes a similar approach for optimizing regular splats that was previiously used for keyword splats in d2c41b1bff1f3102544bb0d03d4e82356d034d33 (via VM_CALL_KW_SPLAT_MUT).
2024-01-14Support keyword splatting nilJeremy Evans
nil is treated similarly to the empty hash in this case, passing no keywords and not calling any conversion methods. Fixes [Bug #20064] Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
2024-01-08Adjust styles and indents [ci skip]Nobuyoshi Nakada
2023-12-07Prevent modification of splat array inside setup_parameters_complexJeremy Evans
For the following: ``` def f(*a); a end p f(*a, kw: 3) ``` `setup_parameters_complex` pushes `{kw: 3}` onto `a`. This worked fine back when `concatarray true` was used and `a` was already a copy. It does not work correctly with the optimization to switch to `concatarray false`. This duplicates the array on the callee side in such a case. This affects cases when passing a regular splat and a keyword splat (or literal keywords) in a method call, where the method does not accept keywords. This allocation could probably be avoided, but doing so would make `setup_parameters_complex` more complicated.
2023-12-07Fix keyword splat passing as regular argumentJeremy Evans
Since Ruby 3.0, Ruby has passed a keyword splat as a regular argument in the case of a call to a Ruby method where the method does not accept keyword arguments, if the method call does not contain an argument splat: ```ruby def self.f(obj) obj end def self.fs(*obj) obj[0] end h = {a: 1} f(**h).equal?(h) # Before: true; After: false fs(**h).equal?(h) # Before: true; After: false a = [] f(*a, **h).equal?(h) # Before and After: false fs(*a, **h).equal?(h) # Before and After: false ``` The fact that the behavior differs when passing an empty argument splat makes it obvious that something is not working the way it is intended. Ruby 2 always copied the keyword splat hash, and that is the expected behavior in Ruby 3. This bug is because of a missed check in setup_parameters_complex. If the keyword splat passed is not mutable, then it points to an existing object and not a new object, and therefore it must be copied. Now, there are 3 specs for the broken behavior of directly using the keyword splatted hash. Fix two specs and add a new version guard. Do not keep the specs for the broken behavior for earlier Ruby versions, in case this fix is backported. For the ruby2_keywords spec, just remove the related line, since that line is unrelated to what the spec is testing. Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
2023-11-18Ensure keyword splat method argument is hashJeremy Evans
Commit e87d0882910001ef3b0c2ccd43bf00cee8c34a0c introduced a regression where the keyword splat object passed by the caller would be directly used by callee as keyword splat parameters, if it implemented #to_hash. The return value of #to_hash would be ignored in this case.
2023-09-12Make Kernel#lambda raise when given non-literal blockAlan Wu
Previously, Kernel#lambda returned a non-lambda proc when given a non-literal block and issued a warning under the `:deprecated` category. With this change, Kernel#lambda will always return a lambda proc, if it returns without raising. Due to interactions with block passing optimizations, we previously had two separate code paths for detecting whether Kernel#lambda got a literal block. This change allows us to remove one path, the hack done with rb_control_frame_t::block_code introduced in 85a337f for supporting situations where Kernel#lambda returned a non-lambda proc. [Feature #19777] Co-authored-by: Takashi Kokubun <takashikkbn@gmail.com> Notes: Merged: https://github.com/ruby/ruby/pull/8405
2023-08-04Fetch the last element only when not emptyNobuyoshi Nakada
Also `flag_keyword_hash` sets to 0 or a hash object. Notes: Merged: https://github.com/ruby/ruby/pull/8173
2023-07-13Remove RARRAY_CONST_PTR_TRANSIENTPeter Zhu
RARRAY_CONST_PTR now does the same things as RARRAY_CONST_PTR_TRANSIENT. Notes: Merged: https://github.com/ruby/ruby/pull/8071
2023-07-10Fix autosplat conditions to handle ruby2_keywords caseJeremy Evans
Autosplat should not occur if there are two arguments but second argument is an array containing a ruby2_keywords splat. Only autosplat if a single argument to be yielded to the block, and there is no splatted flagged keyword hash passed. Fixes [Bug #19759] Notes: Merged: https://github.com/ruby/ruby/pull/8039 Merged-By: jeremyevans <code@jeremyevans.net>
2023-03-15`Hash#dup` for kwsplat argumentsKoichi Sasada
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 Notes: Merged: https://github.com/ruby/ruby/pull/7507
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 ```
2022-11-16Using UNDEF_P macroS-H-GAMELINKS
Notes: Merged: https://github.com/ruby/ruby/pull/6721
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-21Expand tabs [ci skip]Takashi Kokubun
[Misc #18891] Notes: Merged: https://github.com/ruby/ruby/pull/6094
2022-04-05Unflag a splatted flagged hash if the method doesn't use ruby2_keywordsJeremy Evans
For a method such as: def foo(*callee_args) end If this method is called with a flagged hash (created by a method flagged with ruby2_keywords), this previously passed the hash through without modification. With this change, it acts as if the last hash was passed as keywords, so a call to: foo(*caller_args) where the last element of caller_args is a flagged hash, will be treated as: foo(*caller_args[0...-1], **caller_args[-1]) As a result, inside foo, callee_args[-1] is an unflagged duplicate of caller_args[-1] (all other elements of callee_args match caller_args). Fixes [Bug #18625] Notes: Merged: https://github.com/ruby/ruby/pull/5684
2022-03-30Do not autosplat array in block call just because keywords acceptedJeremy Evans
If the block only accepts a single positional argument plus keywords, then do not autosplat. Still autosplat if the block accepts more than one positional argument in addition to keywords. Autosplatting a single positional argument plus keywords made sense in Ruby 2, since a final positional hash could be used as keywords, but it does not make sense in Ruby 3. Fixes [Bug #18633] Notes: Merged: https://github.com/ruby/ruby/pull/5665 Merged-By: jeremyevans <code@jeremyevans.net>
2022-03-24Add ISEQ_BODY macroPeter Zhu
Use ISEQ_BODY macro to get the rb_iseq_constant_body of the ISeq. Using this macro will make it easier for us to change the allocation strategy of rb_iseq_constant_body when using Variable Width Allocation. Notes: Merged: https://github.com/ruby/ruby/pull/5698
2021-10-03Using NIL_P macro instead of `== Qnil`S.H
Notes: Merged: https://github.com/ruby/ruby/pull/4925 Merged-By: nobu <nobu@ruby-lang.org>
2021-09-11Remove printf family from the mjit headerNobuyoshi Nakada
Linking printf family functions makes mjit objects to link unnecessary code. Notes: Merged: https://github.com/ruby/ruby/pull/4820
2021-01-08remove unused declKoichi Sasada
Notes: Merged: https://github.com/ruby/ruby/pull/4037
2020-07-06Run method_missing in the same execution contextNobuyoshi Nakada
2020-05-11Suppress probably impossible maybe-uninitialized warningNobuyoshi Nakada
2020-03-17Reduce allocations for keyword argument hashesJeremy Evans
Previously, passing a keyword splat to a method always allocated a hash on the caller side, and accepting arbitrary keywords in a method allocated a separate hash on the callee side. Passing explicit keywords to a method that accepted a keyword splat did not allocate a hash on the caller side, but resulted in two hashes allocated on the callee side. This commit makes passing a single keyword splat to a method not allocate a hash on the caller side. Passing multiple keyword splats or a mix of explicit keywords and a keyword splat still generates a hash on the caller side. On the callee side, if arbitrary keywords are not accepted, it does not allocate a hash. If arbitrary keywords are accepted, it will allocate a hash, but this commit uses a callinfo flag to indicate whether the caller already allocated a hash, and if so, the callee can use the passed hash without duplicating it. So this commit should make it so that a maximum of a single hash is allocated during method calls. To set the callinfo flag appropriately, method call argument compilation checks if only a single keyword splat is given. If only one keyword splat is given, the VM_CALL_KW_SPLAT_MUT callinfo flag is not set, since in that case the keyword splat is passed directly and not mutable. If more than one splat is used, a new hash needs to be generated on the caller side, and in that case the callinfo flag is set, indicating the keyword splat is mutable by the callee. In compile_hash, used for both hash and keyword argument compilation, if compiling keyword arguments and only a single keyword splat is used, pass the argument directly. On the caller side, in vm_args.c, the callinfo flag needs to be recognized and handled. Because the keyword splat argument may not be a hash, it needs to be converted to a hash first if not. Then, unless the callinfo flag is set, the hash needs to be duplicated. The temporary copy of the callinfo flag, kw_flag, is updated if a hash was duplicated, to prevent the need to duplicate it again. If we are converting to a hash or duplicating a hash, we need to update the argument array, which can including duplicating the positional splat array if one was passed. CALLER_SETUP_ARG and a couple other places needs to be modified to handle similar issues for other types of calls. This includes fairly comprehensive tests for different ways keywords are handled internally, checking that you get equal results but that keyword splats on the caller side result in distinct objects for keyword rest parameters. Included are benchmarks for keyword argument calls. Brief results when compiled without optimization: def kw(a: 1) a end def kws(**kw) kw end h = {a: 1} kw(a: 1) # about same kw(**h) # 2.37x faster kws(a: 1) # 1.30x faster kws(**h) # 2.19x faster kw(a: 1, **h) # 1.03x slower kw(**h, **h) # about same kws(a: 1, **h) # 1.16x faster kws(**h, **h) # 1.14x faster Notes: Merged: https://github.com/ruby/ruby/pull/2945
2020-03-08Do not autosplat when calling procs that accept rest and keywordsJeremy Evans
When providing a single array to a block that takes a splat, pass the array as one argument of the splat instead of as the splat itself, even if the block also accepts keyword arguments. Previously, this behavior was only used for blocks that did not accept keywords. Implements [Feature#16166] Notes: Merged: https://github.com/ruby/ruby/pull/2502
2020-02-22Proc from Symbol needs a receiverNobuyoshi Nakada
So its arity should be -2 instead of -1. [Bug #16640] https://bugs.ruby-lang.org/issues/16640#change-84337
2020-02-22VALUE size packed callinfo (ci).Koichi Sasada
Now, rb_call_info contains how to call the method with tuple of (mid, orig_argc, flags, kwarg). Most of cases, kwarg == NULL and mid+argc+flags only requires 64bits. So this patch packed rb_call_info to VALUE (1 word) on such cases. If we can not represent it in VALUE, then use imemo_callinfo which contains conventional callinfo (rb_callinfo, renamed from rb_call_info). iseq->body->ci_kw_size is removed because all of callinfo is VALUE size (packed ci or a pointer to imemo_callinfo). To access ci information, we need to use these functions: vm_ci_mid(ci), _flag(ci), _argc(ci), _kwarg(ci). struct rb_call_info_kw_arg is renamed to rb_callinfo_kwarg. rb_funcallv_with_cc() and rb_method_basic_definition_p_with_cc() is temporary removed because cd->ci should be marked. Notes: Merged: https://github.com/ruby/ruby/pull/2888
2020-02-22`Proc` made by `Symbol#to_proc` should be a lambda [Bug #16260]Nobuyoshi Nakada
With refinements, too.
2020-01-24Do not autosplat when calling proc with empty keyword splatJeremy Evans
With the removal of the splatted argument when using an empty keyword splat, the autosplat code considered an empty keyword splat the same as no argument at all. However, that results in autosplat behavior changing dependent on the content of the splatted hash, which is not what anyone would expect or want. This change always skips an autosplat if keywords were provided. Fixes [Bug #16560] Notes: Merged: https://github.com/ruby/ruby/pull/2861
2020-01-23Remove empty keyword splats when calling even when using ruby2_keywordsJeremy Evans
Keeping empty keyword splats for ruby2_keywords methods was necessary in 2.7 to prevent the final positional hash being treated as keywords. Now that keyword argument separation has been committed, the final positional hash is never treated as keywords, so there is no need to keep empty keyword splats when using ruby2_keywords. Notes: Merged: https://github.com/ruby/ruby/pull/2857
2020-01-03Fix unused warningsKazuhiro NISHIYAMA
http://ci.rvm.jp/results/trunk_gcc7@silicon-docker/2539622 ``` /tmp/ruby/v2/src/trunk_gcc7/class.c: In function 'rb_scan_args_parse': /tmp/ruby/v2/src/trunk_gcc7/class.c:1971:12: warning: unused variable 'tmp_buffer' [-Wunused-variable] VALUE *tmp_buffer = arg->tmp_buffer; ^~~~~~~~~~ ``` ``` In file included from /tmp/ruby/v2/src/trunk_gcc7/vm_insnhelper.c:1895:0, from /tmp/ruby/v2/src/trunk_gcc7/vm.c:349: /tmp/ruby/v2/src/trunk_gcc7/vm_args.c:212:1: warning: 'args_stored_kw_argv_to_hash' defined but not used [-Wunused-function] args_stored_kw_argv_to_hash(struct args_info *args) ^~~~~~~~~~~~~~~~~~~~~~~~~~~ ```
2020-01-02Fully separate positional arguments and keyword argumentsJeremy Evans
This removes the warnings added in 2.7, and changes the behavior so that a final positional hash is not treated as keywords or vice-versa. To handle the arg_setup_block splat case correctly with keyword arguments, we need to check if we are taking a keyword hash. That case didn't have a test, but it affects real-world code, so add a test for it. This removes rb_empty_keyword_given_p() and related code, as that is not needed in Ruby 3. The empty keyword case is the same as the no keyword case in Ruby 3. This changes rb_scan_args to implement keyword argument separation for C functions when the : character is used. For backwards compatibility, it returns a duped hash. This is a bad idea for performance, but not duping the hash breaks at least Enumerator::ArithmeticSequence#inspect. Instead of having RB_PASS_CALLED_KEYWORDS be a number, simplify the code by just making it be rb_keyword_given_p(). Notes: Merged: https://github.com/ruby/ruby/pull/2794
2019-12-23Reword keyword arguments warning messages to convey these are deprecation ↵Marc-Andre Lafortune
warnings
2019-12-21Kernel#lambda: return forwarded block as non-lambda procAlan Wu
Before this commit, Kernel#lambda can't tell the difference between a directly passed literal block and one passed with an ampersand. A block passed with an ampersand is semantically speaking already a non-lambda proc. When Kernel#lambda receives a non-lambda proc, it should simply return it. Implementation wise, when the VM calls a method with a literal block, it places the code for the block on the calling control frame and passes a pointer (block handler) to the callee. Before this commit, the VM forwards block arguments by simply forwarding the block handler, which leaves the slot for block code unused when a control frame forwards its block argument. I use the vacant space to indicate that a frame has forwarded its block argument and inspect that in Kernel#lambda to detect forwarded blocks. This is a very ad-hoc solution and relies *heavily* on the way block passing works in the VM. However, it's the most self-contained solution I have. [Bug #15620] Notes: Merged: https://github.com/ruby/ruby/pull/2289
2019-12-20vm_args.c: rephrase the warning message of keyword argument separationYusuke Endoh
(old) test.rb:4: warning: The last argument is used as the keyword parameter test.rb:1: warning: for `foo' defined here; maybe ** should be added to the call? (new) test.rb:4: warning: The last argument is used as keyword parameters; maybe ** should be added to the call test.rb:1: warning: The called method `foo' is defined here
2019-12-19Manage deprecation warnings about keyword argumentNobuyoshi Nakada
2019-12-19Adjusted the formatNobuyoshi Nakada
2019-12-10vm_core.h (iseq_unique_id): prefer uintptr_t instead of unsigned longYusuke Endoh
It produced a warning about type cast in LLP64 (i.e., windows).
2019-12-09vm_args.c (rb_warn_check): Use iseq_unique_id instead of its pointerYusuke Endoh
(This is the second try of 036bc1da6c6c9b0fa9b7f5968d897a9554dd770e.) If iseq is GC'ed, the pointer of iseq may be reused, which may hide a deprecation warning of keyword argument change. http://ci.rvm.jp/results/trunk-test1@phosphorus-docker/2474221 ``` 1) Failure: TestKeywordArguments#test_explicit_super_kwsplat [/tmp/ruby/v2/src/trunk-test1/test/ruby/test_keyword.rb:549]: --- expected +++ actual @@ -1 +1 @@ -/The keyword argument is passed as the last hash parameter.* for `m'/m +"" ``` This change ad-hocly adds iseq_unique_id for each iseq, and use it instead of iseq pointer. This covers the case where caller is GC'ed. Still, the case where callee is GC'ed, is not covered. But anyway, it is very rare that iseq is GC'ed. Even when it occurs, it just hides some warnings. It's no big deal.
2019-12-09Revert "vm_args.c (rb_warn_check): Use iseq_unique_id instead of its pointer"Yusuke Endoh
This reverts commit 036bc1da6c6c9b0fa9b7f5968d897a9554dd770e. This caused a failure on iseq_binary mode. http://ci.rvm.jp/results/trunk-iseq_binary@silicon-docker/2474587 Numbering iseqs is not trivial due to dump/load.
2019-12-09Revert "vm_args.c (rb_warn_check): Use unique_id * 2 instead of unique_id"Yusuke Endoh
This reverts commit 751a9b32e5a53336768eb878de1827245a3292bf.
2019-12-09vm_args.c (rb_warn_check): Use unique_id * 2 instead of unique_idYusuke Endoh
The function assumed that the LSB of `callee` was 0.
2019-12-09vm_args.c (rb_warn_check): Use iseq_unique_id instead of its pointerYusuke Endoh
If iseq is GC'ed, the pointer of iseq may be reused, which may hide a deprecation warning of keyword argument change. http://ci.rvm.jp/results/trunk-test1@phosphorus-docker/2474221 ``` 1) Failure: TestKeywordArguments#test_explicit_super_kwsplat [/tmp/ruby/v2/src/trunk-test1/test/ruby/test_keyword.rb:549]: --- expected +++ actual @@ -1 +1 @@ -/The keyword argument is passed as the last hash parameter.* for `m'/m +"" ``` This change ad-hocly adds iseq_unique_id for each iseq, and use it instead of iseq pointer. This covers the case where caller is GC'ed. Still, the case where callee is GC'ed, is not covered. But anyway, it is very rare that iseq is GC'ed. Even when it occurs, it just hides some warnings. It's no big deal.
2019-12-03vm_args.c: make the keyword deprecation message helpfulYusuke Endoh
``` $ ./miniruby -e 'def foo(kw: 1); end; h = {kw: 1}; foo(h)' -e:1: warning: The last argument is used as the keyword parameter -e:1: warning: for `foo' defined here; maybe ** should be added to the call? ```
2019-11-29Reduce duplicated warnings for the change of Ruby 3 keyword argumentsYusuke Endoh
By this change, the following code prints only one warning. ``` def foo(**opt); end 100.times { foo({kw:1}) } ``` A global variable `st_table *caller_to_callees` is a map from caller to a set of callee methods. It remembers that a warning is already printed for each pair of caller and callee. [Feature #16289] Notes: Merged: https://github.com/ruby/ruby/pull/2458
2019-11-27Don't modify rest array when using ruby2_keywordsJeremy Evans
Previously, the rest array was modified, but it turns out that is not necessary. Not modifying the rest array fixes cases when the rest array is used more than once. Notes: Merged: https://github.com/ruby/ruby/pull/2706