Skip to content

Commit e05a506

Browse files
committed
[GR-53439] Change splitting strategy for some core methods
PullRequest: truffleruby/4262
2 parents 6e7fc94 + c591268 commit e05a506

File tree

9 files changed

+73
-17
lines changed

9 files changed

+73
-17
lines changed

src/main/java/org/truffleruby/core/array/ArrayAppendOneNode.java

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import com.oracle.truffle.api.dsl.Bind;
2323
import com.oracle.truffle.api.dsl.Cached;
24+
import com.oracle.truffle.api.dsl.Cached.Exclusive;
2425
import com.oracle.truffle.api.dsl.ImportStatic;
2526
import com.oracle.truffle.api.dsl.NodeChild;
2627
import com.oracle.truffle.api.dsl.Specialization;
@@ -46,7 +47,7 @@ public static ArrayAppendOneNode create() {
4647
// Append of the correct type
4748

4849
@Specialization(
49-
guards = { "stores.acceptsValue(store, value)" },
50+
guards = "stores.acceptsValue(store, value)",
5051
limit = "storageStrategyLimit()")
5152
RubyArray appendOneSameType(RubyArray array, Object value,
5253
@Bind("array.getStore()") Object store,
@@ -68,15 +69,34 @@ RubyArray appendOneSameType(RubyArray array, Object value,
6869
return array;
6970
}
7071

72+
// Append to an empty array
73+
74+
@ReportPolymorphism.Exclude
75+
@Specialization(
76+
guards = "isZeroLengthArrayStore(array.getStore())",
77+
limit = "storageStrategyLimit()")
78+
RubyArray appendOneToEmptyArray(RubyArray array, Object value,
79+
@Bind("array.getStore()") Object currentStore,
80+
@CachedLibrary("currentStore") ArrayStoreLibrary currentStores,
81+
@CachedLibrary(limit = "storageStrategyLimit()") @Exclusive ArrayStoreLibrary newStores) {
82+
final int newCapacity = ArrayUtils.capacityForOneMore(getLanguage(), 0);
83+
final Object newStore = currentStores.allocateForNewValue(currentStore, value, newCapacity);
84+
newStores.write(newStore, 0, value);
85+
setStoreAndSize(array, newStore, 1);
86+
return array;
87+
}
88+
7189
// Append forcing a generalization
7290

7391
@Specialization(
74-
guards = "!currentStores.acceptsValue(array.getStore(), value)",
92+
guards = {
93+
"!isZeroLengthArrayStore(array.getStore())",
94+
"!currentStores.acceptsValue(array.getStore(), value)" },
7595
limit = "storageStrategyLimit()")
7696
RubyArray appendOneGeneralizeNonMutable(RubyArray array, Object value,
7797
@Bind("array.getStore()") Object currentStore,
7898
@CachedLibrary("currentStore") ArrayStoreLibrary currentStores,
79-
@CachedLibrary(limit = "storageStrategyLimit()") ArrayStoreLibrary newStores) {
99+
@CachedLibrary(limit = "storageStrategyLimit()") @Exclusive ArrayStoreLibrary newStores) {
80100
final int oldSize = array.size;
81101
final int newSize = oldSize + 1;
82102
final int oldCapacity = currentStores.capacity(currentStore);

src/main/java/org/truffleruby/core/array/ArrayGuards.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
package org.truffleruby.core.array;
1111

1212
import org.truffleruby.RubyLanguage;
13+
import org.truffleruby.core.array.library.ArrayStoreLibrary;
1314
import org.truffleruby.core.array.library.ZeroLengthArrayStore;
1415

1516
public final class ArrayGuards {
@@ -41,4 +42,8 @@ public static boolean basicStore(Object store) {
4142
public static boolean zeroLengthStore(Object store) {
4243
return store == ZeroLengthArrayStore.ZERO_LENGTH_STORE;
4344
}
45+
46+
public static boolean isZeroLengthArrayStore(Object store) {
47+
return store == ZeroLengthArrayStore.ZERO_LENGTH_STORE || store == ArrayStoreLibrary.SHARED_INITIAL_STORE;
48+
}
4449
}

src/main/java/org/truffleruby/core/array/ArrayNodes.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1712,7 +1712,7 @@ Object popNToInt(RubyArray array, Object n,
17121712

17131713
}
17141714

1715-
@CoreMethod(names = "<<", raiseIfFrozenSelf = true, required = 1)
1715+
@CoreMethod(names = "<<", raiseIfFrozenSelf = true, required = 1, split = Split.ALWAYS)
17161716
public abstract static class AppendNode extends ArrayCoreMethodNode {
17171717

17181718
@Child private ArrayAppendOneNode appendOneNode = ArrayAppendOneNode.create();

src/main/java/org/truffleruby/core/array/library/ArrayStoreLibrary.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public abstract class ArrayStoreLibrary extends Library {
3434
private static final Object INITIAL_STORE = ZeroLengthArrayStore.ZERO_LENGTH_STORE;
3535
private static final ArrayAllocator INITIAL_ALLOCATOR = ZeroLengthArrayStore.ZERO_LENGTH_ALLOCATOR;
3636

37-
private static final Object SHARED_INITIAL_STORE = new SharedArrayStorage(ZeroLengthArrayStore.ZERO_LENGTH_STORE);
37+
public static final Object SHARED_INITIAL_STORE = new SharedArrayStorage(ZeroLengthArrayStore.ZERO_LENGTH_STORE);
3838
private static final ArrayAllocator SHARED_INITIAL_ALLOCATOR = SharedArrayStorage.SHARED_ZERO_LENGTH_ARRAY_ALLOCATOR;
3939

4040
private static final LibraryFactory<ArrayStoreLibrary> FACTORY = LibraryFactory.resolve(ArrayStoreLibrary.class);

src/main/java/org/truffleruby/core/basicobject/BasicObjectNodes.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,17 @@ boolean not(Object value,
106106

107107
}
108108

109-
@CoreMethod(names = "!=", required = 1)
110-
public abstract static class NotEqualNode extends CoreMethodArrayArgumentsNode {
111-
112-
@Child private DispatchNode equalNode = DispatchNode.create();
109+
// Needed to split since it calls `==`. But seems a bit expensive to split, so it should be AlwaysInlinedMethodNode.
110+
@GenerateUncached
111+
@CoreMethod(names = "!=", required = 1, alwaysInlined = true)
112+
public abstract static class NotEqualNode extends AlwaysInlinedMethodNode {
113113

114114
@Specialization
115-
boolean equal(VirtualFrame frame, Object a, Object b,
116-
@Cached BooleanCastNode booleanCastNode) {
117-
return !booleanCastNode.execute(this, equalNode.call(a, "==", b));
115+
boolean equal(Frame frame, Object self, Object[] rubyArgs, RootCallTarget target,
116+
@Cached BooleanCastNode booleanCastNode,
117+
@Cached DispatchNode equalNode) {
118+
final Object object = RubyArguments.getArgument(rubyArgs, 0);
119+
return !booleanCastNode.execute(this, equalNode.call(self, "==", object));
118120
}
119121

120122
}
@@ -126,7 +128,6 @@ boolean equal(VirtualFrame frame, Object a, Object b,
126128
@CoreMethod(names = { "equal?", "==" }, required = 1)
127129
public abstract static class BasicObjectEqualNode extends CoreMethodArrayArgumentsNode {
128130

129-
130131
@Specialization
131132
boolean equal(Object a, Object b,
132133
@Cached ReferenceEqualNode referenceEqualNode) {

src/main/java/org/truffleruby/core/proc/ProcNodes.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import com.oracle.truffle.api.strings.TruffleString;
1818
import org.truffleruby.RubyLanguage;
1919
import org.truffleruby.annotations.CoreMethod;
20+
import org.truffleruby.annotations.Split;
2021
import org.truffleruby.builtins.CoreMethodArrayArgumentsNode;
2122
import org.truffleruby.annotations.CoreModule;
2223
import org.truffleruby.annotations.Primitive;
@@ -60,7 +61,7 @@ RubyProc allocate(RubyClass rubyClass) {
6061
}
6162
}
6263

63-
@CoreMethod(names = "new", constructor = true, needsBlock = true, rest = true)
64+
@CoreMethod(names = "new", constructor = true, needsBlock = true, rest = true, split = Split.HEURISTIC)
6465
public abstract static class ProcNewNode extends CoreMethodArrayArgumentsNode {
6566

6667
@NeverDefault

src/main/ruby/truffleruby/core/kernel.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ def exit!(code = 1)
319319
def extend(*modules)
320320
raise ArgumentError, 'wrong number of arguments (0 for 1+)' if modules.empty?
321321

322-
modules.reverse_each do |mod|
322+
block = proc do |mod|
323323
if !Primitive.is_a?(mod, Module) or Primitive.is_a?(mod, Class)
324324
raise TypeError, "wrong argument type #{Primitive.class(mod)} (expected Module)"
325325
elsif Primitive.is_a?(mod, Refinement)
@@ -329,8 +329,16 @@ def extend(*modules)
329329
mod.__send__ :extend_object, self
330330
mod.__send__ :extended, self
331331
end
332+
333+
# __send__ calls above report polymorphism because they see different singleton classes for each module instance.
334+
# But these methods are called only once per object and module pair, so it is not worth to split for them.
335+
Truffle::Graal.never_split block
336+
337+
modules.reverse_each(&block)
338+
332339
self
333340
end
341+
Truffle::Graal.never_split instance_method(:extend)
334342

335343
def getc
336344
$stdin.getc

src/main/ruby/truffleruby/core/module.rb

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,12 @@ def include?(mod)
7878

7979
def include(*modules)
8080
raise ArgumentError, 'wrong number of arguments (given 0, expected 1+)' if modules.empty?
81+
8182
if Primitive.is_a?(self, Refinement)
8283
raise TypeError, 'Refinement#include has been removed'
8384
end
84-
modules.reverse_each do |mod|
85+
86+
block = proc do |mod|
8587
if !Primitive.is_a?(mod, Module) or Primitive.is_a?(mod, Class)
8688
raise TypeError, "wrong argument type #{Primitive.class(mod)} (expected Module)"
8789
end
@@ -93,15 +95,25 @@ def include(*modules)
9395
mod.__send__ :append_features, self
9496
mod.__send__ :included, self
9597
end
98+
99+
# __send__ calls above report polymorphism because they see different singleton classes for each module instance.
100+
# But these methods are called only once per object and module pair, so it is not worth to split for them.
101+
Truffle::Graal.never_split block
102+
103+
modules.reverse_each(&block)
104+
96105
self
97106
end
107+
Truffle::Graal.never_split instance_method(:include)
98108

99109
def prepend(*modules)
100110
raise ArgumentError, 'wrong number of arguments (given 0, expected 1+)' if modules.empty?
111+
101112
if Primitive.is_a?(self, Refinement)
102113
raise TypeError, 'Refinement#prepend has been removed'
103114
end
104-
modules.reverse_each do |mod|
115+
116+
block = proc do |mod|
105117
if !Primitive.is_a?(mod, Module) or Primitive.is_a?(mod, Class)
106118
raise TypeError, "wrong argument type #{Primitive.class(mod)} (expected Module)"
107119
end
@@ -113,8 +125,16 @@ def prepend(*modules)
113125
mod.__send__ :prepend_features, self
114126
mod.__send__ :prepended, self
115127
end
128+
129+
# __send__ calls above report polymorphism because they see different singleton classes for each module instance.
130+
# But these methods are called only once per object and module pair, so it is not worth to split for them.
131+
Truffle::Graal.never_split block
132+
133+
modules.reverse_each(&block)
134+
116135
self
117136
end
137+
Truffle::Graal.never_split instance_method(:prepend)
118138

119139
def const_defined?(name, inherit = true)
120140
Primitive.module_const_defined?(self, name, inherit, true)

src/main/ruby/truffleruby/core/pre.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ module Kernel
8282
def define_singleton_method(*args, &block)
8383
singleton_class.define_method(*args, &block)
8484
end
85+
Truffle::Graal.never_split instance_method(:define_singleton_method)
8586

8687
def extend(mod)
8788
mod.__send__ :extend_object, self

0 commit comments

Comments
 (0)