diff --git a/js/src/js.msg b/js/src/js.msg index 7b380fa12f6..69906d0b74b 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -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") diff --git a/js/src/jsxml.c b/js/src/jsxml.c index 10f3c5e5b8a..c303fcfe717 100644 --- a/js/src/jsxml.c +++ b/js/src/jsxml.c @@ -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 *