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