blob: d5e12ba0db4ef0b46d08712707c48d12eba16368 [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 Murdoch4a90d5f2016-03-22 12:00:34 +0000149 FieldAccess access = {kTaggedBase, offset, MaybeHandle<Name>(), Type::Any(),
150 MachineType::AnyTagged()};
151 return access;
152 }
153
Ben Murdoch097c5b22016-05-18 11:27:45 +0100154 ElementAccess MakeElementAccess(int header_size) {
155 ElementAccess access = {kTaggedBase, header_size, Type::Any(),
156 MachineType::AnyTagged()};
157 return access;
158 }
159
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000160 // ---------------------------------Assertion Helper--------------------------
161
162 void ExpectReplacement(Node* node, Node* rep) {
163 EXPECT_EQ(rep, escape_analysis()->GetReplacement(node));
164 }
165
166 void ExpectReplacementPhi(Node* node, Node* left, Node* right) {
167 Node* rep = escape_analysis()->GetReplacement(node);
168 ASSERT_NE(nullptr, rep);
169 ASSERT_EQ(IrOpcode::kPhi, rep->opcode());
170 EXPECT_EQ(left, NodeProperties::GetValueInput(rep, 0));
171 EXPECT_EQ(right, NodeProperties::GetValueInput(rep, 1));
172 }
173
174 void ExpectVirtual(Node* node) {
175 EXPECT_TRUE(node->opcode() == IrOpcode::kAllocate ||
176 node->opcode() == IrOpcode::kFinishRegion);
177 EXPECT_TRUE(escape_analysis()->IsVirtual(node));
178 }
179
180 void ExpectEscaped(Node* node) {
181 EXPECT_TRUE(node->opcode() == IrOpcode::kAllocate ||
182 node->opcode() == IrOpcode::kFinishRegion);
183 EXPECT_TRUE(escape_analysis()->IsEscaped(node));
184 }
185
186 SimplifiedOperatorBuilder* simplified() { return &simplified_; }
187
188 Node* effect() { return effect_; }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100189 Node* control() { return control_; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000190
191 private:
192 SimplifiedOperatorBuilder simplified_;
193 JSGraph jsgraph_;
194 EscapeAnalysis escape_analysis_;
195
196 Node* effect_;
197 Node* control_;
198};
199
200
201// -----------------------------------------------------------------------------
202// Test cases.
203
204
205TEST_F(EscapeAnalysisTest, StraightNonEscape) {
206 Node* object1 = Constant(1);
207 BeginRegion();
208 Node* allocation = Allocate(Constant(kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100209 Store(FieldAccessAtIndex(0), allocation, object1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000210 Node* finish = FinishRegion(allocation);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100211 Node* load = Load(FieldAccessAtIndex(0), finish);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000212 Node* result = Return(load);
213 EndGraph();
214
215 Analysis();
216
217 ExpectVirtual(allocation);
218 ExpectReplacement(load, object1);
219
220 Transformation();
221
222 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0));
223}
224
225
Ben Murdoch097c5b22016-05-18 11:27:45 +0100226TEST_F(EscapeAnalysisTest, StraightNonEscapeNonConstStore) {
227 Node* object1 = Constant(1);
228 Node* object2 = Constant(2);
229 BeginRegion();
230 Node* allocation = Allocate(Constant(kPointerSize));
231 Store(FieldAccessAtIndex(0), allocation, object1);
232 Node* index =
233 graph()->NewNode(common()->Select(MachineRepresentation::kTagged),
234 object1, object2, control());
235 StoreElement(MakeElementAccess(0), allocation, index, object1);
236 Node* finish = FinishRegion(allocation);
237 Node* load = Load(FieldAccessAtIndex(0), finish);
238 Node* result = Return(load);
239 EndGraph();
240
241 Analysis();
242
243 ExpectEscaped(allocation);
244 ExpectReplacement(load, nullptr);
245
246 Transformation();
247
248 ASSERT_EQ(load, NodeProperties::GetValueInput(result, 0));
249}
250
251
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000252TEST_F(EscapeAnalysisTest, StraightEscape) {
253 Node* object1 = Constant(1);
254 BeginRegion();
255 Node* allocation = Allocate(Constant(kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100256 Store(FieldAccessAtIndex(0), allocation, object1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000257 Node* finish = FinishRegion(allocation);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100258 Node* load = Load(FieldAccessAtIndex(0), finish);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000259 Node* result = Return(allocation);
260 EndGraph();
261 graph()->end()->AppendInput(zone(), load);
262
263 Analysis();
264
265 ExpectEscaped(allocation);
266 ExpectReplacement(load, object1);
267
268 Transformation();
269
270 ASSERT_EQ(allocation, NodeProperties::GetValueInput(result, 0));
271}
272
273
274TEST_F(EscapeAnalysisTest, StoreLoadEscape) {
275 Node* object1 = Constant(1);
276
277 BeginRegion();
278 Node* allocation1 = Allocate(Constant(kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100279 Store(FieldAccessAtIndex(0), allocation1, object1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000280 Node* finish1 = FinishRegion(allocation1);
281
282 BeginRegion();
283 Node* allocation2 = Allocate(Constant(kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100284 Store(FieldAccessAtIndex(0), allocation2, finish1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000285 Node* finish2 = FinishRegion(allocation2);
286
Ben Murdoch097c5b22016-05-18 11:27:45 +0100287 Node* load = Load(FieldAccessAtIndex(0), finish2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000288 Node* result = Return(load);
289 EndGraph();
290 Analysis();
291
292 ExpectEscaped(allocation1);
293 ExpectVirtual(allocation2);
294 ExpectReplacement(load, finish1);
295
296 Transformation();
297
298 ASSERT_EQ(finish1, NodeProperties::GetValueInput(result, 0));
299}
300
301
302TEST_F(EscapeAnalysisTest, BranchNonEscape) {
303 Node* object1 = Constant(1);
304 Node* object2 = Constant(2);
305 BeginRegion();
306 Node* allocation = Allocate(Constant(kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100307 Store(FieldAccessAtIndex(0), allocation, object1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000308 Node* finish = FinishRegion(allocation);
309 Branch();
310 Node* ifFalse = IfFalse();
311 Node* ifTrue = IfTrue();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100312 Node* effect1 =
313 Store(FieldAccessAtIndex(0), allocation, object1, finish, ifFalse);
314 Node* effect2 =
315 Store(FieldAccessAtIndex(0), allocation, object2, finish, ifTrue);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000316 Node* merge = Merge2(ifFalse, ifTrue);
317 Node* phi = graph()->NewNode(common()->EffectPhi(2), effect1, effect2, merge);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100318 Node* load = Load(FieldAccessAtIndex(0), finish, phi, merge);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000319 Node* result = Return(load, phi);
320 EndGraph();
321 graph()->end()->AppendInput(zone(), result);
322
323 Analysis();
324
325 ExpectVirtual(allocation);
326 ExpectReplacementPhi(load, object1, object2);
327 Node* replacement_phi = escape_analysis()->GetReplacement(load);
328
329 Transformation();
330
331 ASSERT_EQ(replacement_phi, NodeProperties::GetValueInput(result, 0));
332}
333
334
Ben Murdoch097c5b22016-05-18 11:27:45 +0100335TEST_F(EscapeAnalysisTest, BranchEscapeOne) {
336 Node* object1 = Constant(1);
337 Node* object2 = Constant(2);
338 Node* index = graph()->NewNode(common()->Parameter(0), start());
339 BeginRegion();
340 Node* allocation = Allocate(Constant(kPointerSize));
341 Store(FieldAccessAtIndex(0), allocation, object1);
342 Node* finish = FinishRegion(allocation);
343 Branch();
344 Node* ifFalse = IfFalse();
345 Node* ifTrue = IfTrue();
346 Node* effect1 =
347 Store(FieldAccessAtIndex(0), allocation, object1, finish, ifFalse);
348 Node* effect2 = StoreElement(MakeElementAccess(0), allocation, index, object2,
349 finish, ifTrue);
350 Node* merge = Merge2(ifFalse, ifTrue);
351 Node* phi = graph()->NewNode(common()->EffectPhi(2), effect1, effect2, merge);
352 Node* load = Load(FieldAccessAtIndex(0), finish, phi, merge);
353 Node* result = Return(load, phi);
354 EndGraph();
355
356 Analysis();
357
358 ExpectEscaped(allocation);
359 ExpectReplacement(load, nullptr);
360
361 Transformation();
362
363 ASSERT_EQ(load, NodeProperties::GetValueInput(result, 0));
364}
365
366
367TEST_F(EscapeAnalysisTest, BranchEscapeThroughStore) {
368 Node* object1 = Constant(1);
369 Node* object2 = Constant(2);
370 BeginRegion();
371 Node* allocation = Allocate(Constant(kPointerSize));
372 Store(FieldAccessAtIndex(0), allocation, object1);
373 FinishRegion(allocation);
374 BeginRegion();
375 Node* allocation2 = Allocate(Constant(kPointerSize));
376 Store(FieldAccessAtIndex(0), allocation, object2);
377 Node* finish2 = FinishRegion(allocation2);
378 Branch();
379 Node* ifFalse = IfFalse();
380 Node* ifTrue = IfTrue();
381 Node* effect1 =
382 Store(FieldAccessAtIndex(0), allocation, allocation2, finish2, ifFalse);
383 Node* merge = Merge2(ifFalse, ifTrue);
384 Node* phi = graph()->NewNode(common()->EffectPhi(2), effect1, finish2, merge);
385 Node* load = Load(FieldAccessAtIndex(0), finish2, phi, merge);
386 Node* result = Return(allocation, phi);
387 EndGraph();
388 graph()->end()->AppendInput(zone(), load);
389
390 Analysis();
391
392 ExpectEscaped(allocation);
393 ExpectEscaped(allocation2);
394 ExpectReplacement(load, nullptr);
395
396 Transformation();
397
398 ASSERT_EQ(allocation, NodeProperties::GetValueInput(result, 0));
399}
400
401
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000402TEST_F(EscapeAnalysisTest, DanglingLoadOrder) {
403 Node* object1 = Constant(1);
404 Node* object2 = Constant(2);
405 Node* allocation = Allocate(Constant(kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100406 Node* store1 = Store(FieldAccessAtIndex(0), allocation, object1);
407 Node* load1 = Load(FieldAccessAtIndex(0), allocation);
408 Node* store2 = Store(FieldAccessAtIndex(0), allocation, object2);
409 Node* load2 = Load(FieldAccessAtIndex(0), allocation, store1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000410 Node* result = Return(load2);
411 EndGraph();
412 graph()->end()->AppendInput(zone(), store2);
413 graph()->end()->AppendInput(zone(), load1);
414
415 Analysis();
416
417 ExpectVirtual(allocation);
418 ExpectReplacement(load1, object1);
419 ExpectReplacement(load2, object1);
420
421 Transformation();
422
423 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0));
424}
425
426
427TEST_F(EscapeAnalysisTest, DeoptReplacement) {
428 Node* object1 = Constant(1);
429 BeginRegion();
430 Node* allocation = Allocate(Constant(kPointerSize));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100431 Store(FieldAccessAtIndex(0), allocation, object1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000432 Node* finish = FinishRegion(allocation);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100433 Node* effect1 = Store(FieldAccessAtIndex(0), allocation, object1, finish);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000434 Branch();
435 Node* ifFalse = IfFalse();
436 Node* state_values1 = graph()->NewNode(common()->StateValues(1), finish);
437 Node* state_values2 = graph()->NewNode(common()->StateValues(0));
438 Node* state_values3 = graph()->NewNode(common()->StateValues(0));
439 Node* frame_state = graph()->NewNode(
440 common()->FrameState(BailoutId::None(), OutputFrameStateCombine::Ignore(),
441 nullptr),
442 state_values1, state_values2, state_values3, UndefinedConstant(),
443 graph()->start(), graph()->start());
444 Node* deopt = graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
445 frame_state, effect1, ifFalse);
446 Node* ifTrue = IfTrue();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100447 Node* load = Load(FieldAccessAtIndex(0), finish, effect1, ifTrue);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000448 Node* result = Return(load, effect1, ifTrue);
449 EndGraph();
450 graph()->end()->AppendInput(zone(), deopt);
451 Analysis();
452
453 ExpectVirtual(allocation);
454 ExpectReplacement(load, object1);
455
456 Transformation();
457
458 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0));
459 Node* object_state = NodeProperties::GetValueInput(state_values1, 0);
460 ASSERT_EQ(object_state->opcode(), IrOpcode::kObjectState);
461 ASSERT_EQ(1, object_state->op()->ValueInputCount());
462 ASSERT_EQ(object1, NodeProperties::GetValueInput(object_state, 0));
463}
464
465
466TEST_F(EscapeAnalysisTest, DeoptReplacementIdentity) {
467 Node* object1 = Constant(1);
468 BeginRegion();
469 Node* allocation = Allocate(Constant(kPointerSize * 2));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100470 Store(FieldAccessAtIndex(0), allocation, object1);
471 Store(FieldAccessAtIndex(kPointerSize), allocation, allocation);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000472 Node* finish = FinishRegion(allocation);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100473 Node* effect1 = Store(FieldAccessAtIndex(0), allocation, object1, finish);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000474 Branch();
475 Node* ifFalse = IfFalse();
476 Node* state_values1 = graph()->NewNode(common()->StateValues(1), finish);
477 Node* state_values2 = graph()->NewNode(common()->StateValues(1), finish);
478 Node* state_values3 = graph()->NewNode(common()->StateValues(0));
479 Node* frame_state = graph()->NewNode(
480 common()->FrameState(BailoutId::None(), OutputFrameStateCombine::Ignore(),
481 nullptr),
482 state_values1, state_values2, state_values3, UndefinedConstant(),
483 graph()->start(), graph()->start());
484 Node* deopt = graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
485 frame_state, effect1, ifFalse);
486 Node* ifTrue = IfTrue();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100487 Node* load = Load(FieldAccessAtIndex(0), finish, effect1, ifTrue);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000488 Node* result = Return(load, effect1, ifTrue);
489 EndGraph();
490 graph()->end()->AppendInput(zone(), deopt);
491 Analysis();
492
493 ExpectVirtual(allocation);
494 ExpectReplacement(load, object1);
495
496 Transformation();
497
498 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0));
499
500 Node* object_state = NodeProperties::GetValueInput(state_values1, 0);
501 ASSERT_EQ(object_state->opcode(), IrOpcode::kObjectState);
502 ASSERT_EQ(2, object_state->op()->ValueInputCount());
503 ASSERT_EQ(object1, NodeProperties::GetValueInput(object_state, 0));
504 ASSERT_EQ(object_state, NodeProperties::GetValueInput(object_state, 1));
505
506 Node* object_state2 = NodeProperties::GetValueInput(state_values1, 0);
507 ASSERT_EQ(object_state, object_state2);
508}
509
510} // namespace compiler
511} // namespace internal
512} // namespace v8