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