js/src/frontend/BytecodeEmitter.h

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:736cebda765f
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
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_BytecodeEmitter_h
8 #define frontend_BytecodeEmitter_h
9
10 /*
11 * JS bytecode generation.
12 */
13
14 #include "jscntxt.h"
15 #include "jsopcode.h"
16 #include "jsscript.h"
17
18 #include "frontend/ParseMaps.h"
19 #include "frontend/SourceNotes.h"
20
21 namespace js {
22 namespace frontend {
23
24 class FullParseHandler;
25 class ObjectBox;
26 class ParseNode;
27 template <typename ParseHandler> class Parser;
28 class SharedContext;
29 class TokenStream;
30
31 class CGConstList {
32 Vector<Value> list;
33 public:
34 CGConstList(ExclusiveContext *cx) : list(cx) {}
35 bool append(Value v) { JS_ASSERT_IF(v.isString(), v.toString()->isAtom()); return list.append(v); }
36 size_t length() const { return list.length(); }
37 void finish(ConstArray *array);
38 };
39
40 struct CGObjectList {
41 uint32_t length; /* number of emitted so far objects */
42 ObjectBox *lastbox; /* last emitted object */
43
44 CGObjectList() : length(0), lastbox(nullptr) {}
45
46 unsigned add(ObjectBox *objbox);
47 unsigned indexOf(JSObject *obj);
48 void finish(ObjectArray *array);
49 ObjectBox* find(uint32_t index);
50 };
51
52 struct CGTryNoteList {
53 Vector<JSTryNote> list;
54 CGTryNoteList(ExclusiveContext *cx) : list(cx) {}
55
56 bool append(JSTryNoteKind kind, uint32_t stackDepth, size_t start, size_t end);
57 size_t length() const { return list.length(); }
58 void finish(TryNoteArray *array);
59 };
60
61 struct CGBlockScopeList {
62 Vector<BlockScopeNote> list;
63 CGBlockScopeList(ExclusiveContext *cx) : list(cx) {}
64
65 bool append(uint32_t scopeObject, uint32_t offset, uint32_t parent);
66 uint32_t findEnclosingScope(uint32_t index);
67 void recordEnd(uint32_t index, uint32_t offset);
68 size_t length() const { return list.length(); }
69 void finish(BlockScopeArray *array);
70 };
71
72 struct StmtInfoBCE;
73
74 // Use zero inline elements because these go on the stack and affect how many
75 // nested functions are possible.
76 typedef Vector<jsbytecode, 0> BytecodeVector;
77 typedef Vector<jssrcnote, 0> SrcNotesVector;
78
79 struct BytecodeEmitter
80 {
81 typedef StmtInfoBCE StmtInfo;
82
83 SharedContext *const sc; /* context shared between parsing and bytecode generation */
84
85 BytecodeEmitter *const parent; /* enclosing function or global context */
86
87 Rooted<JSScript*> script; /* the JSScript we're ultimately producing */
88
89 struct EmitSection {
90 BytecodeVector code; /* bytecode */
91 SrcNotesVector notes; /* source notes, see below */
92 ptrdiff_t lastNoteOffset; /* code offset for last source note */
93 uint32_t currentLine; /* line number for tree-based srcnote gen */
94 uint32_t lastColumn; /* zero-based column index on currentLine of
95 last SRC_COLSPAN-annotated opcode */
96
97 EmitSection(ExclusiveContext *cx, uint32_t lineNum)
98 : code(cx), notes(cx), lastNoteOffset(0), currentLine(lineNum), lastColumn(0)
99 {}
100 };
101 EmitSection prolog, main, *current;
102
103 /* the parser */
104 Parser<FullParseHandler> *const parser;
105
106 HandleScript evalCaller; /* scripted caller info for eval and dbgapi */
107
108 StmtInfoBCE *topStmt; /* top of statement info stack */
109 StmtInfoBCE *topScopeStmt; /* top lexical scope statement */
110 Rooted<NestedScopeObject *> staticScope;
111 /* compile time scope chain */
112
113 OwnedAtomIndexMapPtr atomIndices; /* literals indexed for mapping */
114 unsigned firstLine; /* first line, for JSScript::initFromEmitter */
115
116 int32_t stackDepth; /* current stack depth in script frame */
117 uint32_t maxStackDepth; /* maximum stack depth so far */
118
119 uint32_t arrayCompDepth; /* stack depth of array in comprehension */
120
121 unsigned emitLevel; /* js::frontend::EmitTree recursion level */
122
123 CGConstList constList; /* constants to be included with the script */
124
125 CGObjectList objectList; /* list of emitted objects */
126 CGObjectList regexpList; /* list of emitted regexp that will be
127 cloned during execution */
128 CGTryNoteList tryNoteList; /* list of emitted try notes */
129 CGBlockScopeList blockScopeList;/* list of emitted block scope notes */
130
131 uint16_t typesetCount; /* Number of JOF_TYPESET opcodes generated */
132
133 bool hasSingletons:1; /* script contains singleton initializer JSOP_OBJECT */
134
135 bool emittingForInit:1; /* true while emitting init expr of for; exclude 'in' */
136
137 bool emittingRunOnceLambda:1; /* true while emitting a lambda which is only
138 expected to run once. */
139 bool lazyRunOnceLambda:1; /* true while lazily emitting a script for
140 * a lambda which is only expected to run once. */
141
142 bool isRunOnceLambda();
143
144 bool insideEval:1; /* True if compiling an eval-expression or a function
145 nested inside an eval. */
146
147 const bool hasGlobalScope:1; /* frontend::CompileScript's scope chain is the
148 global object */
149
150 enum EmitterMode {
151 Normal,
152
153 /*
154 * Emit JSOP_GETINTRINSIC instead of JSOP_NAME and assert that
155 * JSOP_NAME and JSOP_*GNAME don't ever get emitted. See the comment
156 * for the field |selfHostingMode| in Parser.h for details.
157 */
158 SelfHosting,
159
160 /*
161 * Check the static scope chain of the root function for resolving free
162 * variable accesses in the script.
163 */
164 LazyFunction
165 };
166
167 const EmitterMode emitterMode;
168
169 /*
170 * Note that BytecodeEmitters are magic: they own the arena "top-of-stack"
171 * space above their tempMark points. This means that you cannot alloc from
172 * tempLifoAlloc and save the pointer beyond the next BytecodeEmitter
173 * destruction.
174 */
175 BytecodeEmitter(BytecodeEmitter *parent, Parser<FullParseHandler> *parser, SharedContext *sc,
176 HandleScript script, bool insideEval, HandleScript evalCaller,
177 bool hasGlobalScope, uint32_t lineNum, EmitterMode emitterMode = Normal);
178 bool init();
179
180 bool isAliasedName(ParseNode *pn);
181
182 MOZ_ALWAYS_INLINE
183 bool makeAtomIndex(JSAtom *atom, jsatomid *indexp) {
184 AtomIndexAddPtr p = atomIndices->lookupForAdd(atom);
185 if (p) {
186 *indexp = p.value();
187 return true;
188 }
189
190 jsatomid index = atomIndices->count();
191 if (!atomIndices->add(p, atom, index))
192 return false;
193
194 *indexp = index;
195 return true;
196 }
197
198 bool isInLoop();
199 bool checkSingletonContext();
200
201 bool needsImplicitThis();
202
203 void tellDebuggerAboutCompiledScript(ExclusiveContext *cx);
204
205 inline TokenStream *tokenStream();
206
207 BytecodeVector &code() const { return current->code; }
208 jsbytecode *code(ptrdiff_t offset) const { return current->code.begin() + offset; }
209 ptrdiff_t offset() const { return current->code.end() - current->code.begin(); }
210 ptrdiff_t prologOffset() const { return prolog.code.end() - prolog.code.begin(); }
211 void switchToMain() { current = &main; }
212 void switchToProlog() { current = &prolog; }
213
214 SrcNotesVector &notes() const { return current->notes; }
215 ptrdiff_t lastNoteOffset() const { return current->lastNoteOffset; }
216 unsigned currentLine() const { return current->currentLine; }
217 unsigned lastColumn() const { return current->lastColumn; }
218
219 bool reportError(ParseNode *pn, unsigned errorNumber, ...);
220 bool reportStrictWarning(ParseNode *pn, unsigned errorNumber, ...);
221 bool reportStrictModeError(ParseNode *pn, unsigned errorNumber, ...);
222 };
223
224 /*
225 * Emit one bytecode.
226 */
227 ptrdiff_t
228 Emit1(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op);
229
230 /*
231 * Emit two bytecodes, an opcode (op) with a byte of immediate operand (op1).
232 */
233 ptrdiff_t
234 Emit2(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op, jsbytecode op1);
235
236 /*
237 * Emit three bytecodes, an opcode with two bytes of immediate operands.
238 */
239 ptrdiff_t
240 Emit3(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op, jsbytecode op1, jsbytecode op2);
241
242 /*
243 * Emit (1 + extra) bytecodes, for N bytes of op and its immediate operand.
244 */
245 ptrdiff_t
246 EmitN(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op, size_t extra);
247
248 /*
249 * Emit code into bce for the tree rooted at pn.
250 */
251 bool
252 EmitTree(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn);
253
254 /*
255 * Emit function code using bce for the tree rooted at body.
256 */
257 bool
258 EmitFunctionScript(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *body);
259
260 /*
261 * Append a new source note of the given type (and therefore size) to bce's
262 * notes dynamic array, updating bce->noteCount. Return the new note's index
263 * within the array pointed at by bce->current->notes. Return -1 if out of
264 * memory.
265 */
266 int
267 NewSrcNote(ExclusiveContext *cx, BytecodeEmitter *bce, SrcNoteType type);
268
269 int
270 NewSrcNote2(ExclusiveContext *cx, BytecodeEmitter *bce, SrcNoteType type, ptrdiff_t offset);
271
272 int
273 NewSrcNote3(ExclusiveContext *cx, BytecodeEmitter *bce, SrcNoteType type, ptrdiff_t offset1,
274 ptrdiff_t offset2);
275
276 /* NB: this function can add at most one extra extended delta note. */
277 bool
278 AddToSrcNoteDelta(ExclusiveContext *cx, BytecodeEmitter *bce, jssrcnote *sn, ptrdiff_t delta);
279
280 bool
281 FinishTakingSrcNotes(ExclusiveContext *cx, BytecodeEmitter *bce, uint32_t *out);
282
283 void
284 CopySrcNotes(BytecodeEmitter *bce, jssrcnote *destination, uint32_t nsrcnotes);
285
286 } /* namespace frontend */
287 } /* namespace js */
288
289 #endif /* frontend_BytecodeEmitter_h */

mercurial