001/*
002 * Copyright (c) 2011, 2014, 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.lir.amd64;
024
025import jdk.internal.jvmci.amd64.*;
026import jdk.internal.jvmci.code.*;
027import jdk.internal.jvmci.meta.*;
028import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
029import static jdk.internal.jvmci.code.ValueUtil.*;
030
031import com.oracle.graal.asm.amd64.*;
032import com.oracle.graal.asm.amd64.AMD64Assembler.*;
033import com.oracle.graal.compiler.common.spi.*;
034import com.oracle.graal.lir.*;
035import com.oracle.graal.lir.asm.*;
036
037public class AMD64Call {
038
039    public abstract static class CallOp extends AMD64LIRInstruction {
040        public static final LIRInstructionClass<CallOp> TYPE = LIRInstructionClass.create(CallOp.class);
041
042        @Def({REG, ILLEGAL}) protected Value result;
043        @Use({REG, STACK}) protected Value[] parameters;
044        @Temp protected Value[] temps;
045        @State protected LIRFrameState state;
046
047        protected CallOp(LIRInstructionClass<? extends CallOp> c, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
048            super(c);
049            this.result = result;
050            this.parameters = parameters;
051            this.state = state;
052            this.temps = temps;
053            assert temps != null;
054        }
055
056        @Override
057        public boolean destroysCallerSavedRegisters() {
058            return true;
059        }
060    }
061
062    public abstract static class MethodCallOp extends CallOp {
063        public static final LIRInstructionClass<MethodCallOp> TYPE = LIRInstructionClass.create(MethodCallOp.class);
064
065        protected final ResolvedJavaMethod callTarget;
066
067        protected MethodCallOp(LIRInstructionClass<? extends MethodCallOp> c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
068            super(c, result, parameters, temps, state);
069            this.callTarget = callTarget;
070        }
071
072    }
073
074    @Opcode("CALL_DIRECT")
075    public static class DirectCallOp extends MethodCallOp {
076        public static final LIRInstructionClass<DirectCallOp> TYPE = LIRInstructionClass.create(DirectCallOp.class);
077
078        public DirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
079            this(TYPE, callTarget, result, parameters, temps, state);
080        }
081
082        protected DirectCallOp(LIRInstructionClass<? extends DirectCallOp> c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
083            super(c, callTarget, result, parameters, temps, state);
084        }
085
086        @Override
087        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
088            directCall(crb, masm, callTarget, null, true, state);
089        }
090    }
091
092    @Opcode("CALL_INDIRECT")
093    public static class IndirectCallOp extends MethodCallOp {
094        public static final LIRInstructionClass<IndirectCallOp> TYPE = LIRInstructionClass.create(IndirectCallOp.class);
095
096        @Use({REG}) protected Value targetAddress;
097
098        public IndirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress, LIRFrameState state) {
099            this(TYPE, callTarget, result, parameters, temps, targetAddress, state);
100        }
101
102        protected IndirectCallOp(LIRInstructionClass<? extends IndirectCallOp> c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress,
103                        LIRFrameState state) {
104            super(c, callTarget, result, parameters, temps, state);
105            this.targetAddress = targetAddress;
106        }
107
108        @Override
109        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
110            indirectCall(crb, masm, asRegister(targetAddress), callTarget, state);
111        }
112
113        @Override
114        public void verify() {
115            super.verify();
116            assert isRegister(targetAddress) : "The current register allocator cannot handle variables to be used at call sites, it must be in a fixed register for now";
117        }
118    }
119
120    public abstract static class ForeignCallOp extends CallOp {
121        public static final LIRInstructionClass<ForeignCallOp> TYPE = LIRInstructionClass.create(ForeignCallOp.class);
122
123        protected final ForeignCallLinkage callTarget;
124
125        public ForeignCallOp(LIRInstructionClass<? extends ForeignCallOp> c, ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
126            super(c, result, parameters, temps, state);
127            this.callTarget = callTarget;
128        }
129
130        @Override
131        public boolean destroysCallerSavedRegisters() {
132            return callTarget.destroysRegisters();
133        }
134    }
135
136    @Opcode("NEAR_FOREIGN_CALL")
137    public static final class DirectNearForeignCallOp extends ForeignCallOp {
138        public static final LIRInstructionClass<DirectNearForeignCallOp> TYPE = LIRInstructionClass.create(DirectNearForeignCallOp.class);
139
140        public DirectNearForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
141            super(TYPE, linkage, result, parameters, temps, state);
142        }
143
144        @Override
145        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
146            directCall(crb, masm, callTarget, null, false, state);
147        }
148    }
149
150    @Opcode("FAR_FOREIGN_CALL")
151    public static final class DirectFarForeignCallOp extends ForeignCallOp {
152        public static final LIRInstructionClass<DirectFarForeignCallOp> TYPE = LIRInstructionClass.create(DirectFarForeignCallOp.class);
153
154        @Temp({REG}) protected AllocatableValue callTemp;
155
156        public DirectFarForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
157            super(TYPE, callTarget, result, parameters, temps, state);
158            /*
159             * The register allocator does not support virtual registers that are used at the call
160             * site, so use a fixed register.
161             */
162            callTemp = AMD64.rax.asValue(LIRKind.value(Kind.Long));
163            assert ValueUtil.differentRegisters(parameters, callTemp);
164        }
165
166        @Override
167        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
168            directCall(crb, masm, callTarget, ((RegisterValue) callTemp).getRegister(), false, state);
169        }
170    }
171
172    public static void directCall(CompilationResultBuilder crb, AMD64MacroAssembler masm, InvokeTarget callTarget, Register scratch, boolean align, LIRFrameState info) {
173        if (align) {
174            emitAlignmentForDirectCall(crb, masm);
175        }
176        int before = masm.position();
177        if (scratch != null) {
178            // offset might not fit a 32-bit immediate, generate an
179            // indirect call with a 64-bit immediate
180            masm.movq(scratch, 0L);
181            masm.call(scratch);
182        } else {
183            masm.call();
184        }
185        int after = masm.position();
186        crb.recordDirectCall(before, after, callTarget, info);
187        crb.recordExceptionHandlers(after, info);
188        masm.ensureUniquePC();
189    }
190
191    protected static void emitAlignmentForDirectCall(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
192        // make sure that the displacement word of the call ends up word aligned
193        int offset = masm.position();
194        offset += crb.target.arch.getMachineCodeCallDisplacementOffset();
195        int modulus = crb.target.wordSize;
196        if (offset % modulus != 0) {
197            masm.nop(modulus - offset % modulus);
198        }
199    }
200
201    public static void directJmp(CompilationResultBuilder crb, AMD64MacroAssembler masm, InvokeTarget target) {
202        int before = masm.position();
203        masm.jmp(0, true);
204        int after = masm.position();
205        crb.recordDirectCall(before, after, target, null);
206        masm.ensureUniquePC();
207    }
208
209    public static void directConditionalJmp(CompilationResultBuilder crb, AMD64MacroAssembler masm, InvokeTarget target, ConditionFlag cond) {
210        int before = masm.position();
211        masm.jcc(cond, 0, true);
212        int after = masm.position();
213        crb.recordDirectCall(before, after, target, null);
214        masm.ensureUniquePC();
215    }
216
217    public static void indirectCall(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) {
218        int before = masm.position();
219        masm.call(dst);
220        int after = masm.position();
221        crb.recordIndirectCall(before, after, callTarget, info);
222        crb.recordExceptionHandlers(after, info);
223        masm.ensureUniquePC();
224    }
225}