1 /* 2 * Copyright (c) 2012, 2018, 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; 26 27 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; 28 import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.DESTROYS_REGISTERS; 29 30 import jdk.internal.vm.compiler.collections.EconomicSet; 31 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; 32 import org.graalvm.compiler.core.target.Backend; 33 import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; 34 import org.graalvm.compiler.hotspot.stubs.Stub; 35 import org.graalvm.compiler.word.WordTypes; 36 import jdk.internal.vm.compiler.word.LocationIdentity; 37 38 import jdk.vm.ci.code.CallingConvention; 39 import jdk.vm.ci.code.CallingConvention.Type; 40 import jdk.vm.ci.code.CodeCacheProvider; 41 import jdk.vm.ci.code.InstalledCode; 42 import jdk.vm.ci.code.Register; 43 import jdk.vm.ci.code.RegisterConfig; 44 import jdk.vm.ci.code.ValueKindFactory; 45 import jdk.vm.ci.hotspot.HotSpotCallingConventionType; 46 import jdk.vm.ci.hotspot.HotSpotForeignCallTarget; 47 import jdk.vm.ci.meta.AllocatableValue; 48 import jdk.vm.ci.meta.JavaType; 49 import jdk.vm.ci.meta.MetaAccessProvider; 50 import jdk.vm.ci.meta.ResolvedJavaType; 51 import jdk.vm.ci.meta.Value; 52 53 /** 54 * The details required to link a HotSpot runtime or stub call. 55 */ 56 public class HotSpotForeignCallLinkageImpl extends HotSpotForeignCallTarget implements HotSpotForeignCallLinkage { 57 58 /** 59 * The descriptor of the call. 60 */ 61 protected final ForeignCallDescriptor descriptor; 62 63 /** 64 * Non-null (eventually) iff this is a call to a compiled {@linkplain Stub stub}. 65 */ 66 private Stub stub; 67 68 /** 69 * The calling convention for this call. 70 */ 71 private final CallingConvention outgoingCallingConvention; 72 73 /** 74 * The calling convention for incoming arguments to the stub, iff this call uses a compiled 75 * {@linkplain Stub stub}. 76 */ 77 private final CallingConvention incomingCallingConvention; 78 79 private final RegisterEffect effect; 80 81 private final Transition transition; 82 83 /** 84 * The registers and stack slots defined/killed by the call. 85 */ 86 private Value[] temporaries = AllocatableValue.NONE; 87 88 /** 89 * The memory locations killed by the call. 90 */ 91 private final LocationIdentity[] killedLocations; 92 93 private final Reexecutability reexecutability; 94 95 /** 96 * Creates a {@link HotSpotForeignCallLinkage}. 97 * 98 * @param descriptor the descriptor of the call 99 * @param address the address of the code to call 100 * @param effect specifies if the call destroys or preserves all registers (apart from 101 * temporaries which are always destroyed) 102 * @param outgoingCcType outgoing (caller) calling convention type 103 * @param incomingCcType incoming (callee) calling convention type (can be null) 104 * @param transition specifies if this is a {@linkplain #needsDebugInfo() leaf} call 105 * @param reexecutability specifies if the call can be re-executed without (meaningful) side 106 * effects. Deoptimization will not return to a point before a call that cannot be 107 * re-executed. 108 * @param killedLocations the memory locations killed by the call 109 */ create(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, WordTypes wordTypes, HotSpotForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, long address, RegisterEffect effect, Type outgoingCcType, Type incomingCcType, Transition transition, Reexecutability reexecutability, LocationIdentity... killedLocations)110 public static HotSpotForeignCallLinkage create(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, WordTypes wordTypes, HotSpotForeignCallsProvider foreignCalls, 111 ForeignCallDescriptor descriptor, long address, RegisterEffect effect, Type outgoingCcType, Type incomingCcType, Transition transition, Reexecutability reexecutability, 112 LocationIdentity... killedLocations) { 113 CallingConvention outgoingCc = createCallingConvention(metaAccess, codeCache, wordTypes, foreignCalls, descriptor, outgoingCcType); 114 CallingConvention incomingCc = incomingCcType == null ? null : createCallingConvention(metaAccess, codeCache, wordTypes, foreignCalls, descriptor, incomingCcType); 115 HotSpotForeignCallLinkageImpl linkage = new HotSpotForeignCallLinkageImpl(descriptor, address, effect, transition, reexecutability, outgoingCc, incomingCc, 116 killedLocations); 117 if (outgoingCcType == HotSpotCallingConventionType.NativeCall) { 118 linkage.temporaries = foreignCalls.getNativeABICallerSaveRegisters(); 119 } 120 return linkage; 121 } 122 123 /** 124 * Gets a calling convention for a given descriptor and call type. 125 */ createCallingConvention(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, WordTypes wordTypes, ValueKindFactory<?> valueKindFactory, ForeignCallDescriptor descriptor, Type ccType)126 public static CallingConvention createCallingConvention(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, WordTypes wordTypes, ValueKindFactory<?> valueKindFactory, 127 ForeignCallDescriptor descriptor, Type ccType) { 128 assert ccType != null; 129 Class<?>[] argumentTypes = descriptor.getArgumentTypes(); 130 JavaType[] parameterTypes = new JavaType[argumentTypes.length]; 131 for (int i = 0; i < parameterTypes.length; ++i) { 132 parameterTypes[i] = asJavaType(argumentTypes[i], metaAccess, wordTypes); 133 } 134 JavaType returnType = asJavaType(descriptor.getResultType(), metaAccess, wordTypes); 135 RegisterConfig regConfig = codeCache.getRegisterConfig(); 136 return regConfig.getCallingConvention(ccType, returnType, parameterTypes, valueKindFactory); 137 } 138 asJavaType(Class<?> type, MetaAccessProvider metaAccess, WordTypes wordTypes)139 private static JavaType asJavaType(Class<?> type, MetaAccessProvider metaAccess, WordTypes wordTypes) { 140 ResolvedJavaType javaType = metaAccess.lookupJavaType(type); 141 if (wordTypes.isWord(javaType)) { 142 javaType = metaAccess.lookupJavaType(wordTypes.getWordKind().toJavaClass()); 143 } 144 return javaType; 145 } 146 HotSpotForeignCallLinkageImpl(ForeignCallDescriptor descriptor, long address, RegisterEffect effect, Transition transition, Reexecutability reexecutability, CallingConvention outgoingCallingConvention, CallingConvention incomingCallingConvention, LocationIdentity... killedLocations)147 public HotSpotForeignCallLinkageImpl(ForeignCallDescriptor descriptor, long address, RegisterEffect effect, Transition transition, Reexecutability reexecutability, 148 CallingConvention outgoingCallingConvention, CallingConvention incomingCallingConvention, LocationIdentity... killedLocations) { 149 super(address); 150 this.descriptor = descriptor; 151 this.address = address; 152 this.effect = effect; 153 this.transition = transition; 154 this.reexecutability = reexecutability; 155 assert outgoingCallingConvention != null : "only incomingCallingConvention can be null"; 156 this.outgoingCallingConvention = outgoingCallingConvention; 157 this.incomingCallingConvention = incomingCallingConvention != null ? incomingCallingConvention : outgoingCallingConvention; 158 this.killedLocations = killedLocations; 159 } 160 161 @Override toString()162 public String toString() { 163 StringBuilder sb = new StringBuilder(stub == null ? descriptor.toString() : stub.toString()); 164 sb.append("@0x").append(Long.toHexString(address)).append(':').append(outgoingCallingConvention).append(":").append(incomingCallingConvention); 165 if (temporaries != null && temporaries.length != 0) { 166 sb.append("; temps="); 167 String sep = ""; 168 for (Value op : temporaries) { 169 sb.append(sep).append(op); 170 sep = ","; 171 } 172 } 173 return sb.toString(); 174 } 175 176 @Override isReexecutable()177 public boolean isReexecutable() { 178 return reexecutability == Reexecutability.REEXECUTABLE; 179 } 180 181 @Override isReexecutableOnlyAfterException()182 public boolean isReexecutableOnlyAfterException() { 183 return reexecutability == Reexecutability.REEXECUTABLE_ONLY_AFTER_EXCEPTION; 184 } 185 186 @Override isGuaranteedSafepoint()187 public boolean isGuaranteedSafepoint() { 188 return transition == Transition.SAFEPOINT; 189 } 190 191 @Override getKilledLocations()192 public LocationIdentity[] getKilledLocations() { 193 return killedLocations; 194 } 195 196 @Override getOutgoingCallingConvention()197 public CallingConvention getOutgoingCallingConvention() { 198 return outgoingCallingConvention; 199 } 200 201 @Override getIncomingCallingConvention()202 public CallingConvention getIncomingCallingConvention() { 203 return incomingCallingConvention; 204 } 205 206 @Override getTemporaries()207 public Value[] getTemporaries() { 208 if (temporaries.length == 0) { 209 return temporaries; 210 } 211 return temporaries.clone(); 212 } 213 214 @Override getMaxCallTargetOffset()215 public long getMaxCallTargetOffset() { 216 return runtime().getHostJVMCIBackend().getCodeCache().getMaxCallTargetOffset(address); 217 } 218 219 @Override getDescriptor()220 public ForeignCallDescriptor getDescriptor() { 221 return descriptor; 222 } 223 224 @Override setCompiledStub(Stub stub)225 public void setCompiledStub(Stub stub) { 226 assert address == 0L : "cannot set stub for linkage that already has an address: " + this; 227 this.stub = stub; 228 } 229 230 /** 231 * Determines if this is a call to a compiled {@linkplain Stub stub}. 232 */ 233 @Override isCompiledStub()234 public boolean isCompiledStub() { 235 return address == 0L || stub != null; 236 } 237 238 @Override getStub()239 public Stub getStub() { 240 assert checkStubCondition(); 241 return stub; 242 } 243 checkStubCondition()244 private boolean checkStubCondition() { 245 assert stub != null : "linkage without an address must be a stub - forgot to register a Stub associated with " + descriptor + "?"; 246 return true; 247 } 248 249 @Override finalizeAddress(Backend backend)250 public void finalizeAddress(Backend backend) { 251 if (address == 0) { 252 assert checkStubCondition(); 253 InstalledCode code = stub.getCode(backend); 254 255 EconomicSet<Register> destroyedRegisters = stub.getDestroyedCallerRegisters(); 256 if (!destroyedRegisters.isEmpty()) { 257 AllocatableValue[] temporaryLocations = new AllocatableValue[destroyedRegisters.size()]; 258 int i = 0; 259 for (Register reg : destroyedRegisters) { 260 temporaryLocations[i++] = reg.asValue(); 261 } 262 temporaries = temporaryLocations; 263 } 264 address = code.getStart(); 265 } 266 } 267 268 @Override getAddress()269 public long getAddress() { 270 assert address != 0L : "address not yet finalized: " + this; 271 return address; 272 } 273 274 @Override destroysRegisters()275 public boolean destroysRegisters() { 276 return effect == DESTROYS_REGISTERS; 277 } 278 279 @Override needsDebugInfo()280 public boolean needsDebugInfo() { 281 return transition == Transition.SAFEPOINT; 282 } 283 284 @Override mayContainFP()285 public boolean mayContainFP() { 286 return transition != Transition.LEAF_NOFP; 287 } 288 289 @Override needsJavaFrameAnchor()290 public boolean needsJavaFrameAnchor() { 291 if (transition == Transition.SAFEPOINT || transition == Transition.STACK_INSPECTABLE_LEAF) { 292 if (stub != null) { 293 // The stub will do the JavaFrameAnchor management 294 // around the runtime call(s) it makes 295 return false; 296 } else { 297 return true; 298 } 299 } 300 return false; 301 } 302 303 @Override getSymbol()304 public String getSymbol() { 305 return stub == null ? null : stub.toString(); 306 } 307 } 308