Commit 03e9d415 authored by Taketoshi Aono's avatar Taketoshi Aono Committed by Commit Bot

Reland: Reimplement Object.entries/values as CSA to optimize performance.

Add Object.entries/values builtins to debug-evaluate.cc whitelist macro.
This fix revert commit of https://chromium-review.googlesource.com/c/v8/v8/+/859937
Original is https://chromium-review.googlesource.com/c/v8/v8/+/810504
>> Reimplements Object.entries/values as CSA to optimize performance. See more detail about https://bugs.chromium.org/p/v8/issues/ Issue 6804.

This reverts commit 1b49f725.

Bug: v8:6804
Change-Id: I57e8b66e1c4ece2abb52e1630a97fbfd4070d810
Reviewed-on: https://chromium-review.googlesource.com/860679
Commit-Queue: Yang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50492}
parent f9feb5fa
...@@ -135,6 +135,7 @@ Sanjoy Das <sanjoy@playingwithpointers.com> ...@@ -135,6 +135,7 @@ Sanjoy Das <sanjoy@playingwithpointers.com>
Seo Sanghyeon <sanxiyn@gmail.com> Seo Sanghyeon <sanxiyn@gmail.com>
Stefan Penner <stefan.penner@gmail.com> Stefan Penner <stefan.penner@gmail.com>
Sylvestre Ledru <sledru@mozilla.com> Sylvestre Ledru <sledru@mozilla.com>
Taketoshi Aono <brn@b6n.ch>
Tiancheng "Timothy" Gu <timothygu99@gmail.com> Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Tobias Burnus <burnus@net-b.de> Tobias Burnus <burnus@net-b.de>
Victor Costan <costan@gmail.com> Victor Costan <costan@gmail.com>
......
...@@ -1508,9 +1508,9 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object, ...@@ -1508,9 +1508,9 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
object_function, "keys", Builtins::kObjectKeys, 1, true); object_function, "keys", Builtins::kObjectKeys, 1, true);
native_context()->set_object_keys(*object_keys); native_context()->set_object_keys(*object_keys);
SimpleInstallFunction(object_function, factory->entries_string(), SimpleInstallFunction(object_function, factory->entries_string(),
Builtins::kObjectEntries, 1, false); Builtins::kObjectEntries, 1, true);
SimpleInstallFunction(object_function, factory->values_string(), SimpleInstallFunction(object_function, factory->values_string(),
Builtins::kObjectValues, 1, false); Builtins::kObjectValues, 1, true);
SimpleInstallFunction(isolate->initial_object_prototype(), SimpleInstallFunction(isolate->initial_object_prototype(),
"__defineGetter__", Builtins::kObjectDefineGetter, 2, "__defineGetter__", Builtins::kObjectDefineGetter, 2,
......
...@@ -754,7 +754,7 @@ namespace internal { ...@@ -754,7 +754,7 @@ namespace internal {
CPP(ObjectDefineProperties) \ CPP(ObjectDefineProperties) \
CPP(ObjectDefineProperty) \ CPP(ObjectDefineProperty) \
CPP(ObjectDefineSetter) \ CPP(ObjectDefineSetter) \
CPP(ObjectEntries) \ TFJ(ObjectEntries, 1, kObject) \
CPP(ObjectFreeze) \ CPP(ObjectFreeze) \
TFJ(ObjectGetOwnPropertyDescriptor, \ TFJ(ObjectGetOwnPropertyDescriptor, \
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \ SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
...@@ -784,7 +784,7 @@ namespace internal { ...@@ -784,7 +784,7 @@ namespace internal {
/* ES #sec-object.prototype.tolocalestring */ \ /* ES #sec-object.prototype.tolocalestring */ \
TFJ(ObjectPrototypeToLocaleString, 0) \ TFJ(ObjectPrototypeToLocaleString, 0) \
CPP(ObjectSeal) \ CPP(ObjectSeal) \
CPP(ObjectValues) \ TFJ(ObjectValues, 1, kObject) \
\ \
/* instanceof */ \ /* instanceof */ \
TFC(OrdinaryHasInstance, Compare, 1) \ TFC(OrdinaryHasInstance, Compare, 1) \
......
This diff is collapsed.
...@@ -395,31 +395,6 @@ BUILTIN(ObjectIsSealed) { ...@@ -395,31 +395,6 @@ BUILTIN(ObjectIsSealed) {
return isolate->heap()->ToBoolean(result.FromJust()); return isolate->heap()->ToBoolean(result.FromJust());
} }
BUILTIN(ObjectValues) {
HandleScope scope(isolate);
Handle<Object> object = args.atOrUndefined(isolate, 1);
Handle<JSReceiver> receiver;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
Object::ToObject(isolate, object));
Handle<FixedArray> values;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, values, JSReceiver::GetOwnValues(receiver, ENUMERABLE_STRINGS));
return *isolate->factory()->NewJSArrayWithElements(values);
}
BUILTIN(ObjectEntries) {
HandleScope scope(isolate);
Handle<Object> object = args.atOrUndefined(isolate, 1);
Handle<JSReceiver> receiver;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
Object::ToObject(isolate, object));
Handle<FixedArray> entries;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, entries,
JSReceiver::GetOwnEntries(receiver, ENUMERABLE_STRINGS));
return *isolate->factory()->NewJSArrayWithElements(entries);
}
BUILTIN(ObjectGetOwnPropertyDescriptors) { BUILTIN(ObjectGetOwnPropertyDescriptors) {
HandleScope scope(isolate); HandleScope scope(isolate);
Handle<Object> object = args.atOrUndefined(isolate, 1); Handle<Object> object = args.atOrUndefined(isolate, 1);
......
...@@ -4019,19 +4019,6 @@ Node* CodeStubAssembler::InstanceTypeEqual(Node* instance_type, int type) { ...@@ -4019,19 +4019,6 @@ Node* CodeStubAssembler::InstanceTypeEqual(Node* instance_type, int type) {
return Word32Equal(instance_type, Int32Constant(type)); return Word32Equal(instance_type, Int32Constant(type));
} }
Node* CodeStubAssembler::IsSpecialReceiverMap(Node* map) {
CSA_SLOW_ASSERT(this, IsMap(map));
Node* is_special = IsSpecialReceiverInstanceType(LoadMapInstanceType(map));
uint32_t mask =
Map::HasNamedInterceptorBit::kMask | Map::IsAccessCheckNeededBit::kMask;
USE(mask);
// Interceptors or access checks imply special receiver.
CSA_ASSERT(this,
SelectConstant(IsSetWord32(LoadMapBitField(map), mask), is_special,
Int32Constant(1), MachineRepresentation::kWord32));
return is_special;
}
TNode<BoolT> CodeStubAssembler::IsDictionaryMap(SloppyTNode<Map> map) { TNode<BoolT> CodeStubAssembler::IsDictionaryMap(SloppyTNode<Map> map) {
CSA_SLOW_ASSERT(this, IsMap(map)); CSA_SLOW_ASSERT(this, IsMap(map));
Node* bit_field3 = LoadMapBitField3(map); Node* bit_field3 = LoadMapBitField3(map);
...@@ -6380,36 +6367,38 @@ Node* CodeStubAssembler::DescriptorArrayNumberOfEntries(Node* descriptors) { ...@@ -6380,36 +6367,38 @@ Node* CodeStubAssembler::DescriptorArrayNumberOfEntries(Node* descriptors) {
descriptors, IntPtrConstant(DescriptorArray::kDescriptorLengthIndex)); descriptors, IntPtrConstant(DescriptorArray::kDescriptorLengthIndex));
} }
namespace { Node* CodeStubAssembler::DescriptorNumberToIndex(
SloppyTNode<Uint32T> descriptor_number) {
Node* DescriptorNumberToIndex(CodeStubAssembler* a, Node* descriptor_number) { Node* descriptor_size = Int32Constant(DescriptorArray::kEntrySize);
Node* descriptor_size = a->Int32Constant(DescriptorArray::kEntrySize); Node* index = Int32Mul(descriptor_number, descriptor_size);
Node* index = a->Int32Mul(descriptor_number, descriptor_size); return ChangeInt32ToIntPtr(index);
return a->ChangeInt32ToIntPtr(index);
} }
} // namespace
Node* CodeStubAssembler::DescriptorArrayToKeyIndex(Node* descriptor_number) { Node* CodeStubAssembler::DescriptorArrayToKeyIndex(Node* descriptor_number) {
return IntPtrAdd(IntPtrConstant(DescriptorArray::ToKeyIndex(0)), return IntPtrAdd(IntPtrConstant(DescriptorArray::ToKeyIndex(0)),
DescriptorNumberToIndex(this, descriptor_number)); DescriptorNumberToIndex(descriptor_number));
} }
Node* CodeStubAssembler::DescriptorArrayGetSortedKeyIndex( Node* CodeStubAssembler::DescriptorArrayGetSortedKeyIndex(
Node* descriptors, Node* descriptor_number) { Node* descriptors, Node* descriptor_number) {
const int details_offset = DescriptorArray::ToDetailsIndex(0) * kPointerSize; Node* details = DescriptorArrayGetDetails(
Node* details = LoadAndUntagToWord32FixedArrayElement( TNode<DescriptorArray>::UncheckedCast(descriptors),
descriptors, DescriptorNumberToIndex(this, descriptor_number), TNode<Uint32T>::UncheckedCast(descriptor_number));
details_offset);
return DecodeWord32<PropertyDetails::DescriptorPointer>(details); return DecodeWord32<PropertyDetails::DescriptorPointer>(details);
} }
Node* CodeStubAssembler::DescriptorArrayGetKey(Node* descriptors, Node* CodeStubAssembler::DescriptorArrayGetKey(Node* descriptors,
Node* descriptor_number) { Node* descriptor_number) {
const int key_offset = DescriptorArray::ToKeyIndex(0) * kPointerSize; const int key_offset = DescriptorArray::ToKeyIndex(0) * kPointerSize;
return LoadFixedArrayElement(descriptors, return LoadFixedArrayElement(
DescriptorNumberToIndex(this, descriptor_number), descriptors, DescriptorNumberToIndex(descriptor_number), key_offset);
key_offset); }
TNode<Uint32T> CodeStubAssembler::DescriptorArrayGetDetails(
TNode<DescriptorArray> descriptors, TNode<Uint32T> descriptor_number) {
const int details_offset = DescriptorArray::ToDetailsIndex(0) * kPointerSize;
return TNode<Uint32T>::UncheckedCast(LoadAndUntagToWord32FixedArrayElement(
descriptors, DescriptorNumberToIndex(descriptor_number), details_offset));
} }
void CodeStubAssembler::DescriptorLookupBinary(Node* unique_name, void CodeStubAssembler::DescriptorLookupBinary(Node* unique_name,
...@@ -6608,12 +6597,22 @@ void CodeStubAssembler::LoadPropertyFromFastObject(Node* object, Node* map, ...@@ -6608,12 +6597,22 @@ void CodeStubAssembler::LoadPropertyFromFastObject(Node* object, Node* map,
Variable* var_value) { Variable* var_value) {
DCHECK_EQ(MachineRepresentation::kWord32, var_details->rep()); DCHECK_EQ(MachineRepresentation::kWord32, var_details->rep());
DCHECK_EQ(MachineRepresentation::kTagged, var_value->rep()); DCHECK_EQ(MachineRepresentation::kTagged, var_value->rep());
Comment("[ LoadPropertyFromFastObject");
Node* details = Node* details =
LoadDetailsByKeyIndex<DescriptorArray>(descriptors, name_index); LoadDetailsByKeyIndex<DescriptorArray>(descriptors, name_index);
var_details->Bind(details); var_details->Bind(details);
LoadPropertyFromFastObject(object, map, descriptors, name_index, details,
var_value);
}
void CodeStubAssembler::LoadPropertyFromFastObject(Node* object, Node* map,
Node* descriptors,
Node* name_index,
Node* details,
Variable* var_value) {
Comment("[ LoadPropertyFromFastObject");
Node* location = DecodeWord32<PropertyDetails::LocationField>(details); Node* location = DecodeWord32<PropertyDetails::LocationField>(details);
Label if_in_field(this), if_in_descriptor(this), done(this); Label if_in_field(this), if_in_descriptor(this), done(this);
......
...@@ -1114,7 +1114,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { ...@@ -1114,7 +1114,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* IsSequentialStringInstanceType(Node* instance_type); Node* IsSequentialStringInstanceType(Node* instance_type);
Node* IsShortExternalStringInstanceType(Node* instance_type); Node* IsShortExternalStringInstanceType(Node* instance_type);
Node* IsSpecialReceiverInstanceType(Node* instance_type); Node* IsSpecialReceiverInstanceType(Node* instance_type);
Node* IsSpecialReceiverMap(Node* map);
Node* IsSpeciesProtectorCellInvalid(); Node* IsSpeciesProtectorCellInvalid();
Node* IsStringInstanceType(Node* instance_type); Node* IsStringInstanceType(Node* instance_type);
Node* IsString(Node* object); Node* IsString(Node* object);
...@@ -1572,6 +1571,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { ...@@ -1572,6 +1571,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* name_index, Variable* var_details, Node* name_index, Variable* var_details,
Variable* var_value); Variable* var_value);
void LoadPropertyFromFastObject(Node* object, Node* map, Node* descriptors,
Node* name_index, Node* details,
Variable* var_value);
void LoadPropertyFromNameDictionary(Node* dictionary, Node* entry, void LoadPropertyFromNameDictionary(Node* dictionary, Node* entry,
Variable* var_details, Variable* var_details,
Variable* var_value); Variable* var_value);
...@@ -1894,11 +1897,15 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { ...@@ -1894,11 +1897,15 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
void DescriptorLookupBinary(Node* unique_name, Node* descriptors, Node* nof, void DescriptorLookupBinary(Node* unique_name, Node* descriptors, Node* nof,
Label* if_found, Variable* var_name_index, Label* if_found, Variable* var_name_index,
Label* if_not_found); Label* if_not_found);
Node* DescriptorNumberToIndex(SloppyTNode<Uint32T> descriptor_number);
// Implements DescriptorArray::ToKeyIndex. // Implements DescriptorArray::ToKeyIndex.
// Returns an untagged IntPtr. // Returns an untagged IntPtr.
Node* DescriptorArrayToKeyIndex(Node* descriptor_number); Node* DescriptorArrayToKeyIndex(Node* descriptor_number);
// Implements DescriptorArray::GetKey. // Implements DescriptorArray::GetKey.
Node* DescriptorArrayGetKey(Node* descriptors, Node* descriptor_number); Node* DescriptorArrayGetKey(Node* descriptors, Node* descriptor_number);
// Implements DescriptorArray::GetKey.
TNode<Uint32T> DescriptorArrayGetDetails(TNode<DescriptorArray> descriptors,
TNode<Uint32T> descriptor_number);
Node* CallGetterIfAccessor(Node* value, Node* details, Node* context, Node* CallGetterIfAccessor(Node* value, Node* details, Node* context,
Node* receiver, Label* if_bailout, Node* receiver, Label* if_bailout,
......
...@@ -342,7 +342,11 @@ bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) { ...@@ -342,7 +342,11 @@ bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) {
V(AllocateSeqOneByteString) \ V(AllocateSeqOneByteString) \
V(AllocateSeqTwoByteString) \ V(AllocateSeqTwoByteString) \
V(ObjectCreate) \ V(ObjectCreate) \
V(ObjectEntries) \
V(ObjectEntriesSkipFastPath) \
V(ObjectHasOwnProperty) \ V(ObjectHasOwnProperty) \
V(ObjectValues) \
V(ObjectValuesSkipFastPath) \
V(ArrayIndexOf) \ V(ArrayIndexOf) \
V(ArrayIncludes_Slow) \ V(ArrayIncludes_Slow) \
V(ArrayIsArray) \ V(ArrayIsArray) \
......
...@@ -8791,9 +8791,10 @@ MUST_USE_RESULT Maybe<bool> FastGetOwnValuesOrEntries( ...@@ -8791,9 +8791,10 @@ MUST_USE_RESULT Maybe<bool> FastGetOwnValuesOrEntries(
MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate, MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate,
Handle<JSReceiver> object, Handle<JSReceiver> object,
PropertyFilter filter, PropertyFilter filter,
bool try_fast_path,
bool get_entries) { bool get_entries) {
Handle<FixedArray> values_or_entries; Handle<FixedArray> values_or_entries;
if (filter == ENUMERABLE_STRINGS) { if (try_fast_path && filter == ENUMERABLE_STRINGS) {
Maybe<bool> fast_values_or_entries = FastGetOwnValuesOrEntries( Maybe<bool> fast_values_or_entries = FastGetOwnValuesOrEntries(
isolate, object, get_entries, &values_or_entries); isolate, object, get_entries, &values_or_entries);
if (fast_values_or_entries.IsNothing()) return MaybeHandle<FixedArray>(); if (fast_values_or_entries.IsNothing()) return MaybeHandle<FixedArray>();
...@@ -8846,13 +8847,17 @@ MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate, ...@@ -8846,13 +8847,17 @@ MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate,
} }
MaybeHandle<FixedArray> JSReceiver::GetOwnValues(Handle<JSReceiver> object, MaybeHandle<FixedArray> JSReceiver::GetOwnValues(Handle<JSReceiver> object,
PropertyFilter filter) { PropertyFilter filter,
return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, false); bool try_fast_path) {
return GetOwnValuesOrEntries(object->GetIsolate(), object, filter,
try_fast_path, false);
} }
MaybeHandle<FixedArray> JSReceiver::GetOwnEntries(Handle<JSReceiver> object, MaybeHandle<FixedArray> JSReceiver::GetOwnEntries(Handle<JSReceiver> object,
PropertyFilter filter) { PropertyFilter filter,
return GetOwnValuesOrEntries(object->GetIsolate(), object, filter, true); bool try_fast_path) {
return GetOwnValuesOrEntries(object->GetIsolate(), object, filter,
try_fast_path, true);
} }
bool Map::DictionaryElementsInPrototypeChainOnly() { bool Map::DictionaryElementsInPrototypeChainOnly() {
......
...@@ -2182,10 +2182,12 @@ class JSReceiver: public HeapObject { ...@@ -2182,10 +2182,12 @@ class JSReceiver: public HeapObject {
Handle<JSReceiver> object); Handle<JSReceiver> object);
MUST_USE_RESULT static MaybeHandle<FixedArray> GetOwnValues( MUST_USE_RESULT static MaybeHandle<FixedArray> GetOwnValues(
Handle<JSReceiver> object, PropertyFilter filter); Handle<JSReceiver> object, PropertyFilter filter,
bool try_fast_path = true);
MUST_USE_RESULT static MaybeHandle<FixedArray> GetOwnEntries( MUST_USE_RESULT static MaybeHandle<FixedArray> GetOwnEntries(
Handle<JSReceiver> object, PropertyFilter filter); Handle<JSReceiver> object, PropertyFilter filter,
bool try_fast_path = true);
static const int kHashMask = PropertyArray::HashField::kMask; static const int kHashMask = PropertyArray::HashField::kMask;
......
...@@ -439,6 +439,61 @@ RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties) { ...@@ -439,6 +439,61 @@ RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties) {
return *object; return *object;
} }
RUNTIME_FUNCTION(Runtime_ObjectValues) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
Handle<FixedArray> values;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, values,
JSReceiver::GetOwnValues(receiver, PropertyFilter::ENUMERABLE_STRINGS,
true));
return *isolate->factory()->NewJSArrayWithElements(values);
}
RUNTIME_FUNCTION(Runtime_ObjectValuesSkipFastPath) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
Handle<FixedArray> value;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, value,
JSReceiver::GetOwnValues(receiver, PropertyFilter::ENUMERABLE_STRINGS,
false));
return *isolate->factory()->NewJSArrayWithElements(value);
}
RUNTIME_FUNCTION(Runtime_ObjectEntries) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
Handle<FixedArray> entries;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, entries,
JSReceiver::GetOwnEntries(receiver, PropertyFilter::ENUMERABLE_STRINGS,
true));
return *isolate->factory()->NewJSArrayWithElements(entries);
}
RUNTIME_FUNCTION(Runtime_ObjectEntriesSkipFastPath) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
Handle<FixedArray> entries;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, entries,
JSReceiver::GetOwnEntries(receiver, PropertyFilter::ENUMERABLE_STRINGS,
false));
return *isolate->factory()->NewJSArrayWithElements(entries);
}
RUNTIME_FUNCTION(Runtime_GetProperty) { RUNTIME_FUNCTION(Runtime_GetProperty) {
HandleScope scope(isolate); HandleScope scope(isolate);
......
...@@ -392,6 +392,10 @@ namespace internal { ...@@ -392,6 +392,10 @@ namespace internal {
F(ObjectCreate, 2, 1) \ F(ObjectCreate, 2, 1) \
F(InternalSetPrototype, 2, 1) \ F(InternalSetPrototype, 2, 1) \
F(OptimizeObjectForAddingMultipleProperties, 2, 1) \ F(OptimizeObjectForAddingMultipleProperties, 2, 1) \
F(ObjectValues, 1, 1) \
F(ObjectValuesSkipFastPath, 1, 1) \
F(ObjectEntries, 1, 1) \
F(ObjectEntriesSkipFastPath, 1, 1) \
F(GetProperty, 2, 1) \ F(GetProperty, 2, 1) \
F(KeyedGetProperty, 2, 1) \ F(KeyedGetProperty, 2, 1) \
F(AddNamedProperty, 4, 1) \ F(AddNamedProperty, 4, 1) \
......
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