xref: /aosp_15_r20/art/runtime/interpreter/mterp/nterp.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2019 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker /*
18*795d594fSAndroid Build Coastguard Worker  * Mterp entry point and support functions.
19*795d594fSAndroid Build Coastguard Worker  */
20*795d594fSAndroid Build Coastguard Worker #include "nterp.h"
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker #include "arch/instruction_set.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/quasi_atomic.h"
24*795d594fSAndroid Build Coastguard Worker #include "class_linker-inl.h"
25*795d594fSAndroid Build Coastguard Worker #include "dex/dex_instruction_utils.h"
26*795d594fSAndroid Build Coastguard Worker #include "debugger.h"
27*795d594fSAndroid Build Coastguard Worker #include "entrypoints/entrypoint_utils-inl.h"
28*795d594fSAndroid Build Coastguard Worker #include "interpreter/interpreter_cache-inl.h"
29*795d594fSAndroid Build Coastguard Worker #include "interpreter/interpreter_common.h"
30*795d594fSAndroid Build Coastguard Worker #include "interpreter/shadow_frame-inl.h"
31*795d594fSAndroid Build Coastguard Worker #include "mirror/string-alloc-inl.h"
32*795d594fSAndroid Build Coastguard Worker #include "nterp_helpers.h"
33*795d594fSAndroid Build Coastguard Worker 
34*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
35*795d594fSAndroid Build Coastguard Worker namespace interpreter {
36*795d594fSAndroid Build Coastguard Worker 
IsNterpSupported()37*795d594fSAndroid Build Coastguard Worker bool IsNterpSupported() {
38*795d594fSAndroid Build Coastguard Worker   switch (kRuntimeQuickCodeISA) {
39*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kArm:
40*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kThumb2:
41*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kArm64:
42*795d594fSAndroid Build Coastguard Worker       return kReserveMarkingRegister && !kUseTableLookupReadBarrier;
43*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kRiscv64:
44*795d594fSAndroid Build Coastguard Worker       return true;
45*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kX86:
46*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kX86_64:
47*795d594fSAndroid Build Coastguard Worker       return !kUseTableLookupReadBarrier;
48*795d594fSAndroid Build Coastguard Worker     default:
49*795d594fSAndroid Build Coastguard Worker       return false;
50*795d594fSAndroid Build Coastguard Worker   }
51*795d594fSAndroid Build Coastguard Worker }
52*795d594fSAndroid Build Coastguard Worker 
CanRuntimeUseNterp()53*795d594fSAndroid Build Coastguard Worker bool CanRuntimeUseNterp() REQUIRES_SHARED(Locks::mutator_lock_) {
54*795d594fSAndroid Build Coastguard Worker   Runtime* runtime = Runtime::Current();
55*795d594fSAndroid Build Coastguard Worker   instrumentation::Instrumentation* instr = runtime->GetInstrumentation();
56*795d594fSAndroid Build Coastguard Worker   // If the runtime is interpreter only, we currently don't use nterp as some
57*795d594fSAndroid Build Coastguard Worker   // parts of the runtime (like instrumentation) make assumption on an
58*795d594fSAndroid Build Coastguard Worker   // interpreter-only runtime to always be in a switch-like interpreter.
59*795d594fSAndroid Build Coastguard Worker   return IsNterpSupported() && !runtime->IsJavaDebuggable() && !instr->EntryExitStubsInstalled() &&
60*795d594fSAndroid Build Coastguard Worker          !instr->InterpretOnly() && !runtime->IsAotCompiler() &&
61*795d594fSAndroid Build Coastguard Worker          !instr->NeedsSlowInterpreterForListeners() &&
62*795d594fSAndroid Build Coastguard Worker          // An async exception has been thrown. We need to go to the switch interpreter. nterp
63*795d594fSAndroid Build Coastguard Worker          // doesn't know how to deal with these so we could end up never dealing with it if we are
64*795d594fSAndroid Build Coastguard Worker          // in an infinite loop.
65*795d594fSAndroid Build Coastguard Worker          !runtime->AreAsyncExceptionsThrown() &&
66*795d594fSAndroid Build Coastguard Worker          (runtime->GetJit() == nullptr || !runtime->GetJit()->JitAtFirstUse());
67*795d594fSAndroid Build Coastguard Worker }
68*795d594fSAndroid Build Coastguard Worker 
69*795d594fSAndroid Build Coastguard Worker // The entrypoint for nterp, which ArtMethods can directly point to.
70*795d594fSAndroid Build Coastguard Worker extern "C" void ExecuteNterpImpl() REQUIRES_SHARED(Locks::mutator_lock_);
71*795d594fSAndroid Build Coastguard Worker extern "C" void EndExecuteNterpImpl() REQUIRES_SHARED(Locks::mutator_lock_);
72*795d594fSAndroid Build Coastguard Worker 
GetNterpEntryPoint()73*795d594fSAndroid Build Coastguard Worker const void* GetNterpEntryPoint() {
74*795d594fSAndroid Build Coastguard Worker   return reinterpret_cast<const void*>(interpreter::ExecuteNterpImpl);
75*795d594fSAndroid Build Coastguard Worker }
76*795d594fSAndroid Build Coastguard Worker 
NterpImpl()77*795d594fSAndroid Build Coastguard Worker ArrayRef<const uint8_t> NterpImpl() {
78*795d594fSAndroid Build Coastguard Worker   const uint8_t* entry_point = reinterpret_cast<const uint8_t*>(ExecuteNterpImpl);
79*795d594fSAndroid Build Coastguard Worker   size_t size = reinterpret_cast<const uint8_t*>(EndExecuteNterpImpl) - entry_point;
80*795d594fSAndroid Build Coastguard Worker   const uint8_t* code = reinterpret_cast<const uint8_t*>(EntryPointToCodePointer(entry_point));
81*795d594fSAndroid Build Coastguard Worker   return ArrayRef<const uint8_t>(code, size);
82*795d594fSAndroid Build Coastguard Worker }
83*795d594fSAndroid Build Coastguard Worker 
84*795d594fSAndroid Build Coastguard Worker // Another entrypoint, which does a clinit check at entry.
85*795d594fSAndroid Build Coastguard Worker extern "C" void ExecuteNterpWithClinitImpl() REQUIRES_SHARED(Locks::mutator_lock_);
86*795d594fSAndroid Build Coastguard Worker extern "C" void EndExecuteNterpWithClinitImpl() REQUIRES_SHARED(Locks::mutator_lock_);
87*795d594fSAndroid Build Coastguard Worker 
GetNterpWithClinitEntryPoint()88*795d594fSAndroid Build Coastguard Worker const void* GetNterpWithClinitEntryPoint() {
89*795d594fSAndroid Build Coastguard Worker   return reinterpret_cast<const void*>(interpreter::ExecuteNterpWithClinitImpl);
90*795d594fSAndroid Build Coastguard Worker }
91*795d594fSAndroid Build Coastguard Worker 
NterpWithClinitImpl()92*795d594fSAndroid Build Coastguard Worker ArrayRef<const uint8_t> NterpWithClinitImpl() {
93*795d594fSAndroid Build Coastguard Worker   const uint8_t* entry_point = reinterpret_cast<const uint8_t*>(ExecuteNterpWithClinitImpl);
94*795d594fSAndroid Build Coastguard Worker   size_t size = reinterpret_cast<const uint8_t*>(EndExecuteNterpWithClinitImpl) - entry_point;
95*795d594fSAndroid Build Coastguard Worker   const uint8_t* code = reinterpret_cast<const uint8_t*>(EntryPointToCodePointer(entry_point));
96*795d594fSAndroid Build Coastguard Worker   return ArrayRef<const uint8_t>(code, size);
97*795d594fSAndroid Build Coastguard Worker }
98*795d594fSAndroid Build Coastguard Worker 
99*795d594fSAndroid Build Coastguard Worker /*
100*795d594fSAndroid Build Coastguard Worker  * Verify some constants used by the nterp interpreter.
101*795d594fSAndroid Build Coastguard Worker  */
CheckNterpAsmConstants()102*795d594fSAndroid Build Coastguard Worker void CheckNterpAsmConstants() {
103*795d594fSAndroid Build Coastguard Worker   /*
104*795d594fSAndroid Build Coastguard Worker    * If we're using computed goto instruction transitions, make sure
105*795d594fSAndroid Build Coastguard Worker    * none of the handlers overflows the byte limit.  This won't tell
106*795d594fSAndroid Build Coastguard Worker    * which one did, but if any one is too big the total size will
107*795d594fSAndroid Build Coastguard Worker    * overflow.
108*795d594fSAndroid Build Coastguard Worker    */
109*795d594fSAndroid Build Coastguard Worker   constexpr size_t width = kNterpHandlerSize;
110*795d594fSAndroid Build Coastguard Worker   ptrdiff_t interp_size = reinterpret_cast<uintptr_t>(artNterpAsmInstructionEnd) -
111*795d594fSAndroid Build Coastguard Worker                           reinterpret_cast<uintptr_t>(artNterpAsmInstructionStart);
112*795d594fSAndroid Build Coastguard Worker   static_assert(kNumPackedOpcodes * width != 0);
113*795d594fSAndroid Build Coastguard Worker   if (interp_size != kNumPackedOpcodes * width) {
114*795d594fSAndroid Build Coastguard Worker     LOG(FATAL) << "ERROR: unexpected asm interp size " << interp_size
115*795d594fSAndroid Build Coastguard Worker                << "(did an instruction handler exceed " << width << " bytes?)";
116*795d594fSAndroid Build Coastguard Worker   }
117*795d594fSAndroid Build Coastguard Worker }
118*795d594fSAndroid Build Coastguard Worker 
UpdateHotness(ArtMethod * method)119*795d594fSAndroid Build Coastguard Worker inline void UpdateHotness(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
120*795d594fSAndroid Build Coastguard Worker   // The hotness we will add to a method when we perform a
121*795d594fSAndroid Build Coastguard Worker   // field/method/class/string lookup.
122*795d594fSAndroid Build Coastguard Worker   method->UpdateCounter(0xf);
123*795d594fSAndroid Build Coastguard Worker }
124*795d594fSAndroid Build Coastguard Worker 
125*795d594fSAndroid Build Coastguard Worker template<typename T>
UpdateCache(Thread * self,const uint16_t * dex_pc_ptr,T value)126*795d594fSAndroid Build Coastguard Worker inline void UpdateCache(Thread* self, const uint16_t* dex_pc_ptr, T value) {
127*795d594fSAndroid Build Coastguard Worker   self->GetInterpreterCache()->Set(self, dex_pc_ptr, value);
128*795d594fSAndroid Build Coastguard Worker }
129*795d594fSAndroid Build Coastguard Worker 
130*795d594fSAndroid Build Coastguard Worker template<typename T>
UpdateCache(Thread * self,const uint16_t * dex_pc_ptr,T * value)131*795d594fSAndroid Build Coastguard Worker inline void UpdateCache(Thread* self, const uint16_t* dex_pc_ptr, T* value) {
132*795d594fSAndroid Build Coastguard Worker   UpdateCache(self, dex_pc_ptr, reinterpret_cast<size_t>(value));
133*795d594fSAndroid Build Coastguard Worker }
134*795d594fSAndroid Build Coastguard Worker 
135*795d594fSAndroid Build Coastguard Worker #ifdef __arm__
136*795d594fSAndroid Build Coastguard Worker 
NterpStoreArm32Fprs(const char * shorty,uint32_t * registers,uint32_t * stack_args,const uint32_t * fprs)137*795d594fSAndroid Build Coastguard Worker extern "C" void NterpStoreArm32Fprs(const char* shorty,
138*795d594fSAndroid Build Coastguard Worker                                     uint32_t* registers,
139*795d594fSAndroid Build Coastguard Worker                                     uint32_t* stack_args,
140*795d594fSAndroid Build Coastguard Worker                                     const uint32_t* fprs) {
141*795d594fSAndroid Build Coastguard Worker   // Note `shorty` has already the returned type removed.
142*795d594fSAndroid Build Coastguard Worker   ScopedAssertNoThreadSuspension sants("In nterp");
143*795d594fSAndroid Build Coastguard Worker   uint32_t arg_index = 0;
144*795d594fSAndroid Build Coastguard Worker   uint32_t fpr_double_index = 0;
145*795d594fSAndroid Build Coastguard Worker   uint32_t fpr_index = 0;
146*795d594fSAndroid Build Coastguard Worker   for (uint32_t shorty_index = 0; shorty[shorty_index] != '\0'; ++shorty_index) {
147*795d594fSAndroid Build Coastguard Worker     char arg_type = shorty[shorty_index];
148*795d594fSAndroid Build Coastguard Worker     switch (arg_type) {
149*795d594fSAndroid Build Coastguard Worker       case 'D': {
150*795d594fSAndroid Build Coastguard Worker         // Double should not overlap with float.
151*795d594fSAndroid Build Coastguard Worker         fpr_double_index = std::max(fpr_double_index, RoundUp(fpr_index, 2));
152*795d594fSAndroid Build Coastguard Worker         if (fpr_double_index < 16) {
153*795d594fSAndroid Build Coastguard Worker           registers[arg_index] = fprs[fpr_double_index++];
154*795d594fSAndroid Build Coastguard Worker           registers[arg_index + 1] = fprs[fpr_double_index++];
155*795d594fSAndroid Build Coastguard Worker         } else {
156*795d594fSAndroid Build Coastguard Worker           registers[arg_index] = stack_args[arg_index];
157*795d594fSAndroid Build Coastguard Worker           registers[arg_index + 1] = stack_args[arg_index + 1];
158*795d594fSAndroid Build Coastguard Worker         }
159*795d594fSAndroid Build Coastguard Worker         arg_index += 2;
160*795d594fSAndroid Build Coastguard Worker         break;
161*795d594fSAndroid Build Coastguard Worker       }
162*795d594fSAndroid Build Coastguard Worker       case 'F': {
163*795d594fSAndroid Build Coastguard Worker         if (fpr_index % 2 == 0) {
164*795d594fSAndroid Build Coastguard Worker           fpr_index = std::max(fpr_double_index, fpr_index);
165*795d594fSAndroid Build Coastguard Worker         }
166*795d594fSAndroid Build Coastguard Worker         if (fpr_index < 16) {
167*795d594fSAndroid Build Coastguard Worker           registers[arg_index] = fprs[fpr_index++];
168*795d594fSAndroid Build Coastguard Worker         } else {
169*795d594fSAndroid Build Coastguard Worker           registers[arg_index] = stack_args[arg_index];
170*795d594fSAndroid Build Coastguard Worker         }
171*795d594fSAndroid Build Coastguard Worker         arg_index++;
172*795d594fSAndroid Build Coastguard Worker         break;
173*795d594fSAndroid Build Coastguard Worker       }
174*795d594fSAndroid Build Coastguard Worker       case 'J': {
175*795d594fSAndroid Build Coastguard Worker         arg_index += 2;
176*795d594fSAndroid Build Coastguard Worker         break;
177*795d594fSAndroid Build Coastguard Worker       }
178*795d594fSAndroid Build Coastguard Worker       default: {
179*795d594fSAndroid Build Coastguard Worker         arg_index++;
180*795d594fSAndroid Build Coastguard Worker         break;
181*795d594fSAndroid Build Coastguard Worker       }
182*795d594fSAndroid Build Coastguard Worker     }
183*795d594fSAndroid Build Coastguard Worker   }
184*795d594fSAndroid Build Coastguard Worker }
185*795d594fSAndroid Build Coastguard Worker 
NterpSetupArm32Fprs(const char * shorty,uint32_t dex_register,uint32_t stack_index,uint32_t * fprs,uint32_t * registers,uint32_t * stack_args)186*795d594fSAndroid Build Coastguard Worker extern "C" void NterpSetupArm32Fprs(const char* shorty,
187*795d594fSAndroid Build Coastguard Worker                                     uint32_t dex_register,
188*795d594fSAndroid Build Coastguard Worker                                     uint32_t stack_index,
189*795d594fSAndroid Build Coastguard Worker                                     uint32_t* fprs,
190*795d594fSAndroid Build Coastguard Worker                                     uint32_t* registers,
191*795d594fSAndroid Build Coastguard Worker                                     uint32_t* stack_args) {
192*795d594fSAndroid Build Coastguard Worker   // Note `shorty` has already the returned type removed.
193*795d594fSAndroid Build Coastguard Worker   ScopedAssertNoThreadSuspension sants("In nterp");
194*795d594fSAndroid Build Coastguard Worker   uint32_t fpr_double_index = 0;
195*795d594fSAndroid Build Coastguard Worker   uint32_t fpr_index = 0;
196*795d594fSAndroid Build Coastguard Worker   for (uint32_t shorty_index = 0; shorty[shorty_index] != '\0'; ++shorty_index) {
197*795d594fSAndroid Build Coastguard Worker     char arg_type = shorty[shorty_index];
198*795d594fSAndroid Build Coastguard Worker     switch (arg_type) {
199*795d594fSAndroid Build Coastguard Worker       case 'D': {
200*795d594fSAndroid Build Coastguard Worker         // Double should not overlap with float.
201*795d594fSAndroid Build Coastguard Worker         fpr_double_index = std::max(fpr_double_index, RoundUp(fpr_index, 2));
202*795d594fSAndroid Build Coastguard Worker         if (fpr_double_index < 16) {
203*795d594fSAndroid Build Coastguard Worker           fprs[fpr_double_index++] = registers[dex_register++];
204*795d594fSAndroid Build Coastguard Worker           fprs[fpr_double_index++] = registers[dex_register++];
205*795d594fSAndroid Build Coastguard Worker           stack_index += 2;
206*795d594fSAndroid Build Coastguard Worker         } else {
207*795d594fSAndroid Build Coastguard Worker           stack_args[stack_index++] = registers[dex_register++];
208*795d594fSAndroid Build Coastguard Worker           stack_args[stack_index++] = registers[dex_register++];
209*795d594fSAndroid Build Coastguard Worker         }
210*795d594fSAndroid Build Coastguard Worker         break;
211*795d594fSAndroid Build Coastguard Worker       }
212*795d594fSAndroid Build Coastguard Worker       case 'F': {
213*795d594fSAndroid Build Coastguard Worker         if (fpr_index % 2 == 0) {
214*795d594fSAndroid Build Coastguard Worker           fpr_index = std::max(fpr_double_index, fpr_index);
215*795d594fSAndroid Build Coastguard Worker         }
216*795d594fSAndroid Build Coastguard Worker         if (fpr_index < 16) {
217*795d594fSAndroid Build Coastguard Worker           fprs[fpr_index++] = registers[dex_register++];
218*795d594fSAndroid Build Coastguard Worker           stack_index++;
219*795d594fSAndroid Build Coastguard Worker         } else {
220*795d594fSAndroid Build Coastguard Worker           stack_args[stack_index++] = registers[dex_register++];
221*795d594fSAndroid Build Coastguard Worker         }
222*795d594fSAndroid Build Coastguard Worker         break;
223*795d594fSAndroid Build Coastguard Worker       }
224*795d594fSAndroid Build Coastguard Worker       case 'J': {
225*795d594fSAndroid Build Coastguard Worker         stack_index += 2;
226*795d594fSAndroid Build Coastguard Worker         dex_register += 2;
227*795d594fSAndroid Build Coastguard Worker         break;
228*795d594fSAndroid Build Coastguard Worker       }
229*795d594fSAndroid Build Coastguard Worker       default: {
230*795d594fSAndroid Build Coastguard Worker         stack_index++;
231*795d594fSAndroid Build Coastguard Worker         dex_register++;
232*795d594fSAndroid Build Coastguard Worker         break;
233*795d594fSAndroid Build Coastguard Worker       }
234*795d594fSAndroid Build Coastguard Worker     }
235*795d594fSAndroid Build Coastguard Worker   }
236*795d594fSAndroid Build Coastguard Worker }
237*795d594fSAndroid Build Coastguard Worker 
238*795d594fSAndroid Build Coastguard Worker #endif
239*795d594fSAndroid Build Coastguard Worker 
NterpGetCodeItem(ArtMethod * method)240*795d594fSAndroid Build Coastguard Worker extern "C" const dex::CodeItem* NterpGetCodeItem(ArtMethod* method)
241*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
242*795d594fSAndroid Build Coastguard Worker   ScopedAssertNoThreadSuspension sants("In nterp");
243*795d594fSAndroid Build Coastguard Worker   return method->GetCodeItem();
244*795d594fSAndroid Build Coastguard Worker }
245*795d594fSAndroid Build Coastguard Worker 
NterpGetShorty(ArtMethod * method)246*795d594fSAndroid Build Coastguard Worker extern "C" const char* NterpGetShorty(ArtMethod* method)
247*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
248*795d594fSAndroid Build Coastguard Worker   ScopedAssertNoThreadSuspension sants("In nterp");
249*795d594fSAndroid Build Coastguard Worker   return method->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty();
250*795d594fSAndroid Build Coastguard Worker }
251*795d594fSAndroid Build Coastguard Worker 
NterpGetShortyFromMethodId(ArtMethod * caller,uint32_t method_index)252*795d594fSAndroid Build Coastguard Worker extern "C" const char* NterpGetShortyFromMethodId(ArtMethod* caller, uint32_t method_index)
253*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
254*795d594fSAndroid Build Coastguard Worker   ScopedAssertNoThreadSuspension sants("In nterp");
255*795d594fSAndroid Build Coastguard Worker   return caller->GetDexFile()->GetMethodShorty(method_index);
256*795d594fSAndroid Build Coastguard Worker }
257*795d594fSAndroid Build Coastguard Worker 
NterpGetShortyFromInvokePolymorphic(ArtMethod * caller,uint16_t * dex_pc_ptr)258*795d594fSAndroid Build Coastguard Worker extern "C" const char* NterpGetShortyFromInvokePolymorphic(ArtMethod* caller, uint16_t* dex_pc_ptr)
259*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
260*795d594fSAndroid Build Coastguard Worker   ScopedAssertNoThreadSuspension sants("In nterp");
261*795d594fSAndroid Build Coastguard Worker   const Instruction* inst = Instruction::At(dex_pc_ptr);
262*795d594fSAndroid Build Coastguard Worker   dex::ProtoIndex proto_idx(inst->Opcode() == Instruction::INVOKE_POLYMORPHIC
263*795d594fSAndroid Build Coastguard Worker       ? inst->VRegH_45cc()
264*795d594fSAndroid Build Coastguard Worker       : inst->VRegH_4rcc());
265*795d594fSAndroid Build Coastguard Worker   return caller->GetDexFile()->GetShorty(proto_idx);
266*795d594fSAndroid Build Coastguard Worker }
267*795d594fSAndroid Build Coastguard Worker 
NterpGetShortyFromInvokeCustom(ArtMethod * caller,uint16_t * dex_pc_ptr)268*795d594fSAndroid Build Coastguard Worker extern "C" const char* NterpGetShortyFromInvokeCustom(ArtMethod* caller, uint16_t* dex_pc_ptr)
269*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
270*795d594fSAndroid Build Coastguard Worker   ScopedAssertNoThreadSuspension sants("In nterp");
271*795d594fSAndroid Build Coastguard Worker   const Instruction* inst = Instruction::At(dex_pc_ptr);
272*795d594fSAndroid Build Coastguard Worker   uint16_t call_site_index = (inst->Opcode() == Instruction::INVOKE_CUSTOM
273*795d594fSAndroid Build Coastguard Worker       ? inst->VRegB_35c()
274*795d594fSAndroid Build Coastguard Worker       : inst->VRegB_3rc());
275*795d594fSAndroid Build Coastguard Worker   const DexFile* dex_file = caller->GetDexFile();
276*795d594fSAndroid Build Coastguard Worker   dex::ProtoIndex proto_idx = dex_file->GetProtoIndexForCallSite(call_site_index);
277*795d594fSAndroid Build Coastguard Worker   return dex_file->GetShorty(proto_idx);
278*795d594fSAndroid Build Coastguard Worker }
279*795d594fSAndroid Build Coastguard Worker 
280*795d594fSAndroid Build Coastguard Worker static constexpr uint8_t kInvalidInvokeType = 255u;
281*795d594fSAndroid Build Coastguard Worker static_assert(static_cast<uint8_t>(kMaxInvokeType) < kInvalidInvokeType);
282*795d594fSAndroid Build Coastguard Worker 
GetOpcodeInvokeType(uint8_t opcode)283*795d594fSAndroid Build Coastguard Worker static constexpr uint8_t GetOpcodeInvokeType(uint8_t opcode) {
284*795d594fSAndroid Build Coastguard Worker   switch (opcode) {
285*795d594fSAndroid Build Coastguard Worker     case Instruction::INVOKE_DIRECT:
286*795d594fSAndroid Build Coastguard Worker     case Instruction::INVOKE_DIRECT_RANGE:
287*795d594fSAndroid Build Coastguard Worker       return static_cast<uint8_t>(kDirect);
288*795d594fSAndroid Build Coastguard Worker     case Instruction::INVOKE_INTERFACE:
289*795d594fSAndroid Build Coastguard Worker     case Instruction::INVOKE_INTERFACE_RANGE:
290*795d594fSAndroid Build Coastguard Worker       return static_cast<uint8_t>(kInterface);
291*795d594fSAndroid Build Coastguard Worker     case Instruction::INVOKE_STATIC:
292*795d594fSAndroid Build Coastguard Worker     case Instruction::INVOKE_STATIC_RANGE:
293*795d594fSAndroid Build Coastguard Worker       return static_cast<uint8_t>(kStatic);
294*795d594fSAndroid Build Coastguard Worker     case Instruction::INVOKE_SUPER:
295*795d594fSAndroid Build Coastguard Worker     case Instruction::INVOKE_SUPER_RANGE:
296*795d594fSAndroid Build Coastguard Worker       return static_cast<uint8_t>(kSuper);
297*795d594fSAndroid Build Coastguard Worker     case Instruction::INVOKE_VIRTUAL:
298*795d594fSAndroid Build Coastguard Worker     case Instruction::INVOKE_VIRTUAL_RANGE:
299*795d594fSAndroid Build Coastguard Worker       return static_cast<uint8_t>(kVirtual);
300*795d594fSAndroid Build Coastguard Worker 
301*795d594fSAndroid Build Coastguard Worker     default:
302*795d594fSAndroid Build Coastguard Worker       return kInvalidInvokeType;
303*795d594fSAndroid Build Coastguard Worker   }
304*795d594fSAndroid Build Coastguard Worker }
305*795d594fSAndroid Build Coastguard Worker 
GenerateOpcodeInvokeTypes()306*795d594fSAndroid Build Coastguard Worker static constexpr std::array<uint8_t, 256u> GenerateOpcodeInvokeTypes() {
307*795d594fSAndroid Build Coastguard Worker   std::array<uint8_t, 256u> opcode_invoke_types{};
308*795d594fSAndroid Build Coastguard Worker   for (size_t opcode = 0u; opcode != opcode_invoke_types.size(); ++opcode) {
309*795d594fSAndroid Build Coastguard Worker     opcode_invoke_types[opcode] = GetOpcodeInvokeType(opcode);
310*795d594fSAndroid Build Coastguard Worker   }
311*795d594fSAndroid Build Coastguard Worker   return opcode_invoke_types;
312*795d594fSAndroid Build Coastguard Worker }
313*795d594fSAndroid Build Coastguard Worker 
314*795d594fSAndroid Build Coastguard Worker static constexpr std::array<uint8_t, 256u> kOpcodeInvokeTypes = GenerateOpcodeInvokeTypes();
315*795d594fSAndroid Build Coastguard Worker 
316*795d594fSAndroid Build Coastguard Worker LIBART_PROTECTED FLATTEN
NterpGetMethod(Thread * self,ArtMethod * caller,const uint16_t * dex_pc_ptr)317*795d594fSAndroid Build Coastguard Worker extern "C" size_t NterpGetMethod(Thread* self, ArtMethod* caller, const uint16_t* dex_pc_ptr)
318*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
319*795d594fSAndroid Build Coastguard Worker   UpdateHotness(caller);
320*795d594fSAndroid Build Coastguard Worker   const Instruction* inst = Instruction::At(dex_pc_ptr);
321*795d594fSAndroid Build Coastguard Worker   Instruction::Code opcode = inst->Opcode();
322*795d594fSAndroid Build Coastguard Worker   DCHECK(IsUint<8>(static_cast<std::underlying_type_t<Instruction::Code>>(opcode)));
323*795d594fSAndroid Build Coastguard Worker   uint8_t raw_invoke_type = kOpcodeInvokeTypes[opcode];
324*795d594fSAndroid Build Coastguard Worker   DCHECK_LE(raw_invoke_type, kMaxInvokeType);
325*795d594fSAndroid Build Coastguard Worker   InvokeType invoke_type = static_cast<InvokeType>(raw_invoke_type);
326*795d594fSAndroid Build Coastguard Worker 
327*795d594fSAndroid Build Coastguard Worker   // In release mode, this is just a simple load.
328*795d594fSAndroid Build Coastguard Worker   // In debug mode, this checks that we're using the correct instruction format.
329*795d594fSAndroid Build Coastguard Worker   uint16_t method_index =
330*795d594fSAndroid Build Coastguard Worker       (opcode >= Instruction::INVOKE_VIRTUAL_RANGE) ? inst->VRegB_3rc() : inst->VRegB_35c();
331*795d594fSAndroid Build Coastguard Worker 
332*795d594fSAndroid Build Coastguard Worker   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
333*795d594fSAndroid Build Coastguard Worker   ArtMethod* resolved_method = caller->SkipAccessChecks()
334*795d594fSAndroid Build Coastguard Worker       ? class_linker->ResolveMethodId(method_index, caller)
335*795d594fSAndroid Build Coastguard Worker       : class_linker->ResolveMethodWithChecks(method_index, caller, invoke_type);
336*795d594fSAndroid Build Coastguard Worker   if (resolved_method == nullptr) {
337*795d594fSAndroid Build Coastguard Worker     DCHECK(self->IsExceptionPending());
338*795d594fSAndroid Build Coastguard Worker     return 0;
339*795d594fSAndroid Build Coastguard Worker   }
340*795d594fSAndroid Build Coastguard Worker 
341*795d594fSAndroid Build Coastguard Worker   if (invoke_type == kSuper) {
342*795d594fSAndroid Build Coastguard Worker     resolved_method = caller->SkipAccessChecks()
343*795d594fSAndroid Build Coastguard Worker         ? FindSuperMethodToCall</*access_check=*/false>(method_index, resolved_method, caller, self)
344*795d594fSAndroid Build Coastguard Worker         : FindSuperMethodToCall</*access_check=*/true>(method_index, resolved_method, caller, self);
345*795d594fSAndroid Build Coastguard Worker     if (resolved_method == nullptr) {
346*795d594fSAndroid Build Coastguard Worker       DCHECK(self->IsExceptionPending());
347*795d594fSAndroid Build Coastguard Worker       return 0;
348*795d594fSAndroid Build Coastguard Worker     }
349*795d594fSAndroid Build Coastguard Worker   }
350*795d594fSAndroid Build Coastguard Worker 
351*795d594fSAndroid Build Coastguard Worker   if (invoke_type == kInterface) {
352*795d594fSAndroid Build Coastguard Worker     size_t result = 0u;
353*795d594fSAndroid Build Coastguard Worker     if (resolved_method->GetDeclaringClass()->IsObjectClass()) {
354*795d594fSAndroid Build Coastguard Worker       // Set the low bit to notify the interpreter it should do a vtable call.
355*795d594fSAndroid Build Coastguard Worker       DCHECK_LT(resolved_method->GetMethodIndex(), 0x10000);
356*795d594fSAndroid Build Coastguard Worker       result = (resolved_method->GetMethodIndex() << 16) | 1U;
357*795d594fSAndroid Build Coastguard Worker     } else {
358*795d594fSAndroid Build Coastguard Worker       DCHECK(resolved_method->GetDeclaringClass()->IsInterface());
359*795d594fSAndroid Build Coastguard Worker       DCHECK(!resolved_method->IsCopied());
360*795d594fSAndroid Build Coastguard Worker       if (!resolved_method->IsAbstract()) {
361*795d594fSAndroid Build Coastguard Worker         // Set the second bit to notify the interpreter this is a default
362*795d594fSAndroid Build Coastguard Worker         // method.
363*795d594fSAndroid Build Coastguard Worker         result = reinterpret_cast<size_t>(resolved_method) | 2U;
364*795d594fSAndroid Build Coastguard Worker       } else {
365*795d594fSAndroid Build Coastguard Worker         result = reinterpret_cast<size_t>(resolved_method);
366*795d594fSAndroid Build Coastguard Worker       }
367*795d594fSAndroid Build Coastguard Worker     }
368*795d594fSAndroid Build Coastguard Worker     UpdateCache(self, dex_pc_ptr, result);
369*795d594fSAndroid Build Coastguard Worker     return result;
370*795d594fSAndroid Build Coastguard Worker   } else if (resolved_method->IsStringConstructor()) {
371*795d594fSAndroid Build Coastguard Worker     CHECK_NE(invoke_type, kSuper);
372*795d594fSAndroid Build Coastguard Worker     resolved_method = WellKnownClasses::StringInitToStringFactory(resolved_method);
373*795d594fSAndroid Build Coastguard Worker     // Or the result with 1 to notify to nterp this is a string init method. We
374*795d594fSAndroid Build Coastguard Worker     // also don't cache the result as we don't want nterp to have its fast path always
375*795d594fSAndroid Build Coastguard Worker     // check for it, and we expect a lot more regular calls than string init
376*795d594fSAndroid Build Coastguard Worker     // calls.
377*795d594fSAndroid Build Coastguard Worker     return reinterpret_cast<size_t>(resolved_method) | 1;
378*795d594fSAndroid Build Coastguard Worker   } else if (invoke_type == kVirtual) {
379*795d594fSAndroid Build Coastguard Worker     UpdateCache(self, dex_pc_ptr, resolved_method->GetMethodIndex());
380*795d594fSAndroid Build Coastguard Worker     return resolved_method->GetMethodIndex();
381*795d594fSAndroid Build Coastguard Worker   } else {
382*795d594fSAndroid Build Coastguard Worker     UpdateCache(self, dex_pc_ptr, resolved_method);
383*795d594fSAndroid Build Coastguard Worker     return reinterpret_cast<size_t>(resolved_method);
384*795d594fSAndroid Build Coastguard Worker   }
385*795d594fSAndroid Build Coastguard Worker }
386*795d594fSAndroid Build Coastguard Worker 
387*795d594fSAndroid Build Coastguard Worker LIBART_PROTECTED
NterpGetStaticField(Thread * self,ArtMethod * caller,const uint16_t * dex_pc_ptr,size_t resolve_field_type)388*795d594fSAndroid Build Coastguard Worker extern "C" size_t NterpGetStaticField(Thread* self,
389*795d594fSAndroid Build Coastguard Worker                                       ArtMethod* caller,
390*795d594fSAndroid Build Coastguard Worker                                       const uint16_t* dex_pc_ptr,
391*795d594fSAndroid Build Coastguard Worker                                       size_t resolve_field_type)  // Resolve if not zero
392*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
393*795d594fSAndroid Build Coastguard Worker   UpdateHotness(caller);
394*795d594fSAndroid Build Coastguard Worker   const Instruction* inst = Instruction::At(dex_pc_ptr);
395*795d594fSAndroid Build Coastguard Worker   uint16_t field_index = inst->VRegB_21c();
396*795d594fSAndroid Build Coastguard Worker   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
397*795d594fSAndroid Build Coastguard Worker   Instruction::Code opcode = inst->Opcode();
398*795d594fSAndroid Build Coastguard Worker   ArtField* resolved_field = ResolveFieldWithAccessChecks(
399*795d594fSAndroid Build Coastguard Worker       self,
400*795d594fSAndroid Build Coastguard Worker       class_linker,
401*795d594fSAndroid Build Coastguard Worker       field_index,
402*795d594fSAndroid Build Coastguard Worker       caller,
403*795d594fSAndroid Build Coastguard Worker       /*is_static=*/ true,
404*795d594fSAndroid Build Coastguard Worker       /*is_put=*/ IsInstructionSPut(opcode),
405*795d594fSAndroid Build Coastguard Worker       resolve_field_type);
406*795d594fSAndroid Build Coastguard Worker 
407*795d594fSAndroid Build Coastguard Worker   if (resolved_field == nullptr) {
408*795d594fSAndroid Build Coastguard Worker     DCHECK(self->IsExceptionPending());
409*795d594fSAndroid Build Coastguard Worker     return 0;
410*795d594fSAndroid Build Coastguard Worker   }
411*795d594fSAndroid Build Coastguard Worker   if (UNLIKELY(!resolved_field->GetDeclaringClass()->IsVisiblyInitialized())) {
412*795d594fSAndroid Build Coastguard Worker     StackHandleScope<1> hs(self);
413*795d594fSAndroid Build Coastguard Worker     Handle<mirror::Class> h_class(hs.NewHandle(resolved_field->GetDeclaringClass()));
414*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(!class_linker->EnsureInitialized(
415*795d594fSAndroid Build Coastguard Worker                       self, h_class, /*can_init_fields=*/ true, /*can_init_parents=*/ true))) {
416*795d594fSAndroid Build Coastguard Worker       DCHECK(self->IsExceptionPending());
417*795d594fSAndroid Build Coastguard Worker       return 0;
418*795d594fSAndroid Build Coastguard Worker     }
419*795d594fSAndroid Build Coastguard Worker     DCHECK(h_class->IsInitializing());
420*795d594fSAndroid Build Coastguard Worker   }
421*795d594fSAndroid Build Coastguard Worker   if (resolved_field->IsVolatile()) {
422*795d594fSAndroid Build Coastguard Worker     // Or the result with 1 to notify to nterp this is a volatile field. We
423*795d594fSAndroid Build Coastguard Worker     // also don't cache the result as we don't want nterp to have its fast path always
424*795d594fSAndroid Build Coastguard Worker     // check for it.
425*795d594fSAndroid Build Coastguard Worker     return reinterpret_cast<size_t>(resolved_field) | 1;
426*795d594fSAndroid Build Coastguard Worker   } else {
427*795d594fSAndroid Build Coastguard Worker     // For sput-object, try to resolve the field type even if we were not requested to.
428*795d594fSAndroid Build Coastguard Worker     // Only if the field type is successfully resolved can we update the cache. If we
429*795d594fSAndroid Build Coastguard Worker     // fail to resolve the type, we clear the exception to keep interpreter
430*795d594fSAndroid Build Coastguard Worker     // semantics of not throwing when null is stored.
431*795d594fSAndroid Build Coastguard Worker     if (opcode == Instruction::SPUT_OBJECT &&
432*795d594fSAndroid Build Coastguard Worker         resolve_field_type == 0 &&
433*795d594fSAndroid Build Coastguard Worker         resolved_field->ResolveType() == nullptr) {
434*795d594fSAndroid Build Coastguard Worker       DCHECK(self->IsExceptionPending());
435*795d594fSAndroid Build Coastguard Worker       self->ClearException();
436*795d594fSAndroid Build Coastguard Worker     } else {
437*795d594fSAndroid Build Coastguard Worker       UpdateCache(self, dex_pc_ptr, resolved_field);
438*795d594fSAndroid Build Coastguard Worker     }
439*795d594fSAndroid Build Coastguard Worker     return reinterpret_cast<size_t>(resolved_field);
440*795d594fSAndroid Build Coastguard Worker   }
441*795d594fSAndroid Build Coastguard Worker }
442*795d594fSAndroid Build Coastguard Worker 
443*795d594fSAndroid Build Coastguard Worker LIBART_PROTECTED
NterpGetInstanceFieldOffset(Thread * self,ArtMethod * caller,const uint16_t * dex_pc_ptr,size_t resolve_field_type)444*795d594fSAndroid Build Coastguard Worker extern "C" uint32_t NterpGetInstanceFieldOffset(Thread* self,
445*795d594fSAndroid Build Coastguard Worker                                                 ArtMethod* caller,
446*795d594fSAndroid Build Coastguard Worker                                                 const uint16_t* dex_pc_ptr,
447*795d594fSAndroid Build Coastguard Worker                                                 size_t resolve_field_type)  // Resolve if not zero
448*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
449*795d594fSAndroid Build Coastguard Worker   UpdateHotness(caller);
450*795d594fSAndroid Build Coastguard Worker   const Instruction* inst = Instruction::At(dex_pc_ptr);
451*795d594fSAndroid Build Coastguard Worker   uint16_t field_index = inst->VRegC_22c();
452*795d594fSAndroid Build Coastguard Worker   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
453*795d594fSAndroid Build Coastguard Worker   Instruction::Code opcode = inst->Opcode();
454*795d594fSAndroid Build Coastguard Worker   ArtField* resolved_field = ResolveFieldWithAccessChecks(
455*795d594fSAndroid Build Coastguard Worker       self,
456*795d594fSAndroid Build Coastguard Worker       class_linker,
457*795d594fSAndroid Build Coastguard Worker       field_index,
458*795d594fSAndroid Build Coastguard Worker       caller,
459*795d594fSAndroid Build Coastguard Worker       /*is_static=*/ false,
460*795d594fSAndroid Build Coastguard Worker       /*is_put=*/ IsInstructionIPut(opcode),
461*795d594fSAndroid Build Coastguard Worker       resolve_field_type);
462*795d594fSAndroid Build Coastguard Worker   if (resolved_field == nullptr) {
463*795d594fSAndroid Build Coastguard Worker     DCHECK(self->IsExceptionPending());
464*795d594fSAndroid Build Coastguard Worker     return 0;
465*795d594fSAndroid Build Coastguard Worker   }
466*795d594fSAndroid Build Coastguard Worker   if (resolved_field->IsVolatile()) {
467*795d594fSAndroid Build Coastguard Worker     // Don't cache for a volatile field, and return a negative offset as marker
468*795d594fSAndroid Build Coastguard Worker     // of volatile.
469*795d594fSAndroid Build Coastguard Worker     return -resolved_field->GetOffset().Uint32Value();
470*795d594fSAndroid Build Coastguard Worker   }
471*795d594fSAndroid Build Coastguard Worker   // For iput-object, try to resolve the field type even if we were not requested to.
472*795d594fSAndroid Build Coastguard Worker   // Only if the field type is successfully resolved can we update the cache. If we
473*795d594fSAndroid Build Coastguard Worker   // fail to resolve the type, we clear the exception to keep interpreter
474*795d594fSAndroid Build Coastguard Worker   // semantics of not throwing when null is stored.
475*795d594fSAndroid Build Coastguard Worker   if (opcode == Instruction::IPUT_OBJECT &&
476*795d594fSAndroid Build Coastguard Worker       resolve_field_type == 0 &&
477*795d594fSAndroid Build Coastguard Worker       resolved_field->ResolveType() == nullptr) {
478*795d594fSAndroid Build Coastguard Worker     DCHECK(self->IsExceptionPending());
479*795d594fSAndroid Build Coastguard Worker     self->ClearException();
480*795d594fSAndroid Build Coastguard Worker   } else {
481*795d594fSAndroid Build Coastguard Worker     UpdateCache(self, dex_pc_ptr, resolved_field->GetOffset().Uint32Value());
482*795d594fSAndroid Build Coastguard Worker   }
483*795d594fSAndroid Build Coastguard Worker   return resolved_field->GetOffset().Uint32Value();
484*795d594fSAndroid Build Coastguard Worker }
485*795d594fSAndroid Build Coastguard Worker 
NterpGetClass(Thread * self,ArtMethod * caller,uint16_t * dex_pc_ptr)486*795d594fSAndroid Build Coastguard Worker extern "C" mirror::Object* NterpGetClass(Thread* self, ArtMethod* caller, uint16_t* dex_pc_ptr)
487*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
488*795d594fSAndroid Build Coastguard Worker   UpdateHotness(caller);
489*795d594fSAndroid Build Coastguard Worker   const Instruction* inst = Instruction::At(dex_pc_ptr);
490*795d594fSAndroid Build Coastguard Worker   Instruction::Code opcode = inst->Opcode();
491*795d594fSAndroid Build Coastguard Worker   DCHECK(opcode == Instruction::CHECK_CAST ||
492*795d594fSAndroid Build Coastguard Worker          opcode == Instruction::INSTANCE_OF ||
493*795d594fSAndroid Build Coastguard Worker          opcode == Instruction::CONST_CLASS ||
494*795d594fSAndroid Build Coastguard Worker          opcode == Instruction::NEW_ARRAY);
495*795d594fSAndroid Build Coastguard Worker 
496*795d594fSAndroid Build Coastguard Worker   // In release mode, this is just a simple load.
497*795d594fSAndroid Build Coastguard Worker   // In debug mode, this checks that we're using the correct instruction format.
498*795d594fSAndroid Build Coastguard Worker   dex::TypeIndex index = dex::TypeIndex(
499*795d594fSAndroid Build Coastguard Worker       (opcode == Instruction::CHECK_CAST || opcode == Instruction::CONST_CLASS)
500*795d594fSAndroid Build Coastguard Worker           ? inst->VRegB_21c()
501*795d594fSAndroid Build Coastguard Worker           : inst->VRegC_22c());
502*795d594fSAndroid Build Coastguard Worker 
503*795d594fSAndroid Build Coastguard Worker   ObjPtr<mirror::Class> c =
504*795d594fSAndroid Build Coastguard Worker       ResolveVerifyAndClinit(index,
505*795d594fSAndroid Build Coastguard Worker                              caller,
506*795d594fSAndroid Build Coastguard Worker                              self,
507*795d594fSAndroid Build Coastguard Worker                              /* can_run_clinit= */ false,
508*795d594fSAndroid Build Coastguard Worker                              /* verify_access= */ !caller->SkipAccessChecks());
509*795d594fSAndroid Build Coastguard Worker   if (UNLIKELY(c == nullptr)) {
510*795d594fSAndroid Build Coastguard Worker     DCHECK(self->IsExceptionPending());
511*795d594fSAndroid Build Coastguard Worker     return nullptr;
512*795d594fSAndroid Build Coastguard Worker   }
513*795d594fSAndroid Build Coastguard Worker 
514*795d594fSAndroid Build Coastguard Worker   UpdateCache(self, dex_pc_ptr, c.Ptr());
515*795d594fSAndroid Build Coastguard Worker   return c.Ptr();
516*795d594fSAndroid Build Coastguard Worker }
517*795d594fSAndroid Build Coastguard Worker 
NterpAllocateObject(Thread * self,ArtMethod * caller,uint16_t * dex_pc_ptr)518*795d594fSAndroid Build Coastguard Worker extern "C" mirror::Object* NterpAllocateObject(Thread* self,
519*795d594fSAndroid Build Coastguard Worker                                                ArtMethod* caller,
520*795d594fSAndroid Build Coastguard Worker                                                uint16_t* dex_pc_ptr)
521*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
522*795d594fSAndroid Build Coastguard Worker   UpdateHotness(caller);
523*795d594fSAndroid Build Coastguard Worker   const Instruction* inst = Instruction::At(dex_pc_ptr);
524*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(inst->Opcode(), Instruction::NEW_INSTANCE);
525*795d594fSAndroid Build Coastguard Worker   dex::TypeIndex index = dex::TypeIndex(inst->VRegB_21c());
526*795d594fSAndroid Build Coastguard Worker   ObjPtr<mirror::Class> c =
527*795d594fSAndroid Build Coastguard Worker       ResolveVerifyAndClinit(index,
528*795d594fSAndroid Build Coastguard Worker                              caller,
529*795d594fSAndroid Build Coastguard Worker                              self,
530*795d594fSAndroid Build Coastguard Worker                              /* can_run_clinit= */ false,
531*795d594fSAndroid Build Coastguard Worker                              /* verify_access= */ !caller->SkipAccessChecks());
532*795d594fSAndroid Build Coastguard Worker   if (UNLIKELY(c == nullptr)) {
533*795d594fSAndroid Build Coastguard Worker     DCHECK(self->IsExceptionPending());
534*795d594fSAndroid Build Coastguard Worker     return nullptr;
535*795d594fSAndroid Build Coastguard Worker   }
536*795d594fSAndroid Build Coastguard Worker 
537*795d594fSAndroid Build Coastguard Worker   gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
538*795d594fSAndroid Build Coastguard Worker   if (UNLIKELY(c->IsStringClass())) {
539*795d594fSAndroid Build Coastguard Worker     // We don't cache the class for strings as we need to special case their
540*795d594fSAndroid Build Coastguard Worker     // allocation.
541*795d594fSAndroid Build Coastguard Worker     return mirror::String::AllocEmptyString(self, allocator_type).Ptr();
542*795d594fSAndroid Build Coastguard Worker   } else {
543*795d594fSAndroid Build Coastguard Worker     if (!c->IsFinalizable() && c->IsInstantiable()) {
544*795d594fSAndroid Build Coastguard Worker       // Cache non-finalizable classes for next calls.
545*795d594fSAndroid Build Coastguard Worker       UpdateCache(self, dex_pc_ptr, c.Ptr());
546*795d594fSAndroid Build Coastguard Worker     }
547*795d594fSAndroid Build Coastguard Worker     return AllocObjectFromCode(c, self, allocator_type).Ptr();
548*795d594fSAndroid Build Coastguard Worker   }
549*795d594fSAndroid Build Coastguard Worker }
550*795d594fSAndroid Build Coastguard Worker 
NterpLoadObject(Thread * self,ArtMethod * caller,uint16_t * dex_pc_ptr)551*795d594fSAndroid Build Coastguard Worker extern "C" mirror::Object* NterpLoadObject(Thread* self, ArtMethod* caller, uint16_t* dex_pc_ptr)
552*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
553*795d594fSAndroid Build Coastguard Worker   const Instruction* inst = Instruction::At(dex_pc_ptr);
554*795d594fSAndroid Build Coastguard Worker   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
555*795d594fSAndroid Build Coastguard Worker   switch (inst->Opcode()) {
556*795d594fSAndroid Build Coastguard Worker     case Instruction::CONST_STRING:
557*795d594fSAndroid Build Coastguard Worker     case Instruction::CONST_STRING_JUMBO: {
558*795d594fSAndroid Build Coastguard Worker       UpdateHotness(caller);
559*795d594fSAndroid Build Coastguard Worker       dex::StringIndex string_index(
560*795d594fSAndroid Build Coastguard Worker           (inst->Opcode() == Instruction::CONST_STRING)
561*795d594fSAndroid Build Coastguard Worker               ? inst->VRegB_21c()
562*795d594fSAndroid Build Coastguard Worker               : inst->VRegB_31c());
563*795d594fSAndroid Build Coastguard Worker       ObjPtr<mirror::String> str = class_linker->ResolveString(string_index, caller);
564*795d594fSAndroid Build Coastguard Worker       if (str == nullptr) {
565*795d594fSAndroid Build Coastguard Worker         DCHECK(self->IsExceptionPending());
566*795d594fSAndroid Build Coastguard Worker         return nullptr;
567*795d594fSAndroid Build Coastguard Worker       }
568*795d594fSAndroid Build Coastguard Worker       UpdateCache(self, dex_pc_ptr, str.Ptr());
569*795d594fSAndroid Build Coastguard Worker       return str.Ptr();
570*795d594fSAndroid Build Coastguard Worker     }
571*795d594fSAndroid Build Coastguard Worker     case Instruction::CONST_METHOD_HANDLE: {
572*795d594fSAndroid Build Coastguard Worker       // Don't cache: we don't expect this to be performance sensitive, and we
573*795d594fSAndroid Build Coastguard Worker       // don't want the cache to conflict with a performance sensitive entry.
574*795d594fSAndroid Build Coastguard Worker       return class_linker->ResolveMethodHandle(self, inst->VRegB_21c(), caller).Ptr();
575*795d594fSAndroid Build Coastguard Worker     }
576*795d594fSAndroid Build Coastguard Worker     case Instruction::CONST_METHOD_TYPE: {
577*795d594fSAndroid Build Coastguard Worker       // Don't cache: we don't expect this to be performance sensitive, and we
578*795d594fSAndroid Build Coastguard Worker       // don't want the cache to conflict with a performance sensitive entry.
579*795d594fSAndroid Build Coastguard Worker       return class_linker->ResolveMethodType(
580*795d594fSAndroid Build Coastguard Worker           self, dex::ProtoIndex(inst->VRegB_21c()), caller).Ptr();
581*795d594fSAndroid Build Coastguard Worker     }
582*795d594fSAndroid Build Coastguard Worker     default:
583*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "Unreachable";
584*795d594fSAndroid Build Coastguard Worker   }
585*795d594fSAndroid Build Coastguard Worker   return nullptr;
586*795d594fSAndroid Build Coastguard Worker }
587*795d594fSAndroid Build Coastguard Worker 
NterpUnimplemented()588*795d594fSAndroid Build Coastguard Worker extern "C" void NterpUnimplemented() {
589*795d594fSAndroid Build Coastguard Worker   LOG(FATAL) << "Unimplemented";
590*795d594fSAndroid Build Coastguard Worker }
591*795d594fSAndroid Build Coastguard Worker 
DoFilledNewArray(Thread * self,ArtMethod * caller,uint16_t * dex_pc_ptr,uint32_t * regs,bool is_range)592*795d594fSAndroid Build Coastguard Worker static mirror::Object* DoFilledNewArray(Thread* self,
593*795d594fSAndroid Build Coastguard Worker                                         ArtMethod* caller,
594*795d594fSAndroid Build Coastguard Worker                                         uint16_t* dex_pc_ptr,
595*795d594fSAndroid Build Coastguard Worker                                         uint32_t* regs,
596*795d594fSAndroid Build Coastguard Worker                                         bool is_range)
597*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
598*795d594fSAndroid Build Coastguard Worker   const Instruction* inst = Instruction::At(dex_pc_ptr);
599*795d594fSAndroid Build Coastguard Worker   if (kIsDebugBuild) {
600*795d594fSAndroid Build Coastguard Worker     if (is_range) {
601*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(inst->Opcode(), Instruction::FILLED_NEW_ARRAY_RANGE);
602*795d594fSAndroid Build Coastguard Worker     } else {
603*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(inst->Opcode(), Instruction::FILLED_NEW_ARRAY);
604*795d594fSAndroid Build Coastguard Worker     }
605*795d594fSAndroid Build Coastguard Worker   }
606*795d594fSAndroid Build Coastguard Worker   const int32_t length = is_range ? inst->VRegA_3rc() : inst->VRegA_35c();
607*795d594fSAndroid Build Coastguard Worker   DCHECK_GE(length, 0);
608*795d594fSAndroid Build Coastguard Worker   if (!is_range) {
609*795d594fSAndroid Build Coastguard Worker     // Checks FILLED_NEW_ARRAY's length does not exceed 5 arguments.
610*795d594fSAndroid Build Coastguard Worker     DCHECK_LE(length, 5);
611*795d594fSAndroid Build Coastguard Worker   }
612*795d594fSAndroid Build Coastguard Worker   uint16_t type_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c();
613*795d594fSAndroid Build Coastguard Worker   ObjPtr<mirror::Class> array_class =
614*795d594fSAndroid Build Coastguard Worker       ResolveVerifyAndClinit(dex::TypeIndex(type_idx),
615*795d594fSAndroid Build Coastguard Worker                              caller,
616*795d594fSAndroid Build Coastguard Worker                              self,
617*795d594fSAndroid Build Coastguard Worker                              /* can_run_clinit= */ true,
618*795d594fSAndroid Build Coastguard Worker                              /* verify_access= */ !caller->SkipAccessChecks());
619*795d594fSAndroid Build Coastguard Worker   if (UNLIKELY(array_class == nullptr)) {
620*795d594fSAndroid Build Coastguard Worker     DCHECK(self->IsExceptionPending());
621*795d594fSAndroid Build Coastguard Worker     return nullptr;
622*795d594fSAndroid Build Coastguard Worker   }
623*795d594fSAndroid Build Coastguard Worker   DCHECK(array_class->IsArrayClass());
624*795d594fSAndroid Build Coastguard Worker   ObjPtr<mirror::Class> component_class = array_class->GetComponentType();
625*795d594fSAndroid Build Coastguard Worker   const bool is_primitive_int_component = component_class->IsPrimitiveInt();
626*795d594fSAndroid Build Coastguard Worker   if (UNLIKELY(component_class->IsPrimitive() && !is_primitive_int_component)) {
627*795d594fSAndroid Build Coastguard Worker     if (component_class->IsPrimitiveLong() || component_class->IsPrimitiveDouble()) {
628*795d594fSAndroid Build Coastguard Worker       ThrowRuntimeException("Bad filled array request for type %s",
629*795d594fSAndroid Build Coastguard Worker                             component_class->PrettyDescriptor().c_str());
630*795d594fSAndroid Build Coastguard Worker     } else {
631*795d594fSAndroid Build Coastguard Worker       self->ThrowNewExceptionF(
632*795d594fSAndroid Build Coastguard Worker           "Ljava/lang/InternalError;",
633*795d594fSAndroid Build Coastguard Worker           "Found type %s; filled-new-array not implemented for anything but 'int'",
634*795d594fSAndroid Build Coastguard Worker           component_class->PrettyDescriptor().c_str());
635*795d594fSAndroid Build Coastguard Worker     }
636*795d594fSAndroid Build Coastguard Worker     return nullptr;
637*795d594fSAndroid Build Coastguard Worker   }
638*795d594fSAndroid Build Coastguard Worker   ObjPtr<mirror::Object> new_array = mirror::Array::Alloc(
639*795d594fSAndroid Build Coastguard Worker       self,
640*795d594fSAndroid Build Coastguard Worker       array_class,
641*795d594fSAndroid Build Coastguard Worker       length,
642*795d594fSAndroid Build Coastguard Worker       array_class->GetComponentSizeShift(),
643*795d594fSAndroid Build Coastguard Worker       Runtime::Current()->GetHeap()->GetCurrentAllocator());
644*795d594fSAndroid Build Coastguard Worker   if (UNLIKELY(new_array == nullptr)) {
645*795d594fSAndroid Build Coastguard Worker     self->AssertPendingOOMException();
646*795d594fSAndroid Build Coastguard Worker     return nullptr;
647*795d594fSAndroid Build Coastguard Worker   }
648*795d594fSAndroid Build Coastguard Worker   uint32_t arg[Instruction::kMaxVarArgRegs];  // only used in filled-new-array.
649*795d594fSAndroid Build Coastguard Worker   uint32_t vregC = 0;   // only used in filled-new-array-range.
650*795d594fSAndroid Build Coastguard Worker   if (is_range) {
651*795d594fSAndroid Build Coastguard Worker     vregC = inst->VRegC_3rc();
652*795d594fSAndroid Build Coastguard Worker   } else {
653*795d594fSAndroid Build Coastguard Worker     inst->GetVarArgs(arg);
654*795d594fSAndroid Build Coastguard Worker   }
655*795d594fSAndroid Build Coastguard Worker   for (int32_t i = 0; i < length; ++i) {
656*795d594fSAndroid Build Coastguard Worker     size_t src_reg = is_range ? vregC + i : arg[i];
657*795d594fSAndroid Build Coastguard Worker     if (is_primitive_int_component) {
658*795d594fSAndroid Build Coastguard Worker       new_array->AsIntArray()->SetWithoutChecks</* kTransactionActive= */ false>(i, regs[src_reg]);
659*795d594fSAndroid Build Coastguard Worker     } else {
660*795d594fSAndroid Build Coastguard Worker       new_array->AsObjectArray<mirror::Object>()->SetWithoutChecks</* kTransactionActive= */ false>(
661*795d594fSAndroid Build Coastguard Worker           i, reinterpret_cast<mirror::Object*>(regs[src_reg]));
662*795d594fSAndroid Build Coastguard Worker     }
663*795d594fSAndroid Build Coastguard Worker   }
664*795d594fSAndroid Build Coastguard Worker   return new_array.Ptr();
665*795d594fSAndroid Build Coastguard Worker }
666*795d594fSAndroid Build Coastguard Worker 
NterpFilledNewArray(Thread * self,ArtMethod * caller,uint32_t * registers,uint16_t * dex_pc_ptr)667*795d594fSAndroid Build Coastguard Worker extern "C" mirror::Object* NterpFilledNewArray(Thread* self,
668*795d594fSAndroid Build Coastguard Worker                                                ArtMethod* caller,
669*795d594fSAndroid Build Coastguard Worker                                                uint32_t* registers,
670*795d594fSAndroid Build Coastguard Worker                                                uint16_t* dex_pc_ptr)
671*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
672*795d594fSAndroid Build Coastguard Worker   return DoFilledNewArray(self, caller, dex_pc_ptr, registers, /* is_range= */ false);
673*795d594fSAndroid Build Coastguard Worker }
674*795d594fSAndroid Build Coastguard Worker 
NterpFilledNewArrayRange(Thread * self,ArtMethod * caller,uint32_t * registers,uint16_t * dex_pc_ptr)675*795d594fSAndroid Build Coastguard Worker extern "C" mirror::Object* NterpFilledNewArrayRange(Thread* self,
676*795d594fSAndroid Build Coastguard Worker                                                     ArtMethod* caller,
677*795d594fSAndroid Build Coastguard Worker                                                     uint32_t* registers,
678*795d594fSAndroid Build Coastguard Worker                                                     uint16_t* dex_pc_ptr)
679*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
680*795d594fSAndroid Build Coastguard Worker   return DoFilledNewArray(self, caller, dex_pc_ptr, registers, /* is_range= */ true);
681*795d594fSAndroid Build Coastguard Worker }
682*795d594fSAndroid Build Coastguard Worker 
NterpHotMethod(ArtMethod * method,uint16_t * dex_pc_ptr,uint32_t * vregs)683*795d594fSAndroid Build Coastguard Worker extern "C" jit::OsrData* NterpHotMethod(ArtMethod* method, uint16_t* dex_pc_ptr, uint32_t* vregs)
684*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
685*795d594fSAndroid Build Coastguard Worker   // It is important this method is not suspended because it can be called on
686*795d594fSAndroid Build Coastguard Worker   // method entry and async deoptimization does not expect runtime methods other than the
687*795d594fSAndroid Build Coastguard Worker   // suspend entrypoint before executing the first instruction of a Java
688*795d594fSAndroid Build Coastguard Worker   // method.
689*795d594fSAndroid Build Coastguard Worker   ScopedAssertNoThreadSuspension sants("In nterp");
690*795d594fSAndroid Build Coastguard Worker   Runtime* runtime = Runtime::Current();
691*795d594fSAndroid Build Coastguard Worker   if (method->IsMemorySharedMethod()) {
692*795d594fSAndroid Build Coastguard Worker     if (!method->IsIntrinsic()) {
693*795d594fSAndroid Build Coastguard Worker       // Intrinsics are special and will be considered hot from the first call.
694*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(Thread::Current()->GetSharedMethodHotness(), 0u);
695*795d594fSAndroid Build Coastguard Worker       Thread::Current()->ResetSharedMethodHotness();
696*795d594fSAndroid Build Coastguard Worker     }
697*795d594fSAndroid Build Coastguard Worker   } else {
698*795d594fSAndroid Build Coastguard Worker     // Move the counter to the initial threshold in case we have to re-JIT it.
699*795d594fSAndroid Build Coastguard Worker     method->ResetCounter(runtime->GetJITOptions()->GetWarmupThreshold());
700*795d594fSAndroid Build Coastguard Worker     // Mark the method as warm for the profile saver.
701*795d594fSAndroid Build Coastguard Worker     method->SetPreviouslyWarm();
702*795d594fSAndroid Build Coastguard Worker   }
703*795d594fSAndroid Build Coastguard Worker   jit::Jit* jit = runtime->GetJit();
704*795d594fSAndroid Build Coastguard Worker   if (jit != nullptr && jit->UseJitCompilation()) {
705*795d594fSAndroid Build Coastguard Worker     // Nterp passes null on entry where we don't want to OSR.
706*795d594fSAndroid Build Coastguard Worker     if (dex_pc_ptr != nullptr) {
707*795d594fSAndroid Build Coastguard Worker       // This could be a loop back edge, check if we can OSR.
708*795d594fSAndroid Build Coastguard Worker       CodeItemInstructionAccessor accessor(method->DexInstructions());
709*795d594fSAndroid Build Coastguard Worker       uint32_t dex_pc = dex_pc_ptr - accessor.Insns();
710*795d594fSAndroid Build Coastguard Worker       jit::OsrData* osr_data = jit->PrepareForOsr(
711*795d594fSAndroid Build Coastguard Worker           method->GetInterfaceMethodIfProxy(kRuntimePointerSize), dex_pc, vregs);
712*795d594fSAndroid Build Coastguard Worker       if (osr_data != nullptr) {
713*795d594fSAndroid Build Coastguard Worker         return osr_data;
714*795d594fSAndroid Build Coastguard Worker       }
715*795d594fSAndroid Build Coastguard Worker     }
716*795d594fSAndroid Build Coastguard Worker     jit->MaybeEnqueueCompilation(method, Thread::Current());
717*795d594fSAndroid Build Coastguard Worker   }
718*795d594fSAndroid Build Coastguard Worker   return nullptr;
719*795d594fSAndroid Build Coastguard Worker }
720*795d594fSAndroid Build Coastguard Worker 
NterpDoPackedSwitch(const uint16_t * switchData,int32_t testVal)721*795d594fSAndroid Build Coastguard Worker extern "C" ssize_t NterpDoPackedSwitch(const uint16_t* switchData, int32_t testVal)
722*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
723*795d594fSAndroid Build Coastguard Worker   ScopedAssertNoThreadSuspension sants("In nterp");
724*795d594fSAndroid Build Coastguard Worker   const int kInstrLen = 3;
725*795d594fSAndroid Build Coastguard Worker 
726*795d594fSAndroid Build Coastguard Worker   /*
727*795d594fSAndroid Build Coastguard Worker    * Packed switch data format:
728*795d594fSAndroid Build Coastguard Worker    *  ushort ident = 0x0100   magic value
729*795d594fSAndroid Build Coastguard Worker    *  ushort size             number of entries in the table
730*795d594fSAndroid Build Coastguard Worker    *  int first_key           first (and lowest) switch case value
731*795d594fSAndroid Build Coastguard Worker    *  int targets[size]       branch targets, relative to switch opcode
732*795d594fSAndroid Build Coastguard Worker    *
733*795d594fSAndroid Build Coastguard Worker    * Total size is (4+size*2) 16-bit code units.
734*795d594fSAndroid Build Coastguard Worker    */
735*795d594fSAndroid Build Coastguard Worker   uint16_t signature = *switchData++;
736*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(signature, static_cast<uint16_t>(art::Instruction::kPackedSwitchSignature));
737*795d594fSAndroid Build Coastguard Worker 
738*795d594fSAndroid Build Coastguard Worker   uint16_t size = *switchData++;
739*795d594fSAndroid Build Coastguard Worker 
740*795d594fSAndroid Build Coastguard Worker   int32_t firstKey = *switchData++;
741*795d594fSAndroid Build Coastguard Worker   firstKey |= (*switchData++) << 16;
742*795d594fSAndroid Build Coastguard Worker 
743*795d594fSAndroid Build Coastguard Worker   int index = testVal - firstKey;
744*795d594fSAndroid Build Coastguard Worker   if (index < 0 || index >= size) {
745*795d594fSAndroid Build Coastguard Worker     return kInstrLen;
746*795d594fSAndroid Build Coastguard Worker   }
747*795d594fSAndroid Build Coastguard Worker 
748*795d594fSAndroid Build Coastguard Worker   /*
749*795d594fSAndroid Build Coastguard Worker    * The entries are guaranteed to be aligned on a 32-bit boundary;
750*795d594fSAndroid Build Coastguard Worker    * we can treat them as a native int array.
751*795d594fSAndroid Build Coastguard Worker    */
752*795d594fSAndroid Build Coastguard Worker   const int32_t* entries = reinterpret_cast<const int32_t*>(switchData);
753*795d594fSAndroid Build Coastguard Worker   return entries[index];
754*795d594fSAndroid Build Coastguard Worker }
755*795d594fSAndroid Build Coastguard Worker 
756*795d594fSAndroid Build Coastguard Worker /*
757*795d594fSAndroid Build Coastguard Worker  * Find the matching case.  Returns the offset to the handler instructions.
758*795d594fSAndroid Build Coastguard Worker  *
759*795d594fSAndroid Build Coastguard Worker  * Returns 3 if we don't find a match (it's the size of the sparse-switch
760*795d594fSAndroid Build Coastguard Worker  * instruction).
761*795d594fSAndroid Build Coastguard Worker  */
NterpDoSparseSwitch(const uint16_t * switchData,int32_t testVal)762*795d594fSAndroid Build Coastguard Worker extern "C" ssize_t NterpDoSparseSwitch(const uint16_t* switchData, int32_t testVal)
763*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
764*795d594fSAndroid Build Coastguard Worker   ScopedAssertNoThreadSuspension sants("In nterp");
765*795d594fSAndroid Build Coastguard Worker   const int kInstrLen = 3;
766*795d594fSAndroid Build Coastguard Worker   uint16_t size;
767*795d594fSAndroid Build Coastguard Worker   const int32_t* keys;
768*795d594fSAndroid Build Coastguard Worker   const int32_t* entries;
769*795d594fSAndroid Build Coastguard Worker 
770*795d594fSAndroid Build Coastguard Worker   /*
771*795d594fSAndroid Build Coastguard Worker    * Sparse switch data format:
772*795d594fSAndroid Build Coastguard Worker    *  ushort ident = 0x0200   magic value
773*795d594fSAndroid Build Coastguard Worker    *  ushort size             number of entries in the table; > 0
774*795d594fSAndroid Build Coastguard Worker    *  int keys[size]          keys, sorted low-to-high; 32-bit aligned
775*795d594fSAndroid Build Coastguard Worker    *  int targets[size]       branch targets, relative to switch opcode
776*795d594fSAndroid Build Coastguard Worker    *
777*795d594fSAndroid Build Coastguard Worker    * Total size is (2+size*4) 16-bit code units.
778*795d594fSAndroid Build Coastguard Worker    */
779*795d594fSAndroid Build Coastguard Worker 
780*795d594fSAndroid Build Coastguard Worker   uint16_t signature = *switchData++;
781*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(signature, static_cast<uint16_t>(art::Instruction::kSparseSwitchSignature));
782*795d594fSAndroid Build Coastguard Worker 
783*795d594fSAndroid Build Coastguard Worker   size = *switchData++;
784*795d594fSAndroid Build Coastguard Worker 
785*795d594fSAndroid Build Coastguard Worker   /* The keys are guaranteed to be aligned on a 32-bit boundary;
786*795d594fSAndroid Build Coastguard Worker    * we can treat them as a native int array.
787*795d594fSAndroid Build Coastguard Worker    */
788*795d594fSAndroid Build Coastguard Worker   keys = reinterpret_cast<const int32_t*>(switchData);
789*795d594fSAndroid Build Coastguard Worker 
790*795d594fSAndroid Build Coastguard Worker   /* The entries are guaranteed to be aligned on a 32-bit boundary;
791*795d594fSAndroid Build Coastguard Worker    * we can treat them as a native int array.
792*795d594fSAndroid Build Coastguard Worker    */
793*795d594fSAndroid Build Coastguard Worker   entries = keys + size;
794*795d594fSAndroid Build Coastguard Worker 
795*795d594fSAndroid Build Coastguard Worker   /*
796*795d594fSAndroid Build Coastguard Worker    * Binary-search through the array of keys, which are guaranteed to
797*795d594fSAndroid Build Coastguard Worker    * be sorted low-to-high.
798*795d594fSAndroid Build Coastguard Worker    */
799*795d594fSAndroid Build Coastguard Worker   int lo = 0;
800*795d594fSAndroid Build Coastguard Worker   int hi = size - 1;
801*795d594fSAndroid Build Coastguard Worker   while (lo <= hi) {
802*795d594fSAndroid Build Coastguard Worker     int mid = (lo + hi) >> 1;
803*795d594fSAndroid Build Coastguard Worker 
804*795d594fSAndroid Build Coastguard Worker     int32_t foundVal = keys[mid];
805*795d594fSAndroid Build Coastguard Worker     if (testVal < foundVal) {
806*795d594fSAndroid Build Coastguard Worker       hi = mid - 1;
807*795d594fSAndroid Build Coastguard Worker     } else if (testVal > foundVal) {
808*795d594fSAndroid Build Coastguard Worker       lo = mid + 1;
809*795d594fSAndroid Build Coastguard Worker     } else {
810*795d594fSAndroid Build Coastguard Worker       return entries[mid];
811*795d594fSAndroid Build Coastguard Worker     }
812*795d594fSAndroid Build Coastguard Worker   }
813*795d594fSAndroid Build Coastguard Worker   return kInstrLen;
814*795d594fSAndroid Build Coastguard Worker }
815*795d594fSAndroid Build Coastguard Worker 
NterpFree(void * val)816*795d594fSAndroid Build Coastguard Worker extern "C" void NterpFree(void* val) {
817*795d594fSAndroid Build Coastguard Worker   free(val);
818*795d594fSAndroid Build Coastguard Worker }
819*795d594fSAndroid Build Coastguard Worker 
820*795d594fSAndroid Build Coastguard Worker }  // namespace interpreter
821*795d594fSAndroid Build Coastguard Worker }  // namespace art
822