Skip to content

Commit 5c7903e

Browse files
committed
[GR-32001] Always-inline Kernel#respond_to? and Kernel#respond_to_missing?
PullRequest: truffleruby/3301
2 parents 0dd26d5 + 484a614 commit 5c7903e

33 files changed

+144
-171
lines changed

spec/truffle/always_inlined_spec.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@
2020
}.should raise_error(TypeError) { |e| e.backtrace_locations[0].label.should == 'public_send' }
2121
end
2222

23+
it "for #respond_to?" do
24+
-> {
25+
respond_to?()
26+
}.should raise_error(ArgumentError) { |e| e.backtrace_locations[0].label.should == 'respond_to?' }
27+
-> {
28+
respond_to?(Object.new)
29+
}.should raise_error(TypeError) { |e| e.backtrace_locations[0].label.should == 'respond_to?' }
30+
end
31+
2332
it "for #block_given?" do
2433
-> {
2534
block_given?(:wrong)
@@ -191,6 +200,19 @@
191200
end
192201

193202
guard -> { RUBY_ENGINE != "ruby" } do
203+
it "for #respond_to?" do
204+
obj = Object.new
205+
def obj.respond_to_missing?(name, priv)
206+
name == :foo ? raise("foo") : super
207+
end
208+
-> {
209+
obj.respond_to?(:foo)
210+
}.should raise_error(RuntimeError, "foo") { |e|
211+
e.backtrace_locations[0].label.should == 'respond_to_missing?'
212+
e.backtrace_locations[1].label.should.start_with?('block (5 levels)')
213+
}
214+
end
215+
194216
it "for Method#call" do
195217
def method_to_call
196218
raise "foo"

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

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import org.graalvm.collections.EconomicSet;
2222
import org.graalvm.collections.Equivalence;
2323
import org.truffleruby.Layouts;
24-
import org.truffleruby.RubyLanguage;
2524
import org.truffleruby.builtins.CoreMethod;
2625
import org.truffleruby.builtins.CoreMethodArrayArgumentsNode;
2726
import org.truffleruby.builtins.CoreMethodNode;
@@ -1263,7 +1262,7 @@ protected RubyArray initializeFromArray(
12631262
guards = { "!isImplicitLong(object)", "wasProvided(object)", "!isRubyArray(object)" })
12641263
protected RubyArray initialize(RubyArray array, Object object, NotProvided unusedValue, Nil block) {
12651264
RubyArray copy = null;
1266-
if (respondToToAry(getLanguage(), object)) {
1265+
if (respondToToAry(object)) {
12671266
Object toAryResult = callToAry(object);
12681267
if (toAryResult instanceof RubyArray) {
12691268
copy = (RubyArray) toAryResult;
@@ -1278,13 +1277,12 @@ protected RubyArray initialize(RubyArray array, Object object, NotProvided unuse
12781277
}
12791278
}
12801279

1281-
public boolean respondToToAry(RubyLanguage language, Object object) {
1280+
public boolean respondToToAry(Object object) {
12821281
if (respondToToAryNode == null) {
12831282
CompilerDirectives.transferToInterpreterAndInvalidate();
1284-
respondToToAryNode = insert(KernelNodesFactory.RespondToNodeFactory.create(null, null, null));
1283+
respondToToAryNode = insert(KernelNodesFactory.RespondToNodeFactory.create());
12851284
}
1286-
return respondToToAryNode
1287-
.executeDoesRespondTo(null, object, language.coreStrings.TO_ARY.createInstance(getContext()), true);
1285+
return respondToToAryNode.executeDoesRespondTo(object, coreSymbols().TO_ARY, true);
12881286
}
12891287

12901288
protected Object callToAry(Object object) {
@@ -1792,7 +1790,7 @@ protected Object reject(RubyArray array, RubyProc block,
17921790
for (; loopProfile.inject(n < arraySizeProfile.profile(array.size)); n++) {
17931791
final Object value = stores.read(store, n);
17941792

1795-
if (!booleanCastNode.executeToBoolean(callBlock(block, value))) {
1793+
if (!booleanCastNode.execute(callBlock(block, value))) {
17961794
arrayBuilder.appendValue(state, selectedSize, value);
17971795
selectedSize++;
17981796
}
@@ -1858,7 +1856,7 @@ private Object rejectInPlaceInternal(RubyArray array, RubyProc block, ArrayStore
18581856
try {
18591857
for (; loop1Profile.inject(n < arraySizeProfile.profile(array.size)); n++) {
18601858
final Object value = stores.read(store, n);
1861-
if (booleanCastNode.executeToBoolean(callBlock(block, value))) {
1859+
if (booleanCastNode.execute(callBlock(block, value))) {
18621860
continue;
18631861
}
18641862

@@ -2082,7 +2080,7 @@ protected Object select(RubyArray array, RubyProc block,
20822080
for (; loopProfile.inject(n < arraySizeProfile.profile(array.size)); n++) {
20832081
final Object value = stores.read(store, n);
20842082

2085-
if (booleanCastNode.executeToBoolean(callBlock(block, value))) {
2083+
if (booleanCastNode.execute(callBlock(block, value))) {
20862084
arrayBuilder.appendValue(state, selectedSize, value);
20872085
selectedSize++;
20882086
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public abstract static class NotNode extends UnaryCoreMethodNode {
9090
@Specialization
9191
protected boolean not(Object value,
9292
@Cached BooleanCastNode cast) {
93-
return !cast.executeToBoolean(value);
93+
return !cast.execute(value);
9494
}
9595

9696
}
@@ -103,7 +103,7 @@ public abstract static class NotEqualNode extends CoreMethodArrayArgumentsNode {
103103

104104
@Specialization
105105
protected boolean equal(VirtualFrame frame, Object a, Object b) {
106-
return !booleanCastNode.executeToBoolean(equalNode.call(a, "==", b));
106+
return !booleanCastNode.execute(equalNode.call(a, "==", b));
107107
}
108108

109109
}

src/main/java/org/truffleruby/core/bool/FalseClassNodes.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public abstract static class OrXorNode extends UnaryCoreMethodNode {
3535
@Specialization
3636
protected boolean orXor(Object other,
3737
@Cached BooleanCastNode cast) {
38-
return cast.executeToBoolean(other);
38+
return cast.execute(other);
3939
}
4040

4141
}

src/main/java/org/truffleruby/core/bool/TrueClassNodes.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public abstract static class AndNode extends UnaryCoreMethodNode {
2727
@Specialization
2828
protected boolean and(Object other,
2929
@Cached BooleanCastNode cast) {
30-
return cast.executeToBoolean(other);
30+
return cast.execute(other);
3131
}
3232
}
3333

@@ -46,7 +46,7 @@ public abstract static class XorNode extends UnaryCoreMethodNode {
4646
@Specialization
4747
protected boolean xor(Object other,
4848
@Cached BooleanCastNode cast) {
49-
return !cast.executeToBoolean(other);
49+
return !cast.execute(other);
5050
}
5151
}
5252

src/main/java/org/truffleruby/core/cast/BooleanCastNode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ public static BooleanCastNode create() {
3636
}
3737

3838
/** Execute with child node */
39-
public abstract boolean executeBoolean(VirtualFrame frame);
39+
public abstract boolean execute(VirtualFrame frame);
4040

4141
/** Execute with given value */
42-
public abstract boolean executeToBoolean(Object value);
42+
public abstract boolean execute(Object value);
4343

4444
@Specialization
4545
protected boolean doNil(Nil nil) {

src/main/java/org/truffleruby/core/cast/BooleanCastWithDefaultNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ protected boolean doDefault(NotProvided value) {
3939
@Fallback
4040
protected boolean fallback(Object value,
4141
@Cached BooleanCastNode booleanCastNode) {
42-
return booleanCastNode.executeToBoolean(value);
42+
return booleanCastNode.execute(value);
4343
}
4444

4545
}

src/main/java/org/truffleruby/core/cast/CmpIntNode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,11 @@ protected int cmpObject(Object value, Object receiver, Object other,
8484
@Cached BooleanCastNode gtCastNode,
8585
@Cached BooleanCastNode ltCastNode) {
8686

87-
if (gtCastNode.executeToBoolean(gtNode.call(value, ">", 0))) {
87+
if (gtCastNode.execute(gtNode.call(value, ">", 0))) {
8888
return 1;
8989
}
9090

91-
if (ltCastNode.executeToBoolean(ltNode.call(value, "<", 0))) {
91+
if (ltCastNode.execute(ltNode.call(value, "<", 0))) {
9292
return -1;
9393
}
9494

src/main/java/org/truffleruby/core/hash/library/PackedHashStoreLibrary.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ private boolean callEqual(Object receiver, Object key) {
546546
booleanCastNode = insert(BooleanCastNode.create());
547547
}
548548

549-
return booleanCastNode.executeToBoolean(equalNode.call(receiver, "eql?", key));
549+
return booleanCastNode.execute(equalNode.call(receiver, "eql?", key));
550550
}
551551
}
552552

src/main/java/org/truffleruby/core/inlined/AlwaysInlinedMethodNode.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@
1919
import org.truffleruby.language.control.RaiseException;
2020

2121
/** A core method that should always be executed inline, without going through a CallTarget. That enables accessing the
22-
* caller frame efficiently and reliably.
22+
* caller frame efficiently and reliably. It also means there is a copy/"split" of that core method for every call site.
2323
* <p>
2424
* If called from a foreign language, then the caller frame will be null. The node should check using
25-
* {@link #needCallerFrame(Frame, RootCallTarget)} that the caller frame is not null before using it (if it uses it), in
26-
* order to provide a useful exception in that case.
25+
* {@link #needCallerFrame(Frame, RootCallTarget)} that the caller frame is not null before using it (if it needs it),
26+
* in order to provide a useful exception in that case.
2727
* <p>
2828
* Such a method will not appear in backtraces. However, Ruby exceptions emitted from this node will be resent through a
29-
* CallTarget to get the proper backtrace.
29+
* CallTarget to get the proper backtrace. This should be tested in spec/truffle/always_inlined_spec.rb.
3030
* <p>
3131
* Such a core method should not emit significantly more Graal nodes than a non-inlined call, as Truffle cannot decide
3232
* to not inline it, and that could lead to too big methods to compile. */

0 commit comments

Comments
 (0)