49
49
import com .oracle .graal .python .builtins .objects .cext .PythonAbstractNativeObject ;
50
50
import com .oracle .graal .python .builtins .objects .code .PCode ;
51
51
import com .oracle .graal .python .builtins .objects .ints .PInt ;
52
+ import com .oracle .graal .python .builtins .objects .object .PythonObjectLibrary ;
52
53
import com .oracle .graal .python .builtins .objects .type .PythonBuiltinClass ;
53
54
import com .oracle .graal .python .nodes .expression .IsExpressionNodeGen .IsNodeGen ;
55
+ import com .oracle .graal .python .nodes .object .IsBuiltinClassProfile ;
54
56
import com .oracle .graal .python .runtime .PythonContext ;
57
+ import com .oracle .graal .python .runtime .PythonCore ;
55
58
import com .oracle .graal .python .runtime .PythonOptions ;
56
59
import com .oracle .truffle .api .RootCallTarget ;
57
60
import com .oracle .truffle .api .dsl .Cached ;
61
+ import com .oracle .truffle .api .dsl .Cached .Shared ;
58
62
import com .oracle .truffle .api .dsl .CachedContext ;
59
- import com .oracle .truffle .api .dsl .Fallback ;
60
63
import com .oracle .truffle .api .dsl .GenerateUncached ;
64
+ import com .oracle .truffle .api .dsl .ImportStatic ;
61
65
import com .oracle .truffle .api .dsl .Specialization ;
66
+ import com .oracle .truffle .api .library .CachedLibrary ;
62
67
import com .oracle .truffle .api .nodes .Node ;
63
68
64
69
public abstract class IsExpressionNode extends BinaryOpNode {
@@ -72,6 +77,7 @@ boolean doIt(Object left, Object right,
72
77
return isNode .execute (left , right );
73
78
}
74
79
80
+ @ ImportStatic (PythonOptions .class )
75
81
@ GenerateUncached
76
82
public abstract static class IsNode extends Node {
77
83
@@ -81,6 +87,7 @@ public final boolean execute(Object left, Object right) {
81
87
return left == right || executeInternal (left , right );
82
88
}
83
89
90
+ // Primitives
84
91
@ Specialization
85
92
boolean doBB (boolean left , boolean right ) {
86
93
return left == right ;
@@ -104,6 +111,17 @@ boolean doBD(boolean left, double right) {
104
111
return false ;
105
112
}
106
113
114
+ @ Specialization
115
+ boolean doBP (boolean left , PInt right ,
116
+ @ Shared ("ctxt" ) @ CachedContext (PythonLanguage .class ) PythonContext ctxt ) {
117
+ PythonCore core = ctxt .getCore ();
118
+ if (left ) {
119
+ return right == core .getTrue ();
120
+ } else {
121
+ return right == core .getFalse ();
122
+ }
123
+ }
124
+
107
125
@ SuppressWarnings ("unused" )
108
126
@ Specialization
109
127
boolean doIB (int left , boolean right ) {
@@ -127,10 +145,15 @@ boolean doID(int left, double right) {
127
145
}
128
146
129
147
@ Specialization
130
- boolean doIP (int left , PInt right ) {
131
- try {
132
- return right .intValueExact () == left ;
133
- } catch (ArithmeticException e ) {
148
+ boolean doIP (int left , PInt right ,
149
+ @ Shared ("isBuiltin" ) @ Cached IsBuiltinClassProfile isBuiltin ) {
150
+ if (isBuiltin .profileIsAnyBuiltinObject (right )) {
151
+ try {
152
+ return right .intValueExact () == left ;
153
+ } catch (ArithmeticException e ) {
154
+ return false ;
155
+ }
156
+ } else {
134
157
return false ;
135
158
}
136
159
}
@@ -158,10 +181,15 @@ boolean doLD(long left, double right) {
158
181
}
159
182
160
183
@ Specialization
161
- boolean doLP (long left , PInt right ) {
162
- try {
163
- return left == right .longValueExact ();
164
- } catch (ArithmeticException e ) {
184
+ boolean doLP (long left , PInt right ,
185
+ @ Shared ("isBuiltin" ) @ Cached IsBuiltinClassProfile isBuiltin ) {
186
+ if (isBuiltin .profileIsAnyBuiltinObject (right )) {
187
+ try {
188
+ return left == right .longValueExact ();
189
+ } catch (ArithmeticException e ) {
190
+ return false ;
191
+ }
192
+ } else {
165
193
return false ;
166
194
}
167
195
}
@@ -191,6 +219,25 @@ boolean doDD(double left, double right) {
191
219
return left == right || (Double .isNaN (left ) && Double .isNaN (right ));
192
220
}
193
221
222
+ @ Specialization
223
+ boolean doPB (PInt left , boolean right ,
224
+ @ Shared ("ctxt" ) @ CachedContext (PythonLanguage .class ) PythonContext ctxt ) {
225
+ return doBP (right , left , ctxt );
226
+ }
227
+
228
+ @ Specialization
229
+ boolean doPI (PInt left , int right ,
230
+ @ Shared ("isBuiltin" ) @ Cached IsBuiltinClassProfile isBuiltin ) {
231
+ return doIP (right , left , isBuiltin );
232
+ }
233
+
234
+ @ Specialization
235
+ boolean doPL (PInt left , long right ,
236
+ @ Shared ("isBuiltin" ) @ Cached IsBuiltinClassProfile isBuiltin ) {
237
+ return doLP (right , left , isBuiltin );
238
+ }
239
+
240
+ // types
194
241
@ Specialization
195
242
boolean doCT (PythonBuiltinClass left , PythonBuiltinClassType right ) {
196
243
return left .getType () == right ;
@@ -201,33 +248,40 @@ boolean doTC(PythonBuiltinClassType left, PythonBuiltinClass right) {
201
248
return right .getType () == left ;
202
249
}
203
250
251
+ // native objects
204
252
@ Specialization
205
253
boolean doNative (PythonAbstractNativeObject left , PythonAbstractNativeObject right ,
206
254
@ Cached CExtNodes .PointerCompareNode isNode ) {
207
255
return isNode .execute (__EQ__ , left , right );
208
256
}
209
257
258
+ // code
210
259
@ Specialization
211
260
boolean doCode (PCode left , PCode right ) {
212
261
// Special case for code objects: Frames create them on-demand even if they refer to the
213
262
// same function. So we need to compare the root nodes.
214
- RootCallTarget leftCt = left .getRootCallTarget ();
215
- RootCallTarget rightCt = right .getRootCallTarget ();
216
- if (leftCt != null && rightCt != null ) {
217
- // TODO: handle splitting, i.e., cloned root nodes
218
- return leftCt .getRootNode () == rightCt .getRootNode ();
263
+ if (left != right ) {
264
+ RootCallTarget leftCt = left .getRootCallTarget ();
265
+ RootCallTarget rightCt = right .getRootCallTarget ();
266
+ if (leftCt != null && rightCt != null ) {
267
+ // TODO: handle splitting, i.e., cloned root nodes
268
+ return leftCt .getRootNode () == rightCt .getRootNode ();
269
+ } else {
270
+ return false ;
271
+ }
219
272
}
220
- return left == right ;
273
+ return true ;
221
274
}
222
275
276
+ // none
223
277
@ Specialization
224
278
boolean doObjectPNone (Object left , PNone right ,
225
279
@ Cached .Shared ("ctxt" ) @ CachedContext (PythonLanguage .class ) PythonContext ctxt ) {
226
280
if (ctxt .getOption (PythonOptions .EmulateJython ) && ctxt .getEnv ().isHostObject (left ) && ctxt .getEnv ().asHostObject (left ) == null &&
227
281
right == PNone .NONE ) {
228
282
return true ;
229
283
}
230
- return doGeneric ( left , right ) ;
284
+ return left == right ;
231
285
}
232
286
233
287
@ Specialization
@@ -236,9 +290,22 @@ boolean doPNoneObject(PNone left, Object right,
236
290
return doObjectPNone (right , left , ctxt );
237
291
}
238
292
239
- @ Fallback
240
- boolean doGeneric (Object left , Object right ) {
241
- return left == right ;
293
+ // everything else
294
+ @ Specialization (limit = "getCallSiteInlineCacheMaxDepth()" )
295
+ boolean doGeneric (Object left , Object right ,
296
+ @ CachedLibrary ("left" ) PythonObjectLibrary lib ) {
297
+ if (left == right ) {
298
+ return true ;
299
+ }
300
+ if (lib .isForeignObject (left ) || lib .isReflectedObject (left , left )) {
301
+ // If left is foreign, this will check its identity via the interop message. If left
302
+ // is an object that is a wrapped Python object and uses a ReflectionLibrary, it
303
+ // will not appear foreign, but the isSame call will unpack it from its wrapper and
304
+ // may lead straight back to this node, but this time with the unwrapped Python
305
+ // object that will no longer satisfy the isReflectedObject condition.
306
+ return lib .isSame (left , right );
307
+ }
308
+ return false ;
242
309
}
243
310
244
311
public static IsNode create () {
0 commit comments