Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

try {} blocks kill optimization in Safari, IE, Chrome #1176

Closed
hansl opened this issue Apr 7, 2015 · 12 comments
Closed

try {} blocks kill optimization in Safari, IE, Chrome #1176

hansl opened this issue Apr 7, 2015 · 12 comments
Labels
outdated A closed issue/PR that is archived due to age. Recommended to make a new issue

Comments

@hansl
Copy link

hansl commented Apr 7, 2015

The for of operator creates two try {} blocks; one for the content of the loop, and 1 for the return() call on the iterator.

This has been discussed at length in google/traceur-compiler#1773 and #838.

What I want to discuss in this issue is that using a try {} block remove all potential optimization from a function by the JIT. See http://jsperf.com/trycatch-1/

To get around this, some high performance library (lodash and bluebird) use a _tryCatch function which is pretty straightforward:

function _tryCatch(_try, _catch, _finally) {
  try { _try(); }
  catch(ex) { if (_catch) _catch(ex) else throw ex; }
  finally { _finally && _finally(); }
}

The trick is to have _tryCatch be unoptimized but having called functions still be optimized. For functions that are super fast, this is up to 10% slower in most browsers. But for functions that take a long time (and include for loops) this can go as much as 10x faster.

@monsanto
Copy link
Contributor

monsanto commented Apr 7, 2015

Does loose mode not work for you? What iterators are you working with that have a return method? I would imagine in performance sensitive code you would want loose mode for the array fast path optimization anyway.

@hansl
Copy link
Author

hansl commented Apr 10, 2015

Loose mode works, just that your implementation kills performance.

@sebmck
Copy link
Contributor

sebmck commented Apr 10, 2015

i think these kinds of optimisations are misguided. This is a trick for V8 which isn't relevant for some other engines and it may or may not be relevant in the future. Turning blocks into functions (as you suggest) is incredibly finnicky as you need to hoist all variable declarations, realias this, arguments, break, continue, return and more. If you care about performance then you'd already be using loose mode that addresses all of these concerns and then some.

@sebmck sebmck closed this as completed Apr 10, 2015
@hansl
Copy link
Author

hansl commented Apr 10, 2015

Not going to dismiss the aliasing problems, but it's not limited to V8. Firefox and Safari are affected. Unfortunately I don't have a machine for IE under my hand.

@stefanpenner
Copy link
Member

@hansl what you propose also has other costs that the author may want to avoid entirely. I believe this can't be done in a single sweeping transpile step. The correct thing to do would be to hand-roll these problems based on the problem at hand and report browser bugs, as this is a platform bug.

An example of code I would not want babel to touch: https://github.com/tildeio/rsvp.js/blob/master/lib/rsvp/-internal.js#L235-L250

But these scenarios are extremely common, the unfortunate reality is the transformation result you proposed itself has a heavy cost

@hansl
Copy link
Author

hansl commented Apr 10, 2015

If there was a post-transpiler optimization step people would be able to tweak that. AFAIK there isn't, but I might be wrong here.

@stefanpenner
Copy link
Member

If there was a post-transpiler optimization step people would be able to tweak that. AFAIK there isn't, but I might be wrong here.

90% of peoples app code doesn't need this optimization, as it likely isn't in a hot path of any kind and the last 10% likely needs to be done extremely carefully. The small window this does help, I don't believe is sufficient to warrant a sweeping step.

One place where i do feel the transpile can (and babel does) help, is argument splicing. As the resulting transpile is zero cost.

@hansl
Copy link
Author

hansl commented Apr 10, 2015

Don't make blanket statement. Unoptimizing a function CAN be really heavy. See the jsperf above and tell me no one is doing a try-catch with a for loop in it. Most end developers should not care, because libraries and frameworks should care for them. Lodash and Bluebird are prime examples. And Babel sits right there.

And

the unfortunate reality is the transformation result you proposed itself has a heavy cost

is not true. There might be implementation issues on Babel's side, but the final transpiled code would perform better, on all platforms tested (see jsperf).

Please note that I'm only talking about the 2 try-catches in For-Of loops. I'm not saying "you should encapsulate all try-catch"; that would be ridiculous.

Finally, I'm not arguing. You guys clearly have alternative solutions (loose mode) which my project is fine with. But I encountered performance bottlenecks with try catch before, and I'm sure I'm not the only one.

@stefanpenner
Copy link
Member

Please note that I'm only talking about the 2 try-catches in For-Of loops. I'm not saying "you should encapsulate all try-catch"; that would be ridiculous.

this is what i understand, maybe I mis-read.

@hansl
Copy link
Author

hansl commented Apr 10, 2015

The title did not reflect that, but the description started with "The for of operator".

@stefanpenner
Copy link
Member

ah, i suspect that can be generated in a faster way. That is a gnarly little loop for-sure. Ultimately though, even without the loop all the iterator code itself will be a dog :(

@toothbrush7777777
Copy link

When I run the JSPerf test with Firefox Developer Edition 43.0a2, the _trycatch function is 83% slower. I don't know if Firefox has only optimised this recently, but it is much faster to use try { } catch (ex) { }; it is almost (≈0.1% difference) as fast as without a try-catch block.

@lock lock bot added the outdated A closed issue/PR that is archived due to age. Recommended to make a new issue label Jul 11, 2018
@lock lock bot locked as resolved and limited conversation to collaborators Jul 11, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
outdated A closed issue/PR that is archived due to age. Recommended to make a new issue
Projects
None yet
Development

No branches or pull requests

5 participants