js/src/frontend/BytecodeEmitter.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/frontend/BytecodeEmitter.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,289 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#ifndef frontend_BytecodeEmitter_h
    1.11 +#define frontend_BytecodeEmitter_h
    1.12 +
    1.13 +/*
    1.14 + * JS bytecode generation.
    1.15 + */
    1.16 +
    1.17 +#include "jscntxt.h"
    1.18 +#include "jsopcode.h"
    1.19 +#include "jsscript.h"
    1.20 +
    1.21 +#include "frontend/ParseMaps.h"
    1.22 +#include "frontend/SourceNotes.h"
    1.23 +
    1.24 +namespace js {
    1.25 +namespace frontend {
    1.26 +
    1.27 +class FullParseHandler;
    1.28 +class ObjectBox;
    1.29 +class ParseNode;
    1.30 +template <typename ParseHandler> class Parser;
    1.31 +class SharedContext;
    1.32 +class TokenStream;
    1.33 +
    1.34 +class CGConstList {
    1.35 +    Vector<Value> list;
    1.36 +  public:
    1.37 +    CGConstList(ExclusiveContext *cx) : list(cx) {}
    1.38 +    bool append(Value v) { JS_ASSERT_IF(v.isString(), v.toString()->isAtom()); return list.append(v); }
    1.39 +    size_t length() const { return list.length(); }
    1.40 +    void finish(ConstArray *array);
    1.41 +};
    1.42 +
    1.43 +struct CGObjectList {
    1.44 +    uint32_t            length;     /* number of emitted so far objects */
    1.45 +    ObjectBox           *lastbox;   /* last emitted object */
    1.46 +
    1.47 +    CGObjectList() : length(0), lastbox(nullptr) {}
    1.48 +
    1.49 +    unsigned add(ObjectBox *objbox);
    1.50 +    unsigned indexOf(JSObject *obj);
    1.51 +    void finish(ObjectArray *array);
    1.52 +    ObjectBox* find(uint32_t index);
    1.53 +};
    1.54 +
    1.55 +struct CGTryNoteList {
    1.56 +    Vector<JSTryNote> list;
    1.57 +    CGTryNoteList(ExclusiveContext *cx) : list(cx) {}
    1.58 +
    1.59 +    bool append(JSTryNoteKind kind, uint32_t stackDepth, size_t start, size_t end);
    1.60 +    size_t length() const { return list.length(); }
    1.61 +    void finish(TryNoteArray *array);
    1.62 +};
    1.63 +
    1.64 +struct CGBlockScopeList {
    1.65 +    Vector<BlockScopeNote> list;
    1.66 +    CGBlockScopeList(ExclusiveContext *cx) : list(cx) {}
    1.67 +
    1.68 +    bool append(uint32_t scopeObject, uint32_t offset, uint32_t parent);
    1.69 +    uint32_t findEnclosingScope(uint32_t index);
    1.70 +    void recordEnd(uint32_t index, uint32_t offset);
    1.71 +    size_t length() const { return list.length(); }
    1.72 +    void finish(BlockScopeArray *array);
    1.73 +};
    1.74 +
    1.75 +struct StmtInfoBCE;
    1.76 +
    1.77 +// Use zero inline elements because these go on the stack and affect how many
    1.78 +// nested functions are possible.
    1.79 +typedef Vector<jsbytecode, 0> BytecodeVector;
    1.80 +typedef Vector<jssrcnote, 0> SrcNotesVector;
    1.81 +
    1.82 +struct BytecodeEmitter
    1.83 +{
    1.84 +    typedef StmtInfoBCE StmtInfo;
    1.85 +
    1.86 +    SharedContext   *const sc;      /* context shared between parsing and bytecode generation */
    1.87 +
    1.88 +    BytecodeEmitter *const parent;  /* enclosing function or global context */
    1.89 +
    1.90 +    Rooted<JSScript*> script;       /* the JSScript we're ultimately producing */
    1.91 +
    1.92 +    struct EmitSection {
    1.93 +        BytecodeVector code;        /* bytecode */
    1.94 +        SrcNotesVector notes;       /* source notes, see below */
    1.95 +        ptrdiff_t   lastNoteOffset; /* code offset for last source note */
    1.96 +        uint32_t    currentLine;    /* line number for tree-based srcnote gen */
    1.97 +        uint32_t    lastColumn;     /* zero-based column index on currentLine of
    1.98 +                                       last SRC_COLSPAN-annotated opcode */
    1.99 +
   1.100 +        EmitSection(ExclusiveContext *cx, uint32_t lineNum)
   1.101 +          : code(cx), notes(cx), lastNoteOffset(0), currentLine(lineNum), lastColumn(0)
   1.102 +        {}
   1.103 +    };
   1.104 +    EmitSection prolog, main, *current;
   1.105 +
   1.106 +    /* the parser */
   1.107 +    Parser<FullParseHandler> *const parser;
   1.108 +
   1.109 +    HandleScript    evalCaller;     /* scripted caller info for eval and dbgapi */
   1.110 +
   1.111 +    StmtInfoBCE     *topStmt;       /* top of statement info stack */
   1.112 +    StmtInfoBCE     *topScopeStmt;  /* top lexical scope statement */
   1.113 +    Rooted<NestedScopeObject *> staticScope;
   1.114 +                                    /* compile time scope chain */
   1.115 +
   1.116 +    OwnedAtomIndexMapPtr atomIndices; /* literals indexed for mapping */
   1.117 +    unsigned        firstLine;      /* first line, for JSScript::initFromEmitter */
   1.118 +
   1.119 +    int32_t         stackDepth;     /* current stack depth in script frame */
   1.120 +    uint32_t        maxStackDepth;  /* maximum stack depth so far */
   1.121 +
   1.122 +    uint32_t        arrayCompDepth; /* stack depth of array in comprehension */
   1.123 +
   1.124 +    unsigned        emitLevel;      /* js::frontend::EmitTree recursion level */
   1.125 +
   1.126 +    CGConstList     constList;      /* constants to be included with the script */
   1.127 +
   1.128 +    CGObjectList    objectList;     /* list of emitted objects */
   1.129 +    CGObjectList    regexpList;     /* list of emitted regexp that will be
   1.130 +                                       cloned during execution */
   1.131 +    CGTryNoteList   tryNoteList;    /* list of emitted try notes */
   1.132 +    CGBlockScopeList blockScopeList;/* list of emitted block scope notes */
   1.133 +
   1.134 +    uint16_t        typesetCount;   /* Number of JOF_TYPESET opcodes generated */
   1.135 +
   1.136 +    bool            hasSingletons:1;    /* script contains singleton initializer JSOP_OBJECT */
   1.137 +
   1.138 +    bool            emittingForInit:1;  /* true while emitting init expr of for; exclude 'in' */
   1.139 +
   1.140 +    bool            emittingRunOnceLambda:1; /* true while emitting a lambda which is only
   1.141 +                                                expected to run once. */
   1.142 +    bool            lazyRunOnceLambda:1; /* true while lazily emitting a script for
   1.143 +                                          * a lambda which is only expected to run once. */
   1.144 +
   1.145 +    bool isRunOnceLambda();
   1.146 +
   1.147 +    bool            insideEval:1;       /* True if compiling an eval-expression or a function
   1.148 +                                           nested inside an eval. */
   1.149 +
   1.150 +    const bool      hasGlobalScope:1;   /* frontend::CompileScript's scope chain is the
   1.151 +                                           global object */
   1.152 +
   1.153 +    enum EmitterMode {
   1.154 +        Normal,
   1.155 +
   1.156 +        /*
   1.157 +         * Emit JSOP_GETINTRINSIC instead of JSOP_NAME and assert that
   1.158 +         * JSOP_NAME and JSOP_*GNAME don't ever get emitted. See the comment
   1.159 +         * for the field |selfHostingMode| in Parser.h for details.
   1.160 +         */
   1.161 +        SelfHosting,
   1.162 +
   1.163 +        /*
   1.164 +         * Check the static scope chain of the root function for resolving free
   1.165 +         * variable accesses in the script.
   1.166 +         */
   1.167 +        LazyFunction
   1.168 +    };
   1.169 +
   1.170 +    const EmitterMode emitterMode;
   1.171 +
   1.172 +    /*
   1.173 +     * Note that BytecodeEmitters are magic: they own the arena "top-of-stack"
   1.174 +     * space above their tempMark points. This means that you cannot alloc from
   1.175 +     * tempLifoAlloc and save the pointer beyond the next BytecodeEmitter
   1.176 +     * destruction.
   1.177 +     */
   1.178 +    BytecodeEmitter(BytecodeEmitter *parent, Parser<FullParseHandler> *parser, SharedContext *sc,
   1.179 +                    HandleScript script, bool insideEval, HandleScript evalCaller,
   1.180 +                    bool hasGlobalScope, uint32_t lineNum, EmitterMode emitterMode = Normal);
   1.181 +    bool init();
   1.182 +
   1.183 +    bool isAliasedName(ParseNode *pn);
   1.184 +
   1.185 +    MOZ_ALWAYS_INLINE
   1.186 +    bool makeAtomIndex(JSAtom *atom, jsatomid *indexp) {
   1.187 +        AtomIndexAddPtr p = atomIndices->lookupForAdd(atom);
   1.188 +        if (p) {
   1.189 +            *indexp = p.value();
   1.190 +            return true;
   1.191 +        }
   1.192 +
   1.193 +        jsatomid index = atomIndices->count();
   1.194 +        if (!atomIndices->add(p, atom, index))
   1.195 +            return false;
   1.196 +
   1.197 +        *indexp = index;
   1.198 +        return true;
   1.199 +    }
   1.200 +
   1.201 +    bool isInLoop();
   1.202 +    bool checkSingletonContext();
   1.203 +
   1.204 +    bool needsImplicitThis();
   1.205 +
   1.206 +    void tellDebuggerAboutCompiledScript(ExclusiveContext *cx);
   1.207 +
   1.208 +    inline TokenStream *tokenStream();
   1.209 +
   1.210 +    BytecodeVector &code() const { return current->code; }
   1.211 +    jsbytecode *code(ptrdiff_t offset) const { return current->code.begin() + offset; }
   1.212 +    ptrdiff_t offset() const { return current->code.end() - current->code.begin(); }
   1.213 +    ptrdiff_t prologOffset() const { return prolog.code.end() - prolog.code.begin(); }
   1.214 +    void switchToMain() { current = &main; }
   1.215 +    void switchToProlog() { current = &prolog; }
   1.216 +
   1.217 +    SrcNotesVector &notes() const { return current->notes; }
   1.218 +    ptrdiff_t lastNoteOffset() const { return current->lastNoteOffset; }
   1.219 +    unsigned currentLine() const { return current->currentLine; }
   1.220 +    unsigned lastColumn() const { return current->lastColumn; }
   1.221 +
   1.222 +    bool reportError(ParseNode *pn, unsigned errorNumber, ...);
   1.223 +    bool reportStrictWarning(ParseNode *pn, unsigned errorNumber, ...);
   1.224 +    bool reportStrictModeError(ParseNode *pn, unsigned errorNumber, ...);
   1.225 +};
   1.226 +
   1.227 +/*
   1.228 + * Emit one bytecode.
   1.229 + */
   1.230 +ptrdiff_t
   1.231 +Emit1(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op);
   1.232 +
   1.233 +/*
   1.234 + * Emit two bytecodes, an opcode (op) with a byte of immediate operand (op1).
   1.235 + */
   1.236 +ptrdiff_t
   1.237 +Emit2(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op, jsbytecode op1);
   1.238 +
   1.239 +/*
   1.240 + * Emit three bytecodes, an opcode with two bytes of immediate operands.
   1.241 + */
   1.242 +ptrdiff_t
   1.243 +Emit3(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op, jsbytecode op1, jsbytecode op2);
   1.244 +
   1.245 +/*
   1.246 + * Emit (1 + extra) bytecodes, for N bytes of op and its immediate operand.
   1.247 + */
   1.248 +ptrdiff_t
   1.249 +EmitN(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op, size_t extra);
   1.250 +
   1.251 +/*
   1.252 + * Emit code into bce for the tree rooted at pn.
   1.253 + */
   1.254 +bool
   1.255 +EmitTree(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn);
   1.256 +
   1.257 +/*
   1.258 + * Emit function code using bce for the tree rooted at body.
   1.259 + */
   1.260 +bool
   1.261 +EmitFunctionScript(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *body);
   1.262 +
   1.263 +/*
   1.264 + * Append a new source note of the given type (and therefore size) to bce's
   1.265 + * notes dynamic array, updating bce->noteCount. Return the new note's index
   1.266 + * within the array pointed at by bce->current->notes. Return -1 if out of
   1.267 + * memory.
   1.268 + */
   1.269 +int
   1.270 +NewSrcNote(ExclusiveContext *cx, BytecodeEmitter *bce, SrcNoteType type);
   1.271 +
   1.272 +int
   1.273 +NewSrcNote2(ExclusiveContext *cx, BytecodeEmitter *bce, SrcNoteType type, ptrdiff_t offset);
   1.274 +
   1.275 +int
   1.276 +NewSrcNote3(ExclusiveContext *cx, BytecodeEmitter *bce, SrcNoteType type, ptrdiff_t offset1,
   1.277 +               ptrdiff_t offset2);
   1.278 +
   1.279 +/* NB: this function can add at most one extra extended delta note. */
   1.280 +bool
   1.281 +AddToSrcNoteDelta(ExclusiveContext *cx, BytecodeEmitter *bce, jssrcnote *sn, ptrdiff_t delta);
   1.282 +
   1.283 +bool
   1.284 +FinishTakingSrcNotes(ExclusiveContext *cx, BytecodeEmitter *bce, uint32_t *out);
   1.285 +
   1.286 +void
   1.287 +CopySrcNotes(BytecodeEmitter *bce, jssrcnote *destination, uint32_t nsrcnotes);
   1.288 +
   1.289 +} /* namespace frontend */
   1.290 +} /* namespace js */
   1.291 +
   1.292 +#endif /* frontend_BytecodeEmitter_h */

mercurial