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