001/* 002 * Copyright (c) 2011, 2014, 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.compiler.test.ea; 024 025import jdk.internal.jvmci.meta.*; 026 027import org.junit.*; 028 029import com.oracle.graal.graph.*; 030import com.oracle.graal.loop.phases.*; 031import com.oracle.graal.nodes.extended.*; 032import com.oracle.graal.nodes.virtual.*; 033import com.oracle.graal.phases.common.*; 034import com.oracle.graal.phases.schedule.*; 035import com.oracle.graal.virtual.phases.ea.*; 036 037/** 038 * The PartialEscapeAnalysisPhase is expected to remove all allocations and return the correct 039 * values. 040 */ 041public class EscapeAnalysisTest extends EATestBase { 042 043 @Test 044 public void test1() { 045 testEscapeAnalysis("test1Snippet", JavaConstant.forInt(101), false); 046 } 047 048 public static int test1Snippet() { 049 Integer x = new Integer(101); 050 return x.intValue(); 051 } 052 053 @Test 054 public void test2() { 055 testEscapeAnalysis("test2Snippet", JavaConstant.forInt(0), false); 056 } 057 058 public static int test2Snippet() { 059 Integer[] x = new Integer[0]; 060 return x.length; 061 } 062 063 @Test 064 public void test3() { 065 testEscapeAnalysis("test3Snippet", JavaConstant.NULL_POINTER, false); 066 } 067 068 public static Object test3Snippet() { 069 Integer[] x = new Integer[1]; 070 return x[0]; 071 } 072 073 @Test 074 public void testMonitor() { 075 testEscapeAnalysis("testMonitorSnippet", JavaConstant.forInt(0), false); 076 } 077 078 public static int testMonitorSnippet() { 079 Integer x = new Integer(0); 080 Double y = new Double(0); 081 Object z = new Object(); 082 synchronized (x) { 083 synchronized (y) { 084 synchronized (z) { 085 notInlineable(); 086 } 087 } 088 } 089 return x.intValue(); 090 } 091 092 @Test 093 public void testMonitor2() { 094 testEscapeAnalysis("testMonitor2Snippet", JavaConstant.forInt(0), false); 095 } 096 097 /** 098 * This test case differs from the last one in that it requires inlining within a synchronized 099 * region. 100 */ 101 public static int testMonitor2Snippet() { 102 Integer x = new Integer(0); 103 Double y = new Double(0); 104 Object z = new Object(); 105 synchronized (x) { 106 synchronized (y) { 107 synchronized (z) { 108 notInlineable(); 109 return x.intValue(); 110 } 111 } 112 } 113 } 114 115 @Test 116 public void testMerge() { 117 testEscapeAnalysis("testMerge1Snippet", JavaConstant.forInt(0), true); 118 } 119 120 public static int testMerge1Snippet(int a) { 121 TestClassInt obj = new TestClassInt(1, 0); 122 if (a < 0) { 123 obj.x = obj.x + 1; 124 } else { 125 obj.x = obj.x + 2; 126 obj.y = 0; 127 } 128 if (obj.x > 1000) { 129 return 1; 130 } 131 return obj.y; 132 } 133 134 @Test 135 public void testSimpleLoop() { 136 testEscapeAnalysis("testSimpleLoopSnippet", JavaConstant.forInt(1), false); 137 } 138 139 public int testSimpleLoopSnippet(int a) { 140 TestClassInt obj = new TestClassInt(1, 2); 141 for (int i = 0; i < a; i++) { 142 notInlineable(); 143 } 144 return obj.x; 145 } 146 147 @Test 148 public void testModifyingLoop() { 149 testEscapeAnalysis("testModifyingLoopSnippet", JavaConstant.forInt(1), false); 150 } 151 152 public int testModifyingLoopSnippet(int a) { 153 TestClassInt obj = new TestClassInt(1, 2); 154 for (int i = 0; i < a; i++) { 155 obj.x = 3; 156 notInlineable(); 157 } 158 return obj.x <= 3 ? 1 : 0; 159 } 160 161 @Test 162 public void testMergeAllocationsInt() { 163 testEscapeAnalysis("testMergeAllocationsIntSnippet", JavaConstant.forInt(1), false); 164 } 165 166 public int testMergeAllocationsIntSnippet(int a) { 167 TestClassInt obj; 168 if (a < 0) { 169 obj = new TestClassInt(1, 2); 170 notInlineable(); 171 } else { 172 obj = new TestClassInt(1, 2); 173 notInlineable(); 174 } 175 return obj.x <= 3 ? 1 : 0; 176 } 177 178 @Test 179 public void testMergeAllocationsObj() { 180 testEscapeAnalysis("testMergeAllocationsObjSnippet", JavaConstant.forInt(1), false); 181 } 182 183 public int testMergeAllocationsObjSnippet(int a) { 184 TestClassObject obj; 185 Integer one = 1; 186 Integer two = 2; 187 Integer three = 3; 188 if (a < 0) { 189 obj = new TestClassObject(one, two); 190 notInlineable(); 191 } else { 192 obj = new TestClassObject(one, three); 193 notInlineable(); 194 } 195 return ((Integer) obj.x).intValue() <= 3 ? 1 : 0; 196 } 197 198 @Test 199 public void testMergeAllocationsObjCirc() { 200 testEscapeAnalysis("testMergeAllocationsObjCircSnippet", JavaConstant.forInt(1), false); 201 } 202 203 public int testMergeAllocationsObjCircSnippet(int a) { 204 TestClassObject obj; 205 Integer one = 1; 206 Integer two = 2; 207 Integer three = 3; 208 if (a < 0) { 209 obj = new TestClassObject(one); 210 obj.y = obj; 211 obj.y = two; 212 notInlineable(); 213 } else { 214 obj = new TestClassObject(one); 215 obj.y = obj; 216 obj.y = three; 217 notInlineable(); 218 } 219 return ((Integer) obj.x).intValue() <= 3 ? 1 : 0; 220 } 221 222 static class MyException extends RuntimeException { 223 224 private static final long serialVersionUID = 0L; 225 226 protected Integer value; 227 228 public MyException(Integer value) { 229 super((Throwable) null); 230 this.value = value; 231 } 232 233 @SuppressWarnings("sync-override") 234 @Override 235 public final Throwable fillInStackTrace() { 236 return null; 237 } 238 } 239 240 @Test 241 public void testMergeAllocationsException() { 242 testEscapeAnalysis("testMergeAllocationsExceptionSnippet", JavaConstant.forInt(1), false); 243 } 244 245 public int testMergeAllocationsExceptionSnippet(int a) { 246 MyException obj; 247 Integer one = 1; 248 if (a < 0) { 249 obj = new MyException(one); 250 notInlineable(); 251 } else { 252 obj = new MyException(one); 253 notInlineable(); 254 } 255 return obj.value <= 3 ? 1 : 0; 256 } 257 258 @Test 259 public void testCheckCast() { 260 testEscapeAnalysis("testCheckCastSnippet", getSnippetReflection().forObject(TestClassObject.class), false); 261 } 262 263 public Object testCheckCastSnippet() { 264 TestClassObject obj = new TestClassObject(TestClassObject.class); 265 TestClassObject obj2 = new TestClassObject(obj); 266 return ((TestClassObject) obj2.x).x; 267 } 268 269 @Test 270 public void testInstanceOf() { 271 testEscapeAnalysis("testInstanceOfSnippet", JavaConstant.forInt(1), false); 272 } 273 274 public boolean testInstanceOfSnippet() { 275 TestClassObject obj = new TestClassObject(TestClassObject.class); 276 TestClassObject obj2 = new TestClassObject(obj); 277 return obj2.x instanceof TestClassObject; 278 } 279 280 @SuppressWarnings("unused") 281 public static void testNewNodeSnippet() { 282 new ValueAnchorNode(null); 283 } 284 285 /** 286 * This test makes sure that the allocation of a {@link Node} can be removed. It therefore also 287 * tests the intrinsification of {@link Object#getClass()}. 288 */ 289 @Test 290 public void testNewNode() { 291 testEscapeAnalysis("testNewNodeSnippet", null, false); 292 } 293 294 private static final TestClassObject staticObj = new TestClassObject(); 295 296 public static Object testFullyUnrolledLoopSnippet() { 297 /* 298 * This tests a case that can appear if PEA is performed both before and after loop 299 * unrolling/peeling: If the VirtualInstanceNode is not duplicated correctly with the loop, 300 * the resulting object will reference itself, and not a second (different) object. 301 */ 302 TestClassObject obj = staticObj; 303 for (int i = 0; i < 2; i++) { 304 obj = new TestClassObject(obj); 305 } 306 return obj.x; 307 } 308 309 @Test 310 public void testFullyUnrolledLoop() { 311 prepareGraph("testFullyUnrolledLoopSnippet", false); 312 new LoopFullUnrollPhase(new CanonicalizerPhase()).apply(graph, context); 313 new PartialEscapePhase(false, new CanonicalizerPhase()).apply(graph, context); 314 Assert.assertEquals(1, returnNodes.size()); 315 Assert.assertTrue(returnNodes.get(0).result() instanceof AllocatedObjectNode); 316 CommitAllocationNode commit = ((AllocatedObjectNode) returnNodes.get(0).result()).getCommit(); 317 Assert.assertEquals(2, commit.getValues().size()); 318 Assert.assertEquals(1, commit.getVirtualObjects().size()); 319 Assert.assertTrue("non-cyclic data structure expected", commit.getVirtualObjects().get(0) != commit.getValues().get(0)); 320 } 321 322 @SuppressWarnings("unused") private static Object staticField; 323 324 private static TestClassObject inlinedPart(TestClassObject obj) { 325 TestClassObject ret = new TestClassObject(obj); 326 staticField = null; 327 return ret; 328 } 329 330 public static Object testPeeledLoopSnippet() { 331 TestClassObject obj = staticObj; 332 int i = 0; 333 do { 334 obj = inlinedPart(obj); 335 } while (i++ < 10); 336 staticField = obj; 337 return obj.x; 338 } 339 340 @Test 341 public void testPeeledLoop() { 342 prepareGraph("testPeeledLoopSnippet", false); 343 new LoopPeelingPhase().apply(graph); 344 new SchedulePhase().apply(graph); 345 } 346 347 public static void testDeoptMonitorSnippetInner(Object o2, Object t, int i) { 348 staticField = null; 349 if (i == 0) { 350 staticField = o2; 351 Number n = (Number) t; 352 n.toString(); 353 } 354 } 355 356 public static void testDeoptMonitorSnippet(Object t, int i) { 357 TestClassObject o = new TestClassObject(); 358 TestClassObject o2 = new TestClassObject(o); 359 360 synchronized (o) { 361 testDeoptMonitorSnippetInner(o2, t, i); 362 } 363 } 364 365 @Test 366 public void testDeoptMonitor() { 367 test("testDeoptMonitorSnippet", new Object(), 0); 368 } 369}