| 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 |