blob: 02b3be48e8ec52a3ff86e84a8ef7621238f8794a [file] [log] [blame]
Andreas Gampe75a7db62016-09-26 12:04:26 -07001/*
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
26namespace art {
27
28class 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.
35class 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
Mathieu Chartier8c19d242017-03-06 12:35:10 -080084 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
Andreas Gampe75a7db62016-09-26 12:04:26 -070092 // 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:
Mathieu Chartier8c19d242017-03-06 12:35:10 -0800180 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
Andreas Gampe75a7db62016-09-26 12:04:26 -0700188 ArtMethod* GetMethod(size_t index, PointerSize pointer_size) const {
189 if (pointer_size == PointerSize::k64) {
Vladimir Marko78baed52018-10-11 10:44:58 +0100190 return reinterpret_cast64<ArtMethod*>(data64_[index]);
Andreas Gampe75a7db62016-09-26 12:04:26 -0700191 } else {
Vladimir Marko78baed52018-10-11 10:44:58 +0100192 return reinterpret_cast32<ArtMethod*>(data32_[index]);
Andreas Gampe75a7db62016-09-26 12:04:26 -0700193 }
194 }
195
196 void SetMethod(size_t index, PointerSize pointer_size, ArtMethod* method) {
197 if (pointer_size == PointerSize::k64) {
Vladimir Marko78baed52018-10-11 10:44:58 +0100198 data64_[index] = reinterpret_cast64<uint64_t>(method);
Andreas Gampe75a7db62016-09-26 12:04:26 -0700199 } else {
Vladimir Marko78baed52018-10-11 10:44:58 +0100200 data32_[index] = reinterpret_cast32<uint32_t>(method);
Andreas Gampe75a7db62016-09-26 12:04:26 -0700201 }
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_