summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/optimizing/builder.h4
-rw-r--r--compiler/optimizing/inliner.cc28
-rw-r--r--compiler/optimizing/licm.cc15
-rw-r--r--compiler/optimizing/nodes.h4
-rw-r--r--compiler/optimizing/reference_type_propagation.cc64
-rw-r--r--compiler/optimizing/reference_type_propagation.h5
-rw-r--r--compiler/optimizing/ssa_builder.cc2
-rw-r--r--compiler/optimizing/ssa_builder.h6
-rw-r--r--compiler/optimizing/ssa_liveness_analysis.h56
-rw-r--r--compiler/utils/assembler.h6
-rw-r--r--runtime/jit/jit.cc1
-rw-r--r--runtime/oat_file_assistant.cc17
-rw-r--r--runtime/oat_file_manager.cc2
-rw-r--r--runtime/verifier/method_verifier.cc13
-rw-r--r--test/147-stripped-dex-fallback/expected.txt1
-rw-r--r--test/147-stripped-dex-fallback/info.txt2
-rwxr-xr-xtest/147-stripped-dex-fallback/run24
-rw-r--r--test/147-stripped-dex-fallback/src/Main.java21
-rw-r--r--test/594-checker-irreducible-linorder/expected.txt0
-rw-r--r--test/594-checker-irreducible-linorder/info.txt2
-rw-r--r--test/594-checker-irreducible-linorder/smali/IrreducibleLoop.smali64
-rw-r--r--test/594-checker-irreducible-linorder/src/Main.java25
-rw-r--r--test/800-smali/expected.txt1
-rw-r--r--test/800-smali/smali/b_28187158.smali11
-rw-r--r--test/800-smali/src/Main.java2
-rw-r--r--test/Android.run-test.mk4
-rwxr-xr-xtest/etc/run-test-jar19
-rwxr-xr-xtest/run-test6
28 files changed, 345 insertions, 60 deletions
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index 4f46d5edda..580ef72767 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -51,7 +51,7 @@ class HGraphBuilder : public ValueObject {
compiler_driver_(driver),
compilation_stats_(compiler_stats),
block_builder_(graph, dex_file, code_item),
- ssa_builder_(graph, handles),
+ ssa_builder_(graph, dex_compilation_unit->GetDexCache(), handles),
instruction_builder_(graph,
&block_builder_,
&ssa_builder_,
@@ -78,7 +78,7 @@ class HGraphBuilder : public ValueObject {
null_dex_cache_(),
compilation_stats_(nullptr),
block_builder_(graph, nullptr, code_item),
- ssa_builder_(graph, handles),
+ ssa_builder_(graph, null_dex_cache_, handles),
instruction_builder_(graph,
&block_builder_,
&ssa_builder_,
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 77e0cbc600..d60298b954 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -411,7 +411,10 @@ bool HInliner::TryInlineMonomorphicCall(HInvoke* invoke_instruction,
// Run type propagation to get the guard typed, and eventually propagate the
// type of the receiver.
- ReferenceTypePropagation rtp_fixup(graph_, handles_, /* is_first_run */ false);
+ ReferenceTypePropagation rtp_fixup(graph_,
+ outer_compilation_unit_.GetDexCache(),
+ handles_,
+ /* is_first_run */ false);
rtp_fixup.Run();
MaybeRecordStat(kInlinedMonomorphicCall);
@@ -532,7 +535,10 @@ bool HInliner::TryInlinePolymorphicCall(HInvoke* invoke_instruction,
MaybeRecordStat(kInlinedPolymorphicCall);
// Run type propagation to get the guards typed.
- ReferenceTypePropagation rtp_fixup(graph_, handles_, /* is_first_run */ false);
+ ReferenceTypePropagation rtp_fixup(graph_,
+ outer_compilation_unit_.GetDexCache(),
+ handles_,
+ /* is_first_run */ false);
rtp_fixup.Run();
return true;
}
@@ -709,7 +715,10 @@ bool HInliner::TryInlinePolymorphicCallToSameTarget(HInvoke* invoke_instruction,
deoptimize->CopyEnvironmentFrom(invoke_instruction->GetEnvironment());
// Run type propagation to get the guard typed.
- ReferenceTypePropagation rtp_fixup(graph_, handles_, /* is_first_run */ false);
+ ReferenceTypePropagation rtp_fixup(graph_,
+ outer_compilation_unit_.GetDexCache(),
+ handles_,
+ /* is_first_run */ false);
rtp_fixup.Run();
MaybeRecordStat(kInlinedPolymorphicCall);
@@ -971,7 +980,8 @@ HInstanceFieldGet* HInliner::CreateInstanceFieldGet(Handle<mirror::DexCache> dex
// dex pc for the associated stack map. 0 is bogus but valid. Bug: 26854537.
/* dex_pc */ 0);
if (iget->GetType() == Primitive::kPrimNot) {
- ReferenceTypePropagation rtp(graph_, handles_, /* is_first_run */ false);
+ // Use the same dex_cache that we used for field lookup as the hint_dex_cache.
+ ReferenceTypePropagation rtp(graph_, dex_cache, handles_, /* is_first_run */ false);
rtp.Visit(iget);
}
return iget;
@@ -1319,13 +1329,19 @@ void HInliner::FixUpReturnReferenceType(HInvoke* invoke_instruction,
if (invoke_rti.IsStrictSupertypeOf(return_rti)
|| (return_rti.IsExact() && !invoke_rti.IsExact())
|| !return_replacement->CanBeNull()) {
- ReferenceTypePropagation(graph_, handles_, /* is_first_run */ false).Run();
+ ReferenceTypePropagation(graph_,
+ outer_compilation_unit_.GetDexCache(),
+ handles_,
+ /* is_first_run */ false).Run();
}
}
} else if (return_replacement->IsInstanceOf()) {
if (do_rtp) {
// Inlining InstanceOf into an If may put a tighter bound on reference types.
- ReferenceTypePropagation(graph_, handles_, /* is_first_run */ false).Run();
+ ReferenceTypePropagation(graph_,
+ outer_compilation_unit_.GetDexCache(),
+ handles_,
+ /* is_first_run */ false).Run();
}
}
}
diff --git a/compiler/optimizing/licm.cc b/compiler/optimizing/licm.cc
index 7a1e06b951..5a0b89c90a 100644
--- a/compiler/optimizing/licm.cc
+++ b/compiler/optimizing/licm.cc
@@ -79,8 +79,15 @@ static void UpdateLoopPhisIn(HEnvironment* environment, HLoopInformation* info)
void LICM::Run() {
DCHECK(side_effects_.HasRun());
+
// Only used during debug.
- ArenaBitVector visited(graph_->GetArena(), graph_->GetBlocks().size(), false, kArenaAllocLICM);
+ ArenaBitVector* visited = nullptr;
+ if (kIsDebugBuild) {
+ visited = new (graph_->GetArena()) ArenaBitVector(graph_->GetArena(),
+ graph_->GetBlocks().size(),
+ false,
+ kArenaAllocLICM);
+ }
// Post order visit to visit inner loops before outer loops.
for (HPostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
@@ -109,10 +116,12 @@ void LICM::Run() {
DCHECK(inner->IsInLoop());
if (inner->GetLoopInformation() != loop_info) {
// Thanks to post order visit, inner loops were already visited.
- DCHECK(visited.IsBitSet(inner->GetBlockId()));
+ DCHECK(visited->IsBitSet(inner->GetBlockId()));
continue;
}
- visited.SetBit(inner->GetBlockId());
+ if (kIsDebugBuild) {
+ visited->SetBit(inner->GetBlockId());
+ }
if (contains_irreducible_loop) {
// We cannot licm in an irreducible loop, or in a natural loop containing an
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index dc5a8fa9cb..7fc39cbadd 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -169,7 +169,7 @@ class ReferenceTypeInfo : ValueObject {
return handle.GetReference() != nullptr;
}
- bool IsValid() const SHARED_REQUIRES(Locks::mutator_lock_) {
+ bool IsValid() const {
return IsValidHandle(type_handle_);
}
@@ -1933,7 +1933,7 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> {
ReferenceTypeInfo GetReferenceTypeInfo() const {
DCHECK_EQ(GetType(), Primitive::kPrimNot);
return ReferenceTypeInfo::CreateUnchecked(reference_type_handle_,
- GetPackedFlag<kFlagReferenceTypeIsExact>());;
+ GetPackedFlag<kFlagReferenceTypeIsExact>());
}
void AddUseAt(HInstruction* user, size_t index) {
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 95f10e0720..961e3b467c 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -23,6 +23,17 @@
namespace art {
+static inline mirror::DexCache* FindDexCacheWithHint(Thread* self,
+ const DexFile& dex_file,
+ Handle<mirror::DexCache> hint_dex_cache)
+ SHARED_REQUIRES(Locks::mutator_lock_) {
+ if (LIKELY(hint_dex_cache->GetDexFile() == &dex_file)) {
+ return hint_dex_cache.Get();
+ } else {
+ return Runtime::Current()->GetClassLinker()->FindDexCache(self, dex_file);
+ }
+}
+
static inline ReferenceTypeInfo::TypeHandle GetRootHandle(StackHandleScopeCollection* handles,
ClassLinker::ClassRoot class_root,
ReferenceTypeInfo::TypeHandle* cache) {
@@ -54,10 +65,12 @@ ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetThrowabl
class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor {
public:
RTPVisitor(HGraph* graph,
+ Handle<mirror::DexCache> hint_dex_cache,
HandleCache* handle_cache,
ArenaVector<HInstruction*>* worklist,
bool is_first_run)
: HGraphDelegateVisitor(graph),
+ hint_dex_cache_(hint_dex_cache),
handle_cache_(handle_cache),
worklist_(worklist),
is_first_run_(is_first_run) {}
@@ -86,16 +99,19 @@ class ReferenceTypePropagation::RTPVisitor : public HGraphDelegateVisitor {
bool is_exact);
private:
+ Handle<mirror::DexCache> hint_dex_cache_;
HandleCache* handle_cache_;
ArenaVector<HInstruction*>* worklist_;
const bool is_first_run_;
};
ReferenceTypePropagation::ReferenceTypePropagation(HGraph* graph,
+ Handle<mirror::DexCache> hint_dex_cache,
StackHandleScopeCollection* handles,
bool is_first_run,
const char* name)
: HOptimization(graph, name),
+ hint_dex_cache_(hint_dex_cache),
handle_cache_(handles),
worklist_(graph->GetArena()->Adapter(kArenaAllocReferenceTypePropagation)),
is_first_run_(is_first_run) {
@@ -130,7 +146,7 @@ void ReferenceTypePropagation::ValidateTypes() {
}
void ReferenceTypePropagation::Visit(HInstruction* instruction) {
- RTPVisitor visitor(graph_, &handle_cache_, &worklist_, is_first_run_);
+ RTPVisitor visitor(graph_, hint_dex_cache_, &handle_cache_, &worklist_, is_first_run_);
instruction->Accept(&visitor);
}
@@ -149,7 +165,7 @@ void ReferenceTypePropagation::Run() {
}
void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
- RTPVisitor visitor(graph_, &handle_cache_, &worklist_, is_first_run_);
+ RTPVisitor visitor(graph_, hint_dex_cache_, &handle_cache_, &worklist_, is_first_run_);
// Handle Phis first as there might be instructions in the same block who depend on them.
for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
VisitPhi(it.Current()->AsPhi());
@@ -358,7 +374,6 @@ void ReferenceTypePropagation::BoundTypeForIfInstanceOf(HBasicBlock* block) {
HLoadClass* load_class = instanceOf->InputAt(1)->AsLoadClass();
ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
{
- ScopedObjectAccess soa(Thread::Current());
if (!class_rti.IsValid()) {
// He have loaded an unresolved class. Don't bother bounding the type.
return;
@@ -412,7 +427,7 @@ void ReferenceTypePropagation::RTPVisitor::SetClassAsTypeInfo(HInstruction* inst
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<2> hs(soa.Self());
Handle<mirror::DexCache> dex_cache(
- hs.NewHandle(cl->FindDexCache(soa.Self(), invoke->GetDexFile(), false)));
+ hs.NewHandle(FindDexCacheWithHint(soa.Self(), invoke->GetDexFile(), hint_dex_cache_)));
// Use a null loader. We should probably use the compiling method's class loader,
// but then we would need to pass it to RTPVisitor just for this debug check. Since
// the method is from the String class, the null loader is good enough.
@@ -446,8 +461,7 @@ void ReferenceTypePropagation::RTPVisitor::UpdateReferenceTypeInfo(HInstruction*
DCHECK_EQ(instr->GetType(), Primitive::kPrimNot);
ScopedObjectAccess soa(Thread::Current());
- mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(
- soa.Self(), dex_file, false);
+ mirror::DexCache* dex_cache = FindDexCacheWithHint(soa.Self(), dex_file, hint_dex_cache_);
// Get type from dex cache assuming it was populated by the verifier.
SetClassAsTypeInfo(instr, dex_cache->GetResolvedType(type_idx), is_exact);
}
@@ -460,24 +474,24 @@ void ReferenceTypePropagation::RTPVisitor::VisitNewArray(HNewArray* instr) {
UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
}
-static mirror::Class* GetClassFromDexCache(Thread* self, const DexFile& dex_file, uint16_t type_idx)
+static mirror::Class* GetClassFromDexCache(Thread* self,
+ const DexFile& dex_file,
+ uint16_t type_idx,
+ Handle<mirror::DexCache> hint_dex_cache)
SHARED_REQUIRES(Locks::mutator_lock_) {
- mirror::DexCache* dex_cache =
- Runtime::Current()->GetClassLinker()->FindDexCache(self, dex_file, /* allow_failure */ true);
- if (dex_cache == nullptr) {
- // Dex cache could not be found. This should only happen during gtests.
- return nullptr;
- }
+ mirror::DexCache* dex_cache = FindDexCacheWithHint(self, dex_file, hint_dex_cache);
// Get type from dex cache assuming it was populated by the verifier.
return dex_cache->GetResolvedType(type_idx);
}
void ReferenceTypePropagation::RTPVisitor::VisitParameterValue(HParameterValue* instr) {
- ScopedObjectAccess soa(Thread::Current());
// We check if the existing type is valid: the inliner may have set it.
if (instr->GetType() == Primitive::kPrimNot && !instr->GetReferenceTypeInfo().IsValid()) {
- mirror::Class* resolved_class =
- GetClassFromDexCache(soa.Self(), instr->GetDexFile(), instr->GetTypeIndex());
+ ScopedObjectAccess soa(Thread::Current());
+ mirror::Class* resolved_class = GetClassFromDexCache(soa.Self(),
+ instr->GetDexFile(),
+ instr->GetTypeIndex(),
+ hint_dex_cache_);
SetClassAsTypeInfo(instr, resolved_class, /* is_exact */ false);
}
}
@@ -488,11 +502,11 @@ void ReferenceTypePropagation::RTPVisitor::UpdateFieldAccessTypeInfo(HInstructio
return;
}
- ScopedObjectAccess soa(Thread::Current());
mirror::Class* klass = nullptr;
// The field index is unknown only during tests.
if (info.GetFieldIndex() != kUnknownFieldIndex) {
+ ScopedObjectAccess soa(Thread::Current());
ClassLinker* cl = Runtime::Current()->GetClassLinker();
ArtField* field = cl->GetResolvedField(info.GetFieldIndex(), info.GetDexCache().Get());
// TODO: There are certain cases where we can't resolve the field.
@@ -532,8 +546,10 @@ void ReferenceTypePropagation::RTPVisitor::VisitUnresolvedStaticFieldGet(
void ReferenceTypePropagation::RTPVisitor::VisitLoadClass(HLoadClass* instr) {
ScopedObjectAccess soa(Thread::Current());
// Get type from dex cache assuming it was populated by the verifier.
- mirror::Class* resolved_class =
- GetClassFromDexCache(soa.Self(), instr->GetDexFile(), instr->GetTypeIndex());
+ mirror::Class* resolved_class = GetClassFromDexCache(soa.Self(),
+ instr->GetDexFile(),
+ instr->GetTypeIndex(),
+ hint_dex_cache_);
if (resolved_class != nullptr) {
instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(
handle_cache_->NewHandle(resolved_class), /* is_exact */ true));
@@ -567,7 +583,6 @@ void ReferenceTypePropagation::RTPVisitor::VisitLoadException(HLoadException* in
}
void ReferenceTypePropagation::RTPVisitor::VisitNullCheck(HNullCheck* instr) {
- ScopedObjectAccess soa(Thread::Current());
ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
if (parent_rti.IsValid()) {
instr->SetReferenceTypeInfo(parent_rti);
@@ -575,10 +590,9 @@ void ReferenceTypePropagation::RTPVisitor::VisitNullCheck(HNullCheck* instr) {
}
void ReferenceTypePropagation::RTPVisitor::VisitBoundType(HBoundType* instr) {
- ScopedObjectAccess soa(Thread::Current());
-
ReferenceTypeInfo class_rti = instr->GetUpperBound();
if (class_rti.IsValid()) {
+ ScopedObjectAccess soa(Thread::Current());
// Narrow the type as much as possible.
HInstruction* obj = instr->InputAt(0);
ReferenceTypeInfo obj_rti = obj->GetReferenceTypeInfo();
@@ -609,8 +623,6 @@ void ReferenceTypePropagation::RTPVisitor::VisitBoundType(HBoundType* instr) {
}
void ReferenceTypePropagation::RTPVisitor::VisitCheckCast(HCheckCast* check_cast) {
- ScopedObjectAccess soa(Thread::Current());
-
HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
HBoundType* bound_type = check_cast->GetNext()->AsBoundType();
@@ -645,7 +657,6 @@ void ReferenceTypePropagation::VisitPhi(HPhi* phi) {
// point the interpreter jumps to that loop header.
return;
}
- ScopedObjectAccess soa(Thread::Current());
// Set the initial type for the phi. Use the non back edge input for reaching
// a fixed point faster.
HInstruction* first_input = phi->InputAt(0);
@@ -760,7 +771,8 @@ void ReferenceTypePropagation::RTPVisitor::VisitInvoke(HInvoke* instr) {
ScopedObjectAccess soa(Thread::Current());
ClassLinker* cl = Runtime::Current()->GetClassLinker();
- mirror::DexCache* dex_cache = cl->FindDexCache(soa.Self(), instr->GetDexFile());
+ mirror::DexCache* dex_cache =
+ FindDexCacheWithHint(soa.Self(), instr->GetDexFile(), hint_dex_cache_);
size_t pointer_size = cl->GetImagePointerSize();
ArtMethod* method = dex_cache->GetResolvedMethod(instr->GetDexMethodIndex(), pointer_size);
mirror::Class* klass = (method == nullptr) ? nullptr : method->GetReturnType(false, pointer_size);
diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h
index 028a6fc514..7362544e93 100644
--- a/compiler/optimizing/reference_type_propagation.h
+++ b/compiler/optimizing/reference_type_propagation.h
@@ -32,6 +32,7 @@ namespace art {
class ReferenceTypePropagation : public HOptimization {
public:
ReferenceTypePropagation(HGraph* graph,
+ Handle<mirror::DexCache> hint_dex_cache,
StackHandleScopeCollection* handles,
bool is_first_run,
const char* name = kReferenceTypePropagationPassName);
@@ -90,6 +91,10 @@ class ReferenceTypePropagation : public HOptimization {
void ValidateTypes();
+ // Note: hint_dex_cache_ is usually, but not necessarily, the dex cache associated with
+ // graph_->GetDexFile(). Since we may look up also in other dex files, it's used only
+ // as a hint, to reduce the number of calls to the costly ClassLinker::FindDexCache().
+ Handle<mirror::DexCache> hint_dex_cache_;
HandleCache handle_cache_;
ArenaVector<HInstruction*> worklist_;
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index eeadbeb0d1..e43e33f0c0 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -506,7 +506,7 @@ GraphAnalysisResult SsaBuilder::BuildSsa() {
// 4) Compute type of reference type instructions. The pass assumes that
// NullConstant has been fixed up.
- ReferenceTypePropagation(graph_, handles_, /* is_first_run */ true).Run();
+ ReferenceTypePropagation(graph_, dex_cache_, handles_, /* is_first_run */ true).Run();
// 5) HInstructionBuilder duplicated ArrayGet instructions with ambiguous type
// (int/float or long/double) and marked ArraySets with ambiguous input type.
diff --git a/compiler/optimizing/ssa_builder.h b/compiler/optimizing/ssa_builder.h
index c37c28c801..d7360adef8 100644
--- a/compiler/optimizing/ssa_builder.h
+++ b/compiler/optimizing/ssa_builder.h
@@ -47,8 +47,11 @@ namespace art {
*/
class SsaBuilder : public ValueObject {
public:
- SsaBuilder(HGraph* graph, StackHandleScopeCollection* handles)
+ SsaBuilder(HGraph* graph,
+ Handle<mirror::DexCache> dex_cache,
+ StackHandleScopeCollection* handles)
: graph_(graph),
+ dex_cache_(dex_cache),
handles_(handles),
agets_fixed_(false),
ambiguous_agets_(graph->GetArena()->Adapter(kArenaAllocGraphBuilder)),
@@ -112,6 +115,7 @@ class SsaBuilder : public ValueObject {
void RemoveRedundantUninitializedStrings();
HGraph* graph_;
+ Handle<mirror::DexCache> dex_cache_;
StackHandleScopeCollection* const handles_;
// True if types of ambiguous ArrayGets have been resolved.
diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h
index 97f2aeeb1e..719feec468 100644
--- a/compiler/optimizing/ssa_liveness_analysis.h
+++ b/compiler/optimizing/ssa_liveness_analysis.h
@@ -969,6 +969,38 @@ class LiveInterval : public ArenaObject<kArenaAllocSsaLiveness> {
return false;
}
+ bool IsLinearOrderWellFormed(const HGraph& graph) {
+ for (HBasicBlock* header : graph.GetBlocks()) {
+ if (!header->IsLoopHeader()) {
+ continue;
+ }
+
+ HLoopInformation* loop = header->GetLoopInformation();
+ size_t num_blocks = loop->GetBlocks().NumSetBits();
+ size_t found_blocks = 0u;
+
+ for (HLinearOrderIterator it(graph); !it.Done(); it.Advance()) {
+ HBasicBlock* current = it.Current();
+ if (loop->Contains(*current)) {
+ found_blocks++;
+ if (found_blocks == 1u && current != header) {
+ // First block is not the header.
+ return false;
+ } else if (found_blocks == num_blocks && !loop->IsBackEdge(*current)) {
+ // Last block is not a back edge.
+ return false;
+ }
+ } else if (found_blocks != 0u && found_blocks != num_blocks) {
+ // Blocks are not adjacent.
+ return false;
+ }
+ }
+ DCHECK_EQ(found_blocks, num_blocks);
+ }
+
+ return true;
+ }
+
void AddBackEdgeUses(const HBasicBlock& block_at_use) {
DCHECK(block_at_use.IsInLoop());
// Add synthesized uses at the back edge of loops to help the register allocator.
@@ -995,12 +1027,30 @@ class LiveInterval : public ArenaObject<kArenaAllocSsaLiveness> {
if ((first_use_ != nullptr) && (first_use_->GetPosition() <= back_edge_use_position)) {
// There was a use already seen in this loop. Therefore the previous call to `AddUse`
// already inserted the backedge use. We can stop going outward.
- DCHECK(HasSynthesizeUseAt(back_edge_use_position));
+ if (kIsDebugBuild) {
+ if (!HasSynthesizeUseAt(back_edge_use_position)) {
+ // There exists a use prior to `back_edge_use_position` but there is
+ // no synthesized use at the back edge. This can happen in the presence
+ // of irreducible loops, when blocks of the loop are not adjacent in
+ // linear order, i.e. when there is an out-of-loop block between
+ // `block_at_use` and `back_edge_position` that uses this interval.
+ DCHECK(block_at_use.GetGraph()->HasIrreducibleLoops());
+ DCHECK(!IsLinearOrderWellFormed(*block_at_use.GetGraph()));
+ }
+ }
break;
}
- DCHECK(last_in_new_list == nullptr
- || back_edge_use_position > last_in_new_list->GetPosition());
+ if (last_in_new_list != nullptr &&
+ back_edge_use_position <= last_in_new_list->GetPosition()) {
+ // Loops are not properly nested in the linear order, i.e. the back edge
+ // of an outer loop preceeds blocks of an inner loop. This can happen
+ // in the presence of irreducible loops.
+ DCHECK(block_at_use.GetGraph()->HasIrreducibleLoops());
+ DCHECK(!IsLinearOrderWellFormed(*block_at_use.GetGraph()));
+ // We must bail out, otherwise we would generate an unsorted use list.
+ break;
+ }
UsePosition* new_use = new (allocator_) UsePosition(
/* user */ nullptr,
diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h
index 4ea85a2c18..f70fe04ed1 100644
--- a/compiler/utils/assembler.h
+++ b/compiler/utils/assembler.h
@@ -306,8 +306,10 @@ class DebugFrameOpCodeWriterForAssembler FINAL
// Override the last delayed PC. The new PC can be out of order.
void OverrideDelayedPC(size_t pc) {
DCHECK(delay_emitting_advance_pc_);
- DCHECK(!delayed_advance_pcs_.empty());
- delayed_advance_pcs_.back().pc = pc;
+ if (enabled_) {
+ DCHECK(!delayed_advance_pcs_.empty());
+ delayed_advance_pcs_.back().pc = pc;
+ }
}
// Return the number of delayed advance PC entries.
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 4ba90c12ce..558e4435f0 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -153,6 +153,7 @@ Jit* Jit::Create(JitOptions* options, std::string* error_msg) {
jit->hot_method_threshold_ = options->GetCompileThreshold();
jit->warm_method_threshold_ = options->GetWarmupThreshold();
jit->osr_method_threshold_ = options->GetOsrThreshold();
+ jit->priority_thread_weight_ = options->GetPriorityThreadWeight();
jit->CreateThreadPool();
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 78e372ad02..3f95772b4f 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -492,10 +492,21 @@ bool OatFileAssistant::GivenOatFileIsOutOfDate(const OatFile& file) {
const ImageInfo* image_info = GetImageInfo();
if (image_info == nullptr) {
VLOG(oat) << "No image for oat image checksum to match against.";
- return true;
- }
- if (file.GetOatHeader().GetImageFileLocationOatChecksum() != GetCombinedImageChecksum()) {
+ if (HasOriginalDexFiles()) {
+ return true;
+ }
+
+ // If there is no original dex file to fall back to, grudgingly accept
+ // the oat file. This could technically lead to crashes, but there's no
+ // way we could find a better oat file to use for this dex location,
+ // and it's better than being stuck in a boot loop with no way out.
+ // The problem will hopefully resolve itself the next time the runtime
+ // starts up.
+ LOG(WARNING) << "Dex location " << dex_location_ << " does not seem to include dex file. "
+ << "Allow oat file use. This is potentially dangerous.";
+ } else if (file.GetOatHeader().GetImageFileLocationOatChecksum()
+ != GetCombinedImageChecksum()) {
VLOG(oat) << "Oat image checksum does not match image checksum.";
return true;
}
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 94f6345bb0..3846605400 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -364,7 +364,7 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
// However, if the app was part of /system and preopted, there is no original dex file
// available. In that case grudgingly accept the oat file.
- if (!DexFile::MaybeDex(dex_location)) {
+ if (!oat_file_assistant.HasOriginalDexFiles()) {
accept_oat_file = true;
LOG(WARNING) << "Dex location " << dex_location << " does not seem to include dex file. "
<< "Allow oat file use. This is potentially dangerous.";
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index d5319fdb0c..a0987b5161 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -4577,8 +4577,17 @@ ArtField* MethodVerifier::GetInstanceField(const RegType& obj_type, int field_id
// Trying to access C1.field1 using reference of type C2, which is neither C1 or a sub-class
// of C1. For resolution to occur the declared class of the field must be compatible with
// obj_type, we've discovered this wasn't so, so report the field didn't exist.
- Fail(VERIFY_ERROR_NO_FIELD) << "cannot access instance field " << PrettyField(field)
- << " from object of type " << obj_type;
+ VerifyError type;
+ bool is_aot = Runtime::Current()->IsAotCompiler();
+ if (is_aot && (field_klass.IsUnresolvedTypes() || obj_type.IsUnresolvedTypes())) {
+ // Compiler & unresolved types involved, retry at runtime.
+ type = VerifyError::VERIFY_ERROR_NO_CLASS;
+ } else {
+ // Classes known, or at compile time. This is a hard failure.
+ type = VerifyError::VERIFY_ERROR_BAD_CLASS_HARD;
+ }
+ Fail(type) << "cannot access instance field " << PrettyField(field)
+ << " from object of type " << obj_type;
return nullptr;
} else {
return field;
diff --git a/test/147-stripped-dex-fallback/expected.txt b/test/147-stripped-dex-fallback/expected.txt
new file mode 100644
index 0000000000..af5626b4a1
--- /dev/null
+++ b/test/147-stripped-dex-fallback/expected.txt
@@ -0,0 +1 @@
+Hello, world!
diff --git a/test/147-stripped-dex-fallback/info.txt b/test/147-stripped-dex-fallback/info.txt
new file mode 100644
index 0000000000..72a2ca8d4c
--- /dev/null
+++ b/test/147-stripped-dex-fallback/info.txt
@@ -0,0 +1,2 @@
+Verify that we fallback to running out of dex code in the oat file if there is
+no image and the original dex code has been stripped.
diff --git a/test/147-stripped-dex-fallback/run b/test/147-stripped-dex-fallback/run
new file mode 100755
index 0000000000..e594010b9e
--- /dev/null
+++ b/test/147-stripped-dex-fallback/run
@@ -0,0 +1,24 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 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.
+
+# ensure flags includes prebuild.
+flags="$@"
+if [[ "${flags}" == *--no-prebuild* ]] ; then
+ echo "Test 147-stripped-dex-fallback is not intended to run in no-prebuild mode."
+ exit 1
+fi
+
+${RUN} ${flags} --strip-dex --no-dex2oat
diff --git a/test/147-stripped-dex-fallback/src/Main.java b/test/147-stripped-dex-fallback/src/Main.java
new file mode 100644
index 0000000000..1ef6289559
--- /dev/null
+++ b/test/147-stripped-dex-fallback/src/Main.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2011 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) {
+ System.out.println("Hello, world!");
+ }
+}
diff --git a/test/594-checker-irreducible-linorder/expected.txt b/test/594-checker-irreducible-linorder/expected.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/594-checker-irreducible-linorder/expected.txt
diff --git a/test/594-checker-irreducible-linorder/info.txt b/test/594-checker-irreducible-linorder/info.txt
new file mode 100644
index 0000000000..a1783f8ec1
--- /dev/null
+++ b/test/594-checker-irreducible-linorder/info.txt
@@ -0,0 +1,2 @@
+Regression test for a failing DCHECK in SSA liveness analysis in the presence
+of irreducible loops.
diff --git a/test/594-checker-irreducible-linorder/smali/IrreducibleLoop.smali b/test/594-checker-irreducible-linorder/smali/IrreducibleLoop.smali
new file mode 100644
index 0000000000..8e01084841
--- /dev/null
+++ b/test/594-checker-irreducible-linorder/smali/IrreducibleLoop.smali
@@ -0,0 +1,64 @@
+# Copyright (C) 2016 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 LIrreducibleLoop;
+.super Ljava/lang/Object;
+
+# Test case where liveness analysis produces linear order where loop blocks are
+# not adjacent.
+
+## CHECK-START: int IrreducibleLoop.liveness(boolean, boolean, boolean, int) builder (after)
+## CHECK-DAG: Add loop:none
+## CHECK-DAG: Mul loop:<<Loop:B\d+>>
+## CHECK-DAG: Not loop:<<Loop>>
+
+## CHECK-START: int IrreducibleLoop.liveness(boolean, boolean, boolean, int) liveness (after)
+## CHECK-DAG: Add liveness:<<LPreEntry:\d+>>
+## CHECK-DAG: Mul liveness:<<LHeader:\d+>>
+## CHECK-DAG: Not liveness:<<LBackEdge:\d+>>
+## CHECK-EVAL: (<<LHeader>> < <<LPreEntry>>) and (<<LPreEntry>> < <<LBackEdge>>)
+
+.method public static liveness(ZZZI)I
+ .registers 10
+ const/16 v0, 42
+
+ if-eqz p0, :header
+
+ :pre_entry
+ add-int/2addr p3, p3
+ invoke-static {v0}, Ljava/lang/System;->exit(I)V
+ goto :body1
+
+ :header
+ mul-int/2addr p3, p3
+ if-eqz p1, :body2
+
+ :body1
+ goto :body_merge
+
+ :body2
+ invoke-static {v0}, Ljava/lang/System;->exit(I)V
+ goto :body_merge
+
+ :body_merge
+ if-eqz p2, :exit
+
+ :back_edge
+ not-int p3, p3
+ goto :header
+
+ :exit
+ return p3
+
+.end method
diff --git a/test/594-checker-irreducible-linorder/src/Main.java b/test/594-checker-irreducible-linorder/src/Main.java
new file mode 100644
index 0000000000..38b2ab4384
--- /dev/null
+++ b/test/594-checker-irreducible-linorder/src/Main.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2016 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 {
+ // Workaround for b/18051191.
+ class InnerClass {}
+
+ public static void main(String[] args) {
+ // Nothing to run. This regression test merely makes sure the smali test
+ // case successfully compiles.
+ }
+}
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
index c2a9a31aeb..11150c296d 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -66,4 +66,5 @@ b/27799205 (3)
b/27799205 (4)
b/27799205 (5)
b/27799205 (6)
+b/28187158
Done!
diff --git a/test/800-smali/smali/b_28187158.smali b/test/800-smali/smali/b_28187158.smali
new file mode 100644
index 0000000000..7dd2022483
--- /dev/null
+++ b/test/800-smali/smali/b_28187158.smali
@@ -0,0 +1,11 @@
+.class public LB28187158;
+
+# Regression test for iget with wrong classes.
+
+.super Ljava/lang/Object;
+
+.method public static run(Ljava/lang/Integer;)V
+ .registers 2
+ iget v0, p0, Ljava/lang/String;->length:I
+.end method
+
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index 2001cb4abb..c883b7f0f5 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -174,6 +174,8 @@ public class Main {
testCases.add(new TestCase("b/27799205 (5)", "B27799205Helper", "run5", null,
new VerifyError(), null));
testCases.add(new TestCase("b/27799205 (6)", "B27799205Helper", "run6", null, null, null));
+ testCases.add(new TestCase("b/28187158", "B28187158", "run", new Object[] { null} ,
+ new VerifyError(), null));
}
public void runTests() {
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 1edc5993eb..b750524baa 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -235,8 +235,11 @@ ifdef dist_goal
$(IMAGE_TYPES), $(PICTEST_TYPES), $(DEBUGGABLE_TYPES), $(TEST_ART_TIMING_SENSITIVE_RUN_TESTS), $(ALL_ADDRESS_SIZES))
endif
+# 147-stripped-dex-fallback isn't supported on device because --strip-dex
+# requires the zip command.
# 569-checker-pattern-replacement tests behaviour present only on host.
TEST_ART_BROKEN_TARGET_TESTS := \
+ 147-stripped-dex-fallback \
569-checker-pattern-replacement
ifneq (,$(filter target,$(TARGET_TYPES)))
@@ -287,6 +290,7 @@ TEST_ART_BROKEN_PREBUILD_RUN_TESTS :=
# 529 and 555: b/27784033
TEST_ART_BROKEN_NO_PREBUILD_TESTS := \
117-nopatchoat \
+ 147-stripped-dex-fallback \
554-jit-profile-file \
529-checker-unresolved \
555-checker-regression-x86const
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 28a99de099..d61fc8f8fc 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -37,6 +37,7 @@ PATCHOAT=""
PREBUILD="y"
QUIET="n"
RELOCATE="y"
+STRIP_DEX="n"
SECONDARY_DEX=""
TIME_OUT="gdb" # "n" (disabled), "timeout" (use timeout), "gdb" (use gdb)
# Value in seconds
@@ -118,6 +119,9 @@ while true; do
elif [ "x$1" = "x--prebuild" ]; then
PREBUILD="y"
shift
+ elif [ "x$1" = "x--strip-dex" ]; then
+ STRIP_DEX="y"
+ shift
elif [ "x$1" = "x--host" ]; then
HOST="y"
ANDROID_ROOT="$ANDROID_HOST_OUT"
@@ -380,6 +384,7 @@ fi
dex2oat_cmdline="true"
mkdir_cmdline="mkdir -p ${DEX_LOCATION}/dalvik-cache/$ISA"
+strip_cmdline="true"
# Pick a base that will force the app image to get relocated.
app_image="--base=0x4000 --app-image-file=$DEX_LOCATION/oat/$ISA/$TEST_NAME.art"
@@ -409,6 +414,10 @@ if [ "$PREBUILD" = "y" ]; then
fi
fi
+if [ "$STRIP_DEX" = "y" ]; then
+ strip_cmdline="zip --quiet --delete $DEX_LOCATION/$TEST_NAME.jar classes.dex"
+fi
+
DALVIKVM_ISA_FEATURES_ARGS=""
if [ "x$INSTRUCTION_SET_FEATURES" != "x" ] ; then
DALVIKVM_ISA_FEATURES_ARGS="-Xcompiler-option --instruction-set-features=${INSTRUCTION_SET_FEATURES}"
@@ -478,6 +487,7 @@ if [ "$HOST" = "n" ]; then
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH && \
export PATH=$ANDROID_ROOT/bin:$PATH && \
$dex2oat_cmdline && \
+ $strip_cmdline && \
$dalvikvm_cmdline"
cmdfile=$(tempfile -p "cmd-" -s "-$TEST_NAME")
@@ -548,13 +558,7 @@ else
fi
if [ "$DEV_MODE" = "y" ]; then
- if [ "$PREBUILD" = "y" ]; then
- echo "$mkdir_cmdline && $dex2oat_cmdline && $cmdline"
- elif [ "$RELOCATE" = "y" ]; then
- echo "$mkdir_cmdline && $cmdline"
- else
- echo $cmdline
- fi
+ echo "$mkdir_cmdline && $dex2oat_cmdline && $strip_cmdline && $cmdline"
fi
cd $ANDROID_BUILD_TOP
@@ -562,6 +566,7 @@ else
rm -rf ${DEX_LOCATION}/dalvik-cache/
$mkdir_cmdline || exit 1
$dex2oat_cmdline || { echo "Dex2oat failed." >&2 ; exit 2; }
+ $strip_cmdline || { echo "Strip failed." >&2 ; exit 3; }
# For running, we must turn off logging when dex2oat or patchoat are missing. Otherwise we use
# the same defaults as for prebuilt: everything when --dev, otherwise errors and above only.
diff --git a/test/run-test b/test/run-test
index 013fc63e83..fc57d0914f 100755
--- a/test/run-test
+++ b/test/run-test
@@ -190,6 +190,9 @@ while true; do
run_args="${run_args} --prebuild"
prebuild_mode="yes"
shift;
+ elif [ "x$1" = "x--strip-dex" ]; then
+ run_args="${run_args} --strip-dex"
+ shift;
elif [ "x$1" = "x--debuggable" ]; then
run_args="${run_args} -Xcompiler-option --debuggable"
debuggable="yes"
@@ -449,7 +452,7 @@ if [ "$runtime" = "dalvik" ]; then
if [ "$target_mode" = "no" ]; then
framework="${ANDROID_PRODUCT_OUT}/system/framework"
bpath="${framework}/core-libart.jar:${framework}/core-oj.jar:${framework}/conscrypt.jar:${framework}/okhttp.jar:${framework}/bouncycastle.jar:${framework}/ext.jar"
- run_args="${run_args} --boot -Xbootclasspath:${bpath}"
+ run_args="${run_args} --boot --runtime-option -Xbootclasspath:${bpath}"
else
true # defaults to using target BOOTCLASSPATH
fi
@@ -571,6 +574,7 @@ if [ "$usage" = "yes" ]; then
echo " --prebuild Run dex2oat on the files before starting test. (default)"
echo " --no-prebuild Do not run dex2oat on the files before starting"
echo " the test."
+ echo " --strip-dex Strip the dex files before starting test."
echo " --relocate Force the use of relocating in the test, making"
echo " the image and oat files be relocated to a random"
echo " address before running. (default)"