diff options
76 files changed, 1528 insertions, 936 deletions
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc index 96a0c1be4d..a7f16d394e 100644 --- a/compiler/common_compiler_test.cc +++ b/compiler/common_compiler_test.cc @@ -123,7 +123,7 @@ void CommonCompilerTest::MakeExecutable(ObjPtr<mirror::ClassLoader> class_loader Thread* self = Thread::Current(); StackHandleScope<1> hs(self); Handle<mirror::ClassLoader> loader(hs.NewHandle(class_loader)); - mirror::Class* klass = class_linker_->FindClass(self, class_descriptor.c_str(), loader); + ObjPtr<mirror::Class> klass = class_linker_->FindClass(self, class_descriptor.c_str(), loader); CHECK(klass != nullptr) << "Class not found " << class_name; PointerSize pointer_size = class_linker_->GetImagePointerSize(); for (auto& m : klass->GetMethods(pointer_size)) { @@ -222,7 +222,7 @@ void CommonCompilerTest::CompileClass(mirror::ClassLoader* class_loader, const c Thread* self = Thread::Current(); StackHandleScope<1> hs(self); Handle<mirror::ClassLoader> loader(hs.NewHandle(class_loader)); - mirror::Class* klass = class_linker_->FindClass(self, class_descriptor.c_str(), loader); + ObjPtr<mirror::Class> klass = class_linker_->FindClass(self, class_descriptor.c_str(), loader); CHECK(klass != nullptr) << "Class not found " << class_name; auto pointer_size = class_linker_->GetImagePointerSize(); for (auto& m : klass->GetMethods(pointer_size)) { @@ -244,7 +244,8 @@ void CommonCompilerTest::CompileDirectMethod(Handle<mirror::ClassLoader> class_l const char* signature) { std::string class_descriptor(DotToDescriptor(class_name)); Thread* self = Thread::Current(); - mirror::Class* klass = class_linker_->FindClass(self, class_descriptor.c_str(), class_loader); + ObjPtr<mirror::Class> klass = + class_linker_->FindClass(self, class_descriptor.c_str(), class_loader); CHECK(klass != nullptr) << "Class not found " << class_name; auto pointer_size = class_linker_->GetImagePointerSize(); ArtMethod* method = klass->FindClassMethod(method_name, signature, pointer_size); @@ -258,7 +259,8 @@ void CommonCompilerTest::CompileVirtualMethod(Handle<mirror::ClassLoader> class_ const char* signature) { std::string class_descriptor(DotToDescriptor(class_name)); Thread* self = Thread::Current(); - mirror::Class* klass = class_linker_->FindClass(self, class_descriptor.c_str(), class_loader); + ObjPtr<mirror::Class> klass = + class_linker_->FindClass(self, class_descriptor.c_str(), class_loader); CHECK(klass != nullptr) << "Class not found " << class_name; auto pointer_size = class_linker_->GetImagePointerSize(); ArtMethod* method = klass->FindClassMethod(method_name, signature, pointer_size); diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc index c643af787d..3cb4a652ad 100644 --- a/compiler/jni/jni_compiler_test.cc +++ b/compiler/jni/jni_compiler_test.cc @@ -245,7 +245,7 @@ class JniCompilerTest : public CommonCompilerTest { Handle<mirror::ClassLoader> loader( hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader))); // Compile the native method before starting the runtime - mirror::Class* c = class_linker_->FindClass(soa.Self(), "LMyClassNatives;", loader); + ObjPtr<mirror::Class> c = class_linker_->FindClass(soa.Self(), "LMyClassNatives;", loader); const auto pointer_size = class_linker_->GetImagePointerSize(); ArtMethod* method = c->FindClassMethod(method_name, method_sig, pointer_size); ASSERT_TRUE(method != nullptr) << method_name << " " << method_sig; diff --git a/compiler/optimizing/loop_analysis.cc b/compiler/optimizing/loop_analysis.cc index a0760eff69..a2124455e2 100644 --- a/compiler/optimizing/loop_analysis.cc +++ b/compiler/optimizing/loop_analysis.cc @@ -35,6 +35,9 @@ void LoopAnalysis::CalculateLoopBasicProperties(HLoopInformation* loop_info, for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { HInstruction* instruction = it.Current(); + if (it.Current()->GetType() == DataType::Type::kInt64) { + analysis_results->has_long_type_instructions_ = true; + } if (MakesScalarPeelingUnrollingNonBeneficial(instruction)) { analysis_results->has_instructions_preventing_scalar_peeling_ = true; analysis_results->has_instructions_preventing_scalar_unrolling_ = true; @@ -61,34 +64,29 @@ bool LoopAnalysis::HasLoopAtLeastOneInvariantExit(HLoopInformation* loop_info) { return false; } -class Arm64LoopHelper : public ArchDefaultLoopHelper { +// Default implementation of loop helper; used for all targets unless a custom implementation +// is provided. Enables scalar loop peeling and unrolling with the most conservative heuristics. +class ArchDefaultLoopHelper : public ArchNoOptsLoopHelper { public: // Scalar loop unrolling parameters and heuristics. // // Maximum possible unrolling factor. - static constexpr uint32_t kArm64ScalarMaxUnrollFactor = 2; + static constexpr uint32_t kScalarMaxUnrollFactor = 2; // Loop's maximum instruction count. Loops with higher count will not be peeled/unrolled. - static constexpr uint32_t kArm64ScalarHeuristicMaxBodySizeInstr = 40; + static constexpr uint32_t kScalarHeuristicMaxBodySizeInstr = 17; // Loop's maximum basic block count. Loops with higher count will not be peeled/unrolled. - static constexpr uint32_t kArm64ScalarHeuristicMaxBodySizeBlocks = 8; + static constexpr uint32_t kScalarHeuristicMaxBodySizeBlocks = 6; - // SIMD loop unrolling parameters and heuristics. - // - // Maximum possible unrolling factor. - static constexpr uint32_t kArm64SimdMaxUnrollFactor = 8; - // Loop's maximum instruction count. Loops with higher count will not be unrolled. - static constexpr uint32_t kArm64SimdHeuristicMaxBodySizeInstr = 50; - - bool IsLoopTooBigForScalarPeelingUnrolling(LoopAnalysisInfo* loop_analysis_info) const OVERRIDE { - size_t instr_num = loop_analysis_info->GetNumberOfInstructions(); - size_t bb_num = loop_analysis_info->GetNumberOfBasicBlocks(); - return (instr_num >= kArm64ScalarHeuristicMaxBodySizeInstr || - bb_num >= kArm64ScalarHeuristicMaxBodySizeBlocks); + bool IsLoopNonBeneficialForScalarOpts(LoopAnalysisInfo* loop_analysis_info) const OVERRIDE { + return loop_analysis_info->HasLongTypeInstructions() || + IsLoopTooBig(loop_analysis_info, + kScalarHeuristicMaxBodySizeInstr, + kScalarHeuristicMaxBodySizeBlocks); } uint32_t GetScalarUnrollingFactor(HLoopInformation* loop_info ATTRIBUTE_UNUSED, uint64_t trip_count) const OVERRIDE { - uint32_t desired_unrolling_factor = kArm64ScalarMaxUnrollFactor; + uint32_t desired_unrolling_factor = kScalarMaxUnrollFactor; if (trip_count < desired_unrolling_factor || trip_count % desired_unrolling_factor != 0) { return kNoUnrollingFactor; } @@ -98,6 +96,38 @@ class Arm64LoopHelper : public ArchDefaultLoopHelper { bool IsLoopPeelingEnabled() const OVERRIDE { return true; } + protected: + bool IsLoopTooBig(LoopAnalysisInfo* loop_analysis_info, + size_t instr_threshold, + size_t bb_threshold) const { + size_t instr_num = loop_analysis_info->GetNumberOfInstructions(); + size_t bb_num = loop_analysis_info->GetNumberOfBasicBlocks(); + return (instr_num >= instr_threshold || bb_num >= bb_threshold); + } +}; + +// Custom implementation of loop helper for arm64 target. Enables heuristics for scalar loop +// peeling and unrolling and supports SIMD loop unrolling. +class Arm64LoopHelper : public ArchDefaultLoopHelper { + public: + // SIMD loop unrolling parameters and heuristics. + // + // Maximum possible unrolling factor. + static constexpr uint32_t kArm64SimdMaxUnrollFactor = 8; + // Loop's maximum instruction count. Loops with higher count will not be unrolled. + static constexpr uint32_t kArm64SimdHeuristicMaxBodySizeInstr = 50; + + // Loop's maximum instruction count. Loops with higher count will not be peeled/unrolled. + static constexpr uint32_t kArm64ScalarHeuristicMaxBodySizeInstr = 40; + // Loop's maximum basic block count. Loops with higher count will not be peeled/unrolled. + static constexpr uint32_t kArm64ScalarHeuristicMaxBodySizeBlocks = 8; + + bool IsLoopNonBeneficialForScalarOpts(LoopAnalysisInfo* loop_analysis_info) const OVERRIDE { + return IsLoopTooBig(loop_analysis_info, + kArm64ScalarHeuristicMaxBodySizeInstr, + kArm64ScalarHeuristicMaxBodySizeBlocks); + } + uint32_t GetSIMDUnrollingFactor(HBasicBlock* block, int64_t trip_count, uint32_t max_peel, @@ -126,8 +156,8 @@ class Arm64LoopHelper : public ArchDefaultLoopHelper { } }; -ArchDefaultLoopHelper* ArchDefaultLoopHelper::Create(InstructionSet isa, - ArenaAllocator* allocator) { +ArchNoOptsLoopHelper* ArchNoOptsLoopHelper::Create(InstructionSet isa, + ArenaAllocator* allocator) { switch (isa) { case InstructionSet::kArm64: { return new (allocator) Arm64LoopHelper; diff --git a/compiler/optimizing/loop_analysis.h b/compiler/optimizing/loop_analysis.h index ece9858136..c09d3ff00f 100644 --- a/compiler/optimizing/loop_analysis.h +++ b/compiler/optimizing/loop_analysis.h @@ -35,6 +35,7 @@ class LoopAnalysisInfo : public ValueObject { exits_num_(0), has_instructions_preventing_scalar_peeling_(false), has_instructions_preventing_scalar_unrolling_(false), + has_long_type_instructions_(false), loop_info_(loop_info) {} size_t GetNumberOfBasicBlocks() const { return bb_num_; } @@ -49,6 +50,10 @@ class LoopAnalysisInfo : public ValueObject { return has_instructions_preventing_scalar_unrolling_; } + bool HasLongTypeInstructions() const { + return has_long_type_instructions_; + } + const HLoopInformation* GetLoopInfo() const { return loop_info_; } private: @@ -62,6 +67,9 @@ class LoopAnalysisInfo : public ValueObject { bool has_instructions_preventing_scalar_peeling_; // Whether the loop has instructions which make scalar loop unrolling non-beneficial. bool has_instructions_preventing_scalar_unrolling_; + // Whether the loop has instructions of primitive long type; unrolling these loop will + // likely introduce spill/fills on 32-bit targets. + bool has_long_type_instructions_; // Corresponding HLoopInformation. const HLoopInformation* loop_info_; @@ -117,22 +125,21 @@ class LoopAnalysis : public ValueObject { // To support peeling/unrolling for a new architecture one needs to create new helper class, // inherit it from this and add implementation for the following methods. // -class ArchDefaultLoopHelper : public ArenaObject<kArenaAllocOptimization> { +class ArchNoOptsLoopHelper : public ArenaObject<kArenaAllocOptimization> { public: - virtual ~ArchDefaultLoopHelper() {} + virtual ~ArchNoOptsLoopHelper() {} // Creates an instance of specialised helper for the target or default helper if the target // doesn't support loop peeling and unrolling. - static ArchDefaultLoopHelper* Create(InstructionSet isa, ArenaAllocator* allocator); + static ArchNoOptsLoopHelper* Create(InstructionSet isa, ArenaAllocator* allocator); - // Returns whether the loop is too big for loop peeling/unrolling by checking its total number of - // basic blocks and instructions. + // Returns whether the loop is not beneficial for loop peeling/unrolling. // - // If the loop body has too many instructions then peeling/unrolling optimization will not bring - // any noticeable performance improvement however will increase the code size. + // For example, if the loop body has too many instructions then peeling/unrolling optimization + // will not bring any noticeable performance improvement however will increase the code size. // // Returns 'true' by default, should be overridden by particular target loop helper. - virtual bool IsLoopTooBigForScalarPeelingUnrolling( + virtual bool IsLoopNonBeneficialForScalarOpts( LoopAnalysisInfo* loop_analysis_info ATTRIBUTE_UNUSED) const { return true; } // Returns optimal scalar unrolling factor for the loop. diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc index 1ce3524bd6..eda6bd1e86 100644 --- a/compiler/optimizing/loop_optimization.cc +++ b/compiler/optimizing/loop_optimization.cc @@ -33,9 +33,6 @@ namespace art { // Enables vectorization (SIMDization) in the loop optimizer. static constexpr bool kEnableVectorization = true; -// Enables scalar loop unrolling in the loop optimizer. -static constexpr bool kEnableScalarPeelingUnrolling = false; - // // Static helpers. // @@ -457,7 +454,7 @@ HLoopOptimization::HLoopOptimization(HGraph* graph, vector_header_(nullptr), vector_body_(nullptr), vector_index_(nullptr), - arch_loop_helper_(ArchDefaultLoopHelper::Create(compiler_driver_ != nullptr + arch_loop_helper_(ArchNoOptsLoopHelper::Create(compiler_driver_ != nullptr ? compiler_driver_->GetInstructionSet() : InstructionSet::kNone, global_allocator_)) { @@ -761,7 +758,7 @@ bool HLoopOptimization::OptimizeInnerLoop(LoopNode* node) { bool HLoopOptimization::TryUnrollingForBranchPenaltyReduction(LoopNode* node) { // Don't run peeling/unrolling if compiler_driver_ is nullptr (i.e., running under tests) // as InstructionSet is needed. - if (!kEnableScalarPeelingUnrolling || compiler_driver_ == nullptr) { + if (compiler_driver_ == nullptr) { return false; } @@ -781,9 +778,9 @@ bool HLoopOptimization::TryUnrollingForBranchPenaltyReduction(LoopNode* node) { LoopAnalysis::CalculateLoopBasicProperties(loop_info, &loop_analysis_info); // Check "IsLoopClonable" last as it can be time-consuming. - if (arch_loop_helper_->IsLoopTooBigForScalarPeelingUnrolling(&loop_analysis_info) || + if (loop_analysis_info.HasInstructionsPreventingScalarUnrolling() || + arch_loop_helper_->IsLoopNonBeneficialForScalarOpts(&loop_analysis_info) || (loop_analysis_info.GetNumberOfExits() > 1) || - loop_analysis_info.HasInstructionsPreventingScalarUnrolling() || !PeelUnrollHelper::IsLoopClonable(loop_info)) { return false; } @@ -807,7 +804,7 @@ bool HLoopOptimization::TryUnrollingForBranchPenaltyReduction(LoopNode* node) { bool HLoopOptimization::TryPeelingForLoopInvariantExitsElimination(LoopNode* node) { // Don't run peeling/unrolling if compiler_driver_ is nullptr (i.e., running under tests) // as InstructionSet is needed. - if (!kEnableScalarPeelingUnrolling || compiler_driver_ == nullptr) { + if (compiler_driver_ == nullptr) { return false; } @@ -821,8 +818,8 @@ bool HLoopOptimization::TryPeelingForLoopInvariantExitsElimination(LoopNode* nod LoopAnalysis::CalculateLoopBasicProperties(loop_info, &loop_analysis_info); // Check "IsLoopClonable" last as it can be time-consuming. - if (arch_loop_helper_->IsLoopTooBigForScalarPeelingUnrolling(&loop_analysis_info) || - loop_analysis_info.HasInstructionsPreventingScalarPeeling() || + if (loop_analysis_info.HasInstructionsPreventingScalarPeeling() || + arch_loop_helper_->IsLoopNonBeneficialForScalarOpts(&loop_analysis_info) || !LoopAnalysis::HasLoopAtLeastOneInvariantExit(loop_info) || !PeelUnrollHelper::IsLoopClonable(loop_info)) { return false; diff --git a/compiler/optimizing/loop_optimization.h b/compiler/optimizing/loop_optimization.h index 7807da15ed..191a93da26 100644 --- a/compiler/optimizing/loop_optimization.h +++ b/compiler/optimizing/loop_optimization.h @@ -28,7 +28,7 @@ namespace art { class CompilerDriver; -class ArchDefaultLoopHelper; +class ArchNoOptsLoopHelper; /** * Loop optimizations. Builds a loop hierarchy and applies optimizations to @@ -308,7 +308,7 @@ class HLoopOptimization : public HOptimization { HInstruction* vector_index_; // normalized index of the new loop // Helper for target-specific behaviour for loop optimizations. - ArchDefaultLoopHelper* arch_loop_helper_; + ArchNoOptsLoopHelper* arch_loop_helper_; friend class LoopOptimizationTest; diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h index a95252d3ed..4b231ed35c 100644 --- a/dex2oat/linker/image_test.h +++ b/dex2oat/linker/image_test.h @@ -394,7 +394,8 @@ inline void ImageTest::Compile(ImageHeader::StorageMode storage_mode, ScopedObjectAccess soa(Thread::Current()); ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); for (const std::string& image_class : image_classes) { - mirror::Class* klass = class_linker->FindSystemClass(Thread::Current(), image_class.c_str()); + ObjPtr<mirror::Class> klass = + class_linker->FindSystemClass(Thread::Current(), image_class.c_str()); EXPECT_TRUE(klass != nullptr); EXPECT_TRUE(klass->IsInitialized()); } @@ -492,15 +493,15 @@ inline void ImageTest::TestWriteRead(ImageHeader::StorageMode storage_mode) { for (size_t j = 0; j < dex->NumClassDefs(); ++j) { const DexFile::ClassDef& class_def = dex->GetClassDef(j); const char* descriptor = dex->GetClassDescriptor(class_def); - mirror::Class* klass = class_linker_->FindSystemClass(soa.Self(), descriptor); + ObjPtr<mirror::Class> klass = class_linker_->FindSystemClass(soa.Self(), descriptor); EXPECT_TRUE(klass != nullptr) << descriptor; + uint8_t* raw_klass = reinterpret_cast<uint8_t*>(klass.Ptr()); if (image_classes.find(descriptor) == image_classes.end()) { - EXPECT_TRUE(reinterpret_cast<uint8_t*>(klass) >= image_end || - reinterpret_cast<uint8_t*>(klass) < image_begin) << descriptor; + EXPECT_TRUE(raw_klass >= image_end || raw_klass < image_begin) << descriptor; } else { // Image classes should be located inside the image. - EXPECT_LT(image_begin, reinterpret_cast<uint8_t*>(klass)) << descriptor; - EXPECT_LT(reinterpret_cast<uint8_t*>(klass), image_end) << descriptor; + EXPECT_LT(image_begin, raw_klass) << descriptor; + EXPECT_LT(raw_klass, image_end) << descriptor; } EXPECT_TRUE(Monitor::IsValidLockWord(klass->GetLockWord(false))); } diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc index df0641cc7f..0694c4ff9f 100644 --- a/dex2oat/linker/oat_writer_test.cc +++ b/dex2oat/linker/oat_writer_test.cc @@ -463,9 +463,9 @@ TEST_F(OatTest, WriteRead) { } const char* descriptor = dex_file.GetClassDescriptor(class_def); - mirror::Class* klass = class_linker->FindClass(soa.Self(), - descriptor, - ScopedNullHandle<mirror::ClassLoader>()); + ObjPtr<mirror::Class> klass = class_linker->FindClass(soa.Self(), + descriptor, + ScopedNullHandle<mirror::ClassLoader>()); const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(i); CHECK_EQ(ClassStatus::kNotReady, oat_class.GetStatus()) << descriptor; diff --git a/libdexfile/dex/class_accessor-inl.h b/libdexfile/dex/class_accessor-inl.h index bcd0a7b66c..5cfbcaa359 100644 --- a/libdexfile/dex/class_accessor-inl.h +++ b/libdexfile/dex/class_accessor-inl.h @@ -20,19 +20,22 @@ #include "class_accessor.h" #include "base/leb128.h" +#include "class_iterator.h" +#include "code_item_accessors-inl.h" namespace art { -inline ClassAccessor::ClassAccessor(const DexFile& dex_file, const DexFile::ClassDef& class_def) - : ClassAccessor(dex_file, dex_file.GetClassData(class_def)) {} +inline ClassAccessor::ClassAccessor(const ClassIteratorData& data) + : ClassAccessor(data.dex_file_, data.dex_file_.GetClassDef(data.class_def_idx_)) {} -inline ClassAccessor::ClassAccessor(const DexFile& dex_file, const uint8_t* class_data) +inline ClassAccessor::ClassAccessor(const DexFile& dex_file, const DexFile::ClassDef& class_def) : dex_file_(dex_file), - ptr_pos_(class_data), - num_static_fields_(class_data != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u), - num_instance_fields_(class_data != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u), - num_direct_methods_(class_data != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u), - num_virtual_methods_(class_data != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u) {} + descriptor_index_(class_def.class_idx_), + ptr_pos_(dex_file.GetClassData(class_def)), + num_static_fields_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u), + num_instance_fields_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u), + num_direct_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u), + num_virtual_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u) {} inline const uint8_t* ClassAccessor::Method::Read(const uint8_t* ptr) { method_idx_ += DecodeUnsignedLeb128(&ptr); @@ -57,25 +60,33 @@ inline void ClassAccessor::VisitMethodsAndFields( const DirectMethodVisitor& direct_method_visitor, const VirtualMethodVisitor& virtual_method_visitor) const { const uint8_t* ptr = ptr_pos_; - for (size_t i = 0; i < num_static_fields_; ++i) { + { Field data; - ptr = data.Read(ptr); - static_field_visitor(data); + for (size_t i = 0; i < num_static_fields_; ++i) { + ptr = data.Read(ptr); + static_field_visitor(data); + } } - for (size_t i = 0; i < num_instance_fields_; ++i) { + { Field data; - ptr = data.Read(ptr); - instance_field_visitor(data); + for (size_t i = 0; i < num_instance_fields_; ++i) { + ptr = data.Read(ptr); + instance_field_visitor(data); + } } - for (size_t i = 0; i < num_direct_methods_; ++i) { - Method data; - ptr = data.Read(ptr); - direct_method_visitor(data); + { + Method data(dex_file_); + for (size_t i = 0; i < num_direct_methods_; ++i) { + ptr = data.Read(ptr); + direct_method_visitor(data); + } } - for (size_t i = 0; i < num_virtual_methods_; ++i) { - Method data; - ptr = data.Read(ptr); - virtual_method_visitor(data); + { + Method data(dex_file_); + for (size_t i = 0; i < num_virtual_methods_; ++i) { + ptr = data.Read(ptr); + virtual_method_visitor(data); + } } } @@ -99,6 +110,10 @@ inline const DexFile::CodeItem* ClassAccessor::GetCodeItem(const Method& method) return dex_file_.GetCodeItem(method.GetCodeItemOffset()); } +inline CodeItemInstructionAccessor ClassAccessor::Method::GetInstructions() const { + return CodeItemInstructionAccessor(dex_file_, dex_file_.GetCodeItem(GetCodeItemOffset())); +} + } // namespace art #endif // ART_LIBDEXFILE_DEX_CLASS_ACCESSOR_INL_H_ diff --git a/libdexfile/dex/class_accessor.h b/libdexfile/dex/class_accessor.h index 59a6b5dfa5..835c4e2eb7 100644 --- a/libdexfile/dex/class_accessor.h +++ b/libdexfile/dex/class_accessor.h @@ -18,10 +18,13 @@ #define ART_LIBDEXFILE_DEX_CLASS_ACCESSOR_H_ #include "base/utils.h" +#include "code_item_accessors.h" #include "dex_file.h" namespace art { +class ClassIteratorData; + // Classes to access Dex data. class ClassAccessor { public: @@ -40,10 +43,15 @@ class ClassAccessor { return code_off_; } + CodeItemInstructionAccessor GetInstructions() const; + private: + explicit Method(const DexFile& dex_file) : dex_file_(dex_file) {} + const uint8_t* Read(const uint8_t* ptr); // A decoded version of the method of a class_data_item. + const DexFile& dex_file_; uint32_t method_idx_ = 0u; uint32_t access_flags_ = 0u; uint32_t code_off_ = 0u; @@ -72,7 +80,10 @@ class ClassAccessor { friend class ClassAccessor; }; - ALWAYS_INLINE ClassAccessor(const DexFile& dex_file, const DexFile::ClassDef& class_def); + // Not explicit specifically for range-based loops. + ALWAYS_INLINE ClassAccessor(const ClassIteratorData& data); + + ClassAccessor(const DexFile& dex_file, const DexFile::ClassDef& class_def); // Return the code item for a method. const DexFile::CodeItem* GetCodeItem(const Method& method) const; @@ -112,18 +123,19 @@ class ClassAccessor { return num_virtual_methods_; } - protected: - ALWAYS_INLINE ClassAccessor(const DexFile& dex_file, const uint8_t* class_data); + // TODO: Deprecate + dex::TypeIndex GetDescriptorIndex() const { + return descriptor_index_; + } + protected: const DexFile& dex_file_; + const dex::TypeIndex descriptor_index_ = {}; const uint8_t* ptr_pos_ = nullptr; // Pointer into stream of class_data_item. const uint32_t num_static_fields_ = 0u; const uint32_t num_instance_fields_ = 0u; const uint32_t num_direct_methods_ = 0u; const uint32_t num_virtual_methods_ = 0u; - // Only cache descriptor. - const void* class_def_ = nullptr; - const void* class_data_ = nullptr; }; } // namespace art diff --git a/libdexfile/dex/class_iterator.h b/libdexfile/dex/class_iterator.h new file mode 100644 index 0000000000..477c93b508 --- /dev/null +++ b/libdexfile/dex/class_iterator.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_LIBDEXFILE_DEX_CLASS_ITERATOR_H_ +#define ART_LIBDEXFILE_DEX_CLASS_ITERATOR_H_ + +#include "base/logging.h" + +namespace art { + +class ClassAccessor; +class ClassIterator; +class DexFile; + +// Holder class, used to construct ClassAccessors. +class ClassIteratorData { + public: + ClassIteratorData(const DexFile& dex_file, uint32_t class_def_idx) + : dex_file_(dex_file), + class_def_idx_(class_def_idx) {} + + private: + const DexFile& dex_file_; + uint32_t class_def_idx_ = 0u; + + friend class ClassAccessor; + friend class ClassIterator; +}; + +// Iterator for visiting classes in a Dex file. +class ClassIterator : public std::iterator<std::forward_iterator_tag, ClassIteratorData> { + public: + using value_type = std::iterator<std::forward_iterator_tag, ClassIteratorData>::value_type; + using difference_type = std::iterator<std::forward_iterator_tag, value_type>::difference_type; + + ClassIterator(const DexFile& dex_file, uint32_t class_def_idx) + : data_(dex_file, class_def_idx) {} + + // Value after modification. + ClassIterator& operator++() { + ++data_.class_def_idx_; + return *this; + } + + // Value before modification. + ClassIterator operator++(int) { + ClassIterator temp = *this; + ++*this; + return temp; + } + + const value_type& operator*() const { + return data_; + } + + bool operator==(const ClassIterator& rhs) const { + DCHECK_EQ(&data_.dex_file_, &rhs.data_.dex_file_) << "Comparing different dex files."; + return data_.class_def_idx_ == rhs.data_.class_def_idx_; + } + + bool operator!=(const ClassIterator& rhs) const { + return !(*this == rhs); + } + + bool operator<(const ClassIterator& rhs) const { + DCHECK_EQ(&data_.dex_file_, &rhs.data_.dex_file_) << "Comparing different dex files."; + return data_.class_def_idx_ < rhs.data_.class_def_idx_; + } + + bool operator>(const ClassIterator& rhs) const { + return rhs < *this; + } + + bool operator<=(const ClassIterator& rhs) const { + return !(rhs < *this); + } + + bool operator>=(const ClassIterator& rhs) const { + return !(*this < rhs); + } + + protected: + ClassIteratorData data_; +}; + +} // namespace art + +#endif // ART_LIBDEXFILE_DEX_CLASS_ITERATOR_H_ diff --git a/libdexfile/dex/code_item_accessors.h b/libdexfile/dex/code_item_accessors.h index ba7c126ed8..5786d3f611 100644 --- a/libdexfile/dex/code_item_accessors.h +++ b/libdexfile/dex/code_item_accessors.h @@ -47,6 +47,11 @@ class CodeItemInstructionAccessor { return insns_size_in_code_units_; } + uint32_t InsnsSizeInBytes() const { + static constexpr uint32_t kCodeUnitSizeInBytes = 2u; + return insns_size_in_code_units_ * kCodeUnitSizeInBytes; + } + const uint16_t* Insns() const { return insns_; } diff --git a/libdexfile/dex/dex_file-inl.h b/libdexfile/dex/dex_file-inl.h index e78e8d7a44..f5dd374253 100644 --- a/libdexfile/dex/dex_file-inl.h +++ b/libdexfile/dex/dex_file-inl.h @@ -20,6 +20,7 @@ #include "base/casts.h" #include "base/leb128.h" #include "base/stringpiece.h" +#include "class_iterator.h" #include "compact_dex_file.h" #include "dex_file.h" #include "invoke_type.h" @@ -527,6 +528,10 @@ inline void DexFile::ClassDef::VisitMethods(const DexFile* dex_file, const Visit } } +inline IterationRange<ClassIterator> DexFile::GetClasses() const { + return { ClassIterator(*this, 0u), ClassIterator(*this, NumClassDefs()) }; +} + } // namespace art #endif // ART_LIBDEXFILE_DEX_DEX_FILE_INL_H_ diff --git a/libdexfile/dex/dex_file.h b/libdexfile/dex/dex_file.h index 87d2c48ff1..f1f8b505bd 100644 --- a/libdexfile/dex/dex_file.h +++ b/libdexfile/dex/dex_file.h @@ -27,6 +27,7 @@ #include "base/iteration_range.h" #include "base/macros.h" #include "base/value_object.h" +#include "class_iterator.h" #include "dex_file_types.h" #include "dex_instruction_iterator.h" #include "hidden_api_access_flags.h" @@ -1012,6 +1013,8 @@ class DexFile { // Changes the dex file pointed to by class_it to not have any hiddenapi flags. static void UnHideAccessFlags(ClassDataItemIterator& class_it); + inline IterationRange<ClassIterator> GetClasses() const; + protected: // First Dex format version supporting default methods. static const uint32_t kDefaultMethodsVersion = 37; diff --git a/libprofile/profile/profile_compilation_info_test.cc b/libprofile/profile/profile_compilation_info_test.cc index b3262a7a14..ead7cba60b 100644 --- a/libprofile/profile/profile_compilation_info_test.cc +++ b/libprofile/profile/profile_compilation_info_test.cc @@ -54,7 +54,7 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { StackHandleScope<1> hs(self); Handle<mirror::ClassLoader> h_loader( hs.NewHandle(self->DecodeJObject(class_loader)->AsClassLoader())); - mirror::Class* klass = class_linker->FindClass(self, clazz.c_str(), h_loader); + ObjPtr<mirror::Class> klass = class_linker->FindClass(self, clazz.c_str(), h_loader); const auto pointer_size = class_linker->GetImagePointerSize(); std::vector<ArtMethod*> methods; diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 8cd0604ac3..6ed029ceb1 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -62,9 +62,10 @@ class ClassLinkerTest : public CommonRuntimeTest { Thread* self = Thread::Current(); EXPECT_TRUE(class_linker_->FindSystemClass(self, descriptor.c_str()) == nullptr); EXPECT_TRUE(self->IsExceptionPending()); - mirror::Object* exception = self->GetException(); + StackHandleScope<1> hs(self); + Handle<mirror::Object> exception = hs.NewHandle<mirror::Object>(self->GetException()); self->ClearException(); - mirror::Class* exception_class = + ObjPtr<mirror::Class> exception_class = class_linker_->FindSystemClass(self, "Ljava/lang/NoClassDefFoundError;"); EXPECT_TRUE(exception->InstanceOf(exception_class)); } @@ -75,7 +76,7 @@ class ClassLinkerTest : public CommonRuntimeTest { AssertPrimitiveClass(descriptor, class_linker_->FindSystemClass(self, descriptor.c_str())); } - void AssertPrimitiveClass(const std::string& descriptor, mirror::Class* primitive) + void AssertPrimitiveClass(const std::string& descriptor, ObjPtr<mirror::Class> primitive) REQUIRES_SHARED(Locks::mutator_lock_) { ASSERT_TRUE(primitive != nullptr); ASSERT_TRUE(primitive->GetClass() != nullptr); @@ -113,13 +114,13 @@ class ClassLinkerTest : public CommonRuntimeTest { EXPECT_EQ(kAccPublic | kAccFinal | kAccAbstract, primitive->GetAccessFlags()); } - void AssertObjectClass(mirror::Class* JavaLangObject) + void AssertObjectClass(ObjPtr<mirror::Class> JavaLangObject) REQUIRES_SHARED(Locks::mutator_lock_) { ASSERT_TRUE(JavaLangObject != nullptr); ASSERT_TRUE(JavaLangObject->GetClass() != nullptr); ASSERT_EQ(JavaLangObject->GetClass(), JavaLangObject->GetClass()->GetClass()); - EXPECT_EQ(JavaLangObject, JavaLangObject->GetClass()->GetSuperClass()); + EXPECT_OBJ_PTR_EQ(JavaLangObject, JavaLangObject->GetClass()->GetSuperClass()); std::string temp; ASSERT_STREQ(JavaLangObject->GetDescriptor(&temp), "Ljava/lang/Object;"); EXPECT_TRUE(JavaLangObject->GetSuperClass() == nullptr); @@ -172,7 +173,7 @@ class ClassLinkerTest : public CommonRuntimeTest { void AssertArrayClass(const std::string& array_descriptor, const std::string& component_type, - mirror::ClassLoader* class_loader) + ObjPtr<mirror::ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_) { Thread* self = Thread::Current(); StackHandleScope<2> hs(self); @@ -181,7 +182,7 @@ class ClassLinkerTest : public CommonRuntimeTest { hs.NewHandle(class_linker_->FindClass(self, array_descriptor.c_str(), loader))); std::string temp; EXPECT_STREQ(component_type.c_str(), array->GetComponentType()->GetDescriptor(&temp)); - EXPECT_EQ(class_loader, array->GetClassLoader()); + EXPECT_OBJ_PTR_EQ(loader.Get(), array->GetClassLoader()); EXPECT_EQ(kAccFinal | kAccAbstract, (array->GetAccessFlags() & (kAccFinal | kAccAbstract))); AssertArrayClass(array_descriptor, array); } @@ -234,7 +235,7 @@ class ClassLinkerTest : public CommonRuntimeTest { EXPECT_OBJ_PTR_EQ(class_linker_->FindArrayClass(self, &array_ptr), array.Get()); PointerSize pointer_size = class_linker_->GetImagePointerSize(); - mirror::Class* JavaLangObject = + ObjPtr<mirror::Class> JavaLangObject = class_linker_->FindSystemClass(self, "Ljava/lang/Object;"); ImTable* JavaLangObject_imt = JavaLangObject->GetImt(pointer_size); // IMT of a array class should be shared with the IMT of the java.lag.Object @@ -292,9 +293,9 @@ class ClassLinkerTest : public CommonRuntimeTest { } } EXPECT_EQ(klass->IsInterface(), !klass->HasVTable()); - mirror::IfTable* iftable = klass->GetIfTable(); + ObjPtr<mirror::IfTable> iftable = klass->GetIfTable(); for (int i = 0; i < klass->GetIfTableCount(); i++) { - mirror::Class* interface = iftable->GetInterface(i); + ObjPtr<mirror::Class> interface = iftable->GetInterface(i); ASSERT_TRUE(interface != nullptr); if (klass->IsInterface()) { EXPECT_EQ(0U, iftable->GetMethodArrayCount(i)); @@ -322,13 +323,13 @@ class ClassLinkerTest : public CommonRuntimeTest { for (ArtMethod& method : klass->GetDirectMethods(kRuntimePointerSize)) { AssertMethod(&method); EXPECT_TRUE(method.IsDirect()); - EXPECT_EQ(klass.Get(), method.GetDeclaringClass()); + EXPECT_OBJ_PTR_EQ(klass.Get(), method.GetDeclaringClass()); } for (ArtMethod& method : klass->GetDeclaredVirtualMethods(kRuntimePointerSize)) { AssertMethod(&method); EXPECT_FALSE(method.IsDirect()); - EXPECT_EQ(klass.Get(), method.GetDeclaringClass()); + EXPECT_OBJ_PTR_EQ(klass.Get(), method.GetDeclaringClass()); } for (ArtMethod& method : klass->GetCopiedMethods(kRuntimePointerSize)) { @@ -386,7 +387,7 @@ class ClassLinkerTest : public CommonRuntimeTest { ASSERT_EQ(end_ref_offset.Uint32Value(), current_ref_offset.Uint32Value()); uint32_t total_num_reference_instance_fields = 0; - mirror::Class* k = klass.Get(); + ObjPtr<mirror::Class> k = klass.Get(); while (k != nullptr) { total_num_reference_instance_fields += k->NumReferenceInstanceFields(); k = k->GetSuperClass(); @@ -400,7 +401,7 @@ class ClassLinkerTest : public CommonRuntimeTest { } } - void AssertDexFileClass(mirror::ClassLoader* class_loader, const std::string& descriptor) + void AssertDexFileClass(ObjPtr<mirror::ClassLoader> class_loader, const std::string& descriptor) REQUIRES_SHARED(Locks::mutator_lock_) { ASSERT_TRUE(descriptor != nullptr); Thread* self = Thread::Current(); @@ -409,8 +410,8 @@ class ClassLinkerTest : public CommonRuntimeTest { hs.NewHandle(class_linker_->FindSystemClass(self, descriptor.c_str()))); ASSERT_TRUE(klass != nullptr); std::string temp; - EXPECT_STREQ(descriptor.c_str(), klass.Get()->GetDescriptor(&temp)); - EXPECT_EQ(class_loader, klass->GetClassLoader()); + EXPECT_STREQ(descriptor.c_str(), klass->GetDescriptor(&temp)); + EXPECT_OBJ_PTR_EQ(class_loader, klass->GetClassLoader()); if (klass->IsPrimitive()) { AssertPrimitiveClass(descriptor, klass.Get()); } else if (klass->IsArrayClass()) { @@ -420,7 +421,7 @@ class ClassLinkerTest : public CommonRuntimeTest { } } - void AssertDexFile(const DexFile& dex, mirror::ClassLoader* class_loader) + void AssertDexFile(const DexFile& dex, ObjPtr<mirror::ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_) { // Verify all the classes defined in this file for (size_t i = 0; i < dex.NumClassDefs(); i++) { @@ -469,7 +470,7 @@ struct CheckOffsets { bool Check() REQUIRES_SHARED(Locks::mutator_lock_) { Thread* self = Thread::Current(); - mirror::Class* klass = + ObjPtr<mirror::Class> klass = Runtime::Current()->GetClassLinker()->FindSystemClass(self, class_descriptor.c_str()); CHECK(klass != nullptr) << class_descriptor; @@ -875,12 +876,13 @@ TEST_F(ClassLinkerTest, FindClassNested) { Handle<mirror::ClassLoader> class_loader( hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Nested")))); - mirror::Class* outer = class_linker_->FindClass(soa.Self(), "LNested;", class_loader); + ObjPtr<mirror::Class> outer = class_linker_->FindClass(soa.Self(), "LNested;", class_loader); ASSERT_TRUE(outer != nullptr); EXPECT_EQ(0U, outer->NumVirtualMethods()); EXPECT_EQ(1U, outer->NumDirectMethods()); - mirror::Class* inner = class_linker_->FindClass(soa.Self(), "LNested$Inner;", class_loader); + ObjPtr<mirror::Class> inner = + class_linker_->FindClass(soa.Self(), "LNested$Inner;", class_loader); ASSERT_TRUE(inner != nullptr); EXPECT_EQ(0U, inner->NumVirtualMethods()); EXPECT_EQ(1U, inner->NumDirectMethods()); @@ -902,23 +904,24 @@ TEST_F(ClassLinkerTest, FindClass_Primitives) { TEST_F(ClassLinkerTest, FindClass) { ScopedObjectAccess soa(Thread::Current()); - mirror::Class* JavaLangObject = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;"); - AssertObjectClass(JavaLangObject); + StackHandleScope<2> hs(soa.Self()); + Handle<mirror::Class> JavaLangObject = hs.NewHandle( + class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;")); + AssertObjectClass(JavaLangObject.Get()); - StackHandleScope<1> hs(soa.Self()); Handle<mirror::ClassLoader> class_loader( hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("MyClass")))); AssertNonExistentClass("LMyClass;"); - mirror::Class* MyClass = class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader); + ObjPtr<mirror::Class> MyClass = class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader); ASSERT_TRUE(MyClass != nullptr); ASSERT_TRUE(MyClass->GetClass() != nullptr); ASSERT_EQ(MyClass->GetClass(), MyClass->GetClass()->GetClass()); - EXPECT_EQ(JavaLangObject, MyClass->GetClass()->GetSuperClass()); + EXPECT_OBJ_PTR_EQ(JavaLangObject.Get(), MyClass->GetClass()->GetSuperClass()); std::string temp; ASSERT_STREQ(MyClass->GetDescriptor(&temp), "LMyClass;"); - EXPECT_TRUE(MyClass->GetSuperClass() == JavaLangObject); + EXPECT_OBJ_PTR_EQ(MyClass->GetSuperClass(), JavaLangObject.Get()); EXPECT_TRUE(MyClass->HasSuperClass()); - EXPECT_EQ(class_loader.Get(), MyClass->GetClassLoader()); + EXPECT_OBJ_PTR_EQ(class_loader.Get(), MyClass->GetClassLoader()); EXPECT_EQ(ClassStatus::kResolved, MyClass->GetStatus()); EXPECT_FALSE(MyClass->IsErroneous()); EXPECT_TRUE(MyClass->IsLoaded()); @@ -1057,8 +1060,9 @@ TEST_F(ClassLinkerTest, LibCore) { // start of the object TEST_F(ClassLinkerTest, ValidateObjectArrayElementsOffset) { ScopedObjectAccess soa(Thread::Current()); - mirror::Class* array_class = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;"); - mirror::ObjectArray<mirror::String>* array = + ObjPtr<mirror::Class> array_class = + class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;"); + ObjPtr<mirror::ObjectArray<mirror::String>> array = mirror::ObjectArray<mirror::String>::Alloc(soa.Self(), array_class, 0); uintptr_t data_offset = reinterpret_cast<uintptr_t>(array->GetRawData(sizeof(mirror::HeapReference<mirror::String>), @@ -1106,7 +1110,7 @@ TEST_F(ClassLinkerTest, ValidateBoxedTypes) { // This lets UnboxPrimitive avoid searching for the field by name at runtime. ScopedObjectAccess soa(Thread::Current()); ScopedNullHandle<mirror::ClassLoader> class_loader; - mirror::Class* c; + ObjPtr<mirror::Class> c; c = class_linker_->FindClass(soa.Self(), "Ljava/lang/Boolean;", class_loader); EXPECT_STREQ("value", c->GetIFieldsPtr()->At(0).GetName()); c = class_linker_->FindClass(soa.Self(), "Ljava/lang/Byte;", class_loader); @@ -1127,16 +1131,18 @@ TEST_F(ClassLinkerTest, ValidateBoxedTypes) { TEST_F(ClassLinkerTest, TwoClassLoadersOneClass) { ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<2> hs(soa.Self()); + StackHandleScope<3> hs(soa.Self()); Handle<mirror::ClassLoader> class_loader_1( hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("MyClass")))); Handle<mirror::ClassLoader> class_loader_2( hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("MyClass")))); - mirror::Class* MyClass_1 = class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader_1); - mirror::Class* MyClass_2 = class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader_2); + Handle<mirror::Class> MyClass_1 = hs.NewHandle( + class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader_1)); + ObjPtr<mirror::Class> MyClass_2 = + class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader_2); EXPECT_TRUE(MyClass_1 != nullptr); EXPECT_TRUE(MyClass_2 != nullptr); - EXPECT_NE(MyClass_1, MyClass_2); + EXPECT_OBJ_PTR_NE(MyClass_1.Get(), MyClass_2); } TEST_F(ClassLinkerTest, StaticFields) { @@ -1200,7 +1206,7 @@ TEST_F(ClassLinkerTest, StaticFields) { soa.Self(), statics.Get(), "s8", "Ljava/lang/String;"); EXPECT_EQ(s8->GetTypeAsPrimitiveType(), Primitive::kPrimNot); EXPECT_TRUE(s8->GetObject(statics.Get())->AsString()->Equals("android")); - mirror::String* str_value = mirror::String::AllocFromModifiedUtf8(soa.Self(), "robot"); + ObjPtr<mirror::String> str_value = mirror::String::AllocFromModifiedUtf8(soa.Self(), "robot"); s8->SetObject<false>(s8->GetDeclaringClass(), str_value); // TODO: Remove EXPECT_FALSE when GCC can handle EXPECT_EQ @@ -1300,7 +1306,8 @@ TEST_F(ClassLinkerTest, ResolveVerifyAndClinit) { StackHandleScope<1> hs(soa.Self()); Handle<mirror::ClassLoader> class_loader( hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader))); - mirror::Class* klass = class_linker_->FindClass(soa.Self(), "LStaticsFromCode;", class_loader); + ObjPtr<mirror::Class> klass = + class_linker_->FindClass(soa.Self(), "LStaticsFromCode;", class_loader); ArtMethod* clinit = klass->FindClassInitializer(kRuntimePointerSize); ArtMethod* getS0 = klass->FindClassMethod("getS0", "()Ljava/lang/Object;", kRuntimePointerSize); @@ -1345,7 +1352,7 @@ TEST_F(ClassLinkerTest, ErroneousClass) { TEST_F(ClassLinkerTest, FinalizableBit) { ScopedObjectAccess soa(Thread::Current()); - mirror::Class* c; + ObjPtr<mirror::Class> c; // Object has a finalize method, but we know it's empty. c = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;"); @@ -1381,7 +1388,7 @@ TEST_F(ClassLinkerTest, ClassRootDescriptors) { ScopedObjectAccess soa(Thread::Current()); std::string temp; for (int i = 0; i < ClassLinker::kClassRootsMax; i++) { - mirror::Class* klass = class_linker_->GetClassRoot(ClassLinker::ClassRoot(i)); + ObjPtr<mirror::Class> klass = class_linker_->GetClassRoot(ClassLinker::ClassRoot(i)); EXPECT_GT(strlen(klass->GetDescriptor(&temp)), 0U); EXPECT_STREQ(klass->GetDescriptor(&temp), class_linker_->GetClassRootDescriptor(ClassLinker::ClassRoot(i))) << " i = " << i; @@ -1391,7 +1398,7 @@ TEST_F(ClassLinkerTest, ClassRootDescriptors) { TEST_F(ClassLinkerTest, ValidatePredefinedClassSizes) { ScopedObjectAccess soa(Thread::Current()); ScopedNullHandle<mirror::ClassLoader> class_loader; - mirror::Class* c; + ObjPtr<mirror::Class> c; c = class_linker_->FindClass(soa.Self(), "Ljava/lang/Class;", class_loader); ASSERT_TRUE(c != nullptr); @@ -1418,7 +1425,7 @@ static void CheckMethod(ArtMethod* method, bool verified) } } -static void CheckVerificationAttempted(mirror::Class* c, bool preverified) +static void CheckVerificationAttempted(ObjPtr<mirror::Class> c, bool preverified) REQUIRES_SHARED(Locks::mutator_lock_) { EXPECT_EQ((c->GetAccessFlags() & kAccVerificationAttempted) != 0U, preverified) << "Class " << mirror::Class::PrettyClass(c) << " not as expected"; @@ -1430,7 +1437,8 @@ static void CheckVerificationAttempted(mirror::Class* c, bool preverified) TEST_F(ClassLinkerTest, Preverified_InitializedBoot) { ScopedObjectAccess soa(Thread::Current()); - mirror::Class* JavaLangObject = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;"); + ObjPtr<mirror::Class> JavaLangObject = + class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;"); ASSERT_TRUE(JavaLangObject != nullptr); EXPECT_TRUE(JavaLangObject->IsInitialized()) << "Not testing already initialized class from the " "core"; @@ -1479,13 +1487,13 @@ TEST_F(ClassLinkerTest, IsBootStrapClassLoaded) { Handle<mirror::Class> jlo_class( hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;"))); ASSERT_TRUE(jlo_class != nullptr); - EXPECT_TRUE(jlo_class.Get()->IsBootStrapClassLoaded()); + EXPECT_TRUE(jlo_class->IsBootStrapClassLoaded()); // Statics is not a bootstrap class. Handle<mirror::Class> statics( hs.NewHandle(class_linker_->FindClass(soa.Self(), "LStatics;", class_loader))); ASSERT_TRUE(statics != nullptr); - EXPECT_FALSE(statics.Get()->IsBootStrapClassLoaded()); + EXPECT_FALSE(statics->IsBootStrapClassLoaded()); } // Regression test for b/26799552. @@ -1563,13 +1571,13 @@ TEST_F(ClassLinkerMethodHandlesTest, TestResolveMethodTypes) { Handle<mirror::Class> string_class(hs.NewHandle(class_linker_->FindClass(soa.Self(), "Ljava/lang/String;", class_loader))); - ASSERT_EQ(string_class.Get(), method1_type->GetRType()); - ASSERT_EQ(string_class.Get(), method1_type->GetPTypes()->Get(0)); + ASSERT_OBJ_PTR_EQ(string_class.Get(), method1_type->GetRType()); + ASSERT_OBJ_PTR_EQ(string_class.Get(), method1_type->GetPTypes()->Get(0)); // Resolve the method type again and assert that we get back the same value. Handle<mirror::MethodType> method1_type2 = hs.NewHandle( class_linker_->ResolveMethodType(soa.Self(), method1_id.proto_idx_, dex_cache, class_loader)); - ASSERT_EQ(method1_type.Get(), method1_type2.Get()); + ASSERT_OBJ_PTR_EQ(method1_type.Get(), method1_type2.Get()); // Resolve the MethodType associated with a different method signature // and assert it's different. @@ -1582,7 +1590,7 @@ TEST_F(ClassLinkerMethodHandlesTest, TestResolveMethodTypes) { const DexFile::MethodId& method2_id = dex_file.GetMethodId(method2->GetDexMethodIndex()); Handle<mirror::MethodType> method2_type = hs.NewHandle( class_linker_->ResolveMethodType(soa.Self(), method2_id.proto_idx_, dex_cache, class_loader)); - ASSERT_TRUE(method1_type.Get() != method2_type.Get()); + ASSERT_OBJ_PTR_NE(method1_type.Get(), method2_type.Get()); } // Verify that ClassLinker's CreateWellknownClassLoader works as expected @@ -1599,18 +1607,18 @@ TEST_F(ClassLinkerTest, CreateWellKnownClassLoader) { TEST_F(ClassLinkerTest, PrettyClass) { ScopedObjectAccess soa(Thread::Current()); EXPECT_EQ("null", mirror::Class::PrettyClass(nullptr)); - mirror::Class* c = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;"); + ObjPtr<mirror::Class> c = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;"); ASSERT_TRUE(c != nullptr); - mirror::Object* o = mirror::ObjectArray<mirror::String>::Alloc(soa.Self(), c, 0); + ObjPtr<mirror::Object> o = mirror::ObjectArray<mirror::String>::Alloc(soa.Self(), c, 0); EXPECT_EQ("java.lang.Class<java.lang.String[]>", mirror::Class::PrettyClass(o->GetClass())); } TEST_F(ClassLinkerTest, PrettyClassAndClassLoader) { ScopedObjectAccess soa(Thread::Current()); EXPECT_EQ("null", mirror::Class::PrettyClassAndClassLoader(nullptr)); - mirror::Class* c = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;"); + ObjPtr<mirror::Class> c = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;"); ASSERT_TRUE(c != nullptr); - mirror::Object* o = mirror::ObjectArray<mirror::String>::Alloc(soa.Self(), c, 0); + ObjPtr<mirror::Object> o = mirror::ObjectArray<mirror::String>::Alloc(soa.Self(), c, 0); EXPECT_EQ("java.lang.Class<java.lang.String[],null>", mirror::Class::PrettyClassAndClassLoader(o->GetClass())); } @@ -1619,8 +1627,8 @@ TEST_F(ClassLinkerTest, PrettyField) { ScopedObjectAccess soa(Thread::Current()); EXPECT_EQ("null", ArtField::PrettyField(nullptr)); - mirror::Class* java_lang_String = class_linker_->FindSystemClass(soa.Self(), - "Ljava/lang/String;"); + ObjPtr<mirror::Class> java_lang_String = class_linker_->FindSystemClass(soa.Self(), + "Ljava/lang/String;"); ArtField* f; f = java_lang_String->FindDeclaredInstanceField("count", "I"); @@ -1630,7 +1638,7 @@ TEST_F(ClassLinkerTest, PrettyField) { TEST_F(ClassLinkerTest, JniShortName_JniLongName) { ScopedObjectAccess soa(Thread::Current()); - mirror::Class* c = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/String;"); + ObjPtr<mirror::Class> c = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/String;"); ASSERT_TRUE(c != nullptr); ArtMethod* m; @@ -1682,7 +1690,7 @@ class ClassLinkerClassLoaderTest : public ClassLinkerTest { ASSERT_TRUE(klass != nullptr) << descriptor; Handle<mirror::ClassLoader> expected_class_loader( hs.NewHandle(soa.Decode<mirror::ClassLoader>(expected_class_loader_obj))); - ASSERT_EQ(klass->GetClassLoader(), expected_class_loader.Get()); + ASSERT_OBJ_PTR_EQ(klass->GetClassLoader(), expected_class_loader.Get()); } } }; diff --git a/runtime/common_dex_operations.h b/runtime/common_dex_operations.h index 9c2a40b50d..c29043e7c6 100644 --- a/runtime/common_dex_operations.h +++ b/runtime/common_dex_operations.h @@ -205,7 +205,12 @@ ALWAYS_INLINE bool DoFieldPutCommon(Thread* self, HandleWrapperObjPtr<mirror::Object> h_obj(hs.NewHandleWrapper(&obj)); field_class = field->ResolveType(); } - if (!reg->VerifierInstanceOf(field_class.Ptr())) { + // ArtField::ResolveType() may fail as evidenced with a dexing bug (b/78788577). + if (UNLIKELY(field_class.IsNull())) { + Thread::Current()->AssertPendingException(); + return false; + } + if (UNLIKELY(!reg->VerifierInstanceOf(field_class.Ptr()))) { // This should never happen. std::string temp1, temp2, temp3; self->ThrowNewExceptionF("Ljava/lang/InternalError;", diff --git a/runtime/indirect_reference_table_test.cc b/runtime/indirect_reference_table_test.cc index 92785090f5..141feb434f 100644 --- a/runtime/indirect_reference_table_test.cc +++ b/runtime/indirect_reference_table_test.cc @@ -60,8 +60,9 @@ TEST_F(IndirectReferenceTableTest, BasicTest) { &error_msg); ASSERT_TRUE(irt.IsValid()) << error_msg; - mirror::Class* c = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;"); - StackHandleScope<4> hs(soa.Self()); + StackHandleScope<5> hs(soa.Self()); + Handle<mirror::Class> c = + hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;")); ASSERT_TRUE(c != nullptr); Handle<mirror::Object> obj0 = hs.NewHandle(c->AllocObject(soa.Self())); ASSERT_TRUE(obj0 != nullptr); @@ -278,8 +279,9 @@ TEST_F(IndirectReferenceTableTest, Holes) { ScopedObjectAccess soa(Thread::Current()); static const size_t kTableMax = 10; - mirror::Class* c = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;"); - StackHandleScope<5> hs(soa.Self()); + StackHandleScope<6> hs(soa.Self()); + Handle<mirror::Class> c = hs.NewHandle( + class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;")); ASSERT_TRUE(c != nullptr); Handle<mirror::Object> obj0 = hs.NewHandle(c->AllocObject(soa.Self())); ASSERT_TRUE(obj0 != nullptr); @@ -487,8 +489,9 @@ TEST_F(IndirectReferenceTableTest, Resize) { ScopedObjectAccess soa(Thread::Current()); static const size_t kTableMax = 512; - mirror::Class* c = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;"); - StackHandleScope<1> hs(soa.Self()); + StackHandleScope<2> hs(soa.Self()); + Handle<mirror::Class> c = hs.NewHandle( + class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;")); ASSERT_TRUE(c != nullptr); Handle<mirror::Object> obj0 = hs.NewHandle(c->AllocObject(soa.Self())); ASSERT_TRUE(obj0 != nullptr); diff --git a/runtime/instrumentation_test.cc b/runtime/instrumentation_test.cc index 3171eeb861..8ac26afe9f 100644 --- a/runtime/instrumentation_test.cc +++ b/runtime/instrumentation_test.cc @@ -520,7 +520,7 @@ TEST_F(InstrumentationTest, MethodEntryEvent) { ClassLinker* class_linker = runtime->GetClassLinker(); StackHandleScope<1> hs(soa.Self()); Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader))); - mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader); + ObjPtr<mirror::Class> klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader); ASSERT_TRUE(klass != nullptr); ArtMethod* method = klass->FindClassMethod("returnReference", "()Ljava/lang/Object;", kRuntimePointerSize); @@ -540,7 +540,7 @@ TEST_F(InstrumentationTest, MethodExitObjectEvent) { ClassLinker* class_linker = runtime->GetClassLinker(); StackHandleScope<1> hs(soa.Self()); Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader))); - mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader); + ObjPtr<mirror::Class> klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader); ASSERT_TRUE(klass != nullptr); ArtMethod* method = klass->FindClassMethod("returnReference", "()Ljava/lang/Object;", kRuntimePointerSize); @@ -560,7 +560,7 @@ TEST_F(InstrumentationTest, MethodExitPrimEvent) { ClassLinker* class_linker = runtime->GetClassLinker(); StackHandleScope<1> hs(soa.Self()); Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader))); - mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader); + ObjPtr<mirror::Class> klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader); ASSERT_TRUE(klass != nullptr); ArtMethod* method = klass->FindClassMethod("returnPrimitive", "()I", kRuntimePointerSize); ASSERT_TRUE(method != nullptr); @@ -595,7 +595,7 @@ TEST_F(InstrumentationTest, FieldWriteObjectEvent) { ClassLinker* class_linker = runtime->GetClassLinker(); StackHandleScope<1> hs(soa.Self()); Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader))); - mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader); + ObjPtr<mirror::Class> klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader); ASSERT_TRUE(klass != nullptr); ArtField* field = klass->FindDeclaredStaticField("referenceField", "Ljava/lang/Object;"); ASSERT_TRUE(field != nullptr); @@ -613,7 +613,7 @@ TEST_F(InstrumentationTest, FieldWritePrimEvent) { ClassLinker* class_linker = runtime->GetClassLinker(); StackHandleScope<1> hs(soa.Self()); Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader))); - mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader); + ObjPtr<mirror::Class> klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader); ASSERT_TRUE(klass != nullptr); ArtField* field = klass->FindDeclaredStaticField("primitiveField", "I"); ASSERT_TRUE(field != nullptr); @@ -648,7 +648,7 @@ TEST_F(InstrumentationTest, DeoptimizeDirectMethod) { ClassLinker* class_linker = runtime->GetClassLinker(); StackHandleScope<1> hs(soa.Self()); Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader))); - mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader); + ObjPtr<mirror::Class> klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader); ASSERT_TRUE(klass != nullptr); ArtMethod* method_to_deoptimize = klass->FindClassMethod("instanceMethod", "()V", kRuntimePointerSize); @@ -697,7 +697,7 @@ TEST_F(InstrumentationTest, MixedDeoptimization) { ClassLinker* class_linker = runtime->GetClassLinker(); StackHandleScope<1> hs(soa.Self()); Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader))); - mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader); + ObjPtr<mirror::Class> klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader); ASSERT_TRUE(klass != nullptr); ArtMethod* method_to_deoptimize = klass->FindClassMethod("instanceMethod", "()V", kRuntimePointerSize); diff --git a/runtime/jni/jni_internal_test.cc b/runtime/jni/jni_internal_test.cc index 5d74181cef..a25049e681 100644 --- a/runtime/jni/jni_internal_test.cc +++ b/runtime/jni/jni_internal_test.cc @@ -91,7 +91,7 @@ class JniInternalTest : public CommonCompilerTest { jclass GetPrimitiveClass(char descriptor) { ScopedObjectAccess soa(env_); - mirror::Class* c = class_linker_->FindPrimitiveClass(descriptor); + ObjPtr<mirror::Class> c = class_linker_->FindPrimitiveClass(descriptor); CHECK(c != nullptr); return soa.AddLocalReference<jclass>(c); } @@ -624,7 +624,7 @@ class JniInternalTest : public CommonCompilerTest { StackHandleScope<1> hs(soa.Self()); Handle<mirror::ClassLoader> loader( hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader_))); - mirror::Class* c = class_linker_->FindClass(soa.Self(), "LMyClassNatives;", loader); + ObjPtr<mirror::Class> c = class_linker_->FindClass(soa.Self(), "LMyClassNatives;", loader); const auto pointer_size = class_linker_->GetImagePointerSize(); ArtMethod* method = c->FindClassMethod(method_name, method_sig, pointer_size); ASSERT_TRUE(method != nullptr) << method_name << " " << method_sig; diff --git a/runtime/mirror/dex_cache_test.cc b/runtime/mirror/dex_cache_test.cc index 97e0ce6684..7a70cae1ef 100644 --- a/runtime/mirror/dex_cache_test.cc +++ b/runtime/mirror/dex_cache_test.cc @@ -83,7 +83,7 @@ TEST_F(DexCacheTest, LinearAlloc) { StackHandleScope<1> hs(soa.Self()); Handle<mirror::ClassLoader> class_loader(hs.NewHandle( soa.Decode<mirror::ClassLoader>(jclass_loader))); - mirror::Class* klass = class_linker_->FindClass(soa.Self(), "LMain;", class_loader); + ObjPtr<mirror::Class> klass = class_linker_->FindClass(soa.Self(), "LMain;", class_loader); ASSERT_TRUE(klass != nullptr); LinearAlloc* const linear_alloc = klass->GetClassLoader()->GetAllocator(); EXPECT_NE(linear_alloc, runtime_->GetLinearAlloc()); diff --git a/runtime/mirror/method_type_test.cc b/runtime/mirror/method_type_test.cc index a361772c58..16bfc73e04 100644 --- a/runtime/mirror/method_type_test.cc +++ b/runtime/mirror/method_type_test.cc @@ -54,7 +54,7 @@ static mirror::MethodType* CreateMethodType(const std::string& return_type, CHECK(return_clazz != nullptr); ObjPtr<mirror::Class> class_type = mirror::Class::GetJavaLangClass(); - mirror::Class* class_array_type = class_linker->FindArrayClass(self, &class_type); + ObjPtr<mirror::Class> class_array_type = class_linker->FindArrayClass(self, &class_type); Handle<mirror::ObjectArray<mirror::Class>> param_classes = hs.NewHandle( mirror::ObjectArray<mirror::Class>::Alloc(self, class_array_type, param_types.size())); diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc index 5306eac7f6..69ba4b98cf 100644 --- a/runtime/mirror/object_test.cc +++ b/runtime/mirror/object_test.cc @@ -116,7 +116,7 @@ TEST_F(ObjectTest, Clone) { TEST_F(ObjectTest, AllocObjectArray) { ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<2> hs(soa.Self()); + StackHandleScope<3> hs(soa.Self()); Handle<ObjectArray<Object>> oa(hs.NewHandle(AllocObjectArray<Object>(soa.Self(), 2))); EXPECT_EQ(2, oa->GetLength()); EXPECT_TRUE(oa->Get(0) == nullptr); @@ -128,17 +128,17 @@ TEST_F(ObjectTest, AllocObjectArray) { EXPECT_TRUE(oa->Get(0) == oa.Get()); EXPECT_TRUE(oa->Get(1) == oa.Get()); - Class* aioobe = class_linker_->FindSystemClass(soa.Self(), - "Ljava/lang/ArrayIndexOutOfBoundsException;"); + Handle<Class> aioobe = hs.NewHandle( + class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/ArrayIndexOutOfBoundsException;")); EXPECT_TRUE(oa->Get(-1) == nullptr); EXPECT_TRUE(soa.Self()->IsExceptionPending()); - EXPECT_EQ(aioobe, soa.Self()->GetException()->GetClass()); + EXPECT_OBJ_PTR_EQ(aioobe.Get(), soa.Self()->GetException()->GetClass()); soa.Self()->ClearException(); EXPECT_TRUE(oa->Get(2) == nullptr); EXPECT_TRUE(soa.Self()->IsExceptionPending()); - EXPECT_EQ(aioobe, soa.Self()->GetException()->GetClass()); + EXPECT_OBJ_PTR_EQ(aioobe.Get(), soa.Self()->GetException()->GetClass()); soa.Self()->ClearException(); ASSERT_TRUE(oa->GetClass() != nullptr); @@ -152,53 +152,51 @@ TEST_F(ObjectTest, AllocObjectArray) { TEST_F(ObjectTest, AllocArray) { ScopedObjectAccess soa(Thread::Current()); - Class* c = class_linker_->FindSystemClass(soa.Self(), "[I"); - StackHandleScope<1> hs(soa.Self()); - MutableHandle<Array> a( - hs.NewHandle(Array::Alloc<true>(soa.Self(), c, 1, c->GetComponentSizeShift(), - Runtime::Current()->GetHeap()->GetCurrentAllocator()))); - EXPECT_TRUE(c == a->GetClass()); + StackHandleScope<2> hs(soa.Self()); + MutableHandle<Class> c = hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "[I")); + gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator(); + MutableHandle<Array> a = hs.NewHandle( + Array::Alloc<true>(soa.Self(), c.Get(), 1, c->GetComponentSizeShift(), allocator_type)); + EXPECT_TRUE(c.Get() == a->GetClass()); EXPECT_EQ(1, a->GetLength()); - c = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/Object;"); - a.Assign(Array::Alloc<true>(soa.Self(), c, 1, c->GetComponentSizeShift(), - Runtime::Current()->GetHeap()->GetCurrentAllocator())); - EXPECT_TRUE(c == a->GetClass()); + c.Assign(class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/Object;")); + a.Assign(Array::Alloc<true>(soa.Self(), c.Get(), 1, c->GetComponentSizeShift(), allocator_type)); + EXPECT_TRUE(c.Get() == a->GetClass()); EXPECT_EQ(1, a->GetLength()); - c = class_linker_->FindSystemClass(soa.Self(), "[[Ljava/lang/Object;"); - a.Assign(Array::Alloc<true>(soa.Self(), c, 1, c->GetComponentSizeShift(), - Runtime::Current()->GetHeap()->GetCurrentAllocator())); - EXPECT_TRUE(c == a->GetClass()); + c.Assign(class_linker_->FindSystemClass(soa.Self(), "[[Ljava/lang/Object;")); + a.Assign(Array::Alloc<true>(soa.Self(), c.Get(), 1, c->GetComponentSizeShift(), allocator_type)); + EXPECT_TRUE(c.Get() == a->GetClass()); EXPECT_EQ(1, a->GetLength()); } TEST_F(ObjectTest, AllocArray_FillUsable) { ScopedObjectAccess soa(Thread::Current()); - Class* c = class_linker_->FindSystemClass(soa.Self(), "[B"); - StackHandleScope<1> hs(soa.Self()); - MutableHandle<Array> a( - hs.NewHandle(Array::Alloc<true, true>(soa.Self(), c, 1, c->GetComponentSizeShift(), - Runtime::Current()->GetHeap()->GetCurrentAllocator()))); - EXPECT_TRUE(c == a->GetClass()); + StackHandleScope<2> hs(soa.Self()); + MutableHandle<Class> c = hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "[B")); + gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator(); + MutableHandle<Array> a = hs.NewHandle( + Array::Alloc<true, true>(soa.Self(), c.Get(), 1, c->GetComponentSizeShift(), allocator_type)); + EXPECT_TRUE(c.Get() == a->GetClass()); EXPECT_LE(1, a->GetLength()); - c = class_linker_->FindSystemClass(soa.Self(), "[I"); - a.Assign(Array::Alloc<true, true>(soa.Self(), c, 2, c->GetComponentSizeShift(), - Runtime::Current()->GetHeap()->GetCurrentAllocator())); - EXPECT_TRUE(c == a->GetClass()); + c.Assign(class_linker_->FindSystemClass(soa.Self(), "[I")); + a.Assign( + Array::Alloc<true, true>(soa.Self(), c.Get(), 2, c->GetComponentSizeShift(), allocator_type)); + EXPECT_TRUE(c.Get() == a->GetClass()); EXPECT_LE(2, a->GetLength()); - c = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/Object;"); - a.Assign(Array::Alloc<true, true>(soa.Self(), c, 2, c->GetComponentSizeShift(), - Runtime::Current()->GetHeap()->GetCurrentAllocator())); - EXPECT_TRUE(c == a->GetClass()); + c.Assign(class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/Object;")); + a.Assign( + Array::Alloc<true, true>(soa.Self(), c.Get(), 2, c->GetComponentSizeShift(), allocator_type)); + EXPECT_TRUE(c.Get() == a->GetClass()); EXPECT_LE(2, a->GetLength()); - c = class_linker_->FindSystemClass(soa.Self(), "[[Ljava/lang/Object;"); - a.Assign(Array::Alloc<true, true>(soa.Self(), c, 2, c->GetComponentSizeShift(), - Runtime::Current()->GetHeap()->GetCurrentAllocator())); - EXPECT_TRUE(c == a->GetClass()); + c.Assign(class_linker_->FindSystemClass(soa.Self(), "[[Ljava/lang/Object;")); + a.Assign( + Array::Alloc<true, true>(soa.Self(), c.Get(), 2, c->GetComponentSizeShift(), allocator_type)); + EXPECT_TRUE(c.Get() == a->GetClass()); EXPECT_LE(2, a->GetLength()); } @@ -218,16 +216,18 @@ void TestPrimitiveArray(ClassLinker* cl) { EXPECT_EQ(T(123), a->Get(0)); EXPECT_EQ(T(321), a->Get(1)); - Class* aioobe = cl->FindSystemClass(soa.Self(), "Ljava/lang/ArrayIndexOutOfBoundsException;"); + StackHandleScope<1> hs(soa.Self()); + Handle<Class> aioobe = hs.NewHandle( + cl->FindSystemClass(soa.Self(), "Ljava/lang/ArrayIndexOutOfBoundsException;")); EXPECT_EQ(0, a->Get(-1)); EXPECT_TRUE(soa.Self()->IsExceptionPending()); - EXPECT_EQ(aioobe, soa.Self()->GetException()->GetClass()); + EXPECT_OBJ_PTR_EQ(aioobe.Get(), soa.Self()->GetException()->GetClass()); soa.Self()->ClearException(); EXPECT_EQ(0, a->Get(2)); EXPECT_TRUE(soa.Self()->IsExceptionPending()); - EXPECT_EQ(aioobe, soa.Self()->GetException()->GetClass()); + EXPECT_OBJ_PTR_EQ(aioobe.Get(), soa.Self()->GetException()->GetClass()); soa.Self()->ClearException(); } @@ -266,17 +266,18 @@ TEST_F(ObjectTest, PrimitiveArray_Double_Alloc) { EXPECT_DOUBLE_EQ(T(123), a->Get(0)); EXPECT_DOUBLE_EQ(T(321), a->Get(1)); - Class* aioobe = class_linker_->FindSystemClass(soa.Self(), - "Ljava/lang/ArrayIndexOutOfBoundsException;"); + StackHandleScope<1> hs(soa.Self()); + Handle<Class> aioobe = hs.NewHandle( + class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/ArrayIndexOutOfBoundsException;")); EXPECT_DOUBLE_EQ(0, a->Get(-1)); EXPECT_TRUE(soa.Self()->IsExceptionPending()); - EXPECT_EQ(aioobe, soa.Self()->GetException()->GetClass()); + EXPECT_OBJ_PTR_EQ(aioobe.Get(), soa.Self()->GetException()->GetClass()); soa.Self()->ClearException(); EXPECT_DOUBLE_EQ(0, a->Get(2)); EXPECT_TRUE(soa.Self()->IsExceptionPending()); - EXPECT_EQ(aioobe, soa.Self()->GetException()->GetClass()); + EXPECT_OBJ_PTR_EQ(aioobe.Get(), soa.Self()->GetException()->GetClass()); soa.Self()->ClearException(); } @@ -296,17 +297,18 @@ TEST_F(ObjectTest, PrimitiveArray_Float_Alloc) { EXPECT_FLOAT_EQ(T(123), a->Get(0)); EXPECT_FLOAT_EQ(T(321), a->Get(1)); - Class* aioobe = class_linker_->FindSystemClass(soa.Self(), - "Ljava/lang/ArrayIndexOutOfBoundsException;"); + StackHandleScope<1> hs(soa.Self()); + Handle<Class> aioobe = hs.NewHandle( + class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/ArrayIndexOutOfBoundsException;")); EXPECT_FLOAT_EQ(0, a->Get(-1)); EXPECT_TRUE(soa.Self()->IsExceptionPending()); - EXPECT_EQ(aioobe, soa.Self()->GetException()->GetClass()); + EXPECT_OBJ_PTR_EQ(aioobe.Get(), soa.Self()->GetException()->GetClass()); soa.Self()->ClearException(); EXPECT_FLOAT_EQ(0, a->Get(2)); EXPECT_TRUE(soa.Self()->IsExceptionPending()); - EXPECT_EQ(aioobe, soa.Self()->GetException()->GetClass()); + EXPECT_OBJ_PTR_EQ(aioobe.Get(), soa.Self()->GetException()->GetClass()); soa.Self()->ClearException(); } @@ -352,9 +354,10 @@ TEST_F(ObjectTest, StaticFieldFromCode) { jobject class_loader = LoadDex("StaticsFromCode"); const DexFile* dex_file = GetFirstDexFile(class_loader); - StackHandleScope<2> hs(soa.Self()); + StackHandleScope<3> hs(soa.Self()); Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<ClassLoader>(class_loader))); - Class* klass = class_linker_->FindClass(soa.Self(), "LStaticsFromCode;", loader); + Handle<Class> klass = + hs.NewHandle(class_linker_->FindClass(soa.Self(), "LStaticsFromCode;", loader)); ArtMethod* clinit = klass->FindClassInitializer(kRuntimePointerSize); const DexFile::TypeId* klass_type_id = dex_file->FindTypeId("LStaticsFromCode;"); ASSERT_TRUE(klass_type_id != nullptr); @@ -372,15 +375,15 @@ TEST_F(ObjectTest, StaticFieldFromCode) { ArtField* field = FindFieldFromCode<StaticObjectRead, true>(field_idx, clinit, Thread::Current(), sizeof(HeapReference<Object>)); - ObjPtr<Object> s0 = field->GetObj(klass); + ObjPtr<Object> s0 = field->GetObj(klass.Get()); EXPECT_TRUE(s0 != nullptr); Handle<CharArray> char_array(hs.NewHandle(CharArray::Alloc(soa.Self(), 0))); field->SetObj<false>(field->GetDeclaringClass(), char_array.Get()); - EXPECT_OBJ_PTR_EQ(char_array.Get(), field->GetObj(klass)); + EXPECT_OBJ_PTR_EQ(char_array.Get(), field->GetObj(klass.Get())); field->SetObj<false>(field->GetDeclaringClass(), nullptr); - EXPECT_EQ(nullptr, field->GetObj(klass)); + EXPECT_EQ(nullptr, field->GetObj(klass.Get())); // TODO: more exhaustive tests of all 6 cases of ArtField::*FromCode } @@ -486,9 +489,11 @@ TEST_F(ObjectTest, DescriptorCompare) { Handle<ClassLoader> class_loader_1(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader_1))); Handle<ClassLoader> class_loader_2(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader_2))); - Class* klass1 = linker->FindClass(soa.Self(), "LProtoCompare;", class_loader_1); + Handle<Class> klass1 = + hs.NewHandle(linker->FindClass(soa.Self(), "LProtoCompare;", class_loader_1)); ASSERT_TRUE(klass1 != nullptr); - Class* klass2 = linker->FindClass(soa.Self(), "LProtoCompare2;", class_loader_2); + Handle<Class> klass2 = + hs.NewHandle(linker->FindClass(soa.Self(), "LProtoCompare2;", class_loader_2)); ASSERT_TRUE(klass2 != nullptr); ArtMethod* m1_1 = klass1->GetVirtualMethod(0, kRuntimePointerSize); @@ -525,11 +530,11 @@ TEST_F(ObjectTest, StringHashCode) { TEST_F(ObjectTest, InstanceOf) { ScopedObjectAccess soa(Thread::Current()); jobject jclass_loader = LoadDex("XandY"); - StackHandleScope<3> hs(soa.Self()); + StackHandleScope<10> hs(soa.Self()); Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader))); - Class* X = class_linker_->FindClass(soa.Self(), "LX;", class_loader); - Class* Y = class_linker_->FindClass(soa.Self(), "LY;", class_loader); + Handle<Class> X = hs.NewHandle(class_linker_->FindClass(soa.Self(), "LX;", class_loader)); + Handle<Class> Y = hs.NewHandle(class_linker_->FindClass(soa.Self(), "LY;", class_loader)); ASSERT_TRUE(X != nullptr); ASSERT_TRUE(Y != nullptr); @@ -538,51 +543,56 @@ TEST_F(ObjectTest, InstanceOf) { ASSERT_TRUE(x != nullptr); ASSERT_TRUE(y != nullptr); - EXPECT_TRUE(x->InstanceOf(X)); - EXPECT_FALSE(x->InstanceOf(Y)); - EXPECT_TRUE(y->InstanceOf(X)); - EXPECT_TRUE(y->InstanceOf(Y)); + EXPECT_TRUE(x->InstanceOf(X.Get())); + EXPECT_FALSE(x->InstanceOf(Y.Get())); + EXPECT_TRUE(y->InstanceOf(X.Get())); + EXPECT_TRUE(y->InstanceOf(Y.Get())); - Class* java_lang_Class = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Class;"); - Class* Object_array_class = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/Object;"); + Handle<Class> java_lang_Class = + hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Class;")); + Handle<Class> Object_array_class = + hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/Object;")); - EXPECT_FALSE(java_lang_Class->InstanceOf(Object_array_class)); - EXPECT_TRUE(Object_array_class->InstanceOf(java_lang_Class)); + EXPECT_FALSE(java_lang_Class->InstanceOf(Object_array_class.Get())); + EXPECT_TRUE(Object_array_class->InstanceOf(java_lang_Class.Get())); // All array classes implement Cloneable and Serializable. - Object* array = ObjectArray<Object>::Alloc(soa.Self(), Object_array_class, 1); - Class* java_lang_Cloneable = - class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Cloneable;"); - Class* java_io_Serializable = - class_linker_->FindSystemClass(soa.Self(), "Ljava/io/Serializable;"); - EXPECT_TRUE(array->InstanceOf(java_lang_Cloneable)); - EXPECT_TRUE(array->InstanceOf(java_io_Serializable)); + Handle<Object> array = + hs.NewHandle<Object>(ObjectArray<Object>::Alloc(soa.Self(), Object_array_class.Get(), 1)); + Handle<Class> java_lang_Cloneable = + hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Cloneable;")); + Handle<Class> java_io_Serializable = + hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/io/Serializable;")); + EXPECT_TRUE(array->InstanceOf(java_lang_Cloneable.Get())); + EXPECT_TRUE(array->InstanceOf(java_io_Serializable.Get())); } TEST_F(ObjectTest, IsAssignableFrom) { ScopedObjectAccess soa(Thread::Current()); jobject jclass_loader = LoadDex("XandY"); - StackHandleScope<1> hs(soa.Self()); + StackHandleScope<5> hs(soa.Self()); Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader))); - Class* X = class_linker_->FindClass(soa.Self(), "LX;", class_loader); - Class* Y = class_linker_->FindClass(soa.Self(), "LY;", class_loader); + Handle<Class> X = hs.NewHandle(class_linker_->FindClass(soa.Self(), "LX;", class_loader)); + Handle<Class> Y = hs.NewHandle(class_linker_->FindClass(soa.Self(), "LY;", class_loader)); - EXPECT_TRUE(X->IsAssignableFrom(X)); - EXPECT_TRUE(X->IsAssignableFrom(Y)); - EXPECT_FALSE(Y->IsAssignableFrom(X)); - EXPECT_TRUE(Y->IsAssignableFrom(Y)); + EXPECT_TRUE(X->IsAssignableFrom(X.Get())); + EXPECT_TRUE(X->IsAssignableFrom(Y.Get())); + EXPECT_FALSE(Y->IsAssignableFrom(X.Get())); + EXPECT_TRUE(Y->IsAssignableFrom(Y.Get())); // class final String implements CharSequence, .. - Class* string = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/String;"); - Class* charseq = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/CharSequence;"); + Handle<Class> string = + hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/String;")); + Handle<Class> charseq = + hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/CharSequence;")); // Can String be assigned to CharSequence without a cast? - EXPECT_TRUE(charseq->IsAssignableFrom(string)); + EXPECT_TRUE(charseq->IsAssignableFrom(string.Get())); // Can CharSequence be assigned to String without a cast? - EXPECT_FALSE(string->IsAssignableFrom(charseq)); + EXPECT_FALSE(string->IsAssignableFrom(charseq.Get())); // Primitive types are only assignable to themselves const char* prims = "ZBCSIJFD"; - std::vector<Class*> prim_types(strlen(prims)); + std::vector<ObjPtr<Class>> prim_types(strlen(prims)); for (size_t i = 0; i < strlen(prims); i++) { prim_types[i] = class_linker_->FindPrimitiveClass(prims[i]); } @@ -600,55 +610,61 @@ TEST_F(ObjectTest, IsAssignableFrom) { TEST_F(ObjectTest, IsAssignableFromArray) { ScopedObjectAccess soa(Thread::Current()); jobject jclass_loader = LoadDex("XandY"); - StackHandleScope<1> hs(soa.Self()); + StackHandleScope<14> hs(soa.Self()); Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader))); - Class* X = class_linker_->FindClass(soa.Self(), "LX;", class_loader); - Class* Y = class_linker_->FindClass(soa.Self(), "LY;", class_loader); + Handle<Class> X = hs.NewHandle(class_linker_->FindClass(soa.Self(), "LX;", class_loader)); + Handle<Class> Y = hs.NewHandle(class_linker_->FindClass(soa.Self(), "LY;", class_loader)); ASSERT_TRUE(X != nullptr); ASSERT_TRUE(Y != nullptr); - Class* YA = class_linker_->FindClass(soa.Self(), "[LY;", class_loader); - Class* YAA = class_linker_->FindClass(soa.Self(), "[[LY;", class_loader); + Handle<Class> YA = hs.NewHandle(class_linker_->FindClass(soa.Self(), "[LY;", class_loader)); + Handle<Class> YAA = hs.NewHandle(class_linker_->FindClass(soa.Self(), "[[LY;", class_loader)); ASSERT_TRUE(YA != nullptr); ASSERT_TRUE(YAA != nullptr); - Class* XAA = class_linker_->FindClass(soa.Self(), "[[LX;", class_loader); + Handle<Class> XAA = hs.NewHandle(class_linker_->FindClass(soa.Self(), "[[LX;", class_loader)); ASSERT_TRUE(XAA != nullptr); - Class* O = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;"); - Class* OA = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/Object;"); - Class* OAA = class_linker_->FindSystemClass(soa.Self(), "[[Ljava/lang/Object;"); - Class* OAAA = class_linker_->FindSystemClass(soa.Self(), "[[[Ljava/lang/Object;"); + Handle<Class> O = hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;")); + Handle<Class> OA = + hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/Object;")); + Handle<Class> OAA = + hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "[[Ljava/lang/Object;")); + Handle<Class> OAAA = + hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "[[[Ljava/lang/Object;")); ASSERT_TRUE(O != nullptr); ASSERT_TRUE(OA != nullptr); ASSERT_TRUE(OAA != nullptr); ASSERT_TRUE(OAAA != nullptr); - Class* S = class_linker_->FindSystemClass(soa.Self(), "Ljava/io/Serializable;"); - Class* SA = class_linker_->FindSystemClass(soa.Self(), "[Ljava/io/Serializable;"); - Class* SAA = class_linker_->FindSystemClass(soa.Self(), "[[Ljava/io/Serializable;"); + Handle<Class> S = + hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/io/Serializable;")); + Handle<Class> SA = + hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "[Ljava/io/Serializable;")); + Handle<Class> SAA = + hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "[[Ljava/io/Serializable;")); ASSERT_TRUE(S != nullptr); ASSERT_TRUE(SA != nullptr); ASSERT_TRUE(SAA != nullptr); - Class* IA = class_linker_->FindSystemClass(soa.Self(), "[I"); + Handle<Class> IA = hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "[I")); ASSERT_TRUE(IA != nullptr); - EXPECT_TRUE(YAA->IsAssignableFrom(YAA)); // identity - EXPECT_TRUE(XAA->IsAssignableFrom(YAA)); // element superclass - EXPECT_FALSE(YAA->IsAssignableFrom(XAA)); - EXPECT_FALSE(Y->IsAssignableFrom(YAA)); - EXPECT_FALSE(YA->IsAssignableFrom(YAA)); - EXPECT_TRUE(O->IsAssignableFrom(YAA)); // everything is an Object - EXPECT_TRUE(OA->IsAssignableFrom(YAA)); - EXPECT_TRUE(OAA->IsAssignableFrom(YAA)); - EXPECT_TRUE(S->IsAssignableFrom(YAA)); // all arrays are Serializable - EXPECT_TRUE(SA->IsAssignableFrom(YAA)); - EXPECT_FALSE(SAA->IsAssignableFrom(YAA)); // unless Y was Serializable + EXPECT_TRUE(YAA->IsAssignableFrom(YAA.Get())); // identity + EXPECT_TRUE(XAA->IsAssignableFrom(YAA.Get())); // element superclass + EXPECT_FALSE(YAA->IsAssignableFrom(XAA.Get())); + EXPECT_FALSE(Y->IsAssignableFrom(YAA.Get())); + EXPECT_FALSE(YA->IsAssignableFrom(YAA.Get())); + EXPECT_TRUE(O->IsAssignableFrom(YAA.Get())); // everything is an Object + EXPECT_TRUE(OA->IsAssignableFrom(YAA.Get())); + EXPECT_TRUE(OAA->IsAssignableFrom(YAA.Get())); + EXPECT_TRUE(S->IsAssignableFrom(YAA.Get())); // all arrays are Serializable + EXPECT_TRUE(SA->IsAssignableFrom(YAA.Get())); + EXPECT_FALSE(SAA->IsAssignableFrom(YAA.Get())); // unless Y was Serializable - EXPECT_FALSE(IA->IsAssignableFrom(OA)); - EXPECT_FALSE(OA->IsAssignableFrom(IA)); - EXPECT_TRUE(O->IsAssignableFrom(IA)); + EXPECT_FALSE(IA->IsAssignableFrom(OA.Get())); + EXPECT_FALSE(OA->IsAssignableFrom(IA.Get())); + EXPECT_TRUE(O->IsAssignableFrom(IA.Get())); } TEST_F(ObjectTest, FindInstanceField) { @@ -656,7 +672,7 @@ TEST_F(ObjectTest, FindInstanceField) { StackHandleScope<1> hs(soa.Self()); Handle<String> s(hs.NewHandle(String::AllocFromModifiedUtf8(soa.Self(), "ABC"))); ASSERT_TRUE(s != nullptr); - Class* c = s->GetClass(); + ObjPtr<Class> c = s->GetClass(); ASSERT_TRUE(c != nullptr); // Wrong type. @@ -798,7 +814,7 @@ TEST_F(ObjectTest, PrettyTypeOf) { Handle<mirror::ShortArray> a(hs.NewHandle(mirror::ShortArray::Alloc(soa.Self(), 2))); EXPECT_EQ("short[]", mirror::Object::PrettyTypeOf(a.Get())); - mirror::Class* c = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;"); + ObjPtr<mirror::Class> c = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;"); ASSERT_TRUE(c != nullptr); mirror::Object* o = mirror::ObjectArray<mirror::String>::Alloc(soa.Self(), c, 0); EXPECT_EQ("java.lang.String[]", mirror::Object::PrettyTypeOf(o)); diff --git a/runtime/proxy_test.h b/runtime/proxy_test.h index b559823257..98362649f5 100644 --- a/runtime/proxy_test.h +++ b/runtime/proxy_test.h @@ -37,7 +37,9 @@ mirror::Class* GenerateProxyClass(ScopedObjectAccess& soa, const char* className, const std::vector<mirror::Class*>& interfaces) REQUIRES_SHARED(Locks::mutator_lock_) { - mirror::Class* javaLangObject = class_linker->FindSystemClass(soa.Self(), "Ljava/lang/Object;"); + StackHandleScope<1> hs(soa.Self()); + Handle<mirror::Class> javaLangObject = hs.NewHandle( + class_linker->FindSystemClass(soa.Self(), "Ljava/lang/Object;")); CHECK(javaLangObject != nullptr); jclass javaLangClass = soa.AddLocalReference<jclass>(mirror::Class::GetJavaLangClass()); @@ -67,7 +69,7 @@ mirror::Class* GenerateProxyClass(ScopedObjectAccess& soa, "equals", "(Ljava/lang/Object;)Z", kRuntimePointerSize); CHECK(method != nullptr); CHECK(!method->IsDirect()); - CHECK(method->GetDeclaringClass() == javaLangObject); + CHECK(method->GetDeclaringClass() == javaLangObject.Get()); DCHECK(!Runtime::Current()->IsActiveTransaction()); soa.Env()->SetObjectArrayElement( proxyClassMethods, array_index++, soa.AddLocalReference<jobject>( @@ -75,7 +77,7 @@ mirror::Class* GenerateProxyClass(ScopedObjectAccess& soa, method = javaLangObject->FindClassMethod("hashCode", "()I", kRuntimePointerSize); CHECK(method != nullptr); CHECK(!method->IsDirect()); - CHECK(method->GetDeclaringClass() == javaLangObject); + CHECK(method->GetDeclaringClass() == javaLangObject.Get()); soa.Env()->SetObjectArrayElement( proxyClassMethods, array_index++, soa.AddLocalReference<jobject>( mirror::Method::CreateFromArtMethod<kRuntimePointerSize, false>(soa.Self(), method))); @@ -83,7 +85,7 @@ mirror::Class* GenerateProxyClass(ScopedObjectAccess& soa, "toString", "()Ljava/lang/String;", kRuntimePointerSize); CHECK(method != nullptr); CHECK(!method->IsDirect()); - CHECK(method->GetDeclaringClass() == javaLangObject); + CHECK(method->GetDeclaringClass() == javaLangObject.Get()); soa.Env()->SetObjectArrayElement( proxyClassMethods, array_index++, soa.AddLocalReference<jobject>( mirror::Method::CreateFromArtMethod<kRuntimePointerSize, false>(soa.Self(), method))); @@ -64,11 +64,8 @@ if options.gtest or not options.run_test: build_command = 'make' build_command += ' -j' + str(options.n_threads) - build_command += ' -C ' + ANDROID_BUILD_TOP build_command += ' ' + build_target - # Add 'dist' to avoid Jack issues b/36169180. - build_command += ' dist' print build_command diff --git a/test/003-omnibus-opcodes/build b/test/003-omnibus-opcodes/build index dba3549b1a..4d3fb37d1d 100644 --- a/test/003-omnibus-opcodes/build +++ b/test/003-omnibus-opcodes/build @@ -22,15 +22,7 @@ ${JAVAC} -d classes `find src -name '*.java'` rm classes/UnresClass.class ${JAVAC} -d classes `find src2 -name '*.java'` -if [ ${USE_JACK} = "true" ]; then - jar cf classes.jill.jar -C classes . - ${JACK} --import classes.jill.jar --output-dex . -else - if [ ${NEED_DEX} = "true" ]; then - ${DX} -JXmx256m --debug --dex --output=classes.dex classes - fi -fi - if [ ${NEED_DEX} = "true" ]; then + ${DX} -JXmx256m --debug --dex --output=classes.dex classes zip $TEST_NAME.jar classes.dex fi diff --git a/test/005-annotations/build b/test/005-annotations/build index 8b9f55065e..8eb07a9bf5 100644 --- a/test/005-annotations/build +++ b/test/005-annotations/build @@ -28,16 +28,7 @@ ${JAVAC} -d classes `find src2 -name '*.java'` rm 'classes/android/test/anno/MissingAnnotation.class' rm 'classes/android/test/anno/ClassWithInnerAnnotationClass$MissingInnerAnnotationClass.class' -if [ ${USE_JACK} = "true" ]; then - jar cf classes.jill.jar -C classes . - # Jack needs to emit annotations with CLASS retention. - ${JACK} -D jack.dex.annotation.class-retention=true --import classes.jill.jar --output-dex . -else - if [ ${NEED_DEX} = "true" ]; then - ${DX} -JXmx256m --debug --dex --output=classes.dex classes - fi -fi - if [ ${NEED_DEX} = "true" ]; then + ${DX} -JXmx256m --debug --dex --output=classes.dex classes zip $TEST_NAME.jar classes.dex fi diff --git a/test/022-interface/build b/test/022-interface/build index 5cfc7f25b7..f6aad91e97 100644 --- a/test/022-interface/build +++ b/test/022-interface/build @@ -17,13 +17,6 @@ # Stop if something fails. set -e -# Use classes that are compiled with ecj that exposes an invokeinterface -# issue when interfaces override methods in Object -if [ ${USE_JACK} = "true" ]; then - jar cf classes.jill.jar -C classes . - ${JACK} --import classes.jill.jar --output-dex . -else - ${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes -fi +${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes zip $TEST_NAME.jar classes.dex diff --git a/test/023-many-interfaces/build b/test/023-many-interfaces/build index b4b5bd4c4a..faa3ce7178 100644 --- a/test/023-many-interfaces/build +++ b/test/023-many-interfaces/build @@ -21,16 +21,4 @@ set -e gcc -Wall -Werror -o iface-gen iface-gen.c ./iface-gen -if [ ${USE_JACK} = "true" ]; then - # Use the default Jack commands - ./default-build -else - mkdir classes - ${JAVAC} -d classes src/*.java - - # dx needs more memory for that test so do not pass Xmx option here. - if [ ${NEED_DEX} = "true" ]; then - ${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes - zip $TEST_NAME.jar classes.dex - fi -fi +./default-build "$@" diff --git a/test/056-const-string-jumbo/build b/test/056-const-string-jumbo/build index 5344ac38eb..47641d5891 100644 --- a/test/056-const-string-jumbo/build +++ b/test/056-const-string-jumbo/build @@ -39,17 +39,10 @@ function writeFile(name, start, end) { printf("}\n") > fileName; }' -if [ ${USE_JACK} = "true" ]; then - ${JACK} --output-dex . src -else - mkdir classes - ${JAVAC} -d classes src/*.java - - if [ ${NEED_DEX} = "true" ]; then - ${DX} -JXmx500m --debug --dex --no-optimize --positions=none --no-locals --output=classes.dex classes - fi -fi +mkdir classes +${JAVAC} -d classes src/*.java if [ ${NEED_DEX} = "true" ]; then + ${DX} -JXmx500m --debug --dex --no-optimize --positions=none --no-locals --output=classes.dex classes zip $TEST_NAME.jar classes.dex fi diff --git a/test/091-override-package-private-method/build b/test/091-override-package-private-method/build index 073a4ba9bc..ea12b3a540 100755 --- a/test/091-override-package-private-method/build +++ b/test/091-override-package-private-method/build @@ -23,19 +23,9 @@ ${JAVAC} -d classes `find src -name '*.java'` mkdir classes-ex mv classes/OverridePackagePrivateMethodSuper.class classes-ex -if [ ${USE_JACK} = "true" ]; then - jar cf classes.jill.jar -C classes . - jar cf classes-ex.jill.jar -C classes-ex . - - ${JACK} --import classes.jill.jar --output-dex . +if [ ${NEED_DEX} = "true" ]; then + ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes zip $TEST_NAME.jar classes.dex - ${JACK} --import classes-ex.jill.jar --output-dex . + ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex zip ${TEST_NAME}-ex.jar classes.dex -else - if [ ${NEED_DEX} = "true" ]; then - ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes - zip $TEST_NAME.jar classes.dex - ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex - zip ${TEST_NAME}-ex.jar classes.dex - fi fi diff --git a/test/111-unresolvable-exception/build b/test/111-unresolvable-exception/build index cf19f60d51..6fe73af8d8 100644 --- a/test/111-unresolvable-exception/build +++ b/test/111-unresolvable-exception/build @@ -21,15 +21,7 @@ mkdir classes ${JAVAC} -d classes `find src -name '*.java'` rm classes/TestException.class -if [ ${USE_JACK} = "true" ]; then - jar cf classes.jill.jar -C classes . - ${JACK} --import classes.jill.jar --output-dex . -else - if [ ${NEED_DEX} = "true" ]; then - ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes - fi -fi - if [ ${NEED_DEX} = "true" ]; then + ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes zip $TEST_NAME.jar classes.dex fi diff --git a/test/113-multidex/build b/test/113-multidex/build index b980e501be..f945563939 100644 --- a/test/113-multidex/build +++ b/test/113-multidex/build @@ -27,25 +27,11 @@ mkdir classes2 ${JAVAC} -d classes2 `find src -name '*.java'` rm classes2/Second.class classes2/FillerA.class classes2/FillerB.class classes2/Inf*.class -if [ ${USE_JACK} = "true" ]; then - jar cf classes.jill.jar -C classes . - jar cf classes2.jill.jar -C classes2 . - - ${JACK} --import classes.jill.jar --output-dex . - mv classes.dex classes-1.dex - ${JACK} --import classes2.jill.jar --output-dex . - mv classes.dex classes2.dex - mv classes-1.dex classes.dex -else - if [ ${NEED_DEX} = "true" ]; then - # All except Main - ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes - - # Only Main - ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex classes2 - fi -fi - if [ ${NEED_DEX} = "true" ]; then + # All except Main + ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes + + # Only Main + ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex classes2 zip $TEST_NAME.jar classes.dex classes2.dex fi diff --git a/test/124-missing-classes/build b/test/124-missing-classes/build index ea45cd27e5..b13aa6e851 100644 --- a/test/124-missing-classes/build +++ b/test/124-missing-classes/build @@ -26,15 +26,7 @@ ${JAVAC} -d classes `find src -name '*.java'` rm 'classes/MissingClass.class' rm 'classes/Main$MissingInnerClass.class' -if [ ${USE_JACK} = "true" ]; then - jar cf classes.jill.jar -C classes . - ${JACK} --import classes.jill.jar --output-dex . -else - if [ ${NEED_DEX} = "true" ]; then - ${DX} -JXmx256m --debug --dex --output=classes.dex classes - fi -fi - if [ ${NEED_DEX} = "true" ]; then + ${DX} -JXmx256m --debug --dex --output=classes.dex classes zip $TEST_NAME.jar classes.dex fi diff --git a/test/126-miranda-multidex/build b/test/126-miranda-multidex/build index 2a5e7daa12..cf19855316 100644 --- a/test/126-miranda-multidex/build +++ b/test/126-miranda-multidex/build @@ -27,25 +27,11 @@ mkdir classes2 ${JAVAC} -d classes2 `find src -name '*.java'` rm classes2/Main.class classes2/MirandaAbstract.class classes2/MirandaClass*.class classes2/MirandaInterface2*.class -if [ ${USE_JACK} = "true" ]; then - jar cf classes.jill.jar -C classes . - jar cf classes2.jill.jar -C classes2 . - - ${JACK} --import classes.jill.jar --output-dex . - mv classes.dex classes-1.dex - ${JACK} --import classes2.jill.jar --output-dex . - mv classes.dex classes2.dex - mv classes-1.dex classes.dex -else - if [ ${NEED_DEX} = "true" ]; then - # All except Main - ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes - - # Only Main - ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex classes2 - fi -fi - if [ ${NEED_DEX} = "true" ]; then + # All except Main + ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes + + # Only Main + ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex classes2 zip $TEST_NAME.jar classes.dex classes2.dex fi diff --git a/test/127-checker-secondarydex/build b/test/127-checker-secondarydex/build index 7ce46acfed..712774f7ef 100755 --- a/test/127-checker-secondarydex/build +++ b/test/127-checker-secondarydex/build @@ -23,19 +23,9 @@ ${JAVAC} -d classes `find src -name '*.java'` mkdir classes-ex mv classes/Super.class classes-ex -if [ ${USE_JACK} = "true" ]; then - jar cf classes.jill.jar -C classes . - jar cf classes-ex.jill.jar -C classes-ex . - - ${JACK} --import classes.jill.jar --output-dex . +if [ ${NEED_DEX} = "true" ]; then + ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes zip $TEST_NAME.jar classes.dex - ${JACK} --import classes-ex.jill.jar --output-dex . + ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex zip ${TEST_NAME}-ex.jar classes.dex -else - if [ ${NEED_DEX} = "true" ]; then - ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes - zip $TEST_NAME.jar classes.dex - ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex - zip ${TEST_NAME}-ex.jar classes.dex - fi fi diff --git a/test/138-duplicate-classes-check2/build b/test/138-duplicate-classes-check2/build index d346251edb..76d535abf1 100755 --- a/test/138-duplicate-classes-check2/build +++ b/test/138-duplicate-classes-check2/build @@ -24,15 +24,7 @@ mkdir classes-ex ${JAVAC} -d classes-ex `find src-ex -name '*.java'` rm classes-ex/A.class -if [ ${USE_JACK} = "true" ]; then - jar cf classes.jill.jar -C classes . - ${JACK} --import classes.jill.jar --output-dex . - zip ${TEST_NAME}.jar classes.dex - - jar cf classes-ex.jill.jar -C classes-ex . - ${JACK} --import classes-ex.jill.jar --output-dex . - zip ${TEST_NAME}-ex.jar classes.dex -elif [ ${NEED_DEX} = "true" ]; then +if [ ${NEED_DEX} = "true" ]; then ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes zip ${TEST_NAME}.jar classes.dex ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex diff --git a/test/173-missing-field-type/expected.txt b/test/173-missing-field-type/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/173-missing-field-type/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/173-missing-field-type/info.txt b/test/173-missing-field-type/info.txt new file mode 100644 index 0000000000..4e20b4c8e0 --- /dev/null +++ b/test/173-missing-field-type/info.txt @@ -0,0 +1 @@ +Tests handling of fields where the field type is missing (b/79751666). diff --git a/test/173-missing-field-type/smali/BadField.smali b/test/173-missing-field-type/smali/BadField.smali new file mode 100644 index 0000000000..851e8fe9c6 --- /dev/null +++ b/test/173-missing-field-type/smali/BadField.smali @@ -0,0 +1,34 @@ +# +# Copyright (C) 2018 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +.class public LBadField; +.super Ljava/lang/Object; + +# This is a bad field since there is no class Widget in this test. +.field public static widget:LWidget; + +.method public constructor <init>()V + .registers 2 + invoke-direct {v1}, Ljava/lang/Object;-><init>()V + return-void +.end method + +.method public static constructor <clinit>()V + .registers 1 + new-instance v0, Ljava/lang/Object; + invoke-direct {v0}, Ljava/lang/Object;-><init>()V + sput-object v0, LBadField;->widget:LWidget; + return-void +.end method
\ No newline at end of file diff --git a/test/173-missing-field-type/src-art/Main.java b/test/173-missing-field-type/src-art/Main.java new file mode 100644 index 0000000000..61bb918813 --- /dev/null +++ b/test/173-missing-field-type/src-art/Main.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +public class Main { + public static void main(String[] args) throws Throwable { + try { + // Class BadField is defined in BadField.smali. + Class<?> c = Class.forName("BadField"); + System.out.println("Not reached"); + c.newInstance(); + } catch (NoClassDefFoundError expected) { + // The NoClassDefFoundError is for the field widget in class BadField. + if (expected.getMessage().equals("Failed resolution of: LWidget;")) { + System.out.println("passed"); + } else { + System.out.println("failed: " + expected.getMessage()); + } + } + } +} diff --git a/test/173-missing-field-type/src/Main.java b/test/173-missing-field-type/src/Main.java new file mode 100644 index 0000000000..172d6a6214 --- /dev/null +++ b/test/173-missing-field-type/src/Main.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class Main { + // Allow test to pass on RI without adding to knownfailures.json file. + public static void main(String args[]) throws Exception { + System.out.println("passed"); + } +} diff --git a/test/1929-exception-catch-exception/smali/art/Test1929$Impl.smali b/test/1929-exception-catch-exception/smali/art/Test1929$Impl.smali index 4edd56f690..605b408d91 100644 --- a/test/1929-exception-catch-exception/smali/art/Test1929$Impl.smali +++ b/test/1929-exception-catch-exception/smali/art/Test1929$Impl.smali @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# The standard dx/jack/d8 all would leave the move-exception instructions outside of either catch +# The standard dx/d8 would leave the move-exception instructions outside of either catch # block. This is different from the RI which will leave the corresponding aload. # # See b/65203529 for more information. diff --git a/test/1929-exception-catch-exception/src/art/Test1929.java b/test/1929-exception-catch-exception/src/art/Test1929.java index e2deb3f85f..c0995a8468 100644 --- a/test/1929-exception-catch-exception/src/art/Test1929.java +++ b/test/1929-exception-catch-exception/src/art/Test1929.java @@ -149,7 +149,7 @@ public class Test1929 { public void run() { throwCatchBaseTestException(); } } - // dx/d8/jack all do an optimization around catch blocks that (while legal) breaks assumptions + // dx and d8 do an optimization around catch blocks that (while legal) breaks assumptions // this test relies on so we have the actual implementation be corrected smali. This does work // for RI however. diff --git a/test/303-verification-stress/build b/test/303-verification-stress/build index b67eaf2261..ba79541478 100644 --- a/test/303-verification-stress/build +++ b/test/303-verification-stress/build @@ -21,16 +21,11 @@ set -e gcc -Wall -Werror -o classes-gen classes-gen.c ./classes-gen -if [ ${USE_JACK} = "true" ]; then - # Use the default Jack commands - ./default-build -else - mkdir classes - ${JAVAC} -d classes src/*.java +mkdir classes +${JAVAC} -d classes src/*.java - # dx needs more memory for that test so do not pass Xmx option here. - if [ ${NEED_DEX} = "true" ]; then - ${DX} --debug --dex --output=classes.dex classes - zip $TEST_NAME.jar classes.dex - fi +# dx needs more memory for that test so do not pass Xmx option here. +if [ ${NEED_DEX} = "true" ]; then + ${DX} --debug --dex --output=classes.dex classes + zip $TEST_NAME.jar classes.dex fi diff --git a/test/442-checker-constant-folding/build b/test/442-checker-constant-folding/build index 947ec9a560..42b99ad9f8 100755 --- a/test/442-checker-constant-folding/build +++ b/test/442-checker-constant-folding/build @@ -14,12 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# This checker test is incompatible with jack bytecode output, -# so force it to use javac/dx. -export USE_JACK=false -# Also disable desugar because it is missing in jack platform builds. -export DESUGAR=false - # See b/65168732 export DX=$ANDROID_HOST_OUT/bin/dx diff --git a/test/450-checker-types/build b/test/450-checker-types/build index 49292c9ac1..10ffcc537d 100755 --- a/test/450-checker-types/build +++ b/test/450-checker-types/build @@ -14,10 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# This checker test is incompatible with jack bytecode output, -# so force it to use javac/dx. -export USE_JACK=false -# Also disable desugar because it is missing in jack platform builds. -export DESUGAR=false +# See b/65168732 +export USE_D8=false ./default-build "$@" diff --git a/test/458-checker-instruct-simplification/build b/test/458-checker-instruct-simplification/build index 3721955670..10ffcc537d 100755 --- a/test/458-checker-instruct-simplification/build +++ b/test/458-checker-instruct-simplification/build @@ -14,12 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# This checker test is incompatible with jack bytecode output, -# so force it to use javac/dx. -export USE_JACK=false -# Also disable desugar because it is missing in jack platform builds. -export DESUGAR=false - # See b/65168732 export USE_D8=false diff --git a/test/463-checker-boolean-simplifier/build b/test/463-checker-boolean-simplifier/build index 3721955670..10ffcc537d 100755 --- a/test/463-checker-boolean-simplifier/build +++ b/test/463-checker-boolean-simplifier/build @@ -14,12 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# This checker test is incompatible with jack bytecode output, -# so force it to use javac/dx. -export USE_JACK=false -# Also disable desugar because it is missing in jack platform builds. -export DESUGAR=false - # See b/65168732 export USE_D8=false diff --git a/test/482-checker-loop-back-edge-use/src/Main.java b/test/482-checker-loop-back-edge-use/src/Main.java index 47823409a3..8311d8cc4f 100644 --- a/test/482-checker-loop-back-edge-use/src/Main.java +++ b/test/482-checker-loop-back-edge-use/src/Main.java @@ -18,26 +18,28 @@ public class Main { /// CHECK-START: void Main.loop1(boolean) liveness (after) - /// CHECK: <<Arg:z\d+>> ParameterValue liveness:<<ArgLiv:\d+>> ranges:{[<<ArgLiv>>,<<ArgLoopUse:\d+>>)} uses:[<<ArgUse:\d+>>,<<ArgLoopUse>>] - /// CHECK: If [<<Arg>>] liveness:<<IfLiv:\d+>> - /// CHECK: Goto liveness:<<GotoLiv:\d+>> - /// CHECK: Exit + /// CHECK-DAG: <<Arg:z\d+>> ParameterValue liveness:<<ArgLiv:\d+>> ranges:{[<<ArgLiv>>,<<ArgUse:\d+>>)} uses:[<<ArgUse>>] + /// CHECK-DAG: If [<<Arg>>] liveness:<<IfLiv:\d+>> loop:none + /// CHECK-DAG: Goto loop:B{{\d+}} + /// CHECK-DAG: Exit /// CHECK-EVAL: <<IfLiv>> + 1 == <<ArgUse>> - /// CHECK-EVAL: <<GotoLiv>> + 2 == <<ArgLoopUse>> + // + // Loop invariant exit check is hoisted from the loop by peeling. public static void loop1(boolean incoming) { while (incoming) {} } /// CHECK-START: void Main.loop2(boolean) liveness (after) - /// CHECK: <<Arg:z\d+>> ParameterValue liveness:<<ArgLiv:\d+>> ranges:{[<<ArgLiv>>,<<ArgLoopUse2:\d+>>)} uses:[<<ArgUse:\d+>>,<<ArgLoopUse1:\d+>>,<<ArgLoopUse2>>] - /// CHECK: If [<<Arg>>] liveness:<<IfLiv:\d+>> - /// CHECK: Goto liveness:<<GotoLiv1:\d+>> - /// CHECK: Goto liveness:<<GotoLiv2:\d+>> + /// CHECK-DAG: <<Arg:z\d+>> ParameterValue liveness:<<ArgLiv:\d+>> ranges:{[<<ArgLiv>>,<<ArgLoopUse:\d+>>)} uses:[<<ArgUse:\d+>>,<<ArgLoopUse>>] + /// CHECK-DAG: If [<<Arg>>] liveness:<<IfLiv:\d+>> loop:<<Loop1:B\d+>> + /// CHECK-DAG: Goto liveness:<<GotoLiv1:\d+>> loop:<<Loop1>> + /// CHECK-DAG: Goto liveness:<<GotoLiv2:\d+>> loop:<<Loop2:B\d+>> /// CHECK-EVAL: <<IfLiv>> + 1 == <<ArgUse>> /// CHECK-EVAL: <<GotoLiv1>> < <<GotoLiv2>> - /// CHECK-EVAL: <<GotoLiv1>> + 2 == <<ArgLoopUse1>> - /// CHECK-EVAL: <<GotoLiv2>> + 2 == <<ArgLoopUse2>> + /// CHECK-EVAL: <<GotoLiv1>> + 2 == <<ArgLoopUse>> + // + // Loop invariant exit check is hoisted from the loop by peeling. public static void loop2(boolean incoming) { // Add some code at entry to avoid having the entry block be a pre header. @@ -122,17 +124,18 @@ public class Main { } /// CHECK-START: void Main.loop7(boolean) liveness (after) - /// CHECK: <<Arg:z\d+>> ParameterValue liveness:<<ArgLiv:\d+>> ranges:{[<<ArgLiv>>,<<ArgLoopUse2:\d+>>)} uses:[<<ArgUse1:\d+>>,<<ArgUse2:\d+>>,<<ArgLoopUse1:\d+>>,<<ArgLoopUse2>>] - /// CHECK: InvokeVirtual [{{l\d+}},<<Arg>>] method_name:java.io.PrintStream.println liveness:<<InvokeLiv:\d+>> - /// CHECK: If [<<Arg>>] liveness:<<IfLiv:\d+>> - /// CHECK: Goto liveness:<<GotoLiv1:\d+>> - /// CHECK: Goto liveness:<<GotoLiv2:\d+>> - /// CHECK: Exit + /// CHECK-DAG: <<Arg:z\d+>> ParameterValue liveness:<<ArgLiv:\d+>> ranges:{[<<ArgLiv>>,<<ArgLoopUse:\d+>>)} uses:[<<ArgUse1:\d+>>,<<ArgUse2:\d+>>,<<ArgLoopUse>>] + /// CHECK-DAG: InvokeVirtual [{{l\d+}},<<Arg>>] method_name:java.io.PrintStream.println liveness:<<InvokeLiv:\d+>> + /// CHECK-DAG: If [<<Arg>>] liveness:<<IfLiv:\d+>> loop:<<Loop1:B\d+>> + /// CHECK-DAG: Goto liveness:<<GotoLiv1:\d+>> loop:<<Loop1>> + /// CHECK-DAG: Goto liveness:<<GotoLiv2:\d+>> loop:<<Loop2:B\d+>> + /// CHECK-DAG: Exit /// CHECK-EVAL: <<InvokeLiv>> == <<ArgUse1>> /// CHECK-EVAL: <<IfLiv>> + 1 == <<ArgUse2>> /// CHECK-EVAL: <<GotoLiv1>> < <<GotoLiv2>> - /// CHECK-EVAL: <<GotoLiv1>> + 2 == <<ArgLoopUse1>> - /// CHECK-EVAL: <<GotoLiv2>> + 2 == <<ArgLoopUse2>> + /// CHECK-EVAL: <<GotoLiv1>> + 2 == <<ArgLoopUse>> + // + // Loop invariant exit check is hoisted from the loop by peeling. public static void loop7(boolean incoming) { // 'incoming' must have a use at both back edges. @@ -144,15 +147,16 @@ public class Main { } /// CHECK-START: void Main.loop8() liveness (after) - /// CHECK: <<Arg:z\d+>> StaticFieldGet liveness:<<ArgLiv:\d+>> ranges:{[<<ArgLiv>>,<<ArgLoopUse2:\d+>>)} uses:[<<ArgUse:\d+>>,<<ArgLoopUse1:\d+>>,<<ArgLoopUse2>>] - /// CHECK: If [<<Arg>>] liveness:<<IfLiv:\d+>> - /// CHECK: Goto liveness:<<GotoLiv1:\d+>> - /// CHECK: Goto liveness:<<GotoLiv2:\d+>> - /// CHECK: Exit + /// CHECK-DAG: <<Arg:z\d+>> StaticFieldGet liveness:<<ArgLiv:\d+>> ranges:{[<<ArgLiv>>,<<ArgLoopUse:\d+>>)} uses:[<<ArgUse:\d+>>,<<ArgLoopUse>>] + /// CHECK-DAG: If [<<Arg>>] liveness:<<IfLiv:\d+>> loop:<<Loop1:B\d+>> + /// CHECK-DAG: Goto liveness:<<GotoLiv1:\d+>> loop:<<Loop1>> + /// CHECK-DAG: Goto liveness:<<GotoLiv2:\d+>> loop:<<Loop2:B\d+>> + /// CHECK-DAG: Exit /// CHECK-EVAL: <<IfLiv>> + 1 == <<ArgUse>> /// CHECK-EVAL: <<GotoLiv1>> < <<GotoLiv2>> - /// CHECK-EVAL: <<GotoLiv1>> + 2 == <<ArgLoopUse1>> - /// CHECK-EVAL: <<GotoLiv2>> + 2 == <<ArgLoopUse2>> + /// CHECK-EVAL: <<GotoLiv1>> + 2 == <<ArgLoopUse>> + // + // Loop invariant exit check is hoisted from the loop by peeling. public static void loop8() { // 'incoming' must have a use at both back edges. @@ -171,14 +175,15 @@ public class Main { } /// CHECK-START: void Main.loop9() liveness (after) - /// CHECK: <<Arg:z\d+>> StaticFieldGet liveness:<<ArgLiv:\d+>> ranges:{[<<ArgLiv>>,<<ArgLoopUse:\d+>>)} uses:[<<ArgUse:\d+>>,<<ArgLoopUse>>] - /// CHECK: If [<<Arg>>] liveness:<<IfLiv:\d+>> - /// CHECK: Goto liveness:<<GotoLiv1:\d+>> - /// CHECK-DAG: Goto liveness:<<GotoLiv2:\d+>> + /// CHECK-DAG: <<Arg:z\d+>> StaticFieldGet liveness:<<ArgLiv:\d+>> ranges:{[<<ArgLiv>>,<<ArgUse:\d+>>)} uses:[<<ArgUse>>] + /// CHECK-DAG: If [<<Arg>>] liveness:<<IfLiv:\d+>> loop:<<Loop1:B\d+>> + /// CHECK-DAG: Goto liveness:<<GotoLiv1:\d+>> loop:<<Loop1>> + /// CHECK-DAG: Goto liveness:<<GotoLiv2:\d+>> loop:<<Loop2:B\d+>> /// CHECK-DAG: Exit /// CHECK-EVAL: <<IfLiv>> + 1 == <<ArgUse>> /// CHECK-EVAL: <<GotoLiv1>> < <<GotoLiv2>> - /// CHECK-EVAL: <<GotoLiv1>> + 2 == <<ArgLoopUse>> + // + // Loop invariant exit check is hoisted from the loop by peeling. public static void loop9() { // Add some code at entry to avoid having the entry block be a pre header. diff --git a/test/530-checker-peel-unroll/expected.txt b/test/530-checker-peel-unroll/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/530-checker-peel-unroll/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/530-checker-peel-unroll/info.txt b/test/530-checker-peel-unroll/info.txt new file mode 100644 index 0000000000..0e10b36442 --- /dev/null +++ b/test/530-checker-peel-unroll/info.txt @@ -0,0 +1 @@ +Test on loop optimizations, peeling and unrolling. diff --git a/test/530-checker-peel-unroll/src/Main.java b/test/530-checker-peel-unroll/src/Main.java new file mode 100644 index 0000000000..2051b47afe --- /dev/null +++ b/test/530-checker-peel-unroll/src/Main.java @@ -0,0 +1,822 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Test loop optimizations, in particular scalar loop peeling and unrolling. +public class Main { + + static final int LENGTH = 4 * 1024; + int[] a = new int[LENGTH]; + int[] b = new int[LENGTH]; + + private static final int LENGTH_A = LENGTH; + private static final int LENGTH_B = 16; + private static final int RESULT_POS = 4; + + double[][] mA; + double[][] mB; + double[][] mC; + + public Main() { + mA = new double[LENGTH_A][]; + mB = new double[LENGTH_B][]; + mC = new double[LENGTH_B][]; + for (int i = 0; i < LENGTH_A; i++) { + mA[i] = new double[LENGTH_B]; + } + + for (int i = 0; i < LENGTH_B; i++) { + mB[i] = new double[LENGTH_A]; + mC[i] = new double[LENGTH_B]; + } + } + + private static final void initMatrix(double[][] m) { + for (int i = 0; i < m.length; i++) { + for (int j = 0; j < m[i].length; j++) { + m[i][j] = (double) (i * LENGTH / (j + 1)); + } + } + } + + private static final void initIntArray(int[] a) { + for (int i = 0; i < LENGTH; i++) { + a[i] = i % 4; + } + } + + /// CHECK-START: void Main.unrollingLoadStoreElimination(int[]) loop_optimization (before) + /// CHECK-DAG: <<Array:l\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4094 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<If:v\d+>> If [<<Check>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get0:i\d+>> ArrayGet [<<Array>>,<<Phi>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<IndAdd:i\d+>> Add [<<Phi>>,<<Const1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get1:i\d+>> ArrayGet [<<Array>>,<<IndAdd>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<Get0>>,<<Get1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [<<Array>>,<<Phi>>,<<Add>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-NOT: ArraySet loop:<<Loop>> outer_loop:none + + /// CHECK-START: void Main.unrollingLoadStoreElimination(int[]) loop_optimization (after) + /// CHECK-DAG: <<Array:l\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4094 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<If:v\d+>> If [<<Check>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get0:i\d+>> ArrayGet [<<Array>>,<<Phi>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<IndAdd:i\d+>> Add [<<Phi>>,<<Const1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get1:i\d+>> ArrayGet [<<Array>>,<<IndAdd>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<Get0>>,<<Get1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [<<Array>>,<<Phi>>,<<Add>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-DAG: <<CheckA:z\d+>> GreaterThanOrEqual [<<IndAdd>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<IfA:v\d+>> If [<<Const0>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get0A:i\d+>> ArrayGet [<<Array>>,<<IndAdd>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<IndAddA:i\d+>> Add [<<IndAdd>>,<<Const1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get1A:i\d+>> ArrayGet [<<Array>>,<<IndAddA>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddA:i\d+>> Add [<<Get0A>>,<<Get1A>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [<<Array>>,<<IndAdd>>,<<AddA>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-NOT: ArraySet loop:<<Loop>> outer_loop:none + private static final void unrollingLoadStoreElimination(int[] a) { + for (int i = 0; i < LENGTH - 2; i++) { + a[i] += a[i + 1]; + } + } + + /// CHECK-START: void Main.unrollingWhile(int[]) loop_optimization (before) + /// CHECK-DAG: <<Array:l\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2 loop:none + /// CHECK-DAG: <<Const128:i\d+>> IntConstant 128 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4094 loop:none + /// CHECK-DAG: <<PhiI:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<PhiS:i\d+>> Phi [<<Const128>>,{{i\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddI:i\d+>> Add [<<PhiI>>,<<Const1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<PhiI>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<If:v\d+>> If [<<Check>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Rem:i\d+>> Rem [<<AddI>>,<<Const2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<NE:z\d+>> NotEqual [<<Rem>>,<<Const0>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: If [<<NE>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddS:i\d+>> Add [<<PhiS>>,<<Const1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Phi [<<PhiS>>,<<AddS>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-NOT: ArraySet loop:<<Loop>> outer_loop:none + + /// CHECK-START: void Main.unrollingWhile(int[]) loop_optimization (after) + /// CHECK-DAG: <<Array:l\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2 loop:none + /// CHECK-DAG: <<Const128:i\d+>> IntConstant 128 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4094 loop:none + /// CHECK-DAG: <<PhiI:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<PhiS:i\d+>> Phi [<<Const128>>,{{i\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddI:i\d+>> Add [<<PhiI>>,<<Const1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<PhiI>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<If:v\d+>> If [<<Check>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Rem:i\d+>> Rem [<<AddI>>,<<Const2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<NE:z\d+>> NotEqual [<<Rem>>,<<Const0>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: If [<<NE>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddS:i\d+>> Add [<<PhiS>>,<<Const1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},{{i\d+}},<<PhiS>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<PhiSM:i\d+>> Phi [<<PhiS>>,<<AddS>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-DAG: <<AddIA:i\d+>> Add [<<AddI>>,<<Const1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<CheckA:z\d+>> GreaterThanOrEqual [<<AddI>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<IfA:v\d+>> If [<<Const0>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<RemA:i\d+>> Rem [<<AddIA>>,<<Const2>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<NEA:z\d+>> NotEqual [<<RemA>>,<<Const0>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: If [<<NEA>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddSA:i\d+>> Add [<<PhiSM>>,<<Const1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [{{l\d+}},{{i\d+}},<<PhiSM>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Phi [<<AddSA>>,<<PhiSM>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-NOT: ArraySet loop:<<Loop>> outer_loop:none + private static final void unrollingWhile(int[] a) { + int i = 0; + int s = 128; + while (i++ < LENGTH - 2) { + if (i % 2 == 0) { + a[i] = s++; + } + } + } + + // Simple check that loop unrolling has happened. + // + /// CHECK-START: void Main.unrollingSwitch(int[]) loop_optimization (before) + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4096 loop:none + /// CHECK-DAG: <<PhiI:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<PhiI>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<If:v\d+>> If [<<Check>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<PhiI>>,<<Const1>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-NOT: ArraySet loop:<<Loop>> outer_loop:none + + /// CHECK-START: void Main.unrollingSwitch(int[]) loop_optimization (after) + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4096 loop:none + /// CHECK-DAG: <<PhiI:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<PhiI>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<If:v\d+>> If [<<Check>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddI:i\d+>> Add [<<PhiI>>,<<Const1>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-DAG: <<CheckA:z\d+>> GreaterThanOrEqual [<<AddI>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<IfA:v\d+>> If [<<Const0>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<AddI>>,<<Const1>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-NOT: ArraySet loop:<<Loop>> outer_loop:none + private static final void unrollingSwitch(int[] a) { + for (int i = 0; i < LENGTH; i++) { + switch (i % 3) { + case 2: + a[i]++; + break; + default: + break; + } + } + } + + // Simple check that loop unrolling has happened. + // + /// CHECK-START: void Main.unrollingSwapElements(int[]) loop_optimization (before) + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4094 loop:none + /// CHECK-DAG: <<PhiI:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<PhiI>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<If:v\d+>> If [<<Check>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<PhiI>>,<<Const1>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-NOT: ArraySet loop:<<Loop>> outer_loop:none + + /// CHECK-START: void Main.unrollingSwapElements(int[]) loop_optimization (after) + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4094 loop:none + /// CHECK-DAG: <<PhiI:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<PhiI>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<If:v\d+>> If [<<Check>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddI:i\d+>> Add [<<PhiI>>,<<Const1>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-DAG: <<CheckA:z\d+>> GreaterThanOrEqual [<<AddI>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<IfA:v\d+>> If [<<Const0>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<AddI>>,<<Const1>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-NOT: ArraySet loop:<<Loop>> outer_loop:none + private static final void unrollingSwapElements(int[] array) { + for (int i = 0; i < LENGTH - 2; i++) { + if (array[i] > array[i + 1]) { + int temp = array[i + 1]; + array[i + 1] = array[i]; + array[i] = temp; + } + } + } + + // Simple check that loop unrolling has happened. + // + /// CHECK-START: void Main.unrollingRInnerproduct(double[][], double[][], double[][], int, int) loop_optimization (before) + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 16 loop:none + /// CHECK-DAG: <<PhiI:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<PhiI>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<If:v\d+>> If [<<Check>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<PhiI>>,<<Const1>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-NOT: ArraySet loop:<<Loop>> outer_loop:none + + /// CHECK-START: void Main.unrollingRInnerproduct(double[][], double[][], double[][], int, int) loop_optimization (after) + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 16 loop:none + /// CHECK-DAG: <<PhiI:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<PhiI>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<If:v\d+>> If [<<Check>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<AddI:i\d+>> Add [<<PhiI>>,<<Const1>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-DAG: <<CheckA:z\d+>> GreaterThanOrEqual [<<AddI>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<IfA:v\d+>> If [<<Const0>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<AddI>>,<<Const1>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-NOT: ArraySet loop:<<Loop>> outer_loop:none + private static final void unrollingRInnerproduct(double[][] result, + double[][] a, + double[][] b, + int row, + int column) { + // computes the inner product of A[row,*] and B[*,column] + int i; + result[row][column] = 0.0f; + for (i = 0; i < LENGTH_B; i++) { + result[row][column] = result[row][column] + a[row][i] * b[i][column]; + } + } + + // nested loop + // [[[]]] + + /// CHECK-START: void Main.unrollingInTheNest(int[], int[], int) loop_optimization (before) + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 128 loop:none + /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:none + /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop2:B\d+>> outer_loop:<<Loop1>> + /// CHECK-DAG: <<Phi3:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop3:B\d+>> outer_loop:<<Loop2>> + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi3>>,<<Limit>>] loop:<<Loop3>> outer_loop:<<Loop2>> + /// CHECK-DAG: If [<<Check>>] loop:<<Loop3>> outer_loop:<<Loop2>> + /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>> + /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>> + /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>> + /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>> + /// CHECK-DAG: Add [<<Phi3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop2>> + // + /// CHECK-NOT: ArrayGet + /// CHECK-NOT: ArraySet + /// CHECK-NOT: If + + /// CHECK-START: void Main.unrollingInTheNest(int[], int[], int) loop_optimization (after) + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 128 loop:none + /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:none + /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop2:B\d+>> outer_loop:<<Loop1>> + /// CHECK-DAG: <<Phi3:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop3:B\d+>> outer_loop:<<Loop2>> + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi3>>,<<Limit>>] loop:<<Loop3>> outer_loop:<<Loop2>> + /// CHECK-DAG: If [<<Check>>] loop:<<Loop3>> outer_loop:<<Loop2>> + /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>> + /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>> + /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>> + /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>> + /// CHECK-DAG: <<AddI:i\d+>> Add [<<Phi3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop2>> + // + /// CHECK-DAG: If [<<Const0>>] loop:<<Loop3>> outer_loop:<<Loop2>> + /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>> + /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>> + /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop2>> + /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop2>> + // + /// CHECK-NOT: ArrayGet + /// CHECK-NOT: ArraySet + /// CHECK-NOT: If + private static final void unrollingInTheNest(int[] a, int[] b, int x) { + for (int k = 0; k < 16; k++) { + for (int j = 0; j < 16; j++) { + for (int i = 0; i < 128; i++) { + b[x]++; + a[i] = a[i] + 1; + } + } + } + } + + // nested loop: + // [ + // if [] else [] + // ] + + /// CHECK-START: void Main.unrollingTwoLoopsInTheNest(int[], int[], int) loop_optimization (before) + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 128 loop:none + /// CHECK-DAG: <<XThres:i\d+>> IntConstant 100 loop:none + /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:none + // + /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop2:B\d+>> outer_loop:<<Loop1>> + /// CHECK-DAG: <<Check2:z\d+>> GreaterThanOrEqual [<<Phi2>>,<<Limit>>] loop:<<Loop2>> outer_loop:<<Loop1>> + /// CHECK-DAG: If [<<Check2>>] loop:<<Loop2>> outer_loop:<<Loop1>> + /// CHECK-DAG: ArrayGet loop:<<Loop2>> outer_loop:<<Loop1>> + /// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:<<Loop1>> + /// CHECK-DAG: <<AddI2:i\d+>> Add [<<Phi2>>,<<Const1>>] loop:<<Loop2>> outer_loop:<<Loop1>> + // + /// CHECK-DAG: <<Phi3:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop3:B\d+>> outer_loop:<<Loop1>> + /// CHECK-DAG: <<Check3:z\d+>> GreaterThanOrEqual [<<Phi3>>,<<Limit>>] loop:<<Loop3>> outer_loop:<<Loop1>> + /// CHECK-DAG: If [<<Check3>>] loop:<<Loop3>> outer_loop:<<Loop1>> + /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop1>> + /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop1>> + /// CHECK-DAG: <<AddI3:i\d+>> Add [<<Phi3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop1>> + // + /// CHECK-NOT: ArrayGet + /// CHECK-NOT: ArraySet + /// CHECK-NOT: If + + /// CHECK-START: void Main.unrollingTwoLoopsInTheNest(int[], int[], int) loop_optimization (after) + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 128 loop:none + /// CHECK-DAG: <<XThres:i\d+>> IntConstant 100 loop:none + /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:none + // + /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop2:B\d+>> outer_loop:<<Loop1>> + /// CHECK-DAG: <<Check2:z\d+>> GreaterThanOrEqual [<<Phi2>>,<<Limit>>] loop:<<Loop2>> outer_loop:<<Loop1>> + /// CHECK-DAG: If [<<Check2>>] loop:<<Loop2>> outer_loop:<<Loop1>> + /// CHECK-DAG: ArrayGet loop:<<Loop2>> outer_loop:<<Loop1>> + /// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:<<Loop1>> + /// CHECK-DAG: <<AddI2:i\d+>> Add [<<Phi2>>,<<Const1>>] loop:<<Loop2>> outer_loop:<<Loop1>> + /// CHECK-DAG: If [<<Const0>>] loop:<<Loop2>> outer_loop:<<Loop1>> + /// CHECK-DAG: ArrayGet loop:<<Loop2>> outer_loop:<<Loop1>> + /// CHECK-DAG: ArraySet loop:<<Loop2>> outer_loop:<<Loop1>> + /// CHECK-DAG: Add [<<AddI2>>,<<Const1>>] loop:<<Loop2>> outer_loop:<<Loop1>> + // + /// CHECK-DAG: <<Phi3:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop3:B\d+>> outer_loop:<<Loop1>> + /// CHECK-DAG: <<Check3:z\d+>> GreaterThanOrEqual [<<Phi3>>,<<Limit>>] loop:<<Loop3>> outer_loop:<<Loop1>> + /// CHECK-DAG: If [<<Check3>>] loop:<<Loop3>> outer_loop:<<Loop1>> + /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop1>> + /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop1>> + /// CHECK-DAG: <<AddI3:i\d+>> Add [<<Phi3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop1>> + /// CHECK-DAG: If [<<Const0>>] loop:<<Loop3>> outer_loop:<<Loop1>> + /// CHECK-DAG: ArrayGet loop:<<Loop3>> outer_loop:<<Loop1>> + /// CHECK-DAG: ArraySet loop:<<Loop3>> outer_loop:<<Loop1>> + /// CHECK-DAG: Add [<<AddI3>>,<<Const1>>] loop:<<Loop3>> outer_loop:<<Loop1>> + // + /// CHECK-NOT: ArrayGet + /// CHECK-NOT: ArraySet + /// CHECK-NOT: If + private static final void unrollingTwoLoopsInTheNest(int[] a, int[] b, int x) { + for (int k = 0; k < 128; k++) { + if (x > 100) { + for (int j = 0; j < 128; j++) { + a[x]++; + } + } else { + for (int i = 0; i < 128; i++) { + b[x]++; + } + } + } + } + + /// CHECK-START: void Main.noUnrollingOddTripCount(int[]) loop_optimization (before) + /// CHECK-DAG: <<Array:l\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4095 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<If:v\d+>> If [<<Check>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get0:i\d+>> ArrayGet [<<Array>>,<<Phi>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<IndAdd:i\d+>> Add [<<Phi>>,<<Const1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get1:i\d+>> ArrayGet [<<Array>>,<<IndAdd>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<Get0>>,<<Get1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [<<Array>>,<<Phi>>,<<Add>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: Phi + /// CHECK-NOT: If + /// CHECK-NOT: ArrayGet + /// CHECK-NOT: ArraySet + + /// CHECK-START: void Main.noUnrollingOddTripCount(int[]) loop_optimization (after) + /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: If loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: Phi + /// CHECK-NOT: If + /// CHECK-NOT: ArrayGet + /// CHECK-NOT: ArraySet + private static final void noUnrollingOddTripCount(int[] a) { + for (int i = 0; i < LENGTH - 1; i++) { + a[i] += a[i + 1]; + } + } + + /// CHECK-START: void Main.noUnrollingNotKnownTripCount(int[], int) loop_optimization (before) + /// CHECK-DAG: <<Array:l\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Limit:i\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<If:v\d+>> If [<<Check>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get0:i\d+>> ArrayGet [<<Array>>,<<Phi>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<IndAdd:i\d+>> Add [<<Phi>>,<<Const1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get1:i\d+>> ArrayGet [<<Array>>,<<IndAdd>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<Get0>>,<<Get1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet [<<Array>>,<<Phi>>,<<Add>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: Phi + /// CHECK-NOT: ArrayGet + /// CHECK-NOT: ArraySet + + /// CHECK-START: void Main.noUnrollingNotKnownTripCount(int[], int) loop_optimization (after) + /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: If loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: Phi + /// CHECK-NOT: ArrayGet + /// CHECK-NOT: ArraySet + private static final void noUnrollingNotKnownTripCount(int[] a, int n) { + for (int i = 0; i < n; i++) { + a[i] += a[i + 1]; + } + } + + /// CHECK-START: void Main.peelingSimple(int[], boolean) loop_optimization (before) + /// CHECK-DAG: <<Param:z\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4096 loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: If [<<Check>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: If [<<Param>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<IndAdd:i\d+>> Add [<<Phi>>,<<Const1>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: If + /// CHECK-NOT: ArraySet + + /// CHECK-START: void Main.peelingSimple(int[], boolean) loop_optimization (after) + /// CHECK-DAG: <<Param:z\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4096 loop:none + /// CHECK-DAG: <<CheckA:z\d+>> GreaterThanOrEqual [<<Const0>>,<<Limit>>] loop:none + /// CHECK-DAG: If [<<CheckA>>] loop:none + /// CHECK-DAG: If [<<Param>>] loop:none + /// CHECK-DAG: ArrayGet loop:none + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: <<IndAddA:i\d+>> Add [<<Const0>>,<<Const1>>] loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi [<<IndAddA>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: If [<<Check>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: If [<<Const0>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<IndAdd:i\d+>> Add [<<Phi>>,<<Const1>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: If + /// CHECK-NOT: ArraySet + + /// CHECK-START: void Main.peelingSimple(int[], boolean) dead_code_elimination$final (after) + /// CHECK-DAG: <<Param:z\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4096 loop:none + /// CHECK-DAG: If [<<Param>>] loop:none + /// CHECK-DAG: ArrayGet loop:none + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Const1>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi>>,<<Limit>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: If [<<Check>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<IndAdd:i\d+>> Add [<<Phi>>,<<Const1>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: GreaterThanOrEqual + /// CHECK-NOT: If + /// CHECK-NOT: ArrayGet + /// CHECK-NOT: ArraySet + private static final void peelingSimple(int[] a, boolean f) { + for (int i = 0; i < LENGTH; i++) { + if (f) { + break; + } + a[i] += 1; + } + } + + // Often used idiom that, when not hoisted, prevents BCE and vectorization. + // + /// CHECK-START: void Main.peelingAddInts(int[]) loop_optimization (before) + /// CHECK-DAG: <<Param:l\d+>> ParameterValue loop:none + /// CHECK-DAG: <<ConstNull:l\d+>> NullConstant loop:none + /// CHECK-DAG: <<Eq:z\d+>> Equal [<<Param>>,<<ConstNull>>] loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: If [<<Eq>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi>>,{{i\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: If [<<Check>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + + /// CHECK-START: void Main.peelingAddInts(int[]) dead_code_elimination$final (after) + /// CHECK-DAG: <<Param:l\d+>> ParameterValue loop:none + /// CHECK-DAG: <<ConstNull:l\d+>> NullConstant loop:none + /// CHECK-DAG: <<Eq:z\d+>> Equal [<<Param>>,<<ConstNull>>] loop:none + /// CHECK-DAG: If [<<Eq>>] loop:none + /// CHECK-DAG: ArraySet loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi>>,{{i\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: If [<<Check>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: If [<<Eq>>] loop:<<Loop>> outer_loop:none + private static final void peelingAddInts(int[] a) { + for (int i = 0; a != null && i < a.length; i++) { + a[i] += 1; + } + } + + /// CHECK-START: void Main.peelingBreakFromNest(int[], boolean) loop_optimization (before) + /// CHECK-DAG: <<Param:z\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4096 loop:none + /// CHECK-DAG: <<Phi0:i\d+>> Phi [<<Const1>>,{{i\d+}}] loop:<<Loop0:B\d+>> outer_loop:none + /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi1>>,<<Limit>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: If [<<Check>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: If [<<Param>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: ArrayGet loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: ArraySet loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<IndAdd1:i\d+>> Add [<<Phi1>>,<<Const1>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<IndAdd0:i\d+>> Add [<<Phi0>>,<<Const1>>] loop:<<Loop0>> outer_loop:none + // + /// CHECK-NOT: If + /// CHECK-NOT: ArraySet + + /// CHECK-START: void Main.peelingBreakFromNest(int[], boolean) dead_code_elimination$final (after) + /// CHECK-DAG: <<Param:z\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Limit:i\d+>> IntConstant 4096 loop:none + /// CHECK-DAG: <<Phi0:i\d+>> Phi [<<Const1>>,{{i\d+}}] loop:<<Loop0:B\d+>> outer_loop:none + /// CHECK-DAG: If [<<Param>>] loop:<<Loop0>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop0>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop0>> outer_loop:none + /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Const1>>,{{i\d+}}] loop:<<Loop1:B\d+>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<Check:z\d+>> GreaterThanOrEqual [<<Phi1>>,<<Limit>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: If [<<Check>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: ArrayGet loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: ArraySet loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<IndAdd1:i\d+>> Add [<<Phi1>>,<<Const1>>] loop:<<Loop1>> outer_loop:<<Loop0>> + /// CHECK-DAG: <<IndAdd0:i\d+>> Add [<<Phi0>>,<<Const1>>] loop:<<Loop0>> outer_loop:none + // + /// CHECK-NOT: If + /// CHECK-NOT: ArraySet + private static final void peelingBreakFromNest(int[] a, boolean f) { + outer: + for (int i = 1; i < 32; i++) { + for (int j = 0; j < LENGTH; j++) { + if (f) { + break outer; + } + a[j] += 1; + } + } + } + + /// CHECK-START: int Main.peelingHoistOneControl(int) loop_optimization (before) + /// CHECK-DAG: <<Param:i\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Check:z\d+>> NotEqual [<<Param>>,<<Const0>>] loop:none + /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Const0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: If [<<Check>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<IndAdd:i\d+>> Add [<<Phi>>,<<Const1>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-NOT: If + + /// CHECK-START: int Main.peelingHoistOneControl(int) dead_code_elimination$final (after) + /// CHECK-DAG: <<Param:i\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Check:z\d+>> NotEqual [<<Param>>,<<Const0>>] loop:none + /// CHECK-DAG: If [<<Check>>] loop:none + /// CHECK-DAG: SuspendCheck loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: Goto loop:<<Loop>> outer_loop:none + // + // Check that the loop has no instruction except SuspendCheck and Goto (indefinite loop). + /// CHECK-NOT: loop:<<Loop>> outer_loop:none + /// CHECK-NOT: If + /// CHECK-NOT: Phi + /// CHECK-NOT: Add + private static final int peelingHoistOneControl(int x) { + int i = 0; + while (true) { + if (x == 0) + return 1; + i++; + } + } + + /// CHECK-START: int Main.peelingHoistOneControl(int, int) loop_optimization (before) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: If loop:<<Loop>> outer_loop:none + /// CHECK-DAG: If loop:<<Loop>> outer_loop:none + // + /// CHECK-START: int Main.peelingHoistOneControl(int, int) dead_code_elimination$final (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: If loop:<<Loop>> outer_loop:none + /// CHECK-NOT: If loop:<<Loop>> outer_loop:none + private static final int peelingHoistOneControl(int x, int y) { + while (true) { + if (x == 0) + return 1; + if (y == 0) // no longer invariant + return 2; + y--; + } + } + + /// CHECK-START: int Main.peelingHoistTwoControl(int, int, int) loop_optimization (before) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: If loop:<<Loop>> outer_loop:none + /// CHECK-DAG: If loop:<<Loop>> outer_loop:none + /// CHECK-DAG: If loop:<<Loop>> outer_loop:none + // + /// CHECK-START: int Main.peelingHoistTwoControl(int, int, int) dead_code_elimination$final (after) + /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: If loop:<<Loop>> outer_loop:none + /// CHECK-NOT: If loop:<<Loop>> outer_loop:none + private static final int peelingHoistTwoControl(int x, int y, int z) { + while (true) { + if (x == 0) + return 1; + if (y == 0) + return 2; + if (z == 0) // no longer invariant + return 3; + z--; + } + } + + private static void expectEquals(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + public void verifyUnrolling() { + initIntArray(a); + initIntArray(b); + + initMatrix(mA); + initMatrix(mB); + initMatrix(mC); + + int expected = 174291419; + int found = 0; + + unrollingWhile(a); + unrollingLoadStoreElimination(a); + unrollingSwitch(a); + unrollingSwapElements(a); + unrollingRInnerproduct(mC, mA, mB, RESULT_POS, RESULT_POS); + unrollingInTheNest(a, b, RESULT_POS); + unrollingTwoLoopsInTheNest(a, b, RESULT_POS); + + noUnrollingOddTripCount(b); + noUnrollingNotKnownTripCount(b, 128); + + for (int i = 0; i < LENGTH; i++) { + found += a[i]; + found += b[i]; + } + found += (int)mC[RESULT_POS][RESULT_POS]; + + expectEquals(expected, found); + } + + public void verifyPeeling() { + expectEquals(1, peelingHoistOneControl(0)); // anything else loops + expectEquals(1, peelingHoistOneControl(0, 0)); + expectEquals(1, peelingHoistOneControl(0, 1)); + expectEquals(2, peelingHoistOneControl(1, 0)); + expectEquals(2, peelingHoistOneControl(1, 1)); + expectEquals(1, peelingHoistTwoControl(0, 0, 0)); + expectEquals(1, peelingHoistTwoControl(0, 0, 1)); + expectEquals(1, peelingHoistTwoControl(0, 1, 0)); + expectEquals(1, peelingHoistTwoControl(0, 1, 1)); + expectEquals(2, peelingHoistTwoControl(1, 0, 0)); + expectEquals(2, peelingHoistTwoControl(1, 0, 1)); + expectEquals(3, peelingHoistTwoControl(1, 1, 0)); + expectEquals(3, peelingHoistTwoControl(1, 1, 1)); + + initIntArray(a); + peelingSimple(a, false); + peelingSimple(a, true); + peelingAddInts(a); + peelingAddInts(null); // okay + peelingBreakFromNest(a, false); + peelingBreakFromNest(a, true); + + int expected = 141312; + int found = 0; + for (int i = 0; i < a.length; i++) { + found += a[i]; + } + + expectEquals(expected, found); + } + + public static void main(String[] args) { + Main obj = new Main(); + + obj.verifyUnrolling(); + obj.verifyPeeling(); + + System.out.println("passed"); + } +} diff --git a/test/536-checker-intrinsic-optimization/build b/test/536-checker-intrinsic-optimization/build deleted file mode 100755 index 49292c9ac1..0000000000 --- a/test/536-checker-intrinsic-optimization/build +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# -# Copyright 2017 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# This checker test is incompatible with jack bytecode output, -# so force it to use javac/dx. -export USE_JACK=false -# Also disable desugar because it is missing in jack platform builds. -export DESUGAR=false - -./default-build "$@" diff --git a/test/537-checker-inline-and-unverified/build b/test/537-checker-inline-and-unverified/build deleted file mode 100755 index 49292c9ac1..0000000000 --- a/test/537-checker-inline-and-unverified/build +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# -# Copyright 2017 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# This checker test is incompatible with jack bytecode output, -# so force it to use javac/dx. -export USE_JACK=false -# Also disable desugar because it is missing in jack platform builds. -export DESUGAR=false - -./default-build "$@" diff --git a/test/565-checker-doublenegbitwise/build b/test/565-checker-doublenegbitwise/build index 3721955670..10ffcc537d 100755 --- a/test/565-checker-doublenegbitwise/build +++ b/test/565-checker-doublenegbitwise/build @@ -14,12 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# This checker test is incompatible with jack bytecode output, -# so force it to use javac/dx. -export USE_JACK=false -# Also disable desugar because it is missing in jack platform builds. -export DESUGAR=false - # See b/65168732 export USE_D8=false diff --git a/test/586-checker-null-array-get/build b/test/586-checker-null-array-get/build deleted file mode 100755 index 49292c9ac1..0000000000 --- a/test/586-checker-null-array-get/build +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# -# Copyright 2017 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# This checker test is incompatible with jack bytecode output, -# so force it to use javac/dx. -export USE_JACK=false -# Also disable desugar because it is missing in jack platform builds. -export DESUGAR=false - -./default-build "$@" diff --git a/test/593-checker-boolean-2-integral-conv/build b/test/593-checker-boolean-2-integral-conv/build deleted file mode 100755 index 49292c9ac1..0000000000 --- a/test/593-checker-boolean-2-integral-conv/build +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# -# Copyright 2017 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# This checker test is incompatible with jack bytecode output, -# so force it to use javac/dx. -export USE_JACK=false -# Also disable desugar because it is missing in jack platform builds. -export DESUGAR=false - -./default-build "$@" diff --git a/test/633-checker-rtp-getclass/build b/test/633-checker-rtp-getclass/build deleted file mode 100755 index 49292c9ac1..0000000000 --- a/test/633-checker-rtp-getclass/build +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# -# Copyright 2017 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# This checker test is incompatible with jack bytecode output, -# so force it to use javac/dx. -export USE_JACK=false -# Also disable desugar because it is missing in jack platform builds. -export DESUGAR=false - -./default-build "$@" diff --git a/test/636-arm64-veneer-pool/build b/test/636-arm64-veneer-pool/build deleted file mode 100755 index 43f9018f13..0000000000 --- a/test/636-arm64-veneer-pool/build +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -# -# Copyright 2017 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# Make us exit on a failure. - -set -e - -# Use javac+dx instead of jack. -export USE_JACK=false - -# Don't use desugar because the bootclasspath jars will be missing -# on a platform build compiled with ANDROID_COMPILE_WITH_JACK=true. -export USE_DESUGAR=false - -./default-build "$@" diff --git a/test/641-checker-arraycopy/build b/test/641-checker-arraycopy/build deleted file mode 100644 index 12e4423b56..0000000000 --- a/test/641-checker-arraycopy/build +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -# -# Copyright 2017 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# make us exit on a failure -set -e - -# Don't use jack for this test, to ensure we don't use -# the typed System.arraycopy versions directly. -export USE_JACK=false - -# Don't use desugar because the bootclasspath jars will be missing -# on a platform build compiled with ANDROID_COMPILE_WITH_JACK=true. -export USE_DESUGAR=false - -./default-build "$@" diff --git a/test/910-methods/check b/test/910-methods/check index 76b23cb906..61846adf9b 100644 --- a/test/910-methods/check +++ b/test/910-methods/check @@ -14,11 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Jack has a different set of bytecode offsets/method IDs in the expected.txt -if [[ "$USE_JACK" == true ]]; then - patch -p0 expected.txt < expected_jack.diff -fi - ./default-check "$@" if [[ "$?" == "0" ]]; then exit 0; diff --git a/test/910-methods/expected_jack.diff b/test/910-methods/expected_jack.diff deleted file mode 100644 index 2fe6953f6c..0000000000 --- a/test/910-methods/expected_jack.diff +++ /dev/null @@ -1,4 +0,0 @@ -7c7 -< Location end: 39 ---- -> Location end: 40 diff --git a/test/911-get-stack-trace/check b/test/911-get-stack-trace/check index a46ea9e54a..ee00266b36 100644 --- a/test/911-get-stack-trace/check +++ b/test/911-get-stack-trace/check @@ -14,11 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Jack has a different set of bytecode offsets/method IDs in the expected.txt -if [[ "$USE_JACK" == true ]]; then - patch -p0 expected.txt < expected_jack.diff -fi - if [[ "$DX" == 'd8' ]]; then patch -p0 expected.txt < expected_d8.diff fi diff --git a/test/911-get-stack-trace/expected_jack.diff b/test/911-get-stack-trace/expected_jack.diff deleted file mode 100644 index b7481941c7..0000000000 --- a/test/911-get-stack-trace/expected_jack.diff +++ /dev/null @@ -1,32 +0,0 @@ -24c24 -< doTest ()V 34 25 ---- -> doTest ()V 38 25 -44c44 -< doTest ()V 38 26 ---- -> doTest ()V 42 26 -65c65 -< doTest ()V 60 32 ---- -> doTest ()V 65 32 -363c363 -< doTest ()V 122 59 ---- -> doTest ()V 128 59 -598c598 -< doTest ()V 127 61 ---- -> doTest ()V 133 61 -630c630 -< doTest ()V 112 54 ---- -> doTest ()V 116 54 -677c677 -< doTest ()V 117 56 ---- -> doTest ()V 121 56 -792c792 -< [public static void art.Frames.doTestSameThread(), 35] ---- -> [public static void art.Frames.doTestSameThread(), 38] diff --git a/test/913-heaps/check b/test/913-heaps/check index f4892d0a07..c3b47f56ac 100644 --- a/test/913-heaps/check +++ b/test/913-heaps/check @@ -15,10 +15,7 @@ # limitations under the License. # Jack/D8 has a different set of bytecode offsets/method IDs in the expected.txt - -if [[ "$USE_JACK" == true ]]; then - patch -p0 expected.txt < expected_jack.diff -elif [[ "$USE_D8" == true ]]; then +if [[ "$USE_D8" == true ]]; then patch -p0 expected.txt < expected_d8.diff fi diff --git a/test/913-heaps/expected_jack.diff b/test/913-heaps/expected_jack.diff deleted file mode 100644 index 32fef02234..0000000000 --- a/test/913-heaps/expected_jack.diff +++ /dev/null @@ -1,50 +0,0 @@ -4c4 -< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 30])--> 1@1000 [size=16, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 32])--> 1@1000 [size=16, length=-1] -49,50c49,50 -< root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=11,location= 8])--> 1@1000 [size=16, length=-1] -< root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 8])--> 1@1000 [size=16, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=13,location= 10])--> 1@1000 [size=16, length=-1] -> root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 10])--> 1@1000 [size=16, length=-1] -102c102 -< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 30])--> 1@1000 [size=16, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 32])--> 1@1000 [size=16, length=-1] -115,116c115,116 -< root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=11,location= 8])--> 1@1000 [size=16, length=-1] -< root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 8])--> 1@1000 [size=16, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=13,location= 10])--> 1@1000 [size=16, length=-1] -> root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 10])--> 1@1000 [size=16, length=-1] -162c162 -< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 30])--> 1@1000 [size=16, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 32])--> 1@1000 [size=16, length=-1] -177,178c177,178 -< root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=11,location= 8])--> 1@1000 [size=16, length=-1] -< root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 8])--> 1@1000 [size=16, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=13,location= 10])--> 1@1000 [size=16, length=-1] -> root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 10])--> 1@1000 [size=16, length=-1] -201c201 -< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 30])--> 1@1000 [size=16, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 32])--> 1@1000 [size=16, length=-1] -246,247c246,247 -< root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=11,location= 8])--> 1@1000 [size=16, length=-1] -< root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 8])--> 1@1000 [size=16, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=13,location= 10])--> 1@1000 [size=16, length=-1] -> root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 10])--> 1@1000 [size=16, length=-1] -347c347 -< root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 30])--> 1@1000 [size=16, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=13,location= 32])--> 1@1000 [size=16, length=-1] -366,367c366,367 -< root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=11,location= 8])--> 1@1000 [size=16, length=-1] -< root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 8])--> 1@1000 [size=16, length=-1] ---- -> root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=13,location= 10])--> 1@1000 [size=16, length=-1] -> root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 10])--> 1@1000 [size=16, length=-1] diff --git a/test/968-default-partial-compile-gen/build b/test/968-default-partial-compile-gen/build index 00ccb89faf..c8f0384645 100755 --- a/test/968-default-partial-compile-gen/build +++ b/test/968-default-partial-compile-gen/build @@ -17,8 +17,6 @@ # make us exit on a failure set -e -# TODO: Support running with jack. - if [[ $@ == *"--jvm"* ]]; then # Build the Java files if we are running a --jvm test mkdir -p classes diff --git a/test/970-iface-super-resolution-gen/build b/test/970-iface-super-resolution-gen/build index 7217fac601..0594501c91 100755 --- a/test/970-iface-super-resolution-gen/build +++ b/test/970-iface-super-resolution-gen/build @@ -20,16 +20,6 @@ set -e # Should we compile with Java source code. By default we will use Smali. USES_JAVA_SOURCE="false" if [[ $@ == *"--jvm"* ]]; then - USES_JAVA_SOURCE="true" -elif [[ "$USE_JACK" == "true" ]]; then - if $JACK -D jack.java.source.version=1.8 -D jack.android.min-api-level=24 2>/dev/null; then - USES_JAVA_SOURCE="true" - else - echo "WARNING: Cannot use jack because it does not support JLS 1.8. Falling back to smali" >&2 - fi -fi - -if [[ "$USES_JAVA_SOURCE" == "true" ]]; then # Build the Java files mkdir -p src mkdir -p src2 diff --git a/test/971-iface-super/build b/test/971-iface-super/build index 00ccb89faf..c8f0384645 100755 --- a/test/971-iface-super/build +++ b/test/971-iface-super/build @@ -17,8 +17,6 @@ # make us exit on a failure set -e -# TODO: Support running with jack. - if [[ $@ == *"--jvm"* ]]; then # Build the Java files if we are running a --jvm test mkdir -p classes diff --git a/test/etc/default-build b/test/etc/default-build index c61de0ab6e..d0ebe80e68 100755 --- a/test/etc/default-build +++ b/test/etc/default-build @@ -109,7 +109,7 @@ ZIP_COMPRESSION_METHOD="deflate" WITH_ZIP_ALIGN=false ZIP_ALIGN_BYTES="-1" -DX_FLAGS="--min-sdk-version=24" +DX_FLAGS="--min-sdk-version=26" DX_VM_FLAGS="" EXPERIMENTAL="" @@ -120,13 +120,6 @@ DEV_MODE="no" DEFAULT_EXPERIMENT="no-experiment" # Setup experimental flag mappings in a bash associative array. -declare -A JACK_EXPERIMENTAL_ARGS -JACK_EXPERIMENTAL_ARGS["agents"]="-D jack.java.source.version=1.8 -D jack.android.min-api-level=24" -JACK_EXPERIMENTAL_ARGS["default-methods"]="-D jack.java.source.version=1.8 -D jack.android.min-api-level=24" -JACK_EXPERIMENTAL_ARGS["lambdas"]="-D jack.java.source.version=1.8 -D jack.android.min-api-level=24" -JACK_EXPERIMENTAL_ARGS["method-handles"]="-D jack.java.source.version=1.7 -D jack.android.min-api-level=o-b1" -JACK_EXPERIMENTAL_ARGS[${DEFAULT_EXPERIMENT}]="-D jack.java.source.version=1.8 -D jack.android.min-api-level=24" - declare -A SMALI_EXPERIMENTAL_ARGS SMALI_EXPERIMENTAL_ARGS["default-methods"]="--api 24" SMALI_EXPERIMENTAL_ARGS["method-handles"]="--api 26" @@ -223,19 +216,8 @@ fi # Be sure to get any default arguments if not doing any experiments. EXPERIMENTAL="${EXPERIMENTAL} ${DEFAULT_EXPERIMENT}" -if [ "${JACK_SERVER}" = "false" ]; then - # Run in single-threaded mode for the continuous buildbot. - JACK_ARGS="${JACK_ARGS} -D sched.runner=single-threaded" -else - # Run with 4 threads to reduce memory footprint and thread contention. - JACK_ARGS="${JACK_ARGS} -D sched.runner=multi-threaded" - JACK_ARGS="${JACK_ARGS} -D sched.runner.thread.kind=fixed" - JACK_ARGS="${JACK_ARGS} -D sched.runner.thread.fixed.count=4" -fi - # Add args from the experimental mappings. for experiment in ${EXPERIMENTAL}; do - JACK_ARGS="${JACK_ARGS} ${JACK_EXPERIMENTAL_ARGS[${experiment}]}" SMALI_ARGS="${SMALI_ARGS} ${SMALI_EXPERIMENTAL_ARGS[${experiment}]}" JAVAC_ARGS="${JAVAC_ARGS} ${JAVAC_EXPERIMENTAL_ARGS[${experiment}]}" DX_FLAGS="${DX_FLAGS} ${DX_EXPERIMENTAL_ARGS[${experiment}]}" @@ -406,79 +388,39 @@ if [ ${HAS_SRC_DEX2OAT_UNRESOLVED} = "true" ]; then mkdir classes-ex javac_with_bootclasspath -implicit:none -sourcepath src-dex2oat-unresolved -d classes `find src -name '*.java'` javac_with_bootclasspath -implicit:none -sourcepath src -d classes-ex `find src-dex2oat-unresolved -name '*.java'` - if [ ${USE_JACK} = "true" ]; then - jar cf classes.jill.jar -C classes . - jar cf classes-ex.jill.jar -C classes-ex . - - ${JACK} --import classes-ex.jill.jar --output-dex . + if [ ${NEED_DEX} = "true" ]; then + make_dex classes-ex + mv classes-ex.dex classes.dex # rename it so it shows up as "classes.dex" in the zip file. zip ${TEST_NAME}-ex.jar classes.dex - ${JACK} --import classes.jill.jar --output-dex . - else - if [ ${NEED_DEX} = "true" ]; then - make_dex classes-ex - mv classes-ex.dex classes.dex # rename it so it shows up as "classes.dex" in the zip file. - zip ${TEST_NAME}-ex.jar classes.dex - make_dex classes - fi + make_dex classes fi else - if [ ${USE_JACK} = "true" ]; then - # Jack toolchain - if [[ "$HAS_SRC" == true || "$HAS_SRC_ART" == true ]]; then - if [ "${HAS_SRC_MULTIDEX}" = "true" ]; then - # Compile src and src-multidex in the same .jack file. We will apply multidex partitioning - # when creating the output .dex file. - ${JACK} ${JACK_ARGS} --output-jack src.jack $(maybe_dir src) src-multidex $(maybe_dir src-art) - jack_extra_args="${jack_extra_args} -D jack.dex.output.policy=minimal-multidex" - jack_extra_args="${jack_extra_args} -D jack.preprocessor=true" - jack_extra_args="${jack_extra_args} -D jack.preprocessor.file=multidex.jpp" - else - ${JACK} ${JACK_ARGS} --output-jack src.jack $(maybe_dir src) $(maybe_dir src-art) - fi - jack_extra_args="${jack_extra_args} --import src.jack" - fi - - if [ "${HAS_SRC2}" = "true" ]; then - ${JACK} ${JACK_ARGS} --output-jack src2.jack src2 - # In case of duplicate classes, we want to take into account the classes from src2. Therefore - # we apply the 'keep-first' policy and import src2.jack file *before* the src.jack file. - jack_extra_args="${jack_extra_args} -D jack.import.type.policy=keep-first" - jack_extra_args="--import src2.jack ${jack_extra_args}" - fi - - # Compile jack files into a DEX file. - if [ "${HAS_SRC}" = "true" ] || [ "${HAS_SRC2}" = "true" ] || [ "${HAS_SRC_ART}" = "true" ]; then - ${JACK} ${JACK_ARGS} ${jack_extra_args} --output-dex . - fi - else - # Legacy toolchain with javac+dx - if [ "${HAS_SRC}" = "true" ]; then - mkdir -p classes - javac_with_bootclasspath -implicit:none -classpath src-multidex -d classes `find src -name '*.java'` - fi + if [ "${HAS_SRC}" = "true" ]; then + mkdir -p classes + javac_with_bootclasspath -implicit:none -classpath src-multidex -d classes `find src -name '*.java'` + fi - if [ "${HAS_SRC_ART}" = "true" ]; then - mkdir -p classes - javac_with_bootclasspath -implicit:none -classpath src-multidex -d classes `find src-art -name '*.java'` - fi + if [ "${HAS_SRC_ART}" = "true" ]; then + mkdir -p classes + javac_with_bootclasspath -implicit:none -classpath src-multidex -d classes `find src-art -name '*.java'` + fi - if [ "${HAS_SRC_MULTIDEX}" = "true" ]; then - mkdir classes2 - javac_with_bootclasspath -implicit:none -classpath src -d classes2 `find src-multidex -name '*.java'` - if [ ${NEED_DEX} = "true" ]; then - make_dex classes2 - fi + if [ "${HAS_SRC_MULTIDEX}" = "true" ]; then + mkdir classes2 + javac_with_bootclasspath -implicit:none -classpath src -d classes2 `find src-multidex -name '*.java'` + if [ ${NEED_DEX} = "true" ]; then + make_dex classes2 fi + fi - if [ "${HAS_SRC2}" = "true" ]; then - mkdir -p classes - javac_with_bootclasspath -classpath classes -d classes `find src2 -name '*.java'` - fi + if [ "${HAS_SRC2}" = "true" ]; then + mkdir -p classes + javac_with_bootclasspath -classpath classes -d classes `find src2 -name '*.java'` + fi - if [[ "${HAS_SRC}" == "true" || "${HAS_SRC2}" == "true" || "${HAS_SRC_ART}" == "true" ]]; then - if [ ${NEED_DEX} = "true" ]; then - make_dex classes - fi + if [[ "${HAS_SRC}" == "true" || "${HAS_SRC2}" == "true" || "${HAS_SRC_ART}" == "true" ]]; then + if [ ${NEED_DEX} = "true" ]; then + make_dex classes fi fi fi @@ -500,7 +442,10 @@ fi if [ "${HAS_SMALI}" = "true" -a ${NEED_DEX} = "true" ]; then # Compile Smali classes ${SMALI} -JXmx512m assemble ${SMALI_ARGS} --output smali_classes.dex `find smali -name '*.smali'` - + if [[ ! -s smali_classes.dex ]] ; then + echo ${SMALI} produced no output. >&2 + exit 1 + fi # Merge smali files into classes.dex, this takes priority over any jasmin files. make_dexmerge classes.dex smali_classes.dex fi @@ -532,30 +477,20 @@ fi if [ ${HAS_SRC_EX} = "true" ]; then - if [ ${USE_JACK} = "true" ]; then - # Rename previous "classes.dex" so it is not overwritten. - mv classes.dex classes-1.dex - #TODO find another way to append src.jack to the jack classpath - ${JACK}:src.jack ${JACK_ARGS} --output-dex . src-ex - zip $TEST_NAME-ex.jar classes.dex - # Restore previous "classes.dex" so it can be zipped. - mv classes-1.dex classes.dex - else - # Build src-ex into classes-ex. - # Includes 'src', 'src-art' source when compiling classes-ex, but exclude their .class files. - if [[ "${HAS_SRC}" == "true" ]]; then - mkdir -p classes-tmp-for-ex - javac_with_bootclasspath -d classes-tmp-for-ex `find src -name '*.java'` - src_tmp_for_ex="-cp classes-tmp-for-ex" - fi - if [[ "${HAS_SRC_ART}" == "true" ]]; then - mkdir -p classes-tmp-for-ex - javac_with_bootclasspath -d classes-tmp-for-ex `find src-art -name '*.java'` - src_tmp_for_ex="-cp classes-tmp-for-ex" - fi - mkdir classes-ex - javac_with_bootclasspath -d classes-ex $src_tmp_for_ex `find src-ex -name '*.java'` + # Build src-ex into classes-ex. + # Includes 'src', 'src-art' source when compiling classes-ex, but exclude their .class files. + if [[ "${HAS_SRC}" == "true" ]]; then + mkdir -p classes-tmp-for-ex + javac_with_bootclasspath -d classes-tmp-for-ex `find src -name '*.java'` + src_tmp_for_ex="-cp classes-tmp-for-ex" fi + if [[ "${HAS_SRC_ART}" == "true" ]]; then + mkdir -p classes-tmp-for-ex + javac_with_bootclasspath -d classes-tmp-for-ex `find src-art -name '*.java'` + src_tmp_for_ex="-cp classes-tmp-for-ex" + fi + mkdir classes-ex + javac_with_bootclasspath -d classes-ex $src_tmp_for_ex `find src-ex -name '*.java'` fi if [[ -d classes-ex ]] && [ ${NEED_DEX} = "true" ]; then diff --git a/test/run-test b/test/run-test index be0a88d1f9..8e012d13fb 100755 --- a/test/run-test +++ b/test/run-test @@ -46,7 +46,6 @@ export RUN="${progdir}/etc/run-test-jar" export DEX_LOCATION=/data/run-test/${test_dir} export NEED_DEX="true" export USE_D8="true" -export USE_JACK="false" export USE_DESUGAR="true" export SMALI_ARGS="" @@ -72,11 +71,6 @@ if [ -z "$SMALI" ]; then export SMALI="smali" fi -# If jack was not set by the environment variable, assume it is in the path. -if [ -z "$JACK" ]; then - export JACK="jack" -fi - # ANDROID_BUILD_TOP is not set in a build environment. if [ -z "$ANDROID_BUILD_TOP" ]; then export ANDROID_BUILD_TOP=$oldwd @@ -87,13 +81,6 @@ if [ -z "$ANDROID_HOST_OUT" ]; then export ANDROID_HOST_OUT=${OUT_DIR:-$ANDROID_BUILD_TOP/out}/host/linux-x86 fi -# If JACK_CLASSPATH is not set, assume it only contains core-libart. -if [ -z "$JACK_CLASSPATH" ]; then - export JACK_CLASSPATH="${ANDROID_HOST_OUT}/../common/obj/JAVA_LIBRARIES/core-libart-hostdex_intermediates/classes.jack:${ANDROID_HOST_OUT}/../common/obj/JAVA_LIBRARIES/core-oj-hostdex_intermediates/classes.jack" -fi - -export JACK="$JACK -g -cp $JACK_CLASSPATH" - # Allow changing DESUGAR script to something else, or to disable it with DESUGAR=false. if [ -z "$DESUGAR" ]; then export DESUGAR="$ANDROID_BUILD_TOP/art/tools/desugar.sh" @@ -197,7 +184,6 @@ while true; do image_args="" prebuild_mode="no" NEED_DEX="false" - USE_JACK="false" run_args="${run_args} --jvm" shift elif [ "x$1" = "x-O" ]; then @@ -367,12 +353,6 @@ while true; do elif [ "x$1" = "x--build-only" ]; then build_only="yes" shift - elif [ "x$1" = "x--build-with-javac-dx" ]; then - USE_JACK="false" - shift - elif [ "x$1" = "x--build-with-jack" ]; then - USE_JACK="true" - shift elif [ "x$1" = "x--output-path" ]; then shift tmp_dir=$1 @@ -678,7 +658,7 @@ fi # For building with javac and dx always use Java 7. The dx compiler # only support byte codes from Java 7 or earlier (class file major # version 51 or lower). -if [ "$USE_JACK" != "true" ] && [ "$NEED_DEX" = "true" ]; then +if [ "$NEED_DEX" = "true" ]; then export JAVAC="${JAVAC} -source 1.7 -target 1.7" fi @@ -711,9 +691,6 @@ if [ "$usage" = "yes" ]; then echo " --gdb Run under gdb; incompatible with some tests." echo " --gdb-arg Pass an option to gdb." echo " --build-only Build test files only (off by default)." - echo " --build-with-d8 Build test files with javac and d8 (off by default)." - echo " --build-with-javac-dx Build test files with javac and dx (off by default)." - echo " --build-with-jack Build test files with jack and jill (on by default)." echo " --interpreter Enable interpreter only mode (off by default)." echo " --jit Enable jit (off by default)." echo " --optimizing Enable optimizing compiler (default)." diff --git a/test/testrunner/env.py b/test/testrunner/env.py index 0c1c308218..66ed0d0004 100644 --- a/test/testrunner/env.py +++ b/test/testrunner/env.py @@ -68,9 +68,6 @@ def _get_android_build_top(): ANDROID_BUILD_TOP = _get_android_build_top() -# Compiling with jack? Possible values in (True, False, 'default') -ANDROID_COMPILE_WITH_JACK = _get_build_var_boolean('ANDROID_COMPILE_WITH_JACK', 'default') - # Directory used for temporary test files on the host. ART_HOST_TEST_DIR = tempfile.mkdtemp(prefix = 'test-art-') @@ -134,8 +131,8 @@ else: HOST_OUT_EXECUTABLES = os.path.join(ANDROID_BUILD_TOP, _get_build_var("HOST_OUT_EXECUTABLES")) -# Set up default values for $JACK, $DX, $SMALI, etc to the $HOST_OUT_EXECUTABLES/$name path. -for tool in ['jack', 'dx', 'smali', 'jasmin', 'd8']: +# Set up default values for $DX, $SMALI, etc to the $HOST_OUT_EXECUTABLES/$name path. +for tool in ['dx', 'smali', 'jasmin', 'd8']: os.environ.setdefault(tool.upper(), HOST_OUT_EXECUTABLES + '/' + tool) ANDROID_JAVA_TOOLCHAIN = os.path.join(ANDROID_BUILD_TOP, diff --git a/test/testrunner/run_build_test_target.py b/test/testrunner/run_build_test_target.py index e0ccc3e14c..316007933e 100755 --- a/test/testrunner/run_build_test_target.py +++ b/test/testrunner/run_build_test_target.py @@ -68,8 +68,6 @@ if 'make' in target: build_command += ' -j' + str(n_threads) build_command += ' -C ' + env.ANDROID_BUILD_TOP build_command += ' ' + target.get('make') - # Add 'dist' to avoid Jack issues b/36169180. - build_command += ' dist' sys.stdout.write(str(build_command) + '\n') sys.stdout.flush() if subprocess.call(build_command.split()): diff --git a/test/testrunner/testrunner.py b/test/testrunner/testrunner.py index 254ffc9db1..09b9b210fc 100755 --- a/test/testrunner/testrunner.py +++ b/test/testrunner/testrunner.py @@ -482,12 +482,6 @@ def run_tests(tests): options_test += ' --instruction-set-features ' + \ env.HOST_2ND_ARCH_PREFIX_DEX2OAT_HOST_INSTRUCTION_SET_FEATURES - # Use the default run-test behavior unless ANDROID_COMPILE_WITH_JACK is explicitly set. - if env.ANDROID_COMPILE_WITH_JACK == True: - options_test += ' --build-with-jack' - elif env.ANDROID_COMPILE_WITH_JACK == False: - options_test += ' --build-with-javac-dx' - # TODO(http://36039166): This is a temporary solution to # fix build breakages. options_test = (' --output-path %s') % ( @@ -1010,8 +1004,6 @@ def main(): build_command += ' -j' build_command += ' -C ' + env.ANDROID_BUILD_TOP build_command += ' ' + build_targets - # Add 'dist' to avoid Jack issues b/36169180. - build_command += ' dist' if subprocess.call(build_command.split()): sys.exit(1) if user_requested_tests: diff --git a/tools/dexanalyze/dexanalyze_experiments.cc b/tools/dexanalyze/dexanalyze_experiments.cc index f9bf45da4f..427a465caf 100644 --- a/tools/dexanalyze/dexanalyze_experiments.cc +++ b/tools/dexanalyze/dexanalyze_experiments.cc @@ -24,6 +24,7 @@ #include "android-base/stringprintf.h" #include "dex/class_accessor-inl.h" +#include "dex/class_iterator.h" #include "dex/code_item_accessors-inl.h" #include "dex/dex_instruction-inl.h" #include "dex/standard_dex_file.h" @@ -125,20 +126,12 @@ void CountDexIndices::ProcessDexFile(const DexFile& dex_file) { num_field_ids_ += dex_file.NumFieldIds(); num_type_ids_ += dex_file.NumTypeIds(); num_class_defs_ += dex_file.NumClassDefs(); - for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs(); ++class_def_index) { - const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); - ClassAccessor accessor(dex_file, class_def); + for (ClassAccessor accessor : dex_file.GetClasses()) { std::set<size_t> unique_method_ids; std::set<size_t> unique_string_ids; accessor.VisitMethods([&](const ClassAccessor::Method& method) { - const DexFile::CodeItem* code_item = accessor.GetCodeItem(method); - if (code_item == nullptr) { - return; - } - CodeItemInstructionAccessor instructions(dex_file, code_item); - const uint16_t* code_ptr = instructions.Insns(); - dex_code_bytes_ += instructions.InsnsSizeInCodeUnits() * sizeof(code_ptr[0]); - for (const DexInstructionPcPair& inst : instructions) { + dex_code_bytes_ += method.GetInstructions().InsnsSizeInBytes(); + for (const DexInstructionPcPair& inst : method.GetInstructions()) { switch (inst->Opcode()) { case Instruction::CONST_STRING: { const dex::StringIndex string_index(inst->VRegB_21c()); @@ -157,7 +150,7 @@ void CountDexIndices::ProcessDexFile(const DexFile& dex_file) { case Instruction::INVOKE_VIRTUAL_RANGE: { bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE); uint32_t method_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c(); - if (dex_file.GetMethodId(method_idx).class_idx_ == class_def.class_idx_) { + if (dex_file.GetMethodId(method_idx).class_idx_ == accessor.GetDescriptorIndex()) { ++same_class_virtual_; } else { ++other_class_virtual_; @@ -169,7 +162,7 @@ void CountDexIndices::ProcessDexFile(const DexFile& dex_file) { case Instruction::INVOKE_DIRECT_RANGE: { bool is_range = (inst->Opcode() == Instruction::INVOKE_DIRECT_RANGE); uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); - if (dex_file.GetMethodId(method_idx).class_idx_ == class_def.class_idx_) { + if (dex_file.GetMethodId(method_idx).class_idx_ == accessor.GetDescriptorIndex()) { ++same_class_direct_; } else { ++other_class_direct_; @@ -181,7 +174,7 @@ void CountDexIndices::ProcessDexFile(const DexFile& dex_file) { case Instruction::INVOKE_STATIC_RANGE: { bool is_range = (inst->Opcode() == Instruction::INVOKE_STATIC_RANGE); uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); - if (dex_file.GetMethodId(method_idx).class_idx_ == class_def.class_idx_) { + if (dex_file.GetMethodId(method_idx).class_idx_ == accessor.GetDescriptorIndex()) { ++same_class_static_; } else { ++other_class_static_; |