Bug 792215 part 2. Convert old proxy bindings to JSNative getters and setters. r=peterv,ejpbruel
authorKannan Vijayan <kvijayan@mozilla.com>
Tue, 25 Sep 2012 14:44:40 -0400
changeset 108042 ceec86729302ed1145322bf25f3a12c9cabbe5b4
parent 108041 21efec008d919c74a3edbf13478692a7276c6866
child 108043 5337b1d6fcb9846cf2c2562b5bc2a7ab5792e80f
push id15344
push userbzbarsky@mozilla.com
push dateTue, 25 Sep 2012 18:44:54 +0000
treeherdermozilla-inbound@ceec86729302 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv, ejpbruel
bugs792215
milestone18.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 792215 part 2. Convert old proxy bindings to JSNative getters and setters. r=peterv,ejpbruel
dom/imptests/failures/webapps/DOMCore/tests/approved/test_interfaces.html.json
js/src/jsobj.cpp
js/xpconnect/src/codegen.py
js/xpconnect/src/dombindings.cpp
js/xpconnect/src/dombindings.h
js/xpconnect/src/dombindingsgen.py
--- a/dom/imptests/failures/webapps/DOMCore/tests/approved/test_interfaces.html.json
+++ b/dom/imptests/failures/webapps/DOMCore/tests/approved/test_interfaces.html.json
@@ -434,32 +434,28 @@
   "NodeFilter interface: constant SHOW_COMMENT on interface prototype object": true,
   "NodeFilter interface: constant SHOW_DOCUMENT on interface prototype object": true,
   "NodeFilter interface: constant SHOW_DOCUMENT_TYPE on interface prototype object": true,
   "NodeFilter interface: constant SHOW_DOCUMENT_FRAGMENT on interface prototype object": true,
   "NodeFilter interface: constant SHOW_NOTATION on interface prototype object": true,
   "NodeFilter interface: operation acceptNode(Node)": true,
   "NodeList interface: existence and properties of interface object": true,
   "NodeList interface: existence and properties of interface prototype object": true,
-  "NodeList interface: attribute length": true,
   "NodeList interface: calling item(unsigned long) on document.querySelectorAll(\"script\") with too few arguments must throw TypeError": true,
   "HTMLCollection interface: existence and properties of interface object": true,
   "HTMLCollection interface: existence and properties of interface prototype object": true,
-  "HTMLCollection interface: attribute length": true,
   "HTMLCollection interface: calling item(unsigned long) on document.body.children with too few arguments must throw TypeError": true,
   "HTMLCollection interface: calling namedItem(DOMString) on document.body.children with too few arguments must throw TypeError": true,
   "DOMStringList interface: existence and properties of interface object": true,
   "DOMStringList interface: existence and properties of interface prototype object": true,
   "DOMStringList interface: existence and properties of interface prototype object's \"constructor\" property": true,
   "DOMStringList interface: attribute length": true,
   "DOMTokenList interface: existence and properties of interface object": true,
   "DOMTokenList interface: existence and properties of interface prototype object": true,
-  "DOMTokenList interface: attribute length": true,
   "Stringification of document.body.classList": true,
   "DOMTokenList interface: calling item(unsigned long) on document.body.classList with too few arguments must throw TypeError": true,
   "DOMTokenList interface: calling contains(DOMString) on document.body.classList with too few arguments must throw TypeError": true,
   "DOMTokenList interface: calling add(DOMString) on document.body.classList with too few arguments must throw TypeError": true,
   "DOMTokenList interface: calling remove(DOMString) on document.body.classList with too few arguments must throw TypeError": true,
   "DOMTokenList interface: calling toggle(DOMString) on document.body.classList with too few arguments must throw TypeError": true,
   "DOMSettableTokenList interface: existence and properties of interface object": true,
-  "DOMSettableTokenList interface: existence and properties of interface prototype object": true,
-  "DOMSettableTokenList interface: attribute value": true
+  "DOMSettableTokenList interface: existence and properties of interface prototype object": true
 }
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -820,17 +820,16 @@ NewPropertyDescriptorObject(JSContext *c
 }
 
 void
 PropDesc::initFromPropertyDescriptor(const PropertyDescriptor &desc)
 {
     isUndefined_ = false;
     pd_.setUndefined();
     attrs = uint8_t(desc.attrs);
-    JS_ASSERT_IF(attrs & JSPROP_READONLY, !(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
     if (desc.attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
         hasGet_ = true;
         get_ = ((desc.attrs & JSPROP_GETTER) && desc.getter)
                ? CastAsObjectJsval(desc.getter)
                : UndefinedValue();
         hasSet_ = true;
         set_ = ((desc.attrs & JSPROP_SETTER) && desc.setter)
                ? CastAsObjectJsval(desc.setter)
--- a/js/xpconnect/src/codegen.py
+++ b/js/xpconnect/src/codegen.py
@@ -173,18 +173,18 @@ def writeArgumentUnboxing(f, i, name, ty
     # optional - bool - True if the parameter is optional.
     # rvdeclared - bool - False if no |nsresult rv| has been declared earlier.
 
     typeName = xpidl.getBuiltinOrNativeTypeName(type)
 
     isSetter = (i is None)
 
     if isSetter:
-        argPtr = "vp"
-        argVal = "*vp"
+        argPtr = "argv"
+        argVal = "*argv"
     elif optional:
         if typeName == "[jsval]":
             val = "JSVAL_VOID"
         else:
             val = "JSVAL_NULL"
         argVal = "(%d < argc ? argv[%d] : %s)" % (i, i, val)
         argPtr = "(%d < argc ? &argv[%d] : NULL)" % (i, i)
     else:
@@ -424,26 +424,18 @@ def writeStub(f, customMethodCalls, memb
         member = member.iface.namemap[member.forward]
 
     isAttr = (member.kind == 'attribute')
     isMethod = (member.kind == 'method')
     assert isAttr or isMethod
     isNotxpcom = isMethod and member.notxpcom
     isGetter = isAttr and not isSetter
 
-    signature = "static JSBool\n"
-    if isAttr:
-        # JSPropertyOp signature.
-        if isSetter:
-            signature += "%s(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict,%s JSMutableHandleValue vp_)\n"
-        else:
-            signature += "%s(JSContext *cx, JSHandleObject obj, JSHandleId id,%s JSMutableHandleValue vp_)\n"
-    else:
-        # JSFastNative.
-        signature += "%s(JSContext *cx, unsigned argc,%s jsval *vp)\n"
+    signature = ("static JSBool\n"
+                 "%s(JSContext *cx, unsigned argc,%s jsval *vp)\n")
 
     customMethodCall = customMethodCalls.get(stubName, None)
 
     if customMethodCall is None:
         customMethodCall = customMethodCalls.get(member.iface.name + '_', None)
         if customMethodCall is not None:
             if isMethod:
                 code = customMethodCall.get('code', None)
@@ -465,17 +457,17 @@ def writeStub(f, customMethodCalls, memb
             # that's shared between the stubs. The stubs can't have additional
             # arguments, only the template function can.
             callTemplate = signature % (stubName, '')
             callTemplate += "{\n"
 
             argumentValues = (customMethodCall['additionalArgumentValues']
                               % header.methodNativeName(member))
             if isAttr:
-                callTemplate += ("    return %s(cx, obj, id%s, %s, vp_);\n"
+                callTemplate += ("    return %s(cx, obj, id%s, %s, vp);\n"
                                  % (templateName, ", strict" if isSetter else "", argumentValues))
             else:
                 callTemplate += ("    return %s(cx, argc, %s, vp);\n"
                                  % (templateName, argumentValues))
             callTemplate += "}\n\n"
 
             # Fall through and create the template function stub called from the
             # real stubs, but only generate the stub once. Otherwise, just write
@@ -499,43 +491,44 @@ def writeStub(f, customMethodCalls, memb
     if customMethodCall is None or not 'additionalArguments' in customMethodCall:
         additionalArguments = ''
     else:
         additionalArguments = " %s," % customMethodCall['additionalArguments']
     f.write(signature % (stubName, additionalArguments))
     f.write("{\n")
     f.write("    XPC_QS_ASSERT_CONTEXT_OK(cx);\n")
 
-    # Convert JSMutableHandleValue to jsval*
-    if isAttr:
-        f.write("    jsval *vp = vp_.address();\n")
-
-    # For methods, compute "this".
-    if isMethod:
-        f.write("    JSObject *obj = JS_THIS_OBJECT(cx, vp);\n"
-                "    if (!obj)\n"
-                "        return JS_FALSE;\n")
+    # Compute "this".
+    f.write("    JSObject *obj = JS_THIS_OBJECT(cx, vp);\n"
+            "    if (!obj)\n"
+            "        return JS_FALSE;\n")
 
     selfname = writeThisUnwrapping(f, member, isMethod, isGetter, customMethodCall)
 
     rvdeclared = False
     if isMethod:
         inArgs = argumentsLength(member)
         # If there are any required arguments, check argc.
         requiredArgs = inArgs
         while requiredArgs and member.params[requiredArgs-1].optional:
             requiredArgs -= 1
-        if requiredArgs:
-            f.write("    if (argc < %d)\n" % requiredArgs)
-            f.write("        return xpc_qsThrow(cx, "
-                    "NS_ERROR_XPC_NOT_ENOUGH_ARGS);\n")
+    elif isSetter:
+        inArgs = requiredArgs = 1
+    else:
+        inArgs = requiredArgs = 0
 
-        # Convert in-parameters.
-        if inArgs > 0:
-            f.write("    jsval *argv = JS_ARGV(cx, vp);\n")
+    if requiredArgs:
+        f.write("    if (argc < %d)\n" % requiredArgs)
+        f.write("        return xpc_qsThrow(cx, "
+                "NS_ERROR_XPC_NOT_ENOUGH_ARGS);\n")
+
+    # Convert in-parameters.
+    if inArgs > 0:
+        f.write("    jsval *argv = JS_ARGV(cx, vp);\n")
+    if isMethod:
         for i in range(inArgs):
             param = member.params[i]
             argName = 'arg%d' % i
             argTypeKey = argName + 'Type'
             if customMethodCall is None or not argTypeKey in customMethodCall:
                 validateParam(member, param)
                 realtype = param.realtype
             else:
@@ -627,16 +620,17 @@ def writeStub(f, customMethodCalls, memb
     if canFail:
         # Check for errors.
         writeCheckForFailure(f, isMethod, isGetter)
 
     # Convert the return value.
     if isMethod or isGetter:
         writeResultWrapping(f, member, 'vp', '*vp')
     else:
-        f.write("    return JS_TRUE;\n")
+        f.write("    JS_SET_RVAL(cx, vp, JS::UndefinedValue());\n"
+                "    return JS_TRUE;\n")
 
     # Epilog.
     f.write("}\n\n")
 
     # Now write out the call to the template function.
     if customMethodCall is not None:
         f.write(callTemplate)
--- a/js/xpconnect/src/dombindings.cpp
+++ b/js/xpconnect/src/dombindings.cpp
@@ -205,24 +205,27 @@ ListBase<LC>::instanceIsListObject(JSCon
         JS_ReportError(cx, "type error: wrong object");
         return false;
     }
     return true;
 }
 
 template<class LC>
 JSBool
-ListBase<LC>::length_getter(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp)
+ListBase<LC>::length_getter(JSContext *cx, unsigned argc, JS::Value *vp)
 {
+    JSObject *obj = JS_THIS_OBJECT(cx, vp);
+    if (!obj)
+        return false;
     if (!instanceIsListObject(cx, obj, NULL))
         return false;
     uint32_t length;
     getListObject(obj)->GetLength(&length);
     MOZ_ASSERT(int32_t(length) >= 0);
-    vp.set(UINT_TO_JSVAL(length));
+    JS_SET_RVAL(cx, vp, UINT_TO_JSVAL(length));
     return true;
 }
 
 template<class LC>
 bool
 ListBase<LC>::getItemAt(ListType *list, uint32_t i, IndexGetterType &item)
 {
     JS_STATIC_ASSERT(!hasIndexGetter);
@@ -356,22 +359,26 @@ ListBase<LC>::getPrototype(JSContext *cx
     JSObject *global = scope->GetGlobalJSObject();
     interfacePrototype = JS_NewObject(cx, Jsvalify(&sInterfacePrototypeClass), proto, global);
     if (!interfacePrototype)
         return NULL;
 
     for (size_t n = 0; n < sProtoPropertiesCount; ++n) {
         MOZ_ASSERT(sProtoProperties[n].getter);
         jsid id = sProtoProperties[n].id;
-        unsigned attrs = JSPROP_ENUMERATE | JSPROP_SHARED;
+        unsigned attrs = JSPROP_ENUMERATE | JSPROP_SHARED | JSPROP_NATIVE_ACCESSORS;
         if (!sProtoProperties[n].setter)
             attrs |= JSPROP_READONLY;
         if (!JS_DefinePropertyById(cx, interfacePrototype, id, JSVAL_VOID,
-                                   sProtoProperties[n].getter, sProtoProperties[n].setter, attrs))
+                                   (JSPropertyOp) sProtoProperties[n].getter,
+                                   (JSStrictPropertyOp) sProtoProperties[n].setter,
+                                   attrs))
+        {
             return NULL;
+        }
     }
 
     for (size_t n = 0; n < sProtoMethodsCount; ++n) {
         jsid id = sProtoMethods[n].id;
         JSFunction *fun = JS_NewFunctionById(cx, sProtoMethods[n].native, sProtoMethods[n].nargs,
                                              0, js::GetObjectParent(interfacePrototype), id);
         if (!fun)
             return NULL;
@@ -758,22 +765,22 @@ ListBase<LC>::has(JSContext *cx, JSObjec
 template<class LC>
 bool
 ListBase<LC>::resolveNativeName(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc)
 {
     MOZ_ASSERT(xpc::WrapperFactory::IsXrayWrapper(proxy));
 
     for (size_t n = 0; n < sProtoPropertiesCount; ++n) {
         if (id == sProtoProperties[n].id) {
-            desc->attrs = JSPROP_ENUMERATE | JSPROP_SHARED;
+            desc->attrs = JSPROP_ENUMERATE | JSPROP_SHARED | JSPROP_NATIVE_ACCESSORS;
             if (!sProtoProperties[n].setter)
                 desc->attrs |= JSPROP_READONLY;
             desc->obj = proxy;
-            desc->setter = sProtoProperties[n].setter;
-            desc->getter = sProtoProperties[n].getter;
+            desc->setter = (JSStrictPropertyOp) sProtoProperties[n].setter;
+            desc->getter = (JSPropertyOp) sProtoProperties[n].getter;
             return true;
         }
     }
 
     for (size_t n = 0; n < sProtoMethodsCount; ++n) {
         if (id == sProtoMethods[n].id) {
             JSFunction *fun = JS_NewFunctionById(cx, sProtoMethods[n].native,
                                                  sProtoMethods[n].nargs, 0, proxy, id);
--- a/js/xpconnect/src/dombindings.h
+++ b/js/xpconnect/src/dombindings.h
@@ -112,33 +112,33 @@ private:
     friend void Register(nsScriptNameSpaceManager* aNameSpaceManager);
 
     static ListBase<LC> instance;
 
     static js::Class sInterfaceClass;
 
     struct Properties {
         jsid &id;
-        JSPropertyOp getter;
-        JSStrictPropertyOp setter;
+        JSNative getter;
+        JSNative setter;
     };
     struct Methods {
         jsid &id;
         JSNative native;
         unsigned nargs;
     };
 
     static Properties sProtoProperties[];
     static size_t sProtoPropertiesCount;
     static Methods sProtoMethods[];
     static size_t sProtoMethodsCount;
 
     static JSObject *ensureExpandoObject(JSContext *cx, JSObject *obj);
 
-    static JSBool length_getter(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp);
+    static JSBool length_getter(JSContext *cx, unsigned argc, JS::Value *vp);
 
     static inline bool getItemAt(ListType *list, uint32_t i, IndexGetterType &item);
     static inline bool setItemAt(JSContext *cx, ListType *list, uint32_t i, IndexSetterType item);
 
     static inline bool namedItem(JSContext *cx, JSObject *obj, jsval *name, NameGetterType &result,
                                  bool *hasResult);
 
     static inline bool getNamedItem(ListType *list, const nsAString& aName, NameGetterType &item);
--- a/js/xpconnect/src/dombindingsgen.py
+++ b/js/xpconnect/src/dombindingsgen.py
@@ -594,17 +594,17 @@ def writeBindingStub(f, classname, membe
         writeResultConv(f, member.realtype, template, jsvalPtr, jsvalRef)
 
     writeStub(f, {}, member, stubName, writeThisUnwrapping, writeCheckForFailure, writeResultWrapping, isSetter)
 
 def writeAttrStubs(f, classname, attr):
     getterName = classname + '_' + header.attributeNativeName(attr, True)
     writeBindingStub(f, classname, attr, getterName)
     if attr.readonly:
-        setterName = 'xpc_qsGetterOnlyPropertyStub'
+        setterName = 'xpc_qsGetterOnlyNativeStub'
     else:
         setterName = (classname + '_'
                       + header.attributeNativeName(attr, False))
         writeBindingStub(f, classname, attr, setterName, isSetter=True)
 
     return "    { s_%s_id, %s, %s }" % (attr.name, getterName, setterName)
 
 def writeMethodStub(f, classname, method):