AMD64HotSpotLIRGenerator.java revision 12968:4d8a004e5c6d
1/*
2 * Copyright (c) 2012, 2017, 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.amd64;
24
25import static jdk.vm.ci.amd64.AMD64.rbp;
26import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
27import static org.graalvm.compiler.hotspot.HotSpotBackend.INITIALIZE_KLASS_BY_SYMBOL;
28import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL;
29import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS;
30import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL;
31
32import java.util.ArrayList;
33import java.util.List;
34
35import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
36import org.graalvm.compiler.core.amd64.AMD64ArithmeticLIRGenerator;
37import org.graalvm.compiler.core.amd64.AMD64LIRGenerator;
38import org.graalvm.compiler.core.amd64.AMD64MoveFactoryBase.BackupSlotProvider;
39import org.graalvm.compiler.core.common.CompressEncoding;
40import org.graalvm.compiler.core.common.LIRKind;
41import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
42import org.graalvm.compiler.core.common.spi.LIRKindTool;
43import org.graalvm.compiler.debug.Debug;
44import org.graalvm.compiler.debug.GraalError;
45import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
46import org.graalvm.compiler.hotspot.HotSpotBackend;
47import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder;
48import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
49import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult;
50import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
51import org.graalvm.compiler.hotspot.HotSpotLockStack;
52import org.graalvm.compiler.hotspot.debug.BenchmarkCounters;
53import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
54import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
55import org.graalvm.compiler.hotspot.nodes.type.HotSpotLIRKindTool;
56import org.graalvm.compiler.hotspot.stubs.Stub;
57import org.graalvm.compiler.lir.LIR;
58import org.graalvm.compiler.lir.LIRFrameState;
59import org.graalvm.compiler.lir.LIRInstruction;
60import org.graalvm.compiler.lir.LIRInstructionClass;
61import org.graalvm.compiler.lir.LabelRef;
62import org.graalvm.compiler.lir.StandardOp.NoOp;
63import org.graalvm.compiler.lir.SwitchStrategy;
64import org.graalvm.compiler.lir.Variable;
65import org.graalvm.compiler.lir.VirtualStackSlot;
66import org.graalvm.compiler.lir.amd64.AMD64AddressValue;
67import org.graalvm.compiler.lir.amd64.AMD64CCall;
68import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.StrategySwitchOp;
69import org.graalvm.compiler.lir.amd64.AMD64FrameMapBuilder;
70import org.graalvm.compiler.lir.amd64.AMD64Move;
71import org.graalvm.compiler.lir.amd64.AMD64Move.MoveFromRegOp;
72import org.graalvm.compiler.lir.amd64.AMD64PrefetchOp;
73import org.graalvm.compiler.lir.amd64.AMD64ReadTimestampCounter;
74import org.graalvm.compiler.lir.amd64.AMD64RestoreRegistersOp;
75import org.graalvm.compiler.lir.amd64.AMD64SaveRegistersOp;
76import org.graalvm.compiler.lir.amd64.AMD64VZeroUpper;
77import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
78import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
79import org.graalvm.compiler.lir.gen.LIRGenerationResult;
80import org.graalvm.compiler.options.OptionValues;
81
82import jdk.vm.ci.amd64.AMD64;
83import jdk.vm.ci.amd64.AMD64Kind;
84import jdk.vm.ci.code.CallingConvention;
85import jdk.vm.ci.code.Register;
86import jdk.vm.ci.code.RegisterConfig;
87import jdk.vm.ci.code.RegisterValue;
88import jdk.vm.ci.code.StackSlot;
89import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
90import jdk.vm.ci.hotspot.HotSpotObjectConstant;
91import jdk.vm.ci.meta.AllocatableValue;
92import jdk.vm.ci.meta.Constant;
93import jdk.vm.ci.meta.DeoptimizationAction;
94import jdk.vm.ci.meta.DeoptimizationReason;
95import jdk.vm.ci.meta.JavaConstant;
96import jdk.vm.ci.meta.JavaKind;
97import jdk.vm.ci.meta.PlatformKind;
98import jdk.vm.ci.meta.PrimitiveConstant;
99import jdk.vm.ci.meta.Value;
100
101/**
102 * LIR generator specialized for AMD64 HotSpot.
103 */
104public class AMD64HotSpotLIRGenerator extends AMD64LIRGenerator implements HotSpotLIRGenerator {
105
106    final GraalHotSpotVMConfig config;
107    private HotSpotDebugInfoBuilder debugInfoBuilder;
108
109    protected AMD64HotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes) {
110        this(providers, config, lirGenRes, new BackupSlotProvider(lirGenRes.getFrameMapBuilder()));
111    }
112
113    private AMD64HotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes, BackupSlotProvider backupSlotProvider) {
114        this(new AMD64HotSpotLIRKindTool(), new AMD64HotSpotArithmeticLIRGenerator(), new AMD64HotSpotMoveFactory(backupSlotProvider), providers, config, lirGenRes);
115    }
116
117    protected AMD64HotSpotLIRGenerator(LIRKindTool lirKindTool, AMD64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config,
118                    LIRGenerationResult lirGenRes) {
119        super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes);
120        assert config.basicLockSize == 8;
121        this.config = config;
122    }
123
124    @Override
125    public HotSpotProviders getProviders() {
126        return (HotSpotProviders) super.getProviders();
127    }
128
129    /**
130     * Utility for emitting the instruction to save RBP.
131     */
132    class SaveRbp {
133
134        final NoOp placeholder;
135
136        /**
137         * The slot reserved for saving RBP.
138         */
139        final StackSlot reservedSlot;
140
141        SaveRbp(NoOp placeholder) {
142            this.placeholder = placeholder;
143            AMD64FrameMapBuilder frameMapBuilder = (AMD64FrameMapBuilder) getResult().getFrameMapBuilder();
144            this.reservedSlot = frameMapBuilder.allocateRBPSpillSlot();
145        }
146
147        /**
148         * Replaces this operation with the appropriate move for saving rbp.
149         *
150         * @param useStack specifies if rbp must be saved to the stack
151         */
152        public AllocatableValue finalize(boolean useStack) {
153            AllocatableValue dst;
154            if (useStack) {
155                dst = reservedSlot;
156            } else {
157                ((AMD64FrameMapBuilder) getResult().getFrameMapBuilder()).freeRBPSpillSlot();
158                dst = newVariable(LIRKind.value(AMD64Kind.QWORD));
159            }
160
161            placeholder.replace(getResult().getLIR(), new MoveFromRegOp(AMD64Kind.QWORD, dst, rbp.asValue(LIRKind.value(AMD64Kind.QWORD))));
162            return dst;
163        }
164    }
165
166    private SaveRbp saveRbp;
167
168    protected void emitSaveRbp() {
169        NoOp placeholder = new NoOp(getCurrentBlock(), getResult().getLIR().getLIRforBlock(getCurrentBlock()).size());
170        append(placeholder);
171        saveRbp = new SaveRbp(placeholder);
172    }
173
174    protected SaveRbp getSaveRbp() {
175        return saveRbp;
176    }
177
178    /**
179     * Helper instruction to reserve a stack slot for the whole method. Note that the actual users
180     * of the stack slot might be inserted after stack slot allocation. This dummy instruction
181     * ensures that the stack slot is alive and gets a real stack slot assigned.
182     */
183    private static final class RescueSlotDummyOp extends LIRInstruction {
184        public static final LIRInstructionClass<RescueSlotDummyOp> TYPE = LIRInstructionClass.create(RescueSlotDummyOp.class);
185
186        @Alive({OperandFlag.STACK, OperandFlag.UNINITIALIZED}) private AllocatableValue slot;
187
188        RescueSlotDummyOp(FrameMapBuilder frameMapBuilder, LIRKind kind) {
189            super(TYPE);
190            slot = frameMapBuilder.allocateSpillSlot(kind);
191        }
192
193        public AllocatableValue getSlot() {
194            return slot;
195        }
196
197        @Override
198        public void emitCode(CompilationResultBuilder crb) {
199        }
200    }
201
202    private RescueSlotDummyOp rescueSlotOp;
203
204    private AllocatableValue getOrInitRescueSlot() {
205        RescueSlotDummyOp op = getOrInitRescueSlotOp();
206        return op.getSlot();
207    }
208
209    private RescueSlotDummyOp getOrInitRescueSlotOp() {
210        if (rescueSlotOp == null) {
211            // create dummy instruction to keep the rescue slot alive
212            rescueSlotOp = new RescueSlotDummyOp(getResult().getFrameMapBuilder(), getLIRKindTool().getWordKind());
213        }
214        return rescueSlotOp;
215    }
216
217    /**
218     * List of epilogue operations that need to restore RBP.
219     */
220    List<AMD64HotSpotRestoreRbpOp> epilogueOps = new ArrayList<>(2);
221
222    @Override
223    public <I extends LIRInstruction> I append(I op) {
224        I ret = super.append(op);
225        if (op instanceof AMD64HotSpotRestoreRbpOp) {
226            epilogueOps.add((AMD64HotSpotRestoreRbpOp) op);
227        }
228        return ret;
229    }
230
231    @Override
232    public VirtualStackSlot getLockSlot(int lockDepth) {
233        return getLockStack().makeLockSlot(lockDepth);
234    }
235
236    private HotSpotLockStack getLockStack() {
237        assert debugInfoBuilder != null && debugInfoBuilder.lockStack() != null;
238        return debugInfoBuilder.lockStack();
239    }
240
241    private Register findPollOnReturnScratchRegister() {
242        RegisterConfig regConfig = getProviders().getCodeCache().getRegisterConfig();
243        for (Register r : regConfig.getAllocatableRegisters()) {
244            if (!r.equals(regConfig.getReturnRegister(JavaKind.Long)) && !r.equals(AMD64.rbp)) {
245                return r;
246            }
247        }
248        throw GraalError.shouldNotReachHere();
249    }
250
251    private Register pollOnReturnScratchRegister;
252
253    @Override
254    public void emitReturn(JavaKind kind, Value input) {
255        AllocatableValue operand = Value.ILLEGAL;
256        if (input != null) {
257            operand = resultOperandFor(kind, input.getValueKind());
258            emitMove(operand, input);
259        }
260        if (pollOnReturnScratchRegister == null) {
261            pollOnReturnScratchRegister = findPollOnReturnScratchRegister();
262        }
263        append(new AMD64HotSpotReturnOp(operand, getStub() != null, pollOnReturnScratchRegister, config));
264    }
265
266    @Override
267    public boolean needOnlyOopMaps() {
268        // Stubs only need oop maps
269        return getResult().getStub() != null;
270    }
271
272    private LIRFrameState currentRuntimeCallInfo;
273
274    @Override
275    protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
276        currentRuntimeCallInfo = info;
277        HotSpotForeignCallLinkage hsLinkage = (HotSpotForeignCallLinkage) linkage;
278        AMD64 arch = (AMD64) target().arch;
279        if (arch.getFeatures().contains(AMD64.CPUFeature.AVX) && hsLinkage.mayContainFP() && !hsLinkage.isCompiledStub()) {
280            /*
281             * If the target may contain FP ops, and it is not compiled by us, we may have an
282             * AVX-SSE transition.
283             *
284             * We exclude the argument registers from the zeroing LIR instruction since it violates
285             * the LIR semantics of @Temp that values must not be live. Note that the emitted
286             * machine instruction actually zeros _all_ XMM registers which is fine since we know
287             * that their upper half is not used.
288             */
289            append(new AMD64VZeroUpper(arguments));
290        }
291        super.emitForeignCallOp(linkage, result, arguments, temps, info);
292    }
293
294    /**
295     * @param savedRegisters the registers saved by this operation which may be subject to pruning
296     * @param savedRegisterLocations the slots to which the registers are saved
297     * @param supportsRemove determines if registers can be pruned
298     */
299    protected AMD64SaveRegistersOp emitSaveRegisters(Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) {
300        AMD64SaveRegistersOp save = new AMD64SaveRegistersOp(savedRegisters, savedRegisterLocations, supportsRemove);
301        append(save);
302        return save;
303    }
304
305    /**
306     * Allocate a stack slot for saving a register.
307     */
308    protected VirtualStackSlot allocateSaveRegisterLocation(Register register) {
309        PlatformKind kind = target().arch.getLargestStorableKind(register.getRegisterCategory());
310        if (kind.getVectorLength() > 1) {
311            // we don't use vector registers, so there is no need to save them
312            kind = AMD64Kind.DOUBLE;
313        }
314        return getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(kind));
315    }
316
317    /**
318     * Adds a node to the graph that saves all allocatable registers to the stack.
319     *
320     * @param supportsRemove determines if registers can be pruned
321     * @return the register save node
322     */
323    private AMD64SaveRegistersOp emitSaveAllRegisters(Register[] savedRegisters, boolean supportsRemove) {
324        AllocatableValue[] savedRegisterLocations = new AllocatableValue[savedRegisters.length];
325        for (int i = 0; i < savedRegisters.length; i++) {
326            savedRegisterLocations[i] = allocateSaveRegisterLocation(savedRegisters[i]);
327        }
328        return emitSaveRegisters(savedRegisters, savedRegisterLocations, supportsRemove);
329    }
330
331    protected void emitRestoreRegisters(AMD64SaveRegistersOp save) {
332        append(new AMD64RestoreRegistersOp(save.getSlots().clone(), save));
333    }
334
335    /**
336     * Gets the {@link Stub} this generator is generating code for or {@code null} if a stub is not
337     * being generated.
338     */
339    public Stub getStub() {
340        return getResult().getStub();
341    }
342
343    @Override
344    public HotSpotLIRGenerationResult getResult() {
345        return ((HotSpotLIRGenerationResult) super.getResult());
346    }
347
348    public void setDebugInfoBuilder(HotSpotDebugInfoBuilder debugInfoBuilder) {
349        this.debugInfoBuilder = debugInfoBuilder;
350    }
351
352    @Override
353    public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) {
354        HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage;
355        boolean destroysRegisters = hotspotLinkage.destroysRegisters();
356
357        AMD64SaveRegistersOp save = null;
358        Stub stub = getStub();
359        if (destroysRegisters) {
360            if (stub != null && stub.preservesRegisters()) {
361                Register[] savedRegisters = getResult().getFrameMapBuilder().getRegisterConfig().getAllocatableRegisters().toArray();
362                save = emitSaveAllRegisters(savedRegisters, true);
363            }
364        }
365
366        Variable result;
367        LIRFrameState debugInfo = null;
368        if (hotspotLinkage.needsDebugInfo()) {
369            debugInfo = state;
370            assert debugInfo != null || stub != null;
371        }
372
373        if (hotspotLinkage.needsJavaFrameAnchor()) {
374            Register thread = getProviders().getRegisters().getThreadRegister();
375            append(new AMD64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread));
376            result = super.emitForeignCall(hotspotLinkage, debugInfo, args);
377            append(new AMD64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), config.threadLastJavaPcOffset(), thread));
378        } else {
379            result = super.emitForeignCall(hotspotLinkage, debugInfo, args);
380        }
381
382        if (destroysRegisters) {
383            if (stub != null) {
384                if (stub.preservesRegisters()) {
385                    HotSpotLIRGenerationResult generationResult = getResult();
386                    LIRFrameState key = currentRuntimeCallInfo;
387                    if (key == null) {
388                        key = LIRFrameState.NO_STATE;
389                    }
390                    assert !generationResult.getCalleeSaveInfo().containsKey(key);
391                    generationResult.getCalleeSaveInfo().put(key, save);
392                    emitRestoreRegisters(save);
393                }
394            }
395        }
396
397        return result;
398    }
399
400    @Override
401    public Value emitLoadObjectAddress(Constant constant) {
402        HotSpotObjectConstant objectConstant = (HotSpotObjectConstant) constant;
403        HotSpotLIRKindTool kindTool = (HotSpotLIRKindTool) getLIRKindTool();
404        LIRKind kind = objectConstant.isCompressed() ? kindTool.getNarrowOopKind() : kindTool.getObjectKind();
405        Variable result = newVariable(kind);
406        append(new AMD64HotSpotLoadAddressOp(result, constant, HotSpotConstantLoadAction.RESOLVE));
407        return result;
408    }
409
410    @Override
411    public Value emitLoadMetaspaceAddress(Constant constant, HotSpotConstantLoadAction action) {
412        HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) constant;
413        HotSpotLIRKindTool kindTool = (HotSpotLIRKindTool) getLIRKindTool();
414        LIRKind kind = metaspaceConstant.isCompressed() ? kindTool.getNarrowPointerKind() : kindTool.getWordKind();
415        Variable result = newVariable(kind);
416        append(new AMD64HotSpotLoadAddressOp(result, constant, action));
417        return result;
418    }
419
420    @Override
421    public Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
422        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(RESOLVE_STRING_BY_SYMBOL);
423        Constant[] constants = new Constant[]{constant};
424        AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)};
425        Object[] notes = new Object[]{HotSpotConstantLoadAction.RESOLVE};
426        append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes));
427        AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn();
428        return emitMove(result);
429    }
430
431    @Override
432    public Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
433        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(RESOLVE_KLASS_BY_SYMBOL);
434        Constant[] constants = new Constant[]{constant};
435        AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)};
436        Object[] notes = new Object[]{HotSpotConstantLoadAction.RESOLVE};
437        append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes));
438        AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn();
439        return emitMove(result);
440    }
441
442    @Override
443    public Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) {
444        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS);
445        Constant[] constants = new Constant[]{method};
446        AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(klassHint), asAllocatable(methodDescription)};
447        Object[] notes = new Object[]{HotSpotConstantLoadAction.LOAD_COUNTERS};
448        append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes));
449        AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn();
450        return emitMove(result);
451
452    }
453
454    @Override
455    public Value emitKlassInitializationAndRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
456        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(INITIALIZE_KLASS_BY_SYMBOL);
457        Constant[] constants = new Constant[]{constant};
458        AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)};
459        Object[] notes = new Object[]{HotSpotConstantLoadAction.INITIALIZE};
460        append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes));
461        AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn();
462        return emitMove(result);
463    }
464
465    @Override
466    public Value emitLoadConfigValue(int markId, LIRKind kind) {
467        Variable result = newVariable(kind);
468        append(new AMD64HotSpotLoadConfigValueOp(markId, result));
469        return result;
470    }
471
472    @Override
473    public Value emitRandomSeed() {
474        AMD64ReadTimestampCounter timestamp = new AMD64ReadTimestampCounter();
475        append(timestamp);
476        return emitMove(timestamp.getLowResult());
477    }
478
479    @Override
480    public void emitTailcall(Value[] args, Value address) {
481        append(new AMD64TailcallOp(args, address));
482    }
483
484    @Override
485    public void emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args, int numberOfFloatingPointArguments) {
486        Value[] argLocations = new Value[args.length];
487        getResult().getFrameMapBuilder().callsMethod(nativeCallingConvention);
488        // TODO(mg): in case a native function uses floating point varargs, the ABI requires that
489        // RAX contains the length of the varargs
490        PrimitiveConstant intConst = JavaConstant.forInt(numberOfFloatingPointArguments);
491        AllocatableValue numberOfFloatingPointArgumentsRegister = AMD64.rax.asValue(LIRKind.value(AMD64Kind.DWORD));
492        emitMoveConstant(numberOfFloatingPointArgumentsRegister, intConst);
493        for (int i = 0; i < args.length; i++) {
494            Value arg = args[i];
495            AllocatableValue loc = nativeCallingConvention.getArgument(i);
496            emitMove(loc, arg);
497            argLocations[i] = loc;
498        }
499        Value ptr = emitLoadConstant(LIRKind.value(AMD64Kind.QWORD), JavaConstant.forLong(address));
500        append(new AMD64CCall(nativeCallingConvention.getReturn(), ptr, numberOfFloatingPointArgumentsRegister, argLocations));
501    }
502
503    @Override
504    public void emitUnwind(Value exception) {
505        ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER);
506        CallingConvention outgoingCc = linkage.getOutgoingCallingConvention();
507        assert outgoingCc.getArgumentCount() == 2;
508        RegisterValue exceptionParameter = (RegisterValue) outgoingCc.getArgument(0);
509        emitMove(exceptionParameter, exception);
510        append(new AMD64HotSpotUnwindOp(exceptionParameter));
511    }
512
513    private void moveDeoptValuesToThread(Value actionAndReason, Value speculation) {
514        moveValueToThread(actionAndReason, config.pendingDeoptimizationOffset);
515        moveValueToThread(speculation, config.pendingFailedSpeculationOffset);
516    }
517
518    private void moveValueToThread(Value v, int offset) {
519        LIRKind wordKind = LIRKind.value(target().arch.getWordKind());
520        RegisterValue thread = getProviders().getRegisters().getThreadRegister().asValue(wordKind);
521        AMD64AddressValue address = new AMD64AddressValue(wordKind, thread, offset);
522        arithmeticLIRGen.emitStore(v.getValueKind(), address, v, null);
523    }
524
525    @Override
526    public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) {
527        moveDeoptValuesToThread(actionAndReason, speculation);
528        append(new AMD64DeoptimizeOp(state));
529    }
530
531    @Override
532    public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) {
533        Value actionAndReason = emitJavaConstant(getMetaAccess().encodeDeoptActionAndReason(action, reason, 0));
534        Value nullValue = emitConstant(LIRKind.reference(AMD64Kind.QWORD), JavaConstant.NULL_POINTER);
535        moveDeoptValuesToThread(actionAndReason, nullValue);
536        append(new AMD64HotSpotDeoptimizeCallerOp());
537    }
538
539    @Override
540    public void beforeRegisterAllocation() {
541        super.beforeRegisterAllocation();
542        boolean hasDebugInfo = getResult().getLIR().hasDebugInfo();
543        AllocatableValue savedRbp = saveRbp.finalize(hasDebugInfo);
544        if (hasDebugInfo) {
545            getResult().setDeoptimizationRescueSlot(((AMD64FrameMapBuilder) getResult().getFrameMapBuilder()).allocateDeoptimizationRescueSlot());
546        }
547
548        getResult().setMaxInterpreterFrameSize(debugInfoBuilder.maxInterpreterFrameSize());
549
550        for (AMD64HotSpotRestoreRbpOp op : epilogueOps) {
551            op.setSavedRbp(savedRbp);
552        }
553        if (BenchmarkCounters.enabled) {
554            // ensure that the rescue slot is available
555            LIRInstruction op = getOrInitRescueSlotOp();
556            // insert dummy instruction into the start block
557            LIR lir = getResult().getLIR();
558            ArrayList<LIRInstruction> instructions = lir.getLIRforBlock(lir.getControlFlowGraph().getStartBlock());
559            instructions.add(1, op);
560            Debug.dump(Debug.INFO_LOG_LEVEL, lir, "created rescue dummy op");
561        }
562    }
563
564    @Override
565    public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
566        LIRKind inputKind = pointer.getValueKind(LIRKind.class);
567        assert inputKind.getPlatformKind() == AMD64Kind.QWORD;
568        if (inputKind.isReference(0)) {
569            // oop
570            Variable result = newVariable(LIRKind.reference(AMD64Kind.DWORD));
571            append(new AMD64HotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
572            return result;
573        } else {
574            // metaspace pointer
575            Variable result = newVariable(LIRKind.value(AMD64Kind.DWORD));
576            AllocatableValue base = Value.ILLEGAL;
577            OptionValues options = getResult().getLIR().getOptions();
578            if (encoding.hasBase() || GeneratePIC.getValue(options)) {
579                if (GeneratePIC.getValue(options)) {
580                    Variable baseAddress = newVariable(LIRKind.value(AMD64Kind.QWORD));
581                    AMD64HotSpotMove.BaseMove move = new AMD64HotSpotMove.BaseMove(baseAddress, config);
582                    append(move);
583                    base = baseAddress;
584                } else {
585                    base = emitLoadConstant(LIRKind.value(AMD64Kind.QWORD), JavaConstant.forLong(encoding.getBase()));
586                }
587            }
588            append(new AMD64HotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
589            return result;
590        }
591    }
592
593    @Override
594    public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
595        LIRKind inputKind = pointer.getValueKind(LIRKind.class);
596        assert inputKind.getPlatformKind() == AMD64Kind.DWORD;
597        if (inputKind.isReference(0)) {
598            // oop
599            Variable result = newVariable(LIRKind.reference(AMD64Kind.QWORD));
600            append(new AMD64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
601            return result;
602        } else {
603            // metaspace pointer
604            Variable result = newVariable(LIRKind.value(AMD64Kind.QWORD));
605            AllocatableValue base = Value.ILLEGAL;
606            OptionValues options = getResult().getLIR().getOptions();
607            if (encoding.hasBase() || GeneratePIC.getValue(options)) {
608                if (GeneratePIC.getValue(options)) {
609                    Variable baseAddress = newVariable(LIRKind.value(AMD64Kind.QWORD));
610                    AMD64HotSpotMove.BaseMove move = new AMD64HotSpotMove.BaseMove(baseAddress, config);
611                    append(move);
612                    base = baseAddress;
613                } else {
614                    base = emitLoadConstant(LIRKind.value(AMD64Kind.QWORD), JavaConstant.forLong(encoding.getBase()));
615                }
616            }
617            append(new AMD64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
618            return result;
619        }
620    }
621
622    @Override
623    public void emitNullCheck(Value address, LIRFrameState state) {
624        if (address.getValueKind().getPlatformKind() == AMD64Kind.DWORD) {
625            CompressEncoding encoding = config.getOopEncoding();
626            Value uncompressed;
627            if (encoding.getShift() <= 3) {
628                LIRKind wordKind = LIRKind.unknownReference(target().arch.getWordKind());
629                uncompressed = new AMD64AddressValue(wordKind, getProviders().getRegisters().getHeapBaseRegister().asValue(wordKind), asAllocatable(address), Scale.fromInt(1 << encoding.getShift()),
630                                0);
631            } else {
632                uncompressed = emitUncompress(address, encoding, false);
633            }
634            append(new AMD64Move.NullCheckOp(asAddressValue(uncompressed), state));
635        } else {
636            super.emitNullCheck(address, state);
637        }
638    }
639
640    @Override
641    public LIRInstruction createBenchmarkCounter(String name, String group, Value increment) {
642        if (BenchmarkCounters.enabled) {
643            return new AMD64HotSpotCounterOp(name, group, increment, getProviders().getRegisters(), config, getOrInitRescueSlot());
644        }
645        throw GraalError.shouldNotReachHere("BenchmarkCounters are not enabled!");
646    }
647
648    @Override
649    public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) {
650        if (BenchmarkCounters.enabled) {
651            return new AMD64HotSpotCounterOp(names, groups, increments, getProviders().getRegisters(), config, getOrInitRescueSlot());
652        }
653        throw GraalError.shouldNotReachHere("BenchmarkCounters are not enabled!");
654    }
655
656    @Override
657    public void emitPrefetchAllocate(Value address) {
658        append(new AMD64PrefetchOp(asAddressValue(address), config.allocatePrefetchInstr));
659    }
660
661    @Override
662    protected StrategySwitchOp createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue temp) {
663        return new AMD64HotSpotStrategySwitchOp(strategy, keyTargets, defaultTarget, key, temp);
664    }
665}
666