1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "interpreter_common.h" 18 19 #include <limits> 20 21 #include "mirror/string-inl.h" 22 #include "scoped_thread_state_change.h" 23 #include "ScopedLocalRef.h" 24 #include "unstarted_runtime.h" 25 26 namespace art { 27 namespace interpreter { 28 29 static void InterpreterJni(Thread* self, ArtMethod* method, const StringPiece& shorty, 30 Object* receiver, uint32_t* args, JValue* result) 31 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 32 // TODO: The following enters JNI code using a typedef-ed function rather than the JNI compiler, 33 // it should be removed and JNI compiled stubs used instead. 34 ScopedObjectAccessUnchecked soa(self); 35 if (method->IsStatic()) { 36 if (shorty == "L") { 37 typedef jobject (fntype)(JNIEnv*, jclass); 38 fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); 39 ScopedLocalRef<jclass> klass(soa.Env(), 40 soa.AddLocalReference<jclass>(method->GetDeclaringClass())); 41 jobject jresult; 42 { 43 ScopedThreadStateChange tsc(self, kNative); 44 jresult = fn(soa.Env(), klass.get()); 45 } 46 result->SetL(soa.Decode<Object*>(jresult)); 47 } else if (shorty == "V") { 48 typedef void (fntype)(JNIEnv*, jclass); 49 fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); 50 ScopedLocalRef<jclass> klass(soa.Env(), 51 soa.AddLocalReference<jclass>(method->GetDeclaringClass())); 52 ScopedThreadStateChange tsc(self, kNative); 53 fn(soa.Env(), klass.get()); 54 } else if (shorty == "Z") { 55 typedef jboolean (fntype)(JNIEnv*, jclass); 56 fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); 57 ScopedLocalRef<jclass> klass(soa.Env(), 58 soa.AddLocalReference<jclass>(method->GetDeclaringClass())); 59 ScopedThreadStateChange tsc(self, kNative); 60 result->SetZ(fn(soa.Env(), klass.get())); 61 } else if (shorty == "BI") { 62 typedef jbyte (fntype)(JNIEnv*, jclass, jint); 63 fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); 64 ScopedLocalRef<jclass> klass(soa.Env(), 65 soa.AddLocalReference<jclass>(method->GetDeclaringClass())); 66 ScopedThreadStateChange tsc(self, kNative); 67 result->SetB(fn(soa.Env(), klass.get(), args[0])); 68 } else if (shorty == "II") { 69 typedef jint (fntype)(JNIEnv*, jclass, jint); 70 fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); 71 ScopedLocalRef<jclass> klass(soa.Env(), 72 soa.AddLocalReference<jclass>(method->GetDeclaringClass())); 73 ScopedThreadStateChange tsc(self, kNative); 74 result->SetI(fn(soa.Env(), klass.get(), args[0])); 75 } else if (shorty == "LL") { 76 typedef jobject (fntype)(JNIEnv*, jclass, jobject); 77 fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); 78 ScopedLocalRef<jclass> klass(soa.Env(), 79 soa.AddLocalReference<jclass>(method->GetDeclaringClass())); 80 ScopedLocalRef<jobject> arg0(soa.Env(), 81 soa.AddLocalReference<jobject>( 82 reinterpret_cast<Object*>(args[0]))); 83 jobject jresult; 84 { 85 ScopedThreadStateChange tsc(self, kNative); 86 jresult = fn(soa.Env(), klass.get(), arg0.get()); 87 } 88 result->SetL(soa.Decode<Object*>(jresult)); 89 } else if (shorty == "IIZ") { 90 typedef jint (fntype)(JNIEnv*, jclass, jint, jboolean); 91 fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); 92 ScopedLocalRef<jclass> klass(soa.Env(), 93 soa.AddLocalReference<jclass>(method->GetDeclaringClass())); 94 ScopedThreadStateChange tsc(self, kNative); 95 result->SetI(fn(soa.Env(), klass.get(), args[0], args[1])); 96 } else if (shorty == "ILI") { 97 typedef jint (fntype)(JNIEnv*, jclass, jobject, jint); 98 fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>( 99 method->GetEntryPointFromJni())); 100 ScopedLocalRef<jclass> klass(soa.Env(), 101 soa.AddLocalReference<jclass>(method->GetDeclaringClass())); 102 ScopedLocalRef<jobject> arg0(soa.Env(), 103 soa.AddLocalReference<jobject>( 104 reinterpret_cast<Object*>(args[0]))); 105 ScopedThreadStateChange tsc(self, kNative); 106 result->SetI(fn(soa.Env(), klass.get(), arg0.get(), args[1])); 107 } else if (shorty == "SIZ") { 108 typedef jshort (fntype)(JNIEnv*, jclass, jint, jboolean); 109 fntype* const fn = 110 reinterpret_cast<fntype*>(const_cast<void*>(method->GetEntryPointFromJni())); 111 ScopedLocalRef<jclass> klass(soa.Env(), 112 soa.AddLocalReference<jclass>(method->GetDeclaringClass())); 113 ScopedThreadStateChange tsc(self, kNative); 114 result->SetS(fn(soa.Env(), klass.get(), args[0], args[1])); 115 } else if (shorty == "VIZ") { 116 typedef void (fntype)(JNIEnv*, jclass, jint, jboolean); 117 fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); 118 ScopedLocalRef<jclass> klass(soa.Env(), 119 soa.AddLocalReference<jclass>(method->GetDeclaringClass())); 120 ScopedThreadStateChange tsc(self, kNative); 121 fn(soa.Env(), klass.get(), args[0], args[1]); 122 } else if (shorty == "ZLL") { 123 typedef jboolean (fntype)(JNIEnv*, jclass, jobject, jobject); 124 fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); 125 ScopedLocalRef<jclass> klass(soa.Env(), 126 soa.AddLocalReference<jclass>(method->GetDeclaringClass())); 127 ScopedLocalRef<jobject> arg0(soa.Env(), 128 soa.AddLocalReference<jobject>( 129 reinterpret_cast<Object*>(args[0]))); 130 ScopedLocalRef<jobject> arg1(soa.Env(), 131 soa.AddLocalReference<jobject>( 132 reinterpret_cast<Object*>(args[1]))); 133 ScopedThreadStateChange tsc(self, kNative); 134 result->SetZ(fn(soa.Env(), klass.get(), arg0.get(), arg1.get())); 135 } else if (shorty == "ZILL") { 136 typedef jboolean (fntype)(JNIEnv*, jclass, jint, jobject, jobject); 137 fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); 138 ScopedLocalRef<jclass> klass(soa.Env(), 139 soa.AddLocalReference<jclass>(method->GetDeclaringClass())); 140 ScopedLocalRef<jobject> arg1(soa.Env(), 141 soa.AddLocalReference<jobject>( 142 reinterpret_cast<Object*>(args[1]))); 143 ScopedLocalRef<jobject> arg2(soa.Env(), 144 soa.AddLocalReference<jobject>( 145 reinterpret_cast<Object*>(args[2]))); 146 ScopedThreadStateChange tsc(self, kNative); 147 result->SetZ(fn(soa.Env(), klass.get(), args[0], arg1.get(), arg2.get())); 148 } else if (shorty == "VILII") { 149 typedef void (fntype)(JNIEnv*, jclass, jint, jobject, jint, jint); 150 fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); 151 ScopedLocalRef<jclass> klass(soa.Env(), 152 soa.AddLocalReference<jclass>(method->GetDeclaringClass())); 153 ScopedLocalRef<jobject> arg1(soa.Env(), 154 soa.AddLocalReference<jobject>( 155 reinterpret_cast<Object*>(args[1]))); 156 ScopedThreadStateChange tsc(self, kNative); 157 fn(soa.Env(), klass.get(), args[0], arg1.get(), args[2], args[3]); 158 } else if (shorty == "VLILII") { 159 typedef void (fntype)(JNIEnv*, jclass, jobject, jint, jobject, jint, jint); 160 fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); 161 ScopedLocalRef<jclass> klass(soa.Env(), 162 soa.AddLocalReference<jclass>(method->GetDeclaringClass())); 163 ScopedLocalRef<jobject> arg0(soa.Env(), 164 soa.AddLocalReference<jobject>( 165 reinterpret_cast<Object*>(args[0]))); 166 ScopedLocalRef<jobject> arg2(soa.Env(), 167 soa.AddLocalReference<jobject>( 168 reinterpret_cast<Object*>(args[2]))); 169 ScopedThreadStateChange tsc(self, kNative); 170 fn(soa.Env(), klass.get(), arg0.get(), args[1], arg2.get(), args[3], args[4]); 171 } else { 172 LOG(FATAL) << "Do something with static native method: " << PrettyMethod(method) 173 << " shorty: " << shorty; 174 } 175 } else { 176 if (shorty == "L") { 177 typedef jobject (fntype)(JNIEnv*, jobject); 178 fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); 179 ScopedLocalRef<jobject> rcvr(soa.Env(), 180 soa.AddLocalReference<jobject>(receiver)); 181 jobject jresult; 182 { 183 ScopedThreadStateChange tsc(self, kNative); 184 jresult = fn(soa.Env(), rcvr.get()); 185 } 186 result->SetL(soa.Decode<Object*>(jresult)); 187 } else if (shorty == "V") { 188 typedef void (fntype)(JNIEnv*, jobject); 189 fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); 190 ScopedLocalRef<jobject> rcvr(soa.Env(), 191 soa.AddLocalReference<jobject>(receiver)); 192 ScopedThreadStateChange tsc(self, kNative); 193 fn(soa.Env(), rcvr.get()); 194 } else if (shorty == "LL") { 195 typedef jobject (fntype)(JNIEnv*, jobject, jobject); 196 fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); 197 ScopedLocalRef<jobject> rcvr(soa.Env(), 198 soa.AddLocalReference<jobject>(receiver)); 199 ScopedLocalRef<jobject> arg0(soa.Env(), 200 soa.AddLocalReference<jobject>( 201 reinterpret_cast<Object*>(args[0]))); 202 jobject jresult; 203 { 204 ScopedThreadStateChange tsc(self, kNative); 205 jresult = fn(soa.Env(), rcvr.get(), arg0.get()); 206 } 207 result->SetL(soa.Decode<Object*>(jresult)); 208 ScopedThreadStateChange tsc(self, kNative); 209 } else if (shorty == "III") { 210 typedef jint (fntype)(JNIEnv*, jobject, jint, jint); 211 fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); 212 ScopedLocalRef<jobject> rcvr(soa.Env(), 213 soa.AddLocalReference<jobject>(receiver)); 214 ScopedThreadStateChange tsc(self, kNative); 215 result->SetI(fn(soa.Env(), rcvr.get(), args[0], args[1])); 216 } else { 217 LOG(FATAL) << "Do something with native method: " << PrettyMethod(method) 218 << " shorty: " << shorty; 219 } 220 } 221 } 222 223 enum InterpreterImplKind { 224 kSwitchImpl, // Switch-based interpreter implementation. 225 kComputedGotoImplKind // Computed-goto-based interpreter implementation. 226 }; 227 static std::ostream& operator<<(std::ostream& os, const InterpreterImplKind& rhs) { 228 os << ((rhs == kSwitchImpl) ? "Switch-based interpreter" : "Computed-goto-based interpreter"); 229 return os; 230 } 231 232 #if !defined(__clang__) 233 static constexpr InterpreterImplKind kInterpreterImplKind = kComputedGotoImplKind; 234 #else 235 // Clang 3.4 fails to build the goto interpreter implementation. 236 static constexpr InterpreterImplKind kInterpreterImplKind = kSwitchImpl; 237 template<bool do_access_check, bool transaction_active> 238 JValue ExecuteGotoImpl(Thread*, const DexFile::CodeItem*, ShadowFrame&, JValue) { 239 LOG(FATAL) << "UNREACHABLE"; 240 UNREACHABLE(); 241 } 242 // Explicit definitions of ExecuteGotoImpl. 243 template<> SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) 244 JValue ExecuteGotoImpl<true, false>(Thread* self, const DexFile::CodeItem* code_item, 245 ShadowFrame& shadow_frame, JValue result_register); 246 template<> SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) 247 JValue ExecuteGotoImpl<false, false>(Thread* self, const DexFile::CodeItem* code_item, 248 ShadowFrame& shadow_frame, JValue result_register); 249 template<> SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) 250 JValue ExecuteGotoImpl<true, true>(Thread* self, const DexFile::CodeItem* code_item, 251 ShadowFrame& shadow_frame, JValue result_register); 252 template<> SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) 253 JValue ExecuteGotoImpl<false, true>(Thread* self, const DexFile::CodeItem* code_item, 254 ShadowFrame& shadow_frame, JValue result_register); 255 #endif 256 257 static JValue Execute(Thread* self, const DexFile::CodeItem* code_item, ShadowFrame& shadow_frame, 258 JValue result_register) 259 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); 260 261 static inline JValue Execute(Thread* self, const DexFile::CodeItem* code_item, 262 ShadowFrame& shadow_frame, JValue result_register) { 263 DCHECK(!shadow_frame.GetMethod()->IsAbstract()); 264 DCHECK(!shadow_frame.GetMethod()->IsNative()); 265 shadow_frame.GetMethod()->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self); 266 267 bool transaction_active = Runtime::Current()->IsActiveTransaction(); 268 if (LIKELY(shadow_frame.GetMethod()->IsPreverified())) { 269 // Enter the "without access check" interpreter. 270 if (kInterpreterImplKind == kSwitchImpl) { 271 if (transaction_active) { 272 return ExecuteSwitchImpl<false, true>(self, code_item, shadow_frame, result_register); 273 } else { 274 return ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame, result_register); 275 } 276 } else { 277 DCHECK_EQ(kInterpreterImplKind, kComputedGotoImplKind); 278 if (transaction_active) { 279 return ExecuteGotoImpl<false, true>(self, code_item, shadow_frame, result_register); 280 } else { 281 return ExecuteGotoImpl<false, false>(self, code_item, shadow_frame, result_register); 282 } 283 } 284 } else { 285 // Enter the "with access check" interpreter. 286 if (kInterpreterImplKind == kSwitchImpl) { 287 if (transaction_active) { 288 return ExecuteSwitchImpl<true, true>(self, code_item, shadow_frame, result_register); 289 } else { 290 return ExecuteSwitchImpl<true, false>(self, code_item, shadow_frame, result_register); 291 } 292 } else { 293 DCHECK_EQ(kInterpreterImplKind, kComputedGotoImplKind); 294 if (transaction_active) { 295 return ExecuteGotoImpl<true, true>(self, code_item, shadow_frame, result_register); 296 } else { 297 return ExecuteGotoImpl<true, false>(self, code_item, shadow_frame, result_register); 298 } 299 } 300 } 301 } 302 303 void EnterInterpreterFromInvoke(Thread* self, ArtMethod* method, Object* receiver, 304 uint32_t* args, JValue* result) { 305 DCHECK_EQ(self, Thread::Current()); 306 bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks(); 307 if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEndForInterpreter(implicit_check))) { 308 ThrowStackOverflowError(self); 309 return; 310 } 311 312 const char* old_cause = self->StartAssertNoThreadSuspension("EnterInterpreterFromInvoke"); 313 const DexFile::CodeItem* code_item = method->GetCodeItem(); 314 uint16_t num_regs; 315 uint16_t num_ins; 316 if (code_item != nullptr) { 317 num_regs = code_item->registers_size_; 318 num_ins = code_item->ins_size_; 319 } else if (method->IsAbstract()) { 320 self->EndAssertNoThreadSuspension(old_cause); 321 ThrowAbstractMethodError(method); 322 return; 323 } else { 324 DCHECK(method->IsNative()); 325 num_regs = num_ins = ArtMethod::NumArgRegisters(method->GetShorty()); 326 if (!method->IsStatic()) { 327 num_regs++; 328 num_ins++; 329 } 330 } 331 // Set up shadow frame with matching number of reference slots to vregs. 332 ShadowFrame* last_shadow_frame = self->GetManagedStack()->GetTopShadowFrame(); 333 void* memory = alloca(ShadowFrame::ComputeSize(num_regs)); 334 ShadowFrame* shadow_frame(ShadowFrame::Create(num_regs, last_shadow_frame, method, 0, memory)); 335 self->PushShadowFrame(shadow_frame); 336 337 size_t cur_reg = num_regs - num_ins; 338 if (!method->IsStatic()) { 339 CHECK(receiver != nullptr); 340 shadow_frame->SetVRegReference(cur_reg, receiver); 341 ++cur_reg; 342 } 343 uint32_t shorty_len = 0; 344 const char* shorty = method->GetShorty(&shorty_len); 345 for (size_t shorty_pos = 0, arg_pos = 0; cur_reg < num_regs; ++shorty_pos, ++arg_pos, cur_reg++) { 346 DCHECK_LT(shorty_pos + 1, shorty_len); 347 switch (shorty[shorty_pos + 1]) { 348 case 'L': { 349 Object* o = reinterpret_cast<StackReference<Object>*>(&args[arg_pos])->AsMirrorPtr(); 350 shadow_frame->SetVRegReference(cur_reg, o); 351 break; 352 } 353 case 'J': case 'D': { 354 uint64_t wide_value = (static_cast<uint64_t>(args[arg_pos + 1]) << 32) | args[arg_pos]; 355 shadow_frame->SetVRegLong(cur_reg, wide_value); 356 cur_reg++; 357 arg_pos++; 358 break; 359 } 360 default: 361 shadow_frame->SetVReg(cur_reg, args[arg_pos]); 362 break; 363 } 364 } 365 self->EndAssertNoThreadSuspension(old_cause); 366 // Do this after populating the shadow frame in case EnsureInitialized causes a GC. 367 if (method->IsStatic() && UNLIKELY(!method->GetDeclaringClass()->IsInitialized())) { 368 ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); 369 StackHandleScope<1> hs(self); 370 Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass())); 371 if (UNLIKELY(!class_linker->EnsureInitialized(self, h_class, true, true))) { 372 CHECK(self->IsExceptionPending()); 373 self->PopShadowFrame(); 374 return; 375 } 376 } 377 if (LIKELY(!method->IsNative())) { 378 JValue r = Execute(self, code_item, *shadow_frame, JValue()); 379 if (result != nullptr) { 380 *result = r; 381 } 382 } else { 383 // We don't expect to be asked to interpret native code (which is entered via a JNI compiler 384 // generated stub) except during testing and image writing. 385 // Update args to be the args in the shadow frame since the input ones could hold stale 386 // references pointers due to moving GC. 387 args = shadow_frame->GetVRegArgs(method->IsStatic() ? 0 : 1); 388 if (!Runtime::Current()->IsStarted()) { 389 UnstartedRuntime::Jni(self, method, receiver, args, result); 390 } else { 391 InterpreterJni(self, method, shorty, receiver, args, result); 392 } 393 } 394 self->PopShadowFrame(); 395 } 396 397 void EnterInterpreterFromDeoptimize(Thread* self, ShadowFrame* shadow_frame, JValue* ret_val) 398 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 399 JValue value; 400 // Set value to last known result in case the shadow frame chain is empty. 401 value.SetJ(ret_val->GetJ()); 402 while (shadow_frame != nullptr) { 403 self->SetTopOfShadowStack(shadow_frame); 404 const DexFile::CodeItem* code_item = shadow_frame->GetMethod()->GetCodeItem(); 405 const uint32_t dex_pc = shadow_frame->GetDexPC(); 406 uint32_t new_dex_pc; 407 if (UNLIKELY(self->IsExceptionPending())) { 408 const instrumentation::Instrumentation* const instrumentation = 409 Runtime::Current()->GetInstrumentation(); 410 uint32_t found_dex_pc = FindNextInstructionFollowingException(self, *shadow_frame, dex_pc, 411 instrumentation); 412 new_dex_pc = found_dex_pc; // the dex pc of a matching catch handler 413 // or DexFile::kDexNoIndex if there is none. 414 } else { 415 const Instruction* instr = Instruction::At(&code_item->insns_[dex_pc]); 416 // For an invoke, use the dex pc of the next instruction. 417 // TODO: should be tested more once b/17586779 is fixed. 418 new_dex_pc = dex_pc + (instr->IsInvoke() ? instr->SizeInCodeUnits() : 0); 419 } 420 if (new_dex_pc != DexFile::kDexNoIndex) { 421 shadow_frame->SetDexPC(new_dex_pc); 422 value = Execute(self, code_item, *shadow_frame, value); 423 } 424 ShadowFrame* old_frame = shadow_frame; 425 shadow_frame = shadow_frame->GetLink(); 426 ShadowFrame::DeleteDeoptimizedFrame(old_frame); 427 } 428 ret_val->SetJ(value.GetJ()); 429 } 430 431 JValue EnterInterpreterFromEntryPoint(Thread* self, const DexFile::CodeItem* code_item, 432 ShadowFrame* shadow_frame) { 433 DCHECK_EQ(self, Thread::Current()); 434 bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks(); 435 if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEndForInterpreter(implicit_check))) { 436 ThrowStackOverflowError(self); 437 return JValue(); 438 } 439 440 return Execute(self, code_item, *shadow_frame, JValue()); 441 } 442 443 extern "C" void artInterpreterToInterpreterBridge(Thread* self, const DexFile::CodeItem* code_item, 444 ShadowFrame* shadow_frame, JValue* result) { 445 bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks(); 446 if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEndForInterpreter(implicit_check))) { 447 ThrowStackOverflowError(self); 448 return; 449 } 450 451 self->PushShadowFrame(shadow_frame); 452 // Ensure static methods are initialized. 453 const bool is_static = shadow_frame->GetMethod()->IsStatic(); 454 if (is_static) { 455 mirror::Class* declaring_class = shadow_frame->GetMethod()->GetDeclaringClass(); 456 if (UNLIKELY(!declaring_class->IsInitialized())) { 457 StackHandleScope<1> hs(self); 458 HandleWrapper<Class> h_declaring_class(hs.NewHandleWrapper(&declaring_class)); 459 if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized( 460 self, h_declaring_class, true, true))) { 461 DCHECK(self->IsExceptionPending()); 462 self->PopShadowFrame(); 463 return; 464 } 465 CHECK(h_declaring_class->IsInitializing()); 466 } 467 } 468 469 if (LIKELY(!shadow_frame->GetMethod()->IsNative())) { 470 result->SetJ(Execute(self, code_item, *shadow_frame, JValue()).GetJ()); 471 } else { 472 // We don't expect to be asked to interpret native code (which is entered via a JNI compiler 473 // generated stub) except during testing and image writing. 474 CHECK(!Runtime::Current()->IsStarted()); 475 Object* receiver = is_static ? nullptr : shadow_frame->GetVRegReference(0); 476 uint32_t* args = shadow_frame->GetVRegArgs(is_static ? 0 : 1); 477 UnstartedRuntime::Jni(self, shadow_frame->GetMethod(), receiver, args, result); 478 } 479 480 self->PopShadowFrame(); 481 } 482 483 } // namespace interpreter 484 } // namespace art 485