Index: src/builtins.cc |
diff --git a/src/builtins.cc b/src/builtins.cc |
index ed07d5d089101311f1f90c61b396e6ba61de64ca..e529e58a1fab51b6a95df0b94ab8c7ab0a2859ca 100644 |
--- a/src/builtins.cc |
+++ b/src/builtins.cc |
@@ -1222,23 +1222,18 @@ bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver, |
return true; |
} |
- |
-bool HasConcatSpreadableModifier(Isolate* isolate, Handle<JSArray> obj) { |
- Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol()); |
- Maybe<bool> maybe = JSReceiver::HasProperty(obj, key); |
- return maybe.FromMaybe(false); |
-} |
- |
- |
static Maybe<bool> IsConcatSpreadable(Isolate* isolate, Handle<Object> obj) { |
HandleScope handle_scope(isolate); |
if (!obj->IsJSReceiver()) return Just(false); |
- 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)) return Nothing<bool>(); |
- if (!value->IsUndefined()) return Just(value->BooleanValue()); |
+ if (!isolate->IsIsConcatSpreadableLookupChainIntact()) { |
+ // Slow path if @@isConcatSpreadable has been used. |
+ 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)) return Nothing<bool>(); |
+ if (!value->IsUndefined()) return Just(value->BooleanValue()); |
+ } |
return Object::IsArray(obj); |
} |
@@ -1426,8 +1421,24 @@ Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species, |
} |
} |
+bool IsSimpleArray(Isolate* isolate, Handle<JSArray> obj) { |
+ DisallowHeapAllocation no_gc; |
+ Map* map = obj->map(); |
+ // If there is only the 'length' property we are fine. |
+ if (map->prototype() == |
+ isolate->native_context()->initial_array_prototype() && |
+ map->NumberOfOwnDescriptors() == 1) { |
+ return true; |
+ } |
+ // TODO(cbruni): slower lookup for array subclasses and support slow |
+ // @@IsConcatSpreadable lookup. |
+ return false; |
+} |
MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, Arguments* args) { |
+ if (!isolate->IsIsConcatSpreadableLookupChainIntact()) { |
+ return MaybeHandle<JSArray>(); |
+ } |
// We shouldn't overflow when adding another len. |
const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); |
STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); |
@@ -1443,14 +1454,15 @@ MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, Arguments* args) { |
for (int i = 0; i < n_arguments; i++) { |
Object* arg = (*args)[i]; |
if (!arg->IsJSArray()) return MaybeHandle<JSArray>(); |
- if (!JSObject::cast(arg)->HasFastElements()) { |
+ if (!HasOnlySimpleReceiverElements(isolate, JSObject::cast(arg))) { |
return MaybeHandle<JSArray>(); |
} |
- if (!HasOnlySimpleReceiverElements(isolate, JSObject::cast(arg))) { |
+ // TODO(cbruni): support fast concatenation of DICTIONARY_ELEMENTS. |
+ if (!JSObject::cast(arg)->HasFastElements()) { |
return MaybeHandle<JSArray>(); |
} |
Handle<JSArray> array(JSArray::cast(arg), isolate); |
- if (HasConcatSpreadableModifier(isolate, array)) { |
+ if (!IsSimpleArray(isolate, array)) { |
return MaybeHandle<JSArray>(); |
} |
// The Array length is guaranted to be <= kHalfOfMaxInt thus we won't |
@@ -1458,16 +1470,15 @@ MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, Arguments* args) { |
result_len += Smi::cast(array->length())->value(); |
DCHECK(result_len >= 0); |
// Throw an Error if we overflow the FixedArray limits |
- if (FixedDoubleArray::kMaxLength < result_len || |
- FixedArray::kMaxLength < result_len) { |
- AllowHeapAllocation allow_gc; |
+ if (FixedArray::kMaxLength < result_len) { |
+ AllowHeapAllocation gc; |
THROW_NEW_ERROR(isolate, |
NewRangeError(MessageTemplate::kInvalidArrayLength), |
JSArray); |
} |
} |
} |
- return ElementsAccessor::Concat(isolate, args, n_arguments); |
+ return ElementsAccessor::Concat(isolate, args, n_arguments, result_len); |
} |
} // namespace |