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/logging.h"
     24 #include "class_linker-inl.h"
     25 #include "common_throws.h"
     26 #include "dex_file.h"
     27 #include "dex_file-inl.h"
     28 #include "gc_root-inl.h"
     29 #include "jit/profiling_info.h"
     30 #include "mirror/class-inl.h"
     31 #include "mirror/dex_cache-inl.h"
     32 #include "mirror/object-inl.h"
     33 #include "mirror/object_array.h"
     34 #include "oat.h"
     35 #include "quick/quick_method_frame_info.h"
     36 #include "read_barrier-inl.h"
     37 #include "runtime-inl.h"
     38 #include "scoped_thread_state_change.h"
     39 #include "thread-inl.h"
     40 #include "utils.h"
     41 
     42 namespace art {
     43 
     44 template <ReadBarrierOption kReadBarrierOption>
     45 inline mirror::Class* ArtMethod::GetDeclaringClassUnchecked() {
     46   GcRootSource gc_root_source(this);
     47   return declaring_class_.Read<kReadBarrierOption>(&gc_root_source);
     48 }
     49 
     50 template <ReadBarrierOption kReadBarrierOption>
     51 inline mirror::Class* ArtMethod::GetDeclaringClass() {
     52   mirror::Class* result = GetDeclaringClassUnchecked<kReadBarrierOption>();
     53   if (kIsDebugBuild) {
     54     if (!IsRuntimeMethod()) {
     55       CHECK(result != nullptr) << this;
     56       CHECK(result->IsIdxLoaded() || result->IsErroneous())
     57           << result->GetStatus() << " " << PrettyClass(result);
     58     } else {
     59       CHECK(result == nullptr) << this;
     60     }
     61   }
     62   return result;
     63 }
     64 
     65 inline void ArtMethod::SetDeclaringClass(mirror::Class* new_declaring_class) {
     66   declaring_class_ = GcRoot<mirror::Class>(new_declaring_class);
     67 }
     68 
     69 inline bool ArtMethod::CASDeclaringClass(mirror::Class* expected_class,
     70                                          mirror::Class* desired_class) {
     71   GcRoot<mirror::Class> expected_root(expected_class);
     72   GcRoot<mirror::Class> desired_root(desired_class);
     73   return reinterpret_cast<Atomic<GcRoot<mirror::Class>>*>(&declaring_class_)->
     74       CompareExchangeStrongSequentiallyConsistent(
     75           expected_root, desired_root);
     76 }
     77 
     78 // AssertSharedHeld doesn't work in GetAccessFlags, so use a NO_THREAD_SAFETY_ANALYSIS helper.
     79 // TODO: Figure out why ASSERT_SHARED_CAPABILITY doesn't work.
     80 template <ReadBarrierOption kReadBarrierOption>
     81 ALWAYS_INLINE static inline void DoGetAccessFlagsHelper(ArtMethod* method)
     82     NO_THREAD_SAFETY_ANALYSIS {
     83   CHECK(method->IsRuntimeMethod() ||
     84         method->GetDeclaringClass<kReadBarrierOption>()->IsIdxLoaded() ||
     85         method->GetDeclaringClass<kReadBarrierOption>()->IsErroneous());
     86 }
     87 
     88 template <ReadBarrierOption kReadBarrierOption>
     89 inline uint32_t ArtMethod::GetAccessFlags() {
     90   if (kIsDebugBuild) {
     91     Thread* self = Thread::Current();
     92     if (!Locks::mutator_lock_->IsSharedHeld(self)) {
     93       ScopedObjectAccess soa(self);
     94       CHECK(IsRuntimeMethod() ||
     95             GetDeclaringClass<kReadBarrierOption>()->IsIdxLoaded() ||
     96             GetDeclaringClass<kReadBarrierOption>()->IsErroneous());
     97     } else {
     98       // We cannot use SOA in this case. We might be holding the lock, but may not be in the
     99       // runnable state (e.g., during GC).
    100       Locks::mutator_lock_->AssertSharedHeld(self);
    101       DoGetAccessFlagsHelper<kReadBarrierOption>(this);
    102     }
    103   }
    104   return access_flags_;
    105 }
    106 
    107 inline uint16_t ArtMethod::GetMethodIndex() {
    108   DCHECK(IsRuntimeMethod() || GetDeclaringClass()->IsResolved() ||
    109          GetDeclaringClass()->IsErroneous());
    110   return method_index_;
    111 }
    112 
    113 inline uint16_t ArtMethod::GetMethodIndexDuringLinking() {
    114   return method_index_;
    115 }
    116 
    117 inline uint32_t ArtMethod::GetDexMethodIndex() {
    118   DCHECK(IsRuntimeMethod() || GetDeclaringClass()->IsIdxLoaded() ||
    119          GetDeclaringClass()->IsErroneous());
    120   return dex_method_index_;
    121 }
    122 
    123 inline ArtMethod** ArtMethod::GetDexCacheResolvedMethods(size_t pointer_size) {
    124   return GetNativePointer<ArtMethod**>(DexCacheResolvedMethodsOffset(pointer_size),
    125                                        pointer_size);
    126 }
    127 
    128 inline ArtMethod* ArtMethod::GetDexCacheResolvedMethod(uint16_t method_index, size_t ptr_size) {
    129   // NOTE: Unchecked, i.e. not throwing AIOOB. We don't even know the length here
    130   // without accessing the DexCache and we don't want to do that in release build.
    131   DCHECK_LT(method_index,
    132             GetInterfaceMethodIfProxy(ptr_size)->GetDeclaringClass()
    133                 ->GetDexCache()->NumResolvedMethods());
    134   ArtMethod* method = mirror::DexCache::GetElementPtrSize(GetDexCacheResolvedMethods(ptr_size),
    135                                                           method_index,
    136                                                           ptr_size);
    137   if (LIKELY(method != nullptr)) {
    138     auto* declaring_class = method->GetDeclaringClass();
    139     if (LIKELY(declaring_class == nullptr || !declaring_class->IsErroneous())) {
    140       return method;
    141     }
    142   }
    143   return nullptr;
    144 }
    145 
    146 inline void ArtMethod::SetDexCacheResolvedMethod(uint16_t method_index, ArtMethod* new_method,
    147                                                  size_t ptr_size) {
    148   // NOTE: Unchecked, i.e. not throwing AIOOB. We don't even know the length here
    149   // without accessing the DexCache and we don't want to do that in release build.
    150   DCHECK_LT(method_index,
    151             GetInterfaceMethodIfProxy(ptr_size)->GetDeclaringClass()
    152                 ->GetDexCache()->NumResolvedMethods());
    153   DCHECK(new_method == nullptr || new_method->GetDeclaringClass() != nullptr);
    154   mirror::DexCache::SetElementPtrSize(GetDexCacheResolvedMethods(ptr_size),
    155                                       method_index,
    156                                       new_method,
    157                                       ptr_size);
    158 }
    159 
    160 inline bool ArtMethod::HasDexCacheResolvedMethods(size_t pointer_size) {
    161   return GetDexCacheResolvedMethods(pointer_size) != nullptr;
    162 }
    163 
    164 inline bool ArtMethod::HasSameDexCacheResolvedMethods(ArtMethod** other_cache,
    165                                                       size_t pointer_size) {
    166   return GetDexCacheResolvedMethods(pointer_size) == other_cache;
    167 }
    168 
    169 inline bool ArtMethod::HasSameDexCacheResolvedMethods(ArtMethod* other, size_t pointer_size) {
    170   return GetDexCacheResolvedMethods(pointer_size) ==
    171       other->GetDexCacheResolvedMethods(pointer_size);
    172 }
    173 
    174 inline GcRoot<mirror::Class>* ArtMethod::GetDexCacheResolvedTypes(size_t pointer_size) {
    175   return GetNativePointer<GcRoot<mirror::Class>*>(DexCacheResolvedTypesOffset(pointer_size),
    176                                                   pointer_size);
    177 }
    178 
    179 template <bool kWithCheck>
    180 inline mirror::Class* ArtMethod::GetDexCacheResolvedType(uint32_t type_index, size_t ptr_size) {
    181   if (kWithCheck) {
    182     mirror::DexCache* dex_cache =
    183         GetInterfaceMethodIfProxy(ptr_size)->GetDeclaringClass()->GetDexCache();
    184     if (UNLIKELY(type_index >= dex_cache->NumResolvedTypes())) {
    185       ThrowArrayIndexOutOfBoundsException(type_index, dex_cache->NumResolvedTypes());
    186       return nullptr;
    187     }
    188   }
    189   mirror::Class* klass = GetDexCacheResolvedTypes(ptr_size)[type_index].Read();
    190   return (klass != nullptr && !klass->IsErroneous()) ? klass : nullptr;
    191 }
    192 
    193 inline bool ArtMethod::HasDexCacheResolvedTypes(size_t pointer_size) {
    194   return GetDexCacheResolvedTypes(pointer_size) != nullptr;
    195 }
    196 
    197 inline bool ArtMethod::HasSameDexCacheResolvedTypes(GcRoot<mirror::Class>* other_cache,
    198                                                     size_t pointer_size) {
    199   return GetDexCacheResolvedTypes(pointer_size) == other_cache;
    200 }
    201 
    202 inline bool ArtMethod::HasSameDexCacheResolvedTypes(ArtMethod* other, size_t pointer_size) {
    203   return GetDexCacheResolvedTypes(pointer_size) == other->GetDexCacheResolvedTypes(pointer_size);
    204 }
    205 
    206 inline mirror::Class* ArtMethod::GetClassFromTypeIndex(uint16_t type_idx,
    207                                                        bool resolve,
    208                                                        size_t ptr_size) {
    209   mirror::Class* type = GetDexCacheResolvedType(type_idx, ptr_size);
    210   if (type == nullptr && resolve) {
    211     type = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, this);
    212     CHECK(type != nullptr || Thread::Current()->IsExceptionPending());
    213   }
    214   return type;
    215 }
    216 
    217 inline bool ArtMethod::CheckIncompatibleClassChange(InvokeType type) {
    218   switch (type) {
    219     case kStatic:
    220       return !IsStatic();
    221     case kDirect:
    222       return !IsDirect() || IsStatic();
    223     case kVirtual: {
    224       // We have an error if we are direct or a non-default, non-miranda interface method.
    225       mirror::Class* methods_class = GetDeclaringClass();
    226       return IsDirect() || (methods_class->IsInterface() && !IsDefault() && !IsMiranda());
    227     }
    228     case kSuper:
    229       // Constructors and static methods are called with invoke-direct.
    230       return IsConstructor() || IsStatic();
    231     case kInterface: {
    232       mirror::Class* methods_class = GetDeclaringClass();
    233       return IsDirect() || !(methods_class->IsInterface() || methods_class->IsObjectClass());
    234     }
    235     default:
    236       LOG(FATAL) << "Unreachable - invocation type: " << type;
    237       UNREACHABLE();
    238   }
    239 }
    240 
    241 inline bool ArtMethod::IsRuntimeMethod() {
    242   return dex_method_index_ == DexFile::kDexNoIndex;
    243 }
    244 
    245 inline bool ArtMethod::IsCalleeSaveMethod() {
    246   if (!IsRuntimeMethod()) {
    247     return false;
    248   }
    249   Runtime* runtime = Runtime::Current();
    250   bool result = false;
    251   for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
    252     if (this == runtime->GetCalleeSaveMethod(Runtime::CalleeSaveType(i))) {
    253       result = true;
    254       break;
    255     }
    256   }
    257   return result;
    258 }
    259 
    260 inline bool ArtMethod::IsResolutionMethod() {
    261   bool result = this == Runtime::Current()->GetResolutionMethod();
    262   // Check that if we do think it is phony it looks like the resolution method.
    263   DCHECK(!result || IsRuntimeMethod());
    264   return result;
    265 }
    266 
    267 inline bool ArtMethod::IsImtUnimplementedMethod() {
    268   bool result = this == Runtime::Current()->GetImtUnimplementedMethod();
    269   // Check that if we do think it is phony it looks like the imt unimplemented method.
    270   DCHECK(!result || IsRuntimeMethod());
    271   return result;
    272 }
    273 
    274 inline const DexFile* ArtMethod::GetDexFile() {
    275   return GetDexCache()->GetDexFile();
    276 }
    277 
    278 inline const char* ArtMethod::GetDeclaringClassDescriptor() {
    279   uint32_t dex_method_idx = GetDexMethodIndex();
    280   if (UNLIKELY(dex_method_idx == DexFile::kDexNoIndex)) {
    281     return "<runtime method>";
    282   }
    283   DCHECK(!IsProxyMethod());
    284   const DexFile* dex_file = GetDexFile();
    285   return dex_file->GetMethodDeclaringClassDescriptor(dex_file->GetMethodId(dex_method_idx));
    286 }
    287 
    288 inline const char* ArtMethod::GetShorty(uint32_t* out_length) {
    289   DCHECK(!IsProxyMethod());
    290   const DexFile* dex_file = GetDexFile();
    291   return dex_file->GetMethodShorty(dex_file->GetMethodId(GetDexMethodIndex()), out_length);
    292 }
    293 
    294 inline const Signature ArtMethod::GetSignature() {
    295   uint32_t dex_method_idx = GetDexMethodIndex();
    296   if (dex_method_idx != DexFile::kDexNoIndex) {
    297     DCHECK(!IsProxyMethod());
    298     const DexFile* dex_file = GetDexFile();
    299     return dex_file->GetMethodSignature(dex_file->GetMethodId(dex_method_idx));
    300   }
    301   return Signature::NoSignature();
    302 }
    303 
    304 inline const char* ArtMethod::GetName() {
    305   uint32_t dex_method_idx = GetDexMethodIndex();
    306   if (LIKELY(dex_method_idx != DexFile::kDexNoIndex)) {
    307     DCHECK(!IsProxyMethod());
    308     const DexFile* dex_file = GetDexFile();
    309     return dex_file->GetMethodName(dex_file->GetMethodId(dex_method_idx));
    310   }
    311   Runtime* const runtime = Runtime::Current();
    312   if (this == runtime->GetResolutionMethod()) {
    313     return "<runtime internal resolution method>";
    314   } else if (this == runtime->GetImtConflictMethod()) {
    315     return "<runtime internal imt conflict method>";
    316   } else if (this == runtime->GetCalleeSaveMethod(Runtime::kSaveAll)) {
    317     return "<runtime internal callee-save all registers method>";
    318   } else if (this == runtime->GetCalleeSaveMethod(Runtime::kRefsOnly)) {
    319     return "<runtime internal callee-save reference registers method>";
    320   } else if (this == runtime->GetCalleeSaveMethod(Runtime::kRefsAndArgs)) {
    321     return "<runtime internal callee-save reference and argument registers method>";
    322   } else {
    323     return "<unknown runtime internal method>";
    324   }
    325 }
    326 
    327 inline const DexFile::CodeItem* ArtMethod::GetCodeItem() {
    328   return GetDeclaringClass()->GetDexFile().GetCodeItem(GetCodeItemOffset());
    329 }
    330 
    331 inline bool ArtMethod::IsResolvedTypeIdx(uint16_t type_idx, size_t ptr_size) {
    332   DCHECK(!IsProxyMethod());
    333   return GetDexCacheResolvedType(type_idx, ptr_size) != nullptr;
    334 }
    335 
    336 inline int32_t ArtMethod::GetLineNumFromDexPC(uint32_t dex_pc) {
    337   DCHECK(!IsProxyMethod());
    338   if (dex_pc == DexFile::kDexNoIndex) {
    339     return IsNative() ? -2 : -1;
    340   }
    341   return GetDexFile()->GetLineNumFromPC(this, dex_pc);
    342 }
    343 
    344 inline const DexFile::ProtoId& ArtMethod::GetPrototype() {
    345   DCHECK(!IsProxyMethod());
    346   const DexFile* dex_file = GetDexFile();
    347   return dex_file->GetMethodPrototype(dex_file->GetMethodId(GetDexMethodIndex()));
    348 }
    349 
    350 inline const DexFile::TypeList* ArtMethod::GetParameterTypeList() {
    351   DCHECK(!IsProxyMethod());
    352   const DexFile* dex_file = GetDexFile();
    353   const DexFile::ProtoId& proto = dex_file->GetMethodPrototype(
    354       dex_file->GetMethodId(GetDexMethodIndex()));
    355   return dex_file->GetProtoParameters(proto);
    356 }
    357 
    358 inline const char* ArtMethod::GetDeclaringClassSourceFile() {
    359   DCHECK(!IsProxyMethod());
    360   return GetDeclaringClass()->GetSourceFile();
    361 }
    362 
    363 inline uint16_t ArtMethod::GetClassDefIndex() {
    364   DCHECK(!IsProxyMethod());
    365   return GetDeclaringClass()->GetDexClassDefIndex();
    366 }
    367 
    368 inline const DexFile::ClassDef& ArtMethod::GetClassDef() {
    369   DCHECK(!IsProxyMethod());
    370   return GetDexFile()->GetClassDef(GetClassDefIndex());
    371 }
    372 
    373 inline const char* ArtMethod::GetReturnTypeDescriptor() {
    374   DCHECK(!IsProxyMethod());
    375   const DexFile* dex_file = GetDexFile();
    376   const DexFile::MethodId& method_id = dex_file->GetMethodId(GetDexMethodIndex());
    377   const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
    378   uint16_t return_type_idx = proto_id.return_type_idx_;
    379   return dex_file->GetTypeDescriptor(dex_file->GetTypeId(return_type_idx));
    380 }
    381 
    382 inline const char* ArtMethod::GetTypeDescriptorFromTypeIdx(uint16_t type_idx) {
    383   DCHECK(!IsProxyMethod());
    384   const DexFile* dex_file = GetDexFile();
    385   return dex_file->GetTypeDescriptor(dex_file->GetTypeId(type_idx));
    386 }
    387 
    388 inline mirror::ClassLoader* ArtMethod::GetClassLoader() {
    389   DCHECK(!IsProxyMethod());
    390   return GetDeclaringClass()->GetClassLoader();
    391 }
    392 
    393 inline mirror::DexCache* ArtMethod::GetDexCache() {
    394   DCHECK(!IsProxyMethod());
    395   return GetDeclaringClass()->GetDexCache();
    396 }
    397 
    398 inline bool ArtMethod::IsProxyMethod() {
    399   return GetDeclaringClass()->IsProxyClass();
    400 }
    401 
    402 inline ArtMethod* ArtMethod::GetInterfaceMethodIfProxy(size_t pointer_size) {
    403   if (LIKELY(!IsProxyMethod())) {
    404     return this;
    405   }
    406   mirror::Class* klass = GetDeclaringClass();
    407   ArtMethod* interface_method = mirror::DexCache::GetElementPtrSize(
    408       GetDexCacheResolvedMethods(pointer_size),
    409       GetDexMethodIndex(),
    410       pointer_size);
    411   DCHECK(interface_method != nullptr);
    412   DCHECK_EQ(interface_method,
    413             Runtime::Current()->GetClassLinker()->FindMethodForProxy(klass, this));
    414   return interface_method;
    415 }
    416 
    417 inline void ArtMethod::SetDexCacheResolvedMethods(ArtMethod** new_dex_cache_methods,
    418                                                   size_t ptr_size) {
    419   SetNativePointer(DexCacheResolvedMethodsOffset(ptr_size), new_dex_cache_methods, ptr_size);
    420 }
    421 
    422 inline void ArtMethod::SetDexCacheResolvedTypes(GcRoot<mirror::Class>* new_dex_cache_types,
    423                                                 size_t ptr_size) {
    424   SetNativePointer(DexCacheResolvedTypesOffset(ptr_size), new_dex_cache_types, ptr_size);
    425 }
    426 
    427 inline mirror::Class* ArtMethod::GetReturnType(bool resolve, size_t ptr_size) {
    428   DCHECK(!IsProxyMethod());
    429   const DexFile* dex_file = GetDexFile();
    430   const DexFile::MethodId& method_id = dex_file->GetMethodId(GetDexMethodIndex());
    431   const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
    432   uint16_t return_type_idx = proto_id.return_type_idx_;
    433   mirror::Class* type = GetDexCacheResolvedType(return_type_idx, ptr_size);
    434   if (type == nullptr && resolve) {
    435     type = Runtime::Current()->GetClassLinker()->ResolveType(return_type_idx, this);
    436     CHECK(type != nullptr || Thread::Current()->IsExceptionPending());
    437   }
    438   return type;
    439 }
    440 
    441 template<typename RootVisitorType>
    442 void ArtMethod::VisitRoots(RootVisitorType& visitor, size_t pointer_size) {
    443   ArtMethod* interface_method = nullptr;
    444   mirror::Class* klass = declaring_class_.Read();
    445   if (LIKELY(klass != nullptr)) {
    446     if (UNLIKELY(klass->IsProxyClass())) {
    447       // For normal methods, dex cache shortcuts will be visited through the declaring class.
    448       // However, for proxies we need to keep the interface method alive, so we visit its roots.
    449       interface_method = mirror::DexCache::GetElementPtrSize(
    450           GetDexCacheResolvedMethods(pointer_size),
    451           GetDexMethodIndex(),
    452           pointer_size);
    453       DCHECK(interface_method != nullptr);
    454       DCHECK_EQ(interface_method,
    455                 Runtime::Current()->GetClassLinker()->FindMethodForProxy(klass, this));
    456       interface_method->VisitRoots(visitor, pointer_size);
    457     }
    458     visitor.VisitRoot(declaring_class_.AddressWithoutBarrier());
    459     // We know we don't have profiling information if the class hasn't been verified. Note
    460     // that this check also ensures the IsNative call can be made, as IsNative expects a fully
    461     // created class (and not a retired one).
    462     if (klass->IsVerified()) {
    463       // Runtime methods and native methods use the same field as the profiling info for
    464       // storing their own data (jni entrypoint for native methods, and ImtConflictTable for
    465       // some runtime methods).
    466       if (!IsNative() && !IsRuntimeMethod()) {
    467         ProfilingInfo* profiling_info = GetProfilingInfo(pointer_size);
    468         if (profiling_info != nullptr) {
    469           profiling_info->VisitRoots(visitor);
    470         }
    471       }
    472     }
    473   }
    474 }
    475 
    476 template <typename Visitor>
    477 inline void ArtMethod::UpdateObjectsForImageRelocation(const Visitor& visitor,
    478                                                        size_t pointer_size) {
    479   mirror::Class* old_class = GetDeclaringClassUnchecked<kWithoutReadBarrier>();
    480   mirror::Class* new_class = visitor(old_class);
    481   if (old_class != new_class) {
    482     SetDeclaringClass(new_class);
    483   }
    484   ArtMethod** old_methods = GetDexCacheResolvedMethods(pointer_size);
    485   ArtMethod** new_methods = visitor(old_methods);
    486   if (old_methods != new_methods) {
    487     SetDexCacheResolvedMethods(new_methods, pointer_size);
    488   }
    489   GcRoot<mirror::Class>* old_types = GetDexCacheResolvedTypes(pointer_size);
    490   GcRoot<mirror::Class>* new_types = visitor(old_types);
    491   if (old_types != new_types) {
    492     SetDexCacheResolvedTypes(new_types, pointer_size);
    493   }
    494 }
    495 
    496 template <ReadBarrierOption kReadBarrierOption, typename Visitor>
    497 inline void ArtMethod::UpdateEntrypoints(const Visitor& visitor, size_t pointer_size) {
    498   if (IsNative<kReadBarrierOption>()) {
    499     const void* old_native_code = GetEntryPointFromJniPtrSize(pointer_size);
    500     const void* new_native_code = visitor(old_native_code);
    501     if (old_native_code != new_native_code) {
    502       SetEntryPointFromJniPtrSize(new_native_code, pointer_size);
    503     }
    504   } else {
    505     DCHECK(GetEntryPointFromJniPtrSize(pointer_size) == nullptr);
    506   }
    507   const void* old_code = GetEntryPointFromQuickCompiledCodePtrSize(pointer_size);
    508   const void* new_code = visitor(old_code);
    509   if (old_code != new_code) {
    510     SetEntryPointFromQuickCompiledCodePtrSize(new_code, pointer_size);
    511   }
    512 }
    513 
    514 }  // namespace art
    515 
    516 #endif  // ART_RUNTIME_ART_METHOD_INL_H_
    517