1 /* 2 * Copyright (c) 2015, 2016, 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 24 package compiler.jvmci.code.amd64; 25 26 import jdk.vm.ci.amd64.AMD64; 27 import jdk.vm.ci.amd64.AMD64Kind; 28 import jdk.vm.ci.code.CodeCacheProvider; 29 import jdk.vm.ci.code.DebugInfo; 30 import jdk.vm.ci.code.Register; 31 import jdk.vm.ci.code.StackSlot; 32 import jdk.vm.ci.code.site.ConstantReference; 33 import jdk.vm.ci.code.site.DataSectionReference; 34 import jdk.vm.ci.hotspot.HotSpotCallingConventionType; 35 import jdk.vm.ci.hotspot.HotSpotConstant; 36 import jdk.vm.ci.meta.JavaKind; 37 import jdk.vm.ci.meta.LIRKind; 38 import jdk.vm.ci.meta.VMConstant; 39 40 import compiler.jvmci.code.TestAssembler; 41 42 public class AMD64TestAssembler extends TestAssembler { 43 44 public AMD64TestAssembler(CodeCacheProvider codeCache) { 45 super(codeCache, 16, 16, AMD64Kind.DWORD, AMD64.rax, AMD64.rcx, AMD64.rdi, AMD64.r8, AMD64.r9, AMD64.r10); 46 } 47 48 private void emitFatNop() { 49 // 5 byte NOP: 50 // NOP DWORD ptr [EAX + EAX*1 + 00H] 51 code.emitByte(0x0F); 52 code.emitByte(0x1F); 53 code.emitByte(0x44); 54 code.emitByte(0x00); 55 code.emitByte(0x00); 56 } 57 58 @Override 59 public void emitPrologue() { 60 // WARNING: Initial instruction MUST be 5 bytes or longer so that 61 // NativeJump::patch_verified_entry will be able to patch out the entry 62 // code safely. 63 emitFatNop(); 64 code.emitByte(0x50 | AMD64.rbp.encoding); // PUSH rbp 65 emitMove(true, AMD64.rbp, AMD64.rsp); // MOV rbp, rsp 66 setDeoptRescueSlot(newStackSlot(LIRKind.value(AMD64Kind.QWORD))); 67 } 68 69 @Override 70 public void emitGrowStack(int size) { 71 // SUB rsp, size 72 code.emitByte(0x48); 73 code.emitByte(0x81); 74 code.emitByte(0xEC); 75 code.emitInt(size); 76 } 77 78 @Override 79 public Register emitIntArg0() { 80 return codeCache.getRegisterConfig().getCallingConventionRegisters(HotSpotCallingConventionType.JavaCall, JavaKind.Int)[0]; 81 } 82 83 @Override 84 public Register emitIntArg1() { 85 return codeCache.getRegisterConfig().getCallingConventionRegisters(HotSpotCallingConventionType.JavaCall, JavaKind.Int)[1]; 86 } 87 88 private void emitREX(boolean w, int r, int x, int b) { 89 int wrxb = (w ? 0x08 : 0) | ((r >> 3) << 2) | ((x >> 3) << 1) | (b >> 3); 90 if (wrxb != 0) { 91 code.emitByte(0x40 | wrxb); 92 } 93 } 94 95 private void emitModRMReg(boolean w, int opcode, int r, int m) { 96 emitREX(w, r, 0, m); 97 code.emitByte((byte) opcode); 98 code.emitByte((byte) 0xC0 | ((r & 0x7) << 3) | (m & 0x7)); 99 } 100 101 private void emitModRMMemory(boolean w, int opcode, int r, int b, int offset) { 102 emitREX(w, r, 0, b); 103 code.emitByte((byte) opcode); 104 code.emitByte((byte) 0x80 | ((r & 0x7) << 3) | (b & 0x7)); 105 code.emitInt(offset); 106 } 107 108 @Override 109 public Register emitLoadInt(int c) { 110 Register ret = newRegister(); 111 emitREX(false, 0, 0, ret.encoding); 112 code.emitByte(0xB8 | (ret.encoding & 0x7)); // MOV r32, imm32 113 code.emitInt(c); 114 return ret; 115 } 116 117 @Override 118 public Register emitLoadLong(long c) { 119 Register ret = newRegister(); 120 emitREX(true, 0, 0, ret.encoding); 121 code.emitByte(0xB8 | (ret.encoding & 0x7)); // MOV r64, imm64 122 code.emitLong(c); 123 return ret; 124 } 125 126 @Override 127 public Register emitLoadFloat(float c) { 128 DataSectionReference ref = new DataSectionReference(); 129 ref.setOffset(data.position()); 130 data.emitFloat(c); 131 132 recordDataPatchInCode(ref); 133 Register ret = AMD64.xmm0; 134 emitREX(false, ret.encoding, 0, 0); 135 code.emitByte(0xF3); 136 code.emitByte(0x0F); 137 code.emitByte(0x10); // MOVSS xmm1, xmm2/m32 138 code.emitByte(0x05 | ((ret.encoding & 0x7) << 3)); // xmm, [rip+offset] 139 code.emitInt(0xDEADDEAD); 140 return ret; 141 } 142 143 @Override 144 public Register emitLoadPointer(HotSpotConstant c) { 145 recordDataPatchInCode(new ConstantReference((VMConstant) c)); 146 if (c.isCompressed()) { 147 Register ret = newRegister(); 148 emitREX(false, 0, 0, ret.encoding); 149 code.emitByte(0xB8 | (ret.encoding & 0x7)); // MOV r32, imm32 150 code.emitInt(0xDEADDEAD); 151 return ret; 152 } else { 153 return emitLoadLong(0xDEADDEADDEADDEADl); 154 } 155 } 156 157 private Register emitLoadPointer(DataSectionReference ref, boolean narrow) { 158 recordDataPatchInCode(ref); 159 Register ret = newRegister(); 160 emitREX(!narrow, ret.encoding, 0, 0); 161 code.emitByte(0x8B); // MOV r64,r/m64 162 code.emitByte(0x05 | ((ret.encoding & 0x7) << 3)); // r64, [rip+offset] 163 code.emitInt(0xDEADDEAD); 164 return ret; 165 } 166 167 @Override 168 public Register emitLoadPointer(DataSectionReference ref) { 169 return emitLoadPointer(ref, false); 170 } 171 172 @Override 173 public Register emitLoadNarrowPointer(DataSectionReference ref) { 174 return emitLoadPointer(ref, true); 175 } 176 177 @Override 178 public Register emitLoadPointer(Register b, int offset) { 179 Register ret = newRegister(); 180 emitModRMMemory(true, 0x8B, ret.encoding, b.encoding, offset); // MOV r64,r/m64 181 return ret; 182 } 183 184 @Override 185 public StackSlot emitIntToStack(Register a) { 186 StackSlot ret = newStackSlot(LIRKind.value(AMD64Kind.DWORD)); 187 emitModRMMemory(false, 0x89, a.encoding, AMD64.rbp.encoding, ret.getRawOffset() + 16); // MOV r/m32,r32 188 return ret; 189 } 190 191 @Override 192 public StackSlot emitLongToStack(Register a) { 193 StackSlot ret = newStackSlot(LIRKind.value(AMD64Kind.QWORD)); 194 emitModRMMemory(true, 0x89, a.encoding, AMD64.rbp.encoding, ret.getRawOffset() + 16); // MOV r/m64,r64 195 return ret; 196 } 197 198 @Override 199 public StackSlot emitFloatToStack(Register a) { 200 StackSlot ret = newStackSlot(LIRKind.value(AMD64Kind.SINGLE)); 201 emitREX(false, a.encoding, 0, 0); 202 code.emitByte(0xF3); 203 code.emitByte(0x0F); 204 code.emitByte(0x11); // MOVSS xmm2/m32, xmm1 205 code.emitByte(0x85 | ((a.encoding & 0x7) << 3)); // [rbp+offset] 206 code.emitInt(ret.getRawOffset() + 16); 207 return ret; 208 } 209 210 @Override 211 public StackSlot emitPointerToStack(Register a) { 212 StackSlot ret = newStackSlot(LIRKind.reference(AMD64Kind.QWORD)); 213 emitModRMMemory(true, 0x89, a.encoding, AMD64.rbp.encoding, ret.getRawOffset() + 16); // MOV r/m64,r64 214 return ret; 215 } 216 217 @Override 218 public StackSlot emitNarrowPointerToStack(Register a) { 219 StackSlot ret = newStackSlot(LIRKind.reference(AMD64Kind.DWORD)); 220 emitModRMMemory(false, 0x89, a.encoding, AMD64.rbp.encoding, ret.getRawOffset() + 16); // MOV r/m32,r32 221 return ret; 222 } 223 224 @Override 225 public Register emitUncompressPointer(Register compressed, long base, int shift) { 226 if (shift > 0) { 227 emitModRMReg(true, 0xC1, 4, compressed.encoding); 228 code.emitByte(shift); 229 } 230 if (base == 0) { 231 return compressed; 232 } else { 233 Register tmp = emitLoadLong(base); 234 emitModRMReg(true, 0x03, tmp.encoding, compressed.encoding); 235 return tmp; 236 } 237 } 238 239 @Override 240 public Register emitIntAdd(Register a, Register b) { 241 emitModRMReg(false, 0x03, a.encoding, b.encoding); 242 return a; 243 } 244 245 private void emitMove(boolean w, Register to, Register from) { 246 if (to != from) { 247 emitModRMReg(w, 0x8B, to.encoding, from.encoding); 248 } 249 } 250 251 @Override 252 public void emitIntRet(Register a) { 253 emitMove(false, AMD64.rax, a); // MOV eax, ... 254 emitMove(true, AMD64.rsp, AMD64.rbp); // MOV rsp, rbp 255 code.emitByte(0x58 | AMD64.rbp.encoding); // POP rbp 256 code.emitByte(0xC3); // RET 257 } 258 259 @Override 260 public void emitPointerRet(Register a) { 261 emitMove(true, AMD64.rax, a); // MOV rax, ... 262 emitMove(true, AMD64.rsp, AMD64.rbp); // MOV rsp, rbp 263 code.emitByte(0x58 | AMD64.rbp.encoding); // POP rbp 264 code.emitByte(0xC3); // RET 265 } 266 267 @Override 268 public void emitTrap(DebugInfo info) { 269 recordImplicitException(info); 270 // MOV rax, [0] 271 code.emitByte(0x8B); 272 code.emitByte(0x04); 273 code.emitByte(0x25); 274 code.emitInt(0); 275 } 276 }