Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(670)

Side by Side Diff: src/compiler/js-native-context-specialization.cc

Issue 1424733002: [turbofan] Improve deferred code handling for polymorphic property access. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Undo unrelated change. Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/js-native-context-specialization.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/compiler/js-native-context-specialization.h" 5 #include "src/compiler/js-native-context-specialization.h"
6 6
7 #include "src/accessors.h" 7 #include "src/accessors.h"
8 #include "src/compilation-dependencies.h" 8 #include "src/compilation-dependencies.h"
9 #include "src/compiler/access-builder.h" 9 #include "src/compiler/access-builder.h"
10 #include "src/compiler/js-graph.h" 10 #include "src/compiler/js-graph.h"
(...skipping 459 matching lines...) Expand 10 before | Expand all | Expand 10 after
470 if (!ComputePropertyAccessInfo(map, name, access_mode, &access_info)) { 470 if (!ComputePropertyAccessInfo(map, name, access_mode, &access_info)) {
471 return false; 471 return false;
472 } 472 }
473 access_infos->push_back(access_info); 473 access_infos->push_back(access_info);
474 } 474 }
475 } 475 }
476 return true; 476 return true;
477 } 477 }
478 478
479 479
480 Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) { 480 Reduction JSNativeContextSpecialization::ReduceNamedAccess(
481 DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode()); 481 Node* node, Node* value, MapHandleList const& receiver_maps,
482 NamedAccess const& p = NamedAccessOf(node->op()); 482 Handle<Name> name, PropertyAccessMode access_mode) {
483 Handle<Name> name = p.name(); 483 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
484 node->opcode() == IrOpcode::kJSStoreNamed);
484 Node* receiver = NodeProperties::GetValueInput(node, 0); 485 Node* receiver = NodeProperties::GetValueInput(node, 0);
485 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 486 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
486 Node* effect = NodeProperties::GetEffectInput(node); 487 Node* effect = NodeProperties::GetEffectInput(node);
487 Node* control = NodeProperties::GetControlInput(node); 488 Node* control = NodeProperties::GetControlInput(node);
488 489
489 // Not much we can do if deoptimization support is disabled. 490 // Not much we can do if deoptimization support is disabled.
490 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); 491 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
491 492
492 // Extract receiver maps from the LOAD_IC using the LoadICNexus.
493 MapHandleList receiver_maps;
494 if (!p.feedback().IsValid()) return NoChange();
495 LoadICNexus nexus(p.feedback().vector(), p.feedback().slot());
496 if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange();
497 DCHECK_LT(0, receiver_maps.length());
498
499 // Compute property access infos for the receiver maps. 493 // Compute property access infos for the receiver maps.
500 ZoneVector<PropertyAccessInfo> access_infos(zone()); 494 ZoneVector<PropertyAccessInfo> access_infos(zone());
501 if (!ComputePropertyAccessInfos(receiver_maps, name, kLoad, &access_infos)) { 495 if (!ComputePropertyAccessInfos(receiver_maps, name, access_mode,
496 &access_infos)) {
502 return NoChange(); 497 return NoChange();
503 } 498 }
504 499
505 // Nothing to do if we have no non-deprecated maps. 500 // Nothing to do if we have no non-deprecated maps.
506 if (access_infos.empty()) return NoChange(); 501 if (access_infos.empty()) return NoChange();
507 502
508 // The final states for every polymorphic branch. We join them with 503 // The final states for every polymorphic branch. We join them with
509 // Merge+Phi+EffectPhi at the bottom. 504 // Merge++Phi+EffectPhi at the bottom.
510 ZoneVector<Node*> values(zone()); 505 ZoneVector<Node*> values(zone());
511 ZoneVector<Node*> effects(zone()); 506 ZoneVector<Node*> effects(zone());
512 ZoneVector<Node*> controls(zone()); 507 ZoneVector<Node*> controls(zone());
513 508
514 // The list of "exiting" controls, which currently go to a single deoptimize. 509 // The list of "exiting" controls, which currently go to a single deoptimize.
515 // TODO(bmeurer): Consider using an IC as fallback. 510 // TODO(bmeurer): Consider using an IC as fallback.
516 Node* const exit_effect = effect; 511 Node* const exit_effect = effect;
517 ZoneVector<Node*> exit_controls(zone()); 512 ZoneVector<Node*> exit_controls(zone());
518 513
519 // Ensure that {receiver} is a heap object. 514 // Ensure that {receiver} is a heap object.
520 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); 515 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
521 Node* branch = 516 Node* branch =
522 graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control); 517 graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
523 exit_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); 518 exit_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
524 control = graph()->NewNode(common()->IfFalse(), branch); 519 control = graph()->NewNode(common()->IfFalse(), branch);
525 520
526 // Load the {receiver} map. The resulting effect is the dominating effect for 521 // Load the {receiver} map. The resulting effect is the dominating effect for
527 // all (polymorphic) branches. 522 // all (polymorphic) branches.
528 Node* receiver_map = effect = 523 Node* receiver_map = effect =
529 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 524 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
530 receiver, effect, control); 525 receiver, effect, control);
531 526
532 // Generate code for the various different property access patterns. 527 // Generate code for the various different property access patterns.
533 Node* fallthrough_control = control; 528 Node* fallthrough_control = control;
534 for (PropertyAccessInfo const& access_info : access_infos) { 529 for (PropertyAccessInfo const& access_info : access_infos) {
535 Node* this_value = receiver; 530 Node* this_value = value;
531 Node* this_receiver = receiver;
536 Node* this_effect = effect; 532 Node* this_effect = effect;
537 Node* this_control; 533 Node* this_control;
538 534
539 // Perform map check on {receiver}. 535 // Perform map check on {receiver}.
540 Type* receiver_type = access_info.receiver_type(); 536 Type* receiver_type = access_info.receiver_type();
541 if (receiver_type->Is(Type::String())) { 537 if (receiver_type->Is(Type::String())) {
542 // Emit an instance type check for strings. 538 // Emit an instance type check for strings.
543 Node* receiver_instance_type = this_effect = graph()->NewNode( 539 Node* receiver_instance_type = this_effect = graph()->NewNode(
544 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), 540 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
545 receiver_map, this_effect, fallthrough_control); 541 receiver_map, this_effect, fallthrough_control);
546 Node* check = 542 Node* check =
547 graph()->NewNode(machine()->Uint32LessThan(), receiver_instance_type, 543 graph()->NewNode(machine()->Uint32LessThan(), receiver_instance_type,
548 jsgraph()->Uint32Constant(FIRST_NONSTRING_TYPE)); 544 jsgraph()->Uint32Constant(FIRST_NONSTRING_TYPE));
549 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), 545 Node* branch =
550 check, fallthrough_control); 546 graph()->NewNode(common()->Branch(), check, fallthrough_control);
551 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); 547 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
552 this_control = graph()->NewNode(common()->IfTrue(), branch); 548 this_control = graph()->NewNode(common()->IfTrue(), branch);
553 } else { 549 } else {
554 // Emit a (sequence of) map checks for other properties. 550 // Emit a (sequence of) map checks for other properties.
555 ZoneVector<Node*> this_controls(zone()); 551 ZoneVector<Node*> this_controls(zone());
556 for (auto i = access_info.receiver_type()->Classes(); !i.Done(); 552 for (auto i = access_info.receiver_type()->Classes(); !i.Done();
557 i.Advance()) { 553 i.Advance()) {
558 Handle<Map> map = i.Current(); 554 Handle<Map> map = i.Current();
559 Node* check = 555 Node* check =
560 graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()), 556 graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()),
561 receiver_map, jsgraph()->Constant(map)); 557 receiver_map, jsgraph()->Constant(map));
562 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), 558 Node* branch =
563 check, fallthrough_control); 559 graph()->NewNode(common()->Branch(), check, fallthrough_control);
564 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); 560 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
565 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); 561 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
566 } 562 }
567 int const this_control_count = static_cast<int>(this_controls.size()); 563 int const this_control_count = static_cast<int>(this_controls.size());
568 this_control = 564 this_control =
569 (this_control_count == 1) 565 (this_control_count == 1)
570 ? this_controls.front() 566 ? this_controls.front()
571 : graph()->NewNode(common()->Merge(this_control_count), 567 : graph()->NewNode(common()->Merge(this_control_count),
572 this_control_count, &this_controls.front()); 568 this_control_count, &this_controls.front());
573 } 569 }
574 570
575 // Determine actual holder and perform prototype chain checks. 571 // Determine actual holder and perform prototype chain checks.
576 Handle<JSObject> holder; 572 Handle<JSObject> holder;
577 if (access_info.holder().ToHandle(&holder)) { 573 if (access_info.holder().ToHandle(&holder)) {
578 this_value = jsgraph()->Constant(holder);
579 AssumePrototypesStable(receiver_type, holder); 574 AssumePrototypesStable(receiver_type, holder);
575 if (access_mode == kLoad) {
576 this_receiver = jsgraph()->Constant(holder);
577 }
580 } 578 }
581 579
582 // Generate the actual property access. 580 // Generate the actual property access.
583 if (access_info.IsDataConstant()) { 581 if (access_info.IsDataConstant()) {
584 this_value = jsgraph()->Constant(access_info.constant()); 582 this_value = jsgraph()->Constant(access_info.constant());
583 if (access_mode == kStore) {
584 Node* check = graph()->NewNode(
585 simplified()->ReferenceEqual(Type::Tagged()), value, this_value);
586 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
587 check, this_control);
588 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch));
589 this_control = graph()->NewNode(common()->IfTrue(), branch);
590 }
585 } else { 591 } else {
586 // TODO(bmeurer): This is sort of adhoc, and must be refactored into some
587 // common code once we also have support for stores.
588 DCHECK(access_info.IsDataField()); 592 DCHECK(access_info.IsDataField());
589 FieldIndex const field_index = access_info.field_index(); 593 FieldIndex const field_index = access_info.field_index();
590 Type* const field_type = access_info.field_type(); 594 Type* const field_type = access_info.field_type();
591 if (!field_index.is_inobject()) { 595 if (!field_index.is_inobject()) {
592 this_value = this_effect = graph()->NewNode( 596 this_receiver = this_effect = graph()->NewNode(
593 simplified()->LoadField(AccessBuilder::ForJSObjectProperties()), 597 simplified()->LoadField(AccessBuilder::ForJSObjectProperties()),
594 this_value, this_effect, this_control); 598 this_receiver, this_effect, this_control);
595 } 599 }
596 FieldAccess field_access; 600 FieldAccess field_access = {kTaggedBase, field_index.offset(), name,
597 field_access.base_is_tagged = kTaggedBase; 601 field_type, kMachAnyTagged};
598 field_access.offset = field_index.offset(); 602 if (access_mode == kLoad) {
599 field_access.name = name; 603 if (field_type->Is(Type::UntaggedFloat64())) {
600 field_access.type = field_type; 604 if (!field_index.is_inobject() || field_index.is_hidden_field() ||
601 field_access.machine_type = kMachAnyTagged; 605 !FLAG_unbox_double_fields) {
602 if (field_type->Is(Type::UntaggedFloat64())) { 606 this_receiver = this_effect =
603 if (!field_index.is_inobject() || field_index.is_hidden_field() || 607 graph()->NewNode(simplified()->LoadField(field_access),
604 !FLAG_unbox_double_fields) { 608 this_receiver, this_effect, this_control);
605 this_value = this_effect = 609 field_access.offset = HeapNumber::kValueOffset;
606 graph()->NewNode(simplified()->LoadField(field_access), 610 field_access.name = MaybeHandle<Name>();
607 this_value, this_effect, this_control); 611 }
608 field_access.offset = HeapNumber::kValueOffset; 612 field_access.machine_type = kMachFloat64;
609 field_access.name = MaybeHandle<Name>();
610 } 613 }
611 field_access.machine_type = kMachFloat64; 614 this_value = this_effect =
615 graph()->NewNode(simplified()->LoadField(field_access),
616 this_receiver, this_effect, this_control);
617 } else {
618 DCHECK_EQ(kStore, access_mode);
619 if (field_type->Is(Type::TaggedSigned())) {
620 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
621 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
622 check, this_control);
623 exit_controls.push_back(
624 graph()->NewNode(common()->IfFalse(), branch));
625 this_control = graph()->NewNode(common()->IfTrue(), branch);
626 } else if (field_type->Is(Type::TaggedPointer())) {
627 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
628 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse),
629 check, this_control);
630 exit_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
631 this_control = graph()->NewNode(common()->IfFalse(), branch);
632 if (field_type->NumClasses() > 0) {
633 // Emit a (sequence of) map checks for the value.
634 ZoneVector<Node*> this_controls(zone());
635 Node* value_map = this_effect = graph()->NewNode(
636 simplified()->LoadField(AccessBuilder::ForMap()), value,
637 this_effect, this_control);
638 for (auto i = field_type->Classes(); !i.Done(); i.Advance()) {
639 Handle<Map> field_map(i.Current());
640 check = graph()->NewNode(
641 simplified()->ReferenceEqual(Type::Internal()), value_map,
642 jsgraph()->Constant(field_map));
643 branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
644 check, this_control);
645 this_control = graph()->NewNode(common()->IfFalse(), branch);
646 this_controls.push_back(
647 graph()->NewNode(common()->IfTrue(), branch));
648 }
649 exit_controls.push_back(this_control);
650 int const this_control_count =
651 static_cast<int>(this_controls.size());
652 this_control =
653 (this_control_count == 1)
654 ? this_controls.front()
655 : graph()->NewNode(common()->Merge(this_control_count),
656 this_control_count,
657 &this_controls.front());
658 }
659 } else {
660 DCHECK(field_type->Is(Type::Tagged()));
661 }
662 this_effect = graph()->NewNode(simplified()->StoreField(field_access),
663 this_receiver, this_value, this_effect,
664 this_control);
612 } 665 }
613 this_value = this_effect =
614 graph()->NewNode(simplified()->LoadField(field_access), this_value,
615 this_effect, this_control);
616 } 666 }
617 667
618 // Remember the final state for this property access. 668 // Remember the final state for this property access.
619 values.push_back(this_value); 669 values.push_back(this_value);
620 effects.push_back(this_effect); 670 effects.push_back(this_effect);
621 controls.push_back(this_control); 671 controls.push_back(this_control);
622 } 672 }
623 673
624 // Collect the fallthru control as final "exit" control. 674 // Collect the fallthru control as final "exit" control.
675 if (fallthrough_control != control) {
676 // Mark the last fallthru branch as deferred.
677 Node* branch = NodeProperties::GetControlInput(fallthrough_control);
678 DCHECK_EQ(IrOpcode::kBranch, branch->opcode());
679 if (fallthrough_control->opcode() == IrOpcode::kIfTrue) {
680 NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kFalse));
681 } else {
682 DCHECK_EQ(IrOpcode::kIfFalse, fallthrough_control->opcode());
683 NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kTrue));
684 }
685 }
625 exit_controls.push_back(fallthrough_control); 686 exit_controls.push_back(fallthrough_control);
626 687
627 // Generate the single "exit" point, where we get if either all map/instance 688 // Generate the single "exit" point, where we get if either all map/instance
628 // type checks failed, or one of the assumptions inside one of the cases 689 // type checks failed, or one of the assumptions inside one of the cases
629 // failes (i.e. failing prototype chain check). 690 // failes (i.e. failing prototype chain check).
630 // TODO(bmeurer): Consider falling back to IC here if deoptimization is 691 // TODO(bmeurer): Consider falling back to IC here if deoptimization is
631 // disabled. 692 // disabled.
632 int const exit_control_count = static_cast<int>(exit_controls.size()); 693 int const exit_control_count = static_cast<int>(exit_controls.size());
633 Node* exit_control = 694 Node* exit_control =
634 (exit_control_count == 1) 695 (exit_control_count == 1)
635 ? exit_controls.front() 696 ? exit_controls.front()
636 : graph()->NewNode(common()->Merge(exit_control_count), 697 : graph()->NewNode(common()->Merge(exit_control_count),
637 exit_control_count, &exit_controls.front()); 698 exit_control_count, &exit_controls.front());
638 Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state, 699 Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state,
639 exit_effect, exit_control); 700 exit_effect, exit_control);
640 // TODO(bmeurer): This should be on the AdvancedReducer somehow. 701 // TODO(bmeurer): This should be on the AdvancedReducer somehow.
641 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize); 702 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
642 703
643 // Generate the final merge point for all (polymorphic) branches. 704 // Generate the final merge point for all (polymorphic) branches.
644 Node* value;
645 int const control_count = static_cast<int>(controls.size()); 705 int const control_count = static_cast<int>(controls.size());
646 if (control_count == 1) { 706 if (control_count == 1) {
647 value = values.front(); 707 value = values.front();
648 effect = effects.front(); 708 effect = effects.front();
649 control = controls.front(); 709 control = controls.front();
650 } else { 710 } else {
651 control = graph()->NewNode(common()->Merge(control_count), control_count, 711 control = graph()->NewNode(common()->Merge(control_count), control_count,
652 &controls.front()); 712 &controls.front());
653 values.push_back(control); 713 values.push_back(control);
654 value = graph()->NewNode(common()->Phi(kMachAnyTagged, control_count), 714 value = graph()->NewNode(common()->Phi(kMachAnyTagged, control_count),
655 control_count + 1, &values.front()); 715 control_count + 1, &values.front());
656 effects.push_back(control); 716 effects.push_back(control);
657 effect = graph()->NewNode(common()->EffectPhi(control_count), 717 effect = graph()->NewNode(common()->EffectPhi(control_count),
658 control_count + 1, &effects.front()); 718 control_count + 1, &effects.front());
659 } 719 }
660 return Replace(node, value, effect, control); 720 return Replace(node, value, effect, control);
661 } 721 }
662 722
663 723
724 Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
725 DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
726 NamedAccess const& p = NamedAccessOf(node->op());
727 Node* const value = jsgraph()->Dead();
728
729 // Extract receiver maps from the LOAD_IC using the LoadICNexus.
730 MapHandleList receiver_maps;
731 if (!p.feedback().IsValid()) return NoChange();
732 LoadICNexus nexus(p.feedback().vector(), p.feedback().slot());
733 if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange();
734 DCHECK_LT(0, receiver_maps.length());
735
736 // Try to lower the named access based on the {receiver_maps}.
737 return ReduceNamedAccess(node, value, receiver_maps, p.name(), kLoad);
738 }
739
740
664 Reduction JSNativeContextSpecialization::ReduceJSStoreNamed(Node* node) { 741 Reduction JSNativeContextSpecialization::ReduceJSStoreNamed(Node* node) {
665 DCHECK_EQ(IrOpcode::kJSStoreNamed, node->opcode()); 742 DCHECK_EQ(IrOpcode::kJSStoreNamed, node->opcode());
666 NamedAccess const& p = NamedAccessOf(node->op()); 743 NamedAccess const& p = NamedAccessOf(node->op());
667 Handle<Name> name = p.name(); 744 Node* const value = NodeProperties::GetValueInput(node, 1);
668 Node* receiver = NodeProperties::GetValueInput(node, 0);
669 Node* value = NodeProperties::GetValueInput(node, 1);
670 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
671 Node* effect = NodeProperties::GetEffectInput(node);
672 Node* control = NodeProperties::GetControlInput(node);
673
674 // Not much we can do if deoptimization support is disabled.
675 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
676 745
677 // Extract receiver maps from the STORE_IC using the StoreICNexus. 746 // Extract receiver maps from the STORE_IC using the StoreICNexus.
678 MapHandleList receiver_maps; 747 MapHandleList receiver_maps;
679 if (!p.feedback().IsValid()) return NoChange(); 748 if (!p.feedback().IsValid()) return NoChange();
680 StoreICNexus nexus(p.feedback().vector(), p.feedback().slot()); 749 StoreICNexus nexus(p.feedback().vector(), p.feedback().slot());
681 if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange(); 750 if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange();
682 DCHECK_LT(0, receiver_maps.length()); 751 DCHECK_LT(0, receiver_maps.length());
683 752
684 // Compute property access infos for the receiver maps. 753 // Try to lower the named access based on the {receiver_maps}.
685 ZoneVector<PropertyAccessInfo> access_infos(zone()); 754 return ReduceNamedAccess(node, value, receiver_maps, p.name(), kStore);
686 if (!ComputePropertyAccessInfos(receiver_maps, name, kStore, &access_infos)) {
687 return NoChange();
688 }
689
690 // Nothing to do if we have no non-deprecated maps.
691 if (access_infos.empty()) return NoChange();
692
693 // The final states for every polymorphic branch. We join them with
694 // Merge+EffectPhi at the bottom.
695 ZoneVector<Node*> effects(zone());
696 ZoneVector<Node*> controls(zone());
697
698 // The list of "exiting" controls, which currently go to a single deoptimize.
699 // TODO(bmeurer): Consider using an IC as fallback.
700 Node* const exit_effect = effect;
701 ZoneVector<Node*> exit_controls(zone());
702
703 // Ensure that {receiver} is a heap object.
704 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
705 Node* branch =
706 graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
707 exit_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
708 control = graph()->NewNode(common()->IfFalse(), branch);
709
710 // Load the {receiver} map. The resulting effect is the dominating effect for
711 // all (polymorphic) branches.
712 Node* receiver_map = effect =
713 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
714 receiver, effect, control);
715
716 // Generate code for the various different property access patterns.
717 Node* fallthrough_control = control;
718 for (PropertyAccessInfo const& access_info : access_infos) {
719 Node* this_receiver = receiver;
720 Node* this_effect = effect;
721 Node* this_control;
722
723 // Perform map check on {receiver}.
724 Type* receiver_type = access_info.receiver_type();
725 if (receiver_type->Is(Type::String())) {
726 // Emit an instance type check for strings.
727 Node* receiver_instance_type = this_effect = graph()->NewNode(
728 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
729 receiver_map, this_effect, fallthrough_control);
730 Node* check =
731 graph()->NewNode(machine()->Uint32LessThan(), receiver_instance_type,
732 jsgraph()->Uint32Constant(FIRST_NONSTRING_TYPE));
733 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
734 check, fallthrough_control);
735 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
736 this_control = graph()->NewNode(common()->IfTrue(), branch);
737 } else {
738 // Emit a (sequence of) map checks for other properties.
739 ZoneVector<Node*> this_controls(zone());
740 for (auto i = access_info.receiver_type()->Classes(); !i.Done();
741 i.Advance()) {
742 Handle<Map> map = i.Current();
743 Node* check =
744 graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()),
745 receiver_map, jsgraph()->Constant(map));
746 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
747 check, fallthrough_control);
748 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
749 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
750 }
751 int const this_control_count = static_cast<int>(this_controls.size());
752 this_control =
753 (this_control_count == 1)
754 ? this_controls.front()
755 : graph()->NewNode(common()->Merge(this_control_count),
756 this_control_count, &this_controls.front());
757 }
758
759 // Determine actual holder and perform prototype chain checks.
760 Handle<JSObject> holder;
761 if (access_info.holder().ToHandle(&holder)) {
762 AssumePrototypesStable(receiver_type, holder);
763 }
764
765 // Generate the actual property access.
766 if (access_info.IsDataConstant()) {
767 Node* check =
768 graph()->NewNode(simplified()->ReferenceEqual(Type::Tagged()), value,
769 jsgraph()->Constant(access_info.constant()));
770 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
771 check, this_control);
772 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch));
773 this_control = graph()->NewNode(common()->IfTrue(), branch);
774 } else {
775 // TODO(bmeurer): This is sort of adhoc, and must be refactored into some
776 // common code once we also have support for stores.
777 DCHECK(access_info.IsDataField());
778 FieldIndex const field_index = access_info.field_index();
779 Type* const field_type = access_info.field_type();
780 if (!field_index.is_inobject()) {
781 this_receiver = this_effect = graph()->NewNode(
782 simplified()->LoadField(AccessBuilder::ForJSObjectProperties()),
783 this_receiver, this_effect, this_control);
784 }
785 FieldAccess field_access;
786 field_access.base_is_tagged = kTaggedBase;
787 field_access.offset = field_index.offset();
788 field_access.name = name;
789 field_access.type = field_type;
790 field_access.machine_type = kMachAnyTagged;
791 if (field_type->Is(Type::TaggedSigned())) {
792 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
793 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
794 check, this_control);
795 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch));
796 this_control = graph()->NewNode(common()->IfTrue(), branch);
797 } else if (field_type->Is(Type::TaggedPointer())) {
798 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
799 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse),
800 check, this_control);
801 exit_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
802 this_control = graph()->NewNode(common()->IfFalse(), branch);
803 if (field_type->NumClasses() > 0) {
804 // Emit a (sequence of) map checks for the value.
805 ZoneVector<Node*> this_controls(zone());
806 Node* value_map = this_effect =
807 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
808 value, this_effect, this_control);
809 for (auto i = field_type->Classes(); !i.Done(); i.Advance()) {
810 Handle<Map> field_map(i.Current());
811 check =
812 graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()),
813 value_map, jsgraph()->Constant(field_map));
814 branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
815 check, this_control);
816 this_control = graph()->NewNode(common()->IfFalse(), branch);
817 this_controls.push_back(
818 graph()->NewNode(common()->IfTrue(), branch));
819 }
820 exit_controls.push_back(this_control);
821 int const this_control_count = static_cast<int>(this_controls.size());
822 this_control = (this_control_count == 1)
823 ? this_controls.front()
824 : graph()->NewNode(
825 common()->Merge(this_control_count),
826 this_control_count, &this_controls.front());
827 }
828 } else {
829 DCHECK(field_type->Is(Type::Tagged()));
830 }
831 this_effect =
832 graph()->NewNode(simplified()->StoreField(field_access),
833 this_receiver, value, this_effect, this_control);
834 }
835
836 // Remember the final state for this property access.
837 effects.push_back(this_effect);
838 controls.push_back(this_control);
839 }
840
841 // Collect the fallthru control as final "exit" control.
842 exit_controls.push_back(fallthrough_control);
843
844 // Generate the single "exit" point, where we get if either all map/instance
845 // type checks failed, or one of the assumptions inside one of the cases
846 // failes (i.e. failing prototype chain check).
847 // TODO(bmeurer): Consider falling back to IC here if deoptimization is
848 // disabled.
849 int const exit_control_count = static_cast<int>(exit_controls.size());
850 Node* exit_control =
851 (exit_control_count == 1)
852 ? exit_controls.front()
853 : graph()->NewNode(common()->Merge(exit_control_count),
854 exit_control_count, &exit_controls.front());
855 Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state,
856 exit_effect, exit_control);
857 // TODO(bmeurer): This should be on the AdvancedReducer somehow.
858 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
859
860 // Generate the final merge point for all (polymorphic) branches.
861 int const control_count = static_cast<int>(controls.size());
862 if (control_count == 1) {
863 effect = effects.front();
864 control = controls.front();
865 } else {
866 control = graph()->NewNode(common()->Merge(control_count), control_count,
867 &controls.front());
868 effects.push_back(control);
869 effect = graph()->NewNode(common()->EffectPhi(control_count),
870 control_count + 1, &effects.front());
871 }
872 return Replace(node, value, effect, control);
873 } 755 }
874 756
875 757
876 Reduction JSNativeContextSpecialization::Replace(Node* node, 758 Reduction JSNativeContextSpecialization::Replace(Node* node,
877 Handle<Object> value) { 759 Handle<Object> value) {
878 return Replace(node, jsgraph()->Constant(value)); 760 return Replace(node, jsgraph()->Constant(value));
879 } 761 }
880 762
881 763
882 bool JSNativeContextSpecialization::LookupInScriptContextTable( 764 bool JSNativeContextSpecialization::LookupInScriptContextTable(
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
954 } 836 }
955 837
956 838
957 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { 839 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const {
958 return jsgraph()->simplified(); 840 return jsgraph()->simplified();
959 } 841 }
960 842
961 } // namespace compiler 843 } // namespace compiler
962 } // namespace internal 844 } // namespace internal
963 } // namespace v8 845 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/js-native-context-specialization.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698