77
77
import java .math .BigInteger ;
78
78
import java .nio .charset .Charset ;
79
79
import java .nio .charset .CodingErrorAction ;
80
+ import java .util .ArrayDeque ;
80
81
import java .util .ArrayList ;
81
82
import java .util .Arrays ;
82
83
import java .util .List ;
178
179
import com .oracle .graal .python .nodes .util .CastToJavaIntExactNode ;
179
180
import com .oracle .graal .python .nodes .util .CastToJavaLongExactNode ;
180
181
import com .oracle .graal .python .nodes .util .CastToJavaStringNode ;
181
- import com .oracle .graal .python .runtime .ExecutionContext .IndirectCallContext ;
182
182
import com .oracle .graal .python .runtime .PythonContext ;
183
183
import com .oracle .graal .python .runtime .PythonCore ;
184
184
import com .oracle .graal .python .runtime .PythonOptions ;
@@ -1037,108 +1037,88 @@ Object doObject(Object value,
1037
1037
}
1038
1038
}
1039
1039
1040
- // isinstance(object, classinfo)
1041
- @ Builtin (name = ISINSTANCE , minNumOfPositionalArgs = 2 )
1042
- @ GenerateNodeFactory
1043
- public abstract static class IsInstanceNode extends PythonBinaryBuiltinNode {
1040
+ /**
1041
+ * Base class for {@code isinstance} and {@code issubclass} that implements the recursive
1042
+ * iteration of tuples passed as the second argument. The inheriting classes need to just
1043
+ * provide the base for the recursion.
1044
+ */
1045
+ public abstract static class RecursiveBinaryCheckBaseNode extends PythonBinaryBuiltinNode {
1044
1046
static final int MAX_EXPLODE_LOOP = 16 ; // is also divided by recursion depth+1
1047
+ static final byte STOP_RECURSION = Byte .MAX_VALUE ;
1045
1048
1046
1049
@ Child private SequenceStorageNodes .LenNode lenNode ;
1047
1050
@ Child private GetObjectArrayNode getObjectArrayNode ;
1048
1051
protected final byte depth ;
1049
1052
1050
- protected IsInstanceNode (byte depth ) {
1053
+ protected RecursiveBinaryCheckBaseNode (byte depth ) {
1051
1054
this .depth = depth ;
1052
1055
}
1053
1056
1054
- protected IsInstanceNode () {
1055
- this ((byte ) 0 );
1056
- }
1057
+ public abstract boolean executeWith (VirtualFrame frame , Object instance , Object cls );
1057
1058
1058
- public static IsInstanceNode createRecursive (byte currentDepth ) {
1059
- return BuiltinFunctionsFactory . IsInstanceNodeFactory . create ((byte ) (currentDepth + 1 ));
1059
+ public final RecursiveBinaryCheckBaseNode createRecursive () {
1060
+ return createRecursive ((byte ) (depth + 1 ));
1060
1061
}
1061
1062
1062
- private static TriState isInstanceCheckInternal (VirtualFrame frame , Object instance , Object cls , LookupAndCallBinaryNode instanceCheckNode , CoerceToBooleanNode castToBooleanNode ) {
1063
- Object instanceCheckResult = instanceCheckNode .executeObject (frame , cls , instance );
1064
- if (instanceCheckResult == NOT_IMPLEMENTED ) {
1065
- return TriState .UNDEFINED ;
1066
- }
1067
- return TriState .valueOf (castToBooleanNode .executeBoolean (frame , instanceCheckResult ));
1068
- }
1069
-
1070
- public abstract boolean executeWith (VirtualFrame frame , Object instance , Object cls );
1071
-
1072
- @ Specialization (guards = "isPythonClass(cls)" )
1073
- static boolean isInstance (VirtualFrame frame , Object instance , Object cls ,
1074
- @ Shared ("instanceCheck" ) @ Cached ("create(__INSTANCECHECK__)" ) LookupAndCallBinaryNode instanceCheckNode ,
1075
- @ Shared ("boolCast" ) @ Cached ("createIfTrueNode()" ) CoerceToBooleanNode castToBooleanNode ,
1076
- @ Cached GetClassNode getClassNode ,
1077
- @ Cached TypeNodes .IsSameTypeNode isSameTypeNode ,
1078
- @ Cached IsSubtypeNode isSubtypeNode ) {
1079
- Object instanceClass = getClassNode .execute (instance );
1080
- return isSameTypeNode .execute (instanceClass , cls ) || isSubtypeNode .execute (frame , instanceClass , cls )//
1081
- || isInstanceCheckInternal (frame , instance , cls , instanceCheckNode , castToBooleanNode ) == TriState .TRUE ;
1063
+ protected RecursiveBinaryCheckBaseNode createRecursive (@ SuppressWarnings ("unused" ) byte newDepth ) {
1064
+ throw new AbstractMethodError (); // Cannot be really abstract b/c Truffle DSL...
1082
1065
}
1083
1066
1084
1067
protected int getMaxExplodeLoop () {
1085
1068
return MAX_EXPLODE_LOOP / (depth + 1 );
1086
1069
}
1087
1070
1088
- @ Specialization (guards = {"depth < getNodeRecursionLimit()" , "getLength(clsTuple) == cachedLen" , "cachedLen < getMaxExplodeLoop()" }, limit = "getVariableArgumentInlineCacheLimit()" )
1071
+ @ Specialization (guards = {"depth != STOP_RECURSION" , "depth < getNodeRecursionLimit()" , //
1072
+ "getLength(clsTuple) == cachedLen" , "cachedLen < getMaxExplodeLoop()" }, //
1073
+ limit = "getVariableArgumentInlineCacheLimit()" )
1089
1074
@ ExplodeLoop (kind = LoopExplosionKind .FULL_UNROLL_UNTIL_RETURN )
1090
- boolean isInstanceTupleConstantLen (VirtualFrame frame , Object instance , PTuple clsTuple ,
1075
+ final boolean doTupleConstantLen (VirtualFrame frame , Object instance , PTuple clsTuple ,
1091
1076
@ Cached ("getLength(clsTuple)" ) int cachedLen ,
1092
- @ Cached ("createRecursive(depth)" ) IsInstanceNode isInstanceNode ) {
1077
+ @ Cached ("createRecursive(depth)" ) RecursiveBinaryCheckBaseNode recursiveNode ) {
1093
1078
Object [] array = getArray (clsTuple );
1094
1079
for (int i = 0 ; i < cachedLen ; i ++) {
1095
1080
Object cls = array [i ];
1096
- if (isInstanceNode .executeWith (frame , instance , cls )) {
1081
+ if (recursiveNode .executeWith (frame , instance , cls )) {
1097
1082
return true ;
1098
1083
}
1099
1084
}
1100
1085
return false ;
1101
1086
}
1102
1087
1103
- @ Specialization (guards = "depth < getNodeRecursionLimit()" , replaces = "isInstanceTupleConstantLen " )
1104
- boolean isInstanceRecursiveNode (VirtualFrame frame , Object instance , PTuple clsTuple ,
1105
- @ Cached ("createRecursive(depth)" ) IsInstanceNode instanceNode ) {
1088
+ @ Specialization (guards = { "depth != STOP_RECURSION" , "depth < getNodeRecursionLimit()"} , replaces = "doTupleConstantLen " )
1089
+ final boolean doRecursiveWithNode (VirtualFrame frame , Object instance , PTuple clsTuple ,
1090
+ @ Cached ("createRecursive(depth)" ) RecursiveBinaryCheckBaseNode recursiveNode ) {
1106
1091
for (Object cls : getArray (clsTuple )) {
1107
- if (instanceNode .executeWith (frame , instance , cls )) {
1092
+ if (recursiveNode .executeWith (frame , instance , cls )) {
1108
1093
return true ;
1109
1094
}
1110
1095
}
1111
1096
return false ;
1112
1097
}
1113
1098
1114
- @ Specialization (guards = "depth >= getNodeRecursionLimit()" )
1115
- boolean isInstanceRecursiveCall (VirtualFrame frame , Object instance , PTuple clsTuple ) {
1116
- Object state = IndirectCallContext .enter (frame , getContext (), this );
1117
- try {
1118
- return isInstanceRecursiveTruffleBoundary (instance , clsTuple );
1119
- } finally {
1120
- IndirectCallContext .exit (frame , getContext (), state );
1121
- }
1122
- }
1123
-
1124
- @ TruffleBoundary
1125
- boolean isInstanceRecursiveTruffleBoundary (Object instance , PTuple clsTuple ) {
1126
- return isInstanceRecursiveNode (null , instance , clsTuple , this );
1127
- }
1128
-
1129
- @ Specialization (guards = {"!isPTuple(cls)" , "!isPythonClass(cls)" })
1130
- static boolean isInstance (VirtualFrame frame , Object instance , Object cls ,
1131
- @ Shared ("instanceCheck" ) @ Cached ("create(__INSTANCECHECK__)" ) LookupAndCallBinaryNode instanceCheckNode ,
1132
- @ Shared ("boolCast" ) @ Cached ("createIfTrueNode()" ) CoerceToBooleanNode castToBooleanNode ,
1133
- @ Cached TypeBuiltins .InstanceCheckNode typeInstanceCheckNode ) {
1134
- TriState check = isInstanceCheckInternal (frame , instance , cls , instanceCheckNode , castToBooleanNode );
1135
- if (check == TriState .UNDEFINED ) {
1136
- return typeInstanceCheckNode .executeWith (frame , cls , instance );
1099
+ @ Specialization (guards = {"depth != STOP_RECURSION" , "depth >= getNodeRecursionLimit()" })
1100
+ final boolean doRecursiveWithLoop (VirtualFrame frame , Object instance , PTuple clsTuple ,
1101
+ @ Cached ("createRecursive(STOP_RECURSION)" ) RecursiveBinaryCheckBaseNode nonRecursiveNode ) {
1102
+ // Note: we do not put this behind TB to avoid frame materialization, an alternative can
1103
+ // be to use IndirectCallNode, null frame and put this algorithm behind TB
1104
+ ArrayDeque <Object > classes = PythonUtils .newDeque ();
1105
+ PythonUtils .push (classes , clsTuple );
1106
+ while (!classes .isEmpty ()) {
1107
+ Object currentKlass = PythonUtils .pop (classes );
1108
+ if (currentKlass instanceof PTuple ) {
1109
+ Object [] tupleItems = getArray ((PTuple ) currentKlass );
1110
+ // push them in reverse order to pop them in the necessary order
1111
+ for (int i = tupleItems .length - 1 ; i >= 0 ; i --) {
1112
+ PythonUtils .push (classes , tupleItems [i ]);
1113
+ }
1114
+ } else if (nonRecursiveNode .executeWith (frame , instance , currentKlass )) {
1115
+ return true ;
1116
+ }
1137
1117
}
1138
- return check == TriState . TRUE ;
1118
+ return false ;
1139
1119
}
1140
1120
1141
- protected int getLength (PTuple t ) {
1121
+ protected final int getLength (PTuple t ) {
1142
1122
if (lenNode == null ) {
1143
1123
CompilerDirectives .transferToInterpreterAndInvalidate ();
1144
1124
lenNode = insert (SequenceStorageNodes .LenNode .create ());
@@ -1155,78 +1135,78 @@ private Object[] getArray(PTuple tuple) {
1155
1135
}
1156
1136
}
1157
1137
1158
- // issubclass(class , classinfo)
1159
- @ Builtin (name = ISSUBCLASS , minNumOfPositionalArgs = 2 )
1138
+ // isinstance(object , classinfo)
1139
+ @ Builtin (name = ISINSTANCE , minNumOfPositionalArgs = 2 )
1160
1140
@ GenerateNodeFactory
1161
- public abstract static class IsSubClassNode extends PythonBinaryBuiltinNode {
1162
- static final int MAX_EXPLODE_LOOP = 16 ; // is also divided by recursion depth+1
1141
+ public abstract static class IsInstanceNode extends RecursiveBinaryCheckBaseNode {
1163
1142
1164
- @ Child private SequenceStorageNodes .LenNode lenNode ;
1165
- @ Child private GetObjectArrayNode getObjectArrayNode ;
1166
- protected final byte depth ;
1167
-
1168
- protected IsSubClassNode (byte depth ) {
1169
- this .depth = depth ;
1143
+ protected IsInstanceNode (byte depth ) {
1144
+ super (depth );
1170
1145
}
1171
1146
1172
- protected IsSubClassNode () {
1147
+ protected IsInstanceNode () {
1173
1148
this ((byte ) 0 );
1174
1149
}
1175
1150
1176
- public static IsSubClassNode createRecursive (byte currentDepth ) {
1177
- return BuiltinFunctionsFactory .IsSubClassNodeFactory .create ((byte ) (currentDepth + 1 ));
1151
+ @ Override
1152
+ public IsInstanceNode createRecursive (byte newDepth ) {
1153
+ return BuiltinFunctionsFactory .IsInstanceNodeFactory .create (newDepth );
1178
1154
}
1179
1155
1180
- public abstract boolean executeWith (VirtualFrame frame , Object derived , Object cls );
1181
-
1182
- private static boolean isSubclassCheckInternal (VirtualFrame frame , Object derived , Object cls , LookupAndCallBinaryNode subclassCheckNode , CoerceToBooleanNode castToBooleanNode ) {
1183
- Object instanceCheckResult = subclassCheckNode .executeObject (frame , cls , derived );
1184
- return instanceCheckResult != NOT_IMPLEMENTED && castToBooleanNode .executeBoolean (frame , instanceCheckResult );
1156
+ private static TriState isInstanceCheckInternal (VirtualFrame frame , Object instance , Object cls , LookupAndCallBinaryNode instanceCheckNode , CoerceToBooleanNode castToBooleanNode ) {
1157
+ Object instanceCheckResult = instanceCheckNode .executeObject (frame , cls , instance );
1158
+ if (instanceCheckResult == NOT_IMPLEMENTED ) {
1159
+ return TriState .UNDEFINED ;
1160
+ }
1161
+ return TriState .valueOf (castToBooleanNode .executeBoolean (frame , instanceCheckResult ));
1185
1162
}
1186
1163
1187
- protected int getMaxExplodeLoop () {
1188
- return MAX_EXPLODE_LOOP / (depth + 1 );
1164
+ @ Specialization (guards = "isPythonClass(cls)" )
1165
+ static boolean isInstance (VirtualFrame frame , Object instance , Object cls ,
1166
+ @ Shared ("instanceCheck" ) @ Cached ("create(__INSTANCECHECK__)" ) LookupAndCallBinaryNode instanceCheckNode ,
1167
+ @ Shared ("boolCast" ) @ Cached ("createIfTrueNode()" ) CoerceToBooleanNode castToBooleanNode ,
1168
+ @ Cached GetClassNode getClassNode ,
1169
+ @ Cached TypeNodes .IsSameTypeNode isSameTypeNode ,
1170
+ @ Cached IsSubtypeNode isSubtypeNode ) {
1171
+ Object instanceClass = getClassNode .execute (instance );
1172
+ return isSameTypeNode .execute (instanceClass , cls ) || isSubtypeNode .execute (frame , instanceClass , cls )//
1173
+ || isInstanceCheckInternal (frame , instance , cls , instanceCheckNode , castToBooleanNode ) == TriState .TRUE ;
1189
1174
}
1190
1175
1191
- @ Specialization (guards = {"depth < getNodeRecursionLimit()" , "getLength(clsTuple) == cachedLen" , "cachedLen <= getMaxExplodeLoop()" }, limit = "getVariableArgumentInlineCacheLimit()" )
1192
- @ ExplodeLoop (kind = LoopExplosionKind .FULL_UNROLL_UNTIL_RETURN )
1193
- boolean isSubclassTupleConstantLen (VirtualFrame frame , Object derived , PTuple clsTuple ,
1194
- @ Cached ("getLength(clsTuple)" ) int cachedLen ,
1195
- @ Cached ("createRecursive(depth)" ) IsSubClassNode isSubclassNode ) {
1196
- Object [] array = getArray (clsTuple );
1197
- for (int i = 0 ; i < cachedLen ; i ++) {
1198
- Object cls = array [i ];
1199
- if (isSubclassNode .executeWith (frame , derived , cls )) {
1200
- return true ;
1201
- }
1176
+ @ Specialization (guards = {"!isPTuple(cls)" , "!isPythonClass(cls)" })
1177
+ static boolean isInstance (VirtualFrame frame , Object instance , Object cls ,
1178
+ @ Shared ("instanceCheck" ) @ Cached ("create(__INSTANCECHECK__)" ) LookupAndCallBinaryNode instanceCheckNode ,
1179
+ @ Shared ("boolCast" ) @ Cached ("createIfTrueNode()" ) CoerceToBooleanNode castToBooleanNode ,
1180
+ @ Cached TypeBuiltins .InstanceCheckNode typeInstanceCheckNode ) {
1181
+ TriState check = isInstanceCheckInternal (frame , instance , cls , instanceCheckNode , castToBooleanNode );
1182
+ if (check == TriState .UNDEFINED ) {
1183
+ return typeInstanceCheckNode .executeWith (frame , cls , instance );
1202
1184
}
1203
- return false ;
1185
+ return check == TriState . TRUE ;
1204
1186
}
1187
+ }
1205
1188
1206
- @ Specialization (guards = "depth < getNodeRecursionLimit()" , replaces = "isSubclassTupleConstantLen" )
1207
- boolean isSubclassRecursiveNode (VirtualFrame frame , Object derived , PTuple clsTuple ,
1208
- @ Cached ("createRecursive(depth)" ) IsSubClassNode isSubclassNode ) {
1209
- for (Object cls : getArray (clsTuple )) {
1210
- if (isSubclassNode .executeWith (frame , derived , cls )) {
1211
- return true ;
1212
- }
1213
- }
1214
- return false ;
1189
+ // issubclass(class, classinfo)
1190
+ @ Builtin (name = ISSUBCLASS , minNumOfPositionalArgs = 2 )
1191
+ @ GenerateNodeFactory
1192
+ public abstract static class IsSubClassNode extends RecursiveBinaryCheckBaseNode {
1193
+
1194
+ protected IsSubClassNode (byte depth ) {
1195
+ super (depth );
1215
1196
}
1216
1197
1217
- @ Specialization (guards = "depth >= getNodeRecursionLimit()" )
1218
- boolean isSubclassRecursiveCall (VirtualFrame frame , Object derived , PTuple clsTuple ) {
1219
- Object state = IndirectCallContext .enter (frame , getContext (), this );
1220
- try {
1221
- return isSubclassRecursiveTruffleBoundary (derived , clsTuple );
1222
- } finally {
1223
- IndirectCallContext .exit (frame , getContext (), state );
1224
- }
1198
+ protected IsSubClassNode () {
1199
+ this ((byte ) 0 );
1225
1200
}
1226
1201
1227
- @ TruffleBoundary
1228
- private boolean isSubclassRecursiveTruffleBoundary (Object derived , PTuple clsTuple ) {
1229
- return isSubclassRecursiveNode (null , derived , clsTuple , this );
1202
+ @ Override
1203
+ public IsSubClassNode createRecursive (byte newDepth ) {
1204
+ return BuiltinFunctionsFactory .IsSubClassNodeFactory .create (newDepth );
1205
+ }
1206
+
1207
+ private static boolean isSubclassCheckInternal (VirtualFrame frame , Object derived , Object cls , LookupAndCallBinaryNode subclassCheckNode , CoerceToBooleanNode castToBooleanNode ) {
1208
+ Object instanceCheckResult = subclassCheckNode .executeObject (frame , cls , derived );
1209
+ return instanceCheckResult != NOT_IMPLEMENTED && castToBooleanNode .executeBoolean (frame , instanceCheckResult );
1230
1210
}
1231
1211
1232
1212
@ Specialization (guards = "!isPTuple(cls)" )
@@ -1236,22 +1216,6 @@ static boolean isSubclass(VirtualFrame frame, Object derived, Object cls,
1236
1216
@ Cached IsSubtypeNode isSubtypeNode ) {
1237
1217
return isSubclassCheckInternal (frame , derived , cls , subclassCheckNode , castToBooleanNode ) || isSubtypeNode .execute (frame , derived , cls );
1238
1218
}
1239
-
1240
- protected int getLength (PTuple t ) {
1241
- if (lenNode == null ) {
1242
- CompilerDirectives .transferToInterpreterAndInvalidate ();
1243
- lenNode = insert (SequenceStorageNodes .LenNode .create ());
1244
- }
1245
- return lenNode .execute (t .getSequenceStorage ());
1246
- }
1247
-
1248
- private Object [] getArray (PTuple tuple ) {
1249
- if (getObjectArrayNode == null ) {
1250
- CompilerDirectives .transferToInterpreterAndInvalidate ();
1251
- getObjectArrayNode = insert (GetObjectArrayNodeGen .create ());
1252
- }
1253
- return getObjectArrayNode .execute (tuple );
1254
- }
1255
1219
}
1256
1220
1257
1221
// iter(object[, sentinel])
0 commit comments