Home | History | Annotate | Download | only in runtime
      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 "base/logging.h"
     25 #include "class_linker-inl.h"
     26 #include "common_throws.h"
     27 #include "dex_file.h"
     28 #include "dex_file_annotations.h"
     29 #include "dex_file-inl.h"
     30 #include "gc_root-inl.h"
     31 #include "invoke_type.h"
     32 #include "jit/profiling_info.h"
     33 #include "mirror/class-inl.h"
     34 #include "mirror/dex_cache-inl.h"
     35 #include "mirror/object-inl.h"
     36 #include "mirror/object_array.h"
     37 #include "mirror/string.h"
     38 #include "oat.h"
     39 #include "obj_ptr-inl.h"
     40 #include "primitive.h"
     41 #include "quick/quick_method_frame_info.h"
     42 #include "read_barrier-inl.h"
     43 #include "runtime-inl.h"
     44 #include "scoped_thread_state_change-inl.h"
     45 #include "thread-current-inl.h"
     46 #include "utils.h"
     47 
     48 namespace art {
     49 
     50 template <ReadBarrierOption kReadBarrierOption>
     51 inline mirror::Class* ArtMethod::GetDeclaringClassUnchecked() {
     52   GcRootSource gc_root_source(this);
     53   return declaring_class_.Read<kReadBarrierOption>(&gc_root_source);
     54 }
     55 
     56 template <ReadBarrierOption kReadBarrierOption>
     57 inline mirror::Class* ArtMethod::GetDeclaringClass() {
     58   mirror::Class* result = GetDeclaringClassUnchecked<kReadBarrierOption>();
     59   if (kIsDebugBuild) {
     60     if (!IsRuntimeMethod()) {
     61       CHECK(result != nullptr) << this;
     62       if (kCheckDeclaringClassState) {
     63         if (!(result->IsIdxLoaded() || result->IsErroneous())) {
     64           LOG(FATAL_WITHOUT_ABORT) << "Class status: " << result->GetStatus();
     65           LOG(FATAL) << result->PrettyClass();
     66         }
     67       }
     68     } else {
     69       CHECK(result == nullptr) << this;
     70     }
     71   }
     72   return result;
     73 }
     74 
     75 inline void ArtMethod::SetDeclaringClass(ObjPtr<mirror::Class> new_declaring_class) {
     76   declaring_class_ = GcRoot<mirror::Class>(new_declaring_class);
     77 }
     78 
     79 inline bool ArtMethod::CASDeclaringClass(mirror::Class* expected_class,
     80                                          mirror::Class* desired_class) {
     81   GcRoot<mirror::Class> expected_root(expected_class);
     82   GcRoot<mirror::Class> desired_root(desired_class);
     83   return reinterpret_cast<Atomic<GcRoot<mirror::Class>>*>(&declaring_class_)->
     84       CompareExchangeStrongSequentiallyConsistent(
     85           expected_root, desired_root);
     86 }
     87 
     88 inline uint16_t ArtMethod::GetMethodIndex() {
     89   DCHECK(IsRuntimeMethod() || GetDeclaringClass()->IsResolved());
     90   return method_index_;
     91 }
     92 
     93 inline uint16_t ArtMethod::GetMethodIndexDuringLinking() {
     94   return method_index_;
     95 }
     96 
     97 inline uint32_t ArtMethod::GetDexMethodIndex() {
     98   if (kCheckDeclaringClassState) {
     99     CHECK(IsRuntimeMethod() || GetDeclaringClass()->IsIdxLoaded() ||
    100           GetDeclaringClass()->IsErroneous());
    101   }
    102   return GetDexMethodIndexUnchecked();
    103 }
    104 
    105 inline mirror::MethodDexCacheType* ArtMethod::GetDexCacheResolvedMethods(PointerSize pointer_size) {
    106   return GetNativePointer<mirror::MethodDexCacheType*>(DexCacheResolvedMethodsOffset(pointer_size),
    107                                                        pointer_size);
    108 }
    109 
    110 inline ArtMethod* ArtMethod::GetDexCacheResolvedMethod(uint16_t method_index,
    111                                                        PointerSize pointer_size) {
    112   // NOTE: Unchecked, i.e. not throwing AIOOB. We don't even know the length here
    113   // without accessing the DexCache and we don't want to do that in release build.
    114   DCHECK_LT(method_index, GetInterfaceMethodIfProxy(pointer_size)->GetDexFile()->NumMethodIds());
    115   uint32_t slot_idx = method_index % mirror::DexCache::kDexCacheMethodCacheSize;
    116   DCHECK_LT(slot_idx, GetInterfaceMethodIfProxy(pointer_size)->GetDexCache()->NumResolvedMethods());
    117   mirror::MethodDexCachePair pair = mirror::DexCache::GetNativePairPtrSize(
    118       GetDexCacheResolvedMethods(pointer_size), slot_idx, pointer_size);
    119   ArtMethod* method = pair.GetObjectForIndex(method_index);
    120   if (LIKELY(method != nullptr)) {
    121     auto* declaring_class = method->GetDeclaringClass();
    122     if (LIKELY(declaring_class == nullptr || !declaring_class->IsErroneous())) {
    123       return method;
    124     }
    125   }
    126   return nullptr;
    127 }
    128 
    129 inline void ArtMethod::SetDexCacheResolvedMethod(uint16_t method_index,
    130                                                  ArtMethod* new_method,
    131                                                  PointerSize pointer_size) {
    132   // NOTE: Unchecked, i.e. not throwing AIOOB. We don't even know the length here
    133   // without accessing the DexCache and we don't want to do that in release build.
    134   DCHECK_LT(method_index, GetInterfaceMethodIfProxy(pointer_size)->GetDexFile()->NumMethodIds());
    135   DCHECK(new_method == nullptr || new_method->GetDeclaringClass() != nullptr);
    136   uint32_t slot_idx = method_index % mirror::DexCache::kDexCacheMethodCacheSize;
    137   DCHECK_LT(slot_idx, GetInterfaceMethodIfProxy(pointer_size)->GetDexCache()->NumResolvedMethods());
    138   mirror::MethodDexCachePair pair(new_method, method_index);
    139   mirror::DexCache::SetNativePairPtrSize(
    140       GetDexCacheResolvedMethods(pointer_size), slot_idx, pair, pointer_size);
    141 }
    142 
    143 inline bool ArtMethod::HasDexCacheResolvedMethods(PointerSize pointer_size) {
    144   return GetDexCacheResolvedMethods(pointer_size) != nullptr;
    145 }
    146 
    147 inline bool ArtMethod::HasSameDexCacheResolvedMethods(ArtMethod* other, PointerSize pointer_size) {
    148   return GetDexCacheResolvedMethods(pointer_size) ==
    149       other->GetDexCacheResolvedMethods(pointer_size);
    150 }
    151 
    152 inline bool ArtMethod::HasSameDexCacheResolvedMethods(mirror::MethodDexCacheType* other_cache,
    153                                                       PointerSize pointer_size) {
    154   return GetDexCacheResolvedMethods(pointer_size) == other_cache;
    155 }
    156 
    157 inline mirror::Class* ArtMethod::GetClassFromTypeIndex(dex::TypeIndex type_idx, bool resolve) {
    158   // TODO: Refactor this function into two functions, Resolve...() and Lookup...()
    159   // so that we can properly annotate it with no-suspension possible / suspension possible.
    160   ObjPtr<mirror::DexCache> dex_cache = GetDexCache();
    161   ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
    162   if (UNLIKELY(type == nullptr)) {
    163     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
    164     if (resolve) {
    165       type = class_linker->ResolveType(type_idx, this);
    166       CHECK(type != nullptr || Thread::Current()->IsExceptionPending());
    167     } else {
    168       type = class_linker->LookupResolvedType(
    169           *dex_cache->GetDexFile(), type_idx, dex_cache, GetClassLoader());
    170     }
    171   }
    172   return type.Ptr();
    173 }
    174 
    175 inline bool ArtMethod::CheckIncompatibleClassChange(InvokeType type) {
    176   switch (type) {
    177     case kStatic:
    178       return !IsStatic();
    179     case kDirect:
    180       return !IsDirect() || IsStatic();
    181     case kVirtual: {
    182       // We have an error if we are direct or a non-copied (i.e. not part of a real class) interface
    183       // method.
    184       mirror::Class* methods_class = GetDeclaringClass();
    185       return IsDirect() || (methods_class->IsInterface() && !IsCopied());
    186     }
    187     case kSuper:
    188       // Constructors and static methods are called with invoke-direct.
    189       return IsConstructor() || IsStatic();
    190     case kInterface: {
    191       mirror::Class* methods_class = GetDeclaringClass();
    192       return IsDirect() || !(methods_class->IsInterface() || methods_class->IsObjectClass());
    193     }
    194     default:
    195       LOG(FATAL) << "Unreachable - invocation type: " << type;
    196       UNREACHABLE();
    197   }
    198 }
    199 
    200 inline bool ArtMethod::IsCalleeSaveMethod() {
    201   if (!IsRuntimeMethod()) {
    202     return false;
    203   }
    204   Runtime* runtime = Runtime::Current();
    205   bool result = false;
    206   for (uint32_t i = 0; i < static_cast<uint32_t>(CalleeSaveType::kLastCalleeSaveType); i++) {
    207     if (this == runtime->GetCalleeSaveMethod(CalleeSaveType(i))) {
    208       result = true;
    209       break;
    210     }
    211   }
    212   return result;
    213 }
    214 
    215 inline bool ArtMethod::IsResolutionMethod() {
    216   bool result = this == Runtime::Current()->GetResolutionMethod();
    217   // Check that if we do think it is phony it looks like the resolution method.
    218   DCHECK(!result || IsRuntimeMethod());
    219   return result;
    220 }
    221 
    222 inline bool ArtMethod::IsImtUnimplementedMethod() {
    223   bool result = this == Runtime::Current()->GetImtUnimplementedMethod();
    224   // Check that if we do think it is phony it looks like the imt unimplemented method.
    225   DCHECK(!result || IsRuntimeMethod());
    226   return result;
    227 }
    228 
    229 inline const DexFile* ArtMethod::GetDexFile() {
    230   // It is safe to avoid the read barrier here since the dex file is constant, so if we read the
    231   // from-space dex file pointer it will be equal to the to-space copy.
    232   return GetDexCache<kWithoutReadBarrier>()->GetDexFile();
    233 }
    234 
    235 inline const char* ArtMethod::GetDeclaringClassDescriptor() {
    236   uint32_t dex_method_idx = GetDexMethodIndex();
    237   if (UNLIKELY(dex_method_idx == DexFile::kDexNoIndex)) {
    238     return "<runtime method>";
    239   }
    240   DCHECK(!IsProxyMethod());
    241   const DexFile* dex_file = GetDexFile();
    242   return dex_file->GetMethodDeclaringClassDescriptor(dex_file->GetMethodId(dex_method_idx));
    243 }
    244 
    245 inline const char* ArtMethod::GetShorty() {
    246   uint32_t unused_length;
    247   return GetShorty(&unused_length);
    248 }
    249 
    250 inline const char* ArtMethod::GetShorty(uint32_t* out_length) {
    251   DCHECK(!IsProxyMethod());
    252   const DexFile* dex_file = GetDexFile();
    253   return dex_file->GetMethodShorty(dex_file->GetMethodId(GetDexMethodIndex()), out_length);
    254 }
    255 
    256 inline const Signature ArtMethod::GetSignature() {
    257   uint32_t dex_method_idx = GetDexMethodIndex();
    258   if (dex_method_idx != DexFile::kDexNoIndex) {
    259     DCHECK(!IsProxyMethod());
    260     const DexFile* dex_file = GetDexFile();
    261     return dex_file->GetMethodSignature(dex_file->GetMethodId(dex_method_idx));
    262   }
    263   return Signature::NoSignature();
    264 }
    265 
    266 inline const char* ArtMethod::GetName() {
    267   uint32_t dex_method_idx = GetDexMethodIndex();
    268   if (LIKELY(dex_method_idx != DexFile::kDexNoIndex)) {
    269     DCHECK(!IsProxyMethod());
    270     const DexFile* dex_file = GetDexFile();
    271     return dex_file->GetMethodName(dex_file->GetMethodId(dex_method_idx));
    272   }
    273   Runtime* const runtime = Runtime::Current();
    274   if (this == runtime->GetResolutionMethod()) {
    275     return "<runtime internal resolution method>";
    276   } else if (this == runtime->GetImtConflictMethod()) {
    277     return "<runtime internal imt conflict method>";
    278   } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveAllCalleeSaves)) {
    279     return "<runtime internal callee-save all registers method>";
    280   } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveRefsOnly)) {
    281     return "<runtime internal callee-save reference registers method>";
    282   } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveRefsAndArgs)) {
    283     return "<runtime internal callee-save reference and argument registers method>";
    284   } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverything)) {
    285     return "<runtime internal save-every-register method>";
    286   } else {
    287     return "<unknown runtime internal method>";
    288   }
    289 }
    290 
    291 inline const DexFile::CodeItem* ArtMethod::GetCodeItem() {
    292   return GetDexFile()->GetCodeItem(GetCodeItemOffset());
    293 }
    294 
    295 inline bool ArtMethod::IsResolvedTypeIdx(dex::TypeIndex type_idx) {
    296   DCHECK(!IsProxyMethod());
    297   return GetClassFromTypeIndex(type_idx, /* resolve */ false) != nullptr;
    298 }
    299 
    300 inline int32_t ArtMethod::GetLineNumFromDexPC(uint32_t dex_pc) {
    301   DCHECK(!IsProxyMethod());
    302   if (dex_pc == DexFile::kDexNoIndex) {
    303     return IsNative() ? -2 : -1;
    304   }
    305   return annotations::GetLineNumFromPC(GetDexFile(), this, dex_pc);
    306 }
    307 
    308 inline const DexFile::ProtoId& ArtMethod::GetPrototype() {
    309   DCHECK(!IsProxyMethod());
    310   const DexFile* dex_file = GetDexFile();
    311   return dex_file->GetMethodPrototype(dex_file->GetMethodId(GetDexMethodIndex()));
    312 }
    313 
    314 inline const DexFile::TypeList* ArtMethod::GetParameterTypeList() {
    315   DCHECK(!IsProxyMethod());
    316   const DexFile* dex_file = GetDexFile();
    317   const DexFile::ProtoId& proto = dex_file->GetMethodPrototype(
    318       dex_file->GetMethodId(GetDexMethodIndex()));
    319   return dex_file->GetProtoParameters(proto);
    320 }
    321 
    322 inline const char* ArtMethod::GetDeclaringClassSourceFile() {
    323   DCHECK(!IsProxyMethod());
    324   return GetDeclaringClass()->GetSourceFile();
    325 }
    326 
    327 inline uint16_t ArtMethod::GetClassDefIndex() {
    328   DCHECK(!IsProxyMethod());
    329   if (LIKELY(!IsObsolete())) {
    330     return GetDeclaringClass()->GetDexClassDefIndex();
    331   } else {
    332     return FindObsoleteDexClassDefIndex();
    333   }
    334 }
    335 
    336 inline const DexFile::ClassDef& ArtMethod::GetClassDef() {
    337   DCHECK(!IsProxyMethod());
    338   return GetDexFile()->GetClassDef(GetClassDefIndex());
    339 }
    340 
    341 inline const char* ArtMethod::GetReturnTypeDescriptor() {
    342   DCHECK(!IsProxyMethod());
    343   const DexFile* dex_file = GetDexFile();
    344   const DexFile::MethodId& method_id = dex_file->GetMethodId(GetDexMethodIndex());
    345   const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
    346   return dex_file->GetTypeDescriptor(dex_file->GetTypeId(proto_id.return_type_idx_));
    347 }
    348 
    349 inline Primitive::Type ArtMethod::GetReturnTypePrimitive() {
    350   return Primitive::GetType(GetReturnTypeDescriptor()[0]);
    351 }
    352 
    353 inline const char* ArtMethod::GetTypeDescriptorFromTypeIdx(dex::TypeIndex type_idx) {
    354   DCHECK(!IsProxyMethod());
    355   const DexFile* dex_file = GetDexFile();
    356   return dex_file->GetTypeDescriptor(dex_file->GetTypeId(type_idx));
    357 }
    358 
    359 inline mirror::ClassLoader* ArtMethod::GetClassLoader() {
    360   DCHECK(!IsProxyMethod());
    361   return GetDeclaringClass()->GetClassLoader();
    362 }
    363 
    364 template <ReadBarrierOption kReadBarrierOption>
    365 inline mirror::DexCache* ArtMethod::GetDexCache() {
    366   if (LIKELY(!IsObsolete())) {
    367     mirror::Class* klass = GetDeclaringClass<kReadBarrierOption>();
    368     return klass->GetDexCache<kDefaultVerifyFlags, kReadBarrierOption>();
    369   } else {
    370     DCHECK(!IsProxyMethod());
    371     return GetObsoleteDexCache();
    372   }
    373 }
    374 
    375 inline bool ArtMethod::IsProxyMethod() {
    376   // Avoid read barrier since the from-space version of the class will have the correct proxy class
    377   // flags since they are constant for the lifetime of the class.
    378   return GetDeclaringClass<kWithoutReadBarrier>()->IsProxyClass();
    379 }
    380 
    381 inline ArtMethod* ArtMethod::GetInterfaceMethodIfProxy(PointerSize pointer_size) {
    382   if (LIKELY(!IsProxyMethod())) {
    383     return this;
    384   }
    385   uint32_t method_index = GetDexMethodIndex();
    386   uint32_t slot_idx = method_index % mirror::DexCache::kDexCacheMethodCacheSize;
    387   mirror::MethodDexCachePair pair = mirror::DexCache::GetNativePairPtrSize(
    388       GetDexCacheResolvedMethods(pointer_size), slot_idx, pointer_size);
    389   ArtMethod* interface_method = pair.GetObjectForIndex(method_index);
    390   if (LIKELY(interface_method != nullptr)) {
    391     DCHECK_EQ(interface_method, Runtime::Current()->GetClassLinker()->FindMethodForProxy(this));
    392   } else {
    393     interface_method = Runtime::Current()->GetClassLinker()->FindMethodForProxy(this);
    394     DCHECK(interface_method != nullptr);
    395   }
    396   return interface_method;
    397 }
    398 
    399 inline void ArtMethod::SetDexCacheResolvedMethods(mirror::MethodDexCacheType* new_dex_cache_methods,
    400                                                   PointerSize pointer_size) {
    401   SetNativePointer(DexCacheResolvedMethodsOffset(pointer_size),
    402                    new_dex_cache_methods,
    403                    pointer_size);
    404 }
    405 
    406 inline mirror::Class* ArtMethod::GetReturnType(bool resolve) {
    407   DCHECK(!IsProxyMethod());
    408   const DexFile* dex_file = GetDexFile();
    409   const DexFile::MethodId& method_id = dex_file->GetMethodId(GetDexMethodIndex());
    410   const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
    411   dex::TypeIndex return_type_idx = proto_id.return_type_idx_;
    412   return GetClassFromTypeIndex(return_type_idx, resolve);
    413 }
    414 
    415 inline bool ArtMethod::HasSingleImplementation() {
    416   if (IsFinal() || GetDeclaringClass()->IsFinal()) {
    417     // We don't set kAccSingleImplementation for these cases since intrinsic
    418     // can use the flag also.
    419     return true;
    420   }
    421   return (GetAccessFlags() & kAccSingleImplementation) != 0;
    422 }
    423 
    424 inline void ArtMethod::SetIntrinsic(uint32_t intrinsic) {
    425   DCHECK(IsUint<8>(intrinsic));
    426   // Currently we only do intrinsics for static/final methods or methods of final
    427   // classes. We don't set kHasSingleImplementation for those methods.
    428   DCHECK(IsStatic() || IsFinal() || GetDeclaringClass()->IsFinal()) <<
    429       "Potential conflict with kAccSingleImplementation";
    430   uint32_t new_value = (GetAccessFlags() & kAccFlagsNotUsedByIntrinsic) |
    431       kAccIntrinsic |
    432       (intrinsic << POPCOUNT(kAccFlagsNotUsedByIntrinsic));
    433   if (kIsDebugBuild) {
    434     uint32_t java_flags = (GetAccessFlags() & kAccJavaFlagsMask);
    435     bool is_constructor = IsConstructor();
    436     bool is_synchronized = IsSynchronized();
    437     bool skip_access_checks = SkipAccessChecks();
    438     bool is_fast_native = IsFastNative();
    439     bool is_copied = IsCopied();
    440     bool is_miranda = IsMiranda();
    441     bool is_default = IsDefault();
    442     bool is_default_conflict = IsDefaultConflicting();
    443     bool is_compilable = IsCompilable();
    444     bool must_count_locks = MustCountLocks();
    445     SetAccessFlags(new_value);
    446     DCHECK_EQ(java_flags, (GetAccessFlags() & kAccJavaFlagsMask));
    447     DCHECK_EQ(is_constructor, IsConstructor());
    448     DCHECK_EQ(is_synchronized, IsSynchronized());
    449     DCHECK_EQ(skip_access_checks, SkipAccessChecks());
    450     DCHECK_EQ(is_fast_native, IsFastNative());
    451     DCHECK_EQ(is_copied, IsCopied());
    452     DCHECK_EQ(is_miranda, IsMiranda());
    453     DCHECK_EQ(is_default, IsDefault());
    454     DCHECK_EQ(is_default_conflict, IsDefaultConflicting());
    455     DCHECK_EQ(is_compilable, IsCompilable());
    456     DCHECK_EQ(must_count_locks, MustCountLocks());
    457   } else {
    458     SetAccessFlags(new_value);
    459   }
    460 }
    461 
    462 template<ReadBarrierOption kReadBarrierOption, typename RootVisitorType>
    463 void ArtMethod::VisitRoots(RootVisitorType& visitor, PointerSize pointer_size) {
    464   if (LIKELY(!declaring_class_.IsNull())) {
    465     visitor.VisitRoot(declaring_class_.AddressWithoutBarrier());
    466     mirror::Class* klass = declaring_class_.Read<kReadBarrierOption>();
    467     if (UNLIKELY(klass->IsProxyClass())) {
    468       // For normal methods, dex cache shortcuts will be visited through the declaring class.
    469       // However, for proxies we need to keep the interface method alive, so we visit its roots.
    470       ArtMethod* interface_method = GetInterfaceMethodIfProxy(pointer_size);
    471       DCHECK(interface_method != nullptr);
    472       interface_method->VisitRoots(visitor, pointer_size);
    473     }
    474   }
    475 }
    476 
    477 template <typename Visitor>
    478 inline void ArtMethod::UpdateObjectsForImageRelocation(const Visitor& visitor,
    479                                                        PointerSize pointer_size) {
    480   mirror::Class* old_class = GetDeclaringClassUnchecked<kWithoutReadBarrier>();
    481   mirror::Class* new_class = visitor(old_class);
    482   if (old_class != new_class) {
    483     SetDeclaringClass(new_class);
    484   }
    485   mirror::MethodDexCacheType* old_methods = GetDexCacheResolvedMethods(pointer_size);
    486   mirror::MethodDexCacheType* new_methods = visitor(old_methods);
    487   if (old_methods != new_methods) {
    488     SetDexCacheResolvedMethods(new_methods, pointer_size);
    489   }
    490 }
    491 
    492 template <ReadBarrierOption kReadBarrierOption, typename Visitor>
    493 inline void ArtMethod::UpdateEntrypoints(const Visitor& visitor, PointerSize pointer_size) {
    494   if (IsNative<kReadBarrierOption>()) {
    495     const void* old_native_code = GetEntryPointFromJniPtrSize(pointer_size);
    496     const void* new_native_code = visitor(old_native_code);
    497     if (old_native_code != new_native_code) {
    498       SetEntryPointFromJniPtrSize(new_native_code, pointer_size);
    499     }
    500   } else {
    501     DCHECK(GetDataPtrSize(pointer_size) == nullptr);
    502   }
    503   const void* old_code = GetEntryPointFromQuickCompiledCodePtrSize(pointer_size);
    504   const void* new_code = visitor(old_code);
    505   if (old_code != new_code) {
    506     SetEntryPointFromQuickCompiledCodePtrSize(new_code, pointer_size);
    507   }
    508 }
    509 
    510 }  // namespace art
    511 
    512 #endif  // ART_RUNTIME_ART_METHOD_INL_H_
    513