Skip to content

Commit 3e6f071

Browse files
committed
Add Java class caching to LookupAndCall nodes
1 parent b951089 commit 3e6f071

File tree

4 files changed

+120
-29
lines changed

4 files changed

+120
-29
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/LookupAndCallBinaryNode.java

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
import com.oracle.truffle.api.dsl.Cached;
6767
import com.oracle.truffle.api.dsl.ImportStatic;
6868
import com.oracle.truffle.api.dsl.ReportPolymorphism;
69+
import com.oracle.truffle.api.dsl.ReportPolymorphism.Megamorphic;
6970
import com.oracle.truffle.api.dsl.Specialization;
7071
import com.oracle.truffle.api.frame.VirtualFrame;
7172
import com.oracle.truffle.api.nodes.Node;
@@ -386,10 +387,24 @@ boolean callBoolean(VirtualFrame frame, double left, double right,
386387

387388
// Object, Object
388389

389-
@Specialization(guards = {"!isReversible()"})
390-
Object callObject(VirtualFrame frame, Object left, Object right,
390+
@Specialization(guards = {"!isReversible()", "left.getClass() == cachedLeftClass", "right.getClass() == cachedRightClass"}, limit = "5")
391+
Object callObjectGeneric(VirtualFrame frame, Object left, Object right,
392+
@SuppressWarnings("unused") @Cached("left.getClass()") Class<?> cachedLeftClass,
393+
@SuppressWarnings("unused") @Cached("right.getClass()") Class<?> cachedRightClass,
391394
@Cached GetClassNode getClassNode,
392395
@Cached("create(name, ignoreDescriptorException)") LookupSpecialMethodSlotNode getattr) {
396+
return doCallObject(frame, left, right, getClassNode, getattr);
397+
}
398+
399+
@Specialization(guards = "!isReversible()", replaces = "callObjectGeneric")
400+
@Megamorphic
401+
Object callObjectMegamorphic(VirtualFrame frame, Object left, Object right,
402+
@Cached GetClassNode getClassNode,
403+
@Cached("create(name, ignoreDescriptorException)") LookupSpecialMethodSlotNode getattr) {
404+
return doCallObject(frame, left, right, getClassNode, getattr);
405+
}
406+
407+
private Object doCallObject(VirtualFrame frame, Object left, Object right, GetClassNode getClassNode, LookupSpecialMethodSlotNode getattr) {
393408
Object leftClass = getClassNode.execute(left);
394409
Object leftCallable = getattr.execute(frame, leftClass, left);
395410
if (leftCallable == PNone.NO_VALUE) {
@@ -402,8 +417,10 @@ Object callObject(VirtualFrame frame, Object left, Object right,
402417
return ensureDispatch().executeObject(frame, leftCallable, left, right);
403418
}
404419

405-
@Specialization(guards = {"isReversible()"})
406-
Object callObjectR(VirtualFrame frame, Object left, Object right,
420+
@Specialization(guards = {"isReversible()", "left.getClass() == cachedLeftClass", "right.getClass() == cachedRightClass"}, limit = "5")
421+
Object callObjectGenericR(VirtualFrame frame, Object left, Object right,
422+
@SuppressWarnings("unused") @Cached("left.getClass()") Class<?> cachedLeftClass,
423+
@SuppressWarnings("unused") @Cached("right.getClass()") Class<?> cachedRightClass,
407424
@Cached("create(name, ignoreDescriptorException)") LookupSpecialMethodNode getattr,
408425
@Cached("create(rname, ignoreDescriptorException)") LookupSpecialMethodNode getattrR,
409426
@Cached GetClassNode getLeftClassNode,
@@ -417,6 +434,34 @@ Object callObjectR(VirtualFrame frame, Object left, Object right,
417434
@Cached BranchProfile noLeftBuiltinClassType,
418435
@Cached BranchProfile noRightBuiltinClassType,
419436
@Cached BranchProfile gotResultBranch) {
437+
return doCallObjectR(frame, left, right, getattr, getattrR, getLeftClassNode, getRightClassNode, isSameTypeNode, isSubtype, hasLeftCallable, hasRightCallable, notImplementedProfile,
438+
hasEnclosingBuiltin, noLeftBuiltinClassType, noRightBuiltinClassType, gotResultBranch);
439+
}
440+
441+
@Specialization(guards = "isReversible()", replaces = "callObjectGenericR")
442+
@Megamorphic
443+
Object callObjectRMegamorphic(VirtualFrame frame, Object left, Object right,
444+
@Cached("create(name, ignoreDescriptorException)") LookupSpecialMethodNode getattr,
445+
@Cached("create(rname, ignoreDescriptorException)") LookupSpecialMethodNode getattrR,
446+
@Cached GetClassNode getLeftClassNode,
447+
@Cached GetClassNode getRightClassNode,
448+
@Cached TypeNodes.IsSameTypeNode isSameTypeNode,
449+
@Cached IsSubtypeNode isSubtype,
450+
@Cached ConditionProfile hasLeftCallable,
451+
@Cached ConditionProfile hasRightCallable,
452+
@Cached ConditionProfile notImplementedProfile,
453+
@Cached ConditionProfile hasEnclosingBuiltin,
454+
@Cached BranchProfile noLeftBuiltinClassType,
455+
@Cached BranchProfile noRightBuiltinClassType,
456+
@Cached BranchProfile gotResultBranch) {
457+
return doCallObjectR(frame, left, right, getattr, getattrR, getLeftClassNode, getRightClassNode, isSameTypeNode, isSubtype, hasLeftCallable, hasRightCallable, notImplementedProfile,
458+
hasEnclosingBuiltin, noLeftBuiltinClassType, noRightBuiltinClassType, gotResultBranch);
459+
}
460+
461+
private Object doCallObjectR(VirtualFrame frame, Object left, Object right, LookupSpecialMethodNode getattr, LookupSpecialMethodNode getattrR, GetClassNode getLeftClassNode,
462+
GetClassNode getRightClassNode, TypeNodes.IsSameTypeNode isSameTypeNode, IsSubtypeNode isSubtype, ConditionProfile hasLeftCallable, ConditionProfile hasRightCallable,
463+
ConditionProfile notImplementedProfile, ConditionProfile hasEnclosingBuiltin, BranchProfile noLeftBuiltinClassType, BranchProfile noRightBuiltinClassType,
464+
BranchProfile gotResultBranch) {
420465
// This specialization implements the logic from cpython://Objects/abstract.c#binary_op1
421466
// (the structure is modelled closely on it), as well as the additional logic in
422467
// cpython://Objects/typeobject.c#SLOT1BINFULL. The latter has the addition that it swaps

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/LookupAndCallTernaryNode.java

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import com.oracle.truffle.api.CompilerDirectives;
5353
import com.oracle.truffle.api.dsl.Cached;
5454
import com.oracle.truffle.api.dsl.ImportStatic;
55+
import com.oracle.truffle.api.dsl.ReportPolymorphism.Megamorphic;
5556
import com.oracle.truffle.api.dsl.Specialization;
5657
import com.oracle.truffle.api.frame.VirtualFrame;
5758
import com.oracle.truffle.api.nodes.Node;
@@ -84,13 +85,11 @@ public static LookupAndCallTernaryNode create(String name) {
8485
return LookupAndCallTernaryNodeGen.create(name, false, null, false);
8586
}
8687

87-
public static LookupAndCallTernaryNode createReversible(
88-
String name, Supplier<NotImplementedHandler> handlerFactory) {
88+
public static LookupAndCallTernaryNode createReversible(String name, Supplier<NotImplementedHandler> handlerFactory) {
8989
return LookupAndCallTernaryNodeGen.create(name, true, handlerFactory, false);
9090
}
9191

92-
LookupAndCallTernaryNode(
93-
String name, boolean isReversible, Supplier<NotImplementedHandler> handlerFactory, boolean ignoreDescriptorException) {
92+
LookupAndCallTernaryNode(String name, boolean isReversible, Supplier<NotImplementedHandler> handlerFactory, boolean ignoreDescriptorException) {
9493
this.name = name;
9594
this.isReversible = isReversible;
9695
this.handlerFactory = handlerFactory;
@@ -101,24 +100,27 @@ protected boolean isReversible() {
101100
return isReversible;
102101
}
103102

104-
@Specialization(guards = "!isReversible()")
105-
Object callObject(
106-
VirtualFrame frame,
107-
Object arg1,
108-
int arg2,
109-
Object arg3,
103+
@Specialization(guards = {"!isReversible()", "arg1.getClass() == cachedArg1Class"}, limit = "getCallSiteInlineCacheMaxDepth()")
104+
Object callObject(VirtualFrame frame, Object arg1, int arg2, Object arg3,
105+
@SuppressWarnings("unused") @Cached("arg1.getClass()") Class<?> cachedArg1Class,
110106
@Cached GetClassNode getClassNode,
111107
@Cached("create(name, ignoreDescriptorException)") LookupSpecialMethodSlotNode getattr) {
112108
Object klass = getClassNode.execute(arg1);
113109
return dispatchNode.execute(frame, getattr.execute(frame, klass, arg1), arg1, arg2, arg3);
114110
}
115111

116-
@Specialization(guards = "!isReversible()")
117-
Object callObject(
118-
VirtualFrame frame,
119-
Object arg1,
120-
Object arg2,
121-
Object arg3,
112+
@Specialization(guards = {"!isReversible()", "arg1.getClass() == cachedArg1Class"}, limit = "getCallSiteInlineCacheMaxDepth()")
113+
Object callObject(VirtualFrame frame, Object arg1, Object arg2, Object arg3,
114+
@SuppressWarnings("unused") @Cached("arg1.getClass()") Class<?> cachedArg1Class,
115+
@Cached GetClassNode getClassNode,
116+
@Cached("create(name, ignoreDescriptorException)") LookupSpecialMethodSlotNode getattr) {
117+
Object klass = getClassNode.execute(arg1);
118+
return dispatchNode.execute(frame, getattr.execute(frame, klass, arg1), arg1, arg2, arg3);
119+
}
120+
121+
@Specialization(guards = "!isReversible()", replaces = "callObject")
122+
@Megamorphic
123+
Object callObjectMegamorphic(VirtualFrame frame, Object arg1, Object arg2, Object arg3,
122124
@Cached GetClassNode getClassNode,
123125
@Cached("create(name, ignoreDescriptorException)") LookupSpecialMethodSlotNode getattr) {
124126
Object klass = getClassNode.execute(arg1);
@@ -160,19 +162,34 @@ private GetClassNode ensureThirdGetClass() {
160162
return thirdGetClassNode;
161163
}
162164

163-
@Specialization(guards = "isReversible()")
164-
Object callObject(
165-
VirtualFrame frame,
166-
Object v,
167-
Object w,
168-
Object z,
165+
@Specialization(guards = {"isReversible()", "v.getClass() == cachedVClass"}, limit = "getCallSiteInlineCacheMaxDepth()")
166+
Object callObjectR(VirtualFrame frame, Object v, Object w, Object z,
167+
@SuppressWarnings("unused") @Cached("v.getClass()") Class<?> cachedVClass,
169168
@Cached("create(name, ignoreDescriptorException)") LookupSpecialMethodNode getattr,
170169
@Cached("create(name, ignoreDescriptorException)") LookupSpecialMethodNode getattrR,
171170
@Cached GetClassNode getClass,
172171
@Cached GetClassNode getClassR,
173172
@Cached IsSubtypeNode isSubtype,
174173
@Cached IsSameTypeNode isSameTypeNode,
175174
@Cached BranchProfile notImplementedBranch) {
175+
return doCallObjectR(frame, v, w, z, getattr, getattrR, getClass, getClassR, isSubtype, isSameTypeNode, notImplementedBranch);
176+
}
177+
178+
@Specialization(guards = "isReversible()", replaces = "callObjectR")
179+
@Megamorphic
180+
Object callObjectRMegamorphic(VirtualFrame frame, Object v, Object w, Object z,
181+
@Cached("create(name, ignoreDescriptorException)") LookupSpecialMethodNode getattr,
182+
@Cached("create(name, ignoreDescriptorException)") LookupSpecialMethodNode getattrR,
183+
@Cached GetClassNode getClass,
184+
@Cached GetClassNode getClassR,
185+
@Cached IsSubtypeNode isSubtype,
186+
@Cached IsSameTypeNode isSameTypeNode,
187+
@Cached BranchProfile notImplementedBranch) {
188+
return doCallObjectR(frame, v, w, z, getattr, getattrR, getClass, getClassR, isSubtype, isSameTypeNode, notImplementedBranch);
189+
}
190+
191+
private Object doCallObjectR(VirtualFrame frame, Object v, Object w, Object z, LookupSpecialMethodNode getattr, LookupSpecialMethodNode getattrR, GetClassNode getClass, GetClassNode getClassR,
192+
IsSubtypeNode isSubtype, IsSameTypeNode isSameTypeNode, BranchProfile notImplementedBranch) {
176193
// c.f. mostly slot_nb_power and wrap_ternaryfunc_r. like
177194
// cpython://Object/abstract.c#ternary_op we try all three combinations, and the structure
178195
// of this method is modeled after this. However, this method also merges the logic from

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/LookupAndCallUnaryNode.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import com.oracle.truffle.api.dsl.Cached;
5353
import com.oracle.truffle.api.dsl.GenerateUncached;
5454
import com.oracle.truffle.api.dsl.ImportStatic;
55+
import com.oracle.truffle.api.dsl.ReportPolymorphism.Megamorphic;
5556
import com.oracle.truffle.api.dsl.Specialization;
5657
import com.oracle.truffle.api.frame.VirtualFrame;
5758
import com.oracle.truffle.api.nodes.Node;
@@ -214,11 +215,29 @@ static Object callObject(VirtualFrame frame, PNone receiver,
214215

215216
// Object
216217

217-
@Specialization
218-
Object callObject(VirtualFrame frame, Object receiver,
218+
@Specialization(guards = "getObjectClass(receiver) == cachedClass")
219+
Object callObjectGeneric(VirtualFrame frame, Object receiver,
220+
@SuppressWarnings("unused") @Cached("receiver.getClass()") Class<?> cachedClass,
219221
@Cached GetClassNode getClassNode,
220222
@Cached("create(name, ignoreDescriptorException)") LookupSpecialMethodSlotNode getattr,
221223
@Cached CallUnaryMethodNode dispatchNode) {
224+
return doCallObject(frame, receiver, getClassNode, getattr, dispatchNode);
225+
}
226+
227+
@Specialization(replaces = "callObjectGeneric")
228+
@Megamorphic
229+
Object callObjectMegamorphic(VirtualFrame frame, Object receiver,
230+
@Cached GetClassNode getClassNode,
231+
@Cached("create(name, ignoreDescriptorException)") LookupSpecialMethodSlotNode getattr,
232+
@Cached CallUnaryMethodNode dispatchNode) {
233+
return doCallObject(frame, receiver, getClassNode, getattr, dispatchNode);
234+
}
235+
236+
protected Class<?> getObjectClass(Object object) {
237+
return object.getClass();
238+
}
239+
240+
private Object doCallObject(VirtualFrame frame, Object receiver, GetClassNode getClassNode, LookupSpecialMethodSlotNode getattr, CallUnaryMethodNode dispatchNode) {
222241
Object attr = getattr.execute(frame, getClassNode.execute(receiver), receiver);
223242
if (attr == PNone.NO_VALUE) {
224243
if (handlerFactory != null) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/LookupAndCallVarargsNode.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import com.oracle.graal.python.builtins.objects.function.PKeyword;
4444
import com.oracle.graal.python.nodes.object.GetClassNode;
4545
import com.oracle.truffle.api.dsl.Cached;
46+
import com.oracle.truffle.api.dsl.ReportPolymorphism.Megamorphic;
4647
import com.oracle.truffle.api.dsl.Specialization;
4748
import com.oracle.truffle.api.frame.VirtualFrame;
4849
import com.oracle.truffle.api.nodes.Node;
@@ -63,8 +64,17 @@ public static LookupAndCallVarargsNode create(String name) {
6364
this.ignoreDescriptorException = ignoreDescriptorException;
6465
}
6566

66-
@Specialization
67+
@Specialization(guards = {"callable.getClass() == cachedClass"}, limit = "3")
6768
Object callObject(VirtualFrame frame, Object callable, Object[] arguments,
69+
@SuppressWarnings("unused") @Cached("callable.getClass()") Class<?> cachedClass,
70+
@Cached GetClassNode getClassNode,
71+
@Cached("create(name, ignoreDescriptorException)") LookupSpecialMethodNode getattr) {
72+
return dispatchNode.execute(frame, getattr.execute(frame, getClassNode.execute(callable), callable), arguments, PKeyword.EMPTY_KEYWORDS);
73+
}
74+
75+
@Specialization(replaces = "callObject")
76+
@Megamorphic
77+
Object callObjectMegamorphic(VirtualFrame frame, Object callable, Object[] arguments,
6878
@Cached GetClassNode getClassNode,
6979
@Cached("create(name, ignoreDescriptorException)") LookupSpecialMethodNode getattr) {
7080
return dispatchNode.execute(frame, getattr.execute(frame, getClassNode.execute(callable), callable), arguments, PKeyword.EMPTY_KEYWORDS);

0 commit comments

Comments
 (0)