From f91bbb623347a7451f472136d2855227f1f69daf Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Fri, 9 Dec 2011 23:28:59 -0500 Subject: [PATCH] Bug 710932 - Create expressions using a constructor that doesn't examine the token stream. r=jorendorff --HG-- extra : rebase_source : f3b8ca1065e7694cb411d14800052e7cef48f853 --- js/src/frontend/BytecodeEmitter.cpp | 22 +++++++++------ js/src/frontend/FoldConstants.cpp | 6 ++-- js/src/frontend/ParseNode.h | 44 +++++++++++++++++++++++++---- js/src/frontend/Parser.cpp | 15 ++++------ js/src/frontend/TokenStream.h | 7 +++-- js/src/jsreflect.cpp | 23 +++++---------- js/src/jsxml.cpp | 7 +++-- 7 files changed, 78 insertions(+), 46 deletions(-) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index f30d3f4696b3..afa5970344a5 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -1863,23 +1863,29 @@ EmitIndexOp(JSContext *cx, JSOp op, uintN index, BytecodeEmitter *bce, JSOp *psu JS_END_MACRO static bool -EmitAtomOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce, JSOp *psuffix = NULL) +EmitAtomOp(JSContext *cx, JSAtom *atom, JSOp op, BytecodeEmitter *bce, JSOp *psuffix = NULL) { JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM); - if (op == JSOP_GETPROP && - pn->pn_atom == cx->runtime->atomState.lengthAtom) { + if (op == JSOP_GETPROP && atom == cx->runtime->atomState.lengthAtom) { /* Specialize length accesses for the interpreter. */ op = JSOP_LENGTH; } jsatomid index; - if (!bce->makeAtomIndex(pn->pn_atom, &index)) + if (!bce->makeAtomIndex(atom, &index)) return false; return EmitIndexOp(cx, op, index, bce, psuffix); } +static bool +EmitAtomOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce, JSOp *psuffix = NULL) +{ + JS_ASSERT(pn->pn_atom != NULL); + return EmitAtomOp(cx, pn->pn_atom, op, bce, psuffix); +} + static JSBool EmitObjectOp(JSContext *cx, ObjectBox *objbox, JSOp op, BytecodeEmitter *bce) { @@ -5478,16 +5484,16 @@ EmitXMLTag(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) } static bool -EmitXMLProcessingInstruction(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) +EmitXMLProcessingInstruction(JSContext *cx, BytecodeEmitter *bce, XMLProcessingInstruction &pi) { JS_ASSERT(!bce->inStrictMode()); jsatomid index; - if (!bce->makeAtomIndex(pn->pn_pidata, &index)) + if (!bce->makeAtomIndex(pi.data(), &index)) return false; if (!EmitIndexOp(cx, JSOP_QNAMEPART, index, bce)) return false; - if (!EmitAtomOp(cx, pn, JSOP_XMLPI, bce)) + if (!EmitAtomOp(cx, pi.target(), JSOP_XMLPI, bce)) return false; return true; } @@ -7594,7 +7600,7 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) break; case PNK_XMLPI: - if (!EmitXMLProcessingInstruction(cx, bce, pn)) + if (!EmitXMLProcessingInstruction(cx, bce, pn->asXMLProcessingInstruction())) return false; break; #endif /* JS_HAS_XML_SUPPORT */ diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp index 46e848914708..97c2ee07b2b3 100644 --- a/js/src/frontend/FoldConstants.cpp +++ b/js/src/frontend/FoldConstants.cpp @@ -273,11 +273,13 @@ FoldXMLConstants(JSContext *cx, ParseNode *pn, TreeContext *tc) return JS_FALSE; break; - case PNK_XMLPI: - str = js_MakeXMLPIString(cx, pn2->pn_pitarget, pn2->pn_pidata); + case PNK_XMLPI: { + XMLProcessingInstruction &pi = pn2->asXMLProcessingInstruction(); + str = js_MakeXMLPIString(cx, pi.target(), pi.data()); if (!str) return JS_FALSE; break; + } cantfold: default: diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index 9d23930ca367..c5d835125136 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -485,6 +485,7 @@ struct Definition; class LoopControlStatement; class BreakStatement; class ContinueStatement; +class XMLProcessingInstruction; struct ParseNode { private: @@ -617,15 +618,16 @@ struct ParseNode { AtomDefnMapPtr defnMap; ParseNode *tree; /* sub-tree containing name uses */ } nameset; - struct { /* PN_NULLARY variant for E4X XML PI */ - PropertyName *target; /* target in */ - JSAtom *data; /* data (or null) in */ - } xmlpi; jsdouble dval; /* aligned numeric literal value */ class { friend class LoopControlStatement; PropertyName *label; /* target of break/continue statement */ } loopControl; + class { /* E4X XML PI */ + friend class XMLProcessingInstruction; + PropertyName *target; /* non-empty */ + JSAtom *data; /* may be empty, never null */ + } xmlpi; } pn_u; #define pn_funbox pn_u.name.funbox @@ -656,8 +658,6 @@ struct ParseNode { #define pn_names pn_u.nameset.defnMap #define pn_tree pn_u.nameset.tree #define pn_dval pn_u.dval -#define pn_pitarget pn_u.xmlpi.target -#define pn_pidata pn_u.xmlpi.data protected: void init(TokenKind type, JSOp op, ParseNodeArity arity) { @@ -924,6 +924,9 @@ struct ParseNode { /* Casting operations. */ inline BreakStatement &asBreakStatement(); inline ContinueStatement &asContinueStatement(); +#if JS_HAS_XML_SUPPORT + inline XMLProcessingInstruction &asXMLProcessingInstruction(); +#endif }; struct NullaryNode : public ParseNode { @@ -1066,6 +1069,35 @@ class DebuggerStatement : public ParseNode { { } }; +#if JS_HAS_XML_SUPPORT +class XMLProcessingInstruction : public ParseNode { + public: + XMLProcessingInstruction(PropertyName *target, JSAtom *data, const TokenPos &pos) + : ParseNode(PNK_XMLPI, JSOP_NOP, PN_NULLARY, pos) + { + pn_u.xmlpi.target = target; + pn_u.xmlpi.data = data; + } + + PropertyName *target() const { + return pn_u.xmlpi.target; + } + + JSAtom *data() const { + return pn_u.xmlpi.data; + } +}; + +inline XMLProcessingInstruction & +ParseNode::asXMLProcessingInstruction() +{ + JS_ASSERT(isKind(PNK_XMLPI)); + JS_ASSERT(isOp(JSOP_NOP)); + JS_ASSERT(pn_arity == PN_NULLARY); + return *static_cast(this); +} +#endif + ParseNode * CloneLeftHandSide(ParseNode *opn, TreeContext *tc); diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index efbc83015aff..fcdce727025a 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -6363,13 +6363,10 @@ Parser::xmlElementContent(ParseNode *pn) pn2->pn_xflags &= ~PNX_XMLROOT; pn->pn_xflags |= pn2->pn_xflags; } else if (tt == TOK_XMLPI) { - pn2 = NullaryNode::create(PNK_XMLPI, tc); + const Token &tok = tokenStream.currentToken(); + pn2 = new_(tok.xmlPITarget(), tok.xmlPIData(), tok.pos); if (!pn2) return false; - const Token &tok = tokenStream.currentToken(); - pn2->setOp(tok.t_op); - pn2->pn_pitarget = tok.xmlPITarget(); - pn2->pn_pidata = tok.xmlPIData(); } else { JS_ASSERT(tt == TOK_XMLCDATA || tt == TOK_XMLCOMMENT); pn2 = atomNode(tt == TOK_XMLCDATA ? PNK_XMLCDATA : PNK_XMLCOMMENT, @@ -7053,14 +7050,14 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) break; #if JS_HAS_XML_SUPPORT - case TOK_XMLPI: + case TOK_XMLPI: { JS_ASSERT(!tc->inStrictMode()); - pn = NullaryNode::create(PNK_XMLPI, tc); + const Token &tok = tokenStream.currentToken(); + pn = new_(tok.xmlPITarget(), tok.xmlPIData(), tok.pos); if (!pn) return NULL; - pn->pn_pitarget = tokenStream.currentToken().xmlPITarget(); - pn->pn_pidata = tokenStream.currentToken().xmlPIData(); break; + } #endif case TOK_NAME: diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 0490804e7c3a..274a4a18f8f2 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -330,8 +330,8 @@ struct Token { private: friend struct Token; struct { /* pair for XML PI */ - JSAtom *data; /* auxiliary atom table entry */ - PropertyName *target; /* main atom table entry */ + PropertyName *target; /* non-empty */ + JSAtom *data; /* maybe empty, never null */ } xmlpi; uint16_t sharpNumber; /* sharp variable number: #1# or #1= */ jsdouble number; /* floating point number */ @@ -359,6 +359,9 @@ struct Token { } void setProcessingInstruction(PropertyName *target, JSAtom *data) { + JS_ASSERT(target); + JS_ASSERT(data); + JS_ASSERT(!target->empty()); u.xmlpi.target = target; u.xmlpi.data = data; } diff --git a/js/src/jsreflect.cpp b/js/src/jsreflect.cpp index def4ab44aeb8..b08cb675e2c7 100644 --- a/js/src/jsreflect.cpp +++ b/js/src/jsreflect.cpp @@ -619,8 +619,6 @@ class NodeBuilder bool xmlComment(Value text, TokenPos *pos, Value *dst); - bool xmlPI(Value target, TokenPos *pos, Value *dst); - bool xmlPI(Value target, Value content, TokenPos *pos, Value *dst); }; @@ -1570,12 +1568,6 @@ NodeBuilder::xmlComment(Value text, TokenPos *pos, Value *dst) return newNode(AST_XMLCOMMENT, pos, "contents", text, dst); } -bool -NodeBuilder::xmlPI(Value target, TokenPos *pos, Value *dst) -{ - return xmlPI(target, NullValue(), pos, dst); -} - bool NodeBuilder::xmlPI(Value target, Value contents, TokenPos *pos, Value *dst) { @@ -2795,14 +2787,13 @@ ASTSerializer::xml(ParseNode *pn, Value *dst) case PNK_XMLCOMMENT: return builder.xmlComment(atomContents(pn->pn_atom), &pn->pn_pos, dst); - case PNK_XMLPI: - if (!pn->pn_pidata) - return builder.xmlPI(atomContents(pn->pn_pitarget), &pn->pn_pos, dst); - else - return builder.xmlPI(atomContents(pn->pn_pitarget), - atomContents(pn->pn_pidata), - &pn->pn_pos, - dst); + case PNK_XMLPI: { + XMLProcessingInstruction &pi = pn->asXMLProcessingInstruction(); + return builder.xmlPI(atomContents(pi.target()), + atomContents(pi.data()), + &pi.pn_pos, + dst); + } #endif default: diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index 75b0605e90e2..a063021fb48e 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -1621,11 +1621,12 @@ ParseNodeToXML(Parser *parser, ParseNode *pn, goto skip_child; xml_class = JSXML_CLASS_COMMENT; } else if (pn->isKind(PNK_XMLPI)) { + XMLProcessingInstruction &pi = pn->asXMLProcessingInstruction(); if (IS_XML(str)) { Value v = StringValue(str); JSAutoByteString bytes; if (js_ValueToPrintable(cx, v, &bytes)) { - ReportCompileErrorNumber(cx, &parser->tokenStream, pn, + ReportCompileErrorNumber(cx, &parser->tokenStream, &pi, JSREPORT_ERROR, JSMSG_RESERVED_ID, bytes.ptr()); } goto fail; @@ -1634,11 +1635,11 @@ ParseNodeToXML(Parser *parser, ParseNode *pn, if (flags & XSF_IGNORE_PROCESSING_INSTRUCTIONS) goto skip_child; - qn = ParseNodeToQName(parser, pn, inScopeNSes, JS_FALSE); + qn = ParseNodeToQName(parser, &pi, inScopeNSes, JS_FALSE); if (!qn) goto fail; - str = pn->pn_pidata ? pn->pn_pidata : cx->runtime->emptyString; + str = pi.data(); xml_class = JSXML_CLASS_PROCESSING_INSTRUCTION; } else { /* CDATA section content, or element text. */