Skip to content

Commit d23e36f

Browse files
author
Nicolas Laurent
committed
[GR-25976] Separate logic for regular method dispatch and respond_to?.
PullRequest: truffleruby/1979
2 parents 9ba2e2c + 3d037cf commit d23e36f

File tree

12 files changed

+167
-108
lines changed

12 files changed

+167
-108
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.truffleruby.language.arguments.ReadCallerFrameNode;
4242
import org.truffleruby.language.arguments.RubyArguments;
4343
import org.truffleruby.language.control.RaiseException;
44+
import org.truffleruby.language.dispatch.DispatchConfiguration;
4445
import org.truffleruby.language.dispatch.DispatchNode;
4546
import org.truffleruby.language.dispatch.RubyCallNode;
4647
import org.truffleruby.language.eval.CreateEvalSourceNode;
@@ -583,7 +584,7 @@ private boolean lastCallWasVCall(FrameAndCallNode callerFrame) {
583584
@CoreMethod(names = "__send__", needsBlock = true, rest = true, required = 1)
584585
public abstract static class SendNode extends CoreMethodArrayArgumentsNode {
585586

586-
@Child private DispatchNode dispatchNode = DispatchNode.create(DispatchNode.PRIVATE);
587+
@Child private DispatchNode dispatchNode = DispatchNode.create(DispatchConfiguration.PRIVATE);
587588
@Child private ReadCallerFrameNode readCallerFrame = ReadCallerFrameNode.create();
588589
@Child private NameToJavaStringNode nameToJavaString = NameToJavaStringNode.create();
589590

src/main/java/org/truffleruby/core/kernel/KernelNodes.java

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@
1010
package org.truffleruby.core.kernel;
1111

1212
import static org.truffleruby.language.dispatch.DispatchConfiguration.PRIVATE;
13-
import static org.truffleruby.language.dispatch.DispatchConfiguration.PRIVATE_DOES_RESPOND;
1413
import static org.truffleruby.language.dispatch.DispatchConfiguration.PUBLIC;
15-
import static org.truffleruby.language.dispatch.DispatchConfiguration.PUBLIC_DOES_RESPOND;
1614

1715
import java.io.File;
1816
import java.io.PrintStream;
@@ -102,6 +100,7 @@
102100
import org.truffleruby.language.control.RaiseException;
103101
import org.truffleruby.language.dispatch.DispatchConfiguration;
104102
import org.truffleruby.language.dispatch.DispatchNode;
103+
import org.truffleruby.language.dispatch.InternalRespondToNode;
105104
import org.truffleruby.language.dispatch.RubyCallNode;
106105
import org.truffleruby.language.eval.CreateEvalSourceNode;
107106
import org.truffleruby.language.globals.ReadGlobalVariableNodeGen;
@@ -1549,19 +1548,19 @@ protected Object send(VirtualFrame frame, Object self, Object name, Object[] arg
15491548
@NodeChild(value = "includeProtectedAndPrivate", type = RubyNode.class)
15501549
public abstract static class RespondToNode extends CoreMethodNode {
15511550

1552-
@Child private DispatchNode dispatch;
1553-
@Child private DispatchNode dispatchIgnoreVisibility;
1554-
@Child private DispatchNode dispatchRespondToMissing;
1551+
@Child private InternalRespondToNode dispatch;
1552+
@Child private InternalRespondToNode dispatchIgnoreVisibility;
1553+
@Child private InternalRespondToNode dispatchRespondToMissing;
15551554
@Child private DispatchNode respondToMissingNode;
15561555
@Child private BooleanCastNode booleanCastNode;
15571556
private final ConditionProfile ignoreVisibilityProfile = ConditionProfile.create();
15581557
private final ConditionProfile isTrueProfile = ConditionProfile.create();
15591558
private final ConditionProfile respondToMissingProfile = ConditionProfile.create();
15601559

15611560
public RespondToNode() {
1562-
dispatch = DispatchNode.create(PUBLIC_DOES_RESPOND);
1563-
dispatchIgnoreVisibility = DispatchNode.create(PRIVATE_DOES_RESPOND);
1564-
dispatchRespondToMissing = DispatchNode.create(PRIVATE_DOES_RESPOND);
1561+
dispatch = InternalRespondToNode.create(PUBLIC);
1562+
dispatchIgnoreVisibility = InternalRespondToNode.create();
1563+
dispatchRespondToMissing = InternalRespondToNode.create();
15651564
}
15661565

15671566
public abstract boolean executeDoesRespondTo(VirtualFrame frame, Object object, Object name,
@@ -1582,15 +1581,15 @@ protected boolean doesRespondToString(
15821581
final boolean ret;
15831582

15841583
if (ignoreVisibilityProfile.profile(includeProtectedAndPrivate)) {
1585-
ret = dispatchIgnoreVisibility.doesRespondTo(frame, toJavaString.executeToJavaString(name), object);
1584+
ret = dispatchIgnoreVisibility.execute(frame, object, toJavaString.executeToJavaString(name));
15861585
} else {
1587-
ret = dispatch.doesRespondTo(frame, toJavaString.executeToJavaString(name), object);
1586+
ret = dispatch.execute(frame, object, toJavaString.executeToJavaString(name));
15881587
}
15891588

15901589
if (isTrueProfile.profile(ret)) {
15911590
return true;
15921591
} else if (respondToMissingProfile
1593-
.profile(dispatchRespondToMissing.doesRespondTo(frame, "respond_to_missing?", object))) {
1592+
.profile(dispatchRespondToMissing.execute(frame, object, "respond_to_missing?"))) {
15941593
return respondToMissing(
15951594
frame,
15961595
object,
@@ -1611,15 +1610,15 @@ protected boolean doesRespondToSymbol(
16111610
final boolean ret;
16121611

16131612
if (ignoreVisibilityProfile.profile(includeProtectedAndPrivate)) {
1614-
ret = dispatchIgnoreVisibility.doesRespondTo(frame, toJavaString.executeToJavaString(name), object);
1613+
ret = dispatchIgnoreVisibility.execute(frame, object, toJavaString.executeToJavaString(name));
16151614
} else {
1616-
ret = dispatch.doesRespondTo(frame, toJavaString.executeToJavaString(name), object);
1615+
ret = dispatch.execute(frame, object, toJavaString.executeToJavaString(name));
16171616
}
16181617

16191618
if (isTrueProfile.profile(ret)) {
16201619
return true;
16211620
} else if (respondToMissingProfile
1622-
.profile(dispatchRespondToMissing.doesRespondTo(frame, "respond_to_missing?", object))) {
1621+
.profile(dispatchRespondToMissing.execute(frame, object, "respond_to_missing?"))) {
16231622
return respondToMissing(frame, object, name, includeProtectedAndPrivate);
16241623
} else {
16251624
return false;

src/main/java/org/truffleruby/core/objectspace/ObjectSpaceNodes.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
import org.truffleruby.language.RubyDynamicObject;
3030
import org.truffleruby.language.RubyGuards;
3131
import org.truffleruby.language.control.RaiseException;
32-
import org.truffleruby.language.dispatch.DispatchNode;
32+
import org.truffleruby.language.dispatch.InternalRespondToNode;
3333
import org.truffleruby.language.objects.IsANode;
3434
import org.truffleruby.language.objects.ObjectGraph;
3535
import org.truffleruby.language.objects.ObjectIDOperations;
@@ -42,7 +42,6 @@
4242
import com.oracle.truffle.api.frame.VirtualFrame;
4343
import com.oracle.truffle.api.profiles.BranchProfile;
4444

45-
import static org.truffleruby.language.dispatch.DispatchConfiguration.PRIVATE_DOES_RESPOND;
4645

4746
@CoreModule("ObjectSpace")
4847
public abstract class ObjectSpaceNodes {
@@ -197,13 +196,13 @@ public abstract static class DefineFinalizerNode extends CoreMethodArrayArgument
197196

198197
// MRI would do a dynamic call to #respond_to? but it seems better to warn the user earlier.
199198
// Wanting #method_missing(:call) to be called for a finalizer seems highly unlikely.
200-
@Child private DispatchNode respondToCallNode = DispatchNode.create(PRIVATE_DOES_RESPOND);
199+
@Child private InternalRespondToNode respondToCallNode = InternalRespondToNode.create();
201200

202201
@Specialization
203202
protected RubyArray defineFinalizer(VirtualFrame frame, RubyDynamicObject object, Object finalizer,
204203
@Cached BranchProfile errorProfile,
205204
@Cached WriteBarrierNode writeBarrierNode) {
206-
if (respondToCallNode.doesRespondTo(frame, "call", finalizer)) {
205+
if (respondToCallNode.execute(frame, finalizer, "call")) {
207206
if (getContext().getSharedObjects().isSharing()) {
208207
// Share the finalizer, as it might run on a different Thread
209208
writeBarrierNode.executeWriteBarrier(finalizer);

src/main/java/org/truffleruby/language/ImmutableRubyObject.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.truffleruby.interop.ForeignToRubyArgumentsNode;
1616
import org.truffleruby.interop.ForeignToRubyNode;
1717
import org.truffleruby.language.dispatch.DispatchNode;
18+
import org.truffleruby.language.dispatch.InternalRespondToNode;
1819
import org.truffleruby.language.library.RubyLibrary;
1920
import com.oracle.truffle.api.dsl.Cached;
2021
import com.oracle.truffle.api.dsl.Cached.Exclusive;
@@ -111,18 +112,18 @@ public Object getMembers(boolean internal,
111112

112113
@ExportMessage
113114
public boolean isMemberReadable(String name,
114-
@Cached(parameters = "PRIVATE_DOES_RESPOND") @Shared("definedNode") DispatchNode definedNode) {
115-
return definedNode.doesRespondTo(null, name, this);
115+
@Cached @Shared("definedNode") InternalRespondToNode definedNode) {
116+
return definedNode.execute(null, this, name);
116117
}
117118

118119
@ExportMessage
119120
public Object readMember(String name,
120-
@Cached(parameters = "PRIVATE_DOES_RESPOND") @Shared("definedNode") DispatchNode definedNode,
121+
@Cached @Shared("definedNode") InternalRespondToNode definedNode,
121122
@Cached ForeignToRubyNode nameToRubyNode,
122123
@Cached @Exclusive DispatchNode dispatch,
123124
@Shared("errorProfile") @Cached BranchProfile errorProfile)
124125
throws UnknownIdentifierException {
125-
if (definedNode.doesRespondTo(null, name, this)) {
126+
if (definedNode.execute(null, this, name)) {
126127
Object rubyName = nameToRubyNode.executeConvert(name);
127128
return dispatch.call(this, "method", rubyName);
128129
} else {
@@ -133,8 +134,8 @@ public Object readMember(String name,
133134

134135
@ExportMessage
135136
public boolean isMemberInvocable(String name,
136-
@Cached(parameters = "PRIVATE_DOES_RESPOND") @Shared("definedNode") DispatchNode definedNode) {
137-
return definedNode.doesRespondTo(null, name, this);
137+
@Cached @Shared("definedNode") InternalRespondToNode definedNode) {
138+
return definedNode.execute(null, this, name);
138139
}
139140

140141
@ExportMessage
@@ -154,11 +155,11 @@ public Object invokeMember(String name, Object[] arguments,
154155

155156
@ExportMessage
156157
public boolean isMemberInternal(String name,
157-
@Cached(parameters = "PRIVATE_DOES_RESPOND") @Shared("definedNode") DispatchNode definedNode,
158-
@Exclusive @Cached(parameters = "PUBLIC_DOES_RESPOND") DispatchNode definedPublicNode) {
158+
@Cached @Shared("definedNode") InternalRespondToNode definedNode,
159+
@Exclusive @Cached(parameters = "PUBLIC") InternalRespondToNode definedPublicNode) {
159160
// defined but not publicly
160-
return definedNode.doesRespondTo(null, name, this) &&
161-
!definedPublicNode.doesRespondTo(null, name, this);
161+
return definedNode.execute(null, this, name) &&
162+
!definedPublicNode.execute(null, this, name);
162163
}
163164
// endregion
164165
// endregion

src/main/java/org/truffleruby/language/RubyDynamicObject.java

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.truffleruby.interop.TranslateInteropRubyExceptionNode;
2727
import org.truffleruby.language.control.RaiseException;
2828
import org.truffleruby.language.dispatch.DispatchNode;
29+
import org.truffleruby.language.dispatch.InternalRespondToNode;
2930
import org.truffleruby.language.library.RubyLibrary;
3031
import org.truffleruby.language.objects.LogicalClassNode;
3132
import org.truffleruby.language.objects.WriteObjectFieldNode;
@@ -235,7 +236,6 @@ public long getArraySize(
235236
}
236237

237238
@ExportMessage
238-
@SuppressWarnings("unused") // because of throws in ArrayMessages
239239
public Object readArrayElement(long index,
240240
@Shared("errorProfile") @Cached BranchProfile errorProfile,
241241
@Shared("translateRubyException") @Cached TranslateInteropRubyExceptionNode translateRubyException,
@@ -254,7 +254,6 @@ public Object readArrayElement(long index,
254254
}
255255

256256
@ExportMessage
257-
@SuppressWarnings("unused") // because of throws in ArrayMessages
258257
public void writeArrayElement(long index, Object value,
259258
@Shared("errorProfile") @Cached BranchProfile errorProfile,
260259
@Shared("translateRubyException") @Cached TranslateInteropRubyExceptionNode translateRubyException,
@@ -390,7 +389,7 @@ private static boolean isIVar(String name) {
390389
@ExportMessage
391390
public Object readMember(String name,
392391
@CachedLibrary("this") DynamicObjectLibrary objectLibrary,
393-
@Cached(parameters = "PRIVATE_DOES_RESPOND") @Shared("definedNode") DispatchNode definedNode,
392+
@Cached @Shared("definedNode") InternalRespondToNode definedNode,
394393
@Cached @Shared("nameToRubyNode") ForeignToRubyNode nameToRubyNode,
395394
@Cached @Exclusive DispatchNode dispatch,
396395
@Exclusive @Cached(parameters = "PRIVATE_RETURN_MISSING") DispatchNode dispatchNode,
@@ -411,7 +410,7 @@ public Object readMember(String name,
411410
Object iVar = objectLibrary.getOrDefault(this, name, null);
412411
if (ivarFoundProfile.profile(iVar != null)) {
413412
return iVar;
414-
} else if (definedNode.doesRespondTo(null, name, this)) {
413+
} else if (definedNode.execute(null, this, name)) {
415414
return dispatch.call(this, "method", rubyName);
416415
} else {
417416
errorProfile.enter();
@@ -522,7 +521,7 @@ public Object invokeMember(String name, Object[] arguments,
522521
@ExportMessage
523522
public boolean isMemberReadable(String name,
524523
@CachedLibrary("this") DynamicObjectLibrary objectLibrary,
525-
@Cached(parameters = "PRIVATE_DOES_RESPOND") @Shared("definedNode") DispatchNode definedNode,
524+
@Cached @Shared("definedNode") InternalRespondToNode definedNode,
526525
@Exclusive @Cached(parameters = "PRIVATE_RETURN_MISSING") DispatchNode dispatchNode,
527526
@Cached @Shared("nameToRubyNode") ForeignToRubyNode nameToRubyNode,
528527
@Exclusive @Cached BooleanCastNode booleanCastNode,
@@ -534,7 +533,7 @@ public boolean isMemberReadable(String name,
534533
if (ivarFoundProfile.profile(objectLibrary.containsKey(this, name))) {
535534
return true;
536535
} else {
537-
return definedNode.doesRespondTo(null, name, this);
536+
return definedNode.execute(null, this, name);
538537
}
539538
} else {
540539
return booleanCastNode.executeToBoolean(dynamic);
@@ -620,7 +619,7 @@ public boolean isMemberInsertable(String name,
620619
@ExportMessage
621620
public boolean isMemberInvocable(String name,
622621
@CachedLibrary("this") DynamicObjectLibrary objectLibrary,
623-
@Cached(parameters = "PRIVATE_DOES_RESPOND") @Shared("definedNode") DispatchNode definedNode,
622+
@Cached @Shared("definedNode") InternalRespondToNode definedNode,
624623
@Exclusive @Cached(parameters = "PRIVATE_RETURN_MISSING") DispatchNode dispatchNode,
625624
@Cached @Shared("nameToRubyNode") ForeignToRubyNode nameToRubyNode,
626625
@Exclusive @Cached BooleanCastNode booleanCastNode,
@@ -633,7 +632,7 @@ public boolean isMemberInvocable(String name,
633632
if (ivarFoundProfile.profile(iVar != null)) {
634633
return false;
635634
} else {
636-
return definedNode.doesRespondTo(null, name, this);
635+
return definedNode.execute(null, this, name);
637636
}
638637
} else {
639638
return booleanCastNode.executeToBoolean(dynamic);
@@ -643,8 +642,8 @@ public boolean isMemberInvocable(String name,
643642
@ExportMessage
644643
public boolean isMemberInternal(String name,
645644
@CachedLibrary("this") DynamicObjectLibrary objectLibrary,
646-
@Cached(parameters = "PRIVATE_DOES_RESPOND") @Shared("definedNode") DispatchNode definedNode,
647-
@Exclusive @Cached(parameters = "PUBLIC_DOES_RESPOND") DispatchNode definedPublicNode,
645+
@Cached @Shared("definedNode") InternalRespondToNode definedNode,
646+
@Exclusive @Cached(parameters = "PUBLIC") InternalRespondToNode definedPublicNode,
648647
@Exclusive @Cached(parameters = "PRIVATE_RETURN_MISSING") DispatchNode dispatchNode,
649648
@Cached @Shared("nameToRubyNode") ForeignToRubyNode nameToRubyNode,
650649
@Exclusive @Cached BooleanCastNode booleanCastNode,
@@ -658,8 +657,8 @@ public boolean isMemberInternal(String name,
658657
return true;
659658
} else {
660659
// defined but not publicly
661-
return definedNode.doesRespondTo(null, name, this) &&
662-
!definedPublicNode.doesRespondTo(null, name, this);
660+
return definedNode.execute(null, this, name) &&
661+
!definedPublicNode.execute(null, this, name);
663662
}
664663
} else {
665664
return booleanCastNode.executeToBoolean(dynamic);
@@ -700,8 +699,8 @@ public boolean hasMemberWriteSideEffects(String name,
700699
// region Instantiable
701700
@ExportMessage
702701
public boolean isInstantiable(
703-
@Exclusive @Cached(parameters = "PUBLIC_DOES_RESPOND") DispatchNode doesRespond) {
704-
return doesRespond.doesRespondTo(null, "new", this);
702+
@Exclusive @Cached(parameters = "PUBLIC") InternalRespondToNode doesRespond) {
703+
return doesRespond.execute(null, this, "new");
705704
}
706705

707706
@ExportMessage

src/main/java/org/truffleruby/language/arguments/ReadUserKeywordsHashNode.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,13 @@
1717
import com.oracle.truffle.api.CompilerDirectives;
1818
import com.oracle.truffle.api.frame.VirtualFrame;
1919
import com.oracle.truffle.api.profiles.ConditionProfile;
20-
21-
import static org.truffleruby.language.dispatch.DispatchConfiguration.PRIVATE_DOES_RESPOND;
20+
import org.truffleruby.language.dispatch.InternalRespondToNode;
2221

2322
public class ReadUserKeywordsHashNode extends RubyContextSourceNode {
2423

2524
private final int minArgumentCount;
2625

27-
@Child private DispatchNode respondToToHashNode;
26+
@Child private InternalRespondToNode respondToToHashNode;
2827
@Child private DispatchNode callToHashNode;
2928

3029
private final ConditionProfile notEnoughArgumentsProfile = ConditionProfile.create();
@@ -69,9 +68,9 @@ private RubyHash tryConvertToHash(VirtualFrame frame, int argumentCount, Object
6968
private boolean respondToToHash(VirtualFrame frame, Object lastArgument) {
7069
if (respondToToHashNode == null) {
7170
CompilerDirectives.transferToInterpreterAndInvalidate();
72-
respondToToHashNode = insert(DispatchNode.create(PRIVATE_DOES_RESPOND));
71+
respondToToHashNode = insert(InternalRespondToNode.create());
7372
}
74-
return respondToToHashNode.doesRespondTo(frame, "to_hash", lastArgument);
73+
return respondToToHashNode.execute(frame, lastArgument, "to_hash");
7574
}
7675

7776
private Object callToHash(VirtualFrame frame, Object lastArgument) {

src/main/java/org/truffleruby/language/arguments/ShouldDestructureNode.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,16 @@
1111

1212
import org.truffleruby.language.RubyContextSourceNode;
1313
import org.truffleruby.language.RubyGuards;
14-
import org.truffleruby.language.dispatch.DispatchNode;
1514

1615
import com.oracle.truffle.api.CompilerDirectives;
1716
import com.oracle.truffle.api.frame.VirtualFrame;
1817
import com.oracle.truffle.api.profiles.BranchProfile;
18+
import org.truffleruby.language.dispatch.InternalRespondToNode;
1919

20-
import static org.truffleruby.language.dispatch.DispatchConfiguration.PRIVATE_DOES_RESPOND;
2120

2221
public class ShouldDestructureNode extends RubyContextSourceNode {
2322

24-
@Child private DispatchNode respondToToAry;
23+
@Child private InternalRespondToNode respondToToAry;
2524

2625
private final BranchProfile checkIsArrayProfile = BranchProfile.create();
2726

@@ -41,12 +40,12 @@ public Object execute(VirtualFrame frame) {
4140

4241
if (respondToToAry == null) {
4342
CompilerDirectives.transferToInterpreterAndInvalidate();
44-
respondToToAry = insert(DispatchNode.create(PRIVATE_DOES_RESPOND));
43+
respondToToAry = insert(InternalRespondToNode.create());
4544
}
4645

4746
// TODO(cseaton): check this is actually a static "find if there is such method" and not a
4847
// dynamic call to respond_to?
49-
return respondToToAry.doesRespondTo(frame, "to_ary", firstArgument);
48+
return respondToToAry.execute(frame, firstArgument, "to_ary");
5049
}
5150

5251
}

src/main/java/org/truffleruby/language/dispatch/DispatchAction.java

Lines changed: 0 additions & 15 deletions
This file was deleted.

0 commit comments

Comments
 (0)