From 04746c8109051577c4fd8bfb3242e968a71844fb Mon Sep 17 00:00:00 2001 From: peterwmwong Date: Mon, 27 Nov 2017 23:24:33 -0600 Subject: [PATCH] [typedarray] Port TA.p.find() to CSA TFJ This reduces the overhead of calling the builtin. Quick measurements show >5x improvement. As the typed array's size grows, iterating dominates and the performance gap closes. https://github.com/peterwmwong/v8-perf/blob/master/typedarray-find/README.md Bug: v8:5929 Change-Id: Ia74546bb46d446c6161c8956e350d4b5cdc1b328 Reviewed-on: https://chromium-review.googlesource.com/792454 Commit-Queue: Jakob Gruber Reviewed-by: Jakob Gruber Cr-Commit-Position: refs/heads/master@{#49706} --- src/bootstrapper.cc | 2 ++ src/builtins/builtins-array-gen.cc | 34 +++++++++++++++++++++++++++++ src/builtins/builtins-definitions.h | 3 +++ src/js/array.js | 1 - src/js/typedarray.js | 17 --------------- test/mjsunit/messages.js | 23 ++++++++++++++++++- 6 files changed, 61 insertions(+), 19 deletions(-) diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index bcb842a3c2..2659d7bb0d 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -3031,6 +3031,8 @@ void Genesis::InitializeGlobal(Handle global_object, Builtins::kTypedArrayPrototypeEvery, 1, false); SimpleInstallFunction(prototype, "fill", Builtins::kTypedArrayPrototypeFill, 1, false); + SimpleInstallFunction(prototype, "find", Builtins::kTypedArrayPrototypeFind, + 1, false); SimpleInstallFunction(prototype, "forEach", Builtins::kTypedArrayPrototypeForEach, 1, false); SimpleInstallFunction(prototype, "includes", diff --git a/src/builtins/builtins-array-gen.cc b/src/builtins/builtins-array-gen.cc index b3c9f96f3e..0be5cf606f 100644 --- a/src/builtins/builtins-array-gen.cc +++ b/src/builtins/builtins-array-gen.cc @@ -31,6 +31,19 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { typedef std::function PostLoopAction; + void FindResultGenerator() { a_.Bind(UndefinedConstant()); } + + Node* FindProcessor(Node* k_value, Node* k) { + Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), + this_arg(), k_value, k, o()); + Label false_continue(this), return_true(this); + BranchIfToBooleanIsTrue(value, &return_true, &false_continue); + BIND(&return_true); + ReturnFromBuiltin(k_value); + BIND(&false_continue); + return a(); + } + void ForEachResultGenerator() { a_.Bind(UndefinedConstant()); } Node* ForEachProcessor(Node* k_value, Node* k) { @@ -1593,6 +1606,27 @@ TF_BUILTIN(CloneFastJSArray, ArrayBuiltinCodeStubAssembler) { Return(CloneFastJSArray(context, array, mode)); } +// ES #sec-get-%typedarray%.prototype.find +TF_BUILTIN(TypedArrayPrototypeFind, ArrayBuiltinCodeStubAssembler) { + Node* argc = + ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount)); + CodeStubArguments args(this, argc); + Node* context = Parameter(BuiltinDescriptor::kContext); + Node* new_target = Parameter(BuiltinDescriptor::kNewTarget); + Node* receiver = args.GetReceiver(); + Node* callbackfn = args.GetOptionalArgumentValue(0); + Node* this_arg = args.GetOptionalArgumentValue(1); + + InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, + new_target, argc); + + GenerateIteratingTypedArrayBuiltinBody( + "%TypedArray%.prototype.find", + &ArrayBuiltinCodeStubAssembler::FindResultGenerator, + &ArrayBuiltinCodeStubAssembler::FindProcessor, + &ArrayBuiltinCodeStubAssembler::NullPostLoopAction); +} + TF_BUILTIN(ArrayForEachLoopContinuation, ArrayBuiltinCodeStubAssembler) { Node* context = Parameter(Descriptor::kContext); Node* receiver = Parameter(Descriptor::kReceiver); diff --git a/src/builtins/builtins-definitions.h b/src/builtins/builtins-definitions.h index 63b849f3a1..530d42fe07 100644 --- a/src/builtins/builtins-definitions.h +++ b/src/builtins/builtins-definitions.h @@ -1046,6 +1046,9 @@ namespace internal { CPP(TypedArrayPrototypeCopyWithin) \ /* ES6 #sec-%typedarray%.prototype.fill */ \ CPP(TypedArrayPrototypeFill) \ + /* ES6 %TypedArray%.prototype.find */ \ + TFJ(TypedArrayPrototypeFind, \ + SharedFunctionInfo::kDontAdaptArgumentsSentinel) \ /* ES7 #sec-%typedarray%.prototype.includes */ \ CPP(TypedArrayPrototypeIncludes) \ /* ES6 #sec-%typedarray%.prototype.indexof */ \ diff --git a/src/js/array.js b/src/js/array.js index 981db9d525..3c52694de6 100644 --- a/src/js/array.js +++ b/src/js/array.js @@ -1354,7 +1354,6 @@ utils.Export(function(to) { to.ArrayPush = ArrayPush; to.ArrayToString = ArrayToString; to.ArrayValues = ArrayValues; - to.InnerArrayFind = InnerArrayFind; to.InnerArrayFindIndex = InnerArrayFindIndex; to.InnerArrayJoin = InnerArrayJoin; to.InnerArraySort = InnerArraySort; diff --git a/src/js/typedarray.js b/src/js/typedarray.js index f6cfed298a..30736ad9e3 100644 --- a/src/js/typedarray.js +++ b/src/js/typedarray.js @@ -19,7 +19,6 @@ var GlobalArray = global.Array; var GlobalArrayBuffer = global.ArrayBuffer; var GlobalArrayBufferPrototype = GlobalArrayBuffer.prototype; var GlobalObject = global.Object; -var InnerArrayFind; var InnerArrayFindIndex; var InnerArrayJoin; var InnerArraySort; @@ -66,7 +65,6 @@ var GlobalTypedArray = %object_get_prototype_of(GlobalUint8Array); utils.Import(function(from) { GetIterator = from.GetIterator; GetMethod = from.GetMethod; - InnerArrayFind = from.InnerArrayFind; InnerArrayFindIndex = from.InnerArrayFindIndex; InnerArrayJoin = from.InnerArrayJoin; InnerArraySort = from.InnerArraySort; @@ -297,21 +295,6 @@ DEFINE_METHOD_LEN( 1 /* Set function length. */ ); - -// ES6 draft 07-15-13, section 22.2.3.10 -DEFINE_METHOD_LEN( - GlobalTypedArray.prototype, - find(predicate, thisArg) { - ValidateTypedArray(this, "%TypedArray%.prototype.find"); - - var length = %_TypedArrayGetLength(this); - - return InnerArrayFind(predicate, thisArg, this, length); - }, - 1 /* Set function length. */ -); - - // ES6 draft 07-15-13, section 22.2.3.11 DEFINE_METHOD_LEN( GlobalTypedArray.prototype, diff --git a/test/mjsunit/messages.js b/test/mjsunit/messages.js index 238e2fbe06..4876c036ec 100644 --- a/test/mjsunit/messages.js +++ b/test/mjsunit/messages.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --stack-size=100 --harmony +// Flags: --allow-natives-syntax --stack-size=100 --harmony function test(f, expected, type) { try { @@ -15,6 +15,18 @@ function test(f, expected, type) { assertUnreachable("Exception expected"); } +const typedArrayConstructors = [ + Uint8Array, + Int8Array, + Uint16Array, + Int16Array, + Uint32Array, + Int32Array, + Float32Array, + Float64Array, + Uint8ClampedArray +]; + // === Error === // kCyclicProto @@ -156,6 +168,15 @@ test(function() { Object.defineProperty(o, "x", { value: 1 }); }, "Cannot define property x, object is not extensible", TypeError); +// kDetachedOperation +for (constructor of typedArrayConstructors) { + test(() => { + const ta = new constructor([1]); + %ArrayBufferNeuter(ta.buffer); + ta.find(() => {}); + }, "Cannot perform %TypedArray%.prototype.find on a detached ArrayBuffer", TypeError); +} + // kFirstArgumentNotRegExp test(function() { "a".startsWith(/a/);