Skip to content

Commit c471b16

Browse files
committed
use the singleContextAssumption to add specializations to invoke a constant callTarget and disable forced splitting
1 parent f2a14d1 commit c471b16

File tree

2 files changed

+98
-32
lines changed

2 files changed

+98
-32
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/CallDispatchNode.java

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,16 @@
2525
*/
2626
package com.oracle.graal.python.nodes.call;
2727

28+
import com.oracle.graal.python.PythonLanguage;
2829
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
2930
import com.oracle.graal.python.builtins.objects.function.PFunction;
3031
import com.oracle.graal.python.builtins.objects.function.PKeyword;
3132
import com.oracle.graal.python.builtins.objects.function.PythonCallable;
3233
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
3334
import com.oracle.graal.python.builtins.objects.method.PMethod;
3435
import com.oracle.graal.python.runtime.PythonOptions;
36+
import com.oracle.truffle.api.Assumption;
37+
import com.oracle.truffle.api.RootCallTarget;
3538
import com.oracle.truffle.api.dsl.Cached;
3639
import com.oracle.truffle.api.dsl.ImportStatic;
3740
import com.oracle.truffle.api.dsl.Specialization;
@@ -45,40 +48,76 @@ protected static InvokeNode createInvokeNode(PythonCallable callee) {
4548
return InvokeNode.create(callee);
4649
}
4750

51+
protected static CallTargetInvokeNode createCtInvokeNode(PythonCallable callee) {
52+
return CallTargetInvokeNode.create(callee);
53+
}
54+
4855
public static CallDispatchNode create() {
4956
return CallDispatchNodeGen.create();
5057
}
5158

59+
protected Assumption singleContextAssumption() {
60+
return PythonLanguage.singleContextAssumption;
61+
}
62+
5263
public abstract Object executeCall(VirtualFrame frame, Object callee, Object[] arguments, PKeyword[] keywords);
5364

54-
/**
55-
* We have to treat PMethods specially, because we want the PIC to be on the function, not on
56-
* the (transient) bound method.
57-
*/
5865
@SuppressWarnings("unused")
59-
@Specialization(guards = "method.getFunction() == cachedCallee", limit = "getCallSiteInlineCacheMaxDepth()")
66+
@Specialization(guards = "method.getFunction() == cachedCallee", limit = "getCallSiteInlineCacheMaxDepth()", assumptions = "singleContextAssumption()")
6067
protected Object callMethod(VirtualFrame frame, PMethod method, Object[] arguments, PKeyword[] keywords,
6168
@Cached("method.getFunction()") PFunction cachedCallee,
6269
@Cached("createInvokeNode(cachedCallee)") InvokeNode invoke) {
6370
return invoke.execute(frame, arguments, keywords);
6471
}
6572

6673
@SuppressWarnings("unused")
67-
@Specialization(guards = "method.getFunction() == cachedCallee", limit = "getCallSiteInlineCacheMaxDepth()")
74+
@Specialization(guards = "method.getFunction().getCallTarget() == ct", limit = "getCallSiteInlineCacheMaxDepth()")
75+
protected Object callMethod(VirtualFrame frame, PMethod method, Object[] arguments, PKeyword[] keywords,
76+
@Cached("method.getFunction().getCallTarget()") RootCallTarget ct,
77+
@Cached("createCtInvokeNode(method)") CallTargetInvokeNode invoke) {
78+
return invoke.execute(frame, method.getGlobals(), method.getClosure(), method.getArity(), arguments, keywords);
79+
}
80+
81+
@SuppressWarnings("unused")
82+
@Specialization(guards = "method.getFunction() == cachedCallee", limit = "getCallSiteInlineCacheMaxDepth()", assumptions = "singleContextAssumption()")
6883
protected Object callBuiltinMethod(VirtualFrame frame, PBuiltinMethod method, Object[] arguments, PKeyword[] keywords,
6984
@Cached("method.getFunction()") PBuiltinFunction cachedCallee,
7085
@Cached("createInvokeNode(cachedCallee)") InvokeNode invoke) {
7186
return invoke.execute(frame, arguments, keywords);
7287
}
7388

7489
@SuppressWarnings("unused")
75-
@Specialization(guards = "callee == cachedCallee", limit = "getCallSiteInlineCacheMaxDepth()")
90+
@Specialization(guards = "method.getFunction().getCallTarget() == ct", limit = "getCallSiteInlineCacheMaxDepth()")
91+
protected Object callBuiltinMethod(VirtualFrame frame, PBuiltinMethod method, Object[] arguments, PKeyword[] keywords,
92+
@Cached("method.getFunction().getCallTarget()") RootCallTarget ct,
93+
@Cached("createCtInvokeNode(method)") CallTargetInvokeNode invoke) {
94+
return invoke.execute(frame, method.getGlobals(), method.getClosure(), method.getArity(), arguments, keywords);
95+
}
96+
97+
@SuppressWarnings("unused")
98+
@Specialization(guards = "callee == cachedCallee", limit = "getCallSiteInlineCacheMaxDepth()", assumptions = "singleContextAssumption()")
7699
protected Object callFunction(VirtualFrame frame, PythonCallable callee, Object[] arguments, PKeyword[] keywords,
77100
@Cached("callee") PythonCallable cachedCallee,
78101
@Cached("createInvokeNode(cachedCallee)") InvokeNode invoke) {
79102
return invoke.execute(frame, arguments, keywords);
80103
}
81104

105+
@SuppressWarnings("unused")
106+
@Specialization(guards = "callee.getCallTarget() == ct", limit = "getCallSiteInlineCacheMaxDepth()")
107+
protected Object callFunction(VirtualFrame frame, PFunction callee, Object[] arguments, PKeyword[] keywords,
108+
@Cached("callee.getCallTarget()") RootCallTarget ct,
109+
@Cached("createCtInvokeNode(callee)") CallTargetInvokeNode invoke) {
110+
return invoke.execute(frame, callee.getGlobals(), callee.getClosure(), callee.getArity(), arguments, keywords);
111+
}
112+
113+
@SuppressWarnings("unused")
114+
@Specialization(guards = "callee.getCallTarget() == ct", limit = "getCallSiteInlineCacheMaxDepth()")
115+
protected Object callFunction(VirtualFrame frame, PBuiltinFunction callee, Object[] arguments, PKeyword[] keywords,
116+
@Cached("callee.getCallTarget()") RootCallTarget ct,
117+
@Cached("createCtInvokeNode(callee)") CallTargetInvokeNode invoke) {
118+
return invoke.execute(frame, callee.getGlobals(), callee.getClosure(), callee.getArity(), arguments, keywords);
119+
}
120+
82121
@Specialization(replaces = {"callMethod", "callBuiltinMethod", "callFunction"})
83122
protected Object callGeneric(VirtualFrame frame, PythonCallable callee, Object[] arguments, PKeyword[] keywords,
84123
@Cached("create()") GenericInvokeNode invoke) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/InvokeNode.java

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@
2525
*/
2626
package com.oracle.graal.python.nodes.call;
2727

28-
import static com.oracle.graal.python.nodes.SpecialMethodNames.__CALL__;
29-
import static com.oracle.graal.python.nodes.SpecialMethodNames.__GET__;
30-
import static com.oracle.graal.python.nodes.SpecialMethodNames.__INIT__;
3128
import static com.oracle.graal.python.nodes.SpecialMethodNames.__NEW__;
3229

3330
import com.oracle.graal.python.builtins.objects.cell.PCell;
@@ -45,7 +42,6 @@
4542
import com.oracle.graal.python.nodes.argument.ApplyKeywordsNode;
4643
import com.oracle.graal.python.nodes.argument.ArityCheckNode;
4744
import com.oracle.truffle.api.CallTarget;
48-
import com.oracle.truffle.api.CompilerAsserts;
4945
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
5046
import com.oracle.truffle.api.RootCallTarget;
5147
import com.oracle.truffle.api.Truffle;
@@ -56,7 +52,6 @@
5652
import com.oracle.truffle.api.nodes.DirectCallNode;
5753
import com.oracle.truffle.api.nodes.IndirectCallNode;
5854
import com.oracle.truffle.api.nodes.Node;
59-
import com.oracle.truffle.api.nodes.NodeUtil;
6055
import com.oracle.truffle.api.nodes.RootNode;
6156
import com.oracle.truffle.api.profiles.ConditionProfile;
6257

@@ -146,6 +141,58 @@ protected Object execute(VirtualFrame frame, PythonCallable callee, Object[] arg
146141
}
147142
}
148143

144+
abstract class CallTargetInvokeNode extends AbstractInvokeNode {
145+
@Child private DirectCallNode callNode;
146+
@Child private ArityCheckNode arityCheck = ArityCheckNode.create();
147+
protected final boolean isBuiltin;
148+
149+
protected CallTargetInvokeNode(CallTarget callTarget, boolean isBuiltin, boolean isGenerator) {
150+
this.callNode = Truffle.getRuntime().createDirectCallNode(callTarget);
151+
if (isGenerator) {
152+
this.callNode.forceInlining();
153+
}
154+
this.isBuiltin = isBuiltin;
155+
}
156+
157+
@TruffleBoundary
158+
public static CallTargetInvokeNode create(PythonCallable callee) {
159+
RootCallTarget callTarget = getCallTarget(callee);
160+
boolean builtin = isBuiltin(callee);
161+
return CallTargetInvokeNodeGen.create(callTarget, builtin, callee.isGeneratorFunction());
162+
}
163+
164+
public abstract Object execute(VirtualFrame frame, PythonObject globals, PCell[] closure, Arity arity, Object[] arguments, PKeyword[] keywords);
165+
166+
@Specialization(guards = {"keywords.length == 0"})
167+
protected Object doNoKeywords(VirtualFrame frame, PythonObject globals, PCell[] closure, Arity arity, Object[] arguments, PKeyword[] keywords) {
168+
PArguments.setGlobals(arguments, globals);
169+
PArguments.setClosure(arguments, closure);
170+
PArguments.setCallerFrame(arguments, getCallerFrame(frame, callNode.getCallTarget()));
171+
arityCheck.execute(arity, arguments, keywords);
172+
return callNode.call(arguments);
173+
}
174+
175+
@Specialization(guards = {"!isBuiltin"})
176+
protected Object doWithKeywords(VirtualFrame frame, PythonObject globals, PCell[] closure, Arity arity, Object[] arguments, PKeyword[] keywords,
177+
@Cached("create()") ApplyKeywordsNode applyKeywords) {
178+
Object[] combined = applyKeywords.execute(arity, arguments, keywords);
179+
PArguments.setGlobals(combined, globals);
180+
PArguments.setClosure(combined, closure);
181+
PArguments.setCallerFrame(arguments, getCallerFrame(frame, callNode.getCallTarget()));
182+
arityCheck.execute(arity, combined, PArguments.getKeywordArguments(combined));
183+
return callNode.call(combined);
184+
}
185+
186+
@Specialization(guards = "isBuiltin")
187+
protected Object doBuiltinWithKeywords(VirtualFrame frame, @SuppressWarnings("unused") PythonObject globals, @SuppressWarnings("unused") PCell[] closure, Arity arity, Object[] arguments,
188+
PKeyword[] keywords) {
189+
PArguments.setKeywordArguments(arguments, keywords);
190+
PArguments.setCallerFrame(arguments, getCallerFrame(frame, callNode.getCallTarget()));
191+
arityCheck.execute(arity, arguments, keywords);
192+
return callNode.call(arguments);
193+
}
194+
}
195+
149196
public abstract class InvokeNode extends AbstractInvokeNode {
150197
@Child private DirectCallNode callNode;
151198
@Child private ArityCheckNode arityCheck = ArityCheckNode.create();
@@ -170,30 +217,10 @@ protected InvokeNode(CallTarget callTarget, Arity calleeArity, PythonObject glob
170217
@TruffleBoundary
171218
public static InvokeNode create(PythonCallable callee) {
172219
RootCallTarget callTarget = getCallTarget(callee);
173-
174220
boolean builtin = isBuiltin(callee);
175-
if (builtin && shouldSplit(callee)) {
176-
callTarget = split(callTarget);
177-
}
178221
return InvokeNodeGen.create(callTarget, getArity(callee), callee.getGlobals(), callee.getClosure(), builtin, callee.isGeneratorFunction());
179222
}
180223

181-
/**
182-
* Replicate the CallTarget to let each builtin call site executes its own AST.
183-
*/
184-
protected static RootCallTarget split(RootCallTarget callTarget) {
185-
CompilerAsserts.neverPartOfCompilation();
186-
RootNode rootNode = callTarget.getRootNode();
187-
return Truffle.getRuntime().createCallTarget(NodeUtil.cloneNode(rootNode));
188-
}
189-
190-
protected static boolean shouldSplit(PythonCallable callee) {
191-
return callee.getName().equals(__INIT__) ||
192-
callee.getName().equals(__GET__) ||
193-
callee.getName().equals(__NEW__) ||
194-
callee.getName().equals(__CALL__);
195-
}
196-
197224
@Specialization(guards = {"keywords.length == 0"})
198225
protected Object doNoKeywords(VirtualFrame frame, Object[] arguments, PKeyword[] keywords) {
199226
PArguments.setGlobals(arguments, globals);

0 commit comments

Comments
 (0)