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

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

Issue 1418213010: [turbofan] Initial support for keyed access to fast JSArrays. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Address comments 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') | src/compiler/property-access-info.h » ('j') | 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/code-factory.h" 8 #include "src/code-factory.h"
9 #include "src/compilation-dependencies.h" 9 #include "src/compilation-dependencies.h"
10 #include "src/compiler/access-builder.h" 10 #include "src/compiler/access-builder.h"
(...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after
300 } 300 }
301 effect = graph()->NewNode( 301 effect = graph()->NewNode(
302 simplified()->StoreField(AccessBuilder::ForPropertyCellValue()), 302 simplified()->StoreField(AccessBuilder::ForPropertyCellValue()),
303 jsgraph()->Constant(property_cell), value, effect, control); 303 jsgraph()->Constant(property_cell), value, effect, control);
304 return Replace(node, value, effect, control); 304 return Replace(node, value, effect, control);
305 } 305 }
306 306
307 307
308 Reduction JSNativeContextSpecialization::ReduceNamedAccess( 308 Reduction JSNativeContextSpecialization::ReduceNamedAccess(
309 Node* node, Node* value, MapHandleList const& receiver_maps, 309 Node* node, Node* value, MapHandleList const& receiver_maps,
310 Handle<Name> name, PropertyAccessMode access_mode, 310 Handle<Name> name, AccessMode access_mode, LanguageMode language_mode,
311 LanguageMode language_mode, Node* index) { 311 Node* index) {
312 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed || 312 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
313 node->opcode() == IrOpcode::kJSStoreNamed || 313 node->opcode() == IrOpcode::kJSStoreNamed ||
314 node->opcode() == IrOpcode::kJSLoadProperty || 314 node->opcode() == IrOpcode::kJSLoadProperty ||
315 node->opcode() == IrOpcode::kJSStoreProperty); 315 node->opcode() == IrOpcode::kJSStoreProperty);
316 Node* receiver = NodeProperties::GetValueInput(node, 0); 316 Node* receiver = NodeProperties::GetValueInput(node, 0);
317 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 317 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
318 Node* effect = NodeProperties::GetEffectInput(node); 318 Node* effect = NodeProperties::GetEffectInput(node);
319 Node* control = NodeProperties::GetControlInput(node); 319 Node* control = NodeProperties::GetControlInput(node);
320 320
321 // Not much we can do if deoptimization support is disabled. 321 // Not much we can do if deoptimization support is disabled.
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
410 } 410 }
411 411
412 // Determine actual holder and perform prototype chain checks. 412 // Determine actual holder and perform prototype chain checks.
413 Handle<JSObject> holder; 413 Handle<JSObject> holder;
414 if (access_info.holder().ToHandle(&holder)) { 414 if (access_info.holder().ToHandle(&holder)) {
415 AssumePrototypesStable(receiver_type, holder); 415 AssumePrototypesStable(receiver_type, holder);
416 } 416 }
417 417
418 // Generate the actual property access. 418 // Generate the actual property access.
419 if (access_info.IsNotFound()) { 419 if (access_info.IsNotFound()) {
420 DCHECK_EQ(PropertyAccessMode::kLoad, access_mode); 420 DCHECK_EQ(AccessMode::kLoad, access_mode);
421 if (is_strong(language_mode)) { 421 if (is_strong(language_mode)) {
422 // TODO(bmeurer/mstarzinger): Add support for lowering inside try 422 // TODO(bmeurer/mstarzinger): Add support for lowering inside try
423 // blocks rewiring the IfException edge to a runtime call/throw. 423 // blocks rewiring the IfException edge to a runtime call/throw.
424 exit_controls.push_back(this_control); 424 exit_controls.push_back(this_control);
425 continue; 425 continue;
426 } else { 426 } else {
427 this_value = jsgraph()->UndefinedConstant(); 427 this_value = jsgraph()->UndefinedConstant();
428 } 428 }
429 } else if (access_info.IsDataConstant()) { 429 } else if (access_info.IsDataConstant()) {
430 this_value = jsgraph()->Constant(access_info.constant()); 430 this_value = jsgraph()->Constant(access_info.constant());
431 if (access_mode == PropertyAccessMode::kStore) { 431 if (access_mode == AccessMode::kStore) {
432 Node* check = graph()->NewNode( 432 Node* check = graph()->NewNode(
433 simplified()->ReferenceEqual(Type::Tagged()), value, this_value); 433 simplified()->ReferenceEqual(Type::Tagged()), value, this_value);
434 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), 434 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
435 check, this_control); 435 check, this_control);
436 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch)); 436 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch));
437 this_control = graph()->NewNode(common()->IfTrue(), branch); 437 this_control = graph()->NewNode(common()->IfTrue(), branch);
438 } 438 }
439 } else { 439 } else {
440 DCHECK(access_info.IsDataField()); 440 DCHECK(access_info.IsDataField());
441 FieldIndex const field_index = access_info.field_index(); 441 FieldIndex const field_index = access_info.field_index();
442 Type* const field_type = access_info.field_type(); 442 Type* const field_type = access_info.field_type();
443 if (access_mode == PropertyAccessMode::kLoad && 443 if (access_mode == AccessMode::kLoad &&
444 access_info.holder().ToHandle(&holder)) { 444 access_info.holder().ToHandle(&holder)) {
445 this_receiver = jsgraph()->Constant(holder); 445 this_receiver = jsgraph()->Constant(holder);
446 } 446 }
447 Node* this_storage = this_receiver; 447 Node* this_storage = this_receiver;
448 if (!field_index.is_inobject()) { 448 if (!field_index.is_inobject()) {
449 this_storage = this_effect = graph()->NewNode( 449 this_storage = this_effect = graph()->NewNode(
450 simplified()->LoadField(AccessBuilder::ForJSObjectProperties()), 450 simplified()->LoadField(AccessBuilder::ForJSObjectProperties()),
451 this_storage, this_effect, this_control); 451 this_storage, this_effect, this_control);
452 } 452 }
453 FieldAccess field_access = {kTaggedBase, field_index.offset(), name, 453 FieldAccess field_access = {kTaggedBase, field_index.offset(), name,
454 field_type, kMachAnyTagged}; 454 field_type, kMachAnyTagged};
455 if (access_mode == PropertyAccessMode::kLoad) { 455 if (access_mode == AccessMode::kLoad) {
456 if (field_type->Is(Type::UntaggedFloat64())) { 456 if (field_type->Is(Type::UntaggedFloat64())) {
457 if (!field_index.is_inobject() || field_index.is_hidden_field() || 457 if (!field_index.is_inobject() || field_index.is_hidden_field() ||
458 !FLAG_unbox_double_fields) { 458 !FLAG_unbox_double_fields) {
459 this_storage = this_effect = 459 this_storage = this_effect =
460 graph()->NewNode(simplified()->LoadField(field_access), 460 graph()->NewNode(simplified()->LoadField(field_access),
461 this_storage, this_effect, this_control); 461 this_storage, this_effect, this_control);
462 field_access.offset = HeapNumber::kValueOffset; 462 field_access.offset = HeapNumber::kValueOffset;
463 field_access.name = MaybeHandle<Name>(); 463 field_access.name = MaybeHandle<Name>();
464 } 464 }
465 field_access.machine_type = kMachFloat64; 465 field_access.machine_type = kMachFloat64;
466 } 466 }
467 this_value = this_effect = 467 this_value = this_effect =
468 graph()->NewNode(simplified()->LoadField(field_access), 468 graph()->NewNode(simplified()->LoadField(field_access),
469 this_storage, this_effect, this_control); 469 this_storage, this_effect, this_control);
470 } else { 470 } else {
471 DCHECK_EQ(PropertyAccessMode::kStore, access_mode); 471 DCHECK_EQ(AccessMode::kStore, access_mode);
472 if (field_type->Is(Type::UntaggedFloat64())) { 472 if (field_type->Is(Type::UntaggedFloat64())) {
473 Node* check = 473 Node* check =
474 graph()->NewNode(simplified()->ObjectIsNumber(), this_value); 474 graph()->NewNode(simplified()->ObjectIsNumber(), this_value);
475 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), 475 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
476 check, this_control); 476 check, this_control);
477 exit_controls.push_back( 477 exit_controls.push_back(
478 graph()->NewNode(common()->IfFalse(), branch)); 478 graph()->NewNode(common()->IfFalse(), branch));
479 this_control = graph()->NewNode(common()->IfTrue(), branch); 479 this_control = graph()->NewNode(common()->IfTrue(), branch);
480 this_value = graph()->NewNode(common()->Guard(Type::Number()), 480 this_value = graph()->NewNode(common()->Guard(Type::Number()),
481 this_value, this_control); 481 this_value, this_control);
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
574 } 574 }
575 } 575 }
576 } 576 }
577 577
578 // Remember the final state for this property access. 578 // Remember the final state for this property access.
579 values.push_back(this_value); 579 values.push_back(this_value);
580 effects.push_back(this_effect); 580 effects.push_back(this_effect);
581 controls.push_back(this_control); 581 controls.push_back(this_control);
582 } 582 }
583 583
584 // Collect the fallthru control as final "exit" control. 584 // Collect the fallthrough control as final "exit" control.
585 if (fallthrough_control != control) { 585 if (fallthrough_control != control) {
586 // Mark the last fallthru branch as deferred. 586 // Mark the last fallthrough branch as deferred.
587 Node* branch = NodeProperties::GetControlInput(fallthrough_control); 587 Node* branch = NodeProperties::GetControlInput(fallthrough_control);
588 DCHECK_EQ(IrOpcode::kBranch, branch->opcode()); 588 DCHECK_EQ(IrOpcode::kBranch, branch->opcode());
589 if (fallthrough_control->opcode() == IrOpcode::kIfTrue) { 589 if (fallthrough_control->opcode() == IrOpcode::kIfTrue) {
590 NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kFalse)); 590 NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kFalse));
591 } else { 591 } else {
592 DCHECK_EQ(IrOpcode::kIfFalse, fallthrough_control->opcode()); 592 DCHECK_EQ(IrOpcode::kIfFalse, fallthrough_control->opcode());
593 NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kTrue)); 593 NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kTrue));
594 } 594 }
595 } 595 }
596 exit_controls.push_back(fallthrough_control); 596 exit_controls.push_back(fallthrough_control);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
640 640
641 // Extract receiver maps from the LOAD_IC using the LoadICNexus. 641 // Extract receiver maps from the LOAD_IC using the LoadICNexus.
642 MapHandleList receiver_maps; 642 MapHandleList receiver_maps;
643 if (!p.feedback().IsValid()) return NoChange(); 643 if (!p.feedback().IsValid()) return NoChange();
644 LoadICNexus nexus(p.feedback().vector(), p.feedback().slot()); 644 LoadICNexus nexus(p.feedback().vector(), p.feedback().slot());
645 if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange(); 645 if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange();
646 DCHECK_LT(0, receiver_maps.length()); 646 DCHECK_LT(0, receiver_maps.length());
647 647
648 // Try to lower the named access based on the {receiver_maps}. 648 // Try to lower the named access based on the {receiver_maps}.
649 return ReduceNamedAccess(node, value, receiver_maps, p.name(), 649 return ReduceNamedAccess(node, value, receiver_maps, p.name(),
650 PropertyAccessMode::kLoad, p.language_mode()); 650 AccessMode::kLoad, p.language_mode());
651 } 651 }
652 652
653 653
654 Reduction JSNativeContextSpecialization::ReduceJSStoreNamed(Node* node) { 654 Reduction JSNativeContextSpecialization::ReduceJSStoreNamed(Node* node) {
655 DCHECK_EQ(IrOpcode::kJSStoreNamed, node->opcode()); 655 DCHECK_EQ(IrOpcode::kJSStoreNamed, node->opcode());
656 NamedAccess const& p = NamedAccessOf(node->op()); 656 NamedAccess const& p = NamedAccessOf(node->op());
657 Node* const value = NodeProperties::GetValueInput(node, 1); 657 Node* const value = NodeProperties::GetValueInput(node, 1);
658 658
659 // Extract receiver maps from the STORE_IC using the StoreICNexus. 659 // Extract receiver maps from the STORE_IC using the StoreICNexus.
660 MapHandleList receiver_maps; 660 MapHandleList receiver_maps;
661 if (!p.feedback().IsValid()) return NoChange(); 661 if (!p.feedback().IsValid()) return NoChange();
662 StoreICNexus nexus(p.feedback().vector(), p.feedback().slot()); 662 StoreICNexus nexus(p.feedback().vector(), p.feedback().slot());
663 if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange(); 663 if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange();
664 DCHECK_LT(0, receiver_maps.length()); 664 DCHECK_LT(0, receiver_maps.length());
665 665
666 // Try to lower the named access based on the {receiver_maps}. 666 // Try to lower the named access based on the {receiver_maps}.
667 return ReduceNamedAccess(node, value, receiver_maps, p.name(), 667 return ReduceNamedAccess(node, value, receiver_maps, p.name(),
668 PropertyAccessMode::kStore, p.language_mode()); 668 AccessMode::kStore, p.language_mode());
669 }
670
671
672 Reduction JSNativeContextSpecialization::ReduceElementAccess(
673 Node* node, Node* index, Node* value, MapHandleList const& receiver_maps,
674 AccessMode access_mode, LanguageMode language_mode) {
675 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
676 node->opcode() == IrOpcode::kJSStoreProperty);
677 Node* receiver = NodeProperties::GetValueInput(node, 0);
678 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
679 Node* effect = NodeProperties::GetEffectInput(node);
680 Node* control = NodeProperties::GetControlInput(node);
681
682 // Not much we can do if deoptimization support is disabled.
683 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
684
685 // Compute element access infos for the receiver maps.
686 ZoneVector<ElementAccessInfo> access_infos(zone());
687 if (!access_info_factory().ComputeElementAccessInfos(
688 receiver_maps, access_mode, &access_infos)) {
689 return NoChange();
690 }
691
692 // Nothing to do if we have no non-deprecated maps.
693 if (access_infos.empty()) return NoChange();
694
695 // The final states for every polymorphic branch. We join them with
696 // Merge+Phi+EffectPhi at the bottom.
697 ZoneVector<Node*> values(zone());
698 ZoneVector<Node*> effects(zone());
699 ZoneVector<Node*> controls(zone());
700
701 // The list of "exiting" controls, which currently go to a single deoptimize.
702 // TODO(bmeurer): Consider using an IC as fallback.
703 Node* const exit_effect = effect;
704 ZoneVector<Node*> exit_controls(zone());
705
706 // Ensure that {receiver} is a heap object.
707 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
708 Node* branch =
709 graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
710 exit_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
711 control = graph()->NewNode(common()->IfFalse(), branch);
712
713 // Load the {receiver} map. The resulting effect is the dominating effect for
714 // all (polymorphic) branches.
715 Node* receiver_map = effect =
716 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
717 receiver, effect, control);
718
719 // Generate code for the various different element access patterns.
720 Node* fallthrough_control = control;
721 for (ElementAccessInfo const& access_info : access_infos) {
722 Node* this_receiver = receiver;
723 Node* this_value = value;
724 Node* this_index = index;
725 Node* this_effect = effect;
726 Node* this_control;
727
728 // Perform map check on {receiver}.
729 Type* receiver_type = access_info.receiver_type();
730 {
731 ZoneVector<Node*> this_controls(zone());
732 for (auto i = access_info.receiver_type()->Classes(); !i.Done();
733 i.Advance()) {
734 Handle<Map> map = i.Current();
735 Node* check =
736 graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()),
737 receiver_map, jsgraph()->Constant(map));
738 Node* branch =
739 graph()->NewNode(common()->Branch(), check, fallthrough_control);
740 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
741 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
742 }
743 int const this_control_count = static_cast<int>(this_controls.size());
744 this_control =
745 (this_control_count == 1)
746 ? this_controls.front()
747 : graph()->NewNode(common()->Merge(this_control_count),
748 this_control_count, &this_controls.front());
749 }
750
751 // Certain stores need a prototype chain check because shape changes
752 // could allow callbacks on elements in the prototype chain that are
753 // not compatible with (monomorphic) keyed stores.
754 Handle<JSObject> holder;
755 if (access_info.holder().ToHandle(&holder)) {
756 AssumePrototypesStable(receiver_type, holder);
757 }
758
759 // Check that the {index} is actually a Number.
760 if (!NumberMatcher(this_index).HasValue()) {
761 Node* check =
762 graph()->NewNode(simplified()->ObjectIsNumber(), this_index);
763 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
764 check, this_control);
765 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch));
766 this_control = graph()->NewNode(common()->IfTrue(), branch);
767 this_index = graph()->NewNode(common()->Guard(Type::Number()), this_index,
768 this_control);
769 }
770
771 // Convert the {index} to an unsigned32 value and check if the result is
772 // equal to the original {index}.
773 if (!NumberMatcher(this_index).IsInRange(0.0, kMaxUInt32)) {
774 Node* this_index32 =
775 graph()->NewNode(simplified()->NumberToUint32(), this_index);
776 Node* check = graph()->NewNode(simplified()->NumberEqual(), this_index32,
777 this_index);
778 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
779 check, this_control);
780 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch));
781 this_control = graph()->NewNode(common()->IfTrue(), branch);
782 this_index = this_index32;
783 }
784
785 // TODO(bmeurer): We currently specialize based on elements kind. We should
786 // also be able to properly support strings and other JSObjects here.
787 ElementsKind elements_kind = access_info.elements_kind();
788
789 // Load the elements for the {receiver}.
790 Node* this_elements = this_effect = graph()->NewNode(
791 simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
792 this_receiver, this_effect, this_control);
793
794 // Don't try to store to a copy-on-write backing store.
795 if (access_mode == AccessMode::kStore &&
796 IsFastSmiOrObjectElementsKind(elements_kind)) {
797 Node* this_elements_map = this_effect =
798 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
799 this_elements, this_effect, this_control);
800 check = graph()->NewNode(
801 simplified()->ReferenceEqual(Type::Any()), this_elements_map,
802 jsgraph()->HeapConstant(factory()->fixed_array_map()));
803 branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), check,
804 this_control);
805 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch));
806 this_control = graph()->NewNode(common()->IfTrue(), branch);
807 }
808
809 // Load the length of the {receiver}.
810 FieldAccess length_access = {
811 kTaggedBase, JSArray::kLengthOffset, factory()->name_string(),
812 type_cache_.kJSArrayLengthType, kMachAnyTagged};
813 if (IsFastDoubleElementsKind(elements_kind)) {
814 length_access.type = type_cache_.kFixedDoubleArrayLengthType;
815 } else if (IsFastElementsKind(elements_kind)) {
816 length_access.type = type_cache_.kFixedArrayLengthType;
817 }
818 Node* this_length = this_effect =
819 graph()->NewNode(simplified()->LoadField(length_access), this_receiver,
820 this_effect, this_control);
821
822 // Check that the {index} is in the valid range for the {receiver}.
823 Node* check = graph()->NewNode(simplified()->NumberLessThan(), this_index,
824 this_length);
825 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), check,
826 this_control);
827 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch));
828 this_control = graph()->NewNode(common()->IfTrue(), branch);
829
830 // Compute the element access.
831 Type* element_type = Type::Any();
832 MachineType element_machine_type = kMachAnyTagged;
833 if (IsFastDoubleElementsKind(elements_kind)) {
834 element_type = type_cache_.kFloat64;
835 element_machine_type = kMachFloat64;
836 } else if (IsFastSmiElementsKind(elements_kind)) {
837 element_type = type_cache_.kSmi;
838 }
839 ElementAccess element_access = {kTaggedBase, FixedArray::kHeaderSize,
840 element_type, element_machine_type};
841
842 // Access the actual element.
843 if (access_mode == AccessMode::kLoad) {
844 this_value = this_effect = graph()->NewNode(
845 simplified()->LoadElement(element_access), this_elements, this_index,
846 this_effect, this_control);
847 } else {
848 DCHECK_EQ(AccessMode::kStore, access_mode);
849 if (IsFastSmiElementsKind(elements_kind)) {
850 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), this_value);
851 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
852 check, this_control);
853 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch));
854 this_control = graph()->NewNode(common()->IfTrue(), branch);
855 } else if (IsFastDoubleElementsKind(elements_kind)) {
856 Node* check =
857 graph()->NewNode(simplified()->ObjectIsNumber(), this_value);
858 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
859 check, this_control);
860 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch));
861 this_control = graph()->NewNode(common()->IfTrue(), branch);
862 this_value = graph()->NewNode(common()->Guard(Type::Number()),
863 this_value, this_control);
864 }
865 this_effect = graph()->NewNode(simplified()->StoreElement(element_access),
866 this_elements, this_index, this_value,
867 this_effect, this_control);
868 }
869
870 // Remember the final state for this element access.
871 values.push_back(this_value);
872 effects.push_back(this_effect);
873 controls.push_back(this_control);
874 }
875
876 // Collect the fallthrough control as final "exit" control.
877 if (fallthrough_control != control) {
878 // Mark the last fallthrough branch as deferred.
879 Node* branch = NodeProperties::GetControlInput(fallthrough_control);
880 DCHECK_EQ(IrOpcode::kBranch, branch->opcode());
881 if (fallthrough_control->opcode() == IrOpcode::kIfTrue) {
882 NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kFalse));
883 } else {
884 DCHECK_EQ(IrOpcode::kIfFalse, fallthrough_control->opcode());
885 NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kTrue));
886 }
887 }
888 exit_controls.push_back(fallthrough_control);
889
890 // Generate the single "exit" point, where we get if either all map/instance
891 // type checks failed, or one of the assumptions inside one of the cases
892 // failes (i.e. failing prototype chain check).
893 // TODO(bmeurer): Consider falling back to IC here if deoptimization is
894 // disabled.
895 int const exit_control_count = static_cast<int>(exit_controls.size());
896 Node* exit_control =
897 (exit_control_count == 1)
898 ? exit_controls.front()
899 : graph()->NewNode(common()->Merge(exit_control_count),
900 exit_control_count, &exit_controls.front());
901 Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state,
902 exit_effect, exit_control);
903 // TODO(bmeurer): This should be on the AdvancedReducer somehow.
904 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
905
906 // Generate the final merge point for all (polymorphic) branches.
907 int const control_count = static_cast<int>(controls.size());
908 if (control_count == 0) {
909 value = effect = control = jsgraph()->Dead();
910 } else if (control_count == 1) {
911 value = values.front();
912 effect = effects.front();
913 control = controls.front();
914 } else {
915 control = graph()->NewNode(common()->Merge(control_count), control_count,
916 &controls.front());
917 values.push_back(control);
918 value = graph()->NewNode(common()->Phi(kMachAnyTagged, control_count),
919 control_count + 1, &values.front());
920 effects.push_back(control);
921 effect = graph()->NewNode(common()->EffectPhi(control_count),
922 control_count + 1, &effects.front());
923 }
924 return Replace(node, value, effect, control);
669 } 925 }
670 926
671 927
672 Reduction JSNativeContextSpecialization::ReduceKeyedAccess( 928 Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
673 Node* node, Node* index, Node* value, FeedbackNexus const& nexus, 929 Node* node, Node* index, Node* value, FeedbackNexus const& nexus,
674 PropertyAccessMode access_mode, LanguageMode language_mode) { 930 AccessMode access_mode, LanguageMode language_mode) {
675 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty || 931 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
676 node->opcode() == IrOpcode::kJSStoreProperty); 932 node->opcode() == IrOpcode::kJSStoreProperty);
677 933
678 // Extract receiver maps from the {nexus}. 934 // Extract receiver maps from the {nexus}.
679 MapHandleList receiver_maps; 935 MapHandleList receiver_maps;
680 if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange(); 936 if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange();
681 DCHECK_LT(0, receiver_maps.length()); 937 DCHECK_LT(0, receiver_maps.length());
682 938
683 // Optimize access for constant {index}. 939 // Optimize access for constant {index}.
684 HeapObjectMatcher mindex(index); 940 HeapObjectMatcher mindex(index);
685 if (mindex.HasValue() && mindex.Value()->IsPrimitive()) { 941 if (mindex.HasValue() && mindex.Value()->IsPrimitive()) {
686 // Keyed access requires a ToPropertyKey on the {index} first before 942 // Keyed access requires a ToPropertyKey on the {index} first before
687 // looking up the property on the object (see ES6 section 12.3.2.1). 943 // looking up the property on the object (see ES6 section 12.3.2.1).
688 // We can only do this for non-observable ToPropertyKey invocations, 944 // We can only do this for non-observable ToPropertyKey invocations,
689 // so we limit the constant indices to primitives at this point. 945 // so we limit the constant indices to primitives at this point.
690 Handle<Name> name; 946 Handle<Name> name;
691 if (Object::ToName(isolate(), mindex.Value()).ToHandle(&name)) { 947 if (Object::ToName(isolate(), mindex.Value()).ToHandle(&name)) {
692 uint32_t array_index; 948 uint32_t array_index;
693 if (name->AsArrayIndex(&array_index)) { 949 if (name->AsArrayIndex(&array_index)) {
694 // TODO(bmeurer): Optimize element access with constant {index}. 950 // Use the constant array index.
951 index = jsgraph()->Constant(static_cast<double>(array_index));
695 } else { 952 } else {
696 name = factory()->InternalizeName(name); 953 name = factory()->InternalizeName(name);
697 return ReduceNamedAccess(node, value, receiver_maps, name, access_mode, 954 return ReduceNamedAccess(node, value, receiver_maps, name, access_mode,
698 language_mode); 955 language_mode);
699 } 956 }
700 } 957 }
701 } 958 }
702 959
703 // Check if we have feedback for a named access. 960 // Check if we have feedback for a named access.
704 if (Name* name = nexus.FindFirstName()) { 961 if (Name* name = nexus.FindFirstName()) {
705 return ReduceNamedAccess(node, value, receiver_maps, 962 return ReduceNamedAccess(node, value, receiver_maps,
706 handle(name, isolate()), access_mode, 963 handle(name, isolate()), access_mode,
707 language_mode, index); 964 language_mode, index);
708 } 965 }
709 966
710 return NoChange(); 967 // Try to lower the element access based on the {receiver_maps}.
968 return ReduceElementAccess(node, index, value, receiver_maps, access_mode,
969 language_mode);
711 } 970 }
712 971
713 972
714 Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) { 973 Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) {
715 DCHECK_EQ(IrOpcode::kJSLoadProperty, node->opcode()); 974 DCHECK_EQ(IrOpcode::kJSLoadProperty, node->opcode());
716 PropertyAccess const& p = PropertyAccessOf(node->op()); 975 PropertyAccess const& p = PropertyAccessOf(node->op());
717 Node* const index = NodeProperties::GetValueInput(node, 1); 976 Node* const index = NodeProperties::GetValueInput(node, 1);
718 Node* const value = jsgraph()->Dead(); 977 Node* const value = jsgraph()->Dead();
719 978
720 // Extract receiver maps from the KEYED_LOAD_IC using the KeyedLoadICNexus. 979 // Extract receiver maps from the KEYED_LOAD_IC using the KeyedLoadICNexus.
721 if (!p.feedback().IsValid()) return NoChange(); 980 if (!p.feedback().IsValid()) return NoChange();
722 KeyedLoadICNexus nexus(p.feedback().vector(), p.feedback().slot()); 981 KeyedLoadICNexus nexus(p.feedback().vector(), p.feedback().slot());
723 982
724 // Try to lower the keyed access based on the {nexus}. 983 // Try to lower the keyed access based on the {nexus}.
725 return ReduceKeyedAccess(node, index, value, nexus, PropertyAccessMode::kLoad, 984 return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kLoad,
726 p.language_mode()); 985 p.language_mode());
727 } 986 }
728 987
729 988
730 Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) { 989 Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) {
731 DCHECK_EQ(IrOpcode::kJSStoreProperty, node->opcode()); 990 DCHECK_EQ(IrOpcode::kJSStoreProperty, node->opcode());
732 PropertyAccess const& p = PropertyAccessOf(node->op()); 991 PropertyAccess const& p = PropertyAccessOf(node->op());
733 Node* const index = NodeProperties::GetValueInput(node, 1); 992 Node* const index = NodeProperties::GetValueInput(node, 1);
734 Node* const value = NodeProperties::GetValueInput(node, 2); 993 Node* const value = NodeProperties::GetValueInput(node, 2);
735 994
736 // Extract receiver maps from the KEYED_STORE_IC using the KeyedStoreICNexus. 995 // Extract receiver maps from the KEYED_STORE_IC using the KeyedStoreICNexus.
737 if (!p.feedback().IsValid()) return NoChange(); 996 if (!p.feedback().IsValid()) return NoChange();
738 KeyedStoreICNexus nexus(p.feedback().vector(), p.feedback().slot()); 997 KeyedStoreICNexus nexus(p.feedback().vector(), p.feedback().slot());
739 998
740 // Try to lower the keyed access based on the {nexus}. 999 // Try to lower the keyed access based on the {nexus}.
741 return ReduceKeyedAccess(node, index, value, nexus, 1000 return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kStore,
742 PropertyAccessMode::kStore, p.language_mode()); 1001 p.language_mode());
743 } 1002 }
744 1003
745 1004
746 Reduction JSNativeContextSpecialization::Replace(Node* node, 1005 Reduction JSNativeContextSpecialization::Replace(Node* node,
747 Handle<Object> value) { 1006 Handle<Object> value) {
748 return Replace(node, jsgraph()->Constant(value)); 1007 return Replace(node, jsgraph()->Constant(value));
749 } 1008 }
750 1009
751 1010
752 bool JSNativeContextSpecialization::LookupInScriptContextTable( 1011 bool JSNativeContextSpecialization::LookupInScriptContextTable(
(...skipping 20 matching lines...) Expand all
773 // Determine actual holder and perform prototype chain checks. 1032 // Determine actual holder and perform prototype chain checks.
774 for (auto i = receiver_type->Classes(); !i.Done(); i.Advance()) { 1033 for (auto i = receiver_type->Classes(); !i.Done(); i.Advance()) {
775 Handle<Map> map = i.Current(); 1034 Handle<Map> map = i.Current();
776 // Perform the implicit ToObject for primitives here. 1035 // Perform the implicit ToObject for primitives here.
777 // Implemented according to ES6 section 7.3.2 GetV (V, P). 1036 // Implemented according to ES6 section 7.3.2 GetV (V, P).
778 Handle<JSFunction> constructor; 1037 Handle<JSFunction> constructor;
779 if (Map::GetConstructorFunction(map, native_context()) 1038 if (Map::GetConstructorFunction(map, native_context())
780 .ToHandle(&constructor)) { 1039 .ToHandle(&constructor)) {
781 map = handle(constructor->initial_map(), isolate()); 1040 map = handle(constructor->initial_map(), isolate());
782 } 1041 }
783 for (PrototypeIterator j(map);; j.Advance()) { 1042 for (PrototypeIterator j(map); !j.IsAtEnd(); j.Advance()) {
784 // Check that the {prototype} still has the same map. All prototype 1043 // Check that the {prototype} still has the same map. All prototype
785 // maps are guaranteed to be stable, so it's sufficient to add a 1044 // maps are guaranteed to be stable, so it's sufficient to add a
786 // stability dependency here. 1045 // stability dependency here.
787 Handle<JSReceiver> const prototype = 1046 Handle<JSReceiver> const prototype =
788 PrototypeIterator::GetCurrent<JSReceiver>(j); 1047 PrototypeIterator::GetCurrent<JSReceiver>(j);
789 dependencies()->AssumeMapStable(handle(prototype->map(), isolate())); 1048 dependencies()->AssumeMapStable(handle(prototype->map(), isolate()));
790 // Stop once we get to the holder. 1049 // Stop once we get to the holder.
791 if (prototype.is_identical_to(holder)) break; 1050 if (prototype.is_identical_to(holder)) break;
792 } 1051 }
793 } 1052 }
(...skipping 30 matching lines...) Expand all
824 } 1083 }
825 1084
826 1085
827 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { 1086 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const {
828 return jsgraph()->simplified(); 1087 return jsgraph()->simplified();
829 } 1088 }
830 1089
831 } // namespace compiler 1090 } // namespace compiler
832 } // namespace internal 1091 } // namespace internal
833 } // namespace v8 1092 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/js-native-context-specialization.h ('k') | src/compiler/property-access-info.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698