Home | History | Annotate | Download | only in runtime
      1 /*
      2  * Copyright (C) 2016 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_IMT_CONFLICT_TABLE_H_
     18 #define ART_RUNTIME_IMT_CONFLICT_TABLE_H_
     19 
     20 #include <cstddef>
     21 
     22 #include "base/casts.h"
     23 #include "base/enums.h"
     24 #include "base/macros.h"
     25 
     26 namespace art {
     27 
     28 class ArtMethod;
     29 
     30 // Table to resolve IMT conflicts at runtime. The table is attached to
     31 // the jni entrypoint of IMT conflict ArtMethods.
     32 // The table contains a list of pairs of { interface_method, implementation_method }
     33 // with the last entry being null to make an assembly implementation of a lookup
     34 // faster.
     35 class ImtConflictTable {
     36   enum MethodIndex {
     37     kMethodInterface,
     38     kMethodImplementation,
     39     kMethodCount,  // Number of elements in enum.
     40   };
     41 
     42  public:
     43   // Build a new table copying `other` and adding the new entry formed of
     44   // the pair { `interface_method`, `implementation_method` }
     45   ImtConflictTable(ImtConflictTable* other,
     46                    ArtMethod* interface_method,
     47                    ArtMethod* implementation_method,
     48                    PointerSize pointer_size) {
     49     const size_t count = other->NumEntries(pointer_size);
     50     for (size_t i = 0; i < count; ++i) {
     51       SetInterfaceMethod(i, pointer_size, other->GetInterfaceMethod(i, pointer_size));
     52       SetImplementationMethod(i, pointer_size, other->GetImplementationMethod(i, pointer_size));
     53     }
     54     SetInterfaceMethod(count, pointer_size, interface_method);
     55     SetImplementationMethod(count, pointer_size, implementation_method);
     56     // Add the null marker.
     57     SetInterfaceMethod(count + 1, pointer_size, nullptr);
     58     SetImplementationMethod(count + 1, pointer_size, nullptr);
     59   }
     60 
     61   // num_entries excludes the header.
     62   ImtConflictTable(size_t num_entries, PointerSize pointer_size) {
     63     SetInterfaceMethod(num_entries, pointer_size, nullptr);
     64     SetImplementationMethod(num_entries, pointer_size, nullptr);
     65   }
     66 
     67   // Set an entry at an index.
     68   void SetInterfaceMethod(size_t index, PointerSize pointer_size, ArtMethod* method) {
     69     SetMethod(index * kMethodCount + kMethodInterface, pointer_size, method);
     70   }
     71 
     72   void SetImplementationMethod(size_t index, PointerSize pointer_size, ArtMethod* method) {
     73     SetMethod(index * kMethodCount + kMethodImplementation, pointer_size, method);
     74   }
     75 
     76   ArtMethod* GetInterfaceMethod(size_t index, PointerSize pointer_size) const {
     77     return GetMethod(index * kMethodCount + kMethodInterface, pointer_size);
     78   }
     79 
     80   ArtMethod* GetImplementationMethod(size_t index, PointerSize pointer_size) const {
     81     return GetMethod(index * kMethodCount + kMethodImplementation, pointer_size);
     82   }
     83 
     84   void** AddressOfInterfaceMethod(size_t index, PointerSize pointer_size) {
     85     return AddressOfMethod(index * kMethodCount + kMethodInterface, pointer_size);
     86   }
     87 
     88   void** AddressOfImplementationMethod(size_t index, PointerSize pointer_size) {
     89     return AddressOfMethod(index * kMethodCount + kMethodImplementation, pointer_size);
     90   }
     91 
     92   // Return true if two conflict tables are the same.
     93   bool Equals(ImtConflictTable* other, PointerSize pointer_size) const {
     94     size_t num = NumEntries(pointer_size);
     95     if (num != other->NumEntries(pointer_size)) {
     96       return false;
     97     }
     98     for (size_t i = 0; i < num; ++i) {
     99       if (GetInterfaceMethod(i, pointer_size) != other->GetInterfaceMethod(i, pointer_size) ||
    100           GetImplementationMethod(i, pointer_size) !=
    101               other->GetImplementationMethod(i, pointer_size)) {
    102         return false;
    103       }
    104     }
    105     return true;
    106   }
    107 
    108   // Visit all of the entries.
    109   // NO_THREAD_SAFETY_ANALYSIS for calling with held locks. Visitor is passed a pair of ArtMethod*
    110   // and also returns one. The order is <interface, implementation>.
    111   template<typename Visitor>
    112   void Visit(const Visitor& visitor, PointerSize pointer_size) NO_THREAD_SAFETY_ANALYSIS {
    113     uint32_t table_index = 0;
    114     for (;;) {
    115       ArtMethod* interface_method = GetInterfaceMethod(table_index, pointer_size);
    116       if (interface_method == nullptr) {
    117         break;
    118       }
    119       ArtMethod* implementation_method = GetImplementationMethod(table_index, pointer_size);
    120       auto input = std::make_pair(interface_method, implementation_method);
    121       std::pair<ArtMethod*, ArtMethod*> updated = visitor(input);
    122       if (input.first != updated.first) {
    123         SetInterfaceMethod(table_index, pointer_size, updated.first);
    124       }
    125       if (input.second != updated.second) {
    126         SetImplementationMethod(table_index, pointer_size, updated.second);
    127       }
    128       ++table_index;
    129     }
    130   }
    131 
    132   // Lookup the implementation ArtMethod associated to `interface_method`. Return null
    133   // if not found.
    134   ArtMethod* Lookup(ArtMethod* interface_method, PointerSize pointer_size) const {
    135     uint32_t table_index = 0;
    136     for (;;) {
    137       ArtMethod* current_interface_method = GetInterfaceMethod(table_index, pointer_size);
    138       if (current_interface_method == nullptr) {
    139         break;
    140       }
    141       if (current_interface_method == interface_method) {
    142         return GetImplementationMethod(table_index, pointer_size);
    143       }
    144       ++table_index;
    145     }
    146     return nullptr;
    147   }
    148 
    149   // Compute the number of entries in this table.
    150   size_t NumEntries(PointerSize pointer_size) const {
    151     uint32_t table_index = 0;
    152     while (GetInterfaceMethod(table_index, pointer_size) != nullptr) {
    153       ++table_index;
    154     }
    155     return table_index;
    156   }
    157 
    158   // Compute the size in bytes taken by this table.
    159   size_t ComputeSize(PointerSize pointer_size) const {
    160     // Add the end marker.
    161     return ComputeSize(NumEntries(pointer_size), pointer_size);
    162   }
    163 
    164   // Compute the size in bytes needed for copying the given `table` and add
    165   // one more entry.
    166   static size_t ComputeSizeWithOneMoreEntry(ImtConflictTable* table, PointerSize pointer_size) {
    167     return table->ComputeSize(pointer_size) + EntrySize(pointer_size);
    168   }
    169 
    170   // Compute size with a fixed number of entries.
    171   static size_t ComputeSize(size_t num_entries, PointerSize pointer_size) {
    172     return (num_entries + 1) * EntrySize(pointer_size);  // Add one for null terminator.
    173   }
    174 
    175   static size_t EntrySize(PointerSize pointer_size) {
    176     return static_cast<size_t>(pointer_size) * static_cast<size_t>(kMethodCount);
    177   }
    178 
    179  private:
    180   void** AddressOfMethod(size_t index, PointerSize pointer_size) {
    181     if (pointer_size == PointerSize::k64) {
    182       return reinterpret_cast<void**>(&data64_[index]);
    183     } else {
    184       return reinterpret_cast<void**>(&data32_[index]);
    185     }
    186   }
    187 
    188   ArtMethod* GetMethod(size_t index, PointerSize pointer_size) const {
    189     if (pointer_size == PointerSize::k64) {
    190       return reinterpret_cast<ArtMethod*>(static_cast<uintptr_t>(data64_[index]));
    191     } else {
    192       return reinterpret_cast<ArtMethod*>(static_cast<uintptr_t>(data32_[index]));
    193     }
    194   }
    195 
    196   void SetMethod(size_t index, PointerSize pointer_size, ArtMethod* method) {
    197     if (pointer_size == PointerSize::k64) {
    198       data64_[index] = dchecked_integral_cast<uint64_t>(reinterpret_cast<uintptr_t>(method));
    199     } else {
    200       data32_[index] = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(method));
    201     }
    202   }
    203 
    204   // Array of entries that the assembly stubs will iterate over. Note that this is
    205   // not fixed size, and we allocate data prior to calling the constructor
    206   // of ImtConflictTable.
    207   union {
    208     uint32_t data32_[0];
    209     uint64_t data64_[0];
    210   };
    211 
    212   DISALLOW_COPY_AND_ASSIGN(ImtConflictTable);
    213 };
    214 
    215 }  // namespace art
    216 
    217 #endif  // ART_RUNTIME_IMT_CONFLICT_TABLE_H_
    218