1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/frontend/FullParseHandler.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,709 @@ 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_FullParseHandler_h 1.11 +#define frontend_FullParseHandler_h 1.12 + 1.13 +#include "mozilla/PodOperations.h" 1.14 + 1.15 +#include "frontend/ParseNode.h" 1.16 +#include "frontend/SharedContext.h" 1.17 + 1.18 +namespace js { 1.19 +namespace frontend { 1.20 + 1.21 +template <typename ParseHandler> 1.22 +class Parser; 1.23 + 1.24 +class SyntaxParseHandler; 1.25 + 1.26 +// Parse handler used when generating a full parse tree for all code which the 1.27 +// parser encounters. 1.28 +class FullParseHandler 1.29 +{ 1.30 + ParseNodeAllocator allocator; 1.31 + TokenStream &tokenStream; 1.32 + bool foldConstants; 1.33 + 1.34 + ParseNode *allocParseNode(size_t size) { 1.35 + JS_ASSERT(size == sizeof(ParseNode)); 1.36 + return static_cast<ParseNode *>(allocator.allocNode()); 1.37 + } 1.38 + 1.39 + ParseNode *cloneNode(const ParseNode &other) { 1.40 + ParseNode *node = allocParseNode(sizeof(ParseNode)); 1.41 + if (!node) 1.42 + return nullptr; 1.43 + mozilla::PodAssign(node, &other); 1.44 + return node; 1.45 + } 1.46 + 1.47 + /* 1.48 + * If this is a full parse to construct the bytecode for a function that 1.49 + * was previously lazily parsed, that lazy function and the current index 1.50 + * into its inner functions. We do not want to reparse the inner functions. 1.51 + */ 1.52 + LazyScript * const lazyOuterFunction_; 1.53 + size_t lazyInnerFunctionIndex; 1.54 + 1.55 + const TokenPos &pos() { 1.56 + return tokenStream.currentToken().pos; 1.57 + } 1.58 + 1.59 + public: 1.60 + 1.61 + /* 1.62 + * If non-nullptr, points to a syntax parser which can be used for inner 1.63 + * functions. Cleared if language features not handled by the syntax parser 1.64 + * are encountered, in which case all future activity will use the full 1.65 + * parser. 1.66 + */ 1.67 + Parser<SyntaxParseHandler> *syntaxParser; 1.68 + 1.69 + /* new_ methods for creating parse nodes. These report OOM on context. */ 1.70 + JS_DECLARE_NEW_METHODS(new_, allocParseNode, inline) 1.71 + 1.72 + typedef ParseNode *Node; 1.73 + typedef Definition *DefinitionNode; 1.74 + 1.75 + FullParseHandler(ExclusiveContext *cx, LifoAlloc &alloc, 1.76 + TokenStream &tokenStream, bool foldConstants, 1.77 + Parser<SyntaxParseHandler> *syntaxParser, LazyScript *lazyOuterFunction) 1.78 + : allocator(cx, alloc), 1.79 + tokenStream(tokenStream), 1.80 + foldConstants(foldConstants), 1.81 + lazyOuterFunction_(lazyOuterFunction), 1.82 + lazyInnerFunctionIndex(0), 1.83 + syntaxParser(syntaxParser) 1.84 + {} 1.85 + 1.86 + static ParseNode *null() { return nullptr; } 1.87 + 1.88 + ParseNode *freeTree(ParseNode *pn) { return allocator.freeTree(pn); } 1.89 + void prepareNodeForMutation(ParseNode *pn) { return allocator.prepareNodeForMutation(pn); } 1.90 + const Token ¤tToken() { return tokenStream.currentToken(); } 1.91 + 1.92 + ParseNode *newName(PropertyName *name, uint32_t blockid, const TokenPos &pos) { 1.93 + return new_<NameNode>(PNK_NAME, JSOP_NAME, name, blockid, pos); 1.94 + } 1.95 + 1.96 + Definition *newPlaceholder(JSAtom *atom, uint32_t blockid, const TokenPos &pos) { 1.97 + Definition *dn = 1.98 + (Definition *) new_<NameNode>(PNK_NAME, JSOP_NOP, atom, blockid, pos); 1.99 + if (!dn) 1.100 + return nullptr; 1.101 + dn->setDefn(true); 1.102 + dn->pn_dflags |= PND_PLACEHOLDER; 1.103 + return dn; 1.104 + } 1.105 + 1.106 + ParseNode *newIdentifier(JSAtom *atom, const TokenPos &pos) { 1.107 + return new_<NullaryNode>(PNK_NAME, JSOP_NOP, pos, atom); 1.108 + } 1.109 + 1.110 + ParseNode *newNumber(double value, DecimalPoint decimalPoint, const TokenPos &pos) { 1.111 + ParseNode *pn = new_<NullaryNode>(PNK_NUMBER, pos); 1.112 + if (!pn) 1.113 + return nullptr; 1.114 + pn->initNumber(value, decimalPoint); 1.115 + return pn; 1.116 + } 1.117 + 1.118 + ParseNode *newBooleanLiteral(bool cond, const TokenPos &pos) { 1.119 + return new_<BooleanLiteral>(cond, pos); 1.120 + } 1.121 + 1.122 + ParseNode *newStringLiteral(JSAtom *atom, const TokenPos &pos) { 1.123 + return new_<NullaryNode>(PNK_STRING, JSOP_STRING, pos, atom); 1.124 + } 1.125 + 1.126 + ParseNode *newThisLiteral(const TokenPos &pos) { 1.127 + return new_<ThisLiteral>(pos); 1.128 + } 1.129 + 1.130 + ParseNode *newNullLiteral(const TokenPos &pos) { 1.131 + return new_<NullLiteral>(pos); 1.132 + } 1.133 + 1.134 + // The Boxer object here is any object that can allocate ObjectBoxes. 1.135 + // Specifically, a Boxer has a .newObjectBox(T) method that accepts a 1.136 + // Rooted<RegExpObject*> argument and returns an ObjectBox*. 1.137 + template <class Boxer> 1.138 + ParseNode *newRegExp(HandleObject reobj, const TokenPos &pos, Boxer &boxer) { 1.139 + ObjectBox *objbox = boxer.newObjectBox(reobj); 1.140 + if (!objbox) 1.141 + return null(); 1.142 + return new_<RegExpLiteral>(objbox, pos); 1.143 + } 1.144 + 1.145 + ParseNode *newConditional(ParseNode *cond, ParseNode *thenExpr, ParseNode *elseExpr) { 1.146 + return new_<ConditionalExpression>(cond, thenExpr, elseExpr); 1.147 + } 1.148 + 1.149 + void markAsSetCall(ParseNode *pn) { 1.150 + pn->pn_xflags |= PNX_SETCALL; 1.151 + } 1.152 + 1.153 + ParseNode *newDelete(uint32_t begin, ParseNode *expr) { 1.154 + if (expr->getKind() == PNK_NAME) { 1.155 + expr->pn_dflags |= PND_DEOPTIMIZED; 1.156 + expr->setOp(JSOP_DELNAME); 1.157 + } 1.158 + return newUnary(PNK_DELETE, JSOP_NOP, begin, expr); 1.159 + } 1.160 + 1.161 + ParseNode *newNullary(ParseNodeKind kind, JSOp op, const TokenPos &pos) { 1.162 + return new_<NullaryNode>(kind, op, pos); 1.163 + } 1.164 + 1.165 + ParseNode *newUnary(ParseNodeKind kind, JSOp op, uint32_t begin, ParseNode *kid) { 1.166 + TokenPos pos(begin, kid ? kid->pn_pos.end : begin + 1); 1.167 + return new_<UnaryNode>(kind, op, pos, kid); 1.168 + } 1.169 + 1.170 + ParseNode *newBinary(ParseNodeKind kind, JSOp op = JSOP_NOP) { 1.171 + return new_<BinaryNode>(kind, op, pos(), (ParseNode *) nullptr, (ParseNode *) nullptr); 1.172 + } 1.173 + ParseNode *newBinary(ParseNodeKind kind, ParseNode *left, 1.174 + JSOp op = JSOP_NOP) { 1.175 + return new_<BinaryNode>(kind, op, left->pn_pos, left, (ParseNode *) nullptr); 1.176 + } 1.177 + ParseNode *newBinary(ParseNodeKind kind, ParseNode *left, ParseNode *right, 1.178 + JSOp op = JSOP_NOP) { 1.179 + TokenPos pos(left->pn_pos.begin, right->pn_pos.end); 1.180 + return new_<BinaryNode>(kind, op, pos, left, right); 1.181 + } 1.182 + ParseNode *newBinaryOrAppend(ParseNodeKind kind, ParseNode *left, ParseNode *right, 1.183 + ParseContext<FullParseHandler> *pc, JSOp op = JSOP_NOP) 1.184 + { 1.185 + return ParseNode::newBinaryOrAppend(kind, op, left, right, this, pc, foldConstants); 1.186 + } 1.187 + 1.188 + ParseNode *newTernary(ParseNodeKind kind, 1.189 + ParseNode *first, ParseNode *second, ParseNode *third, 1.190 + JSOp op = JSOP_NOP) 1.191 + { 1.192 + return new_<TernaryNode>(kind, op, first, second, third); 1.193 + } 1.194 + 1.195 + // Expressions 1.196 + 1.197 + ParseNode *newArrayComprehension(ParseNode *body, unsigned blockid, const TokenPos &pos) { 1.198 + JS_ASSERT(pos.begin <= body->pn_pos.begin); 1.199 + JS_ASSERT(body->pn_pos.end <= pos.end); 1.200 + ParseNode *pn = new_<ListNode>(PNK_ARRAYCOMP, pos); 1.201 + if (!pn) 1.202 + return nullptr; 1.203 + pn->pn_blockid = blockid; 1.204 + pn->append(body); 1.205 + return pn; 1.206 + } 1.207 + 1.208 + ParseNode *newArrayLiteral(uint32_t begin, unsigned blockid) { 1.209 + ParseNode *literal = new_<ListNode>(PNK_ARRAY, TokenPos(begin, begin + 1)); 1.210 + // Later in this stack: remove dependency on this opcode. 1.211 + if (literal) { 1.212 + literal->setOp(JSOP_NEWINIT); 1.213 + literal->pn_blockid = blockid; 1.214 + } 1.215 + return literal; 1.216 + } 1.217 + 1.218 + bool addElision(ParseNode *literal, const TokenPos &pos) { 1.219 + ParseNode *elision = new_<NullaryNode>(PNK_ELISION, pos); 1.220 + if (!elision) 1.221 + return false; 1.222 + literal->append(elision); 1.223 + literal->pn_xflags |= PNX_SPECIALARRAYINIT | PNX_NONCONST; 1.224 + return true; 1.225 + } 1.226 + 1.227 + bool addSpreadElement(ParseNode *literal, uint32_t begin, ParseNode *inner) { 1.228 + TokenPos pos(begin, inner->pn_pos.end); 1.229 + ParseNode *spread = new_<UnaryNode>(PNK_SPREAD, JSOP_NOP, pos, inner); 1.230 + if (!spread) 1.231 + return null(); 1.232 + literal->append(spread); 1.233 + literal->pn_xflags |= PNX_SPECIALARRAYINIT | PNX_NONCONST; 1.234 + return true; 1.235 + } 1.236 + 1.237 + bool addArrayElement(ParseNode *literal, ParseNode *element) { 1.238 + if (!element->isConstant()) 1.239 + literal->pn_xflags |= PNX_NONCONST; 1.240 + literal->append(element); 1.241 + return true; 1.242 + } 1.243 + 1.244 + ParseNode *newObjectLiteral(uint32_t begin) { 1.245 + ParseNode *literal = new_<ListNode>(PNK_OBJECT, TokenPos(begin, begin + 1)); 1.246 + // Later in this stack: remove dependency on this opcode. 1.247 + if (literal) 1.248 + literal->setOp(JSOP_NEWINIT); 1.249 + return literal; 1.250 + } 1.251 + 1.252 + bool addPropertyDefinition(ParseNode *literal, ParseNode *name, ParseNode *expr) { 1.253 + ParseNode *propdef = newBinary(PNK_COLON, name, expr, JSOP_INITPROP); 1.254 + if (!propdef) 1.255 + return false; 1.256 + literal->append(propdef); 1.257 + return true; 1.258 + } 1.259 + 1.260 + bool addShorthandPropertyDefinition(ParseNode *literal, ParseNode *name) { 1.261 + JS_ASSERT(literal->isArity(PN_LIST)); 1.262 + literal->pn_xflags |= PNX_DESTRUCT | PNX_NONCONST; // XXX why PNX_DESTRUCT? 1.263 + return addPropertyDefinition(literal, name, name); 1.264 + } 1.265 + 1.266 + bool addAccessorPropertyDefinition(ParseNode *literal, ParseNode *name, ParseNode *fn, JSOp op) 1.267 + { 1.268 + JS_ASSERT(literal->isArity(PN_LIST)); 1.269 + literal->pn_xflags |= PNX_NONCONST; 1.270 + 1.271 + ParseNode *propdef = newBinary(PNK_COLON, name, fn, op); 1.272 + if (!propdef) 1.273 + return false; 1.274 + literal->append(propdef); 1.275 + return true; 1.276 + } 1.277 + 1.278 + // Statements 1.279 + 1.280 + ParseNode *newStatementList(unsigned blockid, const TokenPos &pos) { 1.281 + ParseNode *pn = new_<ListNode>(PNK_STATEMENTLIST, pos); 1.282 + if (pn) 1.283 + pn->pn_blockid = blockid; 1.284 + return pn; 1.285 + } 1.286 + 1.287 + template <typename PC> 1.288 + void addStatementToList(ParseNode *list, ParseNode *stmt, PC *pc) { 1.289 + JS_ASSERT(list->isKind(PNK_STATEMENTLIST)); 1.290 + 1.291 + if (stmt->isKind(PNK_FUNCTION)) { 1.292 + if (pc->atBodyLevel()) { 1.293 + // PNX_FUNCDEFS notifies the emitter that the block contains 1.294 + // body-level function definitions that should be processed 1.295 + // before the rest of nodes. 1.296 + list->pn_xflags |= PNX_FUNCDEFS; 1.297 + } else { 1.298 + // General deoptimization was done in Parser::functionDef. 1.299 + JS_ASSERT_IF(pc->sc->isFunctionBox(), 1.300 + pc->sc->asFunctionBox()->hasExtensibleScope()); 1.301 + } 1.302 + } 1.303 + 1.304 + list->append(stmt); 1.305 + } 1.306 + 1.307 + ParseNode *newEmptyStatement(const TokenPos &pos) { 1.308 + return new_<UnaryNode>(PNK_SEMI, JSOP_NOP, pos, (ParseNode *) nullptr); 1.309 + } 1.310 + 1.311 + ParseNode *newImportDeclaration(ParseNode *importSpecSet, 1.312 + ParseNode *moduleSpec, const TokenPos &pos) 1.313 + { 1.314 + ParseNode *pn = new_<BinaryNode>(PNK_IMPORT, JSOP_NOP, pos, 1.315 + importSpecSet, moduleSpec); 1.316 + if (!pn) 1.317 + return null(); 1.318 + return pn; 1.319 + } 1.320 + 1.321 + ParseNode *newExportDeclaration(ParseNode *kid, const TokenPos &pos) { 1.322 + return new_<UnaryNode>(PNK_EXPORT, JSOP_NOP, pos, kid); 1.323 + } 1.324 + 1.325 + ParseNode *newExportFromDeclaration(uint32_t begin, ParseNode *exportSpecSet, 1.326 + ParseNode *moduleSpec) 1.327 + { 1.328 + ParseNode *pn = new_<BinaryNode>(PNK_EXPORT_FROM, JSOP_NOP, exportSpecSet, moduleSpec); 1.329 + if (!pn) 1.330 + return null(); 1.331 + pn->pn_pos.begin = begin; 1.332 + return pn; 1.333 + } 1.334 + 1.335 + ParseNode *newExprStatement(ParseNode *expr, uint32_t end) { 1.336 + JS_ASSERT(expr->pn_pos.end <= end); 1.337 + return new_<UnaryNode>(PNK_SEMI, JSOP_NOP, TokenPos(expr->pn_pos.begin, end), expr); 1.338 + } 1.339 + 1.340 + ParseNode *newIfStatement(uint32_t begin, ParseNode *cond, ParseNode *thenBranch, 1.341 + ParseNode *elseBranch) 1.342 + { 1.343 + ParseNode *pn = new_<TernaryNode>(PNK_IF, JSOP_NOP, cond, thenBranch, elseBranch); 1.344 + if (!pn) 1.345 + return null(); 1.346 + pn->pn_pos.begin = begin; 1.347 + return pn; 1.348 + } 1.349 + 1.350 + ParseNode *newDoWhileStatement(ParseNode *body, ParseNode *cond, const TokenPos &pos) { 1.351 + return new_<BinaryNode>(PNK_DOWHILE, JSOP_NOP, pos, body, cond); 1.352 + } 1.353 + 1.354 + ParseNode *newWhileStatement(uint32_t begin, ParseNode *cond, ParseNode *body) { 1.355 + TokenPos pos(begin, body->pn_pos.end); 1.356 + return new_<BinaryNode>(PNK_WHILE, JSOP_NOP, pos, cond, body); 1.357 + } 1.358 + 1.359 + ParseNode *newForStatement(uint32_t begin, ParseNode *forHead, ParseNode *body, 1.360 + unsigned iflags) 1.361 + { 1.362 + /* A FOR node is binary, left is loop control and right is the body. */ 1.363 + JSOp op = forHead->isKind(PNK_FORIN) ? JSOP_ITER : JSOP_NOP; 1.364 + BinaryNode *pn = new_<BinaryNode>(PNK_FOR, op, TokenPos(begin, body->pn_pos.end), 1.365 + forHead, body); 1.366 + if (!pn) 1.367 + return null(); 1.368 + pn->pn_iflags = iflags; 1.369 + return pn; 1.370 + } 1.371 + 1.372 + ParseNode *newForHead(ParseNodeKind kind, ParseNode *pn1, ParseNode *pn2, ParseNode *pn3, 1.373 + const TokenPos &pos) 1.374 + { 1.375 + JS_ASSERT(kind == PNK_FORIN || kind == PNK_FOROF || kind == PNK_FORHEAD); 1.376 + return new_<TernaryNode>(kind, JSOP_NOP, pn1, pn2, pn3, pos); 1.377 + } 1.378 + 1.379 + ParseNode *newSwitchStatement(uint32_t begin, ParseNode *discriminant, ParseNode *caseList) { 1.380 + TokenPos pos(begin, caseList->pn_pos.end); 1.381 + return new_<BinaryNode>(PNK_SWITCH, JSOP_NOP, pos, discriminant, caseList); 1.382 + } 1.383 + 1.384 + ParseNode *newCaseOrDefault(uint32_t begin, ParseNode *expr, ParseNode *body) { 1.385 + TokenPos pos(begin, body->pn_pos.end); 1.386 + return new_<BinaryNode>(expr ? PNK_CASE : PNK_DEFAULT, JSOP_NOP, pos, expr, body); 1.387 + } 1.388 + 1.389 + ParseNode *newContinueStatement(PropertyName *label, const TokenPos &pos) { 1.390 + return new_<ContinueStatement>(label, pos); 1.391 + } 1.392 + 1.393 + ParseNode *newBreakStatement(PropertyName *label, const TokenPos &pos) { 1.394 + return new_<BreakStatement>(label, pos); 1.395 + } 1.396 + 1.397 + ParseNode *newReturnStatement(ParseNode *expr, const TokenPos &pos) { 1.398 + JS_ASSERT_IF(expr, pos.encloses(expr->pn_pos)); 1.399 + return new_<UnaryNode>(PNK_RETURN, JSOP_RETURN, pos, expr); 1.400 + } 1.401 + 1.402 + ParseNode *newWithStatement(uint32_t begin, ParseNode *expr, ParseNode *body, 1.403 + ObjectBox *staticWith) { 1.404 + return new_<BinaryObjNode>(PNK_WITH, JSOP_NOP, TokenPos(begin, body->pn_pos.end), 1.405 + expr, body, staticWith); 1.406 + } 1.407 + 1.408 + ParseNode *newLabeledStatement(PropertyName *label, ParseNode *stmt, uint32_t begin) { 1.409 + return new_<LabeledStatement>(label, stmt, begin); 1.410 + } 1.411 + 1.412 + ParseNode *newThrowStatement(ParseNode *expr, const TokenPos &pos) { 1.413 + JS_ASSERT(pos.encloses(expr->pn_pos)); 1.414 + return new_<UnaryNode>(PNK_THROW, JSOP_THROW, pos, expr); 1.415 + } 1.416 + 1.417 + ParseNode *newTryStatement(uint32_t begin, ParseNode *body, ParseNode *catchList, 1.418 + ParseNode *finallyBlock) { 1.419 + TokenPos pos(begin, (finallyBlock ? finallyBlock : catchList)->pn_pos.end); 1.420 + return new_<TernaryNode>(PNK_TRY, JSOP_NOP, body, catchList, finallyBlock, pos); 1.421 + } 1.422 + 1.423 + ParseNode *newDebuggerStatement(const TokenPos &pos) { 1.424 + return new_<DebuggerStatement>(pos); 1.425 + } 1.426 + 1.427 + ParseNode *newPropertyAccess(ParseNode *pn, PropertyName *name, uint32_t end) { 1.428 + return new_<PropertyAccess>(pn, name, pn->pn_pos.begin, end); 1.429 + } 1.430 + 1.431 + ParseNode *newPropertyByValue(ParseNode *lhs, ParseNode *index, uint32_t end) { 1.432 + return new_<PropertyByValue>(lhs, index, lhs->pn_pos.begin, end); 1.433 + } 1.434 + 1.435 + inline bool addCatchBlock(ParseNode *catchList, ParseNode *letBlock, 1.436 + ParseNode *catchName, ParseNode *catchGuard, ParseNode *catchBody); 1.437 + 1.438 + inline void setLastFunctionArgumentDefault(ParseNode *funcpn, ParseNode *pn); 1.439 + inline ParseNode *newFunctionDefinition(); 1.440 + void setFunctionBody(ParseNode *pn, ParseNode *kid) { 1.441 + pn->pn_body = kid; 1.442 + } 1.443 + void setFunctionBox(ParseNode *pn, FunctionBox *funbox) { 1.444 + JS_ASSERT(pn->isKind(PNK_FUNCTION)); 1.445 + pn->pn_funbox = funbox; 1.446 + } 1.447 + void addFunctionArgument(ParseNode *pn, ParseNode *argpn) { 1.448 + pn->pn_body->append(argpn); 1.449 + } 1.450 + 1.451 + inline ParseNode *newLexicalScope(ObjectBox *blockbox); 1.452 + inline void setLexicalScopeBody(ParseNode *block, ParseNode *body); 1.453 + 1.454 + bool isOperationWithoutParens(ParseNode *pn, ParseNodeKind kind) { 1.455 + return pn->isKind(kind) && !pn->isInParens(); 1.456 + } 1.457 + 1.458 + inline bool finishInitializerAssignment(ParseNode *pn, ParseNode *init, JSOp op); 1.459 + 1.460 + void setBeginPosition(ParseNode *pn, ParseNode *oth) { 1.461 + setBeginPosition(pn, oth->pn_pos.begin); 1.462 + } 1.463 + void setBeginPosition(ParseNode *pn, uint32_t begin) { 1.464 + pn->pn_pos.begin = begin; 1.465 + JS_ASSERT(pn->pn_pos.begin <= pn->pn_pos.end); 1.466 + } 1.467 + 1.468 + void setEndPosition(ParseNode *pn, ParseNode *oth) { 1.469 + setEndPosition(pn, oth->pn_pos.end); 1.470 + } 1.471 + void setEndPosition(ParseNode *pn, uint32_t end) { 1.472 + pn->pn_pos.end = end; 1.473 + JS_ASSERT(pn->pn_pos.begin <= pn->pn_pos.end); 1.474 + } 1.475 + 1.476 + void setPosition(ParseNode *pn, const TokenPos &pos) { 1.477 + pn->pn_pos = pos; 1.478 + } 1.479 + TokenPos getPosition(ParseNode *pn) { 1.480 + return pn->pn_pos; 1.481 + } 1.482 + 1.483 + ParseNode *newList(ParseNodeKind kind, ParseNode *kid = nullptr, JSOp op = JSOP_NOP) { 1.484 + ParseNode *pn = ListNode::create(kind, this); 1.485 + if (!pn) 1.486 + return nullptr; 1.487 + pn->setOp(op); 1.488 + pn->makeEmpty(); 1.489 + if (kid) { 1.490 + pn->pn_pos.begin = kid->pn_pos.begin; 1.491 + pn->append(kid); 1.492 + } 1.493 + return pn; 1.494 + } 1.495 + void addList(ParseNode *pn, ParseNode *kid) { 1.496 + pn->append(kid); 1.497 + } 1.498 + 1.499 + bool isUnparenthesizedYield(ParseNode *pn) { 1.500 + return pn->isKind(PNK_YIELD) && !pn->isInParens(); 1.501 + } 1.502 + 1.503 + void setOp(ParseNode *pn, JSOp op) { 1.504 + pn->setOp(op); 1.505 + } 1.506 + void setBlockId(ParseNode *pn, unsigned blockid) { 1.507 + pn->pn_blockid = blockid; 1.508 + } 1.509 + void setFlag(ParseNode *pn, unsigned flag) { 1.510 + pn->pn_dflags |= flag; 1.511 + } 1.512 + void setListFlag(ParseNode *pn, unsigned flag) { 1.513 + JS_ASSERT(pn->isArity(PN_LIST)); 1.514 + pn->pn_xflags |= flag; 1.515 + } 1.516 + ParseNode *setInParens(ParseNode *pn) { 1.517 + pn->setInParens(true); 1.518 + return pn; 1.519 + } 1.520 + void setPrologue(ParseNode *pn) { 1.521 + pn->pn_prologue = true; 1.522 + } 1.523 + 1.524 + bool isConstant(ParseNode *pn) { 1.525 + return pn->isConstant(); 1.526 + } 1.527 + PropertyName *isName(ParseNode *pn) { 1.528 + return pn->isKind(PNK_NAME) ? pn->pn_atom->asPropertyName() : nullptr; 1.529 + } 1.530 + bool isCall(ParseNode *pn) { 1.531 + return pn->isKind(PNK_CALL); 1.532 + } 1.533 + PropertyName *isGetProp(ParseNode *pn) { 1.534 + return pn->is<PropertyAccess>() ? &pn->as<PropertyAccess>().name() : nullptr; 1.535 + } 1.536 + JSAtom *isStringExprStatement(ParseNode *pn, TokenPos *pos) { 1.537 + if (JSAtom *atom = pn->isStringExprStatement()) { 1.538 + *pos = pn->pn_kid->pn_pos; 1.539 + return atom; 1.540 + } 1.541 + return nullptr; 1.542 + } 1.543 + 1.544 + inline ParseNode *makeAssignment(ParseNode *pn, ParseNode *rhs); 1.545 + 1.546 + static Definition *getDefinitionNode(Definition *dn) { 1.547 + return dn; 1.548 + } 1.549 + static Definition::Kind getDefinitionKind(Definition *dn) { 1.550 + return dn->kind(); 1.551 + } 1.552 + void linkUseToDef(ParseNode *pn, Definition *dn) 1.553 + { 1.554 + JS_ASSERT(!pn->isUsed()); 1.555 + JS_ASSERT(!pn->isDefn()); 1.556 + JS_ASSERT(pn != dn->dn_uses); 1.557 + JS_ASSERT(dn->isDefn()); 1.558 + pn->pn_link = dn->dn_uses; 1.559 + dn->dn_uses = pn; 1.560 + dn->pn_dflags |= pn->pn_dflags & PND_USE2DEF_FLAGS; 1.561 + pn->setUsed(true); 1.562 + pn->pn_lexdef = dn; 1.563 + } 1.564 + Definition *resolve(Definition *dn) { 1.565 + return dn->resolve(); 1.566 + } 1.567 + void deoptimizeUsesWithin(Definition *dn, const TokenPos &pos) 1.568 + { 1.569 + for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) { 1.570 + JS_ASSERT(pnu->isUsed()); 1.571 + JS_ASSERT(!pnu->isDefn()); 1.572 + if (pnu->pn_pos.begin >= pos.begin && pnu->pn_pos.end <= pos.end) 1.573 + pnu->pn_dflags |= PND_DEOPTIMIZED; 1.574 + } 1.575 + } 1.576 + bool dependencyCovered(ParseNode *pn, unsigned blockid, bool functionScope) { 1.577 + return pn->pn_blockid >= blockid; 1.578 + } 1.579 + 1.580 + static uintptr_t definitionToBits(Definition *dn) { 1.581 + return uintptr_t(dn); 1.582 + } 1.583 + static Definition *definitionFromBits(uintptr_t bits) { 1.584 + return (Definition *) bits; 1.585 + } 1.586 + static Definition *nullDefinition() { 1.587 + return nullptr; 1.588 + } 1.589 + void disableSyntaxParser() { 1.590 + syntaxParser = nullptr; 1.591 + } 1.592 + 1.593 + LazyScript *lazyOuterFunction() { 1.594 + return lazyOuterFunction_; 1.595 + } 1.596 + JSFunction *nextLazyInnerFunction() { 1.597 + JS_ASSERT(lazyInnerFunctionIndex < lazyOuterFunction()->numInnerFunctions()); 1.598 + return lazyOuterFunction()->innerFunctions()[lazyInnerFunctionIndex++]; 1.599 + } 1.600 +}; 1.601 + 1.602 +inline bool 1.603 +FullParseHandler::addCatchBlock(ParseNode *catchList, ParseNode *letBlock, 1.604 + ParseNode *catchName, ParseNode *catchGuard, ParseNode *catchBody) 1.605 +{ 1.606 + ParseNode *catchpn = newTernary(PNK_CATCH, catchName, catchGuard, catchBody); 1.607 + if (!catchpn) 1.608 + return false; 1.609 + 1.610 + catchList->append(letBlock); 1.611 + letBlock->pn_expr = catchpn; 1.612 + return true; 1.613 +} 1.614 + 1.615 +inline void 1.616 +FullParseHandler::setLastFunctionArgumentDefault(ParseNode *funcpn, ParseNode *defaultValue) 1.617 +{ 1.618 + ParseNode *arg = funcpn->pn_body->last(); 1.619 + arg->pn_dflags |= PND_DEFAULT; 1.620 + arg->pn_expr = defaultValue; 1.621 +} 1.622 + 1.623 +inline ParseNode * 1.624 +FullParseHandler::newFunctionDefinition() 1.625 +{ 1.626 + ParseNode *pn = CodeNode::create(PNK_FUNCTION, this); 1.627 + if (!pn) 1.628 + return nullptr; 1.629 + pn->pn_body = nullptr; 1.630 + pn->pn_funbox = nullptr; 1.631 + pn->pn_cookie.makeFree(); 1.632 + pn->pn_dflags = 0; 1.633 + return pn; 1.634 +} 1.635 + 1.636 +inline ParseNode * 1.637 +FullParseHandler::newLexicalScope(ObjectBox *blockbox) 1.638 +{ 1.639 + ParseNode *pn = LexicalScopeNode::create(PNK_LEXICALSCOPE, this); 1.640 + if (!pn) 1.641 + return nullptr; 1.642 + 1.643 + pn->pn_objbox = blockbox; 1.644 + pn->pn_cookie.makeFree(); 1.645 + pn->pn_dflags = 0; 1.646 + return pn; 1.647 +} 1.648 + 1.649 +inline void 1.650 +FullParseHandler::setLexicalScopeBody(ParseNode *block, ParseNode *kid) 1.651 +{ 1.652 + block->pn_expr = kid; 1.653 +} 1.654 + 1.655 +inline bool 1.656 +FullParseHandler::finishInitializerAssignment(ParseNode *pn, ParseNode *init, JSOp op) 1.657 +{ 1.658 + if (pn->isUsed()) { 1.659 + pn = makeAssignment(pn, init); 1.660 + if (!pn) 1.661 + return false; 1.662 + } else { 1.663 + pn->pn_expr = init; 1.664 + } 1.665 + 1.666 + pn->setOp((pn->pn_dflags & PND_BOUND) 1.667 + ? JSOP_SETLOCAL 1.668 + : (op == JSOP_DEFCONST) 1.669 + ? JSOP_SETCONST 1.670 + : JSOP_SETNAME); 1.671 + 1.672 + pn->markAsAssigned(); 1.673 + 1.674 + /* The declarator's position must include the initializer. */ 1.675 + pn->pn_pos.end = init->pn_pos.end; 1.676 + return true; 1.677 +} 1.678 + 1.679 +inline ParseNode * 1.680 +FullParseHandler::makeAssignment(ParseNode *pn, ParseNode *rhs) 1.681 +{ 1.682 + ParseNode *lhs = cloneNode(*pn); 1.683 + if (!lhs) 1.684 + return nullptr; 1.685 + 1.686 + if (pn->isUsed()) { 1.687 + Definition *dn = pn->pn_lexdef; 1.688 + ParseNode **pnup = &dn->dn_uses; 1.689 + 1.690 + while (*pnup != pn) 1.691 + pnup = &(*pnup)->pn_link; 1.692 + *pnup = lhs; 1.693 + lhs->pn_link = pn->pn_link; 1.694 + pn->pn_link = nullptr; 1.695 + } 1.696 + 1.697 + pn->setKind(PNK_ASSIGN); 1.698 + pn->setOp(JSOP_NOP); 1.699 + pn->setArity(PN_BINARY); 1.700 + pn->setInParens(false); 1.701 + pn->setUsed(false); 1.702 + pn->setDefn(false); 1.703 + pn->pn_left = lhs; 1.704 + pn->pn_right = rhs; 1.705 + pn->pn_pos.end = rhs->pn_pos.end; 1.706 + return lhs; 1.707 +} 1.708 + 1.709 +} // frontend 1.710 +} // js 1.711 + 1.712 +#endif /* frontend_FullParseHandler_h */