You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
218 lines
7.7 KiB
218 lines
7.7 KiB
/*
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef ART_RUNTIME_IMT_CONFLICT_TABLE_H_
|
|
#define ART_RUNTIME_IMT_CONFLICT_TABLE_H_
|
|
|
|
#include <cstddef>
|
|
|
|
#include "base/casts.h"
|
|
#include "base/enums.h"
|
|
#include "base/macros.h"
|
|
|
|
namespace art {
|
|
|
|
class ArtMethod;
|
|
|
|
// Table to resolve IMT conflicts at runtime. The table is attached to
|
|
// the jni entrypoint of IMT conflict ArtMethods.
|
|
// The table contains a list of pairs of { interface_method, implementation_method }
|
|
// with the last entry being null to make an assembly implementation of a lookup
|
|
// faster.
|
|
class ImtConflictTable {
|
|
enum MethodIndex {
|
|
kMethodInterface,
|
|
kMethodImplementation,
|
|
kMethodCount, // Number of elements in enum.
|
|
};
|
|
|
|
public:
|
|
// Build a new table copying `other` and adding the new entry formed of
|
|
// the pair { `interface_method`, `implementation_method` }
|
|
ImtConflictTable(ImtConflictTable* other,
|
|
ArtMethod* interface_method,
|
|
ArtMethod* implementation_method,
|
|
PointerSize pointer_size) {
|
|
const size_t count = other->NumEntries(pointer_size);
|
|
for (size_t i = 0; i < count; ++i) {
|
|
SetInterfaceMethod(i, pointer_size, other->GetInterfaceMethod(i, pointer_size));
|
|
SetImplementationMethod(i, pointer_size, other->GetImplementationMethod(i, pointer_size));
|
|
}
|
|
SetInterfaceMethod(count, pointer_size, interface_method);
|
|
SetImplementationMethod(count, pointer_size, implementation_method);
|
|
// Add the null marker.
|
|
SetInterfaceMethod(count + 1, pointer_size, nullptr);
|
|
SetImplementationMethod(count + 1, pointer_size, nullptr);
|
|
}
|
|
|
|
// num_entries excludes the header.
|
|
ImtConflictTable(size_t num_entries, PointerSize pointer_size) {
|
|
SetInterfaceMethod(num_entries, pointer_size, nullptr);
|
|
SetImplementationMethod(num_entries, pointer_size, nullptr);
|
|
}
|
|
|
|
// Set an entry at an index.
|
|
void SetInterfaceMethod(size_t index, PointerSize pointer_size, ArtMethod* method) {
|
|
SetMethod(index * kMethodCount + kMethodInterface, pointer_size, method);
|
|
}
|
|
|
|
void SetImplementationMethod(size_t index, PointerSize pointer_size, ArtMethod* method) {
|
|
SetMethod(index * kMethodCount + kMethodImplementation, pointer_size, method);
|
|
}
|
|
|
|
ArtMethod* GetInterfaceMethod(size_t index, PointerSize pointer_size) const {
|
|
return GetMethod(index * kMethodCount + kMethodInterface, pointer_size);
|
|
}
|
|
|
|
ArtMethod* GetImplementationMethod(size_t index, PointerSize pointer_size) const {
|
|
return GetMethod(index * kMethodCount + kMethodImplementation, pointer_size);
|
|
}
|
|
|
|
void** AddressOfInterfaceMethod(size_t index, PointerSize pointer_size) {
|
|
return AddressOfMethod(index * kMethodCount + kMethodInterface, pointer_size);
|
|
}
|
|
|
|
void** AddressOfImplementationMethod(size_t index, PointerSize pointer_size) {
|
|
return AddressOfMethod(index * kMethodCount + kMethodImplementation, pointer_size);
|
|
}
|
|
|
|
// Return true if two conflict tables are the same.
|
|
bool Equals(ImtConflictTable* other, PointerSize pointer_size) const {
|
|
size_t num = NumEntries(pointer_size);
|
|
if (num != other->NumEntries(pointer_size)) {
|
|
return false;
|
|
}
|
|
for (size_t i = 0; i < num; ++i) {
|
|
if (GetInterfaceMethod(i, pointer_size) != other->GetInterfaceMethod(i, pointer_size) ||
|
|
GetImplementationMethod(i, pointer_size) !=
|
|
other->GetImplementationMethod(i, pointer_size)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Visit all of the entries.
|
|
// NO_THREAD_SAFETY_ANALYSIS for calling with held locks. Visitor is passed a pair of ArtMethod*
|
|
// and also returns one. The order is <interface, implementation>.
|
|
template<typename Visitor>
|
|
void Visit(const Visitor& visitor, PointerSize pointer_size) NO_THREAD_SAFETY_ANALYSIS {
|
|
uint32_t table_index = 0;
|
|
for (;;) {
|
|
ArtMethod* interface_method = GetInterfaceMethod(table_index, pointer_size);
|
|
if (interface_method == nullptr) {
|
|
break;
|
|
}
|
|
ArtMethod* implementation_method = GetImplementationMethod(table_index, pointer_size);
|
|
auto input = std::make_pair(interface_method, implementation_method);
|
|
std::pair<ArtMethod*, ArtMethod*> updated = visitor(input);
|
|
if (input.first != updated.first) {
|
|
SetInterfaceMethod(table_index, pointer_size, updated.first);
|
|
}
|
|
if (input.second != updated.second) {
|
|
SetImplementationMethod(table_index, pointer_size, updated.second);
|
|
}
|
|
++table_index;
|
|
}
|
|
}
|
|
|
|
// Lookup the implementation ArtMethod associated to `interface_method`. Return null
|
|
// if not found.
|
|
ArtMethod* Lookup(ArtMethod* interface_method, PointerSize pointer_size) const {
|
|
uint32_t table_index = 0;
|
|
for (;;) {
|
|
ArtMethod* current_interface_method = GetInterfaceMethod(table_index, pointer_size);
|
|
if (current_interface_method == nullptr) {
|
|
break;
|
|
}
|
|
if (current_interface_method == interface_method) {
|
|
return GetImplementationMethod(table_index, pointer_size);
|
|
}
|
|
++table_index;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// Compute the number of entries in this table.
|
|
size_t NumEntries(PointerSize pointer_size) const {
|
|
uint32_t table_index = 0;
|
|
while (GetInterfaceMethod(table_index, pointer_size) != nullptr) {
|
|
++table_index;
|
|
}
|
|
return table_index;
|
|
}
|
|
|
|
// Compute the size in bytes taken by this table.
|
|
size_t ComputeSize(PointerSize pointer_size) const {
|
|
// Add the end marker.
|
|
return ComputeSize(NumEntries(pointer_size), pointer_size);
|
|
}
|
|
|
|
// Compute the size in bytes needed for copying the given `table` and add
|
|
// one more entry.
|
|
static size_t ComputeSizeWithOneMoreEntry(ImtConflictTable* table, PointerSize pointer_size) {
|
|
return table->ComputeSize(pointer_size) + EntrySize(pointer_size);
|
|
}
|
|
|
|
// Compute size with a fixed number of entries.
|
|
static size_t ComputeSize(size_t num_entries, PointerSize pointer_size) {
|
|
return (num_entries + 1) * EntrySize(pointer_size); // Add one for null terminator.
|
|
}
|
|
|
|
static size_t EntrySize(PointerSize pointer_size) {
|
|
return static_cast<size_t>(pointer_size) * static_cast<size_t>(kMethodCount);
|
|
}
|
|
|
|
private:
|
|
void** AddressOfMethod(size_t index, PointerSize pointer_size) {
|
|
if (pointer_size == PointerSize::k64) {
|
|
return reinterpret_cast<void**>(&data64_[index]);
|
|
} else {
|
|
return reinterpret_cast<void**>(&data32_[index]);
|
|
}
|
|
}
|
|
|
|
ArtMethod* GetMethod(size_t index, PointerSize pointer_size) const {
|
|
if (pointer_size == PointerSize::k64) {
|
|
return reinterpret_cast64<ArtMethod*>(data64_[index]);
|
|
} else {
|
|
return reinterpret_cast32<ArtMethod*>(data32_[index]);
|
|
}
|
|
}
|
|
|
|
void SetMethod(size_t index, PointerSize pointer_size, ArtMethod* method) {
|
|
if (pointer_size == PointerSize::k64) {
|
|
data64_[index] = reinterpret_cast64<uint64_t>(method);
|
|
} else {
|
|
data32_[index] = reinterpret_cast32<uint32_t>(method);
|
|
}
|
|
}
|
|
|
|
// Array of entries that the assembly stubs will iterate over. Note that this is
|
|
// not fixed size, and we allocate data prior to calling the constructor
|
|
// of ImtConflictTable.
|
|
union {
|
|
uint32_t data32_[0];
|
|
uint64_t data64_[0];
|
|
};
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(ImtConflictTable);
|
|
};
|
|
|
|
} // namespace art
|
|
|
|
#endif // ART_RUNTIME_IMT_CONFLICT_TABLE_H_
|