Home | History | Annotate | Download | only in x86_64
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "jni_macro_assembler_x86_64.h"
     18 
     19 #include "base/casts.h"
     20 #include "entrypoints/quick/quick_entrypoints.h"
     21 #include "memory_region.h"
     22 #include "thread.h"
     23 
     24 namespace art {
     25 namespace x86_64 {
     26 
     27 static dwarf::Reg DWARFReg(Register reg) {
     28   return dwarf::Reg::X86_64Core(static_cast<int>(reg));
     29 }
     30 static dwarf::Reg DWARFReg(FloatRegister reg) {
     31   return dwarf::Reg::X86_64Fp(static_cast<int>(reg));
     32 }
     33 
     34 constexpr size_t kFramePointerSize = 8;
     35 
     36 #define __ asm_.
     37 
     38 void X86_64JNIMacroAssembler::BuildFrame(size_t frame_size,
     39                                          ManagedRegister method_reg,
     40                                          ArrayRef<const ManagedRegister> spill_regs,
     41                                          const ManagedRegisterEntrySpills& entry_spills) {
     42   DCHECK_EQ(CodeSize(), 0U);  // Nothing emitted yet.
     43   cfi().SetCurrentCFAOffset(8);  // Return address on stack.
     44   CHECK_ALIGNED(frame_size, kStackAlignment);
     45   int gpr_count = 0;
     46   for (int i = spill_regs.size() - 1; i >= 0; --i) {
     47     x86_64::X86_64ManagedRegister spill = spill_regs[i].AsX86_64();
     48     if (spill.IsCpuRegister()) {
     49       __ pushq(spill.AsCpuRegister());
     50       gpr_count++;
     51       cfi().AdjustCFAOffset(kFramePointerSize);
     52       cfi().RelOffset(DWARFReg(spill.AsCpuRegister().AsRegister()), 0);
     53     }
     54   }
     55   // return address then method on stack.
     56   int64_t rest_of_frame = static_cast<int64_t>(frame_size)
     57                           - (gpr_count * kFramePointerSize)
     58                           - kFramePointerSize /*return address*/;
     59   __ subq(CpuRegister(RSP), Immediate(rest_of_frame));
     60   cfi().AdjustCFAOffset(rest_of_frame);
     61 
     62   // spill xmms
     63   int64_t offset = rest_of_frame;
     64   for (int i = spill_regs.size() - 1; i >= 0; --i) {
     65     x86_64::X86_64ManagedRegister spill = spill_regs[i].AsX86_64();
     66     if (spill.IsXmmRegister()) {
     67       offset -= sizeof(double);
     68       __ movsd(Address(CpuRegister(RSP), offset), spill.AsXmmRegister());
     69       cfi().RelOffset(DWARFReg(spill.AsXmmRegister().AsFloatRegister()), offset);
     70     }
     71   }
     72 
     73   static_assert(static_cast<size_t>(kX86_64PointerSize) == kFramePointerSize,
     74                 "Unexpected frame pointer size.");
     75 
     76   __ movq(Address(CpuRegister(RSP), 0), method_reg.AsX86_64().AsCpuRegister());
     77 
     78   for (size_t i = 0; i < entry_spills.size(); ++i) {
     79     ManagedRegisterSpill spill = entry_spills.at(i);
     80     if (spill.AsX86_64().IsCpuRegister()) {
     81       if (spill.getSize() == 8) {
     82         __ movq(Address(CpuRegister(RSP), frame_size + spill.getSpillOffset()),
     83                 spill.AsX86_64().AsCpuRegister());
     84       } else {
     85         CHECK_EQ(spill.getSize(), 4);
     86         __ movl(Address(CpuRegister(RSP), frame_size + spill.getSpillOffset()),
     87                 spill.AsX86_64().AsCpuRegister());
     88       }
     89     } else {
     90       if (spill.getSize() == 8) {
     91         __ movsd(Address(CpuRegister(RSP), frame_size + spill.getSpillOffset()),
     92                  spill.AsX86_64().AsXmmRegister());
     93       } else {
     94         CHECK_EQ(spill.getSize(), 4);
     95         __ movss(Address(CpuRegister(RSP), frame_size + spill.getSpillOffset()),
     96                  spill.AsX86_64().AsXmmRegister());
     97       }
     98     }
     99   }
    100 }
    101 
    102 void X86_64JNIMacroAssembler::RemoveFrame(size_t frame_size,
    103                                           ArrayRef<const ManagedRegister> spill_regs) {
    104   CHECK_ALIGNED(frame_size, kStackAlignment);
    105   cfi().RememberState();
    106   int gpr_count = 0;
    107   // unspill xmms
    108   int64_t offset = static_cast<int64_t>(frame_size)
    109       - (spill_regs.size() * kFramePointerSize)
    110       - 2 * kFramePointerSize;
    111   for (size_t i = 0; i < spill_regs.size(); ++i) {
    112     x86_64::X86_64ManagedRegister spill = spill_regs[i].AsX86_64();
    113     if (spill.IsXmmRegister()) {
    114       offset += sizeof(double);
    115       __ movsd(spill.AsXmmRegister(), Address(CpuRegister(RSP), offset));
    116       cfi().Restore(DWARFReg(spill.AsXmmRegister().AsFloatRegister()));
    117     } else {
    118       gpr_count++;
    119     }
    120   }
    121   int adjust = static_cast<int>(frame_size) - (gpr_count * kFramePointerSize) - kFramePointerSize;
    122   __ addq(CpuRegister(RSP), Immediate(adjust));
    123   cfi().AdjustCFAOffset(-adjust);
    124   for (size_t i = 0; i < spill_regs.size(); ++i) {
    125     x86_64::X86_64ManagedRegister spill = spill_regs[i].AsX86_64();
    126     if (spill.IsCpuRegister()) {
    127       __ popq(spill.AsCpuRegister());
    128       cfi().AdjustCFAOffset(-static_cast<int>(kFramePointerSize));
    129       cfi().Restore(DWARFReg(spill.AsCpuRegister().AsRegister()));
    130     }
    131   }
    132   __ ret();
    133   // The CFI should be restored for any code that follows the exit block.
    134   cfi().RestoreState();
    135   cfi().DefCFAOffset(frame_size);
    136 }
    137 
    138 void X86_64JNIMacroAssembler::IncreaseFrameSize(size_t adjust) {
    139   CHECK_ALIGNED(adjust, kStackAlignment);
    140   __ addq(CpuRegister(RSP), Immediate(-static_cast<int64_t>(adjust)));
    141   cfi().AdjustCFAOffset(adjust);
    142 }
    143 
    144 static void DecreaseFrameSizeImpl(size_t adjust, X86_64Assembler* assembler) {
    145   CHECK_ALIGNED(adjust, kStackAlignment);
    146   assembler->addq(CpuRegister(RSP), Immediate(adjust));
    147   assembler->cfi().AdjustCFAOffset(-adjust);
    148 }
    149 
    150 void X86_64JNIMacroAssembler::DecreaseFrameSize(size_t adjust) {
    151   DecreaseFrameSizeImpl(adjust, &asm_);
    152 }
    153 
    154 void X86_64JNIMacroAssembler::Store(FrameOffset offs, ManagedRegister msrc, size_t size) {
    155   X86_64ManagedRegister src = msrc.AsX86_64();
    156   if (src.IsNoRegister()) {
    157     CHECK_EQ(0u, size);
    158   } else if (src.IsCpuRegister()) {
    159     if (size == 4) {
    160       CHECK_EQ(4u, size);
    161       __ movl(Address(CpuRegister(RSP), offs), src.AsCpuRegister());
    162     } else {
    163       CHECK_EQ(8u, size);
    164       __ movq(Address(CpuRegister(RSP), offs), src.AsCpuRegister());
    165     }
    166   } else if (src.IsRegisterPair()) {
    167     CHECK_EQ(0u, size);
    168     __ movq(Address(CpuRegister(RSP), offs), src.AsRegisterPairLow());
    169     __ movq(Address(CpuRegister(RSP), FrameOffset(offs.Int32Value()+4)),
    170             src.AsRegisterPairHigh());
    171   } else if (src.IsX87Register()) {
    172     if (size == 4) {
    173       __ fstps(Address(CpuRegister(RSP), offs));
    174     } else {
    175       __ fstpl(Address(CpuRegister(RSP), offs));
    176     }
    177   } else {
    178     CHECK(src.IsXmmRegister());
    179     if (size == 4) {
    180       __ movss(Address(CpuRegister(RSP), offs), src.AsXmmRegister());
    181     } else {
    182       __ movsd(Address(CpuRegister(RSP), offs), src.AsXmmRegister());
    183     }
    184   }
    185 }
    186 
    187 void X86_64JNIMacroAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
    188   X86_64ManagedRegister src = msrc.AsX86_64();
    189   CHECK(src.IsCpuRegister());
    190   __ movl(Address(CpuRegister(RSP), dest), src.AsCpuRegister());
    191 }
    192 
    193 void X86_64JNIMacroAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
    194   X86_64ManagedRegister src = msrc.AsX86_64();
    195   CHECK(src.IsCpuRegister());
    196   __ movq(Address(CpuRegister(RSP), dest), src.AsCpuRegister());
    197 }
    198 
    199 void X86_64JNIMacroAssembler::StoreImmediateToFrame(FrameOffset dest,
    200                                                     uint32_t imm,
    201                                                     ManagedRegister) {
    202   __ movl(Address(CpuRegister(RSP), dest), Immediate(imm));  // TODO(64) movq?
    203 }
    204 
    205 void X86_64JNIMacroAssembler::StoreStackOffsetToThread(ThreadOffset64 thr_offs,
    206                                                        FrameOffset fr_offs,
    207                                                        ManagedRegister mscratch) {
    208   X86_64ManagedRegister scratch = mscratch.AsX86_64();
    209   CHECK(scratch.IsCpuRegister());
    210   __ leaq(scratch.AsCpuRegister(), Address(CpuRegister(RSP), fr_offs));
    211   __ gs()->movq(Address::Absolute(thr_offs, true), scratch.AsCpuRegister());
    212 }
    213 
    214 void X86_64JNIMacroAssembler::StoreStackPointerToThread(ThreadOffset64 thr_offs) {
    215   __ gs()->movq(Address::Absolute(thr_offs, true), CpuRegister(RSP));
    216 }
    217 
    218 void X86_64JNIMacroAssembler::StoreSpanning(FrameOffset /*dst*/,
    219                                             ManagedRegister /*src*/,
    220                                             FrameOffset /*in_off*/,
    221                                             ManagedRegister /*scratch*/) {
    222   UNIMPLEMENTED(FATAL);  // this case only currently exists for ARM
    223 }
    224 
    225 void X86_64JNIMacroAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) {
    226   X86_64ManagedRegister dest = mdest.AsX86_64();
    227   if (dest.IsNoRegister()) {
    228     CHECK_EQ(0u, size);
    229   } else if (dest.IsCpuRegister()) {
    230     if (size == 4) {
    231       CHECK_EQ(4u, size);
    232       __ movl(dest.AsCpuRegister(), Address(CpuRegister(RSP), src));
    233     } else {
    234       CHECK_EQ(8u, size);
    235       __ movq(dest.AsCpuRegister(), Address(CpuRegister(RSP), src));
    236     }
    237   } else if (dest.IsRegisterPair()) {
    238     CHECK_EQ(0u, size);
    239     __ movq(dest.AsRegisterPairLow(), Address(CpuRegister(RSP), src));
    240     __ movq(dest.AsRegisterPairHigh(), Address(CpuRegister(RSP), FrameOffset(src.Int32Value()+4)));
    241   } else if (dest.IsX87Register()) {
    242     if (size == 4) {
    243       __ flds(Address(CpuRegister(RSP), src));
    244     } else {
    245       __ fldl(Address(CpuRegister(RSP), src));
    246     }
    247   } else {
    248     CHECK(dest.IsXmmRegister());
    249     if (size == 4) {
    250       __ movss(dest.AsXmmRegister(), Address(CpuRegister(RSP), src));
    251     } else {
    252       __ movsd(dest.AsXmmRegister(), Address(CpuRegister(RSP), src));
    253     }
    254   }
    255 }
    256 
    257 void X86_64JNIMacroAssembler::LoadFromThread(ManagedRegister mdest,
    258                                              ThreadOffset64 src, size_t size) {
    259   X86_64ManagedRegister dest = mdest.AsX86_64();
    260   if (dest.IsNoRegister()) {
    261     CHECK_EQ(0u, size);
    262   } else if (dest.IsCpuRegister()) {
    263     if (size == 1u) {
    264       __ gs()->movzxb(dest.AsCpuRegister(), Address::Absolute(src, true));
    265     } else {
    266       CHECK_EQ(4u, size);
    267       __ gs()->movl(dest.AsCpuRegister(), Address::Absolute(src, true));
    268     }
    269   } else if (dest.IsRegisterPair()) {
    270     CHECK_EQ(8u, size);
    271     __ gs()->movq(dest.AsRegisterPairLow(), Address::Absolute(src, true));
    272   } else if (dest.IsX87Register()) {
    273     if (size == 4) {
    274       __ gs()->flds(Address::Absolute(src, true));
    275     } else {
    276       __ gs()->fldl(Address::Absolute(src, true));
    277     }
    278   } else {
    279     CHECK(dest.IsXmmRegister());
    280     if (size == 4) {
    281       __ gs()->movss(dest.AsXmmRegister(), Address::Absolute(src, true));
    282     } else {
    283       __ gs()->movsd(dest.AsXmmRegister(), Address::Absolute(src, true));
    284     }
    285   }
    286 }
    287 
    288 void X86_64JNIMacroAssembler::LoadRef(ManagedRegister mdest, FrameOffset src) {
    289   X86_64ManagedRegister dest = mdest.AsX86_64();
    290   CHECK(dest.IsCpuRegister());
    291   __ movq(dest.AsCpuRegister(), Address(CpuRegister(RSP), src));
    292 }
    293 
    294 void X86_64JNIMacroAssembler::LoadRef(ManagedRegister mdest,
    295                                       ManagedRegister mbase,
    296                                       MemberOffset offs,
    297                                       bool unpoison_reference) {
    298   X86_64ManagedRegister base = mbase.AsX86_64();
    299   X86_64ManagedRegister dest = mdest.AsX86_64();
    300   CHECK(base.IsCpuRegister());
    301   CHECK(dest.IsCpuRegister());
    302   __ movl(dest.AsCpuRegister(), Address(base.AsCpuRegister(), offs));
    303   if (unpoison_reference) {
    304     __ MaybeUnpoisonHeapReference(dest.AsCpuRegister());
    305   }
    306 }
    307 
    308 void X86_64JNIMacroAssembler::LoadRawPtr(ManagedRegister mdest,
    309                                          ManagedRegister mbase,
    310                                          Offset offs) {
    311   X86_64ManagedRegister base = mbase.AsX86_64();
    312   X86_64ManagedRegister dest = mdest.AsX86_64();
    313   CHECK(base.IsCpuRegister());
    314   CHECK(dest.IsCpuRegister());
    315   __ movq(dest.AsCpuRegister(), Address(base.AsCpuRegister(), offs));
    316 }
    317 
    318 void X86_64JNIMacroAssembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset64 offs) {
    319   X86_64ManagedRegister dest = mdest.AsX86_64();
    320   CHECK(dest.IsCpuRegister());
    321   __ gs()->movq(dest.AsCpuRegister(), Address::Absolute(offs, true));
    322 }
    323 
    324 void X86_64JNIMacroAssembler::SignExtend(ManagedRegister mreg, size_t size) {
    325   X86_64ManagedRegister reg = mreg.AsX86_64();
    326   CHECK(size == 1 || size == 2) << size;
    327   CHECK(reg.IsCpuRegister()) << reg;
    328   if (size == 1) {
    329     __ movsxb(reg.AsCpuRegister(), reg.AsCpuRegister());
    330   } else {
    331     __ movsxw(reg.AsCpuRegister(), reg.AsCpuRegister());
    332   }
    333 }
    334 
    335 void X86_64JNIMacroAssembler::ZeroExtend(ManagedRegister mreg, size_t size) {
    336   X86_64ManagedRegister reg = mreg.AsX86_64();
    337   CHECK(size == 1 || size == 2) << size;
    338   CHECK(reg.IsCpuRegister()) << reg;
    339   if (size == 1) {
    340     __ movzxb(reg.AsCpuRegister(), reg.AsCpuRegister());
    341   } else {
    342     __ movzxw(reg.AsCpuRegister(), reg.AsCpuRegister());
    343   }
    344 }
    345 
    346 void X86_64JNIMacroAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) {
    347   X86_64ManagedRegister dest = mdest.AsX86_64();
    348   X86_64ManagedRegister src = msrc.AsX86_64();
    349   if (!dest.Equals(src)) {
    350     if (dest.IsCpuRegister() && src.IsCpuRegister()) {
    351       __ movq(dest.AsCpuRegister(), src.AsCpuRegister());
    352     } else if (src.IsX87Register() && dest.IsXmmRegister()) {
    353       // Pass via stack and pop X87 register
    354       __ subl(CpuRegister(RSP), Immediate(16));
    355       if (size == 4) {
    356         CHECK_EQ(src.AsX87Register(), ST0);
    357         __ fstps(Address(CpuRegister(RSP), 0));
    358         __ movss(dest.AsXmmRegister(), Address(CpuRegister(RSP), 0));
    359       } else {
    360         CHECK_EQ(src.AsX87Register(), ST0);
    361         __ fstpl(Address(CpuRegister(RSP), 0));
    362         __ movsd(dest.AsXmmRegister(), Address(CpuRegister(RSP), 0));
    363       }
    364       __ addq(CpuRegister(RSP), Immediate(16));
    365     } else {
    366       // TODO: x87, SSE
    367       UNIMPLEMENTED(FATAL) << ": Move " << dest << ", " << src;
    368     }
    369   }
    370 }
    371 
    372 void X86_64JNIMacroAssembler::CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) {
    373   X86_64ManagedRegister scratch = mscratch.AsX86_64();
    374   CHECK(scratch.IsCpuRegister());
    375   __ movl(scratch.AsCpuRegister(), Address(CpuRegister(RSP), src));
    376   __ movl(Address(CpuRegister(RSP), dest), scratch.AsCpuRegister());
    377 }
    378 
    379 void X86_64JNIMacroAssembler::CopyRawPtrFromThread(FrameOffset fr_offs,
    380                                                    ThreadOffset64 thr_offs,
    381                                                    ManagedRegister mscratch) {
    382   X86_64ManagedRegister scratch = mscratch.AsX86_64();
    383   CHECK(scratch.IsCpuRegister());
    384   __ gs()->movq(scratch.AsCpuRegister(), Address::Absolute(thr_offs, true));
    385   Store(fr_offs, scratch, 8);
    386 }
    387 
    388 void X86_64JNIMacroAssembler::CopyRawPtrToThread(ThreadOffset64 thr_offs,
    389                                                  FrameOffset fr_offs,
    390                                                  ManagedRegister mscratch) {
    391   X86_64ManagedRegister scratch = mscratch.AsX86_64();
    392   CHECK(scratch.IsCpuRegister());
    393   Load(scratch, fr_offs, 8);
    394   __ gs()->movq(Address::Absolute(thr_offs, true), scratch.AsCpuRegister());
    395 }
    396 
    397 void X86_64JNIMacroAssembler::Copy(FrameOffset dest,
    398                                    FrameOffset src,
    399                                    ManagedRegister mscratch,
    400                                    size_t size) {
    401   X86_64ManagedRegister scratch = mscratch.AsX86_64();
    402   if (scratch.IsCpuRegister() && size == 8) {
    403     Load(scratch, src, 4);
    404     Store(dest, scratch, 4);
    405     Load(scratch, FrameOffset(src.Int32Value() + 4), 4);
    406     Store(FrameOffset(dest.Int32Value() + 4), scratch, 4);
    407   } else {
    408     Load(scratch, src, size);
    409     Store(dest, scratch, size);
    410   }
    411 }
    412 
    413 void X86_64JNIMacroAssembler::Copy(FrameOffset /*dst*/,
    414                                    ManagedRegister /*src_base*/,
    415                                    Offset /*src_offset*/,
    416                                    ManagedRegister /*scratch*/,
    417                                    size_t /*size*/) {
    418   UNIMPLEMENTED(FATAL);
    419 }
    420 
    421 void X86_64JNIMacroAssembler::Copy(ManagedRegister dest_base,
    422                                    Offset dest_offset,
    423                                    FrameOffset src,
    424                                    ManagedRegister scratch,
    425                                    size_t size) {
    426   CHECK(scratch.IsNoRegister());
    427   CHECK_EQ(size, 4u);
    428   __ pushq(Address(CpuRegister(RSP), src));
    429   __ popq(Address(dest_base.AsX86_64().AsCpuRegister(), dest_offset));
    430 }
    431 
    432 void X86_64JNIMacroAssembler::Copy(FrameOffset dest,
    433                                    FrameOffset src_base,
    434                                    Offset src_offset,
    435                                    ManagedRegister mscratch,
    436                                    size_t size) {
    437   CpuRegister scratch = mscratch.AsX86_64().AsCpuRegister();
    438   CHECK_EQ(size, 4u);
    439   __ movq(scratch, Address(CpuRegister(RSP), src_base));
    440   __ movq(scratch, Address(scratch, src_offset));
    441   __ movq(Address(CpuRegister(RSP), dest), scratch);
    442 }
    443 
    444 void X86_64JNIMacroAssembler::Copy(ManagedRegister dest,
    445                                    Offset dest_offset,
    446                                    ManagedRegister src,
    447                                    Offset src_offset,
    448                                    ManagedRegister scratch,
    449                                    size_t size) {
    450   CHECK_EQ(size, 4u);
    451   CHECK(scratch.IsNoRegister());
    452   __ pushq(Address(src.AsX86_64().AsCpuRegister(), src_offset));
    453   __ popq(Address(dest.AsX86_64().AsCpuRegister(), dest_offset));
    454 }
    455 
    456 void X86_64JNIMacroAssembler::Copy(FrameOffset dest,
    457                                    Offset dest_offset,
    458                                    FrameOffset src,
    459                                    Offset src_offset,
    460                                    ManagedRegister mscratch,
    461                                    size_t size) {
    462   CpuRegister scratch = mscratch.AsX86_64().AsCpuRegister();
    463   CHECK_EQ(size, 4u);
    464   CHECK_EQ(dest.Int32Value(), src.Int32Value());
    465   __ movq(scratch, Address(CpuRegister(RSP), src));
    466   __ pushq(Address(scratch, src_offset));
    467   __ popq(Address(scratch, dest_offset));
    468 }
    469 
    470 void X86_64JNIMacroAssembler::MemoryBarrier(ManagedRegister) {
    471   __ mfence();
    472 }
    473 
    474 void X86_64JNIMacroAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg,
    475                                                      FrameOffset handle_scope_offset,
    476                                                      ManagedRegister min_reg,
    477                                                      bool null_allowed) {
    478   X86_64ManagedRegister out_reg = mout_reg.AsX86_64();
    479   X86_64ManagedRegister in_reg = min_reg.AsX86_64();
    480   if (in_reg.IsNoRegister()) {  // TODO(64): && null_allowed
    481     // Use out_reg as indicator of null.
    482     in_reg = out_reg;
    483     // TODO: movzwl
    484     __ movl(in_reg.AsCpuRegister(), Address(CpuRegister(RSP), handle_scope_offset));
    485   }
    486   CHECK(in_reg.IsCpuRegister());
    487   CHECK(out_reg.IsCpuRegister());
    488   VerifyObject(in_reg, null_allowed);
    489   if (null_allowed) {
    490     Label null_arg;
    491     if (!out_reg.Equals(in_reg)) {
    492       __ xorl(out_reg.AsCpuRegister(), out_reg.AsCpuRegister());
    493     }
    494     __ testl(in_reg.AsCpuRegister(), in_reg.AsCpuRegister());
    495     __ j(kZero, &null_arg);
    496     __ leaq(out_reg.AsCpuRegister(), Address(CpuRegister(RSP), handle_scope_offset));
    497     __ Bind(&null_arg);
    498   } else {
    499     __ leaq(out_reg.AsCpuRegister(), Address(CpuRegister(RSP), handle_scope_offset));
    500   }
    501 }
    502 
    503 void X86_64JNIMacroAssembler::CreateHandleScopeEntry(FrameOffset out_off,
    504                                                      FrameOffset handle_scope_offset,
    505                                                      ManagedRegister mscratch,
    506                                                      bool null_allowed) {
    507   X86_64ManagedRegister scratch = mscratch.AsX86_64();
    508   CHECK(scratch.IsCpuRegister());
    509   if (null_allowed) {
    510     Label null_arg;
    511     __ movl(scratch.AsCpuRegister(), Address(CpuRegister(RSP), handle_scope_offset));
    512     __ testl(scratch.AsCpuRegister(), scratch.AsCpuRegister());
    513     __ j(kZero, &null_arg);
    514     __ leaq(scratch.AsCpuRegister(), Address(CpuRegister(RSP), handle_scope_offset));
    515     __ Bind(&null_arg);
    516   } else {
    517     __ leaq(scratch.AsCpuRegister(), Address(CpuRegister(RSP), handle_scope_offset));
    518   }
    519   Store(out_off, scratch, 8);
    520 }
    521 
    522 // Given a handle scope entry, load the associated reference.
    523 void X86_64JNIMacroAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg,
    524                                                            ManagedRegister min_reg) {
    525   X86_64ManagedRegister out_reg = mout_reg.AsX86_64();
    526   X86_64ManagedRegister in_reg = min_reg.AsX86_64();
    527   CHECK(out_reg.IsCpuRegister());
    528   CHECK(in_reg.IsCpuRegister());
    529   Label null_arg;
    530   if (!out_reg.Equals(in_reg)) {
    531     __ xorl(out_reg.AsCpuRegister(), out_reg.AsCpuRegister());
    532   }
    533   __ testl(in_reg.AsCpuRegister(), in_reg.AsCpuRegister());
    534   __ j(kZero, &null_arg);
    535   __ movq(out_reg.AsCpuRegister(), Address(in_reg.AsCpuRegister(), 0));
    536   __ Bind(&null_arg);
    537 }
    538 
    539 void X86_64JNIMacroAssembler::VerifyObject(ManagedRegister /*src*/, bool /*could_be_null*/) {
    540   // TODO: not validating references
    541 }
    542 
    543 void X86_64JNIMacroAssembler::VerifyObject(FrameOffset /*src*/, bool /*could_be_null*/) {
    544   // TODO: not validating references
    545 }
    546 
    547 void X86_64JNIMacroAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister) {
    548   X86_64ManagedRegister base = mbase.AsX86_64();
    549   CHECK(base.IsCpuRegister());
    550   __ call(Address(base.AsCpuRegister(), offset.Int32Value()));
    551   // TODO: place reference map on call
    552 }
    553 
    554 void X86_64JNIMacroAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
    555   CpuRegister scratch = mscratch.AsX86_64().AsCpuRegister();
    556   __ movq(scratch, Address(CpuRegister(RSP), base));
    557   __ call(Address(scratch, offset));
    558 }
    559 
    560 void X86_64JNIMacroAssembler::CallFromThread(ThreadOffset64 offset, ManagedRegister /*mscratch*/) {
    561   __ gs()->call(Address::Absolute(offset, true));
    562 }
    563 
    564 void X86_64JNIMacroAssembler::GetCurrentThread(ManagedRegister tr) {
    565   __ gs()->movq(tr.AsX86_64().AsCpuRegister(),
    566                 Address::Absolute(Thread::SelfOffset<kX86_64PointerSize>(), true));
    567 }
    568 
    569 void X86_64JNIMacroAssembler::GetCurrentThread(FrameOffset offset, ManagedRegister mscratch) {
    570   X86_64ManagedRegister scratch = mscratch.AsX86_64();
    571   __ gs()->movq(scratch.AsCpuRegister(),
    572                 Address::Absolute(Thread::SelfOffset<kX86_64PointerSize>(), true));
    573   __ movq(Address(CpuRegister(RSP), offset), scratch.AsCpuRegister());
    574 }
    575 
    576 // Slowpath entered when Thread::Current()->_exception is non-null
    577 class X86_64ExceptionSlowPath FINAL : public SlowPath {
    578  public:
    579   explicit X86_64ExceptionSlowPath(size_t stack_adjust) : stack_adjust_(stack_adjust) {}
    580   virtual void Emit(Assembler *sp_asm) OVERRIDE;
    581  private:
    582   const size_t stack_adjust_;
    583 };
    584 
    585 void X86_64JNIMacroAssembler::ExceptionPoll(ManagedRegister /*scratch*/, size_t stack_adjust) {
    586   X86_64ExceptionSlowPath* slow = new (__ GetArena()) X86_64ExceptionSlowPath(stack_adjust);
    587   __ GetBuffer()->EnqueueSlowPath(slow);
    588   __ gs()->cmpl(Address::Absolute(Thread::ExceptionOffset<kX86_64PointerSize>(), true), Immediate(0));
    589   __ j(kNotEqual, slow->Entry());
    590 }
    591 
    592 std::unique_ptr<JNIMacroLabel> X86_64JNIMacroAssembler::CreateLabel() {
    593   return std::unique_ptr<JNIMacroLabel>(new X86_64JNIMacroLabel());
    594 }
    595 
    596 void X86_64JNIMacroAssembler::Jump(JNIMacroLabel* label) {
    597   CHECK(label != nullptr);
    598   __ jmp(X86_64JNIMacroLabel::Cast(label)->AsX86_64());
    599 }
    600 
    601 void X86_64JNIMacroAssembler::Jump(JNIMacroLabel* label,
    602                                    JNIMacroUnaryCondition condition,
    603                                    ManagedRegister test) {
    604   CHECK(label != nullptr);
    605 
    606   art::x86_64::Condition x86_64_cond;
    607   switch (condition) {
    608     case JNIMacroUnaryCondition::kZero:
    609       x86_64_cond = art::x86_64::kZero;
    610       break;
    611     case JNIMacroUnaryCondition::kNotZero:
    612       x86_64_cond = art::x86_64::kNotZero;
    613       break;
    614     default:
    615       LOG(FATAL) << "Not implemented condition: " << static_cast<int>(condition);
    616       UNREACHABLE();
    617   }
    618 
    619   // TEST reg, reg
    620   // Jcc <Offset>
    621   __ testq(test.AsX86_64().AsCpuRegister(), test.AsX86_64().AsCpuRegister());
    622   __ j(x86_64_cond, X86_64JNIMacroLabel::Cast(label)->AsX86_64());
    623 }
    624 
    625 void X86_64JNIMacroAssembler::Bind(JNIMacroLabel* label) {
    626   CHECK(label != nullptr);
    627   __ Bind(X86_64JNIMacroLabel::Cast(label)->AsX86_64());
    628 }
    629 
    630 #undef __
    631 
    632 void X86_64ExceptionSlowPath::Emit(Assembler *sasm) {
    633   X86_64Assembler* sp_asm = down_cast<X86_64Assembler*>(sasm);
    634 #define __ sp_asm->
    635   __ Bind(&entry_);
    636   // Note: the return value is dead
    637   if (stack_adjust_ != 0) {  // Fix up the frame.
    638     DecreaseFrameSizeImpl(stack_adjust_, sp_asm);
    639   }
    640   // Pass exception as argument in RDI
    641   __ gs()->movq(CpuRegister(RDI),
    642                 Address::Absolute(Thread::ExceptionOffset<kX86_64PointerSize>(), true));
    643   __ gs()->call(
    644       Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64PointerSize, pDeliverException), true));
    645   // this call should never return
    646   __ int3();
    647 #undef __
    648 }
    649 
    650 }  // namespace x86_64
    651 }  // namespace art
    652