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