001/* 002 * Copyright (c) 2013, 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.hotspot.stubs; 024 025import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; 026import static com.oracle.graal.hotspot.nodes.CStringNode.*; 027import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; 028import static com.oracle.graal.word.Word.*; 029import static jdk.internal.jvmci.meta.DeoptimizationReason.*; 030 031import java.lang.reflect.*; 032import java.util.*; 033 034import jdk.internal.jvmci.meta.*; 035 036import com.oracle.graal.api.replacements.*; 037import com.oracle.graal.compiler.common.spi.*; 038import com.oracle.graal.graph.Node.ConstantNodeParameter; 039import com.oracle.graal.graph.Node.NodeIntrinsic; 040import com.oracle.graal.hotspot.nodes.*; 041import com.oracle.graal.hotspot.word.*; 042import com.oracle.graal.nodes.extended.*; 043import com.oracle.graal.replacements.*; 044import com.oracle.graal.word.*; 045 046//JaCoCo Exclude 047 048/** 049 * A collection of methods used in {@link Stub}s. 050 */ 051public class StubUtil { 052 053 public static final ForeignCallDescriptor VM_MESSAGE_C = newDescriptor(StubUtil.class, "vmMessageC", void.class, boolean.class, Word.class, long.class, long.class, long.class); 054 055 public static ForeignCallDescriptor newDescriptor(Class<?> stubClass, String name, Class<?> resultType, Class<?>... argumentTypes) { 056 ForeignCallDescriptor d = new ForeignCallDescriptor(name, resultType, argumentTypes); 057 assert descriptorFor(stubClass, name).equals(d) : descriptorFor(stubClass, name) + " != " + d; 058 return d; 059 } 060 061 /** 062 * Looks for a {@link StubForeignCallNode} node intrinsic named {@code name} in 063 * {@code stubClass} and returns a {@link ForeignCallDescriptor} based on its signature and the 064 * value of {@code hasSideEffect}. 065 */ 066 private static ForeignCallDescriptor descriptorFor(Class<?> stubClass, String name) { 067 Method found = null; 068 for (Method method : stubClass.getDeclaredMethods()) { 069 if (Modifier.isStatic(method.getModifiers()) && method.getAnnotation(NodeIntrinsic.class) != null && method.getName().equals(name)) { 070 if (method.getAnnotation(NodeIntrinsic.class).value().equals(StubForeignCallNode.class)) { 071 assert found == null : "found more than one foreign call named " + name + " in " + stubClass; 072 assert method.getParameterTypes().length != 0 && method.getParameterTypes()[0] == ForeignCallDescriptor.class : "first parameter of foreign call '" + name + "' in " + stubClass + 073 " must be of type " + ForeignCallDescriptor.class.getSimpleName(); 074 found = method; 075 } 076 } 077 } 078 assert found != null : "could not find foreign call named " + name + " in " + stubClass; 079 List<Class<?>> paramList = Arrays.asList(found.getParameterTypes()); 080 Class<?>[] cCallTypes = paramList.subList(1, paramList.size()).toArray(new Class[paramList.size() - 1]); 081 return new ForeignCallDescriptor(name, found.getReturnType(), cCallTypes); 082 } 083 084 public static void handlePendingException(Word thread, boolean isObjectResult) { 085 if (clearPendingException(thread)) { 086 if (isObjectResult) { 087 getAndClearObjectResult(thread); 088 } 089 DeoptimizeCallerNode.deopt(DeoptimizationAction.None, RuntimeConstraint); 090 } 091 } 092 093 /** 094 * Determines if this is a HotSpot build where the ASSERT mechanism is enabled. 095 */ 096 @Fold 097 public static boolean cAssertionsEnabled() { 098 return runtime().getConfig().cAssertions; 099 } 100 101 @NodeIntrinsic(StubForeignCallNode.class) 102 private static native void vmMessageC(@ConstantNodeParameter ForeignCallDescriptor stubPrintfC, boolean vmError, Word format, long v1, long v2, long v3); 103 104 /** 105 * Prints a message to the log stream. 106 * <p> 107 * <b>Stubs must use this instead of {@link Log#printf(String, long)} to avoid an object 108 * constant in a RuntimeStub.</b> 109 * 110 * @param message a message string 111 */ 112 public static void printf(String message) { 113 vmMessageC(VM_MESSAGE_C, false, cstring(message), 0L, 0L, 0L); 114 } 115 116 /** 117 * Prints a message to the log stream. 118 * <p> 119 * <b>Stubs must use this instead of {@link Log#printf(String, long)} to avoid an object 120 * constant in a RuntimeStub.</b> 121 * 122 * @param format a C style printf format value 123 * @param value the value associated with the first conversion specifier in {@code format} 124 */ 125 public static void printf(String format, long value) { 126 vmMessageC(VM_MESSAGE_C, false, cstring(format), value, 0L, 0L); 127 } 128 129 /** 130 * Prints a message to the log stream. 131 * <p> 132 * <b>Stubs must use this instead of {@link Log#printf(String, long, long)} to avoid an object 133 * constant in a RuntimeStub.</b> 134 * 135 * @param format a C style printf format value 136 * @param v1 the value associated with the first conversion specifier in {@code format} 137 * @param v2 the value associated with the second conversion specifier in {@code format} 138 */ 139 public static void printf(String format, long v1, long v2) { 140 vmMessageC(VM_MESSAGE_C, false, cstring(format), v1, v2, 0L); 141 } 142 143 /** 144 * Prints a message to the log stream. 145 * <p> 146 * <b>Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an 147 * object constant in a RuntimeStub.</b> 148 * 149 * @param format a C style printf format value 150 * @param v1 the value associated with the first conversion specifier in {@code format} 151 * @param v2 the value associated with the second conversion specifier in {@code format} 152 * @param v3 the value associated with the third conversion specifier in {@code format} 153 */ 154 public static void printf(String format, long v1, long v2, long v3) { 155 vmMessageC(VM_MESSAGE_C, false, cstring(format), v1, v2, v3); 156 } 157 158 /** 159 * Analyzes a given value and prints information about it to the log stream. 160 */ 161 public static void decipher(long value) { 162 vmMessageC(VM_MESSAGE_C, false, Word.zero(), value, 0L, 0L); 163 } 164 165 /** 166 * Exits the VM with a given error message. 167 * <p> 168 * <b>Stubs must use this instead of {@link VMErrorNode#vmError(String, long)} to avoid an 169 * object constant in a RuntimeStub.</b> 170 * 171 * @param message an error message 172 */ 173 public static void fatal(String message) { 174 vmMessageC(VM_MESSAGE_C, true, cstring(message), 0L, 0L, 0L); 175 } 176 177 /** 178 * Exits the VM with a given error message. 179 * <p> 180 * <b>Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an 181 * object constant in a RuntimeStub.</b> 182 * 183 * @param format a C style printf format value 184 * @param value the value associated with the first conversion specifier in {@code format} 185 */ 186 public static void fatal(String format, long value) { 187 vmMessageC(VM_MESSAGE_C, true, cstring(format), value, 0L, 0L); 188 } 189 190 /** 191 * Exits the VM with a given error message. 192 * <p> 193 * <b>Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an 194 * object constant in a RuntimeStub.</b> 195 * 196 * @param format a C style printf format value 197 * @param v1 the value associated with the first conversion specifier in {@code format} 198 * @param v2 the value associated with the second conversion specifier in {@code format} 199 */ 200 public static void fatal(String format, long v1, long v2) { 201 vmMessageC(VM_MESSAGE_C, true, cstring(format), v1, v2, 0L); 202 } 203 204 /** 205 * Exits the VM with a given error message. 206 * <p> 207 * <b>Stubs must use this instead of {@link Log#printf(String, long, long, long)} to avoid an 208 * object constant in a RuntimeStub.</b> 209 * 210 * @param format a C style printf format value 211 * @param v1 the value associated with the first conversion specifier in {@code format} 212 * @param v2 the value associated with the second conversion specifier in {@code format} 213 * @param v3 the value associated with the third conversion specifier in {@code format} 214 */ 215 public static void fatal(String format, long v1, long v2, long v3) { 216 vmMessageC(VM_MESSAGE_C, true, cstring(format), v1, v2, v3); 217 } 218 219 /** 220 * Verifies that a given object value is well formed if {@code -XX:+VerifyOops} is enabled. 221 */ 222 public static Object verifyObject(Object object) { 223 if (verifyOops()) { 224 Word verifyOopCounter = Word.unsigned(verifyOopCounterAddress()); 225 verifyOopCounter.writeInt(0, verifyOopCounter.readInt(0) + 1); 226 227 Pointer oop = Word.fromObject(object); 228 if (object != null) { 229 GuardingNode anchorNode = SnippetAnchorNode.anchor(); 230 // make sure object is 'reasonable' 231 if (!oop.and(unsigned(verifyOopMask())).equal(unsigned(verifyOopBits()))) { 232 fatal("oop not in heap: %p", oop.rawValue()); 233 } 234 235 KlassPointer klass = loadHubIntrinsic(object, anchorNode); 236 if (klass.isNull()) { 237 fatal("klass for oop %p is null", oop.rawValue()); 238 } 239 } 240 } 241 return object; 242 } 243 244 @Fold 245 private static long verifyOopCounterAddress() { 246 return config().verifyOopCounterAddress; 247 } 248 249 @Fold 250 private static long verifyOopMask() { 251 return config().verifyOopMask; 252 } 253 254 @Fold 255 private static long verifyOopBits() { 256 return config().verifyOopBits; 257 } 258 259 @Fold 260 private static int hubOffset() { 261 return config().hubOffset; 262 } 263}