| 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 |