001/* 002 * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.replacements.test; 024 025import java.util.*; 026 027import jdk.internal.jvmci.code.CompilationResult.*; 028import com.oracle.graal.debug.*; 029import com.oracle.graal.debug.Debug.*; 030import jdk.internal.jvmci.meta.*; 031 032import org.junit.*; 033 034import com.oracle.graal.nodes.*; 035import com.oracle.graal.nodes.StructuredGraph.*; 036import com.oracle.graal.nodes.java.*; 037import com.oracle.graal.phases.common.*; 038import com.oracle.graal.replacements.test.CheckCastTest.Depth12; 039import com.oracle.graal.replacements.test.CheckCastTest.Depth13; 040import com.oracle.graal.replacements.test.CheckCastTest.Depth14; 041 042/** 043 * Tests the implementation of instanceof, allowing profiling information to be manually specified. 044 */ 045public class InstanceOfTest extends TypeCheckTest { 046 047 public InstanceOfTest() { 048 getSuites().getHighTier().findPhase(AbstractInliningPhase.class).remove(); 049 } 050 051 @Override 052 protected void replaceProfile(StructuredGraph graph, JavaTypeProfile profile) { 053 InstanceOfNode ion = graph.getNodes().filter(InstanceOfNode.class).first(); 054 if (ion != null) { 055 LogicNode ionNew = graph.unique(InstanceOfNode.create(ion.type(), ion.getValue(), profile)); 056 graph.replaceFloating(ion, ionNew); 057 } 058 } 059 060 @Test 061 public void test1() { 062 test("isString", profile(), "object"); 063 test("isString", profile(String.class), "object"); 064 065 test("isString", profile(), Object.class); 066 test("isString", profile(String.class), Object.class); 067 } 068 069 @Test 070 public void test2() { 071 test("isStringInt", profile(), "object"); 072 test("isStringInt", profile(String.class), "object"); 073 074 test("isStringInt", profile(), Object.class); 075 test("isStringInt", profile(String.class), Object.class); 076 } 077 078 @Test 079 public void test201() { 080 test("isStringIntComplex", profile(), "object"); 081 test("isStringIntComplex", profile(String.class), "object"); 082 083 test("isStringIntComplex", profile(), Object.class); 084 test("isStringIntComplex", profile(String.class), Object.class); 085 } 086 087 @Test 088 public void test3() { 089 Throwable throwable = new Exception(); 090 test("isThrowable", profile(), throwable); 091 test("isThrowable", profile(Throwable.class), throwable); 092 test("isThrowable", profile(Exception.class, Error.class), throwable); 093 094 test("isThrowable", profile(), Object.class); 095 test("isThrowable", profile(Throwable.class), Object.class); 096 test("isThrowable", profile(Exception.class, Error.class), Object.class); 097 } 098 099 @Test 100 public void test301() { 101 onlyFirstIsException(new Exception(), new Error()); 102 test("onlyFirstIsException", profile(), new Exception(), new Error()); 103 test("onlyFirstIsException", profile(), new Error(), new Exception()); 104 test("onlyFirstIsException", profile(), new Exception(), new Exception()); 105 test("onlyFirstIsException", profile(), new Error(), new Error()); 106 } 107 108 @Test 109 public void test4() { 110 Throwable throwable = new Exception(); 111 test("isThrowableInt", profile(), throwable); 112 test("isThrowableInt", profile(Throwable.class), throwable); 113 test("isThrowableInt", profile(Exception.class, Error.class), throwable); 114 115 test("isThrowableInt", profile(), Object.class); 116 test("isThrowableInt", profile(Throwable.class), Object.class); 117 test("isThrowableInt", profile(Exception.class, Error.class), Object.class); 118 } 119 120 @Test 121 public void test5() { 122 Map<?, ?> map = new HashMap<>(); 123 test("isMap", profile(), map); 124 test("isMap", profile(HashMap.class), map); 125 test("isMap", profile(TreeMap.class, HashMap.class), map); 126 127 test("isMap", profile(), Object.class); 128 test("isMap", profile(HashMap.class), Object.class); 129 test("isMap", profile(TreeMap.class, HashMap.class), Object.class); 130 test("isMap", profile(String.class, HashMap.class), Object.class); 131 } 132 133 @Test 134 public void test6() { 135 Map<?, ?> map = new HashMap<>(); 136 test("isMapInt", profile(), map); 137 test("isMapInt", profile(HashMap.class), map); 138 test("isMapInt", profile(TreeMap.class, HashMap.class), map); 139 140 test("isMapInt", profile(), Object.class); 141 test("isMapInt", profile(HashMap.class), Object.class); 142 test("isMapInt", profile(TreeMap.class, HashMap.class), Object.class); 143 } 144 145 @Test 146 public void test7() { 147 Object o = new Depth13(); 148 test("isDepth12", profile(), o); 149 test("isDepth12", profile(Depth13.class), o); 150 test("isDepth12", profile(Depth13.class, Depth14.class), o); 151 152 o = "not a depth"; 153 test("isDepth12", profile(), o); 154 test("isDepth12", profile(Depth13.class), o); 155 test("isDepth12", profile(Depth13.class, Depth14.class), o); 156 test("isDepth12", profile(String.class, HashMap.class), o); 157 } 158 159 @Test 160 public void test8() { 161 Object o = new Depth13(); 162 test("isDepth12Int", profile(), o); 163 test("isDepth12Int", profile(Depth13.class), o); 164 test("isDepth12Int", profile(Depth13.class, Depth14.class), o); 165 166 o = "not a depth"; 167 test("isDepth12Int", profile(), o); 168 test("isDepth12Int", profile(Depth13.class), o); 169 test("isDepth12Int", profile(Depth13.class, Depth14.class), o); 170 } 171 172 public static boolean isString(Object o) { 173 return o instanceof String; 174 } 175 176 public static int isStringInt(Object o) { 177 if (o instanceof String) { 178 return id(1); 179 } 180 return id(0); 181 } 182 183 public static int isStringIntComplex(Object o) { 184 if (o instanceof String || o instanceof Integer) { 185 return id(o instanceof String ? 1 : 0); 186 } 187 return id(0); 188 } 189 190 public static int id(int value) { 191 return value; 192 } 193 194 public static boolean isThrowable(Object o) { 195 return ((Throwable) o) instanceof Exception; 196 } 197 198 public static int onlyFirstIsException(Throwable t1, Throwable t2) { 199 if (t1 instanceof Exception ^ t2 instanceof Exception) { 200 return t1 instanceof Exception ? 1 : -1; 201 } 202 return -1; 203 } 204 205 public static int isThrowableInt(Object o) { 206 int result = o instanceof Throwable ? 4 : 5; 207 if (o instanceof Throwable) { 208 return id(4); 209 } 210 return result; 211 } 212 213 public static boolean isMap(Object o) { 214 return o instanceof Map; 215 } 216 217 public static int isMapInt(Object o) { 218 if (o instanceof Map) { 219 return id(1); 220 } 221 return id(0); 222 } 223 224 public static boolean isDepth12(Object o) { 225 return o instanceof Depth12; 226 } 227 228 public static int isDepth12Int(Object o) { 229 if (o instanceof Depth12) { 230 return id(0); 231 } 232 return id(0); 233 } 234 235 abstract static class MySite { 236 237 final int offset; 238 239 MySite(int offset) { 240 this.offset = offset; 241 } 242 } 243 244 static class MyMark extends MySite { 245 246 MyMark(int offset) { 247 super(offset); 248 } 249 } 250 251 abstract static class MySafepoint extends MySite { 252 253 MySafepoint(int offset) { 254 super(offset); 255 } 256 } 257 258 static class MyCall extends MySafepoint { 259 260 MyCall(int offset) { 261 super(offset); 262 } 263 } 264 265 @Test 266 public void test9() { 267 MyCall callAt63 = new MyCall(63); 268 MyMark markAt63 = new MyMark(63); 269 test("compareMySites", callAt63, callAt63); 270 test("compareMySites", callAt63, markAt63); 271 test("compareMySites", markAt63, callAt63); 272 test("compareMySites", markAt63, markAt63); 273 } 274 275 public static int compareMySites(MySite s1, MySite s2) { 276 if (s1.offset == s2.offset && (s1 instanceof MyMark ^ s2 instanceof MyMark)) { 277 return s1 instanceof MyMark ? -1 : 1; 278 } 279 return s1.offset - s2.offset; 280 } 281 282 @Test 283 public void test10() { 284 Call callAt63 = new Call(null, 63, 5, true, null); 285 Mark markAt63 = new Mark(63, "1"); 286 test("compareSites", callAt63, callAt63); 287 test("compareSites", callAt63, markAt63); 288 test("compareSites", markAt63, callAt63); 289 test("compareSites", markAt63, markAt63); 290 } 291 292 public static int compareSites(Site s1, Site s2) { 293 if (s1.pcOffset == s2.pcOffset && (s1 instanceof Mark ^ s2 instanceof Mark)) { 294 return s1 instanceof Mark ? -1 : 1; 295 } 296 return s1.pcOffset - s2.pcOffset; 297 } 298 299 /** 300 * This test exists to show the kind of pattern that is be optimizable by 301 * {@code removeIntermediateMaterialization()} in {@link IfNode}. 302 * <p> 303 * The test exists in this source file as the transformation was originally motivated by the 304 * need to remove use of special JumpNodes in the {@code InstanceOfSnippets}. 305 */ 306 @Test 307 public void testRemoveIntermediateMaterialization() { 308 List<String> list = Arrays.asList("1", "2", "3", "4"); 309 test("removeIntermediateMaterialization", profile(), list, "2", "yes", "no"); 310 test("removeIntermediateMaterialization", profile(), list, null, "yes", "no"); 311 test("removeIntermediateMaterialization", profile(), null, "2", "yes", "no"); 312 } 313 314 public static String removeIntermediateMaterialization(List<Object> list, Object e, String a, String b) { 315 boolean test; 316 if (list == null || e == null) { 317 test = false; 318 } else { 319 test = false; 320 for (Object i : list) { 321 if (i.equals(e)) { 322 test = true; 323 break; 324 } 325 } 326 } 327 if (test) { 328 return a; 329 } 330 return b; 331 } 332 333 abstract static class A { 334 } 335 336 static class B extends A { 337 } 338 339 static class C extends B { 340 } 341 342 abstract static class D extends C { 343 } 344 345 public static boolean isArrayOfA(Object o) { 346 return o instanceof A[]; 347 } 348 349 public static boolean isArrayOfB(Object o) { 350 return o instanceof B[]; 351 } 352 353 public static boolean isArrayOfC(Object o) { 354 return o instanceof C[]; 355 } 356 357 public static boolean isArrayOfD(Object o) { 358 return o instanceof D[]; 359 } 360 361 @Test 362 public void testArray() { 363 Object aArray = new A[10]; 364 test("isArrayOfA", aArray); 365 366 Object bArray = new B[10]; 367 test("isArrayOfA", aArray); 368 test("isArrayOfA", bArray); 369 test("isArrayOfB", aArray); 370 test("isArrayOfB", bArray); 371 372 Object cArray = new C[10]; 373 test("isArrayOfA", aArray); 374 test("isArrayOfA", bArray); 375 test("isArrayOfA", cArray); 376 test("isArrayOfB", aArray); 377 test("isArrayOfB", bArray); 378 test("isArrayOfB", cArray); 379 test("isArrayOfC", aArray); 380 test("isArrayOfC", bArray); 381 test("isArrayOfC", cArray); 382 383 Object dArray = new D[10]; 384 test("isArrayOfA", aArray); 385 test("isArrayOfA", bArray); 386 test("isArrayOfA", cArray); 387 test("isArrayOfA", dArray); 388 test("isArrayOfB", aArray); 389 test("isArrayOfB", bArray); 390 test("isArrayOfB", cArray); 391 test("isArrayOfB", dArray); 392 test("isArrayOfC", aArray); 393 test("isArrayOfC", bArray); 394 test("isArrayOfC", cArray); 395 test("isArrayOfC", dArray); 396 test("isArrayOfD", aArray); 397 test("isArrayOfD", bArray); 398 test("isArrayOfD", cArray); 399 test("isArrayOfD", dArray); 400 } 401 402 @SuppressWarnings("unchecked") 403 public static <T> String arrayCopyTypeName(T[] original) { 404 Class<? extends T[]> newType = (Class<? extends T[]>) original.getClass(); 405 if (newType == (Object) Object[].class) { 406 return Object[].class.getName(); 407 } else { 408 return newType.getName(); 409 } 410 } 411 412 @Test 413 public void testArrayCopy() { 414 test("arrayCopyTypeName", (Object) new Object[]{"one", "two", "three"}); 415 test("arrayCopyTypeName", (Object) new String[]{"one", "two", "three"}); 416 } 417 418 public int conditionalInstantiation(Object o) { 419 int total = 0; 420 if (o instanceof CharSequence) { 421 if (o instanceof StringBuilder || o instanceof String) { 422 total = 9; 423 } 424 total += (o instanceof String ? 2 : 1); 425 } 426 427 return total; 428 } 429 430 @Test 431 public void testInstantiation() { 432 test("conditionalInstantiation", "foo"); 433 test("conditionalInstantiation", new StringBuilder()); 434 test("conditionalInstantiation", 1); 435 } 436 437 public boolean exactlyObject(Thread thread) { 438 return thread != null && ((Object) thread).getClass() == Object.class; 439 } 440 441 public boolean exactlyObjectArray(Thread[] threads) { 442 return threads != null && ((Object[]) threads).getClass() == Object[].class; 443 } 444 445 public boolean exactlyString(Thread thread) { 446 return thread != null && ((Object) thread).getClass() == String.class; 447 } 448 449 public boolean exactlyStringArray(Thread[] threads) { 450 return threads != null && ((Object[]) threads).getClass() == String[].class; 451 } 452 453 @SuppressWarnings("cast") 454 public boolean instanceofStringArray(Thread[] threads) { 455 return threads != null && ((Object[]) threads) instanceof String[]; 456 } 457 458 @SuppressWarnings("cast") 459 public boolean instanceofString(Thread thread) { 460 return thread != null && ((Object) thread) instanceof String; 461 } 462 463 /** 464 * {@link TypeCheckNode} and {@link InstanceOfNode} should be equivalently powerful when 465 * comparing disjoint types. 466 */ 467 @Test 468 public void testTypeCheck() { 469 testConstantReturn("exactlyObject", 0); 470 testConstantReturn("exactlyObjectArray", 0); 471 testConstantReturn("exactlyString", 0); 472 testConstantReturn("exactlyStringArray", 0); 473 testConstantReturn("instanceofString", 0); 474 testConstantReturn("instanceofStringArray", 0); 475 } 476 477 private void testConstantReturn(String name, Object value) { 478 StructuredGraph result = buildGraph(name); 479 ReturnNode ret = result.getNodes(ReturnNode.TYPE).first(); 480 assertDeepEquals(1, result.getNodes(ReturnNode.TYPE).count()); 481 482 assertDeepEquals(true, ret.result().isConstant()); 483 assertDeepEquals(value, ret.result().asJavaConstant().asBoxedPrimitive()); 484 } 485 486 protected StructuredGraph buildGraph(final String snippet) { 487 try (Scope s = Debug.scope("InstanceOfTest", getMetaAccess().lookupJavaMethod(getMethod(snippet)))) { 488 StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); 489 compile(graph.method(), graph); 490 Debug.dump(graph, snippet); 491 return graph; 492 } catch (Throwable e) { 493 throw Debug.handle(e); 494 } 495 } 496}