js/src/frontend/BytecodeEmitter.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial