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.hotspot.stubs; 26 27 import static jdk.vm.ci.meta.DeoptimizationReason.RuntimeConstraint; 28 import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase.INJECTED_VMCONFIG; 29 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.clearPendingException; 30 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.getPendingException; 31 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.getAndClearObjectResult; 32 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadHubIntrinsic; 33 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.verifyOops; 34 import static org.graalvm.compiler.replacements.nodes.CStringConstant.cstring; 35 36 import java.lang.reflect.Method; 37 import java.lang.reflect.Modifier; 38 import java.util.Arrays; 39 import java.util.List; 40 41 import org.graalvm.compiler.api.replacements.Fold; 42 import org.graalvm.compiler.api.replacements.Fold.InjectedParameter; 43 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; 44 import org.graalvm.compiler.graph.Node.ConstantNodeParameter; 45 import org.graalvm.compiler.graph.Node.NodeIntrinsic; 46 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; 47 import org.graalvm.compiler.hotspot.nodes.DeoptimizeCallerNode; 48 import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode; 49 import org.graalvm.compiler.hotspot.nodes.VMErrorNode; 50 import org.graalvm.compiler.hotspot.word.KlassPointer; 51 import org.graalvm.compiler.nodes.PiNode; 52 import org.graalvm.compiler.nodes.SnippetAnchorNode; 53 import org.graalvm.compiler.nodes.extended.GuardingNode; 54 import org.graalvm.compiler.replacements.Log; 55 import org.graalvm.compiler.word.Word; 56 import jdk.internal.vm.compiler.word.Pointer; 57 import jdk.internal.vm.compiler.word.WordFactory; 58 59 import jdk.vm.ci.meta.DeoptimizationAction; 60 61 //JaCoCo Exclude 62 63 /** 64 * A collection of methods used in {@link Stub}s. 65 */ 66 public class StubUtil { 67 68 public static final ForeignCallDescriptor VM_MESSAGE_C = newDescriptor(StubUtil.class, "vmMessageC", void.class, boolean.class, Word.class, long.class, long.class, long.class); 69 70 public static ForeignCallDescriptor newDescriptor(Class<?> stubClass, String name, Class<?> resultType, Class<?>... argumentTypes) { 71 ForeignCallDescriptor d = new ForeignCallDescriptor(name, resultType, argumentTypes); 72 assert descriptorFor(stubClass, name).equals(d) : descriptorFor(stubClass, name) + " != " + d; 73 return d; 74 } 75 76 /** 77 * Looks for a {@link StubForeignCallNode} node intrinsic named {@code name} in 78 * {@code stubClass} and returns a {@link ForeignCallDescriptor} based on its signature and the 79 * value of {@code hasSideEffect}. 80 */ 81 private static ForeignCallDescriptor descriptorFor(Class<?> stubClass, String name) { 82 Method found = null; 83 for (Method method : stubClass.getDeclaredMethods()) { 84 if (Modifier.isStatic(method.getModifiers()) && method.getAnnotation(NodeIntrinsic.class) != null && method.getName().equals(name)) { 85 if (method.getAnnotation(NodeIntrinsic.class).value().equals(StubForeignCallNode.class)) { 86 assert found == null : "found more than one foreign call named " + name + " in " + stubClass; 87 assert method.getParameterTypes().length != 0 && method.getParameterTypes()[0] == ForeignCallDescriptor.class : "first parameter of foreign call '" + name + "' in " + stubClass + 88 " must be of type " + ForeignCallDescriptor.class.getSimpleName(); 89 found = method; 90 } 91 } 92 } 93 assert found != null : "could not find foreign call named " + name + " in " + stubClass; 94 List<Class<?>> paramList = Arrays.asList(found.getParameterTypes()); 95 Class<?>[] cCallTypes = paramList.subList(1, paramList.size()).toArray(new Class<?>[paramList.size() - 1]); 96 return new ForeignCallDescriptor(name, found.getReturnType(), cCallTypes); 97 } 98 99 public static void handlePendingException(Word thread, boolean shouldClearException, boolean isObjectResult) { 100 if ((shouldClearException && clearPendingException(thread) != null) || (!shouldClearException && getPendingException(thread) != null)) { 101 if (isObjectResult) { 102 getAndClearObjectResult(thread); 103 } 104 DeoptimizeCallerNode.deopt(DeoptimizationAction.None, RuntimeConstraint); 105 } 106 } 107 108 /** 109 * Determines if this is a HotSpot build where the ASSERT mechanism is enabled. 110 */ 111 @Fold 112 public static boolean cAssertionsEnabled(@InjectedParameter GraalHotSpotVMConfig config) { 113 return config.cAssertions; 114 } 115 116 @NodeIntrinsic(StubForeignCallNode.class) 117 private static native void vmMessageC(@ConstantNodeParameter ForeignCallDescriptor stubPrintfC, boolean vmError, Word format, long v1, long v2, long v3); 118 119 /** 120 * Prints a message to the log stream. 121 * <p> 122 * <b>Stubs must use this instead of {@link Log#printf(String, long)} to avoid an object 123 * constant in a RuntimeStub.</b> 124 * 125 * @param message a message string 126 */ 127 public static void printf(String message) { 215 public static void fatal(String format, long v1, long v2) { 216 vmMessageC(VM_MESSAGE_C, true, cstring(format), v1, v2, 0L); 217 } 218 219 /** 220 * Exits the VM with a given error message. 221 * <p> 222 * <b>Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an 223 * object constant in a RuntimeStub.</b> 224 * 225 * @param format a C style printf format value 226 * @param v1 the value associated with the first conversion specifier in {@code format} 227 * @param v2 the value associated with the second conversion specifier in {@code format} 228 * @param v3 the value associated with the third conversion specifier in {@code format} 229 */ 230 public static void fatal(String format, long v1, long v2, long v3) { 231 vmMessageC(VM_MESSAGE_C, true, cstring(format), v1, v2, v3); 232 } 233 234 /** 235 * Verifies that a given object value is well formed if {@code -XX:+VerifyOops} is enabled. 236 */ 237 public static Object verifyObject(Object object) { 238 if (verifyOops(INJECTED_VMCONFIG)) { 239 Word verifyOopCounter = WordFactory.unsigned(verifyOopCounterAddress(INJECTED_VMCONFIG)); 240 verifyOopCounter.writeInt(0, verifyOopCounter.readInt(0) + 1); 241 242 Pointer oop = Word.objectToTrackedPointer(object); 243 if (object != null) { 244 GuardingNode anchorNode = SnippetAnchorNode.anchor(); 245 // make sure object is 'reasonable' 246 if (!oop.and(WordFactory.unsigned(verifyOopMask(INJECTED_VMCONFIG))).equal(WordFactory.unsigned(verifyOopBits(INJECTED_VMCONFIG)))) { 247 fatal("oop not in heap: %p", oop.rawValue()); 248 } 249 250 KlassPointer klass = loadHubIntrinsic(PiNode.piCastNonNull(object, anchorNode)); 251 if (klass.isNull()) { 252 fatal("klass for oop %p is null", oop.rawValue()); 253 } 254 } 255 } 256 return object; 257 } 258 259 @Fold 260 static long verifyOopCounterAddress(@InjectedParameter GraalHotSpotVMConfig config) { 261 return config.verifyOopCounterAddress; 262 } 263 264 @Fold 265 static long verifyOopMask(@InjectedParameter GraalHotSpotVMConfig config) { 266 return config.verifyOopMask; 267 } 268 269 @Fold 270 static long verifyOopBits(@InjectedParameter GraalHotSpotVMConfig config) { 271 return config.verifyOopBits; 272 } 273 274 /** 275 * Print {@code number} as decimal string to {@code buffer}. 276 * 277 * @param buffer 278 * @param number 279 * @return A pointer pointing one byte right after the last printed digit in {@code buffer}. 280 */ 281 public static Word printNumber(Word buffer, long number) { 282 long tmpNumber = number; 283 int offset; 284 if (tmpNumber <= 0) { 285 tmpNumber = -tmpNumber; 286 offset = 1; 287 } else { 288 offset = 0; 289 } 290 while (tmpNumber > 0) { 291 tmpNumber /= 10; 292 offset++; 293 } 294 tmpNumber = number < 0 ? -number : number; | 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.hotspot.stubs; 26 27 import static org.graalvm.compiler.replacements.nodes.CStringConstant.cstring; 28 29 import java.lang.reflect.Method; 30 import java.lang.reflect.Modifier; 31 import java.util.Arrays; 32 import java.util.List; 33 34 import org.graalvm.compiler.api.replacements.Fold; 35 import org.graalvm.compiler.api.replacements.Fold.InjectedParameter; 36 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; 37 import org.graalvm.compiler.graph.Node.ConstantNodeParameter; 38 import org.graalvm.compiler.graph.Node.NodeIntrinsic; 39 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; 40 import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode; 41 import org.graalvm.compiler.hotspot.nodes.VMErrorNode; 42 import org.graalvm.compiler.replacements.Log; 43 import org.graalvm.compiler.word.Word; 44 import jdk.internal.vm.compiler.word.WordFactory; 45 46 //JaCoCo Exclude 47 48 /** 49 * A collection of methods used in {@link Stub}s. 50 */ 51 public class StubUtil { 52 53 public static final ForeignCallDescriptor VM_MESSAGE_C = newDescriptor(StubUtil.class, "vmMessageC", void.class, boolean.class, Word.class, long.class, long.class, long.class); 54 55 public static ForeignCallDescriptor newDescriptor(Class<?> stubClass, String name, Class<?> resultType, Class<?>... argumentTypes) { 56 ForeignCallDescriptor d = new ForeignCallDescriptor(name, resultType, argumentTypes); 57 assert descriptorFor(stubClass, name).equals(d) : descriptorFor(stubClass, name) + " != " + d; 58 return d; 59 } 60 61 /** 62 * Looks for a {@link StubForeignCallNode} node intrinsic named {@code name} in 63 * {@code stubClass} and returns a {@link ForeignCallDescriptor} based on its signature and the 64 * value of {@code hasSideEffect}. 65 */ 66 private static ForeignCallDescriptor descriptorFor(Class<?> stubClass, String name) { 67 Method found = null; 68 for (Method method : stubClass.getDeclaredMethods()) { 69 if (Modifier.isStatic(method.getModifiers()) && method.getAnnotation(NodeIntrinsic.class) != null && method.getName().equals(name)) { 70 if (method.getAnnotation(NodeIntrinsic.class).value().equals(StubForeignCallNode.class)) { 71 assert found == null : "found more than one foreign call named " + name + " in " + stubClass; 72 assert method.getParameterTypes().length != 0 && method.getParameterTypes()[0] == ForeignCallDescriptor.class : "first parameter of foreign call '" + name + "' in " + stubClass + 73 " must be of type " + ForeignCallDescriptor.class.getSimpleName(); 74 found = method; 75 } 76 } 77 } 78 assert found != null : "could not find foreign call named " + name + " in " + stubClass; 79 List<Class<?>> paramList = Arrays.asList(found.getParameterTypes()); 80 Class<?>[] cCallTypes = paramList.subList(1, paramList.size()).toArray(new Class<?>[paramList.size() - 1]); 81 return new ForeignCallDescriptor(name, found.getReturnType(), cCallTypes); 82 } 83 84 /** 85 * Determines if this is a HotSpot build where the ASSERT mechanism is enabled. 86 */ 87 @Fold 88 public static boolean cAssertionsEnabled(@InjectedParameter GraalHotSpotVMConfig config) { 89 return config.cAssertions; 90 } 91 92 @NodeIntrinsic(StubForeignCallNode.class) 93 private static native void vmMessageC(@ConstantNodeParameter ForeignCallDescriptor stubPrintfC, boolean vmError, Word format, long v1, long v2, long v3); 94 95 /** 96 * Prints a message to the log stream. 97 * <p> 98 * <b>Stubs must use this instead of {@link Log#printf(String, long)} to avoid an object 99 * constant in a RuntimeStub.</b> 100 * 101 * @param message a message string 102 */ 103 public static void printf(String message) { 191 public static void fatal(String format, long v1, long v2) { 192 vmMessageC(VM_MESSAGE_C, true, cstring(format), v1, v2, 0L); 193 } 194 195 /** 196 * Exits the VM with a given error message. 197 * <p> 198 * <b>Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an 199 * object constant in a RuntimeStub.</b> 200 * 201 * @param format a C style printf format value 202 * @param v1 the value associated with the first conversion specifier in {@code format} 203 * @param v2 the value associated with the second conversion specifier in {@code format} 204 * @param v3 the value associated with the third conversion specifier in {@code format} 205 */ 206 public static void fatal(String format, long v1, long v2, long v3) { 207 vmMessageC(VM_MESSAGE_C, true, cstring(format), v1, v2, v3); 208 } 209 210 /** 211 * Print {@code number} as decimal string to {@code buffer}. 212 * 213 * @param buffer 214 * @param number 215 * @return A pointer pointing one byte right after the last printed digit in {@code buffer}. 216 */ 217 public static Word printNumber(Word buffer, long number) { 218 long tmpNumber = number; 219 int offset; 220 if (tmpNumber <= 0) { 221 tmpNumber = -tmpNumber; 222 offset = 1; 223 } else { 224 offset = 0; 225 } 226 while (tmpNumber > 0) { 227 tmpNumber /= 10; 228 offset++; 229 } 230 tmpNumber = number < 0 ? -number : number; |