Skip to content

Commit 3e13349

Browse files
committed
Fix unbounded recursive nodes creation in AbstractObjectIsSubclassNode
1 parent d2b8213 commit 3e13349

File tree

1 file changed

+24
-15
lines changed

1 file changed

+24
-15
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/classes/AbstractObjectIsSubclassNode.java

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,16 @@
6161
@ImportStatic(PythonOptions.class)
6262
@NodeInfo(shortName = "cpython://Objects/abstract.c/abstract_issubclass")
6363
public abstract class AbstractObjectIsSubclassNode extends PNodeWithContext {
64+
static final int MAX_RECURSION = 3; // Cannot use PythonOptions on fast-path
65+
6466
public static AbstractObjectIsSubclassNode create() {
6567
return AbstractObjectIsSubclassNodeGen.create();
6668
}
6769

68-
protected abstract boolean executeInternal(Frame frame, Object derived, Object cls);
70+
protected abstract boolean executeInternal(Frame frame, Object derived, Object cls, int depth);
6971

7072
public final boolean execute(VirtualFrame frame, Object derived, Object cls) {
71-
return executeInternal(frame, derived, cls);
73+
return executeInternal(frame, derived, cls, 0);
7274
}
7375

7476
public final boolean execute(Object derived, Object cls) {
@@ -77,7 +79,7 @@ public final boolean execute(Object derived, Object cls) {
7779

7880
@Specialization(guards = "isSameMetaObject(isSameTypeNode, derived, cls)", limit = "1")
7981
@SuppressWarnings("unused")
80-
static boolean doSameClass(Object derived, Object cls,
82+
static boolean doSameClass(Object derived, Object cls, @SuppressWarnings("unused") int depth,
8183
@Shared("isSameType") @Cached IsSameTypeNode isSameTypeNode) {
8284
return true;
8385
}
@@ -88,8 +90,8 @@ protected static int[] observedSize() {
8890
return ary;
8991
}
9092

91-
@Specialization(guards = {"!isSameMetaObject(isSameTypeNode, derived, cls)", "derived == cachedDerived", "cls == cachedCls"}, limit = "getCallSiteInlineCacheMaxDepth()")
92-
static boolean doSubclass(VirtualFrame frame, @SuppressWarnings("unused") Object derived, @SuppressWarnings("unused") Object cls,
93+
@Specialization(guards = {"depth < MAX_RECURSION", "!isSameMetaObject(isSameTypeNode, derived, cls)", "derived == cachedDerived", "cls == cachedCls"}, limit = "getCallSiteInlineCacheMaxDepth()")
94+
static boolean doSubclass(VirtualFrame frame, @SuppressWarnings("unused") Object derived, @SuppressWarnings("unused") Object cls, int depth,
9395
@Cached(value = "observedSize()", dimensions = 1) int[] observedSizeArray,
9496
@Cached("derived") Object cachedDerived,
9597
@Cached("cls") Object cachedCls,
@@ -108,41 +110,41 @@ static boolean doSubclass(VirtualFrame frame, @SuppressWarnings("unused") Object
108110
CompilerDirectives.transferToInterpreterAndInvalidate();
109111
observedSizeArray[0] = basesAry.length;
110112
}
111-
if (observedSizeArray[0] > 0 && observedSizeArray[0] < 32 && observedSizeArray[0] == basesAry.length) {
113+
if (observedSizeArray[0] > 0 && observedSizeArray[0] < (32 / depth) && observedSizeArray[0] == basesAry.length) {
112114
// we observe a short constant size
113-
return loopBases(frame, cachedCls, basesAry, isSubclassNode);
115+
return loopBases(frame, cachedCls, basesAry, isSubclassNode, depth);
114116
} else if (observedSizeArray[0] > 0) {
115117
// the observed size is too large or not constant, disable explosion
116118
CompilerDirectives.transferToInterpreterAndInvalidate();
117119
observedSizeArray[0] = -1;
118120
}
119-
return loopUnexploded(frame, cachedCls, isSubclassNode, basesAry);
121+
return loopUnexploded(frame, cachedCls, isSubclassNode, basesAry, depth);
120122
}
121123

122-
private static boolean loopUnexploded(VirtualFrame frame, Object cachedCls, AbstractObjectIsSubclassNode isSubclassNode, Object[] basesAry) {
124+
private static boolean loopUnexploded(VirtualFrame frame, Object cachedCls, AbstractObjectIsSubclassNode isSubclassNode, Object[] basesAry, int depth) {
123125
for (Object baseCls : basesAry) {
124-
if (isSubclassNode.execute(frame, baseCls, cachedCls)) {
126+
if (isSubclassNode.executeInternal(frame, baseCls, cachedCls, depth + 1)) {
125127
return true;
126128
}
127129
}
128130
return false;
129131
}
130132

131133
@ExplodeLoop
132-
private static boolean loopBases(VirtualFrame frame, Object cachedCls, Object[] bases, AbstractObjectIsSubclassNode isSubclassNode) {
134+
private static boolean loopBases(VirtualFrame frame, Object cachedCls, Object[] bases, AbstractObjectIsSubclassNode isSubclassNode, int depth) {
133135
for (int i = 0; i < bases.length; i++) {
134-
if (isSubclassNode.execute(frame, bases[i], cachedCls)) {
136+
if (isSubclassNode.executeInternal(frame, bases[i], cachedCls, depth + 1)) {
135137
return true;
136138
}
137139
}
138140
return false;
139141
}
140142

141143
@Specialization(replaces = {"doSubclass", "doSameClass"})
142-
static boolean doGeneric(VirtualFrame frame, Object derived, Object cls,
144+
static boolean doGeneric(VirtualFrame frame, Object derived, Object cls, int depth,
143145
@Cached SequenceStorageNodes.LenNode lenNode,
144146
@Cached AbstractObjectGetBasesNode getBasesNode,
145-
@Cached AbstractObjectIsSubclassNode isSubclassNode,
147+
@Cached("createRecursive(depth)") AbstractObjectIsSubclassNode isSubclassNode,
146148
@Shared("isSameType") @Cached IsSameTypeNode isSameTypeNode,
147149
@Cached GetObjectArrayNode getObjectArrayNode) {
148150
if (isSameMetaObject(isSameTypeNode, derived, cls)) {
@@ -155,13 +157,20 @@ static boolean doGeneric(VirtualFrame frame, Object derived, Object cls,
155157
}
156158

157159
for (Object baseCls : getObjectArrayNode.execute(bases)) {
158-
if (isSubclassNode.execute(frame, baseCls, cls)) {
160+
if (isSubclassNode.executeInternal(frame, baseCls, cls, depth + 1)) {
159161
return true;
160162
}
161163
}
162164
return false;
163165
}
164166

167+
protected AbstractObjectIsSubclassNode createRecursive(int depth) {
168+
if (depth >= MAX_RECURSION) {
169+
return AbstractObjectIsSubclassNodeGen.getUncached();
170+
}
171+
return AbstractObjectIsSubclassNodeGen.create();
172+
}
173+
165174
private static boolean isEmpty(PTuple bases, SequenceStorageNodes.LenNode lenNode) {
166175
return lenNode.execute(bases.getSequenceStorage()) == 0;
167176
}

0 commit comments

Comments
 (0)