diff options
Diffstat (limited to 'compiler')
43 files changed, 885 insertions, 425 deletions
diff --git a/compiler/compiler.h b/compiler/compiler.h index 2ca0b77a73..908d3669ed 100644 --- a/compiler/compiler.h +++ b/compiler/compiler.h @@ -27,6 +27,7 @@ namespace jit { class JitCodeCache; } namespace mirror { + class ClassLoader; class DexCache; } @@ -63,7 +64,7 @@ class Compiler { InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, - jobject class_loader, + Handle<mirror::ClassLoader> class_loader, const DexFile& dex_file, Handle<mirror::DexCache> dex_cache) const = 0; diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index d4f6545c59..76aeaa55d7 100644 --- a/compiler/dex/dex_to_dex_compiler.cc +++ b/compiler/dex/dex_to_dex_compiler.cc @@ -284,16 +284,13 @@ void DexCompiler::CompileInvokeVirtual(Instruction* inst, uint32_t dex_pc, } uint32_t method_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c(); ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<1> hs(soa.Self()); - Handle<mirror::ClassLoader> class_loader(hs.NewHandle( - soa.Decode<mirror::ClassLoader>(unit_.GetClassLoader()))); ClassLinker* class_linker = unit_.GetClassLinker(); ArtMethod* resolved_method = class_linker->ResolveMethod<ClassLinker::kForceICCECheck>( GetDexFile(), method_idx, unit_.GetDexCache(), - class_loader, + unit_.GetClassLoader(), /* referrer */ nullptr, kVirtual); @@ -330,7 +327,7 @@ CompiledMethod* ArtCompileDEX( InvokeType invoke_type ATTRIBUTE_UNUSED, uint16_t class_def_idx, uint32_t method_idx, - jobject class_loader, + Handle<mirror::ClassLoader> 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 0a00d45297..00c596d60e 100644 --- a/compiler/dex/dex_to_dex_compiler.h +++ b/compiler/dex/dex_to_dex_compiler.h @@ -18,6 +18,7 @@ #define ART_COMPILER_DEX_DEX_TO_DEX_COMPILER_H_ #include "dex_file.h" +#include "handle.h" #include "invoke_type.h" namespace art { @@ -25,6 +26,10 @@ namespace art { class CompiledMethod; class CompilerDriver; +namespace mirror { +class ClassLoader; +} // namespace mirror + namespace optimizer { enum class DexToDexCompilationLevel { @@ -40,7 +45,7 @@ CompiledMethod* ArtCompileDEX(CompilerDriver* driver, InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, - jobject class_loader, + Handle<mirror::ClassLoader> 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 f296851ebf..582330611d 100644 --- a/compiler/driver/compiler_driver-inl.h +++ b/compiler/driver/compiler_driver-inl.h @@ -31,17 +31,12 @@ namespace art { -inline mirror::ClassLoader* CompilerDriver::GetClassLoader(const ScopedObjectAccess& soa, - const DexCompilationUnit* mUnit) { - return soa.Decode<mirror::ClassLoader>(mUnit->GetClassLoader()).Ptr(); -} - inline mirror::Class* CompilerDriver::ResolveClass( const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, dex::TypeIndex cls_index, const DexCompilationUnit* mUnit) { DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile()); - DCHECK_EQ(class_loader.Get(), GetClassLoader(soa, mUnit)); + DCHECK_EQ(class_loader.Get(), mUnit->GetClassLoader().Get()); mirror::Class* cls = mUnit->GetClassLinker()->ResolveType( *mUnit->GetDexFile(), cls_index, dex_cache, class_loader); DCHECK_EQ(cls == nullptr, soa.Self()->IsExceptionPending()); @@ -56,7 +51,7 @@ inline mirror::Class* CompilerDriver::ResolveCompilingMethodsClass( const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit) { DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile()); - DCHECK_EQ(class_loader.Get(), GetClassLoader(soa, mUnit)); + DCHECK_EQ(class_loader.Get(), mUnit->GetClassLoader().Get()); const DexFile::MethodId& referrer_method_id = mUnit->GetDexFile()->GetMethodId(mUnit->GetDexMethodIndex()); return ResolveClass(soa, dex_cache, class_loader, referrer_method_id.class_idx_, mUnit); @@ -87,7 +82,7 @@ inline ArtField* CompilerDriver::ResolveField( const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit, uint32_t field_idx, bool is_static) { - DCHECK_EQ(class_loader.Get(), GetClassLoader(soa, mUnit)); + DCHECK_EQ(class_loader.Get(), mUnit->GetClassLoader().Get()); return ResolveFieldWithDexFile(soa, dex_cache, class_loader, mUnit->GetDexFile(), field_idx, is_static); } @@ -139,7 +134,7 @@ inline ArtMethod* CompilerDriver::ResolveMethod( ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit, uint32_t method_idx, InvokeType invoke_type, bool check_incompatible_class_change) { - DCHECK_EQ(class_loader.Get(), GetClassLoader(soa, mUnit)); + DCHECK_EQ(class_loader.Get(), mUnit->GetClassLoader().Get()); ArtMethod* resolved_method = check_incompatible_class_change ? mUnit->GetClassLinker()->ResolveMethod<ClassLinker::kForceICCECheck>( diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index caab5fb5a9..995098799c 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -581,7 +581,7 @@ static void CompileMethod(Thread* self, InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, - jobject class_loader, + Handle<mirror::ClassLoader> class_loader, const DexFile& dex_file, optimizer::DexToDexCompilationLevel dex_to_dex_compilation_level, bool compilation_enabled, @@ -622,9 +622,6 @@ static void CompileMethod(Thread* self, // Look-up the ArtMethod associated with this code_item (if any) // -- It is later used to lookup any [optimization] annotations for this method. ScopedObjectAccess soa(self); - StackHandleScope<1> hs(soa.Self()); - Handle<mirror::ClassLoader> class_loader_handle(hs.NewHandle( - soa.Decode<mirror::ClassLoader>(class_loader))); // TODO: Lookup annotation from DexFile directly without resolving method. ArtMethod* method = @@ -632,7 +629,7 @@ static void CompileMethod(Thread* self, dex_file, method_idx, dex_cache, - class_loader_handle, + class_loader, /* referrer */ nullptr, invoke_type); @@ -679,9 +676,14 @@ 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) { @@ -728,12 +730,14 @@ 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<1> hs(self); + StackHandleScope<2> hs(self); Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache())); + Handle<mirror::ClassLoader> class_loader( + hs.NewHandle(method->GetDeclaringClass()->GetClassLoader())); { ScopedObjectAccessUnchecked soa(self); ScopedLocalRef<jobject> local_class_loader( - soa.Env(), soa.AddLocalReference<jobject>(method->GetDeclaringClass()->GetClassLoader())); + soa.Env(), soa.AddLocalReference<jobject>(class_loader.Get())); jclass_loader = soa.Env()->NewGlobalRef(local_class_loader.get()); // Find the dex_file dex_file = method->GetDexFile(); @@ -767,7 +771,7 @@ void CompilerDriver::CompileOne(Thread* self, ArtMethod* method, TimingLogger* t invoke_type, class_def_idx, method_idx, - jclass_loader, + class_loader, *dex_file, dex_to_dex_compilation_level, true, @@ -793,7 +797,7 @@ void CompilerDriver::CompileOne(Thread* self, ArtMethod* method, TimingLogger* t invoke_type, class_def_idx, method_idx, - jclass_loader, + class_loader, *dex_file, dex_to_dex_compilation_level, true, @@ -1073,22 +1077,30 @@ bool CompilerDriver::ShouldCompileBasedOnProfile(const MethodReference& method_r class ResolveCatchBlockExceptionsClassVisitor : public ClassVisitor { public: - explicit ResolveCatchBlockExceptionsClassVisitor( - std::set<std::pair<dex::TypeIndex, const DexFile*>>& exceptions_to_resolve) - : exceptions_to_resolve_(exceptions_to_resolve) {} + ResolveCatchBlockExceptionsClassVisitor() : classes_() {} virtual bool operator()(ObjPtr<mirror::Class> c) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { + classes_.push_back(c); + return true; + } + + void FindExceptionTypesToResolve( + std::set<std::pair<dex::TypeIndex, const DexFile*>>* exceptions_to_resolve) + REQUIRES_SHARED(Locks::mutator_lock_) { const auto pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); - for (auto& m : c->GetMethods(pointer_size)) { - ResolveExceptionsForMethod(&m); + for (ObjPtr<mirror::Class> klass : classes_) { + for (ArtMethod& method : klass->GetMethods(pointer_size)) { + FindExceptionTypesToResolveForMethod(&method, exceptions_to_resolve); + } } - return true; } private: - void ResolveExceptionsForMethod(ArtMethod* method_handle) + void FindExceptionTypesToResolveForMethod( + ArtMethod* method, + std::set<std::pair<dex::TypeIndex, const DexFile*>>* exceptions_to_resolve) REQUIRES_SHARED(Locks::mutator_lock_) { - const DexFile::CodeItem* code_item = method_handle->GetCodeItem(); + const DexFile::CodeItem* code_item = method->GetCodeItem(); if (code_item == nullptr) { return; // native or abstract method } @@ -1108,9 +1120,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_handle->IsResolvedTypeIdx(encoded_catch_handler_handlers_type_idx)) { - exceptions_to_resolve_.emplace(encoded_catch_handler_handlers_type_idx, - method_handle->GetDexFile()); + if (!method->IsResolvedTypeIdx(encoded_catch_handler_handlers_type_idx)) { + exceptions_to_resolve->emplace(encoded_catch_handler_handlers_type_idx, + method->GetDexFile()); } // ignore address associated with catch handler DecodeUnsignedLeb128(&encoded_catch_handler_list); @@ -1122,7 +1134,7 @@ class ResolveCatchBlockExceptionsClassVisitor : public ClassVisitor { } } - std::set<std::pair<dex::TypeIndex, const DexFile*>>& exceptions_to_resolve_; + std::vector<ObjPtr<mirror::Class>> classes_; }; class RecordImageClassesVisitor : public ClassVisitor { @@ -1176,8 +1188,14 @@ void CompilerDriver::LoadImageClasses(TimingLogger* timings) { hs.NewHandle(class_linker->FindSystemClass(self, "Ljava/lang/Throwable;"))); do { unresolved_exception_types.clear(); - ResolveCatchBlockExceptionsClassVisitor visitor(unresolved_exception_types); - class_linker->VisitClasses(&visitor); + { + // Thread suspension is not allowed while ResolveCatchBlockExceptionsClassVisitor + // is using a std::vector<ObjPtr<mirror::Class>>. + ScopedAssertNoThreadSuspension ants(__FUNCTION__); + ResolveCatchBlockExceptionsClassVisitor visitor; + class_linker->VisitClasses(&visitor); + visitor.FindExceptionTypesToResolve(&unresolved_exception_types); + } for (const auto& exception_type : unresolved_exception_types) { dex::TypeIndex exception_type_idx = exception_type.first; const DexFile* dex_file = exception_type.second; @@ -1428,19 +1446,14 @@ void CompilerDriver::MarkForDexToDexCompilation(Thread* self, const MethodRefere dex_to_dex_references_.back().GetMethodIndexes().SetBit(method_ref.dex_method_index); } -bool CompilerDriver::CanAccessTypeWithoutChecks(uint32_t referrer_idx, - Handle<mirror::DexCache> dex_cache, - dex::TypeIndex type_idx) { - // Get type from dex cache assuming it was populated by the verifier - mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx); +bool CompilerDriver::CanAccessTypeWithoutChecks(ObjPtr<mirror::Class> referrer_class, + ObjPtr<mirror::Class> resolved_class) { 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. @@ -1457,12 +1470,9 @@ bool CompilerDriver::CanAccessTypeWithoutChecks(uint32_t referrer_idx, return is_accessible; } -bool CompilerDriver::CanAccessInstantiableTypeWithoutChecks(uint32_t referrer_idx, - Handle<mirror::DexCache> dex_cache, - dex::TypeIndex type_idx, +bool CompilerDriver::CanAccessInstantiableTypeWithoutChecks(ObjPtr<mirror::Class> referrer_class, + ObjPtr<mirror::Class> resolved_class, 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. @@ -1470,10 +1480,8 @@ bool CompilerDriver::CanAccessInstantiableTypeWithoutChecks(uint32_t referrer_id return false; // Unknown class needs access checks. } *finalizable = resolved_class->IsFinalizable(); - const DexFile::MethodId& method_id = dex_cache->GetDexFile()->GetMethodId(referrer_idx); bool is_accessible = resolved_class->IsPublic(); // Public classes are always accessible. if (!is_accessible) { - mirror::Class* referrer_class = dex_cache->GetResolvedType(method_id.class_idx_); if (referrer_class == nullptr) { stats_->TypeNeedsAccessCheck(); return false; // Incomplete referrer knowledge needs access check. @@ -1517,9 +1525,7 @@ ArtField* CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, mirror::Class* referrer_class; Handle<mirror::DexCache> dex_cache(mUnit->GetDexCache()); { - StackHandleScope<1> hs(soa.Self()); - Handle<mirror::ClassLoader> class_loader_handle( - hs.NewHandle(soa.Decode<mirror::ClassLoader>(mUnit->GetClassLoader()))); + Handle<mirror::ClassLoader> class_loader_handle = 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; @@ -2666,10 +2672,18 @@ 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, jclass_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, + class_loader, + dex_file, + dex_to_dex_compilation_level, + compilation_enabled, + dex_cache); it.Next(); } // Compile virtual methods @@ -2683,10 +2697,17 @@ 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, jclass_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, + class_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 6ba16923a9..cbde587241 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -187,16 +187,14 @@ class CompilerDriver { REQUIRES(!requires_constructor_barrier_lock_); // Are runtime access checks necessary in the compiled code? - bool CanAccessTypeWithoutChecks(uint32_t referrer_idx, - Handle<mirror::DexCache> dex_cache, - dex::TypeIndex type_idx) + bool CanAccessTypeWithoutChecks(ObjPtr<mirror::Class> referrer_class, + ObjPtr<mirror::Class> resolved_class) 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(uint32_t referrer_idx, - Handle<mirror::DexCache> dex_cache, - dex::TypeIndex type_idx, + bool CanAccessInstantiableTypeWithoutChecks(ObjPtr<mirror::Class> referrer_class, + ObjPtr<mirror::Class> resolved_class, bool* out_is_finalizable) REQUIRES_SHARED(Locks::mutator_lock_); @@ -374,10 +372,6 @@ class CompilerDriver { uint32_t field_idx) REQUIRES_SHARED(Locks::mutator_lock_); - mirror::ClassLoader* GetClassLoader(const ScopedObjectAccess& soa, - const DexCompilationUnit* mUnit) - REQUIRES_SHARED(Locks::mutator_lock_); - private: void PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files, diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc index 316117f94b..35aa1eef2d 100644 --- a/compiler/driver/compiler_driver_test.cc +++ b/compiler/driver/compiler_driver_test.cc @@ -101,6 +101,7 @@ 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); @@ -132,9 +133,10 @@ TEST_F(CompilerDriverTest, DISABLED_LARGE_CompileDexLibCore) { << " " << dex.GetMethodDeclaringClassDescriptor(dex.GetMethodId(i)) << " " << dex.GetMethodName(dex.GetMethodId(i)); } - EXPECT_EQ(dex.NumFieldIds(), dex_cache->NumResolvedFields()); + EXPECT_TRUE(dex_cache->StaticArtFieldSize() == dex_cache->NumResolvedFields() + || dex.NumFieldIds() == dex_cache->NumResolvedFields()); for (size_t i = 0; i < dex_cache->NumResolvedFields(); i++) { - ArtField* field = cl->GetResolvedField(i, dex_cache); + ArtField* field = dex_cache->GetResolvedField(i, cl->GetImagePointerSize()); EXPECT_TRUE(field != nullptr) << "field_idx=" << i << " " << dex.GetFieldDeclaringClassDescriptor(dex.GetFieldId(i)) << " " << dex.GetFieldName(dex.GetFieldId(i)); diff --git a/compiler/driver/dex_compilation_unit.cc b/compiler/driver/dex_compilation_unit.cc index 47b19297e5..7e8e812c4a 100644 --- a/compiler/driver/dex_compilation_unit.cc +++ b/compiler/driver/dex_compilation_unit.cc @@ -21,7 +21,7 @@ namespace art { -DexCompilationUnit::DexCompilationUnit(jobject class_loader, +DexCompilationUnit::DexCompilationUnit(Handle<mirror::ClassLoader> 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 854927d747..24a9a5b653 100644 --- a/compiler/driver/dex_compilation_unit.h +++ b/compiler/driver/dex_compilation_unit.h @@ -34,7 +34,7 @@ class VerifiedMethod; class DexCompilationUnit : public DeletableArenaObject<kArenaAllocMisc> { public: - DexCompilationUnit(jobject class_loader, + DexCompilationUnit(Handle<mirror::ClassLoader> class_loader, ClassLinker* class_linker, const DexFile& dex_file, const DexFile::CodeItem* code_item, @@ -44,7 +44,7 @@ class DexCompilationUnit : public DeletableArenaObject<kArenaAllocMisc> { const VerifiedMethod* verified_method, Handle<mirror::DexCache> dex_cache); - jobject GetClassLoader() const { + Handle<mirror::ClassLoader> GetClassLoader() const { return class_loader_; } @@ -113,7 +113,7 @@ class DexCompilationUnit : public DeletableArenaObject<kArenaAllocMisc> { } private: - const jobject class_loader_; + const Handle<mirror::ClassLoader> class_loader_; ClassLinker* const class_linker_; @@ -125,7 +125,7 @@ class DexCompilationUnit : public DeletableArenaObject<kArenaAllocMisc> { const uint32_t access_flags_; const VerifiedMethod* verified_method_; - Handle<mirror::DexCache> dex_cache_; + const Handle<mirror::DexCache> dex_cache_; std::string symbol_; }; diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 9312a1cc40..aa734561b6 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -941,9 +941,11 @@ void ImageWriter::PruneNonImageClasses() { } ObjPtr<mirror::DexCache> dex_cache = self->DecodeJObject(data.weak_root)->AsDexCache(); for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) { - Class* klass = dex_cache->GetResolvedType(dex::TypeIndex(i)); + mirror::TypeDexCachePair pair = + dex_cache->GetResolvedTypes()[i].load(std::memory_order_relaxed); + mirror::Class* klass = pair.object.Read(); if (klass != nullptr && !KeepClass(klass)) { - dex_cache->SetResolvedType(dex::TypeIndex(i), nullptr); + dex_cache->ClearResolvedType(dex::TypeIndex(pair.index)); } } ArtMethod** resolved_methods = dex_cache->GetResolvedMethods(); @@ -966,11 +968,12 @@ void ImageWriter::PruneNonImageClasses() { << Class::PrettyClass(declaring_class) << " not in class linker table"; } } - ArtField** resolved_fields = dex_cache->GetResolvedFields(); + mirror::FieldDexCacheType* resolved_fields = dex_cache->GetResolvedFields(); for (size_t i = 0; i < dex_cache->NumResolvedFields(); i++) { - ArtField* field = mirror::DexCache::GetElementPtrSize(resolved_fields, i, target_ptr_size_); + auto pair = mirror::DexCache::GetNativePairPtrSize(resolved_fields, i, target_ptr_size_); + ArtField* field = pair.object; if (field != nullptr && !KeepClass(field->GetDeclaringClass().Ptr())) { - dex_cache->SetResolvedField(i, nullptr, target_ptr_size_); + dex_cache->ClearResolvedField(pair.index, target_ptr_size_); } } // Clean the dex field. It might have been populated during the initialization phase, but @@ -1575,10 +1578,8 @@ void ImageWriter::CalculateNewObjectOffsets() { } // Calculate the size of the class table. ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_); - CHECK_EQ(class_loaders_.size(), compile_app_image_ ? 1u : 0u); - mirror::ClassLoader* class_loader = compile_app_image_ ? *class_loaders_.begin() : nullptr; - DCHECK_EQ(image_info.class_table_->NumZygoteClasses(class_loader), 0u); - if (image_info.class_table_->NumNonZygoteClasses(class_loader) != 0u) { + DCHECK_EQ(image_info.class_table_->NumReferencedZygoteClasses(), 0u); + if (image_info.class_table_->NumReferencedNonZygoteClasses() != 0u) { image_info.class_table_bytes_ += image_info.class_table_->WriteToMemory(nullptr); } } @@ -1594,7 +1595,7 @@ void ImageWriter::CalculateNewObjectOffsets() { break; } case kBinDexCacheArray: - bin_offset = RoundUp(bin_offset, DexCacheArraysLayout::Alignment()); + bin_offset = RoundUp(bin_offset, DexCacheArraysLayout::Alignment(target_ptr_size_)); break; case kBinImTable: case kBinIMTConflictTable: { @@ -1923,10 +1924,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); - 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)); + CHECK_EQ(temp_class_table.NumReferencedZygoteClasses(), + table->NumReferencedNonZygoteClasses() + table->NumReferencedZygoteClasses()); UnbufferedRootVisitor visitor(&root_visitor, RootInfo(kRootUnknown)); temp_class_table.VisitRoots(visitor); } @@ -2214,7 +2213,7 @@ void ImageWriter::FixupDexCache(mirror::DexCache* orig_dex_cache, orig_dex_cache->FixupStrings(NativeCopyLocation(orig_strings, orig_dex_cache), ImageAddressVisitor(this)); } - GcRoot<mirror::Class>* orig_types = orig_dex_cache->GetResolvedTypes(); + mirror::TypeDexCacheType* orig_types = orig_dex_cache->GetResolvedTypes(); if (orig_types != nullptr) { copy_dex_cache->SetFieldPtrWithSize<false>(mirror::DexCache::ResolvedTypesOffset(), NativeLocationInImage(orig_types), @@ -2235,16 +2234,17 @@ void ImageWriter::FixupDexCache(mirror::DexCache* orig_dex_cache, mirror::DexCache::SetElementPtrSize(copy_methods, i, copy, target_ptr_size_); } } - ArtField** orig_fields = orig_dex_cache->GetResolvedFields(); + mirror::FieldDexCacheType* orig_fields = orig_dex_cache->GetResolvedFields(); if (orig_fields != nullptr) { copy_dex_cache->SetFieldPtrWithSize<false>(mirror::DexCache::ResolvedFieldsOffset(), NativeLocationInImage(orig_fields), PointerSize::k64); - ArtField** copy_fields = NativeCopyLocation(orig_fields, orig_dex_cache); + mirror::FieldDexCacheType* copy_fields = NativeCopyLocation(orig_fields, orig_dex_cache); for (size_t i = 0, num = orig_dex_cache->NumResolvedFields(); i != num; ++i) { - ArtField* orig = mirror::DexCache::GetElementPtrSize(orig_fields, i, target_ptr_size_); - ArtField* copy = NativeLocationInImage(orig); - mirror::DexCache::SetElementPtrSize(copy_fields, i, copy, target_ptr_size_); + mirror::FieldDexCachePair orig = + mirror::DexCache::GetNativePairPtrSize(orig_fields, i, target_ptr_size_); + mirror::FieldDexCachePair copy(NativeLocationInImage(orig.object), orig.index); + mirror::DexCache::SetNativePairPtrSize(copy_fields, i, copy, target_ptr_size_); } } mirror::MethodTypeDexCacheType* orig_method_types = orig_dex_cache->GetResolvedMethodTypes(); diff --git a/compiler/image_writer.h b/compiler/image_writer.h index cc7df1ce21..bdc7146632 100644 --- a/compiler/image_writer.h +++ b/compiler/image_writer.h @@ -51,8 +51,13 @@ class ImageSpace; } // namespace space } // namespace gc +namespace mirror { +class ClassLoader; +} // namespace mirror + class ClassLoaderVisitor; class ClassTable; +class ImtConflictTable; static constexpr int kInvalidFd = -1; @@ -79,6 +84,11 @@ class ImageWriter FINAL { return true; } + ObjPtr<mirror::ClassLoader> GetClassLoader() { + CHECK_EQ(class_loaders_.size(), compile_app_image_ ? 1u : 0u); + return compile_app_image_ ? *class_loaders_.begin() : nullptr; + } + template <typename T> T* GetImageAddress(T* object) const REQUIRES_SHARED(Locks::mutator_lock_) { if (object == nullptr || IsInBootImage(object)) { diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index a3f61d62c5..afcdf5ea17 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -1061,6 +1061,7 @@ 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,6 +1247,7 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { } private: + ObjPtr<mirror::ClassLoader> class_loader_; OutputStream* const out_; const size_t file_offset_; const ScopedObjectAccess soa_; @@ -1304,10 +1306,12 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { } mirror::Class* GetTargetType(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) { + DCHECK(writer_->HasImage()); ObjPtr<mirror::DexCache> dex_cache = GetDexCache(patch.TargetTypeDexFile()); - mirror::Class* type = dex_cache->GetResolvedType(patch.TargetTypeIndex()); + ObjPtr<mirror::Class> type = + ClassLinker::LookupResolvedType(patch.TargetTypeIndex(), dex_cache, class_loader_); CHECK(type != nullptr); - return type; + return type.Ptr(); } mirror::String* GetTargetString(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) { diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h index e4ad4222fb..3a4c9dbd16 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -54,7 +54,10 @@ class HGraphBuilder : public ValueObject { compiler_driver_(driver), compilation_stats_(compiler_stats), block_builder_(graph, dex_file, code_item), - ssa_builder_(graph, dex_compilation_unit->GetDexCache(), handles), + ssa_builder_(graph, + dex_compilation_unit->GetClassLoader(), + dex_compilation_unit->GetDexCache(), + handles), instruction_builder_(graph, &block_builder_, &ssa_builder_, @@ -80,10 +83,12 @@ 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, null_dex_cache_, handles), + ssa_builder_(graph, + handles->NewHandle<mirror::ClassLoader>(nullptr), + handles->NewHandle<mirror::DexCache>(nullptr), + handles), instruction_builder_(graph, &block_builder_, &ssa_builder_, @@ -96,7 +101,7 @@ class HGraphBuilder : public ValueObject { /* code_generator */ nullptr, /* interpreter_metadata */ nullptr, /* compiler_stats */ nullptr, - null_dex_cache_, + handles->NewHandle<mirror::DexCache>(nullptr), handles) {} GraphAnalysisResult BuildGraph(); @@ -117,8 +122,6 @@ class HGraphBuilder : public ValueObject { CompilerDriver* const compiler_driver_; - ScopedNullHandle<mirror::DexCache> null_dex_cache_; - OptimizingCompilerStats* compilation_stats_; HBasicBlockBuilder block_builder_; diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 97b61edbb9..28cc942dfb 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -2395,7 +2395,7 @@ void LocationsBuilderARM64::HandleShift(HBinaryOperation* instr) { case Primitive::kPrimLong: { locations->SetInAt(0, Location::RequiresRegister()); locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1))); - locations->SetOut(Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); break; } default: @@ -2565,7 +2565,7 @@ void LocationsBuilderARM64::VisitIntermediateAddress(HIntermediateAddress* instr new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); locations->SetInAt(0, Location::RequiresRegister()); locations->SetInAt(1, ARM64EncodableConstantOrRegister(instruction->GetOffset(), instruction)); - locations->SetOut(Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); } void InstructionCodeGeneratorARM64::VisitIntermediateAddress(HIntermediateAddress* instruction) { diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index f5ada5224b..d75779cef6 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -2000,15 +2000,10 @@ CodeGeneratorARMVIXL::CodeGeneratorARMVIXL(HGraph* graph, graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) { // Always save the LR register to mimic Quick. AddAllocatedRegister(Location::RegisterLocation(LR)); - // Give d14 and d15 as scratch registers to VIXL. - // They are removed from the register allocator in `SetupBlockedRegisters()`. - // TODO(VIXL): We need two scratch D registers for `EmitSwap` when swapping two double stack - // slots. If that is sufficiently rare, and we have pressure on FP registers, we could instead - // spill in `EmitSwap`. But if we actually are guaranteed to have 32 D registers, we could give - // d30 and d31 to VIXL to avoid removing registers from the allocator. If that is the case, we may - // also want to investigate giving those 14 other D registers to the allocator. - GetVIXLAssembler()->GetScratchVRegisterList()->Combine(d14); - GetVIXLAssembler()->GetScratchVRegisterList()->Combine(d15); + // Give D30 and D31 as scratch register to VIXL. The register allocator only works on + // S0-S31, which alias to D0-D15. + GetVIXLAssembler()->GetScratchVRegisterList()->Combine(d31); + GetVIXLAssembler()->GetScratchVRegisterList()->Combine(d30); } void JumpTableARMVIXL::EmitTable(CodeGeneratorARMVIXL* codegen) { @@ -2074,13 +2069,6 @@ void CodeGeneratorARMVIXL::SetupBlockedRegisters() const { // Reserve temp register. blocked_core_registers_[IP] = true; - // Registers s28-s31 (d14-d15) are left to VIXL for scratch registers. - // (They are given to the `MacroAssembler` in `CodeGeneratorARMVIXL::CodeGeneratorARMVIXL`.) - blocked_fpu_registers_[28] = true; - blocked_fpu_registers_[29] = true; - blocked_fpu_registers_[30] = true; - blocked_fpu_registers_[31] = true; - if (GetGraph()->IsDebuggable()) { // Stubs do not save callee-save floating point registers. If the graph // is debuggable, we need to deal with these registers differently. For @@ -6549,13 +6537,16 @@ void ParallelMoveResolverARMVIXL::Exchange(vixl32::Register reg, int mem) { void ParallelMoveResolverARMVIXL::Exchange(int mem1, int mem2) { // TODO(VIXL32): Double check the performance of this implementation. UseScratchRegisterScope temps(GetAssembler()->GetVIXLAssembler()); - vixl32::SRegister temp_1 = temps.AcquireS(); - vixl32::SRegister temp_2 = temps.AcquireS(); + vixl32::Register temp1 = temps.Acquire(); + ScratchRegisterScope ensure_scratch( + this, temp1.GetCode(), r0.GetCode(), codegen_->GetNumberOfCoreRegisters()); + vixl32::Register temp2(ensure_scratch.GetRegister()); - __ Vldr(temp_1, MemOperand(sp, mem1)); - __ Vldr(temp_2, MemOperand(sp, mem2)); - __ Vstr(temp_1, MemOperand(sp, mem2)); - __ Vstr(temp_2, MemOperand(sp, mem1)); + int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0; + GetAssembler()->LoadFromOffset(kLoadWord, temp1, sp, mem1 + stack_offset); + GetAssembler()->LoadFromOffset(kLoadWord, temp2, sp, mem2 + stack_offset); + GetAssembler()->StoreToOffset(kStoreWord, temp1, sp, mem2 + stack_offset); + GetAssembler()->StoreToOffset(kStoreWord, temp2, sp, mem1 + stack_offset); } void ParallelMoveResolverARMVIXL::EmitSwap(size_t index) { @@ -6578,7 +6569,7 @@ void ParallelMoveResolverARMVIXL::EmitSwap(size_t index) { } else if (source.IsStackSlot() && destination.IsStackSlot()) { Exchange(source.GetStackIndex(), destination.GetStackIndex()); } else if (source.IsFpuRegister() && destination.IsFpuRegister()) { - vixl32::SRegister temp = temps.AcquireS(); + vixl32::Register temp = temps.Acquire(); __ Vmov(temp, SRegisterFrom(source)); __ Vmov(SRegisterFrom(source), SRegisterFrom(destination)); __ Vmov(SRegisterFrom(destination), temp); @@ -6637,12 +6628,12 @@ void ParallelMoveResolverARMVIXL::EmitSwap(size_t index) { } } -void ParallelMoveResolverARMVIXL::SpillScratch(int reg ATTRIBUTE_UNUSED) { - TODO_VIXL32(FATAL); +void ParallelMoveResolverARMVIXL::SpillScratch(int reg) { + __ Push(vixl32::Register(reg)); } -void ParallelMoveResolverARMVIXL::RestoreScratch(int reg ATTRIBUTE_UNUSED) { - TODO_VIXL32(FATAL); +void ParallelMoveResolverARMVIXL::RestoreScratch(int reg) { + __ Pop(vixl32::Register(reg)); } HLoadClass::LoadKind CodeGeneratorARMVIXL::GetSupportedLoadClassKind( diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h index ef01a478f4..781027ab30 100644 --- a/compiler/optimizing/code_generator_arm_vixl.h +++ b/compiler/optimizing/code_generator_arm_vixl.h @@ -35,11 +35,11 @@ #include "aarch32/macro-assembler-aarch32.h" #pragma GCC diagnostic pop -// True if VIXL32 should be used for codegen on ARM. -#ifdef ART_USE_VIXL_ARM_BACKEND -static constexpr bool kArmUseVIXL32 = true; -#else +// Default to use the VIXL-based backend on ARM. +#ifdef ART_USE_OLD_ARM_BACKEND static constexpr bool kArmUseVIXL32 = false; +#else +static constexpr bool kArmUseVIXL32 = true; #endif namespace art { diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index 02c3ad6e39..5246dbc5cb 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -1681,6 +1681,25 @@ void InstructionCodeGeneratorMIPS64::VisitArrayLength(HArrayLength* instruction) } } +Location LocationsBuilderMIPS64::RegisterOrZeroConstant(HInstruction* instruction) { + return (instruction->IsConstant() && instruction->AsConstant()->IsZeroBitPattern()) + ? Location::ConstantLocation(instruction->AsConstant()) + : Location::RequiresRegister(); +} + +Location LocationsBuilderMIPS64::FpuRegisterOrConstantForStore(HInstruction* instruction) { + // We can store 0.0 directly (from the ZERO register) without loading it into an FPU register. + // We can store a non-zero float or double constant without first loading it into the FPU, + // but we should only prefer this if the constant has a single use. + if (instruction->IsConstant() && + (instruction->AsConstant()->IsZeroBitPattern() || + instruction->GetUses().HasExactlyOneElement())) { + return Location::ConstantLocation(instruction->AsConstant()); + // Otherwise fall through and require an FPU register for the constant. + } + return Location::RequiresFpuRegister(); +} + void LocationsBuilderMIPS64::VisitArraySet(HArraySet* instruction) { bool needs_runtime_call = instruction->NeedsTypeCheck(); LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary( @@ -1695,9 +1714,9 @@ void LocationsBuilderMIPS64::VisitArraySet(HArraySet* instruction) { locations->SetInAt(0, Location::RequiresRegister()); locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); if (Primitive::IsFloatingPointType(instruction->InputAt(2)->GetType())) { - locations->SetInAt(2, Location::RequiresFpuRegister()); + locations->SetInAt(2, FpuRegisterOrConstantForStore(instruction->InputAt(2))); } else { - locations->SetInAt(2, Location::RequiresRegister()); + locations->SetInAt(2, RegisterOrZeroConstant(instruction->InputAt(2))); } } } @@ -1706,24 +1725,29 @@ void InstructionCodeGeneratorMIPS64::VisitArraySet(HArraySet* instruction) { LocationSummary* locations = instruction->GetLocations(); GpuRegister obj = locations->InAt(0).AsRegister<GpuRegister>(); Location index = locations->InAt(1); + Location value_location = locations->InAt(2); Primitive::Type value_type = instruction->GetComponentType(); bool needs_runtime_call = locations->WillCall(); bool needs_write_barrier = CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue()); auto null_checker = GetImplicitNullChecker(instruction, codegen_); + GpuRegister base_reg = index.IsConstant() ? obj : TMP; switch (value_type) { case Primitive::kPrimBoolean: case Primitive::kPrimByte: { uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value(); - GpuRegister value = locations->InAt(2).AsRegister<GpuRegister>(); if (index.IsConstant()) { - size_t offset = - (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; - __ StoreToOffset(kStoreByte, value, obj, offset, null_checker); + data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1; } else { - __ Daddu(TMP, obj, index.AsRegister<GpuRegister>()); - __ StoreToOffset(kStoreByte, value, TMP, data_offset, null_checker); + __ Daddu(base_reg, obj, index.AsRegister<GpuRegister>()); + } + if (value_location.IsConstant()) { + int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant()); + __ StoreConstToOffset(kStoreByte, value, base_reg, data_offset, TMP, null_checker); + } else { + GpuRegister value = value_location.AsRegister<GpuRegister>(); + __ StoreToOffset(kStoreByte, value, base_reg, data_offset, null_checker); } break; } @@ -1731,15 +1755,18 @@ void InstructionCodeGeneratorMIPS64::VisitArraySet(HArraySet* instruction) { case Primitive::kPrimShort: case Primitive::kPrimChar: { uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value(); - GpuRegister value = locations->InAt(2).AsRegister<GpuRegister>(); if (index.IsConstant()) { - size_t offset = - (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; - __ StoreToOffset(kStoreHalfword, value, obj, offset, null_checker); + data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2; } else { - __ Dsll(TMP, index.AsRegister<GpuRegister>(), TIMES_2); - __ Daddu(TMP, obj, TMP); - __ StoreToOffset(kStoreHalfword, value, TMP, data_offset, null_checker); + __ Dsll(base_reg, index.AsRegister<GpuRegister>(), TIMES_2); + __ Daddu(base_reg, obj, base_reg); + } + if (value_location.IsConstant()) { + int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant()); + __ StoreConstToOffset(kStoreHalfword, value, base_reg, data_offset, TMP, null_checker); + } else { + GpuRegister value = value_location.AsRegister<GpuRegister>(); + __ StoreToOffset(kStoreHalfword, value, base_reg, data_offset, null_checker); } break; } @@ -1748,54 +1775,57 @@ void InstructionCodeGeneratorMIPS64::VisitArraySet(HArraySet* instruction) { case Primitive::kPrimNot: { if (!needs_runtime_call) { uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); - GpuRegister base_reg; - GpuRegister value = locations->InAt(2).AsRegister<GpuRegister>(); if (index.IsConstant()) { data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4; - base_reg = obj; } else { DCHECK(index.IsRegister()) << index; - __ Dsll(TMP, index.AsRegister<GpuRegister>(), TIMES_4); - __ Daddu(TMP, obj, TMP); - base_reg = TMP; + __ Dsll(base_reg, index.AsRegister<GpuRegister>(), TIMES_4); + __ Daddu(base_reg, obj, base_reg); } - if (kPoisonHeapReferences && needs_write_barrier) { - // Note that in the case where `value` is a null reference, - // we do not enter this block, as a null reference does not - // need poisoning. - DCHECK_EQ(value_type, Primitive::kPrimNot); - // Use Sw() instead of StoreToOffset() in order to be able to - // hold the poisoned reference in AT and thus avoid allocating - // yet another temporary register. - if (index.IsConstant()) { - if (!IsInt<16>(static_cast<int32_t>(data_offset))) { - int16_t low16 = Low16Bits(data_offset); - // For consistency with StoreToOffset() and such treat data_offset as int32_t. - uint64_t high48 = static_cast<uint64_t>(static_cast<int32_t>(data_offset)) - low16; - int16_t upper16 = High16Bits(high48); - // Allow the full [-2GB,+2GB) range in case `low16` is negative and needs a - // compensatory 64KB added, which may push `high48` above 2GB and require - // the dahi instruction. - int16_t higher16 = High32Bits(high48) + ((upper16 < 0) ? 1 : 0); - __ Daui(TMP, obj, upper16); - if (higher16 != 0) { - __ Dahi(TMP, higher16); + if (value_location.IsConstant()) { + int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant()); + __ StoreConstToOffset(kStoreWord, value, base_reg, data_offset, TMP, null_checker); + DCHECK(!needs_write_barrier); + } else { + GpuRegister value = value_location.AsRegister<GpuRegister>(); + if (kPoisonHeapReferences && needs_write_barrier) { + // Note that in the case where `value` is a null reference, + // we do not enter this block, as a null reference does not + // need poisoning. + DCHECK_EQ(value_type, Primitive::kPrimNot); + // Use Sw() instead of StoreToOffset() in order to be able to + // hold the poisoned reference in AT and thus avoid allocating + // yet another temporary register. + if (index.IsConstant()) { + if (!IsInt<16>(static_cast<int32_t>(data_offset))) { + int16_t low16 = Low16Bits(data_offset); + // For consistency with StoreToOffset() and such treat data_offset as int32_t. + uint64_t high48 = static_cast<uint64_t>(static_cast<int32_t>(data_offset)) - low16; + int16_t upper16 = High16Bits(high48); + // Allow the full [-2GB,+2GB) range in case `low16` is negative and needs a + // compensatory 64KB added, which may push `high48` above 2GB and require + // the dahi instruction. + int16_t higher16 = High32Bits(high48) + ((upper16 < 0) ? 1 : 0); + __ Daui(TMP, obj, upper16); + if (higher16 != 0) { + __ Dahi(TMP, higher16); + } + base_reg = TMP; + data_offset = low16; } - base_reg = TMP; - data_offset = low16; + } else { + DCHECK(IsInt<16>(static_cast<int32_t>(data_offset))); } + __ PoisonHeapReference(AT, value); + __ Sw(AT, base_reg, data_offset); + null_checker(); } else { - DCHECK(IsInt<16>(static_cast<int32_t>(data_offset))); + __ StoreToOffset(kStoreWord, value, base_reg, data_offset, null_checker); + } + if (needs_write_barrier) { + DCHECK_EQ(value_type, Primitive::kPrimNot); + codegen_->MarkGCCard(obj, value, instruction->GetValueCanBeNull()); } - __ PoisonHeapReference(AT, value); - __ Sw(AT, base_reg, data_offset); - null_checker(); - } else { - __ StoreToOffset(kStoreWord, value, base_reg, data_offset, null_checker); - } - if (needs_write_barrier) { - DCHECK_EQ(value_type, Primitive::kPrimNot); - codegen_->MarkGCCard(obj, value, instruction->GetValueCanBeNull()); } } else { DCHECK_EQ(value_type, Primitive::kPrimNot); @@ -1809,47 +1839,54 @@ void InstructionCodeGeneratorMIPS64::VisitArraySet(HArraySet* instruction) { case Primitive::kPrimLong: { uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value(); - GpuRegister value = locations->InAt(2).AsRegister<GpuRegister>(); if (index.IsConstant()) { - size_t offset = - (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; - __ StoreToOffset(kStoreDoubleword, value, obj, offset, null_checker); + data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8; } else { - __ Dsll(TMP, index.AsRegister<GpuRegister>(), TIMES_8); - __ Daddu(TMP, obj, TMP); - __ StoreToOffset(kStoreDoubleword, value, TMP, data_offset, null_checker); + __ Dsll(base_reg, index.AsRegister<GpuRegister>(), TIMES_8); + __ Daddu(base_reg, obj, base_reg); + } + if (value_location.IsConstant()) { + int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant()); + __ StoreConstToOffset(kStoreDoubleword, value, base_reg, data_offset, TMP, null_checker); + } else { + GpuRegister value = value_location.AsRegister<GpuRegister>(); + __ StoreToOffset(kStoreDoubleword, value, base_reg, data_offset, null_checker); } break; } case Primitive::kPrimFloat: { uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value(); - FpuRegister value = locations->InAt(2).AsFpuRegister<FpuRegister>(); - DCHECK(locations->InAt(2).IsFpuRegister()); if (index.IsConstant()) { - size_t offset = - (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; - __ StoreFpuToOffset(kStoreWord, value, obj, offset, null_checker); + data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4; } else { - __ Dsll(TMP, index.AsRegister<GpuRegister>(), TIMES_4); - __ Daddu(TMP, obj, TMP); - __ StoreFpuToOffset(kStoreWord, value, TMP, data_offset, null_checker); + __ Dsll(base_reg, index.AsRegister<GpuRegister>(), TIMES_4); + __ Daddu(base_reg, obj, base_reg); + } + if (value_location.IsConstant()) { + int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant()); + __ StoreConstToOffset(kStoreWord, value, base_reg, data_offset, TMP, null_checker); + } else { + FpuRegister value = value_location.AsFpuRegister<FpuRegister>(); + __ StoreFpuToOffset(kStoreWord, value, base_reg, data_offset, null_checker); } break; } case Primitive::kPrimDouble: { uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value(); - FpuRegister value = locations->InAt(2).AsFpuRegister<FpuRegister>(); - DCHECK(locations->InAt(2).IsFpuRegister()); if (index.IsConstant()) { - size_t offset = - (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; - __ StoreFpuToOffset(kStoreDoubleword, value, obj, offset, null_checker); + data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8; } else { - __ Dsll(TMP, index.AsRegister<GpuRegister>(), TIMES_8); - __ Daddu(TMP, obj, TMP); - __ StoreFpuToOffset(kStoreDoubleword, value, TMP, data_offset, null_checker); + __ Dsll(base_reg, index.AsRegister<GpuRegister>(), TIMES_8); + __ Daddu(base_reg, obj, base_reg); + } + if (value_location.IsConstant()) { + int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant()); + __ StoreConstToOffset(kStoreDoubleword, value, base_reg, data_offset, TMP, null_checker); + } else { + FpuRegister value = value_location.AsFpuRegister<FpuRegister>(); + __ StoreFpuToOffset(kStoreDoubleword, value, base_reg, data_offset, null_checker); } break; } @@ -3326,9 +3363,9 @@ void LocationsBuilderMIPS64::HandleFieldSet(HInstruction* instruction, new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); locations->SetInAt(0, Location::RequiresRegister()); if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) { - locations->SetInAt(1, Location::RequiresFpuRegister()); + locations->SetInAt(1, FpuRegisterOrConstantForStore(instruction->InputAt(1))); } else { - locations->SetInAt(1, Location::RequiresRegister()); + locations->SetInAt(1, RegisterOrZeroConstant(instruction->InputAt(1))); } } @@ -3338,6 +3375,7 @@ void InstructionCodeGeneratorMIPS64::HandleFieldSet(HInstruction* instruction, Primitive::Type type = field_info.GetFieldType(); LocationSummary* locations = instruction->GetLocations(); GpuRegister obj = locations->InAt(0).AsRegister<GpuRegister>(); + Location value_location = locations->InAt(1); StoreOperandType store_type = kStoreByte; uint32_t offset = field_info.GetFieldOffset().Uint32Value(); bool needs_write_barrier = CodeGenerator::StoreNeedsWriteBarrier(type, instruction->InputAt(1)); @@ -3365,29 +3403,34 @@ void InstructionCodeGeneratorMIPS64::HandleFieldSet(HInstruction* instruction, LOG(FATAL) << "Unreachable type " << type; UNREACHABLE(); } - if (!Primitive::IsFloatingPointType(type)) { - DCHECK(locations->InAt(1).IsRegister()); - GpuRegister src = locations->InAt(1).AsRegister<GpuRegister>(); - if (kPoisonHeapReferences && needs_write_barrier) { - // Note that in the case where `value` is a null reference, - // we do not enter this block, as a null reference does not - // need poisoning. - DCHECK_EQ(type, Primitive::kPrimNot); - __ PoisonHeapReference(TMP, src); - __ StoreToOffset(store_type, TMP, obj, offset, null_checker); + + if (value_location.IsConstant()) { + int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant()); + __ StoreConstToOffset(store_type, value, obj, offset, TMP, null_checker); + } else { + if (!Primitive::IsFloatingPointType(type)) { + DCHECK(value_location.IsRegister()); + GpuRegister src = value_location.AsRegister<GpuRegister>(); + if (kPoisonHeapReferences && needs_write_barrier) { + // Note that in the case where `value` is a null reference, + // we do not enter this block, as a null reference does not + // need poisoning. + DCHECK_EQ(type, Primitive::kPrimNot); + __ PoisonHeapReference(TMP, src); + __ StoreToOffset(store_type, TMP, obj, offset, null_checker); + } else { + __ StoreToOffset(store_type, src, obj, offset, null_checker); + } } else { - __ StoreToOffset(store_type, src, obj, offset, null_checker); + DCHECK(value_location.IsFpuRegister()); + FpuRegister src = value_location.AsFpuRegister<FpuRegister>(); + __ StoreFpuToOffset(store_type, src, obj, offset, null_checker); } - } else { - DCHECK(locations->InAt(1).IsFpuRegister()); - FpuRegister src = locations->InAt(1).AsFpuRegister<FpuRegister>(); - __ StoreFpuToOffset(store_type, src, obj, offset, null_checker); } - // TODO: memory barriers? if (needs_write_barrier) { - DCHECK(locations->InAt(1).IsRegister()); - GpuRegister src = locations->InAt(1).AsRegister<GpuRegister>(); + DCHECK(value_location.IsRegister()); + GpuRegister src = value_location.AsRegister<GpuRegister>(); codegen_->MarkGCCard(obj, src, value_can_be_null); } } @@ -5067,12 +5110,34 @@ void InstructionCodeGeneratorMIPS64::VisitPackedSwitch(HPackedSwitch* switch_ins } } -void LocationsBuilderMIPS64::VisitClassTableGet(HClassTableGet*) { - UNIMPLEMENTED(FATAL) << "ClassTableGet is unimplemented on mips64"; +void LocationsBuilderMIPS64::VisitClassTableGet(HClassTableGet* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister()); } -void InstructionCodeGeneratorMIPS64::VisitClassTableGet(HClassTableGet*) { - UNIMPLEMENTED(FATAL) << "ClassTableGet is unimplemented on mips64"; +void InstructionCodeGeneratorMIPS64::VisitClassTableGet(HClassTableGet* instruction) { + LocationSummary* locations = instruction->GetLocations(); + if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) { + uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset( + instruction->GetIndex(), kMips64PointerSize).SizeValue(); + __ LoadFromOffset(kLoadDoubleword, + locations->Out().AsRegister<GpuRegister>(), + locations->InAt(0).AsRegister<GpuRegister>(), + method_offset); + } else { + uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement( + instruction->GetIndex(), kMips64PointerSize)); + __ LoadFromOffset(kLoadDoubleword, + locations->Out().AsRegister<GpuRegister>(), + locations->InAt(0).AsRegister<GpuRegister>(), + mirror::Class::ImtPtrOffset(kMips64PointerSize).Uint32Value()); + __ LoadFromOffset(kLoadDoubleword, + locations->Out().AsRegister<GpuRegister>(), + locations->Out().AsRegister<GpuRegister>(), + method_offset); + } } } // namespace mips64 diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h index 3056f7f464..6040dc9492 100644 --- a/compiler/optimizing/code_generator_mips64.h +++ b/compiler/optimizing/code_generator_mips64.h @@ -189,6 +189,8 @@ class LocationsBuilderMIPS64 : public HGraphVisitor { void HandleShift(HBinaryOperation* operation); void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info); void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); + Location RegisterOrZeroConstant(HInstruction* instruction); + Location FpuRegisterOrConstantForStore(HInstruction* instruction); InvokeDexCallingConventionVisitorMIPS64 parameter_visitor_; diff --git a/compiler/optimizing/dex_cache_array_fixups_arm.cc b/compiler/optimizing/dex_cache_array_fixups_arm.cc index cfcb276a98..0c832a5c35 100644 --- a/compiler/optimizing/dex_cache_array_fixups_arm.cc +++ b/compiler/optimizing/dex_cache_array_fixups_arm.cc @@ -17,23 +17,23 @@ #include "dex_cache_array_fixups_arm.h" #include "base/arena_containers.h" -#ifdef ART_USE_VIXL_ARM_BACKEND -#include "code_generator_arm_vixl.h" -#include "intrinsics_arm_vixl.h" -#else +#ifdef ART_USE_OLD_ARM_BACKEND #include "code_generator_arm.h" #include "intrinsics_arm.h" +#else +#include "code_generator_arm_vixl.h" +#include "intrinsics_arm_vixl.h" #endif #include "utils/dex_cache_arrays_layout-inl.h" namespace art { namespace arm { -#ifdef ART_USE_VIXL_ARM_BACKEND -typedef CodeGeneratorARMVIXL CodeGeneratorARMType; -typedef IntrinsicLocationsBuilderARMVIXL IntrinsicLocationsBuilderARMType; -#else +#ifdef ART_USE_OLD_ARM_BACKEND typedef CodeGeneratorARM CodeGeneratorARMType; typedef IntrinsicLocationsBuilderARM IntrinsicLocationsBuilderARMType; +#else +typedef CodeGeneratorARMVIXL CodeGeneratorARMType; +typedef IntrinsicLocationsBuilderARMVIXL IntrinsicLocationsBuilderARMType; #endif /** diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 2e45149b43..8a813bd54c 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -192,9 +192,9 @@ static uint32_t FindMethodIndexIn(ArtMethod* method, } static dex::TypeIndex FindClassIndexIn(mirror::Class* cls, - const DexFile& dex_file, - Handle<mirror::DexCache> dex_cache) + const DexCompilationUnit& compilation_unit) REQUIRES_SHARED(Locks::mutator_lock_) { + const DexFile& dex_file = *compilation_unit.GetDexFile(); dex::TypeIndex index; if (cls->GetDexCache() == nullptr) { DCHECK(cls->IsArrayClass()) << cls->PrettyClass(); @@ -203,22 +203,19 @@ 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(), dex_cache.Get()); + DCHECK_EQ(cls->GetDexCache(), compilation_unit.GetDexCache().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 in the dex cache will resolve to the same class, + // We cannot guarantee the entry will resolve to the same class, // as there may be different class loaders. So only return the index if it's - // the right class in the dex cache already. - if (index.IsValid() && dex_cache->GetResolvedType(index) != cls) { - index = dex::TypeIndex::Invalid(); + // the right class already resolved with the class loader. + if (index.IsValid()) { + ObjPtr<mirror::Class> resolved = ClassLinker::LookupResolvedType( + index, compilation_unit.GetDexCache().Get(), compilation_unit.GetClassLoader().Get()); + if (resolved != cls) { + index = dex::TypeIndex::Invalid(); + } } } @@ -536,7 +533,10 @@ HInliner::InlineCacheType HInliner::ExtractClassesFromOfflineProfile( ObjPtr<mirror::DexCache> dex_cache = dex_profile_index_to_dex_cache[class_ref.dex_profile_index]; DCHECK(dex_cache != nullptr); - ObjPtr<mirror::Class> clazz = dex_cache->GetResolvedType(class_ref.type_index); + ObjPtr<mirror::Class> clazz = ClassLinker::LookupResolvedType( + class_ref.type_index, + dex_cache, + caller_compilation_unit_.GetClassLoader().Get()); if (clazz != nullptr) { inline_cache->Set(ic_index++, clazz); } else { @@ -577,9 +577,8 @@ 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_dex_file, caller_compilation_unit_.GetDexCache()); + GetMonomorphicType(classes), caller_compilation_unit_); if (!class_index.IsValid()) { VLOG(compiler) << "Call to " << ArtMethod::PrettyMethod(resolved_method) << " from inline cache is not inlined because its class is not" @@ -622,6 +621,7 @@ bool HInliner::TryInlineMonomorphicCall(HInvoke* invoke_instruction, // Run type propagation to get the guard typed, and eventually propagate the // type of the receiver. ReferenceTypePropagation rtp_fixup(graph_, + outer_compilation_unit_.GetClassLoader(), outer_compilation_unit_.GetDexCache(), handles_, /* is_first_run */ false); @@ -722,7 +722,6 @@ 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; @@ -744,8 +743,7 @@ 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_dex_file, caller_compilation_unit_.GetDexCache()); + dex::TypeIndex class_index = FindClassIndexIn(handle.Get(), caller_compilation_unit_); HInstruction* return_replacement = nullptr; if (!class_index.IsValid() || !TryBuildAndInline(invoke_instruction, @@ -801,6 +799,7 @@ 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); @@ -893,10 +892,6 @@ bool HInliner::TryInlinePolymorphicCallToSameTarget( return false; } - if (graph_->GetInstructionSet() == kMips64) { - // TODO: Support HClassTableGet for mips64. - return false; - } ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker(); PointerSize pointer_size = class_linker->GetImagePointerSize(); @@ -997,6 +992,7 @@ bool HInliner::TryInlinePolymorphicCallToSameTarget( // Run type propagation to get the guard typed. ReferenceTypePropagation rtp_fixup(graph_, + outer_compilation_unit_.GetClassLoader(), outer_compilation_unit_.GetDexCache(), handles_, /* is_first_run */ false); @@ -1065,6 +1061,7 @@ 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(); @@ -1208,9 +1205,8 @@ bool HInliner::TryPatternSubstitution(HInvoke* invoke_instruction, // TODO: Needs null check. return false; } - Handle<mirror::DexCache> dex_cache(handles_->NewHandle(resolved_method->GetDexCache())); HInstruction* obj = GetInvokeInputForArgVRegIndex(invoke_instruction, data.object_arg); - HInstanceFieldGet* iget = CreateInstanceFieldGet(dex_cache, data.field_idx, obj); + HInstanceFieldGet* iget = CreateInstanceFieldGet(data.field_idx, resolved_method, obj); DCHECK_EQ(iget->GetFieldOffset().Uint32Value(), data.field_offset); DCHECK_EQ(iget->IsVolatile() ? 1u : 0u, data.is_volatile); invoke_instruction->GetBlock()->InsertInstructionBefore(iget, invoke_instruction); @@ -1223,10 +1219,9 @@ bool HInliner::TryPatternSubstitution(HInvoke* invoke_instruction, // TODO: Needs null check. return false; } - Handle<mirror::DexCache> dex_cache(handles_->NewHandle(resolved_method->GetDexCache())); HInstruction* obj = GetInvokeInputForArgVRegIndex(invoke_instruction, data.object_arg); HInstruction* value = GetInvokeInputForArgVRegIndex(invoke_instruction, data.src_arg); - HInstanceFieldSet* iput = CreateInstanceFieldSet(dex_cache, data.field_idx, obj, value); + HInstanceFieldSet* iput = CreateInstanceFieldSet(data.field_idx, resolved_method, obj, value); DCHECK_EQ(iput->GetFieldOffset().Uint32Value(), data.field_offset); DCHECK_EQ(iput->IsVolatile() ? 1u : 0u, data.is_volatile); invoke_instruction->GetBlock()->InsertInstructionBefore(iput, invoke_instruction); @@ -1260,24 +1255,19 @@ bool HInliner::TryPatternSubstitution(HInvoke* invoke_instruction, [](uint16_t index) { return index != DexFile::kDexNoIndex16; })); // Create HInstanceFieldSet for each IPUT that stores non-zero data. - Handle<mirror::DexCache> dex_cache; HInstruction* obj = GetInvokeInputForArgVRegIndex(invoke_instruction, /* this */ 0u); bool needs_constructor_barrier = false; for (size_t i = 0; i != number_of_iputs; ++i) { HInstruction* value = GetInvokeInputForArgVRegIndex(invoke_instruction, iput_args[i]); if (!value->IsConstant() || !value->AsConstant()->IsZeroBitPattern()) { - if (dex_cache.GetReference() == nullptr) { - dex_cache = handles_->NewHandle(resolved_method->GetDexCache()); - } uint16_t field_index = iput_field_indexes[i]; - HInstanceFieldSet* iput = CreateInstanceFieldSet(dex_cache, field_index, obj, value); + bool is_final; + HInstanceFieldSet* iput = + CreateInstanceFieldSet(field_index, resolved_method, obj, value, &is_final); invoke_instruction->GetBlock()->InsertInstructionBefore(iput, invoke_instruction); // Check whether the field is final. If it is, we need to add a barrier. - PointerSize pointer_size = InstructionSetPointerSize(codegen_->GetInstructionSet()); - ArtField* resolved_field = dex_cache->GetResolvedField(field_index, pointer_size); - DCHECK(resolved_field != nullptr); - if (resolved_field->IsFinal()) { + if (is_final) { needs_constructor_barrier = true; } } @@ -1296,12 +1286,13 @@ bool HInliner::TryPatternSubstitution(HInvoke* invoke_instruction, return true; } -HInstanceFieldGet* HInliner::CreateInstanceFieldGet(Handle<mirror::DexCache> dex_cache, - uint32_t field_index, +HInstanceFieldGet* HInliner::CreateInstanceFieldGet(uint32_t field_index, + ArtMethod* referrer, HInstruction* obj) REQUIRES_SHARED(Locks::mutator_lock_) { - PointerSize pointer_size = InstructionSetPointerSize(codegen_->GetInstructionSet()); - ArtField* resolved_field = dex_cache->GetResolvedField(field_index, pointer_size); + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + ArtField* resolved_field = + class_linker->LookupResolvedField(field_index, referrer, /* is_static */ false); DCHECK(resolved_field != nullptr); HInstanceFieldGet* iget = new (graph_->GetArena()) HInstanceFieldGet( obj, @@ -1311,26 +1302,38 @@ HInstanceFieldGet* HInliner::CreateInstanceFieldGet(Handle<mirror::DexCache> dex resolved_field->IsVolatile(), field_index, resolved_field->GetDeclaringClass()->GetDexClassDefIndex(), - *dex_cache->GetDexFile(), + *referrer->GetDexFile(), // Read barrier generates a runtime call in slow path and we need a valid // dex pc for the associated stack map. 0 is bogus but valid. Bug: 26854537. /* 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_, dex_cache, handles_, /* is_first_run */ false); + Handle<mirror::DexCache> dex_cache = handles_->NewHandle(referrer->GetDexCache()); + ReferenceTypePropagation rtp(graph_, + outer_compilation_unit_.GetClassLoader(), + dex_cache, + handles_, + /* is_first_run */ false); rtp.Visit(iget); } return iget; } -HInstanceFieldSet* HInliner::CreateInstanceFieldSet(Handle<mirror::DexCache> dex_cache, - uint32_t field_index, +HInstanceFieldSet* HInliner::CreateInstanceFieldSet(uint32_t field_index, + ArtMethod* referrer, HInstruction* obj, - HInstruction* value) + HInstruction* value, + bool* is_final) REQUIRES_SHARED(Locks::mutator_lock_) { - PointerSize pointer_size = InstructionSetPointerSize(codegen_->GetInstructionSet()); - ArtField* resolved_field = dex_cache->GetResolvedField(field_index, pointer_size); + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + ArtField* resolved_field = + class_linker->LookupResolvedField(field_index, referrer, /* is_static */ false); DCHECK(resolved_field != nullptr); + if (is_final != nullptr) { + // This information is needed only for constructors. + DCHECK(referrer->IsConstructor()); + *is_final = resolved_field->IsFinal(); + } HInstanceFieldSet* iput = new (graph_->GetArena()) HInstanceFieldSet( obj, value, @@ -1340,7 +1343,7 @@ HInstanceFieldSet* HInliner::CreateInstanceFieldSet(Handle<mirror::DexCache> dex resolved_field->IsVolatile(), field_index, resolved_field->GetDeclaringClass()->GetDexClassDefIndex(), - *dex_cache->GetDexFile(), + *referrer->GetDexFile(), // Read barrier generates a runtime call in slow path and we need a valid // dex pc for the associated stack map. 0 is bogus but valid. Bug: 26854537. /* dex_pc */ 0); @@ -1363,7 +1366,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, resolved_method->GetDeclaringClass()->GetClassLoader())); DexCompilationUnit dex_compilation_unit( - class_loader.ToJObject(), + class_loader, class_linker, callee_dex_file, code_item, @@ -1487,6 +1490,7 @@ 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/inliner.h b/compiler/optimizing/inliner.h index 8f8b268cb2..a032042c78 100644 --- a/compiler/optimizing/inliner.h +++ b/compiler/optimizing/inliner.h @@ -107,14 +107,15 @@ class HInliner : public HOptimization { REQUIRES_SHARED(Locks::mutator_lock_); // Create a new HInstanceFieldGet. - HInstanceFieldGet* CreateInstanceFieldGet(Handle<mirror::DexCache> dex_cache, - uint32_t field_index, + HInstanceFieldGet* CreateInstanceFieldGet(uint32_t field_index, + ArtMethod* referrer, HInstruction* obj); // Create a new HInstanceFieldSet. - HInstanceFieldSet* CreateInstanceFieldSet(Handle<mirror::DexCache> dex_cache, - uint32_t field_index, + HInstanceFieldSet* CreateInstanceFieldSet(uint32_t field_index, + ArtMethod* referrer, HInstruction* obj, - HInstruction* value); + HInstruction* value, + bool* is_final = nullptr); // Try inlining the invoke instruction using inline caches. bool TryInlineFromInlineCache( diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index 1053da44d6..88f67fae04 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -677,11 +677,10 @@ static InvokeType GetInvokeTypeFromOpCode(Instruction::Code opcode) { ArtMethod* HInstructionBuilder::ResolveMethod(uint16_t method_idx, InvokeType invoke_type) { ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<3> hs(soa.Self()); + StackHandleScope<2> hs(soa.Self()); ClassLinker* class_linker = dex_compilation_unit_->GetClassLinker(); - Handle<mirror::ClassLoader> class_loader(hs.NewHandle( - soa.Decode<mirror::ClassLoader>(dex_compilation_unit_->GetClassLoader()))); + Handle<mirror::ClassLoader> class_loader = dex_compilation_unit_->GetClassLoader(); Handle<mirror::Class> compiling_class(hs.NewHandle(GetCompilingClass())); // We fetch the referenced class eagerly (that is, the class pointed by in the MethodId // at method_idx), as `CanAccessResolvedMethod` expects it be be in the dex cache. @@ -1268,9 +1267,7 @@ bool HInstructionBuilder::BuildInstanceFieldAccess(const Instruction& instructio static mirror::Class* GetClassFrom(CompilerDriver* driver, const DexCompilationUnit& compilation_unit) { ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<1> hs(soa.Self()); - Handle<mirror::ClassLoader> class_loader(hs.NewHandle( - soa.Decode<mirror::ClassLoader>(compilation_unit.GetClassLoader()))); + Handle<mirror::ClassLoader> class_loader = compilation_unit.GetClassLoader(); Handle<mirror::DexCache> dex_cache = compilation_unit.GetDexCache(); return driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, &compilation_unit); @@ -1286,10 +1283,9 @@ mirror::Class* HInstructionBuilder::GetCompilingClass() const { bool HInstructionBuilder::IsOutermostCompilingClass(dex::TypeIndex type_index) const { ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<3> hs(soa.Self()); + StackHandleScope<2> hs(soa.Self()); Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache(); - Handle<mirror::ClassLoader> class_loader(hs.NewHandle( - soa.Decode<mirror::ClassLoader>(dex_compilation_unit_->GetClassLoader()))); + Handle<mirror::ClassLoader> class_loader = dex_compilation_unit_->GetClassLoader(); Handle<mirror::Class> cls(hs.NewHandle(compiler_driver_->ResolveClass( soa, dex_cache, class_loader, type_index, dex_compilation_unit_))); Handle<mirror::Class> outer_class(hs.NewHandle(GetOutermostCompilingClass())); @@ -1325,8 +1321,7 @@ ArtField* HInstructionBuilder::ResolveField(uint16_t field_idx, bool is_static, StackHandleScope<2> hs(soa.Self()); ClassLinker* class_linker = dex_compilation_unit_->GetClassLinker(); - Handle<mirror::ClassLoader> class_loader(hs.NewHandle( - soa.Decode<mirror::ClassLoader>(dex_compilation_unit_->GetClassLoader()))); + Handle<mirror::ClassLoader> class_loader = dex_compilation_unit_->GetClassLoader(); Handle<mirror::Class> compiling_class(hs.NewHandle(GetCompilingClass())); ArtField* resolved_field = class_linker->ResolveField(*dex_compilation_unit_->GetDexFile(), @@ -1643,10 +1638,8 @@ static TypeCheckKind ComputeTypeCheckKind(Handle<mirror::Class> cls) HLoadClass* HInstructionBuilder::BuildLoadClass(dex::TypeIndex type_index, uint32_t dex_pc) { ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<2> hs(soa.Self()); const DexFile& dex_file = *dex_compilation_unit_->GetDexFile(); - Handle<mirror::ClassLoader> class_loader(hs.NewHandle( - soa.Decode<mirror::ClassLoader>(dex_compilation_unit_->GetClassLoader()))); + Handle<mirror::ClassLoader> class_loader = dex_compilation_unit_->GetClassLoader(); Handle<mirror::Class> klass = handles_->NewHandle(compiler_driver_->ResolveClass( soa, dex_compilation_unit_->GetDexCache(), class_loader, type_index, dex_compilation_unit_)); @@ -1730,17 +1723,9 @@ void HInstructionBuilder::BuildTypeCheck(const Instruction& instruction, } } -bool HInstructionBuilder::NeedsAccessCheck(dex::TypeIndex type_index, - Handle<mirror::DexCache> dex_cache, - bool* finalizable) const { - return !compiler_driver_->CanAccessInstantiableTypeWithoutChecks( - dex_compilation_unit_->GetDexMethodIndex(), dex_cache, type_index, finalizable); -} - bool HInstructionBuilder::NeedsAccessCheck(dex::TypeIndex type_index, bool* finalizable) const { - ScopedObjectAccess soa(Thread::Current()); - Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache(); - return NeedsAccessCheck(type_index, dex_cache, finalizable); + return !compiler_driver_->CanAccessInstantiableTypeWithoutChecks( + LookupReferrerClass(), LookupResolvedType(type_index, *dex_compilation_unit_), finalizable); } bool HInstructionBuilder::CanDecodeQuickenedInfo() const { @@ -2780,4 +2765,18 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction, return true; } // NOLINT(readability/fn_size) +ObjPtr<mirror::Class> HInstructionBuilder::LookupResolvedType( + dex::TypeIndex type_index, + const DexCompilationUnit& compilation_unit) const { + return ClassLinker::LookupResolvedType( + type_index, compilation_unit.GetDexCache().Get(), compilation_unit.GetClassLoader().Get()); +} + +ObjPtr<mirror::Class> HInstructionBuilder::LookupReferrerClass() const { + // TODO: Cache the result in a Handle<mirror::Class>. + const DexFile::MethodId& method_id = + dex_compilation_unit_->GetDexFile()->GetMethodId(dex_compilation_unit_->GetDexMethodIndex()); + return LookupResolvedType(method_id.class_idx_, *dex_compilation_unit_); +} + } // namespace art diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h index 6cb6655252..7fdc1883ca 100644 --- a/compiler/optimizing/instruction_builder.h +++ b/compiler/optimizing/instruction_builder.h @@ -110,11 +110,8 @@ 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, - Handle<mirror::DexCache> dex_cache, - /*out*/bool* finalizable) const + bool NeedsAccessCheck(dex::TypeIndex type_index, /*out*/bool* finalizable) const REQUIRES_SHARED(Locks::mutator_lock_); - bool NeedsAccessCheck(dex::TypeIndex type_index, /*out*/bool* finalizable) const; template<typename T> void Unop_12x(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc); @@ -304,6 +301,12 @@ class HInstructionBuilder : public ValueObject { // be found. ArtField* ResolveField(uint16_t field_idx, bool is_static, bool is_put); + ObjPtr<mirror::Class> LookupResolvedType(dex::TypeIndex type_index, + const DexCompilationUnit& compilation_unit) const + REQUIRES_SHARED(Locks::mutator_lock_); + + ObjPtr<mirror::Class> LookupReferrerClass() const REQUIRES_SHARED(Locks::mutator_lock_); + ArenaAllocator* const arena_; HGraph* const graph_; VariableSizedHandleScope* handles_; diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index 934ba1b9fb..807d6cf54f 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -1560,7 +1560,10 @@ void IntrinsicCodeGeneratorARM64::VisitStringEquals(HInvoke* invoke) { // Load `count` field of the argument string and check if it matches the const string. // Also compares the compression style, if differs return false. __ Ldr(temp, MemOperand(arg.X(), count_offset)); + // Temporarily release temp1 as we may not be able to embed the flagged count in CMP immediate. + scratch_scope.Release(temp1); __ Cmp(temp, Operand(mirror::String::GetFlaggedCount(const_string_length, is_compressed))); + temp1 = scratch_scope.AcquireW(); __ B(&return_false, ne); } else { // Load `count` fields of this and argument strings. diff --git a/compiler/optimizing/optimizing_cfi_test.cc b/compiler/optimizing/optimizing_cfi_test.cc index 0e02311672..490e50cb77 100644 --- a/compiler/optimizing/optimizing_cfi_test.cc +++ b/compiler/optimizing/optimizing_cfi_test.cc @@ -24,17 +24,17 @@ #include "optimizing/code_generator.h" #include "optimizing/optimizing_unit_test.h" #include "utils/assembler.h" -#ifdef ART_USE_VIXL_ARM_BACKEND -#include "utils/arm/assembler_arm_vixl.h" -#else +#ifdef ART_USE_OLD_ARM_BACKEND #include "utils/arm/assembler_thumb2.h" +#else +#include "utils/arm/assembler_arm_vixl.h" #endif #include "utils/mips/assembler_mips.h" #include "utils/mips64/assembler_mips64.h" #include "optimizing/optimizing_cfi_test_expected.inc" -#ifdef ART_USE_VIXL_ARM_BACKEND +#ifndef ART_USE_OLD_ARM_BACKEND namespace vixl32 = vixl::aarch32; using vixl32::r0; @@ -196,7 +196,15 @@ TEST_F(OptimizingCFITest, kThumb2Adjust) { expected_cfi_kThumb2_adjust, expected_cfi_kThumb2_adjust + arraysize(expected_cfi_kThumb2_adjust)); SetUpFrame(kThumb2); -#ifdef ART_USE_VIXL_ARM_BACKEND +#ifdef ART_USE_OLD_ARM_BACKEND +#define __ down_cast<arm::Thumb2Assembler*>(GetCodeGenerator()->GetAssembler())-> + Label target; + __ CompareAndBranchIfZero(arm::R0, &target); + // Push the target out of range of CBZ. + for (size_t i = 0; i != 65; ++i) { + __ ldr(arm::R0, arm::Address(arm::R0)); + } +#else #define __ down_cast<arm::ArmVIXLAssembler*>(GetCodeGenerator() \ ->GetAssembler())->GetVIXLAssembler()-> vixl32::Label target; @@ -205,14 +213,6 @@ TEST_F(OptimizingCFITest, kThumb2Adjust) { for (size_t i = 0; i != 65; ++i) { __ Ldr(r0, vixl32::MemOperand(r0)); } -#else -#define __ down_cast<arm::Thumb2Assembler*>(GetCodeGenerator()->GetAssembler())-> - Label target; - __ CompareAndBranchIfZero(arm::R0, &target); - // Push the target out of range of CBZ. - for (size_t i = 0; i != 65; ++i) { - __ ldr(arm::R0, arm::Address(arm::R0)); - } #endif __ Bind(&target); #undef __ diff --git a/compiler/optimizing/optimizing_cfi_test_expected.inc b/compiler/optimizing/optimizing_cfi_test_expected.inc index 82670c38fe..d84fe6ccff 100644 --- a/compiler/optimizing/optimizing_cfi_test_expected.inc +++ b/compiler/optimizing/optimizing_cfi_test_expected.inc @@ -223,15 +223,15 @@ static constexpr uint8_t expected_cfi_kMips64[] = { // 0x00000040: .cfi_def_cfa_offset: 64 static constexpr uint8_t expected_asm_kThumb2_adjust[] = { -#ifdef ART_USE_VIXL_ARM_BACKEND +#ifdef ART_USE_OLD_ARM_BACKEND + 0x60, 0xB5, 0x2D, 0xED, 0x02, 0x8A, 0x8B, 0xB0, 0x00, 0x28, + 0x40, 0xD0, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, +#else // VIXL emits an extra 2 bytes here for a 32-bit beq as there is no // optimistic 16-bit emit and subsequent fixup for out of reach targets - // as with the current assembler. + // as with the old assembler. 0x60, 0xB5, 0x2D, 0xED, 0x02, 0x8A, 0x8B, 0xB0, 0x00, 0x28, 0x00, 0xF0, 0x41, 0x80, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, -#else - 0x60, 0xB5, 0x2D, 0xED, 0x02, 0x8A, 0x8B, 0xB0, 0x00, 0x28, - 0x40, 0xD0, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, #endif 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, @@ -247,10 +247,10 @@ static constexpr uint8_t expected_asm_kThumb2_adjust[] = { }; static constexpr uint8_t expected_cfi_kThumb2_adjust[] = { 0x42, 0x0E, 0x0C, 0x85, 0x03, 0x86, 0x02, 0x8E, 0x01, 0x44, 0x0E, 0x14, -#ifdef ART_USE_VIXL_ARM_BACKEND - 0x05, 0x50, 0x05, 0x05, 0x51, 0x04, 0x42, 0x0E, 0x40, 0x02, 0x88, 0x0A, -#else +#ifdef ART_USE_OLD_ARM_BACKEND 0x05, 0x50, 0x05, 0x05, 0x51, 0x04, 0x42, 0x0E, 0x40, 0x02, 0x86, 0x0A, +#else + 0x05, 0x50, 0x05, 0x05, 0x51, 0x04, 0x42, 0x0E, 0x40, 0x02, 0x88, 0x0A, #endif 0x42, 0x0E, 0x14, 0x44, 0x0E, 0x0C, 0x06, 0x50, 0x06, 0x51, 0x42, 0x0B, 0x0E, 0x40, diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 918a027aba..d6153b091c 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -307,7 +307,7 @@ class OptimizingCompiler FINAL : public Compiler { InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, - jobject class_loader, + Handle<mirror::ClassLoader> class_loader, const DexFile& dex_file, Handle<mirror::DexCache> dex_cache) const OVERRIDE; @@ -376,7 +376,7 @@ class OptimizingCompiler FINAL : public Compiler { InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, - jobject class_loader, + Handle<mirror::ClassLoader> class_loader, const DexFile& dex_file, Handle<mirror::DexCache> dex_cache, ArtMethod* method, @@ -884,7 +884,7 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* arena, InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, - jobject class_loader, + Handle<mirror::ClassLoader> class_loader, const DexFile& dex_file, Handle<mirror::DexCache> dex_cache, ArtMethod* method, @@ -955,11 +955,8 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* arena, const uint8_t* interpreter_metadata = nullptr; if (method == nullptr) { ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<1> hs(soa.Self()); - Handle<mirror::ClassLoader> loader(hs.NewHandle( - soa.Decode<mirror::ClassLoader>(class_loader))); method = compiler_driver->ResolveMethod( - soa, dex_cache, loader, &dex_compilation_unit, method_idx, invoke_type); + soa, dex_cache, class_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. @@ -968,16 +965,6 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* arena, graph->SetArtMethod(method); ScopedObjectAccess soa(Thread::Current()); interpreter_metadata = method->GetQuickenedInfo(class_linker->GetImagePointerSize()); - dex::TypeIndex type_index = method->GetDeclaringClass()->GetDexTypeIndex(); - - // Update the dex cache if the type is not in it yet. Note that under AOT, - // the verifier must have set it, but under JIT, there's no guarantee, as we - // don't necessarily run the verifier. - // The compiler and the compiler driver assume the compiling class is - // in the dex cache. - if (dex_cache->GetResolvedType(type_index) == nullptr) { - dex_cache->SetResolvedType(type_index, method->GetDeclaringClass()); - } } std::unique_ptr<CodeGenerator> codegen( @@ -1058,7 +1045,7 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item, InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, - jobject jclass_loader, + Handle<mirror::ClassLoader> jclass_loader, const DexFile& dex_file, Handle<mirror::DexCache> dex_cache) const { CompilerDriver* compiler_driver = GetCompilerDriver(); @@ -1172,7 +1159,6 @@ bool OptimizingCompiler::JitCompile(Thread* self, Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache())); DCHECK(method->IsCompilable()); - jobject jclass_loader = class_loader.ToJObject(); const DexFile* dex_file = method->GetDexFile(); const uint16_t class_def_idx = method->GetClassDefIndex(); const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset()); @@ -1196,7 +1182,7 @@ bool OptimizingCompiler::JitCompile(Thread* self, invoke_type, class_def_idx, method_idx, - jclass_loader, + class_loader, *dex_file, dex_cache, method, diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc index c55fccc7d3..6e332ca59b 100644 --- a/compiler/optimizing/reference_type_propagation.cc +++ b/compiler/optimizing/reference_type_propagation.cc @@ -65,11 +65,13 @@ ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetThrowabl class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor { public: RTPVisitor(HGraph* graph, + Handle<mirror::ClassLoader> class_loader, Handle<mirror::DexCache> hint_dex_cache, HandleCache* handle_cache, ArenaVector<HInstruction*>* worklist, bool is_first_run) : HGraphDelegateVisitor(graph), + class_loader_(class_loader), hint_dex_cache_(hint_dex_cache), handle_cache_(handle_cache), worklist_(worklist), @@ -101,6 +103,7 @@ class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor { bool is_exact); private: + Handle<mirror::ClassLoader> class_loader_; Handle<mirror::DexCache> hint_dex_cache_; HandleCache* handle_cache_; ArenaVector<HInstruction*>* worklist_; @@ -108,11 +111,13 @@ class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor { }; ReferenceTypePropagation::ReferenceTypePropagation(HGraph* graph, + Handle<mirror::ClassLoader> class_loader, Handle<mirror::DexCache> hint_dex_cache, VariableSizedHandleScope* handles, bool is_first_run, const char* name) : HOptimization(graph, name), + class_loader_(class_loader), hint_dex_cache_(hint_dex_cache), handle_cache_(handles), worklist_(graph->GetArena()->Adapter(kArenaAllocReferenceTypePropagation)), @@ -147,7 +152,12 @@ void ReferenceTypePropagation::ValidateTypes() { } void ReferenceTypePropagation::Visit(HInstruction* instruction) { - RTPVisitor visitor(graph_, hint_dex_cache_, &handle_cache_, &worklist_, is_first_run_); + RTPVisitor visitor(graph_, + class_loader_, + hint_dex_cache_, + &handle_cache_, + &worklist_, + is_first_run_); instruction->Accept(&visitor); } @@ -321,7 +331,12 @@ void ReferenceTypePropagation::Run() { } void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) { - RTPVisitor visitor(graph_, hint_dex_cache_, &handle_cache_, &worklist_, is_first_run_); + RTPVisitor visitor(graph_, + class_loader_, + 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()); @@ -542,8 +557,9 @@ void ReferenceTypePropagation::RTPVisitor::UpdateReferenceTypeInfo(HInstruction* ScopedObjectAccess soa(Thread::Current()); ObjPtr<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); + ObjPtr<mirror::Class> klass = + ClassLinker::LookupResolvedType(type_idx, dex_cache, class_loader_.Get()); + SetClassAsTypeInfo(instr, klass, is_exact); } void ReferenceTypePropagation::RTPVisitor::VisitNewInstance(HNewInstance* instr) { @@ -556,25 +572,13 @@ void ReferenceTypePropagation::RTPVisitor::VisitNewArray(HNewArray* instr) { SetClassAsTypeInfo(instr, instr->GetLoadClass()->GetClass().Get(), /* is_exact */ true); } -static mirror::Class* GetClassFromDexCache(Thread* self, - const DexFile& dex_file, - dex::TypeIndex type_idx, - Handle<mirror::DexCache> hint_dex_cache) - REQUIRES_SHARED(Locks::mutator_lock_) { - ObjPtr<mirror::DexCache> dex_cache = FindDexCacheWithHint(self, dex_file, hint_dex_cache); - // Get type from dex cache assuming it was populated by the verifier. - return dex_cache->GetResolvedType(type_idx); -} - void ReferenceTypePropagation::RTPVisitor::VisitParameterValue(HParameterValue* instr) { // We check if the existing type is valid: the inliner may have set it. if (instr->GetType() == Primitive::kPrimNot && !instr->GetReferenceTypeInfo().IsValid()) { - 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); + UpdateReferenceTypeInfo(instr, + instr->GetTypeIndex(), + instr->GetDexFile(), + /* is_exact */ false); } } diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h index 4663471729..215e96786b 100644 --- a/compiler/optimizing/reference_type_propagation.h +++ b/compiler/optimizing/reference_type_propagation.h @@ -33,6 +33,7 @@ namespace art { class ReferenceTypePropagation : public HOptimization { public: ReferenceTypePropagation(HGraph* graph, + Handle<mirror::ClassLoader> class_loader, Handle<mirror::DexCache> hint_dex_cache, VariableSizedHandleScope* handles, bool is_first_run, @@ -105,6 +106,8 @@ class ReferenceTypePropagation : public HOptimization { void ValidateTypes(); + Handle<mirror::ClassLoader> class_loader_; + // Note: hint_dex_cache_ is usually, but not necessarily, the dex cache associated with // graph_->GetDexFile(). Since we may look up also in other dex files, it's used only // as a hint, to reduce the number of calls to the costly ClassLinker::FindDexCache(). diff --git a/compiler/optimizing/reference_type_propagation_test.cc b/compiler/optimizing/reference_type_propagation_test.cc index b061c871b0..84a4bab1a9 100644 --- a/compiler/optimizing/reference_type_propagation_test.cc +++ b/compiler/optimizing/reference_type_propagation_test.cc @@ -38,6 +38,7 @@ class ReferenceTypePropagationTest : public CommonCompilerTest { void SetupPropagation(VariableSizedHandleScope* handles) { graph_->InitializeInexactObjectRTI(handles); propagation_ = new (&allocator_) ReferenceTypePropagation(graph_, + Handle<mirror::ClassLoader>(), Handle<mirror::DexCache>(), handles, true, diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc index 487e4dd498..50ab11bc23 100644 --- a/compiler/optimizing/ssa_builder.cc +++ b/compiler/optimizing/ssa_builder.cc @@ -499,7 +499,11 @@ GraphAnalysisResult SsaBuilder::BuildSsa() { // 4) Compute type of reference type instructions. The pass assumes that // NullConstant has been fixed up. - ReferenceTypePropagation(graph_, dex_cache_, handles_, /* is_first_run */ true).Run(); + ReferenceTypePropagation(graph_, + class_loader_, + 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 45dac54115..978f113ec4 100644 --- a/compiler/optimizing/ssa_builder.h +++ b/compiler/optimizing/ssa_builder.h @@ -48,9 +48,11 @@ namespace art { class SsaBuilder : public ValueObject { public: SsaBuilder(HGraph* graph, + Handle<mirror::ClassLoader> class_loader, Handle<mirror::DexCache> dex_cache, VariableSizedHandleScope* handles) : graph_(graph), + class_loader_(class_loader), dex_cache_(dex_cache), handles_(handles), agets_fixed_(false), @@ -115,6 +117,7 @@ class SsaBuilder : public ValueObject { void RemoveRedundantUninitializedStrings(); HGraph* graph_; + Handle<mirror::ClassLoader> class_loader_; Handle<mirror::DexCache> dex_cache_; VariableSizedHandleScope* const handles_; diff --git a/compiler/optimizing/ssa_liveness_analysis_test.cc b/compiler/optimizing/ssa_liveness_analysis_test.cc index cc48d3196b..1916c73ca4 100644 --- a/compiler/optimizing/ssa_liveness_analysis_test.cc +++ b/compiler/optimizing/ssa_liveness_analysis_test.cc @@ -32,6 +32,7 @@ class SsaLivenessAnalysisTest : public testing::Test { : pool_(), allocator_(&pool_), graph_(CreateGraph(&allocator_)), + compiler_options_(), instruction_set_(kRuntimeISA) { std::string error_msg; instruction_set_features_ = @@ -39,7 +40,7 @@ class SsaLivenessAnalysisTest : public testing::Test { codegen_ = CodeGenerator::Create(graph_, instruction_set_, *instruction_set_features_, - CompilerOptions()); + compiler_options_); CHECK(codegen_ != nullptr) << instruction_set_ << " is not a supported target architecture."; // Create entry block. entry_ = new (&allocator_) HBasicBlock(graph_); @@ -59,6 +60,7 @@ class SsaLivenessAnalysisTest : public testing::Test { ArenaPool pool_; ArenaAllocator allocator_; HGraph* graph_; + CompilerOptions compiler_options_; InstructionSet instruction_set_; std::unique_ptr<const InstructionSetFeatures> instruction_set_features_; std::unique_ptr<CodeGenerator> codegen_; diff --git a/compiler/utils/arm/assembler_arm_vixl.cc b/compiler/utils/arm/assembler_arm_vixl.cc index e5eef37b7b..6afc3ddecb 100644 --- a/compiler/utils/arm/assembler_arm_vixl.cc +++ b/compiler/utils/arm/assembler_arm_vixl.cc @@ -230,6 +230,7 @@ void ArmVIXLAssembler::StoreToOffset(StoreOperandType type, if (!CanHoldStoreOffsetThumb(type, offset)) { CHECK_NE(base.GetCode(), kIpCode); if ((reg.GetCode() != kIpCode) && + (!vixl_masm_.GetScratchRegisterList()->IsEmpty()) && ((type != kStoreWordPair) || (reg.GetCode() + 1 != kIpCode))) { tmp_reg = temps.Acquire(); } else { diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h index 8bbe862d19..b98db65fbd 100644 --- a/compiler/utils/mips64/assembler_mips64.h +++ b/compiler/utils/mips64/assembler_mips64.h @@ -782,6 +782,86 @@ class Mips64Assembler FINAL : public Assembler, public JNIMacroAssembler<Pointer public: template <typename ImplicitNullChecker = NoImplicitNullChecker> + void StoreConstToOffset(StoreOperandType type, + int64_t value, + GpuRegister base, + int32_t offset, + GpuRegister temp, + ImplicitNullChecker null_checker = NoImplicitNullChecker()) { + // We permit `base` and `temp` to coincide (however, we check that neither is AT), + // in which case the `base` register may be overwritten in the process. + CHECK_NE(temp, AT); // Must not use AT as temp, so as not to overwrite the adjusted base. + if (!IsInt<16>(offset) || + (type == kStoreDoubleword && !IsAligned<kMips64DoublewordSize>(offset) && + !IsInt<16>(static_cast<int32_t>(offset + kMips64WordSize)))) { + LoadConst32(AT, offset & ~(kMips64DoublewordSize - 1)); + Daddu(AT, AT, base); + base = AT; + offset &= (kMips64DoublewordSize - 1); + } + GpuRegister reg; + // If the adjustment left `base` unchanged and equal to `temp`, we can't use `temp` + // to load and hold the value but we can use AT instead as AT hasn't been used yet. + // Otherwise, `temp` can be used for the value. And if `temp` is the same as the + // original `base` (that is, `base` prior to the adjustment), the original `base` + // register will be overwritten. + if (base == temp) { + temp = AT; + } + + if (type == kStoreDoubleword && IsAligned<kMips64DoublewordSize>(offset)) { + if (value == 0) { + reg = ZERO; + } else { + reg = temp; + LoadConst64(reg, value); + } + Sd(reg, base, offset); + null_checker(); + } else { + uint32_t low = Low32Bits(value); + uint32_t high = High32Bits(value); + if (low == 0) { + reg = ZERO; + } else { + reg = temp; + LoadConst32(reg, low); + } + switch (type) { + case kStoreByte: + Sb(reg, base, offset); + break; + case kStoreHalfword: + Sh(reg, base, offset); + break; + case kStoreWord: + Sw(reg, base, offset); + break; + case kStoreDoubleword: + // not aligned to kMips64DoublewordSize + CHECK_ALIGNED(offset, kMips64WordSize); + Sw(reg, base, offset); + null_checker(); + if (high == 0) { + reg = ZERO; + } else { + reg = temp; + if (high != low) { + LoadConst32(reg, high); + } + } + Sw(reg, base, offset + kMips64WordSize); + break; + default: + LOG(FATAL) << "UNREACHABLE"; + } + if (type != kStoreDoubleword) { + null_checker(); + } + } + } + + template <typename ImplicitNullChecker = NoImplicitNullChecker> void LoadFromOffset(LoadOperandType type, GpuRegister reg, GpuRegister base, diff --git a/compiler/utils/mips64/assembler_mips64_test.cc b/compiler/utils/mips64/assembler_mips64_test.cc index 96a02c46d7..879807ac32 100644 --- a/compiler/utils/mips64/assembler_mips64_test.cc +++ b/compiler/utils/mips64/assembler_mips64_test.cc @@ -2178,6 +2178,82 @@ TEST_F(AssemblerMIPS64Test, StoreFpuToOffset) { DriverStr(expected, "StoreFpuToOffset"); } +TEST_F(AssemblerMIPS64Test, StoreConstToOffset) { + __ StoreConstToOffset(mips64::kStoreByte, 0xFF, mips64::A1, +0, mips64::T8); + __ StoreConstToOffset(mips64::kStoreHalfword, 0xFFFF, mips64::A1, +0, mips64::T8); + __ StoreConstToOffset(mips64::kStoreWord, 0x12345678, mips64::A1, +0, mips64::T8); + __ StoreConstToOffset(mips64::kStoreDoubleword, 0x123456789ABCDEF0, mips64::A1, +0, mips64::T8); + + __ StoreConstToOffset(mips64::kStoreByte, 0, mips64::A1, +0, mips64::T8); + __ StoreConstToOffset(mips64::kStoreHalfword, 0, mips64::A1, +0, mips64::T8); + __ StoreConstToOffset(mips64::kStoreWord, 0, mips64::A1, +0, mips64::T8); + __ StoreConstToOffset(mips64::kStoreDoubleword, 0, mips64::A1, +0, mips64::T8); + + __ StoreConstToOffset(mips64::kStoreDoubleword, 0x1234567812345678, mips64::A1, +0, mips64::T8); + __ StoreConstToOffset(mips64::kStoreDoubleword, 0x1234567800000000, mips64::A1, +0, mips64::T8); + __ StoreConstToOffset(mips64::kStoreDoubleword, 0x0000000012345678, mips64::A1, +0, mips64::T8); + + __ StoreConstToOffset(mips64::kStoreWord, 0, mips64::T8, +0, mips64::T8); + __ StoreConstToOffset(mips64::kStoreWord, 0x12345678, mips64::T8, +0, mips64::T8); + + __ StoreConstToOffset(mips64::kStoreWord, 0, mips64::A1, -0xFFF0, mips64::T8); + __ StoreConstToOffset(mips64::kStoreWord, 0x12345678, mips64::A1, +0xFFF0, mips64::T8); + + __ StoreConstToOffset(mips64::kStoreWord, 0, mips64::T8, -0xFFF0, mips64::T8); + __ StoreConstToOffset(mips64::kStoreWord, 0x12345678, mips64::T8, +0xFFF0, mips64::T8); + + const char* expected = + "ori $t8, $zero, 0xFF\n" + "sb $t8, 0($a1)\n" + "ori $t8, $zero, 0xFFFF\n" + "sh $t8, 0($a1)\n" + "lui $t8, 0x1234\n" + "ori $t8, $t8,0x5678\n" + "sw $t8, 0($a1)\n" + "lui $t8, 0x9abc\n" + "ori $t8, $t8,0xdef0\n" + "dahi $t8, $t8, 0x5679\n" + "dati $t8, $t8, 0x1234\n" + "sd $t8, 0($a1)\n" + "sb $zero, 0($a1)\n" + "sh $zero, 0($a1)\n" + "sw $zero, 0($a1)\n" + "sd $zero, 0($a1)\n" + "lui $t8, 0x1234\n" + "ori $t8, $t8,0x5678\n" + "dins $t8, $t8, 0x20, 0x20\n" + "sd $t8, 0($a1)\n" + "lui $t8, 0x246\n" + "ori $t8, $t8, 0x8acf\n" + "dsll32 $t8, $t8, 0x3\n" + "sd $t8, 0($a1)\n" + "lui $t8, 0x1234\n" + "ori $t8, $t8, 0x5678\n" + "sd $t8, 0($a1)\n" + "sw $zero, 0($t8)\n" + "lui $at,0x1234\n" + "ori $at, $at, 0x5678\n" + "sw $at, 0($t8)\n" + "lui $at, 0xffff\n" + "ori $at, $at, 0x10\n" + "daddu $at, $at, $a1\n" + "sw $zero, 0($at)\n" + "li $at, 0xfff0\n" + "daddu $at, $at, $a1\n" + "lui $t8, 0x1234\n" + "ori $t8, $t8, 0x5678\n" + "sw $t8, 0($at)\n" + "lui $at, 0xffff\n" + "ori $at, $at, 0x10\n" + "daddu $at, $at, $t8\n" + "sw $zero, 0($at)\n" + "li $at, 0xfff0\n" + "daddu $at, $at, $t8\n" + "lui $t8, 0x1234\n" + "ori $t8, $t8, 0x5678\n" + "sw $t8, 0($at)\n"; + DriverStr(expected, "StoreConstToOffset"); +} ////////////////////////////// // Loading/adding Constants // ////////////////////////////// diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc index 6a57f45e42..5307dc09d9 100644 --- a/compiler/utils/x86/assembler_x86.cc +++ b/compiler/utils/x86/assembler_x86.cc @@ -1169,6 +1169,32 @@ void X86Assembler::pand(XmmRegister dst, XmmRegister src) { } +void X86Assembler::andnpd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x55); + EmitXmmRegisterOperand(dst, src); +} + + +void X86Assembler::andnps(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x0F); + EmitUint8(0x55); + EmitXmmRegisterOperand(dst, src); +} + + +void X86Assembler::pandn(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0xDF); + EmitXmmRegisterOperand(dst, src); +} + + void X86Assembler::orpd(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); @@ -1195,6 +1221,43 @@ void X86Assembler::por(XmmRegister dst, XmmRegister src) { } +void X86Assembler::pcmpeqb(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x74); + EmitXmmRegisterOperand(dst, src); +} + + +void X86Assembler::pcmpeqw(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x75); + EmitXmmRegisterOperand(dst, src); +} + + +void X86Assembler::pcmpeqd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x76); + EmitXmmRegisterOperand(dst, src); +} + + +void X86Assembler::pcmpeqq(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitUint8(0x0F); + EmitUint8(0x38); + EmitUint8(0x29); + EmitXmmRegisterOperand(dst, src); +} + + void X86Assembler::shufpd(XmmRegister dst, XmmRegister src, const Immediate& imm) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h index e3c123ccaf..f52cf16c8b 100644 --- a/compiler/utils/x86/assembler_x86.h +++ b/compiler/utils/x86/assembler_x86.h @@ -487,10 +487,19 @@ class X86Assembler FINAL : public Assembler { void andps(XmmRegister dst, const Address& src); void pand(XmmRegister dst, XmmRegister src); // no addr variant (for now) + void andnpd(XmmRegister dst, XmmRegister src); // no addr variant (for now) + void andnps(XmmRegister dst, XmmRegister src); + void pandn(XmmRegister dst, XmmRegister src); + void orpd(XmmRegister dst, XmmRegister src); // no addr variant (for now) void orps(XmmRegister dst, XmmRegister src); void por(XmmRegister dst, XmmRegister src); + void pcmpeqb(XmmRegister dst, XmmRegister src); + void pcmpeqw(XmmRegister dst, XmmRegister src); + void pcmpeqd(XmmRegister dst, XmmRegister src); + void pcmpeqq(XmmRegister dst, XmmRegister src); + void shufpd(XmmRegister dst, XmmRegister src, const Immediate& imm); void shufps(XmmRegister dst, XmmRegister src, const Immediate& imm); void pshufd(XmmRegister dst, XmmRegister src, const Immediate& imm); diff --git a/compiler/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc index 110d0dcd05..23049079e0 100644 --- a/compiler/utils/x86/assembler_x86_test.cc +++ b/compiler/utils/x86/assembler_x86_test.cc @@ -581,6 +581,18 @@ TEST_F(AssemblerX86Test, PAnd) { DriverStr(RepeatFF(&x86::X86Assembler::pand, "pand %{reg2}, %{reg1}"), "pand"); } +TEST_F(AssemblerX86Test, AndnPD) { + DriverStr(RepeatFF(&x86::X86Assembler::andnpd, "andnpd %{reg2}, %{reg1}"), "andnpd"); +} + +TEST_F(AssemblerX86Test, AndnPS) { + DriverStr(RepeatFF(&x86::X86Assembler::andnps, "andnps %{reg2}, %{reg1}"), "andnps"); +} + +TEST_F(AssemblerX86Test, PAndn) { + DriverStr(RepeatFF(&x86::X86Assembler::pandn, "pandn %{reg2}, %{reg1}"), "pandn"); +} + TEST_F(AssemblerX86Test, OrPD) { DriverStr(RepeatFF(&x86::X86Assembler::orpd, "orpd %{reg2}, %{reg1}"), "orpd"); } @@ -593,6 +605,22 @@ TEST_F(AssemblerX86Test, POr) { DriverStr(RepeatFF(&x86::X86Assembler::por, "por %{reg2}, %{reg1}"), "por"); } +TEST_F(AssemblerX86Test, PCmpeqB) { + DriverStr(RepeatFF(&x86::X86Assembler::pcmpeqb, "pcmpeqb %{reg2}, %{reg1}"), "cmpeqb"); +} + +TEST_F(AssemblerX86Test, PCmpeqW) { + DriverStr(RepeatFF(&x86::X86Assembler::pcmpeqw, "pcmpeqw %{reg2}, %{reg1}"), "cmpeqw"); +} + +TEST_F(AssemblerX86Test, PCmpeqD) { + DriverStr(RepeatFF(&x86::X86Assembler::pcmpeqd, "pcmpeqd %{reg2}, %{reg1}"), "cmpeqd"); +} + +TEST_F(AssemblerX86Test, PCmpeqQ) { + DriverStr(RepeatFF(&x86::X86Assembler::pcmpeqq, "pcmpeqq %{reg2}, %{reg1}"), "cmpeqq"); +} + TEST_F(AssemblerX86Test, ShufPS) { DriverStr(RepeatFFI(&x86::X86Assembler::shufps, 1, "shufps ${imm}, %{reg2}, %{reg1}"), "shufps"); } diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc index 688fdcc37d..d20a6965c3 100644 --- a/compiler/utils/x86_64/assembler_x86_64.cc +++ b/compiler/utils/x86_64/assembler_x86_64.cc @@ -1375,6 +1375,32 @@ void X86_64Assembler::pand(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst.LowBits(), src); } +void X86_64Assembler::andnpd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitOptionalRex32(dst, src); + EmitUint8(0x0F); + EmitUint8(0x55); + EmitXmmRegisterOperand(dst.LowBits(), src); +} + +void X86_64Assembler::andnps(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitOptionalRex32(dst, src); + EmitUint8(0x0F); + EmitUint8(0x55); + EmitXmmRegisterOperand(dst.LowBits(), src); +} + +void X86_64Assembler::pandn(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitOptionalRex32(dst, src); + EmitUint8(0x0F); + EmitUint8(0xDF); + EmitXmmRegisterOperand(dst.LowBits(), src); +} + void X86_64Assembler::orpd(XmmRegister dst, XmmRegister src) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); @@ -1401,6 +1427,43 @@ void X86_64Assembler::por(XmmRegister dst, XmmRegister src) { EmitXmmRegisterOperand(dst.LowBits(), src); } +void X86_64Assembler::pcmpeqb(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitOptionalRex32(dst, src); + EmitUint8(0x0F); + EmitUint8(0x74); + EmitXmmRegisterOperand(dst.LowBits(), src); +} + +void X86_64Assembler::pcmpeqw(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitOptionalRex32(dst, src); + EmitUint8(0x0F); + EmitUint8(0x75); + EmitXmmRegisterOperand(dst.LowBits(), src); +} + +void X86_64Assembler::pcmpeqd(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitOptionalRex32(dst, src); + EmitUint8(0x0F); + EmitUint8(0x76); + EmitXmmRegisterOperand(dst.LowBits(), src); +} + +void X86_64Assembler::pcmpeqq(XmmRegister dst, XmmRegister src) { + AssemblerBuffer::EnsureCapacity ensured(&buffer_); + EmitUint8(0x66); + EmitOptionalRex32(dst, src); + EmitUint8(0x0F); + EmitUint8(0x38); + EmitUint8(0x29); + EmitXmmRegisterOperand(dst.LowBits(), src); +} + void X86_64Assembler::shufpd(XmmRegister dst, XmmRegister src, const Immediate& imm) { AssemblerBuffer::EnsureCapacity ensured(&buffer_); EmitUint8(0x66); diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h index 480e7116eb..08e17e81e5 100644 --- a/compiler/utils/x86_64/assembler_x86_64.h +++ b/compiler/utils/x86_64/assembler_x86_64.h @@ -515,10 +515,19 @@ class X86_64Assembler FINAL : public Assembler { void andps(XmmRegister dst, XmmRegister src); // no addr variant (for now) void pand(XmmRegister dst, XmmRegister src); + void andnpd(XmmRegister dst, XmmRegister src); // no addr variant (for now) + void andnps(XmmRegister dst, XmmRegister src); + void pandn(XmmRegister dst, XmmRegister src); + void orpd(XmmRegister dst, XmmRegister src); // no addr variant (for now) void orps(XmmRegister dst, XmmRegister src); void por(XmmRegister dst, XmmRegister src); + void pcmpeqb(XmmRegister dst, XmmRegister src); + void pcmpeqw(XmmRegister dst, XmmRegister src); + void pcmpeqd(XmmRegister dst, XmmRegister src); + void pcmpeqq(XmmRegister dst, XmmRegister src); + void shufpd(XmmRegister dst, XmmRegister src, const Immediate& imm); void shufps(XmmRegister dst, XmmRegister src, const Immediate& imm); void pshufd(XmmRegister dst, XmmRegister src, const Immediate& imm); diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc index ba011c968e..20062fdb07 100644 --- a/compiler/utils/x86_64/assembler_x86_64_test.cc +++ b/compiler/utils/x86_64/assembler_x86_64_test.cc @@ -1269,6 +1269,18 @@ TEST_F(AssemblerX86_64Test, Pand) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::pand, "pand %{reg2}, %{reg1}"), "pand"); } +TEST_F(AssemblerX86_64Test, andnpd) { + DriverStr(RepeatFF(&x86_64::X86_64Assembler::andnpd, "andnpd %{reg2}, %{reg1}"), "andnpd"); +} + +TEST_F(AssemblerX86_64Test, andnps) { + DriverStr(RepeatFF(&x86_64::X86_64Assembler::andnps, "andnps %{reg2}, %{reg1}"), "andnps"); +} + +TEST_F(AssemblerX86_64Test, Pandn) { + DriverStr(RepeatFF(&x86_64::X86_64Assembler::pandn, "pandn %{reg2}, %{reg1}"), "pandn"); +} + TEST_F(AssemblerX86_64Test, Orps) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::orps, "orps %{reg2}, %{reg1}"), "orps"); } @@ -1281,6 +1293,22 @@ TEST_F(AssemblerX86_64Test, Por) { DriverStr(RepeatFF(&x86_64::X86_64Assembler::por, "por %{reg2}, %{reg1}"), "por"); } +TEST_F(AssemblerX86_64Test, PCmpeqb) { + DriverStr(RepeatFF(&x86_64::X86_64Assembler::pcmpeqb, "pcmpeqb %{reg2}, %{reg1}"), "pcmpeqb"); +} + +TEST_F(AssemblerX86_64Test, PCmpeqw) { + DriverStr(RepeatFF(&x86_64::X86_64Assembler::pcmpeqw, "pcmpeqw %{reg2}, %{reg1}"), "pcmpeqw"); +} + +TEST_F(AssemblerX86_64Test, PCmpeqd) { + DriverStr(RepeatFF(&x86_64::X86_64Assembler::pcmpeqd, "pcmpeqd %{reg2}, %{reg1}"), "pcmpeqd"); +} + +TEST_F(AssemblerX86_64Test, PCmpeqq) { + DriverStr(RepeatFF(&x86_64::X86_64Assembler::pcmpeqq, "pcmpeqq %{reg2}, %{reg1}"), "pcmpeqq"); +} + TEST_F(AssemblerX86_64Test, Shufps) { DriverStr(RepeatFFI(&x86_64::X86_64Assembler::shufps, 1, "shufps ${imm}, %{reg2}, %{reg1}"), "shufps"); } diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc index 01c33591e5..1a1d163304 100644 --- a/compiler/verifier_deps_test.cc +++ b/compiler/verifier_deps_test.cc @@ -714,12 +714,12 @@ TEST_F(VerifierDepsTest, MoveException_Unresolved) { TEST_F(VerifierDepsTest, StaticField_Resolved_DeclaredInReferenced) { ASSERT_TRUE(VerifyMethod("StaticField_Resolved_DeclaredInReferenced")); - ASSERT_TRUE(HasClass("Ljava/lang/System;", true, "public final")); + ASSERT_TRUE(HasClass("Ljava/lang/System;", true, "public")); ASSERT_TRUE(HasField("Ljava/lang/System;", "out", "Ljava/io/PrintStream;", true, - "public final static", + "public static", "Ljava/lang/System;")); } @@ -727,13 +727,13 @@ TEST_F(VerifierDepsTest, StaticField_Resolved_DeclaredInSuperclass1) { ASSERT_TRUE(VerifyMethod("StaticField_Resolved_DeclaredInSuperclass1")); ASSERT_TRUE(HasClass("Ljava/util/SimpleTimeZone;", true, "public")); ASSERT_TRUE(HasField( - "Ljava/util/SimpleTimeZone;", "LONG", "I", true, "public final static", "Ljava/util/TimeZone;")); + "Ljava/util/SimpleTimeZone;", "LONG", "I", true, "public static", "Ljava/util/TimeZone;")); } TEST_F(VerifierDepsTest, StaticField_Resolved_DeclaredInSuperclass2) { ASSERT_TRUE(VerifyMethod("StaticField_Resolved_DeclaredInSuperclass2")); ASSERT_TRUE(HasField( - "LMySimpleTimeZone;", "SHORT", "I", true, "public final static", "Ljava/util/TimeZone;")); + "LMySimpleTimeZone;", "SHORT", "I", true, "public static", "Ljava/util/TimeZone;")); } TEST_F(VerifierDepsTest, StaticField_Resolved_DeclaredInInterface1) { @@ -743,7 +743,7 @@ TEST_F(VerifierDepsTest, StaticField_Resolved_DeclaredInInterface1) { "PI_ENABLE_OUTPUT_ESCAPING", "Ljava/lang/String;", true, - "public final static", + "public static", "Ljavax/xml/transform/Result;")); } @@ -753,7 +753,7 @@ TEST_F(VerifierDepsTest, StaticField_Resolved_DeclaredInInterface2) { "PI_ENABLE_OUTPUT_ESCAPING", "Ljava/lang/String;", true, - "public final static", + "public static", "Ljavax/xml/transform/Result;")); } @@ -763,7 +763,7 @@ TEST_F(VerifierDepsTest, StaticField_Resolved_DeclaredInInterface3) { "PI_ENABLE_OUTPUT_ESCAPING", "Ljava/lang/String;", true, - "public final static", + "public static", "Ljavax/xml/transform/Result;")); } @@ -773,13 +773,13 @@ TEST_F(VerifierDepsTest, StaticField_Resolved_DeclaredInInterface4) { "ELEMENT_NODE", "S", true, - "public final static", + "public static", "Lorg/w3c/dom/Node;")); } TEST_F(VerifierDepsTest, StaticField_Unresolved_ReferrerInBoot) { ASSERT_TRUE(VerifyMethod("StaticField_Unresolved_ReferrerInBoot")); - ASSERT_TRUE(HasClass("Ljava/util/TimeZone;", true, "public abstract")); + ASSERT_TRUE(HasClass("Ljava/util/TimeZone;", true, "public")); ASSERT_TRUE(HasField("Ljava/util/TimeZone;", "x", "I", false)); } @@ -851,7 +851,7 @@ TEST_F(VerifierDepsTest, InvokeStatic_Resolved_DeclaredInReferenced) { TEST_F(VerifierDepsTest, InvokeStatic_Resolved_DeclaredInSuperclass1) { ASSERT_TRUE(VerifyMethod("InvokeStatic_Resolved_DeclaredInSuperclass1")); - ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public abstract")); + ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public")); ASSERT_TRUE(HasMethod("direct", "Ljavax/net/ssl/SSLSocket;", "setSocketImplFactory", @@ -874,7 +874,7 @@ TEST_F(VerifierDepsTest, InvokeStatic_Resolved_DeclaredInSuperclass2) { TEST_F(VerifierDepsTest, InvokeStatic_DeclaredInInterface1) { ASSERT_TRUE(VerifyMethod("InvokeStatic_DeclaredInInterface1")); - ASSERT_TRUE(HasClass("Ljava/util/Map$Entry;", true, "public abstract interface")); + ASSERT_TRUE(HasClass("Ljava/util/Map$Entry;", true, "public interface")); ASSERT_TRUE(HasMethod("direct", "Ljava/util/Map$Entry;", "comparingByKey", @@ -896,7 +896,7 @@ TEST_F(VerifierDepsTest, InvokeStatic_DeclaredInInterface2) { TEST_F(VerifierDepsTest, InvokeStatic_Unresolved1) { ASSERT_FALSE(VerifyMethod("InvokeStatic_Unresolved1")); - ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public abstract")); + ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public")); ASSERT_TRUE(HasMethod("direct", "Ljavax/net/ssl/SSLSocket;", "x", "()V", false)); } @@ -914,7 +914,7 @@ TEST_F(VerifierDepsTest, InvokeDirect_Resolved_DeclaredInReferenced) { TEST_F(VerifierDepsTest, InvokeDirect_Resolved_DeclaredInSuperclass1) { ASSERT_FALSE(VerifyMethod("InvokeDirect_Resolved_DeclaredInSuperclass1")); - ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public abstract")); + ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public")); ASSERT_TRUE(HasMethod("direct", "Ljavax/net/ssl/SSLSocket;", "checkOldImpl", @@ -932,7 +932,7 @@ TEST_F(VerifierDepsTest, InvokeDirect_Resolved_DeclaredInSuperclass2) { TEST_F(VerifierDepsTest, InvokeDirect_Unresolved1) { ASSERT_FALSE(VerifyMethod("InvokeDirect_Unresolved1")); - ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public abstract")); + ASSERT_TRUE(HasClass("Ljavax/net/ssl/SSLSocket;", true, "public")); ASSERT_TRUE(HasMethod("direct", "Ljavax/net/ssl/SSLSocket;", "x", "()V", false)); } @@ -987,7 +987,7 @@ TEST_F(VerifierDepsTest, InvokeVirtual_Resolved_DeclaredInSuperinterface) { "size", "()I", true, - "public abstract", + "public", "Ljava/util/Set;")); } @@ -1016,13 +1016,13 @@ TEST_F(VerifierDepsTest, InvokeVirtual_ActuallyDirect) { TEST_F(VerifierDepsTest, InvokeInterface_Resolved_DeclaredInReferenced) { ASSERT_TRUE(VerifyMethod("InvokeInterface_Resolved_DeclaredInReferenced")); - ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public abstract interface")); + ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public interface")); ASSERT_TRUE(HasMethod("interface", "Ljava/lang/Runnable;", "run", "()V", true, - "public abstract", + "public", "Ljava/lang/Runnable;")); } @@ -1038,7 +1038,7 @@ TEST_F(VerifierDepsTest, InvokeInterface_Resolved_DeclaredInSuperinterface1) { "run", "()V", true, - "public abstract", + "public", "Ljava/lang/Runnable;")); } @@ -1049,13 +1049,13 @@ TEST_F(VerifierDepsTest, InvokeInterface_Resolved_DeclaredInSuperinterface2) { "isEmpty", "()Z", true, - "public abstract", + "public", "Ljava/util/Set;")); } TEST_F(VerifierDepsTest, InvokeInterface_Unresolved1) { ASSERT_FALSE(VerifyMethod("InvokeInterface_Unresolved1")); - ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public abstract interface")); + ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public interface")); ASSERT_TRUE(HasMethod("interface", "Ljava/lang/Runnable;", "x", "()V", false)); } @@ -1066,20 +1066,20 @@ TEST_F(VerifierDepsTest, InvokeInterface_Unresolved2) { TEST_F(VerifierDepsTest, InvokeSuper_ThisAssignable) { ASSERT_TRUE(VerifyMethod("InvokeSuper_ThisAssignable")); - ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public abstract interface")); + ASSERT_TRUE(HasClass("Ljava/lang/Runnable;", true, "public interface")); ASSERT_TRUE(HasAssignable("Ljava/lang/Runnable;", "Ljava/lang/Thread;", true)); ASSERT_TRUE(HasMethod("interface", "Ljava/lang/Runnable;", "run", "()V", true, - "public abstract", + "public", "Ljava/lang/Runnable;")); } TEST_F(VerifierDepsTest, InvokeSuper_ThisNotAssignable) { ASSERT_FALSE(VerifyMethod("InvokeSuper_ThisNotAssignable")); - ASSERT_TRUE(HasClass("Ljava/lang/Integer;", true, "public final")); + ASSERT_TRUE(HasClass("Ljava/lang/Integer;", true, "public")); ASSERT_TRUE(HasAssignable("Ljava/lang/Integer;", "Ljava/lang/Thread;", false)); ASSERT_TRUE(HasMethod( "virtual", "Ljava/lang/Integer;", "intValue", "()I", true, "public", "Ljava/lang/Integer;")); @@ -1087,12 +1087,12 @@ TEST_F(VerifierDepsTest, InvokeSuper_ThisNotAssignable) { TEST_F(VerifierDepsTest, ArgumentType_ResolvedReferenceArray) { ASSERT_TRUE(VerifyMethod("ArgumentType_ResolvedReferenceArray")); - ASSERT_TRUE(HasClass("[Ljava/lang/Thread;", true, "public final abstract")); + ASSERT_TRUE(HasClass("[Ljava/lang/Thread;", true, "public")); } TEST_F(VerifierDepsTest, NewArray_Resolved) { ASSERT_TRUE(VerifyMethod("NewArray_Resolved")); - ASSERT_TRUE(HasClass("[Ljava/lang/IllegalStateException;", true, "public final abstract")); + ASSERT_TRUE(HasClass("[Ljava/lang/IllegalStateException;", true, "public")); } TEST_F(VerifierDepsTest, EncodeDecode) { |