diff options
| author | Jeremy Evans <code@jeremyevans.net> | 2024-06-19 11:27:01 -0700 |
|---|---|---|
| committer | Jeremy Evans <code@jeremyevans.net> | 2024-07-10 14:45:38 -0700 |
| commit | 0ee3960685e283d8e75149a8777eb0109d41509a (patch) | |
| tree | 4fc0e7fa2279ef99a80fc439dd5d682d64afcae6 /test/ruby | |
| parent | 48e7112baaf338fa350f68f0386e05085d26606c (diff) | |
Eliminate array allocations for single splat followed by mutable keywords
For calls such as:
m(*ary, a: 2, **h)
m(*ary, **h, **h, **h)
Where m does not take a positional argument splat, there was previously
an array allocation (splatarray true) to dup ary, even though it was not
necessary to do so. This is because the elimination of the array allocation
(splatarray false) was performed in the optimizer, and the optimizer didn't
handle this case, because the instructions for the keywords can be of
arbitrary length.
Move part of the optimization from the optimizer to the compiler,
detecting parse trees of the form:
ARGS_PUSH:
head: SPLAT
tail: HASH (without brace)
And using splatarray false instead of splatarray true for them.
Unfortunately, moving part of the optimization to the compiler broke
the hash allocation elimination optimization for calls of the
form:
m(*ary, a: 2)
That's because the compiler had already set splatarray false,
and the optimizer code was looking for splatarray true.
Split the array allocation elimination and hash allocation
elimination in the optimizer so that the hash allocation
elimination will still apply if the compiler performs the
splatarray false optimization.
Diffstat (limited to 'test/ruby')
| -rw-r--r-- | test/ruby/test_allocation.rb | 55 |
1 files changed, 25 insertions, 30 deletions
diff --git a/test/ruby/test_allocation.rb b/test/ruby/test_allocation.rb index ee489d94a7..6534c123fb 100644 --- a/test/ruby/test_allocation.rb +++ b/test/ruby/test_allocation.rb @@ -273,16 +273,11 @@ class TestAllocation < Test::Unit::TestCase check_allocations(0, 1, "keyword(**hash1, **empty_hash#{block})") check_allocations(1, 0, "keyword(*empty_array, *empty_array, **empty_hash#{block})") - check_allocations(0, 0, "keyword(*empty_array#{block})") - check_allocations(0, 1, "keyword(**hash1, **empty_hash#{block})") - check_allocations(1, 0, "keyword(*empty_array, *empty_array, **empty_hash#{block})") - check_allocations(1, 0, "keyword(*r2k_empty_array#{block})") check_allocations(1, 1, "keyword(*r2k_array#{block})") - # Currently allocates 1 array unnecessarily due to splatarray true - check_allocations(1, 1, "keyword(*empty_array, a: 2, **empty_hash#{block})") - check_allocations(1, 1, "keyword(*empty_array, **hash1, **empty_hash#{block})") + check_allocations(0, 1, "keyword(*empty_array, a: 2, **empty_hash#{block})") + check_allocations(0, 1, "keyword(*empty_array, **hash1, **empty_hash#{block})") RUBY end @@ -314,8 +309,8 @@ class TestAllocation < Test::Unit::TestCase check_allocations(1, 1, "keyword_splat(*r2k_array#{block})") # Currently allocates 1 array unnecessarily due to splatarray true - check_allocations(1, 1, "keyword_splat(*empty_array, a: 2, **empty_hash#{block})") - check_allocations(1, 1, "keyword_splat(*empty_array, **hash1, **empty_hash#{block})") + check_allocations(0, 1, "keyword_splat(*empty_array, a: 2, **empty_hash#{block})") + check_allocations(0, 1, "keyword_splat(*empty_array, **hash1, **empty_hash#{block})") RUBY end @@ -346,9 +341,8 @@ class TestAllocation < Test::Unit::TestCase check_allocations(1, 1, "keyword_and_keyword_splat(*r2k_empty_array#{block})") check_allocations(1, 1, "keyword_and_keyword_splat(*r2k_array#{block})") - # Currently allocates 1 array unnecessarily due to splatarray true - check_allocations(1, 1, "keyword_and_keyword_splat(*empty_array, a: 2, **empty_hash#{block})") - check_allocations(1, 1, "keyword_and_keyword_splat(*empty_array, **hash1, **empty_hash#{block})") + check_allocations(0, 1, "keyword_and_keyword_splat(*empty_array, a: 2, **empty_hash#{block})") + check_allocations(0, 1, "keyword_and_keyword_splat(*empty_array, **hash1, **empty_hash#{block})") RUBY end @@ -391,9 +385,10 @@ class TestAllocation < Test::Unit::TestCase # Currently allocates 1 array unnecessarily due to splatarray true check_allocations(1, 1, "required_and_keyword(1, *empty_array, a: 2, **empty_hash#{block})") check_allocations(1, 1, "required_and_keyword(1, *empty_array, **hash1, **empty_hash#{block})") - check_allocations(1, 1, "required_and_keyword(*array1, **empty_hash, a: 2#{block})") - check_allocations(1, 1, "required_and_keyword(*array1, **hash1, **empty_hash#{block})") - check_allocations(1, 0, "required_and_keyword(*array1, **nil#{block})") + + check_allocations(0, 1, "required_and_keyword(*array1, **empty_hash, a: 2#{block})") + check_allocations(0, 1, "required_and_keyword(*array1, **hash1, **empty_hash#{block})") + check_allocations(0, 0, "required_and_keyword(*array1, **nil#{block})") RUBY end @@ -482,9 +477,9 @@ class TestAllocation < Test::Unit::TestCase # Currently allocates 1 array unnecessarily due to splatarray true check_allocations(1, 1, "required_and_keyword_splat(1, *empty_array, a: 2, **empty_hash#{block})") check_allocations(1, 1, "required_and_keyword_splat(1, *empty_array, **hash1, **empty_hash#{block})") - check_allocations(1, 1, "required_and_keyword_splat(*array1, **empty_hash, a: 2#{block})") - check_allocations(1, 1, "required_and_keyword_splat(*array1, **hash1, **empty_hash#{block})") - check_allocations(1, 1, "required_and_keyword_splat(*array1, **nil#{block})") + check_allocations(0, 1, "required_and_keyword_splat(*array1, **empty_hash, a: 2#{block})") + check_allocations(0, 1, "required_and_keyword_splat(*array1, **hash1, **empty_hash#{block})") + check_allocations(0, 1, "required_and_keyword_splat(*array1, **nil#{block})") RUBY end @@ -569,9 +564,9 @@ class TestAllocation < Test::Unit::TestCase check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(1, *empty_array, a: 2, **empty_hash#{block})") check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(1, *empty_array, **hash1, **empty_hash#{block})") - check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(*array1, **empty_hash, a: 2#{block})") - check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(*array1, **hash1, **empty_hash#{block})") - check_allocations(1, 0, "anon_splat_and_anon_keyword_splat(*array1, **nil#{block})") + check_allocations(0, 1, "anon_splat_and_anon_keyword_splat(*array1, **empty_hash, a: 2#{block})") + check_allocations(0, 1, "anon_splat_and_anon_keyword_splat(*array1, **hash1, **empty_hash#{block})") + check_allocations(0, 0, "anon_splat_and_anon_keyword_splat(*array1, **nil#{block})") check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(*r2k_empty_array#{block})") check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(*r2k_array#{block})") @@ -615,9 +610,9 @@ class TestAllocation < Test::Unit::TestCase check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(1, *empty_array, a: 2, **empty_hash#{block})") check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(1, *empty_array, **hash1, **empty_hash#{block})") - check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(*array1, **empty_hash, a: 2#{block})") - check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(*array1, **hash1, **empty_hash#{block})") - check_allocations(1, 0, "anon_splat_and_anon_keyword_splat(*array1, **nil#{block})") + check_allocations(0, 1, "anon_splat_and_anon_keyword_splat(*array1, **empty_hash, a: 2#{block})") + check_allocations(0, 1, "anon_splat_and_anon_keyword_splat(*array1, **hash1, **empty_hash#{block})") + check_allocations(0, 0, "anon_splat_and_anon_keyword_splat(*array1, **nil#{block})") check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(*r2k_empty_array#{block})") check_allocations(1, 1, "anon_splat_and_anon_keyword_splat(*r2k_array#{block})") @@ -661,9 +656,9 @@ class TestAllocation < Test::Unit::TestCase check_allocations(1, 1, "argument_forwarding(1, *empty_array, a: 2, **empty_hash#{block})") check_allocations(1, 1, "argument_forwarding(1, *empty_array, **hash1, **empty_hash#{block})") - check_allocations(1, 1, "argument_forwarding(*array1, **empty_hash, a: 2#{block})") - check_allocations(1, 1, "argument_forwarding(*array1, **hash1, **empty_hash#{block})") - check_allocations(1, 0, "argument_forwarding(*array1, **nil#{block})") + check_allocations(0, 1, "argument_forwarding(*array1, **empty_hash, a: 2#{block})") + check_allocations(0, 1, "argument_forwarding(*array1, **hash1, **empty_hash#{block})") + check_allocations(0, 0, "argument_forwarding(*array1, **nil#{block})") check_allocations(0, 0, "argument_forwarding(*r2k_empty_array#{block})") check_allocations(0, 0, "argument_forwarding(*r2k_array#{block})") @@ -707,9 +702,9 @@ class TestAllocation < Test::Unit::TestCase check_allocations(1, 1, "argument_forwarding(1, *empty_array, a: 2, **empty_hash#{block})") check_allocations(1, 1, "argument_forwarding(1, *empty_array, **hash1, **empty_hash#{block})") - check_allocations(1, 1, "argument_forwarding(*array1, **empty_hash, a: 2#{block})") - check_allocations(1, 1, "argument_forwarding(*array1, **hash1, **empty_hash#{block})") - check_allocations(1, 0, "argument_forwarding(*array1, **nil#{block})") + check_allocations(0, 1, "argument_forwarding(*array1, **empty_hash, a: 2#{block})") + check_allocations(0, 1, "argument_forwarding(*array1, **hash1, **empty_hash#{block})") + check_allocations(0, 0, "argument_forwarding(*array1, **nil#{block})") check_allocations(0, 0, "argument_forwarding(*r2k_empty_array#{block})") check_allocations(0, 0, "argument_forwarding(*r2k_array#{block})") |
