OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/escape-analysis.h" | 5 #include "src/compiler/escape-analysis.h" |
6 #include "src/bit-vector.h" | 6 #include "src/bit-vector.h" |
7 #include "src/compiler/escape-analysis-reducer.h" | 7 #include "src/compiler/escape-analysis-reducer.h" |
8 #include "src/compiler/graph-visualizer.h" | 8 #include "src/compiler/graph-visualizer.h" |
9 #include "src/compiler/js-graph.h" | 9 #include "src/compiler/js-graph.h" |
10 #include "src/compiler/node-properties.h" | 10 #include "src/compiler/node-properties.h" |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
112 control); | 112 control); |
113 } | 113 } |
114 | 114 |
115 Node* Return(Node* value, Node* effect = nullptr, Node* control = nullptr) { | 115 Node* Return(Node* value, Node* effect = nullptr, Node* control = nullptr) { |
116 if (!effect) { | 116 if (!effect) { |
117 effect = effect_; | 117 effect = effect_; |
118 } | 118 } |
119 if (!control) { | 119 if (!control) { |
120 control = control_; | 120 control = control_; |
121 } | 121 } |
122 return control_ = | 122 Node* zero = graph()->NewNode(common()->Int32Constant(0)); |
123 graph()->NewNode(common()->Return(), value, effect, control); | 123 return control_ = graph()->NewNode(common()->Return(), zero, value, effect, |
| 124 control); |
124 } | 125 } |
125 | 126 |
126 void EndGraph() { | 127 void EndGraph() { |
127 for (Edge edge : graph()->end()->input_edges()) { | 128 for (Edge edge : graph()->end()->input_edges()) { |
128 if (NodeProperties::IsControlEdge(edge)) { | 129 if (NodeProperties::IsControlEdge(edge)) { |
129 edge.UpdateTo(control_); | 130 edge.UpdateTo(control_); |
130 } | 131 } |
131 } | 132 } |
132 } | 133 } |
133 | 134 |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
217 Node* result = Return(load); | 218 Node* result = Return(load); |
218 EndGraph(); | 219 EndGraph(); |
219 | 220 |
220 Analysis(); | 221 Analysis(); |
221 | 222 |
222 ExpectVirtual(allocation); | 223 ExpectVirtual(allocation); |
223 ExpectReplacement(load, object1); | 224 ExpectReplacement(load, object1); |
224 | 225 |
225 Transformation(); | 226 Transformation(); |
226 | 227 |
227 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0)); | 228 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 1)); |
228 } | 229 } |
229 | 230 |
230 | 231 |
231 TEST_F(EscapeAnalysisTest, StraightNonEscapeNonConstStore) { | 232 TEST_F(EscapeAnalysisTest, StraightNonEscapeNonConstStore) { |
232 Node* object1 = Constant(1); | 233 Node* object1 = Constant(1); |
233 Node* object2 = Constant(2); | 234 Node* object2 = Constant(2); |
234 BeginRegion(); | 235 BeginRegion(); |
235 Node* allocation = Allocate(Constant(kPointerSize)); | 236 Node* allocation = Allocate(Constant(kPointerSize)); |
236 Store(FieldAccessAtIndex(0), allocation, object1); | 237 Store(FieldAccessAtIndex(0), allocation, object1); |
237 Node* index = | 238 Node* index = |
238 graph()->NewNode(common()->Select(MachineRepresentation::kTagged), | 239 graph()->NewNode(common()->Select(MachineRepresentation::kTagged), |
239 object1, object2, control()); | 240 object1, object2, control()); |
240 StoreElement(MakeElementAccess(0), allocation, index, object1); | 241 StoreElement(MakeElementAccess(0), allocation, index, object1); |
241 Node* finish = FinishRegion(allocation); | 242 Node* finish = FinishRegion(allocation); |
242 Node* load = Load(FieldAccessAtIndex(0), finish); | 243 Node* load = Load(FieldAccessAtIndex(0), finish); |
243 Node* result = Return(load); | 244 Node* result = Return(load); |
244 EndGraph(); | 245 EndGraph(); |
245 | 246 |
246 Analysis(); | 247 Analysis(); |
247 | 248 |
248 ExpectEscaped(allocation); | 249 ExpectEscaped(allocation); |
249 ExpectReplacement(load, nullptr); | 250 ExpectReplacement(load, nullptr); |
250 | 251 |
251 Transformation(); | 252 Transformation(); |
252 | 253 |
253 ASSERT_EQ(load, NodeProperties::GetValueInput(result, 0)); | 254 ASSERT_EQ(load, NodeProperties::GetValueInput(result, 1)); |
254 } | 255 } |
255 | 256 |
256 | 257 |
257 TEST_F(EscapeAnalysisTest, StraightEscape) { | 258 TEST_F(EscapeAnalysisTest, StraightEscape) { |
258 Node* object1 = Constant(1); | 259 Node* object1 = Constant(1); |
259 BeginRegion(); | 260 BeginRegion(); |
260 Node* allocation = Allocate(Constant(kPointerSize)); | 261 Node* allocation = Allocate(Constant(kPointerSize)); |
261 Store(FieldAccessAtIndex(0), allocation, object1); | 262 Store(FieldAccessAtIndex(0), allocation, object1); |
262 Node* finish = FinishRegion(allocation); | 263 Node* finish = FinishRegion(allocation); |
263 Node* load = Load(FieldAccessAtIndex(0), finish); | 264 Node* load = Load(FieldAccessAtIndex(0), finish); |
264 Node* result = Return(allocation); | 265 Node* result = Return(allocation); |
265 EndGraph(); | 266 EndGraph(); |
266 graph()->end()->AppendInput(zone(), load); | 267 graph()->end()->AppendInput(zone(), load); |
267 | 268 |
268 Analysis(); | 269 Analysis(); |
269 | 270 |
270 ExpectEscaped(allocation); | 271 ExpectEscaped(allocation); |
271 ExpectReplacement(load, object1); | 272 ExpectReplacement(load, object1); |
272 | 273 |
273 Transformation(); | 274 Transformation(); |
274 | 275 |
275 ASSERT_EQ(allocation, NodeProperties::GetValueInput(result, 0)); | 276 ASSERT_EQ(allocation, NodeProperties::GetValueInput(result, 1)); |
276 } | 277 } |
277 | 278 |
278 | 279 |
279 TEST_F(EscapeAnalysisTest, StoreLoadEscape) { | 280 TEST_F(EscapeAnalysisTest, StoreLoadEscape) { |
280 Node* object1 = Constant(1); | 281 Node* object1 = Constant(1); |
281 | 282 |
282 BeginRegion(); | 283 BeginRegion(); |
283 Node* allocation1 = Allocate(Constant(kPointerSize)); | 284 Node* allocation1 = Allocate(Constant(kPointerSize)); |
284 Store(FieldAccessAtIndex(0), allocation1, object1); | 285 Store(FieldAccessAtIndex(0), allocation1, object1); |
285 Node* finish1 = FinishRegion(allocation1); | 286 Node* finish1 = FinishRegion(allocation1); |
286 | 287 |
287 BeginRegion(); | 288 BeginRegion(); |
288 Node* allocation2 = Allocate(Constant(kPointerSize)); | 289 Node* allocation2 = Allocate(Constant(kPointerSize)); |
289 Store(FieldAccessAtIndex(0), allocation2, finish1); | 290 Store(FieldAccessAtIndex(0), allocation2, finish1); |
290 Node* finish2 = FinishRegion(allocation2); | 291 Node* finish2 = FinishRegion(allocation2); |
291 | 292 |
292 Node* load = Load(FieldAccessAtIndex(0), finish2); | 293 Node* load = Load(FieldAccessAtIndex(0), finish2); |
293 Node* result = Return(load); | 294 Node* result = Return(load); |
294 EndGraph(); | 295 EndGraph(); |
295 Analysis(); | 296 Analysis(); |
296 | 297 |
297 ExpectEscaped(allocation1); | 298 ExpectEscaped(allocation1); |
298 ExpectVirtual(allocation2); | 299 ExpectVirtual(allocation2); |
299 ExpectReplacement(load, finish1); | 300 ExpectReplacement(load, finish1); |
300 | 301 |
301 Transformation(); | 302 Transformation(); |
302 | 303 |
303 ASSERT_EQ(finish1, NodeProperties::GetValueInput(result, 0)); | 304 ASSERT_EQ(finish1, NodeProperties::GetValueInput(result, 1)); |
304 } | 305 } |
305 | 306 |
306 | 307 |
307 TEST_F(EscapeAnalysisTest, BranchNonEscape) { | 308 TEST_F(EscapeAnalysisTest, BranchNonEscape) { |
308 Node* object1 = Constant(1); | 309 Node* object1 = Constant(1); |
309 Node* object2 = Constant(2); | 310 Node* object2 = Constant(2); |
310 BeginRegion(); | 311 BeginRegion(); |
311 Node* allocation = Allocate(Constant(kPointerSize)); | 312 Node* allocation = Allocate(Constant(kPointerSize)); |
312 Store(FieldAccessAtIndex(0), allocation, object1); | 313 Store(FieldAccessAtIndex(0), allocation, object1); |
313 Node* finish = FinishRegion(allocation); | 314 Node* finish = FinishRegion(allocation); |
(...skipping 12 matching lines...) Expand all Loading... |
326 graph()->end()->AppendInput(zone(), result); | 327 graph()->end()->AppendInput(zone(), result); |
327 | 328 |
328 Analysis(); | 329 Analysis(); |
329 | 330 |
330 ExpectVirtual(allocation); | 331 ExpectVirtual(allocation); |
331 ExpectReplacementPhi(load, object1, object2); | 332 ExpectReplacementPhi(load, object1, object2); |
332 Node* replacement_phi = escape_analysis()->GetReplacement(load); | 333 Node* replacement_phi = escape_analysis()->GetReplacement(load); |
333 | 334 |
334 Transformation(); | 335 Transformation(); |
335 | 336 |
336 ASSERT_EQ(replacement_phi, NodeProperties::GetValueInput(result, 0)); | 337 ASSERT_EQ(replacement_phi, NodeProperties::GetValueInput(result, 1)); |
337 } | 338 } |
338 | 339 |
339 | 340 |
340 TEST_F(EscapeAnalysisTest, BranchEscapeOne) { | 341 TEST_F(EscapeAnalysisTest, BranchEscapeOne) { |
341 Node* object1 = Constant(1); | 342 Node* object1 = Constant(1); |
342 Node* object2 = Constant(2); | 343 Node* object2 = Constant(2); |
343 Node* index = graph()->NewNode(common()->Parameter(0), start()); | 344 Node* index = graph()->NewNode(common()->Parameter(0), start()); |
344 BeginRegion(); | 345 BeginRegion(); |
345 Node* allocation = Allocate(Constant(kPointerSize)); | 346 Node* allocation = Allocate(Constant(kPointerSize)); |
346 Store(FieldAccessAtIndex(0), allocation, object1); | 347 Store(FieldAccessAtIndex(0), allocation, object1); |
(...skipping 11 matching lines...) Expand all Loading... |
358 Node* result = Return(load, phi); | 359 Node* result = Return(load, phi); |
359 EndGraph(); | 360 EndGraph(); |
360 | 361 |
361 Analysis(); | 362 Analysis(); |
362 | 363 |
363 ExpectEscaped(allocation); | 364 ExpectEscaped(allocation); |
364 ExpectReplacement(load, nullptr); | 365 ExpectReplacement(load, nullptr); |
365 | 366 |
366 Transformation(); | 367 Transformation(); |
367 | 368 |
368 ASSERT_EQ(load, NodeProperties::GetValueInput(result, 0)); | 369 ASSERT_EQ(load, NodeProperties::GetValueInput(result, 1)); |
369 } | 370 } |
370 | 371 |
371 | 372 |
372 TEST_F(EscapeAnalysisTest, BranchEscapeThroughStore) { | 373 TEST_F(EscapeAnalysisTest, BranchEscapeThroughStore) { |
373 Node* object1 = Constant(1); | 374 Node* object1 = Constant(1); |
374 Node* object2 = Constant(2); | 375 Node* object2 = Constant(2); |
375 BeginRegion(); | 376 BeginRegion(); |
376 Node* allocation = Allocate(Constant(kPointerSize)); | 377 Node* allocation = Allocate(Constant(kPointerSize)); |
377 Store(FieldAccessAtIndex(0), allocation, object1); | 378 Store(FieldAccessAtIndex(0), allocation, object1); |
378 FinishRegion(allocation); | 379 FinishRegion(allocation); |
(...skipping 14 matching lines...) Expand all Loading... |
393 graph()->end()->AppendInput(zone(), load); | 394 graph()->end()->AppendInput(zone(), load); |
394 | 395 |
395 Analysis(); | 396 Analysis(); |
396 | 397 |
397 ExpectEscaped(allocation); | 398 ExpectEscaped(allocation); |
398 ExpectEscaped(allocation2); | 399 ExpectEscaped(allocation2); |
399 ExpectReplacement(load, nullptr); | 400 ExpectReplacement(load, nullptr); |
400 | 401 |
401 Transformation(); | 402 Transformation(); |
402 | 403 |
403 ASSERT_EQ(allocation, NodeProperties::GetValueInput(result, 0)); | 404 ASSERT_EQ(allocation, NodeProperties::GetValueInput(result, 1)); |
404 } | 405 } |
405 | 406 |
406 | 407 |
407 TEST_F(EscapeAnalysisTest, DanglingLoadOrder) { | 408 TEST_F(EscapeAnalysisTest, DanglingLoadOrder) { |
408 Node* object1 = Constant(1); | 409 Node* object1 = Constant(1); |
409 Node* object2 = Constant(2); | 410 Node* object2 = Constant(2); |
410 Node* allocation = Allocate(Constant(kPointerSize)); | 411 Node* allocation = Allocate(Constant(kPointerSize)); |
411 Node* store1 = Store(FieldAccessAtIndex(0), allocation, object1); | 412 Node* store1 = Store(FieldAccessAtIndex(0), allocation, object1); |
412 Node* load1 = Load(FieldAccessAtIndex(0), allocation); | 413 Node* load1 = Load(FieldAccessAtIndex(0), allocation); |
413 Node* store2 = Store(FieldAccessAtIndex(0), allocation, object2); | 414 Node* store2 = Store(FieldAccessAtIndex(0), allocation, object2); |
414 Node* load2 = Load(FieldAccessAtIndex(0), allocation, store1); | 415 Node* load2 = Load(FieldAccessAtIndex(0), allocation, store1); |
415 Node* result = Return(load2); | 416 Node* result = Return(load2); |
416 EndGraph(); | 417 EndGraph(); |
417 graph()->end()->AppendInput(zone(), store2); | 418 graph()->end()->AppendInput(zone(), store2); |
418 graph()->end()->AppendInput(zone(), load1); | 419 graph()->end()->AppendInput(zone(), load1); |
419 | 420 |
420 Analysis(); | 421 Analysis(); |
421 | 422 |
422 ExpectVirtual(allocation); | 423 ExpectVirtual(allocation); |
423 ExpectReplacement(load1, object1); | 424 ExpectReplacement(load1, object1); |
424 ExpectReplacement(load2, object1); | 425 ExpectReplacement(load2, object1); |
425 | 426 |
426 Transformation(); | 427 Transformation(); |
427 | 428 |
428 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0)); | 429 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 1)); |
429 } | 430 } |
430 | 431 |
431 | 432 |
432 TEST_F(EscapeAnalysisTest, DeoptReplacement) { | 433 TEST_F(EscapeAnalysisTest, DeoptReplacement) { |
433 Node* object1 = Constant(1); | 434 Node* object1 = Constant(1); |
434 BeginRegion(); | 435 BeginRegion(); |
435 Node* allocation = Allocate(Constant(kPointerSize)); | 436 Node* allocation = Allocate(Constant(kPointerSize)); |
436 Store(FieldAccessAtIndex(0), allocation, object1); | 437 Store(FieldAccessAtIndex(0), allocation, object1); |
437 Node* finish = FinishRegion(allocation); | 438 Node* finish = FinishRegion(allocation); |
438 Node* effect1 = Store(FieldAccessAtIndex(0), allocation, object1, finish); | 439 Node* effect1 = Store(FieldAccessAtIndex(0), allocation, object1, finish); |
(...skipping 15 matching lines...) Expand all Loading... |
454 Node* result = Return(load, effect1, ifTrue); | 455 Node* result = Return(load, effect1, ifTrue); |
455 EndGraph(); | 456 EndGraph(); |
456 graph()->end()->AppendInput(zone(), deopt); | 457 graph()->end()->AppendInput(zone(), deopt); |
457 Analysis(); | 458 Analysis(); |
458 | 459 |
459 ExpectVirtual(allocation); | 460 ExpectVirtual(allocation); |
460 ExpectReplacement(load, object1); | 461 ExpectReplacement(load, object1); |
461 | 462 |
462 Transformation(); | 463 Transformation(); |
463 | 464 |
464 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0)); | 465 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 1)); |
465 Node* object_state = NodeProperties::GetValueInput(state_values1, 0); | 466 Node* object_state = NodeProperties::GetValueInput(state_values1, 0); |
466 ASSERT_EQ(object_state->opcode(), IrOpcode::kObjectState); | 467 ASSERT_EQ(object_state->opcode(), IrOpcode::kObjectState); |
467 ASSERT_EQ(1, object_state->op()->ValueInputCount()); | 468 ASSERT_EQ(1, object_state->op()->ValueInputCount()); |
468 ASSERT_EQ(object1, NodeProperties::GetValueInput(object_state, 0)); | 469 ASSERT_EQ(object1, NodeProperties::GetValueInput(object_state, 0)); |
469 } | 470 } |
470 | 471 |
471 TEST_F(EscapeAnalysisTest, DISABLED_DeoptReplacementIdentity) { | 472 TEST_F(EscapeAnalysisTest, DISABLED_DeoptReplacementIdentity) { |
472 Node* object1 = Constant(1); | 473 Node* object1 = Constant(1); |
473 BeginRegion(); | 474 BeginRegion(); |
474 Node* allocation = Allocate(Constant(kPointerSize * 2)); | 475 Node* allocation = Allocate(Constant(kPointerSize * 2)); |
(...skipping 19 matching lines...) Expand all Loading... |
494 Node* result = Return(load, effect1, ifTrue); | 495 Node* result = Return(load, effect1, ifTrue); |
495 EndGraph(); | 496 EndGraph(); |
496 graph()->end()->AppendInput(zone(), deopt); | 497 graph()->end()->AppendInput(zone(), deopt); |
497 Analysis(); | 498 Analysis(); |
498 | 499 |
499 ExpectVirtual(allocation); | 500 ExpectVirtual(allocation); |
500 ExpectReplacement(load, object1); | 501 ExpectReplacement(load, object1); |
501 | 502 |
502 Transformation(); | 503 Transformation(); |
503 | 504 |
504 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0)); | 505 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 1)); |
505 | 506 |
506 Node* object_state = NodeProperties::GetValueInput(state_values1, 0); | 507 Node* object_state = NodeProperties::GetValueInput(state_values1, 0); |
507 ASSERT_EQ(object_state->opcode(), IrOpcode::kObjectState); | 508 ASSERT_EQ(object_state->opcode(), IrOpcode::kObjectState); |
508 ASSERT_EQ(2, object_state->op()->ValueInputCount()); | 509 ASSERT_EQ(2, object_state->op()->ValueInputCount()); |
509 ASSERT_EQ(object1, NodeProperties::GetValueInput(object_state, 0)); | 510 ASSERT_EQ(object1, NodeProperties::GetValueInput(object_state, 0)); |
510 ASSERT_EQ(object_state, NodeProperties::GetValueInput(object_state, 1)); | 511 ASSERT_EQ(object_state, NodeProperties::GetValueInput(object_state, 1)); |
511 | 512 |
512 Node* object_state2 = NodeProperties::GetValueInput(state_values1, 0); | 513 Node* object_state2 = NodeProperties::GetValueInput(state_values1, 0); |
513 ASSERT_EQ(object_state, object_state2); | 514 ASSERT_EQ(object_state, object_state2); |
514 } | 515 } |
515 | 516 |
516 } // namespace compiler | 517 } // namespace compiler |
517 } // namespace internal | 518 } // namespace internal |
518 } // namespace v8 | 519 } // namespace v8 |
OLD | NEW |