Changeset 167272 in webkit


Ignore:
Timestamp:
Apr 14, 2014 3:05:44 PM (10 years ago)
Author:
oliver@apple.com
Message:

Function.bind itself is too slow
https://bugs.webkit.org/show_bug.cgi?id=131636

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:
Rather than forcing creation of an activation, we now store
bound function properties directly on the returned closure.
This is necessary to deal with code that creates many function
bindings, but does not call them very often.

This is a 60% speed up in the included js/regress test.

  • builtins/BuiltinExecutables.cpp:

(JSC::BuiltinExecutables::createBuiltinExecutable):

  • builtins/Function.prototype.js:

(bind.bindingFunction):
(bind.else.switch.case.1.bindingFunction.bindingFunction.bindingFunction.boundOversizedCallThunk):
(bind.else.switch.case.1.bindingFunction):
(bind.else.switch.case.2.bindingFunction.bindingFunction.bindingFunction.boundOversizedCallThunk):
(bind.else.switch.case.2.bindingFunction):
(bind.else.switch.case.3.bindingFunction.bindingFunction.bindingFunction.boundOversizedCallThunk):
(bind.else.switch.case.3.bindingFunction):
(bind.else.switch.bindingFunction):
(bind):
(bind.else.switch.case.1.bindingFunction.oversizedCall): Deleted.
(bind.else.switch.case.2.bindingFunction.oversizedCall): Deleted.
(bind.else.switch.case.3.bindingFunction.oversizedCall): Deleted.

  • runtime/CommonIdentifiers.h:

LayoutTests:
New test, and fix bogus log in old one

  • js/regress/function-bind-create-expected.html: Added.
  • js/regress/function-bind-create.html: Added.
  • js/regress/script-tests/function-bind-create.js: Added.

(test):

  • js/regress/script-tests/function-bind.js:
Location:
trunk
Files:
3 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r167261 r167272  
     12014-04-14  Oliver Hunt  <oliver@apple.com>
     2
     3        Function.bind itself is too slow
     4        https://bugs.webkit.org/show_bug.cgi?id=131636
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        New test, and fix bogus log in old one
     9
     10        * js/regress/function-bind-create-expected.html: Added.
     11        * js/regress/function-bind-create.html: Added.
     12        * js/regress/script-tests/function-bind-create.js: Added.
     13        (test):
     14        * js/regress/script-tests/function-bind.js:
     15
    1162014-04-14  Brian J. Burg  <burg@cs.washington.edu>
    217
  • trunk/LayoutTests/js/regress/script-tests/function-bind.js

    r167199 r167272  
    77var g2 = foo.bind({}, 1, 2);
    88var g3 = foo.bind({}, 1, 2, 3);
    9 var start = new Date;
    109
    1110var result = 0;
     
    2423    result |= 0;
    2524}
    26 print((new Date - start))
    2725if (result != 1596499010)
    2826    throw "Bad result: " + result;
  • trunk/Source/JavaScriptCore/ChangeLog

    r167269 r167272  
     12014-04-14  Oliver Hunt  <oliver@apple.com>
     2
     3        Function.bind itself is too slow
     4        https://bugs.webkit.org/show_bug.cgi?id=131636
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        Rather than forcing creation of an activation, we now store
     9        bound function properties directly on the returned closure.
     10        This is necessary to deal with code that creates many function
     11        bindings, but does not call them very often.
     12
     13        This is a 60% speed up in the included js/regress test.
     14
     15        * builtins/BuiltinExecutables.cpp:
     16        (JSC::BuiltinExecutables::createBuiltinExecutable):
     17        * builtins/Function.prototype.js:
     18        (bind.bindingFunction):
     19        (bind.else.switch.case.1.bindingFunction.bindingFunction.bindingFunction.boundOversizedCallThunk):
     20        (bind.else.switch.case.1.bindingFunction):
     21        (bind.else.switch.case.2.bindingFunction.bindingFunction.bindingFunction.boundOversizedCallThunk):
     22        (bind.else.switch.case.2.bindingFunction):
     23        (bind.else.switch.case.3.bindingFunction.bindingFunction.bindingFunction.boundOversizedCallThunk):
     24        (bind.else.switch.case.3.bindingFunction):
     25        (bind.else.switch.bindingFunction):
     26        (bind):
     27        (bind.else.switch.case.1.bindingFunction.oversizedCall): Deleted.
     28        (bind.else.switch.case.2.bindingFunction.oversizedCall): Deleted.
     29        (bind.else.switch.case.3.bindingFunction.oversizedCall): Deleted.
     30        * runtime/CommonIdentifiers.h:
     31
    1322014-04-14  Julien Brianceau  <jbriance@cisco.com>
    233
  • trunk/Source/JavaScriptCore/builtins/Function.prototype.js

    r167199 r167272  
    4141        throw new @TypeError("Cannot bind non-function object.");
    4242    var bindingFunction;
    43     var oversizedCall = undefined;
    4443    if (arguments.length <= 1) {
    45         bindingFunction = function () {
     44        bindingFunction = function bindingFunction() {
     45            var thisValue = bindingFunction.@boundThisValue;
     46            var boundFunction = bindingFunction.@boundFunction;
    4647            if (@IsConstructor)
    4748                return new boundFunction(...arguments);
     
    5253        switch (length - 1 /* skip thisValue */) {
    5354        case 1: {
    54             var boundParameter = arguments[1];
    55             bindingFunction = function () {
     55            bindingFunction = function bindingFunction() {
     56                var thisValue = bindingFunction.@boundThisValue;
     57                var boundFunction = bindingFunction.@boundFunction;
     58                var boundParameter = bindingFunction.@boundParameter;
    5659                var argumentLength = arguments.length;
    5760                if (!argumentLength) {
     
    7679                }
    7780                var completeArguments = [boundParameter, ...arguments];
    78                 if (!oversizedCall) {
    79                     oversizedCall = function (isConstruct, boundFunction, thisValue, completeArguments) {
     81                if (!bindingFunction.@boundOversizedCallThunk) {
     82                   bindingFunction.@boundOversizedCallThunk = function (isConstruct, boundFunction, thisValue, completeArguments) {
    8083                        if (isConstruct)
    8184                            return new boundFunction(...completeArguments);
     
    8386                    }
    8487                }
    85                 return oversizedCall(@IsConstructor, boundFunction, thisValue, completeArguments);
    86             }
     88                return bindingFunction.@boundOversizedCallThunk(@IsConstructor, boundFunction, thisValue, completeArguments);
     89            }
     90            bindingFunction.@boundParameter = arguments[1];
    8791            break;
    8892        }
    8993        case 2: {
    90             var boundParameter1 = arguments[1];
    91             var boundParameter2 = arguments[2];
    92             bindingFunction = function () {
     94            bindingFunction = function bindingFunction() {
     95                var thisValue = bindingFunction.@boundThisValue;
     96                var boundFunction = bindingFunction.@boundFunction;
     97                var boundParameter1 = bindingFunction.@boundParameter1;
     98                var boundParameter2 = bindingFunction.@boundParameter2;
    9399                if (!arguments.length) {
    94100                    if (@IsConstructor)
     
    112118                }
    113119                var completeArguments = [boundParameter1, boundParameter2, ...arguments];
    114                 if (!oversizedCall) {
    115                     oversizedCall = function (isConstruct, boundFunction, thisValue, completeArguments) {
     120                if (!bindingFunction.@boundOversizedCallThunk) {
     121                    bindingFunction.@boundOversizedCallThunk = function (isConstruct, boundFunction, thisValue, completeArguments) {
    116122                        if (isConstruct)
    117123                            return new boundFunction(...completeArguments);
     
    119125                    }
    120126                }
    121                 return oversizedCall(@IsConstructor, boundFunction, thisValue, completeArguments);
    122             }
     127                return bindingFunction.@boundOversizedCallThunk(@IsConstructor, boundFunction, thisValue, completeArguments);
     128            }
     129            bindingFunction.@boundParameter1 = arguments[1];
     130            bindingFunction.@boundParameter2 = arguments[2];
    123131            break;
    124132        }
    125133        case 3: {
    126             var boundParameter1 = arguments[1];
    127             var boundParameter2 = arguments[2];
    128             var boundParameter3 = arguments[3];
    129             bindingFunction = function () {
     134            bindingFunction = function bindingFunction() {
     135                var thisValue = bindingFunction.@boundThisValue;
     136                var boundFunction = bindingFunction.@boundFunction;
     137                var boundParameter1 = bindingFunction.@boundParameter1;
     138                var boundParameter2 = bindingFunction.@boundParameter2;
     139                var boundParameter3 = bindingFunction.@boundParameter3;
    130140                if (!arguments.length) {
    131141                    if (@IsConstructor)
     
    149159                }
    150160                var completeArguments = [boundParameter1, boundParameter2, boundParameter3, ...arguments];
    151                 if (!oversizedCall) {
    152                     oversizedCall = function (isConstruct, boundFunction, thisValue, completeArguments) {
     161                if (!bindingFunction.@boundOversizedCallThunk) {
     162                    bindingFunction.@boundOversizedCallThunk = function (isConstruct, boundFunction, thisValue, completeArguments) {
    153163                        if (isConstruct)
    154164                            return new boundFunction(...completeArguments);
     
    156166                    }
    157167                }
    158                 return oversizedCall(@IsConstructor, boundFunction, thisValue, completeArguments);
    159             }
     168                return bindingFunction.@boundOversizedCallThunk(@IsConstructor, boundFunction, thisValue, completeArguments);
     169            }
     170            bindingFunction.@boundParameter1 = arguments[1];
     171            bindingFunction.@boundParameter2 = arguments[2];
     172            bindingFunction.@boundParameter3 = arguments[3];
    160173            break;
    161174        }
     
    165178                boundParameters[i - 1] = arguments[i];
    166179           
    167             bindingFunction = function () {
     180            bindingFunction = function bindingFunction() {
     181                var thisValue = bindingFunction.@boundThisValue;
     182                var boundFunction = bindingFunction.@boundFunction;
     183                var boundParameters = bindingFunction.@boundParameters;
    168184                if (!arguments.length) {
    169185                    if (@IsConstructor)
    170                         return new boundFunction(...boundParameters);
     186                        return new boundFunction(...@boundParameters);
    171187                    return boundFunction.@apply(thisValue, boundParameters);
    172188                }
    173189               
    174190                var completeArguments = [];
    175                 var localBoundParameters = boundParameters;
    176                 var boundLength = localBoundParameters.length;
     191                var boundLength = boundParameters.length;
    177192                for (var i = 0; i < boundLength; i++)
    178                     completeArguments[i] = localBoundParameters[i];
     193                    completeArguments[i] = boundParameters[i];
    179194                for (var i = 0; i < arguments.length; i++)
    180195                    completeArguments[i + boundLength] = arguments[i];
     
    184199                    return boundFunction.@apply(thisValue, completeArguments);
    185200            }
     201            bindingFunction.@boundParameters = boundParameters;
    186202        }
    187203    }
     204    bindingFunction.@boundThisValue = thisValue;
    188205    bindingFunction.@boundFunctionName = this.name;
    189206    bindingFunction.@boundFunction = boundFunction.@boundFunction || boundFunction;
  • trunk/Source/JavaScriptCore/runtime/CommonIdentifiers.h

    r167199 r167272  
    224224    macro(boundFunctionName) \
    225225    macro(boundFunctionParameters) \
     226    macro(boundThisValue) \
     227    macro(boundParameter) \
     228    macro(boundParameter1) \
     229    macro(boundParameter2) \
     230    macro(boundParameter3) \
     231    macro(boundParameters) \
     232    macro(boundOversizedCallThunk) \
    226233    macro(boundFunction) \
    227234    macro(boundFunctionLength) \
Note: See TracChangeset for help on using the changeset viewer.