Skip to content

Commit a256c68

Browse files
committed
Limit recursive inlininig of binary builtins
1 parent 9539823 commit a256c68

File tree

2 files changed

+48
-4
lines changed

2 files changed

+48
-4
lines changed

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

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@
4646
import com.oracle.graal.python.builtins.Builtin;
4747
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
4848
import com.oracle.graal.python.builtins.objects.function.BuiltinMethodDescriptor;
49+
import com.oracle.graal.python.builtins.objects.function.BuiltinMethodDescriptor.BinaryBuiltinDescriptor;
50+
import com.oracle.graal.python.builtins.objects.function.BuiltinMethodDescriptor.TernaryBuiltinDescriptor;
51+
import com.oracle.graal.python.builtins.objects.function.BuiltinMethodDescriptor.UnaryBuiltinDescriptor;
4952
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
5053
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
5154
import com.oracle.graal.python.builtins.objects.method.PMethod;
@@ -72,6 +75,7 @@
7275
import com.oracle.truffle.api.dsl.NodeField;
7376
import com.oracle.truffle.api.dsl.TypeSystemReference;
7477
import com.oracle.truffle.api.frame.VirtualFrame;
78+
import com.oracle.truffle.api.nodes.Node;
7579
import com.oracle.truffle.api.nodes.NodeUtil;
7680
import com.oracle.truffle.api.nodes.RootNode;
7781
import com.oracle.truffle.api.nodes.UnexpectedResultException;
@@ -112,9 +116,49 @@ private <T extends PythonBuiltinBaseNode> T getBuiltin(VirtualFrame frame, PBuil
112116
return null;
113117
}
114118

119+
public PythonUnaryBuiltinNode getBuiltin(UnaryBuiltinDescriptor descriptor) {
120+
PythonUnaryBuiltinNode builtin = descriptor.createNode();
121+
if (!callerExceedsMaxSize(builtin)) {
122+
return builtin;
123+
}
124+
return null;
125+
}
126+
127+
public PythonBinaryBuiltinNode getBuiltin(BinaryBuiltinDescriptor descriptor) {
128+
PythonBinaryBuiltinNode builtin = descriptor.createNode();
129+
if (!callerExceedsMaxSize(builtin)) {
130+
return builtin;
131+
}
132+
return null;
133+
}
134+
135+
public PythonTernaryBuiltinNode getBuiltin(TernaryBuiltinDescriptor descriptor) {
136+
PythonTernaryBuiltinNode builtin = descriptor.createNode();
137+
if (!callerExceedsMaxSize(builtin)) {
138+
return builtin;
139+
}
140+
return null;
141+
}
142+
115143
private <T extends PythonBuiltinBaseNode> boolean callerExceedsMaxSize(T builtinNode) {
116144
CompilerAsserts.neverPartOfCompilation();
117145
if (isAdoptable() && !isMaxSizeExceeded()) {
146+
// to avoid building up AST of recursive builtin calls we check that the same builtin
147+
// isn't already our parent.
148+
Class<? extends PythonBuiltinBaseNode> builtinClass = builtinNode.getClass();
149+
Node parent = getParent();
150+
int recursiveCalls = 0;
151+
while (parent != null && !(parent instanceof RootNode)) {
152+
if (parent.getClass() == builtinClass) {
153+
int recursionLimit = PythonLanguage.get(this).getEngineOption(PythonOptions.NodeRecursionLimit);
154+
if (recursiveCalls == recursionLimit) {
155+
return true;
156+
}
157+
recursiveCalls++;
158+
}
159+
parent = parent.getParent();
160+
}
161+
118162
RootNode root = getRootNode();
119163
int n = root instanceof PRootNode ? ((PRootNode) root).getNodeCount() : NodeUtil.countNodes(root);
120164
// nb: option 'BuiltinsInliningMaxCallerSize' is defined as a compatible option, i.e.,

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,10 @@ public final Object executeObject(Object callable, Object arg1, Object arg2) {
8888
return executeObject(null, callable, arg1, arg2);
8989
}
9090

91-
@Specialization(guards = "cachedInfo == info", limit = "getCallSiteInlineCacheMaxDepth()")
91+
@Specialization(guards = {"cachedInfo == info", "node != null"}, limit = "getCallSiteInlineCacheMaxDepth()")
9292
static Object callBinarySpecialMethodSlotInlined(VirtualFrame frame, @SuppressWarnings("unused") BinaryBuiltinDescriptor info, Object arg1, Object arg2,
9393
@SuppressWarnings("unused") @Cached("info") BinaryBuiltinDescriptor cachedInfo,
94-
@Cached("cachedInfo.createNode()") PythonBinaryBuiltinNode node) {
94+
@Cached("getBuiltin(cachedInfo)") PythonBinaryBuiltinNode node) {
9595
if (cachedInfo.isReverseOperation()) {
9696
return node.execute(frame, arg2, arg1);
9797
} else {
@@ -103,11 +103,11 @@ protected static boolean hasAllowedArgsNum(BuiltinMethodDescriptor descr) {
103103
return descr.minNumOfPositionalArgs() <= 2;
104104
}
105105

106-
@Specialization(guards = "cachedInfo == info", limit = "getCallSiteInlineCacheMaxDepth()")
106+
@Specialization(guards = {"cachedInfo == info", "node != null"}, limit = "getCallSiteInlineCacheMaxDepth()")
107107
Object callTernarySpecialMethodSlotInlined(VirtualFrame frame, @SuppressWarnings("unused") TernaryBuiltinDescriptor info, Object arg1, Object arg2,
108108
@SuppressWarnings("unused") @Cached("info") TernaryBuiltinDescriptor cachedInfo,
109109
@Cached("hasAllowedArgsNum(cachedInfo)") boolean hasValidArgsNum,
110-
@Cached("cachedInfo.createNode()") PythonTernaryBuiltinNode node) {
110+
@Cached("getBuiltin(cachedInfo)") PythonTernaryBuiltinNode node) {
111111
raiseInvalidArgsNumUncached(hasValidArgsNum, cachedInfo);
112112
if (cachedInfo.isReverseOperation()) {
113113
return node.execute(frame, arg2, arg1, PNone.NO_VALUE);

0 commit comments

Comments
 (0)