Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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/load-elimination.h" | 5 #include "src/compiler/load-elimination.h" |
| 6 | 6 |
| 7 #include "src/compiler/common-operator.h" | 7 #include "src/compiler/common-operator.h" |
| 8 #include "src/compiler/js-graph.h" | 8 #include "src/compiler/js-graph.h" |
| 9 #include "src/compiler/node-properties.h" | 9 #include "src/compiler/node-properties.h" |
| 10 #include "src/compiler/simplified-operator.h" | 10 #include "src/compiler/simplified-operator.h" |
| 11 #include "src/factory.h" | |
| 12 #include "src/objects-inl.h" | |
| 11 | 13 |
| 12 namespace v8 { | 14 namespace v8 { |
| 13 namespace internal { | 15 namespace internal { |
| 14 namespace compiler { | 16 namespace compiler { |
| 15 | 17 |
| 16 namespace { | 18 namespace { |
| 17 | 19 |
| 18 enum Aliasing { kNoAlias, kMayAlias, kMustAlias }; | 20 enum Aliasing { kNoAlias, kMayAlias, kMustAlias }; |
| 19 | 21 |
| 20 Aliasing QueryAlias(Node* a, Node* b) { | 22 Aliasing QueryAlias(Node* a, Node* b) { |
| (...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 313 } | 315 } |
| 314 | 316 |
| 315 void LoadElimination::AbstractField::Print() const { | 317 void LoadElimination::AbstractField::Print() const { |
| 316 for (auto pair : info_for_node_) { | 318 for (auto pair : info_for_node_) { |
| 317 PrintF(" #%d:%s -> #%d:%s\n", pair.first->id(), | 319 PrintF(" #%d:%s -> #%d:%s\n", pair.first->id(), |
| 318 pair.first->op()->mnemonic(), pair.second->id(), | 320 pair.first->op()->mnemonic(), pair.second->id(), |
| 319 pair.second->op()->mnemonic()); | 321 pair.second->op()->mnemonic()); |
| 320 } | 322 } |
| 321 } | 323 } |
| 322 | 324 |
| 325 ZoneHandleSet<Map> LoadElimination::AbstractMaps::Lookup(Node* object) const { | |
| 326 for (auto pair : info_for_node_) { | |
| 327 if (MustAlias(object, pair.first)) return pair.second; | |
| 328 } | |
| 329 return ZoneHandleSet<Map>(); | |
| 330 } | |
| 331 | |
| 332 LoadElimination::AbstractMaps const* LoadElimination::AbstractMaps::Kill( | |
| 333 Node* object, Zone* zone) const { | |
| 334 for (auto pair : this->info_for_node_) { | |
| 335 if (MayAlias(object, pair.first)) { | |
| 336 AbstractMaps* that = new (zone) AbstractMaps(zone); | |
| 337 for (auto pair : this->info_for_node_) { | |
| 338 if (!MayAlias(object, pair.first)) that->info_for_node_.insert(pair); | |
| 339 } | |
| 340 return that; | |
| 341 } | |
| 342 } | |
| 343 return this; | |
| 344 } | |
| 345 | |
| 346 void LoadElimination::AbstractMaps::Print() const { | |
| 347 for (auto pair : info_for_node_) { | |
| 348 PrintF(" #%d:%s\n", pair.first->id(), | |
| 349 pair.first->op()->mnemonic()); | |
| 350 OFStream os(stdout); | |
| 351 ZoneHandleSet<Map> const& maps = pair.second; | |
| 352 for (size_t i = 0; i < maps.size(); ++i) { | |
| 353 os << " - " << Brief(*maps[i]) << "\n"; | |
| 354 } | |
| 355 } | |
| 356 } | |
| 357 | |
| 323 bool LoadElimination::AbstractState::Equals(AbstractState const* that) const { | 358 bool LoadElimination::AbstractState::Equals(AbstractState const* that) const { |
| 324 if (this->checks_) { | 359 if (this->checks_) { |
| 325 if (!that->checks_ || !that->checks_->Equals(this->checks_)) { | 360 if (!that->checks_ || !that->checks_->Equals(this->checks_)) { |
| 326 return false; | 361 return false; |
| 327 } | 362 } |
| 328 } else if (that->checks_) { | 363 } else if (that->checks_) { |
| 329 return false; | 364 return false; |
| 330 } | 365 } |
| 331 if (this->elements_) { | 366 if (this->elements_) { |
| 332 if (!that->elements_ || !that->elements_->Equals(this->elements_)) { | 367 if (!that->elements_ || !that->elements_->Equals(this->elements_)) { |
| 333 return false; | 368 return false; |
| 334 } | 369 } |
| 335 } else if (that->elements_) { | 370 } else if (that->elements_) { |
| 336 return false; | 371 return false; |
| 337 } | 372 } |
| 338 for (size_t i = 0u; i < arraysize(fields_); ++i) { | 373 for (size_t i = 0u; i < arraysize(fields_); ++i) { |
| 339 AbstractField const* this_field = this->fields_[i]; | 374 AbstractField const* this_field = this->fields_[i]; |
| 340 AbstractField const* that_field = that->fields_[i]; | 375 AbstractField const* that_field = that->fields_[i]; |
| 341 if (this_field) { | 376 if (this_field) { |
| 342 if (!that_field || !that_field->Equals(this_field)) return false; | 377 if (!that_field || !that_field->Equals(this_field)) return false; |
| 343 } else if (that_field) { | 378 } else if (that_field) { |
| 344 return false; | 379 return false; |
| 345 } | 380 } |
| 346 } | 381 } |
| 382 if (this->maps_) { | |
| 383 if (!that->maps_ || !that->maps_->Equals(this->maps_)) { | |
| 384 return false; | |
| 385 } | |
| 386 } else if (that->maps_) { | |
| 387 return false; | |
| 388 } | |
| 347 return true; | 389 return true; |
| 348 } | 390 } |
| 349 | 391 |
| 350 void LoadElimination::AbstractState::Merge(AbstractState const* that, | 392 void LoadElimination::AbstractState::Merge(AbstractState const* that, |
| 351 Zone* zone) { | 393 Zone* zone) { |
| 352 // Merge the information we have about the checks. | 394 // Merge the information we have about the checks. |
| 353 if (this->checks_) { | 395 if (this->checks_) { |
| 354 this->checks_ = | 396 this->checks_ = |
| 355 that->checks_ ? that->checks_->Merge(this->checks_, zone) : nullptr; | 397 that->checks_ ? that->checks_->Merge(this->checks_, zone) : nullptr; |
| 356 } | 398 } |
| 357 | 399 |
| 358 // Merge the information we have about the elements. | 400 // Merge the information we have about the elements. |
| 359 if (this->elements_) { | 401 if (this->elements_) { |
| 360 this->elements_ = that->elements_ | 402 this->elements_ = that->elements_ |
| 361 ? that->elements_->Merge(this->elements_, zone) | 403 ? that->elements_->Merge(this->elements_, zone) |
| 362 : nullptr; | 404 : nullptr; |
| 363 } | 405 } |
| 364 | 406 |
| 365 // Merge the information we have about the fields. | 407 // Merge the information we have about the fields. |
| 366 for (size_t i = 0; i < arraysize(fields_); ++i) { | 408 for (size_t i = 0; i < arraysize(fields_); ++i) { |
| 367 if (this->fields_[i]) { | 409 if (this->fields_[i]) { |
| 368 if (that->fields_[i]) { | 410 if (that->fields_[i]) { |
| 369 this->fields_[i] = this->fields_[i]->Merge(that->fields_[i], zone); | 411 this->fields_[i] = this->fields_[i]->Merge(that->fields_[i], zone); |
| 370 } else { | 412 } else { |
| 371 this->fields_[i] = nullptr; | 413 this->fields_[i] = nullptr; |
| 372 } | 414 } |
| 373 } | 415 } |
| 374 } | 416 } |
| 417 | |
| 418 // Merge the information we have about the maps. | |
| 419 if (this->maps_) { | |
| 420 this->maps_ = that->maps_ ? that->maps_->Merge(this->maps_, zone) : nullptr; | |
| 421 } | |
| 375 } | 422 } |
| 376 | 423 |
| 377 Node* LoadElimination::AbstractState::LookupCheck(Node* node) const { | 424 Node* LoadElimination::AbstractState::LookupCheck(Node* node) const { |
| 378 return this->checks_ ? this->checks_->Lookup(node) : nullptr; | 425 return this->checks_ ? this->checks_->Lookup(node) : nullptr; |
| 379 } | 426 } |
| 380 | 427 |
| 381 LoadElimination::AbstractState const* LoadElimination::AbstractState::AddCheck( | 428 LoadElimination::AbstractState const* LoadElimination::AbstractState::AddCheck( |
| 382 Node* node, Zone* zone) const { | 429 Node* node, Zone* zone) const { |
| 383 AbstractState* that = new (zone) AbstractState(*this); | 430 AbstractState* that = new (zone) AbstractState(*this); |
| 384 if (that->checks_) { | 431 if (that->checks_) { |
| 385 that->checks_ = that->checks_->Extend(node, zone); | 432 that->checks_ = that->checks_->Extend(node, zone); |
| 386 } else { | 433 } else { |
| 387 that->checks_ = new (zone) AbstractChecks(node, zone); | 434 that->checks_ = new (zone) AbstractChecks(node, zone); |
| 388 } | 435 } |
| 389 return that; | 436 return that; |
| 390 } | 437 } |
| 391 | 438 |
| 439 ZoneHandleSet<Map> LoadElimination::AbstractState::LookupMaps( | |
| 440 Node* object) const { | |
| 441 if (this->maps_) { | |
| 442 return this->maps_->Lookup(object); | |
| 443 } | |
| 444 return ZoneHandleSet<Map>(); | |
| 445 } | |
| 446 | |
| 447 LoadElimination::AbstractState const* LoadElimination::AbstractState::AddMaps( | |
| 448 Node* object, ZoneHandleSet<Map> maps, Zone* zone) const { | |
| 449 AbstractState* that = new (zone) AbstractState(*this); | |
| 450 if (that->maps_) { | |
| 451 that->maps_ = that->maps_->Extend(object, maps, zone); | |
| 452 } else { | |
| 453 that->maps_ = new (zone) AbstractMaps(object, maps, zone); | |
| 454 } | |
| 455 return that; | |
| 456 } | |
| 457 | |
| 458 LoadElimination::AbstractState const* LoadElimination::AbstractState::KillMaps( | |
| 459 Node* object, Zone* zone) const { | |
| 460 if (this->maps_) { | |
| 461 AbstractMaps const* that_maps = this->maps_->Kill(object, zone); | |
| 462 if (this->maps_ != that_maps) { | |
| 463 AbstractState* that = new (zone) AbstractState(*this); | |
| 464 that->maps_ = that_maps; | |
| 465 return that; | |
| 466 } | |
| 467 } | |
| 468 return this; | |
| 469 } | |
| 470 | |
| 392 Node* LoadElimination::AbstractState::LookupElement(Node* object, | 471 Node* LoadElimination::AbstractState::LookupElement(Node* object, |
| 393 Node* index) const { | 472 Node* index) const { |
| 394 if (this->elements_) { | 473 if (this->elements_) { |
| 395 return this->elements_->Lookup(object, index); | 474 return this->elements_->Lookup(object, index); |
| 396 } | 475 } |
| 397 return nullptr; | 476 return nullptr; |
| 398 } | 477 } |
| 399 | 478 |
| 400 LoadElimination::AbstractState const* | 479 LoadElimination::AbstractState const* |
| 401 LoadElimination::AbstractState::AddElement(Node* object, Node* index, | 480 LoadElimination::AbstractState::AddElement(Node* object, Node* index, |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 454 return this_field->Lookup(object); | 533 return this_field->Lookup(object); |
| 455 } | 534 } |
| 456 return nullptr; | 535 return nullptr; |
| 457 } | 536 } |
| 458 | 537 |
| 459 void LoadElimination::AbstractState::Print() const { | 538 void LoadElimination::AbstractState::Print() const { |
| 460 if (checks_) { | 539 if (checks_) { |
| 461 PrintF(" checks:\n"); | 540 PrintF(" checks:\n"); |
| 462 checks_->Print(); | 541 checks_->Print(); |
| 463 } | 542 } |
| 543 if (maps_) { | |
| 544 PrintF(" maps:\n"); | |
| 545 maps_->Print(); | |
| 546 } | |
| 464 if (elements_) { | 547 if (elements_) { |
| 465 PrintF(" elements:\n"); | 548 PrintF(" elements:\n"); |
| 466 elements_->Print(); | 549 elements_->Print(); |
| 467 } | 550 } |
| 468 for (size_t i = 0; i < arraysize(fields_); ++i) { | 551 for (size_t i = 0; i < arraysize(fields_); ++i) { |
| 469 if (AbstractField const* const field = fields_[i]) { | 552 if (AbstractField const* const field = fields_[i]) { |
| 470 PrintF(" field %zu:\n", i); | 553 PrintF(" field %zu:\n", i); |
| 471 field->Print(); | 554 field->Print(); |
| 472 } | 555 } |
| 473 } | 556 } |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 493 if (state == nullptr) return NoChange(); | 576 if (state == nullptr) return NoChange(); |
| 494 if (Node* const check = state->LookupCheck(node)) { | 577 if (Node* const check = state->LookupCheck(node)) { |
| 495 ReplaceWithValue(node, check, effect); | 578 ReplaceWithValue(node, check, effect); |
| 496 return Replace(check); | 579 return Replace(check); |
| 497 } | 580 } |
| 498 state = state->AddCheck(node, zone()); | 581 state = state->AddCheck(node, zone()); |
| 499 return UpdateState(node, state); | 582 return UpdateState(node, state); |
| 500 } | 583 } |
| 501 | 584 |
| 502 Reduction LoadElimination::ReduceCheckMaps(Node* node) { | 585 Reduction LoadElimination::ReduceCheckMaps(Node* node) { |
| 586 ZoneHandleSet<Map> const maps = CheckMapsParametersOf(node->op()).maps(); | |
| 503 Node* const object = NodeProperties::GetValueInput(node, 0); | 587 Node* const object = NodeProperties::GetValueInput(node, 0); |
| 504 Node* const effect = NodeProperties::GetEffectInput(node); | 588 Node* const effect = NodeProperties::GetEffectInput(node); |
| 505 AbstractState const* state = node_states_.Get(effect); | 589 AbstractState const* state = node_states_.Get(effect); |
| 506 if (state == nullptr) return NoChange(); | 590 if (state == nullptr) return NoChange(); |
| 507 int const map_input_count = node->op()->ValueInputCount() - 1; | 591 ZoneHandleSet<Map> object_maps = state->LookupMaps(object); |
| 508 if (Node* const object_map = | 592 if (object_maps.contains(maps)) return Replace(effect); |
|
Jarin
2016/11/16 14:54:41
Still confused.
If I have MapCheck(m1, m2); MapCh
Benedikt Meurer
2016/12/21 08:36:49
Done.
| |
| 509 state->LookupField(object, FieldIndexOf(HeapObject::kMapOffset))) { | 593 // TODO(intersect) |
| 510 for (int i = 0; i < map_input_count; ++i) { | 594 state = state->KillMaps(object, zone()); |
| 511 Node* map = NodeProperties::GetValueInput(node, 1 + i); | 595 state = state->AddMaps(object, maps, zone()); |
| 512 if (map == object_map) return Replace(effect); | |
| 513 } | |
| 514 } | |
| 515 if (map_input_count == 1) { | |
| 516 Node* const map0 = NodeProperties::GetValueInput(node, 1); | |
| 517 state = state->AddField(object, FieldIndexOf(HeapObject::kMapOffset), map0, | |
| 518 zone()); | |
| 519 } | |
| 520 return UpdateState(node, state); | 596 return UpdateState(node, state); |
| 521 } | 597 } |
| 522 | 598 |
| 523 Reduction LoadElimination::ReduceEnsureWritableFastElements(Node* node) { | 599 Reduction LoadElimination::ReduceEnsureWritableFastElements(Node* node) { |
| 524 Node* const object = NodeProperties::GetValueInput(node, 0); | 600 Node* const object = NodeProperties::GetValueInput(node, 0); |
| 525 Node* const elements = NodeProperties::GetValueInput(node, 1); | 601 Node* const elements = NodeProperties::GetValueInput(node, 1); |
| 526 Node* const effect = NodeProperties::GetEffectInput(node); | 602 Node* const effect = NodeProperties::GetEffectInput(node); |
| 527 AbstractState const* state = node_states_.Get(effect); | 603 AbstractState const* state = node_states_.Get(effect); |
| 528 if (state == nullptr) return NoChange(); | 604 if (state == nullptr) return NoChange(); |
| 529 Node* fixed_array_map = jsgraph()->FixedArrayMapConstant(); | |
| 530 if (Node* const elements_map = | |
| 531 state->LookupField(elements, FieldIndexOf(HeapObject::kMapOffset))) { | |
| 532 // Check if the {elements} already have the fixed array map. | 605 // Check if the {elements} already have the fixed array map. |
| 533 if (elements_map == fixed_array_map) { | 606 ZoneHandleSet<Map> elements_maps = state->LookupMaps(elements); |
| 534 ReplaceWithValue(node, elements, effect); | 607 ZoneHandleSet<Map> fixed_array_map(factory()->fixed_array_map()); |
| 535 return Replace(elements); | 608 if (elements_maps == fixed_array_map) { |
| 536 } | 609 ReplaceWithValue(node, elements, effect); |
| 610 return Replace(elements); | |
| 537 } | 611 } |
| 538 // We know that the resulting elements have the fixed array map. | 612 // We know that the resulting elements have the fixed array map. |
| 539 state = state->AddField(node, FieldIndexOf(HeapObject::kMapOffset), | 613 state = state->AddMaps(node, fixed_array_map, zone()); |
| 540 fixed_array_map, zone()); | |
| 541 // Kill the previous elements on {object}. | 614 // Kill the previous elements on {object}. |
| 542 state = | 615 state = |
| 543 state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), zone()); | 616 state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), zone()); |
| 544 // Add the new elements on {object}. | 617 // Add the new elements on {object}. |
| 545 state = state->AddField(object, FieldIndexOf(JSObject::kElementsOffset), node, | 618 state = state->AddField(object, FieldIndexOf(JSObject::kElementsOffset), node, |
| 546 zone()); | 619 zone()); |
| 547 return UpdateState(node, state); | 620 return UpdateState(node, state); |
| 548 } | 621 } |
| 549 | 622 |
| 550 Reduction LoadElimination::ReduceMaybeGrowFastElements(Node* node) { | 623 Reduction LoadElimination::ReduceMaybeGrowFastElements(Node* node) { |
| 551 GrowFastElementsFlags flags = GrowFastElementsFlagsOf(node->op()); | 624 GrowFastElementsFlags flags = GrowFastElementsFlagsOf(node->op()); |
| 552 Node* const object = NodeProperties::GetValueInput(node, 0); | 625 Node* const object = NodeProperties::GetValueInput(node, 0); |
| 553 Node* const effect = NodeProperties::GetEffectInput(node); | 626 Node* const effect = NodeProperties::GetEffectInput(node); |
| 554 AbstractState const* state = node_states_.Get(effect); | 627 AbstractState const* state = node_states_.Get(effect); |
| 555 if (state == nullptr) return NoChange(); | 628 if (state == nullptr) return NoChange(); |
| 556 if (flags & GrowFastElementsFlag::kDoubleElements) { | 629 if (flags & GrowFastElementsFlag::kDoubleElements) { |
| 557 // We know that the resulting elements have the fixed double array map. | 630 // We know that the resulting elements have the fixed double array map. |
| 558 Node* fixed_double_array_map = jsgraph()->FixedDoubleArrayMapConstant(); | 631 state = state->AddMaps( |
| 559 state = state->AddField(node, FieldIndexOf(HeapObject::kMapOffset), | 632 node, ZoneHandleSet<Map>(factory()->fixed_double_array_map()), zone()); |
| 560 fixed_double_array_map, zone()); | |
| 561 } else { | 633 } else { |
| 562 // We know that the resulting elements have the fixed array map. | 634 // We know that the resulting elements have the fixed array map. |
| 563 Node* fixed_array_map = jsgraph()->FixedArrayMapConstant(); | 635 state = state->AddMaps( |
| 564 state = state->AddField(node, FieldIndexOf(HeapObject::kMapOffset), | 636 node, ZoneHandleSet<Map>(factory()->fixed_array_map()), zone()); |
| 565 fixed_array_map, zone()); | |
| 566 } | 637 } |
| 567 if (flags & GrowFastElementsFlag::kArrayObject) { | 638 if (flags & GrowFastElementsFlag::kArrayObject) { |
| 568 // Kill the previous Array::length on {object}. | 639 // Kill the previous Array::length on {object}. |
| 569 state = | 640 state = |
| 570 state->KillField(object, FieldIndexOf(JSArray::kLengthOffset), zone()); | 641 state->KillField(object, FieldIndexOf(JSArray::kLengthOffset), zone()); |
| 571 } | 642 } |
| 572 // Kill the previous elements on {object}. | 643 // Kill the previous elements on {object}. |
| 573 state = | 644 state = |
| 574 state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), zone()); | 645 state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), zone()); |
| 575 // Add the new elements on {object}. | 646 // Add the new elements on {object}. |
| 576 state = state->AddField(object, FieldIndexOf(JSObject::kElementsOffset), node, | 647 state = state->AddField(object, FieldIndexOf(JSObject::kElementsOffset), node, |
| 577 zone()); | 648 zone()); |
| 578 return UpdateState(node, state); | 649 return UpdateState(node, state); |
| 579 } | 650 } |
| 580 | 651 |
| 581 Reduction LoadElimination::ReduceTransitionElementsKind(Node* node) { | 652 Reduction LoadElimination::ReduceTransitionElementsKind(Node* node) { |
| 582 Node* const object = NodeProperties::GetValueInput(node, 0); | 653 Node* const object = NodeProperties::GetValueInput(node, 0); |
| 583 Node* const source_map = NodeProperties::GetValueInput(node, 1); | 654 // Node* const source_map = NodeProperties::GetValueInput(node, 1); |
| 584 Node* const target_map = NodeProperties::GetValueInput(node, 2); | 655 // Node* const target_map = NodeProperties::GetValueInput(node, 2); |
| 585 Node* const effect = NodeProperties::GetEffectInput(node); | 656 Node* const effect = NodeProperties::GetEffectInput(node); |
| 586 AbstractState const* state = node_states_.Get(effect); | 657 AbstractState const* state = node_states_.Get(effect); |
| 587 if (state == nullptr) return NoChange(); | 658 if (state == nullptr) return NoChange(); |
| 659 // TODO(bmeurer): Put the map constants onto the operator. | |
| 660 // ZoneHandleSet<Map> object_maps = state->LookupMaps(object); | |
| 661 #if 0 | |
| 588 if (Node* const object_map = | 662 if (Node* const object_map = |
| 589 state->LookupField(object, FieldIndexOf(HeapObject::kMapOffset))) { | 663 state->LookupField(object, FieldIndexOf(HeapObject::kMapOffset))) { |
| 590 if (target_map == object_map) { | 664 if (target_map == object_map) { |
| 591 // The {object} already has the {target_map}, so this TransitionElements | 665 // The {object} already has the {target_map}, so this TransitionElements |
| 592 // {node} is fully redundant (independent of what {source_map} is). | 666 // {node} is fully redundant (independent of what {source_map} is). |
| 593 return Replace(effect); | 667 return Replace(effect); |
| 594 } | 668 } |
| 595 state = | 669 state = |
| 596 state->KillField(object, FieldIndexOf(HeapObject::kMapOffset), zone()); | 670 state->KillField(object, FieldIndexOf(HeapObject::kMapOffset), zone()); |
| 597 if (source_map == object_map) { | 671 if (source_map == object_map) { |
| 598 state = state->AddField(object, FieldIndexOf(HeapObject::kMapOffset), | 672 state = state->AddField(object, FieldIndexOf(HeapObject::kMapOffset), |
| 599 target_map, zone()); | 673 target_map, zone()); |
| 600 } | 674 } |
| 601 } else { | 675 } else { |
| 602 state = | 676 state = |
| 603 state->KillField(object, FieldIndexOf(HeapObject::kMapOffset), zone()); | 677 state->KillField(object, FieldIndexOf(HeapObject::kMapOffset), zone()); |
| 604 } | 678 } |
| 679 #else | |
| 680 state = state->KillMaps(object, zone()); | |
| 681 #endif | |
| 605 ElementsTransition transition = ElementsTransitionOf(node->op()); | 682 ElementsTransition transition = ElementsTransitionOf(node->op()); |
| 606 switch (transition) { | 683 switch (transition) { |
| 607 case ElementsTransition::kFastTransition: | 684 case ElementsTransition::kFastTransition: |
| 608 break; | 685 break; |
| 609 case ElementsTransition::kSlowTransition: | 686 case ElementsTransition::kSlowTransition: |
| 610 // Kill the elements as well. | 687 // Kill the elements as well. |
| 611 state = state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), | 688 state = state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), |
| 612 zone()); | 689 zone()); |
| 613 break; | 690 break; |
| 614 } | 691 } |
| 615 return UpdateState(node, state); | 692 return UpdateState(node, state); |
| 616 } | 693 } |
| 617 | 694 |
| 618 Reduction LoadElimination::ReduceLoadField(Node* node) { | 695 Reduction LoadElimination::ReduceLoadField(Node* node) { |
| 619 FieldAccess const& access = FieldAccessOf(node->op()); | 696 FieldAccess const& access = FieldAccessOf(node->op()); |
| 620 Node* const object = NodeProperties::GetValueInput(node, 0); | 697 Node* const object = NodeProperties::GetValueInput(node, 0); |
| 621 Node* const effect = NodeProperties::GetEffectInput(node); | 698 Node* const effect = NodeProperties::GetEffectInput(node); |
| 622 Node* const control = NodeProperties::GetControlInput(node); | 699 Node* const control = NodeProperties::GetControlInput(node); |
| 623 AbstractState const* state = node_states_.Get(effect); | 700 AbstractState const* state = node_states_.Get(effect); |
| 624 if (state == nullptr) return NoChange(); | 701 if (state == nullptr) return NoChange(); |
| 625 int field_index = FieldIndexOf(access); | 702 if (access.offset == HeapObject::kMapOffset) { |
| 626 if (field_index >= 0) { | 703 DCHECK_EQ(kTaggedBase, access.base_is_tagged); |
| 627 if (Node* replacement = state->LookupField(object, field_index)) { | 704 DCHECK(IsAnyTagged(access.machine_type.representation())); |
| 628 // Make sure we don't resurrect dead {replacement} nodes. | 705 ZoneHandleSet<Map> object_maps = state->LookupMaps(object); |
| 629 if (!replacement->IsDead()) { | 706 if (object_maps.size() == 1) { |
| 630 // We might need to guard the {replacement} if the type of the | 707 Node* value = jsgraph()->HeapConstant(object_maps[0]); |
| 631 // {node} is more precise than the type of the {replacement}. | 708 ReplaceWithValue(node, value, effect); |
| 632 Type* const node_type = NodeProperties::GetType(node); | 709 return Replace(value); |
| 633 if (!NodeProperties::GetType(replacement)->Is(node_type)) { | 710 } |
| 634 replacement = graph()->NewNode(common()->TypeGuard(node_type), | 711 } else { |
| 635 replacement, control); | 712 int field_index = FieldIndexOf(access); |
| 713 if (field_index >= 0) { | |
| 714 if (Node* replacement = state->LookupField(object, field_index)) { | |
| 715 // Make sure we don't resurrect dead {replacement} nodes. | |
| 716 if (!replacement->IsDead()) { | |
| 717 // We might need to guard the {replacement} if the type of the | |
| 718 // {node} is more precise than the type of the {replacement}. | |
| 719 Type* const node_type = NodeProperties::GetType(node); | |
| 720 if (!NodeProperties::GetType(replacement)->Is(node_type)) { | |
| 721 replacement = graph()->NewNode(common()->TypeGuard(node_type), | |
| 722 replacement, control); | |
| 723 } | |
| 724 ReplaceWithValue(node, replacement, effect); | |
| 725 return Replace(replacement); | |
| 636 } | 726 } |
| 637 ReplaceWithValue(node, replacement, effect); | |
| 638 return Replace(replacement); | |
| 639 } | 727 } |
| 728 state = state->AddField(object, field_index, node, zone()); | |
| 640 } | 729 } |
| 641 state = state->AddField(object, field_index, node, zone()); | |
| 642 } | 730 } |
| 643 return UpdateState(node, state); | 731 return UpdateState(node, state); |
| 644 } | 732 } |
| 645 | 733 |
| 646 Reduction LoadElimination::ReduceStoreField(Node* node) { | 734 Reduction LoadElimination::ReduceStoreField(Node* node) { |
| 647 FieldAccess const& access = FieldAccessOf(node->op()); | 735 FieldAccess const& access = FieldAccessOf(node->op()); |
| 648 Node* const object = NodeProperties::GetValueInput(node, 0); | 736 Node* const object = NodeProperties::GetValueInput(node, 0); |
| 649 Node* const new_value = NodeProperties::GetValueInput(node, 1); | 737 Node* const new_value = NodeProperties::GetValueInput(node, 1); |
| 650 Node* const effect = NodeProperties::GetEffectInput(node); | 738 Node* const effect = NodeProperties::GetEffectInput(node); |
| 651 AbstractState const* state = node_states_.Get(effect); | 739 AbstractState const* state = node_states_.Get(effect); |
| 652 if (state == nullptr) return NoChange(); | 740 if (state == nullptr) return NoChange(); |
| 653 int field_index = FieldIndexOf(access); | 741 if (access.offset == HeapObject::kMapOffset) { |
| 654 if (field_index >= 0) { | 742 DCHECK_EQ(kTaggedBase, access.base_is_tagged); |
| 655 Node* const old_value = state->LookupField(object, field_index); | 743 DCHECK(IsAnyTagged(access.machine_type.representation())); |
| 656 if (old_value == new_value) { | 744 // Kill all potential knowledge about the {object}s map. |
| 657 // This store is fully redundant. | 745 state = state->KillMaps(object, zone()); |
| 658 return Replace(effect); | 746 Type* const new_value_type = NodeProperties::GetType(new_value); |
| 747 if (new_value_type->IsConstant()) { | |
| 748 // Record the new {object} map information. | |
| 749 ZoneHandleSet<Map> object_maps( | |
| 750 Handle<Map>::cast(new_value_type->AsConstant()->Value())); | |
| 751 state = state->AddMaps(object, object_maps, zone()); | |
| 659 } | 752 } |
| 660 // Kill all potentially aliasing fields and record the new value. | |
| 661 state = state->KillField(object, field_index, zone()); | |
| 662 state = state->AddField(object, field_index, new_value, zone()); | |
| 663 } else { | 753 } else { |
| 664 // Unsupported StoreField operator. | 754 int field_index = FieldIndexOf(access); |
| 665 state = empty_state(); | 755 if (field_index >= 0) { |
| 756 Node* const old_value = state->LookupField(object, field_index); | |
| 757 if (old_value == new_value) { | |
| 758 // This store is fully redundant. | |
| 759 return Replace(effect); | |
| 760 } | |
| 761 // Kill all potentially aliasing fields and record the new value. | |
| 762 state = state->KillField(object, field_index, zone()); | |
| 763 state = state->AddField(object, field_index, new_value, zone()); | |
| 764 } else { | |
| 765 // Unsupported StoreField operator. | |
| 766 state = empty_state(); | |
| 767 } | |
| 666 } | 768 } |
| 667 return UpdateState(node, state); | 769 return UpdateState(node, state); |
| 668 } | 770 } |
| 669 | 771 |
| 670 Reduction LoadElimination::ReduceLoadElement(Node* node) { | 772 Reduction LoadElimination::ReduceLoadElement(Node* node) { |
| 671 Node* const object = NodeProperties::GetValueInput(node, 0); | 773 Node* const object = NodeProperties::GetValueInput(node, 0); |
| 672 Node* const index = NodeProperties::GetValueInput(node, 1); | 774 Node* const index = NodeProperties::GetValueInput(node, 1); |
| 673 Node* const effect = NodeProperties::GetEffectInput(node); | 775 Node* const effect = NodeProperties::GetEffectInput(node); |
| 674 Node* const control = NodeProperties::GetControlInput(node); | 776 Node* const control = NodeProperties::GetControlInput(node); |
| 675 AbstractState const* state = node_states_.Get(effect); | 777 AbstractState const* state = node_states_.Get(effect); |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 839 state = state->KillField( | 941 state = state->KillField( |
| 840 object, FieldIndexOf(JSObject::kElementsOffset), zone()); | 942 object, FieldIndexOf(JSObject::kElementsOffset), zone()); |
| 841 if (flags & GrowFastElementsFlag::kArrayObject) { | 943 if (flags & GrowFastElementsFlag::kArrayObject) { |
| 842 state = state->KillField( | 944 state = state->KillField( |
| 843 object, FieldIndexOf(JSArray::kLengthOffset), zone()); | 945 object, FieldIndexOf(JSArray::kLengthOffset), zone()); |
| 844 } | 946 } |
| 845 break; | 947 break; |
| 846 } | 948 } |
| 847 case IrOpcode::kTransitionElementsKind: { | 949 case IrOpcode::kTransitionElementsKind: { |
| 848 Node* const object = NodeProperties::GetValueInput(current, 0); | 950 Node* const object = NodeProperties::GetValueInput(current, 0); |
| 849 state = state->KillField( | 951 state = state->KillMaps(object, zone()); |
| 850 object, FieldIndexOf(HeapObject::kMapOffset), zone()); | |
| 851 state = state->KillField( | 952 state = state->KillField( |
| 852 object, FieldIndexOf(JSObject::kElementsOffset), zone()); | 953 object, FieldIndexOf(JSObject::kElementsOffset), zone()); |
| 853 break; | 954 break; |
| 854 } | 955 } |
| 855 case IrOpcode::kStoreField: { | 956 case IrOpcode::kStoreField: { |
| 856 FieldAccess const& access = FieldAccessOf(current->op()); | 957 FieldAccess const& access = FieldAccessOf(current->op()); |
| 857 Node* const object = NodeProperties::GetValueInput(current, 0); | 958 Node* const object = NodeProperties::GetValueInput(current, 0); |
| 858 int field_index = FieldIndexOf(access); | 959 int field_index = FieldIndexOf(access); |
| 859 if (field_index < 0) return empty_state(); | 960 if (field_index < 0) return empty_state(); |
| 860 state = state->KillField(object, field_index, zone()); | 961 state = state->KillField(object, field_index, zone()); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 881 } | 982 } |
| 882 } | 983 } |
| 883 return state; | 984 return state; |
| 884 } | 985 } |
| 885 | 986 |
| 886 // static | 987 // static |
| 887 int LoadElimination::FieldIndexOf(int offset) { | 988 int LoadElimination::FieldIndexOf(int offset) { |
| 888 DCHECK_EQ(0, offset % kPointerSize); | 989 DCHECK_EQ(0, offset % kPointerSize); |
| 889 int field_index = offset / kPointerSize; | 990 int field_index = offset / kPointerSize; |
| 890 if (field_index >= static_cast<int>(kMaxTrackedFields)) return -1; | 991 if (field_index >= static_cast<int>(kMaxTrackedFields)) return -1; |
| 891 return field_index; | 992 DCHECK_LT(0, field_index); |
| 993 return field_index - 1; | |
| 892 } | 994 } |
| 893 | 995 |
| 894 // static | 996 // static |
| 895 int LoadElimination::FieldIndexOf(FieldAccess const& access) { | 997 int LoadElimination::FieldIndexOf(FieldAccess const& access) { |
| 896 MachineRepresentation rep = access.machine_type.representation(); | 998 MachineRepresentation rep = access.machine_type.representation(); |
| 897 switch (rep) { | 999 switch (rep) { |
| 898 case MachineRepresentation::kNone: | 1000 case MachineRepresentation::kNone: |
| 899 case MachineRepresentation::kBit: | 1001 case MachineRepresentation::kBit: |
| 900 UNREACHABLE(); | 1002 UNREACHABLE(); |
| 901 break; | 1003 break; |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 922 DCHECK_EQ(kTaggedBase, access.base_is_tagged); | 1024 DCHECK_EQ(kTaggedBase, access.base_is_tagged); |
| 923 return FieldIndexOf(access.offset); | 1025 return FieldIndexOf(access.offset); |
| 924 } | 1026 } |
| 925 | 1027 |
| 926 CommonOperatorBuilder* LoadElimination::common() const { | 1028 CommonOperatorBuilder* LoadElimination::common() const { |
| 927 return jsgraph()->common(); | 1029 return jsgraph()->common(); |
| 928 } | 1030 } |
| 929 | 1031 |
| 930 Graph* LoadElimination::graph() const { return jsgraph()->graph(); } | 1032 Graph* LoadElimination::graph() const { return jsgraph()->graph(); } |
| 931 | 1033 |
| 1034 Factory* LoadElimination::factory() const { return jsgraph()->factory(); } | |
| 1035 | |
| 932 } // namespace compiler | 1036 } // namespace compiler |
| 933 } // namespace internal | 1037 } // namespace internal |
| 934 } // namespace v8 | 1038 } // namespace v8 |
| OLD | NEW |