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 jdk.vm.ci.code.test.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.code.test.TestAssembler; 35 import jdk.vm.ci.code.test.TestHotSpotVMConfig; 36 import jdk.vm.ci.hotspot.HotSpotCallingConventionType; 37 import jdk.vm.ci.hotspot.HotSpotConstant; 38 import jdk.vm.ci.hotspot.HotSpotForeignCallTarget; 39 import jdk.vm.ci.meta.JavaKind; 40 import jdk.vm.ci.meta.VMConstant; 41 42 public class AMD64TestAssembler extends TestAssembler { 43 44 public AMD64TestAssembler(CodeCacheProvider codeCache, TestHotSpotVMConfig config) { 45 super(codeCache, config, 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(AMD64Kind.QWORD)); 67 } 68 69 @Override 70 public void emitEpilogue() { 71 recordMark(config.MARKID_DEOPT_HANDLER_ENTRY); 72 recordCall(new HotSpotForeignCallTarget(config.handleDeoptStub), 5, true, null); 73 code.emitByte(0xE8); // CALL rel32 74 code.emitInt(0xDEADDEAD); 75 } 76 77 @Override 78 public void emitGrowStack(int size) { 79 // SUB rsp, size 80 code.emitByte(0x48); 81 code.emitByte(0x81); 82 code.emitByte(0xEC); 83 code.emitInt(size); 84 } 85 86 @Override 87 public Register emitIntArg0() { 88 return codeCache.getRegisterConfig().getCallingConventionRegisters(HotSpotCallingConventionType.JavaCall, JavaKind.Int).get(0); 89 } 90 91 @Override 92 public Register emitIntArg1() { 93 return codeCache.getRegisterConfig().getCallingConventionRegisters(HotSpotCallingConventionType.JavaCall, JavaKind.Int).get(1); 94 } 95 96 private void emitREX(boolean w, int r, int x, int b) { 97 int wrxb = (w ? 0x08 : 0) | ((r >> 3) << 2) | ((x >> 3) << 1) | (b >> 3); 98 if (wrxb != 0) { 99 code.emitByte(0x40 | wrxb); 100 } 101 } 102 103 private void emitModRMReg(boolean w, int opcode, int r, int m) { 104 emitREX(w, r, 0, m); 105 code.emitByte((byte) opcode); 106 code.emitByte((byte) 0xC0 | ((r & 0x7) << 3) | (m & 0x7)); 107 } 108 109 private void emitModRMMemory(boolean w, int opcode, int r, int b, int offset) { 110 emitREX(w, r, 0, b); 111 code.emitByte((byte) opcode); 112 code.emitByte((byte) 0x80 | ((r & 0x7) << 3) | (b & 0x7)); 113 code.emitInt(offset); 114 } 115 116 @Override 117 public Register emitLoadInt(int c) { 118 Register ret = newRegister(); 119 emitREX(false, 0, 0, ret.encoding); 120 code.emitByte(0xB8 | (ret.encoding & 0x7)); // MOV r32, imm32 121 code.emitInt(c); 122 return ret; 123 } 124 125 @Override 126 public Register emitLoadLong(long c) { 127 Register ret = newRegister(); 128 emitREX(true, 0, 0, ret.encoding); 129 code.emitByte(0xB8 | (ret.encoding & 0x7)); // MOV r64, imm64 130 code.emitLong(c); 131 return ret; 132 } 133 134 @Override 135 public Register emitLoadFloat(float c) { 136 DataSectionReference ref = new DataSectionReference(); 137 ref.setOffset(data.position()); 138 data.emitFloat(c); 139 140 recordDataPatchInCode(ref); 141 Register ret = AMD64.xmm0; 142 emitREX(false, ret.encoding, 0, 0); 143 code.emitByte(0xF3); 144 code.emitByte(0x0F); 145 code.emitByte(0x10); // MOVSS xmm1, xmm2/m32 146 code.emitByte(0x05 | ((ret.encoding & 0x7) << 3)); // xmm, [rip+offset] 147 code.emitInt(0xDEADDEAD); 148 return ret; 149 } 150 151 @Override 152 public Register emitLoadPointer(HotSpotConstant c) { 153 recordDataPatchInCode(new ConstantReference((VMConstant) c)); 154 if (c.isCompressed()) { 155 Register ret = newRegister(); 156 emitREX(false, 0, 0, ret.encoding); 157 code.emitByte(0xB8 | (ret.encoding & 0x7)); // MOV r32, imm32 158 code.emitInt(0xDEADDEAD); 159 return ret; 160 } else { 161 return emitLoadLong(0xDEADDEADDEADDEADL); 162 } 163 } 164 165 private Register emitLoadPointer(DataSectionReference ref, boolean narrow) { 166 recordDataPatchInCode(ref); 167 Register ret = newRegister(); 168 emitREX(!narrow, ret.encoding, 0, 0); 169 code.emitByte(0x8B); // MOV r64,r/m64 170 code.emitByte(0x05 | ((ret.encoding & 0x7) << 3)); // r64, [rip+offset] 171 code.emitInt(0xDEADDEAD); 172 return ret; 173 } 174 175 @Override 176 public Register emitLoadPointer(DataSectionReference ref) { 177 return emitLoadPointer(ref, false); 178 } 179 180 @Override 181 public Register emitLoadNarrowPointer(DataSectionReference ref) { 182 return emitLoadPointer(ref, true); 183 } 184 185 @Override 186 public Register emitLoadPointer(Register b, int offset) { 187 Register ret = newRegister(); 188 emitModRMMemory(true, 0x8B, ret.encoding, b.encoding, offset); // MOV r64,r/m64 189 return ret; 190 } 191 192 @Override 193 public StackSlot emitIntToStack(Register a) { 194 StackSlot ret = newStackSlot(AMD64Kind.DWORD); 195 // MOV r/m32,r32 196 emitModRMMemory(false, 0x89, a.encoding, AMD64.rbp.encoding, ret.getRawOffset() + 16); 197 return ret; 198 } 199 200 @Override 201 public StackSlot emitLongToStack(Register a) { 202 StackSlot ret = newStackSlot(AMD64Kind.QWORD); 203 // MOV r/m64,r64 204 emitModRMMemory(true, 0x89, a.encoding, AMD64.rbp.encoding, ret.getRawOffset() + 16); 205 return ret; 206 } 207 208 @Override 209 public StackSlot emitFloatToStack(Register a) { 210 StackSlot ret = newStackSlot(AMD64Kind.SINGLE); 211 emitREX(false, a.encoding, 0, 0); 212 code.emitByte(0xF3); 213 code.emitByte(0x0F); 214 code.emitByte(0x11); // MOVSS xmm2/m32, xmm1 215 code.emitByte(0x85 | ((a.encoding & 0x7) << 3)); // [rbp+offset] 216 code.emitInt(ret.getRawOffset() + 16); 217 return ret; 218 } 219 220 @Override 221 public StackSlot emitPointerToStack(Register a) { 222 StackSlot ret = newStackSlot(AMD64Kind.QWORD); 223 // MOV r/m64,r64 224 emitModRMMemory(true, 0x89, a.encoding, AMD64.rbp.encoding, ret.getRawOffset() + 16); 225 return ret; 226 } 227 228 @Override 229 public StackSlot emitNarrowPointerToStack(Register a) { 230 StackSlot ret = newStackSlot(AMD64Kind.DWORD); 231 // MOV r/m32,r32 232 emitModRMMemory(false, 0x89, a.encoding, AMD64.rbp.encoding, ret.getRawOffset() + 16); 233 return ret; 234 } 235 236 @Override 237 public Register emitUncompressPointer(Register compressed, long base, int shift) { 238 if (shift > 0) { 239 emitModRMReg(true, 0xC1, 4, compressed.encoding); 240 code.emitByte(shift); 241 } 242 if (base == 0) { 243 return compressed; 244 } else { 245 Register tmp = emitLoadLong(base); 246 emitModRMReg(true, 0x03, tmp.encoding, compressed.encoding); 247 return tmp; 248 } 249 } 250 251 @Override 252 public Register emitIntAdd(Register a, Register b) { 253 emitModRMReg(false, 0x03, a.encoding, b.encoding); 254 return a; 255 } 256 257 private void emitMove(boolean w, Register to, Register from) { 258 if (to != from) { 259 emitModRMReg(w, 0x8B, to.encoding, from.encoding); 260 } 261 } 262 263 @Override 264 public void emitIntRet(Register a) { 265 emitMove(false, AMD64.rax, a); // MOV eax, ... 266 emitMove(true, AMD64.rsp, AMD64.rbp); // MOV rsp, rbp 267 code.emitByte(0x58 | AMD64.rbp.encoding); // POP rbp 268 code.emitByte(0xC3); // RET 269 } 270 271 @Override 272 public void emitPointerRet(Register a) { 273 emitMove(true, AMD64.rax, a); // MOV rax, ... 274 emitMove(true, AMD64.rsp, AMD64.rbp); // MOV rsp, rbp 275 code.emitByte(0x58 | AMD64.rbp.encoding); // POP rbp 276 code.emitByte(0xC3); // RET 277 } 278 279 @Override 280 public void emitTrap(DebugInfo info) { 281 recordImplicitException(info); 282 // MOV rax, [0] 283 code.emitByte(0x8B); 284 code.emitByte(0x04); 285 code.emitByte(0x25); 286 code.emitInt(0); 287 } 288 }