1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "nodes.h"
18 
19 #include "base/arena_allocator.h"
20 #include "optimizing_unit_test.h"
21 
22 #include "gtest/gtest.h"
23 
24 namespace art {
25 
26 class NodeTest : public OptimizingUnitTest {};
27 
28 /**
29  * Test that removing instruction from the graph removes itself from user lists
30  * and environment lists.
31  */
TEST_F(NodeTest,RemoveInstruction)32 TEST_F(NodeTest, RemoveInstruction) {
33   HGraph* graph = CreateGraph();
34   HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
35   graph->AddBlock(entry);
36   graph->SetEntryBlock(entry);
37   HInstruction* parameter = new (GetAllocator()) HParameterValue(
38       graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
39   entry->AddInstruction(parameter);
40   entry->AddInstruction(new (GetAllocator()) HGoto());
41 
42   HBasicBlock* first_block = new (GetAllocator()) HBasicBlock(graph);
43   graph->AddBlock(first_block);
44   entry->AddSuccessor(first_block);
45   HInstruction* null_check = new (GetAllocator()) HNullCheck(parameter, 0);
46   first_block->AddInstruction(null_check);
47   first_block->AddInstruction(new (GetAllocator()) HReturnVoid());
48 
49   HBasicBlock* exit_block = new (GetAllocator()) HBasicBlock(graph);
50   graph->AddBlock(exit_block);
51   first_block->AddSuccessor(exit_block);
52   exit_block->AddInstruction(new (GetAllocator()) HExit());
53 
54   HEnvironment* environment = new (GetAllocator()) HEnvironment(
55       GetAllocator(), 1, graph->GetArtMethod(), 0, null_check);
56   null_check->SetRawEnvironment(environment);
57   environment->SetRawEnvAt(0, parameter);
58   parameter->AddEnvUseAt(null_check->GetEnvironment(), 0);
59 
60   ASSERT_TRUE(parameter->HasEnvironmentUses());
61   ASSERT_TRUE(parameter->HasUses());
62 
63   first_block->RemoveInstruction(null_check);
64 
65   ASSERT_FALSE(parameter->HasEnvironmentUses());
66   ASSERT_FALSE(parameter->HasUses());
67 }
68 
69 /**
70  * Test that inserting an instruction in the graph updates user lists.
71  */
TEST_F(NodeTest,InsertInstruction)72 TEST_F(NodeTest, InsertInstruction) {
73   HGraph* graph = CreateGraph();
74   HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
75   graph->AddBlock(entry);
76   graph->SetEntryBlock(entry);
77   HInstruction* parameter1 = new (GetAllocator()) HParameterValue(
78       graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
79   HInstruction* parameter2 = new (GetAllocator()) HParameterValue(
80       graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
81   entry->AddInstruction(parameter1);
82   entry->AddInstruction(parameter2);
83   entry->AddInstruction(new (GetAllocator()) HExit());
84 
85   ASSERT_FALSE(parameter1->HasUses());
86 
87   HInstruction* to_insert = new (GetAllocator()) HNullCheck(parameter1, 0);
88   entry->InsertInstructionBefore(to_insert, parameter2);
89 
90   ASSERT_TRUE(parameter1->HasUses());
91   ASSERT_TRUE(parameter1->GetUses().HasExactlyOneElement());
92 }
93 
94 /**
95  * Test that adding an instruction in the graph updates user lists.
96  */
TEST_F(NodeTest,AddInstruction)97 TEST_F(NodeTest, AddInstruction) {
98   HGraph* graph = CreateGraph();
99   HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
100   graph->AddBlock(entry);
101   graph->SetEntryBlock(entry);
102   HInstruction* parameter = new (GetAllocator()) HParameterValue(
103       graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
104   entry->AddInstruction(parameter);
105 
106   ASSERT_FALSE(parameter->HasUses());
107 
108   HInstruction* to_add = new (GetAllocator()) HNullCheck(parameter, 0);
109   entry->AddInstruction(to_add);
110 
111   ASSERT_TRUE(parameter->HasUses());
112   ASSERT_TRUE(parameter->GetUses().HasExactlyOneElement());
113 }
114 
TEST_F(NodeTest,ParentEnvironment)115 TEST_F(NodeTest, ParentEnvironment) {
116   HGraph* graph = CreateGraph();
117   HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph);
118   graph->AddBlock(entry);
119   graph->SetEntryBlock(entry);
120   HInstruction* parameter1 = new (GetAllocator()) HParameterValue(
121       graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
122   HInstruction* with_environment = new (GetAllocator()) HNullCheck(parameter1, 0);
123   entry->AddInstruction(parameter1);
124   entry->AddInstruction(with_environment);
125   entry->AddInstruction(new (GetAllocator()) HExit());
126 
127   ASSERT_TRUE(parameter1->HasUses());
128   ASSERT_TRUE(parameter1->GetUses().HasExactlyOneElement());
129 
130   HEnvironment* environment = new (GetAllocator()) HEnvironment(
131       GetAllocator(), 1, graph->GetArtMethod(), 0, with_environment);
132   HInstruction* const array[] = { parameter1 };
133 
134   environment->CopyFrom(ArrayRef<HInstruction* const>(array));
135   with_environment->SetRawEnvironment(environment);
136 
137   ASSERT_TRUE(parameter1->HasEnvironmentUses());
138   ASSERT_TRUE(parameter1->GetEnvUses().HasExactlyOneElement());
139 
140   HEnvironment* parent1 = new (GetAllocator()) HEnvironment(
141       GetAllocator(), 1, graph->GetArtMethod(), 0, nullptr);
142   parent1->CopyFrom(ArrayRef<HInstruction* const>(array));
143 
144   ASSERT_EQ(parameter1->GetEnvUses().SizeSlow(), 2u);
145 
146   HEnvironment* parent2 = new (GetAllocator()) HEnvironment(
147       GetAllocator(), 1, graph->GetArtMethod(), 0, nullptr);
148   parent2->CopyFrom(ArrayRef<HInstruction* const>(array));
149   parent1->SetAndCopyParentChain(GetAllocator(), parent2);
150 
151   // One use for parent2, and one other use for the new parent of parent1.
152   ASSERT_EQ(parameter1->GetEnvUses().SizeSlow(), 4u);
153 
154   // We have copied the parent chain. So we now have two more uses.
155   environment->SetAndCopyParentChain(GetAllocator(), parent1);
156   ASSERT_EQ(parameter1->GetEnvUses().SizeSlow(), 6u);
157 }
158 
159 }  // namespace art
160