Bug 749866 part 3. Rejigger overload resolution a bit more so we can tell argument conversion that we know the argument is null or undefined. r=khuey
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 05 Nov 2012 11:58:02 -0500
changeset 112319 5b2c87bfe082d0f3619a4fb2a775213af8b81680
parent 112318 024d12cc40095f471f94c516055aa281129a6a08
child 112320 6f08c574fb7968845fb886de1e1726f6886c7b1d
push id23812
push useremorley@mozilla.com
push dateTue, 06 Nov 2012 14:01:34 +0000
treeherdermozilla-central@f4aeed115e54 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs749866
milestone19.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 749866 part 3. Rejigger overload resolution a bit more so we can tell argument conversion that we know the argument is null or undefined. r=khuey
dom/bindings/Codegen.py
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1877,17 +1877,18 @@ def getJSToNativeConversionTemplate(type
                                     isDefinitelyObject=False,
                                     isMember=False,
                                     isOptional=False,
                                     invalidEnumValueFatal=True,
                                     defaultValue=None,
                                     treatNullAs="Default",
                                     treatUndefinedAs="Default",
                                     isEnforceRange=False,
-                                    isClamp=False):
+                                    isClamp=False,
+                                    isNullOrUndefined=False):
     """
     Get a template for converting a JS value to a native object based on the
     given type and descriptor.  If failureCode is given, then we're actually
     testing whether we can convert the argument to the desired type.  That
     means that failures to convert due to the JS value being the wrong type of
     value need to use failureCode instead of throwing exceptions.  Failures to
     convert that are due to JS exceptions (from toString or valueOf methods) or
     out of memory conditions need to throw exceptions no matter what
@@ -3577,35 +3578,72 @@ class CGMethodCall(CGThing):
                                 getPerSignatureCall(sigs[0], distinguishingIndex)))
                         caseBody.append(CGGeneric("}"))
                     return True
                 return False
 
             def distinguishingType(signature):
                 return signature[1][distinguishingIndex].type
 
+            def tryCall(signature, indent, isDefinitelyObject=False,
+                        isNullOrUndefined=False):
+                assert not isDefinitelyObject or not isNullOrUndefined
+                assert isDefinitelyObject or isNullOrUndefined
+                if isDefinitelyObject:
+                    failureCode = "break;"
+                else:
+                    failureCode = None
+                type = distinguishingType(signature)
+                # The argument at index distinguishingIndex can't possibly
+                # be unset here, because we've already checked that argc is
+                # large enough that we can examine this argument.
+                testCode = instantiateJSToNativeConversionTemplate(
+                    getJSToNativeConversionTemplate(type, descriptor,
+                                                    failureCode=failureCode,
+                                                    isDefinitelyObject=isDefinitelyObject,
+                                                    isNullOrUndefined=isNullOrUndefined),
+                    {
+                        "declName" : "arg%d" % distinguishingIndex,
+                        "holderName" : ("arg%d" % distinguishingIndex) + "_holder",
+                        "val" : distinguishingArg
+                        })
+                caseBody.append(CGIndenter(testCode, indent));
+                # If we got this far, we know we unwrapped to the right
+                # C++ type, so just do the call.  Start conversion with
+                # distinguishingIndex + 1, since we already converted
+                # distinguishingIndex.
+                caseBody.append(CGIndenter(
+                        getPerSignatureCall(signature, distinguishingIndex + 1),
+                        indent))
+
             # First check for null or undefined.  That means looking for
             # nullable arguments at the distinguishing index and outputting a
             # separate branch for them.  But if the nullable argument is a
             # primitive, string, or enum, we don't need to do that.  The reason
             # for that is that at most one argument at the distinguishing index
             # is nullable (since two nullable arguments are not
             # distinguishable), and all the argument types other than
             # primitive/string/enum end up inside isObject() checks.  So if our
             # nullable is a primitive/string/enum it's safe to not output the
             # extra branch: we'll fall through to conversion for those types,
             # which correctly handles null as needed, because isObject() will be
             # false for null and undefined.
-            pickFirstSignature(
-                "%s.isNullOrUndefined()" % distinguishingArg,
-                lambda s: ((distinguishingType(s).nullable() and not
-                            distinguishingType(s).isString() and not
-                            distinguishingType(s).isEnum() and not
-                            distinguishingType(s).isPrimitive()) or
-                           distinguishingType(s).isDictionary()))
+            nullOrUndefSigs = [s for s in possibleSignatures
+                               if ((distinguishingType(s).nullable() and not
+                                    distinguishingType(s).isString() and not
+                                    distinguishingType(s).isEnum() and not
+                                   distinguishingType(s).isPrimitive()) or
+                                   distinguishingType(s).isDictionary())]
+            # Can't have multiple nullable types here
+            assert len(nullOrUndefSigs) < 2
+            if len(nullOrUndefSigs) > 0:
+                caseBody.append(CGGeneric("if (%s.isNullOrUndefined()) {" %
+                                          distinguishingArg))
+                tryCall(nullOrUndefSigs[0], 2, isNullOrUndefined=True)
+                caseBody.append(CGGeneric("}"))
 
             # Now check for distinguishingArg being various kinds of objects.
             # The spec says to check for the following things in order:
             # 1)  A platform object that's not a platform array object, being
             #     passed to an interface or "object" arg.
             # 2)  A platform array object or Array or platform object with
             #     indexed properties being passed to an array or sequence or
             #     "object" arg.
@@ -3648,42 +3686,22 @@ class CGMethodCall(CGThing):
                 # the next overload if the object fails to unwrap correctly,
                 # while "object" accepts any object anyway.  We could even not
                 # do the isObject() check up front here, but in cases where we
                 # have multiple object overloads it makes sense to do it only
                 # once instead of for each overload.  That will also allow the
                 # unwrapping test to skip having to do codegen for the
                 # null-or-undefined case, which we already handled above.
                 caseBody.append(CGGeneric("if (%s.isObject()) {" %
-                                          (distinguishingArg)))
+                                          distinguishingArg))
                 for sig in objectSigs:
                     caseBody.append(CGIndenter(CGGeneric("do {")));
-                    type = distinguishingType(sig)
-
-                    # The argument at index distinguishingIndex can't possibly
-                    # be unset here, because we've already checked that argc is
-                    # large enough that we can examine this argument.
-                    testCode = instantiateJSToNativeConversionTemplate(
-                        getJSToNativeConversionTemplate(type, descriptor,
-                                                        failureCode="break;",
-                                                        isDefinitelyObject=True),
-                        {
-                            "declName" : "arg%d" % distinguishingIndex,
-                            "holderName" : ("arg%d" % distinguishingIndex) + "_holder",
-                            "val" : distinguishingArg
-                            })
-
-                    # Indent by 4, since we need to indent further than our "do" statement
-                    caseBody.append(CGIndenter(testCode, 4));
-                    # If we got this far, we know we unwrapped to the right
-                    # C++ type, so just do the call.  Start conversion with
-                    # distinguishingIndex + 1, since we already converted
-                    # distinguishingIndex.
-                    caseBody.append(CGIndenter(
-                            getPerSignatureCall(sig, distinguishingIndex + 1), 4))
+                    # Indent by 4, since we need to indent further
+                    # than our "do" statement
+                    tryCall(sig, 4, isDefinitelyObject=True)
                     caseBody.append(CGIndenter(CGGeneric("} while (0);")))
 
                 caseBody.append(CGGeneric("}"))
 
             # Check for vanilla JS objects
             # XXXbz Do we need to worry about security wrappers?
             pickFirstSignature("%s.isObject() && !IsPlatformObject(cx, &%s.toObject())" %
                                (distinguishingArg, distinguishingArg),