summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/common_compiler_test.cc10
-rw-r--r--compiler/jni/jni_compiler_test.cc2
-rw-r--r--compiler/optimizing/loop_analysis.cc68
-rw-r--r--compiler/optimizing/loop_analysis.h23
-rw-r--r--compiler/optimizing/loop_optimization.cc17
-rw-r--r--compiler/optimizing/loop_optimization.h4
-rw-r--r--dex2oat/linker/image_test.h13
-rw-r--r--dex2oat/linker/oat_writer_test.cc6
-rw-r--r--libdexfile/dex/class_accessor-inl.h59
-rw-r--r--libdexfile/dex/class_accessor.h24
-rw-r--r--libdexfile/dex/class_iterator.h101
-rw-r--r--libdexfile/dex/code_item_accessors.h5
-rw-r--r--libdexfile/dex/dex_file-inl.h5
-rw-r--r--libdexfile/dex/dex_file.h3
-rw-r--r--libprofile/profile/profile_compilation_info_test.cc2
-rw-r--r--runtime/class_linker_test.cc118
-rw-r--r--runtime/common_dex_operations.h7
-rw-r--r--runtime/indirect_reference_table_test.cc15
-rw-r--r--runtime/instrumentation_test.cc14
-rw-r--r--runtime/jni/jni_internal_test.cc4
-rw-r--r--runtime/mirror/dex_cache_test.cc2
-rw-r--r--runtime/mirror/method_type_test.cc2
-rw-r--r--runtime/mirror/object_test.cc246
-rw-r--r--runtime/proxy_test.h10
-rwxr-xr-xtest.py3
-rw-r--r--test/003-omnibus-opcodes/build10
-rw-r--r--test/005-annotations/build11
-rw-r--r--test/022-interface/build9
-rw-r--r--test/023-many-interfaces/build14
-rw-r--r--test/056-const-string-jumbo/build13
-rwxr-xr-xtest/091-override-package-private-method/build16
-rw-r--r--test/111-unresolvable-exception/build10
-rw-r--r--test/113-multidex/build24
-rw-r--r--test/124-missing-classes/build10
-rw-r--r--test/126-miranda-multidex/build24
-rwxr-xr-xtest/127-checker-secondarydex/build16
-rwxr-xr-xtest/138-duplicate-classes-check2/build10
-rw-r--r--test/173-missing-field-type/expected.txt1
-rw-r--r--test/173-missing-field-type/info.txt1
-rw-r--r--test/173-missing-field-type/smali/BadField.smali34
-rw-r--r--test/173-missing-field-type/src-art/Main.java34
-rw-r--r--test/173-missing-field-type/src/Main.java22
-rw-r--r--test/1929-exception-catch-exception/smali/art/Test1929$Impl.smali2
-rw-r--r--test/1929-exception-catch-exception/src/art/Test1929.java2
-rw-r--r--test/303-verification-stress/build17
-rwxr-xr-xtest/442-checker-constant-folding/build6
-rwxr-xr-xtest/450-checker-types/build7
-rwxr-xr-xtest/458-checker-instruct-simplification/build6
-rwxr-xr-xtest/463-checker-boolean-simplifier/build6
-rw-r--r--test/482-checker-loop-back-edge-use/src/Main.java67
-rw-r--r--test/530-checker-peel-unroll/expected.txt1
-rw-r--r--test/530-checker-peel-unroll/info.txt1
-rw-r--r--test/530-checker-peel-unroll/src/Main.java822
-rwxr-xr-xtest/536-checker-intrinsic-optimization/build23
-rwxr-xr-xtest/537-checker-inline-and-unverified/build23
-rwxr-xr-xtest/565-checker-doublenegbitwise/build6
-rwxr-xr-xtest/586-checker-null-array-get/build23
-rwxr-xr-xtest/593-checker-boolean-2-integral-conv/build23
-rwxr-xr-xtest/633-checker-rtp-getclass/build23
-rwxr-xr-xtest/636-arm64-veneer-pool/build27
-rw-r--r--test/641-checker-arraycopy/build28
-rw-r--r--test/910-methods/check5
-rw-r--r--test/910-methods/expected_jack.diff4
-rw-r--r--test/911-get-stack-trace/check5
-rw-r--r--test/911-get-stack-trace/expected_jack.diff32
-rw-r--r--test/913-heaps/check5
-rw-r--r--test/913-heaps/expected_jack.diff50
-rwxr-xr-xtest/968-default-partial-compile-gen/build2
-rwxr-xr-xtest/970-iface-super-resolution-gen/build10
-rwxr-xr-xtest/971-iface-super/build2
-rwxr-xr-xtest/etc/default-build151
-rwxr-xr-xtest/run-test25
-rw-r--r--test/testrunner/env.py7
-rwxr-xr-xtest/testrunner/run_build_test_target.py2
-rwxr-xr-xtest/testrunner/testrunner.py8
-rw-r--r--tools/dexanalyze/dexanalyze_experiments.cc21
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)));
diff --git a/test.py b/test.py
index 047d8125fb..bc15736bd8 100755
--- a/test.py
+++ b/test.py
@@ -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_;