summaryrefslogtreecommitdiff
path: root/compiler/optimizing
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing')
-rw-r--r--compiler/optimizing/inliner.cc3
-rw-r--r--compiler/optimizing/nodes.cc20
-rw-r--r--compiler/optimizing/reference_type_propagation.cc15
-rw-r--r--compiler/optimizing/reference_type_propagation.h2
-rw-r--r--compiler/optimizing/reference_type_propagation_test.cc190
-rw-r--r--compiler/optimizing/ssa_liveness_analysis.cc2
-rw-r--r--compiler/optimizing/ssa_liveness_analysis.h2
7 files changed, 225 insertions, 9 deletions
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 77e0cbc600..ba6ae6ffb1 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -1303,11 +1303,12 @@ void HInliner::FixUpReturnReferenceType(HInvoke* invoke_instruction,
DCHECK(return_replacement->IsPhi());
size_t pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
mirror::Class* cls = resolved_method->GetReturnType(false /* resolve */, pointer_size);
- if (cls != nullptr) {
+ if (cls != nullptr && !cls->IsErroneous()) {
ReferenceTypeInfo::TypeHandle return_handle = handles_->NewHandle(cls);
return_replacement->SetReferenceTypeInfo(ReferenceTypeInfo::Create(
return_handle, return_handle->CannotBeAssignedFromOtherTypes() /* is_exact */));
} else {
+ // Return inexact object type on failures.
return_replacement->SetReferenceTypeInfo(graph_->GetInexactObjectRti());
}
}
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 53a10f3128..d259c21108 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -618,7 +618,24 @@ void HLoopInformation::Populate() {
}
}
- if (is_irreducible_loop || graph->IsCompilingOsr()) {
+ if (!is_irreducible_loop && graph->IsCompilingOsr()) {
+ // When compiling in OSR mode, all loops in the compiled method may be entered
+ // from the interpreter. We treat this OSR entry point just like an extra entry
+ // to an irreducible loop, so we need to mark the method's loops as irreducible.
+ // This does not apply to inlined loops which do not act as OSR entry points.
+ if (suspend_check_ == nullptr) {
+ // Just building the graph in OSR mode, this loop is not inlined. We never build an
+ // inner graph in OSR mode as we can do OSR transition only from the outer method.
+ is_irreducible_loop = true;
+ } else {
+ // Look at the suspend check's environment to determine if the loop was inlined.
+ DCHECK(suspend_check_->HasEnvironment());
+ if (!suspend_check_->GetEnvironment()->IsFromInlinedInvoke()) {
+ is_irreducible_loop = true;
+ }
+ }
+ }
+ if (is_irreducible_loop) {
irreducible_ = true;
graph->SetHasIrreducibleLoops(true);
}
@@ -2192,6 +2209,7 @@ ReferenceTypeInfo ReferenceTypeInfo::Create(TypeHandle type_handle, bool is_exac
if (kIsDebugBuild) {
ScopedObjectAccess soa(Thread::Current());
DCHECK(IsValidHandle(type_handle));
+ DCHECK(!type_handle->IsErroneous());
if (!is_exact) {
DCHECK(!type_handle->CannotBeAssignedFromOtherTypes())
<< "Callers of ReferenceTypeInfo::Create should ensure is_exact is properly computed";
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index cd4391d2db..c46d6077a2 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -439,9 +439,14 @@ void ReferenceTypePropagation::RTPVisitor::SetClassAsTypeInfo(HInstruction* inst
ReferenceTypeInfo::Create(handle_cache_->GetStringClassHandle(), /* is_exact */ true));
} else if (klass != nullptr) {
ScopedObjectAccess soa(Thread::Current());
- ReferenceTypeInfo::TypeHandle handle = handle_cache_->NewHandle(klass);
- is_exact = is_exact || handle->CannotBeAssignedFromOtherTypes();
- instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, is_exact));
+ if (klass->IsErroneous()) {
+ // Set inexact object type for erroneous types.
+ instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
+ } else {
+ ReferenceTypeInfo::TypeHandle handle = handle_cache_->NewHandle(klass);
+ is_exact = is_exact || handle->CannotBeAssignedFromOtherTypes();
+ instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, is_exact));
+ }
} else {
instr->SetReferenceTypeInfo(instr->GetBlock()->GetGraph()->GetInexactObjectRti());
}
@@ -542,7 +547,7 @@ void ReferenceTypePropagation::RTPVisitor::VisitLoadClass(HLoadClass* instr) {
// Get type from dex cache assuming it was populated by the verifier.
mirror::Class* resolved_class =
GetClassFromDexCache(soa.Self(), instr->GetDexFile(), instr->GetTypeIndex());
- if (resolved_class != nullptr) {
+ if (resolved_class != nullptr && !resolved_class->IsErroneous()) {
instr->SetLoadedClassRTI(ReferenceTypeInfo::Create(
handle_cache_->NewHandle(resolved_class), /* is_exact */ true));
}
@@ -726,7 +731,7 @@ void ReferenceTypePropagation::UpdateArrayGet(HArrayGet* instr, HandleCache* han
}
Handle<mirror::Class> handle = parent_rti.GetTypeHandle();
- if (handle->IsObjectArrayClass()) {
+ if (handle->IsObjectArrayClass() && !handle->GetComponentType()->IsErroneous()) {
ReferenceTypeInfo::TypeHandle component_handle =
handle_cache->NewHandle(handle->GetComponentType());
bool is_exact = component_handle->CannotBeAssignedFromOtherTypes();
diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h
index 028a6fc514..01b5781830 100644
--- a/compiler/optimizing/reference_type_propagation.h
+++ b/compiler/optimizing/reference_type_propagation.h
@@ -99,6 +99,8 @@ class ReferenceTypePropagation : public HOptimization {
static constexpr size_t kDefaultWorklistSize = 8;
+ friend class ReferenceTypePropagationTest;
+
DISALLOW_COPY_AND_ASSIGN(ReferenceTypePropagation);
};
diff --git a/compiler/optimizing/reference_type_propagation_test.cc b/compiler/optimizing/reference_type_propagation_test.cc
new file mode 100644
index 0000000000..99d5f822c1
--- /dev/null
+++ b/compiler/optimizing/reference_type_propagation_test.cc
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+#include "base/arena_allocator.h"
+#include "builder.h"
+#include "nodes.h"
+#include "object_lock.h"
+#include "optimizing_unit_test.h"
+#include "reference_type_propagation.h"
+
+namespace art {
+
+/**
+ * Fixture class for unit testing the ReferenceTypePropagation phase. Used to verify the
+ * functionality of methods and situations that are hard to set up with checker tests.
+ */
+class ReferenceTypePropagationTest : public CommonCompilerTest {
+ public:
+ ReferenceTypePropagationTest() : pool_(), allocator_(&pool_) {
+ graph_ = CreateGraph(&allocator_);
+ }
+
+ ~ReferenceTypePropagationTest() { }
+
+ void SetupPropagation(StackHandleScopeCollection* handles) {
+ graph_->InitializeInexactObjectRTI(handles);
+ propagation_ = new (&allocator_) ReferenceTypePropagation(graph_, handles, true, "test_prop");
+ }
+
+ // Relay method to merge type in reference type propagation.
+ ReferenceTypeInfo MergeTypes(const ReferenceTypeInfo& a,
+ const ReferenceTypeInfo& b) SHARED_REQUIRES(Locks::mutator_lock_) {
+ return propagation_->MergeTypes(a, b);
+ }
+
+ // Helper method to construct an invalid type.
+ ReferenceTypeInfo InvalidType() {
+ return ReferenceTypeInfo::CreateInvalid();
+ }
+
+ // Helper method to construct the Object type.
+ ReferenceTypeInfo ObjectType(bool is_exact = true) SHARED_REQUIRES(Locks::mutator_lock_) {
+ return ReferenceTypeInfo::Create(propagation_->handle_cache_.GetObjectClassHandle(), is_exact);
+ }
+
+ // Helper method to construct the String type.
+ ReferenceTypeInfo StringType(bool is_exact = true) SHARED_REQUIRES(Locks::mutator_lock_) {
+ return ReferenceTypeInfo::Create(propagation_->handle_cache_.GetStringClassHandle(), is_exact);
+ }
+
+ // Helper method to construct the Throwable type.
+ ReferenceTypeInfo ThrowableType(bool is_exact = true) SHARED_REQUIRES(Locks::mutator_lock_) {
+ return ReferenceTypeInfo::Create(propagation_->handle_cache_.GetThrowableClassHandle(), is_exact);
+ }
+
+ // Helper method to provide access to Throwable handle.
+ Handle<mirror::Class> GetThrowableHandle() {
+ return propagation_->handle_cache_.GetThrowableClassHandle();
+ }
+
+ // General building fields.
+ ArenaPool pool_;
+ ArenaAllocator allocator_;
+ HGraph* graph_;
+
+ ReferenceTypePropagation* propagation_;
+};
+
+//
+// The actual ReferenceTypePropgation unit tests.
+//
+
+TEST_F(ReferenceTypePropagationTest, ProperSetup) {
+ ScopedObjectAccess soa(Thread::Current());
+ StackHandleScopeCollection handles(soa.Self());
+ SetupPropagation(&handles);
+
+ EXPECT_TRUE(propagation_ != nullptr);
+ EXPECT_TRUE(graph_->GetInexactObjectRti().IsEqual(ObjectType(false)));
+}
+
+TEST_F(ReferenceTypePropagationTest, MergeInvalidTypes) {
+ ScopedObjectAccess soa(Thread::Current());
+ StackHandleScopeCollection handles(soa.Self());
+ SetupPropagation(&handles);
+
+ // Two invalid types.
+ ReferenceTypeInfo t1(MergeTypes(InvalidType(), InvalidType()));
+ EXPECT_FALSE(t1.IsValid());
+ EXPECT_FALSE(t1.IsExact());
+ EXPECT_TRUE(t1.IsEqual(InvalidType()));
+
+ // Valid type on right.
+ ReferenceTypeInfo t2(MergeTypes(InvalidType(), ObjectType()));
+ EXPECT_TRUE(t2.IsValid());
+ EXPECT_TRUE(t2.IsExact());
+ EXPECT_TRUE(t2.IsEqual(ObjectType()));
+ ReferenceTypeInfo t3(MergeTypes(InvalidType(), StringType()));
+ EXPECT_TRUE(t3.IsValid());
+ EXPECT_TRUE(t3.IsExact());
+ EXPECT_TRUE(t3.IsEqual(StringType()));
+
+ // Valid type on left.
+ ReferenceTypeInfo t4(MergeTypes(ObjectType(), InvalidType()));
+ EXPECT_TRUE(t4.IsValid());
+ EXPECT_TRUE(t4.IsExact());
+ EXPECT_TRUE(t4.IsEqual(ObjectType()));
+ ReferenceTypeInfo t5(MergeTypes(StringType(), InvalidType()));
+ EXPECT_TRUE(t5.IsValid());
+ EXPECT_TRUE(t5.IsExact());
+ EXPECT_TRUE(t5.IsEqual(StringType()));
+}
+
+TEST_F(ReferenceTypePropagationTest, CreateErroneousType) {
+ ScopedObjectAccess soa(Thread::Current());
+ StackHandleScopeCollection handles(soa.Self());
+ SetupPropagation(&handles);
+
+ // Some trickery to make the runtime think something went wrong with loading
+ // the throwable class, making this an erroneous type from here on.
+ soa.Self()->SetException(Thread::GetDeoptimizationException());
+ Handle<mirror::Class> klass = GetThrowableHandle();
+ ObjectLock<mirror::Class> lock(soa.Self(), klass);
+ mirror::Class::SetStatus(klass, mirror::Class::kStatusError, soa.Self());
+ soa.Self()->ClearException();
+ ASSERT_TRUE(klass->IsErroneous());
+
+ // Trying to get an erroneous type crashes (debug mode only).
+ if (kIsDebugBuild) {
+ EXPECT_DEATH(ThrowableType(), "Check failed: !type_handle->IsErroneous()");
+ }
+}
+
+TEST_F(ReferenceTypePropagationTest, MergeValidTypes) {
+ ScopedObjectAccess soa(Thread::Current());
+ StackHandleScopeCollection handles(soa.Self());
+ SetupPropagation(&handles);
+
+ // Same types.
+ ReferenceTypeInfo t1(MergeTypes(ObjectType(), ObjectType()));
+ EXPECT_TRUE(t1.IsValid());
+ EXPECT_TRUE(t1.IsExact());
+ EXPECT_TRUE(t1.IsEqual(ObjectType()));
+ ReferenceTypeInfo t2(MergeTypes(StringType(), StringType()));
+ EXPECT_TRUE(t2.IsValid());
+ EXPECT_TRUE(t2.IsExact());
+ EXPECT_TRUE(t2.IsEqual(StringType()));
+
+ // Left is super class of right.
+ ReferenceTypeInfo t3(MergeTypes(ObjectType(), StringType()));
+ EXPECT_TRUE(t3.IsValid());
+ EXPECT_FALSE(t3.IsExact());
+ EXPECT_TRUE(t3.IsEqual(ObjectType(false)));
+
+ // Right is super class of left.
+ ReferenceTypeInfo t4(MergeTypes(StringType(), ObjectType()));
+ EXPECT_TRUE(t4.IsValid());
+ EXPECT_FALSE(t4.IsExact());
+ EXPECT_TRUE(t4.IsEqual(ObjectType(false)));
+
+ // Same types, but one or both are inexact.
+ ReferenceTypeInfo t5(MergeTypes(ObjectType(false), ObjectType()));
+ EXPECT_TRUE(t5.IsValid());
+ EXPECT_FALSE(t5.IsExact());
+ EXPECT_TRUE(t5.IsEqual(ObjectType(false)));
+ ReferenceTypeInfo t6(MergeTypes(ObjectType(), ObjectType(false)));
+ EXPECT_TRUE(t6.IsValid());
+ EXPECT_FALSE(t6.IsExact());
+ EXPECT_TRUE(t6.IsEqual(ObjectType(false)));
+ ReferenceTypeInfo t7(MergeTypes(ObjectType(false), ObjectType(false)));
+ EXPECT_TRUE(t7.IsValid());
+ EXPECT_FALSE(t7.IsExact());
+ EXPECT_TRUE(t7.IsEqual(ObjectType(false)));
+}
+
+} // namespace art
+
diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc
index d33eca7da3..5534aeac29 100644
--- a/compiler/optimizing/ssa_liveness_analysis.cc
+++ b/compiler/optimizing/ssa_liveness_analysis.cc
@@ -316,7 +316,7 @@ void SsaLivenessAnalysis::ComputeLiveRanges() {
for (uint32_t idx : live_in->Indexes()) {
HInstruction* instruction = GetInstructionFromSsaIndex(idx);
DCHECK(instruction->GetBlock()->IsEntryBlock()) << instruction->DebugName();
- DCHECK(!instruction->IsParameterValue()) << instruction->DebugName();
+ DCHECK(!instruction->IsParameterValue());
DCHECK(instruction->IsCurrentMethod() || instruction->IsConstant())
<< instruction->DebugName();
}
diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h
index 719feec468..40dab74a23 100644
--- a/compiler/optimizing/ssa_liveness_analysis.h
+++ b/compiler/optimizing/ssa_liveness_analysis.h
@@ -971,7 +971,7 @@ class LiveInterval : public ArenaObject<kArenaAllocSsaLiveness> {
bool IsLinearOrderWellFormed(const HGraph& graph) {
for (HBasicBlock* header : graph.GetBlocks()) {
- if (!header->IsLoopHeader()) {
+ if (header == nullptr || !header->IsLoopHeader()) {
continue;
}