Title: [203076] trunk
Revision
203076
Author
[email protected]
Date
2016-07-11 12:13:05 -0700 (Mon, 11 Jul 2016)

Log Message

STP TypedArray.subarray 5x slowdown compared to 9.1
https://bugs.webkit.org/show_bug.cgi?id=156404
Source/_javascript_Core:

<rdar://problem/26493032>

Reviewed by Geoffrey Garen.

This patch moves the species constructor work for
%TypedArray%.prototype.subarray to a js wrapper. By moving the
species constructor work to JS we are able to completely optimize
it out in DFG. The actual work of creating a TypedArray is still
done in C++ since we are able to avoid calling into the
constructor, which is expensive. This patch also changes the error
message when a %TypedArray%.prototype function is passed a non-typed
array this value. Finally, we used to check that the this value
had not been detached, however, this behavior was incorrect.

* builtins/BuiltinNames.h:
* builtins/TypedArrayPrototype.js:
(globalPrivate.typedArraySpeciesConstructor):
(subarray):
* runtime/ConstructData.cpp:
(JSC::construct):
* runtime/ConstructData.h:
* runtime/JSGenericTypedArrayViewPrototypeFunctions.h:
(JSC::genericTypedArrayViewPrivateFuncSubarrayCreate):
(JSC::genericTypedArrayViewProtoFuncSubarray): Deleted.
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
* runtime/JSTypedArrayViewPrototype.cpp:
(JSC::typedArrayViewPrivateFuncLength):
(JSC::typedArrayViewPrivateFuncSubarrayCreate):
(JSC::JSTypedArrayViewPrototype::finishCreation):
(JSC::typedArrayViewProtoFuncSubarray): Deleted.
* runtime/JSTypedArrayViewPrototype.h:

LayoutTests:

Reviewed by Geoffrey Garen.

Add new micro-benchmark for testing subarray performance with small subarray sizes.

* js/regress/script-tests/typed-array-subarray.js: Added.
(createManySubs):
(go):
* js/regress/typed-array-subarray-expected.txt: Added.
* js/regress/typed-array-subarray.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (203075 => 203076)


--- trunk/LayoutTests/ChangeLog	2016-07-11 19:08:24 UTC (rev 203075)
+++ trunk/LayoutTests/ChangeLog	2016-07-11 19:13:05 UTC (rev 203076)
@@ -1,3 +1,18 @@
+2016-07-11  Keith Miller  <[email protected]>
+
+        STP TypedArray.subarray 5x slowdown compared to 9.1
+        https://bugs.webkit.org/show_bug.cgi?id=156404
+
+        Reviewed by Geoffrey Garen.
+
+        Add new micro-benchmark for testing subarray performance with small subarray sizes.
+
+        * js/regress/script-tests/typed-array-subarray.js: Added.
+        (createManySubs):
+        (go):
+        * js/regress/typed-array-subarray-expected.txt: Added.
+        * js/regress/typed-array-subarray.html: Added.
+
 2016-07-11  Nan Wang  <[email protected]>
 
         AX: WKWebView should have API to prevent pinch-to-zoom always being allowed

Added: trunk/LayoutTests/js/regress/script-tests/typed-array-subarray.js (0 => 203076)


--- trunk/LayoutTests/js/regress/script-tests/typed-array-subarray.js	                        (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/typed-array-subarray.js	2016-07-11 19:13:05 UTC (rev 203076)
@@ -0,0 +1,31 @@
+noInline(Float32Array.prototype.subarray);
+function createManySubs(howMany, a, b, c, d) {
+    var storage = new Float32Array(howMany * 4);
+    for (var k=0; k < howMany; ++k) {
+        var r = storage.subarray(k * 4, (k + 1) * 4);
+        r[0] = a; r[1] = b; r[2] = c; r[3] = d;
+
+        // some action
+        r[0] += 2.3; r[1] += 12; r[2] *= 3.14; r[3] -= 999.1;
+    }
+}
+
+function go() {
+    var subtt = [];
+
+    const iterationCount = 25;
+    const arrayCount = 20000;
+
+    var a, b, c, d;
+
+    for (var iter=0; iter < iterationCount; ++iter) {
+        a = Math.random() * 10;
+        b = Math.random() * 10;
+        c = Math.random() * 10;
+        d = Math.random() * 10;
+        createManySubs(arrayCount, a, b, c, d);
+    }
+
+}
+
+go();

Added: trunk/LayoutTests/js/regress/typed-array-subarray-expected.txt (0 => 203076)


--- trunk/LayoutTests/js/regress/typed-array-subarray-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/regress/typed-array-subarray-expected.txt	2016-07-11 19:13:05 UTC (rev 203076)
@@ -0,0 +1,10 @@
+JSRegress/typed-array-subarray
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/regress/typed-array-subarray.html (0 => 203076)


--- trunk/LayoutTests/js/regress/typed-array-subarray.html	                        (rev 0)
+++ trunk/LayoutTests/js/regress/typed-array-subarray.html	2016-07-11 19:13:05 UTC (rev 203076)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>

Modified: trunk/Source/_javascript_Core/ChangeLog (203075 => 203076)


--- trunk/Source/_javascript_Core/ChangeLog	2016-07-11 19:08:24 UTC (rev 203075)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-07-11 19:13:05 UTC (rev 203076)
@@ -1,3 +1,40 @@
+2016-07-11  Keith Miller  <[email protected]>
+
+        STP TypedArray.subarray 5x slowdown compared to 9.1
+        https://bugs.webkit.org/show_bug.cgi?id=156404
+        <rdar://problem/26493032>
+
+        Reviewed by Geoffrey Garen.
+
+        This patch moves the species constructor work for
+        %TypedArray%.prototype.subarray to a js wrapper. By moving the
+        species constructor work to JS we are able to completely optimize
+        it out in DFG. The actual work of creating a TypedArray is still
+        done in C++ since we are able to avoid calling into the
+        constructor, which is expensive. This patch also changes the error
+        message when a %TypedArray%.prototype function is passed a non-typed
+        array this value. Finally, we used to check that the this value
+        had not been detached, however, this behavior was incorrect.
+
+        * builtins/BuiltinNames.h:
+        * builtins/TypedArrayPrototype.js:
+        (globalPrivate.typedArraySpeciesConstructor):
+        (subarray):
+        * runtime/ConstructData.cpp:
+        (JSC::construct):
+        * runtime/ConstructData.h:
+        * runtime/JSGenericTypedArrayViewPrototypeFunctions.h:
+        (JSC::genericTypedArrayViewPrivateFuncSubarrayCreate):
+        (JSC::genericTypedArrayViewProtoFuncSubarray): Deleted.
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        * runtime/JSTypedArrayViewPrototype.cpp:
+        (JSC::typedArrayViewPrivateFuncLength):
+        (JSC::typedArrayViewPrivateFuncSubarrayCreate):
+        (JSC::JSTypedArrayViewPrototype::finishCreation):
+        (JSC::typedArrayViewProtoFuncSubarray): Deleted.
+        * runtime/JSTypedArrayViewPrototype.h:
+
 2016-07-11  Yusuke Suzuki  <[email protected]>
 
         REGRESSION(r202992): JSC varargs tests are broken

Modified: trunk/Source/_javascript_Core/builtins/BuiltinNames.h (203075 => 203076)


--- trunk/Source/_javascript_Core/builtins/BuiltinNames.h	2016-07-11 19:08:24 UTC (rev 203075)
+++ trunk/Source/_javascript_Core/builtins/BuiltinNames.h	2016-07-11 19:13:05 UTC (rev 203076)
@@ -76,6 +76,7 @@
     macro(typedArrayLength) \
     macro(typedArraySort) \
     macro(typedArrayGetOriginalConstructor) \
+    macro(typedArraySubarrayCreate) \
     macro(BuiltinLog) \
     macro(homeObject) \
     macro(getTemplateObject) \

Modified: trunk/Source/_javascript_Core/builtins/TypedArrayPrototype.js (203075 => 203076)


--- trunk/Source/_javascript_Core/builtins/TypedArrayPrototype.js	2016-07-11 19:08:24 UTC (rev 203075)
+++ trunk/Source/_javascript_Core/builtins/TypedArrayPrototype.js	2016-07-11 19:13:05 UTC (rev 203076)
@@ -26,6 +26,32 @@
 // Note that the intrisic @typedArrayLength checks that the argument passed is a typed array
 // and throws if it is not.
 
+
+// Typed Arrays have their own species constructor function since they need
+// to look up their default constructor, which is expensive. If we used the
+// normal speciesConstructor helper we would need to look up the default
+// constructor every time.
+@globalPrivate
+function typedArraySpeciesConstructor(value)
+{
+    "use strict";
+    let constructor = value.constructor;
+    if (constructor === @undefined)
+        return @typedArrayGetOriginalConstructor(value);
+
+    if (!@isObject(constructor))
+        throw new @TypeError("|this|.constructor is not an Object or undefined");
+
+    constructor = constructor.@speciesSymbol;
+    if (constructor == null)
+        return @typedArrayGetOriginalConstructor(value);
+    // The lack of an @isConstructor(constructor) check here is not observable because
+    // the first thing we will do with the value is attempt to construct the result with it.
+    // If any user of this function does not immediately construct the result they need to
+    // verify that the result is a constructor.
+    return constructor;
+}
+
 function values()
 {
     "use strict";
@@ -193,6 +219,23 @@
     return this;
 }
 
+function subarray(begin, end)
+{
+    "use strict";
+
+    if (!@isTypedArrayView(this))
+        throw new @TypeError("|this| should be a typed array view");
+
+    let start = @toInteger(begin);
+    let finish;
+    if (end !== @undefined)
+        finish = @toInteger(end);
+
+    let constructor = @typedArraySpeciesConstructor(this);
+
+    return @typedArraySubarrayCreate.@call(this, start, finish, constructor);
+}
+
 function reduce(callback /* [, initialValue] */)
 {
     // 22.2.3.19

Modified: trunk/Source/_javascript_Core/runtime/ConstructData.cpp (203075 => 203076)


--- trunk/Source/_javascript_Core/runtime/ConstructData.cpp	2016-07-11 19:08:24 UTC (rev 203075)
+++ trunk/Source/_javascript_Core/runtime/ConstructData.cpp	2016-07-11 19:13:05 UTC (rev 203076)
@@ -35,7 +35,7 @@
 
 namespace JSC {
 
-JSObject* construct(ExecState* exec, JSValue constructorObject, const ArgList& args, const String& errorMessage)
+JSObject* construct(ExecState* exec, JSValue constructorObject, const ArgList& args, const char* errorMessage)
 {
     ConstructData constructData;
     ConstructType constructType = getConstructData(constructorObject, constructData);

Modified: trunk/Source/_javascript_Core/runtime/ConstructData.h (203075 => 203076)


--- trunk/Source/_javascript_Core/runtime/ConstructData.h	2016-07-11 19:08:24 UTC (rev 203075)
+++ trunk/Source/_javascript_Core/runtime/ConstructData.h	2016-07-11 19:13:05 UTC (rev 203076)
@@ -59,7 +59,7 @@
 };
 
 // Convenience wrapper so you don't need to deal with CallData and CallType unless you are going to use them.
-JSObject* construct(ExecState*, JSValue functionObject, const ArgList&, const String& errorMessage);
+JSObject* construct(ExecState*, JSValue functionObject, const ArgList&, const char* errorMessage);
 JS_EXPORT_PRIVATE JSObject* construct(ExecState*, JSValue constructor, ConstructType, const ConstructData&, const ArgList&, JSValue newTarget);
 
 ALWAYS_INLINE JSObject* construct(ExecState* exec, JSValue constructorObject, ConstructType constructType, const ConstructData& constructData, const ArgList& args)

Modified: trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewPrototypeFunctions.h (203075 => 203076)


--- trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewPrototypeFunctions.h	2016-07-11 19:08:24 UTC (rev 203075)
+++ trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewPrototypeFunctions.h	2016-07-11 19:13:05 UTC (rev 203076)
@@ -462,7 +462,7 @@
 }
 
 template<typename ViewClass>
-EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncSubarray(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL genericTypedArrayViewPrivateFuncSubarrayCreate(ExecState* exec)
 {
     // 22.2.3.23
     VM& vm = exec->vm();
@@ -475,15 +475,14 @@
     // Get the length here; later assert that the length didn't change.
     unsigned thisLength = thisObject->length();
 
+    ASSERT(exec->argument(0).isAnyInt());
+    ASSERT(exec->argument(1).isUndefined() || exec->argument(1).isAnyInt());
     unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, thisLength);
-    if (vm.exception())
-        return encodedJSValue();
+    ASSERT(!vm.exception());
     unsigned end = argumentClampedIndexFromStartOrEnd(exec, 1, thisLength, thisLength);
-    if (vm.exception())
-        return encodedJSValue();
+    ASSERT(!vm.exception());
 
-    if (thisObject->isNeutered())
-        return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
+    RELEASE_ASSERT(!thisObject->isNeutered());
 
     // Clamp end to begin.
     end = std::max(begin, end);
@@ -497,23 +496,31 @@
 
     unsigned newByteOffset = thisObject->byteOffset() + offset * ViewClass::elementSize;
 
+    JSObject* defaultConstructor = callee->globalObject()->typedArrayConstructor(ViewClass::TypedArrayStorageType);
+    JSValue species = exec->uncheckedArgument(2);
+    if (species == defaultConstructor) {
+        Structure* structure = callee->globalObject()->typedArrayStructure(ViewClass::TypedArrayStorageType);
+
+        return JSValue::encode(ViewClass::create(
+            exec, structure, arrayBuffer,
+            thisObject->byteOffset() + offset * ViewClass::elementSize,
+            length));
+    }
+
     MarkedArgumentBuffer args;
-    args.append(exec->vm().m_typedArrayController->toJS(exec, thisObject->globalObject(), thisObject->buffer()));
+    args.append(vm.m_typedArrayController->toJS(exec, thisObject->globalObject(), thisObject->buffer()));
     args.append(jsNumber(newByteOffset));
     args.append(jsNumber(length));
 
-    JSArrayBufferView* result = speciesConstruct(exec, thisObject, args, [&]() {
-        Structure* structure = callee->globalObject()->typedArrayStructure(ViewClass::TypedArrayStorageType);
-
-        return ViewClass::create(
-            exec, structure, arrayBuffer,
-            thisObject->byteOffset() + offset * ViewClass::elementSize,
-            length);
-    });
+    JSObject* result = construct(exec, species, args, "species is not a constructor");
     if (exec->hadException())
         return JSValue::encode(JSValue());
 
-    return JSValue::encode(result);
+    if (jsDynamicCast<JSArrayBufferView*>(result))
+        return JSValue::encode(result);
+
+    throwTypeError(exec, "species constructor did not return a TypedArray View");
+    return JSValue::encode(JSValue());
 }
 
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (203075 => 203076)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2016-07-11 19:08:24 UTC (rev 203075)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2016-07-11 19:13:05 UTC (rev 203076)
@@ -657,6 +657,7 @@
     JSFunction* privateFuncTypedArrayGetOriginalConstructor = JSFunction::create(vm, this, 0, String(), typedArrayViewPrivateFuncGetOriginalConstructor);
     JSFunction* privateFuncTypedArraySort = JSFunction::create(vm, this, 0, String(), typedArrayViewPrivateFuncSort);
     JSFunction* privateFuncIsTypedArrayView = JSFunction::create(vm, this, 0, String(), typedArrayViewPrivateFuncIsTypedArrayView, IsTypedArrayViewIntrinsic);
+    JSFunction* privateFuncTypedArraySubarrayCreate = JSFunction::create(vm, this, 0, String(), typedArrayViewPrivateFuncSubarrayCreate);
     JSFunction* privateFuncIsBoundFunction = JSFunction::create(vm, this, 0, String(), isBoundFunction);
     JSFunction* privateFuncHasInstanceBoundFunction = JSFunction::create(vm, this, 0, String(), hasInstanceBoundFunction);
     JSFunction* privateFuncInstanceOf = JSFunction::create(vm, this, 0, String(), objectPrivateFuncInstanceOf);
@@ -706,6 +707,7 @@
         GlobalPropertyInfo(vm.propertyNames->builtinNames().typedArrayGetOriginalConstructorPrivateName(), privateFuncTypedArrayGetOriginalConstructor, DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().typedArraySortPrivateName(), privateFuncTypedArraySort, DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().isTypedArrayViewPrivateName(), privateFuncIsTypedArrayView, DontEnum | DontDelete | ReadOnly),
+        GlobalPropertyInfo(vm.propertyNames->builtinNames().typedArraySubarrayCreatePrivateName(), privateFuncTypedArraySubarrayCreate, DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().isBoundFunctionPrivateName(), privateFuncIsBoundFunction, DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().hasInstanceBoundFunctionPrivateName(), privateFuncHasInstanceBoundFunction, DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().instanceOfPrivateName(), privateFuncInstanceOf, DontEnum | DontDelete | ReadOnly),

Modified: trunk/Source/_javascript_Core/runtime/JSTypedArrayViewPrototype.cpp (203075 => 203076)


--- trunk/Source/_javascript_Core/runtime/JSTypedArrayViewPrototype.cpp	2016-07-11 19:08:24 UTC (rev 203075)
+++ trunk/Source/_javascript_Core/runtime/JSTypedArrayViewPrototype.cpp	2016-07-11 19:13:05 UTC (rev 203076)
@@ -74,13 +74,12 @@
 {
     JSValue argument = exec->argument(0);
     if (!argument.isCell() || !isTypedView(argument.asCell()->classInfo()->typedArrayStorageType))
-        return throwVMTypeError(exec, "Receiver should be a typed array view");
+        return throwVMTypeError(exec, ASCIILiteral("Receiver should be a typed array view"));
 
     JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(argument);
-    if (!thisObject || thisObject->mode() == DataViewMode)
-        return throwVMTypeError(exec, ASCIILiteral("Receiver should be a typed array view"));
+
     if (thisObject->isNeutered())
-        return throwVMTypeError(exec, "Underlying ArrayBuffer has been detached from the view");
+        return throwVMTypeError(exec, ASCIILiteral("Underlying ArrayBuffer has been detached from the view"));
 
     return JSValue::encode(jsNumber(thisObject->length()));
 }
@@ -187,12 +186,12 @@
     CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoFuncReverse);
 }
 
-static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncSubarray(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL typedArrayViewPrivateFuncSubarrayCreate(ExecState* exec)
 {
     JSValue thisValue = exec->thisValue();
     if (!thisValue.isObject())
         return throwVMTypeError(exec, ASCIILiteral("Receiver should be a typed array view but was not an object"));
-    CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoFuncSubarray);
+    CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewPrivateFuncSubarrayCreate);
 }
 
 static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncSlice(ExecState* exec)
@@ -276,7 +275,7 @@
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->set, typedArrayViewProtoFuncSet, DontEnum, 1);
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->slice, typedArrayViewProtoFuncSlice, DontEnum, 2);
     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("some", typedArrayPrototypeSomeCodeGenerator, DontEnum);
-    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->subarray, typedArrayViewProtoFuncSubarray, DontEnum, 2);
+    JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->subarray, typedArrayPrototypeSubarrayCodeGenerator, DontEnum);
     JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toLocaleString, typedArrayPrototypeToLocaleStringCodeGenerator, DontEnum);
 
     JSFunction* toStringTagFunction = JSFunction::create(vm, globalObject, 0, ASCIILiteral("get [Symbol.toStringTag]"), typedArrayViewProtoGetterFuncToStringTag, NoIntrinsic);

Modified: trunk/Source/_javascript_Core/runtime/JSTypedArrayViewPrototype.h (203075 => 203076)


--- trunk/Source/_javascript_Core/runtime/JSTypedArrayViewPrototype.h	2016-07-11 19:08:24 UTC (rev 203075)
+++ trunk/Source/_javascript_Core/runtime/JSTypedArrayViewPrototype.h	2016-07-11 19:13:05 UTC (rev 203076)
@@ -50,6 +50,7 @@
 EncodedJSValue JSC_HOST_CALL typedArrayViewPrivateFuncSort(ExecState*);
 EncodedJSValue JSC_HOST_CALL typedArrayViewPrivateFuncLength(ExecState*);
 EncodedJSValue JSC_HOST_CALL typedArrayViewPrivateFuncGetOriginalConstructor(ExecState*);
+EncodedJSValue JSC_HOST_CALL typedArrayViewPrivateFuncSubarrayCreate(ExecState*);
 
     
 } // namespace JSC
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to