| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 86a3343ca6b9e0b405422530c09bc2c11fed2428..a7490d814110ca3a0319e25e88cff3baf94971db 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -12353,98 +12353,18 @@ bool JSObject::HasDictionaryArgumentsElements() {
|
| }
|
|
|
|
|
| -void JSObject::AddFastElement(Handle<JSObject> object, uint32_t index,
|
| - Handle<Object> value) {
|
| - DCHECK(object->HasFastSmiOrObjectElements() ||
|
| - object->HasFastArgumentsElements());
|
| -
|
| - Handle<FixedArray> backing_store(FixedArray::cast(object->elements()));
|
| - if (object->HasSloppyArgumentsElements()) {
|
| - backing_store = handle(FixedArray::cast(backing_store->get(1)));
|
| - } else {
|
| - backing_store = EnsureWritableFastElements(object);
|
| - }
|
| - uint32_t capacity = static_cast<uint32_t>(backing_store->length());
|
| -
|
| - // Check if the length property of this object needs to be updated.
|
| - uint32_t array_length = 0;
|
| - bool must_update_array_length = false;
|
| - bool introduces_holes = true;
|
| - if (object->IsJSArray()) {
|
| - CHECK(JSArray::cast(*object)->length()->ToArrayLength(&array_length));
|
| - introduces_holes = index > array_length;
|
| - if (index >= array_length) {
|
| - must_update_array_length = true;
|
| - array_length = index + 1;
|
| - }
|
| - } else {
|
| - introduces_holes = index >= capacity;
|
| - }
|
| -
|
| - uint32_t new_capacity = capacity;
|
| - // Check if the capacity of the backing store needs to be increased, or if
|
| - // a transition to slow elements is necessary.
|
| - if (index >= capacity) {
|
| - bool convert_to_slow = true;
|
| - if ((index - capacity) < kMaxGap) {
|
| - new_capacity = NewElementsCapacity(index + 1);
|
| - DCHECK_LT(index, new_capacity);
|
| - convert_to_slow = object->ShouldConvertToSlowElements(new_capacity);
|
| - }
|
| - if (convert_to_slow) {
|
| - NormalizeElements(object);
|
| - AddDictionaryElement(object, index, value, NONE);
|
| - return;
|
| - }
|
| - }
|
| -
|
| - if (object->HasFastSmiElements() && !value->IsSmi()) {
|
| - // Convert to fast double elements if appropriate.
|
| - if (value->IsNumber()) {
|
| - ElementsKind to_kind =
|
| - introduces_holes ? FAST_HOLEY_DOUBLE_ELEMENTS : FAST_DOUBLE_ELEMENTS;
|
| - ElementsAccessor* accessor = ElementsAccessor::ForKind(to_kind);
|
| - accessor->GrowCapacityAndConvert(object, new_capacity);
|
| - AddFastDoubleElement(object, index, value);
|
| - return;
|
| - }
|
| -
|
| - // Change elements kind from Smi-only to generic FAST if necessary.
|
| - ElementsKind kind = introduces_holes || object->HasFastHoleyElements()
|
| - ? FAST_HOLEY_ELEMENTS
|
| - : FAST_ELEMENTS;
|
| -
|
| - UpdateAllocationSite(object, kind);
|
| - Handle<Map> new_map = GetElementsTransitionMap(object, kind);
|
| - JSObject::MigrateToMap(object, new_map);
|
| - DCHECK(IsFastObjectElementsKind(object->GetElementsKind()));
|
| - } else if (introduces_holes && !object->HasFastHoleyElements()) {
|
| - // If the array is growing, and it's not growth by a single element at the
|
| - // end, make sure that the ElementsKind is HOLEY.
|
| - ElementsKind transitioned_kind =
|
| - GetHoleyElementsKind(object->GetElementsKind());
|
| - TransitionElementsKind(object, transitioned_kind);
|
| - }
|
| -
|
| - // Increase backing store capacity if that's been decided previously.
|
| - if (capacity != new_capacity) {
|
| - DCHECK(!object->HasFastDoubleElements());
|
| - ElementsAccessor* accessor =
|
| - value->IsSmi() || object->HasSloppyArgumentsElements()
|
| - ? object->GetElementsAccessor()
|
| - : ElementsAccessor::ForKind(FAST_ELEMENTS);
|
| - accessor->GrowCapacityAndConvert(object, new_capacity);
|
| - }
|
| +ElementsAccessor* JSObject::GetElementsAccessor() {
|
| + return ElementsAccessor::ForKind(GetElementsKind());
|
| +}
|
|
|
| - if (must_update_array_length) {
|
| - Handle<JSArray>::cast(object)->set_length(Smi::FromInt(array_length));
|
| - }
|
|
|
| - FixedArray* elements = FixedArray::cast(object->elements());
|
| - if (object->HasSloppyArgumentsElements()) {
|
| - elements = FixedArray::cast(elements->get(1));
|
| +void JSObject::ValidateElements(Handle<JSObject> object) {
|
| +#ifdef ENABLE_SLOW_DCHECKS
|
| + if (FLAG_enable_slow_asserts) {
|
| + ElementsAccessor* accessor = object->GetElementsAccessor();
|
| + accessor->Validate(object);
|
| }
|
| - elements->set(index, *value);
|
| +#endif
|
| }
|
|
|
|
|
| @@ -12484,30 +12404,6 @@ void JSObject::SetDictionaryArgumentsElement(Handle<JSObject> object,
|
| }
|
|
|
|
|
| -void JSObject::AddSloppyArgumentsElement(Handle<JSObject> object,
|
| - uint32_t index, Handle<Object> value,
|
| - PropertyAttributes attributes) {
|
| - DCHECK(object->HasSloppyArgumentsElements());
|
| -
|
| - // TODO(verwaest): Handle with the elements accessor.
|
| - FixedArray* parameter_map = FixedArray::cast(object->elements());
|
| -
|
| -#ifdef DEBUG
|
| - uint32_t length = parameter_map->length();
|
| - if (index < length - 2) {
|
| - Object* probe = parameter_map->get(index + 2);
|
| - DCHECK(probe->IsTheHole());
|
| - }
|
| -#endif
|
| -
|
| - if (parameter_map->get(1)->IsDictionary()) {
|
| - AddDictionaryElement(object, index, value, attributes);
|
| - } else {
|
| - AddFastElement(object, index, value);
|
| - }
|
| -}
|
| -
|
| -
|
| void JSObject::SetDictionaryElement(Handle<JSObject> object, uint32_t index,
|
| Handle<Object> value,
|
| PropertyAttributes attributes) {
|
| @@ -12599,8 +12495,7 @@ void JSObject::AddDictionaryElement(Handle<JSObject> object, uint32_t index,
|
| if (object->ShouldConvertToFastElements()) {
|
| uint32_t new_length = 0;
|
| if (object->IsJSArray()) {
|
| - CHECK(
|
| - Handle<JSArray>::cast(object)->length()->ToArrayLength(&new_length));
|
| + CHECK(JSArray::cast(*object)->length()->ToArrayLength(&new_length));
|
| } else {
|
| new_length = dictionary->max_number_key() + 1;
|
| }
|
| @@ -12618,148 +12513,119 @@ void JSObject::AddDictionaryElement(Handle<JSObject> object, uint32_t index,
|
| }
|
|
|
|
|
| -void JSObject::AddFastDoubleElement(Handle<JSObject> object, uint32_t index,
|
| - Handle<Object> value) {
|
| - DCHECK(object->HasFastDoubleElements());
|
| +// static
|
| +MaybeHandle<Object> JSReceiver::SetElement(Handle<JSReceiver> object,
|
| + uint32_t index, Handle<Object> value,
|
| + LanguageMode language_mode) {
|
| + Isolate* isolate = object->GetIsolate();
|
| + LookupIterator it(isolate, object, index);
|
| + return SetProperty(&it, value, language_mode, MAY_BE_STORE_FROM_KEYED);
|
| +}
|
|
|
| - Handle<FixedArrayBase> base_elms(FixedArrayBase::cast(object->elements()));
|
| - uint32_t capacity = static_cast<uint32_t>(base_elms->length());
|
|
|
| +static void AddFastElement(Handle<JSObject> object, uint32_t index,
|
| + Handle<Object> value, ElementsKind from_kind,
|
| + uint32_t capacity, uint32_t new_capacity) {
|
| // Check if the length property of this object needs to be updated.
|
| uint32_t array_length = 0;
|
| - bool must_update_array_length = false;
|
| bool introduces_holes = true;
|
| if (object->IsJSArray()) {
|
| - // In case of JSArray, the length does not equal the capacity.
|
| CHECK(JSArray::cast(*object)->length()->ToArrayLength(&array_length));
|
| introduces_holes = index > array_length;
|
| - if (index >= array_length) {
|
| - must_update_array_length = true;
|
| - array_length = index + 1;
|
| - }
|
| } else {
|
| introduces_holes = index >= capacity;
|
| }
|
|
|
| - uint32_t new_capacity = capacity;
|
| - // Check if the capacity of the backing store needs to be increased, or if
|
| - // a transition to slow elements is necessary.
|
| - if (index >= capacity) {
|
| - bool convert_to_slow = true;
|
| - if ((index - capacity) < kMaxGap) {
|
| - new_capacity = NewElementsCapacity(index + 1);
|
| - DCHECK_LT(index, new_capacity);
|
| - convert_to_slow = object->ShouldConvertToSlowElements(new_capacity);
|
| - }
|
| - if (convert_to_slow) {
|
| - NormalizeElements(object);
|
| - AddDictionaryElement(object, index, value, NONE);
|
| - return;
|
| - }
|
| - }
|
| -
|
| - // If the value object is not a heap number, switch to fast elements and try
|
| - // again.
|
| - if (!value->IsNumber()) {
|
| - ElementsKind to_kind =
|
| - introduces_holes ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS;
|
| - ElementsAccessor* accessor = ElementsAccessor::ForKind(to_kind);
|
| - accessor->GrowCapacityAndConvert(object, new_capacity);
|
| - return AddFastElement(object, index, value);
|
| - }
|
| -
|
| - // If the array is growing, and it's not growth by a single element at the
|
| - // end, make sure that the ElementsKind is HOLEY.
|
| - if (introduces_holes && !object->HasFastHoleyElements()) {
|
| - ElementsKind transitioned_kind =
|
| - GetHoleyElementsKind(object->GetElementsKind());
|
| - TransitionElementsKind(object, transitioned_kind);
|
| - }
|
| + ElementsKind to_kind = value->OptimalElementsKind();
|
| + if (IsHoleyElementsKind(from_kind)) to_kind = GetHoleyElementsKind(to_kind);
|
| + to_kind = IsMoreGeneralElementsKindTransition(from_kind, to_kind) ? to_kind
|
| + : from_kind;
|
| + if (introduces_holes) to_kind = GetHoleyElementsKind(to_kind);
|
| + ElementsAccessor* accessor = ElementsAccessor::ForKind(to_kind);
|
|
|
| // Increase backing store capacity if that's been decided previously.
|
| - if (capacity != new_capacity) {
|
| - ElementsAccessor* accessor = object->GetElementsAccessor();
|
| + if (capacity != new_capacity || IsDictionaryElementsKind(from_kind) ||
|
| + IsFastDoubleElementsKind(from_kind) !=
|
| + IsFastDoubleElementsKind(to_kind)) {
|
| accessor->GrowCapacityAndConvert(object, new_capacity);
|
| + } else if (from_kind != to_kind) {
|
| + JSObject::TransitionElementsKind(object, to_kind);
|
| }
|
|
|
| - if (must_update_array_length) {
|
| - Handle<JSArray>::cast(object)->set_length(Smi::FromInt(array_length));
|
| + if (object->IsJSArray() && index >= array_length) {
|
| + Handle<JSArray>::cast(object)->set_length(Smi::FromInt(index + 1));
|
| }
|
|
|
| - FixedDoubleArray::cast(object->elements())->set(index, value->Number());
|
| -}
|
| -
|
| -
|
| -// static
|
| -MaybeHandle<Object> JSReceiver::SetElement(Handle<JSReceiver> object,
|
| - uint32_t index, Handle<Object> value,
|
| - LanguageMode language_mode) {
|
| - Isolate* isolate = object->GetIsolate();
|
| - LookupIterator it(isolate, object, index);
|
| - return SetProperty(&it, value, language_mode, MAY_BE_STORE_FROM_KEYED);
|
| + accessor->Set(object->elements(), index, *value);
|
| }
|
|
|
|
|
| // static
|
| -MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> receiver,
|
| +MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> object,
|
| uint32_t index,
|
| Handle<Object> value,
|
| PropertyAttributes attributes) {
|
| - DCHECK(receiver->map()->is_extensible());
|
| + DCHECK(object->map()->is_extensible());
|
|
|
| - Isolate* isolate = receiver->GetIsolate();
|
| + Isolate* isolate = object->GetIsolate();
|
|
|
| // TODO(verwaest): Use ElementAccessor.
|
| Handle<Object> old_length_handle;
|
| - if (receiver->IsJSArray() && receiver->map()->is_observed()) {
|
| - old_length_handle = handle(JSArray::cast(*receiver)->length(), isolate);
|
| - }
|
| -
|
| - if (attributes != NONE) {
|
| - Handle<SeededNumberDictionary> d = JSObject::NormalizeElements(receiver);
|
| - // TODO(verwaest): Move this into NormalizeElements.
|
| - d->set_requires_slow_elements();
|
| + if (object->IsJSArray() && object->map()->is_observed()) {
|
| + old_length_handle = handle(JSArray::cast(*object)->length(), isolate);
|
| + }
|
| +
|
| + ElementsKind kind = object->GetElementsKind();
|
| + bool handle_slow = false;
|
| + uint32_t capacity = 0;
|
| + uint32_t new_capacity = 0;
|
| + if (IsFastElementsKind(kind) || object->HasFastArgumentsElements()) {
|
| + if (attributes != NONE) {
|
| + // TODO(verwaest): Move set_requires_slow_elements into NormalizeElements.
|
| + NormalizeElements(object)->set_requires_slow_elements();
|
| + handle_slow = true;
|
| + } else {
|
| + if (IsSloppyArgumentsElements(kind)) {
|
| + FixedArray* parameter_map = FixedArray::cast(object->elements());
|
| + FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
|
| + capacity = static_cast<uint32_t>(arguments->length());
|
| + } else {
|
| + if (IsFastSmiOrObjectElementsKind(kind)) {
|
| + EnsureWritableFastElements(object);
|
| + }
|
| + capacity = static_cast<uint32_t>(object->elements()->length());
|
| + }
|
| +
|
| + new_capacity = capacity;
|
| + // Check if the capacity of the backing store needs to be increased, or if
|
| + // a transition to slow elements is necessary.
|
| + if (index >= capacity) {
|
| + handle_slow = true;
|
| + if ((index - capacity) < kMaxGap) {
|
| + new_capacity = NewElementsCapacity(index + 1);
|
| + DCHECK_LT(index, new_capacity);
|
| + handle_slow = object->ShouldConvertToSlowElements(new_capacity);
|
| + }
|
| + if (handle_slow) NormalizeElements(object);
|
| + }
|
| + }
|
| + } else {
|
| + handle_slow = true;
|
| }
|
|
|
| - Handle<Object> result = value;
|
| -
|
| - switch (receiver->GetElementsKind()) {
|
| - case FAST_SMI_ELEMENTS:
|
| - case FAST_ELEMENTS:
|
| - case FAST_HOLEY_SMI_ELEMENTS:
|
| - case FAST_HOLEY_ELEMENTS:
|
| - AddFastElement(receiver, index, value);
|
| - break;
|
| - case FAST_DOUBLE_ELEMENTS:
|
| - case FAST_HOLEY_DOUBLE_ELEMENTS:
|
| - AddFastDoubleElement(receiver, index, value);
|
| - break;
|
| -
|
| - case DICTIONARY_ELEMENTS:
|
| - AddDictionaryElement(receiver, index, value, attributes);
|
| - break;
|
| - case SLOPPY_ARGUMENTS_ELEMENTS:
|
| - AddSloppyArgumentsElement(receiver, index, value, attributes);
|
| - break;
|
| -
|
| -// Elements cannot be added to typed arrays.
|
| -#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
|
| - UNREACHABLE();
|
| - break;
|
| + if (handle_slow) {
|
| + DCHECK(object->HasDictionaryElements() ||
|
| + object->HasDictionaryArgumentsElements());
|
| + AddDictionaryElement(object, index, value, attributes);
|
| + } else {
|
| + AddFastElement(object, index, value, kind, capacity, new_capacity);
|
| }
|
|
|
| if (!old_length_handle.is_null() &&
|
| - !old_length_handle->SameValue(
|
| - Handle<JSArray>::cast(receiver)->length())) {
|
| - // |old_length_handle| is kept null above unless the receiver is observed.
|
| - DCHECK(receiver->map()->is_observed());
|
| - Handle<JSArray> array = Handle<JSArray>::cast(receiver);
|
| + !old_length_handle->SameValue(Handle<JSArray>::cast(object)->length())) {
|
| + // |old_length_handle| is kept null above unless the object is observed.
|
| + DCHECK(object->map()->is_observed());
|
| + Handle<JSArray> array = Handle<JSArray>::cast(object);
|
| Handle<String> name = isolate->factory()->Uint32ToString(index);
|
| Handle<Object> new_length_handle(array->length(), isolate);
|
| uint32_t old_length = 0;
|
| @@ -12769,28 +12635,28 @@ MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> receiver,
|
|
|
| RETURN_ON_EXCEPTION(isolate, BeginPerformSplice(array), Object);
|
| RETURN_ON_EXCEPTION(
|
| - isolate, JSObject::EnqueueChangeRecord(
|
| - array, "add", name, isolate->factory()->the_hole_value()),
|
| - Object);
|
| - RETURN_ON_EXCEPTION(
|
| - isolate, JSObject::EnqueueChangeRecord(
|
| - array, "update", isolate->factory()->length_string(),
|
| - old_length_handle),
|
| + isolate, EnqueueChangeRecord(array, "add", name,
|
| + isolate->factory()->the_hole_value()),
|
| Object);
|
| + RETURN_ON_EXCEPTION(isolate,
|
| + EnqueueChangeRecord(array, "update",
|
| + isolate->factory()->length_string(),
|
| + old_length_handle),
|
| + Object);
|
| RETURN_ON_EXCEPTION(isolate, EndPerformSplice(array), Object);
|
| Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
|
| RETURN_ON_EXCEPTION(isolate, EnqueueSpliceRecord(array, old_length, deleted,
|
| new_length - old_length),
|
| Object);
|
| - } else if (receiver->map()->is_observed()) {
|
| + } else if (object->map()->is_observed()) {
|
| Handle<String> name = isolate->factory()->Uint32ToString(index);
|
| - RETURN_ON_EXCEPTION(isolate, JSObject::EnqueueChangeRecord(
|
| - receiver, "add", name,
|
| + RETURN_ON_EXCEPTION(
|
| + isolate, EnqueueChangeRecord(object, "add", name,
|
| isolate->factory()->the_hole_value()),
|
| - Object);
|
| + Object);
|
| }
|
|
|
| - return result;
|
| + return value;
|
| }
|
|
|
|
|
|
|