Why is .bind so slow?

classic Classic list List threaded Threaded
25 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Why is .bind so slow?

Claus Reinke
The TypeScript project tries to emulate arrow functions through the
"_this = this" pattern and keeps running into corner cases where a
semi-naïve renaming is not sufficient.

I have been trying to suggest using .bind to emulate arrow functions
instead, but the counter-arguments are (a) .bind might not be available
(supporting pre-ES5 targets) and (b) .bind is slow.

The polyfill isn't the problem, but I'm a bit shocked every time
someone reminds me of the performance hit for using .bind. Given
that a bound function has strictly more info than an unbound one,
I wouldn't expect that (I expected a bound function to be roughly
the same as an unbound function that does not use "this"). Unless
there is no special casing for the just-add-this case, and .bind is
always treated as a non-standard (meta-level) call.

While playing with test-code, I also found that v8 does a lot better
than other engines when using an .apply-based .bind emulation.

Can anyone explain what is going on with .bind, .apply and the
performance hits?

The TypeScript issue is https://typescript.codeplex.com/workitem/1322 .
My test code (*) is attached there as "bind-for-arrows.html".

Claus
http://clausreinke.github.com/

(*) I also tried to make a jsperf test case, but the way jsperf
    runs the loop seems to prevent the optimization that makes
    v8 look good for the .apply-based bind.
 

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why is .bind so slow?

Allen Wirfs-Brock
you might consider ticketing performance bugs against the various implementations.

Allen


On Jul 10, 2013, at 9:16 AM, Claus Reinke wrote:

> The TypeScript project tries to emulate arrow functions through the
> "_this = this" pattern and keeps running into corner cases where a
> semi-naïve renaming is not sufficient.
>
> I have been trying to suggest using .bind to emulate arrow functions
> instead, but the counter-arguments are (a) .bind might not be available
> (supporting pre-ES5 targets) and (b) .bind is slow.
>
> The polyfill isn't the problem, but I'm a bit shocked every time
> someone reminds me of the performance hit for using .bind. Given
> that a bound function has strictly more info than an unbound one,
> I wouldn't expect that (I expected a bound function to be roughly
> the same as an unbound function that does not use "this"). Unless
> there is no special casing for the just-add-this case, and .bind is
> always treated as a non-standard (meta-level) call.
>
> While playing with test-code, I also found that v8 does a lot better
> than other engines when using an .apply-based .bind emulation.
>
> Can anyone explain what is going on with .bind, .apply and the
> performance hits?
>
> The TypeScript issue is https://typescript.codeplex.com/workitem/1322 .
> My test code (*) is attached there as "bind-for-arrows.html".
>
> Claus
> http://clausreinke.github.com/
>
> (*) I also tried to make a jsperf test case, but the way jsperf
>   runs the loop seems to prevent the optimization that makes
>   v8 look good for the .apply-based bind.
>
> _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why is .bind so slow?

Mark S. Miller-2
If you can manage it, most effective would be to get .bind (or any other operation you want to be faster) into some widely quoted benchmark suite.


On Fri, Jul 12, 2013 at 9:46 AM, Allen Wirfs-Brock <[hidden email]> wrote:
you might consider ticketing performance bugs against the various implementations.

Allen


On Jul 10, 2013, at 9:16 AM, Claus Reinke wrote:

> The TypeScript project tries to emulate arrow functions through the
> "_this = this" pattern and keeps running into corner cases where a
> semi-naïve renaming is not sufficient.
>
> I have been trying to suggest using .bind to emulate arrow functions
> instead, but the counter-arguments are (a) .bind might not be available
> (supporting pre-ES5 targets) and (b) .bind is slow.
>
> The polyfill isn't the problem, but I'm a bit shocked every time
> someone reminds me of the performance hit for using .bind. Given
> that a bound function has strictly more info than an unbound one,
> I wouldn't expect that (I expected a bound function to be roughly
> the same as an unbound function that does not use "this"). Unless
> there is no special casing for the just-add-this case, and .bind is
> always treated as a non-standard (meta-level) call.
>
> While playing with test-code, I also found that v8 does a lot better
> than other engines when using an .apply-based .bind emulation.
>
> Can anyone explain what is going on with .bind, .apply and the
> performance hits?
>
> The TypeScript issue is https://typescript.codeplex.com/workitem/1322 .
> My test code (*) is attached there as "bind-for-arrows.html".
>
> Claus
> http://clausreinke.github.com/
>
> (*) I also tried to make a jsperf test case, but the way jsperf
>   runs the loop seems to prevent the optimization that makes
>   v8 look good for the .apply-based bind.
>
> _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



--
    Cheers,
    --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why is .bind so slow?

Andrea Giammarchi-2
I think we all know that's extremely slow and since ever.
I always wondered the reason too ... in jsperf there are tons of tests about this, here yet another one just quickly created to compare the gap:

in Chrome, bind(context) without even arguments is 87% slower than a closure with call


On Fri, Jul 12, 2013 at 10:09 AM, Mark S. Miller <[hidden email]> wrote:
If you can manage it, most effective would be to get .bind (or any other operation you want to be faster) into some widely quoted benchmark suite.


On Fri, Jul 12, 2013 at 9:46 AM, Allen Wirfs-Brock <[hidden email]> wrote:
you might consider ticketing performance bugs against the various implementations.

Allen


On Jul 10, 2013, at 9:16 AM, Claus Reinke wrote:

> The TypeScript project tries to emulate arrow functions through the
> "_this = this" pattern and keeps running into corner cases where a
> semi-naïve renaming is not sufficient.
>
> I have been trying to suggest using .bind to emulate arrow functions
> instead, but the counter-arguments are (a) .bind might not be available
> (supporting pre-ES5 targets) and (b) .bind is slow.
>
> The polyfill isn't the problem, but I'm a bit shocked every time
> someone reminds me of the performance hit for using .bind. Given
> that a bound function has strictly more info than an unbound one,
> I wouldn't expect that (I expected a bound function to be roughly
> the same as an unbound function that does not use "this"). Unless
> there is no special casing for the just-add-this case, and .bind is
> always treated as a non-standard (meta-level) call.
>
> While playing with test-code, I also found that v8 does a lot better
> than other engines when using an .apply-based .bind emulation.
>
> Can anyone explain what is going on with .bind, .apply and the
> performance hits?
>
> The TypeScript issue is https://typescript.codeplex.com/workitem/1322 .
> My test code (*) is attached there as "bind-for-arrows.html".
>
> Claus
> http://clausreinke.github.com/
>
> (*) I also tried to make a jsperf test case, but the way jsperf
>   runs the loop seems to prevent the optimization that makes
>   v8 look good for the .apply-based bind.
>
> _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



--
    Cheers,
    --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why is .bind so slow?

Filip Pizlo
In reply to this post by Mark S. Miller-2

On Jul 12, 2013, at 10:09 AM, "Mark S. Miller" <[hidden email]> wrote:

If you can manage it, most effective would be to get .bind (or any other operation you want to be faster) into some widely quoted benchmark suite.

In WebKit at least, we have a thing called JSRegress which is meant to be a dumping ground for benchmarks for interesting corners of the language. Microbenchmarks are welcome; the goal is to just expand coverage of things that we measure timings of. It's not widely quoted, and it doesn't get the same priority as "macrobenchmark" suites, but we do care about it and we do optimize for it. For example, all of our optimization a for typeof, switch, and 'in' arose from JSRegress tests, since none of those things were hot enough in any of the "major" benchmarks. 

We don't have coverage for bind, and it would be great to fix that. 

If you have a standalone program that uses bind, you can either post a patch on bugs.webkit.org that adds it to JSRegress (I.e. LayoutTests/fast/js/regress/script-tests), or if you're lazy, you can just email the program to me and I can do the footwork. The less micro-benchmarky the better, but we'll take what we can get. If you have multiple such benchmarks for bind then that's even better still. 

TL;DR getting a benchmark to have visibility among implementors is as easy as telling them about it. 

-Filip



On Fri, Jul 12, 2013 at 9:46 AM, Allen Wirfs-Brock <[hidden email]> wrote:
you might consider ticketing performance bugs against the various implementations.

Allen


On Jul 10, 2013, at 9:16 AM, Claus Reinke wrote:

> The TypeScript project tries to emulate arrow functions through the
> "_this = this" pattern and keeps running into corner cases where a
> semi-naïve renaming is not sufficient.
>
> I have been trying to suggest using .bind to emulate arrow functions
> instead, but the counter-arguments are (a) .bind might not be available
> (supporting pre-ES5 targets) and (b) .bind is slow.
>
> The polyfill isn't the problem, but I'm a bit shocked every time
> someone reminds me of the performance hit for using .bind. Given
> that a bound function has strictly more info than an unbound one,
> I wouldn't expect that (I expected a bound function to be roughly
> the same as an unbound function that does not use "this"). Unless
> there is no special casing for the just-add-this case, and .bind is
> always treated as a non-standard (meta-level) call.
>
> While playing with test-code, I also found that v8 does a lot better
> than other engines when using an .apply-based .bind emulation.
>
> Can anyone explain what is going on with .bind, .apply and the
> performance hits?
>
> The TypeScript issue is https://typescript.codeplex.com/workitem/1322 .
> My test code (*) is attached there as "bind-for-arrows.html".
>
> Claus
> http://clausreinke.github.com/
>
> (*) I also tried to make a jsperf test case, but the way jsperf
>   runs the loop seems to prevent the optimization that makes
>   v8 look good for the .apply-based bind.
>
> _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



--
    Cheers,
    --MarkM
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why is .bind so slow?

Brendan Eich-3
In reply to this post by Allen Wirfs-Brock
Allen Wirfs-Brock wrote:
> you might consider ticketing performance bugs against the various implementations.

Right, and at most summarize with links to those issues for es-discuss.
This is not a language issue, rather a quality of implementation one.

/be

>
> Allen
>
>
> On Jul 10, 2013, at 9:16 AM, Claus Reinke wrote:
>
>> The TypeScript project tries to emulate arrow functions through the
>> "_this = this" pattern and keeps running into corner cases where a
>> semi-naïve renaming is not sufficient.
>>
>> I have been trying to suggest using .bind to emulate arrow functions
>> instead, but the counter-arguments are (a) .bind might not be available
>> (supporting pre-ES5 targets) and (b) .bind is slow.
>>
>> The polyfill isn't the problem, but I'm a bit shocked every time
>> someone reminds me of the performance hit for using .bind. Given
>> that a bound function has strictly more info than an unbound one,
>> I wouldn't expect that (I expected a bound function to be roughly
>> the same as an unbound function that does not use "this"). Unless
>> there is no special casing for the just-add-this case, and .bind is
>> always treated as a non-standard (meta-level) call.
>>
>> While playing with test-code, I also found that v8 does a lot better
>> than other engines when using an .apply-based .bind emulation.
>>
>> Can anyone explain what is going on with .bind, .apply and the
>> performance hits?
>>
>> The TypeScript issue is https://typescript.codeplex.com/workitem/1322 .
>> My test code (*) is attached there as "bind-for-arrows.html".
>>
>> Claus
>> http://clausreinke.github.com/
>>
>> (*) I also tried to make a jsperf test case, but the way jsperf
>>    runs the loop seems to prevent the optimization that makes
>>    v8 look good for the .apply-based bind.
>>
>> _______________________________________________
>> es-discuss mailing list
>> [hidden email]
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>
> _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why is .bind so slow?

Oliver Hunt-2
In reply to this post by Filip Pizlo
Just to clarify, JSRegress is not a "benchmark" in the sunspider/kraken/etc sense, as the tests tend far more towards microbenchmarks than full "real" programme tests.  As the name suggests its main purpose is to help us make sure we're not regressing core language primitives.

--Oliver

On Jul 12, 2013, at 10:49 AM, Filip Pizlo <[hidden email]> wrote:


On Jul 12, 2013, at 10:09 AM, "Mark S. Miller" <[hidden email]> wrote:

If you can manage it, most effective would be to get .bind (or any other operation you want to be faster) into some widely quoted benchmark suite.

In WebKit at least, we have a thing called JSRegress which is meant to be a dumping ground for benchmarks for interesting corners of the language. Microbenchmarks are welcome; the goal is to just expand coverage of things that we measure timings of. It's not widely quoted, and it doesn't get the same priority as "macrobenchmark" suites, but we do care about it and we do optimize for it. For example, all of our optimization a for typeof, switch, and 'in' arose from JSRegress tests, since none of those things were hot enough in any of the "major" benchmarks. 

We don't have coverage for bind, and it would be great to fix that. 

If you have a standalone program that uses bind, you can either post a patch on bugs.webkit.org that adds it to JSRegress (I.e. LayoutTests/fast/js/regress/script-tests), or if you're lazy, you can just email the program to me and I can do the footwork. The less micro-benchmarky the better, but we'll take what we can get. If you have multiple such benchmarks for bind then that's even better still. 

TL;DR getting a benchmark to have visibility among implementors is as easy as telling them about it. 

-Filip



On Fri, Jul 12, 2013 at 9:46 AM, Allen Wirfs-Brock <[hidden email]> wrote:
you might consider ticketing performance bugs against the various implementations.

Allen


On Jul 10, 2013, at 9:16 AM, Claus Reinke wrote:

> The TypeScript project tries to emulate arrow functions through the
> "_this = this" pattern and keeps running into corner cases where a
> semi-naïve renaming is not sufficient.
>
> I have been trying to suggest using .bind to emulate arrow functions
> instead, but the counter-arguments are (a) .bind might not be available
> (supporting pre-ES5 targets) and (b) .bind is slow.
>
> The polyfill isn't the problem, but I'm a bit shocked every time
> someone reminds me of the performance hit for using .bind. Given
> that a bound function has strictly more info than an unbound one,
> I wouldn't expect that (I expected a bound function to be roughly
> the same as an unbound function that does not use "this"). Unless
> there is no special casing for the just-add-this case, and .bind is
> always treated as a non-standard (meta-level) call.
>
> While playing with test-code, I also found that v8 does a lot better
> than other engines when using an .apply-based .bind emulation.
>
> Can anyone explain what is going on with .bind, .apply and the
> performance hits?
>
> The TypeScript issue is https://typescript.codeplex.com/workitem/1322 .
> My test code (*) is attached there as "bind-for-arrows.html".
>
> Claus
> http://clausreinke.github.com/
>
> (*) I also tried to make a jsperf test case, but the way jsperf
>   runs the loop seems to prevent the optimization that makes
>   v8 look good for the .apply-based bind.
>
> _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



-- 
    Cheers,
    --MarkM
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why is .bind so slow?

Katelyn Gadd
In reply to this post by Brendan Eich-3
I've had some back and forth with v8 devs about this since it affects my compiler. I believe they already have open issues about it but I don't know the bug #s.

In general, the problem seems to be that Function.bind creates functions that have different type information from normal functions you wrote in pure JS; they're 'special' native functions in the same fashion as say, a DOM API:

document.createElement
function createElement() { [native code] }
function f () {}
f
function f() {}
f.bind(null)
function () { [native code] }

This is important because v8 tries to gather information about callees at various call sites. Having a mix of these special and non-special functions means that the JIT is not able to make safe optimizations based on all the callers being the same type.

IIRC there are also some other problems specific to v8, like it only being able to optimize Function.apply and Function.call if the .apply/.call methods are the implementations used for pure-JS functions (so bind breaks those too).

I can't comment on why it's slow in SpiderMonkey (I've never asked... I should file a bug) but it is indeed the case that f.bind(null) produces a 'native code' function in SpiderMonkey, so I expect some of the same optimization consequences apply.

I also expect that it is much harder for v8 and spidermonkey to inline a function that contains native code, if not entirely impossible.

All of these problems, as I understand them, are completely fixable. It might be as simple as making bind return a pure-JS function instead of a native function. This is supported by the fact that a pure-JS polyfill for .bind is usually faster in my tests. In general VM authors are much more helpful when shown real world applications affected by these issues, based on my experience. They tend to ignore jsperf microbenchmarks, etc.

I don't know that this could be addressed at all from a specification perspective. The only thing I can think of would be specifying that the result of Function.bind should somehow be indistinguishable from a hand-written JS function (no 'native code' in tostring, etc) but I don't think that sort of spec requirement would actually prevent any of these performance traps.

Hope this helps,
-kg

On Fri, Jul 12, 2013 at 10:59 AM, Brendan Eich <[hidden email]> wrote:
Allen Wirfs-Brock wrote:
you might consider ticketing performance bugs against the various implementations.

Right, and at most summarize with links to those issues for es-discuss. This is not a language issue, rather a quality of implementation one.

/be


Allen


On Jul 10, 2013, at 9:16 AM, Claus Reinke wrote:

The TypeScript project tries to emulate arrow functions through the
"_this = this" pattern and keeps running into corner cases where a
semi-naïve renaming is not sufficient.

I have been trying to suggest using .bind to emulate arrow functions
instead, but the counter-arguments are (a) .bind might not be available
(supporting pre-ES5 targets) and (b) .bind is slow.

The polyfill isn't the problem, but I'm a bit shocked every time
someone reminds me of the performance hit for using .bind. Given
that a bound function has strictly more info than an unbound one,
I wouldn't expect that (I expected a bound function to be roughly
the same as an unbound function that does not use "this"). Unless
there is no special casing for the just-add-this case, and .bind is
always treated as a non-standard (meta-level) call.

While playing with test-code, I also found that v8 does a lot better
than other engines when using an .apply-based .bind emulation.

Can anyone explain what is going on with .bind, .apply and the
performance hits?

The TypeScript issue is https://typescript.codeplex.com/workitem/1322 .
My test code (*) is attached there as "bind-for-arrows.html".

Claus
http://clausreinke.github.com/

(*) I also tried to make a jsperf test case, but the way jsperf
   runs the loop seems to prevent the optimization that makes
   v8 look good for the .apply-based bind.

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why is .bind so slow?

Matthew Robb
In the future wouldn't using a Function Proxy be potentially much faster?


On Fri, Jul 12, 2013 at 1:12 PM, K. Gadd <[hidden email]> wrote:
I've had some back and forth with v8 devs about this since it affects my compiler. I believe they already have open issues about it but I don't know the bug #s.

In general, the problem seems to be that Function.bind creates functions that have different type information from normal functions you wrote in pure JS; they're 'special' native functions in the same fashion as say, a DOM API:

document.createElement
function createElement() { [native code] }
function f () {}
f
function f() {}
f.bind(null)
function () { [native code] }

This is important because v8 tries to gather information about callees at various call sites. Having a mix of these special and non-special functions means that the JIT is not able to make safe optimizations based on all the callers being the same type.

IIRC there are also some other problems specific to v8, like it only being able to optimize Function.apply and Function.call if the .apply/.call methods are the implementations used for pure-JS functions (so bind breaks those too).

I can't comment on why it's slow in SpiderMonkey (I've never asked... I should file a bug) but it is indeed the case that f.bind(null) produces a 'native code' function in SpiderMonkey, so I expect some of the same optimization consequences apply.

I also expect that it is much harder for v8 and spidermonkey to inline a function that contains native code, if not entirely impossible.

All of these problems, as I understand them, are completely fixable. It might be as simple as making bind return a pure-JS function instead of a native function. This is supported by the fact that a pure-JS polyfill for .bind is usually faster in my tests. In general VM authors are much more helpful when shown real world applications affected by these issues, based on my experience. They tend to ignore jsperf microbenchmarks, etc.

I don't know that this could be addressed at all from a specification perspective. The only thing I can think of would be specifying that the result of Function.bind should somehow be indistinguishable from a hand-written JS function (no 'native code' in tostring, etc) but I don't think that sort of spec requirement would actually prevent any of these performance traps.

Hope this helps,
-kg

On Fri, Jul 12, 2013 at 10:59 AM, Brendan Eich <[hidden email]> wrote:
Allen Wirfs-Brock wrote:
you might consider ticketing performance bugs against the various implementations.

Right, and at most summarize with links to those issues for es-discuss. This is not a language issue, rather a quality of implementation one.

/be


Allen


On Jul 10, 2013, at 9:16 AM, Claus Reinke wrote:

The TypeScript project tries to emulate arrow functions through the
"_this = this" pattern and keeps running into corner cases where a
semi-naïve renaming is not sufficient.

I have been trying to suggest using .bind to emulate arrow functions
instead, but the counter-arguments are (a) .bind might not be available
(supporting pre-ES5 targets) and (b) .bind is slow.

The polyfill isn't the problem, but I'm a bit shocked every time
someone reminds me of the performance hit for using .bind. Given
that a bound function has strictly more info than an unbound one,
I wouldn't expect that (I expected a bound function to be roughly
the same as an unbound function that does not use "this"). Unless
there is no special casing for the just-add-this case, and .bind is
always treated as a non-standard (meta-level) call.

While playing with test-code, I also found that v8 does a lot better
than other engines when using an .apply-based .bind emulation.

Can anyone explain what is going on with .bind, .apply and the
performance hits?

The TypeScript issue is https://typescript.codeplex.com/workitem/1322 .
My test code (*) is attached there as "bind-for-arrows.html".

Claus
http://clausreinke.github.com/

(*) I also tried to make a jsperf test case, but the way jsperf
   runs the loop seems to prevent the optimization that makes
   v8 look good for the .apply-based bind.

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss




--
- Matthew Robb

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why is .bind so slow?

Claus Reinke
In reply to this post by Katelyn Gadd
Thanks, kg! Your message represents the kind of discussion/information
I was hoping for. If your hunch as to the reason is correct, it would seem
an easy target for optimization. Partially and efficiently emulating arrow
functions in ES6 transpilers should be a strong argument in favor, though
not the only one (eg bind keeps coming up as a recommendation when
using class methods as callback parameters, etc.).

For those interested, I've put my (micro) bench in a gist:

    https://gist.github.com/clausreinke/5987876

    (note in particular the performance difference between
    .bind and an .apply-based polyfill; other engines do worse)

I used es-discuss for this thread because:

- all engines are slow on .bind, so it is likely a general issue

- all engines are slow on .bind, so recommending .bind as freely as
    I (and several people on this list) used to do does not seem realistic;
    that puts a serious dent in the usability of this part of the spec

- even if that issue may turn out not to be spec-related, this is the only
    list I know of where I can reach all engine developers and es language
    gurus at once.

    If this kind of es implementation/performance discussion is not
    welcome here, a dedicated cross-engine list for such topics would
    be nice. Would only work if all engines had developers listening in.

    As long as there isn't enough traffic to warrant a dedicated list, I
    (as one of the list owners there) welcome such threads on js-tools

    http://groups.google.com/group/js-tools/about

    (on the basis that engines are our most fundamental js tools;-)

Please let me know where to raise such cross-engine threads in future.
Claus

> I've had some back and forth with v8 devs about this since it affects my
> compiler. I believe they already have open issues about it but I don't know
> the bug #s.
>
> In general, the problem seems to be that Function.bind creates functions
> that have different type information from normal functions you wrote in
> pure JS; they're 'special' native functions in the same fashion as say, a
> DOM API:
>...
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why is .bind so slow?

Allen Wirfs-Brock
In reply to this post by Matthew Robb

On Jul 12, 2013, at 1:55 PM, Matthew Robb wrote:

> In the future wouldn't using a Function Proxy be potentially much faster?

It seems highly unlikely that any use of Proxy will be faster than a rough equivalent using an ordinary object.

I expect proxies to be much harder for implementations to optimized than ordinary objects.

Looking at it another way, if implementation haven't found it straightforward to optimize ES5 bound functions why would you expect that would have an easier time with Proxys?

Allen


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why is .bind so slow?

Matthew Robb
If a function proxy is just forwarding an operation through an intermediary (the proxy and it's call trap) to another function it sounds very similar to a regularly wrapped/bound js function. So what I am saying is if browsers implemented bind using a proxy instead of the special native functions it would be theoretically faster.


On Fri, Jul 12, 2013 at 2:54 PM, Allen Wirfs-Brock <[hidden email]> wrote:

On Jul 12, 2013, at 1:55 PM, Matthew Robb wrote:

> In the future wouldn't using a Function Proxy be potentially much faster?

It seems highly unlikely that any use of Proxy will be faster than a rough equivalent using an ordinary object.

I expect proxies to be much harder for implementations to optimized than ordinary objects.

Looking at it another way, if implementation haven't found it straightforward to optimize ES5 bound functions why would you expect that would have an easier time with Proxys?

Allen





--
- Matthew Robb

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why is .bind so slow?

Andrea Giammarchi-2
just to add some extra info to this discussion, lo-dash does some crazy thing to optimize at its best bound functions.

`/\bthis\b/.test(Function.prototype.toString.call(callback))` or something similar to check if the function needs to use call/apply at all, together with the number of arguments, and some other analysis to optimize all further calls to the bound function.

While I believe that's a bit extreme, I have to admit performance gain is huge so maybe some trick used in lo-dash could be used internally too ? Like different specialized bound version? Most common use case is still a method bound to the object itself in order to don't loose the context on some event call.

my 2 cents





On Fri, Jul 12, 2013 at 4:04 PM, Matthew Robb <[hidden email]> wrote:
If a function proxy is just forwarding an operation through an intermediary (the proxy and it's call trap) to another function it sounds very similar to a regularly wrapped/bound js function. So what I am saying is if browsers implemented bind using a proxy instead of the special native functions it would be theoretically faster.


On Fri, Jul 12, 2013 at 2:54 PM, Allen Wirfs-Brock <[hidden email]> wrote:

On Jul 12, 2013, at 1:55 PM, Matthew Robb wrote:

> In the future wouldn't using a Function Proxy be potentially much faster?

It seems highly unlikely that any use of Proxy will be faster than a rough equivalent using an ordinary object.

I expect proxies to be much harder for implementations to optimized than ordinary objects.

Looking at it another way, if implementation haven't found it straightforward to optimize ES5 bound functions why would you expect that would have an easier time with Proxys?

Allen





--
- Matthew Robb

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why is .bind so slow?

Andrea Giammarchi-2
one more thing ... I believe this will impact arrow function too since is basically bound callbacks all over the place (or at least this is how I believe it will be transpiled)


On Fri, Jul 12, 2013 at 4:57 PM, Andrea Giammarchi <[hidden email]> wrote:
just to add some extra info to this discussion, lo-dash does some crazy thing to optimize at its best bound functions.

`/\bthis\b/.test(Function.prototype.toString.call(callback))` or something similar to check if the function needs to use call/apply at all, together with the number of arguments, and some other analysis to optimize all further calls to the bound function.

While I believe that's a bit extreme, I have to admit performance gain is huge so maybe some trick used in lo-dash could be used internally too ? Like different specialized bound version? Most common use case is still a method bound to the object itself in order to don't loose the context on some event call.

my 2 cents





On Fri, Jul 12, 2013 at 4:04 PM, Matthew Robb <[hidden email]> wrote:
If a function proxy is just forwarding an operation through an intermediary (the proxy and it's call trap) to another function it sounds very similar to a regularly wrapped/bound js function. So what I am saying is if browsers implemented bind using a proxy instead of the special native functions it would be theoretically faster.


On Fri, Jul 12, 2013 at 2:54 PM, Allen Wirfs-Brock <[hidden email]> wrote:

On Jul 12, 2013, at 1:55 PM, Matthew Robb wrote:

> In the future wouldn't using a Function Proxy be potentially much faster?

It seems highly unlikely that any use of Proxy will be faster than a rough equivalent using an ordinary object.

I expect proxies to be much harder for implementations to optimized than ordinary objects.

Looking at it another way, if implementation haven't found it straightforward to optimize ES5 bound functions why would you expect that would have an easier time with Proxys?

Allen





--
- Matthew Robb

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss




_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why is .bind so slow?

Jeff Walden-6
On 07/12/2013 04:59 PM, Andrea Giammarchi wrote:
> one more thing ... I believe this will impact arrow function too since is basically bound callbacks all over the place (or at least this is how I believe it will be transpiled)

Sadly, based on the arrow-function patches I've reviewed in SpiderMonkey, I don't believe this will be necessarily true.  Arrow functions and bind-bound functions are two rather different beasts.  Bind-bound functions are potentially constructible; arrow functions never are.  |arguments.callee| inside a function that's been bound doesn't refer to the bound function -- it refers to the lexical entity.  (That is, |function f() { return arguments.callee; } f.bind(null)()| is |f|, not |b|.)   |arguments.callee| inside an arrow function -- at least, so long as arrow functions aren't automatically strict, which decision I would revisit -- refers to the arrow function.  I expect there are other differences I'm not yet aware of, that would affect having a common implementation of the two concepts.

It seems like a pretty bad idea to me for arrow functions to not be substantially semantically similar to bind-bound functions, but they are as it stands now.  I wish I had the time to sit down and think through a solid unification of the two concepts.

Jeff
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why is .bind so slow?

Jeff Walden-6
In reply to this post by Allen Wirfs-Brock
On 07/12/2013 02:54 PM, Allen Wirfs-Brock wrote:
> Looking at it another way, if implementation haven't found it straightforward to optimize ES5 bound functions why would you expect that would have an easier time with Proxys?

I'm pretty sure no implementation has seriously tried to optimize bound functions, and that that's the major reason for any slowness.  I don't think there's anything fundamentally difficult about optimizing bound functions.  It's just never been a priority for engines, because it doesn't show up in benchmarks and because the perf bugs for it are less pressing than other perf work is, as bound functions remain underused on the web.  Chicken and egg?  Sure.

In the meantime, while I wouldn't currently question (as a purely pragmatic choice) avoiding bind in highly intensive code where every bit of perf matters, I do think bound functions are fast enough for the vast majority of cases.  The overhead of calling a bound function will rarely be the difference between adequate and inadequate performance.

Jeff
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why is .bind so slow?

David Bruant-5
In reply to this post by Jeff Walden-6
Le 13/07/2013 20:55, Jeff Walden a écrit :
> On 07/12/2013 04:59 PM, Andrea Giammarchi wrote:
>> one more thing ... I believe this will impact arrow function too since is basically bound callbacks all over the place (or at least this is how I believe it will be transpiled)
> Sadly, based on the arrow-function patches I've reviewed in SpiderMonkey, I don't believe this will be necessarily true.  Arrow functions and bind-bound functions are two rather different beasts.  Bind-bound functions are potentially constructible; arrow functions never are.  |arguments.callee| inside a function that's been bound doesn't refer to the bound function -- it refers to the lexical entity.
One of these things I didn't know (and didn't want to know) about the
language...

> (That is, |function f() { return arguments.callee; } f.bind(null)()| is |f|, not |b|.)   |arguments.callee| inside an arrow function -- at least, so long as arrow functions aren't automatically strict, which decision I would revisit -- refers to the arrow function.
arguments.callee is poisoned is strict mode, so the difference you're
referring only affects non-strict. Should we care? I know I don't.
In general, it should be expected from developers to be in strict mode.
They also shouldn't be using the "arguments" object...

"which decision I would revisit"
=> I disagree. Implicit strictness at the function level would surprise
people a lot. Maybe break their code when turning a function expression
to an arrow function.
Implicit strictness at the module or class level will already surprise
people a lot.

> I expect there are other differences I'm not yet aware of, that would affect having a common implementation of the two concepts.
Even in strict mode? If there are no differences in strict mode, I don't
think we should care.

> It seems like a pretty bad idea to me for arrow functions to not be substantially semantically similar to bind-bound functions, but they are as it stands now.  I wish I had the time to sit down and think through a solid unification of the two concepts.
Hopefully by simplifying how bound functions work?

David
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why is .bind so slow?

Mark S. Miller-2
In reply to this post by Jeff Walden-6
Arrow functions, whether strict or non-strict, are not supposed to have their own |arguments|


On Sat, Jul 13, 2013 at 11:55 AM, Jeff Walden <[hidden email]> wrote:
On 07/12/2013 04:59 PM, Andrea Giammarchi wrote:
> one more thing ... I believe this will impact arrow function too since is basically bound callbacks all over the place (or at least this is how I believe it will be transpiled)

Sadly, based on the arrow-function patches I've reviewed in SpiderMonkey, I don't believe this will be necessarily true.  Arrow functions and bind-bound functions are two rather different beasts.  Bind-bound functions are potentially constructible; arrow functions never are.  |arguments.callee| inside a function that's been bound doesn't refer to the bound function -- it refers to the lexical entity.  (That is, |function f() { return arguments.callee; } f.bind(null)()| is |f|, not |b|.)   |arguments.callee| inside an arrow function -- at least, so long as arrow functions aren't automatically strict, which decision I would revisit -- refers to the arrow function.  I expect there are other differences I'm not yet aware of, that would affect having a common implementation of the two concepts.

It seems like a pretty bad idea to me for arrow functions to not be substantially semantically similar to bind-bound functions, but they are as it stands now.  I wish I had the time to sit down and think through a solid unification of the two concepts.

Jeff
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



--
    Cheers,
    --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why is .bind so slow?

Allen Wirfs-Brock

On Jul 13, 2013, at 12:39 PM, Mark S. Miller wrote:

> Arrow functions, whether strict or non-strict, are not supposed to have their own |arguments|

Correct.  Implementors should be aware that in the current ES6 draft this is stated in a margin note but not in the actual algorithm for function declaration instantiations (10.5.3) step 11.


Allen
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Why is .bind so slow?

Jeff Walden-6
On 07/13/2013 12:56 PM, Allen Wirfs-Brock wrote:
> On Jul 13, 2013, at 12:39 PM, Mark S. Miller wrote:
>> Arrow functions, whether strict or non-strict, are not supposed to have their own |arguments|
>
> Correct.  Implementors should be aware that in the current ES6 draft this is stated in a margin note but not in the actual algorithm for function declaration instantiations (10.5.3) step 11.

Good to know, thanks.  Lack of arguments is sane; last I'd seen in bug commentary was that this wasn't the case.

Jeff
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
12