blob: 4c17ef25d59683a83823bc3730093f40f413f755 [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
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
Ben Murdoch097c5b22016-05-18 11:27:45 +010088 Node* StoreElement(const ElementAccess& access, Node* allocation, Node* index,
89 Node* value, Node* effect = nullptr,
90 Node* control = nullptr) {
91 if (!effect) {
92 effect = effect_;
93 }
94 if (!control) {
95 control = control_;
96 }
97 return effect_ =
98 graph()->NewNode(simplified()->StoreElement(access), allocation,
99 index, value, effect, control);
100 }
101
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000102 Node* Load(const FieldAccess& access, Node* from, Node* effect = nullptr,
103 Node* control = nullptr) {
104 if (!effect) {
105 effect = effect_;
106 }
107 if (!control) {
108 control = control_;
109 }
110 return graph()->NewNode(simplified()->LoadField(access), from, effect,
111 control);
112 }
113
114 Node* Return(Node* value, Node* effect = nullptr, Node* control = nullptr) {
115 if (!effect) {
116 effect = effect_;
117 }
118 if (!control) {
119 control = control_;
120 }
121 return control_ =
122 graph()->NewNode(common()->Return(), value, effect, control);
123 }
124
125 void EndGraph() {
126 for (Edge edge : graph()->end()->input_edges()) {
127 if (NodeProperties::IsControlEdge(edge)) {
128 edge.UpdateTo(control_);
129 }
130 }
131 }
132
133 Node* Branch() {
134 return control_ =
135 graph()->NewNode(common()->Branch(), Constant(0), control_);
136 }
137
138 Node* IfTrue() {
139 return control_ = graph()->NewNode(common()->IfTrue(), control_);
140 }
141
142 Node* IfFalse() { return graph()->NewNode(common()->IfFalse(), control_); }
143
144 Node* Merge2(Node* control1, Node* control2) {
145 return control_ = graph()->NewNode(common()->Merge(2), control1, control2);
146 }
147
Ben Murdoch097c5b22016-05-18 11:27:45 +0100148 FieldAccess FieldAccessAtIndex(int offset) {
Ben Murdochc5610432016-08-08 18:44:38 +0100149 FieldAccess access = {kTaggedBase,
150 offset,
151 MaybeHandle<Name>(),
152 Type::Any(),
153 MachineType::AnyTagged(),
154 kFullWriteBarrier};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000155 return access;
156 }
157
Ben Murdoch097c5b22016-05-18 11:27:45 +0100158 ElementAccess MakeElementAccess(int header_size) {
159 ElementAccess access = {kTaggedBase, header_size, Type::Any(),
Ben Murdochc5610432016-08-08 18:44:38 +0100160 MachineType::AnyTagged(), kFullWriteBarrier};
Ben Murdoch097c5b22016-05-18 11:27:45 +0100161 return access;
162 }
163
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000164 // ---------------------------------Assertion Helper--------------------------
165
166 void ExpectReplacement(Node* node, Node* rep) {
167 EXPECT_EQ(rep, escape_analysis()->GetReplacement(node));
168 }
169
170 void ExpectReplacementPhi(Node* node, Node* left, Node* right) {
171 Node* rep = escape_analysis()->GetReplacement(node);
172 ASSERT_NE(nullptr, rep);
173 ASSERT_EQ(IrOpcode::kPhi, rep->opcode());
174 EXPECT_EQ(left, NodeProperties::GetValueInput(rep, 0));
175 EXPECT_EQ(right, NodeProperties::GetValueInput(rep, 1));
176 }
177
178 void ExpectVirtual(Node* node) {
179 EXPECT_TRUE(node->opcode() == IrOpcode::kAllocate ||
180 node->opcode() == IrOpcode::kFinishRegion);
181 EXPECT_TRUE(escape_analysis()->IsVirtual(node));
182 }
183
184 void ExpectEscaped(Node* node) {
185 EXPECT_TRUE(node->opcode() == IrOpcode::kAllocate ||
186 node->opcode() == IrOpcode::kFinishRegion);
187 EXPECT_TRUE(escape_analysis()->IsEscaped(node));
188 }
189
190 SimplifiedOperatorBuilder* simplified() { return &simplified_; }
191
192 Node* effect() { return effect_; }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100193 Node* control() { return control_; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000194
195 private:
196 SimplifiedOperatorBuilder simplified_;
197 JSGraph jsgraph_;
198 EscapeAnalysis escape_analysis_;
199
200 Node* effect_;
201 Node* control_;
202};
203
204
205// -----------------------------------------------------------------------------
206// Test cases.
207
208
209TEST_F(EscapeAnalysisTest, StraightNonEscape) {
210 Node* object1 = Constant(1);
211 BeginRegion();
212 Node* allocation = Allocate(Constant(kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100213 Store(FieldAccessAtIndex(0), allocation, object1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000214 Node* finish = FinishRegion(allocation);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100215 Node* load = Load(FieldAccessAtIndex(0), finish);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000216 Node* result = Return(load);
217 EndGraph();
218
219 Analysis();
220
221 ExpectVirtual(allocation);
222 ExpectReplacement(load, object1);
223
224 Transformation();
225
226 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0));
227}
228
229
Ben Murdoch097c5b22016-05-18 11:27:45 +0100230TEST_F(EscapeAnalysisTest, StraightNonEscapeNonConstStore) {
231 Node* object1 = Constant(1);
232 Node* object2 = Constant(2);
233 BeginRegion();
234 Node* allocation = Allocate(Constant(kPointerSize));
235 Store(FieldAccessAtIndex(0), allocation, object1);
236 Node* index =
237 graph()->NewNode(common()->Select(MachineRepresentation::kTagged),
238 object1, object2, control());
239 StoreElement(MakeElementAccess(0), allocation, index, object1);
240 Node* finish = FinishRegion(allocation);
241 Node* load = Load(FieldAccessAtIndex(0), finish);
242 Node* result = Return(load);
243 EndGraph();
244
245 Analysis();
246
247 ExpectEscaped(allocation);
248 ExpectReplacement(load, nullptr);
249
250 Transformation();
251
252 ASSERT_EQ(load, NodeProperties::GetValueInput(result, 0));
253}
254
255
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000256TEST_F(EscapeAnalysisTest, StraightEscape) {
257 Node* object1 = Constant(1);
258 BeginRegion();
259 Node* allocation = Allocate(Constant(kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100260 Store(FieldAccessAtIndex(0), allocation, object1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000261 Node* finish = FinishRegion(allocation);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100262 Node* load = Load(FieldAccessAtIndex(0), finish);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000263 Node* result = Return(allocation);
264 EndGraph();
265 graph()->end()->AppendInput(zone(), load);
266
267 Analysis();
268
269 ExpectEscaped(allocation);
270 ExpectReplacement(load, object1);
271
272 Transformation();
273
274 ASSERT_EQ(allocation, NodeProperties::GetValueInput(result, 0));
275}
276
277
278TEST_F(EscapeAnalysisTest, StoreLoadEscape) {
279 Node* object1 = Constant(1);
280
281 BeginRegion();
282 Node* allocation1 = Allocate(Constant(kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100283 Store(FieldAccessAtIndex(0), allocation1, object1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000284 Node* finish1 = FinishRegion(allocation1);
285
286 BeginRegion();
287 Node* allocation2 = Allocate(Constant(kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100288 Store(FieldAccessAtIndex(0), allocation2, finish1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000289 Node* finish2 = FinishRegion(allocation2);
290
Ben Murdoch097c5b22016-05-18 11:27:45 +0100291 Node* load = Load(FieldAccessAtIndex(0), finish2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000292 Node* result = Return(load);
293 EndGraph();
294 Analysis();
295
296 ExpectEscaped(allocation1);
297 ExpectVirtual(allocation2);
298 ExpectReplacement(load, finish1);
299
300 Transformation();
301
302 ASSERT_EQ(finish1, NodeProperties::GetValueInput(result, 0));
303}
304
305
306TEST_F(EscapeAnalysisTest, BranchNonEscape) {
307 Node* object1 = Constant(1);
308 Node* object2 = Constant(2);
309 BeginRegion();
310 Node* allocation = Allocate(Constant(kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100311 Store(FieldAccessAtIndex(0), allocation, object1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000312 Node* finish = FinishRegion(allocation);
313 Branch();
314 Node* ifFalse = IfFalse();
315 Node* ifTrue = IfTrue();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100316 Node* effect1 =
317 Store(FieldAccessAtIndex(0), allocation, object1, finish, ifFalse);
318 Node* effect2 =
319 Store(FieldAccessAtIndex(0), allocation, object2, finish, ifTrue);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000320 Node* merge = Merge2(ifFalse, ifTrue);
321 Node* phi = graph()->NewNode(common()->EffectPhi(2), effect1, effect2, merge);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100322 Node* load = Load(FieldAccessAtIndex(0), finish, phi, merge);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000323 Node* result = Return(load, phi);
324 EndGraph();
325 graph()->end()->AppendInput(zone(), result);
326
327 Analysis();
328
329 ExpectVirtual(allocation);
330 ExpectReplacementPhi(load, object1, object2);
331 Node* replacement_phi = escape_analysis()->GetReplacement(load);
332
333 Transformation();
334
335 ASSERT_EQ(replacement_phi, NodeProperties::GetValueInput(result, 0));
336}
337
338
Ben Murdoch097c5b22016-05-18 11:27:45 +0100339TEST_F(EscapeAnalysisTest, BranchEscapeOne) {
340 Node* object1 = Constant(1);
341 Node* object2 = Constant(2);
342 Node* index = graph()->NewNode(common()->Parameter(0), start());
343 BeginRegion();
344 Node* allocation = Allocate(Constant(kPointerSize));
345 Store(FieldAccessAtIndex(0), allocation, object1);
346 Node* finish = FinishRegion(allocation);
347 Branch();
348 Node* ifFalse = IfFalse();
349 Node* ifTrue = IfTrue();
350 Node* effect1 =
351 Store(FieldAccessAtIndex(0), allocation, object1, finish, ifFalse);
352 Node* effect2 = StoreElement(MakeElementAccess(0), allocation, index, object2,
353 finish, ifTrue);
354 Node* merge = Merge2(ifFalse, ifTrue);
355 Node* phi = graph()->NewNode(common()->EffectPhi(2), effect1, effect2, merge);
356 Node* load = Load(FieldAccessAtIndex(0), finish, phi, merge);
357 Node* result = Return(load, phi);
358 EndGraph();
359
360 Analysis();
361
362 ExpectEscaped(allocation);
363 ExpectReplacement(load, nullptr);
364
365 Transformation();
366
367 ASSERT_EQ(load, NodeProperties::GetValueInput(result, 0));
368}
369
370
371TEST_F(EscapeAnalysisTest, BranchEscapeThroughStore) {
372 Node* object1 = Constant(1);
373 Node* object2 = Constant(2);
374 BeginRegion();
375 Node* allocation = Allocate(Constant(kPointerSize));
376 Store(FieldAccessAtIndex(0), allocation, object1);
377 FinishRegion(allocation);
378 BeginRegion();
379 Node* allocation2 = Allocate(Constant(kPointerSize));
380 Store(FieldAccessAtIndex(0), allocation, object2);
381 Node* finish2 = FinishRegion(allocation2);
382 Branch();
383 Node* ifFalse = IfFalse();
384 Node* ifTrue = IfTrue();
385 Node* effect1 =
386 Store(FieldAccessAtIndex(0), allocation, allocation2, finish2, ifFalse);
387 Node* merge = Merge2(ifFalse, ifTrue);
388 Node* phi = graph()->NewNode(common()->EffectPhi(2), effect1, finish2, merge);
389 Node* load = Load(FieldAccessAtIndex(0), finish2, phi, merge);
390 Node* result = Return(allocation, phi);
391 EndGraph();
392 graph()->end()->AppendInput(zone(), load);
393
394 Analysis();
395
396 ExpectEscaped(allocation);
397 ExpectEscaped(allocation2);
398 ExpectReplacement(load, nullptr);
399
400 Transformation();
401
402 ASSERT_EQ(allocation, NodeProperties::GetValueInput(result, 0));
403}
404
405
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000406TEST_F(EscapeAnalysisTest, DanglingLoadOrder) {
407 Node* object1 = Constant(1);
408 Node* object2 = Constant(2);
409 Node* allocation = Allocate(Constant(kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100410 Node* store1 = Store(FieldAccessAtIndex(0), allocation, object1);
411 Node* load1 = Load(FieldAccessAtIndex(0), allocation);
412 Node* store2 = Store(FieldAccessAtIndex(0), allocation, object2);
413 Node* load2 = Load(FieldAccessAtIndex(0), allocation, store1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000414 Node* result = Return(load2);
415 EndGraph();
416 graph()->end()->AppendInput(zone(), store2);
417 graph()->end()->AppendInput(zone(), load1);
418
419 Analysis();
420
421 ExpectVirtual(allocation);
422 ExpectReplacement(load1, object1);
423 ExpectReplacement(load2, object1);
424
425 Transformation();
426
427 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0));
428}
429
430
431TEST_F(EscapeAnalysisTest, DeoptReplacement) {
432 Node* object1 = Constant(1);
433 BeginRegion();
434 Node* allocation = Allocate(Constant(kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100435 Store(FieldAccessAtIndex(0), allocation, object1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000436 Node* finish = FinishRegion(allocation);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100437 Node* effect1 = Store(FieldAccessAtIndex(0), allocation, object1, finish);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000438 Branch();
439 Node* ifFalse = IfFalse();
440 Node* state_values1 = graph()->NewNode(common()->StateValues(1), finish);
441 Node* state_values2 = graph()->NewNode(common()->StateValues(0));
442 Node* state_values3 = graph()->NewNode(common()->StateValues(0));
443 Node* frame_state = graph()->NewNode(
444 common()->FrameState(BailoutId::None(), OutputFrameStateCombine::Ignore(),
445 nullptr),
446 state_values1, state_values2, state_values3, UndefinedConstant(),
447 graph()->start(), graph()->start());
448 Node* deopt = graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
449 frame_state, effect1, ifFalse);
450 Node* ifTrue = IfTrue();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100451 Node* load = Load(FieldAccessAtIndex(0), finish, effect1, ifTrue);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000452 Node* result = Return(load, effect1, ifTrue);
453 EndGraph();
454 graph()->end()->AppendInput(zone(), deopt);
455 Analysis();
456
457 ExpectVirtual(allocation);
458 ExpectReplacement(load, object1);
459
460 Transformation();
461
462 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0));
463 Node* object_state = NodeProperties::GetValueInput(state_values1, 0);
464 ASSERT_EQ(object_state->opcode(), IrOpcode::kObjectState);
465 ASSERT_EQ(1, object_state->op()->ValueInputCount());
466 ASSERT_EQ(object1, NodeProperties::GetValueInput(object_state, 0));
467}
468
469
470TEST_F(EscapeAnalysisTest, DeoptReplacementIdentity) {
471 Node* object1 = Constant(1);
472 BeginRegion();
473 Node* allocation = Allocate(Constant(kPointerSize * 2));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100474 Store(FieldAccessAtIndex(0), allocation, object1);
475 Store(FieldAccessAtIndex(kPointerSize), allocation, allocation);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000476 Node* finish = FinishRegion(allocation);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100477 Node* effect1 = Store(FieldAccessAtIndex(0), allocation, object1, finish);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000478 Branch();
479 Node* ifFalse = IfFalse();
480 Node* state_values1 = graph()->NewNode(common()->StateValues(1), finish);
481 Node* state_values2 = graph()->NewNode(common()->StateValues(1), finish);
482 Node* state_values3 = graph()->NewNode(common()->StateValues(0));
483 Node* frame_state = graph()->NewNode(
484 common()->FrameState(BailoutId::None(), OutputFrameStateCombine::Ignore(),
485 nullptr),
486 state_values1, state_values2, state_values3, UndefinedConstant(),
487 graph()->start(), graph()->start());
488 Node* deopt = graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
489 frame_state, effect1, ifFalse);
490 Node* ifTrue = IfTrue();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100491 Node* load = Load(FieldAccessAtIndex(0), finish, effect1, ifTrue);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000492 Node* result = Return(load, effect1, ifTrue);
493 EndGraph();
494 graph()->end()->AppendInput(zone(), deopt);
495 Analysis();
496
497 ExpectVirtual(allocation);
498 ExpectReplacement(load, object1);
499
500 Transformation();
501
502 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0));
503
504 Node* object_state = NodeProperties::GetValueInput(state_values1, 0);
505 ASSERT_EQ(object_state->opcode(), IrOpcode::kObjectState);
506 ASSERT_EQ(2, object_state->op()->ValueInputCount());
507 ASSERT_EQ(object1, NodeProperties::GetValueInput(object_state, 0));
508 ASSERT_EQ(object_state, NodeProperties::GetValueInput(object_state, 1));
509
510 Node* object_state2 = NodeProperties::GetValueInput(state_values1, 0);
511 ASSERT_EQ(object_state, object_state2);
512}
513
514} // namespace compiler
515} // namespace internal
516} // namespace v8