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