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