Skip to content

Commit f9868ea

Browse files
shiyu-zhangCommit Bot
authored andcommitted
[builtins] implement fast path of Object.getOwnPropertyNames using CSA.
Migrate the Object.getOwnPropertyNames to the CodeStubAssembler and use the enum cache backing store when 1) the enum cache is avaible 2) the {object} has no elements 3) all own properties are enumerable This makes a speedup of 10x when using Object.getOwnPropertyNames with fast-path. It improves Speedometer2.0 Inferno case by ~9% on ATOM platform. Change-Id: I05e1df0e7d9d53d97664c322248cedb106a7b1d0 Reviewed-on: https://chromium-review.googlesource.com/1004434 Reviewed-by: Yang Guo <[email protected]> Reviewed-by: Benedikt Meurer <[email protected]> Commit-Queue: Shiyu Zhang <[email protected]> Cr-Commit-Position: refs/heads/master@{#53992}
1 parent e1f8671 commit f9868ea

File tree

7 files changed

+158
-7
lines changed

7 files changed

+158
-7
lines changed

src/bootstrapper.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1452,7 +1452,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
14521452
factory->getOwnPropertyDescriptors_string(),
14531453
Builtins::kObjectGetOwnPropertyDescriptors, 1, false);
14541454
SimpleInstallFunction(isolate_, object_function, "getOwnPropertyNames",
1455-
Builtins::kObjectGetOwnPropertyNames, 1, false);
1455+
Builtins::kObjectGetOwnPropertyNames, 1, true);
14561456
SimpleInstallFunction(isolate_, object_function, "getOwnPropertySymbols",
14571457
Builtins::kObjectGetOwnPropertySymbols, 1, false);
14581458
SimpleInstallFunction(isolate_, object_function, "is", Builtins::kObjectIs,

src/builtins/builtins-definitions.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -795,7 +795,7 @@ namespace internal {
795795
TFJ(ObjectGetOwnPropertyDescriptor, \
796796
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
797797
CPP(ObjectGetOwnPropertyDescriptors) \
798-
CPP(ObjectGetOwnPropertyNames) \
798+
TFJ(ObjectGetOwnPropertyNames, 1, kReceiver, kObject) \
799799
CPP(ObjectGetOwnPropertySymbols) \
800800
CPP(ObjectGetPrototypeOf) \
801801
CPP(ObjectSetPrototypeOf) \

src/builtins/builtins-object-gen.cc

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,108 @@ TF_BUILTIN(ObjectKeys, ObjectBuiltinsAssembler) {
779779
}
780780
}
781781

782+
// ES #sec-object.getOwnPropertyNames
783+
TF_BUILTIN(ObjectGetOwnPropertyNames, ObjectBuiltinsAssembler) {
784+
Node* object = Parameter(Descriptor::kObject);
785+
Node* context = Parameter(Descriptor::kContext);
786+
787+
VARIABLE(var_length, MachineRepresentation::kTagged);
788+
VARIABLE(var_elements, MachineRepresentation::kTagged);
789+
Label if_empty(this, Label::kDeferred), if_empty_elements(this),
790+
if_fast(this), try_fast(this, Label::kDeferred),
791+
if_slow(this, Label::kDeferred), if_join(this);
792+
793+
// Check if the {object} has a usable enum cache.
794+
GotoIf(TaggedIsSmi(object), &if_slow);
795+
Node* object_map = LoadMap(object);
796+
Node* object_bit_field3 = LoadMapBitField3(object_map);
797+
Node* object_enum_length =
798+
DecodeWordFromWord32<Map::EnumLengthBits>(object_bit_field3);
799+
GotoIf(
800+
WordEqual(object_enum_length, IntPtrConstant(kInvalidEnumCacheSentinel)),
801+
&try_fast);
802+
803+
// Ensure that the {object} doesn't have any elements.
804+
CSA_ASSERT(this, IsJSObjectMap(object_map));
805+
Node* object_elements = LoadElements(object);
806+
GotoIf(IsEmptyFixedArray(object_elements), &if_empty_elements);
807+
Branch(IsEmptySlowElementDictionary(object_elements), &if_empty_elements,
808+
&if_slow);
809+
810+
// Check whether all own properties are enumerable.
811+
BIND(&if_empty_elements);
812+
Node* number_descriptors =
813+
DecodeWordFromWord32<Map::NumberOfOwnDescriptorsBits>(object_bit_field3);
814+
GotoIfNot(WordEqual(object_enum_length, number_descriptors), &if_slow);
815+
816+
// Check whether there are enumerable properties.
817+
Branch(WordEqual(object_enum_length, IntPtrConstant(0)), &if_empty, &if_fast);
818+
819+
BIND(&if_fast);
820+
{
821+
// The {object} has a usable enum cache and all own properties are
822+
// enumerable, use that.
823+
Node* object_descriptors = LoadMapDescriptors(object_map);
824+
Node* object_enum_cache =
825+
LoadObjectField(object_descriptors, DescriptorArray::kEnumCacheOffset);
826+
Node* object_enum_keys =
827+
LoadObjectField(object_enum_cache, EnumCache::kKeysOffset);
828+
829+
// Allocate a JSArray and copy the elements from the {object_enum_keys}.
830+
Node* array = nullptr;
831+
Node* elements = nullptr;
832+
Node* native_context = LoadNativeContext(context);
833+
Node* array_map = LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
834+
Node* array_length = SmiTag(object_enum_length);
835+
std::tie(array, elements) = AllocateUninitializedJSArrayWithElements(
836+
PACKED_ELEMENTS, array_map, array_length, nullptr, object_enum_length,
837+
INTPTR_PARAMETERS);
838+
CopyFixedArrayElements(PACKED_ELEMENTS, object_enum_keys, elements,
839+
object_enum_length, SKIP_WRITE_BARRIER);
840+
Return(array);
841+
}
842+
843+
BIND(&try_fast);
844+
{
845+
// Let the runtime compute the elements and try initializing enum cache.
846+
Node* elements = CallRuntime(Runtime::kObjectGetOwnPropertyNamesTryFast,
847+
context, object);
848+
var_length.Bind(LoadObjectField(elements, FixedArray::kLengthOffset));
849+
var_elements.Bind(elements);
850+
Goto(&if_join);
851+
}
852+
853+
BIND(&if_empty);
854+
{
855+
// The {object} doesn't have any enumerable keys.
856+
var_length.Bind(SmiConstant(0));
857+
var_elements.Bind(EmptyFixedArrayConstant());
858+
Goto(&if_join);
859+
}
860+
861+
BIND(&if_slow);
862+
{
863+
// Let the runtime compute the elements.
864+
Node* elements =
865+
CallRuntime(Runtime::kObjectGetOwnPropertyNames, context, object);
866+
var_length.Bind(LoadObjectField(elements, FixedArray::kLengthOffset));
867+
var_elements.Bind(elements);
868+
Goto(&if_join);
869+
}
870+
871+
BIND(&if_join);
872+
{
873+
// Wrap the elements into a proper JSArray and return that.
874+
Node* native_context = LoadNativeContext(context);
875+
Node* array_map = LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
876+
Node* array = AllocateUninitializedJSArrayWithoutElements(
877+
array_map, var_length.value(), nullptr);
878+
StoreObjectFieldNoWriteBarrier(array, JSArray::kElementsOffset,
879+
var_elements.value());
880+
Return(array);
881+
}
882+
}
883+
782884
TF_BUILTIN(ObjectValues, ObjectEntriesValuesBuiltinsAssembler) {
783885
TNode<JSObject> object =
784886
TNode<JSObject>::UncheckedCast(Parameter(Descriptor::kObject));

src/builtins/builtins-object.cc

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -326,11 +326,6 @@ Object* GetOwnPropertyKeys(Isolate* isolate, BuiltinArguments args,
326326

327327
} // namespace
328328

329-
// ES6 section 19.1.2.7 Object.getOwnPropertyNames ( O )
330-
BUILTIN(ObjectGetOwnPropertyNames) {
331-
return GetOwnPropertyKeys(isolate, args, SKIP_SYMBOLS);
332-
}
333-
334329
// ES6 section 19.1.2.8 Object.getOwnPropertySymbols ( O )
335330
BUILTIN(ObjectGetOwnPropertySymbols) {
336331
return GetOwnPropertyKeys(isolate, args, SKIP_STRINGS);

src/debug/debug-evaluate.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,8 @@ bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) {
331331
V(ObjectHasOwnProperty) \
332332
V(ObjectValues) \
333333
V(ObjectValuesSkipFastPath) \
334+
V(ObjectGetOwnPropertyNames) \
335+
V(ObjectGetOwnPropertyNamesTryFast) \
334336
V(RegExpInitializeAndCompile) \
335337
V(StackGuard) \
336338
V(StringAdd) \

src/runtime/runtime-object.cc

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,56 @@ RUNTIME_FUNCTION(Runtime_ObjectKeys) {
244244
return *keys;
245245
}
246246

247+
// ES #sec-object.getOwnPropertyNames
248+
RUNTIME_FUNCTION(Runtime_ObjectGetOwnPropertyNames) {
249+
HandleScope scope(isolate);
250+
Handle<Object> object = args.at(0);
251+
252+
// Convert the {object} to a proper {receiver}.
253+
Handle<JSReceiver> receiver;
254+
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
255+
Object::ToObject(isolate, object));
256+
257+
// Collect the own keys for the {receiver}.
258+
Handle<FixedArray> keys;
259+
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
260+
isolate, keys,
261+
KeyAccumulator::GetKeys(receiver, KeyCollectionMode::kOwnOnly,
262+
SKIP_SYMBOLS,
263+
GetKeysConversion::kConvertToString));
264+
return *keys;
265+
}
266+
267+
RUNTIME_FUNCTION(Runtime_ObjectGetOwnPropertyNamesTryFast) {
268+
HandleScope scope(isolate);
269+
Handle<Object> object = args.at(0);
270+
271+
// Convert the {object} to a proper {receiver}.
272+
Handle<JSReceiver> receiver;
273+
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
274+
Object::ToObject(isolate, object));
275+
276+
Handle<Map> map(receiver->map(), isolate);
277+
278+
int nod = map->NumberOfOwnDescriptors();
279+
Handle<FixedArray> keys;
280+
if (nod != 0 && map->NumberOfEnumerableProperties() == nod) {
281+
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
282+
isolate, keys,
283+
KeyAccumulator::GetKeys(receiver, KeyCollectionMode::kOwnOnly,
284+
ENUMERABLE_STRINGS,
285+
GetKeysConversion::kConvertToString));
286+
} else {
287+
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
288+
isolate, keys,
289+
KeyAccumulator::GetKeys(receiver, KeyCollectionMode::kOwnOnly,
290+
SKIP_SYMBOLS,
291+
GetKeysConversion::kConvertToString));
292+
}
293+
294+
return *keys;
295+
}
296+
247297
// ES6 19.1.3.2
248298
RUNTIME_FUNCTION(Runtime_ObjectHasOwnProperty) {
249299
HandleScope scope(isolate);

src/runtime/runtime.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,8 @@ namespace internal {
357357
F(ObjectEntriesSkipFastPath, 1, 1) \
358358
F(ObjectHasOwnProperty, 2, 1) \
359359
F(ObjectKeys, 1, 1) \
360+
F(ObjectGetOwnPropertyNames, 1, 1) \
361+
F(ObjectGetOwnPropertyNamesTryFast, 1, 1) \
360362
F(ObjectValues, 1, 1) \
361363
F(ObjectValuesSkipFastPath, 1, 1) \
362364
F(OptimizeObjectForAddingMultipleProperties, 2, 1) \

0 commit comments

Comments
 (0)