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