From 6a60d5b7a65c86a4c35a74827c6ed2a8488a3498 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Wed, 19 Jun 2013 14:43:38 -0500 Subject: [PATCH] Bug 883226, part 1 - Clean up RegExp parsing. Remove NullaryNode::create in favor of constructors. r=Waldo. --- js/src/frontend/BytecodeEmitter.cpp | 15 ++++------ js/src/frontend/FullParseHandler.h | 12 ++++++++ js/src/frontend/ParseNode.h | 36 +++++++++++++++++++---- js/src/frontend/Parser.cpp | 44 +++++++--------------------- js/src/frontend/Parser.h | 2 +- js/src/frontend/SyntaxParseHandler.h | 4 +++ js/src/jsreflect.cpp | 2 +- 7 files changed, 64 insertions(+), 51 deletions(-) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 81862a85aaae..aa2556f6cd4d 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -2035,19 +2035,15 @@ EmitElemOperands(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce) */ left = pn->maybeExpr(); if (!left) { - left = NullaryNode::create(PNK_STRING, &bce->parser->handler); + left = bce->parser->handler.new_( + PNK_STRING, JSOP_BINDNAME, pn->pn_pos, pn->pn_atom); if (!left) return false; - left->setOp(JSOP_BINDNAME); - left->pn_pos = pn->pn_pos; - left->pn_atom = pn->pn_atom; } - right = NullaryNode::create(PNK_STRING, &bce->parser->handler); + right = bce->parser->handler.new_( + PNK_STRING, JSOP_STRING, pn->pn_pos, pn->pn_atom); if (!right) return false; - right->setOp(JSOP_STRING); - right->pn_pos = pn->pn_pos; - right->pn_atom = pn->pn_atom; } else { JS_ASSERT(pn->isArity(PN_BINARY)); left = pn->pn_left; @@ -6016,8 +6012,7 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) break; case PNK_REGEXP: - JS_ASSERT(pn->isOp(JSOP_REGEXP)); - ok = EmitRegExp(cx, bce->regexpList.add(pn->pn_objbox), bce); + ok = EmitRegExp(cx, bce->regexpList.add(pn->as().objbox()), bce); break; case PNK_TRUE: diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index 857b81c1d0a7..f576bdbf76b0 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -130,6 +130,18 @@ class FullParseHandler ParseNode *newNullLiteral(const TokenPos &pos) { return new_(pos); } + + // The Boxer object here is any object that can allocate ObjectBoxes. + // Specifically, a Boxer has a .newObjectBox(T) method that accepts a + // Rooted argument and returns an ObjectBox*. + template + ParseNode *newRegExp(HandleObject reobj, const TokenPos &pos, Boxer &boxer) { + ObjectBox *objbox = boxer.newObjectBox(reobj); + if (!objbox) + return null(); + return new_(objbox, pos); + } + ParseNode *newConditional(ParseNode *cond, ParseNode *thenExpr, ParseNode *elseExpr) { return new_(cond, thenExpr, elseExpr); } diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index a3029fd47026..5b89a3c7a60c 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -370,12 +370,12 @@ enum ParseNodeKind * PN_NAME node for x on left and right of PNK_COLON * node in PNK_OBJECT's list, has PNX_DESTRUCT flag * PNK_NAME, name pn_atom: name, string, or object atom - * PNK_STRING, pn_op: JSOP_NAME, JSOP_STRING, or JSOP_OBJECT, or - * JSOP_REGEXP - * PNK_REGEXP If JSOP_NAME, pn_op may be JSOP_*ARG or JSOP_*VAR + * PNK_STRING pn_op: JSOP_NAME, JSOP_STRING, or JSOP_OBJECT + * If JSOP_NAME, pn_op may be JSOP_*ARG or JSOP_*VAR * with pn_cookie telling (staticLevel, slot) (see * jsscript.h's UPVAR macros) and pn_dflags telling * const-ness and static analysis results + * PNK_REGEXP nullary pn_objbox: RegExp model object * PNK_NAME name If pn_used, PNK_NAME uses the lexdef member instead * of the expr member it overlays * PNK_NUMBER dval pn_dval: double value of numeric literal @@ -820,9 +820,16 @@ struct NullaryNode : public ParseNode { NullaryNode(ParseNodeKind kind, const TokenPos &pos) : ParseNode(kind, JSOP_NOP, PN_NULLARY, pos) {} + NullaryNode(ParseNodeKind kind, JSOp op, const TokenPos &pos) + : ParseNode(kind, op, PN_NULLARY, pos) {} - static inline NullaryNode *create(ParseNodeKind kind, FullParseHandler *handler) { - return (NullaryNode *) ParseNode::create(kind, PN_NULLARY, handler); + // This constructor is for a few mad uses in the emitter. It populates + // the pn_atom field even though that field belongs to a branch in pn_u + // that nullary nodes shouldn't use -- bogus. + NullaryNode(ParseNodeKind kind, JSOp op, const TokenPos &pos, JSAtom *atom) + : ParseNode(kind, op, PN_NULLARY, pos) + { + pn_atom = atom; } static bool test(const ParseNode &node) { @@ -1112,6 +1119,25 @@ class BooleanLiteral : public ParseNode { } }; +class RegExpLiteral : public NullaryNode +{ + public: + RegExpLiteral(ObjectBox *reobj, const TokenPos &pos) + : NullaryNode(PNK_REGEXP, JSOP_REGEXP, pos) + { + pn_objbox = reobj; + } + + ObjectBox *objbox() const { return pn_objbox; } + + static bool test(const ParseNode &node) { + bool match = node.isKind(PNK_REGEXP); + JS_ASSERT_IF(match, node.isArity(PN_NULLARY)); + JS_ASSERT_IF(match, node.isOp(JSOP_REGEXP)); + return match; + } +}; + class PropertyAccess : public ParseNode { public: diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index ddd40afc446f..4b1d4c3f0da5 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -6488,15 +6488,14 @@ Parser::atomNode(ParseNodeKind kind, JSOp op) return pn; } -template <> -ParseNode * -Parser::newRegExp(const jschar *buf, size_t length, RegExpFlag flags) +template +typename ParseHandler::Node +Parser::newRegExp() { - ParseNode *pn = NullaryNode::create(PNK_REGEXP, &handler); - if (!pn) - return NULL; - - const StableCharPtr chars(buf, length); + // Create the regexp even when doing a syntax parse, to check the regexp's syntax. + size_t length = tokenStream.getTokenbuf().length(); + const StableCharPtr chars(tokenStream.getTokenbuf().begin(), length); + RegExpFlag flags = tokenStream.currentToken().regExpFlags(); Rooted reobj(context); if (RegExpStatics *res = context->regExpStatics()) @@ -6505,30 +6504,9 @@ Parser::newRegExp(const jschar *buf, size_t length, RegExpFlag reobj = RegExpObject::createNoStatics(context, chars.get(), length, flags, &tokenStream); if (!reobj) - return NULL; + return null(); - pn->pn_objbox = newObjectBox(reobj); - if (!pn->pn_objbox) - return NULL; - - pn->setOp(JSOP_REGEXP); - return pn; -} - -template <> -SyntaxParseHandler::Node -Parser::newRegExp(const jschar *buf, size_t length, RegExpFlag flags) -{ - // Create the regexp even when doing a syntax parse, to check the regexp's syntax. - const StableCharPtr chars(buf, length); - - RegExpObject *reobj; - if (RegExpStatics *res = context->regExpStatics()) - reobj = RegExpObject::create(context, res, chars.get(), length, flags, &tokenStream); - else - reobj = RegExpObject::createNoStatics(context, chars.get(), length, flags, &tokenStream); - - return reobj ? SyntaxParseHandler::NodeGeneric : SyntaxParseHandler::NodeFailure; + return handler.newRegExp(reobj, pos(), *this); } template @@ -6932,9 +6910,7 @@ Parser::primaryExpr(TokenKind tt) break; case TOK_REGEXP: - pn = newRegExp(tokenStream.getTokenbuf().begin(), - tokenStream.getTokenbuf().length(), - tokenStream.currentToken().regExpFlags()); + pn = newRegExp(); break; case TOK_NUMBER: diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 36a8ab9d6979..1b044b14c5b2 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -500,7 +500,7 @@ struct Parser : private AutoGCRooter, public StrictModeGetter Node pushLexicalScope(Handle blockObj, StmtInfoPC *stmt); Node pushLetScope(Handle blockObj, StmtInfoPC *stmt); bool noteNameUse(HandlePropertyName name, Node pn); - Node newRegExp(const jschar *chars, size_t length, RegExpFlag flags); + Node newRegExp(); Node newBindingNode(PropertyName *name, bool functionScope, VarContext varContext = HoistVars); bool checkDestructuring(BindData *data, Node left, bool toplevel = true); bool bindDestructuringVar(BindData *data, Node pn); diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index 3a6d17d5aff4..0c6ccc8270aa 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -69,6 +69,10 @@ class SyntaxParseHandler Node newBooleanLiteral(bool cond, const TokenPos &pos) { return NodeGeneric; } Node newThisLiteral(const TokenPos &pos) { return NodeGeneric; } Node newNullLiteral(const TokenPos &pos) { return NodeGeneric; } + + template + Node newRegExp(JSObject *reobj, const TokenPos &pos, Boxer &boxer) { return NodeGeneric; } + Node newConditional(Node cond, Node thenExpr, Node elseExpr) { return NodeGeneric; } Node newElision() { return NodeGeneric; } diff --git a/js/src/jsreflect.cpp b/js/src/jsreflect.cpp index 5f95ed94383c..52a37077f2a6 100644 --- a/js/src/jsreflect.cpp +++ b/js/src/jsreflect.cpp @@ -2648,7 +2648,7 @@ ASTSerializer::literal(ParseNode *pn, MutableHandleValue dst) case PNK_REGEXP: { - RootedObject re1(cx, pn->pn_objbox ? pn->pn_objbox->object : NULL); + RootedObject re1(cx, pn->as().objbox()->object); LOCAL_ASSERT(re1 && re1->is()); RootedObject proto(cx);