Chromium Code Reviews| Index: src/objects.cc |
| diff --git a/src/objects.cc b/src/objects.cc |
| index 45f7ab9ea32e91083b51d4de6df68028a9810823..cdd38367aee002b1283f3b01d7d33461d8f57269 100644 |
| --- a/src/objects.cc |
| +++ b/src/objects.cc |
| @@ -4789,6 +4789,24 @@ static Handle<SeededNumberDictionary> CopyFastElementsToDictionary( |
| } |
| +Handle<SeededNumberDictionary> JSObject::GetNormalizedElementDictionary( |
| + Handle<JSObject> object, Handle<FixedArrayBase> elements) { |
| + DCHECK(!object->HasDictionaryElements()); |
| + DCHECK(!object->HasSlowArgumentsElements()); |
| + Isolate* isolate = object->GetIsolate(); |
| + // Ensure that notifications fire if the array or object prototypes are |
| + // normalizing. |
| + isolate->UpdateArrayProtectorOnNormalizeElements(object); |
| + int length = object->IsJSArray() |
| + ? Smi::cast(Handle<JSArray>::cast(object)->length())->value() |
| + : elements->length(); |
| + int used = object->GetFastElementsUsage(); |
| + Handle<SeededNumberDictionary> dictionary = |
| + SeededNumberDictionary::New(isolate, used); |
| + return CopyFastElementsToDictionary(elements, length, dictionary); |
| +} |
| + |
| + |
| Handle<SeededNumberDictionary> JSObject::NormalizeElements( |
| Handle<JSObject> object) { |
| DCHECK(!object->HasExternalArrayElements() && |
| @@ -4796,34 +4814,23 @@ Handle<SeededNumberDictionary> JSObject::NormalizeElements( |
| Isolate* isolate = object->GetIsolate(); |
| // Find the backing store. |
| - Handle<FixedArrayBase> array(FixedArrayBase::cast(object->elements())); |
| - bool is_arguments = |
| - (array->map() == isolate->heap()->sloppy_arguments_elements_map()); |
| + Handle<FixedArrayBase> elements(object->elements(), isolate); |
| + bool is_arguments = object->HasSloppyArgumentsElements(); |
| if (is_arguments) { |
| - array = handle(FixedArrayBase::cast( |
| - Handle<FixedArray>::cast(array)->get(1))); |
| + FixedArray* parameter_map = FixedArray::cast(*elements); |
| + elements = handle(FixedArrayBase::cast(parameter_map->get(1)), isolate); |
| + } |
| + |
| + if (elements->IsDictionary()) { |
| + return Handle<SeededNumberDictionary>::cast(elements); |
| } |
| - if (array->IsDictionary()) return Handle<SeededNumberDictionary>::cast(array); |
| DCHECK(object->HasFastSmiOrObjectElements() || |
| object->HasFastDoubleElements() || |
| object->HasFastArgumentsElements()); |
| - // Ensure that notifications fire if the array or object prototypes are |
| - // normalizing. |
| - isolate->UpdateArrayProtectorOnNormalizeElements(object); |
| - |
| - // Compute the effective length and allocate a new backing store. |
| - int length = object->IsJSArray() |
| - ? Smi::cast(Handle<JSArray>::cast(object)->length())->value() |
| - : array->length(); |
| - int old_capacity = 0; |
| - int used_elements = 0; |
| - object->GetElementsCapacityAndUsage(&old_capacity, &used_elements); |
| Handle<SeededNumberDictionary> dictionary = |
| - SeededNumberDictionary::New(isolate, used_elements); |
| - |
| - dictionary = CopyFastElementsToDictionary(array, length, dictionary); |
| + GetNormalizedElementDictionary(object, elements); |
| // Switch to using the dictionary as the backing storage for elements. |
| ElementsKind target_kind = |
| @@ -5463,30 +5470,6 @@ bool JSObject::IsExtensible() { |
| } |
| -Handle<SeededNumberDictionary> JSObject::GetNormalizedElementDictionary( |
| - Handle<JSObject> object) { |
| - DCHECK(!object->elements()->IsDictionary()); |
| - Isolate* isolate = object->GetIsolate(); |
| - int length = object->IsJSArray() |
| - ? Smi::cast(Handle<JSArray>::cast(object)->length())->value() |
| - : object->elements()->length(); |
| - if (length > 0) { |
| - int capacity = 0; |
| - int used = 0; |
| - object->GetElementsCapacityAndUsage(&capacity, &used); |
| - Handle<SeededNumberDictionary> new_element_dictionary = |
| - SeededNumberDictionary::New(isolate, used); |
| - |
| - // Move elements to a dictionary; avoid calling NormalizeElements to avoid |
| - // unnecessary transitions. |
| - return CopyFastElementsToDictionary(handle(object->elements()), length, |
| - new_element_dictionary); |
| - } |
| - // No existing elements, use a pre-allocated empty backing store |
| - return isolate->factory()->empty_slow_element_dictionary(); |
| -} |
| - |
| - |
| template <typename Dictionary> |
| static void ApplyAttributesToDictionary(Dictionary* dictionary, |
| const PropertyAttributes attributes) { |
| @@ -5544,9 +5527,15 @@ MaybeHandle<Object> JSObject::PreventExtensionsWithTransition( |
| } |
| Handle<SeededNumberDictionary> new_element_dictionary; |
| - if (!object->elements()->IsDictionary()) { |
| - new_element_dictionary = GetNormalizedElementDictionary(object); |
| - isolate->UpdateArrayProtectorOnNormalizeElements(object); |
| + if (!object->HasDictionaryElements()) { |
| + int length = |
| + object->IsJSArray() |
| + ? Smi::cast(Handle<JSArray>::cast(object)->length())->value() |
| + : object->elements()->length(); |
| + new_element_dictionary = |
| + length == 0 ? isolate->factory()->empty_slow_element_dictionary() |
|
Igor Sheludko
2015/07/15 14:58:06
Probably it would be better if GetNormalizedElemen
Toon Verwaest
2015/07/15 15:07:58
It, unfortunately, cannot. The empty dictionary is
|
| + : GetNormalizedElementDictionary( |
| + object, handle(object->elements())); |
| } |
| Handle<Symbol> transition_marker; |
| @@ -12148,9 +12137,7 @@ static bool ShouldConvertToSlowElements(JSObject* object, uint32_t capacity, |
| // If the fast-case backing storage takes up roughly three times as |
| // much space (in machine words) as a dictionary backing storage |
| // would, the object should have slow elements. |
| - int old_capacity = 0; |
| - int used_elements = 0; |
| - object->GetElementsCapacityAndUsage(&old_capacity, &used_elements); |
| + int used_elements = object->GetFastElementsUsage(); |
| int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) * |
| SeededNumberDictionary::kEntrySize; |
| return 3 * static_cast<uint32_t>(dictionary_size) <= *new_capacity; |
| @@ -12517,78 +12504,47 @@ MaybeHandle<Object> JSArray::ReadOnlyLengthError(Handle<JSArray> array) { |
| } |
| -void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) { |
| - *capacity = 0; |
| - *used = 0; |
| +template <typename BackingStore> |
| +static int FastHoleyElementsUsage(JSObject* object, BackingStore* store) { |
| + int limit = object->IsJSArray() |
| + ? Smi::cast(JSArray::cast(object)->length())->value() |
| + : store->length(); |
| + int used = 0; |
| + for (int i = 0; i < limit; ++i) { |
| + if (!store->is_the_hole(i)) ++used; |
| + } |
| + return used; |
| +} |
| + |
| - FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements()); |
| - FixedArray* backing_store = NULL; |
| +int JSObject::GetFastElementsUsage() { |
| + FixedArrayBase* store = elements(); |
| switch (GetElementsKind()) { |
| - case FAST_SLOPPY_ARGUMENTS_ELEMENTS: |
| - case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: |
| - backing_store_base = |
| - FixedArray::cast(FixedArray::cast(backing_store_base)->get(1)); |
| - backing_store = FixedArray::cast(backing_store_base); |
| - if (backing_store->IsDictionary()) { |
| - SeededNumberDictionary* dictionary = |
| - SeededNumberDictionary::cast(backing_store); |
| - *capacity = dictionary->Capacity(); |
| - *used = dictionary->NumberOfElements(); |
| - break; |
| - } |
| - // Fall through. |
| case FAST_SMI_ELEMENTS: |
| + case FAST_DOUBLE_ELEMENTS: |
| case FAST_ELEMENTS: |
| - if (IsJSArray()) { |
| - *capacity = backing_store_base->length(); |
| - *used = Smi::cast(JSArray::cast(this)->length())->value(); |
| - break; |
| - } |
| - // Fall through if packing is not guaranteed. |
| + // Only JSArray have packed elements. |
| + return Smi::cast(JSArray::cast(this)->length())->value(); |
| + case FAST_SLOPPY_ARGUMENTS_ELEMENTS: |
| + store = FixedArray::cast(FixedArray::cast(store)->get(1)); |
| + // Fall through. |
| case FAST_HOLEY_SMI_ELEMENTS: |
| case FAST_HOLEY_ELEMENTS: |
| - backing_store = FixedArray::cast(backing_store_base); |
| - *capacity = backing_store->length(); |
| - for (int i = 0; i < *capacity; ++i) { |
| - if (!backing_store->get(i)->IsTheHole()) ++(*used); |
| - } |
| - break; |
| - case DICTIONARY_ELEMENTS: { |
| - SeededNumberDictionary* dictionary = element_dictionary(); |
| - *capacity = dictionary->Capacity(); |
| - *used = dictionary->NumberOfElements(); |
| - break; |
| - } |
| - case FAST_DOUBLE_ELEMENTS: |
| - if (IsJSArray()) { |
| - *capacity = backing_store_base->length(); |
| - *used = Smi::cast(JSArray::cast(this)->length())->value(); |
| - break; |
| - } |
| - // Fall through if packing is not guaranteed. |
| - case FAST_HOLEY_DOUBLE_ELEMENTS: { |
| - *capacity = elements()->length(); |
| - if (*capacity == 0) break; |
| - FixedDoubleArray * elms = FixedDoubleArray::cast(elements()); |
| - for (int i = 0; i < *capacity; i++) { |
| - if (!elms->is_the_hole(i)) ++(*used); |
| - } |
| - break; |
| - } |
| + return FastHoleyElementsUsage(this, FixedArray::cast(store)); |
| + case FAST_HOLEY_DOUBLE_ELEMENTS: |
| + if (elements()->length() == 0) return 0; |
| + return FastHoleyElementsUsage(this, FixedDoubleArray::cast(store)); |
| + case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: |
| + case DICTIONARY_ELEMENTS: |
| #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ |
| case EXTERNAL_##TYPE##_ELEMENTS: \ |
| case TYPE##_ELEMENTS: \ |
| TYPED_ARRAYS(TYPED_ARRAY_CASE) |
| #undef TYPED_ARRAY_CASE |
| - { |
| - // External arrays are considered 100% used. |
| - FixedArrayBase* external_array = FixedArrayBase::cast(elements()); |
| - *capacity = external_array->length(); |
| - *used = external_array->length(); |
| - break; |
| - } |
| + UNREACHABLE(); |
| + return 0; |
| } |
| } |