quick_trampoline_entrypoints.cc revision 468532ea115657709bc32ee498e701a4c71762d4
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 "callee_save_frame.h"
18#include "dex_file-inl.h"
19#include "dex_instruction-inl.h"
20#include "interpreter/interpreter.h"
21#include "invoke_arg_array_builder.h"
22#include "mirror/abstract_method-inl.h"
23#include "mirror/class-inl.h"
24#include "mirror/object-inl.h"
25#include "mirror/object_array-inl.h"
26#include "object_utils.h"
27#include "runtime.h"
28
29namespace art {
30
31// Visits the arguments as saved to the stack by a Runtime::kRefAndArgs callee save frame.
32class QuickArgumentVisitor {
33 public:
34// Offset to first (not the Method*) argument in a Runtime::kRefAndArgs callee save frame.
35// Size of Runtime::kRefAndArgs callee save frame.
36// Size of Method* and register parameters in out stack arguments.
37#if defined(__arm__)
38  // The callee save frame is pointed to by SP.
39  // | argN       |  |
40  // | ...        |  |
41  // | arg4       |  |
42  // | arg3 spill |  |  Caller's frame
43  // | arg2 spill |  |
44  // | arg1 spill |  |
45  // | Method*    | ---
46  // | LR         |
47  // | ...        |    callee saves
48  // | R3         |    arg3
49  // | R2         |    arg2
50  // | R1         |    arg1
51  // | R0         |
52  // | Method*    |  <- sp
53#define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 8
54#define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__LR_OFFSET 44
55#define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 48
56#define QUICK_STACK_ARG_SKIP 16
57#elif defined(__mips__)
58  // The callee save frame is pointed to by SP.
59  // | argN       |  |
60  // | ...        |  |
61  // | arg4       |  |
62  // | arg3 spill |  |  Caller's frame
63  // | arg2 spill |  |
64  // | arg1 spill |  |
65  // | Method*    | ---
66  // | RA         |
67  // | ...        |    callee saves
68  // | A3         |    arg3
69  // | A2         |    arg2
70  // | A1         |    arg1
71  // | A0/Method* |  <- sp
72#define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4
73#define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__LR_OFFSET 60
74#define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 64
75#define QUICK_STACK_ARG_SKIP 16
76#elif defined(__i386__)
77  // The callee save frame is pointed to by SP.
78  // | argN        |  |
79  // | ...         |  |
80  // | arg4        |  |
81  // | arg3 spill  |  |  Caller's frame
82  // | arg2 spill  |  |
83  // | arg1 spill  |  |
84  // | Method*     | ---
85  // | Return      |
86  // | EBP,ESI,EDI |    callee saves
87  // | EBX         |    arg3
88  // | EDX         |    arg2
89  // | ECX         |    arg1
90  // | EAX/Method* |  <- sp
91#define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 4
92#define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__LR_OFFSET 28
93#define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 32
94#define QUICK_STACK_ARG_SKIP 16
95#else
96#error "Unsupported architecture"
97#define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET 0
98#define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__LR_OFFSET 0
99#define QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE 0
100#define QUICK_STACK_ARG_SKIP 0
101#endif
102
103  static mirror::AbstractMethod* GetCallingMethod(mirror::AbstractMethod** sp) {
104    byte* previous_sp = reinterpret_cast<byte*>(sp) +
105        QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE;
106    return *reinterpret_cast<mirror::AbstractMethod**>(previous_sp);
107  }
108
109  static uintptr_t GetCallingPc(mirror::AbstractMethod** sp) {
110    byte* lr = reinterpret_cast<byte*>(sp) + QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__LR_OFFSET;
111    return *reinterpret_cast<uintptr_t*>(lr);
112  }
113
114  QuickArgumentVisitor(mirror::AbstractMethod** sp, bool is_static,
115                       const char* shorty, uint32_t shorty_len)
116    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) :
117    is_static_(is_static), shorty_(shorty), shorty_len_(shorty_len),
118    args_in_regs_(ComputeArgsInRegs(is_static, shorty, shorty_len)),
119    num_params_((is_static ? 0 : 1) + shorty_len - 1),  // +1 for this, -1 for return type
120    reg_args_(reinterpret_cast<byte*>(sp) + QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__R1_OFFSET),
121    stack_args_(reinterpret_cast<byte*>(sp) + QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE
122                + QUICK_STACK_ARG_SKIP),
123    cur_args_(reg_args_),
124    cur_arg_index_(0),
125    param_index_(0),
126    is_split_long_or_double_(false) {
127    DCHECK_EQ(static_cast<size_t>(QUICK_CALLEE_SAVE_FRAME__REF_AND_ARGS__FRAME_SIZE),
128              Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes());
129  }
130
131  virtual ~QuickArgumentVisitor() {}
132
133  virtual void Visit() = 0;
134
135  Primitive::Type GetParamPrimitiveType() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
136    size_t index = param_index_;
137    if (is_static_) {
138      index++;  // 0th argument must skip return value at start of the shorty
139    } else if (index == 0) {
140      return Primitive::kPrimNot;
141    }
142    CHECK_LT(index, shorty_len_);
143    return Primitive::GetType(shorty_[index]);
144  }
145
146  byte* GetParamAddress() const {
147    return cur_args_ + (cur_arg_index_ * kPointerSize);
148  }
149
150  bool IsSplitLongOrDouble() const {
151    return is_split_long_or_double_;
152  }
153
154  bool IsParamAReference() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
155    return GetParamPrimitiveType() == Primitive::kPrimNot;
156  }
157
158  bool IsParamALongOrDouble() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
159    Primitive::Type type = GetParamPrimitiveType();
160    return type == Primitive::kPrimLong || type == Primitive::kPrimDouble;
161  }
162
163  uint64_t ReadSplitLongParam() const {
164    DCHECK(IsSplitLongOrDouble());
165    uint64_t low_half = *reinterpret_cast<uint32_t*>(GetParamAddress());
166    uint64_t high_half = *reinterpret_cast<uint32_t*>(stack_args_);
167    return (low_half & 0xffffffffULL) | (high_half << 32);
168  }
169
170  void VisitArguments() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
171    for (cur_arg_index_ = 0;  cur_arg_index_ < args_in_regs_ && param_index_ < num_params_; ) {
172      is_split_long_or_double_ = (cur_arg_index_ == 2) && IsParamALongOrDouble();
173      Visit();
174      cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1);
175      param_index_++;
176    }
177    cur_args_ = stack_args_;
178    cur_arg_index_ = is_split_long_or_double_ ? 1 : 0;
179    is_split_long_or_double_ = false;
180    while (param_index_ < num_params_) {
181      Visit();
182      cur_arg_index_ += (IsParamALongOrDouble() ? 2 : 1);
183      param_index_++;
184    }
185  }
186
187 private:
188  static size_t ComputeArgsInRegs(bool is_static, const char* shorty, uint32_t shorty_len)
189      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
190    size_t args_in_regs = (is_static ? 0 : 1);
191    for (size_t i = 0; i < shorty_len; i++) {
192      char s = shorty[i];
193      if (s == 'J' || s == 'D') {
194        args_in_regs += 2;
195      } else {
196        args_in_regs++;
197      }
198      if (args_in_regs > 3) {
199        args_in_regs = 3;
200        break;
201      }
202    }
203    return args_in_regs;
204  }
205
206  const bool is_static_;
207  const char* const shorty_;
208  const uint32_t shorty_len_;
209  const size_t args_in_regs_;
210  const size_t num_params_;
211  byte* const reg_args_;
212  byte* const stack_args_;
213  byte* cur_args_;
214  size_t cur_arg_index_;
215  size_t param_index_;
216  // Does a 64bit parameter straddle the register and stack arguments?
217  bool is_split_long_or_double_;
218};
219
220// Visits arguments on the stack placing them into the shadow frame.
221class BuildShadowFrameVisitor : public QuickArgumentVisitor {
222 public:
223  BuildShadowFrameVisitor(mirror::AbstractMethod** sp, bool is_static, const char* shorty,
224                          uint32_t shorty_len, ShadowFrame& sf, size_t first_arg_reg) :
225    QuickArgumentVisitor(sp, is_static, shorty, shorty_len), sf_(sf), cur_reg_(first_arg_reg) {}
226
227  virtual void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
228    Primitive::Type type = GetParamPrimitiveType();
229    switch (type) {
230      case Primitive::kPrimLong:  // Fall-through.
231      case Primitive::kPrimDouble:
232        if (IsSplitLongOrDouble()) {
233          sf_.SetVRegLong(cur_reg_, ReadSplitLongParam());
234        } else {
235          sf_.SetVRegLong(cur_reg_, *reinterpret_cast<jlong*>(GetParamAddress()));
236        }
237        ++cur_reg_;
238        break;
239      case Primitive::kPrimNot:
240        sf_.SetVRegReference(cur_reg_, *reinterpret_cast<mirror::Object**>(GetParamAddress()));
241        break;
242      case Primitive::kPrimBoolean:  // Fall-through.
243      case Primitive::kPrimByte:     // Fall-through.
244      case Primitive::kPrimChar:     // Fall-through.
245      case Primitive::kPrimShort:    // Fall-through.
246      case Primitive::kPrimInt:      // Fall-through.
247      case Primitive::kPrimFloat:
248        sf_.SetVReg(cur_reg_, *reinterpret_cast<jint*>(GetParamAddress()));
249        break;
250      case Primitive::kPrimVoid:
251        LOG(FATAL) << "UNREACHABLE";
252        break;
253    }
254    ++cur_reg_;
255  }
256
257 private:
258  ShadowFrame& sf_;
259  size_t cur_reg_;
260
261  DISALLOW_COPY_AND_ASSIGN(BuildShadowFrameVisitor);
262};
263
264extern "C" uint64_t artQuickToInterpreterBridge(mirror::AbstractMethod* method, Thread* self,
265                                                mirror::AbstractMethod** sp)
266    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
267  // Ensure we don't get thread suspension until the object arguments are safely in the shadow
268  // frame.
269  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
270
271  if (method->IsAbstract()) {
272    ThrowAbstractMethodError(method);
273    return 0;
274  } else {
275    const char* old_cause = self->StartAssertNoThreadSuspension("Building interpreter shadow frame");
276    MethodHelper mh(method);
277    const DexFile::CodeItem* code_item = mh.GetCodeItem();
278    uint16_t num_regs = code_item->registers_size_;
279    void* memory = alloca(ShadowFrame::ComputeSize(num_regs));
280    ShadowFrame* shadow_frame(ShadowFrame::Create(num_regs, NULL,  // No last shadow coming from quick.
281                                                  method, 0, memory));
282    size_t first_arg_reg = code_item->registers_size_ - code_item->ins_size_;
283    BuildShadowFrameVisitor shadow_frame_builder(sp, mh.IsStatic(), mh.GetShorty(),
284                                                 mh.GetShortyLength(),
285                                                 *shadow_frame, first_arg_reg);
286    shadow_frame_builder.VisitArguments();
287    // Push a transition back into managed code onto the linked list in thread.
288    ManagedStack fragment;
289    self->PushManagedStackFragment(&fragment);
290    self->PushShadowFrame(shadow_frame);
291    self->EndAssertNoThreadSuspension(old_cause);
292
293    if (method->IsStatic() && !method->GetDeclaringClass()->IsInitializing()) {
294      // Ensure static method's class is initialized.
295      if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(method->GetDeclaringClass(),
296                                                                   true, true)) {
297        DCHECK(Thread::Current()->IsExceptionPending());
298        self->PopManagedStackFragment(fragment);
299        return 0;
300      }
301    }
302
303    JValue result = interpreter::EnterInterpreterFromStub(self, mh, code_item, *shadow_frame);
304    // Pop transition.
305    self->PopManagedStackFragment(fragment);
306    return result.GetJ();
307  }
308}
309
310// Visits arguments on the stack placing them into the args vector, Object* arguments are converted
311// to jobjects.
312class BuildQuickArgumentVisitor : public QuickArgumentVisitor {
313 public:
314  BuildQuickArgumentVisitor(mirror::AbstractMethod** sp, bool is_static, const char* shorty,
315                            uint32_t shorty_len, ScopedObjectAccessUnchecked* soa,
316                            std::vector<jvalue>* args) :
317    QuickArgumentVisitor(sp, is_static, shorty, shorty_len), soa_(soa), args_(args) {}
318
319  virtual void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
320    jvalue val;
321    Primitive::Type type = GetParamPrimitiveType();
322    switch (type) {
323      case Primitive::kPrimNot: {
324        mirror::Object* obj = *reinterpret_cast<mirror::Object**>(GetParamAddress());
325        val.l = soa_->AddLocalReference<jobject>(obj);
326        break;
327      }
328      case Primitive::kPrimLong:  // Fall-through.
329      case Primitive::kPrimDouble:
330        if (IsSplitLongOrDouble()) {
331          val.j = ReadSplitLongParam();
332        } else {
333          val.j = *reinterpret_cast<jlong*>(GetParamAddress());
334        }
335        break;
336      case Primitive::kPrimBoolean:  // Fall-through.
337      case Primitive::kPrimByte:     // Fall-through.
338      case Primitive::kPrimChar:     // Fall-through.
339      case Primitive::kPrimShort:    // Fall-through.
340      case Primitive::kPrimInt:      // Fall-through.
341      case Primitive::kPrimFloat:
342        val.i =  *reinterpret_cast<jint*>(GetParamAddress());
343        break;
344      case Primitive::kPrimVoid:
345        LOG(FATAL) << "UNREACHABLE";
346        val.j = 0;
347        break;
348    }
349    args_->push_back(val);
350  }
351
352 private:
353  ScopedObjectAccessUnchecked* soa_;
354  std::vector<jvalue>* args_;
355
356  DISALLOW_COPY_AND_ASSIGN(BuildQuickArgumentVisitor);
357};
358
359// Handler for invocation on proxy methods. On entry a frame will exist for the proxy object method
360// which is responsible for recording callee save registers. We explicitly place into jobjects the
361// incoming reference arguments (so they survive GC). We invoke the invocation handler, which is a
362// field within the proxy object, which will box the primitive arguments and deal with error cases.
363extern "C" uint64_t artQuickProxyInvokeHandler(mirror::AbstractMethod* proxy_method,
364                                               mirror::Object* receiver,
365                                               Thread* self, mirror::AbstractMethod** sp)
366    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
367  // Ensure we don't get thread suspension until the object arguments are safely in jobjects.
368  const char* old_cause =
369      self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments");
370  // Register the top of the managed stack, making stack crawlable.
371  DCHECK_EQ(*sp, proxy_method);
372  self->SetTopOfStack(sp, 0);
373  DCHECK_EQ(proxy_method->GetFrameSizeInBytes(),
374            Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetFrameSizeInBytes());
375  self->VerifyStack();
376  // Start new JNI local reference state.
377  JNIEnvExt* env = self->GetJniEnv();
378  ScopedObjectAccessUnchecked soa(env);
379  ScopedJniEnvLocalRefState env_state(env);
380  // Create local ref. copies of proxy method and the receiver.
381  jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver);
382
383  // Placing arguments into args vector and remove the receiver.
384  MethodHelper proxy_mh(proxy_method);
385  std::vector<jvalue> args;
386  BuildQuickArgumentVisitor local_ref_visitor(sp, proxy_mh.IsStatic(), proxy_mh.GetShorty(),
387                                              proxy_mh.GetShortyLength(), &soa, &args);
388  local_ref_visitor.VisitArguments();
389  args.erase(args.begin());
390
391  // Convert proxy method into expected interface method.
392  mirror::AbstractMethod* interface_method = proxy_method->FindOverriddenMethod();
393  DCHECK(interface_method != NULL);
394  DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
395  jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_method);
396
397  // All naked Object*s should now be in jobjects, so its safe to go into the main invoke code
398  // that performs allocations.
399  self->EndAssertNoThreadSuspension(old_cause);
400  JValue result = InvokeProxyInvocationHandler(soa, proxy_mh.GetShorty(),
401                                               rcvr_jobj, interface_method_jobj, args);
402  return result.GetJ();
403}
404
405// Read object references held in arguments from quick frames and place in a JNI local references,
406// so they don't get garbage collected.
407class RememberFoGcArgumentVisitor : public QuickArgumentVisitor {
408 public:
409  RememberFoGcArgumentVisitor(mirror::AbstractMethod** sp, bool is_static, const char* shorty,
410                              uint32_t shorty_len, ScopedObjectAccessUnchecked* soa) :
411    QuickArgumentVisitor(sp, is_static, shorty, shorty_len), soa_(soa) {}
412
413  virtual void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
414    if (IsParamAReference()) {
415      soa_->AddLocalReference<jobject>(*reinterpret_cast<mirror::Object**>(GetParamAddress()));
416    }
417  }
418
419 private:
420  ScopedObjectAccessUnchecked* soa_;
421
422  DISALLOW_COPY_AND_ASSIGN(RememberFoGcArgumentVisitor);
423};
424
425// Lazily resolve a method for quick. Called by stub code.
426extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* called,
427                                                    mirror::Object* receiver,
428                                                    Thread* thread, mirror::AbstractMethod** sp)
429    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
430  FinishCalleeSaveFrameSetup(thread, sp, Runtime::kRefsAndArgs);
431  // Start new JNI local reference state
432  JNIEnvExt* env = thread->GetJniEnv();
433  ScopedObjectAccessUnchecked soa(env);
434  ScopedJniEnvLocalRefState env_state(env);
435  const char* old_cause = thread->StartAssertNoThreadSuspension("Quick method resolution set up");
436
437  // Compute details about the called method (avoid GCs)
438  ClassLinker* linker = Runtime::Current()->GetClassLinker();
439  mirror::AbstractMethod* caller = QuickArgumentVisitor::GetCallingMethod(sp);
440  InvokeType invoke_type;
441  const DexFile* dex_file;
442  uint32_t dex_method_idx;
443  if (called->IsRuntimeMethod()) {
444    uint32_t dex_pc = caller->ToDexPc(QuickArgumentVisitor::GetCallingPc(sp));
445    const DexFile::CodeItem* code;
446    {
447      MethodHelper mh(caller);
448      dex_file = &mh.GetDexFile();
449      code = mh.GetCodeItem();
450    }
451    CHECK_LT(dex_pc, code->insns_size_in_code_units_);
452    const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
453    Instruction::Code instr_code = instr->Opcode();
454    bool is_range;
455    switch (instr_code) {
456      case Instruction::INVOKE_DIRECT:
457        invoke_type = kDirect;
458        is_range = false;
459        break;
460      case Instruction::INVOKE_DIRECT_RANGE:
461        invoke_type = kDirect;
462        is_range = true;
463        break;
464      case Instruction::INVOKE_STATIC:
465        invoke_type = kStatic;
466        is_range = false;
467        break;
468      case Instruction::INVOKE_STATIC_RANGE:
469        invoke_type = kStatic;
470        is_range = true;
471        break;
472      case Instruction::INVOKE_SUPER:
473        invoke_type = kSuper;
474        is_range = false;
475        break;
476      case Instruction::INVOKE_SUPER_RANGE:
477        invoke_type = kSuper;
478        is_range = true;
479        break;
480      case Instruction::INVOKE_VIRTUAL:
481        invoke_type = kVirtual;
482        is_range = false;
483        break;
484      case Instruction::INVOKE_VIRTUAL_RANGE:
485        invoke_type = kVirtual;
486        is_range = true;
487        break;
488      case Instruction::INVOKE_INTERFACE:
489        invoke_type = kInterface;
490        is_range = false;
491        break;
492      case Instruction::INVOKE_INTERFACE_RANGE:
493        invoke_type = kInterface;
494        is_range = true;
495        break;
496      default:
497        LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL);
498        // Avoid used uninitialized warnings.
499        invoke_type = kDirect;
500        is_range = false;
501    }
502    dex_method_idx = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c();
503
504  } else {
505    invoke_type = kStatic;
506    dex_file = &MethodHelper(called).GetDexFile();
507    dex_method_idx = called->GetDexMethodIndex();
508  }
509  uint32_t shorty_len;
510  const char* shorty =
511      dex_file->GetMethodShorty(dex_file->GetMethodId(dex_method_idx), &shorty_len);
512  RememberFoGcArgumentVisitor visitor(sp, invoke_type == kStatic, shorty, shorty_len, &soa);
513  visitor.VisitArguments();
514  thread->EndAssertNoThreadSuspension(old_cause);
515  // Resolve method filling in dex cache.
516  if (called->IsRuntimeMethod()) {
517    called = linker->ResolveMethod(dex_method_idx, caller, invoke_type);
518  }
519  const void* code = NULL;
520  if (LIKELY(!thread->IsExceptionPending())) {
521    // Incompatible class change should have been handled in resolve method.
522    CHECK(!called->CheckIncompatibleClassChange(invoke_type));
523    // Refine called method based on receiver.
524    if (invoke_type == kVirtual) {
525      called = receiver->GetClass()->FindVirtualMethodForVirtual(called);
526    } else if (invoke_type == kInterface) {
527      called = receiver->GetClass()->FindVirtualMethodForInterface(called);
528    }
529    // Ensure that the called method's class is initialized.
530    mirror::Class* called_class = called->GetDeclaringClass();
531    linker->EnsureInitialized(called_class, true, true);
532    if (LIKELY(called_class->IsInitialized())) {
533      code = called->GetEntryPointFromCompiledCode();
534    } else if (called_class->IsInitializing()) {
535      if (invoke_type == kStatic) {
536        // Class is still initializing, go to oat and grab code (trampoline must be left in place
537        // until class is initialized to stop races between threads).
538        code = linker->GetOatCodeFor(called);
539      } else {
540        // No trampoline for non-static methods.
541        code = called->GetEntryPointFromCompiledCode();
542      }
543    } else {
544      DCHECK(called_class->IsErroneous());
545    }
546  }
547  CHECK_EQ(code == NULL, thread->IsExceptionPending());
548#ifdef MOVING_GARBAGE_COLLECTOR
549  // TODO: locally saved objects may have moved during a GC during resolution. Need to update the
550  //       registers so that the stale objects aren't passed to the method we've resolved.
551    UNIMPLEMENTED(WARNING);
552#endif
553  // Place called method in callee-save frame to be placed as first argument to quick method.
554  *sp = called;
555  return code;
556}
557
558}  // namespace art
559