001/*
002 * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.hotspot.meta;
024
025import static com.oracle.graal.compiler.target.Backend.*;
026import static com.oracle.graal.hotspot.HotSpotBackend.*;
027import static com.oracle.graal.hotspot.HotSpotBackend.Options.*;
028import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*;
029import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*;
030import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
031import static com.oracle.graal.hotspot.meta.DefaultHotSpotLoweringProvider.RuntimeCalls.*;
032import static com.oracle.graal.hotspot.replacements.AssertionSnippets.*;
033import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
034import static com.oracle.graal.hotspot.replacements.MonitorSnippets.*;
035import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*;
036import static com.oracle.graal.hotspot.replacements.SystemSubstitutions.*;
037import static com.oracle.graal.hotspot.replacements.ThreadSubstitutions.*;
038import static com.oracle.graal.hotspot.replacements.WriteBarrierSnippets.*;
039import static com.oracle.graal.hotspot.stubs.ExceptionHandlerStub.*;
040import static com.oracle.graal.hotspot.stubs.NewArrayStub.*;
041import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*;
042import static com.oracle.graal.hotspot.stubs.StubUtil.*;
043import static com.oracle.graal.hotspot.stubs.UnwindExceptionToCallerStub.*;
044import static com.oracle.graal.nodes.NamedLocationIdentity.*;
045import static com.oracle.graal.nodes.java.ForeignCallDescriptors.*;
046import static com.oracle.graal.replacements.Log.*;
047import static jdk.internal.jvmci.code.CallingConvention.Type.*;
048
049import java.util.*;
050
051import jdk.internal.jvmci.code.*;
052import jdk.internal.jvmci.common.*;
053import jdk.internal.jvmci.hotspot.*;
054import jdk.internal.jvmci.meta.*;
055
056import com.oracle.graal.compiler.common.spi.*;
057import com.oracle.graal.hotspot.*;
058import com.oracle.graal.hotspot.stubs.*;
059import com.oracle.graal.nodes.*;
060import com.oracle.graal.word.*;
061
062/**
063 * HotSpot implementation of {@link ForeignCallsProvider}.
064 */
065public abstract class HotSpotHostForeignCallsProvider extends HotSpotForeignCallsProviderImpl {
066
067    public HotSpotHostForeignCallsProvider(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, CodeCacheProvider codeCache) {
068        super(runtime, metaAccess, codeCache);
069    }
070
071    protected static void link(Stub stub) {
072        stub.getLinkage().setCompiledStub(stub);
073    }
074
075    public static ForeignCallDescriptor lookupCheckcastArraycopyDescriptor(boolean uninit) {
076        return checkcastArraycopyDescriptors[uninit ? 1 : 0];
077    }
078
079    public static ForeignCallDescriptor lookupArraycopyDescriptor(Kind kind, boolean aligned, boolean disjoint, boolean uninit, boolean killAny) {
080        if (uninit) {
081            assert kind == Kind.Object;
082            assert !killAny : "unsupported";
083            return uninitObjectArraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0];
084        }
085        if (killAny) {
086            assert kind == Kind.Object;
087            return objectArraycopyDescriptorsKillAny[aligned ? 1 : 0][disjoint ? 1 : 0];
088        }
089        return arraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0].get(kind);
090    }
091
092    @SuppressWarnings("unchecked") private static final EnumMap<Kind, ForeignCallDescriptor>[][] arraycopyDescriptors = new EnumMap[2][2];
093
094    private static final ForeignCallDescriptor[][] uninitObjectArraycopyDescriptors = new ForeignCallDescriptor[2][2];
095    private static final ForeignCallDescriptor[] checkcastArraycopyDescriptors = new ForeignCallDescriptor[2];
096    private static ForeignCallDescriptor[][] objectArraycopyDescriptorsKillAny = new ForeignCallDescriptor[2][2];
097
098    static {
099        // Populate the EnumMap instances
100        for (int i = 0; i < arraycopyDescriptors.length; i++) {
101            for (int j = 0; j < arraycopyDescriptors[i].length; j++) {
102                arraycopyDescriptors[i][j] = new EnumMap<>(Kind.class);
103            }
104        }
105    }
106
107    private void registerArraycopyDescriptor(Map<Long, ForeignCallDescriptor> descMap, Kind kind, boolean aligned, boolean disjoint, boolean uninit, boolean killAny, long routine) {
108        ForeignCallDescriptor desc = descMap.get(routine);
109        if (desc == null) {
110            desc = buildDescriptor(kind, aligned, disjoint, uninit, killAny, routine);
111            descMap.put(routine, desc);
112        }
113        if (uninit) {
114            assert kind == Kind.Object;
115            uninitObjectArraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0] = desc;
116        } else {
117            arraycopyDescriptors[aligned ? 1 : 0][disjoint ? 1 : 0].put(kind, desc);
118        }
119    }
120
121    private ForeignCallDescriptor buildDescriptor(Kind kind, boolean aligned, boolean disjoint, boolean uninit, boolean killAny, long routine) {
122        assert !killAny || kind == Kind.Object;
123        String name = kind + (aligned ? "Aligned" : "") + (disjoint ? "Disjoint" : "") + (uninit ? "Uninit" : "") + "Arraycopy" + (killAny ? "KillAny" : "");
124        ForeignCallDescriptor desc = new ForeignCallDescriptor(name, void.class, Word.class, Word.class, Word.class);
125        LocationIdentity killed = killAny ? LocationIdentity.any() : NamedLocationIdentity.getArrayLocation(kind);
126        registerForeignCall(desc, routine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed);
127        return desc;
128    }
129
130    private void registerCheckcastArraycopyDescriptor(boolean uninit, long routine) {
131        String name = "Object" + (uninit ? "Uninit" : "") + "Checkcast";
132        // Input:
133        // c_rarg0 - source array address
134        // c_rarg1 - destination array address
135        // c_rarg2 - element count, treated as ssize_t, can be zero
136        // c_rarg3 - size_t ckoff (super_check_offset)
137        // c_rarg4 - oop ckval (super_klass)
138        // return: 0 = success, n = number of copied elements xor'd with -1.
139        ForeignCallDescriptor desc = new ForeignCallDescriptor(name, int.class, Word.class, Word.class, Word.class, Word.class, Word.class);
140        LocationIdentity killed = NamedLocationIdentity.getArrayLocation(Kind.Object);
141        registerForeignCall(desc, routine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed);
142        checkcastArraycopyDescriptors[uninit ? 1 : 0] = desc;
143    }
144
145    private void registerArrayCopy(Kind kind, long routine, long alignedRoutine, long disjointRoutine, long alignedDisjointRoutine) {
146        registerArrayCopy(kind, routine, alignedRoutine, disjointRoutine, alignedDisjointRoutine, false);
147    }
148
149    private void registerArrayCopy(Kind kind, long routine, long alignedRoutine, long disjointRoutine, long alignedDisjointRoutine, boolean uninit) {
150        /*
151         * Sometimes the same function is used for multiple cases so share them when that's the case
152         * but only within the same Kind. For instance short and char are the same copy routines but
153         * they kill different memory so they still have to be distinct.
154         */
155        Map<Long, ForeignCallDescriptor> descMap = new HashMap<>();
156        registerArraycopyDescriptor(descMap, kind, false, false, uninit, false, routine);
157        registerArraycopyDescriptor(descMap, kind, true, false, uninit, false, alignedRoutine);
158        registerArraycopyDescriptor(descMap, kind, false, true, uninit, false, disjointRoutine);
159        registerArraycopyDescriptor(descMap, kind, true, true, uninit, false, alignedDisjointRoutine);
160
161        if (kind == Kind.Object && !uninit) {
162            objectArraycopyDescriptorsKillAny[0][0] = buildDescriptor(kind, false, false, uninit, true, routine);
163            objectArraycopyDescriptorsKillAny[1][0] = buildDescriptor(kind, true, false, uninit, true, alignedRoutine);
164            objectArraycopyDescriptorsKillAny[0][1] = buildDescriptor(kind, false, true, uninit, true, disjointRoutine);
165            objectArraycopyDescriptorsKillAny[1][1] = buildDescriptor(kind, true, true, uninit, true, alignedDisjointRoutine);
166        }
167    }
168
169    public void initialize(HotSpotProviders providers, HotSpotVMConfig c) {
170
171        if (!PreferGraalStubs.getValue()) {
172            registerForeignCall(DEOPTIMIZATION_HANDLER, c.handleDeoptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
173            registerForeignCall(UNCOMMON_TRAP_HANDLER, c.uncommonTrapStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
174        }
175        registerForeignCall(IC_MISS_HANDLER, c.inlineCacheMissStub(), NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
176
177        registerForeignCall(JAVA_TIME_MILLIS, c.javaTimeMillisAddress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
178        registerForeignCall(JAVA_TIME_NANOS, c.javaTimeNanosAddress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
179        registerForeignCall(ARITHMETIC_SIN, c.arithmeticSinAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
180        registerForeignCall(ARITHMETIC_COS, c.arithmeticCosAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
181        registerForeignCall(ARITHMETIC_TAN, c.arithmeticTanAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
182        registerForeignCall(ARITHMETIC_EXP, c.arithmeticExpAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
183        registerForeignCall(ARITHMETIC_LOG, c.arithmeticLogAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
184        registerForeignCall(ARITHMETIC_LOG10, c.arithmeticLog10Address, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
185        registerForeignCall(ARITHMETIC_POW, c.arithmeticPowAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
186        registerForeignCall(LOAD_AND_CLEAR_EXCEPTION, c.loadAndClearExceptionAddress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, any());
187
188        registerForeignCall(EXCEPTION_HANDLER_FOR_PC, c.exceptionHandlerForPcAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, any());
189        registerForeignCall(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, c.exceptionHandlerForReturnAddressAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, any());
190        registerForeignCall(FETCH_UNROLL_INFO, c.deoptimizationFetchUnrollInfo, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, any());
191        registerForeignCall(NEW_ARRAY_C, c.newArrayAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, any());
192        registerForeignCall(NEW_INSTANCE_C, c.newInstanceAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, any());
193        registerForeignCall(UNCOMMON_TRAP, c.deoptimizationUncommonTrap, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, NOT_REEXECUTABLE, any());
194
195        /*
196         * We cannot use LEAF_SP here because on some architectures we have to align the stack
197         * manually before calling into the VM. See {@link
198         * AMD64HotSpotEnterUnpackFramesStackFrameOp#emitCode}.
199         */
200        registerForeignCall(UNPACK_FRAMES, c.deoptimizationUnpackFrames, NativeCall, DESTROYS_REGISTERS, LEAF, NOT_REEXECUTABLE, any());
201
202        /*
203         * This message call is registered twice, where the second one must only be used for calls
204         * that do not return, i.e., that exit the VM.
205         */
206        registerForeignCall(VM_MESSAGE_C, c.vmMessageAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, NO_LOCATIONS);
207        registerForeignCall(ASSERTION_VM_MESSAGE_C, c.vmMessageAddress, NativeCall, PRESERVES_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
208
209        link(new NewInstanceStub(providers, registerStubCall(NEW_INSTANCE, REEXECUTABLE, NOT_LEAF, INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION)));
210        link(new NewArrayStub(providers, registerStubCall(NEW_ARRAY, REEXECUTABLE, NOT_LEAF, INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION)));
211        link(new ExceptionHandlerStub(providers, foreignCalls.get(EXCEPTION_HANDLER)));
212        link(new UnwindExceptionToCallerStub(providers, registerStubCall(UNWIND_EXCEPTION_TO_CALLER, NOT_REEXECUTABLE, NOT_LEAF, any())));
213        link(new VerifyOopStub(providers, registerStubCall(VERIFY_OOP, REEXECUTABLE, LEAF_NOFP, NO_LOCATIONS)));
214
215        linkForeignCall(providers, IDENTITY_HASHCODE, c.identityHashCodeAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, MARK_WORD_LOCATION);
216        linkForeignCall(providers, REGISTER_FINALIZER, c.registerFinalizerAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, any());
217        linkForeignCall(providers, CREATE_NULL_POINTER_EXCEPTION, c.createNullPointerExceptionAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, any());
218        linkForeignCall(providers, CREATE_OUT_OF_BOUNDS_EXCEPTION, c.createOutOfBoundsExceptionAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, any());
219        linkForeignCall(providers, MONITORENTER, c.monitorenterAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, any());
220        linkForeignCall(providers, MONITOREXIT, c.monitorexitAddress, PREPEND_THREAD, STACK_INSPECTABLE_LEAF, NOT_REEXECUTABLE, any());
221        linkForeignCall(providers, NEW_MULTI_ARRAY, c.newMultiArrayAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
222        linkForeignCall(providers, DYNAMIC_NEW_ARRAY, c.dynamicNewArrayAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, INIT_LOCATION);
223        linkForeignCall(providers, DYNAMIC_NEW_INSTANCE, c.dynamicNewInstanceAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, INIT_LOCATION);
224        linkForeignCall(providers, LOG_PRINTF, c.logPrintfAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS);
225        linkForeignCall(providers, LOG_OBJECT, c.logObjectAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS);
226        linkForeignCall(providers, LOG_PRIMITIVE, c.logPrimitiveAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS);
227        linkForeignCall(providers, VM_ERROR, c.vmErrorAddress, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
228        linkForeignCall(providers, OSR_MIGRATION_END, c.osrMigrationEndAddress, DONT_PREPEND_THREAD, LEAF_NOFP, NOT_REEXECUTABLE, NO_LOCATIONS);
229        linkForeignCall(providers, G1WBPRECALL, c.writeBarrierPreAddress, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
230        linkForeignCall(providers, G1WBPOSTCALL, c.writeBarrierPostAddress, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
231        linkForeignCall(providers, VALIDATE_OBJECT, c.validateObject, PREPEND_THREAD, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
232
233        // Cannot be a leaf as VM acquires Thread_lock which requires thread_in_vm state
234        linkForeignCall(providers, THREAD_IS_INTERRUPTED, c.threadIsInterruptedAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, any());
235
236        linkForeignCall(providers, TEST_DEOPTIMIZE_CALL_INT, c.testDeoptimizeCallInt, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, any());
237
238        registerArrayCopy(Kind.Byte, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy);
239        registerArrayCopy(Kind.Boolean, c.jbyteArraycopy, c.jbyteAlignedArraycopy, c.jbyteDisjointArraycopy, c.jbyteAlignedDisjointArraycopy);
240        registerArrayCopy(Kind.Char, c.jshortArraycopy, c.jshortAlignedArraycopy, c.jshortDisjointArraycopy, c.jshortAlignedDisjointArraycopy);
241        registerArrayCopy(Kind.Short, c.jshortArraycopy, c.jshortAlignedArraycopy, c.jshortDisjointArraycopy, c.jshortAlignedDisjointArraycopy);
242        registerArrayCopy(Kind.Int, c.jintArraycopy, c.jintAlignedArraycopy, c.jintDisjointArraycopy, c.jintAlignedDisjointArraycopy);
243        registerArrayCopy(Kind.Float, c.jintArraycopy, c.jintAlignedArraycopy, c.jintDisjointArraycopy, c.jintAlignedDisjointArraycopy);
244        registerArrayCopy(Kind.Long, c.jlongArraycopy, c.jlongAlignedArraycopy, c.jlongDisjointArraycopy, c.jlongAlignedDisjointArraycopy);
245        registerArrayCopy(Kind.Double, c.jlongArraycopy, c.jlongAlignedArraycopy, c.jlongDisjointArraycopy, c.jlongAlignedDisjointArraycopy);
246        registerArrayCopy(Kind.Object, c.oopArraycopy, c.oopAlignedArraycopy, c.oopDisjointArraycopy, c.oopAlignedDisjointArraycopy);
247        registerArrayCopy(Kind.Object, c.oopArraycopyUninit, c.oopAlignedArraycopyUninit, c.oopDisjointArraycopyUninit, c.oopAlignedDisjointArraycopyUninit, true);
248
249        registerCheckcastArraycopyDescriptor(true, c.checkcastArraycopyUninit);
250        registerCheckcastArraycopyDescriptor(false, c.checkcastArraycopy);
251
252        if (c.useAESIntrinsics) {
253            /*
254             * When the java.ext.dirs property is modified then the crypto classes might not be
255             * found. If that's the case we ignore the ClassNotFoundException and continue since we
256             * cannot replace a non-existing method anyway.
257             */
258            try {
259                // These stubs do callee saving
260                registerForeignCall(ENCRYPT_BLOCK, c.aescryptEncryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(Kind.Byte));
261                registerForeignCall(DECRYPT_BLOCK, c.aescryptDecryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(Kind.Byte));
262            } catch (JVMCIError e) {
263                if (!(e.getCause() instanceof ClassNotFoundException)) {
264                    throw e;
265                }
266            }
267            try {
268                // These stubs do callee saving
269                registerForeignCall(ENCRYPT, c.cipherBlockChainingEncryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(Kind.Byte));
270                registerForeignCall(DECRYPT, c.cipherBlockChainingDecryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(Kind.Byte));
271            } catch (JVMCIError e) {
272                if (!(e.getCause() instanceof ClassNotFoundException)) {
273                    throw e;
274                }
275            }
276        }
277    }
278
279    public HotSpotForeignCallLinkage getForeignCall(ForeignCallDescriptor descriptor) {
280        assert foreignCalls != null : descriptor;
281        return foreignCalls.get(descriptor);
282    }
283}