- Added strict warning "reference to undefined XML name {0}" to cope with

ECMA-357 botch where * or @b or (given valid namespace reference n) n::id
  results in undefined, instead of a TypeError.

- Lazily bootstrap AnyName and AttributeName classes, instead of leaving the
  former uninitialized, and initializing the latter only if QName is init'ed.
  These classes, representing ECMA-357 internal types, must be initialized
  in order to string conversion and default value on them to return useful
  results.  So this change also requires the shared qname_toString to cope
  with these classes, which ape QName in having a JSXMLQName as private data.

- Revise Filtering Predicate Expressions bytecode schema to avoid bogo-script
  creating in js_FilterXMLObject.  With a new JSOP_ENDFILTER bytecode acting
  in lieu of JSOP_POPV, but also exiting the nested js_Interpret() call, the
  runtime can avoid trying to fake a JSScript for the subsequence of script
  bytecode in parens in x.(e), that contains the bytecode for e plus the pop
  or endfilter op.

  This requires a historic reparameterization of js_Interpret to take the
  starting pc!  I cleaned up order of declaration, use, and useless init nits
  for a few variables while messing with it.

- Based on the above change, fix the decompiler to handle filtered predicate
  expressions -- that code was stubbed out till now, and I forgot to go back.
  All better now, especially thanks to JSOP_ENDFILTER.

- Also while fixing filtered predicates, eliminate the useless TOK_RP parse
  node above the parenthesized expression, to avoid a JSOP_GROUP bytecode.

- Fix js_GetAttributeNameObject so it doesn't take over its QName parameter's
  object and rebind it to an object of class AttributeName -- instead, clone
  the qn if necessary.  This is important to cope with the errata, noticed a
  while ago but finally recorded:

9.2.1.2 Step 2(e)(i, ii),
9.2.1.2 Step 7(e)(i),
9.2.1.3 Step 2(b)(ii)(1)(a)
        All uses of a.[[Name]] for an attribute a in these sections that pass
        that QName object to [[Delete]] must pass an AttributeName cloned from
        a.[[Name]].  The [[Name]] internal property is always a QName instance
        and never an AttributeName or AnyName instance.  But [[Delete]] will
        not operate on x.[[Attributes]] when given a QName by these sections,
        so a child could be wrongly deleted instead of the attribute of the
        same name.

  This rework exposed a bug in the XML.prototype.name() impl, where it was
  returning an AttributeName, not a QName, for attribute-class XML objects.
  Clearly wrong -- the E4X spec makes plain early on that [[Name]] is always
  a QName -- but the spec and e4x testsuite seemed to require it due to the
  above-noted errata.
This commit is contained in:
brendan%mozilla.org 2004-12-18 02:28:21 +00:00
parent b397544e5e
commit d1291966ce
11 changed files with 169 additions and 88 deletions

View File

@ -276,3 +276,4 @@ MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP, 193, 0, JSEXN_SYNTAXERR, "invalid for each
MSG_DEF(JSMSG_BAD_XMLLIST_PUT, 194, 1, JSEXN_TYPEERR, "can't set property {0} in XMLList") MSG_DEF(JSMSG_BAD_XMLLIST_PUT, 194, 1, JSEXN_TYPEERR, "can't set property {0} in XMLList")
MSG_DEF(JSMSG_UNKNOWN_XML_ENTITY, 195, 1, JSEXN_TYPEERR, "unknown XML entity {0}") MSG_DEF(JSMSG_UNKNOWN_XML_ENTITY, 195, 1, JSEXN_TYPEERR, "unknown XML entity {0}")
MSG_DEF(JSMSG_BAD_XML_NCR, 196, 1, JSEXN_TYPEERR, "malformed XML character {0}") MSG_DEF(JSMSG_BAD_XML_NCR, 196, 1, JSEXN_TYPEERR, "malformed XML character {0}")
MSG_DEF(JSMSG_UNDEFINED_XML_NAME, 197, 1, JSEXN_TYPEERR, "reference to undefined XML name {0}")

View File

@ -1305,6 +1305,8 @@ static JSStdName standard_class_names[] = {
{js_InitXMLClass, LAZILY_PINNED_ATOM(isXMLName)}, {js_InitXMLClass, LAZILY_PINNED_ATOM(isXMLName)},
{js_InitNamespaceClass, LAZILY_PINNED_ATOM(Namespace)}, {js_InitNamespaceClass, LAZILY_PINNED_ATOM(Namespace)},
{js_InitQNameClass, LAZILY_PINNED_ATOM(QName)}, {js_InitQNameClass, LAZILY_PINNED_ATOM(QName)},
{js_InitQNameClass, LAZILY_PINNED_ATOM(AnyName)},
{js_InitQNameClass, LAZILY_PINNED_ATOM(AttributeName)},
{js_InitXMLClass, LAZILY_PINNED_ATOM(XML)}, {js_InitXMLClass, LAZILY_PINNED_ATOM(XML)},
{js_InitXMLClass, LAZILY_PINNED_ATOM(XMLList)}, {js_InitXMLClass, LAZILY_PINNED_ATOM(XMLList)},
#endif #endif

View File

@ -210,6 +210,8 @@ struct JSAtomState {
/* Less frequently used atoms, pinned lazily by JS_ResolveStandardClass. */ /* Less frequently used atoms, pinned lazily by JS_ResolveStandardClass. */
struct { struct {
JSAtom *AnyNameAtom;
JSAtom *AttributeNameAtom;
JSAtom *EvalErrorAtom; JSAtom *EvalErrorAtom;
JSAtom *InfinityAtom; JSAtom *InfinityAtom;
JSAtom *InternalErrorAtom; JSAtom *InternalErrorAtom;

View File

@ -4240,12 +4240,12 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
case TOK_FILTER: case TOK_FILTER:
if (!js_EmitTree(cx, cg, pn->pn_left)) if (!js_EmitTree(cx, cg, pn->pn_left))
return JS_FALSE; return JS_FALSE;
jmp = js_Emit3(cx, cg, pn->pn_op, 0, 0); jmp = js_Emit3(cx, cg, JSOP_FILTER, 0, 0);
if (jmp < 0) if (jmp < 0)
return JS_FALSE; return JS_FALSE;
if (!js_EmitTree(cx, cg, pn->pn_right)) if (!js_EmitTree(cx, cg, pn->pn_right))
return JS_FALSE; return JS_FALSE;
if (js_Emit1(cx, cg, JSOP_POPV) < 0) if (js_Emit1(cx, cg, JSOP_ENDFILTER) < 0)
return JS_FALSE; return JS_FALSE;
CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp); CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
break; break;

View File

@ -1303,7 +1303,7 @@ have_fun:
frame.scopeChain = funobj; frame.scopeChain = funobj;
#endif #endif
} }
ok = js_Interpret(cx, &v); ok = js_Interpret(cx, script->code, &v);
} else { } else {
/* fun might be onerror trying to report a syntax error in itself. */ /* fun might be onerror trying to report a syntax error in itself. */
frame.scopeChain = NULL; frame.scopeChain = NULL;
@ -1513,7 +1513,7 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
* Use frame.rval, not result, so the last result stays rooted across any * Use frame.rval, not result, so the last result stays rooted across any
* GC activations nested within this js_Interpret. * GC activations nested within this js_Interpret.
*/ */
ok = js_Interpret(cx, &frame.rval); ok = js_Interpret(cx, script->code, &frame.rval);
*result = frame.rval; *result = frame.rval;
if (hookData) { if (hookData) {
@ -1774,7 +1774,7 @@ InternNonIntElementId(JSContext *cx, jsval idval, jsid *idp)
#define MAX_INLINE_CALL_COUNT 1000 #define MAX_INLINE_CALL_COUNT 1000
JSBool JSBool
js_Interpret(JSContext *cx, jsval *result) js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result)
{ {
JSRuntime *rt; JSRuntime *rt;
JSStackFrame *fp; JSStackFrame *fp;
@ -1788,7 +1788,7 @@ js_Interpret(JSContext *cx, jsval *result)
jsint depth, len; jsint depth, len;
jsval *sp, *newsp; jsval *sp, *newsp;
void *mark; void *mark;
jsbytecode *pc, *pc2, *endpc; jsbytecode *endpc, *pc2;
JSOp op, op2; JSOp op, op2;
const JSCodeSpec *cs; const JSCodeSpec *cs;
JSAtom *atom; JSAtom *atom;
@ -1876,11 +1876,6 @@ js_Interpret(JSContext *cx, jsval *result)
LOAD_INTERRUPT_HANDLER(rt); LOAD_INTERRUPT_HANDLER(rt);
pc = script->code;
endpc = pc + script->length;
depth = (jsint) script->depth;
len = -1;
/* Check for too much js_Interpret nesting, or too deep a C stack. */ /* Check for too much js_Interpret nesting, or too deep a C stack. */
if (++cx->interpLevel == MAX_INTERP_LEVEL || if (++cx->interpLevel == MAX_INTERP_LEVEL ||
!JS_CHECK_STACK_SIZE(cx, stackDummy)) { !JS_CHECK_STACK_SIZE(cx, stackDummy)) {
@ -1892,6 +1887,7 @@ js_Interpret(JSContext *cx, jsval *result)
/* /*
* Allocate operand and pc stack slots for the script's worst-case depth. * Allocate operand and pc stack slots for the script's worst-case depth.
*/ */
depth = (jsint) script->depth;
newsp = js_AllocRawStack(cx, (uintN)(2 * depth), &mark); newsp = js_AllocRawStack(cx, (uintN)(2 * depth), &mark);
if (!newsp) { if (!newsp) {
ok = JS_FALSE; ok = JS_FALSE;
@ -1901,6 +1897,7 @@ js_Interpret(JSContext *cx, jsval *result)
fp->spbase = sp; fp->spbase = sp;
SAVE_SP(fp); SAVE_SP(fp);
endpc = script->code + script->length;
while (pc < endpc) { while (pc < endpc) {
fp->pc = pc; fp->pc = pc;
op = (JSOp) *pc; op = (JSOp) *pc;
@ -5141,13 +5138,16 @@ js_Interpret(JSContext *cx, jsval *result)
VALUE_TO_OBJECT(cx, lval, obj); VALUE_TO_OBJECT(cx, lval, obj);
len = GET_JUMP_OFFSET(pc); len = GET_JUMP_OFFSET(pc);
SAVE_SP(fp); SAVE_SP(fp);
ok = js_FilterXMLList(cx, obj, pc + cs->length, len - cs->length, ok = js_FilterXMLList(cx, obj, pc + cs->length, &rval);
&rval);
if (!ok) if (!ok)
goto out; goto out;
STORE_OPND(-1, rval); STORE_OPND(-1, rval);
break; break;
case JSOP_ENDFILTER:
*result = POP_OPND();
goto out;
case JSOP_TOXML: case JSOP_TOXML:
rval = FETCH_OPND(-1); rval = FETCH_OPND(-1);
SAVE_SP(fp); SAVE_SP(fp);

View File

@ -297,7 +297,7 @@ js_CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs,
JSObject **objp, JSProperty **propp); JSObject **objp, JSProperty **propp);
extern JSBool extern JSBool
js_Interpret(JSContext *cx, jsval *result); js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result);
JS_END_EXTERN_C JS_END_EXTERN_C

View File

@ -2433,14 +2433,20 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
case JSOP_XMLNAME: case JSOP_XMLNAME:
case JSOP_XMLTAGEXPR: case JSOP_XMLTAGEXPR:
case JSOP_XMLELTEXPR: case JSOP_XMLELTEXPR:
case JSOP_FILTER:
case JSOP_TOXML: case JSOP_TOXML:
case JSOP_TOXMLLIST: case JSOP_TOXMLLIST:
case JSOP_FOREACH: case JSOP_FOREACH:
case JSOP_FILTER:
/* Conversion and prefix ops do nothing in the decompiler. */ /* Conversion and prefix ops do nothing in the decompiler. */
todo = -2; todo = -2;
break; break;
case JSOP_ENDFILTER:
rval = POP_STR();
lval = POP_STR();
todo = Sprint(&ss->sprinter, "%s.(%s)", lval, rval);
break;
case JSOP_DESCENDANTS: case JSOP_DESCENDANTS:
rval = POP_STR(); rval = POP_STR();
lval = POP_STR(); lval = POP_STR();

View File

@ -358,15 +358,16 @@ OPDEF(JSOP_SETXMLNAME, 171,"setxmlname", NULL, 1, 3, 1, 1, JOF_BYTE|J
OPDEF(JSOP_XMLNAME, 172,"xmlname", NULL, 1, 1, 1, 12, JOF_BYTE|JOF_XMLNAME) OPDEF(JSOP_XMLNAME, 172,"xmlname", NULL, 1, 1, 1, 12, JOF_BYTE|JOF_XMLNAME)
OPDEF(JSOP_DESCENDANTS, 173,"descendants",NULL, 1, 2, 1, 11, JOF_BYTE) OPDEF(JSOP_DESCENDANTS, 173,"descendants",NULL, 1, 2, 1, 11, JOF_BYTE)
OPDEF(JSOP_FILTER, 174,"filter", NULL, 3, 1, 1, 11, JOF_JUMP) OPDEF(JSOP_FILTER, 174,"filter", NULL, 3, 1, 1, 11, JOF_JUMP)
OPDEF(JSOP_TOXML, 175,"toxml", NULL, 1, 1, 1, 12, JOF_BYTE) OPDEF(JSOP_ENDFILTER, 175,"endfilter", NULL, 1, 1, 0, 0, JOF_BYTE)
OPDEF(JSOP_TOXMLLIST, 176,"toxmllist", NULL, 1, 1, 1, 12, JOF_BYTE) OPDEF(JSOP_TOXML, 176,"toxml", NULL, 1, 1, 1, 12, JOF_BYTE)
OPDEF(JSOP_XMLTAGEXPR, 177,"xmltagexpr", NULL, 1, 1, 1, 12, JOF_BYTE) OPDEF(JSOP_TOXMLLIST, 177,"toxmllist", NULL, 1, 1, 1, 12, JOF_BYTE)
OPDEF(JSOP_XMLELTEXPR, 178,"xmleltexpr", NULL, 1, 1, 1, 12, JOF_BYTE) OPDEF(JSOP_XMLTAGEXPR, 178,"xmltagexpr", NULL, 1, 1, 1, 12, JOF_BYTE)
OPDEF(JSOP_XMLOBJECT, 179,"xmlobject", NULL, 3, 0, 1, 12, JOF_CONST) OPDEF(JSOP_XMLELTEXPR, 179,"xmleltexpr", NULL, 1, 1, 1, 12, JOF_BYTE)
OPDEF(JSOP_XMLCDATA, 180,"xmlcdata", NULL, 3, 0, 1, 12, JOF_CONST) OPDEF(JSOP_XMLOBJECT, 180,"xmlobject", NULL, 3, 0, 1, 12, JOF_CONST)
OPDEF(JSOP_XMLCOMMENT, 181,"xmlcomment", NULL, 3, 0, 1, 12, JOF_CONST) OPDEF(JSOP_XMLCDATA, 181,"xmlcdata", NULL, 3, 0, 1, 12, JOF_CONST)
OPDEF(JSOP_XMLPI, 182,"xmlpi", NULL, 5, 0, 1, 12, JOF_CONST2) OPDEF(JSOP_XMLCOMMENT, 182,"xmlcomment", NULL, 3, 0, 1, 12, JOF_CONST)
OPDEF(JSOP_GETMETHOD, 183,"getmethod", NULL, 3, 1, 1, 11, JOF_CONST|JOF_PROP) OPDEF(JSOP_XMLPI, 183,"xmlpi", NULL, 5, 0, 1, 12, JOF_CONST2)
OPDEF(JSOP_GETFUNNS, 184,"getfunns", NULL, 1, 0, 1, 12, JOF_BYTE) OPDEF(JSOP_GETMETHOD, 184,"getmethod", NULL, 3, 1, 1, 11, JOF_CONST|JOF_PROP)
OPDEF(JSOP_FOREACH, 185,"foreach", NULL, 1, 0, 0, 0, JOF_BYTE) OPDEF(JSOP_GETFUNNS, 185,"getfunns", NULL, 1, 0, 1, 12, JOF_BYTE)
OPDEF(JSOP_DELDESC, 186,"deldesc", NULL, 1, 2, 1, 10, JOF_BYTE |JOF_ELEM|JOF_DEL) OPDEF(JSOP_FOREACH, 186,"foreach", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_DELDESC, 187,"deldesc", NULL, 1, 2, 1, 10, JOF_BYTE |JOF_ELEM|JOF_DEL)

View File

@ -2871,6 +2871,12 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
pn2->pn_type = TOK_LB; pn2->pn_type = TOK_LB;
pn2->pn_op = JSOP_GETELEM; pn2->pn_op = JSOP_GETELEM;
} else if (tt == TOK_RP) { } else if (tt == TOK_RP) {
JSParseNode *group = pn3;
/* Recycle the useless TOK_RP/JSOP_GROUP node. */
pn3 = group->pn_kid;
group->pn_kid = NULL;
RecycleTree(group, tc);
pn2->pn_type = TOK_FILTER; pn2->pn_type = TOK_FILTER;
pn2->pn_op = JSOP_FILTER; pn2->pn_op = JSOP_FILTER;
} else { } else {

View File

@ -112,20 +112,22 @@ static struct {
/* /*
* Random utilities and global functions. * Random utilities and global functions.
*/ */
const char js_isXMLName_str[] = "isXMLName"; const char js_AnyName_str[] = "AnyName";
const char js_Namespace_str[] = "Namespace"; const char js_AttributeName_str[] = "AttributeName";
const char js_QName_str[] = "QName"; const char js_isXMLName_str[] = "isXMLName";
const char js_XML_str[] = "XML"; const char js_Namespace_str[] = "Namespace";
const char js_XMLList_str[] = "XMLList"; const char js_QName_str[] = "QName";
const char js_localName_str[] = "localName"; const char js_XML_str[] = "XML";
const char js_prefix_str[] = "prefix"; const char js_XMLList_str[] = "XMLList";
const char js_toXMLString_str[] = "toXMLString"; const char js_localName_str[] = "localName";
const char js_uri_str[] = "uri"; const char js_prefix_str[] = "prefix";
const char js_toXMLString_str[] = "toXMLString";
const char js_uri_str[] = "uri";
const char js_amp_entity_str[] = "&amp;"; const char js_amp_entity_str[] = "&amp;";
const char js_gt_entity_str[] = "&gt;"; const char js_gt_entity_str[] = "&gt;";
const char js_lt_entity_str[] = "&lt;"; const char js_lt_entity_str[] = "&lt;";
const char js_quot_entity_str[] = "&quot;"; const char js_quot_entity_str[] = "&quot;";
#define IS_EMPTY(str) (JSSTRING_LENGTH(str) == 0) #define IS_EMPTY(str) (JSSTRING_LENGTH(str) == 0)
#define IS_STAR(str) (JSSTRING_LENGTH(str) == 1 && *JSSTRING_CHARS(str) == '*') #define IS_STAR(str) (JSSTRING_LENGTH(str) == 1 && *JSSTRING_CHARS(str) == '*')
@ -480,7 +482,7 @@ JSExtendedClass js_QNameClass = {
* except that they're never constructed and they have no getters. * except that they're never constructed and they have no getters.
*/ */
JSClass js_AttributeNameClass = { JSClass js_AttributeNameClass = {
"AttributeName", JSCLASS_HAS_PRIVATE | JSCLASS_CONSTRUCT_PROTOTYPE, js_AttributeName_str, JSCLASS_HAS_PRIVATE | JSCLASS_CONSTRUCT_PROTOTYPE,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, qname_finalize, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, qname_finalize,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@ -488,7 +490,7 @@ JSClass js_AttributeNameClass = {
}; };
JSClass js_AnyNameClass = { JSClass js_AnyNameClass = {
"AnyName", JSCLASS_HAS_PRIVATE, js_AnyName_str, JSCLASS_HAS_PRIVATE | JSCLASS_CONSTRUCT_PROTOTYPE,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, qname_finalize, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, qname_finalize,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@ -508,13 +510,21 @@ static JSBool
qname_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, qname_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval) jsval *rval)
{ {
JSClass *clasp;
JSXMLQName *qn; JSXMLQName *qn;
JSString *str, *qualstr; JSString *str, *qualstr;
size_t length;
jschar *chars;
qn = (JSXMLQName *) clasp = OBJ_GET_CLASS(cx, obj);
JS_GetInstancePrivate(cx, obj, &js_QNameClass.base, argv); if (clasp == &js_AttributeNameClass || clasp == &js_AnyNameClass) {
if (!qn) qn = (JSXMLQName *) JS_GetPrivate(cx, obj);
return JS_FALSE; } else {
qn = (JSXMLQName *)
JS_GetInstancePrivate(cx, obj, &js_QNameClass.base, argv);
if (!qn)
return JS_FALSE;
}
if (!qn->uri) { if (!qn->uri) {
/* No uri means wildcard qualifier. */ /* No uri means wildcard qualifier. */
@ -531,6 +541,22 @@ qname_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
str = js_ConcatStrings(cx, str, qn->localName); str = js_ConcatStrings(cx, str, qn->localName);
if (!str) if (!str)
return JS_FALSE; return JS_FALSE;
if (str && clasp == &js_AttributeNameClass) {
length = JSSTRING_LENGTH(str);
chars = (jschar *) JS_malloc(cx, (length + 2) * sizeof(jschar));
if (!chars)
return JS_FALSE;
*chars = '@';
js_strncpy(chars + 1, JSSTRING_CHARS(str), length);
chars[++length] = 0;
str = js_NewString(cx, chars, length, 0);
if (!str) {
JS_free(cx, chars);
return JS_FALSE;
}
}
*rval = STRING_TO_JSVAL(str); *rval = STRING_TO_JSVAL(str);
return JS_TRUE; return JS_TRUE;
} }
@ -610,13 +636,27 @@ js_GetXMLQNameObject(JSContext *cx, JSXMLQName *qn)
JSObject * JSObject *
js_GetAttributeNameObject(JSContext *cx, JSXMLQName *qn) js_GetAttributeNameObject(JSContext *cx, JSXMLQName *qn)
{ {
JSXMLQName *origqn;
JSObject *obj; JSObject *obj;
origqn = qn;
obj = qn->object;
if (obj) {
if (OBJ_GET_CLASS(cx, obj) == &js_AttributeNameClass)
return obj;
qn = js_NewXMLQName(cx, qn->uri, qn->prefix, qn->localName);
if (!qn)
return NULL;
}
obj = js_NewObject(cx, &js_AttributeNameClass, NULL, NULL); obj = js_NewObject(cx, &js_AttributeNameClass, NULL, NULL);
if (!obj || !JS_SetPrivate(cx, obj, qn)) { if (!obj || !JS_SetPrivate(cx, obj, qn)) {
cx->newborn[GCX_OBJECT] = NULL; cx->newborn[GCX_OBJECT] = NULL;
if (qn != origqn)
js_DestroyXMLQName(cx, qn);
return NULL; return NULL;
} }
qn->object = obj; qn->object = obj;
qn->markflag = JSXML_MARK_CLEAR; qn->markflag = JSXML_MARK_CLEAR;
METER(xml_stats.qnameobj); METER(xml_stats.qnameobj);
@ -836,8 +876,16 @@ QName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
return JS_TRUE; return JS_TRUE;
} }
/* Create and return a new QName object exactly as if constructed. */ /*
obj = js_NewObject(cx, &js_QNameClass.base, NULL, NULL); * Create and return a new QName object exactly as if constructed.
* Use the constructor's clasp so we can be shared by AttributeName
* (see below after this function).
*/
obj = js_NewObject(cx,
argv
? JS_ValueToFunction(cx, argv[-2])->clasp
: &js_QNameClass.base,
NULL, NULL);
if (!obj) if (!obj)
return JS_FALSE; return JS_FALSE;
*rval = OBJECT_TO_JSVAL(obj); *rval = OBJECT_TO_JSVAL(obj);
@ -933,6 +981,24 @@ out:
return JS_TRUE; return JS_TRUE;
} }
static JSBool
AnyName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
/* Return the one true AnyName instance. */
return js_GetAnyName(cx, rval);
}
static JSBool
AttributeName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
/*
* Since js_AttributeNameClass was initialized, obj will have that as its
* class, not js_QNameClass.
*/
return QName(cx, obj, argc, argv, rval);
}
/* /*
* XMLArray library functions. * XMLArray library functions.
*/ */
@ -5937,9 +6003,7 @@ xml_name(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
if (!xml->name) { if (!xml->name) {
*rval = JSVAL_NULL; *rval = JSVAL_NULL;
} else { } else {
nameobj = ((xml->xml_class == JSXML_CLASS_ATTRIBUTE) nameobj = js_GetXMLQNameObject(cx, xml->name);
? js_GetAttributeNameObject
: js_GetXMLQNameObject)(cx, xml->name);
if (!nameobj) if (!nameobj)
return JS_FALSE; return JS_FALSE;
*rval = OBJECT_TO_JSVAL(nameobj); *rval = OBJECT_TO_JSVAL(nameobj);
@ -7144,7 +7208,12 @@ js_InitNamespaceClass(JSContext *cx, JSObject *obj)
JSObject * JSObject *
js_InitQNameClass(JSContext *cx, JSObject *obj) js_InitQNameClass(JSContext *cx, JSObject *obj)
{ {
if (!JS_InitClass(cx, obj, NULL, &js_AttributeNameClass, QName, 2, if (!JS_InitClass(cx, obj, NULL, &js_AttributeNameClass, AttributeName, 2,
qname_props, qname_methods, NULL, NULL)) {
return NULL;
}
if (!JS_InitClass(cx, obj, NULL, &js_AnyNameClass, AnyName, 0,
qname_props, qname_methods, NULL, NULL)) { qname_props, qname_methods, NULL, NULL)) {
return NULL; return NULL;
} }
@ -7498,6 +7567,18 @@ js_FindXMLProperty(JSContext *cx, jsval name, JSObject **objp, jsval *namep)
lastobj = obj; lastobj = obj;
} while ((obj = OBJ_GET_PARENT(cx, obj)) != NULL); } while ((obj = OBJ_GET_PARENT(cx, obj)) != NULL);
if (JS_HAS_STRICT_OPTION(cx)) {
JSString *str = js_ValueToString(cx, name);
if (!str ||
!JS_ReportErrorFlagsAndNumber(cx,
JSREPORT_WARNING|JSREPORT_STRICT,
js_GetErrorMessage, NULL,
JSMSG_UNDEFINED_XML_NAME,
JS_GetStringBytes(str))) {
return JS_FALSE;
}
}
*objp = lastobj; *objp = lastobj;
*namep = JSVAL_VOID; *namep = JSVAL_VOID;
return JS_TRUE; return JS_TRUE;
@ -7561,24 +7642,21 @@ js_DeleteXMLListElements(JSContext *cx, JSObject *listobj)
} }
JSBool JSBool
js_FilterXMLList(JSContext *cx, JSObject *obj, jsbytecode *pc, uint32 len, js_FilterXMLList(JSContext *cx, JSObject *obj, jsbytecode *pc, jsval *vp)
jsval *vp)
{ {
JSBool ok, inLRS, match; JSBool ok, match;
JSStackFrame *fp, frame; JSStackFrame *fp;
JSObject *listobj, *resobj, *withobj, *kidobj; JSObject *scobj, *listobj, *resobj, *withobj, *kidobj;
JSXML *xml, *list, *result, *kid; JSXML *xml, *list, *result, *kid;
JSScript script;
uint32 i, n; uint32 i, n;
ok = JS_TRUE; ok = JS_EnterLocalRootScope(cx);
inLRS = JS_FALSE; if (!ok)
fp = cx->fp; return JS_FALSE;
frame = *fp;
frame.down = fp;
frame.flags |= JSFRAME_EVAL;
cx->fp = &frame;
/* All control flow after this point must exit via label out or bad. */
fp = cx->fp;
scobj = fp->scopeChain;
xml = GetPrivate(cx, obj, "filtering predicate operator"); xml = GetPrivate(cx, obj, "filtering predicate operator");
if (!xml) if (!xml)
goto bad; goto bad;
@ -7586,10 +7664,6 @@ js_FilterXMLList(JSContext *cx, JSObject *obj, jsbytecode *pc, uint32 len,
if (xml->xml_class == JSXML_CLASS_LIST) { if (xml->xml_class == JSXML_CLASS_LIST) {
list = xml; list = xml;
} else { } else {
ok = JS_EnterLocalRootScope(cx);
if (!ok)
goto out;
inLRS = JS_TRUE;
listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST);
if (!listobj) if (!listobj)
goto bad; goto bad;
@ -7599,24 +7673,16 @@ js_FilterXMLList(JSContext *cx, JSObject *obj, jsbytecode *pc, uint32 len,
goto out; goto out;
} }
/* Root resobj via frame.rval, whether or not we are inLRS. */
resobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); resobj = js_NewXMLObject(cx, JSXML_CLASS_LIST);
if (!resobj) if (!resobj)
goto bad; goto bad;
result = (JSXML *) JS_GetPrivate(cx, resobj); result = (JSXML *) JS_GetPrivate(cx, resobj);
frame.rval = OBJECT_TO_JSVAL(resobj);
/* Hoist the scope chain update out of the loop over kids. */ /* Hoist the scope chain update out of the loop over kids. */
withobj = js_NewObject(cx, &js_WithClass, NULL, fp->scopeChain); withobj = js_NewObject(cx, &js_WithClass, NULL, scobj);
if (!withobj) if (!withobj)
goto bad; goto bad;
frame.scopeChain = withobj; fp->scopeChain = withobj;
script = *fp->script;
script.code = script.main = pc;
script.length = len;
frame.script = &script;
js_CallNewScriptHook(cx, &script, fp->fun);
for (i = 0, n = list->xml_kids.length; i < n; i++) { for (i = 0, n = list->xml_kids.length; i < n; i++) {
kid = XMLARRAY_MEMBER(&list->xml_kids, i, JSXML); kid = XMLARRAY_MEMBER(&list->xml_kids, i, JSXML);
@ -7624,7 +7690,7 @@ js_FilterXMLList(JSContext *cx, JSObject *obj, jsbytecode *pc, uint32 len,
if (!kidobj) if (!kidobj)
goto bad; goto bad;
OBJ_SET_PROTO(cx, withobj, kidobj); OBJ_SET_PROTO(cx, withobj, kidobj);
ok = js_Interpret(cx, vp); ok = js_Interpret(cx, pc, vp);
if (!ok) if (!ok)
goto out; goto out;
ok = js_ValueToBoolean(cx, *vp, &match); ok = js_ValueToBoolean(cx, *vp, &match);
@ -7640,11 +7706,8 @@ js_FilterXMLList(JSContext *cx, JSObject *obj, jsbytecode *pc, uint32 len,
*vp = OBJECT_TO_JSVAL(resobj); *vp = OBJECT_TO_JSVAL(resobj);
out: out:
if (frame.script == &script) fp->scopeChain = scobj;
js_CallDestroyScriptHook(cx, &script); JS_LeaveLocalRootScope(cx);
if (inLRS)
JS_LeaveLocalRootScope(cx);
cx->fp = fp;
return ok; return ok;
bad: bad:
ok = JS_FALSE; ok = JS_FALSE;

View File

@ -42,6 +42,8 @@
#include "jsstddef.h" #include "jsstddef.h"
#include "jspubtd.h" #include "jspubtd.h"
extern const char js_AnyName_str[];
extern const char js_AttributeName_str[];
extern const char js_isXMLName_str[]; extern const char js_isXMLName_str[];
extern const char js_Namespace_str[]; extern const char js_Namespace_str[];
extern const char js_QName_str[]; extern const char js_QName_str[];
@ -178,7 +180,6 @@ struct JSXML {
JSXMLArray attrs; JSXMLArray attrs;
} elem; } elem;
JSString *value; JSString *value;
jsdouble align;
} u; } u;
/* Don't add anything after u -- see js_NewXML for why. */ /* Don't add anything after u -- see js_NewXML for why. */
@ -300,8 +301,7 @@ extern JSBool
js_DeleteXMLListElements(JSContext *cx, JSObject *listobj); js_DeleteXMLListElements(JSContext *cx, JSObject *listobj);
extern JSBool extern JSBool
js_FilterXMLList(JSContext *cx, JSObject *obj, jsbytecode *pc, uint32 len, js_FilterXMLList(JSContext *cx, JSObject *obj, jsbytecode *pc, jsval *vp);
jsval *vp);
extern JSObject * extern JSObject *
js_ValueToXMLObject(JSContext *cx, jsval v); js_ValueToXMLObject(JSContext *cx, jsval v);