1 /* 2 * Copyright (c) 2011, 2015, 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 */ 23 package org.graalvm.compiler.lir.amd64; 24 25 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; 26 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; 27 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; 28 import static org.graalvm.compiler.lir.LIRValueUtil.differentRegisters; 29 import static jdk.vm.ci.code.ValueUtil.asRegister; 30 import static jdk.vm.ci.code.ValueUtil.isRegister; 31 32 import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag; 33 import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; 34 import org.graalvm.compiler.core.common.LIRKind; 35 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; 36 import org.graalvm.compiler.lir.LIRFrameState; 37 import org.graalvm.compiler.lir.LIRInstructionClass; 38 import org.graalvm.compiler.lir.Opcode; 39 import org.graalvm.compiler.lir.asm.CompilationResultBuilder; 40 import org.graalvm.compiler.lir.gen.DiagnosticLIRGeneratorTool.ZapRegistersAfterInstruction; 41 42 import jdk.vm.ci.amd64.AMD64; 43 import jdk.vm.ci.amd64.AMD64Kind; 44 import jdk.vm.ci.code.Register; 45 import jdk.vm.ci.code.RegisterValue; 46 import jdk.vm.ci.meta.AllocatableValue; 47 import jdk.vm.ci.meta.InvokeTarget; 48 import jdk.vm.ci.meta.ResolvedJavaMethod; 49 import jdk.vm.ci.meta.Value; 50 51 public class AMD64Call { 52 53 public abstract static class CallOp extends AMD64LIRInstruction { 54 public static final LIRInstructionClass<CallOp> TYPE = LIRInstructionClass.create(CallOp.class); 55 56 @Def({REG, ILLEGAL}) protected Value result; 57 @Use({REG, STACK}) protected Value[] parameters; 58 @Temp({REG, STACK}) protected Value[] temps; 59 @State protected LIRFrameState state; 60 61 protected CallOp(LIRInstructionClass<? extends CallOp> c, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { 62 super(c); 63 this.result = result; 64 this.parameters = parameters; 65 this.state = state; 66 this.temps = addStackSlotsToTemporaries(parameters, temps); 67 assert temps != null; 68 } 69 70 @Override 71 public boolean destroysCallerSavedRegisters() { 72 return true; 73 } 74 } 75 76 public abstract static class MethodCallOp extends CallOp { 77 public static final LIRInstructionClass<MethodCallOp> TYPE = LIRInstructionClass.create(MethodCallOp.class); 78 79 protected final ResolvedJavaMethod callTarget; 80 81 protected MethodCallOp(LIRInstructionClass<? extends MethodCallOp> c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { 82 super(c, result, parameters, temps, state); 83 this.callTarget = callTarget; 84 } 85 86 } 87 88 @Opcode("CALL_DIRECT") 89 public static class DirectCallOp extends MethodCallOp { 90 public static final LIRInstructionClass<DirectCallOp> TYPE = LIRInstructionClass.create(DirectCallOp.class); 91 92 public DirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { 93 this(TYPE, callTarget, result, parameters, temps, state); 94 } 95 96 protected DirectCallOp(LIRInstructionClass<? extends DirectCallOp> c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { 97 super(c, callTarget, result, parameters, temps, state); 98 } 99 100 @Override 101 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 102 directCall(crb, masm, callTarget, null, true, state); 103 } 104 } 105 106 @Opcode("CALL_INDIRECT") 107 public static class IndirectCallOp extends MethodCallOp { 108 public static final LIRInstructionClass<IndirectCallOp> TYPE = LIRInstructionClass.create(IndirectCallOp.class); 109 110 @Use({REG}) protected Value targetAddress; 111 112 public IndirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress, LIRFrameState state) { 113 this(TYPE, callTarget, result, parameters, temps, targetAddress, state); 114 } 115 116 protected IndirectCallOp(LIRInstructionClass<? extends IndirectCallOp> c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress, 117 LIRFrameState state) { 118 super(c, callTarget, result, parameters, temps, state); 119 this.targetAddress = targetAddress; 120 } 121 122 @Override 123 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 124 indirectCall(crb, masm, asRegister(targetAddress), callTarget, state); 125 } 126 127 @Override 128 public void verify() { 129 super.verify(); 130 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"; 131 } 132 } 133 134 public abstract static class ForeignCallOp extends CallOp implements ZapRegistersAfterInstruction { 135 public static final LIRInstructionClass<ForeignCallOp> TYPE = LIRInstructionClass.create(ForeignCallOp.class); 136 137 protected final ForeignCallLinkage callTarget; 138 139 public ForeignCallOp(LIRInstructionClass<? extends ForeignCallOp> c, ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { 140 super(c, result, parameters, temps, state); 141 this.callTarget = callTarget; 142 } 143 144 @Override 145 public boolean destroysCallerSavedRegisters() { 146 return callTarget.destroysRegisters(); 147 } 148 } 149 150 @Opcode("NEAR_FOREIGN_CALL") 151 public static final class DirectNearForeignCallOp extends ForeignCallOp { 152 public static final LIRInstructionClass<DirectNearForeignCallOp> TYPE = LIRInstructionClass.create(DirectNearForeignCallOp.class); 153 154 public DirectNearForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { 155 super(TYPE, linkage, result, parameters, temps, state); 156 } 157 158 @Override 159 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 160 directCall(crb, masm, callTarget, null, false, state); 161 } 162 } 163 164 @Opcode("FAR_FOREIGN_CALL") 165 public static final class DirectFarForeignCallOp extends ForeignCallOp { 166 public static final LIRInstructionClass<DirectFarForeignCallOp> TYPE = LIRInstructionClass.create(DirectFarForeignCallOp.class); 167 168 @Temp({REG}) protected AllocatableValue callTemp; 169 170 public DirectFarForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { 171 super(TYPE, callTarget, result, parameters, temps, state); 172 /* 173 * The register allocator does not support virtual registers that are used at the call 174 * site, so use a fixed register. 175 */ 176 callTemp = AMD64.rax.asValue(LIRKind.value(AMD64Kind.QWORD)); 177 assert differentRegisters(parameters, callTemp); 178 } 179 180 @Override 181 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 182 directCall(crb, masm, callTarget, ((RegisterValue) callTemp).getRegister(), false, state); 183 } 184 } 185 186 public static void directCall(CompilationResultBuilder crb, AMD64MacroAssembler masm, InvokeTarget callTarget, Register scratch, boolean align, LIRFrameState info) { 187 if (align) { 188 emitAlignmentForDirectCall(crb, masm); 189 } 190 int before = masm.position(); 191 if (scratch != null) { 192 // offset might not fit a 32-bit immediate, generate an 193 // indirect call with a 64-bit immediate 194 masm.movq(scratch, 0L); 195 masm.call(scratch); 196 } else { 197 masm.call(); 198 } 199 int after = masm.position(); 200 crb.recordDirectCall(before, after, callTarget, info); 201 crb.recordExceptionHandlers(after, info); 202 masm.ensureUniquePC(); 203 } 204 205 protected static void emitAlignmentForDirectCall(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 206 // make sure that the displacement word of the call ends up word aligned 207 int offset = masm.position(); 208 offset += crb.target.arch.getMachineCodeCallDisplacementOffset(); 209 int modulus = crb.target.wordSize; 210 if (offset % modulus != 0) { 211 masm.nop(modulus - offset % modulus); 212 } 213 } 214 215 public static void directJmp(CompilationResultBuilder crb, AMD64MacroAssembler masm, InvokeTarget target) { 216 int before = masm.position(); 217 masm.jmp(0, true); 218 int after = masm.position(); 219 crb.recordDirectCall(before, after, target, null); 220 masm.ensureUniquePC(); 221 } 222 223 public static void directConditionalJmp(CompilationResultBuilder crb, AMD64MacroAssembler masm, InvokeTarget target, ConditionFlag cond) { 224 int before = masm.position(); 225 masm.jcc(cond, 0, true); 226 int after = masm.position(); 227 crb.recordDirectCall(before, after, target, null); 228 masm.ensureUniquePC(); 229 } 230 231 public static void indirectCall(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) { 232 int before = masm.position(); 233 masm.call(dst); 234 int after = masm.position(); 235 crb.recordIndirectCall(before, after, callTarget, info); 236 crb.recordExceptionHandlers(after, info); 237 masm.ensureUniquePC(); 238 } 239 }