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