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}