1 // Copyright 2011 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_AST_VARIABLES_H_ 6 #define V8_AST_VARIABLES_H_ 7 8 #include "src/ast/ast-value-factory.h" 9 #include "src/globals.h" 10 #include "src/zone/zone.h" 11 12 namespace v8 { 13 namespace internal { 14 15 // The AST refers to variables via VariableProxies - placeholders for the actual 16 // variables. Variables themselves are never directly referred to from the AST, 17 // they are maintained by scopes, and referred to from VariableProxies and Slots 18 // after binding and variable allocation. 19 class Variable final : public ZoneObject { 20 public: 21 Variable(Scope* scope, const AstRawString* name, VariableMode mode, 22 VariableKind kind, InitializationFlag initialization_flag, 23 MaybeAssignedFlag maybe_assigned_flag = kNotAssigned) scope_(scope)24 : scope_(scope), 25 name_(name), 26 local_if_not_shadowed_(nullptr), 27 next_(nullptr), 28 index_(-1), 29 initializer_position_(kNoSourcePosition), 30 bit_field_(MaybeAssignedFlagField::encode(maybe_assigned_flag) | 31 InitializationFlagField::encode(initialization_flag) | 32 VariableModeField::encode(mode) | 33 IsUsedField::encode(false) | 34 ForceContextAllocationField::encode(false) | 35 ForceHoleInitializationField::encode(false) | 36 LocationField::encode(VariableLocation::UNALLOCATED) | 37 VariableKindField::encode(kind)) { 38 // Var declared variables never need initialization. 39 DCHECK(!(mode == VariableMode::kVar && 40 initialization_flag == kNeedsInitialization)); 41 } 42 43 explicit Variable(Variable* other); 44 45 // The source code for an eval() call may refer to a variable that is 46 // in an outer scope about which we don't know anything (it may not 47 // be the script scope). scope() is nullptr in that case. Currently the 48 // scope is only used to follow the context chain length. scope()49 Scope* scope() const { return scope_; } 50 51 // This is for adjusting the scope of temporaries used when desugaring 52 // parameter initializers. set_scope(Scope * scope)53 void set_scope(Scope* scope) { scope_ = scope; } 54 name()55 Handle<String> name() const { return name_->string(); } raw_name()56 const AstRawString* raw_name() const { return name_; } mode()57 VariableMode mode() const { return VariableModeField::decode(bit_field_); } has_forced_context_allocation()58 bool has_forced_context_allocation() const { 59 return ForceContextAllocationField::decode(bit_field_); 60 } ForceContextAllocation()61 void ForceContextAllocation() { 62 DCHECK(IsUnallocated() || IsContextSlot() || 63 location() == VariableLocation::MODULE); 64 bit_field_ = ForceContextAllocationField::update(bit_field_, true); 65 } is_used()66 bool is_used() { return IsUsedField::decode(bit_field_); } set_is_used()67 void set_is_used() { bit_field_ = IsUsedField::update(bit_field_, true); } maybe_assigned()68 MaybeAssignedFlag maybe_assigned() const { 69 return MaybeAssignedFlagField::decode(bit_field_); 70 } set_maybe_assigned()71 void set_maybe_assigned() { 72 bit_field_ = MaybeAssignedFlagField::update(bit_field_, kMaybeAssigned); 73 } 74 initializer_position()75 int initializer_position() { return initializer_position_; } set_initializer_position(int pos)76 void set_initializer_position(int pos) { initializer_position_ = pos; } 77 IsUnallocated()78 bool IsUnallocated() const { 79 return location() == VariableLocation::UNALLOCATED; 80 } IsParameter()81 bool IsParameter() const { return location() == VariableLocation::PARAMETER; } IsStackLocal()82 bool IsStackLocal() const { return location() == VariableLocation::LOCAL; } IsStackAllocated()83 bool IsStackAllocated() const { return IsParameter() || IsStackLocal(); } IsContextSlot()84 bool IsContextSlot() const { return location() == VariableLocation::CONTEXT; } IsLookupSlot()85 bool IsLookupSlot() const { return location() == VariableLocation::LOOKUP; } 86 bool IsGlobalObjectProperty() const; 87 is_dynamic()88 bool is_dynamic() const { return IsDynamicVariableMode(mode()); } 89 90 // Returns the InitializationFlag this Variable was created with. 91 // Scope analysis may allow us to relax this initialization 92 // requirement, which will be reflected in the return value of 93 // binding_needs_init(). initialization_flag()94 InitializationFlag initialization_flag() const { 95 return InitializationFlagField::decode(bit_field_); 96 } 97 98 // Whether this variable needs to be initialized with the hole at 99 // declaration time. Only returns valid results after scope analysis. binding_needs_init()100 bool binding_needs_init() const { 101 DCHECK_IMPLIES(initialization_flag() == kNeedsInitialization, 102 IsLexicalVariableMode(mode())); 103 DCHECK_IMPLIES(ForceHoleInitializationField::decode(bit_field_), 104 initialization_flag() == kNeedsInitialization); 105 106 // Always initialize if hole initialization was forced during 107 // scope analysis. 108 if (ForceHoleInitializationField::decode(bit_field_)) return true; 109 110 // If initialization was not forced, no need for initialization 111 // for stack allocated variables, since UpdateNeedsHoleCheck() 112 // in scopes.cc has proven that no VariableProxy refers to 113 // this variable in such a way that a runtime hole check 114 // would be generated. 115 if (IsStackAllocated()) return false; 116 117 // Otherwise, defer to the flag set when this Variable was constructed. 118 return initialization_flag() == kNeedsInitialization; 119 } 120 121 // Called during scope analysis when a VariableProxy is found to 122 // reference this Variable in such a way that a hole check will 123 // be required at runtime. ForceHoleInitialization()124 void ForceHoleInitialization() { 125 DCHECK_EQ(kNeedsInitialization, initialization_flag()); 126 DCHECK(IsLexicalVariableMode(mode())); 127 bit_field_ = ForceHoleInitializationField::update(bit_field_, true); 128 } 129 throw_on_const_assignment(LanguageMode language_mode)130 bool throw_on_const_assignment(LanguageMode language_mode) const { 131 return kind() != SLOPPY_FUNCTION_NAME_VARIABLE || is_strict(language_mode); 132 } 133 is_function()134 bool is_function() const { return kind() == FUNCTION_VARIABLE; } is_this()135 bool is_this() const { return kind() == THIS_VARIABLE; } is_sloppy_function_name()136 bool is_sloppy_function_name() const { 137 return kind() == SLOPPY_FUNCTION_NAME_VARIABLE; 138 } 139 local_if_not_shadowed()140 Variable* local_if_not_shadowed() const { 141 DCHECK(mode() == VariableMode::kDynamicLocal && 142 local_if_not_shadowed_ != nullptr); 143 return local_if_not_shadowed_; 144 } 145 set_local_if_not_shadowed(Variable * local)146 void set_local_if_not_shadowed(Variable* local) { 147 local_if_not_shadowed_ = local; 148 } 149 location()150 VariableLocation location() const { 151 return LocationField::decode(bit_field_); 152 } kind()153 VariableKind kind() const { return VariableKindField::decode(bit_field_); } 154 index()155 int index() const { return index_; } 156 IsReceiver()157 bool IsReceiver() const { 158 DCHECK(IsParameter()); 159 160 return index_ == -1; 161 } 162 IsExport()163 bool IsExport() const { 164 DCHECK_EQ(location(), VariableLocation::MODULE); 165 DCHECK_NE(index(), 0); 166 return index() > 0; 167 } 168 AllocateTo(VariableLocation location,int index)169 void AllocateTo(VariableLocation location, int index) { 170 DCHECK(IsUnallocated() || 171 (this->location() == location && this->index() == index)); 172 DCHECK_IMPLIES(location == VariableLocation::MODULE, index != 0); 173 bit_field_ = LocationField::update(bit_field_, location); 174 DCHECK_EQ(location, this->location()); 175 index_ = index; 176 } 177 DefaultInitializationFlag(VariableMode mode)178 static InitializationFlag DefaultInitializationFlag(VariableMode mode) { 179 DCHECK(IsDeclaredVariableMode(mode)); 180 return mode == VariableMode::kVar ? kCreatedInitialized 181 : kNeedsInitialization; 182 } 183 184 typedef ThreadedList<Variable> List; 185 186 private: 187 Scope* scope_; 188 const AstRawString* name_; 189 190 // If this field is set, this variable references the stored locally bound 191 // variable, but it might be shadowed by variable bindings introduced by 192 // sloppy 'eval' calls between the reference scope (inclusive) and the 193 // binding scope (exclusive). 194 Variable* local_if_not_shadowed_; 195 Variable* next_; 196 int index_; 197 int initializer_position_; 198 uint16_t bit_field_; 199 200 class VariableModeField : public BitField16<VariableMode, 0, 3> {}; 201 class VariableKindField 202 : public BitField16<VariableKind, VariableModeField::kNext, 3> {}; 203 class LocationField 204 : public BitField16<VariableLocation, VariableKindField::kNext, 3> {}; 205 class ForceContextAllocationField 206 : public BitField16<bool, LocationField::kNext, 1> {}; 207 class IsUsedField 208 : public BitField16<bool, ForceContextAllocationField::kNext, 1> {}; 209 class InitializationFlagField 210 : public BitField16<InitializationFlag, IsUsedField::kNext, 1> {}; 211 class ForceHoleInitializationField 212 : public BitField16<bool, InitializationFlagField::kNext, 1> {}; 213 class MaybeAssignedFlagField 214 : public BitField16<MaybeAssignedFlag, 215 ForceHoleInitializationField::kNext, 1> {}; next()216 Variable** next() { return &next_; } 217 friend List; 218 }; 219 } // namespace internal 220 } // namespace v8 221 222 #endif // V8_AST_VARIABLES_H_ 223