xref: /aosp_15_r20/art/runtime/imt_conflict_table.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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