summaryrefslogtreecommitdiff
path: root/compiler/optimizing/load_store_analysis_test.cc
diff options
context:
space:
mode:
authorAlex Light <allight@google.com>2020-11-14 01:28:22 +0000
committerTreehugger Robot <treehugger-gerrit@google.com>2020-11-14 02:54:26 +0000
commit2316b3a0779f3721a78681f5c70ed6624ecaebef (patch)
tree8aa4682729b839a97b2578e6cbe05ee5d35be923 /compiler/optimizing/load_store_analysis_test.cc
parentaeb7f9f8fe718219cfb04e0da5df62683250477d (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.cc1025
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