Changeset 251671 in webkit


Ignore:
Timestamp:
Oct 28, 2019 2:13:57 PM (5 years ago)
Author:
ysuzuki@apple.com
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/JavaScriptCore:

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:
Location:
trunk
Files:
2 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r251588 r251671  
     12019-10-28  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Optimize Promise runtime functions
     4        https://bugs.webkit.org/show_bug.cgi?id=203454
     5
     6        Reviewed by Keith Miller.
     7
     8        * microbenchmarks/promise-reject.js: Added.
     9        * microbenchmarks/promise-resolve.js: Added.
     10
    1112019-10-25  Ross Kirsling  <ross.kirsling@sony.com>
    212
  • trunk/LayoutTests/ChangeLog

    r251668 r251671  
     12019-10-28  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Optimize Promise runtime functions
     4        https://bugs.webkit.org/show_bug.cgi?id=203454
     5
     6        Reviewed by Keith Miller.
     7
     8        * inspector/console/message-stack-trace-expected.txt:
     9
    1102019-10-28  Truitt Savell  <tsavell@apple.com>
    211
  • trunk/LayoutTests/inspector/console/message-stack-trace-expected.txt

    r249509 r251671  
    28280: [N] (anonymous function)
    29291: [N] rejectPromise
    30 2: [N] reject
    31 3: [F] triggerUnhandledRejectionPromiseReject
     302: [N] rejectPromiseWithFirstResolvingFunctionCallCheck
     313: [N] reject
     324: [F] triggerUnhandledRejectionPromiseReject
    3233
    3334-- Running test case: Console.StackTrace.UnhandledPromiseRejection.ExplicitReject
  • trunk/Source/JavaScriptCore/ChangeLog

    r251669 r251671  
     12019-10-28  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Optimize Promise runtime functions
     4        https://bugs.webkit.org/show_bug.cgi?id=203454
     5
     6        Reviewed by Keith Miller.
     7
     8        This patch optimizes Promise runtime functions a bit.
     9
     10        1. Add fast paths to Promise.resolve / Promise.reject.
     11        2. Remove state check in async-functions. Unlike generators, async-function's next function is not exposed to users.
     12           It is called by runtime so we can control state perfectly.
     13        3. Add "enqueueJob" name to make sampling profiler work for this function.
     14        4. Make Promise/InternalPromise constructor inlinable size
     15
     16                                              ToT                     Patched
     17
     18            promise-creation-many       25.5794+-0.3681     ^     22.5410+-0.3229        ^ definitely 1.1348x faster
     19            promise-resolve             32.3793+-0.4252     ^      9.4219+-0.1114        ^ definitely 3.4366x faster
     20            promise-reject             108.5968+-0.7741     ^     36.9383+-0.3770        ^ definitely 2.9400x faster
     21
     22        * builtins/AsyncFunctionPrototype.js:
     23        (globalPrivate.asyncFunctionResume):
     24        * builtins/PromiseConstructor.js:
     25        (reject):
     26        (resolve):
     27        (nakedConstructor.Promise.reject):
     28        (nakedConstructor.Promise):
     29        (nakedConstructor.InternalPromise.reject):
     30        (nakedConstructor.InternalPromise):
     31        (nakedConstructor.Promise.resolve): Deleted.
     32        (nakedConstructor.InternalPromise.resolve): Deleted.
     33        * builtins/PromiseOperations.js:
     34        (globalPrivate.newPromiseCapability.resolve):
     35        (globalPrivate.newPromiseCapability.reject):
     36        (globalPrivate.newPromiseCapability):
     37        (globalPrivate.promiseResolveSlow):
     38        (globalPrivate.promiseRejectSlow):
     39        * runtime/JSGlobalObject.cpp:
     40        (JSC::JSGlobalObject::init):
     41
    1422019-10-28  Yusuke Suzuki  <ysuzuki@apple.com>
    243
  • trunk/Source/JavaScriptCore/builtins/AsyncFunctionPrototype.js

    r250025 r251671  
    3535    var value = @undefined;
    3636
    37     if (state === @GeneratorStateCompleted || (resumeMode !== @GeneratorResumeModeNormal && resumeMode !== @GeneratorResumeModeThrow))
    38         @throwTypeError("Async function illegally resumed");
    39 
    4037    try {
    4138        @putGeneratorInternalField(generator, @generatorFieldState, @GeneratorStateExecuting);
    4239        value = @getGeneratorInternalField(generator, @generatorFieldNext).@call(@getGeneratorInternalField(generator, @generatorFieldThis), generator, state, sentValue, resumeMode, @getGeneratorInternalField(generator, @generatorFieldFrame));
    4340        if (@getGeneratorInternalField(generator, @generatorFieldState) === @GeneratorStateExecuting) {
    44             @putGeneratorInternalField(generator, @generatorFieldState, @GeneratorStateCompleted);
    4541            @resolvePromiseWithFirstResolvingFunctionCallCheck(promise, value);
    4642            return promise;
    4743        }
    4844    } catch (error) {
    49         @putGeneratorInternalField(generator, @generatorFieldState, @GeneratorStateCompleted);
    5045        @rejectPromiseWithFirstResolvingFunctionCallCheck(promise, error);
    5146        return promise;
    5247    }
    5348
     49    var capturedGenerator = generator;
     50    var capturedPromise = promise;
    5451    @resolveWithoutPromise(value,
    55         function(value) { @asyncFunctionResume(generator, promise, value, @GeneratorResumeModeNormal); },
    56         function(error) { @asyncFunctionResume(generator, promise, error, @GeneratorResumeModeThrow); });
     52        function(value) { @asyncFunctionResume(capturedGenerator, capturedPromise, value, @GeneratorResumeModeNormal); },
     53        function(error) { @asyncFunctionResume(capturedGenerator, capturedPromise, error, @GeneratorResumeModeThrow); });
    5754
    5855    return promise;
  • trunk/Source/JavaScriptCore/builtins/PromiseConstructor.js

    r249552 r251671  
    196196        @throwTypeError("|this| is not an object");
    197197
    198     var promiseCapability = @newPromiseCapability(this);
    199 
    200     promiseCapability.@reject.@call(@undefined, reason);
    201 
    202     return promiseCapability.@promise;
     198    if (this === @Promise) {
     199        var promise = @newPromise();
     200        @rejectPromiseWithFirstResolvingFunctionCallCheck(promise, reason);
     201        return promise;
     202    }
     203
     204    return @promiseRejectSlow(this, reason);
    203205}
    204206
     
    216218    }
    217219
    218     var promiseCapability = @newPromiseCapability(this);
    219 
    220     promiseCapability.@resolve.@call(@undefined, value);
    221 
    222     return promiseCapability.@promise;
     220    if (this === @Promise) {
     221        var promise = @newPromise();
     222        @resolvePromiseWithFirstResolvingFunctionCallCheck(promise, value);
     223        return promise;
     224    }
     225
     226    return @promiseResolveSlow(this, value);
    223227}
    224228
     
    231235        @throwTypeError("Promise constructor takes a function argument");
    232236
    233     var promise = @createPromise(new.target, /* isInternalPromise */ false);
     237    var promise = @createPromise(this, /* isInternalPromise */ false);
    234238    var capturedPromise = promise;
    235239
    236     function @resolve(resolution) {
    237         return @resolvePromiseWithFirstResolvingFunctionCallCheck(capturedPromise, resolution);
    238     }
    239 
    240     function @reject(reason) {
     240    // FIXME: We should allow using function-declaration here.
     241    // https://bugs.webkit.org/show_bug.cgi?id=203502
     242    var @reject = function @reject(reason) {
    241243        return @rejectPromiseWithFirstResolvingFunctionCallCheck(capturedPromise, reason);
    242     }
    243 
    244     try {
    245         executor(@resolve, @reject);
     244    };
     245
     246    try {
     247        executor(
     248            function @resolve(resolution) {
     249                return @resolvePromiseWithFirstResolvingFunctionCallCheck(capturedPromise, resolution);
     250            }, @reject);
    246251    } catch (error) {
    247252        @reject(error);
     
    259264        @throwTypeError("InternalPromise constructor takes a function argument");
    260265
    261     var promise = @createPromise(new.target, /* isInternalPromise */ true);
     266    var promise = @createPromise(this, /* isInternalPromise */ true);
    262267    var capturedPromise = promise;
    263268
    264     function @resolve(resolution) {
    265         return @resolvePromiseWithFirstResolvingFunctionCallCheck(capturedPromise, resolution);
    266     }
    267 
    268     function @reject(reason) {
     269    // FIXME: We should allow using function-declaration here.
     270    // https://bugs.webkit.org/show_bug.cgi?id=203502
     271    var @reject = function @reject(reason) {
    269272        return @rejectPromiseWithFirstResolvingFunctionCallCheck(capturedPromise, reason);
    270     }
    271 
    272     try {
    273         executor(@resolve, @reject);
     273    };
     274
     275    try {
     276        executor(
     277            function @resolve(resolution) {
     278                return @resolvePromiseWithFirstResolvingFunctionCallCheck(capturedPromise, resolution);
     279            }, @reject);
    274280    } catch (error) {
    275281        @reject(error);
  • trunk/Source/JavaScriptCore/builtins/PromiseOperations.js

    r249509 r251671  
    8383    if (constructor === @Promise) {
    8484        var promise = @newPromise();
    85         var resolvingFunctions = @createResolvingFunctions(promise);
    86         @putByIdDirectPrivate(resolvingFunctions, "promise", promise);
    87         return resolvingFunctions;
     85        var capturedPromise = promise;
     86        function @resolve(resolution) {
     87            return @resolvePromiseWithFirstResolvingFunctionCallCheck(capturedPromise, resolution);
     88        }
     89        function @reject(reason) {
     90            return @rejectPromiseWithFirstResolvingFunctionCallCheck(capturedPromise, reason);
     91        }
     92        return { @resolve, @reject, @promise: promise };
    8893    }
    8994
    9095    return @newPromiseCapabilitySlow(constructor);
     96}
     97
     98@globalPrivate
     99function promiseResolveSlow(constructor, value)
     100{
     101    @assert(constructor !== @Promise);
     102    var promiseCapability = @newPromiseCapabilitySlow(constructor);
     103    promiseCapability.@resolve.@call(@undefined, value);
     104    return promiseCapability.@promise;
     105}
     106
     107@globalPrivate
     108function promiseRejectSlow(constructor, reason)
     109{
     110    @assert(constructor !== @Promise);
     111    var promiseCapability = @newPromiseCapabilitySlow(constructor);
     112    promiseCapability.@reject.@call(@undefined, reason);
     113    return promiseCapability.@promise;
    91114}
    92115
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp

    r251556 r251671  
    991991        GlobalPropertyInfo(vm.propertyNames->builtinNames().ownKeysPrivateName(), privateFuncOwnKeys, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
    992992        GlobalPropertyInfo(vm.propertyNames->builtinNames().importModulePrivateName(), privateFuncImportModule, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
    993         GlobalPropertyInfo(vm.propertyNames->builtinNames().enqueueJobPrivateName(), JSFunction::create(vm, this, 0, String(), enqueueJob), PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
     993        GlobalPropertyInfo(vm.propertyNames->builtinNames().enqueueJobPrivateName(), JSFunction::create(vm, this, 0, "enqueueJob"_s, enqueueJob), PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
    994994        GlobalPropertyInfo(vm.propertyNames->builtinNames().makeTypeErrorPrivateName(), privateFuncMakeTypeError, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
    995995        GlobalPropertyInfo(vm.propertyNames->builtinNames().typedArrayLengthPrivateName(), privateFuncTypedArrayLength, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
Note: See TracChangeset for help on using the changeset viewer.