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 | |
719 Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object, | 708 Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object, |
720 bool cache_result) { | 709 bool cache_result) { |
721 Isolate* isolate = object->GetIsolate(); | 710 Isolate* isolate = object->GetIsolate(); |
722 if (object->HasFastProperties()) { | 711 if (object->HasFastProperties()) { |
723 if (object->map()->instance_descriptors()->HasEnumCache()) { | 712 if (object->map()->instance_descriptors()->HasEnumCache()) { |
724 int own_property_count = object->map()->EnumLength(); | 713 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); | |
733 | 714 |
734 if (cache_result) object->map()->SetEnumLength(own_property_count); | 715 // Mark that we have an enum cache if we are allowed to cache it. |
| 716 if (cache_result && own_property_count == Map::kInvalidEnumCache) { |
| 717 int num_enum = object->map()->NumberOfDescribedProperties(DONT_ENUM); |
| 718 object->map()->SetEnumLength(num_enum); |
735 } | 719 } |
736 | 720 |
737 DescriptorArray* desc = object->map()->instance_descriptors(); | 721 DescriptorArray* desc = object->map()->instance_descriptors(); |
738 Handle<FixedArray> keys(FixedArray::cast(desc->GetEnumCache()), isolate); | 722 Handle<FixedArray> keys(FixedArray::cast(desc->GetEnumCache()), isolate); |
739 | 723 |
740 // In case the number of properties required in the enum are actually | 724 isolate->counters()->enum_cache_hits()->Increment(); |
741 // present, we can reuse the enum cache. Otherwise, this means that the | 725 return keys; |
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 } | |
748 } | 726 } |
749 | 727 |
750 Handle<Map> map(object->map()); | 728 Handle<Map> map(object->map()); |
751 | 729 |
752 if (map->instance_descriptors()->IsEmpty()) { | 730 if (map->instance_descriptors()->IsEmpty()) { |
753 isolate->counters()->enum_cache_hits()->Increment(); | 731 isolate->counters()->enum_cache_hits()->Increment(); |
754 if (cache_result) map->SetEnumLength(0); | 732 if (cache_result) map->SetEnumLength(0); |
755 return isolate->factory()->empty_fixed_array(); | 733 return isolate->factory()->empty_fixed_array(); |
756 } | 734 } |
757 | 735 |
758 isolate->counters()->enum_cache_misses()->Increment(); | 736 isolate->counters()->enum_cache_misses()->Increment(); |
759 int num_enum = map->NumberOfDescribedProperties(ALL_DESCRIPTORS, DONT_ENUM); | 737 |
| 738 int num_enum = map->NumberOfDescribedProperties(DONT_ENUM); |
760 | 739 |
761 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(num_enum); | 740 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(num_enum); |
762 Handle<FixedArray> indices = isolate->factory()->NewFixedArray(num_enum); | 741 Handle<FixedArray> indices = isolate->factory()->NewFixedArray(num_enum); |
763 | 742 |
764 Handle<DescriptorArray> descs = | 743 Handle<DescriptorArray> descs = |
765 Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate); | 744 Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate); |
766 | 745 |
767 int real_size = map->NumberOfOwnDescriptors(); | |
768 int enum_size = 0; | |
769 int index = 0; | 746 int index = 0; |
770 | |
771 for (int i = 0; i < descs->number_of_descriptors(); i++) { | 747 for (int i = 0; i < descs->number_of_descriptors(); i++) { |
772 PropertyDetails details = descs->GetDetails(i); | 748 PropertyDetails details = descs->GetDetails(i); |
773 if (!details.IsDontEnum()) { | 749 if (!details.IsDontEnum()) { |
774 if (i < real_size) ++enum_size; | |
775 storage->set(index, descs->GetKey(i)); | 750 storage->set(index, descs->GetKey(i)); |
776 if (!indices.is_null()) { | 751 if (!indices.is_null()) { |
777 if (details.type() != FIELD) { | 752 if (details.type() != FIELD) { |
778 indices = Handle<FixedArray>(); | 753 indices = Handle<FixedArray>(); |
779 } else { | 754 } else { |
780 int field_index = Descriptor::IndexFromValue(descs->GetValue(i)); | 755 int field_index = Descriptor::IndexFromValue(descs->GetValue(i)); |
781 if (field_index >= map->inobject_properties()) { | 756 if (field_index >= map->inobject_properties()) { |
782 field_index = -(field_index - map->inobject_properties() + 1); | 757 field_index = -(field_index - map->inobject_properties() + 1); |
783 } | 758 } |
784 indices->set(index, Smi::FromInt(field_index)); | 759 indices->set(index, Smi::FromInt(field_index)); |
785 } | 760 } |
786 } | 761 } |
787 index++; | 762 index++; |
788 } | 763 } |
789 } | 764 } |
790 ASSERT(index == storage->length()); | 765 ASSERT(index == storage->length()); |
791 | 766 |
792 Handle<FixedArray> bridge_storage = | 767 Handle<FixedArray> bridge_storage = |
793 isolate->factory()->NewFixedArray( | 768 isolate->factory()->NewFixedArray( |
794 DescriptorArray::kEnumCacheBridgeLength); | 769 DescriptorArray::kEnumCacheBridgeLength); |
795 DescriptorArray* desc = object->map()->instance_descriptors(); | 770 DescriptorArray* desc = object->map()->instance_descriptors(); |
796 desc->SetEnumCache(*bridge_storage, | 771 desc->SetEnumCache(*bridge_storage, |
797 *storage, | 772 *storage, |
798 indices.is_null() ? Object::cast(Smi::FromInt(0)) | 773 indices.is_null() ? Object::cast(Smi::FromInt(0)) |
799 : Object::cast(*indices)); | 774 : Object::cast(*indices)); |
800 if (cache_result) { | 775 if (cache_result) { |
801 object->map()->SetEnumLength(enum_size); | 776 object->map()->SetEnumLength(index); |
802 } | 777 } |
803 | 778 return storage; |
804 return ReduceFixedArrayTo(storage, enum_size); | |
805 } else { | 779 } else { |
806 Handle<StringDictionary> dictionary(object->property_dictionary()); | 780 Handle<StringDictionary> dictionary(object->property_dictionary()); |
807 | 781 |
808 int length = dictionary->NumberOfElements(); | 782 int length = dictionary->NumberOfElements(); |
809 if (length == 0) { | 783 if (length == 0) { |
810 return Handle<FixedArray>(isolate->heap()->empty_fixed_array()); | 784 return Handle<FixedArray>(isolate->heap()->empty_fixed_array()); |
811 } | 785 } |
812 | 786 |
813 // The enumeration array is generated by allocating an array big enough to | 787 // The enumeration array is generated by allocating an array big enough to |
814 // hold all properties that have been seen, whether they are are deleted or | 788 // 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... |
1058 data->next = prev_next_; | 1032 data->next = prev_next_; |
1059 data->limit = prev_limit_; | 1033 data->limit = prev_limit_; |
1060 #ifdef DEBUG | 1034 #ifdef DEBUG |
1061 handles_detached_ = true; | 1035 handles_detached_ = true; |
1062 #endif | 1036 #endif |
1063 return deferred; | 1037 return deferred; |
1064 } | 1038 } |
1065 | 1039 |
1066 | 1040 |
1067 } } // namespace v8::internal | 1041 } } // namespace v8::internal |
OLD | NEW |