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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
|
/* -*- 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/AbstractScopePtr.h"
#include "frontend/NameAnalysisTypes.h"
#include "frontend/NameCollections.h"
#include "frontend/ParseContext.h"
#include "frontend/SharedContext.h"
#include "js/TypeDecls.h"
#include "vm/BytecodeUtil.h" // JSOp
#include "vm/SharedStencil.h" // GCThingIndex
namespace js {
class Scope;
namespace frontend {
struct BytecodeEmitter;
// 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.
GCThingIndex 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);
MOZ_MUST_USE bool checkSlotLimits(BytecodeEmitter* bce,
const ParserBindingIter& bi);
MOZ_MUST_USE bool checkEnvironmentChainLength(BytecodeEmitter* bce);
void updateFrameFixedSlots(BytecodeEmitter* bce, const ParserBindingIter& bi);
MOZ_MUST_USE bool putNameInCache(BytecodeEmitter* bce, const ParserAtom* name,
NameLocation loc);
mozilla::Maybe<NameLocation> lookupInCache(BytecodeEmitter* bce,
const ParserAtom* name);
EmitterScope* enclosing(BytecodeEmitter** bce) const;
mozilla::Maybe<ScopeIndex> enclosingScopeIndex(BytecodeEmitter* bce) const;
static bool nameCanBeFree(BytecodeEmitter* bce, const ParserAtom* name);
static NameLocation searchInEnclosingScope(JSAtom* name, Scope* scope,
uint8_t hops);
NameLocation searchAndCache(BytecodeEmitter* bce, const ParserAtom* name);
MOZ_MUST_USE bool internEmptyGlobalScopeAsBody(BytecodeEmitter* bce);
template <typename ScopeCreator>
MOZ_MUST_USE bool internScopeCreationData(BytecodeEmitter* bce,
ScopeCreator createScope);
template <typename ScopeCreator>
MOZ_MUST_USE bool internBodyScopeCreationData(BytecodeEmitter* bce,
ScopeCreator createScope);
MOZ_MUST_USE bool appendScopeNote(BytecodeEmitter* bce);
MOZ_MUST_USE bool clearFrameSlotRange(BytecodeEmitter* bce, JSOp opcode,
uint32_t slotStart,
uint32_t slotEnd) const;
MOZ_MUST_USE bool deadZoneFrameSlotRange(BytecodeEmitter* bce,
uint32_t slotStart,
uint32_t slotEnd) const {
return clearFrameSlotRange(bce, JSOp::Uninitialized, slotStart, slotEnd);
}
public:
explicit EmitterScope(BytecodeEmitter* bce);
void dump(BytecodeEmitter* bce);
MOZ_MUST_USE bool enterLexical(BytecodeEmitter* bce, ScopeKind kind,
LexicalScope::ParserData* 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 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);
GCThingIndex index() const {
MOZ_ASSERT(scopeIndex_ != ScopeNote::NoScopeIndex,
"Did you forget to intern a Scope?");
return scopeIndex_;
}
uint32_t noteIndex() const { return noteIndex_; }
AbstractScopePtr scope(const BytecodeEmitter* bce) const;
mozilla::Maybe<ScopeIndex> scopeIndex(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, const ParserAtom* name);
mozilla::Maybe<NameLocation> locationBoundInScope(const ParserAtom* name,
EmitterScope* target);
};
} /* namespace frontend */
} /* namespace js */
#endif /* frontend_EmitterScope_h */
|