Open kphillisjr opened 9 years ago
It seems that this could be implemented in the compiler by pushing a new declarative environment upon entering a block and popping it when the block closes. That's the easy part. Hoisting and TDZ semantics will be more complicated.
Pushing an explicit scope object would be quite slow and it should be avoided in the very common case where it's not needed.
Doing so needs more compiler smarts though.
Try-catch catch block binding uses an explicit scope object and it too is slow. But it's less of an issue for try-catch because error catching is not usually in a hot path.
So cases where each let
variable should just be a register includes things like:
if (something) {
let x = somethingElse;
frobnicate(x);
}
Because no closure can be created inside the if statement, there's no need to use explicit scope objects for the binding. A register allocated for the duration of the "if" is sufficient.
However, here a scope object is needed:
if (something) {
let x = somethingElse;
frobnicate(function () { /*...*/ });
}
Depending on the contents of the inner function it's possible to prove that the binding won't be accessed from the inner function either, but this becomes a bit more difficult for each step.
What I would like as the minimum good baseline is that the former case worked without creating a scope object while any potentially unsafe case (inner function, eval, etc) could conservatively create one.
This may be a somewhat easier task to handle, but it does offer some serious improvements.
[ ] Block-Scoped Function Definitions This is a somewhat important feature new to ES6/ES2015. This provides a lot of source clean ups. New Code: ECMAScript 2015 ( ES6 )
Old Code: ECMAScript 5
[ ] Block-scoped variables (and constants) without hoisting. Another important feature new to ES6/ES2015. This provides a lot of source clean ups. New Code: ECMAScript 2015 ( ES6 )
Old Code: ECMAScript 5