Index: src/elements.cc |
diff --git a/src/elements.cc b/src/elements.cc |
index 60d269a46d31fb4fac4ef562d58908d3ae792a2b..3080c0376e317fdf2ebea005be7ddf756b037124 100644 |
--- a/src/elements.cc |
+++ b/src/elements.cc |
@@ -636,16 +636,13 @@ class ElementsAccessorBase : public ElementsAccessor { |
return MaybeHandle<AccessorPair>(); |
} |
- MUST_USE_RESULT virtual MaybeHandle<Object> SetLength( |
- Handle<JSArray> array, Handle<Object> length) final { |
- return ElementsAccessorSubclass::SetLengthImpl( |
- array, length, handle(array->elements())); |
+ virtual void SetLength(Handle<JSArray> array, uint32_t length) final { |
+ ElementsAccessorSubclass::SetLengthImpl(array, length, |
+ handle(array->elements())); |
} |
- MUST_USE_RESULT static MaybeHandle<Object> SetLengthImpl( |
- Handle<JSObject> obj, |
- Handle<Object> length, |
- Handle<FixedArrayBase> backing_store); |
+ static void SetLengthImpl(Handle<JSArray> array, uint32_t length, |
+ Handle<FixedArrayBase> backing_store); |
virtual void SetCapacityAndLength(Handle<JSArray> array, int capacity, |
int length) final { |
@@ -866,10 +863,8 @@ class FastElementsAccessor |
typedef typename KindTraits::BackingStore BackingStore; |
// Adjusts the length of the fast backing store. |
- static Handle<Object> SetLengthWithoutNormalize( |
- Handle<FixedArrayBase> backing_store, |
- Handle<JSArray> array, |
- Handle<Object> length_object, |
+ static uint32_t SetLengthWithoutNormalize( |
+ Handle<FixedArrayBase> backing_store, Handle<JSArray> array, |
uint32_t length) { |
Isolate* isolate = array->GetIsolate(); |
uint32_t old_capacity = backing_store->length(); |
@@ -904,7 +899,7 @@ class FastElementsAccessor |
Handle<BackingStore>::cast(backing_store)->set_the_hole(i); |
} |
} |
- return length_object; |
+ return length; |
} |
// Check whether the backing store should be expanded. |
@@ -913,7 +908,7 @@ class FastElementsAccessor |
FastElementsAccessorSubclass::SetFastElementsCapacityAndLength( |
array, new_capacity, length); |
JSObject::ValidateElements(array); |
- return length_object; |
+ return length; |
} |
static void DeleteCommon(Handle<JSObject> obj, uint32_t key, |
@@ -1271,13 +1266,10 @@ class TypedElementsAccessor |
return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell); |
} |
- MUST_USE_RESULT static MaybeHandle<Object> SetLengthImpl( |
- Handle<JSObject> obj, |
- Handle<Object> length, |
- Handle<FixedArrayBase> backing_store) { |
+ static void SetLengthImpl(Handle<JSArray> array, uint32_t length, |
+ Handle<FixedArrayBase> backing_store) { |
// External arrays do not support changing their length. |
UNREACHABLE(); |
- return obj; |
} |
virtual void Delete(Handle<JSObject> obj, uint32_t key, |
@@ -1327,20 +1319,35 @@ class DictionaryElementsAccessor |
: ElementsAccessorBase<DictionaryElementsAccessor, |
ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {} |
+ static void SetLengthImpl(Handle<JSArray> array, uint32_t length, |
+ Handle<FixedArrayBase> backing_store) { |
+ uint32_t new_length = |
+ SetLengthWithoutNormalize(backing_store, array, length); |
+ // SetLengthWithoutNormalize does not allow length to drop below the last |
+ // non-deletable element. |
+ DCHECK_GE(new_length, length); |
+ if (new_length <= Smi::kMaxValue) { |
+ array->set_length(Smi::FromInt(new_length)); |
+ } else { |
+ Isolate* isolate = array->GetIsolate(); |
+ Handle<Object> length_obj = |
+ isolate->factory()->NewNumberFromUint(new_length); |
+ array->set_length(*length_obj); |
+ } |
+ } |
+ |
// Adjusts the length of the dictionary backing store and returns the new |
// length according to ES5 section 15.4.5.2 behavior. |
- static Handle<Object> SetLengthWithoutNormalize( |
- Handle<FixedArrayBase> store, |
- Handle<JSArray> array, |
- Handle<Object> length_object, |
- uint32_t length) { |
+ static uint32_t SetLengthWithoutNormalize(Handle<FixedArrayBase> store, |
+ Handle<JSArray> array, |
+ uint32_t length) { |
Handle<SeededNumberDictionary> dict = |
Handle<SeededNumberDictionary>::cast(store); |
Isolate* isolate = array->GetIsolate(); |
int capacity = dict->Capacity(); |
- uint32_t new_length = length; |
- uint32_t old_length = static_cast<uint32_t>(array->length()->Number()); |
- if (new_length < old_length) { |
+ uint32_t old_length = 0; |
+ CHECK(array->length()->ToArrayLength(&old_length)); |
+ if (length < old_length) { |
// Find last non-deletable element in range of elements to be |
// deleted and adjust range accordingly. |
for (int i = 0; i < capacity; i++) { |
@@ -1348,18 +1355,15 @@ class DictionaryElementsAccessor |
Object* key = dict->KeyAt(i); |
if (key->IsNumber()) { |
uint32_t number = static_cast<uint32_t>(key->Number()); |
- if (new_length <= number && number < old_length) { |
+ if (length <= number && number < old_length) { |
PropertyDetails details = dict->DetailsAt(i); |
- if (!details.IsConfigurable()) new_length = number + 1; |
+ if (!details.IsConfigurable()) length = number + 1; |
} |
} |
} |
- if (new_length != length) { |
- length_object = isolate->factory()->NewNumberFromUint(new_length); |
- } |
} |
- if (new_length == 0) { |
+ if (length == 0) { |
// Flush the backing store. |
JSObject::ResetElements(array); |
} else { |
@@ -1371,7 +1375,7 @@ class DictionaryElementsAccessor |
Object* key = dict->KeyAt(i); |
if (key->IsNumber()) { |
uint32_t number = static_cast<uint32_t>(key->Number()); |
- if (new_length <= number && number < old_length) { |
+ if (length <= number && number < old_length) { |
dict->SetEntry(i, the_hole_value, the_hole_value); |
removed_entries++; |
} |
@@ -1381,7 +1385,7 @@ class DictionaryElementsAccessor |
// Update the number of elements. |
dict->ElementsRemoved(removed_entries); |
} |
- return length_object; |
+ return length; |
} |
static void DeleteCommon(Handle<JSObject> obj, uint32_t key, |
@@ -1566,14 +1570,10 @@ class SloppyArgumentsElementsAccessor : public ElementsAccessorBase< |
} |
} |
- MUST_USE_RESULT static MaybeHandle<Object> SetLengthImpl( |
- Handle<JSObject> obj, |
- Handle<Object> length, |
- Handle<FixedArrayBase> parameter_map) { |
- // TODO(mstarzinger): This was never implemented but will be used once we |
- // correctly implement [[DefineOwnProperty]] on arrays. |
- UNIMPLEMENTED(); |
- return obj; |
+ static void SetLengthImpl(Handle<JSArray> array, uint32_t length, |
+ Handle<FixedArrayBase> parameter_map) { |
+ // Sloppy arguments objects are not arrays. |
+ UNREACHABLE(); |
} |
virtual void Delete(Handle<JSObject> obj, uint32_t key, |
@@ -1704,52 +1704,26 @@ void ElementsAccessor::TearDown() { |
template <typename ElementsAccessorSubclass, typename ElementsKindTraits> |
-MUST_USE_RESULT MaybeHandle<Object> ElementsAccessorBase< |
- ElementsAccessorSubclass, |
- ElementsKindTraits>::SetLengthImpl(Handle<JSObject> obj, |
- Handle<Object> length_obj, |
- Handle<FixedArrayBase> backing_store) { |
- Handle<JSArray> array = Handle<JSArray>::cast(obj); |
- |
- uint32_t length = 0; |
- CHECK(length_obj->ToArrayLength(&length)); |
- // Fast case: length fits in a smi. |
- if (length <= Smi::kMaxValue) { |
- Handle<Smi> smi(Smi::FromInt(length), obj->GetIsolate()); |
- Handle<Object> new_length = |
- ElementsAccessorSubclass::SetLengthWithoutNormalize(backing_store, |
- array, smi, length); |
- DCHECK(!new_length.is_null()); |
- |
- // Even though the proposed length was a smi, new_length could |
- // still be a heap number because SetLengthWithoutNormalize doesn't |
- // allow the array length property to drop below the index of |
- // non-deletable elements. |
- DCHECK(new_length->IsSmi() || new_length->IsHeapNumber() || |
- new_length->IsUndefined()); |
- if (new_length->IsSmi()) { |
- array->set_length(*Handle<Smi>::cast(new_length)); |
- return array; |
- } else if (new_length->IsHeapNumber()) { |
- array->set_length(*new_length); |
- return array; |
- } |
+void ElementsAccessorBase<ElementsAccessorSubclass, ElementsKindTraits>:: |
+ SetLengthImpl(Handle<JSArray> array, uint32_t length, |
+ Handle<FixedArrayBase> backing_store) { |
+ // Normalize if the length does not fit in a smi. Fast mode arrays only |
+ // support smi length. |
+ if (JSArray::SetLengthWouldNormalize(array->GetHeap(), length)) { |
+ Handle<SeededNumberDictionary> dictionary = |
+ JSObject::NormalizeElements(array); |
+ DCHECK(!dictionary.is_null()); |
+ DictionaryElementsAccessor::SetLengthImpl(array, length, dictionary); |
+ } else { |
+#ifdef DEBUG |
+ uint32_t max = Smi::kMaxValue; |
+ DCHECK_LE(length, max); |
+#endif |
+ uint32_t new_length = ElementsAccessorSubclass::SetLengthWithoutNormalize( |
+ backing_store, array, length); |
+ DCHECK_EQ(length, new_length); |
+ array->set_length(Smi::FromInt(new_length)); |
} |
- |
- // Slow case: The new length does not fit into a Smi or conversion |
- // to slow elements is needed for other reasons. |
- Handle<SeededNumberDictionary> dictionary = |
- JSObject::NormalizeElements(array); |
- DCHECK(!dictionary.is_null()); |
- |
- Handle<Object> new_length = |
- DictionaryElementsAccessor::SetLengthWithoutNormalize(dictionary, array, |
- length_obj, length); |
- DCHECK(!new_length.is_null()); |
- |
- DCHECK(new_length->IsNumber()); |
- array->set_length(*new_length); |
- return array; |
} |
@@ -1776,15 +1750,14 @@ MaybeHandle<Object> ArrayConstructInitializeElements(Handle<JSArray> array, |
elements_kind = GetHoleyElementsKind(elements_kind); |
JSObject::TransitionElementsKind(array, elements_kind); |
} |
- return array; |
} else if (length == 0) { |
JSArray::Initialize(array, JSArray::kPreallocatedArrayElements); |
- return array; |
+ } else { |
+ // Take the argument as the length. |
+ JSArray::Initialize(array, 0); |
+ JSArray::SetLength(array, length); |
} |
- |
- // Take the argument as the length. |
- JSArray::Initialize(array, 0); |
- return JSArray::SetElementsLength(array, args->at<Object>(0)); |
+ return array; |
} |
Factory* factory = array->GetIsolate()->factory(); |