• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_cast64<ArtMethod*>(data64_[index]);
191      } else {
192        return reinterpret_cast32<ArtMethod*>(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] = reinterpret_cast64<uint64_t>(method);
199      } else {
200        data32_[index] = reinterpret_cast32<uint32_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