blob: 9b584a29f4c4d04c48b8fbfc5262235de4de6341 [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"
Ben Murdoch097c5b22016-05-18 11:27:45 +010012#include "src/types.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013#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
Ben Murdoch61f157c2016-09-16 13:49:30 +010051 return effect_ = graph()->NewNode(
52 common()->BeginRegion(RegionObservability::kObservable), effect);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000053 }
54
55 Node* FinishRegion(Node* value, Node* effect = nullptr) {
56 if (!effect) {
57 effect = effect_;
58 }
59 return effect_ = graph()->NewNode(common()->FinishRegion(), value, effect);
60 }
61
62 Node* Allocate(Node* size, Node* effect = nullptr, Node* control = nullptr) {
63 if (!effect) {
64 effect = effect_;
65 }
66 if (!control) {
67 control = control_;
68 }
69 return effect_ = graph()->NewNode(simplified()->Allocate(), size, effect,
70 control);
71 }
72
73 Node* Constant(int num) {
74 return graph()->NewNode(common()->NumberConstant(num));
75 }
76
77 Node* Store(const FieldAccess& access, Node* allocation, Node* value,
78 Node* effect = nullptr, Node* control = nullptr) {
79 if (!effect) {
80 effect = effect_;
81 }
82 if (!control) {
83 control = control_;
84 }
85 return effect_ = graph()->NewNode(simplified()->StoreField(access),
86 allocation, value, effect, control);
87 }
88
Ben Murdoch097c5b22016-05-18 11:27:45 +010089 Node* StoreElement(const ElementAccess& access, Node* allocation, Node* index,
90 Node* value, Node* effect = nullptr,
91 Node* control = nullptr) {
92 if (!effect) {
93 effect = effect_;
94 }
95 if (!control) {
96 control = control_;
97 }
98 return effect_ =
99 graph()->NewNode(simplified()->StoreElement(access), allocation,
100 index, value, effect, control);
101 }
102
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000103 Node* Load(const FieldAccess& access, Node* from, Node* effect = nullptr,
104 Node* control = nullptr) {
105 if (!effect) {
106 effect = effect_;
107 }
108 if (!control) {
109 control = control_;
110 }
111 return graph()->NewNode(simplified()->LoadField(access), from, effect,
112 control);
113 }
114
115 Node* Return(Node* value, Node* effect = nullptr, Node* control = nullptr) {
116 if (!effect) {
117 effect = effect_;
118 }
119 if (!control) {
120 control = control_;
121 }
122 return control_ =
123 graph()->NewNode(common()->Return(), value, effect, control);
124 }
125
126 void EndGraph() {
127 for (Edge edge : graph()->end()->input_edges()) {
128 if (NodeProperties::IsControlEdge(edge)) {
129 edge.UpdateTo(control_);
130 }
131 }
132 }
133
134 Node* Branch() {
135 return control_ =
136 graph()->NewNode(common()->Branch(), Constant(0), control_);
137 }
138
139 Node* IfTrue() {
140 return control_ = graph()->NewNode(common()->IfTrue(), control_);
141 }
142
143 Node* IfFalse() { return graph()->NewNode(common()->IfFalse(), control_); }
144
145 Node* Merge2(Node* control1, Node* control2) {
146 return control_ = graph()->NewNode(common()->Merge(2), control1, control2);
147 }
148
Ben Murdoch097c5b22016-05-18 11:27:45 +0100149 FieldAccess FieldAccessAtIndex(int offset) {
Ben Murdochc5610432016-08-08 18:44:38 +0100150 FieldAccess access = {kTaggedBase,
151 offset,
152 MaybeHandle<Name>(),
153 Type::Any(),
154 MachineType::AnyTagged(),
155 kFullWriteBarrier};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000156 return access;
157 }
158
Ben Murdoch097c5b22016-05-18 11:27:45 +0100159 ElementAccess MakeElementAccess(int header_size) {
160 ElementAccess access = {kTaggedBase, header_size, Type::Any(),
Ben Murdochc5610432016-08-08 18:44:38 +0100161 MachineType::AnyTagged(), kFullWriteBarrier};
Ben Murdoch097c5b22016-05-18 11:27:45 +0100162 return access;
163 }
164
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000165 // ---------------------------------Assertion Helper--------------------------
166
167 void ExpectReplacement(Node* node, Node* rep) {
168 EXPECT_EQ(rep, escape_analysis()->GetReplacement(node));
169 }
170
171 void ExpectReplacementPhi(Node* node, Node* left, Node* right) {
172 Node* rep = escape_analysis()->GetReplacement(node);
173 ASSERT_NE(nullptr, rep);
174 ASSERT_EQ(IrOpcode::kPhi, rep->opcode());
175 EXPECT_EQ(left, NodeProperties::GetValueInput(rep, 0));
176 EXPECT_EQ(right, NodeProperties::GetValueInput(rep, 1));
177 }
178
179 void ExpectVirtual(Node* node) {
180 EXPECT_TRUE(node->opcode() == IrOpcode::kAllocate ||
181 node->opcode() == IrOpcode::kFinishRegion);
182 EXPECT_TRUE(escape_analysis()->IsVirtual(node));
183 }
184
185 void ExpectEscaped(Node* node) {
186 EXPECT_TRUE(node->opcode() == IrOpcode::kAllocate ||
187 node->opcode() == IrOpcode::kFinishRegion);
188 EXPECT_TRUE(escape_analysis()->IsEscaped(node));
189 }
190
191 SimplifiedOperatorBuilder* simplified() { return &simplified_; }
192
193 Node* effect() { return effect_; }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100194 Node* control() { return control_; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000195
196 private:
197 SimplifiedOperatorBuilder simplified_;
198 JSGraph jsgraph_;
199 EscapeAnalysis escape_analysis_;
200
201 Node* effect_;
202 Node* control_;
203};
204
205
206// -----------------------------------------------------------------------------
207// Test cases.
208
209
210TEST_F(EscapeAnalysisTest, StraightNonEscape) {
211 Node* object1 = Constant(1);
212 BeginRegion();
213 Node* allocation = Allocate(Constant(kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100214 Store(FieldAccessAtIndex(0), allocation, object1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000215 Node* finish = FinishRegion(allocation);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100216 Node* load = Load(FieldAccessAtIndex(0), finish);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000217 Node* result = Return(load);
218 EndGraph();
219
220 Analysis();
221
222 ExpectVirtual(allocation);
223 ExpectReplacement(load, object1);
224
225 Transformation();
226
227 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0));
228}
229
230
Ben Murdoch097c5b22016-05-18 11:27:45 +0100231TEST_F(EscapeAnalysisTest, StraightNonEscapeNonConstStore) {
232 Node* object1 = Constant(1);
233 Node* object2 = Constant(2);
234 BeginRegion();
235 Node* allocation = Allocate(Constant(kPointerSize));
236 Store(FieldAccessAtIndex(0), allocation, object1);
237 Node* index =
238 graph()->NewNode(common()->Select(MachineRepresentation::kTagged),
239 object1, object2, control());
240 StoreElement(MakeElementAccess(0), allocation, index, object1);
241 Node* finish = FinishRegion(allocation);
242 Node* load = Load(FieldAccessAtIndex(0), finish);
243 Node* result = Return(load);
244 EndGraph();
245
246 Analysis();
247
248 ExpectEscaped(allocation);
249 ExpectReplacement(load, nullptr);
250
251 Transformation();
252
253 ASSERT_EQ(load, NodeProperties::GetValueInput(result, 0));
254}
255
256
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000257TEST_F(EscapeAnalysisTest, StraightEscape) {
258 Node* object1 = Constant(1);
259 BeginRegion();
260 Node* allocation = Allocate(Constant(kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100261 Store(FieldAccessAtIndex(0), allocation, object1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000262 Node* finish = FinishRegion(allocation);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100263 Node* load = Load(FieldAccessAtIndex(0), finish);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000264 Node* result = Return(allocation);
265 EndGraph();
266 graph()->end()->AppendInput(zone(), load);
267
268 Analysis();
269
270 ExpectEscaped(allocation);
271 ExpectReplacement(load, object1);
272
273 Transformation();
274
275 ASSERT_EQ(allocation, NodeProperties::GetValueInput(result, 0));
276}
277
278
279TEST_F(EscapeAnalysisTest, StoreLoadEscape) {
280 Node* object1 = Constant(1);
281
282 BeginRegion();
283 Node* allocation1 = Allocate(Constant(kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100284 Store(FieldAccessAtIndex(0), allocation1, object1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000285 Node* finish1 = FinishRegion(allocation1);
286
287 BeginRegion();
288 Node* allocation2 = Allocate(Constant(kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100289 Store(FieldAccessAtIndex(0), allocation2, finish1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000290 Node* finish2 = FinishRegion(allocation2);
291
Ben Murdoch097c5b22016-05-18 11:27:45 +0100292 Node* load = Load(FieldAccessAtIndex(0), finish2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000293 Node* result = Return(load);
294 EndGraph();
295 Analysis();
296
297 ExpectEscaped(allocation1);
298 ExpectVirtual(allocation2);
299 ExpectReplacement(load, finish1);
300
301 Transformation();
302
303 ASSERT_EQ(finish1, NodeProperties::GetValueInput(result, 0));
304}
305
306
307TEST_F(EscapeAnalysisTest, BranchNonEscape) {
308 Node* object1 = Constant(1);
309 Node* object2 = Constant(2);
310 BeginRegion();
311 Node* allocation = Allocate(Constant(kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100312 Store(FieldAccessAtIndex(0), allocation, object1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000313 Node* finish = FinishRegion(allocation);
314 Branch();
315 Node* ifFalse = IfFalse();
316 Node* ifTrue = IfTrue();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100317 Node* effect1 =
318 Store(FieldAccessAtIndex(0), allocation, object1, finish, ifFalse);
319 Node* effect2 =
320 Store(FieldAccessAtIndex(0), allocation, object2, finish, ifTrue);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000321 Node* merge = Merge2(ifFalse, ifTrue);
322 Node* phi = graph()->NewNode(common()->EffectPhi(2), effect1, effect2, merge);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100323 Node* load = Load(FieldAccessAtIndex(0), finish, phi, merge);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000324 Node* result = Return(load, phi);
325 EndGraph();
326 graph()->end()->AppendInput(zone(), result);
327
328 Analysis();
329
330 ExpectVirtual(allocation);
331 ExpectReplacementPhi(load, object1, object2);
332 Node* replacement_phi = escape_analysis()->GetReplacement(load);
333
334 Transformation();
335
336 ASSERT_EQ(replacement_phi, NodeProperties::GetValueInput(result, 0));
337}
338
339
Ben Murdoch097c5b22016-05-18 11:27:45 +0100340TEST_F(EscapeAnalysisTest, BranchEscapeOne) {
341 Node* object1 = Constant(1);
342 Node* object2 = Constant(2);
343 Node* index = graph()->NewNode(common()->Parameter(0), start());
344 BeginRegion();
345 Node* allocation = Allocate(Constant(kPointerSize));
346 Store(FieldAccessAtIndex(0), allocation, object1);
347 Node* finish = FinishRegion(allocation);
348 Branch();
349 Node* ifFalse = IfFalse();
350 Node* ifTrue = IfTrue();
351 Node* effect1 =
352 Store(FieldAccessAtIndex(0), allocation, object1, finish, ifFalse);
353 Node* effect2 = StoreElement(MakeElementAccess(0), allocation, index, object2,
354 finish, ifTrue);
355 Node* merge = Merge2(ifFalse, ifTrue);
356 Node* phi = graph()->NewNode(common()->EffectPhi(2), effect1, effect2, merge);
357 Node* load = Load(FieldAccessAtIndex(0), finish, phi, merge);
358 Node* result = Return(load, phi);
359 EndGraph();
360
361 Analysis();
362
363 ExpectEscaped(allocation);
364 ExpectReplacement(load, nullptr);
365
366 Transformation();
367
368 ASSERT_EQ(load, NodeProperties::GetValueInput(result, 0));
369}
370
371
372TEST_F(EscapeAnalysisTest, BranchEscapeThroughStore) {
373 Node* object1 = Constant(1);
374 Node* object2 = Constant(2);
375 BeginRegion();
376 Node* allocation = Allocate(Constant(kPointerSize));
377 Store(FieldAccessAtIndex(0), allocation, object1);
378 FinishRegion(allocation);
379 BeginRegion();
380 Node* allocation2 = Allocate(Constant(kPointerSize));
381 Store(FieldAccessAtIndex(0), allocation, object2);
382 Node* finish2 = FinishRegion(allocation2);
383 Branch();
384 Node* ifFalse = IfFalse();
385 Node* ifTrue = IfTrue();
386 Node* effect1 =
387 Store(FieldAccessAtIndex(0), allocation, allocation2, finish2, ifFalse);
388 Node* merge = Merge2(ifFalse, ifTrue);
389 Node* phi = graph()->NewNode(common()->EffectPhi(2), effect1, finish2, merge);
390 Node* load = Load(FieldAccessAtIndex(0), finish2, phi, merge);
391 Node* result = Return(allocation, phi);
392 EndGraph();
393 graph()->end()->AppendInput(zone(), load);
394
395 Analysis();
396
397 ExpectEscaped(allocation);
398 ExpectEscaped(allocation2);
399 ExpectReplacement(load, nullptr);
400
401 Transformation();
402
403 ASSERT_EQ(allocation, NodeProperties::GetValueInput(result, 0));
404}
405
406
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000407TEST_F(EscapeAnalysisTest, DanglingLoadOrder) {
408 Node* object1 = Constant(1);
409 Node* object2 = Constant(2);
410 Node* allocation = Allocate(Constant(kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100411 Node* store1 = Store(FieldAccessAtIndex(0), allocation, object1);
412 Node* load1 = Load(FieldAccessAtIndex(0), allocation);
413 Node* store2 = Store(FieldAccessAtIndex(0), allocation, object2);
414 Node* load2 = Load(FieldAccessAtIndex(0), allocation, store1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000415 Node* result = Return(load2);
416 EndGraph();
417 graph()->end()->AppendInput(zone(), store2);
418 graph()->end()->AppendInput(zone(), load1);
419
420 Analysis();
421
422 ExpectVirtual(allocation);
423 ExpectReplacement(load1, object1);
424 ExpectReplacement(load2, object1);
425
426 Transformation();
427
428 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0));
429}
430
431
432TEST_F(EscapeAnalysisTest, DeoptReplacement) {
433 Node* object1 = Constant(1);
434 BeginRegion();
435 Node* allocation = Allocate(Constant(kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100436 Store(FieldAccessAtIndex(0), allocation, object1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000437 Node* finish = FinishRegion(allocation);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100438 Node* effect1 = Store(FieldAccessAtIndex(0), allocation, object1, finish);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000439 Branch();
440 Node* ifFalse = IfFalse();
441 Node* state_values1 = graph()->NewNode(common()->StateValues(1), finish);
442 Node* state_values2 = graph()->NewNode(common()->StateValues(0));
443 Node* state_values3 = graph()->NewNode(common()->StateValues(0));
444 Node* frame_state = graph()->NewNode(
445 common()->FrameState(BailoutId::None(), OutputFrameStateCombine::Ignore(),
446 nullptr),
447 state_values1, state_values2, state_values3, UndefinedConstant(),
448 graph()->start(), graph()->start());
449 Node* deopt = graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
450 frame_state, effect1, ifFalse);
451 Node* ifTrue = IfTrue();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100452 Node* load = Load(FieldAccessAtIndex(0), finish, effect1, ifTrue);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000453 Node* result = Return(load, effect1, ifTrue);
454 EndGraph();
455 graph()->end()->AppendInput(zone(), deopt);
456 Analysis();
457
458 ExpectVirtual(allocation);
459 ExpectReplacement(load, object1);
460
461 Transformation();
462
463 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0));
464 Node* object_state = NodeProperties::GetValueInput(state_values1, 0);
465 ASSERT_EQ(object_state->opcode(), IrOpcode::kObjectState);
466 ASSERT_EQ(1, object_state->op()->ValueInputCount());
467 ASSERT_EQ(object1, NodeProperties::GetValueInput(object_state, 0));
468}
469
470
471TEST_F(EscapeAnalysisTest, DeoptReplacementIdentity) {
472 Node* object1 = Constant(1);
473 BeginRegion();
474 Node* allocation = Allocate(Constant(kPointerSize * 2));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100475 Store(FieldAccessAtIndex(0), allocation, object1);
476 Store(FieldAccessAtIndex(kPointerSize), allocation, allocation);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000477 Node* finish = FinishRegion(allocation);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100478 Node* effect1 = Store(FieldAccessAtIndex(0), allocation, object1, finish);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000479 Branch();
480 Node* ifFalse = IfFalse();
481 Node* state_values1 = graph()->NewNode(common()->StateValues(1), finish);
482 Node* state_values2 = graph()->NewNode(common()->StateValues(1), finish);
483 Node* state_values3 = graph()->NewNode(common()->StateValues(0));
484 Node* frame_state = graph()->NewNode(
485 common()->FrameState(BailoutId::None(), OutputFrameStateCombine::Ignore(),
486 nullptr),
487 state_values1, state_values2, state_values3, UndefinedConstant(),
488 graph()->start(), graph()->start());
489 Node* deopt = graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
490 frame_state, effect1, ifFalse);
491 Node* ifTrue = IfTrue();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100492 Node* load = Load(FieldAccessAtIndex(0), finish, effect1, ifTrue);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000493 Node* result = Return(load, effect1, ifTrue);
494 EndGraph();
495 graph()->end()->AppendInput(zone(), deopt);
496 Analysis();
497
498 ExpectVirtual(allocation);
499 ExpectReplacement(load, object1);
500
501 Transformation();
502
503 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0));
504
505 Node* object_state = NodeProperties::GetValueInput(state_values1, 0);
506 ASSERT_EQ(object_state->opcode(), IrOpcode::kObjectState);
507 ASSERT_EQ(2, object_state->op()->ValueInputCount());
508 ASSERT_EQ(object1, NodeProperties::GetValueInput(object_state, 0));
509 ASSERT_EQ(object_state, NodeProperties::GetValueInput(object_state, 1));
510
511 Node* object_state2 = NodeProperties::GetValueInput(state_values1, 0);
512 ASSERT_EQ(object_state, object_state2);
513}
514
515} // namespace compiler
516} // namespace internal
517} // namespace v8