| 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 6550 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6561 DCHECK(array->length() >= length); | 6561 DCHECK(array->length() >= length); |
| 6562 if (array->length() == length) return array; | 6562 if (array->length() == length) return array; |
| 6563 | 6563 |
| 6564 Handle<FixedArray> new_array = | 6564 Handle<FixedArray> new_array = |
| 6565 array->GetIsolate()->factory()->NewFixedArray(length); | 6565 array->GetIsolate()->factory()->NewFixedArray(length); |
| 6566 for (int i = 0; i < length; ++i) new_array->set(i, array->get(i)); | 6566 for (int i = 0; i < length; ++i) new_array->set(i, array->get(i)); |
| 6567 return new_array; | 6567 return new_array; |
| 6568 } | 6568 } |
| 6569 | 6569 |
| 6570 | 6570 |
| 6571 namespace { | 6571 Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object, |
| 6572 bool cache_result) { |
| 6573 Isolate* isolate = object->GetIsolate(); |
| 6574 if (object->HasFastProperties()) { |
| 6575 int own_property_count = object->map()->EnumLength(); |
| 6576 // If the enum length of the given map is set to kInvalidEnumCache, this |
| 6577 // means that the map itself has never used the present enum cache. The |
| 6578 // first step to using the cache is to set the enum length of the map by |
| 6579 // counting the number of own descriptors that are not DONT_ENUM or |
| 6580 // SYMBOLIC. |
| 6581 if (own_property_count == kInvalidEnumCacheSentinel) { |
| 6582 own_property_count = object->map()->NumberOfDescribedProperties( |
| 6583 OWN_DESCRIPTORS, DONT_SHOW); |
| 6584 } else { |
| 6585 DCHECK(own_property_count == object->map()->NumberOfDescribedProperties( |
| 6586 OWN_DESCRIPTORS, DONT_SHOW)); |
| 6587 } |
| 6572 | 6588 |
| 6573 Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate, | 6589 if (object->map()->instance_descriptors()->HasEnumCache()) { |
| 6574 Handle<JSObject> object, | 6590 DescriptorArray* desc = object->map()->instance_descriptors(); |
| 6575 bool cache_enum_length) { | 6591 Handle<FixedArray> keys(desc->GetEnumCache(), isolate); |
| 6576 Handle<Map> map(object->map()); | |
| 6577 Handle<DescriptorArray> descs = | |
| 6578 Handle<DescriptorArray>(map->instance_descriptors(), isolate); | |
| 6579 int own_property_count = map->EnumLength(); | |
| 6580 // If the enum length of the given map is set to kInvalidEnumCache, this | |
| 6581 // means that the map itself has never used the present enum cache. The | |
| 6582 // first step to using the cache is to set the enum length of the map by | |
| 6583 // counting the number of own descriptors that are not DONT_ENUM or | |
| 6584 // SYMBOLIC. | |
| 6585 if (own_property_count == kInvalidEnumCacheSentinel) { | |
| 6586 own_property_count = | |
| 6587 map->NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_SHOW); | |
| 6588 } else { | |
| 6589 DCHECK(own_property_count == | |
| 6590 map->NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_SHOW)); | |
| 6591 } | |
| 6592 | 6592 |
| 6593 if (descs->HasEnumCache()) { | 6593 // In case the number of properties required in the enum are actually |
| 6594 Handle<FixedArray> keys(descs->GetEnumCache(), isolate); | 6594 // present, we can reuse the enum cache. Otherwise, this means that the |
| 6595 // In case the number of properties required in the enum are actually | 6595 // enum cache was generated for a previous (smaller) version of the |
| 6596 // present, we can reuse the enum cache. Otherwise, this means that the | 6596 // Descriptor Array. In that case we regenerate the enum cache. |
| 6597 // enum cache was generated for a previous (smaller) version of the | 6597 if (own_property_count <= keys->length()) { |
| 6598 // Descriptor Array. In that case we regenerate the enum cache. | 6598 if (cache_result) object->map()->SetEnumLength(own_property_count); |
| 6599 if (own_property_count <= keys->length()) { | 6599 isolate->counters()->enum_cache_hits()->Increment(); |
| 6600 isolate->counters()->enum_cache_hits()->Increment(); | 6600 return ReduceFixedArrayTo(keys, own_property_count); |
| 6601 if (cache_enum_length) map->SetEnumLength(own_property_count); | |
| 6602 return ReduceFixedArrayTo(keys, own_property_count); | |
| 6603 } | |
| 6604 } | |
| 6605 | |
| 6606 if (descs->IsEmpty()) { | |
| 6607 isolate->counters()->enum_cache_hits()->Increment(); | |
| 6608 if (cache_enum_length) map->SetEnumLength(0); | |
| 6609 return isolate->factory()->empty_fixed_array(); | |
| 6610 } | |
| 6611 | |
| 6612 isolate->counters()->enum_cache_misses()->Increment(); | |
| 6613 | |
| 6614 Handle<FixedArray> storage = | |
| 6615 isolate->factory()->NewFixedArray(own_property_count); | |
| 6616 Handle<FixedArray> indices = | |
| 6617 isolate->factory()->NewFixedArray(own_property_count); | |
| 6618 | |
| 6619 int size = map->NumberOfOwnDescriptors(); | |
| 6620 int index = 0; | |
| 6621 | |
| 6622 for (int i = 0; i < size; i++) { | |
| 6623 PropertyDetails details = descs->GetDetails(i); | |
| 6624 Object* key = descs->GetKey(i); | |
| 6625 if (details.IsDontEnum() || key->IsSymbol()) continue; | |
| 6626 storage->set(index, key); | |
| 6627 if (!indices.is_null()) { | |
| 6628 if (details.type() != DATA) { | |
| 6629 indices = Handle<FixedArray>(); | |
| 6630 } else { | |
| 6631 FieldIndex field_index = FieldIndex::ForDescriptor(*map, i); | |
| 6632 int load_by_field_index = field_index.GetLoadByFieldIndex(); | |
| 6633 indices->set(index, Smi::FromInt(load_by_field_index)); | |
| 6634 } | 6601 } |
| 6635 } | 6602 } |
| 6636 index++; | |
| 6637 } | |
| 6638 DCHECK(index == storage->length()); | |
| 6639 | 6603 |
| 6640 descs->SetEnumCache(isolate, storage, indices); | 6604 Handle<Map> map(object->map()); |
| 6641 if (cache_enum_length) { | |
| 6642 map->SetEnumLength(own_property_count); | |
| 6643 } | |
| 6644 return storage; | |
| 6645 } | |
| 6646 | 6605 |
| 6647 } // namespace | 6606 if (map->instance_descriptors()->IsEmpty()) { |
| 6607 isolate->counters()->enum_cache_hits()->Increment(); |
| 6608 if (cache_result) map->SetEnumLength(0); |
| 6609 return isolate->factory()->empty_fixed_array(); |
| 6610 } |
| 6648 | 6611 |
| 6612 isolate->counters()->enum_cache_misses()->Increment(); |
| 6649 | 6613 |
| 6650 Handle<FixedArray> JSObject::GetEnumPropertyKeys(Handle<JSObject> object, | 6614 Handle<FixedArray> storage = isolate->factory()->NewFixedArray( |
| 6651 bool cache_enum_length) { | 6615 own_property_count); |
| 6652 Isolate* isolate = object->GetIsolate(); | 6616 Handle<FixedArray> indices = isolate->factory()->NewFixedArray( |
| 6653 if (object->HasFastProperties()) { | 6617 own_property_count); |
| 6654 return GetFastEnumPropertyKeys(isolate, object, cache_enum_length); | 6618 |
| 6619 Handle<DescriptorArray> descs = |
| 6620 Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate); |
| 6621 |
| 6622 int size = map->NumberOfOwnDescriptors(); |
| 6623 int index = 0; |
| 6624 |
| 6625 for (int i = 0; i < size; i++) { |
| 6626 PropertyDetails details = descs->GetDetails(i); |
| 6627 Object* key = descs->GetKey(i); |
| 6628 if (!(details.IsDontEnum() || key->IsSymbol())) { |
| 6629 storage->set(index, key); |
| 6630 if (!indices.is_null()) { |
| 6631 if (details.type() != DATA) { |
| 6632 indices = Handle<FixedArray>(); |
| 6633 } else { |
| 6634 FieldIndex field_index = FieldIndex::ForDescriptor(*map, i); |
| 6635 int load_by_field_index = field_index.GetLoadByFieldIndex(); |
| 6636 indices->set(index, Smi::FromInt(load_by_field_index)); |
| 6637 } |
| 6638 } |
| 6639 index++; |
| 6640 } |
| 6641 } |
| 6642 DCHECK(index == storage->length()); |
| 6643 |
| 6644 Handle<FixedArray> bridge_storage = |
| 6645 isolate->factory()->NewFixedArray( |
| 6646 DescriptorArray::kEnumCacheBridgeLength); |
| 6647 DescriptorArray* desc = object->map()->instance_descriptors(); |
| 6648 desc->SetEnumCache(*bridge_storage, |
| 6649 *storage, |
| 6650 indices.is_null() ? Object::cast(Smi::FromInt(0)) |
| 6651 : Object::cast(*indices)); |
| 6652 if (cache_result) { |
| 6653 object->map()->SetEnumLength(own_property_count); |
| 6654 } |
| 6655 return storage; |
| 6655 } else if (object->IsGlobalObject()) { | 6656 } else if (object->IsGlobalObject()) { |
| 6656 Handle<GlobalDictionary> dictionary(object->global_dictionary()); | 6657 Handle<GlobalDictionary> dictionary(object->global_dictionary()); |
| 6657 int length = dictionary->NumberOfEnumElements(); | 6658 int length = dictionary->NumberOfEnumElements(); |
| 6658 if (length == 0) { | 6659 if (length == 0) { |
| 6659 return Handle<FixedArray>(isolate->heap()->empty_fixed_array()); | 6660 return Handle<FixedArray>(isolate->heap()->empty_fixed_array()); |
| 6660 } | 6661 } |
| 6661 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); | 6662 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); |
| 6662 dictionary->CopyEnumKeysTo(*storage); | 6663 dictionary->CopyEnumKeysTo(*storage); |
| 6663 return storage; | 6664 return storage; |
| 6664 } else { | 6665 } else { |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6848 // We can cache the computed property keys if access checks are | 6849 // We can cache the computed property keys if access checks are |
| 6849 // not needed and no interceptors are involved. | 6850 // not needed and no interceptors are involved. |
| 6850 // | 6851 // |
| 6851 // We do not use the cache if the object has elements and | 6852 // We do not use the cache if the object has elements and |
| 6852 // therefore it does not make sense to cache the property names | 6853 // therefore it does not make sense to cache the property names |
| 6853 // for arguments objects. Arguments objects will always have | 6854 // for arguments objects. Arguments objects will always have |
| 6854 // elements. | 6855 // elements. |
| 6855 // Wrapped strings have elements, but don't have an elements | 6856 // Wrapped strings have elements, but don't have an elements |
| 6856 // array or dictionary. So the fast inline test for whether to | 6857 // array or dictionary. So the fast inline test for whether to |
| 6857 // use the cache says yes, so we should not create a cache. | 6858 // use the cache says yes, so we should not create a cache. |
| 6858 bool cache_enum_length = | 6859 bool cache_enum_keys = |
| 6859 ((current->map()->GetConstructor() != *arguments_function) && | 6860 ((current->map()->GetConstructor() != *arguments_function) && |
| 6860 !current->IsJSValue() && !current->IsAccessCheckNeeded() && | 6861 !current->IsJSValue() && !current->IsAccessCheckNeeded() && |
| 6861 !current->HasNamedInterceptor() && !current->HasIndexedInterceptor()); | 6862 !current->HasNamedInterceptor() && !current->HasIndexedInterceptor()); |
| 6862 // Compute the property keys and cache them if possible. | 6863 // Compute the property keys and cache them if possible. |
| 6863 | 6864 |
| 6864 Handle<FixedArray> enum_keys = | 6865 Handle<FixedArray> enum_keys = |
| 6865 JSObject::GetEnumPropertyKeys(current, cache_enum_length); | 6866 JSObject::GetEnumPropertyKeys(current, cache_enum_keys); |
| 6866 accumulator.AddKeys(enum_keys, FixedArray::ALL_KEYS); | 6867 accumulator.AddKeys(enum_keys, FixedArray::ALL_KEYS); |
| 6867 DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys())); | 6868 DCHECK(ContainsOnlyValidKeys(accumulator.GetKeys())); |
| 6868 | 6869 |
| 6869 // Add the non-symbol property keys from the interceptor. | 6870 // Add the non-symbol property keys from the interceptor. |
| 6870 if (current->HasNamedInterceptor()) { | 6871 if (current->HasNamedInterceptor()) { |
| 6871 Handle<JSObject> result; | 6872 Handle<JSObject> result; |
| 6872 if (JSObject::GetKeysForNamedInterceptor( | 6873 if (JSObject::GetKeysForNamedInterceptor( |
| 6873 current, object).ToHandle(&result)) { | 6874 current, object).ToHandle(&result)) { |
| 6874 accumulator.AddKeys(result, FixedArray::NON_SYMBOL_KEYS); | 6875 accumulator.AddKeys(result, FixedArray::NON_SYMBOL_KEYS); |
| 6875 } | 6876 } |
| (...skipping 1732 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8608 set(kEnumCacheIndex, Smi::FromInt(0)); | 8609 set(kEnumCacheIndex, Smi::FromInt(0)); |
| 8609 } | 8610 } |
| 8610 | 8611 |
| 8611 | 8612 |
| 8612 void DescriptorArray::Replace(int index, Descriptor* descriptor) { | 8613 void DescriptorArray::Replace(int index, Descriptor* descriptor) { |
| 8613 descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index)); | 8614 descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index)); |
| 8614 Set(index, descriptor); | 8615 Set(index, descriptor); |
| 8615 } | 8616 } |
| 8616 | 8617 |
| 8617 | 8618 |
| 8618 void DescriptorArray::SetEnumCache(Isolate* isolate, | 8619 void DescriptorArray::SetEnumCache(FixedArray* bridge_storage, |
| 8619 Handle<FixedArray> new_cache, | 8620 FixedArray* new_cache, |
| 8620 Handle<FixedArray> new_index_cache) { | 8621 Object* new_index_cache) { |
| 8622 DCHECK(bridge_storage->length() >= kEnumCacheBridgeLength); |
| 8623 DCHECK(new_index_cache->IsSmi() || new_index_cache->IsFixedArray()); |
| 8621 DCHECK(!IsEmpty()); | 8624 DCHECK(!IsEmpty()); |
| 8622 FixedArray* bridge_storage; | 8625 DCHECK(!HasEnumCache() || new_cache->length() > GetEnumCache()->length()); |
| 8623 bool needs_new_enum_cache = !HasEnumCache(); | 8626 FixedArray::cast(bridge_storage)-> |
| 8624 if (needs_new_enum_cache) { | 8627 set(kEnumCacheBridgeCacheIndex, new_cache); |
| 8625 bridge_storage = *isolate->factory()->NewFixedArray( | 8628 FixedArray::cast(bridge_storage)-> |
| 8626 DescriptorArray::kEnumCacheBridgeLength); | 8629 set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache); |
| 8627 } else { | 8630 set(kEnumCacheIndex, bridge_storage); |
| 8628 bridge_storage = FixedArray::cast(get(kEnumCacheIndex)); | |
| 8629 } | |
| 8630 bridge_storage->set(kEnumCacheBridgeCacheIndex, *new_cache); | |
| 8631 bridge_storage->set(kEnumCacheBridgeIndicesCacheIndex, | |
| 8632 new_index_cache.is_null() ? Object::cast(Smi::FromInt(0)) | |
| 8633 : *new_index_cache); | |
| 8634 if (needs_new_enum_cache) { | |
| 8635 set(kEnumCacheIndex, bridge_storage); | |
| 8636 } | |
| 8637 } | 8631 } |
| 8638 | 8632 |
| 8639 | 8633 |
| 8640 void DescriptorArray::CopyFrom(int index, DescriptorArray* src, | 8634 void DescriptorArray::CopyFrom(int index, DescriptorArray* src, |
| 8641 const WhitenessWitness& witness) { | 8635 const WhitenessWitness& witness) { |
| 8642 Object* value = src->GetValue(index); | 8636 Object* value = src->GetValue(index); |
| 8643 PropertyDetails details = src->GetDetails(index); | 8637 PropertyDetails details = src->GetDetails(index); |
| 8644 Descriptor desc(handle(src->GetKey(index)), | 8638 Descriptor desc(handle(src->GetKey(index)), |
| 8645 handle(value, src->GetIsolate()), | 8639 handle(value, src->GetIsolate()), |
| 8646 details); | 8640 details); |
| (...skipping 8104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 16751 if (cell->value() != *new_value) { | 16745 if (cell->value() != *new_value) { |
| 16752 cell->set_value(*new_value); | 16746 cell->set_value(*new_value); |
| 16753 Isolate* isolate = cell->GetIsolate(); | 16747 Isolate* isolate = cell->GetIsolate(); |
| 16754 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 16748 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
| 16755 isolate, DependentCode::kPropertyCellChangedGroup); | 16749 isolate, DependentCode::kPropertyCellChangedGroup); |
| 16756 } | 16750 } |
| 16757 } | 16751 } |
| 16758 | 16752 |
| 16759 } // namespace internal | 16753 } // namespace internal |
| 16760 } // namespace v8 | 16754 } // namespace v8 |
| OLD | NEW |