diff options
Diffstat (limited to 'compiler/optimizing')
| -rw-r--r-- | compiler/optimizing/inliner.cc | 3 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.cc | 20 | ||||
| -rw-r--r-- | compiler/optimizing/reference_type_propagation.cc | 15 | ||||
| -rw-r--r-- | compiler/optimizing/reference_type_propagation.h | 2 | ||||
| -rw-r--r-- | compiler/optimizing/reference_type_propagation_test.cc | 190 | ||||
| -rw-r--r-- | compiler/optimizing/ssa_liveness_analysis.cc | 2 | ||||
| -rw-r--r-- | compiler/optimizing/ssa_liveness_analysis.h | 2 |
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; } |