001/* 002 * Copyright (c) 2012, 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; 024 025import static com.oracle.graal.hotspot.stubs.StubUtil.*; 026 027import java.util.*; 028 029import jdk.internal.jvmci.code.*; 030import jdk.internal.jvmci.code.stack.*; 031import jdk.internal.jvmci.hotspot.*; 032import jdk.internal.jvmci.meta.*; 033import jdk.internal.jvmci.options.*; 034 035import com.oracle.graal.compiler.common.cfg.*; 036import com.oracle.graal.compiler.common.spi.*; 037import com.oracle.graal.compiler.target.*; 038import com.oracle.graal.hotspot.meta.*; 039import com.oracle.graal.hotspot.nodes.*; 040import com.oracle.graal.hotspot.replacements.*; 041import com.oracle.graal.hotspot.stubs.*; 042import com.oracle.graal.lir.*; 043import com.oracle.graal.lir.LIRInstruction.OperandFlag; 044import com.oracle.graal.lir.LIRInstruction.OperandMode; 045import com.oracle.graal.lir.StandardOp.LabelOp; 046import com.oracle.graal.lir.StandardOp.SaveRegistersOp; 047import com.oracle.graal.lir.asm.*; 048import com.oracle.graal.lir.framemap.*; 049import com.oracle.graal.nodes.*; 050import com.oracle.graal.phases.tiers.*; 051import com.oracle.graal.word.*; 052 053/** 054 * HotSpot specific backend. 055 */ 056public abstract class HotSpotBackend extends Backend implements FrameMap.ReferenceMapBuilderFactory { 057 058 public static class Options { 059 // @formatter:off 060 @Option(help = "Use Graal stubs instead of HotSpot stubs where possible") 061 public static final OptionValue<Boolean> PreferGraalStubs = new OptionValue<>(false); 062 @Option(help = "Enables instruction profiling on assembler level. Valid values are a comma separated list of supported instructions." + 063 " Compare with subclasses of Assembler.InstructionCounter.", type = OptionType.Debug) 064 public static final OptionValue<String> ASMInstructionProfiling = new OptionValue<>(null); 065 // @formatter:on 066 } 067 068 /** 069 * Descriptor for {@link ExceptionHandlerStub}. This stub is called by the 070 * {@linkplain HotSpotVMConfig#MARKID_EXCEPTION_HANDLER_ENTRY exception handler} in a compiled 071 * method. 072 */ 073 public static final ForeignCallDescriptor EXCEPTION_HANDLER = new ForeignCallDescriptor("exceptionHandler", void.class, Object.class, Word.class); 074 075 /** 076 * Descriptor for SharedRuntime::get_ic_miss_stub(). 077 */ 078 public static final ForeignCallDescriptor IC_MISS_HANDLER = new ForeignCallDescriptor("icMissHandler", void.class); 079 080 /** 081 * Descriptor for {@link UnwindExceptionToCallerStub}. This stub is called by code generated 082 * from {@link UnwindNode}. 083 */ 084 public static final ForeignCallDescriptor UNWIND_EXCEPTION_TO_CALLER = new ForeignCallDescriptor("unwindExceptionToCaller", void.class, Object.class, Word.class); 085 086 /** 087 * Descriptor for the arguments when unwinding to an exception handler in a caller. 088 */ 089 public static final ForeignCallDescriptor EXCEPTION_HANDLER_IN_CALLER = new ForeignCallDescriptor("exceptionHandlerInCaller", void.class, Object.class, Word.class); 090 091 private final HotSpotGraalRuntimeProvider runtime; 092 093 /** 094 * @see DeoptimizationFetchUnrollInfoCallNode 095 */ 096 public static final ForeignCallDescriptor FETCH_UNROLL_INFO = new ForeignCallDescriptor("fetchUnrollInfo", Word.class, long.class); 097 098 /** 099 * @see DeoptimizationStub#unpackFrames(ForeignCallDescriptor, Word, int) 100 */ 101 public static final ForeignCallDescriptor UNPACK_FRAMES = newDescriptor(DeoptimizationStub.class, "unpackFrames", int.class, Word.class, int.class); 102 103 /** 104 * @see AESCryptSubstitutions#encryptBlockStub(ForeignCallDescriptor, Word, Word, Word) 105 */ 106 public static final ForeignCallDescriptor ENCRYPT_BLOCK = new ForeignCallDescriptor("encrypt_block", void.class, Word.class, Word.class, Word.class); 107 108 /** 109 * @see AESCryptSubstitutions#decryptBlockStub(ForeignCallDescriptor, Word, Word, Word) 110 */ 111 public static final ForeignCallDescriptor DECRYPT_BLOCK = new ForeignCallDescriptor("decrypt_block", void.class, Word.class, Word.class, Word.class); 112 113 /** 114 * @see CipherBlockChainingSubstitutions#crypt 115 */ 116 public static final ForeignCallDescriptor ENCRYPT = new ForeignCallDescriptor("encrypt", void.class, Word.class, Word.class, Word.class, Word.class, int.class); 117 118 /** 119 * @see CipherBlockChainingSubstitutions#crypt 120 */ 121 public static final ForeignCallDescriptor DECRYPT = new ForeignCallDescriptor("decrypt", void.class, Word.class, Word.class, Word.class, Word.class, int.class); 122 123 /** 124 * @see VMErrorNode 125 */ 126 public static final ForeignCallDescriptor VM_ERROR = new ForeignCallDescriptor("vm_error", void.class, Object.class, Object.class, long.class); 127 128 /** 129 * New multi array stub call. 130 */ 131 public static final ForeignCallDescriptor NEW_MULTI_ARRAY = new ForeignCallDescriptor("new_multi_array", Object.class, Word.class, int.class, Word.class); 132 133 /** 134 * New array stub. 135 */ 136 public static final ForeignCallDescriptor NEW_ARRAY = new ForeignCallDescriptor("new_array", Object.class, Word.class, int.class); 137 138 /** 139 * New insstance stub. 140 */ 141 public static final ForeignCallDescriptor NEW_INSTANCE = new ForeignCallDescriptor("new_instance", Object.class, Word.class); 142 143 /** 144 * @see UncommonTrapCallNode 145 */ 146 public static final ForeignCallDescriptor UNCOMMON_TRAP = new ForeignCallDescriptor("uncommonTrap", Word.class, Word.class, int.class); 147 148 public HotSpotBackend(HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) { 149 super(providers); 150 this.runtime = runtime; 151 } 152 153 public HotSpotGraalRuntimeProvider getRuntime() { 154 return runtime; 155 } 156 157 /** 158 * Performs any remaining initialization that was deferred until the {@linkplain #getRuntime() 159 * runtime} object was initialized and this backend was registered with it. 160 */ 161 public void completeInitialization() { 162 } 163 164 /** 165 * Finds all the registers that are defined by some given LIR. 166 * 167 * @param lir the LIR to examine 168 * @return the registers that are defined by or used as temps for any instruction in {@code lir} 169 */ 170 protected static Set<Register> gatherDefinedRegisters(LIR lir) { 171 final Set<Register> definedRegisters = new HashSet<>(); 172 ValueConsumer defConsumer = new ValueConsumer() { 173 174 @Override 175 public void visitValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) { 176 if (ValueUtil.isRegister(value)) { 177 final Register reg = ValueUtil.asRegister(value); 178 definedRegisters.add(reg); 179 } 180 } 181 }; 182 for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) { 183 for (LIRInstruction op : lir.getLIRforBlock(block)) { 184 if (op instanceof LabelOp) { 185 // Don't consider this as a definition 186 } else { 187 op.visitEachTemp(defConsumer); 188 op.visitEachOutput(defConsumer); 189 } 190 } 191 } 192 return definedRegisters; 193 } 194 195 /** 196 * Updates a given stub with respect to the registers it destroys. 197 * <p> 198 * Any entry in {@code calleeSaveInfo} that {@linkplain SaveRegistersOp#supportsRemove() 199 * supports} pruning will have {@code destroyedRegisters} 200 * {@linkplain SaveRegistersOp#remove(Set) removed} as these registers are declared as 201 * temporaries in the stub's {@linkplain ForeignCallLinkage linkage} (and thus will be saved by 202 * the stub's caller). 203 * 204 * @param stub the stub to update 205 * @param destroyedRegisters the registers destroyed by the stub 206 * @param calleeSaveInfo a map from debug infos to the operations that provide their 207 * {@linkplain RegisterSaveLayout callee-save information} 208 * @param frameMap used to {@linkplain FrameMap#offsetForStackSlot(StackSlot) convert} a virtual 209 * slot to a frame slot index 210 */ 211 protected void updateStub(Stub stub, Set<Register> destroyedRegisters, Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo, FrameMap frameMap) { 212 stub.initDestroyedRegisters(destroyedRegisters); 213 214 for (Map.Entry<LIRFrameState, SaveRegistersOp> e : calleeSaveInfo.entrySet()) { 215 SaveRegistersOp save = e.getValue(); 216 if (save.supportsRemove()) { 217 save.remove(destroyedRegisters); 218 } 219 DebugInfo info = e.getKey() == null ? null : e.getKey().debugInfo(); 220 if (info != null) { 221 info.setCalleeSaveInfo(save.getMap(frameMap)); 222 } 223 } 224 } 225 226 @Override 227 public StackIntrospection getStackIntrospection() { 228 return runtime; 229 } 230 231 @Override 232 public HotSpotProviders getProviders() { 233 return (HotSpotProviders) super.getProviders(); 234 } 235 236 @Override 237 public SuitesProvider getSuites() { 238 return getProviders().getSuites(); 239 } 240 241 protected void profileInstructions(LIR lir, CompilationResultBuilder crb) { 242 if (HotSpotBackend.Options.ASMInstructionProfiling.getValue() != null) { 243 HotSpotInstructionProfiling.countInstructions(lir, crb.asm); 244 } 245 } 246 247 @Override 248 public ReferenceMapBuilder newReferenceMapBuilder(int totalFrameSize) { 249 return new HotSpotReferenceMapBuilder(getTarget(), totalFrameSize); 250 } 251}