diff options
author | 2017-03-13 14:50:04 +0000 | |
---|---|---|
committer | 2017-03-13 16:08:01 +0000 | |
commit | 0b66d6174bf1f6023f9d36dda8538490b79c2e9f (patch) | |
tree | 1cc4d2ae868745a65fd0489a6fb2f5f2fc9e880f | |
parent | 6374c58f2ea403b3a05fb27376110fe4d0fc8e3f (diff) |
Revert^5 "Hash-based dex cache type array."
For app images, ImageWriter does not add boot image
classes to the app image class table even though it
keeps them in the dex caches. The reason for that is
unknown, the code looks OK.
Bug: 34839984
Bug: 30627598
Bug: 34659969
Also reverts "Improve debugging output for a crash."
This reverts commits
bfb80d25eaeb7a604d5dd25a370e3869e96a33ab,
8dd56fcb3196f466ecaffd445397cb11ef85f89f.
Test: testrunner.py --host
Change-Id: Ic8db128207c07588c7f11563208ae1e85c8b0e84
47 files changed, 389 insertions, 651 deletions
diff --git a/compiler/compiler.h b/compiler/compiler.h index 908d3669ed..2ca0b77a73 100644 --- a/compiler/compiler.h +++ b/compiler/compiler.h @@ -27,7 +27,6 @@ namespace jit { class JitCodeCache; } namespace mirror { - class ClassLoader; class DexCache; } @@ -64,7 +63,7 @@ class Compiler { InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, - Handle<mirror::ClassLoader> class_loader, + jobject class_loader, const DexFile& dex_file, Handle<mirror::DexCache> dex_cache) const = 0; diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index 76aeaa55d7..d4f6545c59 100644 --- a/compiler/dex/dex_to_dex_compiler.cc +++ b/compiler/dex/dex_to_dex_compiler.cc @@ -284,13 +284,16 @@ void DexCompiler::CompileInvokeVirtual(Instruction* inst, uint32_t dex_pc, } uint32_t method_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c(); ScopedObjectAccess soa(Thread::Current()); + StackHandleScope<1> hs(soa.Self()); + Handle<mirror::ClassLoader> class_loader(hs.NewHandle( + soa.Decode<mirror::ClassLoader>(unit_.GetClassLoader()))); ClassLinker* class_linker = unit_.GetClassLinker(); ArtMethod* resolved_method = class_linker->ResolveMethod<ClassLinker::kForceICCECheck>( GetDexFile(), method_idx, unit_.GetDexCache(), - unit_.GetClassLoader(), + class_loader, /* referrer */ nullptr, kVirtual); @@ -327,7 +330,7 @@ CompiledMethod* ArtCompileDEX( InvokeType invoke_type ATTRIBUTE_UNUSED, uint16_t class_def_idx, uint32_t method_idx, - Handle<mirror::ClassLoader> class_loader, + jobject class_loader, const DexFile& dex_file, DexToDexCompilationLevel dex_to_dex_compilation_level) { DCHECK(driver != nullptr); diff --git a/compiler/dex/dex_to_dex_compiler.h b/compiler/dex/dex_to_dex_compiler.h index 00c596d60e..0a00d45297 100644 --- a/compiler/dex/dex_to_dex_compiler.h +++ b/compiler/dex/dex_to_dex_compiler.h @@ -18,7 +18,6 @@ #define ART_COMPILER_DEX_DEX_TO_DEX_COMPILER_H_ #include "dex_file.h" -#include "handle.h" #include "invoke_type.h" namespace art { @@ -26,10 +25,6 @@ namespace art { class CompiledMethod; class CompilerDriver; -namespace mirror { -class ClassLoader; -} // namespace mirror - namespace optimizer { enum class DexToDexCompilationLevel { @@ -45,7 +40,7 @@ CompiledMethod* ArtCompileDEX(CompilerDriver* driver, InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, - Handle<mirror::ClassLoader> class_loader, + jobject class_loader, const DexFile& dex_file, DexToDexCompilationLevel dex_to_dex_compilation_level); diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h index 582330611d..f296851ebf 100644 --- a/compiler/driver/compiler_driver-inl.h +++ b/compiler/driver/compiler_driver-inl.h @@ -31,12 +31,17 @@ namespace art { +inline mirror::ClassLoader* CompilerDriver::GetClassLoader(const ScopedObjectAccess& soa, + const DexCompilationUnit* mUnit) { + return soa.Decode<mirror::ClassLoader>(mUnit->GetClassLoader()).Ptr(); +} + inline mirror::Class* CompilerDriver::ResolveClass( const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, dex::TypeIndex cls_index, const DexCompilationUnit* mUnit) { DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile()); - DCHECK_EQ(class_loader.Get(), mUnit->GetClassLoader().Get()); + DCHECK_EQ(class_loader.Get(), GetClassLoader(soa, mUnit)); mirror::Class* cls = mUnit->GetClassLinker()->ResolveType( *mUnit->GetDexFile(), cls_index, dex_cache, class_loader); DCHECK_EQ(cls == nullptr, soa.Self()->IsExceptionPending()); @@ -51,7 +56,7 @@ inline mirror::Class* CompilerDriver::ResolveCompilingMethodsClass( const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit) { DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile()); - DCHECK_EQ(class_loader.Get(), mUnit->GetClassLoader().Get()); + DCHECK_EQ(class_loader.Get(), GetClassLoader(soa, mUnit)); const DexFile::MethodId& referrer_method_id = mUnit->GetDexFile()->GetMethodId(mUnit->GetDexMethodIndex()); return ResolveClass(soa, dex_cache, class_loader, referrer_method_id.class_idx_, mUnit); @@ -82,7 +87,7 @@ inline ArtField* CompilerDriver::ResolveField( const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit, uint32_t field_idx, bool is_static) { - DCHECK_EQ(class_loader.Get(), mUnit->GetClassLoader().Get()); + DCHECK_EQ(class_loader.Get(), GetClassLoader(soa, mUnit)); return ResolveFieldWithDexFile(soa, dex_cache, class_loader, mUnit->GetDexFile(), field_idx, is_static); } @@ -134,7 +139,7 @@ inline ArtMethod* CompilerDriver::ResolveMethod( ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit, uint32_t method_idx, InvokeType invoke_type, bool check_incompatible_class_change) { - DCHECK_EQ(class_loader.Get(), mUnit->GetClassLoader().Get()); + DCHECK_EQ(class_loader.Get(), GetClassLoader(soa, mUnit)); ArtMethod* resolved_method = check_incompatible_class_change ? mUnit->GetClassLinker()->ResolveMethod<ClassLinker::kForceICCECheck>( diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 995098799c..caab5fb5a9 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -581,7 +581,7 @@ static void CompileMethod(Thread* self, InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, - Handle<mirror::ClassLoader> class_loader, + jobject class_loader, const DexFile& dex_file, optimizer::DexToDexCompilationLevel dex_to_dex_compilation_level, bool compilation_enabled, @@ -622,6 +622,9 @@ static void CompileMethod(Thread* self, // Look-up the ArtMethod associated with this code_item (if any) // -- It is later used to lookup any [optimization] annotations for this method. ScopedObjectAccess soa(self); + StackHandleScope<1> hs(soa.Self()); + Handle<mirror::ClassLoader> class_loader_handle(hs.NewHandle( + soa.Decode<mirror::ClassLoader>(class_loader))); // TODO: Lookup annotation from DexFile directly without resolving method. ArtMethod* method = @@ -629,7 +632,7 @@ static void CompileMethod(Thread* self, dex_file, method_idx, dex_cache, - class_loader, + class_loader_handle, /* referrer */ nullptr, invoke_type); @@ -676,14 +679,9 @@ static void CompileMethod(Thread* self, if (compile) { // NOTE: if compiler declines to compile this method, it will return null. - compiled_method = driver->GetCompiler()->Compile(code_item, - access_flags, - invoke_type, - class_def_idx, - method_idx, - class_loader, - dex_file, - dex_cache); + compiled_method = driver->GetCompiler()->Compile(code_item, access_flags, invoke_type, + class_def_idx, method_idx, class_loader, + dex_file, dex_cache); } if (compiled_method == nullptr && dex_to_dex_compilation_level != optimizer::DexToDexCompilationLevel::kDontDexToDexCompile) { @@ -730,14 +728,12 @@ void CompilerDriver::CompileOne(Thread* self, ArtMethod* method, TimingLogger* t uint32_t method_idx = method->GetDexMethodIndex(); uint32_t access_flags = method->GetAccessFlags(); InvokeType invoke_type = method->GetInvokeType(); - StackHandleScope<2> hs(self); + StackHandleScope<1> hs(self); Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache())); - Handle<mirror::ClassLoader> class_loader( - hs.NewHandle(method->GetDeclaringClass()->GetClassLoader())); { ScopedObjectAccessUnchecked soa(self); ScopedLocalRef<jobject> local_class_loader( - soa.Env(), soa.AddLocalReference<jobject>(class_loader.Get())); + soa.Env(), soa.AddLocalReference<jobject>(method->GetDeclaringClass()->GetClassLoader())); jclass_loader = soa.Env()->NewGlobalRef(local_class_loader.get()); // Find the dex_file dex_file = method->GetDexFile(); @@ -771,7 +767,7 @@ void CompilerDriver::CompileOne(Thread* self, ArtMethod* method, TimingLogger* t invoke_type, class_def_idx, method_idx, - class_loader, + jclass_loader, *dex_file, dex_to_dex_compilation_level, true, @@ -797,7 +793,7 @@ void CompilerDriver::CompileOne(Thread* self, ArtMethod* method, TimingLogger* t invoke_type, class_def_idx, method_idx, - class_loader, + jclass_loader, *dex_file, dex_to_dex_compilation_level, true, @@ -1077,30 +1073,22 @@ bool CompilerDriver::ShouldCompileBasedOnProfile(const MethodReference& method_r class ResolveCatchBlockExceptionsClassVisitor : public ClassVisitor { public: - ResolveCatchBlockExceptionsClassVisitor() : classes_() {} + explicit ResolveCatchBlockExceptionsClassVisitor( + std::set<std::pair<dex::TypeIndex, const DexFile*>>& exceptions_to_resolve) + : exceptions_to_resolve_(exceptions_to_resolve) {} virtual bool operator()(ObjPtr<mirror::Class> c) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { - classes_.push_back(c); - return true; - } - - void FindExceptionTypesToResolve( - std::set<std::pair<dex::TypeIndex, const DexFile*>>* exceptions_to_resolve) - REQUIRES_SHARED(Locks::mutator_lock_) { const auto pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); - for (ObjPtr<mirror::Class> klass : classes_) { - for (ArtMethod& method : klass->GetMethods(pointer_size)) { - FindExceptionTypesToResolveForMethod(&method, exceptions_to_resolve); - } + for (auto& m : c->GetMethods(pointer_size)) { + ResolveExceptionsForMethod(&m); } + return true; } private: - void FindExceptionTypesToResolveForMethod( - ArtMethod* method, - std::set<std::pair<dex::TypeIndex, const DexFile*>>* exceptions_to_resolve) + void ResolveExceptionsForMethod(ArtMethod* method_handle) REQUIRES_SHARED(Locks::mutator_lock_) { - const DexFile::CodeItem* code_item = method->GetCodeItem(); + const DexFile::CodeItem* code_item = method_handle->GetCodeItem(); if (code_item == nullptr) { return; // native or abstract method } @@ -1120,9 +1108,9 @@ class ResolveCatchBlockExceptionsClassVisitor : public ClassVisitor { dex::TypeIndex encoded_catch_handler_handlers_type_idx = dex::TypeIndex(DecodeUnsignedLeb128(&encoded_catch_handler_list)); // Add to set of types to resolve if not already in the dex cache resolved types - if (!method->IsResolvedTypeIdx(encoded_catch_handler_handlers_type_idx)) { - exceptions_to_resolve->emplace(encoded_catch_handler_handlers_type_idx, - method->GetDexFile()); + if (!method_handle->IsResolvedTypeIdx(encoded_catch_handler_handlers_type_idx)) { + exceptions_to_resolve_.emplace(encoded_catch_handler_handlers_type_idx, + method_handle->GetDexFile()); } // ignore address associated with catch handler DecodeUnsignedLeb128(&encoded_catch_handler_list); @@ -1134,7 +1122,7 @@ class ResolveCatchBlockExceptionsClassVisitor : public ClassVisitor { } } - std::vector<ObjPtr<mirror::Class>> classes_; + std::set<std::pair<dex::TypeIndex, const DexFile*>>& exceptions_to_resolve_; }; class RecordImageClassesVisitor : public ClassVisitor { @@ -1188,14 +1176,8 @@ void CompilerDriver::LoadImageClasses(TimingLogger* timings) { hs.NewHandle(class_linker->FindSystemClass(self, "Ljava/lang/Throwable;"))); do { unresolved_exception_types.clear(); - { - // Thread suspension is not allowed while ResolveCatchBlockExceptionsClassVisitor - // is using a std::vector<ObjPtr<mirror::Class>>. - ScopedAssertNoThreadSuspension ants(__FUNCTION__); - ResolveCatchBlockExceptionsClassVisitor visitor; - class_linker->VisitClasses(&visitor); - visitor.FindExceptionTypesToResolve(&unresolved_exception_types); - } + ResolveCatchBlockExceptionsClassVisitor visitor(unresolved_exception_types); + class_linker->VisitClasses(&visitor); for (const auto& exception_type : unresolved_exception_types) { dex::TypeIndex exception_type_idx = exception_type.first; const DexFile* dex_file = exception_type.second; @@ -1446,14 +1428,19 @@ void CompilerDriver::MarkForDexToDexCompilation(Thread* self, const MethodRefere dex_to_dex_references_.back().GetMethodIndexes().SetBit(method_ref.dex_method_index); } -bool CompilerDriver::CanAccessTypeWithoutChecks(ObjPtr<mirror::Class> referrer_class, - ObjPtr<mirror::Class> resolved_class) { +bool CompilerDriver::CanAccessTypeWithoutChecks(uint32_t referrer_idx, + Handle<mirror::DexCache> dex_cache, + dex::TypeIndex type_idx) { + // Get type from dex cache assuming it was populated by the verifier + mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx); if (resolved_class == nullptr) { stats_->TypeNeedsAccessCheck(); return false; // Unknown class needs access checks. } + const DexFile::MethodId& method_id = dex_cache->GetDexFile()->GetMethodId(referrer_idx); bool is_accessible = resolved_class->IsPublic(); // Public classes are always accessible. if (!is_accessible) { + mirror::Class* referrer_class = dex_cache->GetResolvedType(method_id.class_idx_); if (referrer_class == nullptr) { stats_->TypeNeedsAccessCheck(); return false; // Incomplete referrer knowledge needs access check. @@ -1470,9 +1457,12 @@ bool CompilerDriver::CanAccessTypeWithoutChecks(ObjPtr<mirror::Class> referrer_c return is_accessible; } -bool CompilerDriver::CanAccessInstantiableTypeWithoutChecks(ObjPtr<mirror::Class> referrer_class, - ObjPtr<mirror::Class> resolved_class, +bool CompilerDriver::CanAccessInstantiableTypeWithoutChecks(uint32_t referrer_idx, + Handle<mirror::DexCache> dex_cache, + dex::TypeIndex type_idx, bool* finalizable) { + // Get type from dex cache assuming it was populated by the verifier. + mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx); if (resolved_class == nullptr) { stats_->TypeNeedsAccessCheck(); // Be conservative. @@ -1480,8 +1470,10 @@ bool CompilerDriver::CanAccessInstantiableTypeWithoutChecks(ObjPtr<mirror::Class return false; // Unknown class needs access checks. } *finalizable = resolved_class->IsFinalizable(); + const DexFile::MethodId& method_id = dex_cache->GetDexFile()->GetMethodId(referrer_idx); bool is_accessible = resolved_class->IsPublic(); // Public classes are always accessible. if (!is_accessible) { + mirror::Class* referrer_class = dex_cache->GetResolvedType(method_id.class_idx_); if (referrer_class == nullptr) { stats_->TypeNeedsAccessCheck(); return false; // Incomplete referrer knowledge needs access check. @@ -1525,7 +1517,9 @@ ArtField* CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, mirror::Class* referrer_class; Handle<mirror::DexCache> dex_cache(mUnit->GetDexCache()); { - Handle<mirror::ClassLoader> class_loader_handle = mUnit->GetClassLoader(); + StackHandleScope<1> hs(soa.Self()); + Handle<mirror::ClassLoader> class_loader_handle( + hs.NewHandle(soa.Decode<mirror::ClassLoader>(mUnit->GetClassLoader()))); resolved_field = ResolveField(soa, dex_cache, class_loader_handle, mUnit, field_idx, false); referrer_class = resolved_field != nullptr ? ResolveCompilingMethodsClass(soa, dex_cache, class_loader_handle, mUnit) : nullptr; @@ -2672,18 +2666,10 @@ class CompileClassVisitor : public CompilationVisitor { continue; } previous_direct_method_idx = method_idx; - CompileMethod(soa.Self(), - driver, - it.GetMethodCodeItem(), - it.GetMethodAccessFlags(), - it.GetMethodInvokeType(class_def), - class_def_index, - method_idx, - class_loader, - dex_file, - dex_to_dex_compilation_level, - compilation_enabled, - dex_cache); + CompileMethod(soa.Self(), driver, it.GetMethodCodeItem(), it.GetMethodAccessFlags(), + it.GetMethodInvokeType(class_def), class_def_index, + method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level, + compilation_enabled, dex_cache); it.Next(); } // Compile virtual methods @@ -2697,17 +2683,10 @@ class CompileClassVisitor : public CompilationVisitor { continue; } previous_virtual_method_idx = method_idx; - CompileMethod(soa.Self(), - driver, it.GetMethodCodeItem(), - it.GetMethodAccessFlags(), - it.GetMethodInvokeType(class_def), - class_def_index, - method_idx, - class_loader, - dex_file, - dex_to_dex_compilation_level, - compilation_enabled, - dex_cache); + CompileMethod(soa.Self(), driver, it.GetMethodCodeItem(), it.GetMethodAccessFlags(), + it.GetMethodInvokeType(class_def), class_def_index, + method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level, + compilation_enabled, dex_cache); it.Next(); } DCHECK(!it.HasNext()); diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index cbde587241..6ba16923a9 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -187,14 +187,16 @@ class CompilerDriver { REQUIRES(!requires_constructor_barrier_lock_); // Are runtime access checks necessary in the compiled code? - bool CanAccessTypeWithoutChecks(ObjPtr<mirror::Class> referrer_class, - ObjPtr<mirror::Class> resolved_class) + bool CanAccessTypeWithoutChecks(uint32_t referrer_idx, + Handle<mirror::DexCache> dex_cache, + dex::TypeIndex type_idx) REQUIRES_SHARED(Locks::mutator_lock_); // Are runtime access and instantiable checks necessary in the code? // out_is_finalizable is set to whether the type is finalizable. - bool CanAccessInstantiableTypeWithoutChecks(ObjPtr<mirror::Class> referrer_class, - ObjPtr<mirror::Class> resolved_class, + bool CanAccessInstantiableTypeWithoutChecks(uint32_t referrer_idx, + Handle<mirror::DexCache> dex_cache, + dex::TypeIndex type_idx, bool* out_is_finalizable) REQUIRES_SHARED(Locks::mutator_lock_); @@ -372,6 +374,10 @@ class CompilerDriver { uint32_t field_idx) REQUIRES_SHARED(Locks::mutator_lock_); + mirror::ClassLoader* GetClassLoader(const ScopedObjectAccess& soa, + const DexCompilationUnit* mUnit) + REQUIRES_SHARED(Locks::mutator_lock_); + private: void PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files, diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc index 562f97b3ae..316117f94b 100644 --- a/compiler/driver/compiler_driver_test.cc +++ b/compiler/driver/compiler_driver_test.cc @@ -101,7 +101,6 @@ class CompilerDriverTest : public CommonCompilerTest { }; // Disabled due to 10 second runtime on host -// TODO: Update the test for hash-based dex cache arrays. Bug: 30627598 TEST_F(CompilerDriverTest, DISABLED_LARGE_CompileDexLibCore) { CompileAll(nullptr); diff --git a/compiler/driver/dex_compilation_unit.cc b/compiler/driver/dex_compilation_unit.cc index 7e8e812c4a..47b19297e5 100644 --- a/compiler/driver/dex_compilation_unit.cc +++ b/compiler/driver/dex_compilation_unit.cc @@ -21,7 +21,7 @@ namespace art { -DexCompilationUnit::DexCompilationUnit(Handle<mirror::ClassLoader> class_loader, +DexCompilationUnit::DexCompilationUnit(jobject class_loader, ClassLinker* class_linker, const DexFile& dex_file, const DexFile::CodeItem* code_item, diff --git a/compiler/driver/dex_compilation_unit.h b/compiler/driver/dex_compilation_unit.h index 24a9a5b653..854927d747 100644 --- a/compiler/driver/dex_compilation_unit.h +++ b/compiler/driver/dex_compilation_unit.h @@ -34,7 +34,7 @@ class VerifiedMethod; class DexCompilationUnit : public DeletableArenaObject<kArenaAllocMisc> { public: - DexCompilationUnit(Handle<mirror::ClassLoader> class_loader, + DexCompilationUnit(jobject class_loader, ClassLinker* class_linker, const DexFile& dex_file, const DexFile::CodeItem* code_item, @@ -44,7 +44,7 @@ class DexCompilationUnit : public DeletableArenaObject<kArenaAllocMisc> { const VerifiedMethod* verified_method, Handle<mirror::DexCache> dex_cache); - Handle<mirror::ClassLoader> GetClassLoader() const { + jobject GetClassLoader() const { return class_loader_; } @@ -113,7 +113,7 @@ class DexCompilationUnit : public DeletableArenaObject<kArenaAllocMisc> { } private: - const Handle<mirror::ClassLoader> class_loader_; + const jobject class_loader_; ClassLinker* const class_linker_; @@ -125,7 +125,7 @@ class DexCompilationUnit : public DeletableArenaObject<kArenaAllocMisc> { const uint32_t access_flags_; const VerifiedMethod* verified_method_; - const Handle<mirror::DexCache> dex_cache_; + Handle<mirror::DexCache> dex_cache_; std::string symbol_; }; diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 65d82ed980..9312a1cc40 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -941,11 +941,9 @@ void ImageWriter::PruneNonImageClasses() { } ObjPtr<mirror::DexCache> dex_cache = self->DecodeJObject(data.weak_root)->AsDexCache(); for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) { - mirror::TypeDexCachePair pair = - dex_cache->GetResolvedTypes()[i].load(std::memory_order_relaxed); - mirror::Class* klass = pair.object.Read(); + Class* klass = dex_cache->GetResolvedType(dex::TypeIndex(i)); if (klass != nullptr && !KeepClass(klass)) { - dex_cache->ClearResolvedType(dex::TypeIndex(pair.index)); + dex_cache->SetResolvedType(dex::TypeIndex(i), nullptr); } } ArtMethod** resolved_methods = dex_cache->GetResolvedMethods(); @@ -1925,7 +1923,8 @@ void ImageWriter::CopyAndFixupNativeData(size_t oat_index) { // above comment for intern tables. ClassTable temp_class_table; temp_class_table.ReadFromMemory(class_table_memory_ptr); - ObjPtr<mirror::ClassLoader> class_loader = GetClassLoader(); + CHECK_EQ(class_loaders_.size(), compile_app_image_ ? 1u : 0u); + mirror::ClassLoader* class_loader = compile_app_image_ ? *class_loaders_.begin() : nullptr; CHECK_EQ(temp_class_table.NumZygoteClasses(class_loader), table->NumNonZygoteClasses(class_loader) + table->NumZygoteClasses(class_loader)); UnbufferedRootVisitor visitor(&root_visitor, RootInfo(kRootUnknown)); @@ -2215,7 +2214,7 @@ void ImageWriter::FixupDexCache(mirror::DexCache* orig_dex_cache, orig_dex_cache->FixupStrings(NativeCopyLocation(orig_strings, orig_dex_cache), ImageAddressVisitor(this)); } - mirror::TypeDexCacheType* orig_types = orig_dex_cache->GetResolvedTypes(); + GcRoot<mirror::Class>* orig_types = orig_dex_cache->GetResolvedTypes(); if (orig_types != nullptr) { copy_dex_cache->SetFieldPtrWithSize<false>(mirror::DexCache::ResolvedTypesOffset(), NativeLocationInImage(orig_types), diff --git a/compiler/image_writer.h b/compiler/image_writer.h index bdc7146632..cc7df1ce21 100644 --- a/compiler/image_writer.h +++ b/compiler/image_writer.h @@ -51,13 +51,8 @@ class ImageSpace; } // namespace space } // namespace gc -namespace mirror { -class ClassLoader; -} // namespace mirror - class ClassLoaderVisitor; class ClassTable; -class ImtConflictTable; static constexpr int kInvalidFd = -1; @@ -84,11 +79,6 @@ class ImageWriter FINAL { return true; } - ObjPtr<mirror::ClassLoader> GetClassLoader() { - CHECK_EQ(class_loaders_.size(), compile_app_image_ ? 1u : 0u); - return compile_app_image_ ? *class_loaders_.begin() : nullptr; - } - template <typename T> T* GetImageAddress(T* object) const REQUIRES_SHARED(Locks::mutator_lock_) { if (object == nullptr || IsInBootImage(object)) { diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index afcdf5ea17..a3f61d62c5 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -1061,7 +1061,6 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { WriteCodeMethodVisitor(OatWriter* writer, OutputStream* out, const size_t file_offset, size_t relative_offset) SHARED_LOCK_FUNCTION(Locks::mutator_lock_) : OatDexMethodVisitor(writer, relative_offset), - class_loader_(writer->HasImage() ? writer->image_writer_->GetClassLoader() : nullptr), out_(out), file_offset_(file_offset), soa_(Thread::Current()), @@ -1247,7 +1246,6 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { } private: - ObjPtr<mirror::ClassLoader> class_loader_; OutputStream* const out_; const size_t file_offset_; const ScopedObjectAccess soa_; @@ -1306,12 +1304,10 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { } mirror::Class* GetTargetType(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK(writer_->HasImage()); ObjPtr<mirror::DexCache> dex_cache = GetDexCache(patch.TargetTypeDexFile()); - ObjPtr<mirror::Class> type = - ClassLinker::LookupResolvedType(patch.TargetTypeIndex(), dex_cache, class_loader_); + mirror::Class* type = dex_cache->GetResolvedType(patch.TargetTypeIndex()); CHECK(type != nullptr); - return type.Ptr(); + return type; } mirror::String* GetTargetString(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) { diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h index 3a4c9dbd16..e4ad4222fb 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -54,10 +54,7 @@ class HGraphBuilder : public ValueObject { compiler_driver_(driver), compilation_stats_(compiler_stats), block_builder_(graph, dex_file, code_item), - ssa_builder_(graph, - dex_compilation_unit->GetClassLoader(), - dex_compilation_unit->GetDexCache(), - handles), + ssa_builder_(graph, dex_compilation_unit->GetDexCache(), handles), instruction_builder_(graph, &block_builder_, &ssa_builder_, @@ -83,12 +80,10 @@ class HGraphBuilder : public ValueObject { code_item_(code_item), dex_compilation_unit_(nullptr), compiler_driver_(nullptr), + null_dex_cache_(), compilation_stats_(nullptr), block_builder_(graph, nullptr, code_item), - ssa_builder_(graph, - handles->NewHandle<mirror::ClassLoader>(nullptr), - handles->NewHandle<mirror::DexCache>(nullptr), - handles), + ssa_builder_(graph, null_dex_cache_, handles), instruction_builder_(graph, &block_builder_, &ssa_builder_, @@ -101,7 +96,7 @@ class HGraphBuilder : public ValueObject { /* code_generator */ nullptr, /* interpreter_metadata */ nullptr, /* compiler_stats */ nullptr, - handles->NewHandle<mirror::DexCache>(nullptr), + null_dex_cache_, handles) {} GraphAnalysisResult BuildGraph(); @@ -122,6 +117,8 @@ class HGraphBuilder : public ValueObject { CompilerDriver* const compiler_driver_; + ScopedNullHandle<mirror::DexCache> null_dex_cache_; + OptimizingCompilerStats* compilation_stats_; HBasicBlockBuilder block_builder_; diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 664b95aeb1..2e45149b43 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -192,9 +192,9 @@ static uint32_t FindMethodIndexIn(ArtMethod* method, } static dex::TypeIndex FindClassIndexIn(mirror::Class* cls, - const DexCompilationUnit& compilation_unit) + const DexFile& dex_file, + Handle<mirror::DexCache> dex_cache) REQUIRES_SHARED(Locks::mutator_lock_) { - const DexFile& dex_file = *compilation_unit.GetDexFile(); dex::TypeIndex index; if (cls->GetDexCache() == nullptr) { DCHECK(cls->IsArrayClass()) << cls->PrettyClass(); @@ -203,19 +203,22 @@ static dex::TypeIndex FindClassIndexIn(mirror::Class* cls, DCHECK(cls->IsProxyClass()) << cls->PrettyClass(); // TODO: deal with proxy classes. } else if (IsSameDexFile(cls->GetDexFile(), dex_file)) { - DCHECK_EQ(cls->GetDexCache(), compilation_unit.GetDexCache().Get()); + DCHECK_EQ(cls->GetDexCache(), dex_cache.Get()); index = cls->GetDexTypeIndex(); + // Update the dex cache to ensure the class is in. The generated code will + // consider it is. We make it safe by updating the dex cache, as other + // dex files might also load the class, and there is no guarantee the dex + // cache of the dex file of the class will be updated. + if (dex_cache->GetResolvedType(index) == nullptr) { + dex_cache->SetResolvedType(index, cls); + } } else { index = cls->FindTypeIndexInOtherDexFile(dex_file); - // We cannot guarantee the entry will resolve to the same class, + // We cannot guarantee the entry in the dex cache will resolve to the same class, // as there may be different class loaders. So only return the index if it's - // the right class already resolved with the class loader. - if (index.IsValid()) { - ObjPtr<mirror::Class> resolved = ClassLinker::LookupResolvedType( - index, compilation_unit.GetDexCache().Get(), compilation_unit.GetClassLoader().Get()); - if (resolved != cls) { - index = dex::TypeIndex::Invalid(); - } + // the right class in the dex cache already. + if (index.IsValid() && dex_cache->GetResolvedType(index) != cls) { + index = dex::TypeIndex::Invalid(); } } @@ -533,10 +536,7 @@ HInliner::InlineCacheType HInliner::ExtractClassesFromOfflineProfile( ObjPtr<mirror::DexCache> dex_cache = dex_profile_index_to_dex_cache[class_ref.dex_profile_index]; DCHECK(dex_cache != nullptr); - ObjPtr<mirror::Class> clazz = ClassLinker::LookupResolvedType( - class_ref.type_index, - dex_cache, - caller_compilation_unit_.GetClassLoader().Get()); + ObjPtr<mirror::Class> clazz = dex_cache->GetResolvedType(class_ref.type_index); if (clazz != nullptr) { inline_cache->Set(ic_index++, clazz); } else { @@ -577,8 +577,9 @@ bool HInliner::TryInlineMonomorphicCall(HInvoke* invoke_instruction, DCHECK(invoke_instruction->IsInvokeVirtual() || invoke_instruction->IsInvokeInterface()) << invoke_instruction->DebugName(); + const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile(); dex::TypeIndex class_index = FindClassIndexIn( - GetMonomorphicType(classes), caller_compilation_unit_); + GetMonomorphicType(classes), caller_dex_file, caller_compilation_unit_.GetDexCache()); if (!class_index.IsValid()) { VLOG(compiler) << "Call to " << ArtMethod::PrettyMethod(resolved_method) << " from inline cache is not inlined because its class is not" @@ -621,7 +622,6 @@ bool HInliner::TryInlineMonomorphicCall(HInvoke* invoke_instruction, // Run type propagation to get the guard typed, and eventually propagate the // type of the receiver. ReferenceTypePropagation rtp_fixup(graph_, - outer_compilation_unit_.GetClassLoader(), outer_compilation_unit_.GetDexCache(), handles_, /* is_first_run */ false); @@ -722,6 +722,7 @@ bool HInliner::TryInlinePolymorphicCall(HInvoke* invoke_instruction, ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker(); PointerSize pointer_size = class_linker->GetImagePointerSize(); + const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile(); bool all_targets_inlined = true; bool one_target_inlined = false; @@ -743,7 +744,8 @@ bool HInliner::TryInlinePolymorphicCall(HInvoke* invoke_instruction, HInstruction* cursor = invoke_instruction->GetPrevious(); HBasicBlock* bb_cursor = invoke_instruction->GetBlock(); - dex::TypeIndex class_index = FindClassIndexIn(handle.Get(), caller_compilation_unit_); + dex::TypeIndex class_index = FindClassIndexIn( + handle.Get(), caller_dex_file, caller_compilation_unit_.GetDexCache()); HInstruction* return_replacement = nullptr; if (!class_index.IsValid() || !TryBuildAndInline(invoke_instruction, @@ -799,7 +801,6 @@ bool HInliner::TryInlinePolymorphicCall(HInvoke* invoke_instruction, // Run type propagation to get the guards typed. ReferenceTypePropagation rtp_fixup(graph_, - outer_compilation_unit_.GetClassLoader(), outer_compilation_unit_.GetDexCache(), handles_, /* is_first_run */ false); @@ -996,7 +997,6 @@ bool HInliner::TryInlinePolymorphicCallToSameTarget( // Run type propagation to get the guard typed. ReferenceTypePropagation rtp_fixup(graph_, - outer_compilation_unit_.GetClassLoader(), outer_compilation_unit_.GetDexCache(), handles_, /* is_first_run */ false); @@ -1065,7 +1065,6 @@ bool HInliner::TryInlineAndReplace(HInvoke* invoke_instruction, // Actual return value has a more specific type than the method's declared // return type. Run RTP again on the outer graph to propagate it. ReferenceTypePropagation(graph_, - outer_compilation_unit_.GetClassLoader(), outer_compilation_unit_.GetDexCache(), handles_, /* is_first_run */ false).Run(); @@ -1318,11 +1317,7 @@ HInstanceFieldGet* HInliner::CreateInstanceFieldGet(Handle<mirror::DexCache> dex /* dex_pc */ 0); if (iget->GetType() == Primitive::kPrimNot) { // Use the same dex_cache that we used for field lookup as the hint_dex_cache. - ReferenceTypePropagation rtp(graph_, - outer_compilation_unit_.GetClassLoader(), - dex_cache, - handles_, - /* is_first_run */ false); + ReferenceTypePropagation rtp(graph_, dex_cache, handles_, /* is_first_run */ false); rtp.Visit(iget); } return iget; @@ -1368,7 +1363,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, resolved_method->GetDeclaringClass()->GetClassLoader())); DexCompilationUnit dex_compilation_unit( - class_loader, + class_loader.ToJObject(), class_linker, callee_dex_file, code_item, @@ -1492,7 +1487,6 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, // are more specific than the declared ones, run RTP again on the inner graph. if (run_rtp || ArgumentTypesMoreSpecific(invoke_instruction, resolved_method)) { ReferenceTypePropagation(callee_graph, - outer_compilation_unit_.GetClassLoader(), dex_compilation_unit.GetDexCache(), handles_, /* is_first_run */ false).Run(); diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index 88f67fae04..1053da44d6 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -677,10 +677,11 @@ static InvokeType GetInvokeTypeFromOpCode(Instruction::Code opcode) { ArtMethod* HInstructionBuilder::ResolveMethod(uint16_t method_idx, InvokeType invoke_type) { ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<2> hs(soa.Self()); + StackHandleScope<3> hs(soa.Self()); ClassLinker* class_linker = dex_compilation_unit_->GetClassLinker(); - Handle<mirror::ClassLoader> class_loader = dex_compilation_unit_->GetClassLoader(); + Handle<mirror::ClassLoader> class_loader(hs.NewHandle( + soa.Decode<mirror::ClassLoader>(dex_compilation_unit_->GetClassLoader()))); Handle<mirror::Class> compiling_class(hs.NewHandle(GetCompilingClass())); // We fetch the referenced class eagerly (that is, the class pointed by in the MethodId // at method_idx), as `CanAccessResolvedMethod` expects it be be in the dex cache. @@ -1267,7 +1268,9 @@ bool HInstructionBuilder::BuildInstanceFieldAccess(const Instruction& instructio static mirror::Class* GetClassFrom(CompilerDriver* driver, const DexCompilationUnit& compilation_unit) { ScopedObjectAccess soa(Thread::Current()); - Handle<mirror::ClassLoader> class_loader = compilation_unit.GetClassLoader(); + StackHandleScope<1> hs(soa.Self()); + Handle<mirror::ClassLoader> class_loader(hs.NewHandle( + soa.Decode<mirror::ClassLoader>(compilation_unit.GetClassLoader()))); Handle<mirror::DexCache> dex_cache = compilation_unit.GetDexCache(); return driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, &compilation_unit); @@ -1283,9 +1286,10 @@ mirror::Class* HInstructionBuilder::GetCompilingClass() const { bool HInstructionBuilder::IsOutermostCompilingClass(dex::TypeIndex type_index) const { ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<2> hs(soa.Self()); + StackHandleScope<3> hs(soa.Self()); Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache(); - Handle<mirror::ClassLoader> class_loader = dex_compilation_unit_->GetClassLoader(); + Handle<mirror::ClassLoader> class_loader(hs.NewHandle( + soa.Decode<mirror::ClassLoader>(dex_compilation_unit_->GetClassLoader()))); Handle<mirror::Class> cls(hs.NewHandle(compiler_driver_->ResolveClass( soa, dex_cache, class_loader, type_index, dex_compilation_unit_))); Handle<mirror::Class> outer_class(hs.NewHandle(GetOutermostCompilingClass())); @@ -1321,7 +1325,8 @@ ArtField* HInstructionBuilder::ResolveField(uint16_t field_idx, bool is_static, StackHandleScope<2> hs(soa.Self()); ClassLinker* class_linker = dex_compilation_unit_->GetClassLinker(); - Handle<mirror::ClassLoader> class_loader = dex_compilation_unit_->GetClassLoader(); + Handle<mirror::ClassLoader> class_loader(hs.NewHandle( + soa.Decode<mirror::ClassLoader>(dex_compilation_unit_->GetClassLoader()))); Handle<mirror::Class> compiling_class(hs.NewHandle(GetCompilingClass())); ArtField* resolved_field = class_linker->ResolveField(*dex_compilation_unit_->GetDexFile(), @@ -1638,8 +1643,10 @@ static TypeCheckKind ComputeTypeCheckKind(Handle<mirror::Class> cls) HLoadClass* HInstructionBuilder::BuildLoadClass(dex::TypeIndex type_index, uint32_t dex_pc) { ScopedObjectAccess soa(Thread::Current()); + StackHandleScope<2> hs(soa.Self()); const DexFile& dex_file = *dex_compilation_unit_->GetDexFile(); - Handle<mirror::ClassLoader> class_loader = dex_compilation_unit_->GetClassLoader(); + Handle<mirror::ClassLoader> class_loader(hs.NewHandle( + soa.Decode<mirror::ClassLoader>(dex_compilation_unit_->GetClassLoader()))); Handle<mirror::Class> klass = handles_->NewHandle(compiler_driver_->ResolveClass( soa, dex_compilation_unit_->GetDexCache(), class_loader, type_index, dex_compilation_unit_)); @@ -1723,9 +1730,17 @@ void HInstructionBuilder::BuildTypeCheck(const Instruction& instruction, } } -bool HInstructionBuilder::NeedsAccessCheck(dex::TypeIndex type_index, bool* finalizable) const { +bool HInstructionBuilder::NeedsAccessCheck(dex::TypeIndex type_index, + Handle<mirror::DexCache> dex_cache, + bool* finalizable) const { return !compiler_driver_->CanAccessInstantiableTypeWithoutChecks( - LookupReferrerClass(), LookupResolvedType(type_index, *dex_compilation_unit_), finalizable); + dex_compilation_unit_->GetDexMethodIndex(), dex_cache, type_index, finalizable); +} + +bool HInstructionBuilder::NeedsAccessCheck(dex::TypeIndex type_index, bool* finalizable) const { + ScopedObjectAccess soa(Thread::Current()); + Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache(); + return NeedsAccessCheck(type_index, dex_cache, finalizable); } bool HInstructionBuilder::CanDecodeQuickenedInfo() const { @@ -2765,18 +2780,4 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction, return true; } // NOLINT(readability/fn_size) -ObjPtr<mirror::Class> HInstructionBuilder::LookupResolvedType( - dex::TypeIndex type_index, - const DexCompilationUnit& compilation_unit) const { - return ClassLinker::LookupResolvedType( - type_index, compilation_unit.GetDexCache().Get(), compilation_unit.GetClassLoader().Get()); -} - -ObjPtr<mirror::Class> HInstructionBuilder::LookupReferrerClass() const { - // TODO: Cache the result in a Handle<mirror::Class>. - const DexFile::MethodId& method_id = - dex_compilation_unit_->GetDexFile()->GetMethodId(dex_compilation_unit_->GetDexMethodIndex()); - return LookupResolvedType(method_id.class_idx_, *dex_compilation_unit_); -} - } // namespace art diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h index 7fdc1883ca..6cb6655252 100644 --- a/compiler/optimizing/instruction_builder.h +++ b/compiler/optimizing/instruction_builder.h @@ -110,8 +110,11 @@ class HInstructionBuilder : public ValueObject { // Returns whether the current method needs access check for the type. // Output parameter finalizable is set to whether the type is finalizable. - bool NeedsAccessCheck(dex::TypeIndex type_index, /*out*/bool* finalizable) const + bool NeedsAccessCheck(dex::TypeIndex type_index, + Handle<mirror::DexCache> dex_cache, + /*out*/bool* finalizable) const REQUIRES_SHARED(Locks::mutator_lock_); + bool NeedsAccessCheck(dex::TypeIndex type_index, /*out*/bool* finalizable) const; template<typename T> void Unop_12x(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc); @@ -301,12 +304,6 @@ class HInstructionBuilder : public ValueObject { // be found. ArtField* ResolveField(uint16_t field_idx, bool is_static, bool is_put); - ObjPtr<mirror::Class> LookupResolvedType(dex::TypeIndex type_index, - const DexCompilationUnit& compilation_unit) const - REQUIRES_SHARED(Locks::mutator_lock_); - - ObjPtr<mirror::Class> LookupReferrerClass() const REQUIRES_SHARED(Locks::mutator_lock_); - ArenaAllocator* const arena_; HGraph* const graph_; VariableSizedHandleScope* handles_; diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index d6153b091c..918a027aba 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -307,7 +307,7 @@ class OptimizingCompiler FINAL : public Compiler { InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, - Handle<mirror::ClassLoader> class_loader, + jobject class_loader, const DexFile& dex_file, Handle<mirror::DexCache> dex_cache) const OVERRIDE; @@ -376,7 +376,7 @@ class OptimizingCompiler FINAL : public Compiler { InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, - Handle<mirror::ClassLoader> class_loader, + jobject class_loader, const DexFile& dex_file, Handle<mirror::DexCache> dex_cache, ArtMethod* method, @@ -884,7 +884,7 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* arena, InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, - Handle<mirror::ClassLoader> class_loader, + jobject class_loader, const DexFile& dex_file, Handle<mirror::DexCache> dex_cache, ArtMethod* method, @@ -955,8 +955,11 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* arena, const uint8_t* interpreter_metadata = nullptr; if (method == nullptr) { ScopedObjectAccess soa(Thread::Current()); + StackHandleScope<1> hs(soa.Self()); + Handle<mirror::ClassLoader> loader(hs.NewHandle( + soa.Decode<mirror::ClassLoader>(class_loader))); method = compiler_driver->ResolveMethod( - soa, dex_cache, class_loader, &dex_compilation_unit, method_idx, invoke_type); + soa, dex_cache, loader, &dex_compilation_unit, method_idx, invoke_type); } // For AOT compilation, we may not get a method, for example if its class is erroneous. // JIT should always have a method. @@ -965,6 +968,16 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* arena, graph->SetArtMethod(method); ScopedObjectAccess soa(Thread::Current()); interpreter_metadata = method->GetQuickenedInfo(class_linker->GetImagePointerSize()); + dex::TypeIndex type_index = method->GetDeclaringClass()->GetDexTypeIndex(); + + // Update the dex cache if the type is not in it yet. Note that under AOT, + // the verifier must have set it, but under JIT, there's no guarantee, as we + // don't necessarily run the verifier. + // The compiler and the compiler driver assume the compiling class is + // in the dex cache. + if (dex_cache->GetResolvedType(type_index) == nullptr) { + dex_cache->SetResolvedType(type_index, method->GetDeclaringClass()); + } } std::unique_ptr<CodeGenerator> codegen( @@ -1045,7 +1058,7 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item, InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, - Handle<mirror::ClassLoader> jclass_loader, + jobject jclass_loader, const DexFile& dex_file, Handle<mirror::DexCache> dex_cache) const { CompilerDriver* compiler_driver = GetCompilerDriver(); @@ -1159,6 +1172,7 @@ bool OptimizingCompiler::JitCompile(Thread* self, Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache())); DCHECK(method->IsCompilable()); + jobject jclass_loader = class_loader.ToJObject(); const DexFile* dex_file = method->GetDexFile(); const uint16_t class_def_idx = method->GetClassDefIndex(); const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset()); @@ -1182,7 +1196,7 @@ bool OptimizingCompiler::JitCompile(Thread* self, invoke_type, class_def_idx, method_idx, - class_loader, + jclass_loader, *dex_file, dex_cache, method, diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc index 6e332ca59b..c55fccc7d3 100644 --- a/compiler/optimizing/reference_type_propagation.cc +++ b/compiler/optimizing/reference_type_propagation.cc @@ -65,13 +65,11 @@ ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetThrowabl class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor { public: RTPVisitor(HGraph* graph, - Handle<mirror::ClassLoader> class_loader, Handle<mirror::DexCache> hint_dex_cache, HandleCache* handle_cache, ArenaVector<HInstruction*>* worklist, bool is_first_run) : HGraphDelegateVisitor(graph), - class_loader_(class_loader), hint_dex_cache_(hint_dex_cache), handle_cache_(handle_cache), worklist_(worklist), @@ -103,7 +101,6 @@ class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor { bool is_exact); private: - Handle<mirror::ClassLoader> class_loader_; Handle<mirror::DexCache> hint_dex_cache_; HandleCache* handle_cache_; ArenaVector<HInstruction*>* worklist_; @@ -111,13 +108,11 @@ class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor { }; ReferenceTypePropagation::ReferenceTypePropagation(HGraph* graph, - Handle<mirror::ClassLoader> class_loader, Handle<mirror::DexCache> hint_dex_cache, VariableSizedHandleScope* handles, bool is_first_run, const char* name) : HOptimization(graph, name), - class_loader_(class_loader), hint_dex_cache_(hint_dex_cache), handle_cache_(handles), worklist_(graph->GetArena()->Adapter(kArenaAllocReferenceTypePropagation)), @@ -152,12 +147,7 @@ void ReferenceTypePropagation::ValidateTypes() { } void ReferenceTypePropagation::Visit(HInstruction* instruction) { - RTPVisitor visitor(graph_, - class_loader_, - hint_dex_cache_, - &handle_cache_, - &worklist_, - is_first_run_); + RTPVisitor visitor(graph_, hint_dex_cache_, &handle_cache_, &worklist_, is_first_run_); instruction->Accept(&visitor); } @@ -331,12 +321,7 @@ void ReferenceTypePropagation::Run() { } void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) { - RTPVisitor visitor(graph_, - class_loader_, - hint_dex_cache_, - &handle_cache_, - &worklist_, - is_first_run_); + RTPVisitor visitor(graph_, hint_dex_cache_, &handle_cache_, &worklist_, is_first_run_); // Handle Phis first as there might be instructions in the same block who depend on them. for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) { VisitPhi(it.Current()->AsPhi()); @@ -557,9 +542,8 @@ void ReferenceTypePropagation::RTPVisitor::UpdateReferenceTypeInfo(HInstruction* ScopedObjectAccess soa(Thread::Current()); ObjPtr<mirror::DexCache> dex_cache = FindDexCacheWithHint(soa.Self(), dex_file, hint_dex_cache_); - ObjPtr<mirror::Class> klass = - ClassLinker::LookupResolvedType(type_idx, dex_cache, class_loader_.Get()); - SetClassAsTypeInfo(instr, klass, is_exact); + // Get type from dex cache assuming it was populated by the verifier. + SetClassAsTypeInfo(instr, dex_cache->GetResolvedType(type_idx), is_exact); } void ReferenceTypePropagation::RTPVisitor::VisitNewInstance(HNewInstance* instr) { @@ -572,13 +556,25 @@ void ReferenceTypePropagation::RTPVisitor::VisitNewArray(HNewArray* instr) { SetClassAsTypeInfo(instr, instr->GetLoadClass()->GetClass().Get(), /* is_exact */ true); } +static mirror::Class* GetClassFromDexCache(Thread* self, + const DexFile& dex_file, + dex::TypeIndex type_idx, + Handle<mirror::DexCache> hint_dex_cache) + REQUIRES_SHARED(Locks::mutator_lock_) { + ObjPtr<mirror::DexCache> dex_cache = FindDexCacheWithHint(self, dex_file, hint_dex_cache); + // Get type from dex cache assuming it was populated by the verifier. + return dex_cache->GetResolvedType(type_idx); +} + void ReferenceTypePropagation::RTPVisitor::VisitParameterValue(HParameterValue* instr) { // We check if the existing type is valid: the inliner may have set it. if (instr->GetType() == Primitive::kPrimNot && !instr->GetReferenceTypeInfo().IsValid()) { - UpdateReferenceTypeInfo(instr, - instr->GetTypeIndex(), - instr->GetDexFile(), - /* is_exact */ false); + ScopedObjectAccess soa(Thread::Current()); + mirror::Class* resolved_class = GetClassFromDexCache(soa.Self(), + instr->GetDexFile(), + instr->GetTypeIndex(), + hint_dex_cache_); + SetClassAsTypeInfo(instr, resolved_class, /* is_exact */ false); } } diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h index 215e96786b..4663471729 100644 --- a/compiler/optimizing/reference_type_propagation.h +++ b/compiler/optimizing/reference_type_propagation.h @@ -33,7 +33,6 @@ namespace art { class ReferenceTypePropagation : public HOptimization { public: ReferenceTypePropagation(HGraph* graph, - Handle<mirror::ClassLoader> class_loader, Handle<mirror::DexCache> hint_dex_cache, VariableSizedHandleScope* handles, bool is_first_run, @@ -106,8 +105,6 @@ class ReferenceTypePropagation : public HOptimization { void ValidateTypes(); - Handle<mirror::ClassLoader> class_loader_; - // Note: hint_dex_cache_ is usually, but not necessarily, the dex cache associated with // graph_->GetDexFile(). Since we may look up also in other dex files, it's used only // as a hint, to reduce the number of calls to the costly ClassLinker::FindDexCache(). diff --git a/compiler/optimizing/reference_type_propagation_test.cc b/compiler/optimizing/reference_type_propagation_test.cc index 84a4bab1a9..b061c871b0 100644 --- a/compiler/optimizing/reference_type_propagation_test.cc +++ b/compiler/optimizing/reference_type_propagation_test.cc @@ -38,7 +38,6 @@ class ReferenceTypePropagationTest : public CommonCompilerTest { void SetupPropagation(VariableSizedHandleScope* handles) { graph_->InitializeInexactObjectRTI(handles); propagation_ = new (&allocator_) ReferenceTypePropagation(graph_, - Handle<mirror::ClassLoader>(), Handle<mirror::DexCache>(), handles, true, diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc index 50ab11bc23..487e4dd498 100644 --- a/compiler/optimizing/ssa_builder.cc +++ b/compiler/optimizing/ssa_builder.cc @@ -499,11 +499,7 @@ GraphAnalysisResult SsaBuilder::BuildSsa() { // 4) Compute type of reference type instructions. The pass assumes that // NullConstant has been fixed up. - ReferenceTypePropagation(graph_, - class_loader_, - dex_cache_, - handles_, - /* is_first_run */ true).Run(); + ReferenceTypePropagation(graph_, dex_cache_, handles_, /* is_first_run */ true).Run(); // 5) HInstructionBuilder duplicated ArrayGet instructions with ambiguous type // (int/float or long/double) and marked ArraySets with ambiguous input type. diff --git a/compiler/optimizing/ssa_builder.h b/compiler/optimizing/ssa_builder.h index 978f113ec4..45dac54115 100644 --- a/compiler/optimizing/ssa_builder.h +++ b/compiler/optimizing/ssa_builder.h @@ -48,11 +48,9 @@ namespace art { class SsaBuilder : public ValueObject { public: SsaBuilder(HGraph* graph, - Handle<mirror::ClassLoader> class_loader, Handle<mirror::DexCache> dex_cache, VariableSizedHandleScope* handles) : graph_(graph), - class_loader_(class_loader), dex_cache_(dex_cache), handles_(handles), agets_fixed_(false), @@ -117,7 +115,6 @@ class SsaBuilder : public ValueObject { void RemoveRedundantUninitializedStrings(); HGraph* graph_; - Handle<mirror::ClassLoader> class_loader_; Handle<mirror::DexCache> dex_cache_; VariableSizedHandleScope* const handles_; diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index becb827d20..a0919a1974 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -2244,14 +2244,9 @@ class ImageDumper { ScopedIndentation indent2(&state->vios_); auto* resolved_types = dex_cache->GetResolvedTypes(); for (size_t i = 0; i < num_types; ++i) { - auto pair = resolved_types[i].load(std::memory_order_relaxed); + auto* elem = resolved_types[i].Read(); size_t run = 0; - for (size_t j = i + 1; j != num_types; ++j) { - auto other_pair = resolved_types[j].load(std::memory_order_relaxed); - if (pair.index != other_pair.index || - pair.object.Read() != other_pair.object.Read()) { - break; - } + for (size_t j = i + 1; j != num_types && elem == resolved_types[j].Read(); ++j) { ++run; } if (run == 0) { @@ -2261,13 +2256,12 @@ class ImageDumper { i = i + run; } std::string msg; - auto* elem = pair.object.Read(); if (elem == nullptr) { msg = "null"; } else { msg = elem->PrettyClass(); } - os << StringPrintf("%p %u %s\n", elem, pair.index, msg.c_str()); + os << StringPrintf("%p %s\n", elem, msg.c_str()); } } } diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc index 18a667015d..4426a300df 100644 --- a/patchoat/patchoat.cc +++ b/patchoat/patchoat.cc @@ -512,8 +512,8 @@ void PatchOat::PatchDexFileArrays(mirror::ObjectArray<mirror::Object>* img_roots if (orig_strings != nullptr) { orig_dex_cache->FixupStrings(RelocatedCopyOf(orig_strings), RelocatedPointerVisitor(this)); } - mirror::TypeDexCacheType* orig_types = orig_dex_cache->GetResolvedTypes(); - mirror::TypeDexCacheType* relocated_types = RelocatedAddressOfPointer(orig_types); + GcRoot<mirror::Class>* orig_types = orig_dex_cache->GetResolvedTypes(); + GcRoot<mirror::Class>* relocated_types = RelocatedAddressOfPointer(orig_types); copy_dex_cache->SetField64<false>( mirror::DexCache::ResolvedTypesOffset(), static_cast<int64_t>(reinterpret_cast<uintptr_t>(relocated_types))); diff --git a/runtime/art_field-inl.h b/runtime/art_field-inl.h index 16b73c681f..80af8e7bde 100644 --- a/runtime/art_field-inl.h +++ b/runtime/art_field-inl.h @@ -311,8 +311,6 @@ inline bool ArtField::IsPrimitiveType() REQUIRES_SHARED(Locks::mutator_lock_) { template <bool kResolve> inline ObjPtr<mirror::Class> ArtField::GetType() { - // TODO: Refactor this function into two functions, ResolveType() and LookupType() - // so that we can properly annotate it with no-suspension possible / suspension possible. const uint32_t field_index = GetDexFieldIndex(); ObjPtr<mirror::Class> declaring_class = GetDeclaringClass(); if (UNLIKELY(declaring_class->IsProxyClass())) { @@ -322,16 +320,9 @@ inline ObjPtr<mirror::Class> ArtField::GetType() { const DexFile* const dex_file = dex_cache->GetDexFile(); const DexFile::FieldId& field_id = dex_file->GetFieldId(field_index); ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(field_id.type_idx_); - if (UNLIKELY(type == nullptr)) { - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - if (kResolve) { - type = class_linker->ResolveType(*dex_file, field_id.type_idx_, declaring_class); - CHECK(type != nullptr || Thread::Current()->IsExceptionPending()); - } else { - type = class_linker->LookupResolvedType( - *dex_file, field_id.type_idx_, dex_cache, declaring_class->GetClassLoader()); - DCHECK(!Thread::Current()->IsExceptionPending()); - } + if (kResolve && UNLIKELY(type == nullptr)) { + type = ResolveGetType(field_id.type_idx_); + CHECK(type != nullptr || Thread::Current()->IsExceptionPending()); } return type; } diff --git a/runtime/art_field.cc b/runtime/art_field.cc index 7e131040be..a4a6e5a4fb 100644 --- a/runtime/art_field.cc +++ b/runtime/art_field.cc @@ -48,6 +48,10 @@ ObjPtr<mirror::Class> ArtField::ProxyFindSystemClass(const char* descriptor) { return Runtime::Current()->GetClassLinker()->FindSystemClass(Thread::Current(), descriptor); } +ObjPtr<mirror::Class> ArtField::ResolveGetType(dex::TypeIndex type_idx) { + return Runtime::Current()->GetClassLinker()->ResolveType(type_idx, this); +} + ObjPtr<mirror::String> ArtField::ResolveGetStringName(Thread* self, const DexFile& dex_file, dex::StringIndex string_idx, diff --git a/runtime/art_field.h b/runtime/art_field.h index 75dd981136..427e103749 100644 --- a/runtime/art_field.h +++ b/runtime/art_field.h @@ -217,6 +217,8 @@ class ArtField FINAL { private: ObjPtr<mirror::Class> ProxyFindSystemClass(const char* descriptor) REQUIRES_SHARED(Locks::mutator_lock_); + ObjPtr<mirror::Class> ResolveGetType(dex::TypeIndex type_idx) + REQUIRES_SHARED(Locks::mutator_lock_); ObjPtr<mirror::String> ResolveGetStringName(Thread* self, const DexFile& dex_file, dex::StringIndex string_idx, diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h index 685e26c78d..f54b5d652b 100644 --- a/runtime/art_method-inl.h +++ b/runtime/art_method-inl.h @@ -179,19 +179,12 @@ inline bool ArtMethod::HasSameDexCacheResolvedMethods(ArtMethod* other, PointerS } inline mirror::Class* ArtMethod::GetClassFromTypeIndex(dex::TypeIndex type_idx, bool resolve) { - // TODO: Refactor this function into two functions, Resolve...() and Lookup...() - // so that we can properly annotate it with no-suspension possible / suspension possible. ObjPtr<mirror::DexCache> dex_cache = GetDexCache(); ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx); - if (UNLIKELY(type == nullptr)) { + if (UNLIKELY(type == nullptr) && resolve) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - if (resolve) { - type = class_linker->ResolveType(type_idx, this); - CHECK(type != nullptr || Thread::Current()->IsExceptionPending()); - } else { - type = class_linker->LookupResolvedType( - *dex_cache->GetDexFile(), type_idx, dex_cache, GetClassLoader()); - } + type = class_linker->ResolveType(type_idx, this); + CHECK(type != nullptr || Thread::Current()->IsExceptionPending()); } return type.Ptr(); } diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h index bd510ca0e1..3438810069 100644 --- a/runtime/class_linker-inl.h +++ b/runtime/class_linker-inl.h @@ -78,18 +78,6 @@ inline mirror::String* ClassLinker::ResolveString(dex::StringIndex string_idx, return string.Ptr(); } -inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType( - dex::TypeIndex type_idx, - ObjPtr<mirror::DexCache> dex_cache, - ObjPtr<mirror::ClassLoader> class_loader) { - ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx); - if (type == nullptr) { - type = Runtime::Current()->GetClassLinker()->LookupResolvedType( - *dex_cache->GetDexFile(), type_idx, dex_cache, class_loader); - } - return type; -} - inline mirror::Class* ClassLinker::ResolveType(dex::TypeIndex type_idx, ArtMethod* referrer) { Thread::PoisonObjectPointersIfDebug(); if (kIsDebugBuild) { @@ -103,6 +91,25 @@ inline mirror::Class* ClassLinker::ResolveType(dex::TypeIndex type_idx, ArtMetho Handle<mirror::ClassLoader> class_loader(hs.NewHandle(declaring_class->GetClassLoader())); const DexFile& dex_file = *dex_cache->GetDexFile(); resolved_type = ResolveType(dex_file, type_idx, dex_cache, class_loader); + // Note: We cannot check here to see whether we added the type to the cache. The type + // might be an erroneous class, which results in it being hidden from us. + } + return resolved_type.Ptr(); +} + +inline mirror::Class* ClassLinker::ResolveType(dex::TypeIndex type_idx, ArtField* referrer) { + Thread::PoisonObjectPointersIfDebug(); + ObjPtr<mirror::Class> declaring_class = referrer->GetDeclaringClass(); + ObjPtr<mirror::DexCache> dex_cache_ptr = declaring_class->GetDexCache(); + ObjPtr<mirror::Class> resolved_type = dex_cache_ptr->GetResolvedType(type_idx); + if (UNLIKELY(resolved_type == nullptr)) { + StackHandleScope<2> hs(Thread::Current()); + Handle<mirror::DexCache> dex_cache(hs.NewHandle(dex_cache_ptr)); + Handle<mirror::ClassLoader> class_loader(hs.NewHandle(declaring_class->GetClassLoader())); + const DexFile& dex_file = *dex_cache->GetDexFile(); + resolved_type = ResolveType(dex_file, type_idx, dex_cache, class_loader); + // Note: We cannot check here to see whether we added the type to the cache. The type + // might be an erroneous class, which results in it being hidden from us. } return resolved_type.Ptr(); } diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index b611aa2132..bbf06e1874 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -58,7 +58,6 @@ #include "gc/heap.h" #include "gc/scoped_gc_critical_section.h" #include "gc/space/image_space.h" -#include "gc/space/space-inl.h" #include "handle_scope-inl.h" #include "image-inl.h" #include "imt_conflict_table.h" @@ -1147,35 +1146,6 @@ class VerifyClassInTableArtMethodVisitor : public ArtMethodVisitor { ClassTable* const table_; }; -class VerifyDirectInterfacesInTableClassVisitor { - public: - explicit VerifyDirectInterfacesInTableClassVisitor(ObjPtr<mirror::ClassLoader> class_loader) - : class_loader_(class_loader), self_(Thread::Current()) { } - - bool operator()(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) { - if (!klass->IsPrimitive() && klass->GetClassLoader() == class_loader_) { - classes_.push_back(klass); - } - return true; - } - - void Check() const REQUIRES_SHARED(Locks::mutator_lock_) { - for (ObjPtr<mirror::Class> klass : classes_) { - for (uint32_t i = 0, num = klass->NumDirectInterfaces(); i != num; ++i) { - CHECK(klass->GetDirectInterface(self_, klass, i) != nullptr) - << klass->PrettyDescriptor() << " iface #" << i - << klass->GetDexFile().StringByTypeIdx(klass->GetDirectInterfaceTypeIdx(i)) - << " Bug: 34839984"; - } - } - } - - private: - ObjPtr<mirror::ClassLoader> class_loader_; - Thread* self_; - std::vector<ObjPtr<mirror::Class>> classes_; -}; - class VerifyDeclaringClassVisitor : public ArtMethodVisitor { public: VerifyDeclaringClassVisitor() REQUIRES_SHARED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) @@ -1207,23 +1177,6 @@ static void CopyNonNull(const T* src, size_t count, T* dst, const NullPred& pred } } -template <typename T> -static void CopyDexCachePairs(const std::atomic<mirror::DexCachePair<T>>* src, - size_t count, - std::atomic<mirror::DexCachePair<T>>* dst) { - DCHECK_NE(count, 0u); - DCHECK(!src[0].load(std::memory_order_relaxed).object.IsNull() || - src[0].load(std::memory_order_relaxed).index != 0u); - for (size_t i = 0; i < count; ++i) { - DCHECK_EQ(dst[i].load(std::memory_order_relaxed).index, 0u); - DCHECK(dst[i].load(std::memory_order_relaxed).object.IsNull()); - mirror::DexCachePair<T> source = src[i].load(std::memory_order_relaxed); - if (source.index != 0u || !source.object.IsNull()) { - dst[i].store(source, std::memory_order_relaxed); - } - } -} - bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( gc::space::ImageSpace* space, Handle<mirror::ClassLoader> class_loader, @@ -1277,10 +1230,7 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( if (dex_file->NumStringIds() < num_strings) { num_strings = dex_file->NumStringIds(); } - size_t num_types = mirror::DexCache::kDexCacheTypeCacheSize; - if (dex_file->NumTypeIds() < num_types) { - num_types = dex_file->NumTypeIds(); - } + const size_t num_types = dex_file->NumTypeIds(); const size_t num_methods = dex_file->NumMethodIds(); const size_t num_fields = dex_file->NumFieldIds(); size_t num_method_types = mirror::DexCache::kDexCacheMethodTypeCacheSize; @@ -1300,14 +1250,28 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( mirror::StringDexCacheType* const image_resolved_strings = dex_cache->GetStrings(); mirror::StringDexCacheType* const strings = reinterpret_cast<mirror::StringDexCacheType*>(raw_arrays + layout.StringsOffset()); - CopyDexCachePairs(image_resolved_strings, num_strings, strings); + for (size_t j = 0; j < num_strings; ++j) { + DCHECK_EQ(strings[j].load(std::memory_order_relaxed).index, 0u); + DCHECK(strings[j].load(std::memory_order_relaxed).object.IsNull()); + strings[j].store(image_resolved_strings[j].load(std::memory_order_relaxed), + std::memory_order_relaxed); + } + mirror::StringDexCachePair::Initialize(strings); dex_cache->SetStrings(strings); } if (num_types != 0u) { - mirror::TypeDexCacheType* const image_resolved_types = dex_cache->GetResolvedTypes(); - mirror::TypeDexCacheType* const types = - reinterpret_cast<mirror::TypeDexCacheType*>(raw_arrays + layout.TypesOffset()); - CopyDexCachePairs(image_resolved_types, num_types, types); + GcRoot<mirror::Class>* const image_resolved_types = dex_cache->GetResolvedTypes(); + GcRoot<mirror::Class>* const types = + reinterpret_cast<GcRoot<mirror::Class>*>(raw_arrays + layout.TypesOffset()); + for (size_t j = 0; kIsDebugBuild && j < num_types; ++j) { + DCHECK(types[j].IsNull()); + } + CopyNonNull(image_resolved_types, + num_types, + types, + [](const GcRoot<mirror::Class>& elem) { + return elem.IsNull(); + }); dex_cache->SetResolvedTypes(types); } if (num_methods != 0u) { @@ -1348,7 +1312,15 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( mirror::MethodTypeDexCacheType* const method_types = reinterpret_cast<mirror::MethodTypeDexCacheType*>( raw_arrays + layout.MethodTypesOffset()); - CopyDexCachePairs(image_resolved_method_types, num_method_types, method_types); + for (size_t j = 0; j < num_method_types; ++j) { + DCHECK_EQ(method_types[j].load(std::memory_order_relaxed).index, 0u); + DCHECK(method_types[j].load(std::memory_order_relaxed).object.IsNull()); + method_types[j].store( + image_resolved_method_types[j].load(std::memory_order_relaxed), + std::memory_order_relaxed); + } + + mirror::MethodTypeDexCachePair::Initialize(method_types); dex_cache->SetResolvedMethodTypes(method_types); } if (num_call_sites != 0u) { @@ -1378,11 +1350,11 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( } if (kIsDebugBuild) { CHECK(new_class_set != nullptr); - mirror::TypeDexCacheType* const types = dex_cache->GetResolvedTypes(); + GcRoot<mirror::Class>* const types = dex_cache->GetResolvedTypes(); const size_t num_types = dex_cache->NumResolvedTypes(); - for (size_t j = 0; j != num_types; ++j) { + for (int32_t j = 0; j < static_cast<int32_t>(num_types); j++) { // The image space is not yet added to the heap, avoid read barriers. - ObjPtr<mirror::Class> klass = types[j].load(std::memory_order_relaxed).object.Read(); + ObjPtr<mirror::Class> klass = types[j].Read(); if (space->HasAddress(klass.Ptr())) { DCHECK(!klass->IsErroneous()) << klass->GetStatus(); auto it = new_class_set->Find(ClassTable::TableSlot(klass)); @@ -1741,9 +1713,9 @@ bool ClassLinker::AddImageSpace( // The current dex file field is bogus, overwrite it so that we can get the dex file in the // loop below. dex_cache->SetDexFile(dex_file.get()); - mirror::TypeDexCacheType* const types = dex_cache->GetResolvedTypes(); + GcRoot<mirror::Class>* const types = dex_cache->GetResolvedTypes(); for (int32_t j = 0, num_types = dex_cache->NumResolvedTypes(); j < num_types; j++) { - ObjPtr<mirror::Class> klass = types[j].load(std::memory_order_relaxed).object.Read(); + ObjPtr<mirror::Class> klass = types[j].Read(); if (klass != nullptr) { DCHECK(!klass->IsErroneous()) << klass->GetStatus(); } @@ -1914,12 +1886,6 @@ bool ClassLinker::AddImageSpace( VerifyClassInTableArtMethodVisitor visitor2(class_table); header.VisitPackedArtMethods(&visitor2, space->Begin(), kRuntimePointerSize); } - if (app_image) { - // TODO: Restrict this check to debug builds. Bug: 34839984 - VerifyDirectInterfacesInTableClassVisitor visitor(class_loader.Get()); - class_table->Visit(visitor); - visitor.Check(); - } VLOG(class_linker) << "Adding image space took " << PrettyDuration(NanoTime() - start_time); return true; } @@ -4538,108 +4504,6 @@ bool ClassLinker::CanWeInitializeClass(ObjPtr<mirror::Class> klass, bool can_ini return CanWeInitializeClass(super_class, can_init_statics, can_init_parents); } -std::string DescribeSpace(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) { - std::ostringstream oss; - gc::Heap* heap = Runtime::Current()->GetHeap(); - gc::space::ContinuousSpace* cs = heap->FindContinuousSpaceFromAddress(klass.Ptr()); - if (cs != nullptr) { - if (cs->IsImageSpace()) { - oss << "image/" << cs->GetName() << "/" << cs->AsImageSpace()->GetImageFilename(); - } else { - oss << "continuous/" << cs->GetName(); - } - } else { - gc::space::DiscontinuousSpace* ds = - heap->FindDiscontinuousSpaceFromObject(klass, /* fail_ok */ true); - if (ds != nullptr) { - oss << "discontinuous/" << ds->GetName(); - } else { - oss << "invalid"; - } - } - return oss.str(); -} - -std::string DescribeLoaders(ObjPtr<mirror::Class> klass, const char* iface_descriptor) - REQUIRES_SHARED(Locks::mutator_lock_) { - std::ostringstream oss; - uint32_t hash = ComputeModifiedUtf8Hash(iface_descriptor); - ScopedObjectAccessUnchecked soa(Thread::Current()); - ObjPtr<mirror::Class> path_class_loader = - soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader); - ObjPtr<mirror::Class> dex_class_loader = - soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_DexClassLoader); - - // Print the class loader chain. - bool found_iface; - const char* loader_separator = ""; - for (ObjPtr<mirror::ClassLoader> loader = klass->GetClassLoader(); - loader != nullptr; - loader = loader->GetParent()) { - oss << loader_separator << loader->GetClass()->PrettyDescriptor(); - loader_separator = ";"; - // If we didn't find the interface yet, try to find it in the current class loader. - if (!found_iface) { - ClassTable* table = Runtime::Current()->GetClassLinker()->ClassTableForClassLoader(loader); - ObjPtr<mirror::Class> iface = - (table != nullptr) ? table->Lookup(iface_descriptor, hash) : nullptr; - if (iface != nullptr) { - found_iface = true; - oss << "[hit:" << DescribeSpace(iface) << "]"; - } - } - - // For PathClassLoader or DexClassLoader also dump the dex file locations. - if (loader->GetClass() == path_class_loader || loader->GetClass() == dex_class_loader) { - ArtField* const cookie_field = - jni::DecodeArtField(WellKnownClasses::dalvik_system_DexFile_cookie); - ArtField* const dex_file_field = - jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile); - ObjPtr<mirror::Object> dex_path_list = - jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_pathList)-> - GetObject(loader); - if (dex_path_list != nullptr && dex_file_field != nullptr && cookie_field != nullptr) { - ObjPtr<mirror::Object> dex_elements_obj = - jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList_dexElements)-> - GetObject(dex_path_list); - if (dex_elements_obj != nullptr) { - ObjPtr<mirror::ObjectArray<mirror::Object>> dex_elements = - dex_elements_obj->AsObjectArray<mirror::Object>(); - oss << "("; - const char* path_separator = ""; - for (int32_t i = 0; i != dex_elements->GetLength(); ++i) { - ObjPtr<mirror::Object> element = dex_elements->GetWithoutChecks(i); - ObjPtr<mirror::Object> dex_file = - (element != nullptr) ? dex_file_field->GetObject(element) : nullptr; - ObjPtr<mirror::LongArray> long_array = - (dex_file != nullptr) ? cookie_field->GetObject(dex_file)->AsLongArray() : nullptr; - if (long_array != nullptr) { - int32_t long_array_size = long_array->GetLength(); - // First element is the oat file. - for (int32_t j = kDexFileIndexStart; j < long_array_size; ++j) { - const DexFile* cp_dex_file = reinterpret_cast<const DexFile*>( - static_cast<uintptr_t>(long_array->GetWithoutChecks(j))); - oss << path_separator << cp_dex_file->GetLocation(); - path_separator = ":"; - } - } - } - oss << ")"; - } - } - } - } - - // Do a paranoid check that the `klass` itself is in the class table. - ClassTable* table = - Runtime::Current()->GetClassLinker()->ClassTableForClassLoader(klass->GetClassLoader()); - ObjPtr<mirror::Class> k = (table != nullptr) ? table->LookupByDescriptor(klass) : nullptr; - if (k != klass) { - oss << "{FAIL:" << k.Ptr() << "!=" << klass.Ptr() << "}"; - } - return oss.str(); -} - bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, bool can_init_statics, bool can_init_parents) { // see JLS 3rd edition, 12.4.2 "Detailed Initialization Procedure" for the locking protocol @@ -4787,15 +4651,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, MutableHandle<mirror::Class> handle_scope_iface(hs_iface.NewHandle<mirror::Class>(nullptr)); for (size_t i = 0; i < num_direct_interfaces; i++) { handle_scope_iface.Assign(mirror::Class::GetDirectInterface(self, klass.Get(), i)); - if (UNLIKELY(handle_scope_iface == nullptr)) { - const char* iface_descriptor = - klass->GetDexFile().StringByTypeIdx(klass->GetDirectInterfaceTypeIdx(i)); - LOG(FATAL) << "Check failed: handle_scope_iface != nullptr " - << "Debug data for bug 34839984: " - << klass->PrettyDescriptor() << " iface #" << i << " " << iface_descriptor - << " space: " << DescribeSpace(klass.Get()) - << " loaders: " << DescribeLoaders(klass.Get(), iface_descriptor); - } + CHECK(handle_scope_iface != nullptr); CHECK(handle_scope_iface->IsInterface()); if (handle_scope_iface->HasBeenRecursivelyInitialized()) { // We have already done this for this interface. Skip it. @@ -4931,15 +4787,7 @@ bool ClassLinker::InitializeDefaultInterfaceRecursive(Thread* self, // First we initialize all of iface's super-interfaces recursively. for (size_t i = 0; i < num_direct_ifaces; i++) { ObjPtr<mirror::Class> super_iface = mirror::Class::GetDirectInterface(self, iface.Get(), i); - if (UNLIKELY(super_iface == nullptr)) { - const char* iface_descriptor = - iface->GetDexFile().StringByTypeIdx(iface->GetDirectInterfaceTypeIdx(i)); - LOG(FATAL) << "Check failed: super_iface != nullptr " - << "Debug data for bug 34839984: " - << iface->PrettyDescriptor() << " iface #" << i << " " << iface_descriptor - << " space: " << DescribeSpace(iface.Get()) - << " loaders: " << DescribeLoaders(iface.Get(), iface_descriptor); - } + DCHECK(super_iface != nullptr); if (!super_iface->HasBeenRecursivelyInitialized()) { // Recursive step handle_super_iface.Assign(super_iface); @@ -7914,9 +7762,7 @@ mirror::String* ClassLinker::ResolveString(const DexFile& dex_file, uint32_t utf16_length; const char* utf8_data = dex_file.StringDataAndUtf16LengthByIdx(string_idx, &utf16_length); ObjPtr<mirror::String> string = intern_table_->InternStrong(utf16_length, utf8_data); - if (string != nullptr) { - dex_cache->SetResolvedString(string_idx, string); - } + dex_cache->SetResolvedString(string_idx, string); return string.Ptr(); } @@ -7957,16 +7803,11 @@ ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(const DexFile& dex_file, // Find the class in the loaded classes table. type = LookupClass(self, descriptor, hash, class_loader.Ptr()); } - if (type != nullptr) { - if (type->IsResolved()) { - dex_cache->SetResolvedType(type_idx, type); - } else { - type = nullptr; - } - } } - DCHECK(type == nullptr || type->IsResolved()); - return type; + if (type != nullptr && type->IsResolved()) { + return type.Ptr(); + } + return nullptr; } mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, @@ -7986,12 +7827,6 @@ mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, Thread::PoisonObjectPointersIfDebug(); ObjPtr<mirror::Class> resolved = dex_cache->GetResolvedType(type_idx); if (resolved == nullptr) { - // TODO: Avoid this lookup as it duplicates work done in FindClass(). It is here - // as a workaround for FastNative JNI to avoid AssertNoPendingException() when - // trying to resolve annotations while an exception may be pending. Bug: 34659969 - resolved = LookupResolvedType(dex_file, type_idx, dex_cache.Get(), class_loader.Get()); - } - if (resolved == nullptr) { Thread* self = Thread::Current(); const char* descriptor = dex_file.StringByTypeIdx(type_idx); resolved = FindClass(self, descriptor, class_loader); diff --git a/runtime/class_linker.h b/runtime/class_linker.h index a5d26c7a88..f07156f4dd 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -266,6 +266,10 @@ class ClassLinker { REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); + mirror::Class* ResolveType(dex::TypeIndex type_idx, ArtField* referrer) + REQUIRES_SHARED(Locks::mutator_lock_) + REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); + // Look up a resolved type with the given ID from the DexFile. The ClassLoader is used to search // for the type, since it may be referenced from but not contained within the given DexFile. ObjPtr<mirror::Class> LookupResolvedType(const DexFile& dex_file, @@ -273,10 +277,6 @@ class ClassLinker { ObjPtr<mirror::DexCache> dex_cache, ObjPtr<mirror::ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_); - static ObjPtr<mirror::Class> LookupResolvedType(dex::TypeIndex type_idx, - ObjPtr<mirror::DexCache> dex_cache, - ObjPtr<mirror::ClassLoader> class_loader) - REQUIRES_SHARED(Locks::mutator_lock_); // Resolve a type with the given ID from the DexFile, storing the // result in DexCache. The ClassLoader is used to search for the diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index e5722a13a7..37e01ef969 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -935,7 +935,7 @@ TEST_F(ClassLinkerTest, LookupResolvedType) { class_linker_->LookupResolvedType(dex_file, type_idx, dex_cache, class_loader.Get()), klass); // Zero out the resolved type and make sure LookupResolvedType still finds it. - dex_cache->ClearResolvedType(type_idx); + dex_cache->SetResolvedType(type_idx, nullptr); EXPECT_TRUE(dex_cache->GetResolvedType(type_idx) == nullptr); EXPECT_OBJ_PTR_EQ( class_linker_->LookupResolvedType(dex_file, type_idx, dex_cache, class_loader.Get()), @@ -970,7 +970,7 @@ TEST_F(ClassLinkerTest, LookupResolvedTypeArray) { class_linker_->LookupResolvedType(dex_file, array_idx, dex_cache.Get(), class_loader.Get()), array_klass); // Zero out the resolved type and make sure LookupResolvedType() still finds it. - dex_cache->ClearResolvedType(array_idx); + dex_cache->SetResolvedType(array_idx, nullptr); EXPECT_TRUE(dex_cache->GetResolvedType(array_idx) == nullptr); EXPECT_OBJ_PTR_EQ( class_linker_->LookupResolvedType(dex_file, array_idx, dex_cache.Get(), class_loader.Get()), @@ -993,7 +993,7 @@ TEST_F(ClassLinkerTest, LookupResolvedTypeErroneousInit) { class_linker_->LookupResolvedType(dex_file, type_idx, dex_cache.Get(), class_loader.Get()), klass.Get()); // Zero out the resolved type and make sure LookupResolvedType still finds it. - dex_cache->ClearResolvedType(type_idx); + dex_cache->SetResolvedType(type_idx, nullptr); EXPECT_TRUE(dex_cache->GetResolvedType(type_idx) == nullptr); EXPECT_OBJ_PTR_EQ( class_linker_->LookupResolvedType(dex_file, type_idx, dex_cache.Get(), class_loader.Get()), @@ -1011,7 +1011,7 @@ TEST_F(ClassLinkerTest, LookupResolvedTypeErroneousInit) { class_linker_->LookupResolvedType(dex_file, type_idx, dex_cache.Get(), class_loader.Get()), klass.Get()); // Zero out the resolved type and make sure LookupResolvedType() still finds it. - dex_cache->ClearResolvedType(type_idx); + dex_cache->SetResolvedType(type_idx, nullptr); EXPECT_TRUE(dex_cache->GetResolvedType(type_idx) == nullptr); EXPECT_OBJ_PTR_EQ( class_linker_->LookupResolvedType(dex_file, type_idx, dex_cache.Get(), class_loader.Get()), diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h index 3bc49b8506..28aca6c905 100644 --- a/runtime/entrypoints/entrypoint_utils-inl.h +++ b/runtime/entrypoints/entrypoint_utils-inl.h @@ -709,10 +709,10 @@ inline ArtMethod* FindMethodFast(uint32_t method_idx, return resolved_method; } else if (type == kSuper) { // TODO This lookup is rather slow. - ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache(); - dex::TypeIndex method_type_idx = dex_cache->GetDexFile()->GetMethodId(method_idx).class_idx_; - ObjPtr<mirror::Class> method_reference_class = ClassLinker::LookupResolvedType( - method_type_idx, dex_cache, referrer->GetClassLoader()); + dex::TypeIndex method_type_idx = + referrer->GetDexFile()->GetMethodId(method_idx).class_idx_; + mirror::Class* method_reference_class = + referrer->GetDexCache()->GetResolvedType(method_type_idx); if (method_reference_class == nullptr) { // Need to do full type resolution... return nullptr; diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index 010ef1156a..2163a20e87 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -1237,9 +1237,9 @@ class ImageSpaceLoader { } dex_cache->FixupStrings<kWithoutReadBarrier>(new_strings, fixup_adapter); } - mirror::TypeDexCacheType* types = dex_cache->GetResolvedTypes(); + GcRoot<mirror::Class>* types = dex_cache->GetResolvedTypes(); if (types != nullptr) { - mirror::TypeDexCacheType* new_types = fixup_adapter.ForwardObject(types); + GcRoot<mirror::Class>* new_types = fixup_adapter.ForwardObject(types); if (types != new_types) { dex_cache->SetResolvedTypes(new_types); } diff --git a/runtime/image.cc b/runtime/image.cc index 88f28f3ea1..f545f8d0a0 100644 --- a/runtime/image.cc +++ b/runtime/image.cc @@ -25,7 +25,7 @@ namespace art { const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' }; -const uint8_t ImageHeader::kImageVersion[] = { '0', '4', '0', '\0' }; // Integer.valueOf intrinsic +const uint8_t ImageHeader::kImageVersion[] = { '0', '4', '1', '\0' }; // Revert DexCache types. ImageHeader::ImageHeader(uint32_t image_begin, uint32_t image_size, diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index eb2ec9b3c8..9a9a5d8398 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -951,8 +951,7 @@ ObjPtr<Class> Class::GetDirectInterface(Thread* self, ObjPtr<Class> klass, uint3 return interfaces->Get(idx); } else { dex::TypeIndex type_idx = klass->GetDirectInterfaceTypeIdx(idx); - ObjPtr<Class> interface = ClassLinker::LookupResolvedType( - type_idx, klass->GetDexCache(), klass->GetClassLoader()); + ObjPtr<Class> interface = klass->GetDexCache()->GetResolvedType(type_idx); return interface; } } diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h index 29bf6a0240..973c8ed07d 100644 --- a/runtime/mirror/dex_cache-inl.h +++ b/runtime/mirror/dex_cache-inl.h @@ -41,22 +41,14 @@ inline uint32_t DexCache::ClassSize(PointerSize pointer_size) { return Class::ComputeClassSize(true, vtable_entries, 0, 0, 0, 0, 0, pointer_size); } -inline uint32_t DexCache::StringSlotIndex(dex::StringIndex string_idx) { +inline mirror::String* DexCache::GetResolvedString(dex::StringIndex string_idx) { DCHECK_LT(string_idx.index_, GetDexFile()->NumStringIds()); - const uint32_t slot_idx = string_idx.index_ % kDexCacheStringCacheSize; - DCHECK_LT(slot_idx, NumStrings()); - return slot_idx; + return StringDexCachePair::Lookup(GetStrings(), string_idx.index_, NumStrings()).Read(); } -inline String* DexCache::GetResolvedString(dex::StringIndex string_idx) { - return GetStrings()[StringSlotIndex(string_idx)].load( - std::memory_order_relaxed).GetObjectForIndex(string_idx.index_); -} - -inline void DexCache::SetResolvedString(dex::StringIndex string_idx, ObjPtr<String> resolved) { - DCHECK(resolved != nullptr); - GetStrings()[StringSlotIndex(string_idx)].store( - StringDexCachePair(resolved, string_idx.index_), std::memory_order_relaxed); +inline void DexCache::SetResolvedString(dex::StringIndex string_idx, + ObjPtr<mirror::String> resolved) { + StringDexCachePair::Assign(GetStrings(), string_idx.index_, resolved.Ptr(), NumStrings()); Runtime* const runtime = Runtime::Current(); if (UNLIKELY(runtime->IsActiveTransaction())) { DCHECK(runtime->IsAotCompiler()); @@ -67,70 +59,50 @@ inline void DexCache::SetResolvedString(dex::StringIndex string_idx, ObjPtr<Stri } inline void DexCache::ClearString(dex::StringIndex string_idx) { + const uint32_t slot_idx = string_idx.index_ % NumStrings(); DCHECK(Runtime::Current()->IsAotCompiler()); - uint32_t slot_idx = StringSlotIndex(string_idx); StringDexCacheType* slot = &GetStrings()[slot_idx]; // This is racy but should only be called from the transactional interpreter. if (slot->load(std::memory_order_relaxed).index == string_idx.index_) { - StringDexCachePair cleared(nullptr, StringDexCachePair::InvalidIndexForSlot(slot_idx)); + StringDexCachePair cleared( + nullptr, + StringDexCachePair::InvalidIndexForSlot(slot_idx)); slot->store(cleared, std::memory_order_relaxed); } } -inline uint32_t DexCache::TypeSlotIndex(dex::TypeIndex type_idx) { - DCHECK_LT(type_idx.index_, GetDexFile()->NumTypeIds()); - const uint32_t slot_idx = type_idx.index_ % kDexCacheTypeCacheSize; - DCHECK_LT(slot_idx, NumResolvedTypes()); - return slot_idx; -} - inline Class* DexCache::GetResolvedType(dex::TypeIndex type_idx) { // It is theorized that a load acquire is not required since obtaining the resolved class will // always have an address dependency or a lock. - return GetResolvedTypes()[TypeSlotIndex(type_idx)].load( - std::memory_order_relaxed).GetObjectForIndex(type_idx.index_); + DCHECK_LT(type_idx.index_, NumResolvedTypes()); + return GetResolvedTypes()[type_idx.index_].Read(); } inline void DexCache::SetResolvedType(dex::TypeIndex type_idx, ObjPtr<Class> resolved) { - DCHECK(resolved != nullptr); + DCHECK_LT(type_idx.index_, NumResolvedTypes()); // NOTE: Unchecked, i.e. not throwing AIOOB. // TODO default transaction support. // Use a release store for SetResolvedType. This is done to prevent other threads from seeing a // class but not necessarily seeing the loaded members like the static fields array. // See b/32075261. - GetResolvedTypes()[TypeSlotIndex(type_idx)].store( - TypeDexCachePair(resolved, type_idx.index_), std::memory_order_release); + reinterpret_cast<Atomic<GcRoot<mirror::Class>>&>(GetResolvedTypes()[type_idx.index_]). + StoreRelease(GcRoot<Class>(resolved)); // TODO: Fine-grained marking, so that we don't need to go through all arrays in full. Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(this); } -inline void DexCache::ClearResolvedType(dex::TypeIndex type_idx) { - DCHECK(Runtime::Current()->IsAotCompiler()); - uint32_t slot_idx = TypeSlotIndex(type_idx); - TypeDexCacheType* slot = &GetResolvedTypes()[slot_idx]; - // This is racy but should only be called from the single-threaded ImageWriter and tests. - if (slot->load(std::memory_order_relaxed).index == type_idx.index_) { - TypeDexCachePair cleared(nullptr, TypeDexCachePair::InvalidIndexForSlot(slot_idx)); - slot->store(cleared, std::memory_order_relaxed); - } -} - -inline uint32_t DexCache::MethodTypeSlotIndex(uint32_t proto_idx) { +inline MethodType* DexCache::GetResolvedMethodType(uint32_t proto_idx) { DCHECK(Runtime::Current()->IsMethodHandlesEnabled()); DCHECK_LT(proto_idx, GetDexFile()->NumProtoIds()); - const uint32_t slot_idx = proto_idx % kDexCacheMethodTypeCacheSize; - DCHECK_LT(slot_idx, NumResolvedMethodTypes()); - return slot_idx; -} - -inline MethodType* DexCache::GetResolvedMethodType(uint32_t proto_idx) { - return GetResolvedMethodTypes()[MethodTypeSlotIndex(proto_idx)].load( - std::memory_order_relaxed).GetObjectForIndex(proto_idx); + return MethodTypeDexCachePair::Lookup( + GetResolvedMethodTypes(), proto_idx, NumResolvedMethodTypes()).Read(); } inline void DexCache::SetResolvedMethodType(uint32_t proto_idx, MethodType* resolved) { - DCHECK(resolved != nullptr); - GetResolvedMethodTypes()[MethodTypeSlotIndex(proto_idx)].store( - MethodTypeDexCachePair(resolved, proto_idx), std::memory_order_relaxed); + DCHECK(Runtime::Current()->IsMethodHandlesEnabled()); + DCHECK_LT(proto_idx, GetDexFile()->NumProtoIds()); + + MethodTypeDexCachePair::Assign(GetResolvedMethodTypes(), proto_idx, resolved, + NumResolvedMethodTypes()); // TODO: Fine-grained marking, so that we don't need to go through all arrays in full. Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(this); } @@ -256,13 +228,15 @@ inline void DexCache::VisitReferences(ObjPtr<Class> klass, const Visitor& visito VisitInstanceFieldsReferences<kVerifyFlags, kReadBarrierOption>(klass, visitor); // Visit arrays after. if (kVisitNativeRoots) { - VisitDexCachePairs<String, kReadBarrierOption, Visitor>( + VisitDexCachePairs<mirror::String, kReadBarrierOption, Visitor>( GetStrings(), NumStrings(), visitor); - VisitDexCachePairs<Class, kReadBarrierOption, Visitor>( - GetResolvedTypes(), NumResolvedTypes(), visitor); + GcRoot<mirror::Class>* resolved_types = GetResolvedTypes(); + for (size_t i = 0, num_types = NumResolvedTypes(); i != num_types; ++i) { + visitor.VisitRootIfNonNull(resolved_types[i].AddressWithoutBarrier()); + } - VisitDexCachePairs<MethodType, kReadBarrierOption, Visitor>( + VisitDexCachePairs<mirror::MethodType, kReadBarrierOption, Visitor>( GetResolvedMethodTypes(), NumResolvedMethodTypes(), visitor); GcRoot<mirror::CallSite>* resolved_call_sites = GetResolvedCallSites(); @@ -273,37 +247,35 @@ inline void DexCache::VisitReferences(ObjPtr<Class> klass, const Visitor& visito } template <ReadBarrierOption kReadBarrierOption, typename Visitor> -inline void DexCache::FixupStrings(StringDexCacheType* dest, const Visitor& visitor) { - StringDexCacheType* src = GetStrings(); +inline void DexCache::FixupStrings(mirror::StringDexCacheType* dest, const Visitor& visitor) { + mirror::StringDexCacheType* src = GetStrings(); for (size_t i = 0, count = NumStrings(); i < count; ++i) { StringDexCachePair source = src[i].load(std::memory_order_relaxed); - String* ptr = source.object.Read<kReadBarrierOption>(); - String* new_source = visitor(ptr); + mirror::String* ptr = source.object.Read<kReadBarrierOption>(); + mirror::String* new_source = visitor(ptr); source.object = GcRoot<String>(new_source); dest[i].store(source, std::memory_order_relaxed); } } template <ReadBarrierOption kReadBarrierOption, typename Visitor> -inline void DexCache::FixupResolvedTypes(TypeDexCacheType* dest, const Visitor& visitor) { - TypeDexCacheType* src = GetResolvedTypes(); +inline void DexCache::FixupResolvedTypes(GcRoot<mirror::Class>* dest, const Visitor& visitor) { + GcRoot<mirror::Class>* src = GetResolvedTypes(); for (size_t i = 0, count = NumResolvedTypes(); i < count; ++i) { - TypeDexCachePair source = src[i].load(std::memory_order_relaxed); - Class* ptr = source.object.Read<kReadBarrierOption>(); - Class* new_source = visitor(ptr); - source.object = GcRoot<Class>(new_source); - dest[i].store(source, std::memory_order_relaxed); + mirror::Class* source = src[i].Read<kReadBarrierOption>(); + mirror::Class* new_source = visitor(source); + dest[i] = GcRoot<mirror::Class>(new_source); } } template <ReadBarrierOption kReadBarrierOption, typename Visitor> -inline void DexCache::FixupResolvedMethodTypes(MethodTypeDexCacheType* dest, +inline void DexCache::FixupResolvedMethodTypes(mirror::MethodTypeDexCacheType* dest, const Visitor& visitor) { - MethodTypeDexCacheType* src = GetResolvedMethodTypes(); + mirror::MethodTypeDexCacheType* src = GetResolvedMethodTypes(); for (size_t i = 0, count = NumResolvedMethodTypes(); i < count; ++i) { MethodTypeDexCachePair source = src[i].load(std::memory_order_relaxed); - MethodType* ptr = source.object.Read<kReadBarrierOption>(); - MethodType* new_source = visitor(ptr); + mirror::MethodType* ptr = source.object.Read<kReadBarrierOption>(); + mirror::MethodType* new_source = visitor(ptr); source.object = GcRoot<MethodType>(new_source); dest[i].store(source, std::memory_order_relaxed); } diff --git a/runtime/mirror/dex_cache.cc b/runtime/mirror/dex_cache.cc index 1b8b3913b9..0f6acab7e1 100644 --- a/runtime/mirror/dex_cache.cc +++ b/runtime/mirror/dex_cache.cc @@ -58,8 +58,8 @@ void DexCache::InitializeDexCache(Thread* self, mirror::StringDexCacheType* strings = (dex_file->NumStringIds() == 0u) ? nullptr : reinterpret_cast<mirror::StringDexCacheType*>(raw_arrays + layout.StringsOffset()); - mirror::TypeDexCacheType* types = (dex_file->NumTypeIds() == 0u) ? nullptr : - reinterpret_cast<mirror::TypeDexCacheType*>(raw_arrays + layout.TypesOffset()); + 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 : @@ -69,10 +69,6 @@ void DexCache::InitializeDexCache(Thread* self, if (dex_file->NumStringIds() < num_strings) { num_strings = dex_file->NumStringIds(); } - size_t num_types = mirror::DexCache::kDexCacheTypeCacheSize; - if (dex_file->NumTypeIds() < num_types) { - num_types = dex_file->NumTypeIds(); - } // Note that we allocate the method type dex caches regardless of this flag, // and we make sure here that they're not used by the runtime. This is in the @@ -112,9 +108,8 @@ void DexCache::InitializeDexCache(Thread* self, CHECK_EQ(strings[i].load(std::memory_order_relaxed).index, 0u); CHECK(strings[i].load(std::memory_order_relaxed).object.IsNull()); } - for (size_t i = 0; i < num_types; ++i) { - CHECK_EQ(types[i].load(std::memory_order_relaxed).index, 0u); - CHECK(types[i].load(std::memory_order_relaxed).object.IsNull()); + for (size_t i = 0; i < dex_file->NumTypeIds(); ++i) { + CHECK(types[i].IsNull()); } for (size_t i = 0; i < dex_file->NumMethodIds(); ++i) { CHECK(mirror::DexCache::GetElementPtrSize(methods, i, image_pointer_size) == nullptr); @@ -133,9 +128,6 @@ void DexCache::InitializeDexCache(Thread* self, if (strings != nullptr) { mirror::StringDexCachePair::Initialize(strings); } - if (types != nullptr) { - mirror::TypeDexCachePair::Initialize(types); - } if (method_types != nullptr) { mirror::MethodTypeDexCachePair::Initialize(method_types); } @@ -144,7 +136,7 @@ void DexCache::InitializeDexCache(Thread* self, strings, num_strings, types, - num_types, + dex_file->NumTypeIds(), methods, dex_file->NumMethodIds(), fields, @@ -160,7 +152,7 @@ void DexCache::Init(const DexFile* dex_file, ObjPtr<String> location, StringDexCacheType* strings, uint32_t num_strings, - TypeDexCacheType* resolved_types, + GcRoot<Class>* resolved_types, uint32_t num_resolved_types, ArtMethod** resolved_methods, uint32_t num_resolved_methods, diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h index 057919806f..10bb5aa01c 100644 --- a/runtime/mirror/dex_cache.h +++ b/runtime/mirror/dex_cache.h @@ -18,14 +18,14 @@ #define ART_RUNTIME_MIRROR_DEX_CACHE_H_ #include "array.h" -#include "base/bit_utils.h" +#include "art_field.h" +#include "class.h" #include "dex_file_types.h" #include "object.h" #include "object_array.h" namespace art { -class ArtField; class ArtMethod; struct DexCacheOffsets; class DexFile; @@ -37,7 +37,6 @@ class Thread; namespace mirror { class CallSite; -class Class; class MethodType; class String; @@ -62,7 +61,7 @@ template <typename T> struct PACKED(8) DexCachePair { // it's always non-null if the id branch succeeds (except for the 0th id). // Set the initial state for the 0th entry to be {0,1} which is guaranteed to fail // the lookup id == stored id branch. - DexCachePair(ObjPtr<T> object, uint32_t index) + DexCachePair(T* object, uint32_t index) : object(object), index(index) {} DexCachePair() = default; @@ -76,28 +75,39 @@ template <typename T> struct PACKED(8) DexCachePair { dex_cache[0].store(first_elem, std::memory_order_relaxed); } + static GcRoot<T> Lookup(std::atomic<DexCachePair<T>>* dex_cache, + uint32_t idx, + uint32_t cache_size) { + DCHECK_NE(cache_size, 0u); + DexCachePair<T> element = dex_cache[idx % cache_size].load(std::memory_order_relaxed); + if (idx != element.index) { + return GcRoot<T>(nullptr); + } + + DCHECK(!element.object.IsNull()); + return element.object; + } + + static void Assign(std::atomic<DexCachePair<T>>* dex_cache, + uint32_t idx, + T* object, + uint32_t cache_size) { + DCHECK_LT(idx % cache_size, cache_size); + dex_cache[idx % cache_size].store( + DexCachePair<T>(object, idx), std::memory_order_relaxed); + } + static uint32_t InvalidIndexForSlot(uint32_t slot) { // Since the cache size is a power of two, 0 will always map to slot 0. // Use 1 for slot 0 and 0 for all other slots. return (slot == 0) ? 1u : 0u; } - - T* GetObjectForIndex(uint32_t idx) REQUIRES_SHARED(Locks::mutator_lock_) { - if (idx != index) { - return nullptr; - } - DCHECK(!object.IsNull()); - return object.Read(); - } }; -using TypeDexCachePair = DexCachePair<Class>; -using TypeDexCacheType = std::atomic<TypeDexCachePair>; - -using StringDexCachePair = DexCachePair<String>; +using StringDexCachePair = DexCachePair<mirror::String>; using StringDexCacheType = std::atomic<StringDexCachePair>; -using MethodTypeDexCachePair = DexCachePair<MethodType>; +using MethodTypeDexCachePair = DexCachePair<mirror::MethodType>; using MethodTypeDexCacheType = std::atomic<MethodTypeDexCachePair>; // C++ mirror of java.lang.DexCache. @@ -106,11 +116,6 @@ class MANAGED DexCache FINAL : public Object { // Size of java.lang.DexCache.class. static uint32_t ClassSize(PointerSize pointer_size); - // Size of type dex cache. Needs to be a power of 2 for entrypoint assumptions to hold. - static constexpr size_t kDexCacheTypeCacheSize = 1024; - static_assert(IsPowerOfTwo(kDexCacheTypeCacheSize), - "Type dex cache size is not a power of 2."); - // Size of string dex cache. Needs to be a power of 2 for entrypoint assumptions to hold. static constexpr size_t kDexCacheStringCacheSize = 1024; static_assert(IsPowerOfTwo(kDexCacheStringCacheSize), @@ -122,10 +127,6 @@ class MANAGED DexCache FINAL : public Object { static_assert(IsPowerOfTwo(kDexCacheMethodTypeCacheSize), "MethodType dex cache size is not a power of 2."); - static constexpr size_t StaticTypeSize() { - return kDexCacheTypeCacheSize; - } - static constexpr size_t StaticStringSize() { return kDexCacheStringCacheSize; } @@ -156,7 +157,7 @@ class MANAGED DexCache FINAL : public Object { REQUIRES_SHARED(Locks::mutator_lock_); template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier, typename Visitor> - void FixupResolvedTypes(TypeDexCacheType* dest, const Visitor& visitor) + void FixupResolvedTypes(GcRoot<mirror::Class>* dest, const Visitor& visitor) REQUIRES_SHARED(Locks::mutator_lock_); template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier, typename Visitor> @@ -223,7 +224,7 @@ class MANAGED DexCache FINAL : public Object { return OFFSET_OF_OBJECT_MEMBER(DexCache, num_resolved_call_sites_); } - String* GetResolvedString(dex::StringIndex string_idx) ALWAYS_INLINE + mirror::String* GetResolvedString(dex::StringIndex string_idx) ALWAYS_INLINE REQUIRES_SHARED(Locks::mutator_lock_); void SetResolvedString(dex::StringIndex string_idx, ObjPtr<mirror::String> resolved) ALWAYS_INLINE @@ -238,8 +239,6 @@ class MANAGED DexCache FINAL : public Object { void SetResolvedType(dex::TypeIndex type_idx, ObjPtr<Class> resolved) REQUIRES_SHARED(Locks::mutator_lock_); - void ClearResolvedType(dex::TypeIndex type_idx) REQUIRES_SHARED(Locks::mutator_lock_); - ALWAYS_INLINE ArtMethod* GetResolvedMethod(uint32_t method_idx, PointerSize ptr_size) REQUIRES_SHARED(Locks::mutator_lock_); @@ -279,11 +278,11 @@ class MANAGED DexCache FINAL : public Object { SetFieldPtr<false>(StringsOffset(), strings); } - TypeDexCacheType* GetResolvedTypes() ALWAYS_INLINE REQUIRES_SHARED(Locks::mutator_lock_) { - return GetFieldPtr<TypeDexCacheType*>(ResolvedTypesOffset()); + GcRoot<Class>* GetResolvedTypes() ALWAYS_INLINE REQUIRES_SHARED(Locks::mutator_lock_) { + return GetFieldPtr<GcRoot<Class>*>(ResolvedTypesOffset()); } - void SetResolvedTypes(TypeDexCacheType* resolved_types) + void SetResolvedTypes(GcRoot<Class>* resolved_types) ALWAYS_INLINE REQUIRES_SHARED(Locks::mutator_lock_) { SetFieldPtr<false>(ResolvedTypesOffset(), resolved_types); @@ -364,7 +363,7 @@ class MANAGED DexCache FINAL : public Object { SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, dex_file_), dex_file); } - void SetLocation(ObjPtr<String> location) REQUIRES_SHARED(Locks::mutator_lock_); + void SetLocation(ObjPtr<mirror::String> location) REQUIRES_SHARED(Locks::mutator_lock_); // NOTE: Get/SetElementPtrSize() are intended for working with ArtMethod** and ArtField** // provided by GetResolvedMethods/Fields() and ArtMethod::GetDexCacheResolvedMethods(), @@ -381,7 +380,7 @@ class MANAGED DexCache FINAL : public Object { ObjPtr<String> location, StringDexCacheType* strings, uint32_t num_strings, - TypeDexCacheType* resolved_types, + GcRoot<Class>* resolved_types, uint32_t num_resolved_types, ArtMethod** resolved_methods, uint32_t num_resolved_methods, @@ -394,16 +393,12 @@ class MANAGED DexCache FINAL : public Object { PointerSize pointer_size) REQUIRES_SHARED(Locks::mutator_lock_); - uint32_t StringSlotIndex(dex::StringIndex string_idx) REQUIRES_SHARED(Locks::mutator_lock_); - uint32_t TypeSlotIndex(dex::TypeIndex type_idx) REQUIRES_SHARED(Locks::mutator_lock_); - uint32_t MethodTypeSlotIndex(uint32_t proto_idx) REQUIRES_SHARED(Locks::mutator_lock_); - // Visit instance fields of the dex cache as well as its associated arrays. template <bool kVisitNativeRoots, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, ReadBarrierOption kReadBarrierOption = kWithReadBarrier, typename Visitor> - void VisitReferences(ObjPtr<Class> klass, const Visitor& visitor) + void VisitReferences(ObjPtr<mirror::Class> klass, const Visitor& visitor) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_); HeapReference<Object> dex_; @@ -415,7 +410,7 @@ class MANAGED DexCache FINAL : public Object { uint64_t resolved_method_types_; // std::atomic<MethodTypeDexCachePair>* array with // num_resolved_method_types_ elements. uint64_t resolved_methods_; // ArtMethod*, array with num_resolved_methods_ elements. - uint64_t resolved_types_; // TypeDexCacheType*, array with num_resolved_types_ elements. + uint64_t resolved_types_; // GcRoot<Class>*, array with num_resolved_types_ elements. uint64_t strings_; // std::atomic<StringDexCachePair>*, array with num_strings_ // elements. diff --git a/runtime/mirror/dex_cache_test.cc b/runtime/mirror/dex_cache_test.cc index ef0aaaaa70..5a2ab7151c 100644 --- a/runtime/mirror/dex_cache_test.cc +++ b/runtime/mirror/dex_cache_test.cc @@ -51,8 +51,7 @@ TEST_F(DexCacheTest, Open) { EXPECT_TRUE(dex_cache->StaticStringSize() == dex_cache->NumStrings() || java_lang_dex_file_->NumStringIds() == dex_cache->NumStrings()); - EXPECT_TRUE(dex_cache->StaticTypeSize() == dex_cache->NumResolvedTypes() - || java_lang_dex_file_->NumTypeIds() == dex_cache->NumResolvedTypes()); + EXPECT_EQ(java_lang_dex_file_->NumTypeIds(), dex_cache->NumResolvedTypes()); EXPECT_EQ(java_lang_dex_file_->NumMethodIds(), dex_cache->NumResolvedMethods()); EXPECT_EQ(java_lang_dex_file_->NumFieldIds(), dex_cache->NumResolvedFields()); EXPECT_TRUE(dex_cache->StaticMethodTypeSize() == dex_cache->NumResolvedMethodTypes() diff --git a/runtime/native/java_lang_DexCache.cc b/runtime/native/java_lang_DexCache.cc index 8fda4dfaaf..ada3a9d558 100644 --- a/runtime/native/java_lang_DexCache.cc +++ b/runtime/native/java_lang_DexCache.cc @@ -53,7 +53,7 @@ static jobject DexCache_getDexNative(JNIEnv* env, jobject javaDexCache) { static jobject DexCache_getResolvedType(JNIEnv* env, jobject javaDexCache, jint type_index) { ScopedFastNativeObjectAccess soa(env); ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache); - CHECK_LT(static_cast<size_t>(type_index), dex_cache->GetDexFile()->NumTypeIds()); + CHECK_LT(static_cast<size_t>(type_index), dex_cache->NumResolvedTypes()); return soa.AddLocalReference<jobject>(dex_cache->GetResolvedType(dex::TypeIndex(type_index))); } diff --git a/runtime/oat.h b/runtime/oat.h index 1544121ed1..656b86812e 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -32,7 +32,7 @@ class InstructionSetFeatures; class PACKED(4) OatHeader { public: static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' }; - static constexpr uint8_t kOatVersion[] = { '1', '1', '4', '\0' }; // hash-based DexCache types. + static constexpr uint8_t kOatVersion[] = { '1', '1', '3', '\0' }; // Invoke info change. static constexpr const char* kImageLocationKey = "image-location"; static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline"; diff --git a/runtime/utils/dex_cache_arrays_layout-inl.h b/runtime/utils/dex_cache_arrays_layout-inl.h index f9a1405354..98658215f7 100644 --- a/runtime/utils/dex_cache_arrays_layout-inl.h +++ b/runtime/utils/dex_cache_arrays_layout-inl.h @@ -51,11 +51,9 @@ inline DexCacheArraysLayout::DexCacheArraysLayout(PointerSize pointer_size, cons : DexCacheArraysLayout(pointer_size, dex_file->GetHeader(), dex_file->NumCallSiteIds()) { } -constexpr size_t DexCacheArraysLayout::Alignment() { - // mirror::Type/String/MethodTypeDexCacheType alignment is 8, - // i.e. higher than or equal to the pointer alignment. - static_assert(alignof(mirror::TypeDexCacheType) == 8, - "Expecting alignof(ClassDexCacheType) == 8"); +inline constexpr size_t DexCacheArraysLayout::Alignment() { + // GcRoot<> alignment is 4, i.e. lower than or equal to the pointer alignment. + static_assert(alignof(GcRoot<mirror::Class>) == 4, "Expecting alignof(GcRoot<>) == 4"); static_assert(alignof(mirror::StringDexCacheType) == 8, "Expecting alignof(StringDexCacheType) == 8"); static_assert(alignof(mirror::MethodTypeDexCacheType) == 8, @@ -65,22 +63,17 @@ constexpr size_t DexCacheArraysLayout::Alignment() { } template <typename T> -constexpr PointerSize GcRootAsPointerSize() { +static constexpr PointerSize GcRootAsPointerSize() { static_assert(sizeof(GcRoot<T>) == 4U, "Unexpected GcRoot size"); return PointerSize::k32; } inline size_t DexCacheArraysLayout::TypeOffset(dex::TypeIndex type_idx) const { - return types_offset_ + ElementOffset(PointerSize::k64, - type_idx.index_ % mirror::DexCache::kDexCacheTypeCacheSize); + return types_offset_ + ElementOffset(GcRootAsPointerSize<mirror::Class>(), type_idx.index_); } inline size_t DexCacheArraysLayout::TypesSize(size_t num_elements) const { - size_t cache_size = mirror::DexCache::kDexCacheTypeCacheSize; - if (num_elements < cache_size) { - cache_size = num_elements; - } - return ArraySize(PointerSize::k64, cache_size); + return ArraySize(GcRootAsPointerSize<mirror::Class>(), num_elements); } inline size_t DexCacheArraysLayout::TypesAlignment() const { diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 38d151bc67..16739fa3bc 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -2399,8 +2399,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { const RegType& res_type = ResolveClassAndCheckAccess(type_idx); if (res_type.IsConflict()) { // If this is a primitive type, fail HARD. - ObjPtr<mirror::Class> klass = - ClassLinker::LookupResolvedType(type_idx, dex_cache_.Get(), class_loader_.Get()); + mirror::Class* klass = dex_cache_->GetResolvedType(type_idx); if (klass != nullptr && klass->IsPrimitive()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "using primitive type " << dex_file_->StringByTypeIdx(type_idx) << " in instanceof in " @@ -3723,16 +3722,9 @@ inline bool MethodVerifier::IsInstantiableOrPrimitive(mirror::Class* klass) { } const RegType& MethodVerifier::ResolveClassAndCheckAccess(dex::TypeIndex class_idx) { - mirror::Class* klass = can_load_classes_ - ? Runtime::Current()->GetClassLinker()->ResolveType( - *dex_file_, class_idx, dex_cache_, class_loader_) - : ClassLinker::LookupResolvedType(class_idx, dex_cache_.Get(), class_loader_.Get()).Ptr(); - if (can_load_classes_ && klass == nullptr) { - DCHECK(self_->IsExceptionPending()); - self_->ClearException(); - } + mirror::Class* klass = dex_cache_->GetResolvedType(class_idx); const RegType* result = nullptr; - if (klass != nullptr && !klass->IsErroneous()) { + if (klass != nullptr) { bool precise = klass->CannotBeAssignedFromOtherTypes(); if (precise && !IsInstantiableOrPrimitive(klass)) { const char* descriptor = dex_file_->StringByTypeIdx(class_idx); @@ -3755,6 +3747,10 @@ const RegType& MethodVerifier::ResolveClassAndCheckAccess(dex::TypeIndex class_i << "' in " << GetDeclaringClass(); return *result; } + if (klass == nullptr && !result->IsUnresolvedTypes()) { + klass = result->GetClass(); + dex_cache_->SetResolvedType(class_idx, klass); + } // Record result of class resolution attempt. VerifierDeps::MaybeRecordClassResolution(*dex_file_, class_idx, klass); diff --git a/test/155-java-set-resolved-type/src/Main.java b/test/155-java-set-resolved-type/src/Main.java index 56b8c3ece9..f92363e915 100644 --- a/test/155-java-set-resolved-type/src/Main.java +++ b/test/155-java-set-resolved-type/src/Main.java @@ -55,7 +55,11 @@ public class Main { Class<?> timpl = Class.forName("TestImplementation", false, mainLoader); // Clear the dex cache resolved types to force a proper lookup the next time // we need to find TestInterface. - clearResolvedTypes(timpl); + // TODO: Enable clearing the dex cache when we switch to the hash-based type array + // and do a proper lookup. Currently, ClassLinker fully relies on the DexCache. + if (false) { + clearResolvedTypes(timpl); + } // Force intialization of TestClass2. This expects the interface type to be // resolved and found through simple lookup. diff --git a/test/157-void-class/src/Main.java b/test/157-void-class/src/Main.java index 322b705f1d..0a052e774d 100644 --- a/test/157-void-class/src/Main.java +++ b/test/157-void-class/src/Main.java @@ -35,7 +35,11 @@ public class Main { } // Clear the resolved types of the ojluni dex file to make sure there is no entry // for "V", i.e. void. - clearResolvedTypes(Integer.class); + // TODO: Enable clearing the dex cache when we switch to the hash-based type array + // and do a proper lookup. Currently, ClassLinker fully relies on the DexCache. + if (false) { + clearResolvedTypes(Integer.class); + } // With java.lang.Void being compile-time verified but uninitialized, initialize // it now. Previously, this would indirectly initialize TYPE with the current, // i.e. zero-initialized, value of TYPE. The only thing that could prevent the diff --git a/test/626-const-class-linking/clear_dex_cache_types.cc b/test/626-const-class-linking/clear_dex_cache_types.cc index e1af02edfd..b35dff48ee 100644 --- a/test/626-const-class-linking/clear_dex_cache_types.cc +++ b/test/626-const-class-linking/clear_dex_cache_types.cc @@ -27,8 +27,7 @@ extern "C" JNIEXPORT void JNICALL Java_Main_nativeClearResolvedTypes(JNIEnv*, jc ScopedObjectAccess soa(Thread::Current()); mirror::DexCache* dex_cache = soa.Decode<mirror::Class>(cls)->GetDexCache(); for (size_t i = 0, num_types = dex_cache->NumResolvedTypes(); i != num_types; ++i) { - mirror::TypeDexCachePair cleared(nullptr, mirror::TypeDexCachePair::InvalidIndexForSlot(i)); - dex_cache->GetResolvedTypes()[i].store(cleared, std::memory_order_relaxed); + dex_cache->SetResolvedType(dex::TypeIndex(i), ObjPtr<mirror::Class>(nullptr)); } } |