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 "dex_file.h"
     25 #include "dex_file-inl.h"
     26 #include "gc_root-inl.h"
     27 #include "mirror/class-inl.h"
     28 #include "mirror/dex_cache.h"
     29 #include "mirror/object-inl.h"
     30 #include "mirror/object_array.h"
     31 #include "oat.h"
     32 #include "quick/quick_method_frame_info.h"
     33 #include "read_barrier-inl.h"
     34 #include "runtime-inl.h"
     35 #include "utils.h"
     36 
     37 namespace art {
     38 
     39 inline mirror::Class* ArtMethod::GetDeclaringClassUnchecked() {
     40   return declaring_class_.Read();
     41 }
     42 
     43 inline mirror::Class* ArtMethod::GetDeclaringClassNoBarrier() {
     44   return declaring_class_.Read<kWithoutReadBarrier>();
     45 }
     46 
     47 inline mirror::Class* ArtMethod::GetDeclaringClass() {
     48   mirror::Class* result = GetDeclaringClassUnchecked();
     49   if (kIsDebugBuild) {
     50     if (!IsRuntimeMethod()) {
     51       CHECK(result != nullptr) << this;
     52       CHECK(result->IsIdxLoaded() || result->IsErroneous())
     53           << result->GetStatus() << " " << PrettyClass(result);
     54     } else {
     55       CHECK(result == nullptr) << this;
     56     }
     57   }
     58   return result;
     59 }
     60 
     61 inline void ArtMethod::SetDeclaringClass(mirror::Class* new_declaring_class) {
     62   declaring_class_ = GcRoot<mirror::Class>(new_declaring_class);
     63 }
     64 
     65 inline uint32_t ArtMethod::GetAccessFlags() {
     66   DCHECK(IsRuntimeMethod() || GetDeclaringClass()->IsIdxLoaded() ||
     67          GetDeclaringClass()->IsErroneous());
     68   return access_flags_;
     69 }
     70 
     71 inline uint16_t ArtMethod::GetMethodIndex() {
     72   DCHECK(IsRuntimeMethod() || GetDeclaringClass()->IsResolved() ||
     73          GetDeclaringClass()->IsErroneous());
     74   return method_index_;
     75 }
     76 
     77 inline uint16_t ArtMethod::GetMethodIndexDuringLinking() {
     78   return method_index_;
     79 }
     80 
     81 inline uint32_t ArtMethod::GetDexMethodIndex() {
     82   DCHECK(IsRuntimeMethod() || GetDeclaringClass()->IsIdxLoaded() ||
     83          GetDeclaringClass()->IsErroneous());
     84   return dex_method_index_;
     85 }
     86 
     87 inline mirror::PointerArray* ArtMethod::GetDexCacheResolvedMethods() {
     88   return dex_cache_resolved_methods_.Read();
     89 }
     90 
     91 inline ArtMethod* ArtMethod::GetDexCacheResolvedMethod(uint16_t method_index, size_t ptr_size) {
     92   auto* method = GetDexCacheResolvedMethods()->GetElementPtrSize<ArtMethod*>(
     93       method_index, ptr_size);
     94   if (LIKELY(method != nullptr)) {
     95     auto* declaring_class = method->GetDeclaringClass();
     96     if (LIKELY(declaring_class == nullptr || !declaring_class->IsErroneous())) {
     97       return method;
     98     }
     99   }
    100   return nullptr;
    101 }
    102 
    103 inline void ArtMethod::SetDexCacheResolvedMethod(uint16_t method_idx, ArtMethod* new_method,
    104                                                  size_t ptr_size) {
    105   DCHECK(new_method == nullptr || new_method->GetDeclaringClass() != nullptr);
    106   GetDexCacheResolvedMethods()->SetElementPtrSize(method_idx, new_method, ptr_size);
    107 }
    108 
    109 inline bool ArtMethod::HasDexCacheResolvedMethods() {
    110   return GetDexCacheResolvedMethods() != nullptr;
    111 }
    112 
    113 inline bool ArtMethod::HasSameDexCacheResolvedMethods(mirror::PointerArray* other_cache) {
    114   return GetDexCacheResolvedMethods() == other_cache;
    115 }
    116 
    117 inline bool ArtMethod::HasSameDexCacheResolvedMethods(ArtMethod* other) {
    118   return GetDexCacheResolvedMethods() == other->GetDexCacheResolvedMethods();
    119 }
    120 
    121 inline mirror::ObjectArray<mirror::Class>* ArtMethod::GetDexCacheResolvedTypes() {
    122   return dex_cache_resolved_types_.Read();
    123 }
    124 
    125 template <bool kWithCheck>
    126 inline mirror::Class* ArtMethod::GetDexCacheResolvedType(uint32_t type_index) {
    127   mirror::Class* klass = kWithCheck ?
    128       GetDexCacheResolvedTypes()->Get(type_index) :
    129       GetDexCacheResolvedTypes()->GetWithoutChecks(type_index);
    130   return (klass != nullptr && !klass->IsErroneous()) ? klass : nullptr;
    131 }
    132 
    133 inline bool ArtMethod::HasDexCacheResolvedTypes() {
    134   return GetDexCacheResolvedTypes() != nullptr;
    135 }
    136 
    137 inline bool ArtMethod::HasSameDexCacheResolvedTypes(
    138     mirror::ObjectArray<mirror::Class>* other_cache) {
    139   return GetDexCacheResolvedTypes() == other_cache;
    140 }
    141 
    142 inline bool ArtMethod::HasSameDexCacheResolvedTypes(ArtMethod* other) {
    143   return GetDexCacheResolvedTypes() == other->GetDexCacheResolvedTypes();
    144 }
    145 
    146 inline mirror::Class* ArtMethod::GetClassFromTypeIndex(uint16_t type_idx, bool resolve) {
    147   mirror::Class* type = GetDexCacheResolvedType(type_idx);
    148   if (type == nullptr && resolve) {
    149     type = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, this);
    150     CHECK(type != nullptr || Thread::Current()->IsExceptionPending());
    151   }
    152   return type;
    153 }
    154 
    155 inline uint32_t ArtMethod::GetCodeSize() {
    156   DCHECK(!IsRuntimeMethod() && !IsProxyMethod()) << PrettyMethod(this);
    157   return GetCodeSize(EntryPointToCodePointer(GetEntryPointFromQuickCompiledCode()));
    158 }
    159 
    160 inline uint32_t ArtMethod::GetCodeSize(const void* code) {
    161   if (code == nullptr) {
    162     return 0u;
    163   }
    164   return reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].code_size_;
    165 }
    166 
    167 inline bool ArtMethod::CheckIncompatibleClassChange(InvokeType type) {
    168   switch (type) {
    169     case kStatic:
    170       return !IsStatic();
    171     case kDirect:
    172       return !IsDirect() || IsStatic();
    173     case kVirtual: {
    174       mirror::Class* methods_class = GetDeclaringClass();
    175       return IsDirect() || (methods_class->IsInterface() && !IsMiranda());
    176     }
    177     case kSuper:
    178       // Constructors and static methods are called with invoke-direct.
    179       // Interface methods cannot be invoked with invoke-super.
    180       return IsConstructor() || IsStatic() || GetDeclaringClass()->IsInterface();
    181     case kInterface: {
    182       mirror::Class* methods_class = GetDeclaringClass();
    183       return IsDirect() || !(methods_class->IsInterface() || methods_class->IsObjectClass());
    184     }
    185     default:
    186       LOG(FATAL) << "Unreachable - invocation type: " << type;
    187       UNREACHABLE();
    188   }
    189 }
    190 
    191 inline uint32_t ArtMethod::GetQuickOatCodeOffset() {
    192   DCHECK(!Runtime::Current()->IsStarted());
    193   return PointerToLowMemUInt32(GetEntryPointFromQuickCompiledCode());
    194 }
    195 
    196 inline void ArtMethod::SetQuickOatCodeOffset(uint32_t code_offset) {
    197   DCHECK(!Runtime::Current()->IsStarted());
    198   SetEntryPointFromQuickCompiledCode(reinterpret_cast<void*>(code_offset));
    199 }
    200 
    201 inline const uint8_t* ArtMethod::GetMappingTable(size_t pointer_size) {
    202   const void* code_pointer = GetQuickOatCodePointer(pointer_size);
    203   if (code_pointer == nullptr) {
    204     return nullptr;
    205   }
    206   return GetMappingTable(code_pointer, pointer_size);
    207 }
    208 
    209 inline const uint8_t* ArtMethod::GetMappingTable(const void* code_pointer, size_t pointer_size) {
    210   DCHECK(code_pointer != nullptr);
    211   DCHECK_EQ(code_pointer, GetQuickOatCodePointer(pointer_size));
    212   uint32_t offset =
    213       reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].mapping_table_offset_;
    214   if (UNLIKELY(offset == 0u)) {
    215     return nullptr;
    216   }
    217   return reinterpret_cast<const uint8_t*>(code_pointer) - offset;
    218 }
    219 
    220 inline const uint8_t* ArtMethod::GetVmapTable(size_t pointer_size) {
    221   const void* code_pointer = GetQuickOatCodePointer(pointer_size);
    222   if (code_pointer == nullptr) {
    223     return nullptr;
    224   }
    225   return GetVmapTable(code_pointer, pointer_size);
    226 }
    227 
    228 inline const uint8_t* ArtMethod::GetVmapTable(const void* code_pointer, size_t pointer_size) {
    229   CHECK(!IsOptimized(pointer_size)) << "Unimplemented vmap table for optimized compiler";
    230   DCHECK(code_pointer != nullptr);
    231   DCHECK_EQ(code_pointer, GetQuickOatCodePointer(pointer_size));
    232   uint32_t offset =
    233       reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].vmap_table_offset_;
    234   if (UNLIKELY(offset == 0u)) {
    235     return nullptr;
    236   }
    237   return reinterpret_cast<const uint8_t*>(code_pointer) - offset;
    238 }
    239 
    240 inline CodeInfo ArtMethod::GetOptimizedCodeInfo() {
    241   DCHECK(IsOptimized(sizeof(void*)));
    242   const void* code_pointer = GetQuickOatCodePointer(sizeof(void*));
    243   DCHECK(code_pointer != nullptr);
    244   uint32_t offset =
    245       reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].vmap_table_offset_;
    246   const void* data =
    247       reinterpret_cast<const void*>(reinterpret_cast<const uint8_t*>(code_pointer) - offset);
    248   return CodeInfo(data);
    249 }
    250 
    251 inline const uint8_t* ArtMethod::GetNativeGcMap(size_t pointer_size) {
    252   const void* code_pointer = GetQuickOatCodePointer(pointer_size);
    253   if (code_pointer == nullptr) {
    254     return nullptr;
    255   }
    256   return GetNativeGcMap(code_pointer, pointer_size);
    257 }
    258 
    259 inline const uint8_t* ArtMethod::GetNativeGcMap(const void* code_pointer, size_t pointer_size) {
    260   DCHECK(code_pointer != nullptr);
    261   DCHECK_EQ(code_pointer, GetQuickOatCodePointer(pointer_size));
    262   uint32_t offset =
    263       reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].gc_map_offset_;
    264   if (UNLIKELY(offset == 0u)) {
    265     return nullptr;
    266   }
    267   return reinterpret_cast<const uint8_t*>(code_pointer) - offset;
    268 }
    269 
    270 inline bool ArtMethod::IsRuntimeMethod() {
    271   return dex_method_index_ == DexFile::kDexNoIndex;
    272 }
    273 
    274 inline bool ArtMethod::IsCalleeSaveMethod() {
    275   if (!IsRuntimeMethod()) {
    276     return false;
    277   }
    278   Runtime* runtime = Runtime::Current();
    279   bool result = false;
    280   for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
    281     if (this == runtime->GetCalleeSaveMethod(Runtime::CalleeSaveType(i))) {
    282       result = true;
    283       break;
    284     }
    285   }
    286   return result;
    287 }
    288 
    289 inline bool ArtMethod::IsResolutionMethod() {
    290   bool result = this == Runtime::Current()->GetResolutionMethod();
    291   // Check that if we do think it is phony it looks like the resolution method.
    292   DCHECK(!result || IsRuntimeMethod());
    293   return result;
    294 }
    295 
    296 inline bool ArtMethod::IsImtConflictMethod() {
    297   bool result = this == Runtime::Current()->GetImtConflictMethod();
    298   // Check that if we do think it is phony it looks like the imt conflict method.
    299   DCHECK(!result || IsRuntimeMethod());
    300   return result;
    301 }
    302 
    303 inline bool ArtMethod::IsImtUnimplementedMethod() {
    304   bool result = this == Runtime::Current()->GetImtUnimplementedMethod();
    305   // Check that if we do think it is phony it looks like the imt unimplemented method.
    306   DCHECK(!result || IsRuntimeMethod());
    307   return result;
    308 }
    309 
    310 inline uintptr_t ArtMethod::NativeQuickPcOffset(const uintptr_t pc) {
    311   const void* code = Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(
    312       this, sizeof(void*));
    313   return pc - reinterpret_cast<uintptr_t>(code);
    314 }
    315 
    316 inline QuickMethodFrameInfo ArtMethod::GetQuickFrameInfo(const void* code_pointer) {
    317   DCHECK(code_pointer != nullptr);
    318   if (kIsDebugBuild && !IsProxyMethod()) {
    319     CHECK_EQ(code_pointer, GetQuickOatCodePointer(sizeof(void*)));
    320   }
    321   return reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].frame_info_;
    322 }
    323 
    324 inline const DexFile* ArtMethod::GetDexFile() {
    325   return GetDexCache()->GetDexFile();
    326 }
    327 
    328 inline const char* ArtMethod::GetDeclaringClassDescriptor() {
    329   uint32_t dex_method_idx = GetDexMethodIndex();
    330   if (UNLIKELY(dex_method_idx == DexFile::kDexNoIndex)) {
    331     return "<runtime method>";
    332   }
    333   DCHECK(!IsProxyMethod());
    334   const DexFile* dex_file = GetDexFile();
    335   return dex_file->GetMethodDeclaringClassDescriptor(dex_file->GetMethodId(dex_method_idx));
    336 }
    337 
    338 inline const char* ArtMethod::GetShorty(uint32_t* out_length) {
    339   DCHECK(!IsProxyMethod());
    340   const DexFile* dex_file = GetDexFile();
    341   return dex_file->GetMethodShorty(dex_file->GetMethodId(GetDexMethodIndex()), out_length);
    342 }
    343 
    344 inline const Signature ArtMethod::GetSignature() {
    345   uint32_t dex_method_idx = GetDexMethodIndex();
    346   if (dex_method_idx != DexFile::kDexNoIndex) {
    347     DCHECK(!IsProxyMethod());
    348     const DexFile* dex_file = GetDexFile();
    349     return dex_file->GetMethodSignature(dex_file->GetMethodId(dex_method_idx));
    350   }
    351   return Signature::NoSignature();
    352 }
    353 
    354 inline const char* ArtMethod::GetName() {
    355   uint32_t dex_method_idx = GetDexMethodIndex();
    356   if (LIKELY(dex_method_idx != DexFile::kDexNoIndex)) {
    357     DCHECK(!IsProxyMethod());
    358     const DexFile* dex_file = GetDexFile();
    359     return dex_file->GetMethodName(dex_file->GetMethodId(dex_method_idx));
    360   }
    361   Runtime* const runtime = Runtime::Current();
    362   if (this == runtime->GetResolutionMethod()) {
    363     return "<runtime internal resolution method>";
    364   } else if (this == runtime->GetImtConflictMethod()) {
    365     return "<runtime internal imt conflict method>";
    366   } else if (this == runtime->GetCalleeSaveMethod(Runtime::kSaveAll)) {
    367     return "<runtime internal callee-save all registers method>";
    368   } else if (this == runtime->GetCalleeSaveMethod(Runtime::kRefsOnly)) {
    369     return "<runtime internal callee-save reference registers method>";
    370   } else if (this == runtime->GetCalleeSaveMethod(Runtime::kRefsAndArgs)) {
    371     return "<runtime internal callee-save reference and argument registers method>";
    372   } else {
    373     return "<unknown runtime internal method>";
    374   }
    375 }
    376 
    377 inline const DexFile::CodeItem* ArtMethod::GetCodeItem() {
    378   return GetDeclaringClass()->GetDexFile().GetCodeItem(GetCodeItemOffset());
    379 }
    380 
    381 inline bool ArtMethod::IsResolvedTypeIdx(uint16_t type_idx) {
    382   DCHECK(!IsProxyMethod());
    383   return GetDexCacheResolvedType(type_idx) != nullptr;
    384 }
    385 
    386 inline int32_t ArtMethod::GetLineNumFromDexPC(uint32_t dex_pc) {
    387   DCHECK(!IsProxyMethod());
    388   if (dex_pc == DexFile::kDexNoIndex) {
    389     return IsNative() ? -2 : -1;
    390   }
    391   return GetDexFile()->GetLineNumFromPC(this, dex_pc);
    392 }
    393 
    394 inline const DexFile::ProtoId& ArtMethod::GetPrototype() {
    395   DCHECK(!IsProxyMethod());
    396   const DexFile* dex_file = GetDexFile();
    397   return dex_file->GetMethodPrototype(dex_file->GetMethodId(GetDexMethodIndex()));
    398 }
    399 
    400 inline const DexFile::TypeList* ArtMethod::GetParameterTypeList() {
    401   DCHECK(!IsProxyMethod());
    402   const DexFile* dex_file = GetDexFile();
    403   const DexFile::ProtoId& proto = dex_file->GetMethodPrototype(
    404       dex_file->GetMethodId(GetDexMethodIndex()));
    405   return dex_file->GetProtoParameters(proto);
    406 }
    407 
    408 inline const char* ArtMethod::GetDeclaringClassSourceFile() {
    409   DCHECK(!IsProxyMethod());
    410   return GetDeclaringClass()->GetSourceFile();
    411 }
    412 
    413 inline uint16_t ArtMethod::GetClassDefIndex() {
    414   DCHECK(!IsProxyMethod());
    415   return GetDeclaringClass()->GetDexClassDefIndex();
    416 }
    417 
    418 inline const DexFile::ClassDef& ArtMethod::GetClassDef() {
    419   DCHECK(!IsProxyMethod());
    420   return GetDexFile()->GetClassDef(GetClassDefIndex());
    421 }
    422 
    423 inline const char* ArtMethod::GetReturnTypeDescriptor() {
    424   DCHECK(!IsProxyMethod());
    425   const DexFile* dex_file = GetDexFile();
    426   const DexFile::MethodId& method_id = dex_file->GetMethodId(GetDexMethodIndex());
    427   const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
    428   uint16_t return_type_idx = proto_id.return_type_idx_;
    429   return dex_file->GetTypeDescriptor(dex_file->GetTypeId(return_type_idx));
    430 }
    431 
    432 inline const char* ArtMethod::GetTypeDescriptorFromTypeIdx(uint16_t type_idx) {
    433   DCHECK(!IsProxyMethod());
    434   const DexFile* dex_file = GetDexFile();
    435   return dex_file->GetTypeDescriptor(dex_file->GetTypeId(type_idx));
    436 }
    437 
    438 inline mirror::ClassLoader* ArtMethod::GetClassLoader() {
    439   DCHECK(!IsProxyMethod());
    440   return GetDeclaringClass()->GetClassLoader();
    441 }
    442 
    443 inline mirror::DexCache* ArtMethod::GetDexCache() {
    444   DCHECK(!IsProxyMethod());
    445   return GetDeclaringClass()->GetDexCache();
    446 }
    447 
    448 inline bool ArtMethod::IsProxyMethod() {
    449   return GetDeclaringClass()->IsProxyClass();
    450 }
    451 
    452 inline ArtMethod* ArtMethod::GetInterfaceMethodIfProxy(size_t pointer_size) {
    453   if (LIKELY(!IsProxyMethod())) {
    454     return this;
    455   }
    456   mirror::Class* klass = GetDeclaringClass();
    457   auto interface_method = GetDexCacheResolvedMethods()->GetElementPtrSize<ArtMethod*>(
    458       GetDexMethodIndex(), pointer_size);
    459   DCHECK(interface_method != nullptr);
    460   DCHECK_EQ(interface_method,
    461             Runtime::Current()->GetClassLinker()->FindMethodForProxy(klass, this));
    462   return interface_method;
    463 }
    464 
    465 inline void ArtMethod::SetDexCacheResolvedMethods(mirror::PointerArray* new_dex_cache_methods) {
    466   dex_cache_resolved_methods_ = GcRoot<mirror::PointerArray>(new_dex_cache_methods);
    467 }
    468 
    469 inline void ArtMethod::SetDexCacheResolvedTypes(
    470     mirror::ObjectArray<mirror::Class>* new_dex_cache_types) {
    471   dex_cache_resolved_types_ = GcRoot<mirror::ObjectArray<mirror::Class>>(new_dex_cache_types);
    472 }
    473 
    474 inline mirror::Class* ArtMethod::GetReturnType(bool resolve) {
    475   DCHECK(!IsProxyMethod());
    476   const DexFile* dex_file = GetDexFile();
    477   const DexFile::MethodId& method_id = dex_file->GetMethodId(GetDexMethodIndex());
    478   const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
    479   uint16_t return_type_idx = proto_id.return_type_idx_;
    480   mirror::Class* type = GetDexCacheResolvedType(return_type_idx);
    481   if (type == nullptr && resolve) {
    482     type = Runtime::Current()->GetClassLinker()->ResolveType(return_type_idx, this);
    483     CHECK(type != nullptr || Thread::Current()->IsExceptionPending());
    484   }
    485   return type;
    486 }
    487 
    488 template<typename RootVisitorType>
    489 void ArtMethod::VisitRoots(RootVisitorType& visitor) {
    490   visitor.VisitRootIfNonNull(declaring_class_.AddressWithoutBarrier());
    491   visitor.VisitRootIfNonNull(dex_cache_resolved_methods_.AddressWithoutBarrier());
    492   visitor.VisitRootIfNonNull(dex_cache_resolved_types_.AddressWithoutBarrier());
    493 }
    494 
    495 inline void ArtMethod::CopyFrom(const ArtMethod* src, size_t image_pointer_size) {
    496   memcpy(reinterpret_cast<void*>(this), reinterpret_cast<const void*>(src),
    497          ObjectSize(image_pointer_size));
    498   declaring_class_ = GcRoot<mirror::Class>(const_cast<ArtMethod*>(src)->GetDeclaringClass());
    499   dex_cache_resolved_methods_ = GcRoot<mirror::PointerArray>(
    500       const_cast<ArtMethod*>(src)->GetDexCacheResolvedMethods());
    501   dex_cache_resolved_types_ = GcRoot<mirror::ObjectArray<mirror::Class>>(
    502       const_cast<ArtMethod*>(src)->GetDexCacheResolvedTypes());
    503 }
    504 
    505 }  // namespace art
    506 
    507 #endif  // ART_RUNTIME_ART_METHOD_INL_H_
    508