1 /* 2 * Copyright (c) 2013, 2019, 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.hotspot.meta; 26 27 import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.JavaCall; 28 import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.JavaCallee; 29 import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.DESTROYS_ALL_CALLER_SAVE_REGISTERS; 30 import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.SAFEPOINT; 31 32 import java.util.ArrayList; 33 import java.util.List; 34 35 import jdk.internal.vm.compiler.collections.EconomicMap; 36 import org.graalvm.compiler.core.common.LIRKind; 37 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; 38 import org.graalvm.compiler.debug.GraalError; 39 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; 40 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Reexecutability; 41 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect; 42 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition; 43 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkageImpl; 44 import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; 45 import org.graalvm.compiler.hotspot.stubs.ForeignCallStub; 46 import org.graalvm.compiler.hotspot.stubs.Stub; 47 import org.graalvm.compiler.options.OptionValues; 48 import org.graalvm.compiler.word.Word; 49 import org.graalvm.compiler.word.WordTypes; 50 import jdk.internal.vm.compiler.word.LocationIdentity; 51 52 import jdk.vm.ci.code.CallingConvention; 53 import jdk.vm.ci.code.CodeCacheProvider; 54 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; 55 import jdk.vm.ci.meta.JavaKind; 56 import jdk.vm.ci.meta.MetaAccessProvider; 57 58 /** 59 * HotSpot implementation of {@link HotSpotForeignCallsProvider}. 60 */ 61 public abstract class HotSpotForeignCallsProviderImpl implements HotSpotForeignCallsProvider { 62 63 public static final ForeignCallDescriptor OSR_MIGRATION_END = new ForeignCallDescriptor("OSR_migration_end", void.class, long.class); 64 public static final ForeignCallDescriptor IDENTITY_HASHCODE = new ForeignCallDescriptor("identity_hashcode", int.class, Object.class); 65 public static final ForeignCallDescriptor VERIFY_OOP = new ForeignCallDescriptor("verify_oop", Object.class, Object.class); 66 public static final ForeignCallDescriptor LOAD_AND_CLEAR_EXCEPTION = new ForeignCallDescriptor("load_and_clear_exception", Object.class, Word.class); 67 68 public static final ForeignCallDescriptor TEST_DEOPTIMIZE_CALL_INT = new ForeignCallDescriptor("test_deoptimize_call_int", int.class, int.class); 69 70 protected final HotSpotJVMCIRuntime jvmciRuntime; 71 protected final HotSpotGraalRuntimeProvider runtime; 72 73 protected final EconomicMap<ForeignCallDescriptor, HotSpotForeignCallLinkage> foreignCalls = EconomicMap.create(); 74 protected final MetaAccessProvider metaAccess; 75 protected final CodeCacheProvider codeCache; 76 protected final WordTypes wordTypes; 77 78 public HotSpotForeignCallsProviderImpl(HotSpotJVMCIRuntime jvmciRuntime, HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, CodeCacheProvider codeCache, 79 WordTypes wordTypes) { 80 this.jvmciRuntime = jvmciRuntime; 81 this.runtime = runtime; 82 this.metaAccess = metaAccess; 83 this.codeCache = codeCache; 84 this.wordTypes = wordTypes; 85 } 86 87 /** 88 * Registers the linkage for a foreign call. 89 */ 90 public HotSpotForeignCallLinkage register(HotSpotForeignCallLinkage linkage) { 91 assert !foreignCalls.containsKey(linkage.getDescriptor()) : "already registered linkage for " + linkage.getDescriptor(); 92 foreignCalls.put(linkage.getDescriptor(), linkage); 93 return linkage; 94 } 95 96 /** 97 * Return true if the descriptor has already been registered. 98 */ 99 public boolean isRegistered(ForeignCallDescriptor descriptor) { 100 return foreignCalls.containsKey(descriptor); 101 } 102 103 /** 104 * Creates and registers the details for linking a foreign call to a {@link Stub}. 105 * 106 * @param descriptor the signature of the call to the stub 107 * @param transition specifies if this is a {@linkplain Transition#LEAF leaf} call 108 * @param reexecutability specifies if the stub call can be re-executed without (meaningful) 109 * side effects. Deoptimization will not return to a point before a stub call that 110 * cannot be re-executed. 111 * @param killedLocations the memory locations killed by the stub call 112 */ 113 public HotSpotForeignCallLinkage registerStubCall( 114 ForeignCallDescriptor descriptor, 115 Transition transition, 116 Reexecutability reexecutability, 117 RegisterEffect effect, 118 LocationIdentity... killedLocations) { 119 return register(HotSpotForeignCallLinkageImpl.create(metaAccess, 120 codeCache, 121 wordTypes, 122 this, 123 descriptor, 124 0L, effect, 125 JavaCall, 126 JavaCallee, 127 transition, 128 reexecutability, 129 killedLocations)); 130 } 131 132 /** 133 * Creates and registers the linkage for a foreign call. All foreign calls are assumed to have 134 * the effect {@link RegisterEffect#DESTROYS_ALL_CALLER_SAVE_REGISTERS} since they are outside 135 * of Graal's knowledge. 136 * 137 * @param descriptor the signature of the foreign call 138 * @param address the address of the code to call (must be non-zero) 139 * @param outgoingCcType outgoing (caller) calling convention type 140 * @param transition specifies if this is a {@linkplain Transition#LEAF leaf} call 141 * @param reexecutability specifies if the foreign call can be re-executed without (meaningful) 142 * side effects. Deoptimization will not return to a point before a foreign call that 143 * cannot be re-executed. 144 * @param killedLocations the memory locations killed by the foreign call 145 */ 146 public HotSpotForeignCallLinkage registerForeignCall( 147 ForeignCallDescriptor descriptor, 148 long address, 149 CallingConvention.Type outgoingCcType, 150 Transition transition, 151 Reexecutability reexecutability, 152 LocationIdentity... killedLocations) { 153 Class<?> resultType = descriptor.getResultType(); 154 assert address != 0 : descriptor; 155 assert transition != SAFEPOINT || resultType.isPrimitive() || Word.class.isAssignableFrom(resultType) : "non-leaf foreign calls must return objects in thread local storage: " + descriptor; 156 return register(HotSpotForeignCallLinkageImpl.create(metaAccess, 157 codeCache, 158 wordTypes, 159 this, 160 descriptor, 161 address, 162 DESTROYS_ALL_CALLER_SAVE_REGISTERS, 163 outgoingCcType, 164 null, // incomingCcType 165 transition, 166 reexecutability, 167 killedLocations)); 168 } 169 170 /** 171 * Creates a {@linkplain ForeignCallStub stub} for the foreign call described by 172 * {@code descriptor} if {@code address != 0}. 173 * 174 * @param descriptor the signature of the call to the stub 175 * @param address the address of the foreign code to call 176 * @param prependThread true if the JavaThread value for the current thread is to be prepended 177 * to the arguments for the call to {@code address} 178 * @param transition specifies if this is a {@linkplain Transition#LEAF leaf} call 179 * @param reexecutability specifies if the foreign call can be re-executed without (meaningful) 180 * side effects. Deoptimization will not return to a point before a foreign call that 181 * cannot be re-executed. 182 * @param killedLocations the memory locations killed by the foreign call 183 */ 184 public void linkForeignCall(OptionValues options, 185 HotSpotProviders providers, 186 ForeignCallDescriptor descriptor, 187 long address, 188 boolean prependThread, 189 Transition transition, 190 Reexecutability reexecutability, 191 LocationIdentity... killedLocations) { 192 if (address != 0) { 193 ForeignCallStub stub = new ForeignCallStub(options, jvmciRuntime, providers, address, descriptor, prependThread, transition, reexecutability, killedLocations); 194 HotSpotForeignCallLinkage linkage = stub.getLinkage(); 195 HotSpotForeignCallLinkage targetLinkage = stub.getTargetLinkage(); 196 linkage.setCompiledStub(stub); 197 register(linkage); 198 register(targetLinkage); 199 } 200 } 201 202 public static final boolean PREPEND_THREAD = true; 203 public static final boolean DONT_PREPEND_THREAD = !PREPEND_THREAD; 204 205 public static final LocationIdentity[] NO_LOCATIONS = {}; 206 207 @Override 208 public HotSpotForeignCallLinkage lookupForeignCall(ForeignCallDescriptor descriptor) { 209 assert foreignCalls != null : descriptor; 210 HotSpotForeignCallLinkage callTarget = foreignCalls.get(descriptor); 211 if (callTarget == null) { 212 throw GraalError.shouldNotReachHere("missing implementation for runtime call: " + descriptor); 213 } 214 callTarget.finalizeAddress(runtime.getHostBackend()); 215 return callTarget; 216 } 217 218 @Override 219 public boolean isAvailable(ForeignCallDescriptor descriptor) { 220 return foreignCalls.containsKey(descriptor); 221 } 222 223 @Override 224 public boolean isReexecutable(ForeignCallDescriptor descriptor) { 225 assert foreignCalls.containsKey(descriptor) : "unknown foreign call: " + descriptor; 226 return foreignCalls.get(descriptor).isReexecutable(); 227 } 228 229 @Override 230 public boolean canDeoptimize(ForeignCallDescriptor descriptor) { 231 assert foreignCalls.containsKey(descriptor) : "unknown foreign call: " + descriptor; 232 return foreignCalls.get(descriptor).needsDebugInfo(); 233 } 234 235 @Override 236 public boolean isGuaranteedSafepoint(ForeignCallDescriptor descriptor) { 237 assert foreignCalls.containsKey(descriptor) : "unknown foreign call: " + descriptor; 238 return foreignCalls.get(descriptor).isGuaranteedSafepoint(); 239 } 240 241 @Override 242 public LocationIdentity[] getKilledLocations(ForeignCallDescriptor descriptor) { 243 assert foreignCalls.containsKey(descriptor) : "unknown foreign call: " + descriptor; 244 return foreignCalls.get(descriptor).getKilledLocations(); 245 } 246 247 @Override 248 public LIRKind getValueKind(JavaKind javaKind) { 249 return LIRKind.fromJavaKind(codeCache.getTarget().arch, javaKind); 250 } 251 252 @Override 253 public List<Stub> getStubs() { 254 List<Stub> stubs = new ArrayList<>(); 255 for (HotSpotForeignCallLinkage linkage : foreignCalls.getValues()) { 256 if (linkage.isCompiledStub()) { 257 Stub stub = linkage.getStub(); 258 assert stub != null; 259 stubs.add(stub); 260 } 261 } 262 return stubs; 263 } 264 }