# Dex file dependencies for each gtest.
ART_GTEST_class_linker_test_DEX_DEPS := Interfaces MultiDex MyClass Nested Statics StaticsFromCode
ART_GTEST_compiler_driver_test_DEX_DEPS := AbstractMethod StaticLeafMethods
+ART_GTEST_dex_cache_test_DEX_DEPS := Main
ART_GTEST_dex_file_test_DEX_DEPS := GetMethodSignature Main Nested
ART_GTEST_exception_test_DEX_DEPS := ExceptionHandle
ART_GTEST_instrumentation_test_DEX_DEPS := Instrumentation
nullptr, kVirtual);
} else {
StackHandleScope<1> hs(soa.Self());
- auto target_dex_cache(hs.NewHandle(class_linker->RegisterDexFile(*devirt_target->dex_file)));
+ auto target_dex_cache(hs.NewHandle(class_linker->RegisterDexFile(
+ *devirt_target->dex_file,
+ class_linker->GetOrCreateAllocatorForClassLoader(class_loader.Get()))));
called_method = class_linker->ResolveMethod(
*devirt_target->dex_file, devirt_target->dex_method_index, target_dex_cache,
class_loader, nullptr, kVirtual);
uint16_t exception_type_idx = exception_type.first;
const DexFile* dex_file = exception_type.second;
StackHandleScope<2> hs2(self);
- Handle<mirror::DexCache> dex_cache(hs2.NewHandle(class_linker->RegisterDexFile(*dex_file)));
+ Handle<mirror::DexCache> dex_cache(hs2.NewHandle(class_linker->RegisterDexFile(
+ *dex_file,
+ Runtime::Current()->GetLinearAlloc())));
Handle<mirror::Class> klass(hs2.NewHandle(
class_linker->ResolveType(*dex_file, exception_type_idx, dex_cache,
NullHandle<mirror::ClassLoader>())));
ClassLinker* class_linker = manager_->GetClassLinker();
const DexFile& dex_file = *manager_->GetDexFile();
StackHandleScope<2> hs(soa.Self());
- Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->RegisterDexFile(dex_file)));
Handle<mirror::ClassLoader> class_loader(
hs.NewHandle(soa.Decode<mirror::ClassLoader*>(manager_->GetClassLoader())));
+ Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->RegisterDexFile(
+ dex_file,
+ class_linker->GetOrCreateAllocatorForClassLoader(class_loader.Get()))));
mirror::Class* klass = class_linker->ResolveType(dex_file, type_idx, dex_cache, class_loader);
if (klass == nullptr) {
}
ScopedObjectAccess soa(self);
dex_caches_.push_back(soa.AddLocalReference<jobject>(
- class_linker->RegisterDexFile(*dex_file)));
+ class_linker->RegisterDexFile(*dex_file, Runtime::Current()->GetLinearAlloc())));
}
// If we use a swap file, ensure we are above the threshold to make it necessary.
uint32_t method_access_flags) {
if ((method_access_flags & kAccNative) == 0) {
ScopedObjectAccess soa(Thread::Current());
+ Runtime* const runtime = Runtime::Current();
Handle<mirror::DexCache> dex_cache(
- hs->NewHandle(Runtime::Current()->GetClassLinker()->RegisterDexFile(*dex_file)));
+ hs->NewHandle(runtime->GetClassLinker()->RegisterDexFile(*dex_file,
+ runtime->GetLinearAlloc())));
DCHECK(options_.class_loader_ != nullptr);
return verifier::MethodVerifier::VerifyMethodAndDump(
soa.Self(), vios, dex_method_idx, dex_file, dex_cache, *options_.class_loader_,
// Need to register dex files to get a working dex cache.
ScopedObjectAccess soa(self);
ClassLinker* class_linker = runtime->GetClassLinker();
- Runtime::Current()->GetOatFileManager().RegisterOatFile(
- std::unique_ptr<const OatFile>(oat_file));
+ runtime->GetOatFileManager().RegisterOatFile(std::unique_ptr<const OatFile>(oat_file));
std::vector<const DexFile*> class_path;
for (const OatFile::OatDexFile* odf : oat_file->GetOatDexFiles()) {
std::string error_msg;
const DexFile* const dex_file = OpenDexFile(odf, &error_msg);
CHECK(dex_file != nullptr) << error_msg;
- class_linker->RegisterDexFile(*dex_file);
+ class_linker->RegisterDexFile(*dex_file, runtime->GetLinearAlloc());
class_path.push_back(dex_file);
}
static_cast<mirror::Array*>(mirror::IntArray::Alloc(self, length)));
}
-mirror::DexCache* ClassLinker::AllocDexCache(Thread* self, const DexFile& dex_file) {
+mirror::DexCache* ClassLinker::AllocDexCache(Thread* self,
+ const DexFile& dex_file,
+ LinearAlloc* linear_alloc) {
StackHandleScope<6> hs(self);
auto dex_cache(hs.NewHandle(down_cast<mirror::DexCache*>(
GetClassRoot(kJavaLangDexCache)->AllocObject(self))));
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;
- }
- }
+ // 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*>(
+ (sizeof(void*) == 8u && image_pointer_size_ == 4u)
+ ? Runtime::Current()->GetLinearAlloc()->Alloc(self, layout.Size()) // Zero-initialized.
+ : linear_alloc->Alloc(self, layout.Size())); // Zero-initialized.
}
GcRoot<mirror::String>* strings = (dex_file.NumStringIds() == 0u) ? nullptr :
reinterpret_cast<GcRoot<mirror::String>*>(raw_arrays + layout.StringsOffset());
self->AssertPendingOOMException();
return nullptr;
}
- mirror::DexCache* dex_cache = RegisterDexFile(dex_file);
+ mirror::DexCache* dex_cache = RegisterDexFile(
+ dex_file,
+ GetOrCreateAllocatorForClassLoader(class_loader.Get()));
if (dex_cache == nullptr) {
self->AssertPendingOOMException();
return nullptr;
return allocator;
}
+LinearAlloc* ClassLinker::GetOrCreateAllocatorForClassLoader(mirror::ClassLoader* class_loader) {
+ if (class_loader == nullptr) {
+ return Runtime::Current()->GetLinearAlloc();
+ }
+ WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+ LinearAlloc* allocator = class_loader->GetAllocator();
+ if (allocator == nullptr) {
+ allocator = Runtime::Current()->CreateLinearAlloc();
+ class_loader->SetAllocator(allocator);
+ }
+ return allocator;
+}
+
void ClassLinker::LoadClassMembers(Thread* self,
const DexFile& dex_file,
const uint8_t* class_data,
void ClassLinker::AppendToBootClassPath(Thread* self, const DexFile& dex_file) {
StackHandleScope<1> hs(self);
- Handle<mirror::DexCache> dex_cache(hs.NewHandle(AllocDexCache(self, dex_file)));
+ Handle<mirror::DexCache> dex_cache(hs.NewHandle(AllocDexCache(
+ self,
+ dex_file,
+ Runtime::Current()->GetLinearAlloc())));
CHECK(dex_cache.Get() != nullptr) << "Failed to allocate dex cache for "
<< dex_file.GetLocation();
AppendToBootClassPath(dex_file, dex_cache);
dex_cache->SetDexFile(&dex_file);
}
-mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file) {
+mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file, LinearAlloc* linear_alloc) {
Thread* self = Thread::Current();
{
ReaderMutexLock mu(self, dex_lock_);
// suspend all threads and another thread may need the dex_lock_ to
// get to a suspend point.
StackHandleScope<1> hs(self);
- Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(AllocDexCache(self, dex_file)));
+ Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(AllocDexCache(self, dex_file, linear_alloc)));
WriterMutexLock mu(self, dex_lock_);
mirror::DexCache* dex_cache = FindDexCacheLocked(self, dex_file, true);
if (dex_cache != nullptr) {
std::string descriptor(GetDescriptorForProxy(klass.Get()));
const size_t hash = ComputeModifiedUtf8Hash(descriptor.c_str());
+ // Needs to be before we insert the class so that the allocator field is set.
+ LinearAlloc* const allocator = GetOrCreateAllocatorForClassLoader(klass->GetClassLoader());
+
// Insert the class before loading the fields as the field roots
// (ArtField::declaring_class_) are only visited from the class
// table. There can't be any suspend points between inserting the
mirror::Class* existing = InsertClass(descriptor.c_str(), klass.Get(), hash);
CHECK(existing == nullptr);
- // Needs to be after we insert the class so that the allocator field is set.
- LinearAlloc* const allocator = GetAllocatorForClassLoader(klass->GetClassLoader());
-
// Instance fields are inherited, but we add a couple of static fields...
const size_t num_fields = 2;
LengthPrefixedArray<ArtField>* sfields = AllocArtFieldArray(self, allocator, num_fields);
ClassLoaderData data;
data.weak_root = self->GetJniEnv()->vm->AddWeakGlobalRef(self, class_loader);
data.class_table = class_table;
- data.allocator = Runtime::Current()->CreateLinearAlloc();
- class_loaders_.push_back(data);
// Don't already have a class table, add it to the class loader.
CHECK(class_loader->GetClassTable() == nullptr);
- CHECK(class_loader->GetAllocator() == nullptr);
class_loader->SetClassTable(data.class_table);
- class_loader->SetAllocator(data.allocator);
+ // Should have been set when we registered the dex file.
+ data.allocator = class_loader->GetAllocator();
+ CHECK(data.allocator != nullptr);
+ class_loaders_.push_back(data);
}
return class_table;
}
SHARED_REQUIRES(Locks::mutator_lock_)
REQUIRES(!dex_lock_, !Roles::uninterruptible_);
- mirror::DexCache* RegisterDexFile(const DexFile& dex_file)
+ mirror::DexCache* RegisterDexFile(const DexFile& dex_file, LinearAlloc* linear_alloc)
REQUIRES(!dex_lock_)
SHARED_REQUIRES(Locks::mutator_lock_);
void RegisterDexFile(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache)
static LinearAlloc* GetAllocatorForClassLoader(mirror::ClassLoader* class_loader)
SHARED_REQUIRES(Locks::mutator_lock_);
+ // Return the linear alloc for a class loader if it is already allocated, otherwise allocate and
+ // set it. TODO: Consider using a lock other than classlinker_classes_lock_.
+ static LinearAlloc* GetOrCreateAllocatorForClassLoader(mirror::ClassLoader* class_loader)
+ SHARED_REQUIRES(Locks::mutator_lock_)
+ REQUIRES(!Locks::classlinker_classes_lock_);
+
private:
struct ClassLoaderData {
jweak weak_root; // Weak root to enable class unloading.
mirror::Class* AllocClass(Thread* self, uint32_t class_size)
SHARED_REQUIRES(Locks::mutator_lock_)
REQUIRES(!Roles::uninterruptible_);
- mirror::DexCache* AllocDexCache(Thread* self, const DexFile& dex_file)
+ mirror::DexCache* AllocDexCache(Thread* self,
+ const DexFile& dex_file,
+ LinearAlloc* linear_alloc)
SHARED_REQUIRES(Locks::mutator_lock_)
REQUIRES(!Roles::uninterruptible_);
#include "class_linker.h"
#include "common_runtime_test.h"
-#include "gc/heap.h"
-#include "mirror/object_array-inl.h"
-#include "mirror/object-inl.h"
+#include "linear_alloc.h"
+#include "mirror/class_loader-inl.h"
#include "handle_scope-inl.h"
#include "scoped_thread_state_change.h"
StackHandleScope<1> hs(soa.Self());
ASSERT_TRUE(java_lang_dex_file_ != nullptr);
Handle<DexCache> dex_cache(
- hs.NewHandle(class_linker_->AllocDexCache(soa.Self(), *java_lang_dex_file_)));
+ hs.NewHandle(class_linker_->AllocDexCache(soa.Self(),
+ *java_lang_dex_file_,
+ Runtime::Current()->GetLinearAlloc())));
ASSERT_TRUE(dex_cache.Get() != nullptr);
EXPECT_EQ(java_lang_dex_file_->NumStringIds(), dex_cache->NumStrings());
EXPECT_EQ(java_lang_dex_file_->NumFieldIds(), dex_cache->NumResolvedFields());
}
+TEST_F(DexCacheTest, LinearAlloc) {
+ ScopedObjectAccess soa(Thread::Current());
+ jobject jclass_loader(LoadDex("Main"));
+ ASSERT_TRUE(jclass_loader != nullptr);
+ Runtime* const runtime = Runtime::Current();
+ ClassLinker* const class_linker = runtime->GetClassLinker();
+ StackHandleScope<1> hs(soa.Self());
+ Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
+ soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+ mirror::Class* klass = class_linker->FindClass(soa.Self(), "LMain;", class_loader);
+ ASSERT_TRUE(klass != nullptr);
+ LinearAlloc* const linear_alloc = klass->GetClassLoader()->GetAllocator();
+ EXPECT_NE(linear_alloc, runtime->GetLinearAlloc());
+ EXPECT_TRUE(linear_alloc->Contains(klass->GetDexCache()->GetResolvedMethods()));
+}
+
} // namespace mirror
} // namespace art
if (dex_class_def != nullptr) {
ScopedObjectAccess soa(env);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- class_linker->RegisterDexFile(*dex_file);
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader)));
+ class_linker->RegisterDexFile(
+ *dex_file,
+ class_linker->GetOrCreateAllocatorForClassLoader(class_loader.Get()));
mirror::Class* result = class_linker->DefineClass(soa.Self(),
descriptor.c_str(),
hash,
const DexFile* dex_file = boot_class_path[i];
CHECK(dex_file != nullptr);
StackHandleScope<1> hs(soa.Self());
- Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->RegisterDexFile(*dex_file)));
+ Handle<mirror::DexCache> dex_cache(
+ hs.NewHandle(linker->RegisterDexFile(*dex_file, runtime->GetLinearAlloc())));
if (kPreloadDexCachesStrings) {
for (size_t j = 0; j < dex_cache->NumStrings(); j++) {