Index: src/builtins.cc |
diff --git a/src/builtins.cc b/src/builtins.cc |
index dba56372e469814cb5c4652ef01e1d5d660918ee..805537448a6468d10659b611e4ea6f5a987409fd 100644 |
--- a/src/builtins.cc |
+++ b/src/builtins.cc |
@@ -929,7 +929,7 @@ void CollectElementIndices(Handle<JSObject> object, uint32_t range, |
} |
-bool IterateElementsSlow(Isolate* isolate, Handle<JSObject> receiver, |
+bool IterateElementsSlow(Isolate* isolate, Handle<JSReceiver> receiver, |
uint32_t length, ArrayConcatVisitor* visitor) { |
for (uint32_t i = 0; i < length; ++i) { |
HandleScope loop_scope(isolate); |
@@ -949,7 +949,7 @@ bool IterateElementsSlow(Isolate* isolate, Handle<JSObject> receiver, |
/** |
- * A helper function that visits elements of a JSObject in numerical |
+ * A helper function that visits "array" elements of a JSReceiver in numerical |
* order. |
* |
* The visitor argument called for each existing element in the array |
@@ -958,7 +958,7 @@ bool IterateElementsSlow(Isolate* isolate, Handle<JSObject> receiver, |
* length. |
* Returns false if any access threw an exception, otherwise true. |
*/ |
-bool IterateElements(Isolate* isolate, Handle<JSObject> receiver, |
+bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver, |
ArrayConcatVisitor* visitor) { |
uint32_t length = 0; |
@@ -984,15 +984,16 @@ bool IterateElements(Isolate* isolate, Handle<JSObject> receiver, |
// use the slow case. |
return IterateElementsSlow(isolate, receiver, length, visitor); |
} |
+ Handle<JSObject> array = Handle<JSObject>::cast(receiver); |
- switch (receiver->GetElementsKind()) { |
+ switch (array->GetElementsKind()) { |
case FAST_SMI_ELEMENTS: |
case FAST_ELEMENTS: |
case FAST_HOLEY_SMI_ELEMENTS: |
case FAST_HOLEY_ELEMENTS: { |
// Run through the elements FixedArray and use HasElement and GetElement |
// to check the prototype for missing elements. |
- Handle<FixedArray> elements(FixedArray::cast(receiver->elements())); |
+ Handle<FixedArray> elements(FixedArray::cast(array->elements())); |
int fast_length = static_cast<int>(length); |
DCHECK(fast_length <= elements->length()); |
for (int j = 0; j < fast_length; j++) { |
@@ -1001,14 +1002,14 @@ bool IterateElements(Isolate* isolate, Handle<JSObject> receiver, |
if (!element_value->IsTheHole()) { |
visitor->visit(j, element_value); |
} else { |
- Maybe<bool> maybe = JSReceiver::HasElement(receiver, j); |
+ Maybe<bool> maybe = JSReceiver::HasElement(array, j); |
if (!maybe.IsJust()) return false; |
if (maybe.FromJust()) { |
- // Call GetElement on receiver, not its prototype, or getters won't |
+ // Call GetElement on array, not its prototype, or getters won't |
// have the correct receiver. |
ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
- isolate, element_value, |
- Object::GetElement(isolate, receiver, j), false); |
+ isolate, element_value, Object::GetElement(isolate, array, j), |
+ false); |
visitor->visit(j, element_value); |
} |
} |
@@ -1021,12 +1022,12 @@ bool IterateElements(Isolate* isolate, Handle<JSObject> receiver, |
if (length == 0) break; |
// Run through the elements FixedArray and use HasElement and GetElement |
// to check the prototype for missing elements. |
- if (receiver->elements()->IsFixedArray()) { |
- DCHECK(receiver->elements()->length() == 0); |
+ if (array->elements()->IsFixedArray()) { |
+ DCHECK(array->elements()->length() == 0); |
break; |
} |
Handle<FixedDoubleArray> elements( |
- FixedDoubleArray::cast(receiver->elements())); |
+ FixedDoubleArray::cast(array->elements())); |
int fast_length = static_cast<int>(length); |
DCHECK(fast_length <= elements->length()); |
for (int j = 0; j < fast_length; j++) { |
@@ -1037,15 +1038,15 @@ bool IterateElements(Isolate* isolate, Handle<JSObject> receiver, |
isolate->factory()->NewNumber(double_value); |
visitor->visit(j, element_value); |
} else { |
- Maybe<bool> maybe = JSReceiver::HasElement(receiver, j); |
+ Maybe<bool> maybe = JSReceiver::HasElement(array, j); |
if (!maybe.IsJust()) return false; |
if (maybe.FromJust()) { |
- // Call GetElement on receiver, not its prototype, or getters won't |
+ // Call GetElement on array, not its prototype, or getters won't |
// have the correct receiver. |
Handle<Object> element_value; |
ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
- isolate, element_value, |
- Object::GetElement(isolate, receiver, j), false); |
+ isolate, element_value, Object::GetElement(isolate, array, j), |
+ false); |
visitor->visit(j, element_value); |
} |
} |
@@ -1055,17 +1056,17 @@ bool IterateElements(Isolate* isolate, Handle<JSObject> receiver, |
case DICTIONARY_ELEMENTS: { |
// CollectElementIndices() can't be called when there's a JSProxy |
// on the prototype chain. |
- for (PrototypeIterator iter(isolate, receiver); !iter.IsAtEnd(); |
+ for (PrototypeIterator iter(isolate, array); !iter.IsAtEnd(); |
iter.Advance()) { |
if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { |
- return IterateElementsSlow(isolate, receiver, length, visitor); |
+ return IterateElementsSlow(isolate, array, length, visitor); |
} |
} |
- Handle<SeededNumberDictionary> dict(receiver->element_dictionary()); |
+ Handle<SeededNumberDictionary> dict(array->element_dictionary()); |
List<uint32_t> indices(dict->Capacity() / 2); |
// Collect all indices in the object and the prototypes less |
// than length. This might introduce duplicates in the indices list. |
- CollectElementIndices(receiver, length, &indices); |
+ CollectElementIndices(array, length, &indices); |
indices.Sort(&compareUInt32); |
int j = 0; |
int n = indices.length(); |
@@ -1074,8 +1075,7 @@ bool IterateElements(Isolate* isolate, Handle<JSObject> receiver, |
uint32_t index = indices[j]; |
Handle<Object> element; |
ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
- isolate, element, Object::GetElement(isolate, receiver, index), |
- false); |
+ isolate, element, Object::GetElement(isolate, array, index), false); |
visitor->visit(index, element); |
// Skip to next different index (i.e., omit duplicates). |
do { |
@@ -1086,7 +1086,7 @@ bool IterateElements(Isolate* isolate, Handle<JSObject> receiver, |
} |
case UINT8_CLAMPED_ELEMENTS: { |
Handle<FixedUint8ClampedArray> pixels( |
- FixedUint8ClampedArray::cast(receiver->elements())); |
+ FixedUint8ClampedArray::cast(array->elements())); |
for (uint32_t j = 0; j < length; j++) { |
Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate); |
visitor->visit(j, e); |
@@ -1094,43 +1094,43 @@ bool IterateElements(Isolate* isolate, Handle<JSObject> receiver, |
break; |
} |
case INT8_ELEMENTS: { |
- IterateTypedArrayElements<FixedInt8Array, int8_t>(isolate, receiver, true, |
+ IterateTypedArrayElements<FixedInt8Array, int8_t>(isolate, array, true, |
true, visitor); |
break; |
} |
case UINT8_ELEMENTS: { |
- IterateTypedArrayElements<FixedUint8Array, uint8_t>(isolate, receiver, |
- true, true, visitor); |
+ IterateTypedArrayElements<FixedUint8Array, uint8_t>(isolate, array, true, |
+ true, visitor); |
break; |
} |
case INT16_ELEMENTS: { |
- IterateTypedArrayElements<FixedInt16Array, int16_t>(isolate, receiver, |
- true, true, visitor); |
+ IterateTypedArrayElements<FixedInt16Array, int16_t>(isolate, array, true, |
+ true, visitor); |
break; |
} |
case UINT16_ELEMENTS: { |
IterateTypedArrayElements<FixedUint16Array, uint16_t>( |
- isolate, receiver, true, true, visitor); |
+ isolate, array, true, true, visitor); |
break; |
} |
case INT32_ELEMENTS: { |
- IterateTypedArrayElements<FixedInt32Array, int32_t>(isolate, receiver, |
- true, false, visitor); |
+ IterateTypedArrayElements<FixedInt32Array, int32_t>(isolate, array, true, |
+ false, visitor); |
break; |
} |
case UINT32_ELEMENTS: { |
IterateTypedArrayElements<FixedUint32Array, uint32_t>( |
- isolate, receiver, true, false, visitor); |
+ isolate, array, true, false, visitor); |
break; |
} |
case FLOAT32_ELEMENTS: { |
- IterateTypedArrayElements<FixedFloat32Array, float>( |
- isolate, receiver, false, false, visitor); |
+ IterateTypedArrayElements<FixedFloat32Array, float>(isolate, array, false, |
+ false, visitor); |
break; |
} |
case FLOAT64_ELEMENTS: { |
IterateTypedArrayElements<FixedFloat64Array, double>( |
- isolate, receiver, false, false, visitor); |
+ isolate, array, false, false, visitor); |
break; |
} |
case FAST_SLOPPY_ARGUMENTS_ELEMENTS: |
@@ -1139,8 +1139,7 @@ bool IterateElements(Isolate* isolate, Handle<JSObject> receiver, |
HandleScope loop_scope(isolate); |
Handle<Object> element; |
ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
- isolate, element, Object::GetElement(isolate, receiver, index), |
- false); |
+ isolate, element, Object::GetElement(isolate, array, index), false); |
visitor->visit(index, element); |
} |
break; |
@@ -1152,37 +1151,29 @@ bool IterateElements(Isolate* isolate, Handle<JSObject> receiver, |
bool HasConcatSpreadableModifier(Isolate* isolate, Handle<JSArray> obj) { |
+ DCHECK(isolate->IsFastArrayConstructorPrototypeChainIntact()); |
if (!FLAG_harmony_concat_spreadable) return false; |
Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol()); |
- Maybe<bool> maybe = |
- JSReceiver::HasProperty(Handle<JSReceiver>::cast(obj), key); |
- if (!maybe.IsJust()) return false; |
- return maybe.FromJust(); |
+ Maybe<bool> maybe = JSReceiver::HasProperty(obj, key); |
+ return maybe.FromMaybe(false); |
} |
-bool IsConcatSpreadable(Isolate* isolate, Handle<Object> obj) { |
+static Maybe<bool> IsConcatSpreadable(Isolate* isolate, Handle<Object> obj) { |
HandleScope handle_scope(isolate); |
- if (!obj->IsJSReceiver()) return false; |
+ if (!obj->IsJSReceiver()) return Just(false); |
if (FLAG_harmony_concat_spreadable) { |
Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol()); |
Handle<Object> value; |
MaybeHandle<Object> maybeValue = |
i::Runtime::GetObjectProperty(isolate, obj, key); |
- if (maybeValue.ToHandle(&value) && !value->IsUndefined()) { |
- return value->BooleanValue(); |
- } |
+ if (!maybeValue.ToHandle(&value)) return Nothing<bool>(); |
+ if (!value->IsUndefined()) return Just(value->BooleanValue()); |
} |
- return obj->IsJSArray(); |
+ return Object::IsArray(obj); |
} |
-/** |
- * Array::concat implementation. |
- * See ECMAScript 262, 15.4.4.4. |
- * TODO(581): Fix non-compliance for very large concatenations and update to |
- * following the ECMAScript 5 specification. |
- */ |
Object* Slow_ArrayConcat(Arguments* args, Isolate* isolate) { |
int argument_count = args->length(); |
@@ -1338,10 +1329,10 @@ Object* Slow_ArrayConcat(Arguments* args, Isolate* isolate) { |
for (int i = 0; i < argument_count; i++) { |
Handle<Object> obj((*args)[i], isolate); |
- bool spreadable = IsConcatSpreadable(isolate, obj); |
- if (isolate->has_pending_exception()) return isolate->heap()->exception(); |
- if (spreadable) { |
- Handle<JSObject> object = Handle<JSObject>::cast(obj); |
+ Maybe<bool> spreadable = IsConcatSpreadable(isolate, obj); |
+ MAYBE_RETURN(spreadable, isolate->heap()->exception()); |
+ if (spreadable.FromJust()) { |
+ Handle<JSReceiver> object = Handle<JSReceiver>::cast(obj); |
if (!IterateElements(isolate, object, &visitor)) { |
return isolate->heap()->exception(); |
} |
@@ -1401,6 +1392,7 @@ MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, Arguments* args) { |
} // namespace |
+// ES6 22.1.3.1 Array.prototype.concat |
BUILTIN(ArrayConcat) { |
HandleScope scope(isolate); |
@@ -1423,7 +1415,7 @@ BUILTIN(ArrayConcat) { |
} |
-// ES6 section 22.1.2.2 Array.isArray |
+// ES6 22.1.2.2 Array.isArray |
BUILTIN(ArrayIsArray) { |
HandleScope scope(isolate); |
DCHECK_EQ(2, args.length()); |