Thu, 15 Jan 2015 15:55:04 +0100
Back out 97036ab72558 which inappropriately compared turds to third parties.
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/. */
7 #ifndef frontend_BytecodeEmitter_h
8 #define frontend_BytecodeEmitter_h
10 /*
11 * JS bytecode generation.
12 */
14 #include "jscntxt.h"
15 #include "jsopcode.h"
16 #include "jsscript.h"
18 #include "frontend/ParseMaps.h"
19 #include "frontend/SourceNotes.h"
21 namespace js {
22 namespace frontend {
24 class FullParseHandler;
25 class ObjectBox;
26 class ParseNode;
27 template <typename ParseHandler> class Parser;
28 class SharedContext;
29 class TokenStream;
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 };
40 struct CGObjectList {
41 uint32_t length; /* number of emitted so far objects */
42 ObjectBox *lastbox; /* last emitted object */
44 CGObjectList() : length(0), lastbox(nullptr) {}
46 unsigned add(ObjectBox *objbox);
47 unsigned indexOf(JSObject *obj);
48 void finish(ObjectArray *array);
49 ObjectBox* find(uint32_t index);
50 };
52 struct CGTryNoteList {
53 Vector<JSTryNote> list;
54 CGTryNoteList(ExclusiveContext *cx) : list(cx) {}
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 };
61 struct CGBlockScopeList {
62 Vector<BlockScopeNote> list;
63 CGBlockScopeList(ExclusiveContext *cx) : list(cx) {}
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 };
72 struct StmtInfoBCE;
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;
79 struct BytecodeEmitter
80 {
81 typedef StmtInfoBCE StmtInfo;
83 SharedContext *const sc; /* context shared between parsing and bytecode generation */
85 BytecodeEmitter *const parent; /* enclosing function or global context */
87 Rooted<JSScript*> script; /* the JSScript we're ultimately producing */
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 */
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;
103 /* the parser */
104 Parser<FullParseHandler> *const parser;
106 HandleScript evalCaller; /* scripted caller info for eval and dbgapi */
108 StmtInfoBCE *topStmt; /* top of statement info stack */
109 StmtInfoBCE *topScopeStmt; /* top lexical scope statement */
110 Rooted<NestedScopeObject *> staticScope;
111 /* compile time scope chain */
113 OwnedAtomIndexMapPtr atomIndices; /* literals indexed for mapping */
114 unsigned firstLine; /* first line, for JSScript::initFromEmitter */
116 int32_t stackDepth; /* current stack depth in script frame */
117 uint32_t maxStackDepth; /* maximum stack depth so far */
119 uint32_t arrayCompDepth; /* stack depth of array in comprehension */
121 unsigned emitLevel; /* js::frontend::EmitTree recursion level */
123 CGConstList constList; /* constants to be included with the script */
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 */
131 uint16_t typesetCount; /* Number of JOF_TYPESET opcodes generated */
133 bool hasSingletons:1; /* script contains singleton initializer JSOP_OBJECT */
135 bool emittingForInit:1; /* true while emitting init expr of for; exclude 'in' */
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. */
142 bool isRunOnceLambda();
144 bool insideEval:1; /* True if compiling an eval-expression or a function
145 nested inside an eval. */
147 const bool hasGlobalScope:1; /* frontend::CompileScript's scope chain is the
148 global object */
150 enum EmitterMode {
151 Normal,
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,
160 /*
161 * Check the static scope chain of the root function for resolving free
162 * variable accesses in the script.
163 */
164 LazyFunction
165 };
167 const EmitterMode emitterMode;
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();
180 bool isAliasedName(ParseNode *pn);
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 }
190 jsatomid index = atomIndices->count();
191 if (!atomIndices->add(p, atom, index))
192 return false;
194 *indexp = index;
195 return true;
196 }
198 bool isInLoop();
199 bool checkSingletonContext();
201 bool needsImplicitThis();
203 void tellDebuggerAboutCompiledScript(ExclusiveContext *cx);
205 inline TokenStream *tokenStream();
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; }
214 SrcNotesVector ¬es() 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; }
219 bool reportError(ParseNode *pn, unsigned errorNumber, ...);
220 bool reportStrictWarning(ParseNode *pn, unsigned errorNumber, ...);
221 bool reportStrictModeError(ParseNode *pn, unsigned errorNumber, ...);
222 };
224 /*
225 * Emit one bytecode.
226 */
227 ptrdiff_t
228 Emit1(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op);
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);
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);
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);
248 /*
249 * Emit code into bce for the tree rooted at pn.
250 */
251 bool
252 EmitTree(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn);
254 /*
255 * Emit function code using bce for the tree rooted at body.
256 */
257 bool
258 EmitFunctionScript(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *body);
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);
269 int
270 NewSrcNote2(ExclusiveContext *cx, BytecodeEmitter *bce, SrcNoteType type, ptrdiff_t offset);
272 int
273 NewSrcNote3(ExclusiveContext *cx, BytecodeEmitter *bce, SrcNoteType type, ptrdiff_t offset1,
274 ptrdiff_t offset2);
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);
280 bool
281 FinishTakingSrcNotes(ExclusiveContext *cx, BytecodeEmitter *bce, uint32_t *out);
283 void
284 CopySrcNotes(BytecodeEmitter *bce, jssrcnote *destination, uint32_t nsrcnotes);
286 } /* namespace frontend */
287 } /* namespace js */
289 #endif /* frontend_BytecodeEmitter_h */