• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef ART_RUNTIME_ART_METHOD_INL_H_
18 #define ART_RUNTIME_ART_METHOD_INL_H_
19 
20 #include "art_method.h"
21 
22 #include "art_field.h"
23 #include "base/callee_save_type.h"
24 #include "class_linker-inl.h"
25 #include "common_throws.h"
26 #include "dex/code_item_accessors-inl.h"
27 #include "dex/dex_file-inl.h"
28 #include "dex/dex_file_annotations.h"
29 #include "dex/dex_file_types.h"
30 #include "dex/invoke_type.h"
31 #include "dex/primitive.h"
32 #include "dex/signature.h"
33 #include "gc_root-inl.h"
34 #include "imtable-inl.h"
35 #include "intrinsics_enum.h"
36 #include "jit/jit.h"
37 #include "jit/profiling_info.h"
38 #include "mirror/class-inl.h"
39 #include "mirror/dex_cache-inl.h"
40 #include "mirror/object-inl.h"
41 #include "mirror/object_array.h"
42 #include "mirror/string.h"
43 #include "obj_ptr-inl.h"
44 #include "quick/quick_method_frame_info.h"
45 #include "read_barrier-inl.h"
46 #include "runtime-inl.h"
47 #include "thread-current-inl.h"
48 
49 namespace art {
50 
51 namespace detail {
52 
53 template <> struct ShortyTraits<'V'> {
54   using Type = void;
55   static Type Get(const JValue& value ATTRIBUTE_UNUSED) {}
56   // `kVRegCount` and `Set()` are not defined.
57 };
58 
59 template <> struct ShortyTraits<'Z'> {
60   // Despite using `uint8_t` for `boolean` in `JValue`, we shall use `bool` here.
61   using Type = bool;
62   static Type Get(const JValue& value) { return value.GetZ() != 0u; }
63   static constexpr size_t kVRegCount = 1u;
64   static void Set(uint32_t* args, Type value) { args[0] = static_cast<uint32_t>(value ? 1u : 0u); }
65 };
66 
67 template <> struct ShortyTraits<'B'> {
68   using Type = int8_t;
69   static Type Get(const JValue& value) { return value.GetB(); }
70   static constexpr size_t kVRegCount = 1u;
71   static void Set(uint32_t* args, Type value) { args[0] = static_cast<uint32_t>(value); }
72 };
73 
74 template <> struct ShortyTraits<'C'> {
75   using Type = uint16_t;
76   static Type Get(const JValue& value) { return value.GetC(); }
77   static constexpr size_t kVRegCount = 1u;
78   static void Set(uint32_t* args, Type value) { args[0] = static_cast<uint32_t>(value); }
79 };
80 
81 template <> struct ShortyTraits<'S'> {
82   using Type = int16_t;
83   static Type Get(const JValue& value) { return value.GetS(); }
84   static constexpr size_t kVRegCount = 1u;
85   static void Set(uint32_t* args, Type value) { args[0] = static_cast<uint32_t>(value); }
86 };
87 
88 template <> struct ShortyTraits<'I'> {
89   using Type = int32_t;
90   static Type Get(const JValue& value) { return value.GetI(); }
91   static constexpr size_t kVRegCount = 1u;
92   static void Set(uint32_t* args, Type value) { args[0] = static_cast<uint32_t>(value); }
93 };
94 
95 template <> struct ShortyTraits<'J'> {
96   using Type = int64_t;
97   static Type Get(const JValue& value) { return value.GetJ(); }
98   static constexpr size_t kVRegCount = 2u;
99   static void Set(uint32_t* args, Type value) {
100     // Little-endian representation.
101     args[0] = static_cast<uint32_t>(value);
102     args[1] = static_cast<uint32_t>(static_cast<uint64_t>(value) >> 32);
103   }
104 };
105 
106 template <> struct ShortyTraits<'F'> {
107   using Type = float;
108   static Type Get(const JValue& value) { return value.GetF(); }
109   static constexpr size_t kVRegCount = 1u;
110   static void Set(uint32_t* args, Type value) { args[0] = bit_cast<uint32_t>(value); }
111 };
112 
113 template <> struct ShortyTraits<'D'> {
114   using Type = double;
115   static Type Get(const JValue& value) { return value.GetD(); }
116   static constexpr size_t kVRegCount = 2u;
117   static void Set(uint32_t* args, Type value) {
118     // Little-endian representation.
119     uint64_t v = bit_cast<uint64_t>(value);
120     args[0] = static_cast<uint32_t>(v);
121     args[1] = static_cast<uint32_t>(v >> 32);
122   }
123 };
124 
125 template <> struct ShortyTraits<'L'> {
126   using Type = ObjPtr<mirror::Object>;
127   static Type Get(const JValue& value) REQUIRES_SHARED(Locks::mutator_lock_) {
128       return value.GetL();
129   }
130   static constexpr size_t kVRegCount = 1u;
131   static void Set(uint32_t* args, Type value) REQUIRES_SHARED(Locks::mutator_lock_) {
132     args[0] = StackReference<mirror::Object>::FromMirrorPtr(value.Ptr()).AsVRegValue();
133   }
134 };
135 
136 template <char... Shorty>
137 constexpr auto MaterializeShorty() {
138   constexpr size_t kSize = std::size({Shorty...}) + 1u;
139   return std::array<char, kSize>{Shorty..., '\0'};
140 }
141 
142 template <char... ArgType>
143 constexpr size_t NumberOfVRegs() {
144   constexpr size_t kArgVRegCount[] = {
145     ShortyTraits<ArgType>::kVRegCount...
146   };
147   size_t sum = 0u;
148   for (size_t count : kArgVRegCount) {
149     sum += count;
150   }
151   return sum;
152 }
153 
154 template <char... ArgType>
155 inline ALWAYS_INLINE void FillVRegs(uint32_t* vregs ATTRIBUTE_UNUSED,
156                                     typename ShortyTraits<ArgType>::Type... args ATTRIBUTE_UNUSED)
157     REQUIRES_SHARED(Locks::mutator_lock_) {}
158 
159 template <char FirstArgType, char... ArgType>
160 inline ALWAYS_INLINE void FillVRegs(uint32_t* vregs,
161                                     typename ShortyTraits<FirstArgType>::Type first_arg,
162                                     typename ShortyTraits<ArgType>::Type... args)
163     REQUIRES_SHARED(Locks::mutator_lock_) {
164   ShortyTraits<FirstArgType>::Set(vregs, first_arg);
165   FillVRegs<ArgType...>(vregs + ShortyTraits<FirstArgType>::kVRegCount, args...);
166 }
167 
168 template <char... ArgType>
169 inline ALWAYS_INLINE auto MaterializeVRegs(typename ShortyTraits<ArgType>::Type... args)
170     REQUIRES_SHARED(Locks::mutator_lock_) {
171   constexpr size_t kNumVRegs = NumberOfVRegs<ArgType...>();
172   std::array<uint32_t, kNumVRegs> vregs;
173   FillVRegs<ArgType...>(vregs.data(), args...);
174   return vregs;
175 }
176 
177 }  // namespace detail
178 
179 template <char ReturnType, char... ArgType>
180 inline typename detail::ShortyTraits<ReturnType>::Type
181 ArtMethod::InvokeStatic(Thread* self, typename detail::ShortyTraits<ArgType>::Type... args) {
182   DCHECK(IsStatic());
183   DCHECK(GetDeclaringClass()->IsInitialized());  // Used only for initialized well-known classes.
184   JValue result;
185   constexpr auto shorty = detail::MaterializeShorty<ReturnType, ArgType...>();
186   auto vregs = detail::MaterializeVRegs<ArgType...>(args...);
187   Invoke(self, vregs.data(), sizeof(vregs), &result, shorty.data());
188   return detail::ShortyTraits<ReturnType>::Get(result);
189 }
190 
191 template <char ReturnType, char... ArgType>
192 typename detail::ShortyTraits<ReturnType>::Type
193 ArtMethod::InvokeInstance(Thread* self,
194                           ObjPtr<mirror::Object> receiver,
195                           typename detail::ShortyTraits<ArgType>::Type... args) {
196   DCHECK(!GetDeclaringClass()->IsInterface());
197   DCHECK(!IsStatic());
198   JValue result;
199   constexpr auto shorty = detail::MaterializeShorty<ReturnType, ArgType...>();
200   auto vregs = detail::MaterializeVRegs<'L', ArgType...>(receiver, args...);
201   Invoke(self, vregs.data(), sizeof(vregs), &result, shorty.data());
202   return detail::ShortyTraits<ReturnType>::Get(result);
203 }
204 
205 template <char ReturnType, char... ArgType>
206 typename detail::ShortyTraits<ReturnType>::Type
207 ArtMethod::InvokeFinal(Thread* self,
208                        ObjPtr<mirror::Object> receiver,
209                        typename detail::ShortyTraits<ArgType>::Type... args) {
210   DCHECK(!GetDeclaringClass()->IsInterface());
211   DCHECK(!IsStatic());
212   DCHECK(IsFinal() || GetDeclaringClass()->IsFinal());
213   DCHECK(receiver != nullptr);
214   return InvokeInstance<ReturnType, ArgType...>(self, receiver, args...);
215 }
216 
217 template <char ReturnType, char... ArgType>
218 typename detail::ShortyTraits<ReturnType>::Type
219 ArtMethod::InvokeVirtual(Thread* self,
220                          ObjPtr<mirror::Object> receiver,
221                          typename detail::ShortyTraits<ArgType>::Type... args) {
222   DCHECK(!GetDeclaringClass()->IsInterface());
223   DCHECK(!IsStatic());
224   DCHECK(!IsFinal());
225   DCHECK(receiver != nullptr);
226   ArtMethod* target_method =
227       receiver->GetClass()->FindVirtualMethodForVirtual(this, kRuntimePointerSize);
228   DCHECK(target_method != nullptr);
229   return target_method->InvokeInstance<ReturnType, ArgType...>(self, receiver, args...);
230 }
231 
232 template <char ReturnType, char... ArgType>
233 typename detail::ShortyTraits<ReturnType>::Type
234 ArtMethod::InvokeInterface(Thread* self,
235                            ObjPtr<mirror::Object> receiver,
236                            typename detail::ShortyTraits<ArgType>::Type... args) {
237   DCHECK(GetDeclaringClass()->IsInterface());
238   DCHECK(!IsStatic());
239   DCHECK(receiver != nullptr);
240   ArtMethod* target_method =
241       receiver->GetClass()->FindVirtualMethodForInterface(this, kRuntimePointerSize);
242   DCHECK(target_method != nullptr);
243   return target_method->InvokeInstance<ReturnType, ArgType...>(self, receiver, args...);
244 }
245 
246 template <ReadBarrierOption kReadBarrierOption>
247 inline ObjPtr<mirror::Class> ArtMethod::GetDeclaringClassUnchecked() {
248   GcRootSource gc_root_source(this);
249   return declaring_class_.Read<kReadBarrierOption>(&gc_root_source);
250 }
251 
252 template <ReadBarrierOption kReadBarrierOption>
253 inline ObjPtr<mirror::Class> ArtMethod::GetDeclaringClass() {
254   ObjPtr<mirror::Class> result = GetDeclaringClassUnchecked<kReadBarrierOption>();
255   if (kIsDebugBuild) {
256     if (!IsRuntimeMethod()) {
257       CHECK(result != nullptr) << this;
258     } else {
259       CHECK(result == nullptr) << this;
260     }
261   }
262   return result;
263 }
264 
265 inline void ArtMethod::SetDeclaringClass(ObjPtr<mirror::Class> new_declaring_class) {
266   declaring_class_ = GcRoot<mirror::Class>(new_declaring_class);
267 }
268 
269 inline bool ArtMethod::CASDeclaringClass(ObjPtr<mirror::Class> expected_class,
270                                          ObjPtr<mirror::Class> desired_class) {
271   GcRoot<mirror::Class> expected_root(expected_class);
272   GcRoot<mirror::Class> desired_root(desired_class);
273   auto atomic_root_class = reinterpret_cast<Atomic<GcRoot<mirror::Class>>*>(&declaring_class_);
274   return atomic_root_class->CompareAndSetStrongSequentiallyConsistent(expected_root, desired_root);
275 }
276 
277 inline uint16_t ArtMethod::GetMethodIndex() {
278   DCHECK(IsRuntimeMethod() || GetDeclaringClass()->IsResolved());
279   return method_index_;
280 }
281 
282 inline uint16_t ArtMethod::GetMethodIndexDuringLinking() {
283   return method_index_;
284 }
285 
286 inline ObjPtr<mirror::Class> ArtMethod::LookupResolvedClassFromTypeIndex(dex::TypeIndex type_idx) {
287   ScopedAssertNoThreadSuspension ants(__FUNCTION__);
288   ObjPtr<mirror::Class> type =
289       Runtime::Current()->GetClassLinker()->LookupResolvedType(type_idx, this);
290   DCHECK(!Thread::Current()->IsExceptionPending());
291   return type;
292 }
293 
294 inline ObjPtr<mirror::Class> ArtMethod::ResolveClassFromTypeIndex(dex::TypeIndex type_idx) {
295   ObjPtr<mirror::Class> type = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, this);
296   DCHECK_EQ(type == nullptr, Thread::Current()->IsExceptionPending());
297   return type;
298 }
299 
300 inline bool ArtMethod::IsStringConstructor() {
301   uint32_t access_flags = GetAccessFlags();
302   DCHECK(!IsClassInitializer(access_flags));
303   return IsConstructor(access_flags) &&
304          // No read barrier needed for reading a constant reference only to read
305          // a constant string class flag. See `ReadBarrierOption`.
306          GetDeclaringClass<kWithoutReadBarrier>()->IsStringClass();
307 }
308 
309 inline bool ArtMethod::IsOverridableByDefaultMethod() {
310   // It is safe to avoid the read barrier here since the constant interface flag
311   // in the `Class` object is stored before creating the `ArtMethod` and storing
312   // the declaring class reference. See `ReadBarrierOption`.
313   return GetDeclaringClass<kWithoutReadBarrier>()->IsInterface();
314 }
315 
316 inline bool ArtMethod::CheckIncompatibleClassChange(InvokeType type) {
317   switch (type) {
318     case kStatic:
319       return !IsStatic();
320     case kDirect:
321       return !IsDirect() || IsStatic();
322     case kVirtual: {
323       // We have an error if we are direct or a non-copied (i.e. not part of a real class) interface
324       // method.
325       ObjPtr<mirror::Class> methods_class = GetDeclaringClass();
326       return IsDirect() || (methods_class->IsInterface() && !IsCopied());
327     }
328     case kSuper:
329       // Constructors and static methods are called with invoke-direct.
330       return IsConstructor() || IsStatic();
331     case kInterface: {
332       ObjPtr<mirror::Class> methods_class = GetDeclaringClass();
333       return IsDirect() || !(methods_class->IsInterface() || methods_class->IsObjectClass());
334     }
335     case kPolymorphic:
336       return !IsSignaturePolymorphic();
337     default:
338       LOG(FATAL) << "Unreachable - invocation type: " << type;
339       UNREACHABLE();
340   }
341 }
342 
343 inline bool ArtMethod::IsCalleeSaveMethod() {
344   if (!IsRuntimeMethod()) {
345     return false;
346   }
347   Runtime* runtime = Runtime::Current();
348   bool result = false;
349   for (uint32_t i = 0; i < static_cast<uint32_t>(CalleeSaveType::kLastCalleeSaveType); i++) {
350     if (this == runtime->GetCalleeSaveMethod(CalleeSaveType(i))) {
351       result = true;
352       break;
353     }
354   }
355   return result;
356 }
357 
358 inline bool ArtMethod::IsResolutionMethod() {
359   bool result = this == Runtime::Current()->GetResolutionMethod();
360   // Check that if we do think it is phony it looks like the resolution method.
361   DCHECK_IMPLIES(result, IsRuntimeMethod());
362   return result;
363 }
364 
365 inline bool ArtMethod::IsImtUnimplementedMethod() {
366   bool result = this == Runtime::Current()->GetImtUnimplementedMethod();
367   // Check that if we do think it is phony it looks like the imt unimplemented method.
368   DCHECK_IMPLIES(result, IsRuntimeMethod());
369   return result;
370 }
371 
372 inline const DexFile* ArtMethod::GetDexFile() {
373   // It is safe to avoid the read barrier here since the dex file is constant, so if we read the
374   // from-space dex file pointer it will be equal to the to-space copy.
375   return GetDexCache<kWithoutReadBarrier>()->GetDexFile();
376 }
377 
378 inline const char* ArtMethod::GetDeclaringClassDescriptor() {
379   uint32_t dex_method_idx = GetDexMethodIndex();
380   if (UNLIKELY(dex_method_idx == dex::kDexNoIndex)) {
381     return "<runtime method>";
382   }
383   DCHECK(!IsProxyMethod());
384   const DexFile* dex_file = GetDexFile();
385   return dex_file->GetMethodDeclaringClassDescriptor(dex_file->GetMethodId(dex_method_idx));
386 }
387 
388 inline const char* ArtMethod::GetShorty() {
389   uint32_t unused_length;
390   return GetShorty(&unused_length);
391 }
392 
393 inline const char* ArtMethod::GetShorty(uint32_t* out_length) {
394   DCHECK(!IsProxyMethod());
395   const DexFile* dex_file = GetDexFile();
396   return dex_file->GetMethodShorty(dex_file->GetMethodId(GetDexMethodIndex()), out_length);
397 }
398 
399 inline const Signature ArtMethod::GetSignature() {
400   uint32_t dex_method_idx = GetDexMethodIndex();
401   if (dex_method_idx != dex::kDexNoIndex) {
402     DCHECK(!IsProxyMethod());
403     const DexFile* dex_file = GetDexFile();
404     return dex_file->GetMethodSignature(dex_file->GetMethodId(dex_method_idx));
405   }
406   return Signature::NoSignature();
407 }
408 
409 inline const char* ArtMethod::GetName() {
410   uint32_t dex_method_idx = GetDexMethodIndex();
411   if (LIKELY(dex_method_idx != dex::kDexNoIndex)) {
412     DCHECK(!IsProxyMethod());
413     const DexFile* dex_file = GetDexFile();
414     return dex_file->GetMethodName(dex_file->GetMethodId(dex_method_idx));
415   }
416   return GetRuntimeMethodName();
417 }
418 
419 inline std::string_view ArtMethod::GetNameView() {
420   uint32_t dex_method_idx = GetDexMethodIndex();
421   if (LIKELY(dex_method_idx != dex::kDexNoIndex)) {
422     DCHECK(!IsProxyMethod());
423     const DexFile* dex_file = GetDexFile();
424     return dex_file->GetMethodNameView(dex_method_idx);
425   }
426   return GetRuntimeMethodName();
427 }
428 
429 inline ObjPtr<mirror::String> ArtMethod::ResolveNameString() {
430   DCHECK(!IsProxyMethod());
431   const dex::MethodId& method_id = GetDexFile()->GetMethodId(GetDexMethodIndex());
432   return Runtime::Current()->GetClassLinker()->ResolveString(method_id.name_idx_, this);
433 }
434 
435 inline bool ArtMethod::NameEquals(ObjPtr<mirror::String> name) {
436   DCHECK(!IsProxyMethod());
437   const DexFile* dex_file = GetDexFile();
438   const dex::MethodId& method_id = dex_file->GetMethodId(GetDexMethodIndex());
439   const dex::StringIndex name_idx = method_id.name_idx_;
440   uint32_t utf16_length;
441   const char* utf8_name = dex_file->StringDataAndUtf16LengthByIdx(name_idx, &utf16_length);
442   return dchecked_integral_cast<uint32_t>(name->GetLength()) == utf16_length &&
443          name->Equals(utf8_name);
444 }
445 
446 inline const dex::CodeItem* ArtMethod::GetCodeItem() {
447   if (!HasCodeItem()) {
448     return nullptr;
449   }
450   Runtime* runtime = Runtime::Current();
451   PointerSize pointer_size = runtime->GetClassLinker()->GetImagePointerSize();
452   return runtime->IsAotCompiler()
453       ? GetDexFile()->GetCodeItem(reinterpret_cast32<uint32_t>(GetDataPtrSize(pointer_size)))
454       : reinterpret_cast<const dex::CodeItem*>(
455           reinterpret_cast<uintptr_t>(GetDataPtrSize(pointer_size)) & ~1);
456 }
457 
458 inline bool ArtMethod::IsResolvedTypeIdx(dex::TypeIndex type_idx) {
459   DCHECK(!IsProxyMethod());
460   return LookupResolvedClassFromTypeIndex(type_idx) != nullptr;
461 }
462 
463 inline int32_t ArtMethod::GetLineNumFromDexPC(uint32_t dex_pc) {
464   DCHECK(!IsProxyMethod());
465   if (dex_pc == dex::kDexNoIndex) {
466     return IsNative() ? -2 : -1;
467   }
468   return annotations::GetLineNumFromPC(GetDexFile(), this, dex_pc);
469 }
470 
471 inline const dex::ProtoId& ArtMethod::GetPrototype() {
472   DCHECK(!IsProxyMethod());
473   const DexFile* dex_file = GetDexFile();
474   return dex_file->GetMethodPrototype(dex_file->GetMethodId(GetDexMethodIndex()));
475 }
476 
477 inline const dex::TypeList* ArtMethod::GetParameterTypeList() {
478   DCHECK(!IsProxyMethod());
479   const DexFile* dex_file = GetDexFile();
480   const dex::ProtoId& proto = dex_file->GetMethodPrototype(
481       dex_file->GetMethodId(GetDexMethodIndex()));
482   return dex_file->GetProtoParameters(proto);
483 }
484 
485 inline const char* ArtMethod::GetDeclaringClassSourceFile() {
486   DCHECK(!IsProxyMethod());
487   return GetDeclaringClass()->GetSourceFile();
488 }
489 
490 inline uint16_t ArtMethod::GetClassDefIndex() {
491   DCHECK(!IsProxyMethod());
492   if (LIKELY(!IsObsolete())) {
493     return GetDeclaringClass()->GetDexClassDefIndex();
494   } else {
495     return FindObsoleteDexClassDefIndex();
496   }
497 }
498 
499 inline const dex::ClassDef& ArtMethod::GetClassDef() {
500   DCHECK(!IsProxyMethod());
501   return GetDexFile()->GetClassDef(GetClassDefIndex());
502 }
503 
504 inline size_t ArtMethod::GetNumberOfParameters() {
505   constexpr size_t return_type_count = 1u;
506   uint32_t shorty_length;
507   GetShorty(&shorty_length);
508   return shorty_length - return_type_count;
509 }
510 
511 inline const char* ArtMethod::GetReturnTypeDescriptor() {
512   DCHECK(!IsProxyMethod());
513   const DexFile* dex_file = GetDexFile();
514   return dex_file->GetTypeDescriptor(dex_file->GetTypeId(GetReturnTypeIndex()));
515 }
516 
517 inline Primitive::Type ArtMethod::GetReturnTypePrimitive() {
518   return Primitive::GetType(GetReturnTypeDescriptor()[0]);
519 }
520 
521 inline const char* ArtMethod::GetTypeDescriptorFromTypeIdx(dex::TypeIndex type_idx) {
522   DCHECK(!IsProxyMethod());
523   const DexFile* dex_file = GetDexFile();
524   return dex_file->GetTypeDescriptor(dex_file->GetTypeId(type_idx));
525 }
526 
527 inline ObjPtr<mirror::ClassLoader> ArtMethod::GetClassLoader() {
528   DCHECK(!IsProxyMethod());
529   return GetDeclaringClass()->GetClassLoader();
530 }
531 
532 template <ReadBarrierOption kReadBarrierOption>
533 inline ObjPtr<mirror::DexCache> ArtMethod::GetDexCache() {
534   if (LIKELY(!IsObsolete())) {
535     ObjPtr<mirror::Class> klass = GetDeclaringClass<kReadBarrierOption>();
536     return klass->GetDexCache<kDefaultVerifyFlags, kReadBarrierOption>();
537   } else {
538     DCHECK(!IsProxyMethod());
539     return GetObsoleteDexCache<kReadBarrierOption>();
540   }
541 }
542 
543 inline bool ArtMethod::IsProxyMethod() {
544   DCHECK(!IsRuntimeMethod()) << "ArtMethod::IsProxyMethod called on a runtime method";
545   // No read barrier needed, we're reading the constant declaring class only to read
546   // the constant proxy flag. See ReadBarrierOption.
547   return GetDeclaringClass<kWithoutReadBarrier>()->IsProxyClass();
548 }
549 
550 inline ArtMethod* ArtMethod::GetInterfaceMethodForProxyUnchecked(PointerSize pointer_size) {
551   DCHECK(IsProxyMethod());
552   // Do not check IsAssignableFrom() here as it relies on raw reference comparison
553   // which may give false negatives while visiting references for a non-CC moving GC.
554   return reinterpret_cast<ArtMethod*>(GetDataPtrSize(pointer_size));
555 }
556 
557 inline ArtMethod* ArtMethod::GetInterfaceMethodIfProxy(PointerSize pointer_size) {
558   if (LIKELY(!IsProxyMethod())) {
559     return this;
560   }
561   ArtMethod* interface_method = GetInterfaceMethodForProxyUnchecked(pointer_size);
562   // We can check that the proxy class implements the interface only if the proxy class
563   // is resolved, otherwise the interface table is not yet initialized.
564   DCHECK_IMPLIES(GetDeclaringClass()->IsResolved(),
565                  interface_method->GetDeclaringClass()->IsAssignableFrom(GetDeclaringClass()));
566   return interface_method;
567 }
568 
569 inline dex::TypeIndex ArtMethod::GetReturnTypeIndex() {
570   DCHECK(!IsProxyMethod());
571   const DexFile* dex_file = GetDexFile();
572   const dex::MethodId& method_id = dex_file->GetMethodId(GetDexMethodIndex());
573   const dex::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
574   return proto_id.return_type_idx_;
575 }
576 
577 inline ObjPtr<mirror::Class> ArtMethod::LookupResolvedReturnType() {
578   return LookupResolvedClassFromTypeIndex(GetReturnTypeIndex());
579 }
580 
581 inline ObjPtr<mirror::Class> ArtMethod::ResolveReturnType() {
582   return ResolveClassFromTypeIndex(GetReturnTypeIndex());
583 }
584 
585 inline bool ArtMethod::HasSingleImplementation() {
586   // No read barrier needed for reading a constant reference only to read
587   // a constant final class flag. See `ReadBarrierOption`.
588   if (IsFinal() || GetDeclaringClass<kWithoutReadBarrier>()->IsFinal()) {
589     // We don't set kAccSingleImplementation for these cases since intrinsic
590     // can use the flag also.
591     return true;
592   }
593   return (GetAccessFlags() & kAccSingleImplementation) != 0;
594 }
595 
596 template<ReadBarrierOption kReadBarrierOption, bool kVisitProxyMethod, typename RootVisitorType>
597 void ArtMethod::VisitRoots(RootVisitorType& visitor, PointerSize pointer_size) {
598   if (LIKELY(!declaring_class_.IsNull())) {
599     visitor.VisitRoot(declaring_class_.AddressWithoutBarrier());
600     if (kVisitProxyMethod) {
601       ObjPtr<mirror::Class> klass = declaring_class_.Read<kReadBarrierOption>();
602       if (UNLIKELY(klass->IsProxyClass())) {
603         // For normal methods, dex cache shortcuts will be visited through the declaring class.
604         // However, for proxies we need to keep the interface method alive, so we visit its roots.
605         ArtMethod* interface_method = GetInterfaceMethodForProxyUnchecked(pointer_size);
606         DCHECK(interface_method != nullptr);
607         interface_method->VisitRoots<kReadBarrierOption, kVisitProxyMethod>(visitor, pointer_size);
608       }
609     }
610   }
611 }
612 
613 template<typename RootVisitorType>
614 void ArtMethod::VisitRoots(RootVisitorType& visitor,
615                            uint8_t* start_boundary,
616                            uint8_t* end_boundary,
617                            ArtMethod* method) {
618   mirror::CompressedReference<mirror::Object>* cls_ptr =
619       reinterpret_cast<mirror::CompressedReference<mirror::Object>*>(
620           reinterpret_cast<uint8_t*>(method) + DeclaringClassOffset().Int32Value());
621   if (reinterpret_cast<uint8_t*>(cls_ptr) >= start_boundary
622       && reinterpret_cast<uint8_t*>(cls_ptr) < end_boundary) {
623     visitor.VisitRootIfNonNull(cls_ptr);
624   }
625 }
626 
627 template<PointerSize kPointerSize, typename RootVisitorType>
628 void ArtMethod::VisitArrayRoots(RootVisitorType& visitor,
629                                 uint8_t* start_boundary,
630                                 uint8_t* end_boundary,
631                                 LengthPrefixedArray<ArtMethod>* array) {
632   DCHECK_LE(start_boundary, end_boundary);
633   DCHECK_NE(array->size(), 0u);
634   static constexpr size_t kMethodSize = ArtMethod::Size(kPointerSize);
635   ArtMethod* first_method = &array->At(0, kMethodSize, ArtMethod::Alignment(kPointerSize));
636   DCHECK_LE(static_cast<void*>(end_boundary),
637             static_cast<void*>(reinterpret_cast<uint8_t*>(first_method)
638                                + array->size() * kMethodSize));
639   uint8_t* declaring_class =
640       reinterpret_cast<uint8_t*>(first_method) + DeclaringClassOffset().Int32Value();
641   // Jump to the first class to visit.
642   if (declaring_class < start_boundary) {
643     size_t remainder = (start_boundary - declaring_class) % kMethodSize;
644     declaring_class = start_boundary;
645     if (remainder > 0) {
646       declaring_class += kMethodSize - remainder;
647     }
648   }
649   while (declaring_class < end_boundary) {
650     visitor.VisitRootIfNonNull(
651         reinterpret_cast<mirror::CompressedReference<mirror::Object>*>(declaring_class));
652     declaring_class += kMethodSize;
653   }
654 }
655 
656 template <typename Visitor>
657 inline void ArtMethod::UpdateEntrypoints(const Visitor& visitor, PointerSize pointer_size) {
658   if (IsNative()) {
659     const void* old_native_code = GetEntryPointFromJniPtrSize(pointer_size);
660     const void* new_native_code = visitor(old_native_code);
661     if (old_native_code != new_native_code) {
662       SetEntryPointFromJniPtrSize(new_native_code, pointer_size);
663     }
664   }
665   const void* old_code = GetEntryPointFromQuickCompiledCodePtrSize(pointer_size);
666   const void* new_code = visitor(old_code);
667   if (old_code != new_code) {
668     SetEntryPointFromQuickCompiledCodePtrSize(new_code, pointer_size);
669   }
670 }
671 
672 template <ReadBarrierOption kReadBarrierOption>
673 inline bool ArtMethod::StillNeedsClinitCheck() {
674   if (!NeedsClinitCheckBeforeCall()) {
675     return false;
676   }
677   ObjPtr<mirror::Class> klass = GetDeclaringClass<kReadBarrierOption>();
678   return !klass->IsVisiblyInitialized();
679 }
680 
681 inline bool ArtMethod::StillNeedsClinitCheckMayBeDead() {
682   if (!NeedsClinitCheckBeforeCall()) {
683     return false;
684   }
685   ObjPtr<mirror::Class> klass = GetDeclaringClassMayBeDead();
686   return !klass->IsVisiblyInitialized();
687 }
688 
689 inline bool ArtMethod::IsDeclaringClassVerifiedMayBeDead() {
690   ObjPtr<mirror::Class> klass = GetDeclaringClassMayBeDead();
691   return klass->IsVerified();
692 }
693 
694 inline ObjPtr<mirror::Class> ArtMethod::GetDeclaringClassMayBeDead() {
695   // Helper method for checking the status of the declaring class which may be dead.
696   //
697   // To avoid resurrecting an unreachable object, or crashing the GC in some GC phases,
698   // we must not use a full read barrier. Therefore we read the declaring class without
699   // a read barrier and check if it's already marked. If yes, we check the status of the
700   // to-space class object as intended. Otherwise, there is no to-space object and the
701   // from-space class object contains the most recent value of the status field; even if
702   // this races with another thread doing a read barrier and updating the status, that's
703   // no different from a race with a thread that just updates the status.
704   ObjPtr<mirror::Class> klass = GetDeclaringClass<kWithoutReadBarrier>();
705   ObjPtr<mirror::Class> marked = ReadBarrier::IsMarked(klass.Ptr());
706   return (marked != nullptr) ? marked : klass;
707 }
708 
709 inline CodeItemInstructionAccessor ArtMethod::DexInstructions() {
710   return CodeItemInstructionAccessor(*GetDexFile(), GetCodeItem());
711 }
712 
713 inline CodeItemDataAccessor ArtMethod::DexInstructionData() {
714   return CodeItemDataAccessor(*GetDexFile(), GetCodeItem());
715 }
716 
717 inline CodeItemDebugInfoAccessor ArtMethod::DexInstructionDebugInfo() {
718   return CodeItemDebugInfoAccessor(*GetDexFile(), GetCodeItem(), GetDexMethodIndex());
719 }
720 
721 inline bool ArtMethod::CounterHasChanged(uint16_t threshold) {
722   DCHECK(!IsAbstract());
723   DCHECK_EQ(threshold, Runtime::Current()->GetJITOptions()->GetWarmupThreshold());
724   return hotness_count_ != threshold;
725 }
726 
727 inline void ArtMethod::ResetCounter(uint16_t new_value) {
728   if (IsAbstract()) {
729     return;
730   }
731   if (IsMemorySharedMethod()) {
732     return;
733   }
734   DCHECK_EQ(new_value, Runtime::Current()->GetJITOptions()->GetWarmupThreshold());
735   // Avoid dirtying the value if possible.
736   if (hotness_count_ != new_value) {
737     hotness_count_ = new_value;
738   }
739 }
740 
741 inline void ArtMethod::SetHotCounter() {
742   DCHECK(!IsAbstract());
743   // Avoid dirtying the value if possible.
744   if (hotness_count_ != 0) {
745     hotness_count_ = 0;
746   }
747 }
748 
749 inline void ArtMethod::UpdateCounter(int32_t new_samples) {
750   DCHECK(!IsAbstract());
751   DCHECK_GT(new_samples, 0);
752   DCHECK_LE(new_samples, std::numeric_limits<uint16_t>::max());
753   if (IsMemorySharedMethod()) {
754     return;
755   }
756   uint16_t old_hotness_count = hotness_count_;
757   uint16_t new_count = (old_hotness_count <= new_samples) ? 0u : old_hotness_count - new_samples;
758   // Avoid dirtying the value if possible.
759   if (old_hotness_count != new_count) {
760     hotness_count_ = new_count;
761   }
762 }
763 
764 inline bool ArtMethod::CounterIsHot() {
765   DCHECK(!IsAbstract());
766   return hotness_count_ == 0;
767 }
768 
769 inline bool ArtMethod::CounterHasReached(uint16_t samples, uint16_t threshold) {
770   DCHECK(!IsAbstract());
771   DCHECK_EQ(threshold, Runtime::Current()->GetJITOptions()->GetWarmupThreshold());
772   DCHECK_LE(samples, threshold);
773   return hotness_count_ <= (threshold - samples);
774 }
775 
776 inline uint16_t ArtMethod::GetCounter() {
777   DCHECK(!IsAbstract());
778   return hotness_count_;
779 }
780 
781 inline uint32_t ArtMethod::GetImtIndex() {
782   if (LIKELY(IsAbstract())) {
783     return imt_index_;
784   } else {
785     return ImTable::GetImtIndex(this);
786   }
787 }
788 
789 inline void ArtMethod::CalculateAndSetImtIndex() {
790   DCHECK(IsAbstract()) << PrettyMethod();
791   imt_index_ = ImTable::GetImtIndex(this);
792 }
793 
794 }  // namespace art
795 
796 #endif  // ART_RUNTIME_ART_METHOD_INL_H_
797