Index: src/builtins.cc |
diff --git a/src/builtins.cc b/src/builtins.cc |
index 930c1b3cb51468b7e54362c1470d7c8468b78399..1af71de0f19d39a7d7a952171d5ce800cf94bbea 100644 |
--- a/src/builtins.cc |
+++ b/src/builtins.cc |
@@ -222,12 +222,12 @@ inline bool PrototypeHasNoElements(PrototypeIterator* iter) { |
JSObject* current = iter->GetCurrent<JSObject>(); |
if (current->IsAccessCheckNeeded()) return false; |
if (current->HasIndexedInterceptor()) return false; |
+ if (current->HasStringWrapperElements()) return false; |
if (current->elements()->length() != 0) return false; |
} |
return true; |
} |
- |
inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate, |
JSArray* receiver) { |
DisallowHeapAllocation no_gc; |
@@ -239,12 +239,43 @@ inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate, |
isolate->IsFastArrayConstructorPrototypeChainIntact()) { |
return true; |
} |
- |
// Slow case. |
PrototypeIterator iter(isolate, receiver); |
return PrototypeHasNoElements(&iter); |
} |
+inline bool HasSimpleElements(JSObject* current) { |
+ if (current->IsAccessCheckNeeded()) return false; |
+ if (current->HasIndexedInterceptor()) return false; |
+ if (current->HasStringWrapperElements()) return false; |
+ if (current->GetElementsAccessor()->HasAccessors(current)) return false; |
+ return true; |
+} |
+ |
+inline bool HasOnlySimpleReceiverElements(Isolate* isolate, |
+ JSReceiver* receiver) { |
+ // Check that we have no accessors on the receiver's elements. |
+ JSObject* object = JSObject::cast(receiver); |
+ if (!HasSimpleElements(object)) return false; |
+ // Check that ther are not elements on the prototype. |
+ DisallowHeapAllocation no_gc; |
+ PrototypeIterator iter(isolate, receiver); |
+ return PrototypeHasNoElements(&iter); |
+} |
+ |
+inline bool HasOnlySimpleElements(Isolate* isolate, JSReceiver* receiver) { |
+ // Check that ther are not elements on the prototype. |
+ DisallowHeapAllocation no_gc; |
+ PrototypeIterator iter(isolate, receiver, |
+ PrototypeIterator::START_AT_RECEIVER); |
+ for (; !iter.IsAtEnd(); iter.Advance()) { |
+ if (iter.GetCurrent()->IsJSProxy()) return false; |
+ JSObject* current = iter.GetCurrent<JSObject>(); |
+ if (!HasSimpleElements(current)) return false; |
+ } |
+ return true; |
+} |
+ |
// Returns |false| if not applicable. |
MUST_USE_RESULT |
inline bool EnsureJSArrayWithWritableFastElements(Isolate* isolate, |
@@ -258,7 +289,7 @@ inline bool EnsureJSArrayWithWritableFastElements(Isolate* isolate, |
if (args != nullptr && !IsJSArrayFastElementMovingAllowed(isolate, *array)) { |
return false; |
} |
- ElementsKind origin_kind = array->map()->elements_kind(); |
+ ElementsKind origin_kind = array->GetElementsKind(); |
if (IsDictionaryElementsKind(origin_kind)) return false; |
if (array->map()->is_observed()) return false; |
if (!array->map()->is_extensible()) return false; |
@@ -1063,11 +1094,11 @@ bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver, |
if (!val->ToUint32(&length)) { |
length = 0; |
} |
+ // TODO(cbruni): handle other element kind as well |
+ return IterateElementsSlow(isolate, receiver, length, visitor); |
} |
- if (!receiver->IsJSArray()) { |
- // For classes which are not known to be safe to access via elements alone, |
- // use the slow case. |
+ if (!HasOnlySimpleElements(isolate, *receiver)) { |
return IterateElementsSlow(isolate, receiver, length, visitor); |
} |
Handle<JSObject> array = Handle<JSObject>::cast(receiver); |
@@ -1081,7 +1112,7 @@ bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver, |
// to check the prototype for missing elements. |
Handle<FixedArray> elements(FixedArray::cast(array->elements())); |
int fast_length = static_cast<int>(length); |
- DCHECK(fast_length <= elements->length()); |
+ DCHECK_LE(fast_length, elements->length()); |
for (int j = 0; j < fast_length; j++) { |
HandleScope loop_scope(isolate); |
Handle<Object> element_value(elements->get(j), isolate); |
@@ -1141,14 +1172,6 @@ bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver, |
} |
case DICTIONARY_ELEMENTS: { |
- // CollectElementIndices() can't be called when there's a JSProxy |
- // on the prototype chain. |
- for (PrototypeIterator iter(isolate, array); !iter.IsAtEnd(); |
- iter.Advance()) { |
- if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { |
- return IterateElementsSlow(isolate, array, length, visitor); |
- } |
- } |
Handle<SeededNumberDictionary> dict(array->element_dictionary()); |
List<uint32_t> indices(dict->Capacity() / 2); |
// Collect all indices in the object and the prototypes less |
@@ -1189,6 +1212,7 @@ bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver, |
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS: |
TYPED_ARRAYS(TYPED_ARRAY_CASE) |
#undef TYPED_ARRAY_CASE |
+ return IterateElementsSlow(isolate, receiver, length, visitor); |
case FAST_STRING_WRAPPER_ELEMENTS: |
case SLOW_STRING_WRAPPER_ELEMENTS: |
// |array| is guaranteed to be an array or typed array. |
@@ -1201,7 +1225,6 @@ bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver, |
bool HasConcatSpreadableModifier(Isolate* isolate, Handle<JSArray> obj) { |
- DCHECK(isolate->IsFastArrayConstructorPrototypeChainIntact()); |
Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol()); |
Maybe<bool> maybe = JSReceiver::HasProperty(obj, key); |
return maybe.FromMaybe(false); |
@@ -1246,17 +1269,14 @@ Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species, |
length_estimate = static_cast<uint32_t>(array->length()->Number()); |
if (length_estimate != 0) { |
ElementsKind array_kind = |
- GetPackedElementsKind(array->map()->elements_kind()); |
+ GetPackedElementsKind(array->GetElementsKind()); |
kind = GetMoreGeneralElementsKind(kind, array_kind); |
} |
element_estimate = EstimateElementCount(array); |
} else { |
if (obj->IsHeapObject()) { |
- if (obj->IsNumber()) { |
- kind = GetMoreGeneralElementsKind(kind, FAST_DOUBLE_ELEMENTS); |
- } else { |
- kind = GetMoreGeneralElementsKind(kind, FAST_ELEMENTS); |
- } |
+ kind = GetMoreGeneralElementsKind( |
+ kind, obj->IsNumber() ? FAST_DOUBLE_ELEMENTS : FAST_ELEMENTS); |
} |
length_estimate = 1; |
element_estimate = 1; |
@@ -1299,7 +1319,7 @@ Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species, |
} else { |
JSArray* array = JSArray::cast(*obj); |
uint32_t length = static_cast<uint32_t>(array->length()->Number()); |
- switch (array->map()->elements_kind()) { |
+ switch (array->GetElementsKind()) { |
case FAST_HOLEY_DOUBLE_ELEMENTS: |
case FAST_DOUBLE_ELEMENTS: { |
// Empty array is FixedArray but not FixedDoubleArray. |
@@ -1351,14 +1371,7 @@ Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species, |
} |
} |
if (!failure) { |
- Handle<JSArray> array = isolate->factory()->NewJSArray(0); |
- Smi* length = Smi::FromInt(j); |
- Handle<Map> map; |
- map = JSObject::GetElementsTransitionMap(array, kind); |
- array->set_map(*map); |
- array->set_length(length); |
- array->set_elements(*storage); |
- return *array; |
+ return *isolate->factory()->NewJSArrayWithElements(storage, kind, j); |
} |
// In case of failure, fall through. |
} |
@@ -1415,23 +1428,23 @@ Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species, |
MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, Arguments* args) { |
- if (!isolate->IsFastArrayConstructorPrototypeChainIntact()) { |
- return MaybeHandle<JSArray>(); |
- } |
int n_arguments = args->length(); |
int result_len = 0; |
{ |
DisallowHeapAllocation no_gc; |
- Object* array_proto = isolate->array_function()->prototype(); |
// Iterate through all the arguments performing checks |
// and calculating total length. |
for (int i = 0; i < n_arguments; i++) { |
Object* arg = (*args)[i]; |
if (!arg->IsJSArray()) return MaybeHandle<JSArray>(); |
+ if (!HasOnlySimpleReceiverElements(isolate, JSObject::cast(arg))) { |
+ return MaybeHandle<JSArray>(); |
+ } |
+ // TODO(cbruni): support fast concatenation of DICTIONARY_ELEMENTS. |
+ if (!JSObject::cast(arg)->HasFastElements()) { |
+ return MaybeHandle<JSArray>(); |
+ } |
Handle<JSArray> array(JSArray::cast(arg), isolate); |
- if (!array->HasFastElements()) return MaybeHandle<JSArray>(); |
- PrototypeIterator iter(isolate, *array); |
- if (iter.GetCurrent() != array_proto) return MaybeHandle<JSArray>(); |
if (HasConcatSpreadableModifier(isolate, array)) { |
return MaybeHandle<JSArray>(); |
} |