1 /* 2 * Copyright (c) 2015, 2018, 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 24 25 package org.graalvm.compiler.replacements.test; 26 27 import org.graalvm.compiler.api.directives.GraalDirectives; 28 import org.graalvm.compiler.bytecode.BytecodeProvider; 29 import org.graalvm.compiler.debug.DebugCloseable; 30 import org.graalvm.compiler.debug.DebugContext; 31 import org.graalvm.compiler.debug.GraalError; 32 import org.graalvm.compiler.nodes.ValueNode; 33 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; 34 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; 35 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; 36 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; 37 import org.graalvm.compiler.replacements.Snippets; 38 import org.graalvm.compiler.word.Word; 39 import org.junit.Test; 40 41 import jdk.vm.ci.meta.ResolvedJavaMethod; 42 43 public class PointerTrackingTest extends ReplacementsTest implements Snippets { 44 45 @Test 46 public void testTracking() { 47 Result result = executeActual(getResolvedJavaMethod("trackingSnippet"), null, new Object()); 48 assertEquals(new Result("OK", null), result); 49 } 50 51 public static String trackingSnippet(Object obj) { 52 long trackedBeforeGC = getTrackedPointer(obj); 53 long untrackedBeforeGC = getUntrackedPointer(obj); 54 55 int i = 0; 56 while (untrackedBeforeGC == getTrackedPointer(obj)) { 57 System.gc(); 58 if (i++ > 100) { 59 return "Timeout! Object didn't move after 100 GCs."; 60 } 61 } 62 63 long trackedAfterGC = getTrackedPointer(obj); 64 long untrackedAfterGC = getUntrackedPointer(obj); 65 66 if (untrackedBeforeGC == untrackedAfterGC) { 67 /* 68 * The untracked pointer isn't supposed to be updated, so it should be different before 69 * and after GC. 70 */ 71 return "untrackedBeforeGC == untrackedAfterGC"; 72 } 73 if (trackedBeforeGC != trackedAfterGC) { 74 /* 75 * The trackedBeforeGC variable should be updated to the new location by the GC, so it 76 * should be equal to trackedAfterGC. 77 */ 78 return "trackedBeforeGC != trackedAfterGC"; 79 } 80 81 return "OK"; 82 } 83 84 @Test(expected = GraalError.class) 85 @SuppressWarnings("try") 86 public void testVerification() { 87 DebugContext debug = getDebugContext(); 88 try (DebugCloseable d = debug.disableIntercept(); DebugContext.Scope s = debug.scope("PointerTrackingTest")) { 89 compile(getResolvedJavaMethod("verificationSnippet"), null); 90 } 91 } 92 93 public static long verificationSnippet(Object obj) { 94 long value = getTrackedPointer(obj) * 7 + 3; 95 96 /* 97 * Ensure usage before and after GC to force the value to be alive across the safepoint. 98 * This should lead to a compiler error, since value can not be tracked in the reference 99 * map. 100 */ 101 GraalDirectives.blackhole(value); 102 System.gc(); 103 return value; 104 } 105 106 static long getTrackedPointer(@SuppressWarnings("unused") Object obj) { 107 throw GraalError.shouldNotReachHere("should be intrinsified"); 108 } 109 110 static long getUntrackedPointer(@SuppressWarnings("unused") Object obj) { 111 throw GraalError.shouldNotReachHere("should be intrinsified"); 112 } 113 114 static long getTrackedPointerIntrinsic(Object obj) { 115 return Word.objectToTrackedPointer(obj).rawValue(); 116 } 117 118 static long getUntrackedPointerIntrinsic(Object obj) { 119 return Word.objectToUntrackedPointer(obj).rawValue(); 120 } 121 122 private void register(Registration r, String fnName) { 123 ResolvedJavaMethod intrinsic = getResolvedJavaMethod(fnName + "Intrinsic"); 124 BytecodeProvider bytecodeProvider = getSystemClassLoaderBytecodeProvider(); 125 r.register1(fnName, Object.class, new InvocationPlugin() { 126 @Override 127 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { 128 return b.intrinsify(bytecodeProvider, targetMethod, intrinsic, receiver, new ValueNode[]{arg}); 129 } 130 }); 131 } 132 133 @Override 134 protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) { 135 Registration r = new Registration(invocationPlugins, PointerTrackingTest.class); 136 137 register(r, "getTrackedPointer"); 138 register(r, "getUntrackedPointer"); 139 } 140 }