art_method.cc revision f677ebfd832c9c614fea5e6735725fec2f7a3f2a
1/*
2 * Copyright (C) 2011 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 "art_method.h"
18
19#include "arch/context.h"
20#include "art_field-inl.h"
21#include "art_method-inl.h"
22#include "base/stringpiece.h"
23#include "dex_file-inl.h"
24#include "dex_instruction.h"
25#include "entrypoints/entrypoint_utils.h"
26#include "entrypoints/runtime_asm_entrypoints.h"
27#include "gc/accounting/card_table-inl.h"
28#include "interpreter/interpreter.h"
29#include "jit/jit.h"
30#include "jit/jit_code_cache.h"
31#include "jni_internal.h"
32#include "mapping_table.h"
33#include "mirror/abstract_method.h"
34#include "mirror/class-inl.h"
35#include "mirror/object_array-inl.h"
36#include "mirror/object-inl.h"
37#include "mirror/string.h"
38#include "scoped_thread_state_change.h"
39#include "well_known_classes.h"
40
41namespace art {
42
43extern "C" void art_quick_invoke_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*,
44                                      const char*);
45#if defined(__LP64__) || defined(__arm__) || defined(__i386__)
46extern "C" void art_quick_invoke_static_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*,
47                                             const char*);
48#endif
49
50ArtMethod* ArtMethod::FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable& soa,
51                                          jobject jlr_method) {
52  auto* abstract_method = soa.Decode<mirror::AbstractMethod*>(jlr_method);
53  DCHECK(abstract_method != nullptr);
54  return abstract_method->GetArtMethod();
55}
56
57mirror::String* ArtMethod::GetNameAsString(Thread* self) {
58  CHECK(!IsProxyMethod());
59  StackHandleScope<1> hs(self);
60  Handle<mirror::DexCache> dex_cache(hs.NewHandle(GetDexCache()));
61  auto* dex_file = dex_cache->GetDexFile();
62  uint32_t dex_method_idx = GetDexMethodIndex();
63  const DexFile::MethodId& method_id = dex_file->GetMethodId(dex_method_idx);
64  return Runtime::Current()->GetClassLinker()->ResolveString(*dex_file, method_id.name_idx_,
65                                                             dex_cache);
66}
67
68InvokeType ArtMethod::GetInvokeType() {
69  // TODO: kSuper?
70  if (GetDeclaringClass()->IsInterface()) {
71    return kInterface;
72  } else if (IsStatic()) {
73    return kStatic;
74  } else if (IsDirect()) {
75    return kDirect;
76  } else {
77    return kVirtual;
78  }
79}
80
81size_t ArtMethod::NumArgRegisters(const StringPiece& shorty) {
82  CHECK_LE(1U, shorty.length());
83  uint32_t num_registers = 0;
84  for (size_t i = 1; i < shorty.length(); ++i) {
85    char ch = shorty[i];
86    if (ch == 'D' || ch == 'J') {
87      num_registers += 2;
88    } else {
89      num_registers += 1;
90    }
91  }
92  return num_registers;
93}
94
95static bool HasSameNameAndSignature(ArtMethod* method1, ArtMethod* method2)
96    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
97  ScopedAssertNoThreadSuspension ants(Thread::Current(), "HasSameNameAndSignature");
98  const DexFile* dex_file = method1->GetDexFile();
99  const DexFile::MethodId& mid = dex_file->GetMethodId(method1->GetDexMethodIndex());
100  if (method1->GetDexCache() == method2->GetDexCache()) {
101    const DexFile::MethodId& mid2 = dex_file->GetMethodId(method2->GetDexMethodIndex());
102    return mid.name_idx_ == mid2.name_idx_ && mid.proto_idx_ == mid2.proto_idx_;
103  }
104  const DexFile* dex_file2 = method2->GetDexFile();
105  const DexFile::MethodId& mid2 = dex_file2->GetMethodId(method2->GetDexMethodIndex());
106  if (!DexFileStringEquals(dex_file, mid.name_idx_, dex_file2, mid2.name_idx_)) {
107    return false;  // Name mismatch.
108  }
109  return dex_file->GetMethodSignature(mid) == dex_file2->GetMethodSignature(mid2);
110}
111
112ArtMethod* ArtMethod::FindOverriddenMethod(size_t pointer_size) {
113  if (IsStatic()) {
114    return nullptr;
115  }
116  mirror::Class* declaring_class = GetDeclaringClass();
117  mirror::Class* super_class = declaring_class->GetSuperClass();
118  uint16_t method_index = GetMethodIndex();
119  ArtMethod* result = nullptr;
120  // Did this method override a super class method? If so load the result from the super class'
121  // vtable
122  if (super_class->HasVTable() && method_index < super_class->GetVTableLength()) {
123    result = super_class->GetVTableEntry(method_index, pointer_size);
124  } else {
125    // Method didn't override superclass method so search interfaces
126    if (IsProxyMethod()) {
127      result = GetDexCacheResolvedMethods()->GetElementPtrSize<ArtMethod*>(
128          GetDexMethodIndex(), pointer_size);
129      CHECK_EQ(result,
130               Runtime::Current()->GetClassLinker()->FindMethodForProxy(GetDeclaringClass(), this));
131    } else {
132      mirror::IfTable* iftable = GetDeclaringClass()->GetIfTable();
133      for (size_t i = 0; i < iftable->Count() && result == nullptr; i++) {
134        mirror::Class* interface = iftable->GetInterface(i);
135        for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) {
136          ArtMethod* interface_method = interface->GetVirtualMethod(j, pointer_size);
137          if (HasSameNameAndSignature(
138              this, interface_method->GetInterfaceMethodIfProxy(sizeof(void*)))) {
139            result = interface_method;
140            break;
141          }
142        }
143      }
144    }
145  }
146  DCHECK(result == nullptr || HasSameNameAndSignature(
147      GetInterfaceMethodIfProxy(sizeof(void*)), result->GetInterfaceMethodIfProxy(sizeof(void*))));
148  return result;
149}
150
151uint32_t ArtMethod::FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile,
152                                                     uint32_t name_and_signature_idx) {
153  const DexFile* dexfile = GetDexFile();
154  const uint32_t dex_method_idx = GetDexMethodIndex();
155  const DexFile::MethodId& mid = dexfile->GetMethodId(dex_method_idx);
156  const DexFile::MethodId& name_and_sig_mid = other_dexfile.GetMethodId(name_and_signature_idx);
157  DCHECK_STREQ(dexfile->GetMethodName(mid), other_dexfile.GetMethodName(name_and_sig_mid));
158  DCHECK_EQ(dexfile->GetMethodSignature(mid), other_dexfile.GetMethodSignature(name_and_sig_mid));
159  if (dexfile == &other_dexfile) {
160    return dex_method_idx;
161  }
162  const char* mid_declaring_class_descriptor = dexfile->StringByTypeIdx(mid.class_idx_);
163  const DexFile::StringId* other_descriptor =
164      other_dexfile.FindStringId(mid_declaring_class_descriptor);
165  if (other_descriptor != nullptr) {
166    const DexFile::TypeId* other_type_id =
167        other_dexfile.FindTypeId(other_dexfile.GetIndexForStringId(*other_descriptor));
168    if (other_type_id != nullptr) {
169      const DexFile::MethodId* other_mid = other_dexfile.FindMethodId(
170          *other_type_id, other_dexfile.GetStringId(name_and_sig_mid.name_idx_),
171          other_dexfile.GetProtoId(name_and_sig_mid.proto_idx_));
172      if (other_mid != nullptr) {
173        return other_dexfile.GetIndexForMethodId(*other_mid);
174      }
175    }
176  }
177  return DexFile::kDexNoIndex;
178}
179
180uint32_t ArtMethod::ToDexPc(const uintptr_t pc, bool abort_on_failure) {
181  const void* entry_point = GetQuickOatEntryPoint(sizeof(void*));
182  uint32_t sought_offset = pc - reinterpret_cast<uintptr_t>(entry_point);
183  if (IsOptimized(sizeof(void*))) {
184    CodeInfo code_info = GetOptimizedCodeInfo();
185    StackMapEncoding encoding = code_info.ExtractEncoding();
186    StackMap stack_map = code_info.GetStackMapForNativePcOffset(sought_offset, encoding);
187    if (stack_map.IsValid()) {
188      return stack_map.GetDexPc(encoding);
189    }
190  } else {
191    MappingTable table(entry_point != nullptr ?
192        GetMappingTable(EntryPointToCodePointer(entry_point), sizeof(void*)) : nullptr);
193    if (table.TotalSize() == 0) {
194      // NOTE: Special methods (see Mir2Lir::GenSpecialCase()) have an empty mapping
195      // but they have no suspend checks and, consequently, we never call ToDexPc() for them.
196      DCHECK(IsNative() || IsCalleeSaveMethod() || IsProxyMethod()) << PrettyMethod(this);
197      return DexFile::kDexNoIndex;   // Special no mapping case
198    }
199    // Assume the caller wants a pc-to-dex mapping so check here first.
200    typedef MappingTable::PcToDexIterator It;
201    for (It cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) {
202      if (cur.NativePcOffset() == sought_offset) {
203        return cur.DexPc();
204      }
205    }
206    // Now check dex-to-pc mappings.
207    typedef MappingTable::DexToPcIterator It2;
208    for (It2 cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) {
209      if (cur.NativePcOffset() == sought_offset) {
210        return cur.DexPc();
211      }
212    }
213  }
214  if (abort_on_failure) {
215      LOG(FATAL) << "Failed to find Dex offset for PC offset " << reinterpret_cast<void*>(sought_offset)
216             << "(PC " << reinterpret_cast<void*>(pc) << ", entry_point=" << entry_point
217             << " current entry_point=" << GetQuickOatEntryPoint(sizeof(void*))
218             << ") in " << PrettyMethod(this);
219  }
220  return DexFile::kDexNoIndex;
221}
222
223uintptr_t ArtMethod::ToNativeQuickPc(const uint32_t dex_pc, bool abort_on_failure) {
224  const void* entry_point = GetQuickOatEntryPoint(sizeof(void*));
225  MappingTable table(entry_point != nullptr ?
226      GetMappingTable(EntryPointToCodePointer(entry_point), sizeof(void*)) : nullptr);
227  if (table.TotalSize() == 0) {
228    DCHECK_EQ(dex_pc, 0U);
229    return 0;   // Special no mapping/pc == 0 case
230  }
231  // Assume the caller wants a dex-to-pc mapping so check here first.
232  typedef MappingTable::DexToPcIterator It;
233  for (It cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) {
234    if (cur.DexPc() == dex_pc) {
235      return reinterpret_cast<uintptr_t>(entry_point) + cur.NativePcOffset();
236    }
237  }
238  // Now check pc-to-dex mappings.
239  typedef MappingTable::PcToDexIterator It2;
240  for (It2 cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) {
241    if (cur.DexPc() == dex_pc) {
242      return reinterpret_cast<uintptr_t>(entry_point) + cur.NativePcOffset();
243    }
244  }
245  if (abort_on_failure) {
246    LOG(FATAL) << "Failed to find native offset for dex pc 0x" << std::hex << dex_pc
247               << " in " << PrettyMethod(this);
248  }
249  return UINTPTR_MAX;
250}
251
252uint32_t ArtMethod::FindCatchBlock(Handle<mirror::Class> exception_type,
253                                   uint32_t dex_pc, bool* has_no_move_exception) {
254  const DexFile::CodeItem* code_item = GetCodeItem();
255  // Set aside the exception while we resolve its type.
256  Thread* self = Thread::Current();
257  StackHandleScope<1> hs(self);
258  Handle<mirror::Throwable> exception(hs.NewHandle(self->GetException()));
259  self->ClearException();
260  // Default to handler not found.
261  uint32_t found_dex_pc = DexFile::kDexNoIndex;
262  // Iterate over the catch handlers associated with dex_pc.
263  for (CatchHandlerIterator it(*code_item, dex_pc); it.HasNext(); it.Next()) {
264    uint16_t iter_type_idx = it.GetHandlerTypeIndex();
265    // Catch all case
266    if (iter_type_idx == DexFile::kDexNoIndex16) {
267      found_dex_pc = it.GetHandlerAddress();
268      break;
269    }
270    // Does this catch exception type apply?
271    mirror::Class* iter_exception_type = GetClassFromTypeIndex(iter_type_idx, true);
272    if (UNLIKELY(iter_exception_type == nullptr)) {
273      // Now have a NoClassDefFoundError as exception. Ignore in case the exception class was
274      // removed by a pro-guard like tool.
275      // Note: this is not RI behavior. RI would have failed when loading the class.
276      self->ClearException();
277      // Delete any long jump context as this routine is called during a stack walk which will
278      // release its in use context at the end.
279      delete self->GetLongJumpContext();
280      LOG(WARNING) << "Unresolved exception class when finding catch block: "
281        << DescriptorToDot(GetTypeDescriptorFromTypeIdx(iter_type_idx));
282    } else if (iter_exception_type->IsAssignableFrom(exception_type.Get())) {
283      found_dex_pc = it.GetHandlerAddress();
284      break;
285    }
286  }
287  if (found_dex_pc != DexFile::kDexNoIndex) {
288    const Instruction* first_catch_instr =
289        Instruction::At(&code_item->insns_[found_dex_pc]);
290    *has_no_move_exception = (first_catch_instr->Opcode() != Instruction::MOVE_EXCEPTION);
291  }
292  // Put the exception back.
293  if (exception.Get() != nullptr) {
294    self->SetException(exception.Get());
295  }
296  return found_dex_pc;
297}
298
299void ArtMethod::AssertPcIsWithinQuickCode(uintptr_t pc) {
300  if (IsNative() || IsRuntimeMethod() || IsProxyMethod()) {
301    return;
302  }
303  if (pc == reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc())) {
304    return;
305  }
306  const void* code = GetEntryPointFromQuickCompiledCode();
307  if (code == GetQuickInstrumentationEntryPoint()) {
308    return;
309  }
310  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
311  if (class_linker->IsQuickToInterpreterBridge(code) ||
312      class_linker->IsQuickResolutionStub(code)) {
313    return;
314  }
315  // If we are the JIT then we may have just compiled the method after the
316  // IsQuickToInterpreterBridge check.
317  jit::Jit* const jit = Runtime::Current()->GetJit();
318  if (jit != nullptr &&
319      jit->GetCodeCache()->ContainsCodePtr(reinterpret_cast<const void*>(code))) {
320    return;
321  }
322  /*
323   * During a stack walk, a return PC may point past-the-end of the code
324   * in the case that the last instruction is a call that isn't expected to
325   * return.  Thus, we check <= code + GetCodeSize().
326   *
327   * NOTE: For Thumb both pc and code are offset by 1 indicating the Thumb state.
328   */
329  CHECK(PcIsWithinQuickCode(reinterpret_cast<uintptr_t>(code), pc))
330      << PrettyMethod(this)
331      << " pc=" << std::hex << pc
332      << " code=" << code
333      << " size=" << GetCodeSize(
334          EntryPointToCodePointer(reinterpret_cast<const void*>(code)));
335}
336
337bool ArtMethod::IsEntrypointInterpreter() {
338  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
339  const void* oat_quick_code = class_linker->GetOatMethodQuickCodeFor(this);
340  return oat_quick_code == nullptr || oat_quick_code != GetEntryPointFromQuickCompiledCode();
341}
342
343const void* ArtMethod::GetQuickOatEntryPoint(size_t pointer_size) {
344  if (IsAbstract() || IsRuntimeMethod() || IsProxyMethod()) {
345    return nullptr;
346  }
347  Runtime* runtime = Runtime::Current();
348  ClassLinker* class_linker = runtime->GetClassLinker();
349  const void* code = runtime->GetInstrumentation()->GetQuickCodeFor(this, pointer_size);
350  // On failure, instead of null we get the quick-generic-jni-trampoline for native method
351  // indicating the generic JNI, or the quick-to-interpreter-bridge (but not the trampoline)
352  // for non-native methods.
353  if (class_linker->IsQuickToInterpreterBridge(code) ||
354      class_linker->IsQuickGenericJniStub(code)) {
355    return nullptr;
356  }
357  return code;
358}
359
360#ifndef NDEBUG
361uintptr_t ArtMethod::NativeQuickPcOffset(const uintptr_t pc, const void* quick_entry_point) {
362  CHECK_NE(quick_entry_point, GetQuickToInterpreterBridge());
363  CHECK_EQ(quick_entry_point,
364           Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(this, sizeof(void*)));
365  return pc - reinterpret_cast<uintptr_t>(quick_entry_point);
366}
367#endif
368
369void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result,
370                       const char* shorty) {
371  if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEnd())) {
372    ThrowStackOverflowError(self);
373    return;
374  }
375
376  if (kIsDebugBuild) {
377    self->AssertThreadSuspensionIsAllowable();
378    CHECK_EQ(kRunnable, self->GetState());
379    CHECK_STREQ(GetInterfaceMethodIfProxy(sizeof(void*))->GetShorty(), shorty);
380  }
381
382  // Push a transition back into managed code onto the linked list in thread.
383  ManagedStack fragment;
384  self->PushManagedStackFragment(&fragment);
385
386  Runtime* runtime = Runtime::Current();
387  // Call the invoke stub, passing everything as arguments.
388  // If the runtime is not yet started or it is required by the debugger, then perform the
389  // Invocation by the interpreter.
390  if (UNLIKELY(!runtime->IsStarted() || Dbg::IsForcedInterpreterNeededForCalling(self, this))) {
391    if (IsStatic()) {
392      art::interpreter::EnterInterpreterFromInvoke(self, this, nullptr, args, result);
393    } else {
394      mirror::Object* receiver =
395          reinterpret_cast<StackReference<mirror::Object>*>(&args[0])->AsMirrorPtr();
396      art::interpreter::EnterInterpreterFromInvoke(self, this, receiver, args + 1, result);
397    }
398  } else {
399    DCHECK_EQ(runtime->GetClassLinker()->GetImagePointerSize(), sizeof(void*));
400
401    constexpr bool kLogInvocationStartAndReturn = false;
402    bool have_quick_code = GetEntryPointFromQuickCompiledCode() != nullptr;
403    if (LIKELY(have_quick_code)) {
404      if (kLogInvocationStartAndReturn) {
405        LOG(INFO) << StringPrintf(
406            "Invoking '%s' quick code=%p static=%d", PrettyMethod(this).c_str(),
407            GetEntryPointFromQuickCompiledCode(), static_cast<int>(IsStatic() ? 1 : 0));
408      }
409
410      // Ensure that we won't be accidentally calling quick compiled code when -Xint.
411      if (kIsDebugBuild && runtime->GetInstrumentation()->IsForcedInterpretOnly()) {
412        DCHECK(!runtime->UseJit());
413        CHECK(IsEntrypointInterpreter())
414            << "Don't call compiled code when -Xint " << PrettyMethod(this);
415      }
416
417#if defined(__LP64__) || defined(__arm__) || defined(__i386__)
418      if (!IsStatic()) {
419        (*art_quick_invoke_stub)(this, args, args_size, self, result, shorty);
420      } else {
421        (*art_quick_invoke_static_stub)(this, args, args_size, self, result, shorty);
422      }
423#else
424      (*art_quick_invoke_stub)(this, args, args_size, self, result, shorty);
425#endif
426      if (UNLIKELY(self->GetException() == Thread::GetDeoptimizationException())) {
427        // Unusual case where we were running generated code and an
428        // exception was thrown to force the activations to be removed from the
429        // stack. Continue execution in the interpreter.
430        self->ClearException();
431        ShadowFrame* shadow_frame = self->GetAndClearDeoptimizationShadowFrame(result);
432        self->SetTopOfStack(nullptr);
433        self->SetTopOfShadowStack(shadow_frame);
434        interpreter::EnterInterpreterFromDeoptimize(self, shadow_frame, result);
435      }
436      if (kLogInvocationStartAndReturn) {
437        LOG(INFO) << StringPrintf("Returned '%s' quick code=%p", PrettyMethod(this).c_str(),
438                                  GetEntryPointFromQuickCompiledCode());
439      }
440    } else {
441      LOG(INFO) << "Not invoking '" << PrettyMethod(this) << "' code=null";
442      if (result != nullptr) {
443        result->SetJ(0);
444      }
445    }
446  }
447
448  // Pop transition.
449  self->PopManagedStackFragment(fragment);
450}
451
452// Counts the number of references in the parameter list of the corresponding method.
453// Note: Thus does _not_ include "this" for non-static methods.
454static uint32_t GetNumberOfReferenceArgsWithoutReceiver(ArtMethod* method)
455    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
456  uint32_t shorty_len;
457  const char* shorty = method->GetShorty(&shorty_len);
458  uint32_t refs = 0;
459  for (uint32_t i = 1; i < shorty_len ; ++i) {
460    if (shorty[i] == 'L') {
461      refs++;
462    }
463  }
464  return refs;
465}
466
467QuickMethodFrameInfo ArtMethod::GetQuickFrameInfo() {
468  Runtime* runtime = Runtime::Current();
469
470  if (UNLIKELY(IsAbstract())) {
471    return runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
472  }
473
474  // This goes before IsProxyMethod since runtime methods have a null declaring class.
475  if (UNLIKELY(IsRuntimeMethod())) {
476    return runtime->GetRuntimeMethodFrameInfo(this);
477  }
478
479  // For Proxy method we add special handling for the direct method case  (there is only one
480  // direct method - constructor). Direct method is cloned from original
481  // java.lang.reflect.Proxy class together with code and as a result it is executed as usual
482  // quick compiled method without any stubs. So the frame info should be returned as it is a
483  // quick method not a stub. However, if instrumentation stubs are installed, the
484  // instrumentation->GetQuickCodeFor() returns the artQuickProxyInvokeHandler instead of an
485  // oat code pointer, thus we have to add a special case here.
486  if (UNLIKELY(IsProxyMethod())) {
487    if (IsDirect()) {
488      CHECK(IsConstructor());
489      return GetQuickFrameInfo(EntryPointToCodePointer(GetEntryPointFromQuickCompiledCode()));
490    } else {
491      return runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
492    }
493  }
494
495  const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(this, sizeof(void*));
496  ClassLinker* class_linker = runtime->GetClassLinker();
497  // On failure, instead of null we get the quick-generic-jni-trampoline for native method
498  // indicating the generic JNI, or the quick-to-interpreter-bridge (but not the trampoline)
499  // for non-native methods. And we really shouldn't see a failure for non-native methods here.
500  DCHECK(!class_linker->IsQuickToInterpreterBridge(entry_point));
501
502  if (class_linker->IsQuickGenericJniStub(entry_point)) {
503    // Generic JNI frame.
504    DCHECK(IsNative());
505    uint32_t handle_refs = GetNumberOfReferenceArgsWithoutReceiver(this) + 1;
506    size_t scope_size = HandleScope::SizeOf(handle_refs);
507    QuickMethodFrameInfo callee_info = runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
508
509    // Callee saves + handle scope + method ref + alignment
510    // Note: -sizeof(void*) since callee-save frame stores a whole method pointer.
511    size_t frame_size = RoundUp(callee_info.FrameSizeInBytes() - sizeof(void*) +
512                                sizeof(ArtMethod*) + scope_size, kStackAlignment);
513    return QuickMethodFrameInfo(frame_size, callee_info.CoreSpillMask(), callee_info.FpSpillMask());
514  }
515
516  const void* code_pointer = EntryPointToCodePointer(entry_point);
517  return GetQuickFrameInfo(code_pointer);
518}
519
520void ArtMethod::RegisterNative(const void* native_method, bool is_fast) {
521  CHECK(IsNative()) << PrettyMethod(this);
522  CHECK(!IsFastNative()) << PrettyMethod(this);
523  CHECK(native_method != nullptr) << PrettyMethod(this);
524  if (is_fast) {
525    SetAccessFlags(GetAccessFlags() | kAccFastNative);
526  }
527  SetEntryPointFromJni(native_method);
528}
529
530void ArtMethod::UnregisterNative() {
531  CHECK(IsNative() && !IsFastNative()) << PrettyMethod(this);
532  // restore stub to lookup native pointer via dlsym
533  RegisterNative(GetJniDlsymLookupStub(), false);
534}
535
536bool ArtMethod::EqualParameters(Handle<mirror::ObjectArray<mirror::Class>> params) {
537  auto* dex_cache = GetDexCache();
538  auto* dex_file = dex_cache->GetDexFile();
539  const auto& method_id = dex_file->GetMethodId(GetDexMethodIndex());
540  const auto& proto_id = dex_file->GetMethodPrototype(method_id);
541  const DexFile::TypeList* proto_params = dex_file->GetProtoParameters(proto_id);
542  auto count = proto_params != nullptr ? proto_params->Size() : 0u;
543  auto param_len = params.Get() != nullptr ? params->GetLength() : 0u;
544  if (param_len != count) {
545    return false;
546  }
547  auto* cl = Runtime::Current()->GetClassLinker();
548  for (size_t i = 0; i < count; ++i) {
549    auto type_idx = proto_params->GetTypeItem(i).type_idx_;
550    auto* type = cl->ResolveType(type_idx, this);
551    if (type == nullptr) {
552      Thread::Current()->AssertPendingException();
553      return false;
554    }
555    if (type != params->GetWithoutChecks(i)) {
556      return false;
557    }
558  }
559  return true;
560}
561
562}  // namespace art
563