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 |