Bug 373082: Changine XML method lookup to never alter "this". r=brendan,jwalden

This commit is contained in:
igor@mir2.org 2007-03-26 02:07:24 -07:00
Родитель b40cec0683
Коммит 0291ed98e3
2 изменённых файлов: 209 добавлений и 202 удалений

Просмотреть файл

@ -298,3 +298,4 @@ MSG_DEF(JSMSG_BAD_YIELD_SYNTAX, 215, 0, JSEXN_SYNTAXERR, "yield expression
MSG_DEF(JSMSG_ARRAY_COMP_LEFTSIDE, 216, 0, JSEXN_SYNTAXERR, "invalid array comprehension left-hand side")
MSG_DEF(JSMSG_YIELD_FROM_FILTER, 217, 0, JSEXN_INTERNALERR, "yield not yet supported from filtering predicate")
MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE, 218, 0, JSEXN_TYPEERR, "reduce of empty array with no initial value")
MSG_DEF(JSMSG_NON_LIST_XML_METHOD, 219, 2, JSEXN_TYPEERR, "cannot call {0} method on an XML list with {1} elements")

Просмотреть файл

@ -3966,40 +3966,6 @@ DeleteListElement(JSContext *cx, JSXML *xml, uint32 index)
}
}
/*
* Class compatibility mask flag bits stored in xml_methods[i].extra. If XML
* and XMLList are unified (an incompatible change to ECMA-357), then we don't
* need any of this.
*/
#define XML_MASK 0x1
#define XMLLIST_MASK 0x2
#define GENERIC_MASK (XML_MASK | XMLLIST_MASK)
#define CLASS_TO_MASK(c) (1 + ((c) == JSXML_CLASS_LIST))
static JSBool
GetFunction(JSContext *cx, JSObject *obj, JSXML *xml, jsid id, jsval *vp)
{
JSFunction *fun;
do {
/* XXXbe really want a separate scope for function::*. */
if (!js_GetProperty(cx, obj, id, vp))
return JS_FALSE;
if (VALUE_IS_FUNCTION(cx, *vp)) {
if (xml && OBJECT_IS_XML(cx, obj)) {
fun = (JSFunction *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(*vp));
if (!FUN_INTERPRETED(fun) && fun->u.n.spare &&
(fun->u.n.spare & CLASS_TO_MASK(xml->xml_class)) == 0) {
/* XML method called on XMLList or vice versa. */
*vp = JSVAL_VOID;
}
}
break;
}
} while ((obj = OBJ_GET_PROTO(cx, obj)) != NULL);
return JS_TRUE;
}
static JSBool
SyncInScopeNamespaces(JSContext *cx, JSXML *xml)
{
@ -4122,7 +4088,7 @@ GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
if (!nameqn)
return JS_FALSE;
if (funid)
return GetFunction(cx, obj, xml, funid, vp);
return js_GetXMLFunction(cx, obj, funid, vp);
roots[0] = OBJECT_TO_JSVAL(nameqn->object);
JS_PUSH_TEMP_ROOT(cx, 1, roots, &tvr);
@ -4936,28 +4902,49 @@ HasIndexedProperty(JSXML *xml, uint32 i)
return JS_FALSE;
}
static JSBool
HasSimpleContent(JSXML *xml);
static JSBool
HasFunctionProperty(JSContext *cx, JSObject *obj, jsid funid, JSBool *found)
{
JSObject *pobj;
JSProperty *prop;
JSXML *xml;
JSTempValueRooter tvr;
JSBool ok;
JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_XMLClass);
/*
* This does not perform the extended search for function properties as
* GetFunction does since function::name refers only to the functions that
* exist in obj or its prototype chain.
*/
if (!js_LookupProperty(cx, obj, funid, &pobj, &prop))
return JS_FALSE;
if (prop)
if (prop) {
OBJ_DROP_PROPERTY(cx, pobj, prop);
} else {
xml = (JSXML *) JS_GetPrivate(cx, obj);
if (HasSimpleContent(xml)) {
/*
* Search in String.prototype to set found whenever
* js_GetXMLFunction returns existing function.
*/
JS_PUSH_TEMP_ROOT_OBJECT(cx, NULL, &tvr);
ok = js_GetClassPrototype(cx, NULL, INT_TO_JSID(JSProto_String),
&tvr.u.object);
JS_ASSERT(tvr.u.object);
if (ok) {
ok = js_LookupProperty(cx, tvr.u.object, funid, &pobj, &prop);
if (ok && prop)
OBJ_DROP_PROPERTY(cx, pobj, prop);
}
JS_POP_TEMP_ROOT(cx, &tvr);
if (!ok)
return JS_FALSE;
}
}
*found = (prop != NULL);
return JS_TRUE;
}
/* ECMA-357 9.1.1.6 XML [[HasProperty]] and 9.2.1.5 XMLList [[HasProperty]]. */
static JSBool
HasProperty(JSContext *cx, JSObject *obj, jsval id, JSBool *found)
@ -5041,18 +5028,25 @@ xml_mark_vector(JSContext *cx, JSXML **vec, uint32 len)
* be native. Therefore, xml_lookupProperty must return a valid JSProperty
* pointer parameter via *propp to signify "property found". Since the only
* call to xml_lookupProperty is via OBJ_LOOKUP_PROPERTY, and then only from
* js_FindProperty (in jsobj.c, called from jsinterp.c), the only time we add
* a JSScopeProperty here is when an unqualified name is being accessed.
* js_FindProperty (in jsobj.c, called from jsinterp.c) or from JSOP_IN case
* in the interpreter, the only time we add a JSScopeProperty here is when an
* unqualified name is being accessed or when "name in xml" is called.
*
* This scope property both speeds up subsequent js_FindProperty calls, and
* keeps the JSOP_NAME code in js_Interpret happy by giving it an sprop with
* (getter, setter) == (GetProperty, PutProperty). We can't use that getter
* and setter as js_XMLClass's getProperty and setProperty, because doing so
* would break the XML methods, which are function-valued properties of the
* XML.prototype object.
* This scope property keeps the JSOP_NAME code in js_Interpret happy by
* giving it an sprop with (getter, setter) == (GetProperty, PutProperty).
*
* NB: xml_deleteProperty must take care to remove any property added here.
*/
*
* FIXME This clashes with the function namespace implementation which also
* uses native properties. Effectively after xml_lookupProperty any property
* stored previously using assignments to xml.function::name will be removed.
* We partially workaround the problem in js_GetXMLFunction. There we take
* advatage of the fact that typically function:: is used to access the
* functions is stored in XML.prototype so when js_GetProperty returns
* non-function property, it represents the result of GetProprty setter hiding
* the function. Thus an extra prototype chain lookup should fix this.
* See bug 355257 for the proper solution.
*/
static JSBool
xml_lookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
JSProperty **propp)
@ -5177,22 +5171,6 @@ xml_deleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
JSXMLQName *nameqn;
jsid funid;
/*
* If this object has its own (mutable) scope, and if id isn't an index,
* then we may have added a property to the scope in xml_lookupProperty
* for it to return to mean "found" and to provide a handle for access
* operations to call the property's getter or setter. The property also
* helps speed up unqualified accesses via the property cache, avoiding
* what amount to two HasProperty searches.
*
* But now it's time to remove any such property, to purge the property
* cache and remove the scope entry.
*/
if (OBJ_SCOPE(obj)->object == obj && !JSID_IS_INT(id)) {
if (!js_DeleteProperty(cx, obj, id, rval))
return JS_FALSE;
}
idval = ID_TO_VALUE(id);
xml = (JSXML *) JS_GetPrivate(cx, obj);
if (js_IdIsIndex(idval, &index)) {
@ -5216,6 +5194,16 @@ xml_deleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
&js_AttributeNameClass);
}
/*
* If this object has its own (mutable) scope, then we may have added a
* property to the scope in xml_lookupProperty for it to return to mean
* "found" and to provide a handle for access operations to call the
* property's getter or setter. But now it's time to remove any such
* property, to purge the property cache and remove the scope entry.
*/
if (OBJ_SCOPE(obj)->object == obj && !js_DeleteProperty(cx, obj, id, rval))
return JS_FALSE;
*rval = JSVAL_TRUE;
return JS_TRUE;
}
@ -5350,66 +5338,20 @@ again:
static JSObject *
xml_getMethod(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
{
JSXML *xml;
JSTempValueRooter tvr;
jsval roots[2];
enum {
FUN_ROOT = 0,
OBJ_ROOT = 1
};
JS_ASSERT(JS_InstanceOf(cx, obj, &js_XMLClass, NULL));
xml = (JSXML *) JS_GetPrivate(cx, obj);
memset(roots, 0, sizeof(roots));
JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(roots), roots, &tvr);
/* From this point the control must flow through out: or bad: */
retry:
if (!GetFunction(cx, obj, xml, id, &roots[FUN_ROOT]))
goto bad;
if (JSVAL_IS_VOID(roots[FUN_ROOT]) && OBJECT_IS_XML(cx, obj)) {
if (xml->xml_class == JSXML_CLASS_LIST) {
if (xml->xml_kids.length == 1) {
xml = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML);
if (xml) {
obj = js_GetXMLObject(cx, xml);
if (!obj)
goto bad;
roots[OBJ_ROOT] = OBJECT_TO_JSVAL(obj);
goto retry;
}
}
} else if (HasSimpleContent(xml)) {
JSString *str;
str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj));
if (!str)
goto bad;
if (!js_ValueToObject(cx, STRING_TO_JSVAL(str), &obj))
goto bad;
roots[OBJ_ROOT] = OBJECT_TO_JSVAL(obj);
if (!js_GetProperty(cx, obj, id, &roots[FUN_ROOT]))
goto bad;
}
}
out:
*vp = roots[FUN_ROOT];
if (obj) {
/*
* If we just POP tvr, then it is possible that nothing roots obj, see
* bug 353165. To allow our callers to assume at least weakly rooting
* of the result, we root obj via newborn array. Similarly we root the
* value of roots[FUNCTION] since getMethod callers have a bad habit
* of passing a pointer to unrooted local value as vp.
*/
cx->weakRoots.newborn[GCX_OBJECT] = (JSGCThing *)obj;
cx->weakRoots.lastInternalResult = roots[FUN_ROOT];
}
/*
* As our callers have a bad habit of passing a pointer to an unrooted
* local value as vp, we use a proper root here.
*/
JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr);
if (!js_GetXMLFunction(cx, obj, id, &tvr.u.value))
obj = NULL;
*vp = tvr.u.value;
JS_POP_TEMP_ROOT(cx, &tvr);
return obj;
bad:
obj = NULL;
goto out;
}
static JSBool
@ -5645,6 +5587,40 @@ CallConstructorFunction(JSContext *cx, JSObject *obj, JSClass *clasp,
return JSVAL_TO_OBJECT(rval);
}
static JSXML *
StartNonListXMLMethod(JSContext *cx, JSObject **objp, jsval *argv)
{
JSXML *xml;
JSFunction *fun;
JS_ASSERT(VALUE_IS_FUNCTION(cx, argv[-2]));
xml = (JSXML *) JS_GetInstancePrivate(cx, *objp, &js_XMLClass, argv);
if (!xml || xml->xml_class != JSXML_CLASS_LIST)
return xml;
if (xml->xml_kids.length == 1) {
xml = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML);
if (xml) {
*objp = js_GetXMLObject(cx, xml);
if (!*objp)
return NULL;
argv[-1] = OBJECT_TO_JSVAL(*objp);
return xml;
}
}
fun = (JSFunction *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[-2]));
if (fun) {
char numBuf[12];
JS_snprintf(numBuf, sizeof numBuf, "%u", xml->xml_kids.length);
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_NON_LIST_XML_METHOD,
JS_GetFunctionName(fun), numBuf);
}
return JS_FALSE;
}
#define XML_METHOD_PROLOG \
JS_BEGIN_MACRO \
xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, argv); \
@ -5652,6 +5628,14 @@ CallConstructorFunction(JSContext *cx, JSObject *obj, JSClass *clasp,
return JS_FALSE; \
JS_END_MACRO
#define NON_LIST_XML_METHOD_PROLOG \
JS_BEGIN_MACRO \
xml = StartNonListXMLMethod(cx, &obj, argv); \
if (!xml) \
return JS_FALSE; \
JS_ASSERT(xml->xml_class != JSXML_CLASS_LIST); \
JS_END_MACRO
static JSBool
xml_addNamespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
@ -5660,7 +5644,7 @@ xml_addNamespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
JSObject *nsobj;
JSXMLNamespace *ns;
XML_METHOD_PROLOG;
NON_LIST_XML_METHOD_PROLOG;
if (xml->xml_class != JSXML_CLASS_ELEMENT)
return JS_TRUE;
xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
@ -5688,7 +5672,7 @@ xml_appendChild(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval name, v;
JSObject *vobj;
XML_METHOD_PROLOG;
NON_LIST_XML_METHOD_PROLOG;
xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
if (!xml)
return JS_FALSE;
@ -5851,7 +5835,7 @@ xml_childIndex(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
JSXML *xml, *parent;
uint32 i, n;
XML_METHOD_PROLOG;
NON_LIST_XML_METHOD_PROLOG;
parent = xml->parent;
if (!parent || xml->xml_class == JSXML_CLASS_ATTRIBUTE) {
*rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
@ -6263,7 +6247,7 @@ xml_inScopeNamespaces(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
JSTempRootedNSArray namespaces;
JSBool ok;
XML_METHOD_PROLOG;
NON_LIST_XML_METHOD_PROLOG;
InitTempNSArray(cx, &namespaces);
ok = FindInScopeNamespaces(cx, xml, &namespaces.array) &&
@ -6280,7 +6264,7 @@ xml_insertChildAfter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval arg;
uint32 i;
XML_METHOD_PROLOG;
NON_LIST_XML_METHOD_PROLOG;
if (!JSXML_HAS_KIDS(xml))
return JS_TRUE;
@ -6315,7 +6299,7 @@ xml_insertChildBefore(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval arg;
uint32 i;
XML_METHOD_PROLOG;
NON_LIST_XML_METHOD_PROLOG;
if (!JSXML_HAS_KIDS(xml))
return JS_TRUE;
@ -6363,7 +6347,7 @@ xml_localName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
{
JSXML *xml;
XML_METHOD_PROLOG;
NON_LIST_XML_METHOD_PROLOG;
*rval = xml->name ? STRING_TO_JSVAL(xml->name->localName) : JSVAL_NULL;
return JS_TRUE;
}
@ -6374,7 +6358,7 @@ xml_name(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
JSXML *xml;
JSObject *nameobj;
XML_METHOD_PROLOG;
NON_LIST_XML_METHOD_PROLOG;
if (!xml->name) {
*rval = JSVAL_NULL;
} else {
@ -6398,7 +6382,7 @@ xml_namespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
JSXMLNamespace *ns;
JSObject *nsobj;
XML_METHOD_PROLOG;
NON_LIST_XML_METHOD_PROLOG;
if (argc == 0 && !JSXML_HAS_NAME(xml)) {
*rval = JSVAL_NULL;
return JS_TRUE;
@ -6461,8 +6445,8 @@ xml_namespaceDeclarations(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
uint32 i, n;
JSXMLNamespace *ns;
XML_METHOD_PROLOG;
if (JSXML_HAS_VALUE(xml) || xml->xml_class == JSXML_CLASS_LIST)
NON_LIST_XML_METHOD_PROLOG;
if (JSXML_HAS_VALUE(xml))
return JS_TRUE;
/* From here, control flow must goto out to finish these arrays. */
@ -6526,7 +6510,7 @@ xml_nodeKind(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
JSXML *xml;
JSString *str;
XML_METHOD_PROLOG;
NON_LIST_XML_METHOD_PROLOG;
str = JS_InternString(cx, js_xml_class_str[xml->xml_class]);
if (!str)
return JS_FALSE;
@ -6712,7 +6696,7 @@ xml_prependChild(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
{
JSXML *xml;
XML_METHOD_PROLOG;
NON_LIST_XML_METHOD_PROLOG;
xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
if (!xml)
return JS_FALSE;
@ -6801,7 +6785,7 @@ xml_removeNamespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
JSObject *nsobj;
JSXMLNamespace *ns;
XML_METHOD_PROLOG;
NON_LIST_XML_METHOD_PROLOG;
*rval = OBJECT_TO_JSVAL(obj);
if (xml->xml_class != JSXML_CLASS_ELEMENT)
return JS_TRUE;
@ -6828,7 +6812,7 @@ xml_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
JSObject *nameobj;
JSXMLQName *nameqn;
XML_METHOD_PROLOG;
NON_LIST_XML_METHOD_PROLOG;
*rval = OBJECT_TO_JSVAL(obj);
if (xml->xml_class != JSXML_CLASS_ELEMENT)
return JS_TRUE;
@ -6882,6 +6866,9 @@ static JSBool
xml_setChildren(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
if (!StartNonListXMLMethod(cx, &obj, argv))
return JS_FALSE;
if (!PutProperty(cx, obj, ATOM_KEY(cx->runtime->atomState.starAtom),
&argv[0])) {
return JS_FALSE;
@ -6900,7 +6887,7 @@ xml_setLocalName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
JSXMLQName *nameqn;
JSString *namestr;
XML_METHOD_PROLOG;
NON_LIST_XML_METHOD_PROLOG;
if (!JSXML_HAS_NAME(xml))
return JS_TRUE;
@ -6934,7 +6921,7 @@ xml_setName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
uint32 i, n;
JSXMLNamespace *ns;
XML_METHOD_PROLOG;
NON_LIST_XML_METHOD_PROLOG;
if (!JSXML_HAS_NAME(xml))
return JS_TRUE;
@ -7036,11 +7023,9 @@ xml_setNamespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
JSXMLNamespace *ns;
jsval qnargv[2];
XML_METHOD_PROLOG;
if (xml->xml_class != JSXML_CLASS_ELEMENT &&
xml->xml_class != JSXML_CLASS_ATTRIBUTE) {
NON_LIST_XML_METHOD_PROLOG;
if (!JSXML_HAS_NAME(xml))
return JS_TRUE;
}
xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
if (!xml || !js_GetXMLQNameObject(cx, xml->name))
@ -7199,46 +7184,46 @@ xml_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
}
static JSFunctionSpec xml_methods[] = {
{"addNamespace", xml_addNamespace, 1,0,XML_MASK},
{"appendChild", xml_appendChild, 1,0,XML_MASK},
{js_attribute_str, xml_attribute, 1,0,GENERIC_MASK},
{"attributes", xml_attributes, 0,0,GENERIC_MASK},
{"child", xml_child, 1,0,GENERIC_MASK},
{"childIndex", xml_childIndex, 0,0,XML_MASK},
{"children", xml_children, 0,0,GENERIC_MASK},
{"comments", xml_comments, 0,0,GENERIC_MASK},
{"contains", xml_contains, 1,0,GENERIC_MASK},
{"copy", xml_copy, 0,0,GENERIC_MASK},
{"descendants", xml_descendants, 1,0,GENERIC_MASK},
{"elements", xml_elements, 1,0,GENERIC_MASK},
{"hasOwnProperty", xml_hasOwnProperty, 1,0,GENERIC_MASK},
{"hasComplexContent", xml_hasComplexContent, 1,0,GENERIC_MASK},
{"hasSimpleContent", xml_hasSimpleContent, 1,0,GENERIC_MASK},
{"inScopeNamespaces", xml_inScopeNamespaces, 0,0,XML_MASK},
{"insertChildAfter", xml_insertChildAfter, 2,0,XML_MASK},
{"insertChildBefore", xml_insertChildBefore, 2,0,XML_MASK},
{js_length_str, xml_length, 0,0,GENERIC_MASK},
{js_localName_str, xml_localName, 0,0,XML_MASK},
{js_name_str, xml_name, 0,0,XML_MASK},
{js_namespace_str, xml_namespace, 1,0,XML_MASK},
{"namespaceDeclarations", xml_namespaceDeclarations, 0,0,XML_MASK},
{"nodeKind", xml_nodeKind, 0,0,XML_MASK},
{"normalize", xml_normalize, 0,0,GENERIC_MASK},
{js_xml_parent_str, xml_parent, 0,0,GENERIC_MASK},
{"processingInstructions",xml_processingInstructions,1,0,GENERIC_MASK},
{"prependChild", xml_prependChild, 1,0,XML_MASK},
{"propertyIsEnumerable", xml_propertyIsEnumerable, 1,0,GENERIC_MASK},
{"removeNamespace", xml_removeNamespace, 1,0,XML_MASK},
{"replace", xml_replace, 2,0,XML_MASK},
{"setChildren", xml_setChildren, 1,0,XML_MASK},
{"setLocalName", xml_setLocalName, 1,0,XML_MASK},
{"setName", xml_setName, 1,0,XML_MASK},
{"setNamespace", xml_setNamespace, 1,0,XML_MASK},
{js_text_str, xml_text, 0,0,GENERIC_MASK},
{js_toString_str, xml_toString, 0,0,GENERIC_MASK},
{js_toXMLString_str, xml_toXMLString, 0,0,GENERIC_MASK},
{js_toSource_str, xml_toXMLString, 0,0,GENERIC_MASK},
{js_valueOf_str, xml_valueOf, 0,0,GENERIC_MASK},
{"addNamespace", xml_addNamespace, 1,0,0},
{"appendChild", xml_appendChild, 1,0,0},
{js_attribute_str, xml_attribute, 1,0,0},
{"attributes", xml_attributes, 0,0,0},
{"child", xml_child, 1,0,0},
{"childIndex", xml_childIndex, 0,0,0},
{"children", xml_children, 0,0,0},
{"comments", xml_comments, 0,0,0},
{"contains", xml_contains, 1,0,0},
{"copy", xml_copy, 0,0,0},
{"descendants", xml_descendants, 1,0,0},
{"elements", xml_elements, 1,0,0},
{"hasOwnProperty", xml_hasOwnProperty, 1,0,0},
{"hasComplexContent", xml_hasComplexContent, 1,0,0},
{"hasSimpleContent", xml_hasSimpleContent, 1,0,0},
{"inScopeNamespaces", xml_inScopeNamespaces, 0,0,0},
{"insertChildAfter", xml_insertChildAfter, 2,0,0},
{"insertChildBefore", xml_insertChildBefore, 2,0,0},
{js_length_str, xml_length, 0,0,0},
{js_localName_str, xml_localName, 0,0,0},
{js_name_str, xml_name, 0,0,0},
{js_namespace_str, xml_namespace, 1,0,0},
{"namespaceDeclarations", xml_namespaceDeclarations, 0,0,0},
{"nodeKind", xml_nodeKind, 0,0,0},
{"normalize", xml_normalize, 0,0,0},
{js_xml_parent_str, xml_parent, 0,0,0},
{"processingInstructions",xml_processingInstructions,1,0,0},
{"prependChild", xml_prependChild, 1,0,0},
{"propertyIsEnumerable", xml_propertyIsEnumerable, 1,0,0},
{"removeNamespace", xml_removeNamespace, 1,0,0},
{"replace", xml_replace, 2,0,0},
{"setChildren", xml_setChildren, 1,0,0},
{"setLocalName", xml_setLocalName, 1,0,0},
{"setName", xml_setName, 1,0,0},
{"setNamespace", xml_setNamespace, 1,0,0},
{js_text_str, xml_text, 0,0,0},
{js_toString_str, xml_toString, 0,0,0},
{js_toXMLString_str, xml_toXMLString, 0,0,0},
{js_toSource_str, xml_toXMLString, 0,0,0},
{js_valueOf_str, xml_valueOf, 0,0,0},
{0,0,0,0,0}
};
@ -7642,7 +7627,6 @@ JSObject *
js_InitXMLClass(JSContext *cx, JSObject *obj)
{
JSObject *proto, *pobj, *ctor;
JSFunctionSpec *fs;
JSFunction *fun;
JSXML *xml;
JSProperty *prop;
@ -7655,27 +7639,11 @@ js_InitXMLClass(JSContext *cx, JSObject *obj)
/* Define the XML class constructor and prototype. */
proto = JS_InitClass(cx, obj, NULL, &js_XMLClass, XML, 1,
NULL, NULL,
NULL, xml_methods,
xml_static_props, xml_static_methods);
if (!proto)
return NULL;
/*
* XXX Hack alert: expand JS_DefineFunctions here to copy fs->extra into
* fun->spare, clearing fun->extra. No xml_methods require extra local GC
* roots allocated after actual arguments on the VM stack, but we need a
* way to tell which methods work only on XML objects, which work only on
* XMLList objects, and which work on either.
*/
for (fs = xml_methods; fs->name; fs++) {
fun = JS_DefineFunction(cx, proto, fs->name, fs->call, fs->nargs,
fs->flags);
if (!fun)
return NULL;
fun->u.n.extra = 0;
fun->u.n.spare = (uint16)fs->extra;
}
xml = js_NewXML(cx, JSXML_CLASS_TEXT);
if (!xml || !JS_SetPrivate(cx, proto, xml))
return NULL;
@ -8111,14 +8079,52 @@ js_FindXMLProperty(JSContext *cx, jsval nameval, JSObject **objp, jsid *idp)
return JS_FALSE;
}
extern JSBool
JSBool
js_GetXMLFunction(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
{
JSObject *target;
JSXML *xml;
JSTempValueRooter tvr;
JSBool ok;
JS_ASSERT(OBJECT_IS_XML(cx, obj));
/* After this point, control must flow through label out: to exit. */
JS_PUSH_TEMP_ROOT_OBJECT(cx, NULL, &tvr);
/*
* See comments before xml_lookupProperty about the need for the proto
* chain lookup.
*/
target = obj;
for (;;) {
ok = js_GetProperty(cx, target, id, vp);
if (!ok)
goto out;
if (VALUE_IS_FUNCTION(cx, *vp)) {
ok = JS_TRUE;
goto out;
}
target = OBJ_GET_PROTO(cx, target);
if (target == NULL)
break;
tvr.u.object = target;
}
xml = (JSXML *) JS_GetPrivate(cx, obj);
return GetFunction(cx, obj, xml, id, vp);
if (HasSimpleContent(xml)) {
/* Search in String.prototype to implement 11.2.2.1 Step 3(f). */
ok = js_GetClassPrototype(cx, NULL, INT_TO_JSID(JSProto_String),
&tvr.u.object);
if (!ok)
goto out;
JS_ASSERT(tvr.u.object);
ok = OBJ_GET_PROPERTY(cx, tvr.u.object, id, vp);
}
out:
JS_POP_TEMP_ROOT(cx, &tvr);
return ok;
}
static JSXML *