1 /* 2 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.graalvm.compiler.core.test.ea; 24 25 import jdk.vm.ci.meta.JavaConstant; 26 27 import org.junit.Assert; 28 import org.junit.Test; 29 30 import org.graalvm.compiler.graph.Node; 31 import org.graalvm.compiler.loop.DefaultLoopPolicies; 32 import org.graalvm.compiler.loop.phases.LoopFullUnrollPhase; 33 import org.graalvm.compiler.loop.phases.LoopPeelingPhase; 34 import org.graalvm.compiler.nodes.extended.ValueAnchorNode; 35 import org.graalvm.compiler.nodes.virtual.AllocatedObjectNode; 36 import org.graalvm.compiler.nodes.virtual.CommitAllocationNode; 37 import org.graalvm.compiler.phases.common.CanonicalizerPhase; 38 import org.graalvm.compiler.phases.schedule.SchedulePhase; 39 import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase; 40 41 /** 42 * The PartialEscapeAnalysisPhase is expected to remove all allocations and return the correct 43 * values. 44 */ 45 public class EscapeAnalysisTest extends EATestBase { 46 47 @Test 48 public void test1() { 49 testEscapeAnalysis("test1Snippet", JavaConstant.forInt(101), false); 50 } 51 52 public static int test1Snippet() { 53 Integer x = new Integer(101); 54 return x.intValue(); 55 } 56 57 @Test 58 public void test2() { 59 testEscapeAnalysis("test2Snippet", JavaConstant.forInt(0), false); 60 } 61 62 public static int test2Snippet() { 63 Integer[] x = new Integer[0]; 64 return x.length; 65 } 66 67 @Test 68 public void test3() { 69 testEscapeAnalysis("test3Snippet", JavaConstant.NULL_POINTER, false); 70 } 71 72 public static Object test3Snippet() { 73 Integer[] x = new Integer[1]; 74 return x[0]; 75 } 76 77 @Test 78 public void testMonitor() { 79 testEscapeAnalysis("testMonitorSnippet", JavaConstant.forInt(0), false); 80 } 81 82 public static int testMonitorSnippet() { 83 Integer x = new Integer(0); 84 Double y = new Double(0); 85 Object z = new Object(); 86 synchronized (x) { 87 synchronized (y) { 88 synchronized (z) { 89 notInlineable(); 90 } 91 } 92 } 93 return x.intValue(); 94 } 95 96 @Test 97 public void testMonitor2() { 98 testEscapeAnalysis("testMonitor2Snippet", JavaConstant.forInt(0), false); 99 } 100 101 /** 102 * This test case differs from the last one in that it requires inlining within a synchronized 103 * region. 104 */ 105 public static int testMonitor2Snippet() { 106 Integer x = new Integer(0); 107 Double y = new Double(0); 108 Object z = new Object(); 109 synchronized (x) { 110 synchronized (y) { 111 synchronized (z) { 112 notInlineable(); 113 return x.intValue(); 114 } 115 } 116 } 117 } 118 119 @Test 120 public void testMerge() { 121 testEscapeAnalysis("testMerge1Snippet", JavaConstant.forInt(0), true); 122 } 123 124 public static int testMerge1Snippet(int a) { 125 TestClassInt obj = new TestClassInt(1, 0); 126 if (a < 0) { 127 obj.x = obj.x + 1; 128 } else { 129 obj.x = obj.x + 2; 130 obj.y = 0; 131 } 132 if (obj.x > 1000) { 133 return 1; 134 } 135 return obj.y; 136 } 137 138 @Test 139 public void testSimpleLoop() { 140 testEscapeAnalysis("testSimpleLoopSnippet", JavaConstant.forInt(1), false); 141 } 142 143 public int testSimpleLoopSnippet(int a) { 144 TestClassInt obj = new TestClassInt(1, 2); 145 for (int i = 0; i < a; i++) { 146 notInlineable(); 147 } 148 return obj.x; 149 } 150 151 @Test 152 public void testModifyingLoop() { 153 testEscapeAnalysis("testModifyingLoopSnippet", JavaConstant.forInt(1), false); 154 } 155 156 public int testModifyingLoopSnippet(int a) { 157 TestClassInt obj = new TestClassInt(1, 2); 158 for (int i = 0; i < a; i++) { 159 obj.x = 3; 160 notInlineable(); 161 } 162 return obj.x <= 3 ? 1 : 0; 163 } 164 165 @Test 166 public void testMergeAllocationsInt() { 167 testEscapeAnalysis("testMergeAllocationsIntSnippet", JavaConstant.forInt(1), false); 168 } 169 170 public int testMergeAllocationsIntSnippet(int a) { 171 TestClassInt obj; 172 if (a < 0) { 173 obj = new TestClassInt(1, 2); 174 notInlineable(); 175 } else { 176 obj = new TestClassInt(1, 2); 177 notInlineable(); 178 } 179 return obj.x <= 3 ? 1 : 0; 180 } 181 182 @Test 183 public void testMergeAllocationsObj() { 184 testEscapeAnalysis("testMergeAllocationsObjSnippet", JavaConstant.forInt(1), false); 185 } 186 187 public int testMergeAllocationsObjSnippet(int a) { 188 TestClassObject obj; 189 Integer one = 1; 190 Integer two = 2; 191 Integer three = 3; 192 if (a < 0) { 193 obj = new TestClassObject(one, two); 194 notInlineable(); 195 } else { 196 obj = new TestClassObject(one, three); 197 notInlineable(); 198 } 199 return ((Integer) obj.x).intValue() <= 3 ? 1 : 0; 200 } 201 202 @Test 203 public void testMergeAllocationsObjCirc() { 204 testEscapeAnalysis("testMergeAllocationsObjCircSnippet", JavaConstant.forInt(1), false); 205 } 206 207 public int testMergeAllocationsObjCircSnippet(int a) { 208 TestClassObject obj; 209 Integer one = 1; 210 Integer two = 2; 211 Integer three = 3; 212 if (a < 0) { 213 obj = new TestClassObject(one); 214 obj.y = obj; 215 obj.y = two; 216 notInlineable(); 217 } else { 218 obj = new TestClassObject(one); 219 obj.y = obj; 220 obj.y = three; 221 notInlineable(); 222 } 223 return ((Integer) obj.x).intValue() <= 3 ? 1 : 0; 224 } 225 226 static class MyException extends RuntimeException { 227 228 private static final long serialVersionUID = 0L; 229 230 protected Integer value; 231 232 MyException(Integer value) { 233 super((Throwable) null); 234 this.value = value; 235 } 236 237 @SuppressWarnings("sync-override") 238 @Override 239 public final Throwable fillInStackTrace() { 240 return null; 241 } 242 } 243 244 @Test 245 public void testMergeAllocationsException() { 246 testEscapeAnalysis("testMergeAllocationsExceptionSnippet", JavaConstant.forInt(1), false); 247 } 248 249 public int testMergeAllocationsExceptionSnippet(int a) { 250 MyException obj; 251 Integer one = 1; 252 if (a < 0) { 253 obj = new MyException(one); 254 notInlineable(); 255 } else { 256 obj = new MyException(one); 257 notInlineable(); 258 } 259 return obj.value <= 3 ? 1 : 0; 260 } 261 262 @Test 263 public void testCheckCast() { 264 testEscapeAnalysis("testCheckCastSnippet", getSnippetReflection().forObject(TestClassObject.class), false); 265 } 266 267 public Object testCheckCastSnippet() { 268 TestClassObject obj = new TestClassObject(TestClassObject.class); 269 TestClassObject obj2 = new TestClassObject(obj); 270 return ((TestClassObject) obj2.x).x; 271 } 272 273 @Test 274 public void testInstanceOf() { 275 testEscapeAnalysis("testInstanceOfSnippet", JavaConstant.forInt(1), false); 276 } 277 278 public boolean testInstanceOfSnippet() { 279 TestClassObject obj = new TestClassObject(TestClassObject.class); 280 TestClassObject obj2 = new TestClassObject(obj); 281 return obj2.x instanceof TestClassObject; 282 } 283 284 @SuppressWarnings("unused") 285 public static void testNewNodeSnippet() { 286 new ValueAnchorNode(null); 287 } 288 289 /** 290 * This test makes sure that the allocation of a {@link Node} can be removed. It therefore also 291 * tests the intrinsification of {@link Object#getClass()}. 292 */ 293 @Test 294 public void testNewNode() { 295 testEscapeAnalysis("testNewNodeSnippet", null, false); 296 } 297 298 private static final TestClassObject staticObj = new TestClassObject(); 299 300 public static Object testFullyUnrolledLoopSnippet() { 301 /* 302 * This tests a case that can appear if PEA is performed both before and after loop 303 * unrolling/peeling: If the VirtualInstanceNode is not duplicated correctly with the loop, 304 * the resulting object will reference itself, and not a second (different) object. 305 */ 306 TestClassObject obj = staticObj; 307 for (int i = 0; i < 2; i++) { 308 obj = new TestClassObject(obj); 309 } 310 return obj.x; 311 } 312 313 @Test 314 public void testFullyUnrolledLoop() { 315 prepareGraph("testFullyUnrolledLoopSnippet", false); 316 new LoopFullUnrollPhase(new CanonicalizerPhase(), new DefaultLoopPolicies()).apply(graph, context); 317 new PartialEscapePhase(false, new CanonicalizerPhase()).apply(graph, context); 318 Assert.assertEquals(1, returnNodes.size()); 319 Assert.assertTrue(returnNodes.get(0).result() instanceof AllocatedObjectNode); 320 CommitAllocationNode commit = ((AllocatedObjectNode) returnNodes.get(0).result()).getCommit(); 321 Assert.assertEquals(2, commit.getValues().size()); 322 Assert.assertEquals(1, commit.getVirtualObjects().size()); 323 Assert.assertTrue("non-cyclic data structure expected", commit.getVirtualObjects().get(0) != commit.getValues().get(0)); 324 } 325 326 @SuppressWarnings("unused") private static Object staticField; 327 328 private static TestClassObject inlinedPart(TestClassObject obj) { 329 TestClassObject ret = new TestClassObject(obj); 330 staticField = null; 331 return ret; 332 } 333 334 public static Object testPeeledLoopSnippet() { 335 TestClassObject obj = staticObj; 336 int i = 0; 337 do { 338 obj = inlinedPart(obj); 339 } while (i++ < 10); 340 staticField = obj; 341 return obj.x; 342 } 343 344 @Test 345 public void testPeeledLoop() { 346 prepareGraph("testPeeledLoopSnippet", false); 347 new LoopPeelingPhase(new DefaultLoopPolicies()).apply(graph, getDefaultHighTierContext()); 348 new SchedulePhase().apply(graph); 349 } 350 351 public static void testDeoptMonitorSnippetInner(Object o2, Object t, int i) { 352 staticField = null; 353 if (i == 0) { 354 staticField = o2; 355 Number n = (Number) t; 356 n.toString(); 357 } 358 } 359 360 public static void testDeoptMonitorSnippet(Object t, int i) { 361 TestClassObject o = new TestClassObject(); 362 TestClassObject o2 = new TestClassObject(o); 363 364 synchronized (o) { 365 testDeoptMonitorSnippetInner(o2, t, i); 366 } 367 } 368 369 @Test 370 public void testDeoptMonitor() { 371 test("testDeoptMonitorSnippet", new Object(), 0); 372 } 373 }