mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-06 00:55:37 +00:00
Attachment 255316: Optimize GetProperty to get rid of intermediate objects. r=brendan
This commit is contained in:
parent
248c6fb367
commit
e039e2a2ff
214
js/src/jsxml.c
214
js/src/jsxml.c
@ -4056,34 +4056,72 @@ SyncInScopeNamespaces(JSContext *cx, JSXML *xml)
|
|||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static JSBool
|
||||||
|
GetNamedProperty(JSContext *cx, JSXML *xml, JSXMLQName* nameqn,
|
||||||
|
JSBool attributes, JSXML *list)
|
||||||
|
{
|
||||||
|
JSXMLArray *array;
|
||||||
|
JSXMLNameMatcher matcher;
|
||||||
|
JSXMLArrayCursor cursor;
|
||||||
|
JSXML *kid;
|
||||||
|
JSBool ok;
|
||||||
|
|
||||||
|
if (!JSXML_HAS_KIDS(xml))
|
||||||
|
return JS_TRUE;
|
||||||
|
|
||||||
|
if (attributes) {
|
||||||
|
array = &xml->xml_attrs;
|
||||||
|
matcher = MatchAttrName;
|
||||||
|
} else {
|
||||||
|
array = &xml->xml_kids;
|
||||||
|
matcher = MatchElemName;
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLArrayCursorInit(&cursor, array);
|
||||||
|
while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) {
|
||||||
|
if (matcher(nameqn, kid)) {
|
||||||
|
if (!attributes && kid->xml_class == JSXML_CLASS_ELEMENT) {
|
||||||
|
ok = SyncInScopeNamespaces(cx, kid);
|
||||||
|
if (!ok)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
ok = Append(cx, list, kid);
|
||||||
|
if (!ok)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ok = JS_TRUE;
|
||||||
|
|
||||||
|
out:
|
||||||
|
XMLArrayCursorFinish(&cursor);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
/* ECMA-357 9.1.1.1 XML [[Get]] and 9.2.1.1 XMLList [[Get]]. */
|
/* ECMA-357 9.1.1.1 XML [[Get]] and 9.2.1.1 XMLList [[Get]]. */
|
||||||
static JSBool
|
static JSBool
|
||||||
GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
||||||
{
|
{
|
||||||
JSXML *xml, *list, *kid;
|
JSXML *xml, *list, *kid;
|
||||||
uint32 index;
|
uint32 index;
|
||||||
JSObject *kidobj, *listobj, *nameobj;
|
JSObject *kidobj, *listobj;
|
||||||
JSXMLQName *nameqn;
|
JSXMLQName *nameqn;
|
||||||
jsid funid;
|
jsid funid;
|
||||||
JSBool ok;
|
jsval roots[2];
|
||||||
|
JSTempValueRooter tvr;
|
||||||
|
JSBool attributes;
|
||||||
JSXMLArrayCursor cursor;
|
JSXMLArrayCursor cursor;
|
||||||
jsval kidval;
|
|
||||||
JSXMLArray *array;
|
|
||||||
JSXMLNameMatcher matcher;
|
|
||||||
|
|
||||||
xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, NULL);
|
xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, NULL);
|
||||||
if (!xml)
|
if (!xml)
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
|
|
||||||
#ifdef __GNUC__
|
if (js_IdIsIndex(id, &index)) {
|
||||||
list = NULL; /* quell GCC overwarning */
|
if (xml->xml_class != JSXML_CLASS_LIST) {
|
||||||
#endif
|
*vp = (index == 0) ? OBJECT_TO_JSVAL(obj) : JSVAL_VOID;
|
||||||
|
} else {
|
||||||
retry:
|
|
||||||
if (xml->xml_class == JSXML_CLASS_LIST) {
|
|
||||||
/* ECMA-357 9.2.1.1 starts here. */
|
|
||||||
if (js_IdIsIndex(id, &index)) {
|
|
||||||
/*
|
/*
|
||||||
|
* ECMA-357 9.2.1.1 starts here.
|
||||||
|
*
|
||||||
* Erratum: 9.2 is not completely clear that indexed properties
|
* Erratum: 9.2 is not completely clear that indexed properties
|
||||||
* correspond to kids, but that's what it seems to say, and it's
|
* correspond to kids, but that's what it seems to say, and it's
|
||||||
* what any sane user would want.
|
* what any sane user would want.
|
||||||
@ -4102,133 +4140,61 @@ retry:
|
|||||||
} else {
|
} else {
|
||||||
*vp = JSVAL_VOID;
|
*vp = JSVAL_VOID;
|
||||||
}
|
}
|
||||||
return JS_TRUE;
|
|
||||||
}
|
}
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
nameqn = ToXMLName(cx, id, &funid);
|
/*
|
||||||
if (!nameqn)
|
* ECMA-357 9.2.1.1/9.1.1.1 qname case.
|
||||||
return JS_FALSE;
|
*/
|
||||||
if (funid)
|
nameqn = ToXMLName(cx, id, &funid);
|
||||||
return GetFunction(cx, obj, xml, funid, vp);
|
if (!nameqn)
|
||||||
|
return JS_FALSE;
|
||||||
|
if (funid)
|
||||||
|
return GetFunction(cx, obj, xml, funid, vp);
|
||||||
|
|
||||||
/*
|
roots[0] = OBJECT_TO_JSVAL(nameqn->object);
|
||||||
* Recursion through GetProperty may allocate more list objects, so
|
JS_PUSH_TEMP_ROOT(cx, 1, roots, &tvr);
|
||||||
* we make use of local root scopes here. Each new allocation will
|
|
||||||
* push the newborn onto the local root stack.
|
|
||||||
*/
|
|
||||||
ok = js_EnterLocalRootScope(cx);
|
|
||||||
if (!ok)
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
/*
|
listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST);
|
||||||
* NB: nameqn is already protected from GC by cx->newborn[GCX_OBJECT]
|
if (listobj) {
|
||||||
* until listobj is created. After that, a local root keeps listobj
|
roots[1] = OBJECT_TO_JSVAL(listobj);
|
||||||
* alive, and listobj's private keeps nameqn alive via targetprop.
|
tvr.count++;
|
||||||
*/
|
|
||||||
listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST);
|
|
||||||
if (!listobj) {
|
|
||||||
ok = JS_FALSE;
|
|
||||||
} else {
|
|
||||||
list = (JSXML *) JS_GetPrivate(cx, listobj);
|
|
||||||
list->xml_target = xml;
|
|
||||||
|
|
||||||
|
list = (JSXML *) JS_GetPrivate(cx, listobj);
|
||||||
|
attributes = (OBJ_GET_CLASS(cx, nameqn->object) ==
|
||||||
|
&js_AttributeNameClass);
|
||||||
|
|
||||||
|
if (xml->xml_class == JSXML_CLASS_LIST) {
|
||||||
XMLArrayCursorInit(&cursor, &xml->xml_kids);
|
XMLArrayCursorInit(&cursor, &xml->xml_kids);
|
||||||
while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) {
|
while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) {
|
||||||
if (kid->xml_class == JSXML_CLASS_ELEMENT) {
|
if (kid->xml_class == JSXML_CLASS_ELEMENT &&
|
||||||
kidobj = js_GetXMLObject(cx, kid);
|
!GetNamedProperty(cx, kid, nameqn, attributes, list)) {
|
||||||
if (!kidobj) {
|
listobj = NULL;
|
||||||
ok = JS_FALSE;
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
ok = GetProperty(cx, kidobj, id, &kidval);
|
|
||||||
if (!ok)
|
|
||||||
break;
|
|
||||||
kidobj = JSVAL_TO_OBJECT(kidval);
|
|
||||||
kid = (JSXML *) JS_GetPrivate(cx, kidobj);
|
|
||||||
if (JSXML_LENGTH(kid) > 0) {
|
|
||||||
ok = Append(cx, list, kid);
|
|
||||||
if (!ok)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
XMLArrayCursorFinish(&cursor);
|
XMLArrayCursorFinish(&cursor);
|
||||||
|
} else {
|
||||||
|
if (!GetNamedProperty(cx, xml, nameqn, attributes, list))
|
||||||
|
listobj = NULL;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
/* ECMA-357 9.1.1.1 starts here. */
|
|
||||||
if (js_IdIsIndex(id, &index)) {
|
|
||||||
obj = ToXMLList(cx, OBJECT_TO_JSVAL(obj));
|
|
||||||
if (!obj)
|
|
||||||
return JS_FALSE;
|
|
||||||
xml = (JSXML *) JS_GetPrivate(cx, obj);
|
|
||||||
goto retry;
|
|
||||||
}
|
|
||||||
|
|
||||||
nameqn = ToXMLName(cx, id, &funid);
|
|
||||||
if (!nameqn)
|
|
||||||
return JS_FALSE;
|
|
||||||
if (funid)
|
|
||||||
return GetFunction(cx, obj, xml, funid, vp);
|
|
||||||
nameobj = nameqn->object;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Recursion through GetProperty may allocate more list objects, so
|
* Erratum: ECMA-357 9.1.1.1 misses that [[Append]] sets the given
|
||||||
* we make use of local root scopes here. Each new allocation will
|
* list's [[TargetProperty]] to the property that is being appended.
|
||||||
* push the newborn onto the local root stack.
|
* This means that any use of the internal [[Get]] property returns
|
||||||
|
* a list which, when used by e.g. [[Insert]] duplicates the last
|
||||||
|
* element matched by id.
|
||||||
|
* See bug 336921.
|
||||||
*/
|
*/
|
||||||
ok = js_EnterLocalRootScope(cx);
|
list->xml_target = xml;
|
||||||
if (!ok)
|
list->xml_targetprop = nameqn;
|
||||||
return JS_FALSE;
|
*vp = OBJECT_TO_JSVAL(listobj);
|
||||||
|
|
||||||
listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST);
|
|
||||||
if (!listobj) {
|
|
||||||
ok = JS_FALSE;
|
|
||||||
} else {
|
|
||||||
list = (JSXML *) JS_GetPrivate(cx, listobj);
|
|
||||||
list->xml_target = xml;
|
|
||||||
|
|
||||||
if (JSXML_HAS_KIDS(xml)) {
|
|
||||||
if (OBJ_GET_CLASS(cx, nameobj) == &js_AttributeNameClass) {
|
|
||||||
array = &xml->xml_attrs;
|
|
||||||
matcher = MatchAttrName;
|
|
||||||
} else {
|
|
||||||
array = &xml->xml_kids;
|
|
||||||
matcher = MatchElemName;
|
|
||||||
}
|
|
||||||
XMLArrayCursorInit(&cursor, array);
|
|
||||||
while ((kid = (JSXML *) XMLArrayCursorNext(&cursor)) != NULL) {
|
|
||||||
if (matcher(nameqn, kid)) {
|
|
||||||
if (array == &xml->xml_kids &&
|
|
||||||
kid->xml_class == JSXML_CLASS_ELEMENT) {
|
|
||||||
ok = SyncInScopeNamespaces(cx, kid);
|
|
||||||
if (!ok)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ok = Append(cx, list, kid);
|
|
||||||
if (!ok)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
XMLArrayCursorFinish(&cursor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Common tail code for list and non-list cases. */
|
JS_POP_TEMP_ROOT(cx, &tvr);
|
||||||
js_LeaveLocalRootScopeWithResult(cx, (jsval) listobj);
|
return listobj != NULL;
|
||||||
if (!ok)
|
|
||||||
return JS_FALSE;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Erratum: ECMA-357 9.1.1.1 misses that [[Append]] sets the given list's
|
|
||||||
* [[TargetProperty]] to the property that is being appended. This means
|
|
||||||
* that any use of the internal [[Get]] property returns a list which,
|
|
||||||
* when used by e.g. [[Insert]] duplicates the last element matched by id.
|
|
||||||
* See bug 336921.
|
|
||||||
*/
|
|
||||||
list->xml_targetprop = nameqn;
|
|
||||||
*vp = OBJECT_TO_JSVAL(listobj);
|
|
||||||
return JS_TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSXML *
|
static JSXML *
|
||||||
|
Loading…
Reference in New Issue
Block a user