OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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/objects.h" | 5 #include "src/objects.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 #include <iomanip> | 8 #include <iomanip> |
9 #include <sstream> | 9 #include <sstream> |
10 | 10 |
(...skipping 6594 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6605 DCHECK(array->length() >= length); | 6605 DCHECK(array->length() >= length); |
6606 if (array->length() == length) return array; | 6606 if (array->length() == length) return array; |
6607 | 6607 |
6608 Handle<FixedArray> new_array = | 6608 Handle<FixedArray> new_array = |
6609 array->GetIsolate()->factory()->NewFixedArray(length); | 6609 array->GetIsolate()->factory()->NewFixedArray(length); |
6610 for (int i = 0; i < length; ++i) new_array->set(i, array->get(i)); | 6610 for (int i = 0; i < length; ++i) new_array->set(i, array->get(i)); |
6611 return new_array; | 6611 return new_array; |
6612 } | 6612 } |
6613 | 6613 |
6614 | 6614 |
| 6615 namespace { |
| 6616 |
| 6617 Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate, |
| 6618 Handle<JSObject> object, |
| 6619 bool cache_enum_length) { |
| 6620 Handle<Map> map(object->map()); |
| 6621 Handle<DescriptorArray> descs = |
| 6622 Handle<DescriptorArray>(map->instance_descriptors(), isolate); |
| 6623 int own_property_count = map->EnumLength(); |
| 6624 // If the enum length of the given map is set to kInvalidEnumCache, this |
| 6625 // means that the map itself has never used the present enum cache. The |
| 6626 // first step to using the cache is to set the enum length of the map by |
| 6627 // counting the number of own descriptors that are not DONT_ENUM or |
| 6628 // SYMBOLIC. |
| 6629 if (own_property_count == kInvalidEnumCacheSentinel) { |
| 6630 own_property_count = |
| 6631 map->NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_SHOW); |
| 6632 } else { |
| 6633 DCHECK(own_property_count == |
| 6634 map->NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_SHOW)); |
| 6635 } |
| 6636 |
| 6637 if (descs->HasEnumCache()) { |
| 6638 Handle<FixedArray> keys(descs->GetEnumCache(), isolate); |
| 6639 // In case the number of properties required in the enum are actually |
| 6640 // present, we can reuse the enum cache. Otherwise, this means that the |
| 6641 // enum cache was generated for a previous (smaller) version of the |
| 6642 // Descriptor Array. In that case we regenerate the enum cache. |
| 6643 if (own_property_count <= keys->length()) { |
| 6644 isolate->counters()->enum_cache_hits()->Increment(); |
| 6645 if (cache_enum_length) map->SetEnumLength(own_property_count); |
| 6646 return ReduceFixedArrayTo(keys, own_property_count); |
| 6647 } |
| 6648 } |
| 6649 |
| 6650 if (descs->IsEmpty()) { |
| 6651 isolate->counters()->enum_cache_hits()->Increment(); |
| 6652 if (cache_enum_length) map->SetEnumLength(0); |
| 6653 return isolate->factory()->empty_fixed_array(); |
| 6654 } |
| 6655 |
| 6656 isolate->counters()->enum_cache_misses()->Increment(); |
| 6657 |
| 6658 Handle<FixedArray> storage = |
| 6659 isolate->factory()->NewFixedArray(own_property_count); |
| 6660 Handle<FixedArray> indices = |
| 6661 isolate->factory()->NewFixedArray(own_property_count); |
| 6662 |
| 6663 int size = map->NumberOfOwnDescriptors(); |
| 6664 int index = 0; |
| 6665 |
| 6666 for (int i = 0; i < size; i++) { |
| 6667 PropertyDetails details = descs->GetDetails(i); |
| 6668 Object* key = descs->GetKey(i); |
| 6669 if (details.IsDontEnum() || key->IsSymbol()) continue; |
| 6670 storage->set(index, key); |
| 6671 if (!indices.is_null()) { |
| 6672 if (details.type() != DATA) { |
| 6673 indices = Handle<FixedArray>(); |
| 6674 } else { |
| 6675 FieldIndex field_index = FieldIndex::ForDescriptor(*map, i); |
| 6676 int load_by_field_index = field_index.GetLoadByFieldIndex(); |
| 6677 indices->set(index, Smi::FromInt(load_by_field_index)); |
| 6678 } |
| 6679 } |
| 6680 index++; |
| 6681 } |
| 6682 DCHECK(index == storage->length()); |
| 6683 |
| 6684 DescriptorArray::SetEnumCache(descs, isolate, storage, indices); |
| 6685 if (cache_enum_length) { |
| 6686 map->SetEnumLength(own_property_count); |
| 6687 } |
| 6688 return storage; |
| 6689 } |
| 6690 |
| 6691 } // namespace |
| 6692 |
| 6693 |
6615 Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object, | 6694 Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object, |
6616 bool cache_result) { | 6695 bool cache_enum_length) { |
6617 Isolate* isolate = object->GetIsolate(); | 6696 Isolate* isolate = object->GetIsolate(); |
6618 if (object->HasFastProperties()) { | 6697 if (object->HasFastProperties()) { |
6619 int own_property_count = object->map()->EnumLength(); | 6698 return GetFastEnumPropertyKeys(isolate, object, cache_enum_length); |
6620 // If the enum length of the given map is set to kInvalidEnumCache, this | |
6621 // means that the map itself has never used the present enum cache. The | |
6622 // first step to using the cache is to set the enum length of the map by | |
6623 // counting the number of own descriptors that are not DONT_ENUM or | |
6624 // SYMBOLIC. | |
6625 if (own_property_count == kInvalidEnumCacheSentinel) { | |
6626 own_property_count = object->map()->NumberOfDescribedProperties( | |
6627 OWN_DESCRIPTORS, DONT_SHOW); | |
6628 } else { | |
6629 DCHECK(own_property_count == object->map()->NumberOfDescribedProperties( | |
6630 OWN_DESCRIPTORS, DONT_SHOW)); | |
6631 } | |
6632 | |
6633 if (object->map()->instance_descriptors()->HasEnumCache()) { | |
6634 DescriptorArray* desc = object->map()->instance_descriptors(); | |
6635 Handle<FixedArray> keys(desc->GetEnumCache(), isolate); | |
6636 | |
6637 // In case the number of properties required in the enum are actually | |
6638 // present, we can reuse the enum cache. Otherwise, this means that the | |
6639 // enum cache was generated for a previous (smaller) version of the | |
6640 // Descriptor Array. In that case we regenerate the enum cache. | |
6641 if (own_property_count <= keys->length()) { | |
6642 if (cache_result) object->map()->SetEnumLength(own_property_count); | |
6643 isolate->counters()->enum_cache_hits()->Increment(); | |
6644 return ReduceFixedArrayTo(keys, own_property_count); | |
6645 } | |
6646 } | |
6647 | |
6648 Handle<Map> map(object->map()); | |
6649 | |
6650 if (map->instance_descriptors()->IsEmpty()) { | |
6651 isolate->counters()->enum_cache_hits()->Increment(); | |
6652 if (cache_result) map->SetEnumLength(0); | |
6653 return isolate->factory()->empty_fixed_array(); | |
6654 } | |
6655 | |
6656 isolate->counters()->enum_cache_misses()->Increment(); | |
6657 | |
6658 Handle<FixedArray> storage = isolate->factory()->NewFixedArray( | |
6659 own_property_count); | |
6660 Handle<FixedArray> indices = isolate->factory()->NewFixedArray( | |
6661 own_property_count); | |
6662 | |
6663 Handle<DescriptorArray> descs = | |
6664 Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate); | |
6665 | |
6666 int size = map->NumberOfOwnDescriptors(); | |
6667 int index = 0; | |
6668 | |
6669 for (int i = 0; i < size; i++) { | |
6670 PropertyDetails details = descs->GetDetails(i); | |
6671 Object* key = descs->GetKey(i); | |
6672 if (!(details.IsDontEnum() || key->IsSymbol())) { | |
6673 storage->set(index, key); | |
6674 if (!indices.is_null()) { | |
6675 if (details.type() != DATA) { | |
6676 indices = Handle<FixedArray>(); | |
6677 } else { | |
6678 FieldIndex field_index = FieldIndex::ForDescriptor(*map, i); | |
6679 int load_by_field_index = field_index.GetLoadByFieldIndex(); | |
6680 indices->set(index, Smi::FromInt(load_by_field_index)); | |
6681 } | |
6682 } | |
6683 index++; | |
6684 } | |
6685 } | |
6686 DCHECK(index == storage->length()); | |
6687 | |
6688 Handle<FixedArray> bridge_storage = | |
6689 isolate->factory()->NewFixedArray( | |
6690 DescriptorArray::kEnumCacheBridgeLength); | |
6691 DescriptorArray* desc = object->map()->instance_descriptors(); | |
6692 desc->SetEnumCache(*bridge_storage, | |
6693 *storage, | |
6694 indices.is_null() ? Object::cast(Smi::FromInt(0)) | |
6695 : Object::cast(*indices)); | |
6696 if (cache_result) { | |
6697 object->map()->SetEnumLength(own_property_count); | |
6698 } | |
6699 return storage; | |
6700 } else if (object->IsGlobalObject()) { | 6699 } else if (object->IsGlobalObject()) { |
6701 Handle<GlobalDictionary> dictionary(object->global_dictionary()); | 6700 Handle<GlobalDictionary> dictionary(object->global_dictionary()); |
6702 int length = dictionary->NumberOfEnumElements(); | 6701 int length = dictionary->NumberOfEnumElements(); |
6703 if (length == 0) { | 6702 if (length == 0) { |
6704 return Handle<FixedArray>(isolate->heap()->empty_fixed_array()); | 6703 return Handle<FixedArray>(isolate->heap()->empty_fixed_array()); |
6705 } | 6704 } |
6706 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); | 6705 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); |
6707 dictionary->CopyEnumKeysTo(*storage); | 6706 dictionary->CopyEnumKeysTo(*storage); |
6708 return storage; | 6707 return storage; |
6709 } else { | 6708 } else { |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6893 // We can cache the computed property keys if access checks are | 6892 // We can cache the computed property keys if access checks are |
6894 // not needed and no interceptors are involved. | 6893 // not needed and no interceptors are involved. |
6895 // | 6894 // |
6896 // We do not use the cache if the object has elements and | 6895 // We do not use the cache if the object has elements and |
6897 // therefore it does not make sense to cache the property names | 6896 // therefore it does not make sense to cache the property names |
6898 // for arguments objects. Arguments objects will always have | 6897 // for arguments objects. Arguments objects will always have |
6899 // elements. | 6898 // elements. |
6900 // Wrapped strings have elements, but don't have an elements | 6899 // Wrapped strings have elements, but don't have an elements |
6901 // array or dictionary. So the fast inline test for whether to | 6900 // array or dictionary. So the fast inline test for whether to |
6902 // use the cache says yes, so we should not create a cache. | 6901 // use the cache says yes, so we should not create a cache. |
6903 bool cache_enum_keys = | 6902 bool cache_enum_length = |
6904 ((current->map()->GetConstructor() != *arguments_function) && | 6903 ((current->map()->GetConstructor() != *arguments_function) && |
6905 !current->IsJSValue() && !current->IsAccessCheckNeeded() && | 6904 !current->IsJSValue() && !current->IsAccessCheckNeeded() && |
6906 !current->HasNamedInterceptor() && !current->HasIndexedInterceptor()); | 6905 !current->HasNamedInterceptor() && !current->HasIndexedInterceptor()); |
6907 // Compute the property keys and cache them if possible. | 6906 // Compute the property keys and cache them if possible. |
6908 | 6907 |
6909 Handle<FixedArray> enum_keys = | 6908 Handle<FixedArray> enum_keys = |
6910 JSObject::GetEnumPropertyKeys(current, cache_enum_keys); | 6909 JSObject::GetEnumPropertyKeys(current, cache_enum_length); |
6911 accumulator.AddKeys(enum_keys, FixedArray::ALL_KEYS); | 6910 accumulator.AddKeys(enum_keys, FixedArray::ALL_KEYS); |
6912 DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys())); | 6911 DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys())); |
6913 | 6912 |
6914 // Add the non-symbol property keys from the interceptor. | 6913 // Add the non-symbol property keys from the interceptor. |
6915 if (current->HasNamedInterceptor()) { | 6914 if (current->HasNamedInterceptor()) { |
6916 Handle<JSObject> result; | 6915 Handle<JSObject> result; |
6917 if (JSObject::GetKeysForNamedInterceptor( | 6916 if (JSObject::GetKeysForNamedInterceptor( |
6918 current, object).ToHandle(&result)) { | 6917 current, object).ToHandle(&result)) { |
6919 accumulator.AddKeys(result, FixedArray::NON_SYMBOL_KEYS); | 6918 accumulator.AddKeys(result, FixedArray::NON_SYMBOL_KEYS); |
6920 } | 6919 } |
(...skipping 1732 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8653 set(kEnumCacheIndex, Smi::FromInt(0)); | 8652 set(kEnumCacheIndex, Smi::FromInt(0)); |
8654 } | 8653 } |
8655 | 8654 |
8656 | 8655 |
8657 void DescriptorArray::Replace(int index, Descriptor* descriptor) { | 8656 void DescriptorArray::Replace(int index, Descriptor* descriptor) { |
8658 descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index)); | 8657 descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index)); |
8659 Set(index, descriptor); | 8658 Set(index, descriptor); |
8660 } | 8659 } |
8661 | 8660 |
8662 | 8661 |
8663 void DescriptorArray::SetEnumCache(FixedArray* bridge_storage, | 8662 // static |
8664 FixedArray* new_cache, | 8663 void DescriptorArray::SetEnumCache(Handle<DescriptorArray> descriptors, |
8665 Object* new_index_cache) { | 8664 Isolate* isolate, |
8666 DCHECK(bridge_storage->length() >= kEnumCacheBridgeLength); | 8665 Handle<FixedArray> new_cache, |
8667 DCHECK(new_index_cache->IsSmi() || new_index_cache->IsFixedArray()); | 8666 Handle<FixedArray> new_index_cache) { |
8668 DCHECK(!IsEmpty()); | 8667 DCHECK(!descriptors->IsEmpty()); |
8669 DCHECK(!HasEnumCache() || new_cache->length() > GetEnumCache()->length()); | 8668 FixedArray* bridge_storage; |
8670 FixedArray::cast(bridge_storage)-> | 8669 bool needs_new_enum_cache = !descriptors->HasEnumCache(); |
8671 set(kEnumCacheBridgeCacheIndex, new_cache); | 8670 if (needs_new_enum_cache) { |
8672 FixedArray::cast(bridge_storage)-> | 8671 bridge_storage = *isolate->factory()->NewFixedArray( |
8673 set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache); | 8672 DescriptorArray::kEnumCacheBridgeLength); |
8674 set(kEnumCacheIndex, bridge_storage); | 8673 } else { |
| 8674 bridge_storage = FixedArray::cast(descriptors->get(kEnumCacheIndex)); |
| 8675 } |
| 8676 bridge_storage->set(kEnumCacheBridgeCacheIndex, *new_cache); |
| 8677 bridge_storage->set(kEnumCacheBridgeIndicesCacheIndex, |
| 8678 new_index_cache.is_null() ? Object::cast(Smi::FromInt(0)) |
| 8679 : *new_index_cache); |
| 8680 if (needs_new_enum_cache) { |
| 8681 descriptors->set(kEnumCacheIndex, bridge_storage); |
| 8682 } |
8675 } | 8683 } |
8676 | 8684 |
8677 | 8685 |
8678 void DescriptorArray::CopyFrom(int index, DescriptorArray* src, | 8686 void DescriptorArray::CopyFrom(int index, DescriptorArray* src, |
8679 const WhitenessWitness& witness) { | 8687 const WhitenessWitness& witness) { |
8680 Object* value = src->GetValue(index); | 8688 Object* value = src->GetValue(index); |
8681 PropertyDetails details = src->GetDetails(index); | 8689 PropertyDetails details = src->GetDetails(index); |
8682 Descriptor desc(handle(src->GetKey(index)), | 8690 Descriptor desc(handle(src->GetKey(index)), |
8683 handle(value, src->GetIsolate()), | 8691 handle(value, src->GetIsolate()), |
8684 details); | 8692 details); |
(...skipping 8103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16788 if (cell->value() != *new_value) { | 16796 if (cell->value() != *new_value) { |
16789 cell->set_value(*new_value); | 16797 cell->set_value(*new_value); |
16790 Isolate* isolate = cell->GetIsolate(); | 16798 Isolate* isolate = cell->GetIsolate(); |
16791 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 16799 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
16792 isolate, DependentCode::kPropertyCellChangedGroup); | 16800 isolate, DependentCode::kPropertyCellChangedGroup); |
16793 } | 16801 } |
16794 } | 16802 } |
16795 | 16803 |
16796 } // namespace internal | 16804 } // namespace internal |
16797 } // namespace v8 | 16805 } // namespace v8 |
OLD | NEW |