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(ForeignCallDescriptor descriptor, Transition transition, Reexecutability reexecutability, 113 LocationIdentity... killedLocations) { 114 return register(HotSpotForeignCallLinkageImpl.create(metaAccess, codeCache, wordTypes, this, descriptor, 0L, PRESERVES_REGISTERS, JavaCall, JavaCallee, transition, reexecutability, 115 killedLocations)); 116 } 117 118 /** 119 * Creates and registers the linkage for a foreign call. 120 * 121 * @param descriptor the signature of the foreign call 122 * @param address the address of the code to call 123 * @param outgoingCcType outgoing (caller) calling convention type 124 * @param effect specifies if the call destroys or preserves all registers (apart from 125 * temporaries which are always destroyed) 126 * @param transition specifies if this is a {@linkplain Transition#LEAF leaf} call 127 * @param reexecutability specifies if the foreign call can be re-executed without (meaningful) 128 * side effects. Deoptimization will not return to a point before a foreign call that 129 * cannot be re-executed. 130 * @param killedLocations the memory locations killed by the foreign call 131 */ 132 public HotSpotForeignCallLinkage registerForeignCall(ForeignCallDescriptor descriptor, long address, CallingConvention.Type outgoingCcType, RegisterEffect effect, Transition transition, 133 Reexecutability reexecutability, LocationIdentity... killedLocations) { 134 Class<?> resultType = descriptor.getResultType(); 135 assert address != 0; 136 assert transition != SAFEPOINT || resultType.isPrimitive() || Word.class.isAssignableFrom(resultType) : "non-leaf foreign calls must return objects in thread local storage: " + descriptor; 137 return register(HotSpotForeignCallLinkageImpl.create(metaAccess, codeCache, wordTypes, this, descriptor, address, effect, outgoingCcType, null, transition, reexecutability, killedLocations)); 138 } 139 140 /** 141 * Creates a {@linkplain ForeignCallStub stub} for a foreign call. 142 * 143 * @param descriptor the signature of the call to the stub 144 * @param address the address of the foreign code to call 145 * @param prependThread true if the JavaThread value for the current thread is to be prepended 146 * to the arguments for the call to {@code address} 147 * @param transition specifies if this is a {@linkplain Transition#LEAF leaf} call 148 * @param reexecutability specifies if the foreign call can be re-executed without (meaningful) 149 * side effects. Deoptimization will not return to a point before a foreign call that 150 * cannot be re-executed. 151 * @param killedLocations the memory locations killed by the foreign call 152 */ 153 public void linkForeignCall(OptionValues options, HotSpotProviders providers, ForeignCallDescriptor descriptor, long address, boolean prependThread, Transition transition, 154 Reexecutability reexecutability, LocationIdentity... killedLocations) { 155 ForeignCallStub stub = new ForeignCallStub(options, jvmciRuntime, providers, address, descriptor, prependThread, transition, reexecutability, killedLocations); 156 HotSpotForeignCallLinkage linkage = stub.getLinkage(); 157 HotSpotForeignCallLinkage targetLinkage = stub.getTargetLinkage(); 158 linkage.setCompiledStub(stub); 159 register(linkage); 160 register(targetLinkage); 161 } 162 163 public static final boolean PREPEND_THREAD = true; 164 public static final boolean DONT_PREPEND_THREAD = !PREPEND_THREAD; 165 166 public static final LocationIdentity[] NO_LOCATIONS = {}; 167 168 @Override 169 public HotSpotForeignCallLinkage lookupForeignCall(ForeignCallDescriptor descriptor) { 170 assert foreignCalls != null : descriptor; 171 HotSpotForeignCallLinkage callTarget = foreignCalls.get(descriptor); 172 callTarget.finalizeAddress(runtime.getHostBackend()); 173 return callTarget; 174 } 175 176 @Override 177 public boolean isReexecutable(ForeignCallDescriptor descriptor) { 178 assert foreignCalls.containsKey(descriptor) : "unknown foreign call: " + descriptor; 179 return foreignCalls.get(descriptor).isReexecutable(); 180 } 181 182 @Override 183 public boolean canDeoptimize(ForeignCallDescriptor descriptor) { 184 assert foreignCalls.containsKey(descriptor) : "unknown foreign call: " + descriptor; 185 return foreignCalls.get(descriptor).needsDebugInfo(); 186 } 187 188 @Override 189 public boolean isGuaranteedSafepoint(ForeignCallDescriptor descriptor) { 190 assert foreignCalls.containsKey(descriptor) : "unknown foreign call: " + descriptor; 191 return foreignCalls.get(descriptor).isGuaranteedSafepoint(); 192 } 193 194 @Override 195 public LocationIdentity[] getKilledLocations(ForeignCallDescriptor descriptor) { 196 assert foreignCalls.containsKey(descriptor) : "unknown foreign call: " + descriptor; 197 return foreignCalls.get(descriptor).getKilledLocations(); 198 } 199 200 @Override 201 public LIRKind getValueKind(JavaKind javaKind) { 202 return LIRKind.fromJavaKind(codeCache.getTarget().arch, javaKind); 203 } 204 205 @Override 206 public List<Stub> getStubs() { 207 List<Stub> stubs = new ArrayList<>(); 208 for (HotSpotForeignCallLinkage linkage : foreignCalls.getValues()) { 209 if (linkage.isCompiledStub()) { 210 Stub stub = linkage.getStub(); 211 assert stub != null; 212 stubs.add(stub); 213 } 214 } 215 return stubs; 216 } 217 }