diff options
author | Andreas Gampe <agampe@google.com> | 2015-08-10 23:09:50 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2015-08-10 23:09:50 +0000 |
commit | ab3764e251eef3e515e353a9a20381c5c8dd2694 (patch) | |
tree | aead903f2740b4dd4aa3d3b286c0fa25a4c4f8ff | |
parent | a76c5ff153e1ef788c7eb2abf722a98f8b9b9bac (diff) | |
parent | f695a009725c8c840d916d01c14998f5c5f816d2 (diff) | |
download | art-ab3764e251eef3e515e353a9a20381c5c8dd2694.tar.gz art-ab3764e251eef3e515e353a9a20381c5c8dd2694.tar.bz2 art-ab3764e251eef3e515e353a9a20381c5c8dd2694.zip |
am f695a009: ART: Change UnresolvedMergedType internal representation
* commit 'f695a009725c8c840d916d01c14998f5c5f816d2':
ART: Change UnresolvedMergedType internal representation
-rw-r--r-- | compiler/dex/gvn_dead_code_elimination.cc | 2 | ||||
-rw-r--r-- | runtime/base/bit_vector.cc | 37 | ||||
-rw-r--r-- | runtime/base/bit_vector.h | 13 | ||||
-rw-r--r-- | runtime/base/bit_vector_test.cc | 4 | ||||
-rw-r--r-- | runtime/verifier/reg_type.cc | 61 | ||||
-rw-r--r-- | runtime/verifier/reg_type.h | 51 | ||||
-rw-r--r-- | runtime/verifier/reg_type_cache.cc | 57 | ||||
-rw-r--r-- | runtime/verifier/reg_type_test.cc | 10 | ||||
-rw-r--r-- | test/800-smali/expected.txt | 1 | ||||
-rw-r--r-- | test/800-smali/smali/b_22881413.smali | 291 | ||||
-rw-r--r-- | test/800-smali/src/Main.java | 1 | ||||
-rwxr-xr-x | test/etc/run-test-jar | 14 |
12 files changed, 452 insertions, 90 deletions
diff --git a/compiler/dex/gvn_dead_code_elimination.cc b/compiler/dex/gvn_dead_code_elimination.cc index 044989e2a9..d29b865ce9 100644 --- a/compiler/dex/gvn_dead_code_elimination.cc +++ b/compiler/dex/gvn_dead_code_elimination.cc @@ -74,7 +74,7 @@ inline void GvnDeadCodeElimination::MIRData::RemovePrevChange(int v_reg, MIRData GvnDeadCodeElimination::VRegChains::VRegChains(uint32_t num_vregs, ScopedArenaAllocator* alloc) : num_vregs_(num_vregs), vreg_data_(alloc->AllocArray<VRegValue>(num_vregs, kArenaAllocMisc)), - vreg_high_words_(num_vregs, false, Allocator::GetNoopAllocator(), + vreg_high_words_(false, Allocator::GetNoopAllocator(), BitVector::BitsToWords(num_vregs), alloc->AllocArray<uint32_t>(BitVector::BitsToWords(num_vregs))), mir_data_(alloc->Adapter()) { diff --git a/runtime/base/bit_vector.cc b/runtime/base/bit_vector.cc index 39ce0d2cbe..cfd3d24aad 100644 --- a/runtime/base/bit_vector.cc +++ b/runtime/base/bit_vector.cc @@ -24,11 +24,7 @@ namespace art { -// TODO: replace excessive argument defaulting when we are at gcc 4.7 -// or later on host with delegating constructor support. Specifically, -// starts_bits and storage_size/storage are mutually exclusive. -BitVector::BitVector(uint32_t start_bits, - bool expandable, +BitVector::BitVector(bool expandable, Allocator* allocator, uint32_t storage_size, uint32_t* storage) @@ -36,12 +32,31 @@ BitVector::BitVector(uint32_t start_bits, storage_size_(storage_size), allocator_(allocator), expandable_(expandable) { + DCHECK(storage_ != nullptr); + static_assert(sizeof(*storage_) == kWordBytes, "word bytes"); static_assert(sizeof(*storage_) * 8u == kWordBits, "word bits"); - if (storage_ == nullptr) { - storage_size_ = BitsToWords(start_bits); - storage_ = static_cast<uint32_t*>(allocator_->Alloc(storage_size_ * kWordBytes)); - } +} + +BitVector::BitVector(uint32_t start_bits, + bool expandable, + Allocator* allocator) + : BitVector(expandable, + allocator, + BitsToWords(start_bits), + static_cast<uint32_t*>(allocator->Alloc(BitsToWords(start_bits) * kWordBytes))) { +} + + +BitVector::BitVector(const BitVector& src, + bool expandable, + Allocator* allocator) + : BitVector(expandable, + allocator, + src.storage_size_, + static_cast<uint32_t*>(allocator->Alloc(src.storage_size_ * kWordBytes))) { + // Direct memcpy would be faster, but this should be fine too and is cleaner. + Copy(&src); } BitVector::~BitVector() { @@ -357,4 +372,8 @@ void BitVector::EnsureSize(uint32_t idx) { } } +Allocator* BitVector::GetAllocator() const { + return allocator_; +} + } // namespace art diff --git a/runtime/base/bit_vector.h b/runtime/base/bit_vector.h index 17835f5610..237bc90c85 100644 --- a/runtime/base/bit_vector.h +++ b/runtime/base/bit_vector.h @@ -112,9 +112,16 @@ class BitVector { BitVector(uint32_t start_bits, bool expandable, + Allocator* allocator); + + BitVector(bool expandable, Allocator* allocator, - uint32_t storage_size = 0, - uint32_t* storage = nullptr); + uint32_t storage_size, + uint32_t* storage); + + BitVector(const BitVector& src, + bool expandable, + Allocator* allocator); virtual ~BitVector(); @@ -231,6 +238,8 @@ class BitVector { void Dump(std::ostream& os, const char* prefix) const; + Allocator* GetAllocator() const; + private: /** * @brief Dump the bitvector into buffer in a 00101..01 format. diff --git a/runtime/base/bit_vector_test.cc b/runtime/base/bit_vector_test.cc index c51b9b0570..76095c28be 100644 --- a/runtime/base/bit_vector_test.cc +++ b/runtime/base/bit_vector_test.cc @@ -71,7 +71,7 @@ TEST(BitVector, NoopAllocator) { uint32_t bits[kWords]; memset(bits, 0, sizeof(bits)); - BitVector bv(0U, false, Allocator::GetNoopAllocator(), kWords, bits); + BitVector bv(false, Allocator::GetNoopAllocator(), kWords, bits); EXPECT_EQ(kWords, bv.GetStorageSize()); EXPECT_EQ(kWords * sizeof(uint32_t), bv.GetSizeOf()); EXPECT_EQ(bits, bv.GetRawStorage()); @@ -128,7 +128,7 @@ TEST(BitVector, SetInitialBits) { uint32_t bits[kWords]; memset(bits, 0, sizeof(bits)); - BitVector bv(0U, false, Allocator::GetNoopAllocator(), kWords, bits); + BitVector bv(false, Allocator::GetNoopAllocator(), kWords, bits); bv.SetInitialBits(0u); EXPECT_EQ(0u, bv.NumSetBits()); bv.SetInitialBits(1u); diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc index 1435607e48..2cdb73d2f1 100644 --- a/runtime/verifier/reg_type.cc +++ b/runtime/verifier/reg_type.cc @@ -16,6 +16,7 @@ #include "reg_type-inl.h" +#include "base/bit_vector-inl.h" #include "base/casts.h" #include "class_linker-inl.h" #include "dex_file-inl.h" @@ -307,13 +308,17 @@ PreciseReferenceType::PreciseReferenceType(mirror::Class* klass, const std::stri std::string UnresolvedMergedType::Dump() const { std::stringstream result; - std::set<uint16_t> types = GetMergedTypes(); - result << "UnresolvedMergedReferences("; - auto it = types.begin(); - result << reg_type_cache_->GetFromId(*it).Dump(); - for (++it; it != types.end(); ++it) { - result << ", "; - result << reg_type_cache_->GetFromId(*it).Dump(); + result << "UnresolvedMergedReferences(" << GetResolvedPart().Dump() << " | "; + const BitVector& types = GetUnresolvedTypes(); + + bool first = true; + for (uint32_t idx : types.Indexes()) { + if (!first) { + result << ", "; + } else { + first = false; + } + result << reg_type_cache_->GetFromId(idx).Dump(); } result << ")"; return result.str(); @@ -490,32 +495,6 @@ bool UnresolvedType::IsNonZeroReferenceTypes() const { return true; } -std::set<uint16_t> UnresolvedMergedType::GetMergedTypes() const { - std::pair<uint16_t, uint16_t> refs = GetTopMergedTypes(); - const RegType& left = reg_type_cache_->GetFromId(refs.first); - const RegType& right = reg_type_cache_->GetFromId(refs.second); - - std::set<uint16_t> types; - if (left.IsUnresolvedMergedReference()) { - types = down_cast<const UnresolvedMergedType*>(&left)->GetMergedTypes(); - } else { - types.insert(refs.first); - } - if (right.IsUnresolvedMergedReference()) { - std::set<uint16_t> right_types = - down_cast<const UnresolvedMergedType*>(&right)->GetMergedTypes(); - types.insert(right_types.begin(), right_types.end()); - } else { - types.insert(refs.second); - } - if (kIsDebugBuild) { - for (const auto& type : types) { - CHECK(!reg_type_cache_->GetFromId(type).IsUnresolvedMergedReference()); - } - } - return types; -} - const RegType& RegType::GetSuperClass(RegTypeCache* cache) const { if (!IsUnresolvedTypes()) { mirror::Class* super_klass = GetClass()->GetSuperClass(); @@ -805,12 +784,24 @@ void UnresolvedUninitializedRefType::CheckInvariants() const { CHECK(klass_.IsNull()) << *this; } +UnresolvedMergedType::UnresolvedMergedType(const RegType& resolved, + const BitVector& unresolved, + const RegTypeCache* reg_type_cache, + uint16_t cache_id) + : UnresolvedType("", cache_id), + reg_type_cache_(reg_type_cache), + resolved_part_(resolved), + unresolved_types_(unresolved, false, unresolved.GetAllocator()) { + if (kIsDebugBuild) { + CheckInvariants(); + } +} void UnresolvedMergedType::CheckInvariants() const { // Unresolved merged types: merged types should be defined. CHECK(descriptor_.empty()) << *this; CHECK(klass_.IsNull()) << *this; - CHECK_NE(merged_types_.first, 0U) << *this; - CHECK_NE(merged_types_.second, 0U) << *this; + CHECK(resolved_part_.IsReferenceTypes()); + CHECK(!resolved_part_.IsUnresolvedTypes()); } void UnresolvedReferenceType::CheckInvariants() const { diff --git a/runtime/verifier/reg_type.h b/runtime/verifier/reg_type.h index d08c937a64..2af0eadb71 100644 --- a/runtime/verifier/reg_type.h +++ b/runtime/verifier/reg_type.h @@ -22,6 +22,7 @@ #include <set> #include <string> +#include "base/bit_vector.h" #include "base/macros.h" #include "base/mutex.h" #include "gc_root.h" @@ -230,6 +231,14 @@ class RegType { // from another. const RegType& Merge(const RegType& incoming_type, RegTypeCache* reg_types) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Same as above, but also handles the case where incoming_type == this. + const RegType& SafeMerge(const RegType& incoming_type, RegTypeCache* reg_types) const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + if (Equals(incoming_type)) { + return *this; + } + return Merge(incoming_type, reg_types); + } /* * A basic Join operation on classes. For a pair of types S and T the Join, @@ -868,30 +877,23 @@ class UnresolvedSuperClass FINAL : public UnresolvedType { const RegTypeCache* const reg_type_cache_; }; -// A merge of two unresolved types. If the types were resolved this may be -// Conflict or another -// known ReferenceType. +// A merge of unresolved (and resolved) types. If the types were resolved this may be +// Conflict or another known ReferenceType. class UnresolvedMergedType FINAL : public UnresolvedType { public: - UnresolvedMergedType(uint16_t left_id, uint16_t right_id, + // Note: the constructor will copy the unresolved BitVector, not use it directly. + UnresolvedMergedType(const RegType& resolved, const BitVector& unresolved, const RegTypeCache* reg_type_cache, uint16_t cache_id) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) - : UnresolvedType("", cache_id), - reg_type_cache_(reg_type_cache), - merged_types_(left_id, right_id) { - if (kIsDebugBuild) { - CheckInvariants(); - } - } + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - // The top of a tree of merged types. - std::pair<uint16_t, uint16_t> GetTopMergedTypes() const { - DCHECK(IsUnresolvedMergedReference()); - return merged_types_; + // The resolved part. See description below. + const RegType& GetResolvedPart() const { + return resolved_part_; + } + // The unresolved part. + const BitVector& GetUnresolvedTypes() const { + return unresolved_types_; } - - // The complete set of merged types. - std::set<uint16_t> GetMergedTypes() const; bool IsUnresolvedMergedReference() const OVERRIDE { return true; } @@ -903,7 +905,16 @@ class UnresolvedMergedType FINAL : public UnresolvedType { void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); const RegTypeCache* const reg_type_cache_; - const std::pair<uint16_t, uint16_t> merged_types_; + + // The original implementation of merged types was a binary tree. Collection of the flattened + // types ("leaves") can be expensive, so we store the expanded list now, as two components: + // 1) A resolved component. We use Zero when there is no resolved component, as that will be + // an identity merge. + // 2) A bitvector of the unresolved reference types. A bitvector was chosen with the assumption + // that there should not be too many types in flight in practice. (We also bias the index + // against the index of Zero, which is one of the later default entries in any cache.) + const RegType& resolved_part_; + const BitVector unresolved_types_; }; std::ostream& operator<<(std::ostream& os, const RegType& rhs) diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc index b371d7e391..a597c8fdf9 100644 --- a/runtime/verifier/reg_type_cache.cc +++ b/runtime/verifier/reg_type_cache.cc @@ -317,39 +317,62 @@ void RegTypeCache::CreatePrimitiveAndSmallConstantTypes() { } const RegType& RegTypeCache::FromUnresolvedMerge(const RegType& left, const RegType& right) { - std::set<uint16_t> types; + BitVector types(1, // Allocate at least a word. + true, // Is expandable. + Allocator::GetMallocAllocator()); // TODO: Arenas in the verifier. + const RegType* left_resolved; if (left.IsUnresolvedMergedReference()) { - RegType& non_const(const_cast<RegType&>(left)); - types = (down_cast<UnresolvedMergedType*>(&non_const))->GetMergedTypes(); + const UnresolvedMergedType* left_merge = down_cast<const UnresolvedMergedType*>(&left); + types.Copy(&left_merge->GetUnresolvedTypes()); + left_resolved = &left_merge->GetResolvedPart(); + } else if (left.IsUnresolvedReference()) { + types.SetBit(left.GetId()); + left_resolved = &Zero(); } else { - types.insert(left.GetId()); + left_resolved = &left; } + + const RegType* right_resolved; if (right.IsUnresolvedMergedReference()) { - RegType& non_const(const_cast<RegType&>(right)); - std::set<uint16_t> right_types = (down_cast<UnresolvedMergedType*>(&non_const))->GetMergedTypes(); - types.insert(right_types.begin(), right_types.end()); + const UnresolvedMergedType* right_merge = down_cast<const UnresolvedMergedType*>(&right); + types.Union(&right_merge->GetUnresolvedTypes()); + right_resolved = &right_merge->GetResolvedPart(); + } else if (right.IsUnresolvedReference()) { + types.SetBit(right.GetId()); + right_resolved = &Zero(); } else { - types.insert(right.GetId()); + right_resolved = &right; + } + + // Merge the resolved parts. Left and right might be equal, so use SafeMerge. + const RegType& resolved_parts_merged = left_resolved->SafeMerge(*right_resolved, this); + // If we get a conflict here, the merge result is a conflict, not an unresolved merge type. + if (resolved_parts_merged.IsConflict()) { + return Conflict(); } + // Check if entry already exists. for (size_t i = primitive_count_; i < entries_.size(); i++) { const RegType* cur_entry = entries_[i]; if (cur_entry->IsUnresolvedMergedReference()) { - std::set<uint16_t> cur_entry_types = - (down_cast<const UnresolvedMergedType*>(cur_entry))->GetMergedTypes(); - if (cur_entry_types == types) { + const UnresolvedMergedType* cmp_type = down_cast<const UnresolvedMergedType*>(cur_entry); + const RegType& resolved_part = cmp_type->GetResolvedPart(); + const BitVector& unresolved_part = cmp_type->GetUnresolvedTypes(); + // Use SameBitsSet. "types" is expandable to allow merging in the components, but the + // BitVector in the final RegType will be made non-expandable. + if (&resolved_part == &resolved_parts_merged && + types.SameBitsSet(&unresolved_part)) { return *cur_entry; } } } + // Create entry. - RegType* entry = new UnresolvedMergedType(left.GetId(), right.GetId(), this, entries_.size()); + RegType* entry = new UnresolvedMergedType(resolved_parts_merged, + types, + this, + entries_.size()); AddEntry(entry); - if (kIsDebugBuild) { - UnresolvedMergedType* tmp_entry = down_cast<UnresolvedMergedType*>(entry); - std::set<uint16_t> check_types = tmp_entry->GetMergedTypes(); - CHECK(check_types == types); - } return *entry; } diff --git a/runtime/verifier/reg_type_test.cc b/runtime/verifier/reg_type_test.cc index 2fecc8b25f..971b1f5d0f 100644 --- a/runtime/verifier/reg_type_test.cc +++ b/runtime/verifier/reg_type_test.cc @@ -18,6 +18,7 @@ #include <set> +#include "base/bit_vector.h" #include "base/casts.h" #include "common_runtime_test.h" #include "reg_type_cache-inl.h" @@ -421,7 +422,7 @@ TEST_F(RegTypeReferenceTest, Dump) { EXPECT_EQ(expected, resolved_unintialiesd.Dump()); expected = "Unresolved And Uninitialized Reference: java.lang.DoesNotExist Allocation PC: 12"; EXPECT_EQ(expected, unresolved_unintialized.Dump()); - expected = "UnresolvedMergedReferences(Unresolved Reference: java.lang.DoesNotExist, Unresolved Reference: java.lang.DoesNotExistEither)"; + expected = "UnresolvedMergedReferences(Zero/null | Unresolved Reference: java.lang.DoesNotExist, Unresolved Reference: java.lang.DoesNotExistEither)"; EXPECT_EQ(expected, unresolved_merged.Dump()); } @@ -477,9 +478,10 @@ TEST_F(RegTypeReferenceTest, Merging) { EXPECT_TRUE(merged.IsUnresolvedMergedReference()); RegType& merged_nonconst = const_cast<RegType&>(merged); - std::set<uint16_t> merged_ids = (down_cast<UnresolvedMergedType*>(&merged_nonconst))->GetMergedTypes(); - EXPECT_EQ(ref_type_0.GetId(), *(merged_ids.begin())); - EXPECT_EQ(ref_type_1.GetId(), *((++merged_ids.begin()))); + const BitVector& unresolved_parts = + down_cast<UnresolvedMergedType*>(&merged_nonconst)->GetUnresolvedTypes(); + EXPECT_TRUE(unresolved_parts.IsBitSet(ref_type_0.GetId())); + EXPECT_TRUE(unresolved_parts.IsBitSet(ref_type_1.GetId())); } TEST_F(RegTypeTest, MergingFloat) { diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt index 659f1044aa..77668daadd 100644 --- a/test/800-smali/expected.txt +++ b/test/800-smali/expected.txt @@ -27,4 +27,5 @@ b/22244733 b/22331663 b/22331663 (pass) b/22331663 (fail) +b/22881413 Done! diff --git a/test/800-smali/smali/b_22881413.smali b/test/800-smali/smali/b_22881413.smali new file mode 100644 index 0000000000..f624734353 --- /dev/null +++ b/test/800-smali/smali/b_22881413.smali @@ -0,0 +1,291 @@ +.class public LB22881413; +.super Ljava/lang/Object; + +# A couple of fields to allow "loading" resolved and unresolved types. Use non-final classes to +# avoid automatically getting precise reference types. +.field private static res1:Ljava/lang/Number; +.field private static res2:Ljava/lang/ClassLoader; +.field private static res3:Ljava/lang/Package; +.field private static res4:Ljava/lang/RuntimeException; +.field private static res5:Ljava/lang/Exception; +.field private static res6:Ljava/util/ArrayList; +.field private static res7:Ljava/util/LinkedList; +.field private static res8:Ljava/lang/Thread; +.field private static res9:Ljava/lang/ThreadGroup; +.field private static res10:Ljava/lang/Runtime; + +.field private static unres1:La/b/c/d1; +.field private static unres2:La/b/c/d2; +.field private static unres3:La/b/c/d3; +.field private static unres4:La/b/c/d4; +.field private static unres5:La/b/c/d5; +.field private static unres6:La/b/c/d6; +.field private static unres7:La/b/c/d7; +.field private static unres8:La/b/c/d8; +.field private static unres9:La/b/c/d9; +.field private static unres10:La/b/c/d10; + +.field private static unresBase0:La/b/c/dBase0; +.field private static unresBase1:La/b/c/dBase1; +.field private static unresBase2:La/b/c/dBase2; +.field private static unresBase3:La/b/c/dBase3; +.field private static unresBase4:La/b/c/dBase4; +.field private static unresBase5:La/b/c/dBase5; +.field private static unresBase6:La/b/c/dBase6; +.field private static unresBase7:La/b/c/dBase7; +.field private static unresBase8:La/b/c/dBase8; + +# Empty, ignore this. We want to see if the other method can be verified in a reasonable amount of +# time. +.method public static run()V +.registers 2 + return-void +.end method + +.method public static foo(IZZ) V +.registers 11 + # v8 = int, v9 = boolean, v10 = boolean + + sget-object v0, LB22881413;->unresBase0:La/b/c/dBase0; + const v1, 0 + const v2, 0 + +# We're trying to create something like this (with more loops to amplify things). +# +# v0 = Unresolved1 +# while (something) { +# +# [Repeatedly] +# if (cond) { +# v0 = ResolvedX; +# } else { +# v0 = UnresolvedX; +# } +# +# v0 = Unresolved2 +# }; +# +# Important points: +# 1) Use a while, so that the end of the loop is a goto. That way, the merging of outer-loop +# unresolved classes is postponed. +# 2) Put the else cases after all if cases. That way there are backward gotos that will lead +# to stabilization loops in the body. +# + +:Loop1 + + const v6, 0 + add-int/lit16 v8, v8, -1 + if-ge v8, v6, :Loop1End + +:Loop2 + + const v6, 0 + add-int/lit16 v8, v8, -1 + if-ge v8, v6, :Loop2End + +:Loop3 + + const v6, 0 + add-int/lit16 v8, v8, -1 + if-ge v8, v6, :Loop3End + +:Loop4 + + const v6, 0 + add-int/lit16 v8, v8, -1 + if-ge v8, v6, :Loop4End + +:Loop5 + + const v6, 0 + add-int/lit16 v8, v8, -1 + if-ge v8, v6, :Loop5End + +:Loop6 + + const v6, 0 + add-int/lit16 v8, v8, -1 + if-ge v8, v6, :Loop6End + +:Loop7 + + const v6, 0 + add-int/lit16 v8, v8, -1 + if-ge v8, v6, :Loop7End + +:Loop8 + + const v6, 0 + add-int/lit16 v8, v8, -1 + if-ge v8, v6, :Loop8End + +# Prototype: +# +# if-eqz v9, :ElseX +# sget-object v0, LB22881413;->res1:Ljava/lang/Number; +#:JoinX +# +# And somewhere at the end +# +#:ElseX +# sget-object v0, LB22881413;->unresX:La/b/c/dX; +# goto :JoinX +# +# + + if-eqz v10, :Join1 + if-eqz v9, :Else1 + sget-object v0, LB22881413;->res1:Ljava/lang/Number; +:Join1 + + + if-eqz v10, :Join2 + if-eqz v9, :Else2 + sget-object v0, LB22881413;->res2:Ljava/lang/ClassLoader; +:Join2 + + + if-eqz v10, :Join3 + if-eqz v9, :Else3 + sget-object v0, LB22881413;->res3:Ljava/lang/Package; +:Join3 + + + if-eqz v10, :Join4 + if-eqz v9, :Else4 + sget-object v0, LB22881413;->res4:Ljava/lang/RuntimeException; +:Join4 + + + if-eqz v10, :Join5 + if-eqz v9, :Else5 + sget-object v0, LB22881413;->res5:Ljava/lang/Exception; +:Join5 + + + if-eqz v10, :Join6 + if-eqz v9, :Else6 + sget-object v0, LB22881413;->res6:Ljava/util/ArrayList; +:Join6 + + + if-eqz v10, :Join7 + if-eqz v9, :Else7 + sget-object v0, LB22881413;->res7:Ljava/util/LinkedList; +:Join7 + + + if-eqz v10, :Join8 + if-eqz v9, :Else8 + sget-object v0, LB22881413;->res8:Ljava/lang/Thread; +:Join8 + + + if-eqz v10, :Join9 + if-eqz v9, :Else9 + sget-object v0, LB22881413;->res9:Ljava/lang/ThreadGroup; +:Join9 + + + if-eqz v10, :Join10 + if-eqz v9, :Else10 + sget-object v0, LB22881413;->res10:Ljava/lang/Runtime; +:Join10 + + + goto :InnerMostLoopEnd + +:Else1 + sget-object v0, LB22881413;->unres1:La/b/c/d1; + goto :Join1 + +:Else2 + sget-object v0, LB22881413;->unres2:La/b/c/d2; + goto :Join2 + +:Else3 + sget-object v0, LB22881413;->unres3:La/b/c/d3; + goto :Join3 + +:Else4 + sget-object v0, LB22881413;->unres4:La/b/c/d4; + goto :Join4 + +:Else5 + sget-object v0, LB22881413;->unres5:La/b/c/d5; + goto :Join5 + +:Else6 + sget-object v0, LB22881413;->unres6:La/b/c/d6; + goto :Join6 + +:Else7 + sget-object v0, LB22881413;->unres7:La/b/c/d7; + goto :Join7 + +:Else8 + sget-object v0, LB22881413;->unres8:La/b/c/d8; + goto :Join8 + +:Else9 + sget-object v0, LB22881413;->unres9:La/b/c/d9; + goto :Join9 + +:Else10 + sget-object v0, LB22881413;->unres10:La/b/c/d10; + goto :Join10 + +:InnerMostLoopEnd + + # Loop 8 end of body. + sget-object v0, LB22881413;->unresBase8:La/b/c/dBase8; + goto :Loop8 + +:Loop8End + + # Loop 7 end of body. + sget-object v0, LB22881413;->unresBase7:La/b/c/dBase7; + goto :Loop7 + +:Loop7End + + # Loop 6 end of body. + sget-object v0, LB22881413;->unresBase6:La/b/c/dBase6; + goto :Loop6 + +:Loop6End + + # Loop 5 end of body + sget-object v0, LB22881413;->unresBase5:La/b/c/dBase5; + goto :Loop5 + +:Loop5End + + # Loop 4 end of body + sget-object v0, LB22881413;->unresBase4:La/b/c/dBase4; + goto :Loop4 + +:Loop4End + + # Loop 3 end of body + sget-object v0, LB22881413;->unresBase3:La/b/c/dBase3; + goto :Loop3 + +:Loop3End + + # Loop 2 end of body + sget-object v0, LB22881413;->unresBase2:La/b/c/dBase2; + goto :Loop2 + +:Loop2End + + # Loop 1 end of body + sget-object v0, LB22881413;->unresBase1:La/b/c/dBase1; + goto :Loop1 + +:Loop1End + + return-void + +.end method diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java index 709c7f66a9..7ee1e45312 100644 --- a/test/800-smali/src/Main.java +++ b/test/800-smali/src/Main.java @@ -101,6 +101,7 @@ public class Main { new Object[] { false }, null, null)); testCases.add(new TestCase("b/22331663 (fail)", "B22331663Fail", "run", new Object[] { false }, new VerifyError(), null)); + testCases.add(new TestCase("b/22881413", "B22881413", "run", null, null, null)); } public void runTests() { diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar index 240ed41ff2..1a8853a559 100755 --- a/test/etc/run-test-jar +++ b/test/etc/run-test-jar @@ -316,6 +316,20 @@ if [ "$PREBUILD" = "y" ]; then --dex-file=$DEX_LOCATION/$TEST_NAME.jar \ --oat-file=$DEX_LOCATION/dalvik-cache/$ISA/$(echo $DEX_LOCATION/$TEST_NAME.jar/classes.dex | cut -d/ -f 2- | sed "s:/:@:g") \ --instruction-set=$ISA" + if [ "x$INSTRUCTION_SET_FEATURES" != "x" ] ; then + dex2oat_cmdline="${dex2oat_cmdline} --instruction-set-features=${INSTRUCTION_SET_FEATURES}" + fi + + # Add in a timeout. This is important for testing the compilation/verification time of + # pathological cases. + # Note: as we don't know how decent targets are (e.g., emulator), only do this on the host for + # now. We should try to improve this. + # The current value is rather arbitrary. run-tests should compile quickly. + if [ "$HOST" != "n" ]; then + # Use SIGRTMIN+2 to try to dump threads. + # Use -k 1m to SIGKILL it a minute later if it hasn't ended. + dex2oat_cmdline="timeout -k 1m -s SIGRTMIN+2 1m ${dex2oat_cmdline}" + fi fi dalvikvm_cmdline="$INVOKE_WITH $GDB $ANDROID_ROOT/bin/$DALVIKVM \ |