Skip to content

Commit 2f8f138

Browse files
committed
implement reverse wrapper logic for CallSpecialNodes
1 parent d23b4c2 commit 2f8f138

File tree

11 files changed

+359
-44
lines changed

11 files changed

+359
-44
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,7 @@ protected void disposeThread(PythonContext context, Thread thread) {
582582
}
583583

584584
public RootCallTarget getOrComputeBuiltinCallTarget(Builtin builtin, Function<Builtin, RootCallTarget> supplier) {
585-
synchronized(this) {
585+
synchronized (this) {
586586
return builtinCallTargetCache.computeIfAbsent(builtin, supplier);
587587
}
588588
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/function/PBuiltinFunction.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,19 @@ public NodeFactory<? extends PythonBuiltinBaseNode> getBuiltinNodeFactory() {
102102
}
103103
}
104104

105+
public boolean isReverseOperationSlot() {
106+
return isReverseOperationSlot(callTarget);
107+
}
108+
109+
public static boolean isReverseOperationSlot(RootCallTarget ct) {
110+
RootNode functionRootNode = ct.getRootNode();
111+
if (functionRootNode instanceof BuiltinFunctionRootNode) {
112+
return ((BuiltinFunctionRootNode) functionRootNode).getBuiltin().reverseOperation();
113+
} else {
114+
return false;
115+
}
116+
}
117+
105118
public Class<? extends PythonBuiltinBaseNode> getNodeClass() {
106119
return getBuiltinNodeFactory() != null ? getBuiltinNodeFactory().getNodeClass() : null;
107120
}

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

Lines changed: 210 additions & 20 deletions
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.graal.python.nodes.call.special;
42+
43+
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
44+
import com.oracle.truffle.api.CompilerAsserts;
45+
import com.oracle.truffle.api.RootCallTarget;
46+
import com.oracle.truffle.api.dsl.NodeField;
47+
48+
@NodeField(name = "forReverseBinaryOperation", type = boolean.class)
49+
abstract class CallReversibleMethodNode extends CallSpecialMethodNode {
50+
protected abstract boolean isForReverseBinaryOperation();
51+
52+
protected boolean isForReverseBinaryOperation(PBuiltinFunction func) {
53+
boolean isReverseOperationSlot = func.isReverseOperationSlot();
54+
CompilerAsserts.partialEvaluationConstant(isReverseOperationSlot);
55+
return isForReverseBinaryOperation() && isReverseOperationSlot;
56+
}
57+
58+
protected boolean isForReverseBinaryOperation(RootCallTarget ct) {
59+
boolean isReverseOperationSlot = PBuiltinFunction.isReverseOperationSlot(ct);
60+
CompilerAsserts.partialEvaluationConstant(isReverseOperationSlot);
61+
return isForReverseBinaryOperation() && isReverseOperationSlot;
62+
}
63+
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@
7878
abstract class CallSpecialMethodNode extends Node {
7979

8080
/**
81-
* for interpreter performance: cache if we exceeded the max caller size. We never allow inlining
82-
* in the uncached case.
81+
* for interpreter performance: cache if we exceeded the max caller size. We never allow
82+
* inlining in the uncached case.
8383
*/
8484
protected abstract boolean isMaxSizeExceeded();
8585

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

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
import com.oracle.graal.python.builtins.objects.function.PKeyword;
4545
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
4646
import com.oracle.graal.python.nodes.call.CallNode;
47-
import com.oracle.graal.python.nodes.call.special.CallTernaryMethodNodeGen;
4847
import com.oracle.graal.python.nodes.function.builtins.PythonQuaternaryBuiltinNode;
4948
import com.oracle.graal.python.nodes.function.builtins.PythonTernaryBuiltinNode;
5049
import com.oracle.truffle.api.RootCallTarget;
@@ -57,10 +56,13 @@
5756

5857
@ReportPolymorphism
5958
@GenerateUncached
60-
public abstract class CallTernaryMethodNode extends CallSpecialMethodNode {
61-
59+
public abstract class CallTernaryMethodNode extends CallReversibleMethodNode {
6260
public static CallTernaryMethodNode create() {
63-
return CallTernaryMethodNodeGen.create();
61+
return CallTernaryMethodNodeGen.create(false);
62+
}
63+
64+
static CallTernaryMethodNode createReversed() {
65+
return CallTernaryMethodNodeGen.create(true);
6466
}
6567

6668
public static CallTernaryMethodNode getUncached() {
@@ -71,38 +73,82 @@ public static CallTernaryMethodNode getUncached() {
7173

7274
public abstract Object execute(Frame frame, Object callable, Object arg1, Object arg2, Object arg3);
7375

74-
@Specialization(guards = {"func == cachedFunc", "builtinNode != null", "frame != null || unusedFrame"}, limit = "getCallSiteInlineCacheMaxDepth()", assumptions = "singleContextAssumption()")
76+
@Specialization(guards = {"func == cachedFunc", "builtinNode != null", "!isReverse",
77+
"frame != null || unusedFrame"}, limit = "getCallSiteInlineCacheMaxDepth()", assumptions = "singleContextAssumption()")
7578
Object doBuiltinFunctionOIOCached(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinFunction func, Object arg1, int arg2, Object arg3,
7679
@SuppressWarnings("unused") @Cached("func") PBuiltinFunction cachedFunc,
80+
@SuppressWarnings("unused") @Cached("isForReverseBinaryOperation(func.getCallTarget())") boolean isReverse,
7781
@Cached("getTernary(frame, func)") PythonTernaryBuiltinNode builtinNode,
7882
@SuppressWarnings("unused") @Cached("frameIsUnused(builtinNode)") boolean unusedFrame) {
7983
return builtinNode.executeWithInt(frame, arg1, arg2, arg3);
8084
}
8185

82-
@Specialization(guards = {"func == cachedFunc", "builtinNode != null", "frame != null || unusedFrame"}, limit = "getCallSiteInlineCacheMaxDepth()", assumptions = "singleContextAssumption()")
86+
@Specialization(guards = {"func == cachedFunc", "builtinNode != null", "isReverse",
87+
"frame != null || unusedFrame"}, limit = "getCallSiteInlineCacheMaxDepth()", assumptions = "singleContextAssumption()")
88+
Object doBuiltinFunctionOIOCachedReverse(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinFunction func, Object arg1, int arg2, Object arg3,
89+
@SuppressWarnings("unused") @Cached("func") PBuiltinFunction cachedFunc,
90+
@SuppressWarnings("unused") @Cached("isForReverseBinaryOperation(func.getCallTarget())") boolean isReverse,
91+
@Cached("getTernary(frame, func)") PythonTernaryBuiltinNode builtinNode,
92+
@SuppressWarnings("unused") @Cached("frameIsUnused(builtinNode)") boolean unusedFrame) {
93+
return builtinNode.execute(frame, arg2, arg1, arg3);
94+
}
95+
96+
@Specialization(guards = {"func == cachedFunc", "builtinNode != null", "!isReverse",
97+
"frame != null || unusedFrame"}, limit = "getCallSiteInlineCacheMaxDepth()", assumptions = "singleContextAssumption()")
8398
Object doBuiltinFunctionCached(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinFunction func, Object arg1, Object arg2, Object arg3,
8499
@SuppressWarnings("unused") @Cached("func") PBuiltinFunction cachedFunc,
100+
@SuppressWarnings("unused") @Cached("isForReverseBinaryOperation(func.getCallTarget())") boolean isReverse,
85101
@Cached("getTernary(frame, func)") PythonTernaryBuiltinNode builtinNode,
86102
@SuppressWarnings("unused") @Cached("frameIsUnused(builtinNode)") boolean unusedFrame) {
87103
return builtinNode.execute(frame, arg1, arg2, arg3);
88104
}
89105

90-
@Specialization(guards = {"func.getCallTarget() == ct", "builtinNode != null", "frame != null || unusedFrame"}, limit = "getCallSiteInlineCacheMaxDepth()")
106+
@Specialization(guards = {"func == cachedFunc", "builtinNode != null", "isReverse",
107+
"frame != null || unusedFrame"}, limit = "getCallSiteInlineCacheMaxDepth()", assumptions = "singleContextAssumption()")
108+
Object doBuiltinFunctionCachedReverse(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinFunction func, Object arg1, Object arg2, Object arg3,
109+
@SuppressWarnings("unused") @Cached("func") PBuiltinFunction cachedFunc,
110+
@SuppressWarnings("unused") @Cached("isForReverseBinaryOperation(func.getCallTarget())") boolean isReverse,
111+
@Cached("getTernary(frame, func)") PythonTernaryBuiltinNode builtinNode,
112+
@SuppressWarnings("unused") @Cached("frameIsUnused(builtinNode)") boolean unusedFrame) {
113+
return builtinNode.execute(frame, arg2, arg1, arg3);
114+
}
115+
116+
@Specialization(guards = {"func.getCallTarget() == ct", "builtinNode != null", "!isReverse", "frame != null || unusedFrame"}, limit = "getCallSiteInlineCacheMaxDepth()")
91117
Object doBuiltinFunctionOIOCtCached(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinFunction func, Object arg1, int arg2, Object arg3,
92118
@SuppressWarnings("unused") @Cached("func.getCallTarget()") RootCallTarget ct,
119+
@SuppressWarnings("unused") @Cached("isForReverseBinaryOperation(func.getCallTarget())") boolean isReverse,
93120
@Cached("getTernary(frame, func)") PythonTernaryBuiltinNode builtinNode,
94121
@SuppressWarnings("unused") @Cached("frameIsUnused(builtinNode)") boolean unusedFrame) {
95122
return builtinNode.executeWithInt(frame, arg1, arg2, arg3);
96123
}
97124

98-
@Specialization(guards = {"func.getCallTarget() == ct", "builtinNode != null", "frame != null || unusedFrame"}, limit = "getCallSiteInlineCacheMaxDepth()")
125+
@Specialization(guards = {"func.getCallTarget() == ct", "builtinNode != null", "isReverse", "frame != null || unusedFrame"}, limit = "getCallSiteInlineCacheMaxDepth()")
126+
Object doBuiltinFunctionOIOCtCachedReverse(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinFunction func, Object arg1, int arg2, Object arg3,
127+
@SuppressWarnings("unused") @Cached("func.getCallTarget()") RootCallTarget ct,
128+
@SuppressWarnings("unused") @Cached("isForReverseBinaryOperation(func.getCallTarget())") boolean isReverse,
129+
@Cached("getTernary(frame, func)") PythonTernaryBuiltinNode builtinNode,
130+
@SuppressWarnings("unused") @Cached("frameIsUnused(builtinNode)") boolean unusedFrame) {
131+
return builtinNode.execute(frame, arg2, arg1, arg3);
132+
}
133+
134+
@Specialization(guards = {"func.getCallTarget() == ct", "builtinNode != null", "!isReverse", "frame != null || unusedFrame"}, limit = "getCallSiteInlineCacheMaxDepth()")
99135
Object doBuiltinFunctionCtCached(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinFunction func, Object arg1, Object arg2, Object arg3,
100136
@SuppressWarnings("unused") @Cached("func.getCallTarget()") RootCallTarget ct,
137+
@SuppressWarnings("unused") @Cached("isForReverseBinaryOperation(func.getCallTarget())") boolean isReverse,
101138
@Cached("getTernary(frame, func)") PythonTernaryBuiltinNode builtinNode,
102139
@SuppressWarnings("unused") @Cached("frameIsUnused(builtinNode)") boolean unusedFrame) {
103140
return builtinNode.execute(frame, arg1, arg2, arg3);
104141
}
105142

143+
@Specialization(guards = {"func.getCallTarget() == ct", "builtinNode != null", "isReverse", "frame != null || unusedFrame"}, limit = "getCallSiteInlineCacheMaxDepth()")
144+
Object doBuiltinFunctionCtCachedReverse(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinFunction func, Object arg1, Object arg2, Object arg3,
145+
@SuppressWarnings("unused") @Cached("func.getCallTarget()") RootCallTarget ct,
146+
@SuppressWarnings("unused") @Cached("isForReverseBinaryOperation(func.getCallTarget())") boolean isReverse,
147+
@Cached("getTernary(frame, func)") PythonTernaryBuiltinNode builtinNode,
148+
@SuppressWarnings("unused") @Cached("frameIsUnused(builtinNode)") boolean unusedFrame) {
149+
return builtinNode.execute(frame, arg2, arg1, arg3);
150+
}
151+
106152
@Specialization(guards = {"func == cachedFunc", "builtinNode != null", "!takesSelfArg",
107153
"frame != null || unusedFrame"}, limit = "getCallSiteInlineCacheMaxDepth()", assumptions = "singleContextAssumption()")
108154
Object doBuiltinMethodOIOCached(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinMethod func, Object arg1, int arg2, Object arg3,
@@ -160,8 +206,10 @@ Object callSelfMethod(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinMe
160206
return builtinNode.execute(frame, func.getSelf(), arg1, arg2, arg3);
161207
}
162208

163-
@Specialization(replaces = {"doBuiltinFunctionOIOCached", "doBuiltinFunctionCached", "doBuiltinFunctionOIOCtCached", "doBuiltinFunctionCtCached", "doBuiltinMethodOIOCached",
164-
"doBuiltinMethodCached", "doBuiltinMethodOIOCtCached", "doBuiltinMethodCtCached", "callSelfMethodSingleContext", "callSelfMethod"})
209+
@Specialization(replaces = {"doBuiltinFunctionOIOCached", "doBuiltinFunctionCached", "doBuiltinFunctionOIOCtCached", "doBuiltinFunctionCtCached",
210+
"doBuiltinFunctionOIOCachedReverse", "doBuiltinFunctionCachedReverse", "doBuiltinFunctionOIOCtCachedReverse", "doBuiltinFunctionCtCachedReverse",
211+
"doBuiltinMethodOIOCached", "doBuiltinMethodCached", "doBuiltinMethodOIOCtCached", "doBuiltinMethodCtCached", "callSelfMethodSingleContext",
212+
"callSelfMethod"})
165213
static Object call(VirtualFrame frame, Object func, Object arg1, Object arg2, Object arg3,
166214
@Cached CallNode callNode) {
167215
return callNode.execute(frame, func, new Object[]{arg1, arg2, arg3}, PKeyword.EMPTY_KEYWORDS);

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
import com.oracle.graal.python.builtins.objects.function.PKeyword;
4545
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
4646
import com.oracle.graal.python.nodes.call.CallNode;
47-
import com.oracle.graal.python.nodes.call.special.CallUnaryMethodNodeGen;
4847
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
4948
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
5049
import com.oracle.truffle.api.RootCallTarget;
@@ -113,7 +112,7 @@ int callInt(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinFunction fun
113112
@Cached("getUnary(frame, func)") PythonUnaryBuiltinNode builtinNode,
114113
@SuppressWarnings("unused") @Cached("frameIsUnused(builtinNode)") boolean unusedFrame) throws UnexpectedResultException {
115114
return builtinNode.executeInt(frame, receiver);
116-
}
115+
}
117116

118117
@Specialization(guards = {"func == cachedFunc",
119118
"builtinNode != null",
@@ -218,7 +217,8 @@ Object callSelfMethod(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinMe
218217
return builtinNode.execute(frame, func.getSelf(), arg);
219218
}
220219

221-
@Specialization(replaces = {"callIntSingle", "callInt", "callLongSingle", "callLong", "callDoubleSingle", "callDouble", "callBoolSingle", "callBool", "callObjectSingleContext", "callMethodSingleContext", "callSelfMethodSingleContext", "callMethod", "callSelfMethod"})
220+
@Specialization(replaces = {"callIntSingle", "callInt", "callLongSingle", "callLong", "callDoubleSingle", "callDouble", "callBoolSingle", "callBool", "callObjectSingleContext",
221+
"callMethodSingleContext", "callSelfMethodSingleContext", "callMethod", "callSelfMethod"})
222222
static Object call(VirtualFrame frame, Object func, Object receiver,
223223
@Cached("create()") CallNode callNode) {
224224
return callNode.execute(frame, func, new Object[]{receiver}, PKeyword.EMPTY_KEYWORDS);

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
import com.oracle.graal.python.builtins.objects.function.PKeyword;
4646
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
4747
import com.oracle.graal.python.nodes.call.CallNode;
48-
import com.oracle.graal.python.nodes.call.special.CallVarargsMethodNodeGen;
4948
import com.oracle.graal.python.nodes.function.builtins.PythonVarargsBuiltinNode;
5049
import com.oracle.graal.python.nodes.function.builtins.PythonVarargsBuiltinNode.VarargsBuiltinDirectInvocationNotSupported;
5150
import com.oracle.truffle.api.RootCallTarget;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ private CallBinaryMethodNode ensureReverseDispatch() {
147147
// this also serves as a branch profile
148148
if (reverseDispatchNode == null) {
149149
CompilerDirectives.transferToInterpreterAndInvalidate();
150-
reverseDispatchNode = insert(CallBinaryMethodNode.create());
150+
reverseDispatchNode = insert(CallBinaryMethodNode.createReversed());
151151
}
152152
return reverseDispatchNode;
153153
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ private CallTernaryMethodNode ensureReverseDispatch() {
125125
// this also serves as a branch profile
126126
if (reverseDispatchNode == null) {
127127
CompilerDirectives.transferToInterpreterAndInvalidate();
128-
reverseDispatchNode = insert(CallTernaryMethodNode.create());
128+
reverseDispatchNode = insert(CallTernaryMethodNode.createReversed());
129129
}
130130
return reverseDispatchNode;
131131
}
@@ -161,7 +161,7 @@ Object callObject(
161161
@Cached("create()") IsSubtypeNode isSubtype,
162162
@Cached("create()") IsSameTypeNode isSameTypeNode,
163163
@Cached("create()") BranchProfile notImplementedBranch) {
164-
// c.f. mostly slot_nb_power and wrap_ternaryfunc_r. like
164+
// c.f. mostly slot_nb_power and wrap_ternaryfunc_r. like
165165
// cpython://Object/abstract.c#ternary_op we try all three combinations, and the structure
166166
// of this method is modeled after this. However, this method also merges the logic from
167167
// slot_nb_power/wrap_ternaryfunc_r in that it swaps arguments around. The reversal is

0 commit comments

Comments
 (0)