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