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