| Index: src/ast/scopes.cc
|
| diff --git a/src/ast/scopes.cc b/src/ast/scopes.cc
|
| index d9f34c894238ce934848e3636e7a361e0b602208..679aff5796a6e73943cde9c7ec08c28925abc20b 100644
|
| --- a/src/ast/scopes.cc
|
| +++ b/src/ast/scopes.cc
|
| @@ -1611,6 +1611,51 @@ void Scope::ResolveVariable(ParseInfo* info, VariableProxy* proxy) {
|
| }
|
| }
|
|
|
| +namespace {
|
| +
|
| +bool AccessNeedsHoleCheck(Variable* var, VariableProxy* proxy, Scope* scope) {
|
| + if (!var->binding_needs_init()) {
|
| + return false;
|
| + }
|
| +
|
| + DCHECK(var->scope() != NULL);
|
| +
|
| + if (var->is_this()) {
|
| + DCHECK(
|
| + IsSubclassConstructor(scope->GetDeclarationScope()->function_kind()));
|
| + // TODO(littledan): implement 'this' hole check elimination.
|
| + return true;
|
| + }
|
| +
|
| + // We should always have valid source positions.
|
| + DCHECK(var->initializer_position() != kNoSourcePosition);
|
| + DCHECK(proxy->position() != kNoSourcePosition);
|
| +
|
| + // Check if the binding really needs an initialization check. The check
|
| + // can be skipped in the following situation: we have a LET or CONST
|
| + // binding, both the Variable and the VariableProxy have the same
|
| + // declaration scope (i.e. they are both in global code, in the
|
| + // same function or in the same eval code), the VariableProxy is in
|
| + // the source physically located after the initializer of the variable,
|
| + // and that the initializer cannot be skipped due to a nonlinear scope.
|
| + //
|
| + // The condition on the declaration scopes is a conservative check for
|
| + // nested functions that access a binding and are called before the
|
| + // binding is initialized:
|
| + // function() { f(); let x = 1; function f() { x = 2; } }
|
| + //
|
| + // The check cannot be skipped on non-linear scopes, namely switch
|
| + // scopes, to ensure tests are done in cases like the following:
|
| + // switch (1) { case 0: let x = 2; case 1: f(x); }
|
| + // The scope of the variable needs to be checked, in case the use is
|
| + // in a sub-block which may be linear.
|
| + return var->scope()->GetDeclarationScope() != scope->GetDeclarationScope() ||
|
| + var->scope()->is_nonlinear() ||
|
| + var->initializer_position() >= proxy->position();
|
| +}
|
| +
|
| +} // anonymous namespace
|
| +
|
| void Scope::ResolveTo(ParseInfo* info, VariableProxy* proxy, Variable* var) {
|
| #ifdef DEBUG
|
| if (info->script_is_native()) {
|
| @@ -1635,6 +1680,7 @@ void Scope::ResolveTo(ParseInfo* info, VariableProxy* proxy, Variable* var) {
|
|
|
| DCHECK_NOT_NULL(var);
|
| if (proxy->is_assigned()) var->set_maybe_assigned();
|
| + if (AccessNeedsHoleCheck(var, proxy, this)) proxy->set_needs_hole_check();
|
| proxy->BindTo(var);
|
| }
|
|
|
|
|