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 |