зеркало из https://github.com/mozilla/pjs.git
Bug 373082: Changine XML method lookup to never alter "this". r=brendan,jwalden
This commit is contained in:
Родитель
b40cec0683
Коммит
0291ed98e3
|
@ -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")
|
||||
|
|
410
js/src/jsxml.c
410
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 *
|
||||
|
|
Загрузка…
Ссылка в новой задаче