4949import com .oracle .graal .python .builtins .objects .cext .PythonAbstractNativeObject ;
5050import com .oracle .graal .python .builtins .objects .code .PCode ;
5151import com .oracle .graal .python .builtins .objects .ints .PInt ;
52+ import com .oracle .graal .python .builtins .objects .object .PythonObjectLibrary ;
5253import com .oracle .graal .python .builtins .objects .type .PythonBuiltinClass ;
5354import com .oracle .graal .python .nodes .expression .IsExpressionNodeGen .IsNodeGen ;
55+ import com .oracle .graal .python .nodes .object .IsBuiltinClassProfile ;
5456import com .oracle .graal .python .runtime .PythonContext ;
57+ import com .oracle .graal .python .runtime .PythonCore ;
5558import com .oracle .graal .python .runtime .PythonOptions ;
5659import com .oracle .truffle .api .RootCallTarget ;
5760import com .oracle .truffle .api .dsl .Cached ;
61+ import com .oracle .truffle .api .dsl .Cached .Shared ;
5862import com .oracle .truffle .api .dsl .CachedContext ;
59- import com .oracle .truffle .api .dsl .Fallback ;
6063import com .oracle .truffle .api .dsl .GenerateUncached ;
64+ import com .oracle .truffle .api .dsl .ImportStatic ;
6165import com .oracle .truffle .api .dsl .Specialization ;
66+ import com .oracle .truffle .api .library .CachedLibrary ;
6267import com .oracle .truffle .api .nodes .Node ;
6368
6469public abstract class IsExpressionNode extends BinaryOpNode {
@@ -72,6 +77,7 @@ boolean doIt(Object left, Object right,
7277 return isNode .execute (left , right );
7378 }
7479
80+ @ ImportStatic (PythonOptions .class )
7581 @ GenerateUncached
7682 public abstract static class IsNode extends Node {
7783
@@ -81,6 +87,7 @@ public final boolean execute(Object left, Object right) {
8187 return left == right || executeInternal (left , right );
8288 }
8389
90+ // Primitives
8491 @ Specialization
8592 boolean doBB (boolean left , boolean right ) {
8693 return left == right ;
@@ -104,6 +111,17 @@ boolean doBD(boolean left, double right) {
104111 return false ;
105112 }
106113
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+
107125 @ SuppressWarnings ("unused" )
108126 @ Specialization
109127 boolean doIB (int left , boolean right ) {
@@ -127,10 +145,15 @@ boolean doID(int left, double right) {
127145 }
128146
129147 @ 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 {
134157 return false ;
135158 }
136159 }
@@ -158,10 +181,15 @@ boolean doLD(long left, double right) {
158181 }
159182
160183 @ 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 {
165193 return false ;
166194 }
167195 }
@@ -191,6 +219,25 @@ boolean doDD(double left, double right) {
191219 return left == right || (Double .isNaN (left ) && Double .isNaN (right ));
192220 }
193221
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
194241 @ Specialization
195242 boolean doCT (PythonBuiltinClass left , PythonBuiltinClassType right ) {
196243 return left .getType () == right ;
@@ -201,33 +248,40 @@ boolean doTC(PythonBuiltinClassType left, PythonBuiltinClass right) {
201248 return right .getType () == left ;
202249 }
203250
251+ // native objects
204252 @ Specialization
205253 boolean doNative (PythonAbstractNativeObject left , PythonAbstractNativeObject right ,
206254 @ Cached CExtNodes .PointerCompareNode isNode ) {
207255 return isNode .execute (__EQ__ , left , right );
208256 }
209257
258+ // code
210259 @ Specialization
211260 boolean doCode (PCode left , PCode right ) {
212261 // Special case for code objects: Frames create them on-demand even if they refer to the
213262 // 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+ }
219272 }
220- return left == right ;
273+ return true ;
221274 }
222275
276+ // none
223277 @ Specialization
224278 boolean doObjectPNone (Object left , PNone right ,
225279 @ Cached .Shared ("ctxt" ) @ CachedContext (PythonLanguage .class ) PythonContext ctxt ) {
226280 if (ctxt .getOption (PythonOptions .EmulateJython ) && ctxt .getEnv ().isHostObject (left ) && ctxt .getEnv ().asHostObject (left ) == null &&
227281 right == PNone .NONE ) {
228282 return true ;
229283 }
230- return doGeneric ( left , right ) ;
284+ return left == right ;
231285 }
232286
233287 @ Specialization
@@ -236,9 +290,22 @@ boolean doPNoneObject(PNone left, Object right,
236290 return doObjectPNone (right , left , ctxt );
237291 }
238292
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 ;
242309 }
243310
244311 public static IsNode create () {
0 commit comments