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 }