Chromium Code Reviews| 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 if (FLAG_track_fields) { | |
| 616 GotoIf(Word32Equal(representation, Int32Constant(Representation::kSmi)), | |
| 617 &r_smi); | |
| 618 } | |
| 619 if (FLAG_track_double_fields) { | |
| 620 GotoIf(Word32Equal(representation, Int32Constant(Representation::kDouble)), | |
| 621 &r_double); | |
| 622 } | |
| 623 if (FLAG_track_heap_object_fields) { | |
| 624 GotoIf( | |
| 625 Word32Equal(representation, Int32Constant(Representation::kHeapObject)), | |
| 626 &r_heapobject); | |
| 627 } | |
| 628 if (FLAG_track_fields) { | |
| 629 GotoIf(Word32Equal(representation, Int32Constant(Representation::kNone)), | |
| 630 bailout); | |
| 631 } | |
|
Igor Sheludko
2017/02/16 16:04:37
CSA_ASSERT(representation == kTagged)?
Jakob Kummerow
2017/02/16 18:24:27
Done.
| |
| 632 Goto(&all_fine); | |
| 633 | |
| 634 Bind(&r_smi); | |
|
Igor Sheludko
2017/02/16 16:04:37
1) "if (FLAG_track_fields) {" or we will have an u
Jakob Kummerow
2017/02/16 18:24:27
I agree, but as discussed, that unfortunately does
| |
| 635 { Branch(TaggedIsSmi(value), &all_fine, bailout); } | |
| 636 | |
| 637 Bind(&r_double); | |
|
Igor Sheludko
2017/02/16 16:04:37
Same here.
| |
| 638 { | |
| 639 GotoIf(TaggedIsSmi(value), &all_fine); | |
| 640 Node* value_map = LoadMap(value); | |
| 641 // While supporting mutable HeapNumbers would be straightforward, such | |
| 642 // objects should not end up here anyway. | |
| 643 CSA_ASSERT(this, | |
| 644 WordNotEqual(value_map, | |
| 645 LoadRoot(Heap::kMutableHeapNumberMapRootIndex))); | |
| 646 Branch(IsHeapNumberMap(value_map), &all_fine, bailout); | |
| 647 } | |
| 648 | |
| 649 Bind(&r_heapobject); | |
|
Igor Sheludko
2017/02/16 16:04:37
Same here.
| |
| 650 { | |
| 651 GotoIf(TaggedIsSmi(value), bailout); | |
| 652 Node* field_type = | |
| 653 LoadValueByKeyIndex<DescriptorArray>(descriptors, name_index); | |
| 654 intptr_t kNoneType = reinterpret_cast<intptr_t>(FieldType::None()); | |
| 655 intptr_t kAnyType = reinterpret_cast<intptr_t>(FieldType::Any()); | |
| 656 // FieldType::None can't hold any value. | |
| 657 GotoIf(WordEqual(field_type, IntPtrConstant(kNoneType)), bailout); | |
| 658 // FieldType::Any can hold any value. | |
| 659 GotoIf(WordEqual(field_type, IntPtrConstant(kAnyType)), &all_fine); | |
| 660 CSA_ASSERT(this, IsWeakCell(field_type)); | |
| 661 // Cleared WeakCells count as FieldType::None, which can't hold any value. | |
| 662 field_type = LoadWeakCellValue(field_type, bailout); | |
| 663 // FieldType::Class(...) performs a map check. | |
| 664 CSA_ASSERT(this, IsMap(field_type)); | |
| 665 Branch(WordEqual(LoadMap(value), field_type), &all_fine, bailout); | |
| 666 } | |
| 667 | |
| 668 Bind(&all_fine); | |
| 669 } | |
| 670 | |
| 671 void KeyedStoreGenericAssembler::OverwriteExistingFastProperty( | |
| 672 Node* object, Node* object_map, Node* properties, Node* descriptors, | |
| 673 Node* descriptor_name_index, Node* details, Node* value, Label* slow) { | |
| 674 // Properties in descriptors can't be overwritten without map transition. | |
| 675 GotoIf(Word32NotEqual(DecodeWord32<PropertyDetails::LocationField>(details), | |
| 676 Int32Constant(kField)), | |
| 677 slow); | |
| 678 | |
| 679 if (FLAG_track_constant_fields) { | |
| 680 // TODO(ishell): Taking the slow path is not necessary if new and old | |
| 681 // values are identical. | |
| 682 GotoIf(Word32Equal(DecodeWord32<PropertyDetails::ConstnessField>(details), | |
| 683 Int32Constant(kConst)), | |
| 684 slow); | |
| 685 } | |
| 686 | |
| 687 Label done(this); | |
| 688 Node* representation = | |
| 689 DecodeWord32<PropertyDetails::RepresentationField>(details); | |
| 690 | |
| 691 CheckFieldType(descriptors, descriptor_name_index, representation, value, | |
| 692 slow); | |
| 693 Node* field_index = | |
| 694 DecodeWordFromWord32<PropertyDetails::FieldIndexField>(details); | |
| 695 Node* inobject_properties = LoadMapInobjectProperties(object_map); | |
| 696 | |
| 697 Label inobject(this), backing_store(this); | |
| 698 Branch(UintPtrLessThan(field_index, inobject_properties), &inobject, | |
| 699 &backing_store); | |
| 700 | |
| 701 Bind(&inobject); | |
| 702 { | |
| 703 Node* field_offset = | |
| 704 IntPtrMul(IntPtrSub(LoadMapInstanceSize(object_map), | |
| 705 IntPtrSub(inobject_properties, field_index)), | |
| 706 IntPtrConstant(kPointerSize)); | |
| 707 Label tagged_rep(this), double_rep(this); | |
| 708 Branch(Word32Equal(representation, Int32Constant(Representation::kDouble)), | |
| 709 &double_rep, &tagged_rep); | |
| 710 Bind(&double_rep); | |
| 711 { | |
| 712 Node* double_value = ChangeNumberToFloat64(value); | |
| 713 if (FLAG_unbox_double_fields) { | |
| 714 StoreObjectFieldNoWriteBarrier(object, field_offset, double_value, | |
| 715 MachineRepresentation::kFloat64); | |
| 716 } else { | |
| 717 Node* mutable_heap_number = LoadObjectField(object, field_offset); | |
| 718 StoreHeapNumberValue(mutable_heap_number, double_value); | |
| 719 } | |
| 720 Goto(&done); | |
| 721 } | |
| 722 | |
| 723 Bind(&tagged_rep); | |
| 724 { | |
| 725 StoreObjectField(object, field_offset, value); | |
| 726 Goto(&done); | |
| 727 } | |
| 728 } | |
| 729 | |
| 730 Bind(&backing_store); | |
| 731 { | |
| 732 Node* backing_store_index = IntPtrSub(field_index, inobject_properties); | |
| 733 Label tagged_rep(this), double_rep(this); | |
| 734 Branch(Word32Equal(representation, Int32Constant(Representation::kDouble)), | |
| 735 &double_rep, &tagged_rep); | |
| 736 Bind(&double_rep); | |
| 737 { | |
| 738 Node* double_value = ChangeNumberToFloat64(value); | |
| 739 Node* mutable_heap_number = | |
| 740 LoadFixedArrayElement(properties, backing_store_index); | |
| 741 StoreHeapNumberValue(mutable_heap_number, double_value); | |
| 742 Goto(&done); | |
| 743 } | |
| 744 Bind(&tagged_rep); | |
| 745 { | |
| 746 StoreFixedArrayElement(properties, backing_store_index, value); | |
| 747 Goto(&done); | |
| 748 } | |
| 749 } | |
| 750 Bind(&done); | |
| 751 } | |
| 752 | |
| 602 void KeyedStoreGenericAssembler::EmitGenericPropertyStore( | 753 void KeyedStoreGenericAssembler::EmitGenericPropertyStore( |
| 603 Node* receiver, Node* receiver_map, const StoreICParameters* p, Label* slow, | 754 Node* receiver, Node* receiver_map, const StoreICParameters* p, Label* slow, |
| 604 LanguageMode language_mode) { | 755 LanguageMode language_mode) { |
| 605 Variable var_accessor_pair(this, MachineRepresentation::kTagged); | 756 Variable var_accessor_pair(this, MachineRepresentation::kTagged); |
| 606 Variable var_accessor_holder(this, MachineRepresentation::kTagged); | 757 Variable var_accessor_holder(this, MachineRepresentation::kTagged); |
| 607 Label stub_cache(this), fast_properties(this), dictionary_properties(this), | 758 Label stub_cache(this), fast_properties(this), dictionary_properties(this), |
| 608 accessor(this), readonly(this); | 759 accessor(this), readonly(this); |
| 609 Node* properties = LoadProperties(receiver); | 760 Node* properties = LoadProperties(receiver); |
| 610 Node* properties_map = LoadMap(properties); | 761 Node* properties_map = LoadMap(properties); |
| 611 Branch(WordEqual(properties_map, LoadRoot(Heap::kHashTableMapRootIndex)), | 762 Branch(WordEqual(properties_map, LoadRoot(Heap::kHashTableMapRootIndex)), |
| 612 &dictionary_properties, &fast_properties); | 763 &dictionary_properties, &fast_properties); |
| 613 | 764 |
| 614 Bind(&fast_properties); | 765 Bind(&fast_properties); |
| 615 { | 766 { |
| 616 // TODO(jkummerow): Does it make sense to support some cases here inline? | 767 Comment("fast property store"); |
| 617 // Maybe overwrite existing writable properties? | 768 Node* bitfield3 = LoadMapBitField3(receiver_map); |
| 618 // Maybe support map transitions? | 769 Node* descriptors = LoadMapDescriptors(receiver_map); |
| 619 Goto(&stub_cache); | 770 Label descriptor_found(this); |
| 771 Variable var_name_index(this, MachineType::PointerRepresentation()); | |
| 772 // TODO(jkummerow): Maybe look for existing map transitions? | |
| 773 Label* notfound = &stub_cache; | |
| 774 DescriptorLookup(p->name, descriptors, bitfield3, &descriptor_found, | |
| 775 &var_name_index, notfound); | |
| 776 | |
| 777 Bind(&descriptor_found); | |
| 778 { | |
| 779 Node* name_index = var_name_index.value(); | |
| 780 Node* details = | |
| 781 LoadDetailsByKeyIndex<DescriptorArray>(descriptors, name_index); | |
| 782 Label data_property(this); | |
| 783 JumpIfDataProperty(details, &data_property, &readonly); | |
| 784 | |
| 785 // Accessor case. | |
| 786 // TODO(jkummerow): Implement a trimmed-down LoadAccessorFromFastObject. | |
| 787 Variable var_details(this, MachineRepresentation::kWord32); | |
| 788 LoadPropertyFromFastObject(receiver, receiver_map, descriptors, | |
| 789 name_index, &var_details, &var_accessor_pair); | |
| 790 var_accessor_holder.Bind(receiver); | |
| 791 Goto(&accessor); | |
| 792 | |
| 793 Bind(&data_property); | |
| 794 { | |
| 795 OverwriteExistingFastProperty(receiver, receiver_map, properties, | |
| 796 descriptors, name_index, details, | |
| 797 p->value, slow); | |
| 798 Return(p->value); | |
| 799 } | |
| 800 } | |
| 620 } | 801 } |
| 621 | 802 |
| 622 Bind(&dictionary_properties); | 803 Bind(&dictionary_properties); |
| 623 { | 804 { |
| 624 Comment("dictionary property store"); | 805 Comment("dictionary property store"); |
| 625 // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out | 806 // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out |
| 626 // seeing global objects here (which would need special handling). | 807 // seeing global objects here (which would need special handling). |
| 627 | 808 |
| 628 Variable var_name_index(this, MachineType::PointerRepresentation()); | 809 Variable var_name_index(this, MachineType::PointerRepresentation()); |
| 629 Label dictionary_found(this, &var_name_index), not_found(this); | 810 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); | 950 Bind(&slow); |
| 770 { | 951 { |
| 771 Comment("KeyedStoreGeneric_slow"); | 952 Comment("KeyedStoreGeneric_slow"); |
| 772 TailCallRuntime(Runtime::kSetProperty, context, receiver, name, value, | 953 TailCallRuntime(Runtime::kSetProperty, context, receiver, name, value, |
| 773 SmiConstant(language_mode)); | 954 SmiConstant(language_mode)); |
| 774 } | 955 } |
| 775 } | 956 } |
| 776 | 957 |
| 777 } // namespace internal | 958 } // namespace internal |
| 778 } // namespace v8 | 959 } // namespace v8 |
| OLD | NEW |