diff options
author | Alex Light <allight@google.com> | 2020-11-14 01:28:22 +0000 |
---|---|---|
committer | Treehugger Robot <treehugger-gerrit@google.com> | 2020-11-14 02:54:26 +0000 |
commit | 2316b3a0779f3721a78681f5c70ed6624ecaebef (patch) | |
tree | 8aa4682729b839a97b2578e6cbe05ee5d35be923 /compiler/optimizing/load_store_analysis_test.cc | |
parent | aeb7f9f8fe718219cfb04e0da5df62683250477d (diff) |
Revert^3 "Partial LSE analysis & store removal"
This reverts commit b6837f0350ff66c13582b0e94178dd5ca283ff0a
This unreverts commit fe270426c8a2a69a8f669339e83b86fbf40e25a1.
This rereverts commit bb6cda60e4418c0ab557ea4090e046bed8206763.
Bug: 67037140
Bug: 173120044
Reason for revert: Git-blame seems to point to the CL as cause of
b/173120044. Revert during investigation.
Change-Id: I46f557ce79c15f07f4e77aacded1926b192754c3
Diffstat (limited to 'compiler/optimizing/load_store_analysis_test.cc')
-rw-r--r-- | compiler/optimizing/load_store_analysis_test.cc | 1025 |
1 files changed, 9 insertions, 1016 deletions
diff --git a/compiler/optimizing/load_store_analysis_test.cc b/compiler/optimizing/load_store_analysis_test.cc index 228481106f..c518f03fbe 100644 --- a/compiler/optimizing/load_store_analysis_test.cc +++ b/compiler/optimizing/load_store_analysis_test.cc @@ -15,49 +15,16 @@ */ #include "load_store_analysis.h" - -#include <array> -#include <string_view> -#include <unordered_map> -#include <unordered_set> - -#include "base/scoped_arena_allocator.h" -#include "class_root.h" -#include "dex/dex_file_types.h" -#include "dex/method_reference.h" -#include "entrypoints/quick/quick_entrypoints_enum.h" -#include "execution_subgraph.h" -#include "execution_subgraph_test.h" -#include "gtest/gtest.h" -#include "handle.h" -#include "handle_scope.h" #include "nodes.h" -#include "optimizing/data_type.h" #include "optimizing_unit_test.h" -#include "scoped_thread_state_change.h" + +#include "gtest/gtest.h" namespace art { class LoadStoreAnalysisTest : public OptimizingUnitTest { public: - LoadStoreAnalysisTest() : graph_(CreateGraph()) {} - - AdjacencyListGraph SetupFromAdjacencyList( - const std::string_view entry_name, - const std::string_view exit_name, - const std::vector<AdjacencyListGraph::Edge>& adj) { - return AdjacencyListGraph(graph_, GetAllocator(), entry_name, exit_name, adj); - } - - bool IsValidSubgraph(const ExecutionSubgraph* esg) { - return ExecutionSubgraphTestHelper::CalculateValidity(graph_, esg); - } - - bool IsValidSubgraph(const ExecutionSubgraph& esg) { - return ExecutionSubgraphTestHelper::CalculateValidity(graph_, &esg); - } - void CheckReachability(const AdjacencyListGraph& adj, - const std::vector<AdjacencyListGraph::Edge>& reach); + LoadStoreAnalysisTest() : graph_(CreateGraph()) { } HGraph* graph_; }; @@ -100,8 +67,7 @@ TEST_F(LoadStoreAnalysisTest, ArrayHeapLocations) { // Test HeapLocationCollector initialization. // Should be no heap locations, no operations on the heap. ScopedArenaAllocator allocator(graph_->GetArenaStack()); - HeapLocationCollector heap_location_collector( - graph_, &allocator, /*for_partial_elimination=*/true); + HeapLocationCollector heap_location_collector(graph_, &allocator); ASSERT_EQ(heap_location_collector.GetNumberOfHeapLocations(), 0U); ASSERT_FALSE(heap_location_collector.HasHeapStores()); @@ -198,8 +164,7 @@ TEST_F(LoadStoreAnalysisTest, FieldHeapLocations) { // Test HeapLocationCollector initialization. // Should be no heap locations, no operations on the heap. ScopedArenaAllocator allocator(graph_->GetArenaStack()); - HeapLocationCollector heap_location_collector( - graph_, &allocator, /*for_partial_elimination=*/true); + HeapLocationCollector heap_location_collector(graph_, &allocator); ASSERT_EQ(heap_location_collector.GetNumberOfHeapLocations(), 0U); ASSERT_FALSE(heap_location_collector.HasHeapStores()); @@ -279,7 +244,7 @@ TEST_F(LoadStoreAnalysisTest, ArrayIndexAliasingTest) { entry->AddInstruction(arr_set8); // array[i-(-1)] = c0 ScopedArenaAllocator allocator(graph_->GetArenaStack()); - LoadStoreAnalysis lsa(graph_, nullptr, &allocator, /*for_elimination=*/false); + LoadStoreAnalysis lsa(graph_, &allocator); lsa.Run(); const HeapLocationCollector& heap_location_collector = lsa.GetHeapLocationCollector(); @@ -446,7 +411,7 @@ TEST_F(LoadStoreAnalysisTest, ArrayAliasingTest) { entry->AddInstruction(vstore_i_add6_vlen2); ScopedArenaAllocator allocator(graph_->GetArenaStack()); - LoadStoreAnalysis lsa(graph_, nullptr, &allocator, /*for_elimination=*/false); + LoadStoreAnalysis lsa(graph_, &allocator); lsa.Run(); const HeapLocationCollector& heap_location_collector = lsa.GetHeapLocationCollector(); @@ -605,7 +570,7 @@ TEST_F(LoadStoreAnalysisTest, ArrayIndexCalculationOverflowTest) { entry->AddInstruction(arr_set_8); ScopedArenaAllocator allocator(graph_->GetArenaStack()); - LoadStoreAnalysis lsa(graph_, nullptr, &allocator, /*for_elimination=*/false); + LoadStoreAnalysis lsa(graph_, &allocator); lsa.Run(); const HeapLocationCollector& heap_location_collector = lsa.GetHeapLocationCollector(); @@ -695,8 +660,7 @@ TEST_F(LoadStoreAnalysisTest, TestHuntOriginalRef) { entry->AddInstruction(array_get4); ScopedArenaAllocator allocator(graph_->GetArenaStack()); - HeapLocationCollector heap_location_collector( - graph_, &allocator, /*for_partial_elimination=*/true); + HeapLocationCollector heap_location_collector(graph_, &allocator); heap_location_collector.VisitBasicBlock(entry); // Test that the HeapLocationCollector should be able to tell @@ -714,975 +678,4 @@ TEST_F(LoadStoreAnalysisTest, TestHuntOriginalRef) { ASSERT_EQ(loc1, loc4); } -void LoadStoreAnalysisTest::CheckReachability(const AdjacencyListGraph& adj, - const std::vector<AdjacencyListGraph::Edge>& reach) { - uint32_t cnt = 0; - for (HBasicBlock* blk : graph_->GetBlocks()) { - if (adj.HasBlock(blk)) { - for (HBasicBlock* other : graph_->GetBlocks()) { - if (other == nullptr) { - continue; - } - if (adj.HasBlock(other)) { - bool contains_edge = - std::find(reach.begin(), - reach.end(), - AdjacencyListGraph::Edge { adj.GetName(blk), adj.GetName(other) }) != - reach.end(); - if (graph_->PathBetween(blk, other)) { - cnt++; - EXPECT_TRUE(contains_edge) << "Unexpected edge found between " << adj.GetName(blk) - << " and " << adj.GetName(other); - } else { - EXPECT_FALSE(contains_edge) << "Expected edge not found between " << adj.GetName(blk) - << " and " << adj.GetName(other); - } - } else if (graph_->PathBetween(blk, other)) { - ADD_FAILURE() << "block " << adj.GetName(blk) - << " has path to non-adjacency-graph block id: " << other->GetBlockId(); - } - } - } else { - for (HBasicBlock* other : graph_->GetBlocks()) { - if (other == nullptr) { - continue; - } - EXPECT_FALSE(graph_->PathBetween(blk, other)) - << "Reachable blocks outside of adjacency-list"; - } - } - } - EXPECT_EQ(cnt, reach.size()); -} - -TEST_F(LoadStoreAnalysisTest, ReachabilityTest1) { - AdjacencyListGraph blks(SetupFromAdjacencyList( - "entry", - "exit", - { { "entry", "left" }, { "entry", "right" }, { "left", "exit" }, { "right", "exit" } })); - CheckReachability(blks, - { - { "entry", "left" }, - { "entry", "right" }, - { "entry", "exit" }, - { "right", "exit" }, - { "left", "exit" }, - }); -} - -TEST_F(LoadStoreAnalysisTest, ReachabilityTest2) { - AdjacencyListGraph blks(SetupFromAdjacencyList( - "entry", - "exit", - { { "entry", "loop-header" }, { "loop-header", "loop" }, { "loop", "loop-header" } })); - CheckReachability(blks, - { - { "entry", "loop-header" }, - { "entry", "loop" }, - { "loop-header", "loop-header" }, - { "loop-header", "loop" }, - { "loop", "loop-header" }, - { "loop", "loop" }, - }); -} - -TEST_F(LoadStoreAnalysisTest, ReachabilityTest3) { - AdjacencyListGraph blks(SetupFromAdjacencyList("entry", - "exit", - { { "entry", "loop-header" }, - { "loop-header", "loop" }, - { "loop", "loop-header" }, - { "entry", "right" }, - { "right", "exit" } })); - CheckReachability(blks, - { - { "entry", "loop-header" }, - { "entry", "loop" }, - { "entry", "right" }, - { "entry", "exit" }, - { "loop-header", "loop-header" }, - { "loop-header", "loop" }, - { "loop", "loop-header" }, - { "loop", "loop" }, - { "right", "exit" }, - }); -} - -static bool AreExclusionsIndependent(HGraph* graph, const ExecutionSubgraph* esg) { - auto excluded = esg->GetExcludedCohorts(); - if (excluded.size() < 2) { - return true; - } - for (auto first = excluded.begin(); first != excluded.end(); ++first) { - for (auto second = excluded.begin(); second != excluded.end(); ++second) { - if (first == second) { - continue; - } - for (const HBasicBlock* entry : first->EntryBlocks()) { - for (const HBasicBlock* exit : second->ExitBlocks()) { - if (graph->PathBetween(exit, entry)) { - return false; - } - } - } - } - } - return true; -} - -// // ENTRY -// obj = new Obj(); -// if (parameter_value) { -// // LEFT -// call_func(obj); -// } else { -// // RIGHT -// obj.field = 1; -// } -// // EXIT -// obj.field; -TEST_F(LoadStoreAnalysisTest, PartialEscape) { - AdjacencyListGraph blks(SetupFromAdjacencyList( - "entry", - "exit", - { { "entry", "left" }, { "entry", "right" }, { "left", "exit" }, { "right", "exit" } })); - HBasicBlock* entry = blks.Get("entry"); - HBasicBlock* left = blks.Get("left"); - HBasicBlock* right = blks.Get("right"); - HBasicBlock* exit = blks.Get("exit"); - - HInstruction* bool_value = new (GetAllocator()) - HParameterValue(graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kBool); - HInstruction* c0 = graph_->GetIntConstant(0); - HInstruction* cls = new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(), - dex::TypeIndex(10), - graph_->GetDexFile(), - ScopedNullHandle<mirror::Class>(), - false, - 0, - false); - HInstruction* new_inst = - new (GetAllocator()) HNewInstance(cls, - 0, - dex::TypeIndex(10), - graph_->GetDexFile(), - false, - QuickEntrypointEnum::kQuickAllocObjectInitialized); - HInstruction* if_inst = new (GetAllocator()) HIf(bool_value); - entry->AddInstruction(bool_value); - entry->AddInstruction(cls); - entry->AddInstruction(new_inst); - entry->AddInstruction(if_inst); - - HInstruction* call_left = new (GetAllocator()) - HInvokeStaticOrDirect(GetAllocator(), - 1, - DataType::Type::kVoid, - 0, - { nullptr, 0 }, - nullptr, - {}, - InvokeType::kStatic, - { nullptr, 0 }, - HInvokeStaticOrDirect::ClinitCheckRequirement::kNone); - HInstruction* goto_left = new (GetAllocator()) HGoto(); - call_left->AsInvoke()->SetRawInputAt(0, new_inst); - left->AddInstruction(call_left); - left->AddInstruction(goto_left); - - HInstruction* write_right = new (GetAllocator()) HInstanceFieldSet(new_inst, - c0, - nullptr, - DataType::Type::kInt32, - MemberOffset(10), - false, - 0, - 0, - graph_->GetDexFile(), - 0); - HInstruction* goto_right = new (GetAllocator()) HGoto(); - right->AddInstruction(write_right); - right->AddInstruction(goto_right); - - HInstruction* read_final = new (GetAllocator()) HInstanceFieldGet(new_inst, - nullptr, - DataType::Type::kInt32, - MemberOffset(10), - false, - 0, - 0, - graph_->GetDexFile(), - 0); - exit->AddInstruction(read_final); - - ScopedArenaAllocator allocator(graph_->GetArenaStack()); - LoadStoreAnalysis lsa(graph_, nullptr, &allocator, /*for_elimination=*/true); - lsa.Run(); - - const HeapLocationCollector& heap_location_collector = lsa.GetHeapLocationCollector(); - ReferenceInfo* info = heap_location_collector.FindReferenceInfoOf(new_inst); - const ExecutionSubgraph* esg = info->GetNoEscapeSubgraph(); - - ASSERT_TRUE(esg->IsValid()); - ASSERT_TRUE(IsValidSubgraph(esg)); - ASSERT_TRUE(AreExclusionsIndependent(graph_, esg)); - std::unordered_set<const HBasicBlock*> contents(esg->ReachableBlocks().begin(), - esg->ReachableBlocks().end()); - - ASSERT_EQ(contents.size(), 3u); - ASSERT_TRUE(contents.find(blks.Get("left")) == contents.end()); - - ASSERT_TRUE(contents.find(blks.Get("right")) != contents.end()); - ASSERT_TRUE(contents.find(blks.Get("entry")) != contents.end()); - ASSERT_TRUE(contents.find(blks.Get("exit")) != contents.end()); -} - -// // ENTRY -// obj = new Obj(); -// if (parameter_value) { -// // LEFT -// call_func(obj); -// } else { -// // RIGHT -// obj.field = 1; -// } -// // EXIT -// obj.field2; -TEST_F(LoadStoreAnalysisTest, PartialEscape2) { - AdjacencyListGraph blks(SetupFromAdjacencyList( - "entry", - "exit", - { { "entry", "left" }, { "entry", "right" }, { "left", "exit" }, { "right", "exit" } })); - HBasicBlock* entry = blks.Get("entry"); - HBasicBlock* left = blks.Get("left"); - HBasicBlock* right = blks.Get("right"); - HBasicBlock* exit = blks.Get("exit"); - - HInstruction* bool_value = new (GetAllocator()) - HParameterValue(graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kBool); - HInstruction* c0 = graph_->GetIntConstant(0); - HInstruction* cls = new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(), - dex::TypeIndex(10), - graph_->GetDexFile(), - ScopedNullHandle<mirror::Class>(), - false, - 0, - false); - HInstruction* new_inst = - new (GetAllocator()) HNewInstance(cls, - 0, - dex::TypeIndex(10), - graph_->GetDexFile(), - false, - QuickEntrypointEnum::kQuickAllocObjectInitialized); - HInstruction* if_inst = new (GetAllocator()) HIf(bool_value); - entry->AddInstruction(bool_value); - entry->AddInstruction(cls); - entry->AddInstruction(new_inst); - entry->AddInstruction(if_inst); - - HInstruction* call_left = new (GetAllocator()) - HInvokeStaticOrDirect(GetAllocator(), - 1, - DataType::Type::kVoid, - 0, - { nullptr, 0 }, - nullptr, - {}, - InvokeType::kStatic, - { nullptr, 0 }, - HInvokeStaticOrDirect::ClinitCheckRequirement::kNone); - HInstruction* goto_left = new (GetAllocator()) HGoto(); - call_left->AsInvoke()->SetRawInputAt(0, new_inst); - left->AddInstruction(call_left); - left->AddInstruction(goto_left); - - HInstruction* write_right = new (GetAllocator()) HInstanceFieldSet(new_inst, - c0, - nullptr, - DataType::Type::kInt32, - MemberOffset(10), - false, - 0, - 0, - graph_->GetDexFile(), - 0); - HInstruction* goto_right = new (GetAllocator()) HGoto(); - right->AddInstruction(write_right); - right->AddInstruction(goto_right); - - HInstruction* read_final = new (GetAllocator()) HInstanceFieldGet(new_inst, - nullptr, - DataType::Type::kInt32, - MemberOffset(16), - false, - 0, - 0, - graph_->GetDexFile(), - 0); - exit->AddInstruction(read_final); - - ScopedArenaAllocator allocator(graph_->GetArenaStack()); - LoadStoreAnalysis lsa(graph_, nullptr, &allocator, /*for_elimination=*/true); - lsa.Run(); - - const HeapLocationCollector& heap_location_collector = lsa.GetHeapLocationCollector(); - ReferenceInfo* info = heap_location_collector.FindReferenceInfoOf(new_inst); - const ExecutionSubgraph* esg = info->GetNoEscapeSubgraph(); - - ASSERT_TRUE(esg->IsValid()); - ASSERT_TRUE(IsValidSubgraph(esg)); - ASSERT_TRUE(AreExclusionsIndependent(graph_, esg)); - std::unordered_set<const HBasicBlock*> contents(esg->ReachableBlocks().begin(), - esg->ReachableBlocks().end()); - - ASSERT_EQ(contents.size(), 3u); - ASSERT_TRUE(contents.find(blks.Get("left")) == contents.end()); - - ASSERT_TRUE(contents.find(blks.Get("right")) != contents.end()); - ASSERT_TRUE(contents.find(blks.Get("entry")) != contents.end()); - ASSERT_TRUE(contents.find(blks.Get("exit")) != contents.end()); -} - -// // ENTRY -// obj = new Obj(); -// obj.field = 10; -// if (parameter_value) { -// // LEFT -// call_func(obj); -// } else { -// // RIGHT -// obj.field = 20; -// } -// // EXIT -// obj.field; -TEST_F(LoadStoreAnalysisTest, PartialEscape3) { - AdjacencyListGraph blks(SetupFromAdjacencyList( - "entry", - "exit", - { { "entry", "left" }, { "entry", "right" }, { "left", "exit" }, { "right", "exit" } })); - HBasicBlock* entry = blks.Get("entry"); - HBasicBlock* left = blks.Get("left"); - HBasicBlock* right = blks.Get("right"); - HBasicBlock* exit = blks.Get("exit"); - - HInstruction* bool_value = new (GetAllocator()) - HParameterValue(graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kBool); - HInstruction* c10 = graph_->GetIntConstant(10); - HInstruction* c20 = graph_->GetIntConstant(20); - HInstruction* cls = new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(), - dex::TypeIndex(10), - graph_->GetDexFile(), - ScopedNullHandle<mirror::Class>(), - false, - 0, - false); - HInstruction* new_inst = - new (GetAllocator()) HNewInstance(cls, - 0, - dex::TypeIndex(10), - graph_->GetDexFile(), - false, - QuickEntrypointEnum::kQuickAllocObjectInitialized); - - HInstruction* write_entry = new (GetAllocator()) HInstanceFieldSet(new_inst, - c10, - nullptr, - DataType::Type::kInt32, - MemberOffset(10), - false, - 0, - 0, - graph_->GetDexFile(), - 0); - HInstruction* if_inst = new (GetAllocator()) HIf(bool_value); - entry->AddInstruction(bool_value); - entry->AddInstruction(cls); - entry->AddInstruction(new_inst); - entry->AddInstruction(write_entry); - entry->AddInstruction(if_inst); - - HInstruction* call_left = new (GetAllocator()) - HInvokeStaticOrDirect(GetAllocator(), - 1, - DataType::Type::kVoid, - 0, - { nullptr, 0 }, - nullptr, - {}, - InvokeType::kStatic, - { nullptr, 0 }, - HInvokeStaticOrDirect::ClinitCheckRequirement::kNone); - HInstruction* goto_left = new (GetAllocator()) HGoto(); - call_left->AsInvoke()->SetRawInputAt(0, new_inst); - left->AddInstruction(call_left); - left->AddInstruction(goto_left); - - HInstruction* write_right = new (GetAllocator()) HInstanceFieldSet(new_inst, - c20, - nullptr, - DataType::Type::kInt32, - MemberOffset(10), - false, - 0, - 0, - graph_->GetDexFile(), - 0); - HInstruction* goto_right = new (GetAllocator()) HGoto(); - right->AddInstruction(write_right); - right->AddInstruction(goto_right); - - HInstruction* read_final = new (GetAllocator()) HInstanceFieldGet(new_inst, - nullptr, - DataType::Type::kInt32, - MemberOffset(10), - false, - 0, - 0, - graph_->GetDexFile(), - 0); - exit->AddInstruction(read_final); - - ScopedArenaAllocator allocator(graph_->GetArenaStack()); - LoadStoreAnalysis lsa(graph_, nullptr, &allocator, /*for_elimination=*/true); - lsa.Run(); - - const HeapLocationCollector& heap_location_collector = lsa.GetHeapLocationCollector(); - ReferenceInfo* info = heap_location_collector.FindReferenceInfoOf(new_inst); - const ExecutionSubgraph* esg = info->GetNoEscapeSubgraph(); - - ASSERT_TRUE(esg->IsValid()); - ASSERT_TRUE(IsValidSubgraph(esg)); - ASSERT_TRUE(AreExclusionsIndependent(graph_, esg)); - std::unordered_set<const HBasicBlock*> contents(esg->ReachableBlocks().begin(), - esg->ReachableBlocks().end()); - - ASSERT_EQ(contents.size(), 3u); - ASSERT_TRUE(contents.find(blks.Get("left")) == contents.end()); - - ASSERT_TRUE(contents.find(blks.Get("right")) != contents.end()); - ASSERT_TRUE(contents.find(blks.Get("entry")) != contents.end()); - ASSERT_TRUE(contents.find(blks.Get("exit")) != contents.end()); -} - -// // ENTRY -// obj = new Obj(); -// if (parameter_value) { -// // LEFT -// call_func(obj); -// } else { -// // RIGHT -// obj.f1 = 0; -// } -// // EXIT -// // call_func prevents the elimination of this store. -// obj.f2 = 0; -TEST_F(LoadStoreAnalysisTest, TotalEscapeAdjacent) { - AdjacencyListGraph blks(SetupFromAdjacencyList( - "entry", - "exit", - { { "entry", "left" }, { "entry", "right" }, { "left", "exit" }, { "right", "exit" } })); - HBasicBlock* entry = blks.Get("entry"); - HBasicBlock* left = blks.Get("left"); - HBasicBlock* right = blks.Get("right"); - HBasicBlock* exit = blks.Get("exit"); - - HInstruction* bool_value = new (GetAllocator()) - HParameterValue(graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kBool); - HInstruction* c0 = graph_->GetIntConstant(0); - HInstruction* cls = new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(), - dex::TypeIndex(10), - graph_->GetDexFile(), - ScopedNullHandle<mirror::Class>(), - false, - 0, - false); - HInstruction* new_inst = - new (GetAllocator()) HNewInstance(cls, - 0, - dex::TypeIndex(10), - graph_->GetDexFile(), - false, - QuickEntrypointEnum::kQuickAllocObjectInitialized); - HInstruction* if_inst = new (GetAllocator()) HIf(bool_value); - entry->AddInstruction(bool_value); - entry->AddInstruction(cls); - entry->AddInstruction(new_inst); - entry->AddInstruction(if_inst); - - HInstruction* call_left = new (GetAllocator()) - HInvokeStaticOrDirect(GetAllocator(), - 1, - DataType::Type::kVoid, - 0, - { nullptr, 0 }, - nullptr, - {}, - InvokeType::kStatic, - { nullptr, 0 }, - HInvokeStaticOrDirect::ClinitCheckRequirement::kNone); - HInstruction* goto_left = new (GetAllocator()) HGoto(); - call_left->AsInvoke()->SetRawInputAt(0, new_inst); - left->AddInstruction(call_left); - left->AddInstruction(goto_left); - - HInstruction* write_right = new (GetAllocator()) HInstanceFieldSet(new_inst, - c0, - nullptr, - DataType::Type::kInt32, - MemberOffset(10), - false, - 0, - 0, - graph_->GetDexFile(), - 0); - HInstruction* goto_right = new (GetAllocator()) HGoto(); - right->AddInstruction(write_right); - right->AddInstruction(goto_right); - - HInstruction* write_final = new (GetAllocator()) HInstanceFieldSet(new_inst, - c0, - nullptr, - DataType::Type::kInt32, - MemberOffset(16), - false, - 0, - 0, - graph_->GetDexFile(), - 0); - exit->AddInstruction(write_final); - - ScopedArenaAllocator allocator(graph_->GetArenaStack()); - LoadStoreAnalysis lsa(graph_, nullptr, &allocator, /*for_elimination=*/true); - lsa.Run(); - - const HeapLocationCollector& heap_location_collector = lsa.GetHeapLocationCollector(); - ReferenceInfo* info = heap_location_collector.FindReferenceInfoOf(new_inst); - const ExecutionSubgraph* esg = info->GetNoEscapeSubgraph(); - - ASSERT_FALSE(esg->IsValid()) << esg->GetExcludedCohorts(); - ASSERT_FALSE(IsValidSubgraph(esg)); - std::unordered_set<const HBasicBlock*> contents(esg->ReachableBlocks().begin(), - esg->ReachableBlocks().end()); - - ASSERT_EQ(contents.size(), 0u); - ASSERT_TRUE(contents.find(blks.Get("left")) == contents.end()); - ASSERT_TRUE(contents.find(blks.Get("right")) == contents.end()); - ASSERT_TRUE(contents.find(blks.Get("entry")) == contents.end()); - ASSERT_TRUE(contents.find(blks.Get("exit")) == contents.end()); -} - -// // ENTRY -// obj = new Obj(); -// if (parameter_value) { -// // LEFT -// call_func(obj); -// } else { -// // RIGHT -// obj.f0 = 0; -// call_func2(obj); -// } -// // EXIT -// obj.f0; -TEST_F(LoadStoreAnalysisTest, TotalEscape) { - AdjacencyListGraph blks(SetupFromAdjacencyList( - "entry", - "exit", - { { "entry", "left" }, { "entry", "right" }, { "left", "exit" }, { "right", "exit" } })); - HBasicBlock* entry = blks.Get("entry"); - HBasicBlock* left = blks.Get("left"); - HBasicBlock* right = blks.Get("right"); - HBasicBlock* exit = blks.Get("exit"); - - HInstruction* bool_value = new (GetAllocator()) - HParameterValue(graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kBool); - HInstruction* c0 = graph_->GetIntConstant(0); - HInstruction* cls = new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(), - dex::TypeIndex(10), - graph_->GetDexFile(), - ScopedNullHandle<mirror::Class>(), - false, - 0, - false); - HInstruction* new_inst = - new (GetAllocator()) HNewInstance(cls, - 0, - dex::TypeIndex(10), - graph_->GetDexFile(), - false, - QuickEntrypointEnum::kQuickAllocObjectInitialized); - HInstruction* if_inst = new (GetAllocator()) HIf(bool_value); - entry->AddInstruction(bool_value); - entry->AddInstruction(cls); - entry->AddInstruction(new_inst); - entry->AddInstruction(if_inst); - - HInstruction* call_left = new (GetAllocator()) - HInvokeStaticOrDirect(GetAllocator(), - 1, - DataType::Type::kVoid, - 0, - { nullptr, 0 }, - nullptr, - {}, - InvokeType::kStatic, - { nullptr, 0 }, - HInvokeStaticOrDirect::ClinitCheckRequirement::kNone); - HInstruction* goto_left = new (GetAllocator()) HGoto(); - call_left->AsInvoke()->SetRawInputAt(0, new_inst); - left->AddInstruction(call_left); - left->AddInstruction(goto_left); - - HInstruction* call_right = new (GetAllocator()) - HInvokeStaticOrDirect(GetAllocator(), - 1, - DataType::Type::kVoid, - 0, - { nullptr, 0 }, - nullptr, - {}, - InvokeType::kStatic, - { nullptr, 0 }, - HInvokeStaticOrDirect::ClinitCheckRequirement::kNone); - HInstruction* write_right = new (GetAllocator()) HInstanceFieldSet(new_inst, - c0, - nullptr, - DataType::Type::kInt32, - MemberOffset(10), - false, - 0, - 0, - graph_->GetDexFile(), - 0); - HInstruction* goto_right = new (GetAllocator()) HGoto(); - call_right->AsInvoke()->SetRawInputAt(0, new_inst); - right->AddInstruction(write_right); - right->AddInstruction(call_right); - right->AddInstruction(goto_right); - - HInstruction* read_final = new (GetAllocator()) HInstanceFieldGet(new_inst, - nullptr, - DataType::Type::kInt32, - MemberOffset(10), - false, - 0, - 0, - graph_->GetDexFile(), - 0); - exit->AddInstruction(read_final); - - ScopedArenaAllocator allocator(graph_->GetArenaStack()); - LoadStoreAnalysis lsa(graph_, nullptr, &allocator, /*for_elimination=*/true); - lsa.Run(); - - const HeapLocationCollector& heap_location_collector = lsa.GetHeapLocationCollector(); - ReferenceInfo* info = heap_location_collector.FindReferenceInfoOf(new_inst); - const ExecutionSubgraph* esg = info->GetNoEscapeSubgraph(); - - ASSERT_FALSE(esg->IsValid()); - ASSERT_FALSE(IsValidSubgraph(esg)); - std::unordered_set<const HBasicBlock*> contents(esg->ReachableBlocks().begin(), - esg->ReachableBlocks().end()); - - ASSERT_EQ(contents.size(), 0u); - ASSERT_TRUE(contents.find(blks.Get("left")) == contents.end()); - ASSERT_TRUE(contents.find(blks.Get("right")) == contents.end()); - ASSERT_TRUE(contents.find(blks.Get("entry")) == contents.end()); - ASSERT_TRUE(contents.find(blks.Get("exit")) == contents.end()); -} - -// // ENTRY -// obj = new Obj(); -// obj.foo = 0; -// // EXIT -// return obj; -TEST_F(LoadStoreAnalysisTest, TotalEscape2) { - AdjacencyListGraph blks(SetupFromAdjacencyList("entry", "exit", { { "entry", "exit" } })); - HBasicBlock* entry = blks.Get("entry"); - HBasicBlock* exit = blks.Get("exit"); - - HInstruction* c0 = graph_->GetIntConstant(0); - HInstruction* cls = new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(), - dex::TypeIndex(10), - graph_->GetDexFile(), - ScopedNullHandle<mirror::Class>(), - false, - 0, - false); - HInstruction* new_inst = - new (GetAllocator()) HNewInstance(cls, - 0, - dex::TypeIndex(10), - graph_->GetDexFile(), - false, - QuickEntrypointEnum::kQuickAllocObjectInitialized); - - HInstruction* write_start = new (GetAllocator()) HInstanceFieldSet(new_inst, - c0, - nullptr, - DataType::Type::kInt32, - MemberOffset(10), - false, - 0, - 0, - graph_->GetDexFile(), - 0); - HInstruction* goto_inst = new (GetAllocator()) HGoto(); - entry->AddInstruction(cls); - entry->AddInstruction(new_inst); - entry->AddInstruction(write_start); - entry->AddInstruction(goto_inst); - - HInstruction* return_final = new (GetAllocator()) HReturn(new_inst); - exit->AddInstruction(return_final); - - ScopedArenaAllocator allocator(graph_->GetArenaStack()); - LoadStoreAnalysis lsa(graph_, nullptr, &allocator, /*for_elimination=*/true); - lsa.Run(); - - const HeapLocationCollector& heap_location_collector = lsa.GetHeapLocationCollector(); - ReferenceInfo* info = heap_location_collector.FindReferenceInfoOf(new_inst); - const ExecutionSubgraph* esg = info->GetNoEscapeSubgraph(); - - ASSERT_FALSE(esg->IsValid()); - ASSERT_FALSE(IsValidSubgraph(esg)); - std::unordered_set<const HBasicBlock*> contents(esg->ReachableBlocks().begin(), - esg->ReachableBlocks().end()); - - ASSERT_EQ(contents.size(), 0u); - ASSERT_TRUE(contents.find(blks.Get("entry")) == contents.end()); - ASSERT_TRUE(contents.find(blks.Get("exit")) == contents.end()); -} - -// // ENTRY -// obj = new Obj(); -// if (parameter_value) { -// // HIGH_LEFT -// call_func(obj); -// } else { -// // HIGH_RIGHT -// obj.f0 = 1; -// } -// // MID -// obj.f0 *= 2; -// if (parameter_value2) { -// // LOW_LEFT -// call_func(obj); -// } else { -// // LOW_RIGHT -// obj.f0 = 1; -// } -// // EXIT -// obj.f0 -TEST_F(LoadStoreAnalysisTest, DoubleDiamondEscape) { - AdjacencyListGraph blks(SetupFromAdjacencyList("entry", - "exit", - { { "entry", "high_left" }, - { "entry", "high_right" }, - { "low_left", "exit" }, - { "low_right", "exit" }, - { "high_right", "mid" }, - { "high_left", "mid" }, - { "mid", "low_left" }, - { "mid", "low_right" } })); - HBasicBlock* entry = blks.Get("entry"); - HBasicBlock* high_left = blks.Get("high_left"); - HBasicBlock* high_right = blks.Get("high_right"); - HBasicBlock* mid = blks.Get("mid"); - HBasicBlock* low_left = blks.Get("low_left"); - HBasicBlock* low_right = blks.Get("low_right"); - HBasicBlock* exit = blks.Get("exit"); - - HInstruction* bool_value1 = new (GetAllocator()) - HParameterValue(graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kBool); - HInstruction* bool_value2 = new (GetAllocator()) - HParameterValue(graph_->GetDexFile(), dex::TypeIndex(1), 2, DataType::Type::kBool); - HInstruction* c0 = graph_->GetIntConstant(0); - HInstruction* c2 = graph_->GetIntConstant(2); - HInstruction* cls = new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(), - dex::TypeIndex(10), - graph_->GetDexFile(), - ScopedNullHandle<mirror::Class>(), - false, - 0, - false); - HInstruction* new_inst = - new (GetAllocator()) HNewInstance(cls, - 0, - dex::TypeIndex(10), - graph_->GetDexFile(), - false, - QuickEntrypointEnum::kQuickAllocObjectInitialized); - HInstruction* if_inst = new (GetAllocator()) HIf(bool_value1); - entry->AddInstruction(bool_value1); - entry->AddInstruction(bool_value2); - entry->AddInstruction(cls); - entry->AddInstruction(new_inst); - entry->AddInstruction(if_inst); - - HInstruction* call_left = new (GetAllocator()) - HInvokeStaticOrDirect(GetAllocator(), - 1, - DataType::Type::kVoid, - 0, - { nullptr, 0 }, - nullptr, - {}, - InvokeType::kStatic, - { nullptr, 0 }, - HInvokeStaticOrDirect::ClinitCheckRequirement::kNone); - HInstruction* goto_left = new (GetAllocator()) HGoto(); - call_left->AsInvoke()->SetRawInputAt(0, new_inst); - high_left->AddInstruction(call_left); - high_left->AddInstruction(goto_left); - - HInstruction* write_right = new (GetAllocator()) HInstanceFieldSet(new_inst, - c0, - nullptr, - DataType::Type::kInt32, - MemberOffset(10), - false, - 0, - 0, - graph_->GetDexFile(), - 0); - HInstruction* goto_right = new (GetAllocator()) HGoto(); - high_right->AddInstruction(write_right); - high_right->AddInstruction(goto_right); - - HInstruction* read_mid = new (GetAllocator()) HInstanceFieldGet(new_inst, - nullptr, - DataType::Type::kInt32, - MemberOffset(10), - false, - 0, - 0, - graph_->GetDexFile(), - 0); - HInstruction* mul_mid = new (GetAllocator()) HMul(DataType::Type::kInt32, read_mid, c2); - HInstruction* write_mid = new (GetAllocator()) HInstanceFieldSet(new_inst, - mul_mid, - nullptr, - DataType::Type::kInt32, - MemberOffset(10), - false, - 0, - 0, - graph_->GetDexFile(), - 0); - HInstruction* if_mid = new (GetAllocator()) HIf(bool_value2); - mid->AddInstruction(read_mid); - mid->AddInstruction(mul_mid); - mid->AddInstruction(write_mid); - mid->AddInstruction(if_mid); - - HInstruction* call_low_left = new (GetAllocator()) - HInvokeStaticOrDirect(GetAllocator(), - 1, - DataType::Type::kVoid, - 0, - { nullptr, 0 }, - nullptr, - {}, - InvokeType::kStatic, - { nullptr, 0 }, - HInvokeStaticOrDirect::ClinitCheckRequirement::kNone); - HInstruction* goto_low_left = new (GetAllocator()) HGoto(); - call_low_left->AsInvoke()->SetRawInputAt(0, new_inst); - low_left->AddInstruction(call_low_left); - low_left->AddInstruction(goto_low_left); - - HInstruction* write_low_right = new (GetAllocator()) HInstanceFieldSet(new_inst, - c0, - nullptr, - DataType::Type::kInt32, - MemberOffset(10), - false, - 0, - 0, - graph_->GetDexFile(), - 0); - HInstruction* goto_low_right = new (GetAllocator()) HGoto(); - low_right->AddInstruction(write_low_right); - low_right->AddInstruction(goto_low_right); - - HInstruction* read_final = new (GetAllocator()) HInstanceFieldGet(new_inst, - nullptr, - DataType::Type::kInt32, - MemberOffset(10), - false, - 0, - 0, - graph_->GetDexFile(), - 0); - exit->AddInstruction(read_final); - - ScopedArenaAllocator allocator(graph_->GetArenaStack()); - LoadStoreAnalysis lsa(graph_, nullptr, &allocator, /*for_elimination=*/true); - lsa.Run(); - - const HeapLocationCollector& heap_location_collector = lsa.GetHeapLocationCollector(); - ReferenceInfo* info = heap_location_collector.FindReferenceInfoOf(new_inst); - const ExecutionSubgraph* esg = info->GetNoEscapeSubgraph(); - - ASSERT_FALSE(esg->IsValid()); - ASSERT_FALSE(IsValidSubgraph(esg)); - std::unordered_set<const HBasicBlock*> contents(esg->ReachableBlocks().begin(), - esg->ReachableBlocks().end()); - - ASSERT_EQ(contents.size(), 0u); -} - -// ┌───────┐ ┌────────────┐ -// ┌─ │ right │ ◀── │ entry │ -// │ └───────┘ └────────────┘ -// │ │ -// │ │ -// │ ▼ -// │ ┌────────────┐ -// │ │ esc_top │ -// │ └────────────┘ -// │ │ -// │ │ -// │ ▼ -// │ ┌────────────┐ -// └──────────────▶ │ middle │ ─┐ -// └────────────┘ │ -// │ │ -// │ │ -// ▼ │ -// ┌────────────┐ │ -// │ esc_bottom │ │ -// └────────────┘ │ -// │ │ -// │ │ -// ▼ │ -// ┌────────────┐ │ -// │ exit │ ◀┘ -// └────────────┘ -TEST_F(LoadStoreAnalysisTest, InAndOutEscape) { - AdjacencyListGraph blks(SetupFromAdjacencyList("entry", - "exit", - { { "entry", "esc_top" }, - { "entry", "right" }, - { "esc_top", "middle" }, - { "right", "middle" }, - { "middle", "exit" }, - { "middle", "esc_bottom" }, - { "esc_bottom", "exit" } })); - - ExecutionSubgraph esg(graph_, /*analysis_possible=*/true, GetScopedAllocator()); - esg.RemoveBlock(blks.Get("esc_top")); - esg.RemoveBlock(blks.Get("esc_bottom")); - esg.Finalize(); - - std::unordered_set<const HBasicBlock*> contents(esg.ReachableBlocks().begin(), - esg.ReachableBlocks().end()); - ASSERT_EQ(contents.size(), 0u); - ASSERT_FALSE(esg.IsValid()); - ASSERT_FALSE(IsValidSubgraph(esg)); - - ASSERT_EQ(contents.size(), 0u); -} - } // namespace art |