OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/ast/scopes.h" | 5 #include "src/ast/scopes.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 | 8 |
9 #include "src/accessors.h" | 9 #include "src/accessors.h" |
10 #include "src/ast/ast.h" | 10 #include "src/ast/ast.h" |
(...skipping 1593 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1604 // We don't know what the (potentially lazy parsed) inner function | 1604 // We don't know what the (potentially lazy parsed) inner function |
1605 // does with the variable; pessimistically assume that it's assigned. | 1605 // does with the variable; pessimistically assume that it's assigned. |
1606 var->set_maybe_assigned(); | 1606 var->set_maybe_assigned(); |
1607 } | 1607 } |
1608 } | 1608 } |
1609 scope = scope->outer_scope_; | 1609 scope = scope->outer_scope_; |
1610 } | 1610 } |
1611 } | 1611 } |
1612 } | 1612 } |
1613 | 1613 |
| 1614 namespace { |
| 1615 |
| 1616 bool AccessNeedsHoleCheck(Variable* var, VariableProxy* proxy, Scope* scope) { |
| 1617 if (!var->binding_needs_init()) { |
| 1618 return false; |
| 1619 } |
| 1620 |
| 1621 DCHECK(var->scope() != NULL); |
| 1622 |
| 1623 if (var->is_this()) { |
| 1624 DCHECK( |
| 1625 IsSubclassConstructor(scope->GetDeclarationScope()->function_kind())); |
| 1626 // TODO(littledan): implement 'this' hole check elimination. |
| 1627 return true; |
| 1628 } |
| 1629 |
| 1630 // We should always have valid source positions. |
| 1631 DCHECK(var->initializer_position() != kNoSourcePosition); |
| 1632 DCHECK(proxy->position() != kNoSourcePosition); |
| 1633 |
| 1634 // Check if the binding really needs an initialization check. The check |
| 1635 // can be skipped in the following situation: we have a LET or CONST |
| 1636 // binding, both the Variable and the VariableProxy have the same |
| 1637 // declaration scope (i.e. they are both in global code, in the |
| 1638 // same function or in the same eval code), the VariableProxy is in |
| 1639 // the source physically located after the initializer of the variable, |
| 1640 // and that the initializer cannot be skipped due to a nonlinear scope. |
| 1641 // |
| 1642 // The condition on the declaration scopes is a conservative check for |
| 1643 // nested functions that access a binding and are called before the |
| 1644 // binding is initialized: |
| 1645 // function() { f(); let x = 1; function f() { x = 2; } } |
| 1646 // |
| 1647 // The check cannot be skipped on non-linear scopes, namely switch |
| 1648 // scopes, to ensure tests are done in cases like the following: |
| 1649 // switch (1) { case 0: let x = 2; case 1: f(x); } |
| 1650 // The scope of the variable needs to be checked, in case the use is |
| 1651 // in a sub-block which may be linear. |
| 1652 return var->scope()->GetDeclarationScope() != scope->GetDeclarationScope() || |
| 1653 var->scope()->is_nonlinear() || |
| 1654 var->initializer_position() >= proxy->position(); |
| 1655 } |
| 1656 |
| 1657 } // anonymous namespace |
| 1658 |
1614 void Scope::ResolveTo(ParseInfo* info, VariableProxy* proxy, Variable* var) { | 1659 void Scope::ResolveTo(ParseInfo* info, VariableProxy* proxy, Variable* var) { |
1615 #ifdef DEBUG | 1660 #ifdef DEBUG |
1616 if (info->script_is_native()) { | 1661 if (info->script_is_native()) { |
1617 // To avoid polluting the global object in native scripts | 1662 // To avoid polluting the global object in native scripts |
1618 // - Variables must not be allocated to the global scope. | 1663 // - Variables must not be allocated to the global scope. |
1619 CHECK_NOT_NULL(outer_scope()); | 1664 CHECK_NOT_NULL(outer_scope()); |
1620 // - Variables must be bound locally or unallocated. | 1665 // - Variables must be bound locally or unallocated. |
1621 if (var->IsGlobalObjectProperty()) { | 1666 if (var->IsGlobalObjectProperty()) { |
1622 // The following variable name may be minified. If so, disable | 1667 // The following variable name may be minified. If so, disable |
1623 // minification in js2c.py for better output. | 1668 // minification in js2c.py for better output. |
1624 Handle<String> name = proxy->raw_name()->string(); | 1669 Handle<String> name = proxy->raw_name()->string(); |
1625 V8_Fatal(__FILE__, __LINE__, "Unbound variable: '%s' in native script.", | 1670 V8_Fatal(__FILE__, __LINE__, "Unbound variable: '%s' in native script.", |
1626 name->ToCString().get()); | 1671 name->ToCString().get()); |
1627 } | 1672 } |
1628 VariableLocation location = var->location(); | 1673 VariableLocation location = var->location(); |
1629 CHECK(location == VariableLocation::LOCAL || | 1674 CHECK(location == VariableLocation::LOCAL || |
1630 location == VariableLocation::CONTEXT || | 1675 location == VariableLocation::CONTEXT || |
1631 location == VariableLocation::PARAMETER || | 1676 location == VariableLocation::PARAMETER || |
1632 location == VariableLocation::UNALLOCATED); | 1677 location == VariableLocation::UNALLOCATED); |
1633 } | 1678 } |
1634 #endif | 1679 #endif |
1635 | 1680 |
1636 DCHECK_NOT_NULL(var); | 1681 DCHECK_NOT_NULL(var); |
1637 if (proxy->is_assigned()) var->set_maybe_assigned(); | 1682 if (proxy->is_assigned()) var->set_maybe_assigned(); |
| 1683 if (AccessNeedsHoleCheck(var, proxy, this)) proxy->set_needs_hole_check(); |
1638 proxy->BindTo(var); | 1684 proxy->BindTo(var); |
1639 } | 1685 } |
1640 | 1686 |
1641 void Scope::ResolveVariablesRecursively(ParseInfo* info) { | 1687 void Scope::ResolveVariablesRecursively(ParseInfo* info) { |
1642 DCHECK(info->script_scope()->is_script_scope()); | 1688 DCHECK(info->script_scope()->is_script_scope()); |
1643 | 1689 |
1644 // Resolve unresolved variables for this scope. | 1690 // Resolve unresolved variables for this scope. |
1645 for (VariableProxy* proxy = unresolved_; proxy != nullptr; | 1691 for (VariableProxy* proxy = unresolved_; proxy != nullptr; |
1646 proxy = proxy->next_unresolved()) { | 1692 proxy = proxy->next_unresolved()) { |
1647 ResolveVariable(info, proxy); | 1693 ResolveVariable(info, proxy); |
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1945 Variable* function = | 1991 Variable* function = |
1946 is_function_scope() ? AsDeclarationScope()->function_var() : nullptr; | 1992 is_function_scope() ? AsDeclarationScope()->function_var() : nullptr; |
1947 bool is_function_var_in_context = | 1993 bool is_function_var_in_context = |
1948 function != nullptr && function->IsContextSlot(); | 1994 function != nullptr && function->IsContextSlot(); |
1949 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - | 1995 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - |
1950 (is_function_var_in_context ? 1 : 0); | 1996 (is_function_var_in_context ? 1 : 0); |
1951 } | 1997 } |
1952 | 1998 |
1953 } // namespace internal | 1999 } // namespace internal |
1954 } // namespace v8 | 2000 } // namespace v8 |
OLD | NEW |