Bug 710932 - Create <?target data?> expressions using a constructor that doesn't examine the token stream. r=jorendorff

--HG--
extra : rebase_source : f3b8ca1065e7694cb411d14800052e7cef48f853
This commit is contained in:
Jeff Walden 2011-12-09 23:28:59 -05:00
parent e57cbd8a79
commit f91bbb6233
7 changed files with 78 additions and 46 deletions

View File

@ -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 */

View File

@ -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:

View File

@ -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 <?target data?> */
JSAtom *data; /* data (or null) in <?target data?> */
} xmlpi;
jsdouble dval; /* aligned numeric literal value */
class {
friend class LoopControlStatement;
PropertyName *label; /* target of break/continue statement */
} loopControl;
class { /* E4X <?target data?> 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<XMLProcessingInstruction *>(this);
}
#endif
ParseNode *
CloneLeftHandSide(ParseNode *opn, TreeContext *tc);

View File

@ -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_<XMLProcessingInstruction>(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_<XMLProcessingInstruction>(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:

View File

@ -330,8 +330,8 @@ struct Token {
private:
friend struct Token;
struct { /* pair for <?target data?> 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;
}

View File

@ -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:

View File

@ -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. */