OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 687 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
698 | 698 |
699 Handle<JSArray> GetKeysFor(Handle<JSReceiver> object, bool* threw) { | 699 Handle<JSArray> GetKeysFor(Handle<JSReceiver> object, bool* threw) { |
700 Isolate* isolate = object->GetIsolate(); | 700 Isolate* isolate = object->GetIsolate(); |
701 isolate->counters()->for_in()->Increment(); | 701 isolate->counters()->for_in()->Increment(); |
702 Handle<FixedArray> elements = | 702 Handle<FixedArray> elements = |
703 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, threw); | 703 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, threw); |
704 return isolate->factory()->NewJSArrayWithElements(elements); | 704 return isolate->factory()->NewJSArrayWithElements(elements); |
705 } | 705 } |
706 | 706 |
707 | 707 |
| 708 Handle<FixedArray> ReduceFixedArrayTo(Handle<FixedArray> array, int length) { |
| 709 ASSERT(array->length() >= length); |
| 710 if (array->length() == length) return array; |
| 711 |
| 712 Handle<FixedArray> new_array = |
| 713 array->GetIsolate()->factory()->NewFixedArray(length); |
| 714 for (int i = 0; i < length; ++i) new_array->set(i, array->get(i)); |
| 715 return new_array; |
| 716 } |
| 717 |
| 718 |
708 Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object, | 719 Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object, |
709 bool cache_result) { | 720 bool cache_result) { |
710 Isolate* isolate = object->GetIsolate(); | 721 Isolate* isolate = object->GetIsolate(); |
711 if (object->HasFastProperties()) { | 722 if (object->HasFastProperties()) { |
712 if (object->map()->instance_descriptors()->HasEnumCache()) { | 723 if (object->map()->instance_descriptors()->HasEnumCache()) { |
713 int own_property_count = object->map()->EnumLength(); | 724 int own_property_count = object->map()->EnumLength(); |
| 725 // If we have an enum cache, but the enum length of the given map is set |
| 726 // to kInvalidEnumCache, this means that the map itself has never used the |
| 727 // present enum cache. The first step to using the cache is to set the |
| 728 // enum length of the map by counting the number of own descriptors that |
| 729 // are not DONT_ENUM. |
| 730 if (own_property_count == Map::kInvalidEnumCache) { |
| 731 own_property_count = object->map()->NumberOfDescribedProperties( |
| 732 OWN_DESCRIPTORS, DONT_ENUM); |
714 | 733 |
715 // Mark that we have an enum cache if we are allowed to cache it. | 734 if (cache_result) object->map()->SetEnumLength(own_property_count); |
716 if (cache_result && own_property_count == Map::kInvalidEnumCache) { | |
717 int num_enum = object->map()->NumberOfDescribedProperties(DONT_ENUM); | |
718 object->map()->SetEnumLength(num_enum); | |
719 } | 735 } |
720 | 736 |
721 DescriptorArray* desc = object->map()->instance_descriptors(); | 737 DescriptorArray* desc = object->map()->instance_descriptors(); |
722 Handle<FixedArray> keys(FixedArray::cast(desc->GetEnumCache()), isolate); | 738 Handle<FixedArray> keys(FixedArray::cast(desc->GetEnumCache()), isolate); |
723 | 739 |
724 isolate->counters()->enum_cache_hits()->Increment(); | 740 // In case the number of properties required in the enum are actually |
725 return keys; | 741 // present, we can reuse the enum cache. Otherwise, this means that the |
| 742 // enum cache was generated for a previous (smaller) version of the |
| 743 // Descriptor Array. In that case we regenerate the enum cache. |
| 744 if (own_property_count <= keys->length()) { |
| 745 isolate->counters()->enum_cache_hits()->Increment(); |
| 746 return ReduceFixedArrayTo(keys, own_property_count); |
| 747 } |
726 } | 748 } |
727 | 749 |
728 Handle<Map> map(object->map()); | 750 Handle<Map> map(object->map()); |
729 | 751 |
730 if (map->instance_descriptors()->IsEmpty()) { | 752 if (map->instance_descriptors()->IsEmpty()) { |
731 isolate->counters()->enum_cache_hits()->Increment(); | 753 isolate->counters()->enum_cache_hits()->Increment(); |
732 if (cache_result) map->SetEnumLength(0); | 754 if (cache_result) map->SetEnumLength(0); |
733 return isolate->factory()->empty_fixed_array(); | 755 return isolate->factory()->empty_fixed_array(); |
734 } | 756 } |
735 | 757 |
736 isolate->counters()->enum_cache_misses()->Increment(); | 758 isolate->counters()->enum_cache_misses()->Increment(); |
737 | 759 int num_enum = map->NumberOfDescribedProperties(ALL_DESCRIPTORS, DONT_ENUM); |
738 int num_enum = map->NumberOfDescribedProperties(DONT_ENUM); | |
739 | 760 |
740 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(num_enum); | 761 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(num_enum); |
741 Handle<FixedArray> indices = isolate->factory()->NewFixedArray(num_enum); | 762 Handle<FixedArray> indices = isolate->factory()->NewFixedArray(num_enum); |
742 | 763 |
743 Handle<DescriptorArray> descs = | 764 Handle<DescriptorArray> descs = |
744 Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate); | 765 Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate); |
745 | 766 |
| 767 int real_size = map->NumberOfOwnDescriptors(); |
| 768 int enum_size = 0; |
746 int index = 0; | 769 int index = 0; |
| 770 |
747 for (int i = 0; i < descs->number_of_descriptors(); i++) { | 771 for (int i = 0; i < descs->number_of_descriptors(); i++) { |
748 PropertyDetails details = descs->GetDetails(i); | 772 PropertyDetails details = descs->GetDetails(i); |
749 if (!details.IsDontEnum()) { | 773 if (!details.IsDontEnum()) { |
| 774 if (i < real_size) ++enum_size; |
750 storage->set(index, descs->GetKey(i)); | 775 storage->set(index, descs->GetKey(i)); |
751 if (!indices.is_null()) { | 776 if (!indices.is_null()) { |
752 if (details.type() != FIELD) { | 777 if (details.type() != FIELD) { |
753 indices = Handle<FixedArray>(); | 778 indices = Handle<FixedArray>(); |
754 } else { | 779 } else { |
755 int field_index = Descriptor::IndexFromValue(descs->GetValue(i)); | 780 int field_index = Descriptor::IndexFromValue(descs->GetValue(i)); |
756 if (field_index >= map->inobject_properties()) { | 781 if (field_index >= map->inobject_properties()) { |
757 field_index = -(field_index - map->inobject_properties() + 1); | 782 field_index = -(field_index - map->inobject_properties() + 1); |
758 } | 783 } |
759 indices->set(index, Smi::FromInt(field_index)); | 784 indices->set(index, Smi::FromInt(field_index)); |
760 } | 785 } |
761 } | 786 } |
762 index++; | 787 index++; |
763 } | 788 } |
764 } | 789 } |
765 ASSERT(index == storage->length()); | 790 ASSERT(index == storage->length()); |
766 | 791 |
767 Handle<FixedArray> bridge_storage = | 792 Handle<FixedArray> bridge_storage = |
768 isolate->factory()->NewFixedArray( | 793 isolate->factory()->NewFixedArray( |
769 DescriptorArray::kEnumCacheBridgeLength); | 794 DescriptorArray::kEnumCacheBridgeLength); |
770 DescriptorArray* desc = object->map()->instance_descriptors(); | 795 DescriptorArray* desc = object->map()->instance_descriptors(); |
771 desc->SetEnumCache(*bridge_storage, | 796 desc->SetEnumCache(*bridge_storage, |
772 *storage, | 797 *storage, |
773 indices.is_null() ? Object::cast(Smi::FromInt(0)) | 798 indices.is_null() ? Object::cast(Smi::FromInt(0)) |
774 : Object::cast(*indices)); | 799 : Object::cast(*indices)); |
775 if (cache_result) { | 800 if (cache_result) { |
776 object->map()->SetEnumLength(index); | 801 object->map()->SetEnumLength(enum_size); |
777 } | 802 } |
778 return storage; | 803 |
| 804 return ReduceFixedArrayTo(storage, enum_size); |
779 } else { | 805 } else { |
780 Handle<StringDictionary> dictionary(object->property_dictionary()); | 806 Handle<StringDictionary> dictionary(object->property_dictionary()); |
781 | 807 |
782 int length = dictionary->NumberOfElements(); | 808 int length = dictionary->NumberOfElements(); |
783 if (length == 0) { | 809 if (length == 0) { |
784 return Handle<FixedArray>(isolate->heap()->empty_fixed_array()); | 810 return Handle<FixedArray>(isolate->heap()->empty_fixed_array()); |
785 } | 811 } |
786 | 812 |
787 // The enumeration array is generated by allocating an array big enough to | 813 // The enumeration array is generated by allocating an array big enough to |
788 // hold all properties that have been seen, whether they are are deleted or | 814 // hold all properties that have been seen, whether they are are deleted or |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1032 data->next = prev_next_; | 1058 data->next = prev_next_; |
1033 data->limit = prev_limit_; | 1059 data->limit = prev_limit_; |
1034 #ifdef DEBUG | 1060 #ifdef DEBUG |
1035 handles_detached_ = true; | 1061 handles_detached_ = true; |
1036 #endif | 1062 #endif |
1037 return deferred; | 1063 return deferred; |
1038 } | 1064 } |
1039 | 1065 |
1040 | 1066 |
1041 } } // namespace v8::internal | 1067 } } // namespace v8::internal |
OLD | NEW |