Clean up wrapping a tad and hook up the proto object creation to the interface.hasInterfaceObject stuff
authorBoris Zbarsky <bzbarsky@mit.edu>
Tue, 21 Feb 2012 16:07:51 -0500
changeset 87319 8d6b7cd7baeece56b10a2085ae26e282579fba22
parent 87318 5dff147e65338c9343d379e86aeff70495c844c8
child 87463 7e6c70d95373cd3de8cba3095b2b227f9806810b
push id131
push userbzbarsky@mozilla.com
push dateTue, 21 Feb 2012 21:08:00 +0000
milestone13.0a1
Clean up wrapping a tad and hook up the proto object creation to the interface.hasInterfaceObject stuff
dom/bindings/Codegen.py
dom/bindings/Utils.cpp
dom/bindings/Utils.h
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -473,18 +473,17 @@ class CGCreateProtoObjectMethod(CGAbstra
             getParentProto = "JS_GetObjectPrototype(aCx, aGlobal)"
         else:
             parentProtoName = self.descriptor.prototypeChain[-2]
             getParentProto = "%s::GetProtoObject(aCx, aGlobal)" % (parentProtoName)
 
         defineMethods = MethodDefiner(self.descriptor)
         defineAttributes = AttrDefiner(self.descriptor);
 
-        # XXXbz this should be False if we're [NoInterfaceObject]
-        needInterfaceObject = True
+        needInterfaceObject = self.descriptor.interface.hasInterfaceObject
 
         return """
   JSObject* parentProto = %s;
   if (!parentProto) {
     return NULL;
   }
 
 %s
@@ -798,36 +797,30 @@ def getWrapTemplateForTypeImpl(type, res
     if type.isInterface() and not type.isArrayBuffer():
         descriptor = descriptorProvider.getDescriptor(type.inner.identifier.name)
         wrappingCode = ("""
   if (!%s) {
     ${jsvalRef} = JSVAL_NULL;
     return true;
   }""" % result) if type.nullable() else ""
         if descriptor.concrete:
-            # All our concrete objects inherit from wrapper cache for now
             wrappingCode += """
   if (WrapNewBindingObject(cx, obj, %s, ${jsvalPtr})) {
     return true;
-  }
-  if (JS_IsExceptionPending(cx)) {
-    return false;
   }""" % result
-            if not descriptor.workers:
+            if descriptor.workers:
+                # Worker bindings can only fail to wrap as a new-binding object
+                # if they already threw an exception
+                wrappingCode += """
+  MOZ_ASSERT(JS_IsExceptionPending(cx));
+  return false;"""
+            else:
                 # Try old-style wrapping for non-worker bindings
                 wrappingCode += """
-  if (WrapOtherObject(cx, obj, %s, ${jsvalPtr})) {
-    return true;
-  }
-  if (JS_IsExceptionPending(cx)) {
-    return false;
-  }""" % result
-            wrappingCode += """
-  return ThrowMethodFailedWithDetails(cx, NS_ERROR_XPC_BAD_CONVERT_JS,
-                                      "${interfaceName}", "${methodName}");"""
+  return HandleNewBindingWrappingFailure(cx, obj, %s, ${jsvalPtr});""" % result
         else:
             raise TypeError("Don't know how to wrap non-concrete types yet")
         return wrappingCode
 
     if type.isString():
         if type.nullable():
             return """
   return xpc::StringToJsval(cx, %s, ${jsvalPtr});""" % result
@@ -1036,20 +1029,17 @@ class PerSignatureCall(CGThing):
         assert(False) # Override me
     def getErrorReport(self):
         assert(False) # Override me
 
     def isFallible(self):
         return not 'infallible' in self.extendedAttributes
 
     def wrap_return_value(self):
-        resultTemplateValues = {'jsvalRef': '*vp', 'jsvalPtr': 'vp',
-                                'interfaceName': \
-                                    self.descriptor.interface.identifier.name,
-                                'methodName': self.idlNode.identifier.name }
+        resultTemplateValues = {'jsvalRef': '*vp', 'jsvalPtr': 'vp'}
         return string.Template(
             getWrapTemplateForType(self.returnType, self.descriptor,
                                    self.resultAlreadyAddRefed)
             ).substitute(resultTemplateValues)
 
     def getErrorReport(self):
         return 'return ThrowMethodFailedWithDetails(cx, rv, "%s", "%s");'\
                % (self.descriptor.interface.identifier.name,
--- a/dom/bindings/Utils.cpp
+++ b/dom/bindings/Utils.cpp
@@ -55,12 +55,40 @@ CreateProtoObject(JSContext *cx, JSObjec
                            NULL, NULL, 0)) {
       return NULL;
     }
   }
 
   return ourProto;
 }
 
+template <class T>
+bool
+HandleNewBindingWrappingFailure(JSContext *cx, JSObject *scope,
+                                T *value, jsval *vp)
+{
+  if (JS_IsExceptionPending(cx)) {
+    return false;
+  }
+
+  XPCLazyCallContext lccx(JS_CALLER, cx, scope);
+
+  nsCOMPtr<nsISupports> canonical;
+  if (NS_SUCCEEDED(CallQueryInterface(value, getter_AddRefs(canonical)))) {
+    xpcObjectHelper helper(canonical);
+    nsresult rv;
+    if (XPCConvert::NativeInterface2JSObject(lccx, vp, NULL, helper, NULL, NULL,
+                                             true, OBJ_IS_NOT_GLOBAL, &rv)) {
+      return true;
+    }
+    
+    if (!JS_IsExceptionPending(cx)) {
+      return Throw(cx, rv);
+    }
+  }
+
+  return Throw(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
+}
+
 } // namespace bindings
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/bindings/Utils.h
+++ b/dom/bindings/Utils.h
@@ -158,54 +158,53 @@ WrapNewBindingObject(JSContext *cx, JSOb
   if (obj && js::GetObjectCompartment(obj) == js::GetObjectCompartment(scope)) {
     *vp = JS::ObjectValue(*obj);
     return true;
   }
 
   // XXXbz figure out the actual security wrapper story here
   bool triedToWrap;
   obj = value->WrapObject(cx, scope, &triedToWrap);
-  if (triedToWrap && obj) {
+  if (obj) {
     *vp = JS::ObjectValue(*obj);
     return true;
   }
 
+  // At this point, obj is null, so just return false.  We could try to
+  // communicate triedToWrap to the caller, but in practice callers seem to be
+  // testing JS_IsExceptionPending(cx) to figure out whether WrapObject() threw
+  // instead.
   return false;
 }
 
 // Helper for smart pointers (nsAutoPtr/nsRefPtr/nsCOMPtr).
 template <template <class> class SmartPtr, class T>
 inline bool
 WrapNewBindingObject(JSContext *cx, JSObject *scope, const SmartPtr<T>& value,
                      jsval *vp)
 {
   return WrapNewBindingObject(cx, scope, value.get(), vp);
 }
 
+/**
+ * A method to handle new-binding wrap failure, by possibly falling back to
+ * wrapping as a non-new-binding object.
+ */
 template <class T>
-inline bool
-WrapOtherObject(JSContext *cx, JSObject *scope, T *value, jsval *vp)
-{
-  XPCLazyCallContext lccx(JS_CALLER, cx, scope);
-
-  nsCOMPtr<nsISupports> canonical;
-  if (NS_FAILED(CallQueryInterface(value, getter_AddRefs(canonical)))) {
-    return false;
-  }
+bool
+HandleNewBindingWrappingFailure(JSContext *cx, JSObject *scope,
+                                T *value, jsval *vp);
 
-  xpcObjectHelper helper(canonical);
-  nsresult rv;
-  if (!XPCConvert::NativeInterface2JSObject(lccx, vp, NULL, helper, NULL, NULL,
-                                            true, OBJ_IS_NOT_GLOBAL, &rv)) {
-    if (!JS_IsExceptionPending(cx))
-      Throw(cx, rv);
-    return false;
-  }
-
-  return true;
+// Helper for smart pointers (nsAutoPtr/nsRefPtr/nsCOMPtr).
+template <template <class> class SmartPtr, class T>
+inline bool
+HandleNewBindingWrappingFailure(JSContext *cx, JSObject *scope,
+                                const SmartPtr<T>& value, jsval *vp)
+{
+  return HandleNewBindingWrappingFailure(cx, scope, value.get(), vp);
 }
 
 // Support for nullable types
 template <typename T>
 struct Nullable
 {
 private:
   T mValue;
@@ -234,25 +233,16 @@ public:
     return mValue;
   }
 
   bool IsNull() {
     return mIsNull;
   }
 };
 
-// Helper for smart pointers (nsAutoPtr/nsRefPtr/nsCOMPtr).
-template <template <class> class SmartPtr, class T>
-inline bool
-WrapOtherObject(JSContext *cx, JSObject *scope, const SmartPtr<T>& value,
-                jsval *vp)
-{
-  return WrapOtherObject(cx, scope, value.get(), vp);
-}
-
 inline int
 FindEnumStringIndex(JSContext *cx, jsval v, const char** values, bool *ok)
 {
   JSString* str = JS_ValueToString(cx, v);
   if (!str) {
     *ok = false;
     return 0;
   }