1 /* 2 * Copyright (c) 2016, 2016, 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.api.directives.test; 24 25 import java.io.IOException; 26 27 import org.junit.Assert; 28 import org.junit.Test; 29 30 import org.graalvm.compiler.api.directives.GraalDirectives; 31 import org.graalvm.compiler.core.common.GraalOptions; 32 import org.graalvm.compiler.core.test.GraalCompilerTest; 33 import org.graalvm.compiler.options.OptionValue; 34 import org.graalvm.compiler.options.OptionValue.OverrideScope; 35 36 import jdk.internal.org.objectweb.asm.Opcodes; 37 import jdk.vm.ci.code.InstalledCode; 38 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; 39 import jdk.vm.ci.meta.ResolvedJavaMethod; 40 41 @SuppressWarnings("try") 42 public class AllocationInstrumentationTest extends GraalCompilerTest { 43 44 private TinyInstrumentor instrumentor; 45 46 public AllocationInstrumentationTest() { 47 HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(ClassA.class, "notInlinedMethod"); 48 method.setNotInlineable(); 49 50 try { 51 instrumentor = new TinyInstrumentor(AllocationInstrumentationTest.class, "instrumentation"); 52 } catch (IOException e) { 53 Assert.fail("unable to initialize the instrumentor: " + e); 54 } 55 } 56 57 public static class ClassA { 58 // This method should be marked as not inlineable 59 public void notInlinedMethod() { 60 } 61 } 62 63 public static boolean allocationWasExecuted; 64 65 private static void resetFlag() { 66 allocationWasExecuted = false; 67 } 68 69 static void instrumentation() { 70 GraalDirectives.instrumentationBeginForPredecessor(); 71 allocationWasExecuted = true; 72 GraalDirectives.instrumentationEnd(); 73 } 74 75 public static void notEscapeSnippet() { 76 @SuppressWarnings("unused") 77 ClassA a = new ClassA(); // a does not escape 78 } 79 80 @Test 81 public void testNotEscape() { 82 try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) { 83 Class<?> clazz = instrumentor.instrument(AllocationInstrumentationTest.class, "notEscapeSnippet", Opcodes.NEW); 84 ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "notEscapeSnippet"); 85 executeExpected(method, null); // ensure the method is fully resolved 86 resetFlag(); 87 // The allocation in the snippet does not escape and will be optimized away. We expect 88 // the instrumentation is removed. 89 InstalledCode code = getCode(method); 90 code.executeVarargs(); 91 Assert.assertFalse("allocation should not take place", allocationWasExecuted); 92 } catch (Throwable e) { 93 throw new AssertionError(e); 94 } 95 } 96 97 public static void mustEscapeSnippet() { 98 ClassA a = new ClassA(); 99 a.notInlinedMethod(); // a escapses 100 } 101 102 @Test 103 public void testMustEscape() { 104 try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) { 105 Class<?> clazz = instrumentor.instrument(AllocationInstrumentationTest.class, "mustEscapeSnippet", Opcodes.NEW); 106 ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "mustEscapeSnippet"); 107 executeExpected(method, null); // ensure the method is fully resolved 108 resetFlag(); 109 // The allocation in the snippet escapes. We expect the instrumentation is preserved. 110 InstalledCode code = getCode(method); 111 code.executeVarargs(); 112 Assert.assertTrue("allocation should take place", allocationWasExecuted); 113 } catch (Throwable e) { 114 throw new AssertionError(e); 115 } 116 } 117 118 public static void partialEscapeSnippet(boolean condition) { 119 ClassA a = new ClassA(); 120 121 if (condition) { 122 a.notInlinedMethod(); // a escapes in the then-clause 123 } 124 } 125 126 @Test 127 public void testPartialEscape() { 128 try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) { 129 Class<?> clazz = instrumentor.instrument(AllocationInstrumentationTest.class, "partialEscapeSnippet", Opcodes.NEW); 130 ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "partialEscapeSnippet"); 131 executeExpected(method, null, true); // ensure the method is fully resolved 132 resetFlag(); 133 // The allocation in the snippet escapes in the then-clause, and will be relocated to 134 // this branch. We expect the instrumentation follows and will only be effective when 135 // the then-clause is taken. 136 InstalledCode code = getCode(method); 137 code.executeVarargs(false); 138 Assert.assertFalse("allocation should not take place", allocationWasExecuted); 139 code.executeVarargs(true); 140 Assert.assertTrue("allocation should take place", allocationWasExecuted); 141 } catch (Throwable e) { 142 throw new AssertionError(e); 143 } 144 } 145 146 }