DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (b6d82b1a6b02)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef frontend_EmitterScope_h
#define frontend_EmitterScope_h

#include "mozilla/Attributes.h"
#include "mozilla/Maybe.h"

#include <stdint.h>

#include "ds/Nestable.h"
#include "frontend/NameAnalysisTypes.h"
#include "frontend/NameCollections.h"
#include "frontend/ParseContext.h"
#include "frontend/SharedContext.h"
#include "js/TypeDecls.h"

namespace js {

class Scope;

namespace frontend {

// A scope that introduces bindings.
class EmitterScope : public Nestable<EmitterScope> {
  // The cache of bound names that may be looked up in the
  // scope. Initially populated as the set of names this scope binds. As
  // names are looked up in enclosing scopes, they are cached on the
  // current scope.
  PooledMapPtr<NameLocationMap> nameCache_;

  // If this scope's cache does not include free names, such as the
  // global scope, the NameLocation to return.
  mozilla::Maybe<NameLocation> fallbackFreeNameLocation_;

  // True if there is a corresponding EnvironmentObject on the environment
  // chain, false if all bindings are stored in frame slots on the stack.
  bool hasEnvironment_;

  // The number of enclosing environments. Used for error checking.
  uint8_t environmentChainLength_;

  // The next usable slot on the frame for not-closed over bindings.
  //
  // The initial frame slot when assigning slots to bindings is the
  // enclosing scope's nextFrameSlot. For the first scope in a frame,
  // the initial frame slot is 0.
  uint32_t nextFrameSlot_;

  // The index in the BytecodeEmitter's interned scope vector, otherwise
  // ScopeNote::NoScopeIndex.
  uint32_t scopeIndex_;

  // If kind is Lexical, Catch, or With, the index in the BytecodeEmitter's
  // block scope note list. Otherwise ScopeNote::NoScopeNote.
  uint32_t noteIndex_;

  MOZ_MUST_USE bool ensureCache(BytecodeEmitter* bce);

  template <typename BindingIter>
  MOZ_MUST_USE bool checkSlotLimits(BytecodeEmitter* bce,
                                    const BindingIter& bi);

  MOZ_MUST_USE bool checkEnvironmentChainLength(BytecodeEmitter* bce);

  void updateFrameFixedSlots(BytecodeEmitter* bce, const BindingIter& bi);

  MOZ_MUST_USE bool putNameInCache(BytecodeEmitter* bce, JSAtom* name,
                                   NameLocation loc);

  mozilla::Maybe<NameLocation> lookupInCache(BytecodeEmitter* bce,
                                             JSAtom* name);

  EmitterScope* enclosing(BytecodeEmitter** bce) const;

  Scope* enclosingScope(BytecodeEmitter* bce) const;

  static bool nameCanBeFree(BytecodeEmitter* bce, JSAtom* name);

  static NameLocation searchInEnclosingScope(JSAtom* name, Scope* scope,
                                             uint8_t hops);
  NameLocation searchAndCache(BytecodeEmitter* bce, JSAtom* name);

  template <typename ScopeCreator>
  MOZ_MUST_USE bool internScope(BytecodeEmitter* bce, ScopeCreator createScope);
  template <typename ScopeCreator>
  MOZ_MUST_USE bool internBodyScope(BytecodeEmitter* bce,
                                    ScopeCreator createScope);
  MOZ_MUST_USE bool appendScopeNote(BytecodeEmitter* bce);

  MOZ_MUST_USE bool deadZoneFrameSlotRange(BytecodeEmitter* bce,
                                           uint32_t slotStart,
                                           uint32_t slotEnd) const;

 public:
  explicit EmitterScope(BytecodeEmitter* bce);

  void dump(BytecodeEmitter* bce);

  MOZ_MUST_USE bool enterLexical(BytecodeEmitter* bce, ScopeKind kind,
                                 Handle<LexicalScope::Data*> bindings);
  MOZ_MUST_USE bool enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox);
  MOZ_MUST_USE bool enterFunction(BytecodeEmitter* bce, FunctionBox* funbox);
  MOZ_MUST_USE bool enterFunctionExtraBodyVar(BytecodeEmitter* bce,
                                              FunctionBox* funbox);
  MOZ_MUST_USE bool enterParameterExpressionVar(BytecodeEmitter* bce);
  MOZ_MUST_USE bool enterGlobal(BytecodeEmitter* bce,
                                GlobalSharedContext* globalsc);
  MOZ_MUST_USE bool enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc);
  MOZ_MUST_USE bool enterModule(BytecodeEmitter* module,
                                ModuleSharedContext* modulesc);
  MOZ_MUST_USE bool enterWith(BytecodeEmitter* bce);
  MOZ_MUST_USE bool deadZoneFrameSlots(BytecodeEmitter* bce) const;

  MOZ_MUST_USE bool leave(BytecodeEmitter* bce, bool nonLocal = false);

  uint32_t index() const {
    MOZ_ASSERT(scopeIndex_ != ScopeNote::NoScopeIndex,
               "Did you forget to intern a Scope?");
    return scopeIndex_;
  }

  uint32_t noteIndex() const { return noteIndex_; }

  Scope* scope(const BytecodeEmitter* bce) const;

  bool hasEnvironment() const { return hasEnvironment_; }

  // The first frame slot used.
  uint32_t frameSlotStart() const {
    if (EmitterScope* inFrame = enclosingInFrame()) {
      return inFrame->nextFrameSlot_;
    }
    return 0;
  }

  // The last frame slot used + 1.
  uint32_t frameSlotEnd() const { return nextFrameSlot_; }

  EmitterScope* enclosingInFrame() const {
    return Nestable<EmitterScope>::enclosing();
  }

  NameLocation lookup(BytecodeEmitter* bce, JSAtom* name);

  mozilla::Maybe<NameLocation> locationBoundInScope(JSAtom* name,
                                                    EmitterScope* target);
};

} /* namespace frontend */
} /* namespace js */

#endif /* frontend_EmitterScope_h */