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