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 java.util.EnumSet; 26 27 import org.graalvm.compiler.code.CompilationResult; 28 import org.graalvm.compiler.core.common.CompilationIdentifier; 29 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; 30 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; 31 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; 32 import org.graalvm.compiler.core.target.Backend; 33 import org.graalvm.compiler.graph.Node.ConstantNodeParameter; 34 import org.graalvm.compiler.graph.Node.NodeIntrinsic; 35 import org.graalvm.compiler.hotspot.meta.HotSpotProviders; 36 import org.graalvm.compiler.hotspot.nodes.VMErrorNode; 37 import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantStubCall; 38 import org.graalvm.compiler.hotspot.replacements.AESCryptSubstitutions; 39 import org.graalvm.compiler.hotspot.replacements.BigIntegerSubstitutions; 40 import org.graalvm.compiler.hotspot.replacements.CipherBlockChainingSubstitutions; 41 import org.graalvm.compiler.hotspot.replacements.SHA2Substitutions; 42 import org.graalvm.compiler.hotspot.replacements.SHA5Substitutions; 43 import org.graalvm.compiler.hotspot.replacements.SHASubstitutions; 44 import org.graalvm.compiler.hotspot.stubs.ExceptionHandlerStub; 45 import org.graalvm.compiler.hotspot.stubs.Stub; 46 import org.graalvm.compiler.hotspot.stubs.UnwindExceptionToCallerStub; 47 import org.graalvm.compiler.hotspot.word.KlassPointer; 48 import org.graalvm.compiler.hotspot.word.MethodCountersPointer; 49 import org.graalvm.compiler.lir.LIR; 50 import org.graalvm.compiler.lir.LIRFrameState; 51 import org.graalvm.compiler.lir.LIRInstruction; 52 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; 53 import org.graalvm.compiler.lir.LIRInstruction.OperandMode; 54 import org.graalvm.compiler.lir.StandardOp.LabelOp; 55 import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; 56 import org.graalvm.compiler.lir.ValueConsumer; 57 import org.graalvm.compiler.lir.asm.CompilationResultBuilder; 58 import org.graalvm.compiler.lir.framemap.FrameMap; 59 import org.graalvm.compiler.nodes.UnwindNode; 60 import org.graalvm.compiler.nodes.extended.ForeignCallNode; 61 import org.graalvm.compiler.options.Option; 62 import org.graalvm.compiler.options.OptionKey; 63 import org.graalvm.compiler.options.OptionType; 64 import org.graalvm.compiler.options.OptionValues; 65 import org.graalvm.compiler.phases.tiers.SuitesProvider; 66 import org.graalvm.compiler.word.Word; 67 import org.graalvm.util.EconomicMap; 68 import org.graalvm.util.EconomicSet; 69 import org.graalvm.util.Equivalence; 70 import org.graalvm.util.MapCursor; 71 import org.graalvm.word.Pointer; 72 73 import jdk.vm.ci.code.CompilationRequest; 74 import jdk.vm.ci.code.CompiledCode; 75 import jdk.vm.ci.code.Register; 76 import jdk.vm.ci.code.RegisterSaveLayout; 77 import jdk.vm.ci.code.StackSlot; 78 import jdk.vm.ci.code.ValueUtil; 79 import jdk.vm.ci.hotspot.HotSpotCompilationRequest; 80 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; 81 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; 82 import jdk.vm.ci.meta.ResolvedJavaMethod; 83 import jdk.vm.ci.meta.Value; 84 import jdk.vm.ci.runtime.JVMCICompiler; 85 86 /** 87 * HotSpot specific backend. 88 */ 89 public abstract class HotSpotBackend extends Backend implements FrameMap.ReferenceMapBuilderFactory { 90 91 public static class Options { 92 // @formatter:off 93 @Option(help = "Use Graal arithmetic stubs instead of HotSpot stubs where possible") 94 public static final OptionKey<Boolean> GraalArithmeticStubs = new OptionKey<>(true); 95 @Option(help = "Enables instruction profiling on assembler level. Valid values are a comma separated list of supported instructions." + 96 " Compare with subclasses of Assembler.InstructionCounter.", type = OptionType.Debug) 97 public static final OptionKey<String> ASMInstructionProfiling = new OptionKey<>(null); 98 // @formatter:on 99 } 100 101 /** 102 * Descriptor for {@link ExceptionHandlerStub}. This stub is called by the 103 * {@linkplain GraalHotSpotVMConfig#MARKID_EXCEPTION_HANDLER_ENTRY exception handler} in a 104 * compiled method. 105 */ 106 public static final ForeignCallDescriptor EXCEPTION_HANDLER = new ForeignCallDescriptor("exceptionHandler", void.class, Object.class, Word.class); 107 108 /** 109 * Descriptor for SharedRuntime::get_ic_miss_stub(). 110 */ 111 public static final ForeignCallDescriptor IC_MISS_HANDLER = new ForeignCallDescriptor("icMissHandler", void.class); 112 113 /** 114 * Descriptor for SharedRuntime::get_handle_wrong_method_stub(). 115 */ 116 public static final ForeignCallDescriptor WRONG_METHOD_HANDLER = new ForeignCallDescriptor("wrongMethodHandler", void.class); 117 118 /** 119 * Descriptor for {@link UnwindExceptionToCallerStub}. This stub is called by code generated 120 * from {@link UnwindNode}. 121 */ 122 public static final ForeignCallDescriptor UNWIND_EXCEPTION_TO_CALLER = new ForeignCallDescriptor("unwindExceptionToCaller", void.class, Object.class, Word.class); 123 124 /** 125 * Descriptor for the arguments when unwinding to an exception handler in a caller. 126 */ 127 public static final ForeignCallDescriptor EXCEPTION_HANDLER_IN_CALLER = new ForeignCallDescriptor("exceptionHandlerInCaller", void.class, Object.class, Word.class); 128 129 private final HotSpotGraalRuntimeProvider runtime; 130 131 /** 132 * @see AESCryptSubstitutions#encryptBlockStub(ForeignCallDescriptor, Word, Word, Pointer) 133 */ 134 public static final ForeignCallDescriptor ENCRYPT_BLOCK = new ForeignCallDescriptor("encrypt_block", void.class, Word.class, Word.class, Pointer.class); 135 136 /** 137 * @see AESCryptSubstitutions#decryptBlockStub(ForeignCallDescriptor, Word, Word, Pointer) 138 */ 139 public static final ForeignCallDescriptor DECRYPT_BLOCK = new ForeignCallDescriptor("decrypt_block", void.class, Word.class, Word.class, Pointer.class); 140 141 /** 142 * @see AESCryptSubstitutions#decryptBlockStub(ForeignCallDescriptor, Word, Word, Pointer) 143 */ 144 public static final ForeignCallDescriptor DECRYPT_BLOCK_WITH_ORIGINAL_KEY = new ForeignCallDescriptor("decrypt_block_with_original_key", void.class, Word.class, Word.class, Pointer.class, 145 Pointer.class); 146 147 /** 148 * @see CipherBlockChainingSubstitutions#crypt 149 */ 150 public static final ForeignCallDescriptor ENCRYPT = new ForeignCallDescriptor("encrypt", void.class, Word.class, Word.class, Pointer.class, Pointer.class, int.class); 151 152 /** 153 * @see CipherBlockChainingSubstitutions#crypt 154 */ 155 public static final ForeignCallDescriptor DECRYPT = new ForeignCallDescriptor("decrypt", void.class, Word.class, Word.class, Pointer.class, Pointer.class, int.class); 156 157 /** 158 * @see CipherBlockChainingSubstitutions#crypt 159 */ 160 public static final ForeignCallDescriptor DECRYPT_WITH_ORIGINAL_KEY = new ForeignCallDescriptor("decrypt_with_original_key", void.class, Word.class, Word.class, Pointer.class, Pointer.class, 161 int.class, Pointer.class); 162 163 /** 164 * @see BigIntegerSubstitutions#multiplyToLen 165 */ 166 public static final ForeignCallDescriptor MULTIPLY_TO_LEN = new ForeignCallDescriptor("multiplyToLen", void.class, Word.class, int.class, Word.class, int.class, Word.class, int.class); 167 168 public static void multiplyToLenStub(Word xAddr, int xlen, Word yAddr, int ylen, Word zAddr, int zLen) { 169 multiplyToLenStub(HotSpotBackend.MULTIPLY_TO_LEN, xAddr, xlen, yAddr, ylen, zAddr, zLen); 170 } 171 172 @NodeIntrinsic(ForeignCallNode.class) 173 private static native void multiplyToLenStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word xIn, int xLen, Word yIn, int yLen, Word zIn, int zLen); 174 175 /** 176 * @see BigIntegerSubstitutions#mulAdd 177 */ 178 public static final ForeignCallDescriptor MUL_ADD = new ForeignCallDescriptor("mulAdd", int.class, Word.class, Word.class, int.class, int.class, int.class); 179 180 public static int mulAddStub(Word inAddr, Word outAddr, int newOffset, int len, int k) { 181 return mulAddStub(HotSpotBackend.MUL_ADD, inAddr, outAddr, newOffset, len, k); 182 } 183 184 @NodeIntrinsic(ForeignCallNode.class) 185 private static native int mulAddStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word inAddr, Word outAddr, int newOffset, int len, int k); 186 187 /** 188 * @see BigIntegerSubstitutions#implMontgomeryMultiply 189 */ 190 public static final ForeignCallDescriptor MONTGOMERY_MULTIPLY = new ForeignCallDescriptor("implMontgomeryMultiply", void.class, Word.class, Word.class, Word.class, int.class, long.class, 191 Word.class); 192 193 public static void implMontgomeryMultiply(Word aAddr, Word bAddr, Word nAddr, int len, long inv, Word productAddr) { 194 implMontgomeryMultiply(HotSpotBackend.MONTGOMERY_MULTIPLY, aAddr, bAddr, nAddr, len, inv, productAddr); 195 } 196 197 @NodeIntrinsic(ForeignCallNode.class) 198 private static native void implMontgomeryMultiply(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word aAddr, Word bAddr, Word nAddr, int len, long inv, Word productAddr); 199 200 /** 201 * @see BigIntegerSubstitutions#implMontgomerySquare 202 */ 203 public static final ForeignCallDescriptor MONTGOMERY_SQUARE = new ForeignCallDescriptor("implMontgomerySquare", void.class, Word.class, Word.class, int.class, long.class, Word.class); 204 205 public static void implMontgomerySquare(Word aAddr, Word nAddr, int len, long inv, Word productAddr) { 206 implMontgomerySquare(HotSpotBackend.MONTGOMERY_SQUARE, aAddr, nAddr, len, inv, productAddr); 207 } 208 209 @NodeIntrinsic(ForeignCallNode.class) 210 private static native void implMontgomerySquare(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word aAddr, Word nAddr, int len, long inv, Word productAddr); 211 212 /** 213 * @see BigIntegerSubstitutions#implSquareToLen 214 */ 215 public static final ForeignCallDescriptor SQUARE_TO_LEN = new ForeignCallDescriptor("implSquareToLen", void.class, Word.class, int.class, Word.class, int.class); 216 217 public static void implSquareToLen(Word xAddr, int len, Word zAddr, int zLen) { 218 implSquareToLen(SQUARE_TO_LEN, xAddr, len, zAddr, zLen); 219 } 220 221 @NodeIntrinsic(ForeignCallNode.class) 222 private static native void implSquareToLen(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word xAddr, int len, Word zAddr, int zLen); 223 224 /** 225 * @see SHASubstitutions#implCompress0 226 */ 227 public static final ForeignCallDescriptor SHA_IMPL_COMPRESS = new ForeignCallDescriptor("shaImplCompress", void.class, Word.class, Object.class); 228 229 public static void shaImplCompressStub(Word bufAddr, Object state) { 230 shaImplCompressStub(HotSpotBackend.SHA_IMPL_COMPRESS, bufAddr, state); 231 } 232 233 @NodeIntrinsic(ForeignCallNode.class) 234 private static native void shaImplCompressStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word bufAddr, Object state); 235 236 /** 237 * @see SHA2Substitutions#implCompress0 238 */ 239 public static final ForeignCallDescriptor SHA2_IMPL_COMPRESS = new ForeignCallDescriptor("sha2ImplCompress", void.class, Word.class, Object.class); 240 241 public static void sha2ImplCompressStub(Word bufAddr, Object state) { 242 sha2ImplCompressStub(HotSpotBackend.SHA2_IMPL_COMPRESS, bufAddr, state); 243 } 244 245 @NodeIntrinsic(ForeignCallNode.class) 246 private static native void sha2ImplCompressStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word bufAddr, Object state); 247 248 /** 249 * @see SHA5Substitutions#implCompress0 250 */ 251 public static final ForeignCallDescriptor SHA5_IMPL_COMPRESS = new ForeignCallDescriptor("sha5ImplCompress", void.class, Word.class, Object.class); 252 253 public static void sha5ImplCompressStub(Word bufAddr, Object state) { 254 sha5ImplCompressStub(HotSpotBackend.SHA5_IMPL_COMPRESS, bufAddr, state); 255 } 256 257 @NodeIntrinsic(ForeignCallNode.class) 258 private static native void sha5ImplCompressStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word bufAddr, Object state); 259 260 /** 261 * @see org.graalvm.compiler.hotspot.meta.HotSpotUnsafeSubstitutions#copyMemory 262 */ 263 public static final ForeignCallDescriptor UNSAFE_ARRAYCOPY = new ForeignCallDescriptor("unsafe_arraycopy", void.class, Word.class, Word.class, Word.class); 264 265 public static void unsafeArraycopy(Word srcAddr, Word dstAddr, Word size) { 266 unsafeArraycopyStub(HotSpotBackend.UNSAFE_ARRAYCOPY, srcAddr, dstAddr, size); 267 } 268 269 @NodeIntrinsic(ForeignCallNode.class) 270 private static native void unsafeArraycopyStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word srcAddr, Word dstAddr, Word size); 271 272 /** 273 * @see VMErrorNode 274 */ 275 public static final ForeignCallDescriptor VM_ERROR = new ForeignCallDescriptor("vm_error", void.class, Object.class, Object.class, long.class); 276 277 /** 278 * New multi array stub call. 279 */ 280 public static final ForeignCallDescriptor NEW_MULTI_ARRAY = new ForeignCallDescriptor("new_multi_array", Object.class, KlassPointer.class, int.class, Word.class); 281 282 /** 283 * New array stub. 284 */ 285 public static final ForeignCallDescriptor NEW_ARRAY = new ForeignCallDescriptor("new_array", Object.class, KlassPointer.class, int.class, boolean.class); 286 287 /** 288 * New instance stub. 289 */ 290 public static final ForeignCallDescriptor NEW_INSTANCE = new ForeignCallDescriptor("new_instance", Object.class, KlassPointer.class); 291 292 /** 293 * @see ResolveConstantStubCall 294 */ 295 public static final ForeignCallDescriptor RESOLVE_STRING_BY_SYMBOL = new ForeignCallDescriptor("resolve_string_by_symbol", Object.class, Word.class, Word.class); 296 297 /** 298 * @see ResolveConstantStubCall 299 */ 300 public static final ForeignCallDescriptor RESOLVE_KLASS_BY_SYMBOL = new ForeignCallDescriptor("resolve_klass_by_symbol", Word.class, Word.class, Word.class); 301 302 /** 303 * @see ResolveConstantStubCall 304 */ 305 public static final ForeignCallDescriptor INITIALIZE_KLASS_BY_SYMBOL = new ForeignCallDescriptor("initialize_klass_by_symbol", Word.class, Word.class, Word.class); 306 307 /** 308 * @see ResolveConstantStubCall 309 */ 310 public static final ForeignCallDescriptor RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS = new ForeignCallDescriptor("resolve_method_by_symbol_and_load_counters", Word.class, Word.class, Word.class, 311 Word.class); 312 313 /** 314 * Tiered support. 315 */ 316 public static final ForeignCallDescriptor INVOCATION_EVENT = new ForeignCallDescriptor("invocation_event", void.class, MethodCountersPointer.class); 317 public static final ForeignCallDescriptor BACKEDGE_EVENT = new ForeignCallDescriptor("backedge_event", void.class, MethodCountersPointer.class, int.class, int.class); 318 319 public HotSpotBackend(HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) { 320 super(providers); 321 this.runtime = runtime; 322 } 323 324 public HotSpotGraalRuntimeProvider getRuntime() { 325 return runtime; 326 } 327 328 /** 329 * Performs any remaining initialization that was deferred until the {@linkplain #getRuntime() 330 * runtime} object was initialized and this backend was registered with it. 331 * 332 * @param jvmciRuntime 333 * @param options 334 */ 335 public void completeInitialization(HotSpotJVMCIRuntime jvmciRuntime, OptionValues options) { 336 } 337 338 /** 339 * Finds all the registers that are defined by some given LIR. 340 * 341 * @param lir the LIR to examine 342 * @return the registers that are defined by or used as temps for any instruction in {@code lir} 343 */ 344 protected final EconomicSet<Register> gatherDestroyedCallerRegisters(LIR lir) { 345 final EconomicSet<Register> destroyedRegisters = EconomicSet.create(Equivalence.IDENTITY); 346 ValueConsumer defConsumer = new ValueConsumer() { 347 348 @Override 349 public void visitValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) { 350 if (ValueUtil.isRegister(value)) { 351 final Register reg = ValueUtil.asRegister(value); 352 destroyedRegisters.add(reg); 353 } 354 } 355 }; 356 for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) { 357 if (block == null) { 358 continue; 359 } 360 for (LIRInstruction op : lir.getLIRforBlock(block)) { 361 if (op instanceof LabelOp) { 362 // Don't consider this as a definition 363 } else { 364 op.visitEachTemp(defConsumer); 365 op.visitEachOutput(defConsumer); 366 } 367 } 368 } 369 return translateToCallerRegisters(destroyedRegisters); 370 } 371 372 /** 373 * Updates a given stub with respect to the registers it destroys. 374 * <p> 375 * Any entry in {@code calleeSaveInfo} that {@linkplain SaveRegistersOp#supportsRemove() 376 * supports} pruning will have {@code destroyedRegisters} 377 * {@linkplain SaveRegistersOp#remove(EconomicSet) removed} as these registers are declared as 378 * temporaries in the stub's {@linkplain ForeignCallLinkage linkage} (and thus will be saved by 379 * the stub's caller). 380 * 381 * @param stub the stub to update 382 * @param destroyedRegisters the registers destroyed by the stub 383 * @param calleeSaveInfo a map from debug infos to the operations that provide their 384 * {@linkplain RegisterSaveLayout callee-save information} 385 * @param frameMap used to {@linkplain FrameMap#offsetForStackSlot(StackSlot) convert} a virtual 386 * slot to a frame slot index 387 */ 388 protected void updateStub(Stub stub, EconomicSet<Register> destroyedRegisters, EconomicMap<LIRFrameState, SaveRegistersOp> calleeSaveInfo, FrameMap frameMap) { 389 stub.initDestroyedCallerRegisters(destroyedRegisters); 390 391 MapCursor<LIRFrameState, SaveRegistersOp> cursor = calleeSaveInfo.getEntries(); 392 while (cursor.advance()) { 393 SaveRegistersOp save = cursor.getValue(); 394 if (save.supportsRemove()) { 395 save.remove(destroyedRegisters); 396 } 397 if (cursor.getKey() != LIRFrameState.NO_STATE) { 398 cursor.getKey().debugInfo().setCalleeSaveInfo(save.getMap(frameMap)); 399 } 400 } 401 } 402 403 @Override 404 public HotSpotProviders getProviders() { 405 return (HotSpotProviders) super.getProviders(); 406 } 407 408 @Override 409 public SuitesProvider getSuites() { 410 return getProviders().getSuites(); 411 } 412 413 protected void profileInstructions(LIR lir, CompilationResultBuilder crb) { 414 if (HotSpotBackend.Options.ASMInstructionProfiling.getValue(lir.getOptions()) != null) { 415 HotSpotInstructionProfiling.countInstructions(lir, crb.asm); 416 } 417 } 418 419 @Override 420 public CompiledCode createCompiledCode(ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compResult) { 421 HotSpotCompilationRequest compRequest = compilationRequest instanceof HotSpotCompilationRequest ? (HotSpotCompilationRequest) compilationRequest : null; 422 return HotSpotCompiledCodeBuilder.createCompiledCode(getCodeCache(), method, compRequest, compResult); 423 } 424 425 @Override 426 public CompilationIdentifier getCompilationIdentifier(ResolvedJavaMethod resolvedJavaMethod) { 427 if (resolvedJavaMethod instanceof HotSpotResolvedJavaMethod) { 428 HotSpotCompilationRequest request = new HotSpotCompilationRequest((HotSpotResolvedJavaMethod) resolvedJavaMethod, JVMCICompiler.INVOCATION_ENTRY_BCI, 0L); 429 return new HotSpotCompilationIdentifier(request); 430 } 431 return super.getCompilationIdentifier(resolvedJavaMethod); 432 } 433 }