1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/frontend/SyntaxParseHandler.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,264 @@ 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_SyntaxParseHandler_h 1.11 +#define frontend_SyntaxParseHandler_h 1.12 + 1.13 +#include "frontend/ParseNode.h" 1.14 +#include "frontend/TokenStream.h" 1.15 + 1.16 +namespace js { 1.17 +namespace frontend { 1.18 + 1.19 +template <typename ParseHandler> 1.20 +class Parser; 1.21 + 1.22 +// Parse handler used when processing the syntax in a block of code, to generate 1.23 +// the minimal information which is required to detect syntax errors and allow 1.24 +// bytecode to be emitted for outer functions. 1.25 +// 1.26 +// When parsing, we start at the top level with a full parse, and when possible 1.27 +// only check the syntax for inner functions, so that they can be lazily parsed 1.28 +// into bytecode when/if they first run. Checking the syntax of a function is 1.29 +// several times faster than doing a full parse/emit, and lazy parsing improves 1.30 +// both performance and memory usage significantly when pages contain large 1.31 +// amounts of code that never executes (which happens often). 1.32 +class SyntaxParseHandler 1.33 +{ 1.34 + // Remember the last encountered name or string literal during syntax parses. 1.35 + JSAtom *lastAtom; 1.36 + TokenPos lastStringPos; 1.37 + TokenStream &tokenStream; 1.38 + 1.39 + public: 1.40 + enum Node { 1.41 + NodeFailure = 0, 1.42 + NodeGeneric, 1.43 + NodeName, 1.44 + NodeGetProp, 1.45 + NodeString, 1.46 + NodeStringExprStatement, 1.47 + NodeLValue 1.48 + }; 1.49 + typedef Definition::Kind DefinitionNode; 1.50 + 1.51 + SyntaxParseHandler(ExclusiveContext *cx, LifoAlloc &alloc, 1.52 + TokenStream &tokenStream, bool foldConstants, 1.53 + Parser<SyntaxParseHandler> *syntaxParser, LazyScript *lazyOuterFunction) 1.54 + : lastAtom(nullptr), 1.55 + tokenStream(tokenStream) 1.56 + {} 1.57 + 1.58 + static Node null() { return NodeFailure; } 1.59 + 1.60 + void trace(JSTracer *trc) {} 1.61 + 1.62 + Node newName(PropertyName *name, uint32_t blockid, const TokenPos &pos) { 1.63 + lastAtom = name; 1.64 + return NodeName; 1.65 + } 1.66 + 1.67 + DefinitionNode newPlaceholder(JSAtom *atom, uint32_t blockid, const TokenPos &pos) { 1.68 + return Definition::PLACEHOLDER; 1.69 + } 1.70 + 1.71 + Node newIdentifier(JSAtom *atom, const TokenPos &pos) { return NodeString; } 1.72 + Node newNumber(double value, DecimalPoint decimalPoint, const TokenPos &pos) { return NodeGeneric; } 1.73 + Node newBooleanLiteral(bool cond, const TokenPos &pos) { return NodeGeneric; } 1.74 + 1.75 + Node newStringLiteral(JSAtom *atom, const TokenPos &pos) { 1.76 + lastAtom = atom; 1.77 + lastStringPos = pos; 1.78 + return NodeString; 1.79 + } 1.80 + 1.81 + Node newThisLiteral(const TokenPos &pos) { return NodeGeneric; } 1.82 + Node newNullLiteral(const TokenPos &pos) { return NodeGeneric; } 1.83 + 1.84 + template <class Boxer> 1.85 + Node newRegExp(JSObject *reobj, const TokenPos &pos, Boxer &boxer) { return NodeGeneric; } 1.86 + 1.87 + Node newConditional(Node cond, Node thenExpr, Node elseExpr) { return NodeGeneric; } 1.88 + 1.89 + Node newElision() { return NodeGeneric; } 1.90 + 1.91 + Node newDelete(uint32_t begin, Node expr) { return NodeGeneric; } 1.92 + 1.93 + Node newUnary(ParseNodeKind kind, JSOp op, uint32_t begin, Node kid) { 1.94 + return NodeGeneric; 1.95 + } 1.96 + 1.97 + Node newBinary(ParseNodeKind kind, JSOp op = JSOP_NOP) { return NodeGeneric; } 1.98 + Node newBinary(ParseNodeKind kind, Node left, JSOp op = JSOP_NOP) { return NodeGeneric; } 1.99 + Node newBinary(ParseNodeKind kind, Node left, Node right, JSOp op = JSOP_NOP) { 1.100 + return NodeGeneric; 1.101 + } 1.102 + Node newBinaryOrAppend(ParseNodeKind kind, Node left, Node right, 1.103 + ParseContext<SyntaxParseHandler> *pc, JSOp op = JSOP_NOP) { 1.104 + return NodeGeneric; 1.105 + } 1.106 + 1.107 + Node newTernary(ParseNodeKind kind, Node first, Node second, Node third, JSOp op = JSOP_NOP) { 1.108 + return NodeGeneric; 1.109 + } 1.110 + 1.111 + // Expressions 1.112 + 1.113 + Node newArrayComprehension(Node body, unsigned blockid, const TokenPos &pos) { 1.114 + return NodeGeneric; 1.115 + } 1.116 + Node newArrayLiteral(uint32_t begin, unsigned blockid) { return NodeGeneric; } 1.117 + bool addElision(Node literal, const TokenPos &pos) { return true; } 1.118 + bool addSpreadElement(Node literal, uint32_t begin, Node inner) { return true; } 1.119 + bool addArrayElement(Node literal, Node element) { return true; } 1.120 + 1.121 + Node newObjectLiteral(uint32_t begin) { return NodeGeneric; } 1.122 + bool addPrototypeMutation(Node literal, uint32_t begin, Node expr) { return true; } 1.123 + bool addPropertyDefinition(Node literal, Node name, Node expr) { return true; } 1.124 + bool addShorthandPropertyDefinition(Node literal, Node name) { return true; } 1.125 + bool addAccessorPropertyDefinition(Node literal, Node name, Node fn, JSOp op) { return true; } 1.126 + 1.127 + // Statements 1.128 + 1.129 + Node newStatementList(unsigned blockid, const TokenPos &pos) { return NodeGeneric; } 1.130 + void addStatementToList(Node list, Node stmt, ParseContext<SyntaxParseHandler> *pc) {} 1.131 + Node newEmptyStatement(const TokenPos &pos) { return NodeGeneric; } 1.132 + 1.133 + Node newExprStatement(Node expr, uint32_t end) { 1.134 + return expr == NodeString ? NodeStringExprStatement : NodeGeneric; 1.135 + } 1.136 + 1.137 + Node newIfStatement(uint32_t begin, Node cond, Node then, Node else_) { return NodeGeneric; } 1.138 + Node newDoWhileStatement(Node body, Node cond, const TokenPos &pos) { return NodeGeneric; } 1.139 + Node newWhileStatement(uint32_t begin, Node cond, Node body) { return NodeGeneric; } 1.140 + Node newSwitchStatement(uint32_t begin, Node discriminant, Node caseList) { return NodeGeneric; } 1.141 + Node newCaseOrDefault(uint32_t begin, Node expr, Node body) { return NodeGeneric; } 1.142 + Node newContinueStatement(PropertyName *label, const TokenPos &pos) { return NodeGeneric; } 1.143 + Node newBreakStatement(PropertyName *label, const TokenPos &pos) { return NodeGeneric; } 1.144 + Node newReturnStatement(Node expr, const TokenPos &pos) { return NodeGeneric; } 1.145 + 1.146 + Node newLabeledStatement(PropertyName *label, Node stmt, uint32_t begin) { 1.147 + return NodeGeneric; 1.148 + } 1.149 + 1.150 + Node newThrowStatement(Node expr, const TokenPos &pos) { return NodeGeneric; } 1.151 + Node newTryStatement(uint32_t begin, Node body, Node catchList, Node finallyBlock) { 1.152 + return NodeGeneric; 1.153 + } 1.154 + Node newDebuggerStatement(const TokenPos &pos) { return NodeGeneric; } 1.155 + 1.156 + Node newPropertyAccess(Node pn, PropertyName *name, uint32_t end) { 1.157 + lastAtom = name; 1.158 + return NodeGetProp; 1.159 + } 1.160 + 1.161 + Node newPropertyByValue(Node pn, Node kid, uint32_t end) { return NodeLValue; } 1.162 + 1.163 + bool addCatchBlock(Node catchList, Node letBlock, 1.164 + Node catchName, Node catchGuard, Node catchBody) { return true; } 1.165 + 1.166 + void setLastFunctionArgumentDefault(Node funcpn, Node pn) {} 1.167 + Node newFunctionDefinition() { return NodeGeneric; } 1.168 + void setFunctionBody(Node pn, Node kid) {} 1.169 + void setFunctionBox(Node pn, FunctionBox *funbox) {} 1.170 + void addFunctionArgument(Node pn, Node argpn) {} 1.171 + 1.172 + Node newForStatement(uint32_t begin, Node forHead, Node body, unsigned iflags) { 1.173 + return NodeGeneric; 1.174 + } 1.175 + 1.176 + Node newForHead(ParseNodeKind kind, Node decls, Node lhs, Node rhs, const TokenPos &pos) { 1.177 + return NodeGeneric; 1.178 + } 1.179 + 1.180 + Node newLexicalScope(ObjectBox *blockbox) { return NodeGeneric; } 1.181 + void setLexicalScopeBody(Node block, Node body) {} 1.182 + 1.183 + bool isOperationWithoutParens(Node pn, ParseNodeKind kind) { 1.184 + // It is OK to return false here, callers should only use this method 1.185 + // for reporting strict option warnings and parsing code which the 1.186 + // syntax parser does not handle. 1.187 + return false; 1.188 + } 1.189 + 1.190 + bool finishInitializerAssignment(Node pn, Node init, JSOp op) { return true; } 1.191 + 1.192 + void setBeginPosition(Node pn, Node oth) {} 1.193 + void setBeginPosition(Node pn, uint32_t begin) {} 1.194 + 1.195 + void setEndPosition(Node pn, Node oth) {} 1.196 + void setEndPosition(Node pn, uint32_t end) {} 1.197 + 1.198 + 1.199 + void setPosition(Node pn, const TokenPos &pos) {} 1.200 + TokenPos getPosition(Node pn) { 1.201 + return tokenStream.currentToken().pos; 1.202 + } 1.203 + 1.204 + Node newList(ParseNodeKind kind, Node kid = NodeGeneric, JSOp op = JSOP_NOP) { 1.205 + return NodeGeneric; 1.206 + } 1.207 + void addList(Node pn, Node kid) {} 1.208 + bool isUnparenthesizedYield(Node pn) { return false; } 1.209 + 1.210 + void setOp(Node pn, JSOp op) {} 1.211 + void setBlockId(Node pn, unsigned blockid) {} 1.212 + void setFlag(Node pn, unsigned flag) {} 1.213 + void setListFlag(Node pn, unsigned flag) {} 1.214 + Node setInParens(Node pn) { 1.215 + // String literals enclosed by parentheses are ignored during 1.216 + // strict mode parsing. 1.217 + return NodeGeneric; 1.218 + } 1.219 + void setPrologue(Node pn) {} 1.220 + 1.221 + bool isConstant(Node pn) { return false; } 1.222 + PropertyName *isName(Node pn) { 1.223 + return (pn == NodeName) ? lastAtom->asPropertyName() : nullptr; 1.224 + } 1.225 + PropertyName *isGetProp(Node pn) { 1.226 + return (pn == NodeGetProp) ? lastAtom->asPropertyName() : nullptr; 1.227 + } 1.228 + JSAtom *isStringExprStatement(Node pn, TokenPos *pos) { 1.229 + if (pn == NodeStringExprStatement) { 1.230 + *pos = lastStringPos; 1.231 + return lastAtom; 1.232 + } 1.233 + return nullptr; 1.234 + } 1.235 + 1.236 + Node makeAssignment(Node pn, Node rhs) { return NodeGeneric; } 1.237 + 1.238 + static Node getDefinitionNode(DefinitionNode dn) { return NodeGeneric; } 1.239 + static Definition::Kind getDefinitionKind(DefinitionNode dn) { return dn; } 1.240 + void linkUseToDef(Node pn, DefinitionNode dn) {} 1.241 + DefinitionNode resolve(DefinitionNode dn) { return dn; } 1.242 + void deoptimizeUsesWithin(DefinitionNode dn, const TokenPos &pos) {} 1.243 + bool dependencyCovered(Node pn, unsigned blockid, bool functionScope) { 1.244 + // Only resolve lexical dependencies in cases where a definition covers 1.245 + // the entire function. Not enough information is kept to compare the 1.246 + // dependency location with blockid. 1.247 + return functionScope; 1.248 + } 1.249 + 1.250 + static uintptr_t definitionToBits(DefinitionNode dn) { 1.251 + // Use a shift, as DefinitionList tags the lower bit of its associated union. 1.252 + return uintptr_t(dn << 1); 1.253 + } 1.254 + static DefinitionNode definitionFromBits(uintptr_t bits) { 1.255 + return (DefinitionNode) (bits >> 1); 1.256 + } 1.257 + static DefinitionNode nullDefinition() { 1.258 + return Definition::MISSING; 1.259 + } 1.260 + void disableSyntaxParser() { 1.261 + } 1.262 +}; 1.263 + 1.264 +} // namespace frontend 1.265 +} // namespace js 1.266 + 1.267 +#endif /* frontend_SyntaxParseHandler_h */