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/ic/keyed-store-generic.h" | 5 #include "src/ic/keyed-store-generic.h" |
6 | 6 |
7 #include "src/code-factory.h" | 7 #include "src/code-factory.h" |
8 #include "src/code-stub-assembler.h" | 8 #include "src/code-stub-assembler.h" |
9 #include "src/contexts.h" | 9 #include "src/contexts.h" |
10 #include "src/ic/accessor-assembler.h" | 10 #include "src/ic/accessor-assembler.h" |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
65 Node* current_elements_kind, Node* context, | 65 Node* current_elements_kind, Node* context, |
66 ElementsKind packed_kind, | 66 ElementsKind packed_kind, |
67 ElementsKind packed_kind_2, Label* bailout); | 67 ElementsKind packed_kind_2, Label* bailout); |
68 | 68 |
69 void JumpIfDataProperty(Node* details, Label* writable, Label* readonly); | 69 void JumpIfDataProperty(Node* details, Label* writable, Label* readonly); |
70 void LookupPropertyOnPrototypeChain(Node* receiver_map, Node* name, | 70 void LookupPropertyOnPrototypeChain(Node* receiver_map, Node* name, |
71 Label* accessor, | 71 Label* accessor, |
72 Variable* var_accessor_pair, | 72 Variable* var_accessor_pair, |
73 Variable* var_accessor_holder, | 73 Variable* var_accessor_holder, |
74 Label* readonly, Label* bailout); | 74 Label* readonly, Label* bailout); |
| 75 |
| 76 void CheckFieldType(Node* descriptors, Node* name_index, Node* representation, |
| 77 Node* value, Label* bailout); |
| 78 void OverwriteExistingFastProperty(Node* object, Node* object_map, |
| 79 Node* properties, Node* descriptors, |
| 80 Node* descriptor_name_index, Node* details, |
| 81 Node* value, Label* slow); |
75 }; | 82 }; |
76 | 83 |
77 void KeyedStoreGenericGenerator::Generate(compiler::CodeAssemblerState* state, | 84 void KeyedStoreGenericGenerator::Generate(compiler::CodeAssemblerState* state, |
78 LanguageMode language_mode) { | 85 LanguageMode language_mode) { |
79 KeyedStoreGenericAssembler assembler(state); | 86 KeyedStoreGenericAssembler assembler(state); |
80 assembler.KeyedStoreGeneric(language_mode); | 87 assembler.KeyedStoreGeneric(language_mode); |
81 } | 88 } |
82 | 89 |
83 void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements( | 90 void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements( |
84 Node* receiver_map, Label* non_fast_elements, Label* only_fast_elements) { | 91 Node* receiver_map, Label* non_fast_elements, Label* only_fast_elements) { |
(...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
537 &var_entry, &next_proto, bailout); | 544 &var_entry, &next_proto, bailout); |
538 Bind(&found_fast); | 545 Bind(&found_fast); |
539 { | 546 { |
540 Node* descriptors = var_meta_storage.value(); | 547 Node* descriptors = var_meta_storage.value(); |
541 Node* name_index = var_entry.value(); | 548 Node* name_index = var_entry.value(); |
542 Node* details = | 549 Node* details = |
543 LoadDetailsByKeyIndex<DescriptorArray>(descriptors, name_index); | 550 LoadDetailsByKeyIndex<DescriptorArray>(descriptors, name_index); |
544 JumpIfDataProperty(details, &ok_to_write, readonly); | 551 JumpIfDataProperty(details, &ok_to_write, readonly); |
545 | 552 |
546 // Accessor case. | 553 // Accessor case. |
| 554 // TODO(jkummerow): Implement a trimmed-down LoadAccessorFromFastObject. |
547 Variable var_details(this, MachineRepresentation::kWord32); | 555 Variable var_details(this, MachineRepresentation::kWord32); |
548 LoadPropertyFromFastObject(holder, holder_map, descriptors, name_index, | 556 LoadPropertyFromFastObject(holder, holder_map, descriptors, name_index, |
549 &var_details, var_accessor_pair); | 557 &var_details, var_accessor_pair); |
550 var_accessor_holder->Bind(holder); | 558 var_accessor_holder->Bind(holder); |
551 Goto(accessor); | 559 Goto(accessor); |
552 } | 560 } |
553 | 561 |
554 Bind(&found_dict); | 562 Bind(&found_dict); |
555 { | 563 { |
556 Node* dictionary = var_meta_storage.value(); | 564 Node* dictionary = var_meta_storage.value(); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
592 bailout); | 600 bailout); |
593 Node* proto = LoadMapPrototype(holder_map); | 601 Node* proto = LoadMapPrototype(holder_map); |
594 GotoIf(WordEqual(proto, NullConstant()), &ok_to_write); | 602 GotoIf(WordEqual(proto, NullConstant()), &ok_to_write); |
595 var_holder.Bind(proto); | 603 var_holder.Bind(proto); |
596 var_holder_map.Bind(LoadMap(proto)); | 604 var_holder_map.Bind(LoadMap(proto)); |
597 Goto(&loop); | 605 Goto(&loop); |
598 } | 606 } |
599 Bind(&ok_to_write); | 607 Bind(&ok_to_write); |
600 } | 608 } |
601 | 609 |
| 610 void KeyedStoreGenericAssembler::CheckFieldType(Node* descriptors, |
| 611 Node* name_index, |
| 612 Node* representation, |
| 613 Node* value, Label* bailout) { |
| 614 Label r_smi(this), r_double(this), r_heapobject(this), all_fine(this); |
| 615 // Ignore FLAG_track_fields etc. and always emit code for all checks, |
| 616 // because this builtin is part of the snapshot and therefore should |
| 617 // be flag independent. |
| 618 GotoIf(Word32Equal(representation, Int32Constant(Representation::kSmi)), |
| 619 &r_smi); |
| 620 GotoIf(Word32Equal(representation, Int32Constant(Representation::kDouble)), |
| 621 &r_double); |
| 622 GotoIf( |
| 623 Word32Equal(representation, Int32Constant(Representation::kHeapObject)), |
| 624 &r_heapobject); |
| 625 GotoIf(Word32Equal(representation, Int32Constant(Representation::kNone)), |
| 626 bailout); |
| 627 CSA_ASSERT(this, Word32Equal(representation, |
| 628 Int32Constant(Representation::kTagged))); |
| 629 Goto(&all_fine); |
| 630 |
| 631 Bind(&r_smi); |
| 632 { Branch(TaggedIsSmi(value), &all_fine, bailout); } |
| 633 |
| 634 Bind(&r_double); |
| 635 { |
| 636 GotoIf(TaggedIsSmi(value), &all_fine); |
| 637 Node* value_map = LoadMap(value); |
| 638 // While supporting mutable HeapNumbers would be straightforward, such |
| 639 // objects should not end up here anyway. |
| 640 CSA_ASSERT(this, |
| 641 WordNotEqual(value_map, |
| 642 LoadRoot(Heap::kMutableHeapNumberMapRootIndex))); |
| 643 Branch(IsHeapNumberMap(value_map), &all_fine, bailout); |
| 644 } |
| 645 |
| 646 Bind(&r_heapobject); |
| 647 { |
| 648 GotoIf(TaggedIsSmi(value), bailout); |
| 649 Node* field_type = |
| 650 LoadValueByKeyIndex<DescriptorArray>(descriptors, name_index); |
| 651 intptr_t kNoneType = reinterpret_cast<intptr_t>(FieldType::None()); |
| 652 intptr_t kAnyType = reinterpret_cast<intptr_t>(FieldType::Any()); |
| 653 // FieldType::None can't hold any value. |
| 654 GotoIf(WordEqual(field_type, IntPtrConstant(kNoneType)), bailout); |
| 655 // FieldType::Any can hold any value. |
| 656 GotoIf(WordEqual(field_type, IntPtrConstant(kAnyType)), &all_fine); |
| 657 CSA_ASSERT(this, IsWeakCell(field_type)); |
| 658 // Cleared WeakCells count as FieldType::None, which can't hold any value. |
| 659 field_type = LoadWeakCellValue(field_type, bailout); |
| 660 // FieldType::Class(...) performs a map check. |
| 661 CSA_ASSERT(this, IsMap(field_type)); |
| 662 Branch(WordEqual(LoadMap(value), field_type), &all_fine, bailout); |
| 663 } |
| 664 |
| 665 Bind(&all_fine); |
| 666 } |
| 667 |
| 668 void KeyedStoreGenericAssembler::OverwriteExistingFastProperty( |
| 669 Node* object, Node* object_map, Node* properties, Node* descriptors, |
| 670 Node* descriptor_name_index, Node* details, Node* value, Label* slow) { |
| 671 // Properties in descriptors can't be overwritten without map transition. |
| 672 GotoIf(Word32NotEqual(DecodeWord32<PropertyDetails::LocationField>(details), |
| 673 Int32Constant(kField)), |
| 674 slow); |
| 675 |
| 676 if (FLAG_track_constant_fields) { |
| 677 // TODO(ishell): Taking the slow path is not necessary if new and old |
| 678 // values are identical. |
| 679 GotoIf(Word32Equal(DecodeWord32<PropertyDetails::ConstnessField>(details), |
| 680 Int32Constant(kConst)), |
| 681 slow); |
| 682 } |
| 683 |
| 684 Label done(this); |
| 685 Node* representation = |
| 686 DecodeWord32<PropertyDetails::RepresentationField>(details); |
| 687 |
| 688 CheckFieldType(descriptors, descriptor_name_index, representation, value, |
| 689 slow); |
| 690 Node* field_index = |
| 691 DecodeWordFromWord32<PropertyDetails::FieldIndexField>(details); |
| 692 Node* inobject_properties = LoadMapInobjectProperties(object_map); |
| 693 |
| 694 Label inobject(this), backing_store(this); |
| 695 Branch(UintPtrLessThan(field_index, inobject_properties), &inobject, |
| 696 &backing_store); |
| 697 |
| 698 Bind(&inobject); |
| 699 { |
| 700 Node* field_offset = |
| 701 IntPtrMul(IntPtrSub(LoadMapInstanceSize(object_map), |
| 702 IntPtrSub(inobject_properties, field_index)), |
| 703 IntPtrConstant(kPointerSize)); |
| 704 Label tagged_rep(this), double_rep(this); |
| 705 Branch(Word32Equal(representation, Int32Constant(Representation::kDouble)), |
| 706 &double_rep, &tagged_rep); |
| 707 Bind(&double_rep); |
| 708 { |
| 709 Node* double_value = ChangeNumberToFloat64(value); |
| 710 if (FLAG_unbox_double_fields) { |
| 711 StoreObjectFieldNoWriteBarrier(object, field_offset, double_value, |
| 712 MachineRepresentation::kFloat64); |
| 713 } else { |
| 714 Node* mutable_heap_number = LoadObjectField(object, field_offset); |
| 715 StoreHeapNumberValue(mutable_heap_number, double_value); |
| 716 } |
| 717 Goto(&done); |
| 718 } |
| 719 |
| 720 Bind(&tagged_rep); |
| 721 { |
| 722 StoreObjectField(object, field_offset, value); |
| 723 Goto(&done); |
| 724 } |
| 725 } |
| 726 |
| 727 Bind(&backing_store); |
| 728 { |
| 729 Node* backing_store_index = IntPtrSub(field_index, inobject_properties); |
| 730 Label tagged_rep(this), double_rep(this); |
| 731 Branch(Word32Equal(representation, Int32Constant(Representation::kDouble)), |
| 732 &double_rep, &tagged_rep); |
| 733 Bind(&double_rep); |
| 734 { |
| 735 Node* double_value = ChangeNumberToFloat64(value); |
| 736 Node* mutable_heap_number = |
| 737 LoadFixedArrayElement(properties, backing_store_index); |
| 738 StoreHeapNumberValue(mutable_heap_number, double_value); |
| 739 Goto(&done); |
| 740 } |
| 741 Bind(&tagged_rep); |
| 742 { |
| 743 StoreFixedArrayElement(properties, backing_store_index, value); |
| 744 Goto(&done); |
| 745 } |
| 746 } |
| 747 Bind(&done); |
| 748 } |
| 749 |
602 void KeyedStoreGenericAssembler::EmitGenericPropertyStore( | 750 void KeyedStoreGenericAssembler::EmitGenericPropertyStore( |
603 Node* receiver, Node* receiver_map, const StoreICParameters* p, Label* slow, | 751 Node* receiver, Node* receiver_map, const StoreICParameters* p, Label* slow, |
604 LanguageMode language_mode) { | 752 LanguageMode language_mode) { |
605 Variable var_accessor_pair(this, MachineRepresentation::kTagged); | 753 Variable var_accessor_pair(this, MachineRepresentation::kTagged); |
606 Variable var_accessor_holder(this, MachineRepresentation::kTagged); | 754 Variable var_accessor_holder(this, MachineRepresentation::kTagged); |
607 Label stub_cache(this), fast_properties(this), dictionary_properties(this), | 755 Label stub_cache(this), fast_properties(this), dictionary_properties(this), |
608 accessor(this), readonly(this); | 756 accessor(this), readonly(this); |
609 Node* properties = LoadProperties(receiver); | 757 Node* properties = LoadProperties(receiver); |
610 Node* properties_map = LoadMap(properties); | 758 Node* properties_map = LoadMap(properties); |
611 Branch(WordEqual(properties_map, LoadRoot(Heap::kHashTableMapRootIndex)), | 759 Branch(WordEqual(properties_map, LoadRoot(Heap::kHashTableMapRootIndex)), |
612 &dictionary_properties, &fast_properties); | 760 &dictionary_properties, &fast_properties); |
613 | 761 |
614 Bind(&fast_properties); | 762 Bind(&fast_properties); |
615 { | 763 { |
616 // TODO(jkummerow): Does it make sense to support some cases here inline? | 764 Comment("fast property store"); |
617 // Maybe overwrite existing writable properties? | 765 Node* bitfield3 = LoadMapBitField3(receiver_map); |
618 // Maybe support map transitions? | 766 Node* descriptors = LoadMapDescriptors(receiver_map); |
619 Goto(&stub_cache); | 767 Label descriptor_found(this); |
| 768 Variable var_name_index(this, MachineType::PointerRepresentation()); |
| 769 // TODO(jkummerow): Maybe look for existing map transitions? |
| 770 Label* notfound = &stub_cache; |
| 771 DescriptorLookup(p->name, descriptors, bitfield3, &descriptor_found, |
| 772 &var_name_index, notfound); |
| 773 |
| 774 Bind(&descriptor_found); |
| 775 { |
| 776 Node* name_index = var_name_index.value(); |
| 777 Node* details = |
| 778 LoadDetailsByKeyIndex<DescriptorArray>(descriptors, name_index); |
| 779 Label data_property(this); |
| 780 JumpIfDataProperty(details, &data_property, &readonly); |
| 781 |
| 782 // Accessor case. |
| 783 // TODO(jkummerow): Implement a trimmed-down LoadAccessorFromFastObject. |
| 784 Variable var_details(this, MachineRepresentation::kWord32); |
| 785 LoadPropertyFromFastObject(receiver, receiver_map, descriptors, |
| 786 name_index, &var_details, &var_accessor_pair); |
| 787 var_accessor_holder.Bind(receiver); |
| 788 Goto(&accessor); |
| 789 |
| 790 Bind(&data_property); |
| 791 { |
| 792 OverwriteExistingFastProperty(receiver, receiver_map, properties, |
| 793 descriptors, name_index, details, |
| 794 p->value, slow); |
| 795 Return(p->value); |
| 796 } |
| 797 } |
620 } | 798 } |
621 | 799 |
622 Bind(&dictionary_properties); | 800 Bind(&dictionary_properties); |
623 { | 801 { |
624 Comment("dictionary property store"); | 802 Comment("dictionary property store"); |
625 // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out | 803 // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out |
626 // seeing global objects here (which would need special handling). | 804 // seeing global objects here (which would need special handling). |
627 | 805 |
628 Variable var_name_index(this, MachineType::PointerRepresentation()); | 806 Variable var_name_index(this, MachineType::PointerRepresentation()); |
629 Label dictionary_found(this, &var_name_index), not_found(this); | 807 Label dictionary_found(this, &var_name_index), not_found(this); |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
769 Bind(&slow); | 947 Bind(&slow); |
770 { | 948 { |
771 Comment("KeyedStoreGeneric_slow"); | 949 Comment("KeyedStoreGeneric_slow"); |
772 TailCallRuntime(Runtime::kSetProperty, context, receiver, name, value, | 950 TailCallRuntime(Runtime::kSetProperty, context, receiver, name, value, |
773 SmiConstant(language_mode)); | 951 SmiConstant(language_mode)); |
774 } | 952 } |
775 } | 953 } |
776 | 954 |
777 } // namespace internal | 955 } // namespace internal |
778 } // namespace v8 | 956 } // namespace v8 |
OLD | NEW |