NameAnalysisTypes.h (12631B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef frontend_NameAnalysisTypes_h 8 #define frontend_NameAnalysisTypes_h 9 10 #include "mozilla/Assertions.h" // MOZ_ASSERT, MOZ_CRASH 11 #include "mozilla/Casting.h" // mozilla::AssertedCast 12 13 #include <stdint.h> // uint8_t, uint16_t, uint32_t 14 15 #include "vm/BindingKind.h" // BindingKind, BindingLocation 16 #include "vm/BytecodeFormatFlags.h" // JOF_ENVCOORD 17 #include "vm/BytecodeUtil.h" // ENVCOORD_HOPS_BITS, ENVCOORD_SLOT_BITS, GET_ENVCOORD_HOPS, GET_ENVCOORD_SLOT, ENVCOORD_HOPS_LEN, JOF_OPTYPE, JSOp, LOCALNO_LIMIT 18 19 namespace js { 20 21 // An "environment coordinate" describes how to get from head of the 22 // environment chain to a given lexically-enclosing variable. An environment 23 // coordinate has two dimensions: 24 // - hops: the number of environment objects on the scope chain to skip 25 // - slot: the slot on the environment object holding the variable's value 26 class EnvironmentCoordinate { 27 uint32_t hops_; 28 uint32_t slot_; 29 30 // Technically, hops_/slot_ are ENVCOORD_(HOPS|SLOT)_BITS wide. Since 31 // EnvironmentCoordinate is a temporary value, don't bother with a bitfield as 32 // this only adds overhead. 33 static_assert(ENVCOORD_HOPS_BITS <= 32, "We have enough bits below"); 34 static_assert(ENVCOORD_SLOT_BITS <= 32, "We have enough bits below"); 35 36 public: 37 explicit inline EnvironmentCoordinate(jsbytecode* pc) 38 : hops_(GET_ENVCOORD_HOPS(pc)), 39 slot_(GET_ENVCOORD_SLOT(pc + ENVCOORD_HOPS_LEN)) { 40 MOZ_ASSERT(JOF_OPTYPE(JSOp(*pc)) == JOF_ENVCOORD || 41 JOF_OPTYPE(JSOp(*pc)) == JOF_DEBUGCOORD); 42 } 43 44 EnvironmentCoordinate() = default; 45 46 void setHops(uint32_t hops) { 47 MOZ_ASSERT(hops < ENVCOORD_HOPS_LIMIT); 48 hops_ = hops; 49 } 50 51 void setSlot(uint32_t slot) { 52 MOZ_ASSERT(slot < ENVCOORD_SLOT_LIMIT); 53 slot_ = slot; 54 } 55 56 uint32_t hops() const { 57 MOZ_ASSERT(hops_ < ENVCOORD_HOPS_LIMIT); 58 return hops_; 59 } 60 61 uint32_t slot() const { 62 MOZ_ASSERT(slot_ < ENVCOORD_SLOT_LIMIT); 63 return slot_; 64 } 65 66 bool operator==(const EnvironmentCoordinate& rhs) const { 67 return hops() == rhs.hops() && slot() == rhs.slot(); 68 } 69 }; 70 71 namespace frontend { 72 73 enum class ParseGoal : uint8_t { Script, Module }; 74 75 // A detailed kind used for tracking declarations in the Parser. Used for 76 // specific early error semantics and better error messages. 77 enum class DeclarationKind : uint8_t { 78 PositionalFormalParameter, 79 FormalParameter, 80 CoverArrowParameter, 81 Var, 82 Let, 83 Const, 84 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 85 Using, 86 AwaitUsing, 87 #endif 88 Class, // Handled as same as `let` after parsing. 89 Import, 90 BodyLevelFunction, 91 ModuleBodyLevelFunction, 92 LexicalFunction, 93 SloppyLexicalFunction, 94 VarForAnnexBLexicalFunction, 95 SimpleCatchParameter, 96 CatchParameter, 97 PrivateName, 98 Synthetic, 99 PrivateMethod, // slot to store nonstatic private method 100 }; 101 102 // Class field kind. 103 enum class FieldPlacement : uint8_t { Unspecified, Instance, Static }; 104 105 static inline BindingKind DeclarationKindToBindingKind(DeclarationKind kind) { 106 switch (kind) { 107 case DeclarationKind::PositionalFormalParameter: 108 case DeclarationKind::FormalParameter: 109 case DeclarationKind::CoverArrowParameter: 110 return BindingKind::FormalParameter; 111 112 case DeclarationKind::Var: 113 case DeclarationKind::BodyLevelFunction: 114 case DeclarationKind::ModuleBodyLevelFunction: 115 case DeclarationKind::VarForAnnexBLexicalFunction: 116 return BindingKind::Var; 117 118 case DeclarationKind::Let: 119 case DeclarationKind::Class: 120 case DeclarationKind::LexicalFunction: 121 case DeclarationKind::SloppyLexicalFunction: 122 case DeclarationKind::SimpleCatchParameter: 123 case DeclarationKind::CatchParameter: 124 return BindingKind::Let; 125 126 case DeclarationKind::Const: 127 return BindingKind::Const; 128 129 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 130 case DeclarationKind::AwaitUsing: 131 case DeclarationKind::Using: 132 return BindingKind::Using; 133 #endif 134 135 case DeclarationKind::Import: 136 return BindingKind::Import; 137 138 case DeclarationKind::Synthetic: 139 case DeclarationKind::PrivateName: 140 return BindingKind::Synthetic; 141 142 case DeclarationKind::PrivateMethod: 143 return BindingKind::PrivateMethod; 144 } 145 146 MOZ_CRASH("Bad DeclarationKind"); 147 } 148 149 static inline bool DeclarationKindIsLexical(DeclarationKind kind) { 150 return BindingKindIsLexical(DeclarationKindToBindingKind(kind)); 151 } 152 153 // Used in Parser and BytecodeEmitter to track the kind of a private name. 154 enum class PrivateNameKind : uint8_t { 155 None, 156 Field, 157 Method, 158 Getter, 159 Setter, 160 GetterSetter, 161 }; 162 163 enum class ClosedOver : bool { No = false, Yes = true }; 164 165 // Used in Parser to track declared names. 166 class DeclaredNameInfo { 167 uint32_t pos_; 168 DeclarationKind kind_; 169 170 // If the declared name is a binding, whether the binding is closed 171 // over. Its value is meaningless if the declared name is not a binding 172 // (i.e., a 'var' declared name in a non-var scope). 173 bool closedOver_; 174 175 PrivateNameKind privateNameKind_; 176 177 // Only updated for private names (see noteDeclaredPrivateName), 178 // tracks if declaration was instance or static to allow issuing 179 // early errors in the case where we mismatch instance and static 180 // private getter/setters. 181 FieldPlacement placement_; 182 183 public: 184 explicit DeclaredNameInfo(DeclarationKind kind, uint32_t pos, 185 ClosedOver closedOver = ClosedOver::No) 186 : pos_(pos), 187 kind_(kind), 188 closedOver_(bool(closedOver)), 189 privateNameKind_(PrivateNameKind::None), 190 placement_(FieldPlacement::Unspecified) { 191 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 192 // TODO: present we are brute forcing our way to 193 // enforce creating an environment object whenever we encounter 194 // a using declaration. This is temporary for prototyping 195 // this must be optimized. (Bug 1899502) 196 if (kind == DeclarationKind::Using || kind == DeclarationKind::AwaitUsing) { 197 closedOver_ = true; 198 } 199 #endif 200 } 201 202 // Needed for InlineMap. 203 DeclaredNameInfo() = default; 204 205 DeclarationKind kind() const { return kind_; } 206 207 static const uint32_t npos = uint32_t(-1); 208 209 uint32_t pos() const { return pos_; } 210 211 void alterKind(DeclarationKind kind) { kind_ = kind; } 212 213 void setClosedOver() { closedOver_ = true; } 214 215 bool closedOver() const { return closedOver_; } 216 217 void setPrivateNameKind(PrivateNameKind privateNameKind) { 218 privateNameKind_ = privateNameKind; 219 } 220 221 void setFieldPlacement(FieldPlacement placement) { 222 MOZ_ASSERT(placement != FieldPlacement::Unspecified); 223 placement_ = placement; 224 } 225 226 PrivateNameKind privateNameKind() const { return privateNameKind_; } 227 228 FieldPlacement placement() const { return placement_; } 229 }; 230 231 // Used in BytecodeEmitter to map names to locations. 232 class NameLocation { 233 public: 234 enum class Kind : uint8_t { 235 // Cannot statically determine where the name lives. Needs to walk the 236 // environment chain to search for the name. 237 Dynamic, 238 239 // The name lives on the global or is a global lexical binding. Search 240 // for the name on the global scope. 241 Global, 242 243 // Special mode used only when emitting self-hosted scripts. See 244 // BytecodeEmitter::lookupName. 245 Intrinsic, 246 247 // In a named lambda, the name is the callee itself. 248 NamedLambdaCallee, 249 250 // The name is a positional formal parameter name and can be retrieved 251 // directly from the stack using slot_. 252 ArgumentSlot, 253 254 // The name is not closed over and lives on the frame in slot_. 255 FrameSlot, 256 257 // The name is closed over and lives on an environment hops_ away in slot_. 258 EnvironmentCoordinate, 259 260 // The name is closed over and lives on an environment hops_ away in slot_, 261 // where one or more of the environments may be a DebugEnvironmentProxy 262 DebugEnvironmentCoordinate, 263 264 // An imported name in a module. 265 Import, 266 267 // Cannot statically determine where the synthesized var for Annex 268 // B.3.3 lives. 269 DynamicAnnexBVar 270 }; 271 272 private: 273 // Where the name lives. 274 Kind kind_; 275 276 // If the name is not Dynamic or DynamicAnnexBVar, the kind of the 277 // binding. 278 BindingKind bindingKind_; 279 280 // If the name is closed over and accessed via EnvironmentCoordinate, the 281 // number of dynamic environments to skip. 282 // 283 // Otherwise UINT16_MAX. 284 uint16_t hops_; 285 286 // If the name lives on the frame, the slot frame. 287 // 288 // If the name is closed over and accessed via EnvironmentCoordinate, the 289 // slot on the environment. 290 // 291 // Otherwise 0. 292 uint32_t slot_ : ENVCOORD_SLOT_BITS; 293 294 static_assert(LOCALNO_BITS == ENVCOORD_SLOT_BITS, 295 "Frame and environment slots must be same sized."); 296 297 NameLocation(Kind kind, BindingKind bindingKind, uint16_t hops = UINT16_MAX, 298 uint32_t slot = 0) 299 : kind_(kind), bindingKind_(bindingKind), hops_(hops), slot_(slot) {} 300 301 public: 302 // Default constructor for InlineMap. 303 NameLocation() = default; 304 305 static NameLocation Dynamic() { 306 return NameLocation(Kind::Dynamic, BindingKind::Import); 307 } 308 309 static NameLocation Global(BindingKind bindKind) { 310 MOZ_ASSERT(bindKind != BindingKind::FormalParameter); 311 return NameLocation(Kind::Global, bindKind); 312 } 313 314 static NameLocation Intrinsic() { 315 return NameLocation(Kind::Intrinsic, BindingKind::Var); 316 } 317 318 static NameLocation NamedLambdaCallee() { 319 return NameLocation(Kind::NamedLambdaCallee, 320 BindingKind::NamedLambdaCallee); 321 } 322 323 static NameLocation ArgumentSlot(uint16_t slot) { 324 return NameLocation(Kind::ArgumentSlot, BindingKind::FormalParameter, 0, 325 slot); 326 } 327 328 static NameLocation FrameSlot(BindingKind bindKind, uint32_t slot) { 329 MOZ_ASSERT(slot < LOCALNO_LIMIT); 330 return NameLocation(Kind::FrameSlot, bindKind, 0, slot); 331 } 332 333 static NameLocation EnvironmentCoordinate(BindingKind bindKind, uint16_t hops, 334 uint32_t slot) { 335 MOZ_ASSERT(slot < ENVCOORD_SLOT_LIMIT); 336 return NameLocation(Kind::EnvironmentCoordinate, bindKind, hops, slot); 337 } 338 static NameLocation DebugEnvironmentCoordinate(BindingKind bindKind, 339 uint16_t hops, uint32_t slot) { 340 MOZ_ASSERT(slot < ENVCOORD_SLOT_LIMIT); 341 return NameLocation(Kind::DebugEnvironmentCoordinate, bindKind, hops, slot); 342 } 343 344 static NameLocation Import() { 345 return NameLocation(Kind::Import, BindingKind::Import); 346 } 347 348 static NameLocation DynamicAnnexBVar() { 349 return NameLocation(Kind::DynamicAnnexBVar, BindingKind::Var); 350 } 351 352 bool operator==(const NameLocation& other) const { 353 return kind_ == other.kind_ && bindingKind_ == other.bindingKind_ && 354 hops_ == other.hops_ && slot_ == other.slot_; 355 } 356 357 bool operator!=(const NameLocation& other) const { return !(*this == other); } 358 359 Kind kind() const { return kind_; } 360 361 uint16_t argumentSlot() const { 362 MOZ_ASSERT(kind_ == Kind::ArgumentSlot); 363 return mozilla::AssertedCast<uint16_t>(slot_); 364 } 365 366 uint32_t frameSlot() const { 367 MOZ_ASSERT(kind_ == Kind::FrameSlot); 368 return slot_; 369 } 370 371 NameLocation addHops(uint16_t more) { 372 MOZ_ASSERT(hops_ < ENVCOORD_HOPS_LIMIT - more); 373 MOZ_ASSERT(kind_ == Kind::EnvironmentCoordinate); 374 return NameLocation(kind_, bindingKind_, hops_ + more, slot_); 375 } 376 377 class EnvironmentCoordinate environmentCoordinate() const { 378 MOZ_ASSERT(kind_ == Kind::EnvironmentCoordinate || 379 kind_ == Kind::DebugEnvironmentCoordinate); 380 class EnvironmentCoordinate coord; 381 coord.setHops(hops_); 382 coord.setSlot(slot_); 383 return coord; 384 } 385 386 BindingKind bindingKind() const { 387 MOZ_ASSERT(kind_ != Kind::Dynamic); 388 return bindingKind_; 389 } 390 391 bool isLexical() const { return BindingKindIsLexical(bindingKind()); } 392 393 bool isConst() const { 394 return bindingKind() == BindingKind::Const || 395 bindingKind() == BindingKind::Using; 396 } 397 398 bool isSynthetic() const { return bindingKind() == BindingKind::Synthetic; } 399 400 bool isPrivateMethod() const { 401 return bindingKind() == BindingKind::PrivateMethod; 402 } 403 404 bool hasKnownSlot() const { 405 return kind_ == Kind::ArgumentSlot || kind_ == Kind::FrameSlot || 406 kind_ == Kind::EnvironmentCoordinate; 407 } 408 }; 409 410 } // namespace frontend 411 } // namespace js 412 413 #endif // frontend_NameAnalysisTypes_h