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