Title: [251671] trunk
Revision
251671
Author
ysuz...@apple.com
Date
2019-10-28 14:13:57 -0700 (Mon, 28 Oct 2019)

Log Message

[JSC] Optimize Promise runtime functions
https://bugs.webkit.org/show_bug.cgi?id=203454

Reviewed by Keith Miller.

JSTests:

* microbenchmarks/promise-reject.js: Added.
* microbenchmarks/promise-resolve.js: Added.

Source/_javascript_Core:

This patch optimizes Promise runtime functions a bit.

1. Add fast paths to Promise.resolve / Promise.reject.
2. Remove state check in async-functions. Unlike generators, async-function's next function is not exposed to users.
   It is called by runtime so we can control state perfectly.
3. Add "enqueueJob" name to make sampling profiler work for this function.
4. Make Promise/InternalPromise constructor inlinable size

                                      ToT                     Patched

    promise-creation-many       25.5794+-0.3681     ^     22.5410+-0.3229        ^ definitely 1.1348x faster
    promise-resolve             32.3793+-0.4252     ^      9.4219+-0.1114        ^ definitely 3.4366x faster
    promise-reject             108.5968+-0.7741     ^     36.9383+-0.3770        ^ definitely 2.9400x faster

* builtins/AsyncFunctionPrototype.js:
(globalPrivate.asyncFunctionResume):
* builtins/PromiseConstructor.js:
(reject):
(resolve):
(nakedConstructor.Promise.reject):
(nakedConstructor.Promise):
(nakedConstructor.InternalPromise.reject):
(nakedConstructor.InternalPromise):
(nakedConstructor.Promise.resolve): Deleted.
(nakedConstructor.InternalPromise.resolve): Deleted.
* builtins/PromiseOperations.js:
(globalPrivate.newPromiseCapability.resolve):
(globalPrivate.newPromiseCapability.reject):
(globalPrivate.newPromiseCapability):
(globalPrivate.promiseResolveSlow):
(globalPrivate.promiseRejectSlow):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):

LayoutTests:

* inspector/console/message-stack-trace-expected.txt:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (251670 => 251671)


--- trunk/JSTests/ChangeLog	2019-10-28 20:50:47 UTC (rev 251670)
+++ trunk/JSTests/ChangeLog	2019-10-28 21:13:57 UTC (rev 251671)
@@ -1,3 +1,13 @@
+2019-10-28  Yusuke Suzuki  <ysuz...@apple.com>
+
+        [JSC] Optimize Promise runtime functions
+        https://bugs.webkit.org/show_bug.cgi?id=203454
+
+        Reviewed by Keith Miller.
+
+        * microbenchmarks/promise-reject.js: Added.
+        * microbenchmarks/promise-resolve.js: Added.
+
 2019-10-25  Ross Kirsling  <ross.kirsl...@sony.com>
 
         test262-runner should be able to pass JSC a feature flag

Added: trunk/JSTests/microbenchmarks/promise-reject.js (0 => 251671)


--- trunk/JSTests/microbenchmarks/promise-reject.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/promise-reject.js	2019-10-28 21:13:57 UTC (rev 251671)
@@ -0,0 +1,2 @@
+for (var i = 0; i < 1e6; ++i)
+    Promise.reject(42);

Added: trunk/JSTests/microbenchmarks/promise-resolve.js (0 => 251671)


--- trunk/JSTests/microbenchmarks/promise-resolve.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/promise-resolve.js	2019-10-28 21:13:57 UTC (rev 251671)
@@ -0,0 +1,2 @@
+for (var i = 0; i < 1e6; ++i)
+    Promise.resolve(42);

Modified: trunk/LayoutTests/ChangeLog (251670 => 251671)


--- trunk/LayoutTests/ChangeLog	2019-10-28 20:50:47 UTC (rev 251670)
+++ trunk/LayoutTests/ChangeLog	2019-10-28 21:13:57 UTC (rev 251671)
@@ -1,3 +1,12 @@
+2019-10-28  Yusuke Suzuki  <ysuz...@apple.com>
+
+        [JSC] Optimize Promise runtime functions
+        https://bugs.webkit.org/show_bug.cgi?id=203454
+
+        Reviewed by Keith Miller.
+
+        * inspector/console/message-stack-trace-expected.txt:
+
 2019-10-28  Truitt Savell  <tsav...@apple.com>
 
         Two imported tests from r251591 are failing

Modified: trunk/LayoutTests/inspector/console/message-stack-trace-expected.txt (251670 => 251671)


--- trunk/LayoutTests/inspector/console/message-stack-trace-expected.txt	2019-10-28 20:50:47 UTC (rev 251670)
+++ trunk/LayoutTests/inspector/console/message-stack-trace-expected.txt	2019-10-28 21:13:57 UTC (rev 251671)
@@ -27,8 +27,9 @@
 CALL STACK:
 0: [N] (anonymous function)
 1: [N] rejectPromise
-2: [N] reject
-3: [F] triggerUnhandledRejectionPromiseReject
+2: [N] rejectPromiseWithFirstResolvingFunctionCallCheck
+3: [N] reject
+4: [F] triggerUnhandledRejectionPromiseReject
 
 -- Running test case: Console.StackTrace.UnhandledPromiseRejection.ExplicitReject
 CALL STACK:

Modified: trunk/Source/_javascript_Core/ChangeLog (251670 => 251671)


--- trunk/Source/_javascript_Core/ChangeLog	2019-10-28 20:50:47 UTC (rev 251670)
+++ trunk/Source/_javascript_Core/ChangeLog	2019-10-28 21:13:57 UTC (rev 251671)
@@ -1,5 +1,46 @@
 2019-10-28  Yusuke Suzuki  <ysuz...@apple.com>
 
+        [JSC] Optimize Promise runtime functions
+        https://bugs.webkit.org/show_bug.cgi?id=203454
+
+        Reviewed by Keith Miller.
+
+        This patch optimizes Promise runtime functions a bit.
+
+        1. Add fast paths to Promise.resolve / Promise.reject.
+        2. Remove state check in async-functions. Unlike generators, async-function's next function is not exposed to users.
+           It is called by runtime so we can control state perfectly.
+        3. Add "enqueueJob" name to make sampling profiler work for this function.
+        4. Make Promise/InternalPromise constructor inlinable size
+
+                                              ToT                     Patched
+
+            promise-creation-many       25.5794+-0.3681     ^     22.5410+-0.3229        ^ definitely 1.1348x faster
+            promise-resolve             32.3793+-0.4252     ^      9.4219+-0.1114        ^ definitely 3.4366x faster
+            promise-reject             108.5968+-0.7741     ^     36.9383+-0.3770        ^ definitely 2.9400x faster
+
+        * builtins/AsyncFunctionPrototype.js:
+        (globalPrivate.asyncFunctionResume):
+        * builtins/PromiseConstructor.js:
+        (reject):
+        (resolve):
+        (nakedConstructor.Promise.reject):
+        (nakedConstructor.Promise):
+        (nakedConstructor.InternalPromise.reject):
+        (nakedConstructor.InternalPromise):
+        (nakedConstructor.Promise.resolve): Deleted.
+        (nakedConstructor.InternalPromise.resolve): Deleted.
+        * builtins/PromiseOperations.js:
+        (globalPrivate.newPromiseCapability.resolve):
+        (globalPrivate.newPromiseCapability.reject):
+        (globalPrivate.newPromiseCapability):
+        (globalPrivate.promiseResolveSlow):
+        (globalPrivate.promiseRejectSlow):
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+
+2019-10-28  Yusuke Suzuki  <ysuz...@apple.com>
+
         [JSC] Use FTLOutput::callWithoutSideEffects if operation does not have side effects
         https://bugs.webkit.org/show_bug.cgi?id=203485
 

Modified: trunk/Source/_javascript_Core/builtins/AsyncFunctionPrototype.js (251670 => 251671)


--- trunk/Source/_javascript_Core/builtins/AsyncFunctionPrototype.js	2019-10-28 20:50:47 UTC (rev 251670)
+++ trunk/Source/_javascript_Core/builtins/AsyncFunctionPrototype.js	2019-10-28 21:13:57 UTC (rev 251671)
@@ -34,26 +34,23 @@
     var state = @getGeneratorInternalField(generator, @generatorFieldState);
     var value = @undefined;
 
-    if (state === @GeneratorStateCompleted || (resumeMode !== @GeneratorResumeModeNormal && resumeMode !== @GeneratorResumeModeThrow))
-        @throwTypeError("Async function illegally resumed");
-
     try {
         @putGeneratorInternalField(generator, @generatorFieldState, @GeneratorStateExecuting);
         value = @getGeneratorInternalField(generator, @generatorFieldNext).@call(@getGeneratorInternalField(generator, @generatorFieldThis), generator, state, sentValue, resumeMode, @getGeneratorInternalField(generator, @generatorFieldFrame));
         if (@getGeneratorInternalField(generator, @generatorFieldState) === @GeneratorStateExecuting) {
-            @putGeneratorInternalField(generator, @generatorFieldState, @GeneratorStateCompleted);
             @resolvePromiseWithFirstResolvingFunctionCallCheck(promise, value);
             return promise;
         }
     } catch (error) {
-        @putGeneratorInternalField(generator, @generatorFieldState, @GeneratorStateCompleted);
         @rejectPromiseWithFirstResolvingFunctionCallCheck(promise, error);
         return promise;
     }
 
+    var capturedGenerator = generator;
+    var capturedPromise = promise;
     @resolveWithoutPromise(value,
-        function(value) { @asyncFunctionResume(generator, promise, value, @GeneratorResumeModeNormal); },
-        function(error) { @asyncFunctionResume(generator, promise, error, @GeneratorResumeModeThrow); });
+        function(value) { @asyncFunctionResume(capturedGenerator, capturedPromise, value, @GeneratorResumeModeNormal); },
+        function(error) { @asyncFunctionResume(capturedGenerator, capturedPromise, error, @GeneratorResumeModeThrow); });
 
     return promise;
 }

Modified: trunk/Source/_javascript_Core/builtins/PromiseConstructor.js (251670 => 251671)


--- trunk/Source/_javascript_Core/builtins/PromiseConstructor.js	2019-10-28 20:50:47 UTC (rev 251670)
+++ trunk/Source/_javascript_Core/builtins/PromiseConstructor.js	2019-10-28 21:13:57 UTC (rev 251671)
@@ -195,11 +195,13 @@
     if (!@isObject(this))
         @throwTypeError("|this| is not an object");
 
-    var promiseCapability = @newPromiseCapability(this);
+    if (this === @Promise) {
+        var promise = @newPromise();
+        @rejectPromiseWithFirstResolvingFunctionCallCheck(promise, reason);
+        return promise;
+    }
 
-    promiseCapability.@reject.@call(@undefined, reason);
-
-    return promiseCapability.@promise;
+    return @promiseRejectSlow(this, reason);
 }
 
 function resolve(value)
@@ -215,11 +217,13 @@
             return value;
     }
 
-    var promiseCapability = @newPromiseCapability(this);
+    if (this === @Promise) {
+        var promise = @newPromise();
+        @resolvePromiseWithFirstResolvingFunctionCallCheck(promise, value);
+        return promise;
+    }
 
-    promiseCapability.@resolve.@call(@undefined, value);
-
-    return promiseCapability.@promise;
+    return @promiseResolveSlow(this, value);
 }
 
 @nakedConstructor
@@ -230,19 +234,20 @@
     if (typeof executor !== "function")
         @throwTypeError("Promise constructor takes a function argument");
 
-    var promise = @createPromise(new.target, /* isInternalPromise */ false);
+    var promise = @createPromise(this, /* isInternalPromise */ false);
     var capturedPromise = promise;
 
-    function @resolve(resolution) {
-        return @resolvePromiseWithFirstResolvingFunctionCallCheck(capturedPromise, resolution);
-    }
-
-    function @reject(reason) {
+    // FIXME: We should allow using function-declaration here.
+    // https://bugs.webkit.org/show_bug.cgi?id=203502
+    var @reject = function @reject(reason) {
         return @rejectPromiseWithFirstResolvingFunctionCallCheck(capturedPromise, reason);
-    }
+    };
 
     try {
-        executor(@resolve, @reject);
+        executor(
+            function @resolve(resolution) {
+                return @resolvePromiseWithFirstResolvingFunctionCallCheck(capturedPromise, resolution);
+            }, @reject);
     } catch (error) {
         @reject(error);
     }
@@ -258,19 +263,20 @@
     if (typeof executor !== "function")
         @throwTypeError("InternalPromise constructor takes a function argument");
 
-    var promise = @createPromise(new.target, /* isInternalPromise */ true);
+    var promise = @createPromise(this, /* isInternalPromise */ true);
     var capturedPromise = promise;
 
-    function @resolve(resolution) {
-        return @resolvePromiseWithFirstResolvingFunctionCallCheck(capturedPromise, resolution);
-    }
-
-    function @reject(reason) {
+    // FIXME: We should allow using function-declaration here.
+    // https://bugs.webkit.org/show_bug.cgi?id=203502
+    var @reject = function @reject(reason) {
         return @rejectPromiseWithFirstResolvingFunctionCallCheck(capturedPromise, reason);
-    }
+    };
 
     try {
-        executor(@resolve, @reject);
+        executor(
+            function @resolve(resolution) {
+                return @resolvePromiseWithFirstResolvingFunctionCallCheck(capturedPromise, resolution);
+            }, @reject);
     } catch (error) {
         @reject(error);
     }

Modified: trunk/Source/_javascript_Core/builtins/PromiseOperations.js (251670 => 251671)


--- trunk/Source/_javascript_Core/builtins/PromiseOperations.js	2019-10-28 20:50:47 UTC (rev 251670)
+++ trunk/Source/_javascript_Core/builtins/PromiseOperations.js	2019-10-28 21:13:57 UTC (rev 251671)
@@ -82,9 +82,14 @@
 
     if (constructor === @Promise) {
         var promise = @newPromise();
-        var resolvingFunctions = @createResolvingFunctions(promise);
-        @putByIdDirectPrivate(resolvingFunctions, "promise", promise);
-        return resolvingFunctions;
+        var capturedPromise = promise;
+        function @resolve(resolution) {
+            return @resolvePromiseWithFirstResolvingFunctionCallCheck(capturedPromise, resolution);
+        }
+        function @reject(reason) {
+            return @rejectPromiseWithFirstResolvingFunctionCallCheck(capturedPromise, reason);
+        }
+        return { @resolve, @reject, @promise: promise };
     }
 
     return @newPromiseCapabilitySlow(constructor);
@@ -91,6 +96,24 @@
 }
 
 @globalPrivate
+function promiseResolveSlow(constructor, value)
+{
+    @assert(constructor !== @Promise);
+    var promiseCapability = @newPromiseCapabilitySlow(constructor);
+    promiseCapability.@resolve.@call(@undefined, value);
+    return promiseCapability.@promise;
+}
+
+@globalPrivate
+function promiseRejectSlow(constructor, reason)
+{
+    @assert(constructor !== @Promise);
+    var promiseCapability = @newPromiseCapabilitySlow(constructor);
+    promiseCapability.@reject.@call(@undefined, reason);
+    return promiseCapability.@promise;
+}
+
+@globalPrivate
 function newHandledRejectedPromise(error)
 {
     "use strict";

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (251670 => 251671)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2019-10-28 20:50:47 UTC (rev 251670)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2019-10-28 21:13:57 UTC (rev 251671)
@@ -990,7 +990,7 @@
         GlobalPropertyInfo(vm.propertyNames->builtinNames().propertyIsEnumerablePrivateName(), privateFuncPropertyIsEnumerable, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().ownKeysPrivateName(), privateFuncOwnKeys, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().importModulePrivateName(), privateFuncImportModule, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
-        GlobalPropertyInfo(vm.propertyNames->builtinNames().enqueueJobPrivateName(), JSFunction::create(vm, this, 0, String(), enqueueJob), PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
+        GlobalPropertyInfo(vm.propertyNames->builtinNames().enqueueJobPrivateName(), JSFunction::create(vm, this, 0, "enqueueJob"_s, enqueueJob), PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().makeTypeErrorPrivateName(), privateFuncMakeTypeError, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().typedArrayLengthPrivateName(), privateFuncTypedArrayLength, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().typedArrayGetOriginalConstructorPrivateName(), privateFuncTypedArrayGetOriginalConstructor, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to