ART: Move DexCache arrays to native.
This CL has a companion CL in libcore/
https://android-review.googlesource.com/162985
Change-Id: Icbc9e20ad1b565e603195b12714762bb446515fa
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index e78914c..fc1127c 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -80,6 +80,7 @@
#include "handle_scope-inl.h"
#include "thread-inl.h"
#include "utils.h"
+#include "utils/dex_cache_arrays_layout-inl.h"
#include "verifier/method_verifier.h"
#include "well_known_classes.h"
@@ -420,6 +421,7 @@
Handle<mirror::Class> java_lang_DexCache(hs.NewHandle(
AllocClass(self, java_lang_Class.Get(), mirror::DexCache::ClassSize(image_pointer_size_))));
SetClassRoot(kJavaLangDexCache, java_lang_DexCache.Get());
+ java_lang_DexCache->SetDexCacheClass();
java_lang_DexCache->SetObjectSize(mirror::DexCache::InstanceSize());
mirror::Class::SetStatus(java_lang_DexCache, mirror::Class::kStatusResolved, self);
@@ -1059,6 +1061,26 @@
}
}
+static void SanityCheckArtMethodPointerArray(
+ ArtMethod** arr,
+ size_t size,
+ size_t pointer_size,
+ gc::space::ImageSpace* space) SHARED_REQUIRES(Locks::mutator_lock_) {
+ CHECK_EQ(arr != nullptr, size != 0u);
+ if (arr != nullptr) {
+ auto offset = reinterpret_cast<uint8_t*>(arr) - space->Begin();
+ CHECK(space->GetImageHeader().GetImageSection(
+ ImageHeader::kSectionDexCacheArrays).Contains(offset));
+ }
+ for (size_t j = 0; j < size; ++j) {
+ ArtMethod* method = mirror::DexCache::GetElementPtrSize(arr, j, pointer_size);
+ // expected_class == null means we are a dex cache.
+ if (method != nullptr) {
+ SanityCheckArtMethod(method, nullptr, space);
+ }
+ }
+}
+
static void SanityCheckObjectsCallback(mirror::Object* obj, void* arg ATTRIBUTE_UNUSED)
SHARED_REQUIRES(Locks::mutator_lock_) {
DCHECK(obj != nullptr);
@@ -1188,8 +1210,10 @@
}
if (kSanityCheckObjects) {
- SanityCheckArtMethodPointerArray(dex_cache->GetResolvedMethods(), nullptr,
- image_pointer_size_, space);
+ SanityCheckArtMethodPointerArray(dex_cache->GetResolvedMethods(),
+ dex_cache->NumResolvedMethods(),
+ image_pointer_size_,
+ space);
}
CHECK_EQ(dex_file->GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum());
@@ -1476,28 +1500,44 @@
self->AssertPendingOOMException();
return nullptr;
}
- auto strings(hs.NewHandle(AllocStringArray(self, dex_file.NumStringIds())));
- if (strings.Get() == nullptr) {
- self->AssertPendingOOMException();
- return nullptr;
+ DexCacheArraysLayout layout(image_pointer_size_, &dex_file);
+ uint8_t* raw_arrays = nullptr;
+ if (dex_file.NumStringIds() != 0u || dex_file.NumTypeIds() != 0u ||
+ dex_file.NumMethodIds() != 0u || dex_file.NumFieldIds() != 0u) {
+ // NOTE: We "leak" the raw_arrays because we never destroy the dex cache.
+ DCHECK(image_pointer_size_ == 4u || image_pointer_size_ == 8u);
+ if (sizeof(void*) == 8u && image_pointer_size_ == 4u) {
+ // When cross-compiling for a 32-bit target on a 64-bit host, we need these arrays
+ // in the low 4GiB address space so that we can store pointers in 32-bit fields.
+ // This is conveniently provided by the linear allocator.
+ raw_arrays = reinterpret_cast<uint8_t*>(
+ Runtime::Current()->GetLinearAlloc()->Alloc(self, layout.Size())); // Zero-initialized.
+ } else {
+ raw_arrays = reinterpret_cast<uint8_t*>(calloc(layout.Size(), 1u)); // Zero-initialized.
+ if (raw_arrays == nullptr) {
+ return nullptr;
+ }
+ }
}
- auto types(hs.NewHandle(AllocClassArray(self, dex_file.NumTypeIds())));
- if (types.Get() == nullptr) {
- self->AssertPendingOOMException();
- return nullptr;
- }
- auto methods(hs.NewHandle(AllocPointerArray(self, dex_file.NumMethodIds())));
- if (methods.Get() == nullptr) {
- self->AssertPendingOOMException();
- return nullptr;
- }
- auto fields(hs.NewHandle(AllocPointerArray(self, dex_file.NumFieldIds())));
- if (fields.Get() == nullptr) {
- self->AssertPendingOOMException();
- return nullptr;
- }
- dex_cache->Init(&dex_file, location.Get(), strings.Get(), types.Get(), methods.Get(),
- fields.Get(), image_pointer_size_);
+ GcRoot<mirror::String>* strings = (dex_file.NumStringIds() == 0u) ? nullptr :
+ reinterpret_cast<GcRoot<mirror::String>*>(raw_arrays + layout.StringsOffset());
+ GcRoot<mirror::Class>* types = (dex_file.NumTypeIds() == 0u) ? nullptr :
+ reinterpret_cast<GcRoot<mirror::Class>*>(raw_arrays + layout.TypesOffset());
+ ArtMethod** methods = (dex_file.NumMethodIds() == 0u) ? nullptr :
+ reinterpret_cast<ArtMethod**>(raw_arrays + layout.MethodsOffset());
+ ArtField** fields = (dex_file.NumFieldIds() == 0u) ? nullptr :
+ reinterpret_cast<ArtField**>(raw_arrays + layout.FieldsOffset());
+ dex_cache->Init(&dex_file,
+ location.Get(),
+ strings,
+ dex_file.NumStringIds(),
+ types,
+ dex_file.NumTypeIds(),
+ methods,
+ dex_file.NumMethodIds(),
+ fields,
+ dex_file.NumFieldIds(),
+ image_pointer_size_);
return dex_cache.Get();
}
@@ -2418,8 +2458,8 @@
dst->SetDeclaringClass(klass.Get());
dst->SetCodeItemOffset(it.GetMethodCodeItemOffset());
- dst->SetDexCacheResolvedMethods(klass->GetDexCache()->GetResolvedMethods());
- dst->SetDexCacheResolvedTypes(klass->GetDexCache()->GetResolvedTypes());
+ dst->SetDexCacheResolvedMethods(klass->GetDexCache()->GetResolvedMethods(), image_pointer_size_);
+ dst->SetDexCacheResolvedTypes(klass->GetDexCache()->GetResolvedTypes(), image_pointer_size_);
uint32_t access_flags = it.GetMethodAccessFlags();
@@ -2895,9 +2935,9 @@
ClassTable* const class_table = InsertClassTableForClassLoader(nullptr);
for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
mirror::DexCache* dex_cache = dex_caches->Get(i);
- mirror::ObjectArray<mirror::Class>* types = dex_cache->GetResolvedTypes();
- for (int32_t j = 0; j < types->GetLength(); j++) {
- mirror::Class* klass = types->Get(j);
+ GcRoot<mirror::Class>* types = dex_cache->GetResolvedTypes();
+ for (int32_t j = 0, num_types = dex_cache->NumResolvedTypes(); j < num_types; j++) {
+ mirror::Class* klass = types[j].Read();
if (klass != nullptr) {
DCHECK(klass->GetClassLoader() == nullptr);
const char* descriptor = klass->GetDescriptor(&temp);
@@ -3418,7 +3458,8 @@
for (jobject weak_root : dex_caches_) {
mirror::DexCache* dex_cache = down_cast<mirror::DexCache*>(self->DecodeJObject(weak_root));
if (dex_cache != nullptr &&
- proxy_method->HasSameDexCacheResolvedTypes(dex_cache->GetResolvedTypes())) {
+ proxy_method->HasSameDexCacheResolvedTypes(dex_cache->GetResolvedTypes(),
+ image_pointer_size_)) {
ArtMethod* resolved_method = dex_cache->GetResolvedMethod(
proxy_method->GetDexMethodIndex(), image_pointer_size_);
CHECK(resolved_method != nullptr);
@@ -3491,8 +3532,8 @@
// The proxy method doesn't have its own dex cache or dex file and so it steals those of its
// interface prototype. The exception to this are Constructors and the Class of the Proxy itself.
- CHECK(prototype->HasSameDexCacheResolvedMethods(method));
- CHECK(prototype->HasSameDexCacheResolvedTypes(method));
+ CHECK(prototype->HasSameDexCacheResolvedMethods(method, image_pointer_size_));
+ CHECK(prototype->HasSameDexCacheResolvedTypes(method, image_pointer_size_));
auto* np = method->GetInterfaceMethodIfProxy(image_pointer_size_);
CHECK_EQ(prototype->GetDeclaringClass()->GetDexCache(), np->GetDexCache());
CHECK_EQ(prototype->GetDexMethodIndex(), method->GetDexMethodIndex());
@@ -3500,7 +3541,8 @@
CHECK_STREQ(np->GetName(), prototype->GetName());
CHECK_STREQ(np->GetShorty(), prototype->GetShorty());
// More complex sanity - via dex cache
- CHECK_EQ(np->GetReturnType(), prototype->GetReturnType());
+ CHECK_EQ(np->GetReturnType(true /* resolve */, image_pointer_size_),
+ prototype->GetReturnType(true /* resolve */, image_pointer_size_));
}
bool ClassLinker::CanWeInitializeClass(mirror::Class* klass, bool can_init_statics,
@@ -3838,6 +3880,7 @@
}
static bool HasSameSignatureWithDifferentClassLoaders(Thread* self,
+ size_t pointer_size,
Handle<mirror::Class> klass,
Handle<mirror::Class> super_klass,
ArtMethod* method1,
@@ -3845,12 +3888,14 @@
SHARED_REQUIRES(Locks::mutator_lock_) {
{
StackHandleScope<1> hs(self);
- Handle<mirror::Class> return_type(hs.NewHandle(method1->GetReturnType()));
+ Handle<mirror::Class> return_type(hs.NewHandle(method1->GetReturnType(true /* resolve */,
+ pointer_size)));
if (UNLIKELY(return_type.Get() == nullptr)) {
ThrowSignatureCheckResolveReturnTypeException(klass, super_klass, method1, method1);
return false;
}
- mirror::Class* other_return_type = method2->GetReturnType();
+ mirror::Class* other_return_type = method2->GetReturnType(true /* resolve */,
+ pointer_size);
if (UNLIKELY(other_return_type == nullptr)) {
ThrowSignatureCheckResolveReturnTypeException(klass, super_klass, method1, method2);
return false;
@@ -3895,7 +3940,7 @@
StackHandleScope<1> hs(self);
uint32_t param_type_idx = types1->GetTypeItem(i).type_idx_;
Handle<mirror::Class> param_type(hs.NewHandle(
- method1->GetClassFromTypeIndex(param_type_idx, true)));
+ method1->GetClassFromTypeIndex(param_type_idx, true /* resolve */, pointer_size)));
if (UNLIKELY(param_type.Get() == nullptr)) {
ThrowSignatureCheckResolveArgException(klass, super_klass, method1,
method1, i, param_type_idx);
@@ -3903,7 +3948,7 @@
}
uint32_t other_param_type_idx = types2->GetTypeItem(i).type_idx_;
mirror::Class* other_param_type =
- method2->GetClassFromTypeIndex(other_param_type_idx, true);
+ method2->GetClassFromTypeIndex(other_param_type_idx, true /* resolve */, pointer_size);
if (UNLIKELY(other_param_type == nullptr)) {
ThrowSignatureCheckResolveArgException(klass, super_klass, method1,
method2, i, other_param_type_idx);
@@ -3939,7 +3984,8 @@
auto* m = klass->GetVTableEntry(i, image_pointer_size_);
auto* super_m = klass->GetSuperClass()->GetVTableEntry(i, image_pointer_size_);
if (m != super_m) {
- if (UNLIKELY(!HasSameSignatureWithDifferentClassLoaders(self, klass, super_klass,
+ if (UNLIKELY(!HasSameSignatureWithDifferentClassLoaders(self, image_pointer_size_,
+ klass, super_klass,
m, super_m))) {
self->AssertPendingException();
return false;
@@ -3956,7 +4002,8 @@
j, image_pointer_size_);
auto* super_m = super_klass->GetVirtualMethod(j, image_pointer_size_);
if (m != super_m) {
- if (UNLIKELY(!HasSameSignatureWithDifferentClassLoaders(self, klass, super_klass,
+ if (UNLIKELY(!HasSameSignatureWithDifferentClassLoaders(self, image_pointer_size_,
+ klass, super_klass,
m, super_m))) {
self->AssertPendingException();
return false;
@@ -5091,8 +5138,8 @@
// Check that there are no stale methods are in the dex cache array.
if (kIsDebugBuild) {
auto* resolved_methods = klass->GetDexCache()->GetResolvedMethods();
- for (size_t i = 0, count = resolved_methods->GetLength(); i < count; ++i) {
- auto* m = resolved_methods->GetElementPtrSize<ArtMethod*>(i, image_pointer_size_);
+ for (size_t i = 0, count = klass->GetDexCache()->NumResolvedMethods(); i < count; ++i) {
+ auto* m = mirror::DexCache::GetElementPtrSize(resolved_methods, i, image_pointer_size_);
CHECK(move_table.find(m) == move_table.end()) << PrettyMethod(m);
}
}