Bug 677703 - Add element-valued methods to ObjectOps. Implement forward-to-property versions where necessary for classes which have custom ObjectOps. r=cdleary
authorJeff Walden <jwalden@mit.edu>
Wed, 10 Aug 2011 14:54:51 -0700
changeset 76669 b221c62a19c353c8c50cceed82da2dab0982a379
parent 76668 45b321b68c2f3196785f9c61b1d216501a6fd35b
child 76670 1ddde977131ab1245e0d6e209cf75b3bc4b70553
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewerscdleary
bugs677703
milestone9.0a1
Bug 677703 - Add element-valued methods to ObjectOps. Implement forward-to-property versions where necessary for classes which have custom ObjectOps. r=cdleary
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsobj.cpp
js/src/jsproxy.cpp
js/src/jsprvtd.h
js/src/jstypedarray.cpp
js/src/jstypedarray.h
js/src/jsvalue.h
js/src/jsxml.cpp
js/src/xpconnect/src/xpcprivate.h
js/src/xpconnect/src/xpcwrappednativejsops.cpp
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1990,17 +1990,17 @@ struct JSClass {
     JSCheckAccessOp     checkAccess;
     JSNative            call;
     JSNative            construct;
     JSXDRObjectOp       xdrObject;
     JSHasInstanceOp     hasInstance;
     JSTraceOp           trace;
 
     JSClassInternal     reserved1;
-    void                *reserved[19];
+    void                *reserved[26];
 };
 
 #define JSCLASS_HAS_PRIVATE             (1<<0)  /* objects have private slot */
 #define JSCLASS_NEW_ENUMERATE           (1<<1)  /* has JSNewEnumerateOp hook */
 #define JSCLASS_NEW_RESOLVE             (1<<2)  /* has JSNewResolveOp hook */
 #define JSCLASS_PRIVATE_IS_NSISUPPORTS  (1<<3)  /* private is (nsISupports *) */
 #define JSCLASS_CONCURRENT_FINALIZER    (1<<4)  /* finalize is called on background thread */
 #define JSCLASS_NEW_RESOLVE_GETS_START  (1<<5)  /* JSNewResolveOp gets starting
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -718,16 +718,26 @@ array_lookupProperty(JSContext *cx, JSOb
     if (!proto) {
         *objp = NULL;
         *propp = NULL;
         return JS_TRUE;
     }
     return proto->lookupProperty(cx, id, objp, propp);
 }
 
+static JSBool
+array_lookupElement(JSContext *cx, JSObject *obj, uint32 index, JSObject **objp,
+                    JSProperty **propp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return array_lookupProperty(cx, obj, id, objp, propp);
+}
+
 JSBool
 js_GetDenseArrayElementValue(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     JS_ASSERT(obj->isDenseArray());
 
     uint32 i;
     if (!js_IdIsIndex(id, &i)) {
         JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom));
@@ -785,16 +795,25 @@ array_getProperty(JSContext *cx, JSObjec
     /* Type information for dense array elements must be correct. */
     JS_ASSERT_IF(!obj->hasSingletonType(),
                  js::types::TypeHasProperty(cx, obj->type(), JSID_VOID, *vp));
 
     return JS_TRUE;
 }
 
 static JSBool
+array_getElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32 index, Value *vp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return array_getProperty(cx, obj, receiver, id, vp);
+}
+
+static JSBool
 slowarray_addProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     jsuint index, length;
 
     if (!js_IdIsIndex(id, &index))
         return JS_TRUE;
     length = obj->getArrayLength();
     if (index >= length)
@@ -839,16 +858,25 @@ array_setProperty(JSContext *cx, JSObjec
         return true;
     } while (false);
 
     if (!obj->makeDenseArraySlow(cx))
         return false;
     return js_SetPropertyHelper(cx, obj, id, 0, vp, strict);
 }
 
+static JSBool
+array_setElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return array_setProperty(cx, obj, id, vp, strict);
+}
+
 JSBool
 js_PrototypeHasIndexedProperties(JSContext *cx, JSObject *obj)
 {
     /*
      * Walk up the prototype chain and see if this indexed element already
      * exists. If we hit the end of the prototype chain, it's safe to set the
      * element on the original object.
      */
@@ -863,16 +891,17 @@ js_PrototypeHasIndexedProperties(JSConte
         if (obj->isIndexed())
             return JS_TRUE;
     }
     return JS_FALSE;
 }
 
 namespace js {
 
+/* non-static for direct definition of array elements within the engine */
 JSBool
 array_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
                      PropertyOp getter, StrictPropertyOp setter, uintN attrs)
 {
     if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
         return JS_TRUE;
 
     if (!obj->isDenseArray())
@@ -898,36 +927,66 @@ array_defineProperty(JSContext *cx, JSOb
         return true;
     } while (false);
 
     if (!obj->makeDenseArraySlow(cx))
         return false;
     return js_DefineProperty(cx, obj, id, value, getter, setter, attrs);
 }
 
+/* non-static for direct definition of array elements within the engine */
+JSBool
+array_defineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *value,
+                    PropertyOp getter, StrictPropertyOp setter, uintN attrs)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return array_defineProperty(cx, obj, id, value, getter, setter, attrs);
+}
+
 } // namespace js
 
 static JSBool
 array_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     *attrsp = JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)
         ? JSPROP_PERMANENT : JSPROP_ENUMERATE;
     return JS_TRUE;
 }
 
 static JSBool
+array_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return array_getAttributes(cx, obj, id, attrsp);
+}
+
+static JSBool
 array_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                          JSMSG_CANT_SET_ARRAY_ATTRS);
     return JS_FALSE;
 }
 
+static JSBool
+array_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return array_setAttributes(cx, obj, id, attrsp);
+}
+
 namespace js {
 
+/* non-static for direct deletion of array elements within the engine */
 JSBool
 array_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
 {
     uint32 i;
 
     if (!obj->isDenseArray())
         return js_DeleteProperty(cx, obj, id, rval, strict);
 
@@ -943,16 +1002,26 @@ array_deleteProperty(JSContext *cx, JSOb
 
     if (!js_SuppressDeletedProperty(cx, obj, id))
         return false;
 
     rval->setBoolean(true);
     return JS_TRUE;
 }
 
+/* non-static for direct deletion of array elements within the engine */
+JSBool
+array_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return array_deleteProperty(cx, obj, id, rval, strict);
+}
+
 } // namespace js
 
 static void
 array_trace(JSTracer *trc, JSObject *obj)
 {
     JS_ASSERT(obj->isDenseArray());
 
     uint32 initLength = obj->getDenseArrayInitializedLength();
@@ -992,22 +1061,29 @@ Class js::ArrayClass = {
     NULL,           /* call        */
     NULL,           /* construct   */
     NULL,           /* xdrObject   */
     NULL,           /* hasInstance */
     array_trace,    /* trace       */
     JS_NULL_CLASS_EXT,
     {
         array_lookupProperty,
+        array_lookupElement,
         array_defineProperty,
+        array_defineElement,
         array_getProperty,
+        array_getElement,
         array_setProperty,
+        array_setElement,
         array_getAttributes,
+        array_getElementAttributes,
         array_setAttributes,
+        array_setElementAttributes,
         array_deleteProperty,
+        array_deleteElement,
         NULL,       /* enumerate      */
         array_typeOf,
         array_fix,
         NULL,       /* thisObject     */
         NULL,       /* clear          */
     }
 };
 
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3265,46 +3265,101 @@ with_LookupProperty(JSContext *cx, JSObj
     if (flags == RESOLVE_INFER)
         flags = js_InferFlags(cx, flags);
     flags |= JSRESOLVE_WITH;
     JSAutoResolveFlags rf(cx, flags);
     return obj->getProto()->lookupProperty(cx, id, objp, propp);
 }
 
 static JSBool
+with_LookupElement(JSContext *cx, JSObject *obj, uint32 index, JSObject **objp,
+                   JSProperty **propp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return with_LookupProperty(cx, obj, id, objp, propp);
+}
+
+static JSBool
 with_GetProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
 {
     return obj->getProto()->getProperty(cx, id, vp);
 }
 
 static JSBool
+with_GetElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32 index, Value *vp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return with_GetProperty(cx, obj, receiver, id, vp);
+}
+
+static JSBool
 with_SetProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
 {
     return obj->getProto()->setProperty(cx, id, vp, strict);
 }
 
 static JSBool
+with_SetElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return with_SetProperty(cx, obj, id, vp, strict);
+}
+
+static JSBool
 with_GetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     return obj->getProto()->getAttributes(cx, id, attrsp);
 }
 
 static JSBool
+with_GetElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return with_GetAttributes(cx, obj, id, attrsp);
+}
+
+static JSBool
 with_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     return obj->getProto()->setAttributes(cx, id, attrsp);
 }
 
 static JSBool
+with_SetElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return with_SetAttributes(cx, obj, id, attrsp);
+}
+
+static JSBool
 with_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
 {
     return obj->getProto()->deleteProperty(cx, id, rval, strict);
 }
 
 static JSBool
+with_DeleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return with_DeleteProperty(cx, obj, id, rval, strict);
+}
+
+static JSBool
 with_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
                Value *statep, jsid *idp)
 {
     return obj->getProto()->enumerate(cx, enum_op, statep, idp);
 }
 
 static JSType
 with_TypeOf(JSContext *cx, JSObject *obj)
@@ -3334,22 +3389,29 @@ Class js::WithClass = {
     NULL,                 /* call        */
     NULL,                 /* construct   */
     NULL,                 /* xdrObject   */
     NULL,                 /* hasInstance */
     NULL,                 /* trace       */
     JS_NULL_CLASS_EXT,
     {
         with_LookupProperty,
+        with_LookupElement,
         NULL,             /* defineProperty */
+        NULL,             /* defineElement */
         with_GetProperty,
+        with_GetElement,
         with_SetProperty,
+        with_SetElement,
         with_GetAttributes,
+        with_GetElementAttributes,
         with_SetAttributes,
+        with_SetElementAttributes,
         with_DeleteProperty,
+        with_DeleteElement,
         with_Enumerate,
         with_TypeOf,
         NULL,             /* fix   */
         with_ThisObject,
         NULL,             /* clear */
     }
 };
 
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -897,73 +897,138 @@ proxy_LookupProperty(JSContext *cx, JSOb
     } else {
         *objp = NULL;
         *propp = NULL;
     }
     return true;
 }
 
 static JSBool
+proxy_LookupElement(JSContext *cx, JSObject *obj, uint32 index, JSObject **objp,
+                    JSProperty **propp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return proxy_LookupProperty(cx, obj, id, objp, propp);
+}
+
+static JSBool
 proxy_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
                      PropertyOp getter, StrictPropertyOp setter, uintN attrs)
 {
     AutoPropertyDescriptorRooter desc(cx);
     desc.obj = obj;
     desc.value = *value;
     desc.attrs = (attrs & (~JSPROP_SHORTID));
     desc.getter = getter;
     desc.setter = setter;
     desc.shortid = 0;
     return JSProxy::defineProperty(cx, obj, id, &desc);
 }
 
 static JSBool
+proxy_DefineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *value,
+                    PropertyOp getter, StrictPropertyOp setter, uintN attrs)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return proxy_DefineProperty(cx, obj, id, value, getter, setter, attrs);
+}
+
+static JSBool
 proxy_GetProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
 {
     return JSProxy::get(cx, obj, receiver, id, vp);
 }
 
 static JSBool
+proxy_GetElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32 index, Value *vp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return proxy_GetProperty(cx, obj, receiver, id, vp);
+}
+
+static JSBool
 proxy_SetProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
 {
     return JSProxy::set(cx, obj, obj, id, strict, vp);
 }
 
 static JSBool
+proxy_SetElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return proxy_SetProperty(cx, obj, id, vp, strict);
+}
+
+static JSBool
 proxy_GetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     AutoPropertyDescriptorRooter desc(cx);
     if (!JSProxy::getOwnPropertyDescriptor(cx, obj, id, false, &desc))
         return false;
     *attrsp = desc.attrs;
     return true;
 }
 
 static JSBool
+proxy_GetElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return proxy_GetAttributes(cx, obj, id, attrsp);
+}
+
+static JSBool
 proxy_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     /* Lookup the current property descriptor so we have setter/getter/value. */
     AutoPropertyDescriptorRooter desc(cx);
     if (!JSProxy::getOwnPropertyDescriptor(cx, obj, id, true, &desc))
         return false;
     desc.attrs = (*attrsp & (~JSPROP_SHORTID));
     return JSProxy::defineProperty(cx, obj, id, &desc);
 }
 
 static JSBool
+proxy_SetElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return proxy_SetAttributes(cx, obj, id, attrsp);
+}
+
+static JSBool
 proxy_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
 {
     // TODO: throwing away strict
     bool deleted;
     if (!JSProxy::delete_(cx, obj, id, &deleted) || !js_SuppressDeletedProperty(cx, obj, id))
         return false;
     rval->setBoolean(deleted);
     return true;
 }
 
+static JSBool
+proxy_DeleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return proxy_DeleteProperty(cx, obj, id, rval, strict);
+}
+
 static void
 proxy_TraceObject(JSTracer *trc, JSObject *obj)
 {
     obj->getProxyHandler()->trace(trc, obj);
     MarkCrossCompartmentValue(trc, obj->getProxyPrivate(), "private");
     MarkCrossCompartmentValue(trc, obj->getProxyExtra(), "extra");
     if (obj->isFunctionProxy()) {
         MarkCrossCompartmentValue(trc, GetCall(obj), "call");
@@ -1041,22 +1106,29 @@ JS_FRIEND_DATA(Class) js::ObjectProxyCla
     NULL,                 /* call        */
     NULL,                 /* construct   */
     NULL,                 /* xdrObject   */
     proxy_HasInstance,    /* hasInstance */
     proxy_TraceObject,    /* trace       */
     JS_NULL_CLASS_EXT,
     {
         proxy_LookupProperty,
+        proxy_LookupElement,
         proxy_DefineProperty,
+        proxy_DefineElement,
         proxy_GetProperty,
+        proxy_GetElement,
         proxy_SetProperty,
+        proxy_SetElement,
         proxy_GetAttributes,
+        proxy_GetElementAttributes,
         proxy_SetAttributes,
+        proxy_SetElementAttributes,
         proxy_DeleteProperty,
+        proxy_DeleteElement,
         NULL,             /* enumerate       */
         proxy_TypeOf,
         proxy_Fix,        /* fix             */
         NULL,             /* thisObject      */
         NULL,             /* clear           */
     }
 };
 
@@ -1081,22 +1153,29 @@ JS_FRIEND_DATA(Class) js::OuterWindowPro
     {
         NULL,             /* equality    */
         NULL,             /* outerObject */
         proxy_innerObject,
         NULL        /* unused */
     },
     {
         proxy_LookupProperty,
+        proxy_LookupElement,
         proxy_DefineProperty,
+        proxy_DefineElement,
         proxy_GetProperty,
+        proxy_GetElement,
         proxy_SetProperty,
+        proxy_SetElement,
         proxy_GetAttributes,
+        proxy_GetElementAttributes,
         proxy_SetAttributes,
+        proxy_SetElementAttributes,
         proxy_DeleteProperty,
+        proxy_DeleteElement,
         NULL,             /* enumerate       */
         NULL,             /* typeof          */
         NULL,             /* fix             */
         NULL,             /* thisObject      */
         NULL,             /* clear           */
     }
 };
 
@@ -1133,22 +1212,29 @@ JS_FRIEND_DATA(Class) js::FunctionProxyC
     proxy_Call,
     proxy_Construct,
     NULL,                 /* xdrObject   */
     FunctionClass.hasInstance,
     proxy_TraceFunction,  /* trace       */
     JS_NULL_CLASS_EXT,
     {
         proxy_LookupProperty,
+        proxy_LookupElement,
         proxy_DefineProperty,
+        proxy_DefineElement,
         proxy_GetProperty,
+        proxy_GetElement,
         proxy_SetProperty,
+        proxy_SetElement,
         proxy_GetAttributes,
+        proxy_GetElementAttributes,
         proxy_SetAttributes,
+        proxy_SetElementAttributes,
         proxy_DeleteProperty,
+        proxy_DeleteElement,
         NULL,             /* enumerate       */
         proxy_TypeOf,
         NULL,             /* fix             */
         NULL,             /* thisObject      */
         NULL,             /* clear           */
     }
 };
 
--- a/js/src/jsprvtd.h
+++ b/js/src/jsprvtd.h
@@ -323,21 +323,16 @@ typedef struct JSDebugHooks {
  * exception, true on success.  On success, return null in *propp if id was
  * not found.  If id was found, return the first object searching from obj
  * along its prototype chain in which id names a direct property in *objp, and
  * return a non-null, opaque property pointer in *propp.
  *
  * If JSLookupPropOp succeeds and returns with *propp non-null, that pointer
  * may be passed as the prop parameter to a JSAttributesOp, as a short-cut
  * that bypasses id re-lookup.
- *
- * NB: successful return with non-null *propp means the implementation may
- * have locked *objp and added a reference count associated with *propp, so
- * callers should not risk deadlock by nesting or interleaving other lookups
- * or any obj-bearing ops before dropping *propp.
  */
 typedef JSBool
 (* JSLookupPropOp)(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
                    JSProperty **propp);
 
 /*
  * Get or set attributes of the property obj[id]. Return false on error or
  * exception, true with current attributes in *attrsp.
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -60,16 +60,17 @@
 #include "jsstaticcheck.h"
 #include "jsbit.h"
 #include "jsvector.h"
 #include "jstypedarray.h"
 #include "jsutil.h"
 
 #include "vm/GlobalObject.h"
 
+#include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jstypedarrayinlines.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
@@ -272,44 +273,73 @@ ArrayBuffer::obj_lookupProperty(JSContex
         *propp = NULL;
         return true;
     }
 
     return proto->lookupProperty(cx, id, objp, propp);
 }
 
 JSBool
+ArrayBuffer::obj_lookupElement(JSContext *cx, JSObject *obj, uint32 index,
+                               JSObject **objp, JSProperty **propp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return obj_lookupProperty(cx, obj, id, objp, propp);
+}
+
+JSBool
 ArrayBuffer::obj_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v,
                    PropertyOp getter, StrictPropertyOp setter, uintN attrs)
 {
     if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom))
         return true;
 
     JSObject *delegate = DelegateObject(cx, obj);
     if (!delegate)
         return false;
     return js_DefineProperty(cx, delegate, id, v, getter, setter, attrs);
 }
 
 JSBool
+ArrayBuffer::obj_defineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *v,
+                   PropertyOp getter, StrictPropertyOp setter, uintN attrs)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return obj_defineProperty(cx, obj, id, v, getter, setter, attrs);
+}
+
+JSBool
 ArrayBuffer::obj_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
 {
     obj = getArrayBuffer(obj);
     if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) {
         vp->setInt32(obj->arrayBufferByteLength());
         return true;
     }
 
     JSObject *delegate = DelegateObject(cx, obj);
     if (!delegate)
         return false;
     return js_GetProperty(cx, delegate, receiver, id, vp);
 }
 
 JSBool
+ArrayBuffer::obj_getElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32 index, Value *vp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return obj_getProperty(cx, obj, receiver, id, vp);
+}
+
+JSBool
 ArrayBuffer::obj_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
 {
     if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom))
         return true;
 
     if (JSID_IS_ATOM(id, cx->runtime->atomState.protoAtom)) {
         // setting __proto__ = null
         // effectively removes the prototype chain.
@@ -354,59 +384,95 @@ ArrayBuffer::obj_setProperty(JSContext *
     JSObject *delegate = DelegateObject(cx, obj);
     if (!delegate)
         return false;
 
     return js_SetPropertyHelper(cx, delegate, id, 0, vp, strict);
 }
 
 JSBool
+ArrayBuffer::obj_setElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return obj_setProperty(cx, obj, id, vp, strict);
+}
+
+JSBool
 ArrayBuffer::obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) {
         *attrsp = JSPROP_PERMANENT | JSPROP_READONLY;
         return true;
     }
 
     JSObject *delegate = DelegateObject(cx, obj);
     if (!delegate)
         return false;
     return js_GetAttributes(cx, delegate, id, attrsp);
 }
 
 JSBool
+ArrayBuffer::obj_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return obj_getAttributes(cx, obj, id, attrsp);
+}
+
+JSBool
 ArrayBuffer::obj_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_CANT_SET_ARRAY_ATTRS);
         return false;
     }
 
     JSObject *delegate = DelegateObject(cx, obj);
     if (!delegate)
         return false;
     return js_SetAttributes(cx, delegate, id, attrsp);
 }
 
 JSBool
+ArrayBuffer::obj_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return obj_setAttributes(cx, obj, id, attrsp);
+}
+
+JSBool
 ArrayBuffer::obj_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
 {
     if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) {
         rval->setBoolean(false);
         return true;
     }
 
     JSObject *delegate = DelegateObject(cx, obj);
     if (!delegate)
         return false;
     return js_DeleteProperty(cx, delegate, id, rval, strict);
 }
 
 JSBool
+ArrayBuffer::obj_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return obj_deleteElement(cx, obj, index, rval, strict);
+}
+
+JSBool
 ArrayBuffer::obj_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
               Value *statep, jsid *idp)
 {
     statep->setNull();
     return true;
 }
 
 JSType
@@ -534,32 +600,60 @@ TypedArray::obj_lookupProperty(JSContext
         *propp = NULL;
         return true;
     }
 
     return proto->lookupProperty(cx, id, objp, propp);
 }
 
 JSBool
+TypedArray::obj_lookupElement(JSContext *cx, JSObject *obj, uint32 index,
+                              JSObject **objp, JSProperty **propp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return obj_lookupProperty(cx, obj, id, objp, propp);
+}
+
+JSBool
 TypedArray::obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     *attrsp = (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
               ? JSPROP_PERMANENT | JSPROP_READONLY
               : JSPROP_PERMANENT | JSPROP_ENUMERATE;
     return true;
 }
 
 JSBool
+TypedArray::obj_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return obj_getAttributes(cx, obj, id, attrsp);
+}
+
+JSBool
 TypedArray::obj_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                          JSMSG_CANT_SET_ARRAY_ATTRS);
     return false;
 }
 
+JSBool
+TypedArray::obj_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return obj_setAttributes(cx, obj, id, attrsp);
+}
+
 /* static */ int
 TypedArray::lengthOffset()
 {
     return JSObject::getFixedSlotOffset(FIELD_LENGTH) + offsetof(jsval_layout, s.payload);
 }
 
 /* static */ int
 TypedArray::dataOffset()
@@ -773,16 +867,25 @@ class TypedArrayTemplate
                 }
             }
         }
 
         return true;
     }
 
     static JSBool
+    obj_getElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32 index, Value *vp)
+    {
+        jsid id;
+        if (!IndexToId(cx, index, &id))
+            return false;
+        return obj_getProperty(cx, obj, receiver, id, vp);
+    }
+
+    static JSBool
     obj_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
     {
         JSObject *tarray = getTypedArray(obj);
         JS_ASSERT(tarray);
 
         if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
             vp->setNumber(getLength(tarray));
             return true;
@@ -850,27 +953,46 @@ class TypedArrayTemplate
             int32 n = js_DoubleToECMAInt32(d);
             setIndex(tarray, index, NativeType(n));
         }
 
         return true;
     }
 
     static JSBool
+    obj_setElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict)
+    {
+        jsid id;
+        if (!IndexToId(cx, index, &id))
+            return false;
+        return obj_setProperty(cx, obj, id, vp, strict);
+    }
+
+    static JSBool
     obj_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v,
                        PropertyOp getter, StrictPropertyOp setter, uintN attrs)
     {
         if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
             return true;
 
         Value tmp = *v;
         return obj_setProperty(cx, obj, id, &tmp, false);
     }
 
     static JSBool
+    obj_defineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *v,
+                       PropertyOp getter, StrictPropertyOp setter, uintN attrs)
+    {
+        jsid id;
+        if (!IndexToId(cx, index, &id))
+            return false;
+        return obj_defineProperty(cx, obj, id, v, getter, setter, attrs);
+    }
+
+    static JSBool
     obj_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
     {
         if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
             rval->setBoolean(false);
             return true;
         }
 
         JSObject *tarray = TypedArray::getTypedArray(obj);
@@ -881,16 +1003,25 @@ class TypedArrayTemplate
             return true;
         }
 
         rval->setBoolean(true);
         return true;
     }
 
     static JSBool
+    obj_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict)
+    {
+        jsid id;
+        if (!IndexToId(cx, index, &id))
+            return false;
+        return obj_deleteProperty(cx, obj, id, rval, strict);
+    }
+
+    static JSBool
     obj_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
                   Value *statep, jsid *idp)
     {
         JSObject *tarray = getTypedArray(obj);
         JS_ASSERT(tarray);
 
         /*
          * Iteration is "length" (if JSENUMERATE_INIT_ALL), then [0, length).
@@ -1713,22 +1844,29 @@ Class js::ArrayBufferClass = {
     NULL,           /* call        */
     NULL,           /* construct   */
     NULL,           /* xdrObject   */
     NULL,           /* hasInstance */
     ArrayBuffer::obj_trace,
     JS_NULL_CLASS_EXT,
     {
         ArrayBuffer::obj_lookupProperty,
+        ArrayBuffer::obj_lookupElement,
         ArrayBuffer::obj_defineProperty,
+        ArrayBuffer::obj_defineElement,
         ArrayBuffer::obj_getProperty,
+        ArrayBuffer::obj_getElement,
         ArrayBuffer::obj_setProperty,
+        ArrayBuffer::obj_setElement,
         ArrayBuffer::obj_getAttributes,
+        ArrayBuffer::obj_getElementAttributes,
         ArrayBuffer::obj_setAttributes,
+        ArrayBuffer::obj_setElementAttributes,
         ArrayBuffer::obj_deleteProperty,
+        ArrayBuffer::obj_deleteElement,
         ArrayBuffer::obj_enumerate,
         ArrayBuffer::obj_typeOf,
         NULL,       /* thisObject      */
         NULL,       /* clear           */
     }
 };
 
 JSPropertySpec ArrayBuffer::jsprops[] = {
@@ -1804,22 +1942,29 @@ JSFunctionSpec _typedArray::jsfuncs[] = 
     NULL,           /* call        */                                          \
     NULL,           /* construct   */                                          \
     NULL,           /* xdrObject   */                                          \
     NULL,           /* hasInstance */                                          \
     _typedArray::obj_trace,           /* trace       */                                          \
     JS_NULL_CLASS_EXT,                                                         \
     {                                                                          \
         _typedArray::obj_lookupProperty,                                       \
+        _typedArray::obj_lookupElement,                                        \
         _typedArray::obj_defineProperty,                                       \
+        _typedArray::obj_defineElement,                                        \
         _typedArray::obj_getProperty,                                          \
+        _typedArray::obj_getElement,                                           \
         _typedArray::obj_setProperty,                                          \
+        _typedArray::obj_setElement,                                           \
         _typedArray::obj_getAttributes,                                        \
+        _typedArray::obj_getElementAttributes,                                 \
         _typedArray::obj_setAttributes,                                        \
+        _typedArray::obj_setElementAttributes,                                 \
         _typedArray::obj_deleteProperty,                                       \
+        _typedArray::obj_deleteElement,                                        \
         _typedArray::obj_enumerate,                                            \
         _typedArray::obj_typeOf,                                               \
         NULL,       /* thisObject      */                                      \
         NULL,       /* clear           */                                      \
     }                                                                          \
 }
 
 template<class ArrayType>
--- a/js/src/jstypedarray.h
+++ b/js/src/jstypedarray.h
@@ -74,35 +74,58 @@ struct JS_FRIEND_API(ArrayBuffer) {
     static void
     obj_trace(JSTracer *trc, JSObject *obj);
 
     static JSBool
     obj_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
                        JSObject **objp, JSProperty **propp);
 
     static JSBool
+    obj_lookupElement(JSContext *cx, JSObject *obj, uint32 index,
+                      JSObject **objp, JSProperty **propp);
+
+    static JSBool
     obj_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v,
                        PropertyOp getter, StrictPropertyOp setter, uintN attrs);
 
     static JSBool
+    obj_defineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *v,
+                      PropertyOp getter, StrictPropertyOp setter, uintN attrs);
+
+    static JSBool
     obj_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp);
 
     static JSBool
+    obj_getElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32 index, Value *vp);
+
+    static JSBool
     obj_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict);
 
     static JSBool
+    obj_setElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict);
+
+    static JSBool
     obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
 
     static JSBool
+    obj_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp);
+
+    static JSBool
     obj_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
 
     static JSBool
+    obj_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp);
+
+    static JSBool
     obj_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict);
 
     static JSBool
+    obj_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict);
+
+    static JSBool
     obj_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
                   Value *statep, jsid *idp);
 
     static JSType
     obj_typeOf(JSContext *cx, JSObject *obj);
 
     static JSObject *
     getArrayBuffer(JSObject *obj);
@@ -159,20 +182,24 @@ struct JS_FRIEND_API(TypedArray) {
 
     static JSBool prop_getBuffer(JSContext *cx, JSObject *obj, jsid id, Value *vp);
     static JSBool prop_getByteOffset(JSContext *cx, JSObject *obj, jsid id, Value *vp);
     static JSBool prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp);
     static JSBool prop_getLength(JSContext *cx, JSObject *obj, jsid id, Value *vp);
 
     static JSBool obj_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
                                      JSObject **objp, JSProperty **propp);
+    static JSBool obj_lookupElement(JSContext *cx, JSObject *obj, uint32 index,
+                                    JSObject **objp, JSProperty **propp);
 
     static JSBool obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
+    static JSBool obj_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp);
 
     static JSBool obj_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
+    static JSBool obj_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp);
 
     static JSUint32 getLength(JSObject *obj);
     static JSUint32 getByteOffset(JSObject *obj);
     static JSUint32 getByteLength(JSObject *obj);
     static JSUint32 getType(JSObject *obj);
     static JSObject * getBuffer(JSObject *obj);
     static void * getDataOffset(JSObject *obj);
 
--- a/js/src/jsvalue.h
+++ b/js/src/jsvalue.h
@@ -944,28 +944,42 @@ typedef JSBool
 (* CheckAccessOp)(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
                   Value *vp);
 typedef JSBool
 (* EqualityOp)(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp);
 typedef JSBool
 (* DefinePropOp)(JSContext *cx, JSObject *obj, jsid id, const Value *value,
                  PropertyOp getter, StrictPropertyOp setter, uintN attrs);
 typedef JSBool
+(* DefineElementOp)(JSContext *cx, JSObject *obj, uint32 index, const Value *value,
+                    PropertyOp getter, StrictPropertyOp setter, uintN attrs);
+typedef JSBool
 (* PropertyIdOp)(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp);
 typedef JSBool
+(* ElementIdOp)(JSContext *cx, JSObject *obj, JSObject *receiver, uint32 index, Value *vp);
+typedef JSBool
 (* StrictPropertyIdOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict);
 typedef JSBool
+(* StrictElementIdOp)(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict);
+typedef JSBool
 (* DeleteIdOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict);
 typedef JSBool
+(* DeleteElementOp)(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict);
+typedef JSBool
 (* CallOp)(JSContext *cx, uintN argc, Value *vp);
 typedef JSBool
 (* LookupPropOp)(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
                  JSProperty **propp);
 typedef JSBool
+(* LookupElementOp)(JSContext *cx, JSObject *obj, uint32 index, JSObject **objp,
+                    JSProperty **propp);
+typedef JSBool
 (* AttributesOp)(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
+typedef JSBool
+(* ElementAttributesOp)(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp);
 typedef JSType
 (* TypeOfOp)(JSContext *cx, JSObject *obj);
 typedef JSObject *
 (* ObjectOp)(JSContext *cx, JSObject *obj);
 typedef void
 (* FinalizeOp)(JSContext *cx, JSObject *obj);
 
 class AutoIdVector;
@@ -1053,30 +1067,40 @@ struct ClassExtension {
      */
     bool                isWrappedNative;
 };
 
 #define JS_NULL_CLASS_EXT   {NULL,NULL,NULL,NULL,NULL,false}
 
 struct ObjectOps {
     js::LookupPropOp        lookupProperty;
+    js::LookupElementOp     lookupElement;
     js::DefinePropOp        defineProperty;
+    js::DefineElementOp     defineElement;
     js::PropertyIdOp        getProperty;
+    js::ElementIdOp         getElement;
     js::StrictPropertyIdOp  setProperty;
+    js::StrictElementIdOp   setElement;
     js::AttributesOp        getAttributes;
+    js::ElementAttributesOp getElementAttributes;
     js::AttributesOp        setAttributes;
+    js::ElementAttributesOp setElementAttributes;
     js::DeleteIdOp          deleteProperty;
+    js::DeleteElementOp     deleteElement;
+
     js::NewEnumerateOp      enumerate;
     js::TypeOfOp            typeOf;
     js::FixOp               fix;
     js::ObjectOp            thisObject;
     js::FinalizeOp          clear;
 };
 
-#define JS_NULL_OBJECT_OPS  {NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL}
+#define JS_NULL_OBJECT_OPS                                                    \
+    {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,   \
+     NULL,NULL,NULL,NULL,NULL}
 
 struct Class {
     JS_CLASS_MEMBERS;
     ClassExtension      ext;
     ObjectOps           ops;
     uint8               pad[sizeof(JSClass) - sizeof(ClassSizeMeasurement) -
                             sizeof(ClassExtension) - sizeof(ObjectOps)];
 
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -4729,73 +4729,129 @@ xml_lookupProperty(JSContext *cx, JSObje
 
         *objp = obj;
         *propp = (JSProperty *) shape;
     }
     return JS_TRUE;
 }
 
 static JSBool
+xml_lookupElement(JSContext *cx, JSObject *obj, uint32 index, JSObject **objp,
+                  JSProperty **propp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return xml_lookupProperty(cx, obj, id, objp, propp);
+}
+
+static JSBool
 xml_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v,
                    PropertyOp getter, StrictPropertyOp setter, uintN attrs)
 {
     if (IsFunctionObject(*v) || getter || setter ||
         (attrs & JSPROP_ENUMERATE) == 0 ||
         (attrs & (JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED))) {
         return js_DefineProperty(cx, obj, id, v, getter, setter, attrs);
     }
 
     jsval tmp = Jsvalify(*v);
     return PutProperty(cx, obj, id, false, &tmp);
 }
 
 static JSBool
+xml_defineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *v,
+                  PropertyOp getter, StrictPropertyOp setter, uintN attrs)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return xml_defineProperty(cx, obj, id, v, getter, setter, attrs);
+}
+
+static JSBool
 xml_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
 {
     if (JSID_IS_DEFAULT_XML_NAMESPACE(id)) {
         vp->setUndefined();
         return JS_TRUE;
     }
 
     return GetProperty(cx, obj, id, Jsvalify(vp));
 }
 
 static JSBool
+xml_getElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32 index, Value *vp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return xml_getProperty(cx, obj, receiver, id, vp);
+}
+
+static JSBool
 xml_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
 {
     return PutProperty(cx, obj, id, strict, Jsvalify(vp));
 }
 
 static JSBool
+xml_setElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return xml_setProperty(cx, obj, id, vp, strict);
+}
+
+static JSBool
 xml_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     JSBool found;
     if (!HasProperty(cx, obj, IdToJsval(id), &found))
         return false;
 
     *attrsp = found ? JSPROP_ENUMERATE : 0;
     return JS_TRUE;
 }
 
 static JSBool
+xml_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return xml_getAttributes(cx, obj, id, attrsp);
+}
+
+static JSBool
 xml_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     JSBool found;
     if (!HasProperty(cx, obj, IdToJsval(id), &found))
         return false;
 
     if (found) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_CANT_SET_XML_ATTRS);
         return false;
     }
     return true;
 }
 
 static JSBool
+xml_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return xml_setAttributes(cx, obj, id, attrsp);
+}
+
+static JSBool
 xml_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
 {
     JSXML *xml;
     jsval idval;
     uint32 index;
     JSObject *nameqn;
     jsid funid;
 
@@ -4830,16 +4886,25 @@ xml_deleteProperty(JSContext *cx, JSObje
      */
     if (!obj->nativeEmpty() && !js_DeleteProperty(cx, obj, id, rval, false))
         return false;
 
     rval->setBoolean(true);
     return true;
 }
 
+static JSBool
+xml_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return xml_deleteProperty(cx, obj, id, rval, strict);
+}
+
 static JSString *
 xml_toString_helper(JSContext *cx, JSXML *xml);
 
 JSBool
 xml_convert(JSContext *cx, JSObject *obj, JSType hint, Value *rval)
 {
     JS_ASSERT(hint == JSTYPE_NUMBER || hint == JSTYPE_STRING || hint == JSTYPE_VOID);
     JS_ASSERT(obj->isXML());
@@ -5129,22 +5194,29 @@ JS_FRIEND_DATA(Class) js::XMLClass = {
     NULL,                 /* call        */
     NULL,                 /* construct   */
     NULL,                 /* xdrObject   */
     xml_hasInstance,
     xml_trace,
     JS_NULL_CLASS_EXT,
     {
         xml_lookupProperty,
+        xml_lookupElement,
         xml_defineProperty,
+        xml_defineElement,
         xml_getProperty,
+        xml_getElement,
         xml_setProperty,
+        xml_setElement,
         xml_getAttributes,
+        xml_getElementAttributes,
         xml_setAttributes,
+        xml_setElementAttributes,
         xml_deleteProperty,
+        xml_deleteElement,
         xml_enumerate,
         xml_typeOf,
         xml_fix,
         NULL,       /* thisObject     */
         xml_clear
     }
 };
 
--- a/js/src/xpconnect/src/xpcprivate.h
+++ b/js/src/xpconnect/src/xpcprivate.h
@@ -1384,38 +1384,52 @@ XPC_WN_JSOp_Clear(JSContext *cx, JSObjec
 
 extern JSObject*
 XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj);
 
 // Macros to initialize Object or Function like XPC_WN classes
 #define XPC_WN_WithCall_ObjectOps                                             \
     {                                                                         \
         nsnull, /* lookupProperty */                                          \
+        nsnull, /* lookupElement */                                           \
         nsnull, /* defineProperty */                                          \
+        nsnull, /* defineElement */                                           \
         nsnull, /* getProperty    */                                          \
+        nsnull, /* getElement    */                                           \
         nsnull, /* setProperty    */                                          \
+        nsnull, /* setElement    */                                           \
         nsnull, /* getAttributes  */                                          \
+        nsnull, /* getElementAttributes  */                                   \
         nsnull, /* setAttributes  */                                          \
+        nsnull, /* setElementAttributes  */                                   \
         nsnull, /* deleteProperty */                                          \
+        nsnull, /* deleteElement */                                           \
         js::Valueify(XPC_WN_JSOp_Enumerate),                                  \
         XPC_WN_JSOp_TypeOf_Function,                                          \
         nsnull, /* fix            */                                          \
         XPC_WN_JSOp_ThisObject,                                               \
         XPC_WN_JSOp_Clear                                                     \
     }
 
 #define XPC_WN_NoCall_ObjectOps                                               \
     {                                                                         \
         nsnull, /* lookupProperty */                                          \
+        nsnull, /* lookupElement */                                           \
         nsnull, /* defineProperty */                                          \
+        nsnull, /* defineElement */                                           \
         nsnull, /* getProperty    */                                          \
+        nsnull, /* getElement    */                                           \
         nsnull, /* setProperty    */                                          \
+        nsnull, /* setElement    */                                           \
         nsnull, /* getAttributes  */                                          \
+        nsnull, /* getElementAttributes  */                                   \
         nsnull, /* setAttributes  */                                          \
+        nsnull, /* setElementAttributes  */                                   \
         nsnull, /* deleteProperty */                                          \
+        nsnull, /* deleteElement */                                           \
         js::Valueify(XPC_WN_JSOp_Enumerate),                                  \
         XPC_WN_JSOp_TypeOf_Object,                                            \
         nsnull, /* fix            */                                          \
         XPC_WN_JSOp_ThisObject,                                               \
         XPC_WN_JSOp_Clear                                                     \
     }
 
 // Maybe this macro should check for class->enumerate ==
--- a/js/src/xpconnect/src/xpcwrappednativejsops.cpp
+++ b/js/src/xpconnect/src/xpcwrappednativejsops.cpp
@@ -902,22 +902,29 @@ js::Class XPC_WN_NoHelper_JSClass = {
         nsnull, // iteratorObject
         nsnull, // unused
         true,   // isWrappedNative
     },
    
     // ObjectOps
     {
         nsnull, // lookupProperty
+        nsnull, // lookupElement
         nsnull, // defineProperty
+        nsnull, // defineElement
         nsnull, // getProperty
+        nsnull, // getElement
         nsnull, // setProperty
+        nsnull, // setElement
         nsnull, // getAttributes
+        nsnull, // getElementAttributes
         nsnull, // setAttributes
+        nsnull, // setElementAttributes
         nsnull, // deleteProperty
+        nsnull, // deleteElement
         JS_VALUEIFY(js::NewEnumerateOp, XPC_WN_JSOp_Enumerate),
         XPC_WN_JSOp_TypeOf_Object,
         nsnull, // fix
         XPC_WN_JSOp_ThisObject,
         XPC_WN_JSOp_Clear
     }
 };