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