OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 the V8 project authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "src/bit-vector.h" | |
6 #include "src/compiler/escape-analysis.h" | |
7 #include "src/compiler/escape-analysis-reducer.h" | |
8 #include "src/compiler/graph-visualizer.h" | |
9 #include "src/compiler/node-properties.h" | |
10 #include "src/compiler/simplified-operator.h" | |
11 #include "src/types-inl.h" | |
12 #include "src/zone-containers.h" | |
13 #include "test/unittests/compiler/graph-unittest.h" | |
14 | |
15 namespace v8 { | |
16 namespace internal { | |
17 namespace compiler { | |
18 | |
19 class EscapeAnalysisTest : public GraphTest { | |
20 public: | |
21 EscapeAnalysisTest() | |
22 : simplified_(zone()), | |
23 jsgraph_(isolate(), graph(), common(), nullptr, nullptr, nullptr), | |
24 escape_objects_(graph(), common(), zone()), | |
25 escape_status_(&escape_objects_, graph(), zone()), | |
26 effect_(graph()->start()), | |
27 control_(graph()->start()) {} | |
28 | |
29 ~EscapeAnalysisTest() {} | |
30 | |
31 EscapeStatusAnalysis* escape_status() { return &escape_status_; } | |
32 EscapeObjectAnalysis* escape_objects() { return &escape_objects_; } | |
33 | |
34 protected: | |
35 void Analysis() { | |
36 escape_objects_.Run(); | |
37 escape_status_.Run(); | |
38 } | |
39 | |
40 void Transformation() { | |
41 GraphReducer graph_reducer(zone(), graph()); | |
42 EscapeAnalysisReducer escape_reducer( | |
43 &graph_reducer, &jsgraph_, &escape_status_, &escape_objects_, zone()); | |
44 graph_reducer.AddReducer(&escape_reducer); | |
45 graph_reducer.ReduceGraph(); | |
46 } | |
47 | |
48 // ---------------------------------Node Creation Helper---------------------- | |
49 | |
50 Node* BeginRegion(Node* effect = nullptr) { | |
51 if (!effect) { | |
52 effect = effect_; | |
53 } | |
54 | |
55 return effect_ = graph()->NewNode(common()->BeginRegion(), effect); | |
56 } | |
57 | |
58 Node* FinishRegion(Node* value, Node* effect = nullptr) { | |
59 if (!effect) { | |
60 effect = effect_; | |
61 } | |
62 return effect_ = graph()->NewNode(common()->FinishRegion(), value, effect); | |
63 } | |
64 | |
65 Node* Allocate(Node* size, Node* effect = nullptr, Node* control = nullptr) { | |
66 if (!effect) { | |
67 effect = effect_; | |
68 } | |
69 if (!control) { | |
70 control = control_; | |
71 } | |
72 return effect_ = graph()->NewNode(simplified()->Allocate(), size, effect, | |
73 control); | |
74 } | |
75 | |
76 Node* Constant(int num) { | |
77 return graph()->NewNode(common()->NumberConstant(num)); | |
78 } | |
79 | |
80 Node* Store(const FieldAccess& access, Node* allocation, Node* value, | |
81 Node* effect = nullptr, Node* control = nullptr) { | |
82 if (!effect) { | |
83 effect = effect_; | |
84 } | |
85 if (!control) { | |
86 control = control_; | |
87 } | |
88 return effect_ = graph()->NewNode(simplified()->StoreField(access), | |
89 allocation, value, effect, control); | |
90 } | |
91 | |
92 Node* Load(const FieldAccess& access, Node* from, Node* effect = nullptr, | |
93 Node* control = nullptr) { | |
94 if (!effect) { | |
95 effect = effect_; | |
96 } | |
97 if (!control) { | |
98 control = control_; | |
99 } | |
100 return graph()->NewNode(simplified()->LoadField(access), from, effect, | |
101 control); | |
102 } | |
103 | |
104 Node* Return(Node* value, Node* effect = nullptr, Node* control = nullptr) { | |
105 if (!effect) { | |
106 effect = effect_; | |
107 } | |
108 if (!control) { | |
109 control = control_; | |
110 } | |
111 return control_ = | |
112 graph()->NewNode(common()->Return(), value, effect, control); | |
113 } | |
114 | |
115 void EndGraph() { | |
116 for (Edge edge : graph()->end()->input_edges()) { | |
117 if (NodeProperties::IsControlEdge(edge)) { | |
118 edge.UpdateTo(control_); | |
119 } | |
120 } | |
121 } | |
122 | |
123 Node* Branch() { | |
124 return control_ = | |
125 graph()->NewNode(common()->Branch(), Constant(0), control_); | |
126 } | |
127 | |
128 Node* IfTrue() { | |
129 return control_ = graph()->NewNode(common()->IfTrue(), control_); | |
130 } | |
131 | |
132 Node* IfFalse() { return graph()->NewNode(common()->IfFalse(), control_); } | |
133 | |
134 Node* Merge2(Node* control1, Node* control2) { | |
135 return control_ = graph()->NewNode(common()->Merge(2), control1, control2); | |
136 } | |
137 | |
138 FieldAccess AccessAtIndex(int offset) { | |
139 FieldAccess access = {kTaggedBase, offset, MaybeHandle<Name>(), Type::Any(), | |
140 kMachAnyTagged}; | |
141 return access; | |
142 } | |
143 | |
144 // ---------------------------------Assertion Helper-------------------------- | |
145 | |
146 void ExpectRepresentation(Node* node, Node* rep) { | |
Michael Starzinger
2015/12/01 17:18:38
nit: s/Representation/Replacement/
sigurds
2015/12/02 10:12:20
Done.
| |
147 EXPECT_EQ(rep, escape_objects()->GetReplacement(node, node->id())); | |
148 } | |
149 | |
150 void ExpectRepresentationPhi(Node* node, Node* left, Node* right) { | |
Michael Starzinger
2015/12/01 17:18:38
nit: Likewise.
sigurds
2015/12/02 10:12:20
Done.
| |
151 Node* rep = escape_objects()->GetReplacement(node, node->id()); | |
152 ASSERT_NE(nullptr, rep); | |
153 ASSERT_EQ(IrOpcode::kPhi, rep->opcode()); | |
154 EXPECT_EQ(left, NodeProperties::GetValueInput(rep, 0)); | |
155 EXPECT_EQ(right, NodeProperties::GetValueInput(rep, 1)); | |
156 } | |
157 | |
158 void ExpectVirtual(Node* node) { | |
159 EXPECT_TRUE(node->opcode() == IrOpcode::kAllocate || | |
160 node->opcode() == IrOpcode::kFinishRegion); | |
161 EXPECT_TRUE(escape_status()->IsVirtual(node)); | |
162 } | |
163 | |
164 void ExpectEscaped(Node* node) { | |
165 EXPECT_TRUE(node->opcode() == IrOpcode::kAllocate || | |
166 node->opcode() == IrOpcode::kFinishRegion); | |
167 EXPECT_TRUE(escape_status()->IsEscaped(node)); | |
168 } | |
169 | |
170 SimplifiedOperatorBuilder* simplified() { return &simplified_; } | |
171 | |
172 Node* effect() { return effect_; } | |
173 | |
174 private: | |
175 SimplifiedOperatorBuilder simplified_; | |
176 JSGraph jsgraph_; | |
177 EscapeObjectAnalysis escape_objects_; | |
178 EscapeStatusAnalysis escape_status_; | |
179 | |
180 Node* effect_; | |
181 Node* control_; | |
182 }; | |
183 | |
184 | |
185 // ----------------------------------------------------------------------------- | |
186 // Test cases. | |
187 | |
188 | |
189 TEST_F(EscapeAnalysisTest, StraightNonEscape) { | |
190 Node* object1 = Constant(1); | |
191 BeginRegion(); | |
192 Node* allocation = Allocate(Constant(kPointerSize)); | |
193 Store(AccessAtIndex(0), allocation, object1); | |
194 Node* finish = FinishRegion(allocation); | |
195 Node* load = Load(AccessAtIndex(0), finish); | |
196 Node* result = Return(load); | |
197 EndGraph(); | |
198 Analysis(); | |
199 | |
200 ExpectVirtual(allocation); | |
201 ExpectRepresentation(load, object1); | |
202 | |
203 Transformation(); | |
204 | |
205 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0)); | |
206 } | |
207 | |
208 | |
209 TEST_F(EscapeAnalysisTest, StraightEscape) { | |
210 Node* object1 = Constant(1); | |
211 BeginRegion(); | |
212 Node* allocation = Allocate(Constant(kPointerSize)); | |
213 Store(AccessAtIndex(0), allocation, object1); | |
214 Node* finish = FinishRegion(allocation); | |
215 Node* load = Load(AccessAtIndex(0), finish); | |
216 Node* result = Return(allocation); | |
217 EndGraph(); | |
218 Analysis(); | |
219 | |
220 ExpectEscaped(allocation); | |
221 ExpectRepresentation(load, object1); | |
222 | |
223 Transformation(); | |
224 | |
225 ASSERT_EQ(allocation, NodeProperties::GetValueInput(result, 0)); | |
226 } | |
227 | |
228 | |
229 TEST_F(EscapeAnalysisTest, StoreLoadEscape) { | |
230 Node* object1 = Constant(1); | |
231 | |
232 BeginRegion(); | |
233 Node* allocation1 = Allocate(Constant(kPointerSize)); | |
234 Store(AccessAtIndex(0), allocation1, object1); | |
235 Node* finish1 = FinishRegion(allocation1); | |
236 | |
237 BeginRegion(); | |
238 Node* allocation2 = Allocate(Constant(kPointerSize)); | |
239 Store(AccessAtIndex(0), allocation2, finish1); | |
240 Node* finish2 = FinishRegion(allocation2); | |
241 | |
242 Node* load = Load(AccessAtIndex(0), finish2); | |
243 Node* result = Return(load); | |
244 EndGraph(); | |
245 Analysis(); | |
246 | |
247 ExpectEscaped(allocation1); | |
248 ExpectVirtual(allocation2); | |
249 ExpectRepresentation(load, finish1); | |
250 | |
251 Transformation(); | |
252 | |
253 ASSERT_EQ(finish1, NodeProperties::GetValueInput(result, 0)); | |
254 } | |
255 | |
256 | |
257 TEST_F(EscapeAnalysisTest, BranchNonEscape) { | |
258 Node* object1 = Constant(1); | |
259 Node* object2 = Constant(2); | |
260 BeginRegion(); | |
261 Node* allocation = Allocate(Constant(kPointerSize)); | |
262 Store(AccessAtIndex(0), allocation, object1); | |
263 Node* finish = FinishRegion(allocation); | |
264 Branch(); | |
265 Node* ifFalse = IfFalse(); | |
266 Node* ifTrue = IfTrue(); | |
267 Node* effect1 = Store(AccessAtIndex(0), allocation, object1, finish, ifFalse); | |
268 Node* effect2 = Store(AccessAtIndex(0), allocation, object2, finish, ifTrue); | |
269 Node* merge = Merge2(ifFalse, ifTrue); | |
270 Node* phi = graph()->NewNode(common()->EffectPhi(2), effect1, effect2, merge); | |
271 Node* load = Load(AccessAtIndex(0), finish, phi, merge); | |
272 Node* result = Return(load, phi); | |
273 EndGraph(); | |
274 Analysis(); | |
275 | |
276 ExpectVirtual(allocation); | |
277 ExpectRepresentationPhi(load, object1, object2); | |
278 Node* replacement_phi = escape_objects()->GetReplacement(load, load->id()); | |
279 | |
280 Transformation(); | |
281 | |
282 ASSERT_EQ(replacement_phi, NodeProperties::GetValueInput(result, 0)); | |
283 } | |
284 | |
285 | |
286 TEST_F(EscapeAnalysisTest, DanglingLoadOrder) { | |
287 Node* object1 = Constant(1); | |
288 Node* object2 = Constant(2); | |
289 Node* allocation = Allocate(Constant(kPointerSize)); | |
290 Node* store1 = Store(AccessAtIndex(0), allocation, object1); | |
291 Node* load1 = Load(AccessAtIndex(0), allocation); | |
292 Store(AccessAtIndex(0), allocation, object2); | |
293 Node* load2 = Load(AccessAtIndex(0), allocation, store1); | |
294 Node* result = Return(load2); | |
295 EndGraph(); | |
296 | |
297 Analysis(); | |
298 | |
299 ExpectVirtual(allocation); | |
300 ExpectRepresentation(load1, object1); | |
301 ExpectRepresentation(load2, object1); | |
302 | |
303 Transformation(); | |
304 | |
305 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0)); | |
306 } | |
307 | |
308 } // namespace compiler | |
309 } // namespace internal | |
310 } // namespace v8 | |
OLD | NEW |