From d16363a93053de0f32252c7897d839a46aff14ae Mon Sep 17 00:00:00 2001 From: Vladimir Marko Date: Wed, 1 Feb 2017 14:09:13 +0000 Subject: [PATCH] Revert "Hash-based dex cache type array." Reverting to work around some programs crashing with Check failed: handle_scope_iface.Get() != nullptr. though the reason for the failure not yet understood. Test: m test-art-host Bug: 34839984 Bug: 30627598 Bug: 34659969 Bug: 30419309 This reverts commit ec7862283dd49f5a58d0ac45960ce27c2f7671b8. Change-Id: Ifded663633082f1e59e5b6ff2e026dc559bd6b82 --- compiler/compiler.h | 3 +- compiler/dex/dex_to_dex_compiler.cc | 7 +- compiler/dex/dex_to_dex_compiler.h | 7 +- compiler/driver/compiler_driver-inl.h | 13 ++- compiler/driver/compiler_driver.cc | 123 +++++++++------------ compiler/driver/compiler_driver.h | 14 ++- compiler/driver/compiler_driver_test.cc | 1 - compiler/driver/dex_compilation_unit.cc | 2 +- compiler/driver/dex_compilation_unit.h | 8 +- compiler/image_writer.cc | 11 +- compiler/image_writer.h | 10 -- compiler/oat_writer.cc | 16 +-- compiler/optimizing/builder.h | 15 +-- compiler/optimizing/inliner.cc | 45 ++++---- compiler/optimizing/instruction_builder.cc | 49 ++++---- compiler/optimizing/instruction_builder.h | 11 +- compiler/optimizing/optimizing_compiler.cc | 26 ++++- compiler/optimizing/reference_type_propagation.cc | 46 ++++---- compiler/optimizing/reference_type_propagation.h | 3 - .../optimizing/reference_type_propagation_test.cc | 1 - compiler/optimizing/ssa_builder.cc | 6 +- compiler/optimizing/ssa_builder.h | 3 - oatdump/oatdump.cc | 12 +- patchoat/patchoat.cc | 4 +- runtime/art_field-inl.h | 15 +-- runtime/art_field.cc | 4 + runtime/art_field.h | 2 + runtime/art_method-inl.h | 13 +-- runtime/class_linker-inl.h | 31 ++++-- runtime/class_linker.cc | 77 ++++++------- runtime/class_linker.h | 8 +- runtime/class_linker_test.cc | 8 +- runtime/entrypoints/entrypoint_utils-inl.h | 8 +- runtime/gc/space/image_space.cc | 4 +- runtime/image.cc | 2 +- runtime/interpreter/interpreter_common.cc | 22 ++-- runtime/mirror/class.cc | 3 +- runtime/mirror/dex_cache-inl.h | 110 +++++++----------- runtime/mirror/dex_cache.cc | 20 +--- runtime/mirror/dex_cache.h | 77 ++++++------- runtime/mirror/dex_cache_test.cc | 3 +- runtime/native/java_lang_DexCache.cc | 14 +-- runtime/oat.h | 2 +- runtime/utils/dex_cache_arrays_layout-inl.h | 19 +--- runtime/verifier/method_verifier.cc | 8 +- .../clear_dex_cache_types.cc | 3 +- 46 files changed, 384 insertions(+), 505 deletions(-) diff --git a/compiler/compiler.h b/compiler/compiler.h index 908d3669e..2ca0b77a7 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 class_loader, + jobject class_loader, const DexFile& dex_file, Handle dex_cache) const = 0; diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index 76aeaa55d..d4f6545c5 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 class_loader(hs.NewHandle( + soa.Decode(unit_.GetClassLoader()))); ClassLinker* class_linker = unit_.GetClassLinker(); ArtMethod* resolved_method = class_linker->ResolveMethod( 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 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 00c596d60..0a00d4529 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 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 81d80f4f8..f056dd3c0 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(mUnit->GetClassLoader()).Ptr(); +} + inline mirror::Class* CompilerDriver::ResolveClass( const ScopedObjectAccess& soa, Handle dex_cache, Handle 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 dex_cache, Handle 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 dex_cache, Handle 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); } @@ -193,7 +198,7 @@ inline ArtMethod* CompilerDriver::ResolveMethod( ScopedObjectAccess& soa, Handle dex_cache, Handle 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( diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 4e19dbe94..1d4eaf8c5 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -583,7 +583,7 @@ static void CompileMethod(Thread* self, InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, - Handle class_loader, + jobject class_loader, const DexFile& dex_file, optimizer::DexToDexCompilationLevel dex_to_dex_compilation_level, bool compilation_enabled, @@ -624,6 +624,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 class_loader_handle(hs.NewHandle( + soa.Decode(class_loader))); // TODO: Lookup annotation from DexFile directly without resolving method. ArtMethod* method = @@ -631,7 +634,7 @@ static void CompileMethod(Thread* self, dex_file, method_idx, dex_cache, - class_loader, + class_loader_handle, /* referrer */ nullptr, invoke_type); @@ -678,14 +681,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) { @@ -732,14 +730,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 dex_cache(hs.NewHandle(method->GetDexCache())); - Handle class_loader( - hs.NewHandle(method->GetDeclaringClass()->GetClassLoader())); { ScopedObjectAccessUnchecked soa(self); ScopedLocalRef local_class_loader( - soa.Env(), soa.AddLocalReference(class_loader.Get())); + soa.Env(), soa.AddLocalReference(method->GetDeclaringClass()->GetClassLoader())); jclass_loader = soa.Env()->NewGlobalRef(local_class_loader.get()); // Find the dex_file dex_file = method->GetDexFile(); @@ -773,7 +769,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, @@ -799,7 +795,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, @@ -1074,30 +1070,22 @@ bool CompilerDriver::ShouldCompileBasedOnProfile(const MethodReference& method_r class ResolveCatchBlockExceptionsClassVisitor : public ClassVisitor { public: - ResolveCatchBlockExceptionsClassVisitor() : classes_() {} + explicit ResolveCatchBlockExceptionsClassVisitor( + std::set>& exceptions_to_resolve) + : exceptions_to_resolve_(exceptions_to_resolve) {} virtual bool operator()(ObjPtr c) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { - classes_.push_back(c); - return true; - } - - void FindExceptionTypesToResolve( - std::set>* exceptions_to_resolve) - REQUIRES_SHARED(Locks::mutator_lock_) { const auto pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); - for (ObjPtr 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>* 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 } @@ -1117,9 +1105,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); @@ -1131,7 +1119,7 @@ class ResolveCatchBlockExceptionsClassVisitor : public ClassVisitor { } } - std::vector> classes_; + std::set>& exceptions_to_resolve_; }; class RecordImageClassesVisitor : public ClassVisitor { @@ -1185,14 +1173,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>. - 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; @@ -1441,14 +1423,19 @@ void CompilerDriver::MarkForDexToDexCompilation(Thread* self, const MethodRefere dex_to_dex_references_.back().GetMethodIndexes().SetBit(method_ref.dex_method_index); } -bool CompilerDriver::CanAccessTypeWithoutChecks(ObjPtr referrer_class, - ObjPtr resolved_class) { +bool CompilerDriver::CanAccessTypeWithoutChecks(uint32_t referrer_idx, + Handle 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. @@ -1465,9 +1452,12 @@ bool CompilerDriver::CanAccessTypeWithoutChecks(ObjPtr referrer_c return is_accessible; } -bool CompilerDriver::CanAccessInstantiableTypeWithoutChecks(ObjPtr referrer_class, - ObjPtr resolved_class, +bool CompilerDriver::CanAccessInstantiableTypeWithoutChecks(uint32_t referrer_idx, + Handle 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. @@ -1475,8 +1465,10 @@ bool CompilerDriver::CanAccessInstantiableTypeWithoutChecks(ObjPtrIsFinalizable(); + 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. @@ -1520,7 +1512,9 @@ ArtField* CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, mirror::Class* referrer_class; Handle dex_cache(mUnit->GetDexCache()); { - Handle class_loader_handle = mUnit->GetClassLoader(); + StackHandleScope<1> hs(soa.Self()); + Handle class_loader_handle( + hs.NewHandle(soa.Decode(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; @@ -2593,18 +2587,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 @@ -2618,17 +2604,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 d032a26fd..503fe3adf 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 referrer_class, - ObjPtr resolved_class) + bool CanAccessTypeWithoutChecks(uint32_t referrer_idx, + Handle 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 referrer_class, - ObjPtr resolved_class, + bool CanAccessInstantiableTypeWithoutChecks(uint32_t referrer_idx, + Handle dex_cache, + dex::TypeIndex type_idx, bool* out_is_finalizable) REQUIRES_SHARED(Locks::mutator_lock_); @@ -404,6 +406,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& dex_files, diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc index e4b66ebc5..1e4ca1684 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 7e8e812c4..47b19297e 100644 --- a/compiler/driver/dex_compilation_unit.cc +++ b/compiler/driver/dex_compilation_unit.cc @@ -21,7 +21,7 @@ namespace art { -DexCompilationUnit::DexCompilationUnit(Handle 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 24a9a5b65..854927d74 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 { public: - DexCompilationUnit(Handle 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 { const VerifiedMethod* verified_method, Handle dex_cache); - Handle GetClassLoader() const { + jobject GetClassLoader() const { return class_loader_; } @@ -113,7 +113,7 @@ class DexCompilationUnit : public DeletableArenaObject { } private: - const Handle class_loader_; + const jobject class_loader_; ClassLinker* const class_linker_; @@ -125,7 +125,7 @@ class DexCompilationUnit : public DeletableArenaObject { const uint32_t access_flags_; const VerifiedMethod* verified_method_; - const Handle dex_cache_; + Handle dex_cache_; std::string symbol_; }; diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 3e9ae0834..c72edb18a 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -940,11 +940,9 @@ void ImageWriter::PruneNonImageClasses() { } ObjPtr 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(); @@ -1924,7 +1922,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 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)); @@ -2214,7 +2213,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* orig_types = orig_dex_cache->GetResolvedTypes(); if (orig_types != nullptr) { copy_dex_cache->SetFieldPtrWithSize(mirror::DexCache::ResolvedTypesOffset(), NativeLocationInImage(orig_types), diff --git a/compiler/image_writer.h b/compiler/image_writer.h index bdc714663..cc7df1ce2 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 GetClassLoader() { - CHECK_EQ(class_loaders_.size(), compile_app_image_ ? 1u : 0u); - return compile_app_image_ ? *class_loaders_.begin() : nullptr; - } - template 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 227fdc487..bd2c5e3bf 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -1060,7 +1060,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()), @@ -1246,13 +1245,12 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { } private: - ObjPtr class_loader_; OutputStream* const out_; const size_t file_offset_; const ScopedObjectAccess soa_; const ScopedAssertNoThreadSuspension no_thread_suspension_; ClassLinker* const class_linker_; - ObjPtr dex_cache_; + mirror::DexCache* dex_cache_; std::vector patched_code_; void ReportWriteFailure(const char* what, const ClassDataItemIterator& it) { @@ -1263,7 +1261,7 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { ArtMethod* GetTargetMethod(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) { MethodReference ref = patch.TargetMethod(); - ObjPtr dex_cache = + mirror::DexCache* dex_cache = (dex_file_ == ref.dex_file) ? dex_cache_ : class_linker_->FindDexCache( Thread::Current(), *ref.dex_file); ArtMethod* method = dex_cache->GetResolvedMethod( @@ -1297,7 +1295,7 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { return target_offset; } - ObjPtr GetDexCache(const DexFile* target_dex_file) + mirror::DexCache* GetDexCache(const DexFile* target_dex_file) REQUIRES_SHARED(Locks::mutator_lock_) { return (target_dex_file == dex_file_) ? dex_cache_ @@ -1305,12 +1303,10 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { } mirror::Class* GetTargetType(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK(writer_->HasImage()); - ObjPtr dex_cache = GetDexCache(patch.TargetTypeDexFile()); - ObjPtr type = - ClassLinker::LookupResolvedType(patch.TargetTypeIndex(), dex_cache, class_loader_); + mirror::DexCache* dex_cache = GetDexCache(patch.TargetTypeDexFile()); + 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 223439b0c..8cf4089eb 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -51,10 +51,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_, @@ -79,12 +76,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(nullptr), - handles->NewHandle(nullptr), - handles), + ssa_builder_(graph, null_dex_cache_, handles), instruction_builder_(graph, &block_builder_, &ssa_builder_, @@ -96,7 +91,7 @@ class HGraphBuilder : public ValueObject { /* compiler_driver */ nullptr, /* interpreter_metadata */ nullptr, /* compiler_stats */ nullptr, - handles->NewHandle(nullptr), + null_dex_cache_, handles) {} GraphAnalysisResult BuildGraph(); @@ -117,6 +112,8 @@ class HGraphBuilder : public ValueObject { CompilerDriver* const compiler_driver_; + ScopedNullHandle null_dex_cache_; + OptimizingCompilerStats* compilation_stats_; HBasicBlockBuilder block_builder_; diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 22f0646fd..7772e8f97 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -198,9 +198,9 @@ static uint32_t FindMethodIndexIn(ArtMethod* method, } static dex::TypeIndex FindClassIndexIn(mirror::Class* cls, - const DexCompilationUnit& compilation_unit) + const DexFile& dex_file, + Handle 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(); @@ -209,19 +209,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 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(); } } @@ -448,8 +451,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" @@ -492,7 +496,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); @@ -583,6 +586,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; @@ -604,7 +608,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, @@ -660,7 +665,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); @@ -855,7 +859,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); @@ -924,7 +927,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(); @@ -1177,11 +1179,7 @@ HInstanceFieldGet* HInliner::CreateInstanceFieldGet(Handle 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; @@ -1227,7 +1225,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, @@ -1343,7 +1341,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 3d911d77b..cac385ce3 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -668,10 +668,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 class_loader = dex_compilation_unit_->GetClassLoader(); + Handle class_loader(hs.NewHandle( + soa.Decode(dex_compilation_unit_->GetClassLoader()))); Handle 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. @@ -1283,7 +1284,9 @@ bool HInstructionBuilder::BuildInstanceFieldAccess(const Instruction& instructio static mirror::Class* GetClassFrom(CompilerDriver* driver, const DexCompilationUnit& compilation_unit) { ScopedObjectAccess soa(Thread::Current()); - Handle class_loader = compilation_unit.GetClassLoader(); + StackHandleScope<1> hs(soa.Self()); + Handle class_loader(hs.NewHandle( + soa.Decode(compilation_unit.GetClassLoader()))); Handle dex_cache = compilation_unit.GetDexCache(); return driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, &compilation_unit); @@ -1299,9 +1302,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 dex_cache = dex_compilation_unit_->GetDexCache(); - Handle class_loader = dex_compilation_unit_->GetClassLoader(); + Handle class_loader(hs.NewHandle( + soa.Decode(dex_compilation_unit_->GetClassLoader()))); Handle cls(hs.NewHandle(compiler_driver_->ResolveClass( soa, dex_cache, class_loader, type_index, dex_compilation_unit_))); Handle outer_class(hs.NewHandle(GetOutermostCompilingClass())); @@ -1339,8 +1343,10 @@ bool HInstructionBuilder::BuildStaticFieldAccess(const Instruction& instruction, uint16_t field_index = instruction.VRegB_21c(); ScopedObjectAccess soa(Thread::Current()); + StackHandleScope<3> hs(soa.Self()); Handle dex_cache = dex_compilation_unit_->GetDexCache(); - Handle class_loader = dex_compilation_unit_->GetClassLoader(); + Handle class_loader(hs.NewHandle( + soa.Decode(dex_compilation_unit_->GetClassLoader()))); ArtField* resolved_field = compiler_driver_->ResolveField( soa, dex_cache, class_loader, dex_compilation_unit_, field_index, true); @@ -1351,7 +1357,6 @@ bool HInstructionBuilder::BuildStaticFieldAccess(const Instruction& instruction, return true; } - StackHandleScope<2> hs(soa.Self()); Primitive::Type field_type = resolved_field->GetTypeAsPrimitiveType(); Handle outer_dex_cache = outer_compilation_unit_->GetDexCache(); Handle outer_class(hs.NewHandle(GetOutermostCompilingClass())); @@ -1630,7 +1635,9 @@ HLoadClass* HInstructionBuilder::BuildLoadClass(dex::TypeIndex type_index, const DexCompilationUnit* compilation_unit = outer ? outer_compilation_unit_ : dex_compilation_unit_; const DexFile& dex_file = *compilation_unit->GetDexFile(); - Handle class_loader = dex_compilation_unit_->GetClassLoader(); + StackHandleScope<1> hs(soa.Self()); + Handle class_loader(hs.NewHandle( + soa.Decode(dex_compilation_unit_->GetClassLoader()))); Handle klass = handles_->NewHandle(compiler_driver_->ResolveClass( soa, compilation_unit->GetDexCache(), class_loader, type_index, compilation_unit)); @@ -1685,9 +1692,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 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 dex_cache = dex_compilation_unit_->GetDexCache(); + return NeedsAccessCheck(type_index, dex_cache, finalizable); } bool HInstructionBuilder::CanDecodeQuickenedInfo() const { @@ -2727,18 +2742,4 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction, return true; } // NOLINT(readability/fn_size) -ObjPtr 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 HInstructionBuilder::LookupReferrerClass() const { - // TODO: Cache the result in a Handle. - 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 6e3b078db..5efe95094 100644 --- a/compiler/optimizing/instruction_builder.h +++ b/compiler/optimizing/instruction_builder.h @@ -103,8 +103,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 dex_cache, + /*out*/bool* finalizable) const REQUIRES_SHARED(Locks::mutator_lock_); + bool NeedsAccessCheck(dex::TypeIndex type_index, /*out*/bool* finalizable) const; template void Unop_12x(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc); @@ -287,12 +290,6 @@ class HInstructionBuilder : public ValueObject { // not be resolved. ArtMethod* ResolveMethod(uint16_t method_idx, InvokeType invoke_type); - ObjPtr LookupResolvedType(dex::TypeIndex type_index, - const DexCompilationUnit& compilation_unit) const - REQUIRES_SHARED(Locks::mutator_lock_); - - ObjPtr 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 dad87e3d9..297500b12 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -305,7 +305,7 @@ class OptimizingCompiler FINAL : public Compiler { InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, - Handle class_loader, + jobject class_loader, const DexFile& dex_file, Handle dex_cache) const OVERRIDE; @@ -374,7 +374,7 @@ class OptimizingCompiler FINAL : public Compiler { InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, - Handle class_loader, + jobject class_loader, const DexFile& dex_file, Handle dex_cache, ArtMethod* method, @@ -871,7 +871,7 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* arena, InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, - Handle class_loader, + jobject class_loader, const DexFile& dex_file, Handle dex_cache, ArtMethod* method, @@ -942,8 +942,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 loader(hs.NewHandle( + soa.Decode(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. @@ -952,6 +955,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 codegen( @@ -1031,7 +1044,7 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item, InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, - Handle jclass_loader, + jobject jclass_loader, const DexFile& dex_file, Handle dex_cache) const { CompilerDriver* compiler_driver = GetCompilerDriver(); @@ -1126,6 +1139,7 @@ bool OptimizingCompiler::JitCompile(Thread* self, Handle 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()); @@ -1149,7 +1163,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 be4857a49..b02f2509a 100644 --- a/compiler/optimizing/reference_type_propagation.cc +++ b/compiler/optimizing/reference_type_propagation.cc @@ -66,13 +66,11 @@ ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetThrowabl class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor { public: RTPVisitor(HGraph* graph, - Handle class_loader, Handle hint_dex_cache, HandleCache* handle_cache, ArenaVector* worklist, bool is_first_run) : HGraphDelegateVisitor(graph), - class_loader_(class_loader), hint_dex_cache_(hint_dex_cache), handle_cache_(handle_cache), worklist_(worklist), @@ -104,7 +102,6 @@ class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor { bool is_exact); private: - Handle class_loader_; Handle hint_dex_cache_; HandleCache* handle_cache_; ArenaVector* worklist_; @@ -112,13 +109,11 @@ class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor { }; ReferenceTypePropagation::ReferenceTypePropagation(HGraph* graph, - Handle class_loader, Handle 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)), @@ -153,12 +148,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); } @@ -332,12 +322,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,10 +542,9 @@ void ReferenceTypePropagation::RTPVisitor::UpdateReferenceTypeInfo(HInstruction* DCHECK_EQ(instr->GetType(), Primitive::kPrimNot); ScopedObjectAccess soa(Thread::Current()); - ObjPtr dex_cache = FindDexCacheWithHint(soa.Self(), dex_file, hint_dex_cache_); - ObjPtr klass = - ClassLinker::LookupResolvedType(type_idx, dex_cache, class_loader_.Get()); - SetClassAsTypeInfo(instr, klass, is_exact); + mirror::DexCache* dex_cache = FindDexCacheWithHint(soa.Self(), dex_file, hint_dex_cache_); + // 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) { @@ -573,13 +557,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 hint_dex_cache) + REQUIRES_SHARED(Locks::mutator_lock_) { + 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 215e96786..466347172 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 class_loader, Handle hint_dex_cache, VariableSizedHandleScope* handles, bool is_first_run, @@ -106,8 +105,6 @@ class ReferenceTypePropagation : public HOptimization { void ValidateTypes(); - Handle 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 84a4bab1a..b061c871b 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(), Handle(), handles, true, diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc index d6edb650b..ae1e36999 100644 --- a/compiler/optimizing/ssa_builder.cc +++ b/compiler/optimizing/ssa_builder.cc @@ -497,11 +497,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 978f113ec..45dac5411 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 class_loader, Handle 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 class_loader_; Handle dex_cache_; VariableSizedHandleScope* const handles_; diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index c95cc748b..ae175eb11 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -2173,14 +2173,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) { @@ -2190,13 +2185,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 254682261..9a73830f9 100644 --- a/patchoat/patchoat.cc +++ b/patchoat/patchoat.cc @@ -643,8 +643,8 @@ void PatchOat::PatchDexFileArrays(mirror::ObjectArray* 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* orig_types = orig_dex_cache->GetResolvedTypes(); + GcRoot* relocated_types = RelocatedAddressOfPointer(orig_types); copy_dex_cache->SetField64( mirror::DexCache::ResolvedTypesOffset(), static_cast(reinterpret_cast(relocated_types))); diff --git a/runtime/art_field-inl.h b/runtime/art_field-inl.h index 16b73c681..80af8e7bd 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 inline ObjPtr 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 declaring_class = GetDeclaringClass(); if (UNLIKELY(declaring_class->IsProxyClass())) { @@ -322,16 +320,9 @@ inline ObjPtr ArtField::GetType() { const DexFile* const dex_file = dex_cache->GetDexFile(); const DexFile::FieldId& field_id = dex_file->GetFieldId(field_index); ObjPtr 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 7e131040b..a4a6e5a4f 100644 --- a/runtime/art_field.cc +++ b/runtime/art_field.cc @@ -48,6 +48,10 @@ ObjPtr ArtField::ProxyFindSystemClass(const char* descriptor) { return Runtime::Current()->GetClassLinker()->FindSystemClass(Thread::Current(), descriptor); } +ObjPtr ArtField::ResolveGetType(dex::TypeIndex type_idx) { + return Runtime::Current()->GetClassLinker()->ResolveType(type_idx, this); +} + ObjPtr 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 75dd98113..427e10374 100644 --- a/runtime/art_field.h +++ b/runtime/art_field.h @@ -217,6 +217,8 @@ class ArtField FINAL { private: ObjPtr ProxyFindSystemClass(const char* descriptor) REQUIRES_SHARED(Locks::mutator_lock_); + ObjPtr ResolveGetType(dex::TypeIndex type_idx) + REQUIRES_SHARED(Locks::mutator_lock_); ObjPtr 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 efcdbbff5..7ec3900aa 100644 --- a/runtime/art_method-inl.h +++ b/runtime/art_method-inl.h @@ -175,19 +175,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 dex_cache = GetDexCache(); ObjPtr 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 e928344fb..34b737c73 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 ClassLinker::LookupResolvedType( - dex::TypeIndex type_idx, - ObjPtr dex_cache, - ObjPtr class_loader) { - ObjPtr 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 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 declaring_class = referrer->GetDeclaringClass(); + ObjPtr dex_cache_ptr = declaring_class->GetDexCache(); + ObjPtr resolved_type = dex_cache_ptr->GetResolvedType(type_idx); + if (UNLIKELY(resolved_type == nullptr)) { + StackHandleScope<2> hs(Thread::Current()); + Handle dex_cache(hs.NewHandle(dex_cache_ptr)); + Handle 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 866936739..edd6e3b52 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -1171,23 +1171,6 @@ static void CopyNonNull(const T* src, size_t count, T* dst, const NullPred& pred } } -template -static void CopyDexCachePairs(const std::atomic>* src, - size_t count, - std::atomic>* 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 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 class_loader, @@ -1241,10 +1224,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; @@ -1263,14 +1243,28 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( mirror::StringDexCacheType* const image_resolved_strings = dex_cache->GetStrings(); mirror::StringDexCacheType* const strings = reinterpret_cast(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(raw_arrays + layout.TypesOffset()); - CopyDexCachePairs(image_resolved_types, num_types, types); + GcRoot* const image_resolved_types = dex_cache->GetResolvedTypes(); + GcRoot* const types = + reinterpret_cast*>(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& elem) { + return elem.IsNull(); + }); dex_cache->SetResolvedTypes(types); } if (num_methods != 0u) { @@ -1311,7 +1305,15 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( mirror::MethodTypeDexCacheType* const method_types = reinterpret_cast( 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); } } @@ -1333,11 +1335,11 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( } if (kIsDebugBuild) { CHECK(new_class_set != nullptr); - mirror::TypeDexCacheType* const types = dex_cache->GetResolvedTypes(); + GcRoot* 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(num_types); j++) { // The image space is not yet added to the heap, avoid read barriers. - ObjPtr klass = types[j].load(std::memory_order_relaxed).object.Read(); + ObjPtr klass = types[j].Read(); if (space->HasAddress(klass.Ptr())) { DCHECK(!klass->IsErroneous()) << klass->GetStatus(); auto it = new_class_set->Find(ClassTable::TableSlot(klass)); @@ -1698,9 +1700,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. h_dex_cache->SetDexFile(dex_file.get()); - mirror::TypeDexCacheType* const types = h_dex_cache->GetResolvedTypes(); + GcRoot* const types = h_dex_cache->GetResolvedTypes(); for (int32_t j = 0, num_types = h_dex_cache->NumResolvedTypes(); j < num_types; j++) { - ObjPtr klass = types[j].load(std::memory_order_relaxed).object.Read(); + ObjPtr klass = types[j].Read(); if (klass != nullptr) { DCHECK(!klass->IsErroneous()) << klass->GetStatus(); } @@ -7696,9 +7698,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 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(); } @@ -7741,7 +7741,6 @@ ObjPtr ClassLinker::LookupResolvedType(const DexFile& dex_file, } } if (type != nullptr && type->IsResolved()) { - dex_cache->SetResolvedType(type_idx, type); return type.Ptr(); } return nullptr; @@ -7764,12 +7763,6 @@ mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, Thread::PoisonObjectPointersIfDebug(); ObjPtr 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 21edd513a..5042fb760 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -262,6 +262,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 LookupResolvedType(const DexFile& dex_file, @@ -269,10 +273,6 @@ class ClassLinker { ObjPtr dex_cache, ObjPtr class_loader) REQUIRES_SHARED(Locks::mutator_lock_); - static ObjPtr LookupResolvedType(dex::TypeIndex type_idx, - ObjPtr dex_cache, - ObjPtr 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 6eee0bd61..17510bb59 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -914,7 +914,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()), @@ -949,7 +949,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()), @@ -972,7 +972,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()), @@ -990,7 +990,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 1b267eb99..ac0ce3601 100644 --- a/runtime/entrypoints/entrypoint_utils-inl.h +++ b/runtime/entrypoints/entrypoint_utils-inl.h @@ -705,10 +705,10 @@ inline ArtMethod* FindMethodFast(uint32_t method_idx, return resolved_method; } else if (type == kSuper) { // TODO This lookup is rather slow. - ObjPtr dex_cache = referrer->GetDexCache(); - dex::TypeIndex method_type_idx = dex_cache->GetDexFile()->GetMethodId(method_idx).class_idx_; - ObjPtr 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 e56f0dc61..e03958d71 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -1225,9 +1225,9 @@ class ImageSpaceLoader { } dex_cache->FixupStrings(new_strings, fixup_adapter); } - mirror::TypeDexCacheType* types = dex_cache->GetResolvedTypes(); + GcRoot* types = dex_cache->GetResolvedTypes(); if (types != nullptr) { - mirror::TypeDexCacheType* new_types = fixup_adapter.ForwardObject(types); + GcRoot* 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 87f429568..54b099eb1 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', '3', '7', '\0' }; // hash-based DexCache types +const uint8_t ImageHeader::kImageVersion[] = { '0', '3', '6', '\0' }; // Erroneous resolved class. ImageHeader::ImageHeader(uint32_t image_begin, uint32_t image_size, diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index c23531702..28bcb9710 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -438,22 +438,14 @@ void AbortTransactionV(Thread* self, const char* fmt, va_list args) { // about ALWAYS_INLINE (-Werror, -Wgcc-compat) in definitions. // -// b/30419309 -#if defined(__i386__) -#define IF_X86_OPTNONE_ELSE_ALWAYS_INLINE __attribute__((optnone)) -#else -#define IF_X86_OPTNONE_ELSE_ALWAYS_INLINE ALWAYS_INLINE -#endif - template -IF_X86_OPTNONE_ELSE_ALWAYS_INLINE -static bool DoCallCommon(ArtMethod* called_method, - Thread* self, - ShadowFrame& shadow_frame, - JValue* result, - uint16_t number_of_inputs, - uint32_t (&arg)[Instruction::kMaxVarArgRegs], - uint32_t vregC) REQUIRES_SHARED(Locks::mutator_lock_); +static ALWAYS_INLINE bool DoCallCommon(ArtMethod* called_method, + Thread* self, + ShadowFrame& shadow_frame, + JValue* result, + uint16_t number_of_inputs, + uint32_t (&arg)[Instruction::kMaxVarArgRegs], + uint32_t vregC) REQUIRES_SHARED(Locks::mutator_lock_); template ALWAYS_INLINE void CopyRegisters(ShadowFrame& caller_frame, diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index 85636fb5b..f08d4daf9 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -951,8 +951,7 @@ ObjPtr Class::GetDirectInterface(Thread* self, ObjPtr klass, uint3 return interfaces->Get(idx); } else { dex::TypeIndex type_idx = klass->GetDirectInterfaceTypeIdx(idx); - ObjPtr interface = ClassLinker::LookupResolvedType( - type_idx, klass->GetDexCache(), klass->GetClassLoader()); + ObjPtr 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 bef3ad29a..a59bb7b88 100644 --- a/runtime/mirror/dex_cache-inl.h +++ b/runtime/mirror/dex_cache-inl.h @@ -40,22 +40,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 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 resolved) { + StringDexCachePair::Assign(GetStrings(), string_idx.index_, resolved.Ptr(), NumStrings()); Runtime* const runtime = Runtime::Current(); if (UNLIKELY(runtime->IsActiveTransaction())) { DCHECK(runtime->IsAotCompiler()); @@ -66,70 +58,50 @@ inline void DexCache::SetResolvedString(dex::StringIndex string_idx, ObjPtrIsAotCompiler()); - 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 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>&>(GetResolvedTypes()[type_idx.index_]). + StoreRelease(GcRoot(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); } @@ -226,49 +198,49 @@ inline void DexCache::VisitReferences(ObjPtr klass, const Visitor& visito VisitInstanceFieldsReferences(klass, visitor); // Visit arrays after. if (kVisitNativeRoots) { - VisitDexCachePairs( + VisitDexCachePairs( GetStrings(), NumStrings(), visitor); - VisitDexCachePairs( - GetResolvedTypes(), NumResolvedTypes(), visitor); + GcRoot* resolved_types = GetResolvedTypes(); + for (size_t i = 0, num_types = NumResolvedTypes(); i != num_types; ++i) { + visitor.VisitRootIfNonNull(resolved_types[i].AddressWithoutBarrier()); + } - VisitDexCachePairs( + VisitDexCachePairs( GetResolvedMethodTypes(), NumResolvedMethodTypes(), visitor); } } template -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(); - String* new_source = visitor(ptr); + mirror::String* ptr = source.object.Read(); + mirror::String* new_source = visitor(ptr); source.object = GcRoot(new_source); dest[i].store(source, std::memory_order_relaxed); } } template -inline void DexCache::FixupResolvedTypes(TypeDexCacheType* dest, const Visitor& visitor) { - TypeDexCacheType* src = GetResolvedTypes(); +inline void DexCache::FixupResolvedTypes(GcRoot* dest, const Visitor& visitor) { + GcRoot* 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(); - Class* new_source = visitor(ptr); - source.object = GcRoot(new_source); - dest[i].store(source, std::memory_order_relaxed); + mirror::Class* source = src[i].Read(); + mirror::Class* new_source = visitor(source); + dest[i] = GcRoot(new_source); } } template -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(); - MethodType* new_source = visitor(ptr); + mirror::MethodType* ptr = source.object.Read(); + mirror::MethodType* new_source = visitor(ptr); source.object = GcRoot(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 3103a92c8..741cf3bb4 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(raw_arrays + layout.StringsOffset()); - mirror::TypeDexCacheType* types = (dex_file->NumTypeIds() == 0u) ? nullptr : - reinterpret_cast(raw_arrays + layout.TypesOffset()); + GcRoot* types = (dex_file->NumTypeIds() == 0u) ? nullptr : + reinterpret_cast*>(raw_arrays + layout.TypesOffset()); ArtMethod** methods = (dex_file->NumMethodIds() == 0u) ? nullptr : reinterpret_cast(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 @@ -108,9 +104,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); @@ -126,9 +121,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); } @@ -137,7 +129,7 @@ void DexCache::InitializeDexCache(Thread* self, strings, num_strings, types, - num_types, + dex_file->NumTypeIds(), methods, dex_file->NumMethodIds(), fields, @@ -151,7 +143,7 @@ void DexCache::Init(const DexFile* dex_file, ObjPtr location, StringDexCacheType* strings, uint32_t num_strings, - TypeDexCacheType* resolved_types, + GcRoot* 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 e68b0c721..6f88cc5df 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; @@ -36,7 +36,6 @@ class Thread; namespace mirror { -class Class; class MethodType; class String; @@ -61,7 +60,7 @@ template 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 object, uint32_t index) + DexCachePair(T* object, uint32_t index) : object(object), index(index) {} DexCachePair() = default; @@ -75,28 +74,39 @@ template struct PACKED(8) DexCachePair { dex_cache[0].store(first_elem, std::memory_order_relaxed); } + static GcRoot Lookup(std::atomic>* dex_cache, + uint32_t idx, + uint32_t cache_size) { + DCHECK_NE(cache_size, 0u); + DexCachePair element = dex_cache[idx % cache_size].load(std::memory_order_relaxed); + if (idx != element.index) { + return GcRoot(nullptr); + } + + DCHECK(!element.object.IsNull()); + return element.object; + } + + static void Assign(std::atomic>* 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(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; -using TypeDexCacheType = std::atomic; - -using StringDexCachePair = DexCachePair; +using StringDexCachePair = DexCachePair; using StringDexCacheType = std::atomic; -using MethodTypeDexCachePair = DexCachePair; +using MethodTypeDexCachePair = DexCachePair; using MethodTypeDexCacheType = std::atomic; // C++ mirror of java.lang.DexCache. @@ -105,11 +115,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), @@ -121,10 +126,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; } @@ -155,7 +156,7 @@ class MANAGED DexCache FINAL : public Object { REQUIRES_SHARED(Locks::mutator_lock_); template - void FixupResolvedTypes(TypeDexCacheType* dest, const Visitor& visitor) + void FixupResolvedTypes(GcRoot* dest, const Visitor& visitor) REQUIRES_SHARED(Locks::mutator_lock_); template @@ -210,7 +211,7 @@ class MANAGED DexCache FINAL : public Object { return OFFSET_OF_OBJECT_MEMBER(DexCache, num_resolved_method_types_); } - 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 resolved) ALWAYS_INLINE @@ -225,8 +226,6 @@ class MANAGED DexCache FINAL : public Object { void SetResolvedType(dex::TypeIndex type_idx, ObjPtr 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_); @@ -255,11 +254,11 @@ class MANAGED DexCache FINAL : public Object { SetFieldPtr(StringsOffset(), strings); } - TypeDexCacheType* GetResolvedTypes() ALWAYS_INLINE REQUIRES_SHARED(Locks::mutator_lock_) { - return GetFieldPtr(ResolvedTypesOffset()); + GcRoot* GetResolvedTypes() ALWAYS_INLINE REQUIRES_SHARED(Locks::mutator_lock_) { + return GetFieldPtr*>(ResolvedTypesOffset()); } - void SetResolvedTypes(TypeDexCacheType* resolved_types) + void SetResolvedTypes(GcRoot* resolved_types) ALWAYS_INLINE REQUIRES_SHARED(Locks::mutator_lock_) { SetFieldPtr(ResolvedTypesOffset(), resolved_types); @@ -324,7 +323,7 @@ class MANAGED DexCache FINAL : public Object { SetFieldPtr(OFFSET_OF_OBJECT_MEMBER(DexCache, dex_file_), dex_file); } - void SetLocation(ObjPtr location) REQUIRES_SHARED(Locks::mutator_lock_); + void SetLocation(ObjPtr location) REQUIRES_SHARED(Locks::mutator_lock_); // NOTE: Get/SetElementPtrSize() are intended for working with ArtMethod** and ArtField** // provided by GetResolvedMethods/Fields() and ArtMethod::GetDexCacheResolvedMethods(), @@ -341,7 +340,7 @@ class MANAGED DexCache FINAL : public Object { ObjPtr location, StringDexCacheType* strings, uint32_t num_strings, - TypeDexCacheType* resolved_types, + GcRoot* resolved_types, uint32_t num_resolved_types, ArtMethod** resolved_methods, uint32_t num_resolved_methods, @@ -352,16 +351,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 - void VisitReferences(ObjPtr klass, const Visitor& visitor) + void VisitReferences(ObjPtr klass, const Visitor& visitor) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_); HeapReference dex_; @@ -371,7 +366,7 @@ class MANAGED DexCache FINAL : public Object { uint64_t resolved_method_types_; // std::atomic* 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*, array with num_resolved_types_ elements. uint64_t strings_; // std::atomic*, array with num_strings_ // elements. diff --git a/runtime/mirror/dex_cache_test.cc b/runtime/mirror/dex_cache_test.cc index 5693f6764..8f978e122 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 0b667fec4..f1c350f23 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 dex_cache = soa.Decode(javaDexCache); - CHECK_LT(static_cast(type_index), dex_cache->GetDexFile()->NumTypeIds()); + CHECK_LT(static_cast(type_index), dex_cache->NumResolvedTypes()); return soa.AddLocalReference(dex_cache->GetResolvedType(dex::TypeIndex(type_index))); } @@ -69,11 +69,8 @@ static void DexCache_setResolvedType(JNIEnv* env, jobject javaDexCache, jint typ jobject type) { ScopedFastNativeObjectAccess soa(env); ObjPtr dex_cache = soa.Decode(javaDexCache); - CHECK_LT(static_cast(type_index), dex_cache->GetDexFile()->NumTypeIds()); - ObjPtr t = soa.Decode(type); - if (t != nullptr) { - dex_cache->SetResolvedType(dex::TypeIndex(type_index), t); - } + CHECK_LT(static_cast(type_index), dex_cache->NumResolvedTypes()); + dex_cache->SetResolvedType(dex::TypeIndex(type_index), soa.Decode(type)); } static void DexCache_setResolvedString(JNIEnv* env, jobject javaDexCache, jint string_index, @@ -81,10 +78,7 @@ static void DexCache_setResolvedString(JNIEnv* env, jobject javaDexCache, jint s ScopedFastNativeObjectAccess soa(env); ObjPtr dex_cache = soa.Decode(javaDexCache); CHECK_LT(static_cast(string_index), dex_cache->GetDexFile()->NumStringIds()); - ObjPtr s = soa.Decode(string); - if (s != nullptr) { - dex_cache->SetResolvedString(dex::StringIndex(string_index), s); - } + dex_cache->SetResolvedString(dex::StringIndex(string_index), soa.Decode(string)); } static JNINativeMethod gMethods[] = { diff --git a/runtime/oat.h b/runtime/oat.h index 403371619..e7f5c7fe7 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', '0', '7', '\0' }; // Stack map stack mask change. + static constexpr uint8_t kOatVersion[] = { '1', '0', '8', '\0' }; // revert: hash DexCache types 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 2812c2100..bd1b044da 100644 --- a/runtime/utils/dex_cache_arrays_layout-inl.h +++ b/runtime/utils/dex_cache_arrays_layout-inl.h @@ -48,11 +48,9 @@ inline DexCacheArraysLayout::DexCacheArraysLayout(PointerSize pointer_size, cons : DexCacheArraysLayout(pointer_size, dex_file->GetHeader()) { } -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) == 4, "Expecting alignof(GcRoot<>) == 4"); static_assert(alignof(mirror::StringDexCacheType) == 8, "Expecting alignof(StringDexCacheType) == 8"); static_assert(alignof(mirror::MethodTypeDexCacheType) == 8, @@ -62,22 +60,17 @@ constexpr size_t DexCacheArraysLayout::Alignment() { } template -constexpr PointerSize GcRootAsPointerSize() { +static constexpr PointerSize GcRootAsPointerSize() { static_assert(sizeof(GcRoot) == 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(), 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(), num_elements); } inline size_t DexCacheArraysLayout::TypesAlignment() const { diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index ba429d8c3..b91545755 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 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 " @@ -3685,10 +3684,9 @@ inline bool MethodVerifier::IsInstantiableOrPrimitive(mirror::Class* klass) { } const RegType& MethodVerifier::ResolveClassAndCheckAccess(dex::TypeIndex class_idx) { - mirror::Class* klass = - ClassLinker::LookupResolvedType(class_idx, dex_cache_.Get(), class_loader_.Get()).Ptr(); + 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); 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 6d4b645db..b03589616 100644 --- a/test/626-const-class-linking/clear_dex_cache_types.cc +++ b/test/626-const-class-linking/clear_dex_cache_types.cc @@ -24,8 +24,7 @@ extern "C" JNIEXPORT void JNICALL Java_Main_nativeClearResolvedTypes(JNIEnv*, jc ScopedObjectAccess soa(Thread::Current()); mirror::DexCache* dex_cache = soa.Decode(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(nullptr)); } } -- 2.11.0