| 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 bool LoadElimination::AbstractMaps::Lookup( |
| 326 Node* object, ZoneHandleSet<Map>* object_maps) const { |
| 327 for (auto pair : info_for_node_) { |
| 328 if (MustAlias(object, pair.first)) { |
| 329 *object_maps = pair.second; |
| 330 return true; |
| 331 } |
| 332 } |
| 333 return false; |
| 334 } |
| 335 |
| 336 LoadElimination::AbstractMaps const* LoadElimination::AbstractMaps::Kill( |
| 337 Node* object, Zone* zone) const { |
| 338 for (auto pair : this->info_for_node_) { |
| 339 if (MayAlias(object, pair.first)) { |
| 340 AbstractMaps* that = new (zone) AbstractMaps(zone); |
| 341 for (auto pair : this->info_for_node_) { |
| 342 if (!MayAlias(object, pair.first)) that->info_for_node_.insert(pair); |
| 343 } |
| 344 return that; |
| 345 } |
| 346 } |
| 347 return this; |
| 348 } |
| 349 |
| 350 void LoadElimination::AbstractMaps::Print() const { |
| 351 for (auto pair : info_for_node_) { |
| 352 PrintF(" #%d:%s\n", pair.first->id(), pair.first->op()->mnemonic()); |
| 353 OFStream os(stdout); |
| 354 ZoneHandleSet<Map> const& maps = pair.second; |
| 355 for (size_t i = 0; i < maps.size(); ++i) { |
| 356 os << " - " << Brief(*maps[i]) << "\n"; |
| 357 } |
| 358 } |
| 359 } |
| 360 |
| 323 bool LoadElimination::AbstractState::Equals(AbstractState const* that) const { | 361 bool LoadElimination::AbstractState::Equals(AbstractState const* that) const { |
| 324 if (this->checks_) { | 362 if (this->checks_) { |
| 325 if (!that->checks_ || !that->checks_->Equals(this->checks_)) { | 363 if (!that->checks_ || !that->checks_->Equals(this->checks_)) { |
| 326 return false; | 364 return false; |
| 327 } | 365 } |
| 328 } else if (that->checks_) { | 366 } else if (that->checks_) { |
| 329 return false; | 367 return false; |
| 330 } | 368 } |
| 331 if (this->elements_) { | 369 if (this->elements_) { |
| 332 if (!that->elements_ || !that->elements_->Equals(this->elements_)) { | 370 if (!that->elements_ || !that->elements_->Equals(this->elements_)) { |
| 333 return false; | 371 return false; |
| 334 } | 372 } |
| 335 } else if (that->elements_) { | 373 } else if (that->elements_) { |
| 336 return false; | 374 return false; |
| 337 } | 375 } |
| 338 for (size_t i = 0u; i < arraysize(fields_); ++i) { | 376 for (size_t i = 0u; i < arraysize(fields_); ++i) { |
| 339 AbstractField const* this_field = this->fields_[i]; | 377 AbstractField const* this_field = this->fields_[i]; |
| 340 AbstractField const* that_field = that->fields_[i]; | 378 AbstractField const* that_field = that->fields_[i]; |
| 341 if (this_field) { | 379 if (this_field) { |
| 342 if (!that_field || !that_field->Equals(this_field)) return false; | 380 if (!that_field || !that_field->Equals(this_field)) return false; |
| 343 } else if (that_field) { | 381 } else if (that_field) { |
| 344 return false; | 382 return false; |
| 345 } | 383 } |
| 346 } | 384 } |
| 385 if (this->maps_) { |
| 386 if (!that->maps_ || !that->maps_->Equals(this->maps_)) { |
| 387 return false; |
| 388 } |
| 389 } else if (that->maps_) { |
| 390 return false; |
| 391 } |
| 347 return true; | 392 return true; |
| 348 } | 393 } |
| 349 | 394 |
| 350 void LoadElimination::AbstractState::Merge(AbstractState const* that, | 395 void LoadElimination::AbstractState::Merge(AbstractState const* that, |
| 351 Zone* zone) { | 396 Zone* zone) { |
| 352 // Merge the information we have about the checks. | 397 // Merge the information we have about the checks. |
| 353 if (this->checks_) { | 398 if (this->checks_) { |
| 354 this->checks_ = | 399 this->checks_ = |
| 355 that->checks_ ? that->checks_->Merge(this->checks_, zone) : nullptr; | 400 that->checks_ ? that->checks_->Merge(this->checks_, zone) : nullptr; |
| 356 } | 401 } |
| 357 | 402 |
| 358 // Merge the information we have about the elements. | 403 // Merge the information we have about the elements. |
| 359 if (this->elements_) { | 404 if (this->elements_) { |
| 360 this->elements_ = that->elements_ | 405 this->elements_ = that->elements_ |
| 361 ? that->elements_->Merge(this->elements_, zone) | 406 ? that->elements_->Merge(this->elements_, zone) |
| 362 : nullptr; | 407 : nullptr; |
| 363 } | 408 } |
| 364 | 409 |
| 365 // Merge the information we have about the fields. | 410 // Merge the information we have about the fields. |
| 366 for (size_t i = 0; i < arraysize(fields_); ++i) { | 411 for (size_t i = 0; i < arraysize(fields_); ++i) { |
| 367 if (this->fields_[i]) { | 412 if (this->fields_[i]) { |
| 368 if (that->fields_[i]) { | 413 if (that->fields_[i]) { |
| 369 this->fields_[i] = this->fields_[i]->Merge(that->fields_[i], zone); | 414 this->fields_[i] = this->fields_[i]->Merge(that->fields_[i], zone); |
| 370 } else { | 415 } else { |
| 371 this->fields_[i] = nullptr; | 416 this->fields_[i] = nullptr; |
| 372 } | 417 } |
| 373 } | 418 } |
| 374 } | 419 } |
| 420 |
| 421 // Merge the information we have about the maps. |
| 422 if (this->maps_) { |
| 423 this->maps_ = that->maps_ ? that->maps_->Merge(this->maps_, zone) : nullptr; |
| 424 } |
| 375 } | 425 } |
| 376 | 426 |
| 377 Node* LoadElimination::AbstractState::LookupCheck(Node* node) const { | 427 Node* LoadElimination::AbstractState::LookupCheck(Node* node) const { |
| 378 return this->checks_ ? this->checks_->Lookup(node) : nullptr; | 428 return this->checks_ ? this->checks_->Lookup(node) : nullptr; |
| 379 } | 429 } |
| 380 | 430 |
| 381 LoadElimination::AbstractState const* LoadElimination::AbstractState::AddCheck( | 431 LoadElimination::AbstractState const* LoadElimination::AbstractState::AddCheck( |
| 382 Node* node, Zone* zone) const { | 432 Node* node, Zone* zone) const { |
| 383 AbstractState* that = new (zone) AbstractState(*this); | 433 AbstractState* that = new (zone) AbstractState(*this); |
| 384 if (that->checks_) { | 434 if (that->checks_) { |
| 385 that->checks_ = that->checks_->Extend(node, zone); | 435 that->checks_ = that->checks_->Extend(node, zone); |
| 386 } else { | 436 } else { |
| 387 that->checks_ = new (zone) AbstractChecks(node, zone); | 437 that->checks_ = new (zone) AbstractChecks(node, zone); |
| 388 } | 438 } |
| 389 return that; | 439 return that; |
| 390 } | 440 } |
| 391 | 441 |
| 442 bool LoadElimination::AbstractState::LookupMaps( |
| 443 Node* object, ZoneHandleSet<Map>* object_map) const { |
| 444 return this->maps_ && this->maps_->Lookup(object, object_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 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 474 return this_field->Lookup(object); | 553 return this_field->Lookup(object); |
| 475 } | 554 } |
| 476 return nullptr; | 555 return nullptr; |
| 477 } | 556 } |
| 478 | 557 |
| 479 void LoadElimination::AbstractState::Print() const { | 558 void LoadElimination::AbstractState::Print() const { |
| 480 if (checks_) { | 559 if (checks_) { |
| 481 PrintF(" checks:\n"); | 560 PrintF(" checks:\n"); |
| 482 checks_->Print(); | 561 checks_->Print(); |
| 483 } | 562 } |
| 563 if (maps_) { |
| 564 PrintF(" maps:\n"); |
| 565 maps_->Print(); |
| 566 } |
| 484 if (elements_) { | 567 if (elements_) { |
| 485 PrintF(" elements:\n"); | 568 PrintF(" elements:\n"); |
| 486 elements_->Print(); | 569 elements_->Print(); |
| 487 } | 570 } |
| 488 for (size_t i = 0; i < arraysize(fields_); ++i) { | 571 for (size_t i = 0; i < arraysize(fields_); ++i) { |
| 489 if (AbstractField const* const field = fields_[i]) { | 572 if (AbstractField const* const field = fields_[i]) { |
| 490 PrintF(" field %zu:\n", i); | 573 PrintF(" field %zu:\n", i); |
| 491 field->Print(); | 574 field->Print(); |
| 492 } | 575 } |
| 493 } | 576 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 513 if (state == nullptr) return NoChange(); | 596 if (state == nullptr) return NoChange(); |
| 514 if (Node* const check = state->LookupCheck(node)) { | 597 if (Node* const check = state->LookupCheck(node)) { |
| 515 ReplaceWithValue(node, check, effect); | 598 ReplaceWithValue(node, check, effect); |
| 516 return Replace(check); | 599 return Replace(check); |
| 517 } | 600 } |
| 518 state = state->AddCheck(node, zone()); | 601 state = state->AddCheck(node, zone()); |
| 519 return UpdateState(node, state); | 602 return UpdateState(node, state); |
| 520 } | 603 } |
| 521 | 604 |
| 522 Reduction LoadElimination::ReduceCheckMaps(Node* node) { | 605 Reduction LoadElimination::ReduceCheckMaps(Node* node) { |
| 606 ZoneHandleSet<Map> const maps = CheckMapsParametersOf(node->op()).maps(); |
| 523 Node* const object = NodeProperties::GetValueInput(node, 0); | 607 Node* const object = NodeProperties::GetValueInput(node, 0); |
| 524 Node* const effect = NodeProperties::GetEffectInput(node); | 608 Node* const effect = NodeProperties::GetEffectInput(node); |
| 525 AbstractState const* state = node_states_.Get(effect); | 609 AbstractState const* state = node_states_.Get(effect); |
| 526 if (state == nullptr) return NoChange(); | 610 if (state == nullptr) return NoChange(); |
| 527 int const map_input_count = node->op()->ValueInputCount() - 1; | 611 ZoneHandleSet<Map> object_maps; |
| 528 if (Node* const object_map = | 612 if (state->LookupMaps(object, &object_maps)) { |
| 529 state->LookupField(object, FieldIndexOf(HeapObject::kMapOffset))) { | 613 if (maps.contains(object_maps)) return Replace(effect); |
| 530 for (int i = 0; i < map_input_count; ++i) { | 614 state = state->KillMaps(object, zone()); |
| 531 Node* map = NodeProperties::GetValueInput(node, 1 + i); | 615 // TODO(turbofan): Compute the intersection. |
| 532 if (map == object_map) return Replace(effect); | |
| 533 } | |
| 534 } | 616 } |
| 535 if (map_input_count == 1) { | 617 state = state->AddMaps(object, maps, zone()); |
| 536 Node* const map0 = NodeProperties::GetValueInput(node, 1); | |
| 537 state = state->AddField(object, FieldIndexOf(HeapObject::kMapOffset), map0, | |
| 538 zone()); | |
| 539 } | |
| 540 return UpdateState(node, state); | 618 return UpdateState(node, state); |
| 541 } | 619 } |
| 542 | 620 |
| 543 Reduction LoadElimination::ReduceEnsureWritableFastElements(Node* node) { | 621 Reduction LoadElimination::ReduceEnsureWritableFastElements(Node* node) { |
| 544 Node* const object = NodeProperties::GetValueInput(node, 0); | 622 Node* const object = NodeProperties::GetValueInput(node, 0); |
| 545 Node* const elements = NodeProperties::GetValueInput(node, 1); | 623 Node* const elements = NodeProperties::GetValueInput(node, 1); |
| 546 Node* const effect = NodeProperties::GetEffectInput(node); | 624 Node* const effect = NodeProperties::GetEffectInput(node); |
| 547 AbstractState const* state = node_states_.Get(effect); | 625 AbstractState const* state = node_states_.Get(effect); |
| 548 if (state == nullptr) return NoChange(); | 626 if (state == nullptr) return NoChange(); |
| 549 Node* fixed_array_map = jsgraph()->FixedArrayMapConstant(); | |
| 550 if (Node* const elements_map = | |
| 551 state->LookupField(elements, FieldIndexOf(HeapObject::kMapOffset))) { | |
| 552 // Check if the {elements} already have the fixed array map. | 627 // Check if the {elements} already have the fixed array map. |
| 553 if (elements_map == fixed_array_map) { | 628 ZoneHandleSet<Map> elements_maps; |
| 554 ReplaceWithValue(node, elements, effect); | 629 ZoneHandleSet<Map> fixed_array_maps(factory()->fixed_array_map()); |
| 555 return Replace(elements); | 630 if (state->LookupMaps(elements, &elements_maps) && |
| 556 } | 631 fixed_array_maps.contains(elements_maps)) { |
| 632 ReplaceWithValue(node, elements, effect); |
| 633 return Replace(elements); |
| 557 } | 634 } |
| 558 // We know that the resulting elements have the fixed array map. | 635 // We know that the resulting elements have the fixed array map. |
| 559 state = state->AddField(node, FieldIndexOf(HeapObject::kMapOffset), | 636 state = state->AddMaps(node, fixed_array_maps, zone()); |
| 560 fixed_array_map, zone()); | |
| 561 // Kill the previous elements on {object}. | 637 // Kill the previous elements on {object}. |
| 562 state = | 638 state = |
| 563 state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), zone()); | 639 state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), zone()); |
| 564 // Add the new elements on {object}. | 640 // Add the new elements on {object}. |
| 565 state = state->AddField(object, FieldIndexOf(JSObject::kElementsOffset), node, | 641 state = state->AddField(object, FieldIndexOf(JSObject::kElementsOffset), node, |
| 566 zone()); | 642 zone()); |
| 567 return UpdateState(node, state); | 643 return UpdateState(node, state); |
| 568 } | 644 } |
| 569 | 645 |
| 570 Reduction LoadElimination::ReduceMaybeGrowFastElements(Node* node) { | 646 Reduction LoadElimination::ReduceMaybeGrowFastElements(Node* node) { |
| 571 GrowFastElementsFlags flags = GrowFastElementsFlagsOf(node->op()); | 647 GrowFastElementsFlags flags = GrowFastElementsFlagsOf(node->op()); |
| 572 Node* const object = NodeProperties::GetValueInput(node, 0); | 648 Node* const object = NodeProperties::GetValueInput(node, 0); |
| 573 Node* const effect = NodeProperties::GetEffectInput(node); | 649 Node* const effect = NodeProperties::GetEffectInput(node); |
| 574 AbstractState const* state = node_states_.Get(effect); | 650 AbstractState const* state = node_states_.Get(effect); |
| 575 if (state == nullptr) return NoChange(); | 651 if (state == nullptr) return NoChange(); |
| 576 if (flags & GrowFastElementsFlag::kDoubleElements) { | 652 if (flags & GrowFastElementsFlag::kDoubleElements) { |
| 577 // We know that the resulting elements have the fixed double array map. | 653 // We know that the resulting elements have the fixed double array map. |
| 578 Node* fixed_double_array_map = jsgraph()->FixedDoubleArrayMapConstant(); | 654 state = state->AddMaps( |
| 579 state = state->AddField(node, FieldIndexOf(HeapObject::kMapOffset), | 655 node, ZoneHandleSet<Map>(factory()->fixed_double_array_map()), zone()); |
| 580 fixed_double_array_map, zone()); | |
| 581 } else { | 656 } else { |
| 582 // We know that the resulting elements have the fixed array map. | 657 // We know that the resulting elements have the fixed array map. |
| 583 Node* fixed_array_map = jsgraph()->FixedArrayMapConstant(); | 658 state = state->AddMaps( |
| 584 state = state->AddField(node, FieldIndexOf(HeapObject::kMapOffset), | 659 node, ZoneHandleSet<Map>(factory()->fixed_array_map()), zone()); |
| 585 fixed_array_map, zone()); | |
| 586 } | 660 } |
| 587 if (flags & GrowFastElementsFlag::kArrayObject) { | 661 if (flags & GrowFastElementsFlag::kArrayObject) { |
| 588 // Kill the previous Array::length on {object}. | 662 // Kill the previous Array::length on {object}. |
| 589 state = | 663 state = |
| 590 state->KillField(object, FieldIndexOf(JSArray::kLengthOffset), zone()); | 664 state->KillField(object, FieldIndexOf(JSArray::kLengthOffset), zone()); |
| 591 } | 665 } |
| 592 // Kill the previous elements on {object}. | 666 // Kill the previous elements on {object}. |
| 593 state = | 667 state = |
| 594 state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), zone()); | 668 state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), zone()); |
| 595 // Add the new elements on {object}. | 669 // Add the new elements on {object}. |
| 596 state = state->AddField(object, FieldIndexOf(JSObject::kElementsOffset), node, | 670 state = state->AddField(object, FieldIndexOf(JSObject::kElementsOffset), node, |
| 597 zone()); | 671 zone()); |
| 598 return UpdateState(node, state); | 672 return UpdateState(node, state); |
| 599 } | 673 } |
| 600 | 674 |
| 601 Reduction LoadElimination::ReduceTransitionElementsKind(Node* node) { | 675 Reduction LoadElimination::ReduceTransitionElementsKind(Node* node) { |
| 676 ElementsTransition transition = ElementsTransitionOf(node->op()); |
| 602 Node* const object = NodeProperties::GetValueInput(node, 0); | 677 Node* const object = NodeProperties::GetValueInput(node, 0); |
| 603 Node* const source_map = NodeProperties::GetValueInput(node, 1); | 678 Handle<Map> source_map(transition.source()); |
| 604 Node* const target_map = NodeProperties::GetValueInput(node, 2); | 679 Handle<Map> target_map(transition.target()); |
| 605 Node* const effect = NodeProperties::GetEffectInput(node); | 680 Node* const effect = NodeProperties::GetEffectInput(node); |
| 606 AbstractState const* state = node_states_.Get(effect); | 681 AbstractState const* state = node_states_.Get(effect); |
| 607 if (state == nullptr) return NoChange(); | 682 if (state == nullptr) return NoChange(); |
| 608 if (Node* const object_map = | 683 ZoneHandleSet<Map> object_maps; |
| 609 state->LookupField(object, FieldIndexOf(HeapObject::kMapOffset))) { | 684 if (state->LookupMaps(object, &object_maps)) { |
| 610 if (target_map == object_map) { | 685 if (ZoneHandleSet<Map>(target_map).contains(object_maps)) { |
| 611 // The {object} already has the {target_map}, so this TransitionElements | 686 // The {object} already has the {target_map}, so this TransitionElements |
| 612 // {node} is fully redundant (independent of what {source_map} is). | 687 // {node} is fully redundant (independent of what {source_map} is). |
| 613 return Replace(effect); | 688 return Replace(effect); |
| 614 } | 689 } |
| 615 state = | 690 if (object_maps.contains(ZoneHandleSet<Map>(source_map))) { |
| 616 state->KillField(object, FieldIndexOf(HeapObject::kMapOffset), zone()); | 691 object_maps.remove(source_map, zone()); |
| 617 if (source_map == object_map) { | 692 object_maps.insert(target_map, zone()); |
| 618 state = state->AddField(object, FieldIndexOf(HeapObject::kMapOffset), | 693 state = state->KillMaps(object, zone()); |
| 619 target_map, zone()); | 694 state = state->AddMaps(object, object_maps, zone()); |
| 620 } | 695 } |
| 621 } else { | 696 } else { |
| 622 state = | 697 state = state->KillMaps(object, zone()); |
| 623 state->KillField(object, FieldIndexOf(HeapObject::kMapOffset), zone()); | |
| 624 } | 698 } |
| 625 ElementsTransition transition = ElementsTransitionOf(node->op()); | 699 switch (transition.mode()) { |
| 626 switch (transition) { | |
| 627 case ElementsTransition::kFastTransition: | 700 case ElementsTransition::kFastTransition: |
| 628 break; | 701 break; |
| 629 case ElementsTransition::kSlowTransition: | 702 case ElementsTransition::kSlowTransition: |
| 630 // Kill the elements as well. | 703 // Kill the elements as well. |
| 631 state = state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), | 704 state = state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), |
| 632 zone()); | 705 zone()); |
| 633 break; | 706 break; |
| 634 } | 707 } |
| 635 return UpdateState(node, state); | 708 return UpdateState(node, state); |
| 636 } | 709 } |
| 637 | 710 |
| 638 Reduction LoadElimination::ReduceLoadField(Node* node) { | 711 Reduction LoadElimination::ReduceLoadField(Node* node) { |
| 639 FieldAccess const& access = FieldAccessOf(node->op()); | 712 FieldAccess const& access = FieldAccessOf(node->op()); |
| 640 Node* const object = NodeProperties::GetValueInput(node, 0); | 713 Node* const object = NodeProperties::GetValueInput(node, 0); |
| 641 Node* const effect = NodeProperties::GetEffectInput(node); | 714 Node* const effect = NodeProperties::GetEffectInput(node); |
| 642 Node* const control = NodeProperties::GetControlInput(node); | 715 Node* const control = NodeProperties::GetControlInput(node); |
| 643 AbstractState const* state = node_states_.Get(effect); | 716 AbstractState const* state = node_states_.Get(effect); |
| 644 if (state == nullptr) return NoChange(); | 717 if (state == nullptr) return NoChange(); |
| 645 int field_index = FieldIndexOf(access); | 718 if (access.offset == HeapObject::kMapOffset && |
| 646 if (field_index >= 0) { | 719 access.base_is_tagged == kTaggedBase) { |
| 647 if (Node* replacement = state->LookupField(object, field_index)) { | 720 DCHECK(IsAnyTagged(access.machine_type.representation())); |
| 648 // Make sure we don't resurrect dead {replacement} nodes. | 721 ZoneHandleSet<Map> object_maps; |
| 649 if (!replacement->IsDead()) { | 722 if (state->LookupMaps(object, &object_maps) && object_maps.size() == 1) { |
| 650 // We might need to guard the {replacement} if the type of the | 723 Node* value = jsgraph()->HeapConstant(object_maps[0]); |
| 651 // {node} is more precise than the type of the {replacement}. | 724 ReplaceWithValue(node, value, effect); |
| 652 Type* const node_type = NodeProperties::GetType(node); | 725 return Replace(value); |
| 653 if (!NodeProperties::GetType(replacement)->Is(node_type)) { | 726 } |
| 654 replacement = graph()->NewNode(common()->TypeGuard(node_type), | 727 } else { |
| 655 replacement, control); | 728 int field_index = FieldIndexOf(access); |
| 729 if (field_index >= 0) { |
| 730 if (Node* replacement = state->LookupField(object, field_index)) { |
| 731 // Make sure we don't resurrect dead {replacement} nodes. |
| 732 if (!replacement->IsDead()) { |
| 733 // We might need to guard the {replacement} if the type of the |
| 734 // {node} is more precise than the type of the {replacement}. |
| 735 Type* const node_type = NodeProperties::GetType(node); |
| 736 if (!NodeProperties::GetType(replacement)->Is(node_type)) { |
| 737 replacement = graph()->NewNode(common()->TypeGuard(node_type), |
| 738 replacement, control); |
| 739 } |
| 740 ReplaceWithValue(node, replacement, effect); |
| 741 return Replace(replacement); |
| 656 } | 742 } |
| 657 ReplaceWithValue(node, replacement, effect); | |
| 658 return Replace(replacement); | |
| 659 } | 743 } |
| 744 state = state->AddField(object, field_index, node, zone()); |
| 660 } | 745 } |
| 661 state = state->AddField(object, field_index, node, zone()); | |
| 662 } | 746 } |
| 663 return UpdateState(node, state); | 747 return UpdateState(node, state); |
| 664 } | 748 } |
| 665 | 749 |
| 666 Reduction LoadElimination::ReduceStoreField(Node* node) { | 750 Reduction LoadElimination::ReduceStoreField(Node* node) { |
| 667 FieldAccess const& access = FieldAccessOf(node->op()); | 751 FieldAccess const& access = FieldAccessOf(node->op()); |
| 668 Node* const object = NodeProperties::GetValueInput(node, 0); | 752 Node* const object = NodeProperties::GetValueInput(node, 0); |
| 669 Node* const new_value = NodeProperties::GetValueInput(node, 1); | 753 Node* const new_value = NodeProperties::GetValueInput(node, 1); |
| 670 Node* const effect = NodeProperties::GetEffectInput(node); | 754 Node* const effect = NodeProperties::GetEffectInput(node); |
| 671 AbstractState const* state = node_states_.Get(effect); | 755 AbstractState const* state = node_states_.Get(effect); |
| 672 if (state == nullptr) return NoChange(); | 756 if (state == nullptr) return NoChange(); |
| 673 int field_index = FieldIndexOf(access); | 757 if (access.offset == HeapObject::kMapOffset && |
| 674 if (field_index >= 0) { | 758 access.base_is_tagged == kTaggedBase) { |
| 675 Node* const old_value = state->LookupField(object, field_index); | 759 DCHECK(IsAnyTagged(access.machine_type.representation())); |
| 676 if (old_value == new_value) { | 760 // Kill all potential knowledge about the {object}s map. |
| 677 // This store is fully redundant. | 761 state = state->KillMaps(object, zone()); |
| 678 return Replace(effect); | 762 Type* const new_value_type = NodeProperties::GetType(new_value); |
| 763 if (new_value_type->IsHeapConstant()) { |
| 764 // Record the new {object} map information. |
| 765 ZoneHandleSet<Map> object_maps( |
| 766 Handle<Map>::cast(new_value_type->AsHeapConstant()->Value())); |
| 767 state = state->AddMaps(object, object_maps, zone()); |
| 679 } | 768 } |
| 680 // Kill all potentially aliasing fields and record the new value. | |
| 681 state = state->KillField(object, field_index, zone()); | |
| 682 state = state->AddField(object, field_index, new_value, zone()); | |
| 683 } else { | 769 } else { |
| 684 // Unsupported StoreField operator. | 770 int field_index = FieldIndexOf(access); |
| 685 state = state->KillFields(object, zone()); | 771 if (field_index >= 0) { |
| 772 Node* const old_value = state->LookupField(object, field_index); |
| 773 if (old_value == new_value) { |
| 774 // This store is fully redundant. |
| 775 return Replace(effect); |
| 776 } |
| 777 // Kill all potentially aliasing fields and record the new value. |
| 778 state = state->KillField(object, field_index, zone()); |
| 779 state = state->AddField(object, field_index, new_value, zone()); |
| 780 } else { |
| 781 // Unsupported StoreField operator. |
| 782 state = state->KillFields(object, zone()); |
| 783 } |
| 686 } | 784 } |
| 687 return UpdateState(node, state); | 785 return UpdateState(node, state); |
| 688 } | 786 } |
| 689 | 787 |
| 690 Reduction LoadElimination::ReduceLoadElement(Node* node) { | 788 Reduction LoadElimination::ReduceLoadElement(Node* node) { |
| 691 Node* const object = NodeProperties::GetValueInput(node, 0); | 789 Node* const object = NodeProperties::GetValueInput(node, 0); |
| 692 Node* const index = NodeProperties::GetValueInput(node, 1); | 790 Node* const index = NodeProperties::GetValueInput(node, 1); |
| 693 Node* const effect = NodeProperties::GetEffectInput(node); | 791 Node* const effect = NodeProperties::GetEffectInput(node); |
| 694 Node* const control = NodeProperties::GetControlInput(node); | 792 Node* const control = NodeProperties::GetControlInput(node); |
| 695 AbstractState const* state = node_states_.Get(effect); | 793 AbstractState const* state = node_states_.Get(effect); |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 858 Node* const object = NodeProperties::GetValueInput(current, 0); | 956 Node* const object = NodeProperties::GetValueInput(current, 0); |
| 859 state = state->KillField( | 957 state = state->KillField( |
| 860 object, FieldIndexOf(JSObject::kElementsOffset), zone()); | 958 object, FieldIndexOf(JSObject::kElementsOffset), zone()); |
| 861 if (flags & GrowFastElementsFlag::kArrayObject) { | 959 if (flags & GrowFastElementsFlag::kArrayObject) { |
| 862 state = state->KillField( | 960 state = state->KillField( |
| 863 object, FieldIndexOf(JSArray::kLengthOffset), zone()); | 961 object, FieldIndexOf(JSArray::kLengthOffset), zone()); |
| 864 } | 962 } |
| 865 break; | 963 break; |
| 866 } | 964 } |
| 867 case IrOpcode::kTransitionElementsKind: { | 965 case IrOpcode::kTransitionElementsKind: { |
| 966 ElementsTransition transition = ElementsTransitionOf(current->op()); |
| 868 Node* const object = NodeProperties::GetValueInput(current, 0); | 967 Node* const object = NodeProperties::GetValueInput(current, 0); |
| 869 Node* const target_map = NodeProperties::GetValueInput(current, 2); | 968 ZoneHandleSet<Map> object_maps; |
| 870 Node* const object_map = state->LookupField( | 969 if (!state->LookupMaps(object, &object_maps) || |
| 871 object, FieldIndexOf(HeapObject::kMapOffset)); | 970 !ZoneHandleSet<Map>(transition.target()) |
| 872 if (target_map != object_map) { | 971 .contains(object_maps)) { |
| 873 state = state->KillField( | 972 state = state->KillMaps(object, zone()); |
| 874 object, FieldIndexOf(HeapObject::kMapOffset), zone()); | |
| 875 state = state->KillField( | 973 state = state->KillField( |
| 876 object, FieldIndexOf(JSObject::kElementsOffset), zone()); | 974 object, FieldIndexOf(JSObject::kElementsOffset), zone()); |
| 877 } | 975 } |
| 878 break; | 976 break; |
| 879 } | 977 } |
| 880 case IrOpcode::kStoreField: { | 978 case IrOpcode::kStoreField: { |
| 881 FieldAccess const& access = FieldAccessOf(current->op()); | 979 FieldAccess const& access = FieldAccessOf(current->op()); |
| 882 Node* const object = NodeProperties::GetValueInput(current, 0); | 980 Node* const object = NodeProperties::GetValueInput(current, 0); |
| 883 int field_index = FieldIndexOf(access); | 981 if (access.offset == HeapObject::kMapOffset) { |
| 884 if (field_index < 0) { | 982 // Invalidate what we know about the {object}s map. |
| 885 state = state->KillFields(object, zone()); | 983 state = state->KillMaps(object, zone()); |
| 886 } else { | 984 } else { |
| 887 state = state->KillField(object, field_index, zone()); | 985 int field_index = FieldIndexOf(access); |
| 986 if (field_index < 0) { |
| 987 state = state->KillFields(object, zone()); |
| 988 } else { |
| 989 state = state->KillField(object, field_index, zone()); |
| 990 } |
| 888 } | 991 } |
| 889 break; | 992 break; |
| 890 } | 993 } |
| 891 case IrOpcode::kStoreElement: { | 994 case IrOpcode::kStoreElement: { |
| 892 Node* const object = NodeProperties::GetValueInput(current, 0); | 995 Node* const object = NodeProperties::GetValueInput(current, 0); |
| 893 Node* const index = NodeProperties::GetValueInput(current, 1); | 996 Node* const index = NodeProperties::GetValueInput(current, 1); |
| 894 state = state->KillElement(object, index, zone()); | 997 state = state->KillElement(object, index, zone()); |
| 895 break; | 998 break; |
| 896 } | 999 } |
| 897 case IrOpcode::kStoreBuffer: | 1000 case IrOpcode::kStoreBuffer: |
| (...skipping 11 matching lines...) Expand all Loading... |
| 909 } | 1012 } |
| 910 } | 1013 } |
| 911 return state; | 1014 return state; |
| 912 } | 1015 } |
| 913 | 1016 |
| 914 // static | 1017 // static |
| 915 int LoadElimination::FieldIndexOf(int offset) { | 1018 int LoadElimination::FieldIndexOf(int offset) { |
| 916 DCHECK_EQ(0, offset % kPointerSize); | 1019 DCHECK_EQ(0, offset % kPointerSize); |
| 917 int field_index = offset / kPointerSize; | 1020 int field_index = offset / kPointerSize; |
| 918 if (field_index >= static_cast<int>(kMaxTrackedFields)) return -1; | 1021 if (field_index >= static_cast<int>(kMaxTrackedFields)) return -1; |
| 919 return field_index; | 1022 DCHECK_LT(0, field_index); |
| 1023 return field_index - 1; |
| 920 } | 1024 } |
| 921 | 1025 |
| 922 // static | 1026 // static |
| 923 int LoadElimination::FieldIndexOf(FieldAccess const& access) { | 1027 int LoadElimination::FieldIndexOf(FieldAccess const& access) { |
| 924 MachineRepresentation rep = access.machine_type.representation(); | 1028 MachineRepresentation rep = access.machine_type.representation(); |
| 925 switch (rep) { | 1029 switch (rep) { |
| 926 case MachineRepresentation::kNone: | 1030 case MachineRepresentation::kNone: |
| 927 case MachineRepresentation::kBit: | 1031 case MachineRepresentation::kBit: |
| 928 case MachineRepresentation::kSimd128: | 1032 case MachineRepresentation::kSimd128: |
| 929 UNREACHABLE(); | 1033 UNREACHABLE(); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 955 } | 1059 } |
| 956 return FieldIndexOf(access.offset); | 1060 return FieldIndexOf(access.offset); |
| 957 } | 1061 } |
| 958 | 1062 |
| 959 CommonOperatorBuilder* LoadElimination::common() const { | 1063 CommonOperatorBuilder* LoadElimination::common() const { |
| 960 return jsgraph()->common(); | 1064 return jsgraph()->common(); |
| 961 } | 1065 } |
| 962 | 1066 |
| 963 Graph* LoadElimination::graph() const { return jsgraph()->graph(); } | 1067 Graph* LoadElimination::graph() const { return jsgraph()->graph(); } |
| 964 | 1068 |
| 1069 Factory* LoadElimination::factory() const { return jsgraph()->factory(); } |
| 1070 |
| 965 } // namespace compiler | 1071 } // namespace compiler |
| 966 } // namespace internal | 1072 } // namespace internal |
| 967 } // namespace v8 | 1073 } // namespace v8 |
| OLD | NEW |