Move SetFastElementsCapacity into GrowCapacityAndConvert
BUG=v8:4137 LOG=n Review URL: https://codereview.chromium.org/1197133003 Cr-Commit-Position: refs/heads/master@{#29222}
This commit is contained in:
parent
22b691ba0e
commit
046e91dd1a
@ -544,6 +544,7 @@ void ArrayLiteral::BuildConstantElements(Isolate* isolate) {
|
||||
if (array_index != values()->length()) {
|
||||
JSArray::SetLength(array, array_index);
|
||||
}
|
||||
JSObject::ValidateElements(array);
|
||||
Handle<FixedArrayBase> element_values(array->elements());
|
||||
|
||||
// Simple and shallow arrays can be lazily copied, we transform the
|
||||
|
120
src/elements.cc
120
src/elements.cc
@ -556,7 +556,7 @@ class ElementsAccessorBase : public ElementsAccessor {
|
||||
typedef ElementsTraitsParam ElementsTraits;
|
||||
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) {
|
||||
}
|
||||
@ -644,9 +644,59 @@ class ElementsAccessorBase : public ElementsAccessor {
|
||||
static void SetLengthImpl(Handle<JSArray> array, uint32_t length,
|
||||
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) {
|
||||
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,
|
||||
@ -1035,16 +1085,6 @@ class FastSmiOrObjectElementsAccessor
|
||||
#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
|
||||
: FastElementsAccessor<FastElementsAccessorSubclass,
|
||||
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:
|
||||
static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
|
||||
FixedArrayBase* to, ElementsKind from_kind,
|
||||
@ -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) {
|
||||
FixedArray* parameter_map = FixedArray::cast(store);
|
||||
Object* probe = GetParameterMapArg(parameter_map, key);
|
||||
@ -1556,7 +1584,15 @@ class SloppyArgumentsElementsAccessor : public ElementsAccessorBase<
|
||||
FixedArrayBase* to, ElementsKind from_kind,
|
||||
uint32_t to_start, int packed_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,
|
||||
|
@ -20,7 +20,6 @@ class ElementsAccessor {
|
||||
explicit ElementsAccessor(const char* name) : name_(name) { }
|
||||
virtual ~ElementsAccessor() { }
|
||||
|
||||
virtual ElementsKind kind() const = 0;
|
||||
const char* name() const { return name_; }
|
||||
|
||||
// Checks the elements of an object for consistency, asserting when a problem
|
||||
|
377
src/objects.cc
377
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;
|
||||
} 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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2025,10 +2025,7 @@ class JSObject: public JSReceiver {
|
||||
// storage would. In that case the JSObject should have fast
|
||||
// elements.
|
||||
bool ShouldConvertToFastElements();
|
||||
// Returns true if the elements of JSObject contains only values that can be
|
||||
// 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);
|
||||
ElementsKind BestFittingFastElementsKind();
|
||||
|
||||
// Computes the new capacity when expanding the elements of a JSObject.
|
||||
static uint32_t NewElementsCapacity(uint32_t old_capacity) {
|
||||
@ -2040,27 +2037,6 @@ class JSObject: public JSReceiver {
|
||||
static void UpdateAllocationSite(Handle<JSObject> object,
|
||||
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
|
||||
// objects.
|
||||
inline bool HasNamedInterceptor();
|
||||
|
@ -102,6 +102,7 @@ RUNTIME_FUNCTION(Runtime_PushIfAbsent) {
|
||||
// Strict not needed. Used for cycle detection in Array join implementation.
|
||||
RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, JSObject::AddDataElement(array, length, element, NONE));
|
||||
JSObject::ValidateElements(array);
|
||||
return isolate->heap()->true_value();
|
||||
}
|
||||
|
||||
|
@ -576,6 +576,7 @@ RUNTIME_FUNCTION(Runtime_AppendElement) {
|
||||
Handle<Object> result;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, result, JSObject::AddDataElement(array, index, value, NONE));
|
||||
JSObject::ValidateElements(array);
|
||||
return *array;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user