Commit 536d8cbb authored by verwaest's avatar verwaest Committed by Commit bot

Speed up PrototypeHasNoElements and drop the "fast" path before, it's now slower.

BUG=

Review URL: https://codereview.chromium.org/1815663002

Cr-Commit-Position: refs/heads/master@{#34942}
parent e3680e9c
......@@ -214,57 +214,38 @@ inline bool GetSloppyArgumentsLength(Isolate* isolate, Handle<JSObject> object,
return *out <= object->elements()->length();
}
inline bool PrototypeHasNoElements(PrototypeIterator* iter) {
inline bool PrototypeHasNoElements(Isolate* isolate, JSObject* object) {
DisallowHeapAllocation no_gc;
for (; !iter->IsAtEnd(); iter->Advance()) {
if (iter->GetCurrent()->IsJSProxy()) return false;
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;
HeapObject* prototype = HeapObject::cast(object->map()->prototype());
HeapObject* null = isolate->heap()->null_value();
HeapObject* empty = isolate->heap()->empty_fixed_array();
while (prototype != null) {
Map* map = prototype->map();
if (map->instance_type() <= LAST_CUSTOM_ELEMENTS_RECEIVER) return false;
if (JSObject::cast(prototype)->elements() != empty) return false;
prototype = HeapObject::cast(map->prototype());
}
return true;
}
inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate,
JSArray* receiver) {
DisallowHeapAllocation no_gc;
// If the array prototype chain is intact (and free of elements), and if the
// receiver's prototype is the array prototype, then we are done.
Object* prototype = receiver->map()->prototype();
if (prototype->IsJSArray() &&
isolate->is_initial_array_prototype(JSArray::cast(prototype)) &&
isolate->IsFastArrayConstructorPrototypeChainIntact()) {
return true;
}
// Slow case.
PrototypeIterator iter(isolate, receiver);
return PrototypeHasNoElements(&iter);
return PrototypeHasNoElements(isolate, receiver);
}
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;
return current->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER &&
!current->GetElementsAccessor()->HasAccessors(current);
}
inline bool HasOnlySimpleReceiverElements(Isolate* isolate,
JSReceiver* receiver) {
JSObject* 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);
if (!HasSimpleElements(receiver)) return false;
return PrototypeHasNoElements(isolate, receiver);
}
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);
......@@ -284,17 +265,16 @@ inline bool EnsureJSArrayWithWritableFastElements(Isolate* isolate,
int first_added_arg) {
if (!receiver->IsJSArray()) return false;
Handle<JSArray> array = Handle<JSArray>::cast(receiver);
// If there may be elements accessors in the prototype chain, the fast path
// cannot be used if there arguments to add to the array.
if (args != nullptr && !IsJSArrayFastElementMovingAllowed(isolate, *array)) {
return false;
}
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;
if (args == nullptr) return true;
// If there may be elements accessors in the prototype chain, the fast path
// cannot be used if there arguments to add to the array.
if (!IsJSArrayFastElementMovingAllowed(isolate, *array)) return false;
// Adding elements to the array prototype would break code that makes sure
// it has no elements. Handle that elsewhere.
if (isolate->IsAnyInitialArrayPrototype(array)) return false;
......@@ -308,10 +288,8 @@ inline bool EnsureJSArrayWithWritableFastElements(Isolate* isolate,
ElementsKind target_kind = origin_kind;
{
DisallowHeapAllocation no_gc;
int arg_count = args_length - first_added_arg;
Object** arguments = args->arguments() - first_added_arg - (arg_count - 1);
for (int i = 0; i < arg_count; i++) {
Object* arg = arguments[i];
for (int i = first_added_arg; i < args_length; i++) {
Object* arg = (*args)[i];
if (arg->IsHeapObject()) {
if (arg->IsHeapNumber()) {
target_kind = FAST_DOUBLE_ELEMENTS;
......
......@@ -709,7 +709,7 @@ enum InstanceType {
JS_GLOBAL_PROXY_TYPE,
// Like JS_OBJECT_TYPE, but requires access checks and/or has interceptors.
JS_SPECIAL_API_OBJECT_TYPE, // LAST_SPECIAL_RECEIVER_TYPE
JS_VALUE_TYPE,
JS_VALUE_TYPE, // LAST_CUSTOM_ELEMENTS_RECEIVER
JS_MESSAGE_OBJECT_TYPE,
JS_DATE_TYPE,
JS_OBJECT_TYPE,
......@@ -760,6 +760,10 @@ enum InstanceType {
LAST_JS_OBJECT_TYPE = LAST_TYPE,
// Boundary for testing JSReceivers that need special property lookup handling
LAST_SPECIAL_RECEIVER_TYPE = JS_SPECIAL_API_OBJECT_TYPE,
// Boundary case for testing JSReceivers that may have elements while having
// an empty fixed array as elements backing store. This is true for string
// wrappers.
LAST_CUSTOM_ELEMENTS_RECEIVER = JS_VALUE_TYPE,
};
STATIC_ASSERT(JS_OBJECT_TYPE == Internals::kJSObjectType);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment