K. Gadd (2013-07-12T20:12:58.000Z)
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 <brendan at mozilla.com> 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<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
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/**listinfo/es-discuss<https://mail.mozilla.org/listinfo/es-discuss>
>>>
>>>
>> ______________________________**_________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/**listinfo/es-discuss<https://mail.mozilla.org/listinfo/es-discuss>
>>
>>  ______________________________**_________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/**listinfo/es-discuss<https://mail.mozilla.org/listinfo/es-discuss>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20130712/1ac83d47/attachment-0001.html>
forbes at lindesay.co.uk (2013-07-12T20:36:28.956Z)
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,