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}