blob: b088367a583ec0f87933723718389ea189a1e090 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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/js-graph.h"
10#include "src/compiler/node-properties.h"
11#include "src/compiler/simplified-operator.h"
12#include "src/types-inl.h"
13#include "src/zone-containers.h"
14#include "test/unittests/compiler/graph-unittest.h"
15
16namespace v8 {
17namespace internal {
18namespace compiler {
19
20class EscapeAnalysisTest : public GraphTest {
21 public:
22 EscapeAnalysisTest()
23 : simplified_(zone()),
24 jsgraph_(isolate(), graph(), common(), nullptr, nullptr, nullptr),
25 escape_analysis_(graph(), common(), zone()),
26 effect_(graph()->start()),
27 control_(graph()->start()) {}
28
29 ~EscapeAnalysisTest() {}
30
31 EscapeAnalysis* escape_analysis() { return &escape_analysis_; }
32
33 protected:
34 void Analysis() { escape_analysis_.Run(); }
35
36 void Transformation() {
37 GraphReducer graph_reducer(zone(), graph());
38 EscapeAnalysisReducer escape_reducer(&graph_reducer, &jsgraph_,
39 &escape_analysis_, zone());
40 graph_reducer.AddReducer(&escape_reducer);
41 graph_reducer.ReduceGraph();
42 }
43
44 // ---------------------------------Node Creation Helper----------------------
45
46 Node* BeginRegion(Node* effect = nullptr) {
47 if (!effect) {
48 effect = effect_;
49 }
50
51 return effect_ = graph()->NewNode(common()->BeginRegion(), effect);
52 }
53
54 Node* FinishRegion(Node* value, Node* effect = nullptr) {
55 if (!effect) {
56 effect = effect_;
57 }
58 return effect_ = graph()->NewNode(common()->FinishRegion(), value, effect);
59 }
60
61 Node* Allocate(Node* size, Node* effect = nullptr, Node* control = nullptr) {
62 if (!effect) {
63 effect = effect_;
64 }
65 if (!control) {
66 control = control_;
67 }
68 return effect_ = graph()->NewNode(simplified()->Allocate(), size, effect,
69 control);
70 }
71
72 Node* Constant(int num) {
73 return graph()->NewNode(common()->NumberConstant(num));
74 }
75
76 Node* Store(const FieldAccess& access, Node* allocation, Node* value,
77 Node* effect = nullptr, Node* control = nullptr) {
78 if (!effect) {
79 effect = effect_;
80 }
81 if (!control) {
82 control = control_;
83 }
84 return effect_ = graph()->NewNode(simplified()->StoreField(access),
85 allocation, value, effect, control);
86 }
87
88 Node* Load(const FieldAccess& access, Node* from, Node* effect = nullptr,
89 Node* control = nullptr) {
90 if (!effect) {
91 effect = effect_;
92 }
93 if (!control) {
94 control = control_;
95 }
96 return graph()->NewNode(simplified()->LoadField(access), from, effect,
97 control);
98 }
99
100 Node* Return(Node* value, Node* effect = nullptr, Node* control = nullptr) {
101 if (!effect) {
102 effect = effect_;
103 }
104 if (!control) {
105 control = control_;
106 }
107 return control_ =
108 graph()->NewNode(common()->Return(), value, effect, control);
109 }
110
111 void EndGraph() {
112 for (Edge edge : graph()->end()->input_edges()) {
113 if (NodeProperties::IsControlEdge(edge)) {
114 edge.UpdateTo(control_);
115 }
116 }
117 }
118
119 Node* Branch() {
120 return control_ =
121 graph()->NewNode(common()->Branch(), Constant(0), control_);
122 }
123
124 Node* IfTrue() {
125 return control_ = graph()->NewNode(common()->IfTrue(), control_);
126 }
127
128 Node* IfFalse() { return graph()->NewNode(common()->IfFalse(), control_); }
129
130 Node* Merge2(Node* control1, Node* control2) {
131 return control_ = graph()->NewNode(common()->Merge(2), control1, control2);
132 }
133
134 FieldAccess AccessAtIndex(int offset) {
135 FieldAccess access = {kTaggedBase, offset, MaybeHandle<Name>(), Type::Any(),
136 MachineType::AnyTagged()};
137 return access;
138 }
139
140 // ---------------------------------Assertion Helper--------------------------
141
142 void ExpectReplacement(Node* node, Node* rep) {
143 EXPECT_EQ(rep, escape_analysis()->GetReplacement(node));
144 }
145
146 void ExpectReplacementPhi(Node* node, Node* left, Node* right) {
147 Node* rep = escape_analysis()->GetReplacement(node);
148 ASSERT_NE(nullptr, rep);
149 ASSERT_EQ(IrOpcode::kPhi, rep->opcode());
150 EXPECT_EQ(left, NodeProperties::GetValueInput(rep, 0));
151 EXPECT_EQ(right, NodeProperties::GetValueInput(rep, 1));
152 }
153
154 void ExpectVirtual(Node* node) {
155 EXPECT_TRUE(node->opcode() == IrOpcode::kAllocate ||
156 node->opcode() == IrOpcode::kFinishRegion);
157 EXPECT_TRUE(escape_analysis()->IsVirtual(node));
158 }
159
160 void ExpectEscaped(Node* node) {
161 EXPECT_TRUE(node->opcode() == IrOpcode::kAllocate ||
162 node->opcode() == IrOpcode::kFinishRegion);
163 EXPECT_TRUE(escape_analysis()->IsEscaped(node));
164 }
165
166 SimplifiedOperatorBuilder* simplified() { return &simplified_; }
167
168 Node* effect() { return effect_; }
169
170 private:
171 SimplifiedOperatorBuilder simplified_;
172 JSGraph jsgraph_;
173 EscapeAnalysis escape_analysis_;
174
175 Node* effect_;
176 Node* control_;
177};
178
179
180// -----------------------------------------------------------------------------
181// Test cases.
182
183
184TEST_F(EscapeAnalysisTest, StraightNonEscape) {
185 Node* object1 = Constant(1);
186 BeginRegion();
187 Node* allocation = Allocate(Constant(kPointerSize));
188 Store(AccessAtIndex(0), allocation, object1);
189 Node* finish = FinishRegion(allocation);
190 Node* load = Load(AccessAtIndex(0), finish);
191 Node* result = Return(load);
192 EndGraph();
193
194 Analysis();
195
196 ExpectVirtual(allocation);
197 ExpectReplacement(load, object1);
198
199 Transformation();
200
201 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0));
202}
203
204
205TEST_F(EscapeAnalysisTest, StraightEscape) {
206 Node* object1 = Constant(1);
207 BeginRegion();
208 Node* allocation = Allocate(Constant(kPointerSize));
209 Store(AccessAtIndex(0), allocation, object1);
210 Node* finish = FinishRegion(allocation);
211 Node* load = Load(AccessAtIndex(0), finish);
212 Node* result = Return(allocation);
213 EndGraph();
214 graph()->end()->AppendInput(zone(), load);
215
216 Analysis();
217
218 ExpectEscaped(allocation);
219 ExpectReplacement(load, object1);
220
221 Transformation();
222
223 ASSERT_EQ(allocation, NodeProperties::GetValueInput(result, 0));
224}
225
226
227TEST_F(EscapeAnalysisTest, StoreLoadEscape) {
228 Node* object1 = Constant(1);
229
230 BeginRegion();
231 Node* allocation1 = Allocate(Constant(kPointerSize));
232 Store(AccessAtIndex(0), allocation1, object1);
233 Node* finish1 = FinishRegion(allocation1);
234
235 BeginRegion();
236 Node* allocation2 = Allocate(Constant(kPointerSize));
237 Store(AccessAtIndex(0), allocation2, finish1);
238 Node* finish2 = FinishRegion(allocation2);
239
240 Node* load = Load(AccessAtIndex(0), finish2);
241 Node* result = Return(load);
242 EndGraph();
243 Analysis();
244
245 ExpectEscaped(allocation1);
246 ExpectVirtual(allocation2);
247 ExpectReplacement(load, finish1);
248
249 Transformation();
250
251 ASSERT_EQ(finish1, NodeProperties::GetValueInput(result, 0));
252}
253
254
255TEST_F(EscapeAnalysisTest, BranchNonEscape) {
256 Node* object1 = Constant(1);
257 Node* object2 = Constant(2);
258 BeginRegion();
259 Node* allocation = Allocate(Constant(kPointerSize));
260 Store(AccessAtIndex(0), allocation, object1);
261 Node* finish = FinishRegion(allocation);
262 Branch();
263 Node* ifFalse = IfFalse();
264 Node* ifTrue = IfTrue();
265 Node* effect1 = Store(AccessAtIndex(0), allocation, object1, finish, ifFalse);
266 Node* effect2 = Store(AccessAtIndex(0), allocation, object2, finish, ifTrue);
267 Node* merge = Merge2(ifFalse, ifTrue);
268 Node* phi = graph()->NewNode(common()->EffectPhi(2), effect1, effect2, merge);
269 Node* load = Load(AccessAtIndex(0), finish, phi, merge);
270 Node* result = Return(load, phi);
271 EndGraph();
272 graph()->end()->AppendInput(zone(), result);
273
274 Analysis();
275
276 ExpectVirtual(allocation);
277 ExpectReplacementPhi(load, object1, object2);
278 Node* replacement_phi = escape_analysis()->GetReplacement(load);
279
280 Transformation();
281
282 ASSERT_EQ(replacement_phi, NodeProperties::GetValueInput(result, 0));
283}
284
285
286TEST_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 Node* store2 = Store(AccessAtIndex(0), allocation, object2);
293 Node* load2 = Load(AccessAtIndex(0), allocation, store1);
294 Node* result = Return(load2);
295 EndGraph();
296 graph()->end()->AppendInput(zone(), store2);
297 graph()->end()->AppendInput(zone(), load1);
298
299 Analysis();
300
301 ExpectVirtual(allocation);
302 ExpectReplacement(load1, object1);
303 ExpectReplacement(load2, object1);
304
305 Transformation();
306
307 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0));
308}
309
310
311TEST_F(EscapeAnalysisTest, DeoptReplacement) {
312 Node* object1 = Constant(1);
313 BeginRegion();
314 Node* allocation = Allocate(Constant(kPointerSize));
315 Store(AccessAtIndex(0), allocation, object1);
316 Node* finish = FinishRegion(allocation);
317 Node* effect1 = Store(AccessAtIndex(0), allocation, object1, finish);
318 Branch();
319 Node* ifFalse = IfFalse();
320 Node* state_values1 = graph()->NewNode(common()->StateValues(1), finish);
321 Node* state_values2 = graph()->NewNode(common()->StateValues(0));
322 Node* state_values3 = graph()->NewNode(common()->StateValues(0));
323 Node* frame_state = graph()->NewNode(
324 common()->FrameState(BailoutId::None(), OutputFrameStateCombine::Ignore(),
325 nullptr),
326 state_values1, state_values2, state_values3, UndefinedConstant(),
327 graph()->start(), graph()->start());
328 Node* deopt = graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
329 frame_state, effect1, ifFalse);
330 Node* ifTrue = IfTrue();
331 Node* load = Load(AccessAtIndex(0), finish, effect1, ifTrue);
332 Node* result = Return(load, effect1, ifTrue);
333 EndGraph();
334 graph()->end()->AppendInput(zone(), deopt);
335 Analysis();
336
337 ExpectVirtual(allocation);
338 ExpectReplacement(load, object1);
339
340 Transformation();
341
342 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0));
343 Node* object_state = NodeProperties::GetValueInput(state_values1, 0);
344 ASSERT_EQ(object_state->opcode(), IrOpcode::kObjectState);
345 ASSERT_EQ(1, object_state->op()->ValueInputCount());
346 ASSERT_EQ(object1, NodeProperties::GetValueInput(object_state, 0));
347}
348
349
350TEST_F(EscapeAnalysisTest, DeoptReplacementIdentity) {
351 Node* object1 = Constant(1);
352 BeginRegion();
353 Node* allocation = Allocate(Constant(kPointerSize * 2));
354 Store(AccessAtIndex(0), allocation, object1);
355 Store(AccessAtIndex(kPointerSize), allocation, allocation);
356 Node* finish = FinishRegion(allocation);
357 Node* effect1 = Store(AccessAtIndex(0), allocation, object1, finish);
358 Branch();
359 Node* ifFalse = IfFalse();
360 Node* state_values1 = graph()->NewNode(common()->StateValues(1), finish);
361 Node* state_values2 = graph()->NewNode(common()->StateValues(1), finish);
362 Node* state_values3 = graph()->NewNode(common()->StateValues(0));
363 Node* frame_state = graph()->NewNode(
364 common()->FrameState(BailoutId::None(), OutputFrameStateCombine::Ignore(),
365 nullptr),
366 state_values1, state_values2, state_values3, UndefinedConstant(),
367 graph()->start(), graph()->start());
368 Node* deopt = graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
369 frame_state, effect1, ifFalse);
370 Node* ifTrue = IfTrue();
371 Node* load = Load(AccessAtIndex(0), finish, effect1, ifTrue);
372 Node* result = Return(load, effect1, ifTrue);
373 EndGraph();
374 graph()->end()->AppendInput(zone(), deopt);
375 Analysis();
376
377 ExpectVirtual(allocation);
378 ExpectReplacement(load, object1);
379
380 Transformation();
381
382 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0));
383
384 Node* object_state = NodeProperties::GetValueInput(state_values1, 0);
385 ASSERT_EQ(object_state->opcode(), IrOpcode::kObjectState);
386 ASSERT_EQ(2, object_state->op()->ValueInputCount());
387 ASSERT_EQ(object1, NodeProperties::GetValueInput(object_state, 0));
388 ASSERT_EQ(object_state, NodeProperties::GetValueInput(object_state, 1));
389
390 Node* object_state2 = NodeProperties::GetValueInput(state_values1, 0);
391 ASSERT_EQ(object_state, object_state2);
392}
393
394} // namespace compiler
395} // namespace internal
396} // namespace v8