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}