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