11cb0ef41Sopenharmony_ci// Copyright 2011 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#ifndef V8_AST_VARIABLES_H_ 61cb0ef41Sopenharmony_ci#define V8_AST_VARIABLES_H_ 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci#include "src/ast/ast-value-factory.h" 91cb0ef41Sopenharmony_ci#include "src/base/threaded-list.h" 101cb0ef41Sopenharmony_ci#include "src/common/globals.h" 111cb0ef41Sopenharmony_ci#include "src/execution/isolate.h" 121cb0ef41Sopenharmony_ci#include "src/zone/zone.h" 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_cinamespace v8 { 151cb0ef41Sopenharmony_cinamespace internal { 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_ci// The AST refers to variables via VariableProxies - placeholders for the actual 181cb0ef41Sopenharmony_ci// variables. Variables themselves are never directly referred to from the AST, 191cb0ef41Sopenharmony_ci// they are maintained by scopes, and referred to from VariableProxies and Slots 201cb0ef41Sopenharmony_ci// after binding and variable allocation. 211cb0ef41Sopenharmony_ciclass Variable final : public ZoneObject { 221cb0ef41Sopenharmony_ci public: 231cb0ef41Sopenharmony_ci Variable(Scope* scope, const AstRawString* name, VariableMode mode, 241cb0ef41Sopenharmony_ci VariableKind kind, InitializationFlag initialization_flag, 251cb0ef41Sopenharmony_ci MaybeAssignedFlag maybe_assigned_flag = kNotAssigned, 261cb0ef41Sopenharmony_ci IsStaticFlag is_static_flag = IsStaticFlag::kNotStatic) 271cb0ef41Sopenharmony_ci : scope_(scope), 281cb0ef41Sopenharmony_ci name_(name), 291cb0ef41Sopenharmony_ci local_if_not_shadowed_(nullptr), 301cb0ef41Sopenharmony_ci next_(nullptr), 311cb0ef41Sopenharmony_ci index_(-1), 321cb0ef41Sopenharmony_ci initializer_position_(kNoSourcePosition), 331cb0ef41Sopenharmony_ci bit_field_(MaybeAssignedFlagField::encode(maybe_assigned_flag) | 341cb0ef41Sopenharmony_ci InitializationFlagField::encode(initialization_flag) | 351cb0ef41Sopenharmony_ci VariableModeField::encode(mode) | 361cb0ef41Sopenharmony_ci IsUsedField::encode(false) | 371cb0ef41Sopenharmony_ci ForceContextAllocationBit::encode(false) | 381cb0ef41Sopenharmony_ci ForceHoleInitializationField::encode(false) | 391cb0ef41Sopenharmony_ci LocationField::encode(VariableLocation::UNALLOCATED) | 401cb0ef41Sopenharmony_ci VariableKindField::encode(kind) | 411cb0ef41Sopenharmony_ci IsStaticFlagField::encode(is_static_flag)) { 421cb0ef41Sopenharmony_ci // Var declared variables never need initialization. 431cb0ef41Sopenharmony_ci DCHECK(!(mode == VariableMode::kVar && 441cb0ef41Sopenharmony_ci initialization_flag == kNeedsInitialization)); 451cb0ef41Sopenharmony_ci DCHECK_IMPLIES(is_static_flag == IsStaticFlag::kStatic, 461cb0ef41Sopenharmony_ci IsConstVariableMode(mode)); 471cb0ef41Sopenharmony_ci } 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ci explicit Variable(Variable* other); 501cb0ef41Sopenharmony_ci 511cb0ef41Sopenharmony_ci // The source code for an eval() call may refer to a variable that is 521cb0ef41Sopenharmony_ci // in an outer scope about which we don't know anything (it may not 531cb0ef41Sopenharmony_ci // be the script scope). scope() is nullptr in that case. Currently the 541cb0ef41Sopenharmony_ci // scope is only used to follow the context chain length. 551cb0ef41Sopenharmony_ci Scope* scope() const { return scope_; } 561cb0ef41Sopenharmony_ci 571cb0ef41Sopenharmony_ci // This is for adjusting the scope of temporaries used when desugaring 581cb0ef41Sopenharmony_ci // parameter initializers. 591cb0ef41Sopenharmony_ci void set_scope(Scope* scope) { scope_ = scope; } 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_ci Handle<String> name() const { return name_->string(); } 621cb0ef41Sopenharmony_ci const AstRawString* raw_name() const { return name_; } 631cb0ef41Sopenharmony_ci VariableMode mode() const { return VariableModeField::decode(bit_field_); } 641cb0ef41Sopenharmony_ci void set_mode(VariableMode mode) { 651cb0ef41Sopenharmony_ci bit_field_ = VariableModeField::update(bit_field_, mode); 661cb0ef41Sopenharmony_ci } 671cb0ef41Sopenharmony_ci void set_is_static_flag(IsStaticFlag is_static_flag) { 681cb0ef41Sopenharmony_ci bit_field_ = IsStaticFlagField::update(bit_field_, is_static_flag); 691cb0ef41Sopenharmony_ci } 701cb0ef41Sopenharmony_ci IsStaticFlag is_static_flag() const { 711cb0ef41Sopenharmony_ci return IsStaticFlagField::decode(bit_field_); 721cb0ef41Sopenharmony_ci } 731cb0ef41Sopenharmony_ci bool is_static() const { return is_static_flag() == IsStaticFlag::kStatic; } 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci bool has_forced_context_allocation() const { 761cb0ef41Sopenharmony_ci return ForceContextAllocationBit::decode(bit_field_); 771cb0ef41Sopenharmony_ci } 781cb0ef41Sopenharmony_ci void ForceContextAllocation() { 791cb0ef41Sopenharmony_ci DCHECK(IsUnallocated() || IsContextSlot() || IsLookupSlot() || 801cb0ef41Sopenharmony_ci location() == VariableLocation::MODULE); 811cb0ef41Sopenharmony_ci bit_field_ = ForceContextAllocationBit::update(bit_field_, true); 821cb0ef41Sopenharmony_ci } 831cb0ef41Sopenharmony_ci bool is_used() { return IsUsedField::decode(bit_field_); } 841cb0ef41Sopenharmony_ci void set_is_used() { bit_field_ = IsUsedField::update(bit_field_, true); } 851cb0ef41Sopenharmony_ci MaybeAssignedFlag maybe_assigned() const { 861cb0ef41Sopenharmony_ci return MaybeAssignedFlagField::decode(bit_field_); 871cb0ef41Sopenharmony_ci } 881cb0ef41Sopenharmony_ci void clear_maybe_assigned() { 891cb0ef41Sopenharmony_ci bit_field_ = MaybeAssignedFlagField::update(bit_field_, kNotAssigned); 901cb0ef41Sopenharmony_ci } 911cb0ef41Sopenharmony_ci void SetMaybeAssigned() { 921cb0ef41Sopenharmony_ci if (mode() == VariableMode::kConst) return; 931cb0ef41Sopenharmony_ci // Private names are only initialized once by us. 941cb0ef41Sopenharmony_ci if (name_->IsPrivateName()) { 951cb0ef41Sopenharmony_ci return; 961cb0ef41Sopenharmony_ci } 971cb0ef41Sopenharmony_ci // If this variable is dynamically shadowing another variable, then that 981cb0ef41Sopenharmony_ci // variable could also be assigned (in the non-shadowing case). 991cb0ef41Sopenharmony_ci if (has_local_if_not_shadowed()) { 1001cb0ef41Sopenharmony_ci // Avoid repeatedly marking the same tree of variables by only recursing 1011cb0ef41Sopenharmony_ci // when this variable's maybe_assigned status actually changes. 1021cb0ef41Sopenharmony_ci if (!maybe_assigned()) { 1031cb0ef41Sopenharmony_ci local_if_not_shadowed()->SetMaybeAssigned(); 1041cb0ef41Sopenharmony_ci } 1051cb0ef41Sopenharmony_ci DCHECK_IMPLIES(local_if_not_shadowed()->mode() != VariableMode::kConst, 1061cb0ef41Sopenharmony_ci local_if_not_shadowed()->maybe_assigned()); 1071cb0ef41Sopenharmony_ci } 1081cb0ef41Sopenharmony_ci set_maybe_assigned(); 1091cb0ef41Sopenharmony_ci } 1101cb0ef41Sopenharmony_ci 1111cb0ef41Sopenharmony_ci bool requires_brand_check() const { 1121cb0ef41Sopenharmony_ci return IsPrivateMethodOrAccessorVariableMode(mode()); 1131cb0ef41Sopenharmony_ci } 1141cb0ef41Sopenharmony_ci 1151cb0ef41Sopenharmony_ci int initializer_position() { return initializer_position_; } 1161cb0ef41Sopenharmony_ci void set_initializer_position(int pos) { initializer_position_ = pos; } 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_ci bool IsUnallocated() const { 1191cb0ef41Sopenharmony_ci return location() == VariableLocation::UNALLOCATED; 1201cb0ef41Sopenharmony_ci } 1211cb0ef41Sopenharmony_ci bool IsParameter() const { return location() == VariableLocation::PARAMETER; } 1221cb0ef41Sopenharmony_ci bool IsStackLocal() const { return location() == VariableLocation::LOCAL; } 1231cb0ef41Sopenharmony_ci bool IsStackAllocated() const { return IsParameter() || IsStackLocal(); } 1241cb0ef41Sopenharmony_ci bool IsContextSlot() const { return location() == VariableLocation::CONTEXT; } 1251cb0ef41Sopenharmony_ci bool IsLookupSlot() const { return location() == VariableLocation::LOOKUP; } 1261cb0ef41Sopenharmony_ci bool IsGlobalObjectProperty() const; 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_ci // True for 'let' and 'const' variables declared in the script scope of a REPL 1291cb0ef41Sopenharmony_ci // script. 1301cb0ef41Sopenharmony_ci bool IsReplGlobal() const; 1311cb0ef41Sopenharmony_ci 1321cb0ef41Sopenharmony_ci bool is_dynamic() const { return IsDynamicVariableMode(mode()); } 1331cb0ef41Sopenharmony_ci 1341cb0ef41Sopenharmony_ci // Returns the InitializationFlag this Variable was created with. 1351cb0ef41Sopenharmony_ci // Scope analysis may allow us to relax this initialization 1361cb0ef41Sopenharmony_ci // requirement, which will be reflected in the return value of 1371cb0ef41Sopenharmony_ci // binding_needs_init(). 1381cb0ef41Sopenharmony_ci InitializationFlag initialization_flag() const { 1391cb0ef41Sopenharmony_ci return InitializationFlagField::decode(bit_field_); 1401cb0ef41Sopenharmony_ci } 1411cb0ef41Sopenharmony_ci 1421cb0ef41Sopenharmony_ci // Whether this variable needs to be initialized with the hole at 1431cb0ef41Sopenharmony_ci // declaration time. Only returns valid results after scope analysis. 1441cb0ef41Sopenharmony_ci bool binding_needs_init() const { 1451cb0ef41Sopenharmony_ci DCHECK_IMPLIES(initialization_flag() == kNeedsInitialization, 1461cb0ef41Sopenharmony_ci IsLexicalVariableMode(mode()) || 1471cb0ef41Sopenharmony_ci IsPrivateMethodOrAccessorVariableMode(mode())); 1481cb0ef41Sopenharmony_ci DCHECK_IMPLIES(ForceHoleInitializationField::decode(bit_field_), 1491cb0ef41Sopenharmony_ci initialization_flag() == kNeedsInitialization); 1501cb0ef41Sopenharmony_ci 1511cb0ef41Sopenharmony_ci // Always initialize if hole initialization was forced during 1521cb0ef41Sopenharmony_ci // scope analysis. 1531cb0ef41Sopenharmony_ci if (ForceHoleInitializationField::decode(bit_field_)) return true; 1541cb0ef41Sopenharmony_ci 1551cb0ef41Sopenharmony_ci // If initialization was not forced, no need for initialization 1561cb0ef41Sopenharmony_ci // for stack allocated variables, since UpdateNeedsHoleCheck() 1571cb0ef41Sopenharmony_ci // in scopes.cc has proven that no VariableProxy refers to 1581cb0ef41Sopenharmony_ci // this variable in such a way that a runtime hole check 1591cb0ef41Sopenharmony_ci // would be generated. 1601cb0ef41Sopenharmony_ci if (IsStackAllocated()) return false; 1611cb0ef41Sopenharmony_ci 1621cb0ef41Sopenharmony_ci // Otherwise, defer to the flag set when this Variable was constructed. 1631cb0ef41Sopenharmony_ci return initialization_flag() == kNeedsInitialization; 1641cb0ef41Sopenharmony_ci } 1651cb0ef41Sopenharmony_ci 1661cb0ef41Sopenharmony_ci // Called during scope analysis when a VariableProxy is found to 1671cb0ef41Sopenharmony_ci // reference this Variable in such a way that a hole check will 1681cb0ef41Sopenharmony_ci // be required at runtime. 1691cb0ef41Sopenharmony_ci void ForceHoleInitialization() { 1701cb0ef41Sopenharmony_ci DCHECK_EQ(kNeedsInitialization, initialization_flag()); 1711cb0ef41Sopenharmony_ci DCHECK(IsLexicalVariableMode(mode()) || 1721cb0ef41Sopenharmony_ci IsPrivateMethodOrAccessorVariableMode(mode())); 1731cb0ef41Sopenharmony_ci bit_field_ = ForceHoleInitializationField::update(bit_field_, true); 1741cb0ef41Sopenharmony_ci } 1751cb0ef41Sopenharmony_ci 1761cb0ef41Sopenharmony_ci bool throw_on_const_assignment(LanguageMode language_mode) const { 1771cb0ef41Sopenharmony_ci return kind() != SLOPPY_FUNCTION_NAME_VARIABLE || is_strict(language_mode); 1781cb0ef41Sopenharmony_ci } 1791cb0ef41Sopenharmony_ci 1801cb0ef41Sopenharmony_ci bool is_this() const { return kind() == THIS_VARIABLE; } 1811cb0ef41Sopenharmony_ci bool is_sloppy_function_name() const { 1821cb0ef41Sopenharmony_ci return kind() == SLOPPY_FUNCTION_NAME_VARIABLE; 1831cb0ef41Sopenharmony_ci } 1841cb0ef41Sopenharmony_ci 1851cb0ef41Sopenharmony_ci bool is_parameter() const { return kind() == PARAMETER_VARIABLE; } 1861cb0ef41Sopenharmony_ci bool is_sloppy_block_function() { 1871cb0ef41Sopenharmony_ci return kind() == SLOPPY_BLOCK_FUNCTION_VARIABLE; 1881cb0ef41Sopenharmony_ci } 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ci Variable* local_if_not_shadowed() const { 1911cb0ef41Sopenharmony_ci DCHECK((mode() == VariableMode::kDynamicLocal || 1921cb0ef41Sopenharmony_ci mode() == VariableMode::kDynamic) && 1931cb0ef41Sopenharmony_ci has_local_if_not_shadowed()); 1941cb0ef41Sopenharmony_ci return local_if_not_shadowed_; 1951cb0ef41Sopenharmony_ci } 1961cb0ef41Sopenharmony_ci 1971cb0ef41Sopenharmony_ci bool has_local_if_not_shadowed() const { 1981cb0ef41Sopenharmony_ci return local_if_not_shadowed_ != nullptr; 1991cb0ef41Sopenharmony_ci } 2001cb0ef41Sopenharmony_ci 2011cb0ef41Sopenharmony_ci void set_local_if_not_shadowed(Variable* local) { 2021cb0ef41Sopenharmony_ci local_if_not_shadowed_ = local; 2031cb0ef41Sopenharmony_ci } 2041cb0ef41Sopenharmony_ci 2051cb0ef41Sopenharmony_ci VariableLocation location() const { 2061cb0ef41Sopenharmony_ci return LocationField::decode(bit_field_); 2071cb0ef41Sopenharmony_ci } 2081cb0ef41Sopenharmony_ci VariableKind kind() const { return VariableKindField::decode(bit_field_); } 2091cb0ef41Sopenharmony_ci 2101cb0ef41Sopenharmony_ci int index() const { return index_; } 2111cb0ef41Sopenharmony_ci 2121cb0ef41Sopenharmony_ci bool IsReceiver() const { 2131cb0ef41Sopenharmony_ci DCHECK(IsParameter()); 2141cb0ef41Sopenharmony_ci 2151cb0ef41Sopenharmony_ci return index_ == -1; 2161cb0ef41Sopenharmony_ci } 2171cb0ef41Sopenharmony_ci 2181cb0ef41Sopenharmony_ci bool IsExport() const { 2191cb0ef41Sopenharmony_ci DCHECK_EQ(location(), VariableLocation::MODULE); 2201cb0ef41Sopenharmony_ci DCHECK_NE(index(), 0); 2211cb0ef41Sopenharmony_ci return index() > 0; 2221cb0ef41Sopenharmony_ci } 2231cb0ef41Sopenharmony_ci 2241cb0ef41Sopenharmony_ci void AllocateTo(VariableLocation location, int index) { 2251cb0ef41Sopenharmony_ci DCHECK(IsUnallocated() || 2261cb0ef41Sopenharmony_ci (this->location() == location && this->index() == index)); 2271cb0ef41Sopenharmony_ci DCHECK_IMPLIES(location == VariableLocation::MODULE, index != 0); 2281cb0ef41Sopenharmony_ci bit_field_ = LocationField::update(bit_field_, location); 2291cb0ef41Sopenharmony_ci DCHECK_EQ(location, this->location()); 2301cb0ef41Sopenharmony_ci index_ = index; 2311cb0ef41Sopenharmony_ci } 2321cb0ef41Sopenharmony_ci 2331cb0ef41Sopenharmony_ci void MakeParameterNonSimple() { 2341cb0ef41Sopenharmony_ci DCHECK(is_parameter()); 2351cb0ef41Sopenharmony_ci bit_field_ = VariableModeField::update(bit_field_, VariableMode::kLet); 2361cb0ef41Sopenharmony_ci bit_field_ = 2371cb0ef41Sopenharmony_ci InitializationFlagField::update(bit_field_, kNeedsInitialization); 2381cb0ef41Sopenharmony_ci } 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_ci static InitializationFlag DefaultInitializationFlag(VariableMode mode) { 2411cb0ef41Sopenharmony_ci DCHECK(IsDeclaredVariableMode(mode)); 2421cb0ef41Sopenharmony_ci return mode == VariableMode::kVar ? kCreatedInitialized 2431cb0ef41Sopenharmony_ci : kNeedsInitialization; 2441cb0ef41Sopenharmony_ci } 2451cb0ef41Sopenharmony_ci 2461cb0ef41Sopenharmony_ci // Rewrites the VariableLocation of repl script scope 'lets' to REPL_GLOBAL. 2471cb0ef41Sopenharmony_ci void RewriteLocationForRepl(); 2481cb0ef41Sopenharmony_ci 2491cb0ef41Sopenharmony_ci using List = base::ThreadedList<Variable>; 2501cb0ef41Sopenharmony_ci 2511cb0ef41Sopenharmony_ci private: 2521cb0ef41Sopenharmony_ci Scope* scope_; 2531cb0ef41Sopenharmony_ci const AstRawString* name_; 2541cb0ef41Sopenharmony_ci 2551cb0ef41Sopenharmony_ci // If this field is set, this variable references the stored locally bound 2561cb0ef41Sopenharmony_ci // variable, but it might be shadowed by variable bindings introduced by with 2571cb0ef41Sopenharmony_ci // blocks or sloppy 'eval' calls between the reference scope (inclusive) and 2581cb0ef41Sopenharmony_ci // the binding scope (exclusive). 2591cb0ef41Sopenharmony_ci Variable* local_if_not_shadowed_; 2601cb0ef41Sopenharmony_ci Variable* next_; 2611cb0ef41Sopenharmony_ci int index_; 2621cb0ef41Sopenharmony_ci int initializer_position_; 2631cb0ef41Sopenharmony_ci uint16_t bit_field_; 2641cb0ef41Sopenharmony_ci 2651cb0ef41Sopenharmony_ci void set_maybe_assigned() { 2661cb0ef41Sopenharmony_ci bit_field_ = MaybeAssignedFlagField::update(bit_field_, kMaybeAssigned); 2671cb0ef41Sopenharmony_ci } 2681cb0ef41Sopenharmony_ci 2691cb0ef41Sopenharmony_ci using VariableModeField = base::BitField16<VariableMode, 0, 4>; 2701cb0ef41Sopenharmony_ci using VariableKindField = VariableModeField::Next<VariableKind, 3>; 2711cb0ef41Sopenharmony_ci using LocationField = VariableKindField::Next<VariableLocation, 3>; 2721cb0ef41Sopenharmony_ci using ForceContextAllocationBit = LocationField::Next<bool, 1>; 2731cb0ef41Sopenharmony_ci using IsUsedField = ForceContextAllocationBit::Next<bool, 1>; 2741cb0ef41Sopenharmony_ci using InitializationFlagField = IsUsedField::Next<InitializationFlag, 1>; 2751cb0ef41Sopenharmony_ci using ForceHoleInitializationField = InitializationFlagField::Next<bool, 1>; 2761cb0ef41Sopenharmony_ci using MaybeAssignedFlagField = 2771cb0ef41Sopenharmony_ci ForceHoleInitializationField::Next<MaybeAssignedFlag, 1>; 2781cb0ef41Sopenharmony_ci using IsStaticFlagField = MaybeAssignedFlagField::Next<IsStaticFlag, 1>; 2791cb0ef41Sopenharmony_ci 2801cb0ef41Sopenharmony_ci Variable** next() { return &next_; } 2811cb0ef41Sopenharmony_ci friend List; 2821cb0ef41Sopenharmony_ci friend base::ThreadedListTraits<Variable>; 2831cb0ef41Sopenharmony_ci}; 2841cb0ef41Sopenharmony_ci} // namespace internal 2851cb0ef41Sopenharmony_ci} // namespace v8 2861cb0ef41Sopenharmony_ci 2871cb0ef41Sopenharmony_ci#endif // V8_AST_VARIABLES_H_ 288