Bug 774970. Add the ability to generate code for dealing with an XPConnect 'this' object in some cases. r=peterv
authorBoris Zbarsky <bzbarsky@mit.edu>
Tue, 28 Aug 2012 13:10:09 -0400
changeset 105713 41b8acc383568b521ae0efd691ebd30ca92c10b1
parent 105712 561f1e6ccdc9e7efe9a4e17e35a1cc0d937a4522
child 105714 9dbfbeaf89e385974a54a4bba7101a6b01419725
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
reviewerspeterv
bugs774970
milestone18.0a1
Bug 774970. Add the ability to generate code for dealing with an XPConnect 'this' object in some cases. r=peterv
dom/bindings/Codegen.py
dom/bindings/Configuration.py
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1465,21 +1465,39 @@ class CastableObjectUnwrapper():
     A class for unwrapping an object named by the "source" argument
     based on the passed-in descriptor and storing it in a variable
     called by the name in the "target" argument.
 
     codeOnFailure is the code to run if unwrapping fails.
     """
     def __init__(self, descriptor, source, target, codeOnFailure):
         assert descriptor.castable
+
         self.substitution = { "type" : descriptor.nativeType,
                               "protoID" : "prototypes::id::" + descriptor.name,
                               "source" : source,
                               "target" : target,
                               "codeOnFailure" : CGIndenter(CGGeneric(codeOnFailure), 4).define() }
+        if descriptor.hasXPConnectImpls:
+            # We don't use xpc_qsUnwrapThis because it will always throw on
+            # unwrap failure, whereas we want to control whether we throw or
+            # not.
+            self.substitution["codeOnFailure"] = CGIndenter(CGGeneric(string.Template(
+                "${type} *objPtr;\n"
+                "xpc_qsSelfRef objRef;\n"
+                "JS::Value val = JS::ObjectValue(*${source});\n"
+                "nsresult rv = xpc_qsUnwrapArg<${type}>(cx, val, &objPtr, &objRef.ptr, &val);\n"
+                "if (NS_FAILED(rv)) {\n"
+                "${codeOnFailure}\n"
+                "}\n"
+                "// We should be castable!\n"
+                "MOZ_ASSERT(!objRef.ptr);\n"
+                "// We should have an object, too!\n"
+                "MOZ_ASSERT(objPtr);\n"
+                "${target} = objPtr;").substitute(self.substitution)), 4).define()
 
     def __str__(self):
         return string.Template(
 """{
   nsresult rv = UnwrapObject<${protoID}, ${type}>(cx, ${source}, ${target});
   if (NS_FAILED(rv)) {
 ${codeOnFailure}
   }
@@ -3296,16 +3314,17 @@ class CGSetterCall(CGPerSignatureCall):
         return ""
 
 class FakeCastableDescriptor():
     def __init__(self, descriptor):
         self.castable = True
         self.workers = descriptor.workers
         self.nativeType = descriptor.nativeType
         self.name = descriptor.name
+        self.hasXPConnectImpls = descriptor.hasXPConnectImpls
 
 class CGAbstractBindingMethod(CGAbstractStaticMethod):
     """
     Common class to generate the JSNatives for all our methods, getters, and
     setters.  This will generate the function declaration and unwrap the
     |this| object.  Subclasses are expected to override the generate_code
     function to do the rest of the work.  This function should return a
     CGThing which is already properly indented.
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -156,16 +156,18 @@ class Descriptor(DescriptorProvider):
                                 "setting" % self.interface.identifier.name)
             self.castable = False
         else:
             self.castable = desc.get('castable', True)
 
         self.notflattened = desc.get('notflattened', False)
         self.register = desc.get('register', True)
 
+        self.hasXPConnectImpls = desc.get('hasXPConnectImpls', False)
+
         # If we're concrete, we need to crawl our ancestor interfaces and mark
         # them as having a concrete descendant.
         self.concrete = desc.get('concrete', not self.interface.isExternal())
         if self.concrete:
             self.proxy = False
             operations = {
                 'IndexedGetter': None,
                 'IndexedSetter': None,