Commit 046e91dd authored by verwaest's avatar verwaest Committed by Commit bot

Move SetFastElementsCapacity into GrowCapacityAndConvert

BUG=v8:4137
LOG=n

Review URL: https://codereview.chromium.org/1197133003

Cr-Commit-Position: refs/heads/master@{#29222}
parent 22b691ba
...@@ -544,6 +544,7 @@ void ArrayLiteral::BuildConstantElements(Isolate* isolate) { ...@@ -544,6 +544,7 @@ void ArrayLiteral::BuildConstantElements(Isolate* isolate) {
if (array_index != values()->length()) { if (array_index != values()->length()) {
JSArray::SetLength(array, array_index); JSArray::SetLength(array, array_index);
} }
JSObject::ValidateElements(array);
Handle<FixedArrayBase> element_values(array->elements()); Handle<FixedArrayBase> element_values(array->elements());
// Simple and shallow arrays can be lazily copied, we transform the // Simple and shallow arrays can be lazily copied, we transform the
......
...@@ -556,7 +556,7 @@ class ElementsAccessorBase : public ElementsAccessor { ...@@ -556,7 +556,7 @@ class ElementsAccessorBase : public ElementsAccessor {
typedef ElementsTraitsParam ElementsTraits; typedef ElementsTraitsParam ElementsTraits;
typedef typename ElementsTraitsParam::BackingStore BackingStore; typedef typename ElementsTraitsParam::BackingStore BackingStore;
ElementsKind kind() const final { return ElementsTraits::Kind; } static ElementsKind kind() { return ElementsTraits::Kind; }
static void ValidateContents(Handle<JSObject> holder, int length) { static void ValidateContents(Handle<JSObject> holder, int length) {
} }
...@@ -644,9 +644,59 @@ class ElementsAccessorBase : public ElementsAccessor { ...@@ -644,9 +644,59 @@ class ElementsAccessorBase : public ElementsAccessor {
static void SetLengthImpl(Handle<JSArray> array, uint32_t length, static void SetLengthImpl(Handle<JSArray> array, uint32_t length,
Handle<FixedArrayBase> backing_store); Handle<FixedArrayBase> backing_store);
static void GrowCapacityAndConvertImpl(Handle<JSObject> obj, static Handle<FixedArrayBase> ConvertElementsWithCapacity(
Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
ElementsKind from_kind, uint32_t capacity) {
Isolate* isolate = object->GetIsolate();
Handle<FixedArrayBase> elements;
if (IsFastDoubleElementsKind(kind())) {
elements = isolate->factory()->NewFixedDoubleArray(capacity);
} else {
elements = isolate->factory()->NewUninitializedFixedArray(capacity);
}
int packed = kPackedSizeNotKnown;
if (IsFastPackedElementsKind(from_kind) && object->IsJSArray()) {
packed = Smi::cast(JSArray::cast(*object)->length())->value();
}
ElementsAccessorSubclass::CopyElementsImpl(
*old_elements, 0, *elements, from_kind, 0, packed,
ElementsAccessor::kCopyToEndAndInitializeToHole);
return elements;
}
static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
uint32_t capacity) { uint32_t capacity) {
UNIMPLEMENTED(); ElementsKind from_kind = object->GetElementsKind();
if (IsFastSmiOrObjectElementsKind(from_kind)) {
// 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.
object->GetIsolate()->UpdateArrayProtectorOnSetLength(object);
}
Handle<FixedArrayBase> old_elements(object->elements());
// This method should only be called if there's a reason to update the
// elements.
DCHECK(IsFastDoubleElementsKind(from_kind) !=
IsFastDoubleElementsKind(kind()) ||
IsDictionaryElementsKind(from_kind) ||
static_cast<uint32_t>(old_elements->length()) < capacity);
Handle<FixedArrayBase> elements =
ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
ElementsKind to_kind = kind();
if (IsHoleyElementsKind(from_kind)) to_kind = GetHoleyElementsKind(to_kind);
Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, to_kind);
JSObject::SetMapAndElements(object, new_map, elements);
// Transition through the allocation site as well if present.
JSObject::UpdateAllocationSite(object, to_kind);
if (FLAG_trace_elements_transitions) {
JSObject::PrintElementsTransition(stdout, object, from_kind, old_elements,
to_kind, elements);
}
} }
virtual void GrowCapacityAndConvert(Handle<JSObject> object, virtual void GrowCapacityAndConvert(Handle<JSObject> object,
...@@ -1035,16 +1085,6 @@ class FastSmiOrObjectElementsAccessor ...@@ -1035,16 +1085,6 @@ class FastSmiOrObjectElementsAccessor
#undef TYPED_ARRAY_CASE #undef TYPED_ARRAY_CASE
} }
} }
static void GrowCapacityAndConvertImpl(Handle<JSObject> obj,
uint32_t capacity) {
JSObject::SetFastElementsCapacitySmiMode set_capacity_mode =
obj->HasFastSmiElements()
? JSObject::kAllowSmiElements
: JSObject::kDontAllowSmiElements;
JSObject::SetFastElementsCapacity(obj, capacity, set_capacity_mode);
}
}; };
...@@ -1105,34 +1145,6 @@ class FastDoubleElementsAccessor ...@@ -1105,34 +1145,6 @@ class FastDoubleElementsAccessor
: FastElementsAccessor<FastElementsAccessorSubclass, : FastElementsAccessor<FastElementsAccessorSubclass,
KindTraits>(name) {} KindTraits>(name) {}
static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
uint32_t capacity) {
Handle<FixedArrayBase> elements =
object->GetIsolate()->factory()->NewFixedDoubleArray(capacity);
ElementsKind from_kind = object->GetElementsKind();
ElementsKind to_kind = IsHoleyElementsKind(from_kind)
? FAST_HOLEY_DOUBLE_ELEMENTS
: FAST_DOUBLE_ELEMENTS;
Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, to_kind);
Handle<FixedArrayBase> old_elements(object->elements());
int packed = kPackedSizeNotKnown;
if (IsFastPackedElementsKind(from_kind) && object->IsJSArray()) {
packed = Smi::cast(JSArray::cast(*object)->length())->value();
}
CopyElementsImpl(*old_elements, 0, *elements, from_kind, 0, packed,
ElementsAccessor::kCopyToEndAndInitializeToHole);
JSObject::SetMapAndElements(object, new_map, elements);
JSObject::ValidateElements(object);
if (FLAG_trace_elements_transitions) {
JSObject::PrintElementsTransition(stdout, object, from_kind, old_elements,
to_kind, elements);
}
}
protected: protected:
static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start, static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
FixedArrayBase* to, ElementsKind from_kind, FixedArrayBase* to, ElementsKind from_kind,
...@@ -1494,6 +1506,22 @@ class SloppyArgumentsElementsAccessor : public ElementsAccessorBase< ...@@ -1494,6 +1506,22 @@ class SloppyArgumentsElementsAccessor : public ElementsAccessorBase<
} }
} }
static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
uint32_t capacity) {
Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
Handle<FixedArray> old_elements(FixedArray::cast(parameter_map->get(1)));
ElementsKind from_kind = old_elements->IsDictionary() ? DICTIONARY_ELEMENTS
: FAST_HOLEY_ELEMENTS;
// This method should only be called if there's a reason to update the
// elements.
DCHECK(IsDictionaryElementsKind(from_kind) ||
static_cast<uint32_t>(old_elements->length()) < capacity);
Handle<FixedArrayBase> elements =
ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
parameter_map->set(1, *elements);
JSObject::ValidateElements(object);
}
static void SetImpl(FixedArrayBase* store, uint32_t key, Object* value) { static void SetImpl(FixedArrayBase* store, uint32_t key, Object* value) {
FixedArray* parameter_map = FixedArray::cast(store); FixedArray* parameter_map = FixedArray::cast(store);
Object* probe = GetParameterMapArg(parameter_map, key); Object* probe = GetParameterMapArg(parameter_map, key);
...@@ -1556,7 +1584,15 @@ class SloppyArgumentsElementsAccessor : public ElementsAccessorBase< ...@@ -1556,7 +1584,15 @@ class SloppyArgumentsElementsAccessor : public ElementsAccessorBase<
FixedArrayBase* to, ElementsKind from_kind, FixedArrayBase* to, ElementsKind from_kind,
uint32_t to_start, int packed_size, uint32_t to_start, int packed_size,
int copy_size) { int copy_size) {
UNREACHABLE(); DCHECK(!to->IsDictionary());
if (from_kind == DICTIONARY_ELEMENTS) {
CopyDictionaryToObjectElements(from, from_start, to, FAST_HOLEY_ELEMENTS,
to_start, copy_size);
} else {
DCHECK_EQ(FAST_HOLEY_ELEMENTS, from_kind);
CopyObjectToObjectElements(from, from_kind, from_start, to,
FAST_HOLEY_ELEMENTS, to_start, copy_size);
}
} }
static uint32_t GetCapacityImpl(JSObject* holder, static uint32_t GetCapacityImpl(JSObject* holder,
......
...@@ -20,7 +20,6 @@ class ElementsAccessor { ...@@ -20,7 +20,6 @@ class ElementsAccessor {
explicit ElementsAccessor(const char* name) : name_(name) { } explicit ElementsAccessor(const char* name) : name_(name) { }
virtual ~ElementsAccessor() { } virtual ~ElementsAccessor() { }
virtual ElementsKind kind() const = 0;
const char* name() const { return name_; } const char* name() const { return name_; }
// Checks the elements of an object for consistency, asserting when a problem // Checks the elements of an object for consistency, asserting when a problem
......
...@@ -3389,7 +3389,10 @@ MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it, ...@@ -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 { } else {
// Migrate to the most up-to-date map that will be able to store |value| // Migrate to the most up-to-date map that will be able to store |value|
// under it->name() with |attributes|. // under it->name() with |attributes|.
...@@ -11802,89 +11805,6 @@ void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT ...@@ -11802,89 +11805,6 @@ void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT
#endif // ENABLE_DISASSEMBLER #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 // static
void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) { void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
DCHECK(capacity >= 0); DCHECK(capacity >= 0);
...@@ -12438,28 +12358,20 @@ void JSObject::AddFastElement(Handle<JSObject> object, uint32_t index, ...@@ -12438,28 +12358,20 @@ void JSObject::AddFastElement(Handle<JSObject> object, uint32_t index,
DCHECK(object->HasFastSmiOrObjectElements() || DCHECK(object->HasFastSmiOrObjectElements() ||
object->HasFastArgumentsElements()); object->HasFastArgumentsElements());
Isolate* isolate = object->GetIsolate();
Handle<FixedArray> backing_store(FixedArray::cast(object->elements())); Handle<FixedArray> backing_store(FixedArray::cast(object->elements()));
if (object->HasSloppyArgumentsElements()) { if (object->HasSloppyArgumentsElements()) {
backing_store = handle(FixedArray::cast(backing_store->get(1))); backing_store = handle(FixedArray::cast(backing_store->get(1)));
} else { } 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); backing_store = EnsureWritableFastElements(object);
} }
uint32_t capacity = static_cast<uint32_t>(backing_store->length()); 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. // Check if the length property of this object needs to be updated.
uint32_t array_length = 0; uint32_t array_length = 0;
bool must_update_array_length = false; bool must_update_array_length = false;
bool introduces_holes = true; bool introduces_holes = true;
if (object->IsJSArray()) { if (object->IsJSArray()) {
CHECK( CHECK(JSArray::cast(*object)->length()->ToArrayLength(&array_length));
Handle<JSArray>::cast(object)->length()->ToArrayLength(&array_length));
introduces_holes = index > array_length; introduces_holes = index > array_length;
if (index >= array_length) { if (index >= array_length) {
must_update_array_length = true; must_update_array_length = true;
...@@ -12469,24 +12381,15 @@ void JSObject::AddFastElement(Handle<JSObject> object, uint32_t index, ...@@ -12469,24 +12381,15 @@ void JSObject::AddFastElement(Handle<JSObject> object, uint32_t index,
introduces_holes = index >= capacity; introduces_holes = index >= capacity;
} }
// If the array is growing, and it's not growth by a single element at the uint32_t new_capacity = capacity;
// end, make sure that the ElementsKind is HOLEY.
if (introduces_holes && !IsFastHoleyElementsKind(object->GetElementsKind())) {
ElementsKind transitioned_kind =
GetHoleyElementsKind(object->GetElementsKind());
TransitionElementsKind(object, transitioned_kind);
}
// Check if the capacity of the backing store needs to be increased, or if // Check if the capacity of the backing store needs to be increased, or if
// a transition to slow elements is necessary. // a transition to slow elements is necessary.
if (index >= capacity) { if (index >= capacity) {
bool convert_to_slow = true; bool convert_to_slow = true;
if ((index - capacity) < kMaxGap) { if ((index - capacity) < kMaxGap) {
new_capacity = NewElementsCapacity(index + 1); new_capacity = NewElementsCapacity(index + 1);
DCHECK(new_capacity > index); DCHECK_LT(index, new_capacity);
if (!object->ShouldConvertToSlowElements(new_capacity)) { convert_to_slow = object->ShouldConvertToSlowElements(new_capacity);
convert_to_slow = false;
}
} }
if (convert_to_slow) { if (convert_to_slow) {
NormalizeElements(object); NormalizeElements(object);
...@@ -12498,50 +12401,50 @@ void JSObject::AddFastElement(Handle<JSObject> object, uint32_t index, ...@@ -12498,50 +12401,50 @@ void JSObject::AddFastElement(Handle<JSObject> object, uint32_t index,
if (object->HasFastSmiElements() && !value->IsSmi()) { if (object->HasFastSmiElements() && !value->IsSmi()) {
// Convert to fast double elements if appropriate. // Convert to fast double elements if appropriate.
if (value->IsNumber()) { if (value->IsNumber()) {
// Consider fixing the boilerplate as well if we have one. ElementsKind to_kind =
ElementsKind to_kind = IsHoleyElementsKind(object->GetElementsKind()) introduces_holes ? FAST_HOLEY_DOUBLE_ELEMENTS : FAST_DOUBLE_ELEMENTS;
? FAST_HOLEY_DOUBLE_ELEMENTS ElementsAccessor* accessor = ElementsAccessor::ForKind(to_kind);
: FAST_DOUBLE_ELEMENTS; accessor->GrowCapacityAndConvert(object, new_capacity);
AddFastDoubleElement(object, index, value);
UpdateAllocationSite(object, to_kind);
SetFastDoubleElementsCapacityAndLength(object, new_capacity,
array_length);
FixedDoubleArray::cast(object->elements())->set(index, value->Number());
JSObject::ValidateElements(object);
return; return;
} }
// Change elements kind from Smi-only to generic FAST if necessary. // Change elements kind from Smi-only to generic FAST if necessary.
ElementsKind kind = object->HasFastHoleyElements() ElementsKind kind = introduces_holes || object->HasFastHoleyElements()
? FAST_HOLEY_ELEMENTS ? FAST_HOLEY_ELEMENTS
: FAST_ELEMENTS; : FAST_ELEMENTS;
UpdateAllocationSite(object, kind); UpdateAllocationSite(object, kind);
Handle<Map> new_map = GetElementsTransitionMap(object, kind); Handle<Map> new_map = GetElementsTransitionMap(object, kind);
JSObject::MigrateToMap(object, new_map); JSObject::MigrateToMap(object, new_map);
DCHECK(IsFastObjectElementsKind(object->GetElementsKind())); 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. // Increase backing store capacity if that's been decided previously.
// Otherwise, set the new element and length. if (capacity != new_capacity) {
if (new_capacity == capacity) { DCHECK(!object->HasFastDoubleElements());
DCHECK(object->elements()->IsFixedArray()); ElementsAccessor* accessor =
backing_store->set(index, *value); value->IsSmi() || object->HasSloppyArgumentsElements()
if (must_update_array_length) { ? object->GetElementsAccessor()
Handle<JSArray>::cast(object)->set_length(Smi::FromInt(array_length)); : ElementsAccessor::ForKind(FAST_ELEMENTS);
} accessor->GrowCapacityAndConvert(object, new_capacity);
} 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 (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, ...@@ -12701,19 +12604,9 @@ void JSObject::AddDictionaryElement(Handle<JSObject> object, uint32_t index,
} else { } else {
new_length = dictionary->max_number_key() + 1; new_length = dictionary->max_number_key() + 1;
} }
bool has_smi_only_elements = false; ElementsKind to_kind = object->BestFittingFastElementsKind();
bool should_convert_to_fast_double_elements = ElementsAccessor* accessor = ElementsAccessor::ForKind(to_kind);
object->ShouldConvertToFastDoubleElements(&has_smi_only_elements); accessor->GrowCapacityAndConvert(object, new_length);
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);
#ifdef DEBUG #ifdef DEBUG
if (FLAG_trace_normalization) { if (FLAG_trace_normalization) {
OFStream os(stdout); OFStream os(stdout);
...@@ -12730,72 +12623,70 @@ void JSObject::AddFastDoubleElement(Handle<JSObject> object, uint32_t index, ...@@ -12730,72 +12623,70 @@ void JSObject::AddFastDoubleElement(Handle<JSObject> object, uint32_t index,
DCHECK(object->HasFastDoubleElements()); DCHECK(object->HasFastDoubleElements());
Handle<FixedArrayBase> base_elms(FixedArrayBase::cast(object->elements())); Handle<FixedArrayBase> base_elms(FixedArrayBase::cast(object->elements()));
uint32_t elms_length = static_cast<uint32_t>(base_elms->length()); uint32_t capacity = static_cast<uint32_t>(base_elms->length());
uint32_t length = 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; bool introduces_holes = true;
if (object->IsJSArray()) { if (object->IsJSArray()) {
// In case of JSArray, the length does not equal the capacity. // In case of JSArray, the length does not equal the capacity.
CHECK(Handle<JSArray>::cast(object)->length()->ToArrayLength(&length)); CHECK(JSArray::cast(*object)->length()->ToArrayLength(&array_length));
introduces_holes = index > length; introduces_holes = index > array_length;
if (index >= array_length) {
must_update_array_length = true;
array_length = index + 1;
}
} else { } 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 // If the value object is not a heap number, switch to fast elements and try
// again. // again.
if (!value->IsNumber()) { if (!value->IsNumber()) {
SetFastElementsCapacityAndLength(object, elms_length, length, ElementsKind to_kind =
kDontAllowSmiElements); introduces_holes ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS;
AddFastElement(object, index, value); ElementsAccessor* accessor = ElementsAccessor::ForKind(to_kind);
return; 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 // If the array is growing, and it's not growth by a single element at the
// end, make sure that the ElementsKind is HOLEY. // end, make sure that the ElementsKind is HOLEY.
if (introduces_holes && !IsFastHoleyElementsKind(object->GetElementsKind())) { if (introduces_holes && !object->HasFastHoleyElements()) {
ElementsKind transitioned_kind = FAST_HOLEY_DOUBLE_ELEMENTS; ElementsKind transitioned_kind =
GetHoleyElementsKind(object->GetElementsKind());
TransitionElementsKind(object, transitioned_kind); TransitionElementsKind(object, transitioned_kind);
} }
// Check whether there is extra space in the fixed array. // Increase backing store capacity if that's been decided previously.
if (index < elms_length) { if (capacity != new_capacity) {
Handle<FixedDoubleArray> elms(FixedDoubleArray::cast(object->elements())); ElementsAccessor* accessor = object->GetElementsAccessor();
elms->set(index, value->Number()); accessor->GrowCapacityAndConvert(object, new_capacity);
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;
} }
// Allow gap in fast case. if (must_update_array_length) {
if ((index - elms_length) < kMaxGap) { Handle<JSArray>::cast(object)->set_length(Smi::FromInt(array_length));
// 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;
}
} }
// Otherwise default to slow case. FixedDoubleArray::cast(object->elements())->set(index, value->Number());
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);
} }
...@@ -13023,25 +12914,23 @@ void JSObject::UpdateAllocationSite(Handle<JSObject> object, ...@@ -13023,25 +12914,23 @@ void JSObject::UpdateAllocationSite(Handle<JSObject> object,
void JSObject::TransitionElementsKind(Handle<JSObject> object, void JSObject::TransitionElementsKind(Handle<JSObject> object,
ElementsKind to_kind) { ElementsKind to_kind) {
ElementsKind from_kind = object->map()->elements_kind(); ElementsKind from_kind = object->GetElementsKind();
if (IsFastHoleyElementsKind(from_kind)) { if (IsFastHoleyElementsKind(from_kind)) {
to_kind = GetHoleyElementsKind(to_kind); to_kind = GetHoleyElementsKind(to_kind);
} }
if (from_kind == to_kind) return; 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(); // This method should never be called for any other case.
if (object->elements() == isolate->heap()->empty_fixed_array() || DCHECK(IsFastElementsKind(from_kind));
(IsFastSmiOrObjectElementsKind(from_kind) && DCHECK(IsFastElementsKind(to_kind));
IsFastSmiOrObjectElementsKind(to_kind)) || DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind);
(from_kind == FAST_DOUBLE_ELEMENTS &&
to_kind == FAST_HOLEY_DOUBLE_ELEMENTS)) { UpdateAllocationSite(object, to_kind);
DCHECK(from_kind != TERMINAL_FAST_ELEMENTS_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 // No change is needed to the elements() buffer, the transition
// only requires a map change. // only requires a map change.
Handle<Map> new_map = GetElementsTransitionMap(object, to_kind); Handle<Map> new_map = GetElementsTransitionMap(object, to_kind);
...@@ -13050,42 +12939,14 @@ void JSObject::TransitionElementsKind(Handle<JSObject> object, ...@@ -13050,42 +12939,14 @@ void JSObject::TransitionElementsKind(Handle<JSObject> object,
Handle<FixedArrayBase> elms(object->elements()); Handle<FixedArrayBase> elms(object->elements());
PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms); PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms);
} }
return; } else {
} DCHECK((IsFastSmiElementsKind(from_kind) &&
IsFastDoubleElementsKind(to_kind)) ||
Handle<FixedArrayBase> elms(object->elements()); (IsFastDoubleElementsKind(from_kind) &&
uint32_t capacity = static_cast<uint32_t>(elms->length()); IsFastObjectElementsKind(to_kind)));
uint32_t length = capacity; uint32_t c = static_cast<uint32_t>(object->elements()->length());
ElementsAccessor::ForKind(to_kind)->GrowCapacityAndConvert(object, c);
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;
} }
// This method should never be called for any other case than the ones
// handled above.
UNREACHABLE();
} }
...@@ -13300,29 +13161,23 @@ bool JSObject::ShouldConvertToFastElements() { ...@@ -13300,29 +13161,23 @@ bool JSObject::ShouldConvertToFastElements() {
} }
bool JSObject::ShouldConvertToFastDoubleElements( ElementsKind JSObject::BestFittingFastElementsKind() {
bool* has_smi_only_elements) { if (HasSloppyArgumentsElements()) return FAST_HOLEY_ELEMENTS;
*has_smi_only_elements = false; DCHECK(HasDictionaryElements());
if (HasSloppyArgumentsElements()) return false; SeededNumberDictionary* dictionary = element_dictionary();
if (FLAG_unbox_double_arrays) { ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS;
DCHECK(HasDictionaryElements()); for (int i = 0; i < dictionary->Capacity(); i++) {
SeededNumberDictionary* dictionary = element_dictionary(); Object* key = dictionary->KeyAt(i);
bool found_double = false; if (key->IsNumber()) {
for (int i = 0; i < dictionary->Capacity(); i++) { Object* value = dictionary->ValueAt(i);
Object* key = dictionary->KeyAt(i); if (!value->IsNumber()) return FAST_HOLEY_ELEMENTS;
if (key->IsNumber()) { if (!value->IsSmi()) {
Object* value = dictionary->ValueAt(i); if (!FLAG_unbox_double_arrays) return FAST_HOLEY_ELEMENTS;
if (!value->IsNumber()) return false; kind = FAST_HOLEY_DOUBLE_ELEMENTS;
if (!value->IsSmi()) {
found_double = true;
}
} }
} }
*has_smi_only_elements = !found_double;
return found_double;
} else {
return false;
} }
return kind;
} }
......
...@@ -2025,10 +2025,7 @@ class JSObject: public JSReceiver { ...@@ -2025,10 +2025,7 @@ class JSObject: public JSReceiver {
// storage would. In that case the JSObject should have fast // storage would. In that case the JSObject should have fast
// elements. // elements.
bool ShouldConvertToFastElements(); bool ShouldConvertToFastElements();
// Returns true if the elements of JSObject contains only values that can be ElementsKind BestFittingFastElementsKind();
// represented in a FixedDoubleArray and has at least one value that can only
// be represented as a double and not a Smi.
bool ShouldConvertToFastDoubleElements(bool* has_smi_only_elements);
// Computes the new capacity when expanding the elements of a JSObject. // Computes the new capacity when expanding the elements of a JSObject.
static uint32_t NewElementsCapacity(uint32_t old_capacity) { static uint32_t NewElementsCapacity(uint32_t old_capacity) {
...@@ -2040,27 +2037,6 @@ class JSObject: public JSReceiver { ...@@ -2040,27 +2037,6 @@ class JSObject: public JSReceiver {
static void UpdateAllocationSite(Handle<JSObject> object, static void UpdateAllocationSite(Handle<JSObject> object,
ElementsKind to_kind); ElementsKind to_kind);
enum SetFastElementsCapacitySmiMode {
kAllowSmiElements,
kForceSmiElements,
kDontAllowSmiElements
};
static Handle<FixedArray> SetFastElementsCapacity(
Handle<JSObject> object, int capacity,
SetFastElementsCapacitySmiMode smi_mode);
// Replace the elements' backing store with fast elements of the given
// capacity. Update the length for JSArrays. Returns the new backing
// store.
static Handle<FixedArray> SetFastElementsCapacityAndLength(
Handle<JSObject> object,
int capacity,
int length,
SetFastElementsCapacitySmiMode smi_mode);
static void SetFastDoubleElementsCapacityAndLength(Handle<JSObject> object,
int capacity, int length);
// Lookup interceptors are used for handling properties controlled by host // Lookup interceptors are used for handling properties controlled by host
// objects. // objects.
inline bool HasNamedInterceptor(); inline bool HasNamedInterceptor();
......
...@@ -102,6 +102,7 @@ RUNTIME_FUNCTION(Runtime_PushIfAbsent) { ...@@ -102,6 +102,7 @@ RUNTIME_FUNCTION(Runtime_PushIfAbsent) {
// Strict not needed. Used for cycle detection in Array join implementation. // Strict not needed. Used for cycle detection in Array join implementation.
RETURN_FAILURE_ON_EXCEPTION( RETURN_FAILURE_ON_EXCEPTION(
isolate, JSObject::AddDataElement(array, length, element, NONE)); isolate, JSObject::AddDataElement(array, length, element, NONE));
JSObject::ValidateElements(array);
return isolate->heap()->true_value(); return isolate->heap()->true_value();
} }
......
...@@ -576,6 +576,7 @@ RUNTIME_FUNCTION(Runtime_AppendElement) { ...@@ -576,6 +576,7 @@ RUNTIME_FUNCTION(Runtime_AppendElement) {
Handle<Object> result; Handle<Object> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION( ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result, JSObject::AddDataElement(array, index, value, NONE)); isolate, result, JSObject::AddDataElement(array, index, value, NONE));
JSObject::ValidateElements(array);
return *array; return *array;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment