Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index f2d617b8298e93d45d9dfb580f8549a7bfbfb0fa..86a3343ca6b9e0b405422530c09bc2c11fed2428 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -3389,7 +3389,10 @@ MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it, |
} |
} |
- return JSObject::AddDataElement(receiver, it->index(), value, attributes); |
+ MaybeHandle<Object> result = |
+ JSObject::AddDataElement(receiver, it->index(), value, attributes); |
+ JSObject::ValidateElements(receiver); |
+ return result; |
} else { |
// Migrate to the most up-to-date map that will be able to store |value| |
// under it->name() with |attributes|. |
@@ -11802,89 +11805,6 @@ void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT |
#endif // ENABLE_DISASSEMBLER |
-Handle<FixedArray> JSObject::SetFastElementsCapacity( |
- Handle<JSObject> object, int capacity, |
- SetFastElementsCapacitySmiMode smi_mode) { |
- // We should never end in here with a pixel or external array. |
- DCHECK(!object->HasExternalArrayElements()); |
- |
- // Allocate a new fast elements backing store. |
- Isolate* isolate = object->GetIsolate(); |
- Handle<FixedArray> new_elements = |
- isolate->factory()->NewUninitializedFixedArray(capacity); |
- |
- isolate->UpdateArrayProtectorOnSetLength(object); |
- |
- ElementsKind elements_kind = object->GetElementsKind(); |
- ElementsKind new_elements_kind; |
- // The resized array has FAST_*_SMI_ELEMENTS if the capacity mode forces it, |
- // or if it's allowed and the old elements array contained only SMIs. |
- bool has_fast_smi_elements = |
- (smi_mode == kForceSmiElements) || |
- ((smi_mode == kAllowSmiElements) && object->HasFastSmiElements()); |
- if (has_fast_smi_elements) { |
- if (IsHoleyElementsKind(elements_kind)) { |
- new_elements_kind = FAST_HOLEY_SMI_ELEMENTS; |
- } else { |
- new_elements_kind = FAST_SMI_ELEMENTS; |
- } |
- } else { |
- if (IsHoleyElementsKind(elements_kind)) { |
- new_elements_kind = FAST_HOLEY_ELEMENTS; |
- } else { |
- new_elements_kind = FAST_ELEMENTS; |
- } |
- } |
- Handle<FixedArrayBase> old_elements(object->elements()); |
- ElementsAccessor* accessor = ElementsAccessor::ForKind(new_elements_kind); |
- accessor->CopyElements(object, new_elements, elements_kind); |
- |
- if (elements_kind == SLOPPY_ARGUMENTS_ELEMENTS) { |
- Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(old_elements); |
- parameter_map->set(1, *new_elements); |
- } else { |
- Handle<Map> new_map = (new_elements_kind != elements_kind) |
- ? GetElementsTransitionMap(object, new_elements_kind) |
- : handle(object->map()); |
- JSObject::ValidateElements(object); |
- JSObject::SetMapAndElements(object, new_map, new_elements); |
- |
- // Transition through the allocation site as well if present. |
- JSObject::UpdateAllocationSite(object, new_elements_kind); |
- } |
- |
- if (FLAG_trace_elements_transitions) { |
- PrintElementsTransition(stdout, object, elements_kind, old_elements, |
- object->GetElementsKind(), new_elements); |
- } |
- |
- return new_elements; |
-} |
- |
- |
-Handle<FixedArray> JSObject::SetFastElementsCapacityAndLength( |
- Handle<JSObject> object, int capacity, int length, |
- SetFastElementsCapacitySmiMode smi_mode) { |
- Handle<FixedArray> new_elements = |
- SetFastElementsCapacity(object, capacity, smi_mode); |
- if (object->IsJSArray()) { |
- Handle<JSArray>::cast(object)->set_length(Smi::FromInt(length)); |
- } |
- return new_elements; |
-} |
- |
- |
-void JSObject::SetFastDoubleElementsCapacityAndLength(Handle<JSObject> object, |
- int capacity, |
- int length) { |
- ElementsAccessor* accessor = ElementsAccessor::ForKind(FAST_DOUBLE_ELEMENTS); |
- accessor->GrowCapacityAndConvert(object, capacity); |
- if (object->IsJSArray()) { |
- Handle<JSArray>::cast(object)->set_length(Smi::FromInt(length)); |
- } |
-} |
- |
- |
// static |
void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) { |
DCHECK(capacity >= 0); |
@@ -12438,28 +12358,20 @@ void JSObject::AddFastElement(Handle<JSObject> object, uint32_t index, |
DCHECK(object->HasFastSmiOrObjectElements() || |
object->HasFastArgumentsElements()); |
- Isolate* isolate = object->GetIsolate(); |
- |
Handle<FixedArray> backing_store(FixedArray::cast(object->elements())); |
if (object->HasSloppyArgumentsElements()) { |
backing_store = handle(FixedArray::cast(backing_store->get(1))); |
} else { |
- // Array optimizations rely on the prototype lookups of Array objects always |
- // returning undefined. If there is a store to the initial prototype object, |
- // make sure all of these optimizations are invalidated. |
- isolate->UpdateArrayProtectorOnSetElement(object); |
backing_store = EnsureWritableFastElements(object); |
} |
uint32_t capacity = static_cast<uint32_t>(backing_store->length()); |
- uint32_t new_capacity = 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()) { |
- CHECK( |
- Handle<JSArray>::cast(object)->length()->ToArrayLength(&array_length)); |
+ CHECK(JSArray::cast(*object)->length()->ToArrayLength(&array_length)); |
introduces_holes = index > array_length; |
if (index >= array_length) { |
must_update_array_length = true; |
@@ -12469,24 +12381,15 @@ void JSObject::AddFastElement(Handle<JSObject> object, uint32_t index, |
introduces_holes = index >= capacity; |
} |
- // 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 && !IsFastHoleyElementsKind(object->GetElementsKind())) { |
- ElementsKind transitioned_kind = |
- GetHoleyElementsKind(object->GetElementsKind()); |
- TransitionElementsKind(object, transitioned_kind); |
- } |
- |
+ 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(new_capacity > index); |
- if (!object->ShouldConvertToSlowElements(new_capacity)) { |
- convert_to_slow = false; |
- } |
+ DCHECK_LT(index, new_capacity); |
+ convert_to_slow = object->ShouldConvertToSlowElements(new_capacity); |
} |
if (convert_to_slow) { |
NormalizeElements(object); |
@@ -12498,50 +12401,50 @@ void JSObject::AddFastElement(Handle<JSObject> object, uint32_t index, |
if (object->HasFastSmiElements() && !value->IsSmi()) { |
// Convert to fast double elements if appropriate. |
if (value->IsNumber()) { |
- // Consider fixing the boilerplate as well if we have one. |
- ElementsKind to_kind = IsHoleyElementsKind(object->GetElementsKind()) |
- ? FAST_HOLEY_DOUBLE_ELEMENTS |
- : FAST_DOUBLE_ELEMENTS; |
- |
- UpdateAllocationSite(object, to_kind); |
- |
- SetFastDoubleElementsCapacityAndLength(object, new_capacity, |
- array_length); |
- FixedDoubleArray::cast(object->elements())->set(index, value->Number()); |
- JSObject::ValidateElements(object); |
+ 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 = object->HasFastHoleyElements() |
- ? FAST_HOLEY_ELEMENTS |
- : FAST_ELEMENTS; |
+ 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. |
- // Otherwise, set the new element and length. |
- if (new_capacity == capacity) { |
- DCHECK(object->elements()->IsFixedArray()); |
- backing_store->set(index, *value); |
- if (must_update_array_length) { |
- Handle<JSArray>::cast(object)->set_length(Smi::FromInt(array_length)); |
- } |
- } else { |
- SetFastElementsCapacitySmiMode smi_mode = |
- value->IsSmi() && object->HasFastSmiElements() |
- ? kAllowSmiElements |
- : kDontAllowSmiElements; |
- Handle<FixedArray> new_elements = |
- SetFastElementsCapacityAndLength(object, new_capacity, array_length, |
- smi_mode); |
- new_elements->set(index, *value); |
- JSObject::ValidateElements(object); |
+ if (capacity != new_capacity) { |
+ DCHECK(!object->HasFastDoubleElements()); |
+ ElementsAccessor* accessor = |
+ value->IsSmi() || object->HasSloppyArgumentsElements() |
+ ? object->GetElementsAccessor() |
+ : ElementsAccessor::ForKind(FAST_ELEMENTS); |
+ accessor->GrowCapacityAndConvert(object, new_capacity); |
} |
+ |
+ 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)); |
+ } |
+ elements->set(index, *value); |
} |
@@ -12701,19 +12604,9 @@ void JSObject::AddDictionaryElement(Handle<JSObject> object, uint32_t index, |
} else { |
new_length = dictionary->max_number_key() + 1; |
} |
- bool has_smi_only_elements = false; |
- bool should_convert_to_fast_double_elements = |
- object->ShouldConvertToFastDoubleElements(&has_smi_only_elements); |
- SetFastElementsCapacitySmiMode smi_mode = |
- has_smi_only_elements ? kForceSmiElements : kAllowSmiElements; |
- |
- if (should_convert_to_fast_double_elements) { |
- SetFastDoubleElementsCapacityAndLength(object, new_length, new_length); |
- } else { |
- SetFastElementsCapacityAndLength(object, new_length, new_length, |
- smi_mode); |
- } |
- JSObject::ValidateElements(object); |
+ ElementsKind to_kind = object->BestFittingFastElementsKind(); |
+ ElementsAccessor* accessor = ElementsAccessor::ForKind(to_kind); |
+ accessor->GrowCapacityAndConvert(object, new_length); |
#ifdef DEBUG |
if (FLAG_trace_normalization) { |
OFStream os(stdout); |
@@ -12730,72 +12623,70 @@ void JSObject::AddFastDoubleElement(Handle<JSObject> object, uint32_t index, |
DCHECK(object->HasFastDoubleElements()); |
Handle<FixedArrayBase> base_elms(FixedArrayBase::cast(object->elements())); |
- uint32_t elms_length = static_cast<uint32_t>(base_elms->length()); |
- uint32_t length = elms_length; |
+ uint32_t capacity = static_cast<uint32_t>(base_elms->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()) { |
// In case of JSArray, the length does not equal the capacity. |
- CHECK(Handle<JSArray>::cast(object)->length()->ToArrayLength(&length)); |
- introduces_holes = index > length; |
+ 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 >= elms_length; |
+ 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()) { |
- SetFastElementsCapacityAndLength(object, elms_length, length, |
- kDontAllowSmiElements); |
- AddFastElement(object, index, value); |
- return; |
+ 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 && !IsFastHoleyElementsKind(object->GetElementsKind())) { |
- ElementsKind transitioned_kind = FAST_HOLEY_DOUBLE_ELEMENTS; |
+ if (introduces_holes && !object->HasFastHoleyElements()) { |
+ ElementsKind transitioned_kind = |
+ GetHoleyElementsKind(object->GetElementsKind()); |
TransitionElementsKind(object, transitioned_kind); |
} |
- // Check whether there is extra space in the fixed array. |
- if (index < elms_length) { |
- Handle<FixedDoubleArray> elms(FixedDoubleArray::cast(object->elements())); |
- elms->set(index, value->Number()); |
- if (object->IsJSArray()) { |
- // Update the length of the array if needed. |
- uint32_t array_length = 0; |
- CHECK(Handle<JSArray>::cast(object)->length()->ToArrayLength( |
- &array_length)); |
- if (index >= array_length) { |
- Handle<JSArray>::cast(object)->set_length(Smi::FromInt(index + 1)); |
- } |
- } |
- return; |
+ // Increase backing store capacity if that's been decided previously. |
+ if (capacity != new_capacity) { |
+ ElementsAccessor* accessor = object->GetElementsAccessor(); |
+ accessor->GrowCapacityAndConvert(object, new_capacity); |
} |
- // Allow gap in fast case. |
- if ((index - elms_length) < kMaxGap) { |
- // Try allocating extra space. |
- int new_capacity = NewElementsCapacity(index+1); |
- if (!object->ShouldConvertToSlowElements(new_capacity)) { |
- DCHECK(static_cast<uint32_t>(new_capacity) > index); |
- SetFastDoubleElementsCapacityAndLength(object, new_capacity, index + 1); |
- FixedDoubleArray::cast(object->elements())->set(index, value->Number()); |
- JSObject::ValidateElements(object); |
- return; |
- } |
+ if (must_update_array_length) { |
+ Handle<JSArray>::cast(object)->set_length(Smi::FromInt(array_length)); |
} |
- // Otherwise default to slow case. |
- DCHECK(object->HasFastDoubleElements()); |
- DCHECK(object->map()->has_fast_double_elements()); |
- DCHECK(object->elements()->IsFixedDoubleArray() || |
- object->elements()->length() == 0); |
- |
- NormalizeElements(object); |
- DCHECK(object->HasDictionaryElements()); |
- AddDictionaryElement(object, index, value, NONE); |
+ FixedDoubleArray::cast(object->elements())->set(index, value->Number()); |
} |
@@ -13023,25 +12914,23 @@ void JSObject::UpdateAllocationSite(Handle<JSObject> object, |
void JSObject::TransitionElementsKind(Handle<JSObject> object, |
ElementsKind to_kind) { |
- ElementsKind from_kind = object->map()->elements_kind(); |
+ ElementsKind from_kind = object->GetElementsKind(); |
if (IsFastHoleyElementsKind(from_kind)) { |
to_kind = GetHoleyElementsKind(to_kind); |
} |
if (from_kind == to_kind) return; |
- // Don't update the site if to_kind isn't fast |
- if (IsFastElementsKind(to_kind)) { |
- UpdateAllocationSite(object, to_kind); |
- } |
- Isolate* isolate = object->GetIsolate(); |
- if (object->elements() == isolate->heap()->empty_fixed_array() || |
- (IsFastSmiOrObjectElementsKind(from_kind) && |
- IsFastSmiOrObjectElementsKind(to_kind)) || |
- (from_kind == FAST_DOUBLE_ELEMENTS && |
- to_kind == FAST_HOLEY_DOUBLE_ELEMENTS)) { |
- DCHECK(from_kind != TERMINAL_FAST_ELEMENTS_KIND); |
+ // This method should never be called for any other case. |
+ DCHECK(IsFastElementsKind(from_kind)); |
+ DCHECK(IsFastElementsKind(to_kind)); |
+ DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind); |
+ |
+ UpdateAllocationSite(object, to_kind); |
+ if (object->elements() == object->GetHeap()->empty_fixed_array() || |
+ IsFastDoubleElementsKind(from_kind) == |
+ IsFastDoubleElementsKind(to_kind)) { |
// No change is needed to the elements() buffer, the transition |
// only requires a map change. |
Handle<Map> new_map = GetElementsTransitionMap(object, to_kind); |
@@ -13050,42 +12939,14 @@ void JSObject::TransitionElementsKind(Handle<JSObject> object, |
Handle<FixedArrayBase> elms(object->elements()); |
PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms); |
} |
- return; |
- } |
- |
- Handle<FixedArrayBase> elms(object->elements()); |
- uint32_t capacity = static_cast<uint32_t>(elms->length()); |
- uint32_t length = capacity; |
- |
- if (object->IsJSArray()) { |
- Object* raw_length = Handle<JSArray>::cast(object)->length(); |
- if (raw_length->IsUndefined()) { |
- // If length is undefined, then JSArray is being initialized and has no |
- // elements, assume a length of zero. |
- length = 0; |
- } else { |
- CHECK(raw_length->ToArrayLength(&length)); |
- } |
- } |
- |
- if (IsFastSmiElementsKind(from_kind) && |
- IsFastDoubleElementsKind(to_kind)) { |
- SetFastDoubleElementsCapacityAndLength(object, capacity, length); |
- JSObject::ValidateElements(object); |
- return; |
- } |
- |
- if (IsFastDoubleElementsKind(from_kind) && |
- IsFastObjectElementsKind(to_kind)) { |
- SetFastElementsCapacityAndLength(object, capacity, length, |
- kDontAllowSmiElements); |
- JSObject::ValidateElements(object); |
- return; |
+ } else { |
+ DCHECK((IsFastSmiElementsKind(from_kind) && |
+ IsFastDoubleElementsKind(to_kind)) || |
+ (IsFastDoubleElementsKind(from_kind) && |
+ IsFastObjectElementsKind(to_kind))); |
+ uint32_t c = static_cast<uint32_t>(object->elements()->length()); |
+ ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c); |
} |
- |
- // This method should never be called for any other case than the ones |
- // handled above. |
- UNREACHABLE(); |
} |
@@ -13300,29 +13161,23 @@ bool JSObject::ShouldConvertToFastElements() { |
} |
-bool JSObject::ShouldConvertToFastDoubleElements( |
- bool* has_smi_only_elements) { |
- *has_smi_only_elements = false; |
- if (HasSloppyArgumentsElements()) return false; |
- if (FLAG_unbox_double_arrays) { |
- DCHECK(HasDictionaryElements()); |
- SeededNumberDictionary* dictionary = element_dictionary(); |
- bool found_double = false; |
- for (int i = 0; i < dictionary->Capacity(); i++) { |
- Object* key = dictionary->KeyAt(i); |
- if (key->IsNumber()) { |
- Object* value = dictionary->ValueAt(i); |
- if (!value->IsNumber()) return false; |
- if (!value->IsSmi()) { |
- found_double = true; |
- } |
+ElementsKind JSObject::BestFittingFastElementsKind() { |
+ if (HasSloppyArgumentsElements()) return FAST_HOLEY_ELEMENTS; |
+ DCHECK(HasDictionaryElements()); |
+ SeededNumberDictionary* dictionary = element_dictionary(); |
+ ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS; |
+ for (int i = 0; i < dictionary->Capacity(); i++) { |
+ Object* key = dictionary->KeyAt(i); |
+ if (key->IsNumber()) { |
+ Object* value = dictionary->ValueAt(i); |
+ if (!value->IsNumber()) return FAST_HOLEY_ELEMENTS; |
+ if (!value->IsSmi()) { |
+ if (!FLAG_unbox_double_arrays) return FAST_HOLEY_ELEMENTS; |
+ kind = FAST_HOLEY_DOUBLE_ELEMENTS; |
} |
} |
- *has_smi_only_elements = !found_double; |
- return found_double; |
- } else { |
- return false; |
} |
+ return kind; |
} |