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` } ImtConflictTable(ImtConflictTable * other,ArtMethod * interface_method,ArtMethod * implementation_method,PointerSize pointer_size)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. ImtConflictTable(size_t num_entries,PointerSize pointer_size)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. SetInterfaceMethod(size_t index,PointerSize pointer_size,ArtMethod * method)68 void SetInterfaceMethod(size_t index, PointerSize pointer_size, ArtMethod* method) { 69 SetMethod(index * kMethodCount + kMethodInterface, pointer_size, method); 70 } 71 SetImplementationMethod(size_t index,PointerSize pointer_size,ArtMethod * method)72 void SetImplementationMethod(size_t index, PointerSize pointer_size, ArtMethod* method) { 73 SetMethod(index * kMethodCount + kMethodImplementation, pointer_size, method); 74 } 75 GetInterfaceMethod(size_t index,PointerSize pointer_size)76 ArtMethod* GetInterfaceMethod(size_t index, PointerSize pointer_size) const { 77 return GetMethod(index * kMethodCount + kMethodInterface, pointer_size); 78 } 79 GetImplementationMethod(size_t index,PointerSize pointer_size)80 ArtMethod* GetImplementationMethod(size_t index, PointerSize pointer_size) const { 81 return GetMethod(index * kMethodCount + kMethodImplementation, pointer_size); 82 } 83 AddressOfInterfaceMethod(size_t index,PointerSize pointer_size)84 void** AddressOfInterfaceMethod(size_t index, PointerSize pointer_size) { 85 return AddressOfMethod(index * kMethodCount + kMethodInterface, pointer_size); 86 } 87 AddressOfImplementationMethod(size_t index,PointerSize pointer_size)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. Equals(ImtConflictTable * other,PointerSize pointer_size)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> Visit(const Visitor & visitor,PointerSize pointer_size)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. Lookup(ArtMethod * interface_method,PointerSize pointer_size)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. NumEntries(PointerSize pointer_size)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. ComputeSize(PointerSize pointer_size)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. ComputeSizeWithOneMoreEntry(ImtConflictTable * table,PointerSize pointer_size)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. ComputeSize(size_t num_entries,PointerSize pointer_size)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 EntrySize(PointerSize pointer_size)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: AddressOfMethod(size_t index,PointerSize pointer_size)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 GetMethod(size_t index,PointerSize pointer_size)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 SetMethod(size_t index,PointerSize pointer_size,ArtMethod * method)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