Home | History | Annotate | Download | only in mterp
      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 /*
     18  * Mterp entry point and support functions.
     19  */
     20 #include "interpreter/interpreter_common.h"
     21 #include "interpreter/interpreter_intrinsics.h"
     22 #include "entrypoints/entrypoint_utils-inl.h"
     23 #include "mterp.h"
     24 #include "debugger.h"
     25 
     26 namespace art {
     27 namespace interpreter {
     28 /*
     29  * Verify some constants used by the mterp interpreter.
     30  */
     31 void CheckMterpAsmConstants() {
     32   /*
     33    * If we're using computed goto instruction transitions, make sure
     34    * none of the handlers overflows the 128-byte limit.  This won't tell
     35    * which one did, but if any one is too big the total size will
     36    * overflow.
     37    */
     38   const int width = 128;
     39   int interp_size = (uintptr_t) artMterpAsmInstructionEnd -
     40                     (uintptr_t) artMterpAsmInstructionStart;
     41   if ((interp_size == 0) || (interp_size != (art::kNumPackedOpcodes * width))) {
     42       LOG(FATAL) << "ERROR: unexpected asm interp size " << interp_size
     43                  << "(did an instruction handler exceed " << width << " bytes?)";
     44   }
     45 }
     46 
     47 void InitMterpTls(Thread* self) {
     48   self->SetMterpDefaultIBase(artMterpAsmInstructionStart);
     49   self->SetMterpAltIBase(artMterpAsmAltInstructionStart);
     50   self->SetMterpCurrentIBase((kTraceExecutionEnabled || kTestExportPC) ?
     51                              artMterpAsmAltInstructionStart :
     52                              artMterpAsmInstructionStart);
     53 }
     54 
     55 /*
     56  * Find the matching case.  Returns the offset to the handler instructions.
     57  *
     58  * Returns 3 if we don't find a match (it's the size of the sparse-switch
     59  * instruction).
     60  */
     61 extern "C" ssize_t MterpDoSparseSwitch(const uint16_t* switchData, int32_t testVal) {
     62   const int kInstrLen = 3;
     63   uint16_t size;
     64   const int32_t* keys;
     65   const int32_t* entries;
     66 
     67   /*
     68    * Sparse switch data format:
     69    *  ushort ident = 0x0200   magic value
     70    *  ushort size             number of entries in the table; > 0
     71    *  int keys[size]          keys, sorted low-to-high; 32-bit aligned
     72    *  int targets[size]       branch targets, relative to switch opcode
     73    *
     74    * Total size is (2+size*4) 16-bit code units.
     75    */
     76 
     77   uint16_t signature = *switchData++;
     78   DCHECK_EQ(signature, static_cast<uint16_t>(art::Instruction::kSparseSwitchSignature));
     79 
     80   size = *switchData++;
     81 
     82   /* The keys are guaranteed to be aligned on a 32-bit boundary;
     83    * we can treat them as a native int array.
     84    */
     85   keys = reinterpret_cast<const int32_t*>(switchData);
     86 
     87   /* The entries are guaranteed to be aligned on a 32-bit boundary;
     88    * we can treat them as a native int array.
     89    */
     90   entries = keys + size;
     91 
     92   /*
     93    * Binary-search through the array of keys, which are guaranteed to
     94    * be sorted low-to-high.
     95    */
     96   int lo = 0;
     97   int hi = size - 1;
     98   while (lo <= hi) {
     99     int mid = (lo + hi) >> 1;
    100 
    101     int32_t foundVal = keys[mid];
    102     if (testVal < foundVal) {
    103       hi = mid - 1;
    104     } else if (testVal > foundVal) {
    105       lo = mid + 1;
    106     } else {
    107       return entries[mid];
    108     }
    109   }
    110   return kInstrLen;
    111 }
    112 
    113 extern "C" ssize_t MterpDoPackedSwitch(const uint16_t* switchData, int32_t testVal) {
    114   const int kInstrLen = 3;
    115 
    116   /*
    117    * Packed switch data format:
    118    *  ushort ident = 0x0100   magic value
    119    *  ushort size             number of entries in the table
    120    *  int first_key           first (and lowest) switch case value
    121    *  int targets[size]       branch targets, relative to switch opcode
    122    *
    123    * Total size is (4+size*2) 16-bit code units.
    124    */
    125   uint16_t signature = *switchData++;
    126   DCHECK_EQ(signature, static_cast<uint16_t>(art::Instruction::kPackedSwitchSignature));
    127 
    128   uint16_t size = *switchData++;
    129 
    130   int32_t firstKey = *switchData++;
    131   firstKey |= (*switchData++) << 16;
    132 
    133   int index = testVal - firstKey;
    134   if (index < 0 || index >= size) {
    135     return kInstrLen;
    136   }
    137 
    138   /*
    139    * The entries are guaranteed to be aligned on a 32-bit boundary;
    140    * we can treat them as a native int array.
    141    */
    142   const int32_t* entries = reinterpret_cast<const int32_t*>(switchData);
    143   return entries[index];
    144 }
    145 
    146 extern "C" size_t MterpShouldSwitchInterpreters()
    147     REQUIRES_SHARED(Locks::mutator_lock_) {
    148   const instrumentation::Instrumentation* const instrumentation =
    149       Runtime::Current()->GetInstrumentation();
    150   return instrumentation->NonJitProfilingActive() || Dbg::IsDebuggerActive();
    151 }
    152 
    153 
    154 extern "C" size_t MterpInvokeVirtual(Thread* self,
    155                                      ShadowFrame* shadow_frame,
    156                                      uint16_t* dex_pc_ptr,
    157                                      uint16_t inst_data)
    158     REQUIRES_SHARED(Locks::mutator_lock_) {
    159   JValue* result_register = shadow_frame->GetResultRegister();
    160   const Instruction* inst = Instruction::At(dex_pc_ptr);
    161   return DoFastInvoke<kVirtual>(
    162       self, *shadow_frame, inst, inst_data, result_register);
    163 }
    164 
    165 extern "C" size_t MterpInvokeSuper(Thread* self,
    166                                    ShadowFrame* shadow_frame,
    167                                    uint16_t* dex_pc_ptr,
    168                                    uint16_t inst_data)
    169     REQUIRES_SHARED(Locks::mutator_lock_) {
    170   JValue* result_register = shadow_frame->GetResultRegister();
    171   const Instruction* inst = Instruction::At(dex_pc_ptr);
    172   return DoInvoke<kSuper, false, false>(
    173       self, *shadow_frame, inst, inst_data, result_register);
    174 }
    175 
    176 extern "C" size_t MterpInvokeInterface(Thread* self,
    177                                        ShadowFrame* shadow_frame,
    178                                        uint16_t* dex_pc_ptr,
    179                                        uint16_t inst_data)
    180     REQUIRES_SHARED(Locks::mutator_lock_) {
    181   JValue* result_register = shadow_frame->GetResultRegister();
    182   const Instruction* inst = Instruction::At(dex_pc_ptr);
    183   return DoInvoke<kInterface, false, false>(
    184       self, *shadow_frame, inst, inst_data, result_register);
    185 }
    186 
    187 extern "C" size_t MterpInvokeDirect(Thread* self,
    188                                     ShadowFrame* shadow_frame,
    189                                     uint16_t* dex_pc_ptr,
    190                                     uint16_t inst_data)
    191     REQUIRES_SHARED(Locks::mutator_lock_) {
    192   JValue* result_register = shadow_frame->GetResultRegister();
    193   const Instruction* inst = Instruction::At(dex_pc_ptr);
    194   return DoFastInvoke<kDirect>(
    195       self, *shadow_frame, inst, inst_data, result_register);
    196 }
    197 
    198 extern "C" size_t MterpInvokeStatic(Thread* self,
    199                                     ShadowFrame* shadow_frame,
    200                                     uint16_t* dex_pc_ptr,
    201                                     uint16_t inst_data)
    202     REQUIRES_SHARED(Locks::mutator_lock_) {
    203   JValue* result_register = shadow_frame->GetResultRegister();
    204   const Instruction* inst = Instruction::At(dex_pc_ptr);
    205   return DoFastInvoke<kStatic>(
    206       self, *shadow_frame, inst, inst_data, result_register);
    207 }
    208 
    209 extern "C" size_t MterpInvokeVirtualRange(Thread* self,
    210                                           ShadowFrame* shadow_frame,
    211                                           uint16_t* dex_pc_ptr,
    212                                           uint16_t inst_data)
    213     REQUIRES_SHARED(Locks::mutator_lock_) {
    214   JValue* result_register = shadow_frame->GetResultRegister();
    215   const Instruction* inst = Instruction::At(dex_pc_ptr);
    216   return DoInvoke<kVirtual, true, false>(
    217       self, *shadow_frame, inst, inst_data, result_register);
    218 }
    219 
    220 extern "C" size_t MterpInvokeSuperRange(Thread* self,
    221                                         ShadowFrame* shadow_frame,
    222                                         uint16_t* dex_pc_ptr,
    223                                         uint16_t inst_data)
    224     REQUIRES_SHARED(Locks::mutator_lock_) {
    225   JValue* result_register = shadow_frame->GetResultRegister();
    226   const Instruction* inst = Instruction::At(dex_pc_ptr);
    227   return DoInvoke<kSuper, true, false>(
    228       self, *shadow_frame, inst, inst_data, result_register);
    229 }
    230 
    231 extern "C" size_t MterpInvokeInterfaceRange(Thread* self,
    232                                             ShadowFrame* shadow_frame,
    233                                             uint16_t* dex_pc_ptr,
    234                                             uint16_t inst_data)
    235     REQUIRES_SHARED(Locks::mutator_lock_) {
    236   JValue* result_register = shadow_frame->GetResultRegister();
    237   const Instruction* inst = Instruction::At(dex_pc_ptr);
    238   return DoInvoke<kInterface, true, false>(
    239       self, *shadow_frame, inst, inst_data, result_register);
    240 }
    241 
    242 extern "C" size_t MterpInvokeDirectRange(Thread* self,
    243                                          ShadowFrame* shadow_frame,
    244                                          uint16_t* dex_pc_ptr,
    245                                          uint16_t inst_data)
    246     REQUIRES_SHARED(Locks::mutator_lock_) {
    247   JValue* result_register = shadow_frame->GetResultRegister();
    248   const Instruction* inst = Instruction::At(dex_pc_ptr);
    249   return DoInvoke<kDirect, true, false>(
    250       self, *shadow_frame, inst, inst_data, result_register);
    251 }
    252 
    253 extern "C" size_t MterpInvokeStaticRange(Thread* self,
    254                                          ShadowFrame* shadow_frame,
    255                                          uint16_t* dex_pc_ptr,
    256                                          uint16_t inst_data)
    257     REQUIRES_SHARED(Locks::mutator_lock_) {
    258   JValue* result_register = shadow_frame->GetResultRegister();
    259   const Instruction* inst = Instruction::At(dex_pc_ptr);
    260   return DoInvoke<kStatic, true, false>(
    261       self, *shadow_frame, inst, inst_data, result_register);
    262 }
    263 
    264 extern "C" size_t MterpInvokeVirtualQuick(Thread* self,
    265                                           ShadowFrame* shadow_frame,
    266                                           uint16_t* dex_pc_ptr,
    267                                           uint16_t inst_data)
    268     REQUIRES_SHARED(Locks::mutator_lock_) {
    269   JValue* result_register = shadow_frame->GetResultRegister();
    270   const Instruction* inst = Instruction::At(dex_pc_ptr);
    271   const uint32_t vregC = inst->VRegC_35c();
    272   const uint32_t vtable_idx = inst->VRegB_35c();
    273   ObjPtr<mirror::Object> const receiver = shadow_frame->GetVRegReference(vregC);
    274   if (receiver != nullptr) {
    275     ArtMethod* const called_method = receiver->GetClass()->GetEmbeddedVTableEntry(
    276         vtable_idx, kRuntimePointerSize);
    277     if ((called_method != nullptr) && called_method->IsIntrinsic()) {
    278       if (MterpHandleIntrinsic(shadow_frame, called_method, inst, inst_data, result_register)) {
    279         jit::Jit* jit = Runtime::Current()->GetJit();
    280         if (jit != nullptr) {
    281           jit->InvokeVirtualOrInterface(
    282               receiver, shadow_frame->GetMethod(), shadow_frame->GetDexPC(), called_method);
    283           jit->AddSamples(self, shadow_frame->GetMethod(), 1, /*with_backedges*/false);
    284         }
    285         return !self->IsExceptionPending();
    286       }
    287     }
    288   }
    289   return DoInvokeVirtualQuick<false>(
    290       self, *shadow_frame, inst, inst_data, result_register);
    291 }
    292 
    293 extern "C" size_t MterpInvokeVirtualQuickRange(Thread* self,
    294                                                ShadowFrame* shadow_frame,
    295                                                uint16_t* dex_pc_ptr,
    296                                                uint16_t inst_data)
    297     REQUIRES_SHARED(Locks::mutator_lock_) {
    298   JValue* result_register = shadow_frame->GetResultRegister();
    299   const Instruction* inst = Instruction::At(dex_pc_ptr);
    300   return DoInvokeVirtualQuick<true>(
    301       self, *shadow_frame, inst, inst_data, result_register);
    302 }
    303 
    304 extern "C" void MterpThreadFenceForConstructor() {
    305   QuasiAtomic::ThreadFenceForConstructor();
    306 }
    307 
    308 extern "C" size_t MterpConstString(uint32_t index,
    309                                    uint32_t tgt_vreg,
    310                                    ShadowFrame* shadow_frame,
    311                                    Thread* self)
    312     REQUIRES_SHARED(Locks::mutator_lock_) {
    313   ObjPtr<mirror::String> s = ResolveString(self, *shadow_frame, dex::StringIndex(index));
    314   if (UNLIKELY(s == nullptr)) {
    315     return true;
    316   }
    317   shadow_frame->SetVRegReference(tgt_vreg, s.Ptr());
    318   return false;
    319 }
    320 
    321 extern "C" size_t MterpConstClass(uint32_t index,
    322                                   uint32_t tgt_vreg,
    323                                   ShadowFrame* shadow_frame,
    324                                   Thread* self)
    325     REQUIRES_SHARED(Locks::mutator_lock_) {
    326   mirror::Class* c = ResolveVerifyAndClinit(dex::TypeIndex(index),
    327                                             shadow_frame->GetMethod(),
    328                                             self,
    329                                             false,
    330                                             false);
    331   if (UNLIKELY(c == nullptr)) {
    332     return true;
    333   }
    334   shadow_frame->SetVRegReference(tgt_vreg, c);
    335   return false;
    336 }
    337 
    338 extern "C" size_t MterpCheckCast(uint32_t index,
    339                                  StackReference<mirror::Object>* vreg_addr,
    340                                  art::ArtMethod* method,
    341                                  Thread* self)
    342     REQUIRES_SHARED(Locks::mutator_lock_) {
    343   ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(index),
    344                                                    method,
    345                                                    self,
    346                                                    false,
    347                                                    false);
    348   if (UNLIKELY(c == nullptr)) {
    349     return true;
    350   }
    351   // Must load obj from vreg following ResolveVerifyAndClinit due to moving gc.
    352   mirror::Object* obj = vreg_addr->AsMirrorPtr();
    353   if (UNLIKELY(obj != nullptr && !obj->InstanceOf(c))) {
    354     ThrowClassCastException(c, obj->GetClass());
    355     return true;
    356   }
    357   return false;
    358 }
    359 
    360 extern "C" size_t MterpInstanceOf(uint32_t index,
    361                                   StackReference<mirror::Object>* vreg_addr,
    362                                   art::ArtMethod* method,
    363                                   Thread* self)
    364     REQUIRES_SHARED(Locks::mutator_lock_) {
    365   ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(index),
    366                                                    method,
    367                                                    self,
    368                                                    false,
    369                                                    false);
    370   if (UNLIKELY(c == nullptr)) {
    371     return false;  // Caller will check for pending exception.  Return value unimportant.
    372   }
    373   // Must load obj from vreg following ResolveVerifyAndClinit due to moving gc.
    374   mirror::Object* obj = vreg_addr->AsMirrorPtr();
    375   return (obj != nullptr) && obj->InstanceOf(c);
    376 }
    377 
    378 extern "C" size_t MterpFillArrayData(mirror::Object* obj, const Instruction::ArrayDataPayload* payload)
    379     REQUIRES_SHARED(Locks::mutator_lock_) {
    380   return FillArrayData(obj, payload);
    381 }
    382 
    383 extern "C" size_t MterpNewInstance(ShadowFrame* shadow_frame, Thread* self, uint32_t inst_data)
    384     REQUIRES_SHARED(Locks::mutator_lock_) {
    385   const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
    386   mirror::Object* obj = nullptr;
    387   mirror::Class* c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
    388                                             shadow_frame->GetMethod(),
    389                                             self,
    390                                             false,
    391                                             false);
    392   if (LIKELY(c != nullptr)) {
    393     if (UNLIKELY(c->IsStringClass())) {
    394       gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
    395       obj = mirror::String::AllocEmptyString<true>(self, allocator_type);
    396     } else {
    397       obj = AllocObjectFromCode<true>(c,
    398                                       self,
    399                                       Runtime::Current()->GetHeap()->GetCurrentAllocator());
    400     }
    401   }
    402   if (UNLIKELY(obj == nullptr)) {
    403     return false;
    404   }
    405   obj->GetClass()->AssertInitializedOrInitializingInThread(self);
    406   shadow_frame->SetVRegReference(inst->VRegA_21c(inst_data), obj);
    407   return true;
    408 }
    409 
    410 extern "C" size_t MterpSputObject(ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr,
    411                                 uint32_t inst_data, Thread* self)
    412     REQUIRES_SHARED(Locks::mutator_lock_) {
    413   const Instruction* inst = Instruction::At(dex_pc_ptr);
    414   return DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, false, false>
    415       (self, *shadow_frame, inst, inst_data);
    416 }
    417 
    418 extern "C" size_t MterpIputObject(ShadowFrame* shadow_frame,
    419                                   uint16_t* dex_pc_ptr,
    420                                   uint32_t inst_data,
    421                                   Thread* self)
    422     REQUIRES_SHARED(Locks::mutator_lock_) {
    423   const Instruction* inst = Instruction::At(dex_pc_ptr);
    424   return DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, false, false>
    425       (self, *shadow_frame, inst, inst_data);
    426 }
    427 
    428 extern "C" size_t MterpIputObjectQuick(ShadowFrame* shadow_frame,
    429                                        uint16_t* dex_pc_ptr,
    430                                        uint32_t inst_data)
    431     REQUIRES_SHARED(Locks::mutator_lock_) {
    432   const Instruction* inst = Instruction::At(dex_pc_ptr);
    433   return DoIPutQuick<Primitive::kPrimNot, false>(*shadow_frame, inst, inst_data);
    434 }
    435 
    436 extern "C" size_t MterpAputObject(ShadowFrame* shadow_frame,
    437                                   uint16_t* dex_pc_ptr,
    438                                   uint32_t inst_data)
    439     REQUIRES_SHARED(Locks::mutator_lock_) {
    440   const Instruction* inst = Instruction::At(dex_pc_ptr);
    441   mirror::Object* a = shadow_frame->GetVRegReference(inst->VRegB_23x());
    442   if (UNLIKELY(a == nullptr)) {
    443     return false;
    444   }
    445   int32_t index = shadow_frame->GetVReg(inst->VRegC_23x());
    446   mirror::Object* val = shadow_frame->GetVRegReference(inst->VRegA_23x(inst_data));
    447   mirror::ObjectArray<mirror::Object>* array = a->AsObjectArray<mirror::Object>();
    448   if (array->CheckIsValidIndex(index) && array->CheckAssignable(val)) {
    449     array->SetWithoutChecks<false>(index, val);
    450     return true;
    451   }
    452   return false;
    453 }
    454 
    455 extern "C" size_t MterpFilledNewArray(ShadowFrame* shadow_frame,
    456                                       uint16_t* dex_pc_ptr,
    457                                       Thread* self)
    458     REQUIRES_SHARED(Locks::mutator_lock_) {
    459   const Instruction* inst = Instruction::At(dex_pc_ptr);
    460   return DoFilledNewArray<false, false, false>(inst, *shadow_frame, self,
    461                                                shadow_frame->GetResultRegister());
    462 }
    463 
    464 extern "C" size_t MterpFilledNewArrayRange(ShadowFrame* shadow_frame,
    465                                            uint16_t* dex_pc_ptr,
    466                                            Thread* self)
    467     REQUIRES_SHARED(Locks::mutator_lock_) {
    468   const Instruction* inst = Instruction::At(dex_pc_ptr);
    469   return DoFilledNewArray<true, false, false>(inst, *shadow_frame, self,
    470                                               shadow_frame->GetResultRegister());
    471 }
    472 
    473 extern "C" size_t MterpNewArray(ShadowFrame* shadow_frame,
    474                                 uint16_t* dex_pc_ptr,
    475                                 uint32_t inst_data, Thread* self)
    476     REQUIRES_SHARED(Locks::mutator_lock_) {
    477   const Instruction* inst = Instruction::At(dex_pc_ptr);
    478   int32_t length = shadow_frame->GetVReg(inst->VRegB_22c(inst_data));
    479   mirror::Object* obj = AllocArrayFromCode<false, true>(
    480       dex::TypeIndex(inst->VRegC_22c()), length, shadow_frame->GetMethod(), self,
    481       Runtime::Current()->GetHeap()->GetCurrentAllocator());
    482   if (UNLIKELY(obj == nullptr)) {
    483       return false;
    484   }
    485   shadow_frame->SetVRegReference(inst->VRegA_22c(inst_data), obj);
    486   return true;
    487 }
    488 
    489 extern "C" size_t MterpHandleException(Thread* self, ShadowFrame* shadow_frame)
    490     REQUIRES_SHARED(Locks::mutator_lock_) {
    491   DCHECK(self->IsExceptionPending());
    492   const instrumentation::Instrumentation* const instrumentation =
    493       Runtime::Current()->GetInstrumentation();
    494   uint32_t found_dex_pc = FindNextInstructionFollowingException(self, *shadow_frame,
    495                                                                 shadow_frame->GetDexPC(),
    496                                                                 instrumentation);
    497   if (found_dex_pc == DexFile::kDexNoIndex) {
    498     return false;
    499   }
    500   // OK - we can deal with it.  Update and continue.
    501   shadow_frame->SetDexPC(found_dex_pc);
    502   return true;
    503 }
    504 
    505 extern "C" void MterpCheckBefore(Thread* self, ShadowFrame* shadow_frame, uint16_t* dex_pc_ptr)
    506     REQUIRES_SHARED(Locks::mutator_lock_) {
    507   const Instruction* inst = Instruction::At(dex_pc_ptr);
    508   uint16_t inst_data = inst->Fetch16(0);
    509   if (inst->Opcode(inst_data) == Instruction::MOVE_EXCEPTION) {
    510     self->AssertPendingException();
    511   } else {
    512     self->AssertNoPendingException();
    513   }
    514   if (kTraceExecutionEnabled) {
    515     uint32_t dex_pc = dex_pc_ptr - shadow_frame->GetCodeItem()->insns_;
    516     TraceExecution(*shadow_frame, inst, dex_pc);
    517   }
    518   if (kTestExportPC) {
    519     // Save invalid dex pc to force segfault if improperly used.
    520     shadow_frame->SetDexPCPtr(reinterpret_cast<uint16_t*>(kExportPCPoison));
    521   }
    522 }
    523 
    524 extern "C" void MterpLogDivideByZeroException(Thread* self, ShadowFrame* shadow_frame)
    525     REQUIRES_SHARED(Locks::mutator_lock_) {
    526   UNUSED(self);
    527   const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
    528   uint16_t inst_data = inst->Fetch16(0);
    529   LOG(INFO) << "DivideByZero: " << inst->Opcode(inst_data);
    530 }
    531 
    532 extern "C" void MterpLogArrayIndexException(Thread* self, ShadowFrame* shadow_frame)
    533     REQUIRES_SHARED(Locks::mutator_lock_) {
    534   UNUSED(self);
    535   const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
    536   uint16_t inst_data = inst->Fetch16(0);
    537   LOG(INFO) << "ArrayIndex: " << inst->Opcode(inst_data);
    538 }
    539 
    540 extern "C" void MterpLogNegativeArraySizeException(Thread* self, ShadowFrame* shadow_frame)
    541     REQUIRES_SHARED(Locks::mutator_lock_) {
    542   UNUSED(self);
    543   const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
    544   uint16_t inst_data = inst->Fetch16(0);
    545   LOG(INFO) << "NegativeArraySize: " << inst->Opcode(inst_data);
    546 }
    547 
    548 extern "C" void MterpLogNoSuchMethodException(Thread* self, ShadowFrame* shadow_frame)
    549     REQUIRES_SHARED(Locks::mutator_lock_) {
    550   UNUSED(self);
    551   const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
    552   uint16_t inst_data = inst->Fetch16(0);
    553   LOG(INFO) << "NoSuchMethod: " << inst->Opcode(inst_data);
    554 }
    555 
    556 extern "C" void MterpLogExceptionThrownException(Thread* self, ShadowFrame* shadow_frame)
    557     REQUIRES_SHARED(Locks::mutator_lock_) {
    558   UNUSED(self);
    559   const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
    560   uint16_t inst_data = inst->Fetch16(0);
    561   LOG(INFO) << "ExceptionThrown: " << inst->Opcode(inst_data);
    562 }
    563 
    564 extern "C" void MterpLogNullObjectException(Thread* self, ShadowFrame* shadow_frame)
    565     REQUIRES_SHARED(Locks::mutator_lock_) {
    566   UNUSED(self);
    567   const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
    568   uint16_t inst_data = inst->Fetch16(0);
    569   LOG(INFO) << "NullObject: " << inst->Opcode(inst_data);
    570 }
    571 
    572 extern "C" void MterpLogFallback(Thread* self, ShadowFrame* shadow_frame)
    573     REQUIRES_SHARED(Locks::mutator_lock_) {
    574   UNUSED(self);
    575   const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
    576   uint16_t inst_data = inst->Fetch16(0);
    577   LOG(INFO) << "Fallback: " << inst->Opcode(inst_data) << ", Suspend Pending?: "
    578             << self->IsExceptionPending();
    579 }
    580 
    581 extern "C" void MterpLogOSR(Thread* self, ShadowFrame* shadow_frame, int32_t offset)
    582     REQUIRES_SHARED(Locks::mutator_lock_) {
    583   UNUSED(self);
    584   const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
    585   uint16_t inst_data = inst->Fetch16(0);
    586   LOG(INFO) << "OSR: " << inst->Opcode(inst_data) << ", offset = " << offset;
    587 }
    588 
    589 extern "C" void MterpLogSuspendFallback(Thread* self, ShadowFrame* shadow_frame, uint32_t flags)
    590     REQUIRES_SHARED(Locks::mutator_lock_) {
    591   UNUSED(self);
    592   const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
    593   uint16_t inst_data = inst->Fetch16(0);
    594   if (flags & kCheckpointRequest) {
    595     LOG(INFO) << "Checkpoint fallback: " << inst->Opcode(inst_data);
    596   } else if (flags & kSuspendRequest) {
    597     LOG(INFO) << "Suspend fallback: " << inst->Opcode(inst_data);
    598   } else if (flags & kEmptyCheckpointRequest) {
    599     LOG(INFO) << "Empty checkpoint fallback: " << inst->Opcode(inst_data);
    600   }
    601 }
    602 
    603 extern "C" size_t MterpSuspendCheck(Thread* self)
    604     REQUIRES_SHARED(Locks::mutator_lock_) {
    605   self->AllowThreadSuspension();
    606   return MterpShouldSwitchInterpreters();
    607 }
    608 
    609 extern "C" ssize_t artSet8InstanceFromMterp(uint32_t field_idx,
    610                                             mirror::Object* obj,
    611                                             uint8_t new_value,
    612                                             ArtMethod* referrer)
    613     REQUIRES_SHARED(Locks::mutator_lock_) {
    614   ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(int8_t));
    615   if (LIKELY(field != nullptr && obj != nullptr)) {
    616     Primitive::Type type = field->GetTypeAsPrimitiveType();
    617     if (type == Primitive::kPrimBoolean) {
    618       field->SetBoolean<false>(obj, new_value);
    619     } else {
    620       DCHECK_EQ(Primitive::kPrimByte, type);
    621       field->SetByte<false>(obj, new_value);
    622     }
    623     return 0;  // success
    624   }
    625   return -1;  // failure
    626 }
    627 
    628 extern "C" ssize_t artSet16InstanceFromMterp(uint32_t field_idx,
    629                                              mirror::Object* obj,
    630                                              uint16_t new_value,
    631                                              ArtMethod* referrer)
    632     REQUIRES_SHARED(Locks::mutator_lock_) {
    633   ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
    634                                           sizeof(int16_t));
    635   if (LIKELY(field != nullptr && obj != nullptr)) {
    636     Primitive::Type type = field->GetTypeAsPrimitiveType();
    637     if (type == Primitive::kPrimChar) {
    638       field->SetChar<false>(obj, new_value);
    639     } else {
    640       DCHECK_EQ(Primitive::kPrimShort, type);
    641       field->SetShort<false>(obj, new_value);
    642     }
    643     return 0;  // success
    644   }
    645   return -1;  // failure
    646 }
    647 
    648 extern "C" ssize_t artSet32InstanceFromMterp(uint32_t field_idx,
    649                                              mirror::Object* obj,
    650                                              uint32_t new_value,
    651                                              ArtMethod* referrer)
    652     REQUIRES_SHARED(Locks::mutator_lock_) {
    653   ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
    654                                           sizeof(int32_t));
    655   if (LIKELY(field != nullptr && obj != nullptr)) {
    656     field->Set32<false>(obj, new_value);
    657     return 0;  // success
    658   }
    659   return -1;  // failure
    660 }
    661 
    662 extern "C" ssize_t artSet64InstanceFromMterp(uint32_t field_idx,
    663                                              mirror::Object* obj,
    664                                              uint64_t* new_value,
    665                                              ArtMethod* referrer)
    666     REQUIRES_SHARED(Locks::mutator_lock_) {
    667   ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
    668                                           sizeof(int64_t));
    669   if (LIKELY(field != nullptr  && obj != nullptr)) {
    670     field->Set64<false>(obj, *new_value);
    671     return 0;  // success
    672   }
    673   return -1;  // failure
    674 }
    675 
    676 extern "C" ssize_t artSetObjInstanceFromMterp(uint32_t field_idx,
    677                                               mirror::Object* obj,
    678                                               mirror::Object* new_value,
    679                                               ArtMethod* referrer)
    680     REQUIRES_SHARED(Locks::mutator_lock_) {
    681   ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite,
    682                                           sizeof(mirror::HeapReference<mirror::Object>));
    683   if (LIKELY(field != nullptr && obj != nullptr)) {
    684     field->SetObj<false>(obj, new_value);
    685     return 0;  // success
    686   }
    687   return -1;  // failure
    688 }
    689 
    690 template <typename return_type, Primitive::Type primitive_type>
    691 ALWAYS_INLINE return_type MterpGetStatic(uint32_t field_idx,
    692                                          ArtMethod* referrer,
    693                                          Thread* self,
    694                                          return_type (ArtField::*func)(ObjPtr<mirror::Object>))
    695     REQUIRES_SHARED(Locks::mutator_lock_) {
    696   return_type res = 0;  // On exception, the result will be ignored.
    697   ArtField* f =
    698       FindFieldFromCode<StaticPrimitiveRead, false>(field_idx,
    699                                                     referrer,
    700                                                     self,
    701                                                     primitive_type);
    702   if (LIKELY(f != nullptr)) {
    703     ObjPtr<mirror::Object> obj = f->GetDeclaringClass();
    704     res = (f->*func)(obj);
    705   }
    706   return res;
    707 }
    708 
    709 extern "C" int32_t MterpGetBooleanStatic(uint32_t field_idx,
    710                                          ArtMethod* referrer,
    711                                          Thread* self)
    712     REQUIRES_SHARED(Locks::mutator_lock_) {
    713   return MterpGetStatic<uint8_t, Primitive::kPrimBoolean>(field_idx,
    714                                                           referrer,
    715                                                           self,
    716                                                           &ArtField::GetBoolean);
    717 }
    718 
    719 extern "C" int32_t MterpGetByteStatic(uint32_t field_idx,
    720                                       ArtMethod* referrer,
    721                                       Thread* self)
    722     REQUIRES_SHARED(Locks::mutator_lock_) {
    723   return MterpGetStatic<int8_t, Primitive::kPrimByte>(field_idx,
    724                                                       referrer,
    725                                                       self,
    726                                                       &ArtField::GetByte);
    727 }
    728 
    729 extern "C" uint32_t MterpGetCharStatic(uint32_t field_idx,
    730                                        ArtMethod* referrer,
    731                                        Thread* self)
    732     REQUIRES_SHARED(Locks::mutator_lock_) {
    733   return MterpGetStatic<uint16_t, Primitive::kPrimChar>(field_idx,
    734                                                         referrer,
    735                                                         self,
    736                                                         &ArtField::GetChar);
    737 }
    738 
    739 extern "C" int32_t MterpGetShortStatic(uint32_t field_idx,
    740                                        ArtMethod* referrer,
    741                                        Thread* self)
    742     REQUIRES_SHARED(Locks::mutator_lock_) {
    743   return MterpGetStatic<int16_t, Primitive::kPrimShort>(field_idx,
    744                                                         referrer,
    745                                                         self,
    746                                                         &ArtField::GetShort);
    747 }
    748 
    749 extern "C" mirror::Object* MterpGetObjStatic(uint32_t field_idx,
    750                                              ArtMethod* referrer,
    751                                              Thread* self)
    752     REQUIRES_SHARED(Locks::mutator_lock_) {
    753   return MterpGetStatic<ObjPtr<mirror::Object>, Primitive::kPrimNot>(field_idx,
    754                                                                      referrer,
    755                                                                      self,
    756                                                                      &ArtField::GetObject).Ptr();
    757 }
    758 
    759 extern "C" int32_t MterpGet32Static(uint32_t field_idx,
    760                                     ArtMethod* referrer,
    761                                     Thread* self)
    762     REQUIRES_SHARED(Locks::mutator_lock_) {
    763   return MterpGetStatic<int32_t, Primitive::kPrimInt>(field_idx,
    764                                                       referrer,
    765                                                       self,
    766                                                       &ArtField::GetInt);
    767 }
    768 
    769 extern "C" int64_t MterpGet64Static(uint32_t field_idx, ArtMethod* referrer, Thread* self)
    770     REQUIRES_SHARED(Locks::mutator_lock_) {
    771   return MterpGetStatic<int64_t, Primitive::kPrimLong>(field_idx,
    772                                                        referrer,
    773                                                        self,
    774                                                        &ArtField::GetLong);
    775 }
    776 
    777 
    778 template <typename field_type, Primitive::Type primitive_type>
    779 int MterpSetStatic(uint32_t field_idx,
    780                    field_type new_value,
    781                    ArtMethod* referrer,
    782                    Thread* self,
    783                    void (ArtField::*func)(ObjPtr<mirror::Object>, field_type val))
    784     REQUIRES_SHARED(Locks::mutator_lock_) {
    785   int res = 0;  // Assume success (following quick_field_entrypoints conventions)
    786   ArtField* f =
    787       FindFieldFromCode<StaticPrimitiveWrite, false>(field_idx, referrer, self, primitive_type);
    788   if (LIKELY(f != nullptr)) {
    789     ObjPtr<mirror::Object> obj = f->GetDeclaringClass();
    790     (f->*func)(obj, new_value);
    791   } else {
    792     res = -1;  // Failure
    793   }
    794   return res;
    795 }
    796 
    797 extern "C" int MterpSetBooleanStatic(uint32_t field_idx,
    798                                      uint8_t new_value,
    799                                      ArtMethod* referrer,
    800                                      Thread* self)
    801     REQUIRES_SHARED(Locks::mutator_lock_) {
    802   return MterpSetStatic<uint8_t, Primitive::kPrimBoolean>(field_idx,
    803                                                           new_value,
    804                                                           referrer,
    805                                                           self,
    806                                                           &ArtField::SetBoolean<false>);
    807 }
    808 
    809 extern "C" int MterpSetByteStatic(uint32_t field_idx,
    810                                   int8_t new_value,
    811                                   ArtMethod* referrer,
    812                                   Thread* self)
    813     REQUIRES_SHARED(Locks::mutator_lock_) {
    814   return MterpSetStatic<int8_t, Primitive::kPrimByte>(field_idx,
    815                                                       new_value,
    816                                                       referrer,
    817                                                       self,
    818                                                       &ArtField::SetByte<false>);
    819 }
    820 
    821 extern "C" int MterpSetCharStatic(uint32_t field_idx,
    822                                   uint16_t new_value,
    823                                   ArtMethod* referrer,
    824                                   Thread* self)
    825     REQUIRES_SHARED(Locks::mutator_lock_) {
    826   return MterpSetStatic<uint16_t, Primitive::kPrimChar>(field_idx,
    827                                                         new_value,
    828                                                         referrer,
    829                                                         self,
    830                                                         &ArtField::SetChar<false>);
    831 }
    832 
    833 extern "C" int MterpSetShortStatic(uint32_t field_idx,
    834                                    int16_t new_value,
    835                                    ArtMethod* referrer,
    836                                    Thread* self)
    837     REQUIRES_SHARED(Locks::mutator_lock_) {
    838   return MterpSetStatic<int16_t, Primitive::kPrimShort>(field_idx,
    839                                                         new_value,
    840                                                         referrer,
    841                                                         self,
    842                                                         &ArtField::SetShort<false>);
    843 }
    844 
    845 extern "C" int MterpSet32Static(uint32_t field_idx,
    846                                 int32_t new_value,
    847                                 ArtMethod* referrer,
    848                                 Thread* self)
    849     REQUIRES_SHARED(Locks::mutator_lock_) {
    850   return MterpSetStatic<int32_t, Primitive::kPrimInt>(field_idx,
    851                                                       new_value,
    852                                                       referrer,
    853                                                       self,
    854                                                       &ArtField::SetInt<false>);
    855 }
    856 
    857 extern "C" int MterpSet64Static(uint32_t field_idx,
    858                                 int64_t* new_value,
    859                                 ArtMethod* referrer,
    860                                 Thread* self)
    861     REQUIRES_SHARED(Locks::mutator_lock_) {
    862   return MterpSetStatic<int64_t, Primitive::kPrimLong>(field_idx,
    863                                                        *new_value,
    864                                                        referrer,
    865                                                        self,
    866                                                        &ArtField::SetLong<false>);
    867 }
    868 
    869 extern "C" mirror::Object* artAGetObjectFromMterp(mirror::Object* arr,
    870                                                   int32_t index)
    871     REQUIRES_SHARED(Locks::mutator_lock_) {
    872   if (UNLIKELY(arr == nullptr)) {
    873     ThrowNullPointerExceptionFromInterpreter();
    874     return nullptr;
    875   }
    876   mirror::ObjectArray<mirror::Object>* array = arr->AsObjectArray<mirror::Object>();
    877   if (LIKELY(array->CheckIsValidIndex(index))) {
    878     return array->GetWithoutChecks(index);
    879   } else {
    880     return nullptr;
    881   }
    882 }
    883 
    884 extern "C" mirror::Object* artIGetObjectFromMterp(mirror::Object* obj,
    885                                                   uint32_t field_offset)
    886     REQUIRES_SHARED(Locks::mutator_lock_) {
    887   if (UNLIKELY(obj == nullptr)) {
    888     ThrowNullPointerExceptionFromInterpreter();
    889     return nullptr;
    890   }
    891   return obj->GetFieldObject<mirror::Object>(MemberOffset(field_offset));
    892 }
    893 
    894 /*
    895  * Create a hotness_countdown based on the current method hotness_count and profiling
    896  * mode.  In short, determine how many hotness events we hit before reporting back
    897  * to the full instrumentation via MterpAddHotnessBatch.  Called once on entry to the method,
    898  * and regenerated following batch updates.
    899  */
    900 extern "C" ssize_t MterpSetUpHotnessCountdown(ArtMethod* method, ShadowFrame* shadow_frame)
    901     REQUIRES_SHARED(Locks::mutator_lock_) {
    902   uint16_t hotness_count = method->GetCounter();
    903   int32_t countdown_value = jit::kJitHotnessDisabled;
    904   jit::Jit* jit = Runtime::Current()->GetJit();
    905   if (jit != nullptr) {
    906     int32_t warm_threshold = jit->WarmMethodThreshold();
    907     int32_t hot_threshold = jit->HotMethodThreshold();
    908     int32_t osr_threshold = jit->OSRMethodThreshold();
    909     if (hotness_count < warm_threshold) {
    910       countdown_value = warm_threshold - hotness_count;
    911     } else if (hotness_count < hot_threshold) {
    912       countdown_value = hot_threshold - hotness_count;
    913     } else if (hotness_count < osr_threshold) {
    914       countdown_value = osr_threshold - hotness_count;
    915     } else {
    916       countdown_value = jit::kJitCheckForOSR;
    917     }
    918     if (jit::Jit::ShouldUsePriorityThreadWeight()) {
    919       int32_t priority_thread_weight = jit->PriorityThreadWeight();
    920       countdown_value = std::min(countdown_value, countdown_value / priority_thread_weight);
    921     }
    922   }
    923   /*
    924    * The actual hotness threshold may exceed the range of our int16_t countdown value.  This is
    925    * not a problem, though.  We can just break it down into smaller chunks.
    926    */
    927   countdown_value = std::min(countdown_value,
    928                              static_cast<int32_t>(std::numeric_limits<int16_t>::max()));
    929   shadow_frame->SetCachedHotnessCountdown(countdown_value);
    930   shadow_frame->SetHotnessCountdown(countdown_value);
    931   return countdown_value;
    932 }
    933 
    934 /*
    935  * Report a batch of hotness events to the instrumentation and then return the new
    936  * countdown value to the next time we should report.
    937  */
    938 extern "C" ssize_t MterpAddHotnessBatch(ArtMethod* method,
    939                                         ShadowFrame* shadow_frame,
    940                                         Thread* self)
    941     REQUIRES_SHARED(Locks::mutator_lock_) {
    942   jit::Jit* jit = Runtime::Current()->GetJit();
    943   if (jit != nullptr) {
    944     int16_t count = shadow_frame->GetCachedHotnessCountdown() - shadow_frame->GetHotnessCountdown();
    945     jit->AddSamples(self, method, count, /*with_backedges*/ true);
    946   }
    947   return MterpSetUpHotnessCountdown(method, shadow_frame);
    948 }
    949 
    950 extern "C" size_t MterpMaybeDoOnStackReplacement(Thread* self,
    951                                                  ShadowFrame* shadow_frame,
    952                                                  int32_t offset)
    953     REQUIRES_SHARED(Locks::mutator_lock_) {
    954   int16_t osr_countdown = shadow_frame->GetCachedHotnessCountdown() - 1;
    955   bool did_osr = false;
    956   /*
    957    * To reduce the cost of polling the compiler to determine whether the requested OSR
    958    * compilation has completed, only check every Nth time.  NOTE: the "osr_countdown <= 0"
    959    * condition is satisfied either by the decrement below or the initial setting of
    960    * the cached countdown field to kJitCheckForOSR, which elsewhere is asserted to be -1.
    961    */
    962   if (osr_countdown <= 0) {
    963     ArtMethod* method = shadow_frame->GetMethod();
    964     JValue* result = shadow_frame->GetResultRegister();
    965     uint32_t dex_pc = shadow_frame->GetDexPC();
    966     jit::Jit* jit = Runtime::Current()->GetJit();
    967     osr_countdown = jit::Jit::kJitRecheckOSRThreshold;
    968     if (offset <= 0) {
    969       // Keep updating hotness in case a compilation request was dropped.  Eventually it will retry.
    970       jit->AddSamples(self, method, osr_countdown, /*with_backedges*/ true);
    971     }
    972     did_osr = jit::Jit::MaybeDoOnStackReplacement(self, method, dex_pc, offset, result);
    973   }
    974   shadow_frame->SetCachedHotnessCountdown(osr_countdown);
    975   return did_osr;
    976 }
    977 
    978 }  // namespace interpreter
    979 }  // namespace art
    980