| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 45f7ab9ea32e91083b51d4de6df68028a9810823..4deb64da048e335e582f10797dd0853963dd4496 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()
|
| + : 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,79 +12504,48 @@ 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;
|
| }
|
|
|
|
|
|
|