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(), nullptr, nullptr, nullptr, nullptr), | |
24 escape_status_(nullptr), | |
25 escape_objects_(nullptr), | |
26 effect_(graph()->start()), | |
27 control_(graph()->start()) {} | |
28 | |
29 ~EscapeAnalysisTest() { | |
30 if (escape_status_) { | |
31 delete escape_status_; | |
32 } | |
33 if (escape_objects_) { | |
34 delete escape_objects_; | |
35 } | |
36 } | |
37 | |
38 EscapeStatusAnalysis* escape_status() { return escape_status_; } | |
39 EscapeObjectAnalysis* escape_objects() { return escape_objects_; } | |
40 | |
41 protected: | |
42 void Analysis() { | |
43 escape_status_ = new EscapeStatusAnalysis(graph(), zone()); | |
Michael Starzinger
2015/11/30 10:05:39
Would it be possible to just embed these two class
sigurds
2015/11/30 13:50:24
Done.
| |
44 escape_status_->Run(); | |
45 escape_objects_ = new EscapeObjectAnalysis(graph(), common(), zone()); | |
46 escape_objects_->Run(); | |
47 } | |
48 | |
49 void Transformation() { | |
50 GraphReducer graph_reducer(zone(), graph()); | |
51 EscapeAnalysisReducer red(&graph_reducer, &jsgraph_, escape_status_, | |
52 escape_objects_, zone()); | |
53 graph_reducer.AddReducer(&red); | |
54 graph_reducer.ReduceGraph(); | |
55 } | |
56 | |
57 // ---------------------------------Node Creation Helper---------------------- | |
58 | |
59 Node* BeginRegion(Node* effect = nullptr) { | |
60 if (!effect) { | |
61 effect = effect_; | |
62 } | |
63 | |
64 return effect_ = graph()->NewNode(common()->BeginRegion(), effect); | |
65 } | |
66 | |
67 Node* FinishRegion(Node* value, Node* effect = nullptr) { | |
68 if (!effect) { | |
69 effect = effect_; | |
70 } | |
71 return effect_ = graph()->NewNode(common()->FinishRegion(), value, effect); | |
72 } | |
73 | |
74 Node* Allocate(Node* size, Node* effect = nullptr, Node* control = nullptr) { | |
75 if (!effect) { | |
76 effect = effect_; | |
77 } | |
78 if (!control) { | |
79 control = control_; | |
80 } | |
81 return effect_ = graph()->NewNode(simplified()->Allocate(), size, effect, | |
82 control); | |
83 } | |
84 | |
85 Node* Constant(int num) { | |
86 return graph()->NewNode(common()->NumberConstant(num)); | |
87 } | |
88 | |
89 Node* Store(const FieldAccess& access, Node* allocation, Node* value, | |
90 Node* effect = nullptr, Node* control = nullptr) { | |
91 if (!effect) { | |
92 effect = effect_; | |
93 } | |
94 if (!control) { | |
95 control = control_; | |
96 } | |
97 return effect_ = graph()->NewNode(simplified()->StoreField(access), | |
98 allocation, value, effect, control); | |
99 } | |
100 | |
101 Node* Load(const FieldAccess& access, Node* from, Node* effect = nullptr, | |
102 Node* control = nullptr) { | |
103 if (!effect) { | |
104 effect = effect_; | |
105 } | |
106 if (!control) { | |
107 control = control_; | |
108 } | |
109 return graph()->NewNode(simplified()->LoadField(access), from, effect, | |
110 control); | |
111 } | |
112 | |
113 Node* Return(Node* value, Node* effect = nullptr, Node* control = nullptr) { | |
114 if (!effect) { | |
115 effect = effect_; | |
116 } | |
117 if (!control) { | |
118 control = control_; | |
119 } | |
120 return control_ = | |
121 graph()->NewNode(common()->Return(), value, effect, control); | |
122 } | |
123 | |
124 void EndGraph() { | |
125 for (Edge edge : graph()->end()->input_edges()) { | |
126 if (NodeProperties::IsControlEdge(edge)) { | |
127 edge.UpdateTo(control_); | |
128 } | |
129 } | |
130 } | |
131 | |
132 Node* Branch() { | |
133 return control_ = | |
134 graph()->NewNode(common()->Branch(), Constant(0), control_); | |
135 } | |
136 | |
137 Node* IfTrue() { | |
138 return control_ = graph()->NewNode(common()->IfTrue(), control_); | |
139 } | |
140 | |
141 Node* IfFalse() { return graph()->NewNode(common()->IfFalse(), control_); } | |
142 | |
143 Node* Merge2(Node* control1, Node* control2) { | |
144 return control_ = graph()->NewNode(common()->Merge(2), control1, control2); | |
145 } | |
146 | |
147 FieldAccess AccessAtIndex(int offset) { | |
148 FieldAccess access = {kTaggedBase, offset, MaybeHandle<Name>(), Type::Any(), | |
149 kMachAnyTagged}; | |
150 return access; | |
151 } | |
152 | |
153 // ---------------------------------Assertion Helper-------------------------- | |
154 | |
155 void ExpectRepresentation(Node* node, Node* rep) { | |
156 EXPECT_EQ(rep, escape_objects()->representation(node, node->id())); | |
157 } | |
158 | |
159 void ExpectRepresentationPhi(Node* node, Node* left, Node* right) { | |
160 Node* rep = escape_objects()->representation(node, node->id()); | |
161 ASSERT_NE(nullptr, rep); | |
162 ASSERT_EQ(IrOpcode::kPhi, rep->opcode()); | |
163 EXPECT_EQ(left, NodeProperties::GetValueInput(rep, 0)); | |
164 EXPECT_EQ(right, NodeProperties::GetValueInput(rep, 1)); | |
165 } | |
166 | |
167 void ExpectVirtual(Node* node) { | |
168 EXPECT_TRUE(node->opcode() == IrOpcode::kAllocate || | |
169 node->opcode() == IrOpcode::kFinishRegion); | |
170 EXPECT_TRUE(escape_status()->IsVirtual(node)); | |
171 } | |
172 | |
173 void ExpectEscaped(Node* node) { | |
174 EXPECT_TRUE(node->opcode() == IrOpcode::kAllocate || | |
175 node->opcode() == IrOpcode::kFinishRegion); | |
176 EXPECT_TRUE(escape_status()->IsEscaped(node)); | |
177 } | |
178 | |
179 SimplifiedOperatorBuilder* simplified() { return &simplified_; } | |
180 | |
181 Node* effect() { return effect_; } | |
182 | |
183 private: | |
184 SimplifiedOperatorBuilder simplified_; | |
185 JSGraph jsgraph_; | |
186 EscapeStatusAnalysis* escape_status_; | |
187 EscapeObjectAnalysis* escape_objects_; | |
188 | |
189 Node* effect_; | |
190 Node* control_; | |
191 }; | |
192 | |
193 | |
194 // ----------------------------------------------------------------------------- | |
195 // Test cases. | |
196 | |
197 | |
198 TEST_F(EscapeAnalysisTest, StraightNonEscape) { | |
199 Node* object1 = Constant(1); | |
200 BeginRegion(); | |
201 Node* allocation = Allocate(Constant(8)); | |
202 Store(AccessAtIndex(0), allocation, object1); | |
203 Node* finish = FinishRegion(allocation); | |
204 Node* load = Load(AccessAtIndex(0), finish); | |
205 Node* result = Return(load); | |
206 EndGraph(); | |
207 Analysis(); | |
208 | |
209 ExpectVirtual(allocation); | |
210 ExpectRepresentation(load, object1); | |
211 | |
212 Transformation(); | |
213 | |
214 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0)); | |
215 } | |
216 | |
217 | |
218 TEST_F(EscapeAnalysisTest, StraightEscape) { | |
219 Node* object1 = Constant(1); | |
220 BeginRegion(); | |
221 Node* allocation = Allocate(Constant(8)); | |
222 Store(AccessAtIndex(0), allocation, object1); | |
223 Node* finish = FinishRegion(allocation); | |
224 Node* load = Load(AccessAtIndex(0), finish); | |
225 Node* result = Return(allocation); | |
226 EndGraph(); | |
227 Analysis(); | |
228 | |
229 ExpectEscaped(allocation); | |
230 ExpectRepresentation(load, object1); | |
231 | |
232 Transformation(); | |
233 | |
234 ASSERT_EQ(allocation, NodeProperties::GetValueInput(result, 0)); | |
235 } | |
236 | |
237 | |
238 TEST_F(EscapeAnalysisTest, BranchNonEscape) { | |
239 Node* object1 = Constant(1); | |
240 Node* object2 = Constant(2); | |
241 BeginRegion(); | |
242 Node* allocation = Allocate(Constant(8)); | |
243 Store(AccessAtIndex(0), allocation, object1); | |
244 Node* finish = FinishRegion(allocation); | |
245 Branch(); | |
246 Node* ifFalse = IfFalse(); | |
247 Node* ifTrue = IfTrue(); | |
248 Node* effect1 = Store(AccessAtIndex(0), allocation, object1, finish, ifFalse); | |
249 Node* effect2 = Store(AccessAtIndex(0), allocation, object2, finish, ifTrue); | |
250 Node* merge = Merge2(ifFalse, ifTrue); | |
251 Node* phi = graph()->NewNode(common()->EffectPhi(2), effect1, effect2, merge); | |
252 Node* load = Load(AccessAtIndex(0), finish, phi, merge); | |
253 Node* result = Return(load, phi); | |
254 EndGraph(); | |
255 Analysis(); | |
256 | |
257 ExpectVirtual(allocation); | |
258 ExpectRepresentationPhi(load, object1, object2); | |
259 Node* replacement_phi = escape_objects()->representation(load, load->id()); | |
260 | |
261 Transformation(); | |
262 | |
263 ASSERT_EQ(replacement_phi, NodeProperties::GetValueInput(result, 0)); | |
264 } | |
265 | |
266 | |
267 TEST_F(EscapeAnalysisTest, DanglingLoadOrder) { | |
268 Node* object1 = Constant(1); | |
269 Node* object2 = Constant(2); | |
270 Node* allocation = Allocate(Constant(8)); | |
271 Node* store1 = Store(AccessAtIndex(0), allocation, object1); | |
272 Node* load1 = Load(AccessAtIndex(0), allocation); | |
273 Store(AccessAtIndex(0), allocation, object2); | |
274 Node* load2 = Load(AccessAtIndex(0), allocation, store1); | |
275 Node* result = Return(load2); | |
276 EndGraph(); | |
277 | |
278 Analysis(); | |
279 | |
280 ExpectVirtual(allocation); | |
281 ExpectRepresentation(load1, object1); | |
282 ExpectRepresentation(load2, object1); | |
283 | |
284 Transformation(); | |
285 | |
286 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0)); | |
287 } | |
288 | |
289 } // namespace compiler | |
290 } // namespace internal | |
291 } // namespace v8 | |
OLD | NEW |