|
27 | 27 | import org.truffleruby.core.Hashing;
|
28 | 28 | import org.truffleruby.core.array.ArrayEachIteratorNode.ArrayElementConsumerNode;
|
29 | 29 | import org.truffleruby.core.array.ArrayNodesFactory.ReplaceNodeFactory;
|
| 30 | +import org.truffleruby.core.array.ArrayOperationNodes.ArrayExtractRangeCopyOnWriteNode; |
30 | 31 | import org.truffleruby.core.cast.CmpIntNode;
|
| 32 | +import org.truffleruby.core.cast.ToAryNode; |
31 | 33 | import org.truffleruby.core.cast.ToAryNodeGen;
|
32 | 34 | import org.truffleruby.core.cast.ToIntNode;
|
33 | 35 | import org.truffleruby.core.cast.ToIntNodeGen;
|
@@ -328,7 +330,7 @@ public abstract static class CompactNode extends ArrayCoreMethodNode {
|
328 | 330 | @Specialization(guards = { "strategy.matches(array)", "strategy.isPrimitive()" }, limit = "STORAGE_STRATEGIES")
|
329 | 331 | protected DynamicObject compactPrimitive(DynamicObject array,
|
330 | 332 | @Cached("of(array)") ArrayStrategy strategy,
|
331 |
| - @Cached("strategy.extractRangeCopyOnWriteNode()") ArrayOperationNodes.ArrayExtractRangeCopyOnWriteNode extractRangeCopyOnWriteNode) { |
| 333 | + @Cached("strategy.extractRangeCopyOnWriteNode()") ArrayExtractRangeCopyOnWriteNode extractRangeCopyOnWriteNode) { |
332 | 334 | final int size = strategy.getSize(array);
|
333 | 335 | Object compactMirror = extractRangeCopyOnWriteNode.execute(array, 0, size);
|
334 | 336 | return createArray(compactMirror, size);
|
@@ -406,25 +408,70 @@ protected Object compactObjectsNonMutable(DynamicObject array,
|
406 | 408 |
|
407 | 409 | }
|
408 | 410 |
|
409 |
| - @CoreMethod(names = "concat", required = 1, raiseIfFrozenSelf = true) |
410 |
| - @NodeChild(value = "array", type = RubyNode.class) |
411 |
| - @NodeChild(value = "other", type = RubyNode.class) |
| 411 | + @CoreMethod(names = "concat", optional = 1, rest = true, raiseIfFrozenSelf = true) |
412 | 412 | @ImportStatic(ArrayGuards.class)
|
| 413 | + @NodeChild(value = "array", type = RubyNode.class) |
| 414 | + @NodeChild(value = "first", type = RubyNode.class) |
| 415 | + @NodeChild(value = "rest", type = RubyNode.class) |
413 | 416 | public abstract static class ConcatNode extends CoreMethodNode {
|
414 | 417 |
|
415 |
| - @Child private ArrayAppendManyNode appendManyNode = ArrayAppendManyNodeGen.create(); |
416 |
| - |
417 |
| - @CreateCast("other") |
418 |
| - protected RubyNode coerceOtherToAry(RubyNode other) { |
419 |
| - return ToAryNodeGen.create(other); |
| 418 | + @Specialization(guards = "rest.length == 0") |
| 419 | + protected DynamicObject concatZero(DynamicObject array, NotProvided first, Object[] rest) { |
| 420 | + return array; |
420 | 421 | }
|
421 | 422 |
|
422 |
| - @Specialization |
423 |
| - protected DynamicObject concat(DynamicObject array, DynamicObject other) { |
424 |
| - appendManyNode.executeAppendMany(array, other); |
| 423 | + @Specialization(guards = "rest.length == 0") |
| 424 | + protected DynamicObject concatOne(DynamicObject array, DynamicObject first, Object[] rest, |
| 425 | + @Cached("createInternal()") ToAryNode toAryNode, |
| 426 | + @Cached ArrayAppendManyNode appendManyNode) { |
| 427 | + appendManyNode.executeAppendMany(array, toAryNode.executeToAry(first)); |
425 | 428 | return array;
|
426 | 429 | }
|
427 | 430 |
|
| 431 | + @ExplodeLoop |
| 432 | + @Specialization(guards = { "wasProvided(first)", "rest.length > 0", "rest.length == cachedLength" }) |
| 433 | + protected Object concatMany(DynamicObject array, DynamicObject first, Object[] rest, |
| 434 | + @Cached("rest.length") int cachedLength, |
| 435 | + @Cached("createInternal()") ToAryNode toAryNode, |
| 436 | + @Cached ArrayAppendManyNode appendManyNode, |
| 437 | + @Cached("createBinaryProfile()") ConditionProfile selfArgProfile, |
| 438 | + @Cached("of(array)") ArrayStrategy strategy, |
| 439 | + @Cached("strategy.extractRangeCopyOnWriteNode()") ArrayExtractRangeCopyOnWriteNode extractRangeNode) { |
| 440 | + int size = Layouts.ARRAY.getSize(array); |
| 441 | + Object store = extractRangeNode.execute(array, 0, size); |
| 442 | + DynamicObject copy = createArray(store, size); |
| 443 | + DynamicObject result = appendManyNode.executeAppendMany(array, toAryNode.executeToAry(first)); |
| 444 | + for (int i = 0; i < cachedLength; ++i) { |
| 445 | + if (selfArgProfile.profile(rest[i] == array)) { |
| 446 | + result = appendManyNode.executeAppendMany(array, copy); |
| 447 | + } else { |
| 448 | + result = appendManyNode.executeAppendMany(array, toAryNode.executeToAry(rest[i])); |
| 449 | + } |
| 450 | + } |
| 451 | + return result; |
| 452 | + } |
| 453 | + |
| 454 | + /** Same implementation as {@link #concatMany}, safe for the use of {@code cachedLength} */ |
| 455 | + @Specialization(guards = { "wasProvided(first)", "rest.length > 0" }, replaces = "concatMany") |
| 456 | + protected Object concatManyGeneral(DynamicObject array, DynamicObject first, Object[] rest, |
| 457 | + @Cached("createInternal()") ToAryNode toAryNode, |
| 458 | + @Cached ArrayAppendManyNode appendManyNode, |
| 459 | + @Cached("createBinaryProfile()") ConditionProfile selfArgProfile, |
| 460 | + @Cached("of(array)") ArrayStrategy strategy, |
| 461 | + @Cached("strategy.extractRangeCopyOnWriteNode()") ArrayExtractRangeCopyOnWriteNode extractRangeNode) { |
| 462 | + int size = Layouts.ARRAY.getSize(array); |
| 463 | + Object store = extractRangeNode.execute(array, 0, size); |
| 464 | + |
| 465 | + DynamicObject result = appendManyNode.executeAppendMany(array, toAryNode.executeToAry(first)); |
| 466 | + for (Object arg : rest) { |
| 467 | + if (selfArgProfile.profile(arg == array)) { |
| 468 | + result = appendManyNode.executeAppendMany(array, createArray(store, size)); |
| 469 | + } else { |
| 470 | + result = appendManyNode.executeAppendMany(array, toAryNode.executeToAry(arg)); |
| 471 | + } |
| 472 | + } |
| 473 | + return result; |
| 474 | + } |
428 | 475 | }
|
429 | 476 |
|
430 | 477 | @CoreMethod(names = "delete", required = 1, needsBlock = true)
|
@@ -1635,7 +1682,7 @@ protected RubyNode coerceOtherToAry(RubyNode index) {
|
1635 | 1682 | protected DynamicObject replace(DynamicObject array, DynamicObject other,
|
1636 | 1683 | @Cached("of(array)") ArrayStrategy arrayStrategy,
|
1637 | 1684 | @Cached("of(other)") ArrayStrategy otherStrategy,
|
1638 |
| - @Cached("otherStrategy.extractRangeCopyOnWriteNode()") ArrayOperationNodes.ArrayExtractRangeCopyOnWriteNode extractRangeCopyOnWriteNode) { |
| 1685 | + @Cached("otherStrategy.extractRangeCopyOnWriteNode()") ArrayExtractRangeCopyOnWriteNode extractRangeCopyOnWriteNode) { |
1639 | 1686 | propagateSharingNode.propagate(array, other);
|
1640 | 1687 |
|
1641 | 1688 | final int size = getSize(other);
|
@@ -1830,7 +1877,7 @@ protected Object shiftEmpty(DynamicObject array, NotProvided n) {
|
1830 | 1877 | @Specialization(guards = { "strategy.matches(array)", "!isEmptyArray(array)" }, limit = "STORAGE_STRATEGIES")
|
1831 | 1878 | protected Object shiftOther(DynamicObject array, NotProvided n,
|
1832 | 1879 | @Cached("of(array)") ArrayStrategy strategy,
|
1833 |
| - @Cached("strategy.extractRangeCopyOnWriteNode()") ArrayOperationNodes.ArrayExtractRangeCopyOnWriteNode extractRangeCopyOnWriteNode, |
| 1880 | + @Cached("strategy.extractRangeCopyOnWriteNode()") ArrayExtractRangeCopyOnWriteNode extractRangeCopyOnWriteNode, |
1834 | 1881 | @Cached("strategy.getNode()") ArrayOperationNodes.ArrayGetNode getNode) {
|
1835 | 1882 | final int size = strategy.getSize(array);
|
1836 | 1883 | final Object value = getNode.execute(Layouts.ARRAY.getStore(array), 0);
|
@@ -1862,8 +1909,8 @@ protected Object shiftManyEmpty(DynamicObject array, int n) {
|
1862 | 1909 | limit = "STORAGE_STRATEGIES")
|
1863 | 1910 | protected Object shiftMany(DynamicObject array, int n,
|
1864 | 1911 | @Cached("of(array)") ArrayStrategy strategy,
|
1865 |
| - @Cached("strategy.extractRangeCopyOnWriteNode()") ArrayOperationNodes.ArrayExtractRangeCopyOnWriteNode extractRangeCopyOnWriteNode1, |
1866 |
| - @Cached("strategy.sharedStorageStrategy().extractRangeCopyOnWriteNode()") ArrayOperationNodes.ArrayExtractRangeCopyOnWriteNode extractRangeCopyOnWriteNode2, |
| 1912 | + @Cached("strategy.extractRangeCopyOnWriteNode()") ArrayExtractRangeCopyOnWriteNode extractRangeCopyOnWriteNode1, |
| 1913 | + @Cached("strategy.sharedStorageStrategy().extractRangeCopyOnWriteNode()") ArrayExtractRangeCopyOnWriteNode extractRangeCopyOnWriteNode2, |
1867 | 1914 | @Cached("createBinaryProfile()") ConditionProfile minProfile) {
|
1868 | 1915 | final int size = strategy.getSize(array);
|
1869 | 1916 | final int numShift = minProfile.profile(size < n) ? size : n;
|
|
0 commit comments