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; |
} |