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 1617 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1628 // We don't know what the (potentially lazy parsed) inner function | 1628 // We don't know what the (potentially lazy parsed) inner function |
1629 // does with the variable; pessimistically assume that it's assigned. | 1629 // does with the variable; pessimistically assume that it's assigned. |
1630 var->set_maybe_assigned(); | 1630 var->set_maybe_assigned(); |
1631 } | 1631 } |
1632 } | 1632 } |
1633 scope = scope->outer_scope_; | 1633 scope = scope->outer_scope_; |
1634 } | 1634 } |
1635 } | 1635 } |
1636 } | 1636 } |
1637 | 1637 |
| 1638 namespace { |
| 1639 |
| 1640 bool AccessNeedsHoleCheck(Variable* var, VariableProxy* proxy, Scope* scope) { |
| 1641 if (!var->binding_needs_init()) { |
| 1642 return false; |
| 1643 } |
| 1644 |
| 1645 // It's impossible to eliminate module import hole checks here, because it's |
| 1646 // unknown at compilation time whether the binding referred to in the |
| 1647 // exporting module itself requires hole checks. |
| 1648 if (var->location() == VariableLocation::MODULE && !var->IsExport()) { |
| 1649 return true; |
| 1650 } |
| 1651 |
| 1652 // Check if the binding really needs an initialization check. The check |
| 1653 // can be skipped in the following situation: we have a LET or CONST |
| 1654 // binding, both the Variable and the VariableProxy have the same |
| 1655 // declaration scope (i.e. they are both in global code, in the |
| 1656 // same function or in the same eval code), the VariableProxy is in |
| 1657 // the source physically located after the initializer of the variable, |
| 1658 // and that the initializer cannot be skipped due to a nonlinear scope. |
| 1659 // |
| 1660 // The condition on the declaration scopes is a conservative check for |
| 1661 // nested functions that access a binding and are called before the |
| 1662 // binding is initialized: |
| 1663 // function() { f(); let x = 1; function f() { x = 2; } } |
| 1664 // |
| 1665 // The check cannot be skipped on non-linear scopes, namely switch |
| 1666 // scopes, to ensure tests are done in cases like the following: |
| 1667 // switch (1) { case 0: let x = 2; case 1: f(x); } |
| 1668 // The scope of the variable needs to be checked, in case the use is |
| 1669 // in a sub-block which may be linear. |
| 1670 if (var->scope()->GetDeclarationScope() != scope->GetDeclarationScope()) { |
| 1671 return true; |
| 1672 } |
| 1673 |
| 1674 if (var->is_this()) { |
| 1675 DCHECK( |
| 1676 IsSubclassConstructor(scope->GetDeclarationScope()->function_kind())); |
| 1677 // TODO(littledan): implement 'this' hole check elimination. |
| 1678 return true; |
| 1679 } |
| 1680 |
| 1681 // We should always have valid source positions. |
| 1682 DCHECK(var->initializer_position() != kNoSourcePosition); |
| 1683 DCHECK(proxy->position() != kNoSourcePosition); |
| 1684 |
| 1685 return var->scope()->is_nonlinear() || |
| 1686 var->initializer_position() >= proxy->position(); |
| 1687 } |
| 1688 |
| 1689 } // anonymous namespace |
| 1690 |
1638 void Scope::ResolveTo(ParseInfo* info, VariableProxy* proxy, Variable* var) { | 1691 void Scope::ResolveTo(ParseInfo* info, VariableProxy* proxy, Variable* var) { |
1639 #ifdef DEBUG | 1692 #ifdef DEBUG |
1640 if (info->script_is_native()) { | 1693 if (info->script_is_native()) { |
1641 // To avoid polluting the global object in native scripts | 1694 // To avoid polluting the global object in native scripts |
1642 // - Variables must not be allocated to the global scope. | 1695 // - Variables must not be allocated to the global scope. |
1643 CHECK_NOT_NULL(outer_scope()); | 1696 CHECK_NOT_NULL(outer_scope()); |
1644 // - Variables must be bound locally or unallocated. | 1697 // - Variables must be bound locally or unallocated. |
1645 if (var->IsGlobalObjectProperty()) { | 1698 if (var->IsGlobalObjectProperty()) { |
1646 // The following variable name may be minified. If so, disable | 1699 // The following variable name may be minified. If so, disable |
1647 // minification in js2c.py for better output. | 1700 // minification in js2c.py for better output. |
1648 Handle<String> name = proxy->raw_name()->string(); | 1701 Handle<String> name = proxy->raw_name()->string(); |
1649 V8_Fatal(__FILE__, __LINE__, "Unbound variable: '%s' in native script.", | 1702 V8_Fatal(__FILE__, __LINE__, "Unbound variable: '%s' in native script.", |
1650 name->ToCString().get()); | 1703 name->ToCString().get()); |
1651 } | 1704 } |
1652 VariableLocation location = var->location(); | 1705 VariableLocation location = var->location(); |
1653 CHECK(location == VariableLocation::LOCAL || | 1706 CHECK(location == VariableLocation::LOCAL || |
1654 location == VariableLocation::CONTEXT || | 1707 location == VariableLocation::CONTEXT || |
1655 location == VariableLocation::PARAMETER || | 1708 location == VariableLocation::PARAMETER || |
1656 location == VariableLocation::UNALLOCATED); | 1709 location == VariableLocation::UNALLOCATED); |
1657 } | 1710 } |
1658 #endif | 1711 #endif |
1659 | 1712 |
1660 DCHECK_NOT_NULL(var); | 1713 DCHECK_NOT_NULL(var); |
1661 if (proxy->is_assigned()) var->set_maybe_assigned(); | 1714 if (proxy->is_assigned()) var->set_maybe_assigned(); |
| 1715 if (AccessNeedsHoleCheck(var, proxy, this)) proxy->set_needs_hole_check(); |
1662 proxy->BindTo(var); | 1716 proxy->BindTo(var); |
1663 } | 1717 } |
1664 | 1718 |
1665 void Scope::ResolveVariablesRecursively(ParseInfo* info) { | 1719 void Scope::ResolveVariablesRecursively(ParseInfo* info) { |
1666 DCHECK(info->script_scope()->is_script_scope()); | 1720 DCHECK(info->script_scope()->is_script_scope()); |
1667 | 1721 |
1668 // Resolve unresolved variables for this scope. | 1722 // Resolve unresolved variables for this scope. |
1669 for (VariableProxy* proxy = unresolved_; proxy != nullptr; | 1723 for (VariableProxy* proxy = unresolved_; proxy != nullptr; |
1670 proxy = proxy->next_unresolved()) { | 1724 proxy = proxy->next_unresolved()) { |
1671 ResolveVariable(info, proxy); | 1725 ResolveVariable(info, proxy); |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1859 | 1913 |
1860 if (new_target_ != nullptr && !MustAllocate(new_target_)) { | 1914 if (new_target_ != nullptr && !MustAllocate(new_target_)) { |
1861 new_target_ = nullptr; | 1915 new_target_ = nullptr; |
1862 } | 1916 } |
1863 | 1917 |
1864 if (this_function_ != nullptr && !MustAllocate(this_function_)) { | 1918 if (this_function_ != nullptr && !MustAllocate(this_function_)) { |
1865 this_function_ = nullptr; | 1919 this_function_ = nullptr; |
1866 } | 1920 } |
1867 } | 1921 } |
1868 | 1922 |
1869 void ModuleScope::AllocateModuleVariables() { | 1923 void ModuleScope::AllocateModuleExports() { |
1870 for (const auto& it : module()->regular_imports()) { | |
1871 Variable* var = LookupLocal(it.first); | |
1872 // TODO(neis): Use a meaningful index. | |
1873 var->AllocateTo(VariableLocation::MODULE, 42); | |
1874 } | |
1875 | |
1876 for (const auto& it : module()->regular_exports()) { | 1924 for (const auto& it : module()->regular_exports()) { |
1877 Variable* var = LookupLocal(it.first); | 1925 Variable* var = LookupLocal(it.first); |
1878 var->AllocateTo(VariableLocation::MODULE, 0); | 1926 var->AllocateTo(VariableLocation::MODULE, Variable::kModuleExportIndex); |
1879 } | 1927 } |
1880 } | 1928 } |
1881 | 1929 |
1882 void Scope::AllocateVariablesRecursively() { | 1930 void Scope::AllocateVariablesRecursively() { |
1883 DCHECK(!already_resolved_); | 1931 DCHECK(!already_resolved_); |
1884 DCHECK_EQ(0, num_stack_slots_); | 1932 DCHECK_EQ(0, num_stack_slots_); |
1885 // Don't allocate variables of preparsed scopes. | 1933 // Don't allocate variables of preparsed scopes. |
1886 if (is_declaration_scope() && AsDeclarationScope()->is_lazily_parsed()) { | 1934 if (is_declaration_scope() && AsDeclarationScope()->is_lazily_parsed()) { |
1887 return; | 1935 return; |
1888 } | 1936 } |
1889 | 1937 |
1890 // Allocate variables for inner scopes. | 1938 // Allocate variables for inner scopes. |
1891 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { | 1939 for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) { |
1892 scope->AllocateVariablesRecursively(); | 1940 scope->AllocateVariablesRecursively(); |
1893 } | 1941 } |
1894 | 1942 |
1895 DCHECK(!already_resolved_); | 1943 DCHECK(!already_resolved_); |
1896 DCHECK_EQ(Context::MIN_CONTEXT_SLOTS, num_heap_slots_); | 1944 DCHECK_EQ(Context::MIN_CONTEXT_SLOTS, num_heap_slots_); |
1897 | 1945 |
1898 // Allocate variables for this scope. | 1946 // Allocate variables for this scope. |
1899 // Parameters must be allocated first, if any. | 1947 // Parameters must be allocated first, if any. |
1900 if (is_declaration_scope()) { | 1948 if (is_declaration_scope()) { |
1901 if (is_module_scope()) { | 1949 if (is_module_scope()) { |
1902 AsModuleScope()->AllocateModuleVariables(); | 1950 AsModuleScope()->AllocateModuleExports(); |
1903 } else if (is_function_scope()) { | 1951 } else if (is_function_scope()) { |
1904 AsDeclarationScope()->AllocateParameterLocals(); | 1952 AsDeclarationScope()->AllocateParameterLocals(); |
1905 } | 1953 } |
1906 AsDeclarationScope()->AllocateReceiver(); | 1954 AsDeclarationScope()->AllocateReceiver(); |
1907 } | 1955 } |
1908 AllocateNonParameterLocalsAndDeclaredGlobals(); | 1956 AllocateNonParameterLocalsAndDeclaredGlobals(); |
1909 | 1957 |
1910 // Force allocation of a context for this scope if necessary. For a 'with' | 1958 // Force allocation of a context for this scope if necessary. For a 'with' |
1911 // scope and for a function scope that makes an 'eval' call we need a context, | 1959 // scope and for a function scope that makes an 'eval' call we need a context, |
1912 // even if no local variables were statically allocated in the scope. | 1960 // even if no local variables were statically allocated in the scope. |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1972 Variable* function = | 2020 Variable* function = |
1973 is_function_scope() ? AsDeclarationScope()->function_var() : nullptr; | 2021 is_function_scope() ? AsDeclarationScope()->function_var() : nullptr; |
1974 bool is_function_var_in_context = | 2022 bool is_function_var_in_context = |
1975 function != nullptr && function->IsContextSlot(); | 2023 function != nullptr && function->IsContextSlot(); |
1976 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - | 2024 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - |
1977 (is_function_var_in_context ? 1 : 0); | 2025 (is_function_var_in_context ? 1 : 0); |
1978 } | 2026 } |
1979 | 2027 |
1980 } // namespace internal | 2028 } // namespace internal |
1981 } // namespace v8 | 2029 } // namespace v8 |
OLD | NEW |