ForeignCallStub.java revision 12968:4d8a004e5c6d
1160814Ssimon/* 2160814Ssimon * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. 3160814Ssimon * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4160814Ssimon * 5160814Ssimon * This code is free software; you can redistribute it and/or modify it 6160814Ssimon * under the terms of the GNU General Public License version 2 only, as 7160814Ssimon * published by the Free Software Foundation. 8160814Ssimon * 9160814Ssimon * This code is distributed in the hope that it will be useful, but WITHOUT 10160814Ssimon * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11160814Ssimon * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12160814Ssimon * version 2 for more details (a copy is included in the LICENSE file that 13160814Ssimon * accompanied this code). 14160814Ssimon * 15160814Ssimon * You should have received a copy of the GNU General Public License version 16160814Ssimon * 2 along with this work; if not, write to the Free Software Foundation, 17160814Ssimon * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18160814Ssimon * 19160814Ssimon * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20160814Ssimon * or visit www.oracle.com if you need additional information or have any 21160814Ssimon * questions. 22160814Ssimon */ 23160814Ssimonpackage org.graalvm.compiler.hotspot.stubs; 24280297Sjkim 25160814Ssimonimport static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.DESTROYS_REGISTERS; 26160814Ssimonimport static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.PRESERVES_REGISTERS; 27160814Ssimonimport static jdk.vm.ci.hotspot.HotSpotCallingConventionType.JavaCall; 28160814Ssimonimport static jdk.vm.ci.hotspot.HotSpotCallingConventionType.JavaCallee; 29160814Ssimonimport static jdk.vm.ci.hotspot.HotSpotCallingConventionType.NativeCall; 30160814Ssimon 31160814Ssimonimport org.graalvm.compiler.core.common.CompilationIdentifier; 32160814Ssimonimport org.graalvm.compiler.core.common.LIRKind; 33160814Ssimonimport org.graalvm.compiler.core.common.LocationIdentity; 34160814Ssimonimport org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; 35160814Ssimonimport org.graalvm.compiler.core.common.type.StampFactory; 36160814Ssimonimport org.graalvm.compiler.core.common.type.StampPair; 37160814Ssimonimport org.graalvm.compiler.debug.Debug; 38160814Ssimonimport org.graalvm.compiler.debug.JavaMethodContext; 39160814Ssimonimport org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; 40160814Ssimonimport org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition; 41160814Ssimonimport org.graalvm.compiler.hotspot.HotSpotForeignCallLinkageImpl; 42160814Ssimonimport org.graalvm.compiler.hotspot.meta.HotSpotProviders; 43160814Ssimonimport org.graalvm.compiler.hotspot.nodes.StubForeignCallNode; 44160814Ssimonimport org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil; 45160814Ssimonimport org.graalvm.compiler.nodes.ConstantNode; 46160814Ssimonimport org.graalvm.compiler.nodes.InvokeNode; 47160814Ssimonimport org.graalvm.compiler.nodes.ParameterNode; 48160814Ssimonimport org.graalvm.compiler.nodes.ReturnNode; 49160814Ssimonimport org.graalvm.compiler.nodes.StructuredGraph; 50160814Ssimonimport org.graalvm.compiler.nodes.ValueNode; 51160814Ssimonimport org.graalvm.compiler.options.OptionValues; 52160814Ssimonimport org.graalvm.compiler.phases.common.RemoveValueProxyPhase; 53160814Ssimonimport org.graalvm.compiler.replacements.GraphKit; 54160814Ssimonimport org.graalvm.compiler.replacements.nodes.ReadRegisterNode; 55160814Ssimonimport org.graalvm.compiler.word.Word; 56160814Ssimonimport org.graalvm.compiler.word.WordTypes; 57160814Ssimon 58160814Ssimonimport jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; 59160814Ssimonimport jdk.vm.ci.hotspot.HotSpotSignature; 60160814Ssimonimport jdk.vm.ci.meta.JavaMethod; 61160814Ssimonimport jdk.vm.ci.meta.JavaType; 62160814Ssimonimport jdk.vm.ci.meta.MetaAccessProvider; 63160814Ssimonimport jdk.vm.ci.meta.ResolvedJavaMethod; 64160814Ssimonimport jdk.vm.ci.meta.ResolvedJavaType; 65160814Ssimonimport jdk.vm.ci.meta.Signature; 66160814Ssimon 67160814Ssimon/** 68160814Ssimon * A {@linkplain #getGraph generated} stub for a {@link Transition non-leaf} foreign call from 69160814Ssimon * compiled code. A stub is required for such calls as the caller may be scheduled for 70160814Ssimon * deoptimization while the call is in progress. And since these are foreign/runtime calls on slow 71160814Ssimon * paths, we don't want to force the register allocator to spill around the call. As such, this stub 72160814Ssimon * saves and restores all allocatable registers. It also 73280297Sjkim * {@linkplain StubUtil#handlePendingException(Word, boolean) handles} any exceptions raised during 74160814Ssimon * the foreign call. 75160814Ssimon */ 76238405Sjkimpublic class ForeignCallStub extends Stub { 77280297Sjkim 78238405Sjkim private final HotSpotJVMCIRuntimeProvider jvmciRuntime; 79160814Ssimon 80280297Sjkim /** 81160814Ssimon * The target of the call. 82160814Ssimon */ 83160814Ssimon private final HotSpotForeignCallLinkage target; 84160814Ssimon 85160814Ssimon /** 86280297Sjkim * Specifies if the JavaThread value for the current thread is to be prepended to the arguments 87160814Ssimon * for the call to {@link #target}. 88160814Ssimon */ 89280297Sjkim protected final boolean prependThread; 90280297Sjkim 91280297Sjkim /** 92160814Ssimon * Creates a stub for a call to code at a given address. 93160814Ssimon * 94280297Sjkim * @param address the address of the code to call 95280297Sjkim * @param descriptor the signature of the call to this stub 96238405Sjkim * @param prependThread true if the JavaThread value for the current thread is to be prepended 97280297Sjkim * to the arguments for the call to {@code address} 98280297Sjkim * @param reexecutable specifies if the stub call can be re-executed without (meaningful) side 99280297Sjkim * effects. Deoptimization will not return to a point before a stub call that cannot 100280297Sjkim * be re-executed. 101238405Sjkim * @param killedLocations the memory locations killed by the stub call 102280297Sjkim */ 103238405Sjkim public ForeignCallStub(OptionValues options, HotSpotJVMCIRuntimeProvider runtime, HotSpotProviders providers, long address, ForeignCallDescriptor descriptor, boolean prependThread, 104280297Sjkim Transition transition, 105280297Sjkim boolean reexecutable, LocationIdentity... killedLocations) { 106280297Sjkim super(options, providers, HotSpotForeignCallLinkageImpl.create(providers.getMetaAccess(), providers.getCodeCache(), providers.getWordTypes(), providers.getForeignCalls(), descriptor, 0L, 107160814Ssimon PRESERVES_REGISTERS, JavaCall, JavaCallee, transition, reexecutable, killedLocations)); 108160814Ssimon this.jvmciRuntime = runtime; 109280297Sjkim this.prependThread = prependThread; 110280297Sjkim Class<?>[] targetParameterTypes = createTargetParameters(descriptor); 111160814Ssimon ForeignCallDescriptor targetSig = new ForeignCallDescriptor(descriptor.getName() + ":C", descriptor.getResultType(), targetParameterTypes); 112280297Sjkim target = HotSpotForeignCallLinkageImpl.create(providers.getMetaAccess(), providers.getCodeCache(), providers.getWordTypes(), providers.getForeignCalls(), targetSig, address, 113160814Ssimon DESTROYS_REGISTERS, NativeCall, NativeCall, transition, reexecutable, killedLocations); 114280297Sjkim } 115280297Sjkim 116160814Ssimon /** 117238405Sjkim * Gets the linkage information for the call from this stub. 118280297Sjkim */ 119280297Sjkim public HotSpotForeignCallLinkage getTargetLinkage() { 120280297Sjkim return target; 121238405Sjkim } 122160814Ssimon 123280297Sjkim private Class<?>[] createTargetParameters(ForeignCallDescriptor descriptor) { 124280297Sjkim Class<?>[] parameters = descriptor.getArgumentTypes(); 125280297Sjkim if (prependThread) { 126280297Sjkim Class<?>[] newParameters = new Class<?>[parameters.length + 1]; 127160814Ssimon System.arraycopy(parameters, 0, newParameters, 1, parameters.length); 128280297Sjkim newParameters[0] = Word.class; 129160814Ssimon return newParameters; 130280297Sjkim } 131280297Sjkim return parameters; 132160814Ssimon } 133280297Sjkim 134280297Sjkim @Override 135160814Ssimon protected ResolvedJavaMethod getInstalledCodeOwner() { 136160814Ssimon return null; 137280297Sjkim } 138280297Sjkim 139160814Ssimon private class DebugScopeContext implements JavaMethod, JavaMethodContext { 140280297Sjkim @Override 141280297Sjkim public JavaMethod asJavaMethod() { 142280297Sjkim return this; 143280297Sjkim } 144280297Sjkim 145160814Ssimon @Override 146280297Sjkim public Signature getSignature() { 147160814Ssimon ForeignCallDescriptor d = linkage.getDescriptor(); 148280297Sjkim MetaAccessProvider metaAccess = providers.getMetaAccess(); 149280297Sjkim Class<?>[] arguments = d.getArgumentTypes(); 150160814Ssimon ResolvedJavaType[] parameters = new ResolvedJavaType[arguments.length]; 151280297Sjkim for (int i = 0; i < arguments.length; i++) { 152280297Sjkim parameters[i] = metaAccess.lookupJavaType(arguments[i]); 153280297Sjkim } 154280297Sjkim return new HotSpotSignature(jvmciRuntime, metaAccess.lookupJavaType(d.getResultType()), parameters); 155280297Sjkim } 156280297Sjkim 157280297Sjkim @Override 158280297Sjkim public String getName() { 159280297Sjkim return linkage.getDescriptor().getName(); 160280297Sjkim } 161280297Sjkim 162160814Ssimon @Override 163160814Ssimon public JavaType getDeclaringClass() { 164280297Sjkim return providers.getMetaAccess().lookupJavaType(ForeignCallStub.class); 165280297Sjkim } 166160814Ssimon 167280297Sjkim @Override 168280297Sjkim public String toString() { 169280297Sjkim return format("ForeignCallStub<%n(%p)>"); 170280297Sjkim } 171280297Sjkim } 172280297Sjkim 173280297Sjkim @Override 174280297Sjkim protected Object debugScopeContext() { 175160814Ssimon return new DebugScopeContext() { 176160814Ssimon 177280297Sjkim }; 178280297Sjkim } 179280297Sjkim 180160814Ssimon /** 181160814Ssimon * Creates a graph for this stub. 182160814Ssimon * <p> 183280297Sjkim * If the stub returns an object, the graph created corresponds to this pseudo code: 184160814Ssimon * 185280297Sjkim * <pre> 186280297Sjkim * Object foreignFunctionStub(args...) { 187280297Sjkim * foreignFunction(currentThread, args); 188160814Ssimon * if (clearPendingException(thread())) { 189280297Sjkim * getAndClearObjectResult(thread()); 190160814Ssimon * DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint); 191160814Ssimon * } 192160814Ssimon * return verifyObject(getAndClearObjectResult(thread())); 193280297Sjkim * } 194280297Sjkim * </pre> 195160814Ssimon * 196160814Ssimon * If the stub returns a primitive or word, the graph created corresponds to this pseudo code 197280297Sjkim * (using {@code int} as the primitive return type): 198280297Sjkim * 199160814Ssimon * <pre> 200160814Ssimon * int foreignFunctionStub(args...) { 201280297Sjkim * int result = foreignFunction(currentThread, args); 202160814Ssimon * if (clearPendingException(thread())) { 203280297Sjkim * DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint); 204160814Ssimon * } 205280297Sjkim * return result; 206280297Sjkim * } 207160814Ssimon * </pre> 208160814Ssimon * 209280297Sjkim * If the stub is void, the graph created corresponds to this pseudo code: 210280297Sjkim * 211280297Sjkim * <pre> 212280297Sjkim * void foreignFunctionStub(args...) { 213280297Sjkim * foreignFunction(currentThread, args); 214280297Sjkim * if (clearPendingException(thread())) { 215280297Sjkim * DeoptimizeCallerNode.deopt(InvalidateReprofile, RuntimeConstraint); 216280297Sjkim * } 217280297Sjkim * } 218280297Sjkim * </pre> 219280297Sjkim * 220280297Sjkim * In each example above, the {@code currentThread} argument is the C++ JavaThread value (i.e., 221280297Sjkim * %r15 on AMD64) and is only prepended if {@link #prependThread} is true. 222280297Sjkim */ 223280297Sjkim @Override 224280297Sjkim protected StructuredGraph getGraph(CompilationIdentifier compilationId) { 225280297Sjkim WordTypes wordTypes = providers.getWordTypes(); 226280297Sjkim Class<?>[] args = linkage.getDescriptor().getArgumentTypes(); 227280297Sjkim boolean isObjectResult = !LIRKind.isValue(linkage.getOutgoingCallingConvention().getReturn()); 228325337Sjkim 229325337Sjkim StructuredGraph graph = new StructuredGraph.Builder(options).name(toString()).compilationId(compilationId).build(); 230325337Sjkim graph.disableUnsafeAccessTracking(); 231325337Sjkim 232325337Sjkim GraphKit kit = new GraphKit(graph, providers, wordTypes, providers.getGraphBuilderPlugins()); 233325337Sjkim ParameterNode[] params = createParameters(kit, args); 234280297Sjkim 235325337Sjkim ReadRegisterNode thread = kit.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), wordTypes.getWordKind(), true, false)); 236280297Sjkim ValueNode result = createTargetCall(kit, params, thread); 237325337Sjkim kit.createInvoke(StubUtil.class, "handlePendingException", thread, ConstantNode.forBoolean(isObjectResult, graph)); 238238405Sjkim if (isObjectResult) { 239280297Sjkim InvokeNode object = kit.createInvoke(HotSpotReplacementsUtil.class, "getAndClearObjectResult", thread); 240280297Sjkim result = kit.createInvoke(StubUtil.class, "verifyObject", object); 241280297Sjkim } 242280297Sjkim kit.append(new ReturnNode(linkage.getDescriptor().getResultType() == void.class ? null : result)); 243280297Sjkim 244238405Sjkim if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) { 245160814Ssimon Debug.dump(Debug.INFO_LOG_LEVEL, graph, "Initial stub graph"); 246280297Sjkim } 247280297Sjkim 248160814Ssimon kit.inlineInvokes(); 249160814Ssimon 250280297Sjkim new RemoveValueProxyPhase().apply(graph); 251280297Sjkim 252280297Sjkim if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) { 253280297Sjkim Debug.dump(Debug.INFO_LOG_LEVEL, graph, "Stub graph before compilation"); 254280297Sjkim } 255160814Ssimon 256160814Ssimon return graph; 257280297Sjkim } 258280297Sjkim 259280297Sjkim private ParameterNode[] createParameters(GraphKit kit, Class<?>[] args) { 260280297Sjkim ParameterNode[] params = new ParameterNode[args.length]; 261280297Sjkim ResolvedJavaType accessingClass = providers.getMetaAccess().lookupJavaType(getClass()); 262280297Sjkim for (int i = 0; i < args.length; i++) { 263280297Sjkim ResolvedJavaType type = providers.getMetaAccess().lookupJavaType(args[i]).resolve(accessingClass); 264160814Ssimon StampPair stamp = StampFactory.forDeclaredType(kit.getGraph().getAssumptions(), type, false); 265160814Ssimon ParameterNode param = kit.unique(new ParameterNode(i, stamp)); 266280297Sjkim params[i] = param; 267280297Sjkim } 268280297Sjkim return params; 269280297Sjkim } 270280297Sjkim 271280297Sjkim private StubForeignCallNode createTargetCall(GraphKit kit, ParameterNode[] params, ReadRegisterNode thread) { 272280297Sjkim if (prependThread) { 273 ValueNode[] targetArguments = new ValueNode[1 + params.length]; 274 targetArguments[0] = thread; 275 System.arraycopy(params, 0, targetArguments, 1, params.length); 276 return kit.append(new StubForeignCallNode(providers.getForeignCalls(), target.getDescriptor(), targetArguments)); 277 } else { 278 return kit.append(new StubForeignCallNode(providers.getForeignCalls(), target.getDescriptor(), params)); 279 } 280 } 281} 282