dom/bindings/Codegen.py

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 # This Source Code Form is subject to the terms of the Mozilla Public
     2 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
     3 # You can obtain one at http://mozilla.org/MPL/2.0/.
     5 # Common codegen classes.
     7 import os
     8 import re
     9 import string
    10 import math
    11 import textwrap
    13 from WebIDL import BuiltinTypes, IDLBuiltinType, IDLNullValue, IDLSequenceType, IDLType, IDLAttribute, IDLUndefinedValue
    14 from Configuration import NoSuchDescriptorError, getTypesFromDescriptor, getTypesFromDictionary, getTypesFromCallback, Descriptor
    16 AUTOGENERATED_WARNING_COMMENT = \
    17     "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
    18 ADDPROPERTY_HOOK_NAME = '_addProperty'
    19 FINALIZE_HOOK_NAME = '_finalize'
    20 CONSTRUCT_HOOK_NAME = '_constructor'
    21 LEGACYCALLER_HOOK_NAME = '_legacycaller'
    22 HASINSTANCE_HOOK_NAME = '_hasInstance'
    23 NEWRESOLVE_HOOK_NAME = '_newResolve'
    24 ENUMERATE_HOOK_NAME = '_enumerate'
    25 ENUM_ENTRY_VARIABLE_NAME = 'strings'
    26 INSTANCE_RESERVED_SLOTS = 3
    29 def memberReservedSlot(member):
    30     return "(DOM_INSTANCE_RESERVED_SLOTS + %d)" % member.slotIndex
    33 def toStringBool(arg):
    34     return str(not not arg).lower()
    37 def toBindingNamespace(arg):
    38     return re.sub("((_workers)?$)", "Binding\\1", arg)
    41 def isTypeCopyConstructible(type):
    42     # Nullable and sequence stuff doesn't affect copy-constructibility
    43     type = type.unroll()
    44     return (type.isPrimitive() or type.isString() or type.isEnum() or
    45             (type.isUnion() and
    46              CGUnionStruct.isUnionCopyConstructible(type)) or
    47             (type.isDictionary() and
    48              CGDictionary.isDictionaryCopyConstructible(type.inner)) or
    49             # Interface types are only copy-constructible if they're Gecko
    50             # interfaces.  SpiderMonkey interfaces are not copy-constructible
    51             # because of rooting issues.
    52             (type.isInterface() and type.isGeckoInterface()))
    55 def wantsAddProperty(desc):
    56     return (desc.concrete and
    57             desc.wrapperCache and
    58             not (desc.workers and
    59                  desc.interface.getExtendedAttribute("Global")))
    62 # We'll want to insert the indent at the beginnings of lines, but we
    63 # don't want to indent empty lines.  So only indent lines that have a
    64 # non-newline character on them.
    65 lineStartDetector = re.compile("^(?=[^\n#])", re.MULTILINE)
    68 def indent(s, indentLevel=2):
    69     """
    70     Indent C++ code.
    72     Weird secret feature: this doesn't indent lines that start with # (such as
    73     #include lines).
    74     """
    75     if s == "":
    76         return s
    77     return re.sub(lineStartDetector, indentLevel * " ", s)
    80 def dedent(s):
    81     """
    82     Remove all leading whitespace from s, and remove a blank line
    83     at the beginning.
    84     """
    85     if s.startswith('\n'):
    86         s = s[1:]
    87     return textwrap.dedent(s)
    89 def fill(template, **args):
    90     """
    91     Convenience function for filling in a multiline template.
    93     `fill(template, name1=v1, name2=v2)` is a lot like
    94     `string.Template(template).substitute({"name1": v1, "name2": v2})`.
    96     However, it's shorter, and has a few nice features:
    98       * If `template` is indented, fill() automatically dedents it!
    99         This makes code using fill() with Python's multiline strings
   100         much nicer to look at.
   102       * If `template` starts with a blank line, fill() strips it off.
   103         (Again, convenient with multiline strings.)
   105       * fill() recognizes a special kind of substitution
   106         of the form `$*{name}`.
   108         Use this to paste in, and automatically indent, multiple lines.
   109         (Mnemonic: The `*` is for "multiple lines").
   111         A `$*` substitution must appear by itself on a line, with optional
   112         preceding indentation (spaces only). The whole line is replaced by the
   113         corresponding keyword argument, indented appropriately.  If the
   114         argument is an empty string, no output is generated, not even a blank
   115         line.
   116     """
   118     # This works by transforming the fill()-template to an equivalent
   119     # string.Template.
   120     multiline_substitution_re = re.compile(r"( *)\$\*{(\w+)}(\n)?")
   122     def replace(match):
   123         """
   124         Replaces a line like '  $*{xyz}\n' with '${xyz_n}',
   125         where n is the indent depth, and add a corresponding entry to args.
   126         """
   127         indentation, name, nl = match.groups()
   128         depth = len(indentation)
   130         # Check that $*{xyz} appears by itself on a line.
   131         prev = match.string[:match.start()]
   132         if (prev and not prev.endswith("\n")) or nl is None:
   133             raise ValueError("Invalid fill() template: $*{%s} must appear by itself on a line" % name)
   135         # Multiline text without a newline at the end is probably a mistake.
   136         if not (args[name] == "" or args[name].endswith("\n")):
   137             raise ValueError("Argument %s with value %r is missing a newline" % (name, args[name]))
   139         # Now replace this whole line of template with the indented equivalent.
   140         modified_name = name + "_" + str(depth)
   141         indented_value = indent(args[name], depth)
   142         if modified_name in args:
   143             assert args[modified_name] == indented_value
   144         else:
   145             args[modified_name] = indented_value
   146         return "${" + modified_name + "}"
   148     t = dedent(template)
   149     assert t.endswith("\n") or "\n" not in t
   150     t = re.sub(multiline_substitution_re, replace, t)
   151     t = string.Template(t)
   152     return t.substitute(args)
   155 class CGThing():
   156     """
   157     Abstract base class for things that spit out code.
   158     """
   159     def __init__(self):
   160         pass  # Nothing for now
   162     def declare(self):
   163         """Produce code for a header file."""
   164         assert False  # Override me!
   166     def define(self):
   167         """Produce code for a cpp file."""
   168         assert False  # Override me!
   170     def deps(self):
   171         """Produce the deps for a pp file"""
   172         assert False  # Override me!
   175 class CGStringTable(CGThing):
   176     """
   177     Generate a string table for the given strings with a function accessor:
   179     const char *accessorName(unsigned int index) {
   180       static const char table[] = "...";
   181       static const uint16_t indices = { ... };
   182       return &table[indices[index]];
   183     }
   185     This is more efficient than the more natural:
   187     const char *table[] = {
   188       ...
   189     };
   191     The uint16_t indices are smaller than the pointer equivalents, and the
   192     string table requires no runtime relocations.
   193     """
   194     def __init__(self, accessorName, strings):
   195         CGThing.__init__(self)
   196         self.accessorName = accessorName
   197         self.strings = strings
   199     def declare(self):
   200         return "extern const char *%s(unsigned int aIndex);\n" % self.accessorName
   202     def define(self):
   203         table = ' "\\0" '.join('"%s"' % s for s in self.strings)
   204         indices = []
   205         currentIndex = 0
   206         for s in self.strings:
   207             indices.append(currentIndex)
   208             currentIndex += len(s) + 1  # for the null terminator
   209         return fill(
   210             """
   211             const char *${name}(unsigned int aIndex)
   212             {
   213               static const char table[] = ${table};
   214               static const uint16_t indices[] = { ${indices} };
   215               static_assert(${currentIndex} <= UINT16_MAX, "string table overflow!");
   216               return &table[indices[aIndex]];
   217             }
   218             """,
   219             name=self.accessorName,
   220             table=table,
   221             indices=", ".join("%d" % index for index in indices),
   222             currentIndex=currentIndex)
   225 class CGNativePropertyHooks(CGThing):
   226     """
   227     Generate a NativePropertyHooks for a given descriptor
   228     """
   229     def __init__(self, descriptor, properties):
   230         CGThing.__init__(self)
   231         self.descriptor = descriptor
   232         self.properties = properties
   234     def declare(self):
   235         if self.descriptor.workers:
   236             return ""
   237         return dedent("""
   238             // We declare this as an array so that retrieving a pointer to this
   239             // binding's property hooks only requires compile/link-time resolvable
   240             // address arithmetic.  Declaring it as a pointer instead would require
   241             // doing a run-time load to fetch a pointer to this binding's property
   242             // hooks.  And then structures which embedded a pointer to this structure
   243             // would require a run-time load for proper initialization, which would
   244             // then induce static constructors.  Lots of static constructors.
   245             extern const NativePropertyHooks sNativePropertyHooks[];
   246             """).rstrip()  # BOGUS strip newline from the last line here (!)
   248     def define(self):
   249         if self.descriptor.workers:
   250             return ""
   251         if self.descriptor.concrete and self.descriptor.proxy:
   252             resolveOwnProperty = "ResolveOwnProperty"
   253             enumerateOwnProperties = "EnumerateOwnProperties"
   254         elif self.descriptor.needsXrayResolveHooks():
   255             resolveOwnProperty = "ResolveOwnPropertyViaNewresolve"
   256             enumerateOwnProperties = "EnumerateOwnPropertiesViaGetOwnPropertyNames"
   257         else:
   258             resolveOwnProperty = "nullptr"
   259             enumerateOwnProperties = "nullptr"
   260         if self.properties.hasNonChromeOnly():
   261             regular = "&sNativeProperties"
   262         else:
   263             regular = "nullptr"
   264         if self.properties.hasChromeOnly():
   265             chrome = "&sChromeOnlyNativeProperties"
   266         else:
   267             chrome = "nullptr"
   268         constructorID = "constructors::id::"
   269         if self.descriptor.interface.hasInterfaceObject():
   270             constructorID += self.descriptor.name
   271         else:
   272             constructorID += "_ID_Count"
   273         prototypeID = "prototypes::id::"
   274         if self.descriptor.interface.hasInterfacePrototypeObject():
   275             prototypeID += self.descriptor.name
   276         else:
   277             prototypeID += "_ID_Count"
   278         parent = self.descriptor.interface.parent
   279         parentHooks = (toBindingNamespace(parent.identifier.name) + "::sNativePropertyHooks"
   280                        if parent else 'nullptr')
   282         return fill(
   283             """
   284             const NativePropertyHooks sNativePropertyHooks[] = { {
   285               ${resolveOwnProperty},
   286               ${enumerateOwnProperties},
   287               { ${regular}, ${chrome} },
   288               ${prototypeID},
   289               ${constructorID},
   290               ${parentHooks}
   291             } };
   292             """,
   293             resolveOwnProperty=resolveOwnProperty,
   294             enumerateOwnProperties=enumerateOwnProperties,
   295             regular=regular,
   296             chrome=chrome,
   297             prototypeID=prototypeID,
   298             constructorID=constructorID,
   299             parentHooks=parentHooks)
   302 def NativePropertyHooks(descriptor):
   303     return "&sWorkerNativePropertyHooks" if descriptor.workers else "sNativePropertyHooks"
   306 def DOMClass(descriptor):
   307     def make_name(d):
   308         return "%s%s" % (d.interface.identifier.name, '_workers' if d.workers else '')
   310     protoList = ['prototypes::id::' + make_name(descriptor.getDescriptor(proto)) for proto in descriptor.prototypeChain]
   311     # Pad out the list to the right length with _ID_Count so we
   312     # guarantee that all the lists are the same length.  _ID_Count
   313     # is never the ID of any prototype, so it's safe to use as
   314     # padding.
   315     protoList.extend(['prototypes::id::_ID_Count'] * (descriptor.config.maxProtoChainLength - len(protoList)))
   317     return fill(
   318         """
   319         {
   320           { ${protoChain} },
   321           IsBaseOf<nsISupports, ${nativeType} >::value,
   322           ${hooks},
   323           GetParentObject<${nativeType}>::Get,
   324           GetProtoObject,
   325           GetCCParticipant<${nativeType}>::Get()
   326         }
   327         """,
   328         protoChain=', '.join(protoList),
   329         nativeType=descriptor.nativeType,
   330         hooks=NativePropertyHooks(descriptor))
   333 class CGDOMJSClass(CGThing):
   334     """
   335     Generate a DOMJSClass for a given descriptor
   336     """
   337     def __init__(self, descriptor):
   338         CGThing.__init__(self)
   339         self.descriptor = descriptor
   341     def declare(self):
   342         return ""
   344     def define(self):
   345         traceHook = 'nullptr'
   346         callHook = LEGACYCALLER_HOOK_NAME if self.descriptor.operations["LegacyCaller"] else 'nullptr'
   347         slotCount = INSTANCE_RESERVED_SLOTS + self.descriptor.interface.totalMembersInSlots
   348         classFlags = "JSCLASS_IS_DOMJSCLASS | "
   349         classExtensionAndObjectOps = """\
   350 JS_NULL_CLASS_EXT,
   351 JS_NULL_OBJECT_OPS
   352 """
   353         if self.descriptor.interface.getExtendedAttribute("Global"):
   354             classFlags += "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS) | JSCLASS_IMPLEMENTS_BARRIERS"
   355             traceHook = "JS_GlobalObjectTraceHook"
   356             if not self.descriptor.workers:
   357                 classExtensionAndObjectOps = """\
   358 {
   359   nsGlobalWindow::OuterObject, /* outerObject */
   360   nullptr, /* innerObject */
   361   nullptr, /* iteratorObject */
   362   false, /* isWrappedNative */
   363   nullptr /* weakmapKeyDelegateOp */
   364 },
   365 {
   366   nullptr, /* lookupGeneric */
   367   nullptr, /* lookupProperty */
   368   nullptr, /* lookupElement */
   369   nullptr, /* defineGeneric */
   370   nullptr, /* defineProperty */
   371   nullptr, /* defineElement */
   372   nullptr, /* getGeneric  */
   373   nullptr, /* getProperty */
   374   nullptr, /* getElement */
   375   nullptr, /* setGeneric */
   376   nullptr, /* setProperty */
   377   nullptr, /* setElement */
   378   nullptr, /* getGenericAttributes */
   379   nullptr, /* setGenericAttributes */
   380   nullptr, /* deleteProperty */
   381   nullptr, /* deleteElement */
   382   nullptr, /* watch */
   383   nullptr, /* unwatch */
   384   nullptr, /* slice */
   385   nullptr, /* enumerate */
   386   JS_ObjectToOuterObject /* thisObject */
   387 }
   388 """
   389         else:
   390             classFlags += "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount
   391         if self.descriptor.interface.getExtendedAttribute("NeedNewResolve"):
   392             newResolveHook = "(JSResolveOp)" + NEWRESOLVE_HOOK_NAME
   393             classFlags += " | JSCLASS_NEW_RESOLVE"
   394             enumerateHook = ENUMERATE_HOOK_NAME
   395         elif self.descriptor.interface.getExtendedAttribute("Global"):
   396             newResolveHook = "(JSResolveOp) mozilla::dom::ResolveGlobal"
   397             classFlags += " | JSCLASS_NEW_RESOLVE"
   398             enumerateHook = "mozilla::dom::EnumerateGlobal"
   399         else:
   400             newResolveHook = "JS_ResolveStub"
   401             enumerateHook = "JS_EnumerateStub"
   403         return fill(  # BOGUS extra blank line at the top
   404             """
   406             static const DOMJSClass Class = {
   407               { "${name}",
   408                 ${flags},
   409                 ${addProperty}, /* addProperty */
   410                 JS_DeletePropertyStub, /* delProperty */
   411                 JS_PropertyStub,       /* getProperty */
   412                 JS_StrictPropertyStub, /* setProperty */
   413                 ${enumerate}, /* enumerate */
   414                 ${resolve}, /* resolve */
   415                 JS_ConvertStub,
   416                 ${finalize}, /* finalize */
   417                 ${call}, /* call */
   418                 nullptr,               /* hasInstance */
   419                 nullptr,               /* construct */
   420                 ${trace}, /* trace */
   421                 JS_NULL_CLASS_SPEC,
   422                 $*{classExtensionAndObjectOps}
   423               },
   424               $*{descriptor}
   425             };
   426             """,
   427             name=self.descriptor.interface.identifier.name,
   428             flags=classFlags,
   429             addProperty=ADDPROPERTY_HOOK_NAME if wantsAddProperty(self.descriptor) else 'JS_PropertyStub',
   430             enumerate=enumerateHook,
   431             resolve=newResolveHook,
   432             finalize=FINALIZE_HOOK_NAME,
   433             call=callHook,
   434             trace=traceHook,
   435             classExtensionAndObjectOps=classExtensionAndObjectOps,
   436             descriptor=DOMClass(self.descriptor))
   439 class CGDOMProxyJSClass(CGThing):
   440     """
   441     Generate a DOMJSClass for a given proxy descriptor
   442     """
   443     def __init__(self, descriptor):
   444         CGThing.__init__(self)
   445         self.descriptor = descriptor
   447     def declare(self):
   448         return ""
   450     def define(self):
   451         flags = ["JSCLASS_IS_DOMJSCLASS"]
   452         # We don't use an IDL annotation for JSCLASS_EMULATES_UNDEFINED because
   453         # we don't want people ever adding that to any interface other than
   454         # HTMLAllCollection.  So just hardcode it here.
   455         if self.descriptor.interface.identifier.name == "HTMLAllCollection":
   456             flags.append("JSCLASS_EMULATES_UNDEFINED")
   457         callHook = LEGACYCALLER_HOOK_NAME if self.descriptor.operations["LegacyCaller"] else 'nullptr'
   458         return fill(  # BOGUS extra blank line at the top
   459             """
   461             static const DOMJSClass Class = {
   462               PROXY_CLASS_DEF("${name}",
   463                               0, /* extra slots */
   464                               ${flags},
   465                               ${call}, /* call */
   466                               nullptr  /* construct */),
   467               $*{descriptor}
   468             };
   469             """,
   470             name=self.descriptor.interface.identifier.name,
   471             flags=" | ".join(flags),
   472             call=callHook,
   473             descriptor=DOMClass(self.descriptor))
   476 def PrototypeIDAndDepth(descriptor):
   477     prototypeID = "prototypes::id::"
   478     if descriptor.interface.hasInterfacePrototypeObject():
   479         prototypeID += descriptor.interface.identifier.name
   480         if descriptor.workers:
   481             prototypeID += "_workers"
   482         depth = "PrototypeTraits<%s>::Depth" % prototypeID
   483     else:
   484         prototypeID += "_ID_Count"
   485         depth = "0"
   486     return (prototypeID, depth)
   489 def UseHolderForUnforgeable(descriptor):
   490     return (descriptor.concrete and
   491             descriptor.proxy and
   492             any(m for m in descriptor.interface.members if m.isAttr() and m.isUnforgeable()))
   495 def CallOnUnforgeableHolder(descriptor, code, isXrayCheck=None,
   496                             useSharedRoot=False):
   497     """
   498     Generate the code to execute the code in "code" on an unforgeable holder if
   499     needed. code should be a string containing the code to execute. If it
   500     contains a ${holder} string parameter it will be replaced with the
   501     unforgeable holder object.
   503     If isXrayCheck is not None it should be a string that contains a statement
   504     returning whether proxy is an Xray. If isXrayCheck is None the generated
   505     code won't try to unwrap Xrays.
   507     If useSharedRoot is true, we will use an existing
   508     JS::Rooted<JSObject*> sharedRoot for storing our unforgeable holder instead
   509     of declaring a new Rooted.
   510     """
   511     if isXrayCheck is not None:
   512         pre = fill(
   513             """
   514             // Scope for 'global', 'ac' and 'unforgeableHolder'
   515             {
   516               JS::Rooted<JSObject*> global(cx);
   517               Maybe<JSAutoCompartment> ac;
   518               if (${isXrayCheck}) {
   519                 global = js::GetGlobalForObjectCrossCompartment(js::UncheckedUnwrap(proxy));
   520                 ac.construct(cx, global);
   521               } else {
   522                 global = js::GetGlobalForObjectCrossCompartment(proxy);
   523               }
   524             """,
   525             isXrayCheck=isXrayCheck)
   526     else:
   527         pre = dedent("""
   528             // Scope for 'global' and 'unforgeableHolder'
   529             {
   530               JSObject* global = js::GetGlobalForObjectCrossCompartment(proxy);
   531             """)
   533     if useSharedRoot:
   534         holderDecl = "JS::Rooted<JSObject*>& unforgeableHolder(sharedRoot);\n"
   535     else:
   536         holderDecl = "JS::Rooted<JSObject*> unforgeableHolder(cx);\n"
   538     code = string.Template(code).substitute({"holder": "unforgeableHolder"})
   539     return fill(
   540         """
   541         $*{pre}
   542           $*{holderDecl}
   543           unforgeableHolder = GetUnforgeableHolder(global, prototypes::id::${name});
   544           $*{code}
   545         }
   546         """,
   547         pre=pre,
   548         holderDecl=holderDecl,
   549         name=descriptor.name,
   550         code=code)
   553 class CGPrototypeJSClass(CGThing):
   554     def __init__(self, descriptor, properties):
   555         CGThing.__init__(self)
   556         self.descriptor = descriptor
   557         self.properties = properties
   559     def declare(self):
   560         # We're purely for internal consumption
   561         return ""
   563     def define(self):
   564         prototypeID, depth = PrototypeIDAndDepth(self.descriptor)
   565         slotCount = "DOM_INTERFACE_PROTO_SLOTS_BASE"
   566         if UseHolderForUnforgeable(self.descriptor):
   567             slotCount += " + 1 /* slot for the JSObject holding the unforgeable properties */"
   568         return fill(
   569             """
   570             static const DOMIfaceAndProtoJSClass PrototypeClass = {
   571               {
   572                 "${name}Prototype",
   573                 JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(${slotCount}),
   574                 JS_PropertyStub,       /* addProperty */
   575                 JS_DeletePropertyStub, /* delProperty */
   576                 JS_PropertyStub,       /* getProperty */
   577                 JS_StrictPropertyStub, /* setProperty */
   578                 JS_EnumerateStub,
   579                 JS_ResolveStub,
   580                 JS_ConvertStub,
   581                 nullptr,               /* finalize */
   582                 nullptr,               /* call */
   583                 nullptr,               /* hasInstance */
   584                 nullptr,               /* construct */
   585                 nullptr,               /* trace */
   586                 JSCLASS_NO_INTERNAL_MEMBERS
   587               },
   588               eInterfacePrototype,
   589               ${hooks},
   590               "[object ${name}Prototype]",
   591               ${prototypeID},
   592               ${depth}
   593             };
   594             """,
   595             name=self.descriptor.interface.identifier.name,
   596             slotCount=slotCount,
   597             hooks=NativePropertyHooks(self.descriptor),
   598             prototypeID=prototypeID,
   599             depth=depth)
   602 def NeedsGeneratedHasInstance(descriptor):
   603     return descriptor.hasXPConnectImpls or descriptor.interface.isConsequential()
   606 class CGInterfaceObjectJSClass(CGThing):
   607     def __init__(self, descriptor, properties):
   608         CGThing.__init__(self)
   609         self.descriptor = descriptor
   610         self.properties = properties
   612     def declare(self):
   613         # We're purely for internal consumption
   614         return ""
   616     def define(self):
   617         if self.descriptor.interface.ctor():
   618             ctorname = CONSTRUCT_HOOK_NAME
   619         else:
   620             ctorname = "ThrowingConstructor"
   621         if NeedsGeneratedHasInstance(self.descriptor):
   622             hasinstance = HASINSTANCE_HOOK_NAME
   623         elif self.descriptor.interface.hasInterfacePrototypeObject():
   624             hasinstance = "InterfaceHasInstance"
   625         else:
   626             hasinstance = "nullptr"
   627         prototypeID, depth = PrototypeIDAndDepth(self.descriptor)
   628         slotCount = "DOM_INTERFACE_SLOTS_BASE"
   629         if len(self.descriptor.interface.namedConstructors) > 0:
   630             slotCount += (" + %i /* slots for the named constructors */" %
   631                           len(self.descriptor.interface.namedConstructors))
   632         return fill(  # BOGUS extra newline at the top
   633             """
   635             static const DOMIfaceAndProtoJSClass InterfaceObjectClass = {
   636               {
   637                 "Function",
   638                 JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(${slotCount}),
   639                 JS_PropertyStub,       /* addProperty */
   640                 JS_DeletePropertyStub, /* delProperty */
   641                 JS_PropertyStub,       /* getProperty */
   642                 JS_StrictPropertyStub, /* setProperty */
   643                 JS_EnumerateStub,
   644                 JS_ResolveStub,
   645                 JS_ConvertStub,
   646                 nullptr,               /* finalize */
   647                 ${ctorname}, /* call */
   648                 ${hasInstance}, /* hasInstance */
   649                 ${ctorname}, /* construct */
   650                 nullptr,               /* trace */
   651                 JSCLASS_NO_INTERNAL_MEMBERS
   652               },
   653               eInterface,
   654               ${hooks},
   655               "function ${name}() {\\n    [native code]\\n}",
   656               ${prototypeID},
   657               ${depth}
   658             };
   659             """,
   660             slotCount=slotCount,
   661             ctorname=ctorname,
   662             hasInstance=hasinstance,
   663             hooks=NativePropertyHooks(self.descriptor),
   664             name=self.descriptor.interface.identifier.name,
   665             prototypeID=prototypeID,
   666             depth=depth)
   669 class CGList(CGThing):
   670     """
   671     Generate code for a list of GCThings.  Just concatenates them together, with
   672     an optional joiner string.  "\n" is a common joiner.
   673     """
   674     def __init__(self, children, joiner=""):
   675         CGThing.__init__(self)
   676         # Make a copy of the kids into a list, because if someone passes in a
   677         # generator we won't be able to both declare and define ourselves, or
   678         # define ourselves more than once!
   679         self.children = list(children)
   680         self.joiner = joiner
   682     def append(self, child):
   683         self.children.append(child)
   685     def prepend(self, child):
   686         self.children.insert(0, child)
   688     def extend(self, kids):
   689         self.children.extend(kids)
   691     def join(self, iterable):
   692         return self.joiner.join(s for s in iterable if len(s) > 0)
   694     def declare(self):
   695         return self.join(child.declare() for child in self.children if child is not None)
   697     def define(self):
   698         return self.join(child.define() for child in self.children if child is not None)
   700     def deps(self):
   701         deps = set()
   702         for child in self.children:
   703             if child is None:
   704                 continue
   705             deps = deps.union(child.deps())
   706         return deps
   709 class CGGeneric(CGThing):
   710     """
   711     A class that spits out a fixed string into the codegen.  Can spit out a
   712     separate string for the declaration too.
   713     """
   714     def __init__(self, define="", declare=""):
   715         self.declareText = declare
   716         self.defineText = define
   718     def declare(self):
   719         return self.declareText
   721     def define(self):
   722         return self.defineText
   724     def deps(self):
   725         return set()
   728 class CGIndenter(CGThing):
   729     """
   730     A class that takes another CGThing and generates code that indents that
   731     CGThing by some number of spaces.  The default indent is two spaces.
   732     """
   733     def __init__(self, child, indentLevel=2, declareOnly=False):
   734         assert isinstance(child, CGThing)
   735         CGThing.__init__(self)
   736         self.child = child
   737         self.indentLevel = indentLevel
   738         self.declareOnly = declareOnly
   740     def declare(self):
   741         return indent(self.child.declare(), self.indentLevel)
   743     def define(self):
   744         defn = self.child.define()
   745         if self.declareOnly:
   746             return defn
   747         else:
   748             return indent(defn, self.indentLevel)
   751 class CGWrapper(CGThing):
   752     """
   753     Generic CGThing that wraps other CGThings with pre and post text.
   754     """
   755     def __init__(self, child, pre="", post="", declarePre=None,
   756                  declarePost=None, definePre=None, definePost=None,
   757                  declareOnly=False, defineOnly=False, reindent=False):
   758         CGThing.__init__(self)
   759         self.child = child
   760         self.declarePre = declarePre or pre
   761         self.declarePost = declarePost or post
   762         self.definePre = definePre or pre
   763         self.definePost = definePost or post
   764         self.declareOnly = declareOnly
   765         self.defineOnly = defineOnly
   766         self.reindent = reindent
   768     def declare(self):
   769         if self.defineOnly:
   770             return ''
   771         decl = self.child.declare()
   772         if self.reindent:
   773             decl = self.reindentString(decl, self.declarePre)
   774         return self.declarePre + decl + self.declarePost
   776     def define(self):
   777         if self.declareOnly:
   778             return ''
   779         defn = self.child.define()
   780         if self.reindent:
   781             defn = self.reindentString(defn, self.definePre)
   782         return self.definePre + defn + self.definePost
   784     @staticmethod
   785     def reindentString(stringToIndent, widthString):
   786         # We don't use lineStartDetector because we don't want to
   787         # insert whitespace at the beginning of our _first_ line.
   788         # Use the length of the last line of width string, in case
   789         # it is a multiline string.
   790         lastLineWidth = len(widthString.splitlines()[-1])
   791         return stripTrailingWhitespace(
   792             stringToIndent.replace("\n", "\n" + (" " * lastLineWidth)))
   794     def deps(self):
   795         return self.child.deps()
   798 class CGIfWrapper(CGList):
   799     def __init__(self, child, condition):
   800         CGList.__init__(self, [
   801             CGWrapper(CGGeneric(condition), pre="if (", post=") {\n", reindent=True),
   802             CGIndenter(child),
   803             CGGeneric("}\n")
   804         ])
   807 class CGIfElseWrapper(CGList):
   808     def __init__(self, condition, ifTrue, ifFalse):
   809         CGList.__init__(self, [
   810             CGWrapper(CGGeneric(condition), pre="if (", post=") {\n", reindent=True),
   811             CGIndenter(ifTrue),
   812             CGGeneric("} else {\n"),
   813             CGIndenter(ifFalse),
   814             CGGeneric("}\n")
   815         ])
   818 class CGElseChain(CGThing):
   819     """
   820     Concatenate if statements in an if-else-if-else chain.
   821     """
   822     def __init__(self, children):
   823         self.children = [c for c in children if c is not None]
   825     def declare(self):
   826         assert False
   828     def define(self):
   829         if not self.children:
   830             return ""
   831         s = self.children[0].define()
   832         assert s.endswith("\n")
   833         for child in self.children[1:]:
   834             code = child.define()
   835             assert code.startswith("if") or code.startswith("{")
   836             assert code.endswith("\n")
   837             s = s.rstrip() + " else " + code
   838         return s
   841 class CGTemplatedType(CGWrapper):
   842     def __init__(self, templateName, child, isConst=False, isReference=False):
   843         const = "const " if isConst else ""
   844         pre = "%s%s<" % (const, templateName)
   845         ref = "&" if isReference else ""
   846         post = ">%s" % ref
   847         CGWrapper.__init__(self, child, pre=pre, post=post)
   850 class CGNamespace(CGWrapper):
   851     def __init__(self, namespace, child, declareOnly=False):
   852         pre = "namespace %s {\n" % namespace
   853         post = "} // namespace %s\n" % namespace
   854         CGWrapper.__init__(self, child, pre=pre, post=post,
   855                            declareOnly=declareOnly)
   857     @staticmethod
   858     def build(namespaces, child, declareOnly=False):
   859         """
   860         Static helper method to build multiple wrapped namespaces.
   861         """
   862         if not namespaces:
   863             return CGWrapper(child, declareOnly=declareOnly)
   864         inner = CGNamespace.build(namespaces[1:], child, declareOnly=declareOnly)
   865         return CGNamespace(namespaces[0], inner, declareOnly=declareOnly)
   868 class CGIncludeGuard(CGWrapper):
   869     """
   870     Generates include guards for a header.
   871     """
   872     def __init__(self, prefix, child):
   873         """|prefix| is the filename without the extension."""
   874         define = 'mozilla_dom_%s_h' % prefix
   875         CGWrapper.__init__(self, child,
   876                            declarePre='#ifndef %s\n#define %s\n\n' % (define, define),
   877                            declarePost='\n#endif // %s\n' % define)
   880 def getRelevantProviders(descriptor, config):
   881     if descriptor is not None:
   882         return [descriptor]
   883     # Do both the non-worker and worker versions
   884     return [
   885         config.getDescriptorProvider(False),
   886         config.getDescriptorProvider(True)
   887     ]
   890 def getAllTypes(descriptors, dictionaries, callbacks):
   891     """
   892     Generate all the types we're dealing with.  For each type, a tuple
   893     containing type, descriptor, dictionary is yielded.  The
   894     descriptor and dictionary can be None if the type does not come
   895     from a descriptor or dictionary; they will never both be non-None.
   896     """
   897     for d in descriptors:
   898         if d.interface.isExternal():
   899             continue
   900         for t in getTypesFromDescriptor(d):
   901             yield (t, d, None)
   902     for dictionary in dictionaries:
   903         for t in getTypesFromDictionary(dictionary):
   904             yield (t, None, dictionary)
   905     for callback in callbacks:
   906         for t in getTypesFromCallback(callback):
   907             yield (t, None, None)
   910 class CGHeaders(CGWrapper):
   911     """
   912     Generates the appropriate include statements.
   913     """
   914     def __init__(self, descriptors, dictionaries, callbacks,
   915                  callbackDescriptors,
   916                  declareIncludes, defineIncludes, prefix, child,
   917                  config=None, jsImplementedDescriptors=[]):
   918         """
   919         Builds a set of includes to cover |descriptors|.
   921         Also includes the files in |declareIncludes| in the header
   922         file and the files in |defineIncludes| in the .cpp.
   924         |prefix| contains the basename of the file that we generate include
   925         statements for.
   926         """
   928         # Determine the filenames for which we need headers.
   929         interfaceDeps = [d.interface for d in descriptors]
   930         ancestors = []
   931         for iface in interfaceDeps:
   932             if iface.parent:
   933                 # We're going to need our parent's prototype, to use as the
   934                 # prototype of our prototype object.
   935                 ancestors.append(iface.parent)
   936                 # And if we have an interface object, we'll need the nearest
   937                 # ancestor with an interface object too, so we can use its
   938                 # interface object as the proto of our interface object.
   939                 if iface.hasInterfaceObject():
   940                     parent = iface.parent
   941                     while parent and not parent.hasInterfaceObject():
   942                         parent = parent.parent
   943                     if parent:
   944                         ancestors.append(parent)
   945         interfaceDeps.extend(ancestors)
   946         bindingIncludes = set(self.getDeclarationFilename(d) for d in interfaceDeps)
   948         # Grab all the implementation declaration files we need.
   949         implementationIncludes = set(d.headerFile for d in descriptors if d.needsHeaderInclude())
   951         # Grab the includes for checking hasInstance
   952         interfacesImplementingSelf = set()
   953         for d in descriptors:
   954             interfacesImplementingSelf |= d.interface.interfacesImplementingSelf
   955         implementationIncludes |= set(self.getDeclarationFilename(i) for i in
   956                                       interfacesImplementingSelf)
   958          # Grab the includes for the things that involve XPCOM interfaces
   959         hasInstanceIncludes = set("nsIDOM" + d.interface.identifier.name + ".h" for d
   960                                   in descriptors if
   961                                   NeedsGeneratedHasInstance(d) and
   962                                   d.interface.hasInterfacePrototypeObject())
   964         # Now find all the things we'll need as arguments because we
   965         # need to wrap or unwrap them.
   966         bindingHeaders = set()
   967         declareIncludes = set(declareIncludes)
   969         def addHeadersForType((t, descriptor, dictionary)):
   970             """
   971             Add the relevant headers for this type.  We use descriptor and
   972             dictionary, if passed, to decide what to do with interface types.
   973             """
   974             assert not descriptor or not dictionary
   975             # Dictionaries have members that need to be actually
   976             # declared, not just forward-declared.
   977             if dictionary:
   978                 headerSet = declareIncludes
   979             else:
   980                 headerSet = bindingHeaders
   981             if t.nullable():
   982                 # Need to make sure that Nullable as a dictionary
   983                 # member works.
   984                 headerSet.add("mozilla/dom/Nullable.h")
   985             unrolled = t.unroll()
   986             if unrolled.isUnion():
   987                 # UnionConversions.h includes UnionTypes.h
   988                 bindingHeaders.add("mozilla/dom/UnionConversions.h")
   989                 if dictionary:
   990                     # Our dictionary definition is in the header and
   991                     # needs the union type.
   992                     declareIncludes.add("mozilla/dom/UnionTypes.h")
   993             elif unrolled.isDate():
   994                 if dictionary or jsImplementedDescriptors:
   995                     declareIncludes.add("mozilla/dom/Date.h")
   996                 else:
   997                     bindingHeaders.add("mozilla/dom/Date.h")
   998             elif unrolled.isInterface():
   999                 if unrolled.isSpiderMonkeyInterface():
  1000                     bindingHeaders.add("jsfriendapi.h")
  1001                     headerSet.add("mozilla/dom/TypedArray.h")
  1002                 else:
  1003                     providers = getRelevantProviders(descriptor, config)
  1004                     for p in providers:
  1005                         try:
  1006                             typeDesc = p.getDescriptor(unrolled.inner.identifier.name)
  1007                         except NoSuchDescriptorError:
  1008                             continue
  1009                         # Dictionaries with interface members rely on the
  1010                         # actual class definition of that interface member
  1011                         # being visible in the binding header, because they
  1012                         # store them in nsRefPtr and have inline
  1013                         # constructors/destructors.
  1015                         # XXXbz maybe dictionaries with interface members
  1016                         # should just have out-of-line constructors and
  1017                         # destructors?
  1018                         headerSet.add(typeDesc.headerFile)
  1019             elif unrolled.isDictionary():
  1020                 headerSet.add(self.getDeclarationFilename(unrolled.inner))
  1021             elif unrolled.isCallback():
  1022                 # Callbacks are both a type and an object
  1023                 headerSet.add(self.getDeclarationFilename(unrolled))
  1024             elif unrolled.isFloat() and not unrolled.isUnrestricted():
  1025                 # Restricted floats are tested for finiteness
  1026                 bindingHeaders.add("mozilla/FloatingPoint.h")
  1027                 bindingHeaders.add("mozilla/dom/PrimitiveConversions.h")
  1028             elif unrolled.isEnum():
  1029                 filename = self.getDeclarationFilename(unrolled.inner)
  1030                 declareIncludes.add(filename)
  1031             elif unrolled.isPrimitive():
  1032                 bindingHeaders.add("mozilla/dom/PrimitiveConversions.h")
  1033             elif unrolled.isMozMap():
  1034                 if dictionary or jsImplementedDescriptors:
  1035                     declareIncludes.add("mozilla/dom/MozMap.h")
  1036                 else:
  1037                     bindingHeaders.add("mozilla/dom/MozMap.h")
  1038                 # Also add headers for the type the MozMap is
  1039                 # parametrized over, if needed.
  1040                 addHeadersForType((t.inner, descriptor, dictionary))
  1042         map(addHeadersForType,
  1043             getAllTypes(descriptors + callbackDescriptors, dictionaries,
  1044                         callbacks))
  1046         # Now make sure we're not trying to include the header from inside itself
  1047         declareIncludes.discard(prefix + ".h")
  1049         # Now for non-callback descriptors make sure we include any
  1050         # headers needed by Func declarations.
  1051         for desc in descriptors:
  1052             if desc.interface.isExternal():
  1053                 continue
  1055             def addHeaderForFunc(func):
  1056                 if func is None:
  1057                     return
  1058                 # Include the right class header, which we can only do
  1059                 # if this is a class member function.
  1060                 if not desc.headerIsDefault:
  1061                     # An explicit header file was provided, assume that we know
  1062                     # what we're doing.
  1063                     return
  1065                 if "::" in func:
  1066                     # Strip out the function name and convert "::" to "/"
  1067                     bindingHeaders.add("/".join(func.split("::")[:-1]) + ".h")
  1069             for m in desc.interface.members:
  1070                 addHeaderForFunc(PropertyDefiner.getStringAttr(m, "Func"))
  1071             # getExtendedAttribute() returns a list, extract the entry.
  1072             funcList = desc.interface.getExtendedAttribute("Func")
  1073             if funcList is not None:
  1074                 addHeaderForFunc(funcList[0])
  1076         for d in dictionaries:
  1077             if d.parent:
  1078                 declareIncludes.add(self.getDeclarationFilename(d.parent))
  1079             bindingHeaders.add(self.getDeclarationFilename(d))
  1081         for c in callbacks:
  1082             bindingHeaders.add(self.getDeclarationFilename(c))
  1084         for c in callbackDescriptors:
  1085             bindingHeaders.add(self.getDeclarationFilename(c.interface))
  1087         if len(callbacks) != 0:
  1088             # We need CallbackFunction to serve as our parent class
  1089             declareIncludes.add("mozilla/dom/CallbackFunction.h")
  1090             # And we need BindingUtils.h so we can wrap "this" objects
  1091             declareIncludes.add("mozilla/dom/BindingUtils.h")
  1093         if len(callbackDescriptors) != 0 or len(jsImplementedDescriptors) != 0:
  1094             # We need CallbackInterface to serve as our parent class
  1095             declareIncludes.add("mozilla/dom/CallbackInterface.h")
  1096             # And we need BindingUtils.h so we can wrap "this" objects
  1097             declareIncludes.add("mozilla/dom/BindingUtils.h")
  1099         # Also need to include the headers for ancestors of
  1100         # JS-implemented interfaces.
  1101         for jsImplemented in jsImplementedDescriptors:
  1102             jsParent = jsImplemented.interface.parent
  1103             if jsParent:
  1104                 parentDesc = jsImplemented.getDescriptor(jsParent.identifier.name)
  1105                 declareIncludes.add(parentDesc.jsImplParentHeader)
  1107         # Let the machinery do its thing.
  1108         def _includeString(includes):
  1109             return ''.join(['#include "%s"\n' % i for i in includes]) + '\n'
  1110         CGWrapper.__init__(self, child,
  1111                            declarePre=_includeString(sorted(declareIncludes)),
  1112                            definePre=_includeString(sorted(set(defineIncludes) |
  1113                                                            bindingIncludes |
  1114                                                            bindingHeaders |
  1115                                                            hasInstanceIncludes |
  1116                                                            implementationIncludes)))
  1118     @staticmethod
  1119     def getDeclarationFilename(decl):
  1120         # Use our local version of the header, not the exported one, so that
  1121         # test bindings, which don't export, will work correctly.
  1122         basename = os.path.basename(decl.filename())
  1123         return basename.replace('.webidl', 'Binding.h')
  1126 def SortedDictValues(d):
  1127     """
  1128     Returns a list of values from the dict sorted by key.
  1129     """
  1130     return [v for k, v in sorted(d.items())]
  1133 def UnionTypes(descriptors, dictionaries, callbacks, config):
  1134     """
  1135     Returns a tuple containing a set of header filenames to include in
  1136     UnionTypes.h, a set of header filenames to include in UnionTypes.cpp, a set
  1137     of tuples containing a type declaration and a boolean if the type is a
  1138     struct for member types of the unions and a CGList containing CGUnionStructs
  1139     for every union.
  1140     """
  1142     # Now find all the things we'll need as arguments and return values because
  1143     # we need to wrap or unwrap them.
  1144     headers = set()
  1145     implheaders = set(["UnionTypes.h"])
  1146     declarations = set()
  1147     unionStructs = dict()
  1148     owningUnionStructs = dict()
  1150     for t, descriptor, dictionary in getAllTypes(descriptors, dictionaries, callbacks):
  1151         # Add info for the given type.  descriptor and dictionary, if present, are
  1152         # used to figure out what to do with interface types.
  1153         assert not descriptor or not dictionary
  1155         t = t.unroll()
  1156         while t.isMozMap():
  1157             t = t.inner.unroll()
  1158         if not t.isUnion():
  1159             continue
  1160         name = str(t)
  1161         if name not in unionStructs:
  1162             providers = getRelevantProviders(descriptor, config)
  1163             # FIXME: Unions are broken in workers.  See bug 809899.
  1164             unionStructs[name] = CGUnionStruct(t, providers[0])
  1165             owningUnionStructs[name] = CGUnionStruct(t, providers[0],
  1166                                                      ownsMembers=True)
  1168             def addHeadersForType(f):
  1169                 if f.nullable():
  1170                     headers.add("mozilla/dom/Nullable.h")
  1171                 f = f.unroll()
  1172                 if f.isInterface():
  1173                     if f.isSpiderMonkeyInterface():
  1174                         headers.add("jsfriendapi.h")
  1175                         headers.add("mozilla/dom/TypedArray.h")
  1176                     else:
  1177                         for p in providers:
  1178                             try:
  1179                                 typeDesc = p.getDescriptor(f.inner.identifier.name)
  1180                             except NoSuchDescriptorError:
  1181                                 continue
  1182                             if typeDesc.interface.isCallback():
  1183                                 # Callback interfaces always use strong refs, so
  1184                                 # we need to include the right header to be able
  1185                                 # to Release() in our inlined code.
  1186                                 headers.add(typeDesc.headerFile)
  1187                             else:
  1188                                 declarations.add((typeDesc.nativeType, False))
  1189                                 implheaders.add(typeDesc.headerFile)
  1190                 elif f.isDictionary():
  1191                     # For a dictionary, we need to see its declaration in
  1192                     # UnionTypes.h so we have its sizeof and know how big to
  1193                     # make our union.
  1194                     headers.add(CGHeaders.getDeclarationFilename(f.inner))
  1195                     # And if it needs rooting, we need RootedDictionary too
  1196                     if typeNeedsRooting(f):
  1197                         headers.add("mozilla/dom/RootedDictionary.h")
  1198                 elif f.isEnum():
  1199                     # Need to see the actual definition of the enum,
  1200                     # unfortunately.
  1201                     headers.add(CGHeaders.getDeclarationFilename(f.inner))
  1202                 elif f.isCallback():
  1203                     # Callbacks always use strong refs, so we need to include
  1204                     # the right header to be able to Release() in our inlined
  1205                     # code.
  1206                     headers.add(CGHeaders.getDeclarationFilename(f))
  1207                 elif f.isMozMap():
  1208                     headers.add("mozilla/dom/MozMap.h")
  1209                     # And add headers for the type we're parametrized over
  1210                     addHeadersForType(f.inner)
  1212             for f in t.flatMemberTypes:
  1213                 assert not f.nullable()
  1214                 addHeadersForType(f)
  1216     return (headers, implheaders, declarations,
  1217             CGList(SortedDictValues(unionStructs) +
  1218                    SortedDictValues(owningUnionStructs),
  1219                    "\n"))
  1222 def UnionConversions(descriptors, dictionaries, callbacks, config):
  1223     """
  1224     Returns a CGThing to declare all union argument conversion helper structs.
  1225     """
  1226     # Now find all the things we'll need as arguments because we
  1227     # need to unwrap them.
  1228     headers = set()
  1229     unionConversions = dict()
  1231     for t, descriptor, dictionary in getAllTypes(descriptors, dictionaries, callbacks):
  1232         # Add info for the given type.  descriptor and dictionary, if passed, are
  1233         # used to figure out what to do with interface types.
  1234         assert not descriptor or not dictionary
  1236         t = t.unroll()
  1237         if not t.isUnion():
  1238             continue
  1239         name = str(t)
  1240         if name not in unionConversions:
  1241             providers = getRelevantProviders(descriptor, config)
  1242             unionConversions[name] = CGUnionConversionStruct(t, providers[0])
  1243             def addHeadersForType(f, providers):
  1244                 f = f.unroll()
  1245                 if f.isInterface():
  1246                     if f.isSpiderMonkeyInterface():
  1247                         headers.add("jsfriendapi.h")
  1248                         headers.add("mozilla/dom/TypedArray.h")
  1249                     elif f.inner.isExternal():
  1250                         providers = getRelevantProviders(descriptor, config)
  1251                         for p in providers:
  1252                             try:
  1253                                 typeDesc = p.getDescriptor(f.inner.identifier.name)
  1254                             except NoSuchDescriptorError:
  1255                                 continue
  1256                             headers.add(typeDesc.headerFile)
  1257                     else:
  1258                         headers.add(CGHeaders.getDeclarationFilename(f.inner))
  1259                     # Check for whether we have a possibly-XPConnect-implemented
  1260                     # interface.  If we do, the right descriptor will come from
  1261                     # providers[0], because that would be the non-worker
  1262                     # descriptor provider, if we have one at all.
  1263                     if (f.isGeckoInterface() and
  1264                         providers[0].getDescriptor(f.inner.identifier.name).hasXPConnectImpls):
  1265                         headers.add("nsDOMQS.h")
  1266                 elif f.isDictionary():
  1267                     headers.add(CGHeaders.getDeclarationFilename(f.inner))
  1268                 elif f.isPrimitive():
  1269                     headers.add("mozilla/dom/PrimitiveConversions.h")
  1270                 elif f.isMozMap():
  1271                     headers.add("mozilla/dom/MozMap.h")
  1272                     # And the internal type of the MozMap
  1273                     addHeadersForType(f.inner, providers)
  1275             for f in t.flatMemberTypes:
  1276                 addHeadersForType(f, providers)
  1278     return (headers,
  1279             CGWrapper(CGList(SortedDictValues(unionConversions), "\n"),
  1280                       post="\n\n"))
  1283 class Argument():
  1284     """
  1285     A class for outputting the type and name of an argument
  1286     """
  1287     def __init__(self, argType, name, default=None):
  1288         self.argType = argType
  1289         self.name = name
  1290         self.default = default
  1292     def declare(self):
  1293         string = self.argType + ' ' + self.name
  1294         if self.default is not None:
  1295             string += " = " + self.default
  1296         return string
  1298     def define(self):
  1299         return self.argType + ' ' + self.name
  1302 class CGAbstractMethod(CGThing):
  1303     """
  1304     An abstract class for generating code for a method.  Subclasses
  1305     should override definition_body to create the actual code.
  1307     descriptor is the descriptor for the interface the method is associated with
  1309     name is the name of the method as a string
  1311     returnType is the IDLType of the return value
  1313     args is a list of Argument objects
  1315     inline should be True to generate an inline method, whose body is
  1316     part of the declaration.
  1318     alwaysInline should be True to generate an inline method annotated with
  1319     MOZ_ALWAYS_INLINE.
  1321     static should be True to generate a static method, which only has
  1322     a definition.
  1324     If templateArgs is not None it should be a list of strings containing
  1325     template arguments, and the function will be templatized using those
  1326     arguments.
  1327     """
  1328     def __init__(self, descriptor, name, returnType, args, inline=False, alwaysInline=False, static=False, templateArgs=None):
  1329         CGThing.__init__(self)
  1330         self.descriptor = descriptor
  1331         self.name = name
  1332         self.returnType = returnType
  1333         self.args = args
  1334         self.inline = inline
  1335         self.alwaysInline = alwaysInline
  1336         self.static = static
  1337         self.templateArgs = templateArgs
  1339     def _argstring(self, declare):
  1340         return ', '.join([a.declare() if declare else a.define() for a in self.args])
  1342     def _template(self):
  1343         if self.templateArgs is None:
  1344             return ''
  1345         return 'template <%s>\n' % ', '.join(self.templateArgs)
  1347     def _decorators(self):
  1348         decorators = []
  1349         if self.alwaysInline:
  1350             decorators.append('MOZ_ALWAYS_INLINE')
  1351         elif self.inline:
  1352             decorators.append('inline')
  1353         if self.static:
  1354             decorators.append('static')
  1355         decorators.append(self.returnType)
  1356         maybeNewline = " " if self.inline else "\n"
  1357         return ' '.join(decorators) + maybeNewline
  1359     def declare(self):
  1360         if self.inline:
  1361             return self._define(True)
  1362         return "%s%s%s(%s);\n" % (self._template(), self._decorators(), self.name, self._argstring(True))
  1364     def _define(self, fromDeclare=False):
  1365         return self.definition_prologue(fromDeclare) + self.definition_body() + self.definition_epilogue()
  1367     def define(self):
  1368         return "" if self.inline else self._define()
  1370     def definition_prologue(self, fromDeclare):
  1371         return "%s%s%s(%s)\n{\n" % (self._template(), self._decorators(),
  1372                                     self.name, self._argstring(fromDeclare))
  1374     def definition_epilogue(self):
  1375         return "}\n"
  1377     def definition_body(self):
  1378         assert False  # Override me!
  1381 class CGAbstractStaticMethod(CGAbstractMethod):
  1382     """
  1383     Abstract base class for codegen of implementation-only (no
  1384     declaration) static methods.
  1385     """
  1386     def __init__(self, descriptor, name, returnType, args):
  1387         CGAbstractMethod.__init__(self, descriptor, name, returnType, args,
  1388                                   inline=False, static=True)
  1390     def declare(self):
  1391         # We only have implementation
  1392         return ""
  1395 class CGAbstractClassHook(CGAbstractStaticMethod):
  1396     """
  1397     Meant for implementing JSClass hooks, like Finalize or Trace. Does very raw
  1398     'this' unwrapping as it assumes that the unwrapped type is always known.
  1399     """
  1400     def __init__(self, descriptor, name, returnType, args):
  1401         CGAbstractStaticMethod.__init__(self, descriptor, name, returnType,
  1402                                         args)
  1404     def definition_body_prologue(self):
  1405         return ("\n"  # BOGUS extra blank line at start of function
  1406                 "  %s* self = UnwrapDOMObject<%s>(obj);\n" %
  1407                 (self.descriptor.nativeType, self.descriptor.nativeType))
  1409     def definition_body(self):
  1410         return self.definition_body_prologue() + self.generate_code()
  1412     def generate_code(self):
  1413         assert False  # Override me!
  1416 class CGGetJSClassMethod(CGAbstractMethod):
  1417     def __init__(self, descriptor):
  1418         CGAbstractMethod.__init__(self, descriptor, 'GetJSClass', 'const JSClass*',
  1419                                   [])
  1421     def definition_body(self):
  1422         return "  return Class.ToJSClass();\n"
  1425 class CGAddPropertyHook(CGAbstractClassHook):
  1426     """
  1427     A hook for addProperty, used to preserve our wrapper from GC.
  1428     """
  1429     def __init__(self, descriptor):
  1430         args = [Argument('JSContext*', 'cx'),
  1431                 Argument('JS::Handle<JSObject*>', 'obj'),
  1432                 Argument('JS::Handle<jsid>', 'id'),
  1433                 Argument('JS::MutableHandle<JS::Value>', 'vp')]
  1434         CGAbstractClassHook.__init__(self, descriptor, ADDPROPERTY_HOOK_NAME,
  1435                                      'bool', args)
  1437     def generate_code(self):
  1438         assert self.descriptor.wrapperCache
  1439         return indent(dedent("""
  1440             // We don't want to preserve if we don't have a wrapper.
  1441             if (self->GetWrapperPreserveColor()) {
  1442               PreserveWrapper(self);
  1444             return true;
  1445             """))
  1448 def DeferredFinalizeSmartPtr(descriptor):
  1449     if descriptor.nativeOwnership == 'owned':
  1450         smartPtr = 'nsAutoPtr'
  1451     else:
  1452         smartPtr = 'nsRefPtr'
  1453     return smartPtr
  1456 def finalizeHook(descriptor, hookName, freeOp):
  1457     finalize = "JSBindingFinalized<%s>::Finalized(self);\n" % descriptor.nativeType
  1458     if descriptor.wrapperCache:
  1459         finalize += "ClearWrapper(self, self);\n"
  1460     if descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
  1461         finalize += "self->mExpandoAndGeneration.expando = JS::UndefinedValue();\n"
  1462     if descriptor.interface.getExtendedAttribute("Global"):
  1463         finalize += "mozilla::dom::FinalizeGlobal(CastToJSFreeOp(%s), obj);\n" % freeOp
  1464     finalize += ("AddForDeferredFinalization<%s, %s >(self);\n" %
  1465                  (descriptor.nativeType, DeferredFinalizeSmartPtr(descriptor)))
  1466     return CGIfWrapper(CGGeneric(finalize), "self")
  1469 class CGClassFinalizeHook(CGAbstractClassHook):
  1470     """
  1471     A hook for finalize, used to release our native object.
  1472     """
  1473     def __init__(self, descriptor):
  1474         args = [Argument('js::FreeOp*', 'fop'), Argument('JSObject*', 'obj')]
  1475         CGAbstractClassHook.__init__(self, descriptor, FINALIZE_HOOK_NAME,
  1476                                      'void', args)
  1478     def generate_code(self):
  1479         return indent(finalizeHook(self.descriptor, self.name, self.args[0].name).define())
  1482 class CGClassConstructor(CGAbstractStaticMethod):
  1483     """
  1484     JS-visible constructor for our objects
  1485     """
  1486     def __init__(self, descriptor, ctor, name=CONSTRUCT_HOOK_NAME):
  1487         args = [Argument('JSContext*', 'cx'),
  1488                 Argument('unsigned', 'argc'),
  1489                 Argument('JS::Value*', 'vp')]
  1490         CGAbstractStaticMethod.__init__(self, descriptor, name, 'bool', args)
  1491         self._ctor = ctor
  1493     def define(self):
  1494         if not self._ctor:
  1495             return ""
  1496         return CGAbstractStaticMethod.define(self)
  1498     def definition_body(self):
  1499         return self.generate_code()
  1501     def generate_code(self):
  1502         # [ChromeOnly] interfaces may only be constructed by chrome.
  1503         chromeOnlyCheck = ""
  1504         if isChromeOnly(self._ctor):
  1505             chromeOnlyCheck = dedent("""
  1506                 if (!nsContentUtils::ThreadsafeIsCallerChrome()) {
  1507                   return ThrowingConstructor(cx, argc, vp);
  1510                 """)
  1512         # Additionally, we want to throw if a caller does a bareword invocation
  1513         # of a constructor without |new|. We don't enforce this for chrome in
  1514         # realease builds to avoid the addon compat fallout of making that
  1515         # change. See bug 916644.
  1517         # Figure out the name of our constructor for error reporting purposes.
  1518         # For unnamed webidl constructors, identifier.name is "constructor" but
  1519         # the name JS sees is the interface name; for named constructors
  1520         # identifier.name is the actual name.
  1521         name = self._ctor.identifier.name
  1522         if name != "constructor":
  1523             ctorName = name
  1524         else:
  1525             ctorName = self.descriptor.interface.identifier.name
  1527         preamble = fill(  # BOGUS extra blank line at beginning of function body
  1528             """
  1530             JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  1531             JS::Rooted<JSObject*> obj(cx, &args.callee());
  1532             $*{chromeOnlyCheck}
  1533             bool mayInvoke = args.isConstructing();
  1534             #ifdef RELEASE_BUILD
  1535             mayInvoke = mayInvoke || nsContentUtils::ThreadsafeIsCallerChrome();
  1536             #endif // RELEASE_BUILD
  1537             if (!mayInvoke) {
  1538               // XXXbz wish I could get the name from the callee instead of
  1539               // Adding more relocations
  1540               return ThrowConstructorWithoutNew(cx, "${ctorName}");
  1542             """,
  1543             chromeOnlyCheck=chromeOnlyCheck,
  1544             ctorName=ctorName)
  1546         name = self._ctor.identifier.name
  1547         nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
  1548         callGenerator = CGMethodCall(nativeName, True, self.descriptor,
  1549                                      self._ctor, isConstructor=True,
  1550                                      constructorName=ctorName)
  1551         return indent(preamble) + callGenerator.define()
  1554 # Encapsulate the constructor in a helper method to share genConstructorBody with CGJSImplMethod.
  1555 class CGConstructNavigatorObjectHelper(CGAbstractStaticMethod):
  1556     """
  1557     Construct a new JS-implemented WebIDL DOM object, for use on navigator.
  1558     """
  1559     def __init__(self, descriptor):
  1560         name = "ConstructNavigatorObjectHelper"
  1561         args = [Argument('JSContext*', 'cx'),
  1562                 Argument('GlobalObject&', 'global'),
  1563                 Argument('ErrorResult&', 'aRv')]
  1564         rtype = 'already_AddRefed<%s>' % descriptor.name
  1565         CGAbstractStaticMethod.__init__(self, descriptor, name, rtype, args)
  1567     def definition_body(self):
  1568         return indent(genConstructorBody(self.descriptor))
  1571 class CGConstructNavigatorObject(CGAbstractMethod):
  1572     """
  1573     Wrap a JS-implemented WebIDL object into a JS value, for use on navigator.
  1574     """
  1575     def __init__(self, descriptor):
  1576         name = 'ConstructNavigatorObject'
  1577         args = [Argument('JSContext*', 'aCx'), Argument('JS::Handle<JSObject*>', 'aObj')]
  1578         CGAbstractMethod.__init__(self, descriptor, name, 'JSObject*', args)
  1580     def definition_body(self):
  1581         if not self.descriptor.interface.isJSImplemented():
  1582             raise TypeError("Only JS-implemented classes are currently supported "
  1583                             "on navigator. See bug 856820.")
  1584         return indent(fill(
  1585             """
  1586             GlobalObject global(aCx, aObj);
  1587             if (global.Failed()) {
  1588               return nullptr;
  1590             ErrorResult rv;
  1591             JS::Rooted<JS::Value> v(aCx);
  1592             {  // Scope to make sure |result| goes out of scope while |v| is rooted
  1593               nsRefPtr<mozilla::dom::${descriptorName}> result = ConstructNavigatorObjectHelper(aCx, global, rv);
  1594               rv.WouldReportJSException();
  1595               if (rv.Failed()) {
  1596                 ThrowMethodFailedWithDetails(aCx, rv, "${descriptorName}", "navigatorConstructor");
  1597                 return nullptr;
  1599               if (!WrapNewBindingObject(aCx, result, &v)) {
  1600                 //XXX Assertion disabled for now, see bug 991271.
  1601                 MOZ_ASSERT(true || JS_IsExceptionPending(aCx));
  1602                 return nullptr;
  1605             return &v.toObject();
  1606             """,
  1607             descriptorName=self.descriptor.name))
  1610 class CGClassConstructHookHolder(CGGeneric):
  1611     def __init__(self, descriptor):
  1612         if descriptor.interface.ctor():
  1613             constructHook = CONSTRUCT_HOOK_NAME
  1614         else:
  1615             constructHook = "ThrowingConstructor"
  1616         CGGeneric.__init__(self, fill(
  1617             """
  1618             static const JSNativeHolder ${CONSTRUCT_HOOK_NAME}_holder = {
  1619               ${constructHook},
  1620               ${hooks}
  1621             };
  1622             """,
  1623             CONSTRUCT_HOOK_NAME=CONSTRUCT_HOOK_NAME,
  1624             constructHook=constructHook,
  1625             hooks=NativePropertyHooks(descriptor)))
  1628 def NamedConstructorName(m):
  1629     return '_' + m.identifier.name
  1632 class CGNamedConstructors(CGThing):
  1633     def __init__(self, descriptor):
  1634         self.descriptor = descriptor
  1635         CGThing.__init__(self)
  1637     def declare(self):
  1638         return ""
  1640     def define(self):
  1641         if len(self.descriptor.interface.namedConstructors) == 0:
  1642             return ""
  1644         constructorID = "constructors::id::"
  1645         if self.descriptor.interface.hasInterfaceObject():
  1646             constructorID += self.descriptor.name
  1647         else:
  1648             constructorID += "_ID_Count"
  1650         namedConstructors = ""
  1651         for n in self.descriptor.interface.namedConstructors:
  1652             namedConstructors += (
  1653                 "{ \"%s\", { %s, &sNamedConstructorNativePropertyHooks }, %i },\n" %
  1654                 (n.identifier.name, NamedConstructorName(n), methodLength(n)))
  1656         return fill(
  1657             """
  1658             const NativePropertyHooks sNamedConstructorNativePropertyHooks = {
  1659                 nullptr,
  1660                 nullptr,
  1661                 { nullptr, nullptr },
  1662                 prototypes::id::${name},
  1663                 ${constructorID},
  1664                 nullptr
  1665             };
  1667             static const NamedConstructor namedConstructors[] = {
  1668               $*{namedConstructors}
  1669               { nullptr, { nullptr, nullptr }, 0 }
  1670             };
  1671             """,
  1672             name=self.descriptor.name,
  1673             constructorID=constructorID,
  1674             namedConstructors=namedConstructors)
  1677 class CGClassHasInstanceHook(CGAbstractStaticMethod):
  1678     def __init__(self, descriptor):
  1679         args = [Argument('JSContext*', 'cx'),
  1680                 Argument('JS::Handle<JSObject*>', 'obj'),
  1681                 Argument('JS::MutableHandle<JS::Value>', 'vp'),
  1682                 Argument('bool*', 'bp')]
  1683         CGAbstractStaticMethod.__init__(self, descriptor, HASINSTANCE_HOOK_NAME,
  1684                                         'bool', args)
  1686     def define(self):
  1687         if not NeedsGeneratedHasInstance(self.descriptor):
  1688             return ""
  1689         return CGAbstractStaticMethod.define(self)
  1691     def definition_body(self):
  1692         return self.generate_code()
  1694     def generate_code(self):
  1695         # BOGUS extra blank line at start of function
  1696         header = dedent("""
  1698             if (!vp.isObject()) {
  1699               *bp = false;
  1700               return true;
  1703             JS::Rooted<JSObject*> instance(cx, &vp.toObject());
  1704             """)
  1705         if self.descriptor.interface.hasInterfacePrototypeObject():
  1706             return indent(
  1707                 header +
  1708                 fill(
  1709                     """
  1711                     static_assert(IsBaseOf<nsISupports, ${nativeType}>::value,
  1712                                   "HasInstance only works for nsISupports-based classes.");
  1714                     bool ok = InterfaceHasInstance(cx, obj, instance, bp);
  1715                     if (!ok || *bp) {
  1716                       return ok;
  1719                     // FIXME Limit this to chrome by checking xpc::AccessCheck::isChrome(obj).
  1720                     nsISupports* native =
  1721                       nsContentUtils::XPConnect()->GetNativeOfWrapper(cx,
  1722                                                                       js::UncheckedUnwrap(instance));
  1723                     nsCOMPtr<nsIDOM${name}> qiResult = do_QueryInterface(native);
  1724                     *bp = !!qiResult;
  1725                     return true;
  1727                     """,  # BOGUS extra blank line at end of function
  1728                     nativeType=self.descriptor.nativeType,
  1729                     name=self.descriptor.interface.identifier.name))
  1731         hasInstanceCode = dedent("""
  1733             const DOMClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance));
  1734             *bp = false;
  1735             if (!domClass) {
  1736               // Not a DOM object, so certainly not an instance of this interface
  1737               return true;
  1739             """)
  1740         if self.descriptor.interface.identifier.name == "ChromeWindow":
  1741             setBp = "*bp = UnwrapDOMObject<nsGlobalWindow>(js::UncheckedUnwrap(instance))->IsChromeWindow()"
  1742         else:
  1743             setBp = "*bp = true"
  1744         # Sort interaces implementing self by name so we get stable output.
  1745         for iface in sorted(self.descriptor.interface.interfacesImplementingSelf,
  1746                             key=lambda iface: iface.identifier.name):
  1747             hasInstanceCode += fill(
  1748                 """
  1750                 if (domClass->mInterfaceChain[PrototypeTraits<prototypes::id::${name}>::Depth] == prototypes::id::${name}) {
  1751                   ${setBp};
  1752                   return true;
  1754                 """,
  1755                 name=iface.identifier.name,
  1756                 setBp=setBp)
  1757         hasInstanceCode += "return true;\n"
  1758         return indent(header + hasInstanceCode)
  1761 def isChromeOnly(m):
  1762     return m.getExtendedAttribute("ChromeOnly")
  1765 def getAvailableInTestFunc(obj):
  1766     availableIn = obj.getExtendedAttribute("AvailableIn")
  1767     if availableIn is None:
  1768         return None
  1769     assert isinstance(availableIn, list) and len(availableIn) == 1
  1770     if availableIn[0] == "PrivilegedApps":
  1771         return "IsInPrivilegedApp"
  1772     if availableIn[0] == "CertifiedApps":
  1773         return "IsInCertifiedApp"
  1774     raise TypeError("Unknown AvailableIn value '%s'" % availableIn[0])
  1777 class MemberCondition:
  1778     """
  1779     An object representing the condition for a member to actually be
  1780     exposed.  Any of pref, func, and available can be None.  If not
  1781     None, they should be strings that have the pref name (for "pref")
  1782     or function name (for "func" and "available").
  1783     """
  1784     def __init__(self, pref, func, available=None):
  1785         assert pref is None or isinstance(pref, str)
  1786         assert func is None or isinstance(func, str)
  1787         assert available is None or isinstance(available, str)
  1788         self.pref = pref
  1790         def toFuncPtr(val):
  1791             if val is None:
  1792                 return "nullptr"
  1793             return "&" + val
  1794         self.func = toFuncPtr(func)
  1795         self.available = toFuncPtr(available)
  1797     def __eq__(self, other):
  1798         return (self.pref == other.pref and self.func == other.func and
  1799                 self.available == other.available)
  1801     def __ne__(self, other):
  1802         return not self.__eq__(other)
  1805 class PropertyDefiner:
  1806     """
  1807     A common superclass for defining things on prototype objects.
  1809     Subclasses should implement generateArray to generate the actual arrays of
  1810     things we're defining.  They should also set self.chrome to the list of
  1811     things only exposed to chrome and self.regular to the list of things exposed
  1812     to both chrome and web pages.
  1813     """
  1814     def __init__(self, descriptor, name):
  1815         self.descriptor = descriptor
  1816         self.name = name
  1817         # self.prefCacheData will store an array of (prefname, bool*)
  1818         # pairs for our bool var caches.  generateArray will fill it
  1819         # in as needed.
  1820         self.prefCacheData = []
  1822     def hasChromeOnly(self):
  1823         return len(self.chrome) > 0
  1825     def hasNonChromeOnly(self):
  1826         return len(self.regular) > 0
  1828     def variableName(self, chrome):
  1829         if chrome:
  1830             if self.hasChromeOnly():
  1831                 return "sChrome" + self.name
  1832         else:
  1833             if self.hasNonChromeOnly():
  1834                 return "s" + self.name
  1835         return "nullptr"
  1837     def usedForXrays(self):
  1838         # No Xrays in workers.
  1839         return not self.descriptor.workers
  1841     def __str__(self):
  1842         # We only need to generate id arrays for things that will end
  1843         # up used via ResolveProperty or EnumerateProperties.
  1844         str = self.generateArray(self.regular, self.variableName(False),
  1845                                  self.usedForXrays())
  1846         if self.hasChromeOnly():
  1847             str += self.generateArray(self.chrome, self.variableName(True),
  1848                                       self.usedForXrays())
  1849         return str
  1851     @staticmethod
  1852     def getStringAttr(member, name):
  1853         attr = member.getExtendedAttribute(name)
  1854         if attr is None:
  1855             return None
  1856         # It's a list of strings
  1857         assert len(attr) == 1
  1858         assert attr[0] is not None
  1859         return attr[0]
  1861     @staticmethod
  1862     def getControllingCondition(interfaceMember):
  1863         return MemberCondition(PropertyDefiner.getStringAttr(interfaceMember,
  1864                                                              "Pref"),
  1865                                PropertyDefiner.getStringAttr(interfaceMember,
  1866                                                              "Func"),
  1867                                getAvailableInTestFunc(interfaceMember))
  1869     def generatePrefableArray(self, array, name, specTemplate, specTerminator,
  1870                               specType, getCondition, getDataTuple, doIdArrays):
  1871         """
  1872         This method generates our various arrays.
  1874         array is an array of interface members as passed to generateArray
  1876         name is the name as passed to generateArray
  1878         specTemplate is a template for each entry of the spec array
  1880         specTerminator is a terminator for the spec array (inserted every time
  1881           our controlling pref changes and at the end of the array)
  1883         specType is the actual typename of our spec
  1885         getCondition is a callback function that takes an array entry and
  1886           returns the corresponding MemberCondition.
  1888         getDataTuple is a callback function that takes an array entry and
  1889           returns a tuple suitable for substitution into specTemplate.
  1890         """
  1892         # We want to generate a single list of specs, but with specTerminator
  1893         # inserted at every point where the pref name controlling the member
  1894         # changes.  That will make sure the order of the properties as exposed
  1895         # on the interface and interface prototype objects does not change when
  1896         # pref control is added to members while still allowing us to define all
  1897         # the members in the smallest number of JSAPI calls.
  1898         assert len(array) != 0
  1899         lastCondition = getCondition(array[0])  # So we won't put a specTerminator
  1900                                                 # at the very front of the list.
  1901         specs = []
  1902         prefableSpecs = []
  1904         prefableTemplate = '  { true, %s, %s, &%s[%d] }'
  1905         prefCacheTemplate = '&%s[%d].enabled'
  1907         def switchToCondition(props, condition):
  1908             # Remember the info about where our pref-controlled
  1909             # booleans live.
  1910             if condition.pref is not None:
  1911                 props.prefCacheData.append(
  1912                     (condition.pref,
  1913                      prefCacheTemplate % (name, len(prefableSpecs))))
  1914             # Set up pointers to the new sets of specs inside prefableSpecs
  1915             prefableSpecs.append(prefableTemplate %
  1916                                  (condition.func,
  1917                                   condition.available,
  1918                                   name + "_specs", len(specs)))
  1920         switchToCondition(self, lastCondition)
  1922         for member in array:
  1923             curCondition = getCondition(member)
  1924             if lastCondition != curCondition:
  1925                 # Terminate previous list
  1926                 specs.append(specTerminator)
  1927                 # And switch to our new pref
  1928                 switchToCondition(self, curCondition)
  1929                 lastCondition = curCondition
  1930             # And the actual spec
  1931             specs.append(specTemplate % getDataTuple(member))
  1932         specs.append(specTerminator)
  1933         prefableSpecs.append("  { false, nullptr }")
  1935         specType = "const " + specType
  1936         arrays = fill(
  1937             """
  1938             static ${specType} ${name}_specs[] = {
  1939             ${specs}
  1940             };
  1942             // Can't be const because the pref-enabled boolean needs to be writable
  1943             static Prefable<${specType}> ${name}[] = {
  1944             ${prefableSpecs}
  1945             };
  1947             """,
  1948             specType=specType,
  1949             name=name,
  1950             specs=',\n'.join(specs),
  1951             prefableSpecs=',\n'.join(prefableSpecs))
  1952         if doIdArrays:
  1953             arrays += "static jsid %s_ids[%i];\n\n" % (name, len(specs))
  1954         return arrays
  1957 # The length of a method is the minimum of the lengths of the
  1958 # argument lists of all its overloads.
  1959 def overloadLength(arguments):
  1960     i = len(arguments)
  1961     while i > 0 and arguments[i - 1].optional:
  1962         i -= 1
  1963     return i
  1966 def methodLength(method):
  1967     signatures = method.signatures()
  1968     return min(overloadLength(arguments) for retType, arguments in signatures)
  1971 class MethodDefiner(PropertyDefiner):
  1972     """
  1973     A class for defining methods on a prototype object.
  1974     """
  1975     def __init__(self, descriptor, name, static):
  1976         PropertyDefiner.__init__(self, descriptor, name)
  1978         # FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=772822
  1979         #       We should be able to check for special operations without an
  1980         #       identifier. For now we check if the name starts with __
  1982         # Ignore non-static methods for interfaces without a proto object
  1983         if descriptor.interface.hasInterfacePrototypeObject() or static:
  1984             methods = [m for m in descriptor.interface.members if
  1985                        m.isMethod() and m.isStatic() == static and
  1986                        not m.isIdentifierLess()]
  1987         else:
  1988             methods = []
  1989         self.chrome = []
  1990         self.regular = []
  1991         for m in methods:
  1992             if m.identifier.name == 'queryInterface':
  1993                 if self.descriptor.workers:
  1994                     continue
  1995                 if m.isStatic():
  1996                     raise TypeError("Legacy queryInterface member shouldn't be static")
  1997                 signatures = m.signatures()
  1999                 def argTypeIsIID(arg):
  2000                     return arg.type.inner.isExternal() and arg.type.inner.identifier.name == 'IID'
  2001                 if len(signatures) > 1 or len(signatures[0][1]) > 1 or not argTypeIsIID(signatures[0][1][0]):
  2002                     raise TypeError("There should be only one queryInterface method with 1 argument of type IID")
  2004                 # Make sure to not stick QueryInterface on abstract interfaces that
  2005                 # have hasXPConnectImpls (like EventTarget).  So only put it on
  2006                 # interfaces that are concrete and all of whose ancestors are abstract.
  2007                 def allAncestorsAbstract(iface):
  2008                     if not iface.parent:
  2009                         return True
  2010                     desc = self.descriptor.getDescriptor(iface.parent.identifier.name)
  2011                     if desc.concrete:
  2012                         return False
  2013                     return allAncestorsAbstract(iface.parent)
  2014                 if (not self.descriptor.interface.hasInterfacePrototypeObject() or
  2015                     not self.descriptor.concrete or
  2016                     not allAncestorsAbstract(self.descriptor.interface)):
  2017                     raise TypeError("QueryInterface is only supported on "
  2018                                     "interfaces that are concrete and all "
  2019                                     "of whose ancestors are abstract: " +
  2020                                     self.descriptor.name)
  2021                 condition = "WantsQueryInterface<%s>::Enabled" % descriptor.nativeType
  2022                 self.regular.append({
  2023                     "name": 'QueryInterface',
  2024                     "methodInfo": False,
  2025                     "length": 1,
  2026                     "flags": "0",
  2027                     "condition": MemberCondition(None, condition)
  2028                 })
  2029                 continue
  2031             method = {
  2032                 "name": m.identifier.name,
  2033                 "methodInfo": not m.isStatic(),
  2034                 "length": methodLength(m),
  2035                 "flags": "JSPROP_ENUMERATE",
  2036                 "condition": PropertyDefiner.getControllingCondition(m),
  2037                 "allowCrossOriginThis": m.getExtendedAttribute("CrossOriginCallable"),
  2038                 "returnsPromise": m.returnsPromise()
  2040             if isChromeOnly(m):
  2041                 self.chrome.append(method)
  2042             else:
  2043                 self.regular.append(method)
  2045         # FIXME Check for an existing iterator on the interface first.
  2046         if any(m.isGetter() and m.isIndexed() for m in methods):
  2047             self.regular.append({
  2048                 "name": "@@iterator",
  2049                 "methodInfo": False,
  2050                 "selfHostedName": "ArrayValues",
  2051                 "length": 0,
  2052                 "flags": "JSPROP_ENUMERATE",
  2053                 "condition": MemberCondition(None, None)
  2054             })
  2056         if not static:
  2057             stringifier = descriptor.operations['Stringifier']
  2058             if stringifier:
  2059                 toStringDesc = {
  2060                     "name": "toString",
  2061                     "nativeName": stringifier.identifier.name,
  2062                     "length": 0,
  2063                     "flags": "JSPROP_ENUMERATE",
  2064                     "condition": PropertyDefiner.getControllingCondition(stringifier)
  2066                 if isChromeOnly(stringifier):
  2067                     self.chrome.append(toStringDesc)
  2068                 else:
  2069                     self.regular.append(toStringDesc)
  2070             jsonifier = descriptor.operations['Jsonifier']
  2071             if jsonifier:
  2072                 toJSONDesc = {
  2073                     "name": "toJSON",
  2074                     "nativeName": jsonifier.identifier.name,
  2075                     "length": 0,
  2076                     "flags": "JSPROP_ENUMERATE",
  2077                     "condition": PropertyDefiner.getControllingCondition(jsonifier)
  2079                 if isChromeOnly(jsonifier):
  2080                     self.chrome.append(toJSONDesc)
  2081                 else:
  2082                     self.regular.append(toJSONDesc)
  2083         elif (descriptor.interface.isJSImplemented() and
  2084               descriptor.interface.hasInterfaceObject()):
  2085             self.chrome.append({
  2086                 "name": '_create',
  2087                 "nativeName": ("%s::_Create" % descriptor.name),
  2088                 "methodInfo": False,
  2089                 "length": 2,
  2090                 "flags": "0",
  2091                 "condition": MemberCondition(None, None)
  2092             })
  2094         if static:
  2095             if not descriptor.interface.hasInterfaceObject():
  2096                 # static methods go on the interface object
  2097                 assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
  2098         else:
  2099             if not descriptor.interface.hasInterfacePrototypeObject():
  2100                 # non-static methods go on the interface prototype object
  2101                 assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
  2103     def generateArray(self, array, name, doIdArrays):
  2104         if len(array) == 0:
  2105             return ""
  2107         def condition(m):
  2108             return m["condition"]
  2110         def specData(m):
  2111             if "selfHostedName" in m:
  2112                 selfHostedName = '"%s"' % m["selfHostedName"]
  2113                 assert not m.get("methodInfo", True)
  2114                 accessor = "nullptr"
  2115                 jitinfo = "nullptr"
  2116             else:
  2117                 selfHostedName = "nullptr"
  2118                 accessor = m.get("nativeName", m["name"])
  2119                 if m.get("methodInfo", True):
  2120                     # Cast this in case the methodInfo is a
  2121                     # JSTypedMethodJitInfo.
  2122                     jitinfo = ("reinterpret_cast<const JSJitInfo*>(&%s_methodinfo)" % accessor)
  2123                     if m.get("allowCrossOriginThis", False):
  2124                         if m.get("returnsPromise", False):
  2125                             raise TypeError("%s returns a Promise but should "
  2126                                             "be allowed cross-origin?" %
  2127                                             accessor)
  2128                         accessor = "genericCrossOriginMethod"
  2129                     elif self.descriptor.needsSpecialGenericOps():
  2130                         if m.get("returnsPromise", False):
  2131                             raise TypeError("%s returns a Promise but needs "
  2132                                             "special generic ops?" %
  2133                                             accessor)
  2134                         accessor = "genericMethod"
  2135                     elif m.get("returnsPromise", False):
  2136                         accessor = "GenericPromiseReturningBindingMethod"
  2137                     else:
  2138                         accessor = "GenericBindingMethod"
  2139                 else:
  2140                     if m.get("returnsPromise", False):
  2141                         jitinfo = "&%s_methodinfo" % accessor
  2142                         accessor = "StaticMethodPromiseWrapper"
  2143                     else:
  2144                         jitinfo = "nullptr"
  2146             return (m["name"], accessor, jitinfo, m["length"], m["flags"], selfHostedName)
  2148         return self.generatePrefableArray(
  2149             array, name,
  2150             '  JS_FNSPEC("%s", %s, %s, %s, %s, %s)',
  2151             '  JS_FS_END',
  2152             'JSFunctionSpec',
  2153             condition, specData, doIdArrays)
  2156 class AttrDefiner(PropertyDefiner):
  2157     def __init__(self, descriptor, name, static, unforgeable=False):
  2158         assert not (static and unforgeable)
  2159         PropertyDefiner.__init__(self, descriptor, name)
  2160         self.name = name
  2161         # Ignore non-static attributes for interfaces without a proto object
  2162         if descriptor.interface.hasInterfacePrototypeObject() or static:
  2163             attributes = [m for m in descriptor.interface.members if
  2164                           m.isAttr() and m.isStatic() == static and
  2165                           m.isUnforgeable() == unforgeable]
  2166         else:
  2167             attributes = []
  2168         self.chrome = [m for m in attributes if isChromeOnly(m)]
  2169         self.regular = [m for m in attributes if not isChromeOnly(m)]
  2170         self.static = static
  2171         self.unforgeable = unforgeable
  2173         if static:
  2174             if not descriptor.interface.hasInterfaceObject():
  2175                 # static attributes go on the interface object
  2176                 assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
  2177         else:
  2178             if not descriptor.interface.hasInterfacePrototypeObject():
  2179                 # non-static attributes go on the interface prototype object
  2180                 assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
  2182     def generateArray(self, array, name, doIdArrays):
  2183         if len(array) == 0:
  2184             return ""
  2186         def flags(attr):
  2187             unforgeable = " | JSPROP_PERMANENT" if self.unforgeable else ""
  2188             return ("JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_NATIVE_ACCESSORS" +
  2189                     unforgeable)
  2191         def getter(attr):
  2192             if self.static:
  2193                 accessor = 'get_' + attr.identifier.name
  2194                 jitinfo = "nullptr"
  2195             else:
  2196                 if attr.hasLenientThis():
  2197                     accessor = "genericLenientGetter"
  2198                 elif attr.getExtendedAttribute("CrossOriginReadable"):
  2199                     accessor = "genericCrossOriginGetter"
  2200                 elif self.descriptor.needsSpecialGenericOps():
  2201                     accessor = "genericGetter"
  2202                 else:
  2203                     accessor = "GenericBindingGetter"
  2204                 jitinfo = "&%s_getterinfo" % attr.identifier.name
  2205             return "{ { JS_CAST_NATIVE_TO(%s, JSPropertyOp), %s } }" % \
  2206                    (accessor, jitinfo)
  2208         def setter(attr):
  2209             if (attr.readonly and
  2210                 attr.getExtendedAttribute("PutForwards") is None and
  2211                 attr.getExtendedAttribute("Replaceable") is None):
  2212                 return "JSOP_NULLWRAPPER"
  2213             if self.static:
  2214                 accessor = 'set_' + attr.identifier.name
  2215                 jitinfo = "nullptr"
  2216             else:
  2217                 if attr.hasLenientThis():
  2218                     accessor = "genericLenientSetter"
  2219                 elif attr.getExtendedAttribute("CrossOriginWritable"):
  2220                     accessor = "genericCrossOriginSetter"
  2221                 elif self.descriptor.needsSpecialGenericOps():
  2222                     accessor = "genericSetter"
  2223                 else:
  2224                     accessor = "GenericBindingSetter"
  2225                 jitinfo = "&%s_setterinfo" % attr.identifier.name
  2226             return "{ { JS_CAST_NATIVE_TO(%s, JSStrictPropertyOp), %s } }" % \
  2227                    (accessor, jitinfo)
  2229         def specData(attr):
  2230             return (attr.identifier.name, flags(attr), getter(attr),
  2231                     setter(attr))
  2233         return self.generatePrefableArray(
  2234             array, name,
  2235             '  { "%s", %s, %s, %s}',
  2236             '  JS_PS_END',
  2237             'JSPropertySpec',
  2238             PropertyDefiner.getControllingCondition, specData, doIdArrays)
  2241 class ConstDefiner(PropertyDefiner):
  2242     """
  2243     A class for definining constants on the interface object
  2244     """
  2245     def __init__(self, descriptor, name):
  2246         PropertyDefiner.__init__(self, descriptor, name)
  2247         self.name = name
  2248         constants = [m for m in descriptor.interface.members if m.isConst()]
  2249         self.chrome = [m for m in constants if isChromeOnly(m)]
  2250         self.regular = [m for m in constants if not isChromeOnly(m)]
  2252     def generateArray(self, array, name, doIdArrays):
  2253         if len(array) == 0:
  2254             return ""
  2256         def specData(const):
  2257             return (const.identifier.name,
  2258                     convertConstIDLValueToJSVal(const.value))
  2260         return self.generatePrefableArray(
  2261             array, name,
  2262             '  { "%s", %s }',
  2263             '  { 0, JS::UndefinedValue() }',
  2264             'ConstantSpec',
  2265             PropertyDefiner.getControllingCondition, specData, doIdArrays)
  2268 class PropertyArrays():
  2269     def __init__(self, descriptor):
  2270         self.staticMethods = MethodDefiner(descriptor, "StaticMethods",
  2271                                            static=True)
  2272         self.staticAttrs = AttrDefiner(descriptor, "StaticAttributes",
  2273                                        static=True)
  2274         self.methods = MethodDefiner(descriptor, "Methods", static=False)
  2275         self.attrs = AttrDefiner(descriptor, "Attributes", static=False)
  2276         self.unforgeableAttrs = AttrDefiner(descriptor, "UnforgeableAttributes",
  2277                                             static=False, unforgeable=True)
  2278         self.consts = ConstDefiner(descriptor, "Constants")
  2280     @staticmethod
  2281     def arrayNames():
  2282         return ["staticMethods", "staticAttrs", "methods", "attrs",
  2283                 "unforgeableAttrs", "consts"]
  2285     def hasChromeOnly(self):
  2286         return any(getattr(self, a).hasChromeOnly() for a in self.arrayNames())
  2288     def hasNonChromeOnly(self):
  2289         return any(getattr(self, a).hasNonChromeOnly() for a in self.arrayNames())
  2291     def __str__(self):
  2292         define = ""
  2293         for array in self.arrayNames():
  2294             define += str(getattr(self, array))
  2295         return define
  2298 class CGNativeProperties(CGList):
  2299     def __init__(self, descriptor, properties):
  2300         def generateNativeProperties(name, chrome):
  2301             def check(p):
  2302                 return p.hasChromeOnly() if chrome else p.hasNonChromeOnly()
  2304             nativeProps = []
  2305             for array in properties.arrayNames():
  2306                 propertyArray = getattr(properties, array)
  2307                 if check(propertyArray):
  2308                     if propertyArray.usedForXrays():
  2309                         ids = "%(name)s_ids"
  2310                     else:
  2311                         ids = "nullptr"
  2312                     props = "%(name)s, " + ids + ", %(name)s_specs"
  2313                     props = (props % {'name': propertyArray.variableName(chrome)})
  2314                 else:
  2315                     props = "nullptr, nullptr, nullptr"
  2316                 nativeProps.append(CGGeneric(props))
  2317             return CGWrapper(CGIndenter(CGList(nativeProps, ",\n")),
  2318                              pre="static const NativeProperties %s = {\n" % name,
  2319                              post="\n};\n")
  2321         nativeProperties = []
  2322         if properties.hasNonChromeOnly():
  2323             nativeProperties.append(
  2324                 generateNativeProperties("sNativeProperties", False))
  2325         if properties.hasChromeOnly():
  2326             nativeProperties.append(
  2327                 generateNativeProperties("sChromeOnlyNativeProperties", True))
  2329         CGList.__init__(self, nativeProperties, "\n")
  2331     def declare(self):
  2332         return ""
  2334     def define(self):
  2335         # BOGUSly strip off a newline
  2336         return CGList.define(self).rstrip()
  2339 class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
  2340     """
  2341     Generate the CreateInterfaceObjects method for an interface descriptor.
  2343     properties should be a PropertyArrays instance.
  2344     """
  2345     def __init__(self, descriptor, properties):
  2346         args = [Argument('JSContext*', 'aCx'),
  2347                 Argument('JS::Handle<JSObject*>', 'aGlobal'),
  2348                 Argument('ProtoAndIfaceCache&', 'aProtoAndIfaceCache'),
  2349                 Argument('bool', 'aDefineOnGlobal')]
  2350         CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args)
  2351         self.properties = properties
  2353     def definition_body(self):
  2354         if len(self.descriptor.prototypeChain) == 1:
  2355             parentProtoType = "Rooted"
  2356             if self.descriptor.interface.getExtendedAttribute("ArrayClass"):
  2357                 getParentProto = "aCx, JS_GetArrayPrototype(aCx, aGlobal)"
  2358             else:
  2359                 getParentProto = "aCx, JS_GetObjectPrototype(aCx, aGlobal)"
  2360         else:
  2361             parentProtoName = self.descriptor.prototypeChain[-2]
  2362             parentDesc = self.descriptor.getDescriptor(parentProtoName)
  2363             if parentDesc.workers:
  2364                 parentProtoName += '_workers'
  2365             getParentProto = ("%s::GetProtoObject(aCx, aGlobal)" %
  2366                               toBindingNamespace(parentProtoName))
  2367             parentProtoType = "Handle"
  2369         parentWithInterfaceObject = self.descriptor.interface.parent
  2370         while (parentWithInterfaceObject and
  2371                not parentWithInterfaceObject.hasInterfaceObject()):
  2372             parentWithInterfaceObject = parentWithInterfaceObject.parent
  2373         if parentWithInterfaceObject:
  2374             parentIfaceName = parentWithInterfaceObject.identifier.name
  2375             parentDesc = self.descriptor.getDescriptor(parentIfaceName)
  2376             if parentDesc.workers:
  2377                 parentIfaceName += "_workers"
  2378             getConstructorProto = ("%s::GetConstructorObject(aCx, aGlobal)" %
  2379                                    toBindingNamespace(parentIfaceName))
  2380             constructorProtoType = "Handle"
  2381         else:
  2382             getConstructorProto = "aCx, JS_GetFunctionPrototype(aCx, aGlobal)"
  2383             constructorProtoType = "Rooted"
  2385         needInterfaceObject = self.descriptor.interface.hasInterfaceObject()
  2386         needInterfacePrototypeObject = self.descriptor.interface.hasInterfacePrototypeObject()
  2388         # if we don't need to create anything, why are we generating this?
  2389         assert needInterfaceObject or needInterfacePrototypeObject
  2391         idsToInit = []
  2392         # There is no need to init any IDs in workers, because worker bindings
  2393         # don't have Xrays.
  2394         if not self.descriptor.workers:
  2395             for var in self.properties.arrayNames():
  2396                 props = getattr(self.properties, var)
  2397                 # We only have non-chrome ids to init if we have no chrome ids.
  2398                 if props.hasChromeOnly():
  2399                     idsToInit.append(props.variableName(True))
  2400                 if props.hasNonChromeOnly():
  2401                     idsToInit.append(props.variableName(False))
  2402         if len(idsToInit) > 0:
  2403             initIdCalls = ["!InitIds(aCx, %s, %s_ids)" % (varname, varname)
  2404                            for varname in idsToInit]
  2405             idsInitedFlag = CGGeneric("static bool sIdsInited = false;\n")
  2406             setFlag = CGGeneric("sIdsInited = true;\n")
  2407             initIdConditionals = [CGIfWrapper(CGGeneric("return;\n"), call)
  2408                                   for call in initIdCalls]
  2409             initIds = CGList([idsInitedFlag,
  2410                               CGIfWrapper(CGList(initIdConditionals + [setFlag]),
  2411                                           "!sIdsInited && NS_IsMainThread()")])
  2412         else:
  2413             initIds = None
  2415         prefCacheData = []
  2416         for var in self.properties.arrayNames():
  2417             props = getattr(self.properties, var)
  2418             prefCacheData.extend(props.prefCacheData)
  2419         if len(prefCacheData) != 0:
  2420             prefCacheData = [
  2421                 CGGeneric('Preferences::AddBoolVarCache(%s, "%s");\n' % (ptr, pref))
  2422                 for pref, ptr in prefCacheData]
  2423             prefCache = CGWrapper(CGIndenter(CGList(prefCacheData)),
  2424                                   pre=("static bool sPrefCachesInited = false;\n"
  2425                                        "if (!sPrefCachesInited) {\n"
  2426                                        "  sPrefCachesInited = true;\n"),
  2427                                   post="}\n")
  2428         else:
  2429             prefCache = None
  2431         if UseHolderForUnforgeable(self.descriptor):
  2432             createUnforgeableHolder = CGGeneric(dedent("""
  2433                 JS::Rooted<JSObject*> unforgeableHolder(aCx,
  2434                   JS_NewObjectWithGivenProto(aCx, nullptr, JS::NullPtr(), JS::NullPtr()));
  2435                 if (!unforgeableHolder) {
  2436                   return;
  2438                 """))
  2439             defineUnforgeables = InitUnforgeablePropertiesOnObject(self.descriptor,
  2440                                                                    "unforgeableHolder",
  2441                                                                    self.properties)
  2442             createUnforgeableHolder = CGList(
  2443                 [createUnforgeableHolder, defineUnforgeables])
  2444         else:
  2445             createUnforgeableHolder = None
  2447         getParentProto = fill(
  2448             """
  2449             JS::${type}<JSObject*> parentProto(${getParentProto});
  2450             if (!parentProto) {
  2451               return;
  2453             """,
  2454             type=parentProtoType,
  2455             getParentProto=getParentProto)
  2457         getConstructorProto = fill(
  2458             """
  2459             JS::${type}<JSObject*> constructorProto(${getConstructorProto});
  2460             if (!constructorProto) {
  2461               return;
  2463             """,
  2464             type=constructorProtoType,
  2465             getConstructorProto=getConstructorProto)
  2467         if (needInterfaceObject and
  2468             self.descriptor.needsConstructHookHolder()):
  2469             constructHookHolder = "&" + CONSTRUCT_HOOK_NAME + "_holder"
  2470         else:
  2471             constructHookHolder = "nullptr"
  2472         if self.descriptor.interface.ctor():
  2473             constructArgs = methodLength(self.descriptor.interface.ctor())
  2474         else:
  2475             constructArgs = 0
  2476         if len(self.descriptor.interface.namedConstructors) > 0:
  2477             namedConstructors = "namedConstructors"
  2478         else:
  2479             namedConstructors = "nullptr"
  2481         if needInterfacePrototypeObject:
  2482             protoClass = "&PrototypeClass.mBase"
  2483             protoCache = "&aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::%s)" % self.descriptor.name
  2484         else:
  2485             protoClass = "nullptr"
  2486             protoCache = "nullptr"
  2487         if needInterfaceObject:
  2488             interfaceClass = "&InterfaceObjectClass.mBase"
  2489             interfaceCache = "&aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::%s)" % self.descriptor.name
  2490         else:
  2491             # We don't have slots to store the named constructors.
  2492             assert len(self.descriptor.interface.namedConstructors) == 0
  2493             interfaceClass = "nullptr"
  2494             interfaceCache = "nullptr"
  2496         if self.descriptor.concrete:
  2497             domClass = "&Class.mClass"
  2498         else:
  2499             domClass = "nullptr"
  2501         if self.properties.hasNonChromeOnly():
  2502             properties = "&sNativeProperties"
  2503         else:
  2504             properties = "nullptr"
  2505         if self.properties.hasChromeOnly():
  2506             accessCheck = "nsContentUtils::ThreadsafeIsCallerChrome()"
  2507             chromeProperties = accessCheck + " ? &sChromeOnlyNativeProperties : nullptr"
  2508         else:
  2509             chromeProperties = "nullptr"
  2511         call = fill(
  2512             """
  2513             dom::CreateInterfaceObjects(aCx, aGlobal, parentProto,
  2514                                         ${protoClass}, ${protoCache},
  2515                                         constructorProto, ${interfaceClass}, ${constructHookHolder}, ${constructArgs}, ${namedConstructors},
  2516                                         ${interfaceCache},
  2517                                         ${domClass},
  2518                                         ${properties},
  2519                                         ${chromeProperties},
  2520                                         ${name}, aDefineOnGlobal);
  2521             """,
  2522             protoClass=protoClass,
  2523             protoCache=protoCache,
  2524             interfaceClass=interfaceClass,
  2525             constructHookHolder=constructHookHolder,
  2526             constructArgs=constructArgs,
  2527             namedConstructors=namedConstructors,
  2528             interfaceCache=interfaceCache,
  2529             domClass=domClass,
  2530             properties=properties,
  2531             chromeProperties=chromeProperties,
  2532             name='"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "nullptr")
  2534         if UseHolderForUnforgeable(self.descriptor):
  2535             assert needInterfacePrototypeObject
  2536             setUnforgeableHolder = CGGeneric(fill(
  2537                 """
  2538                 JSObject* proto = aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::${name});
  2539                 if (proto) {
  2540                   js::SetReservedSlot(proto, DOM_INTERFACE_PROTO_SLOTS_BASE,
  2541                                       JS::ObjectValue(*unforgeableHolder));
  2543                 """,
  2544                 name=self.descriptor.name))
  2545         else:
  2546             setUnforgeableHolder = None
  2547         functionBody = CGList(
  2548             [CGGeneric(getParentProto), CGGeneric(getConstructorProto), initIds,
  2549              prefCache, createUnforgeableHolder, CGGeneric(call), setUnforgeableHolder],
  2550             "\n")
  2551         return CGIndenter(functionBody).define()
  2554 class CGGetPerInterfaceObject(CGAbstractMethod):
  2555     """
  2556     A method for getting a per-interface object (a prototype object or interface
  2557     constructor object).
  2558     """
  2559     def __init__(self, descriptor, name, idPrefix="", extraArgs=[]):
  2560         args = [Argument('JSContext*', 'aCx'),
  2561                 Argument('JS::Handle<JSObject*>', 'aGlobal')] + extraArgs
  2562         CGAbstractMethod.__init__(self, descriptor, name,
  2563                                   'JS::Handle<JSObject*>', args)
  2564         self.id = idPrefix + "id::" + self.descriptor.name
  2566     def definition_body(self):
  2567         # BOGUS extra blank line at the beginning of the code below
  2568         # BOGUS - should be a blank line between an if-block and following comment below
  2569         return indent(fill(
  2570             """
  2572             /* Make sure our global is sane.  Hopefully we can remove this sometime */
  2573             if (!(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL)) {
  2574               return JS::NullPtr();
  2576             /* Check to see whether the interface objects are already installed */
  2577             ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(aGlobal);
  2578             if (!protoAndIfaceCache.EntrySlotIfExists(${id})) {
  2579               CreateInterfaceObjects(aCx, aGlobal, protoAndIfaceCache, aDefineOnGlobal);
  2582             /*
  2583              * The object might _still_ be null, but that's OK.
  2585              * Calling fromMarkedLocation() is safe because protoAndIfaceCache is
  2586              * traced by TraceProtoAndIfaceCache() and its contents are never
  2587              * changed after they have been set.
  2588              */
  2589             return JS::Handle<JSObject*>::fromMarkedLocation(protoAndIfaceCache.EntrySlotMustExist(${id}).address());
  2590             """,
  2591             id=self.id))
  2594 class CGGetProtoObjectMethod(CGGetPerInterfaceObject):
  2595     """
  2596     A method for getting the interface prototype object.
  2597     """
  2598     def __init__(self, descriptor):
  2599         CGGetPerInterfaceObject.__init__(self, descriptor, "GetProtoObject",
  2600                                          "prototypes::")
  2602     def definition_body(self):
  2603         # BOGUS extra blank line at start of method
  2604         return indent(dedent("""
  2606             /* Get the interface prototype object for this class.  This will create the
  2607                object as needed. */
  2608             bool aDefineOnGlobal = true;
  2609             """)) + CGGetPerInterfaceObject.definition_body(self)
  2612 class CGGetConstructorObjectMethod(CGGetPerInterfaceObject):
  2613     """
  2614     A method for getting the interface constructor object.
  2615     """
  2616     def __init__(self, descriptor):
  2617         CGGetPerInterfaceObject.__init__(
  2618             self, descriptor, "GetConstructorObject",
  2619             "constructors::",
  2620             extraArgs=[Argument("bool", "aDefineOnGlobal", "true")])
  2622     def definition_body(self):
  2623         # BOGUS extra blank line at start of method
  2624         return indent(dedent("""
  2626             /* Get the interface object for this class.  This will create the object as
  2627                needed. */
  2628             """)) + CGGetPerInterfaceObject.definition_body(self)
  2631 class CGDefineDOMInterfaceMethod(CGAbstractMethod):
  2632     """
  2633     A method for resolve hooks to try to lazily define the interface object for
  2634     a given interface.
  2635     """
  2636     def __init__(self, descriptor):
  2637         args = [Argument('JSContext*', 'aCx'),
  2638                 Argument('JS::Handle<JSObject*>', 'aGlobal'),
  2639                 Argument('JS::Handle<jsid>', 'id'),
  2640                 Argument('bool', 'aDefineOnGlobal')]
  2641         CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'JSObject*', args)
  2643     def declare(self):
  2644         if self.descriptor.workers:
  2645             return ''
  2646         return CGAbstractMethod.declare(self)
  2648     def define(self):
  2649         if self.descriptor.workers:
  2650             return ''
  2651         return CGAbstractMethod.define(self)
  2653     def definition_body(self):
  2654         if len(self.descriptor.interface.namedConstructors) > 0:
  2655             getConstructor = indent(dedent("""
  2656                 JSObject* interfaceObject = GetConstructorObject(aCx, aGlobal, aDefineOnGlobal);
  2657                 if (!interfaceObject) {
  2658                   return nullptr;
  2660                 for (unsigned slot = DOM_INTERFACE_SLOTS_BASE; slot < JSCLASS_RESERVED_SLOTS(&InterfaceObjectClass.mBase); ++slot) {
  2661                   JSObject* constructor = &js::GetReservedSlot(interfaceObject, slot).toObject();
  2662                   if (JS_GetFunctionId(JS_GetObjectFunction(constructor)) == JSID_TO_STRING(id)) {
  2663                     return constructor;
  2666                 return interfaceObject;
  2667                 """))
  2668         else:
  2669             getConstructor = "  return GetConstructorObject(aCx, aGlobal, aDefineOnGlobal);\n"
  2670         return getConstructor
  2673 class CGConstructorEnabled(CGAbstractMethod):
  2674     """
  2675     A method for testing whether we should be exposing this interface
  2676     object or navigator property.  This can perform various tests
  2677     depending on what conditions are specified on the interface.
  2678     """
  2679     def __init__(self, descriptor):
  2680         CGAbstractMethod.__init__(self, descriptor,
  2681                                   'ConstructorEnabled', 'bool',
  2682                                   [Argument("JSContext*", "aCx"),
  2683                                    Argument("JS::Handle<JSObject*>", "aObj")])
  2685     def definition_body(self):
  2686         conditions = []
  2687         iface = self.descriptor.interface
  2688         pref = iface.getExtendedAttribute("Pref")
  2689         if pref:
  2690             assert isinstance(pref, list) and len(pref) == 1
  2691             conditions.append('Preferences::GetBool("%s")' % pref[0])
  2692         if iface.getExtendedAttribute("ChromeOnly"):
  2693             conditions.append("nsContentUtils::ThreadsafeIsCallerChrome()")
  2694         func = iface.getExtendedAttribute("Func")
  2695         if func:
  2696             assert isinstance(func, list) and len(func) == 1
  2697             conditions.append("%s(aCx, aObj)" % func[0])
  2698         availableIn = getAvailableInTestFunc(iface)
  2699         if availableIn:
  2700             conditions.append("%s(aCx, aObj)" % availableIn)
  2701         # We should really have some conditions
  2702         assert len(conditions)
  2703         body = CGWrapper(CGList((CGGeneric(cond) for cond in conditions),
  2704                                 " &&\n"),
  2705                          pre="return ", post=";\n", reindent=True)
  2706         return CGIndenter(body).define()
  2709 def CreateBindingJSObject(descriptor, properties, parent):
  2710     # We don't always need to root obj, but there are a variety
  2711     # of cases where we do, so for simplicity, just always root it.
  2712     objDecl = "JS::Rooted<JSObject*> obj(aCx);\n"
  2713     if descriptor.proxy:
  2714         create = fill(
  2715             """
  2716             JS::Rooted<JS::Value> proxyPrivateVal(aCx, JS::PrivateValue(aObject));
  2717             js::ProxyOptions options;
  2718             options.setClass(&Class.mBase);
  2719             obj = NewProxyObject(aCx, DOMProxyHandler::getInstance(),
  2720                                  proxyPrivateVal, proto, ${parent}, options);
  2721             if (!obj) {
  2722               return nullptr;
  2725             """,
  2726             parent=parent)
  2727         if descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
  2728             create += dedent("""
  2729                 js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO,
  2730                                   JS::PrivateValue(&aObject->mExpandoAndGeneration));
  2732                 """)
  2733     else:
  2734         create = fill(
  2735             """
  2736             obj = JS_NewObject(aCx, Class.ToJSClass(), proto, ${parent});
  2737             if (!obj) {
  2738               return nullptr;
  2741             js::SetReservedSlot(obj, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aObject));
  2742             """,
  2743             parent=parent)
  2744         if "Window" in descriptor.interface.identifier.name:
  2745             create = dedent("""
  2746                 MOZ_ASSERT(false,
  2747                            "Our current reserved slot situation is unsafe for globals. Fix "
  2748                            "bug 760095!");
  2749                 """) + create
  2750     create = objDecl + create
  2752     if descriptor.nativeOwnership == 'refcounted':
  2753         create += "NS_ADDREF(aObject);\n"
  2754     else:
  2755         create += dedent("""
  2756             // Make sure the native objects inherit from NonRefcountedDOMObject so that we
  2757             // log their ctor and dtor.
  2758             MustInheritFromNonRefcountedDOMObject(aObject);
  2759             *aTookOwnership = true;
  2760             """)
  2761     return create
  2764 def InitUnforgeablePropertiesOnObject(descriptor, obj, properties, failureReturnValue=""):
  2765     """
  2766     properties is a PropertyArrays instance
  2767     """
  2768     defineUnforgeables = fill(
  2769         """
  2770         if (!DefineUnforgeableAttributes(aCx, ${obj}, %s)) {
  2771           return${rv};
  2773         """,
  2774         obj=obj,
  2775         rv=" " + failureReturnValue if failureReturnValue else "")
  2777     unforgeableAttrs = properties.unforgeableAttrs
  2778     unforgeables = []
  2779     if unforgeableAttrs.hasNonChromeOnly():
  2780         unforgeables.append(CGGeneric(defineUnforgeables %
  2781                                       unforgeableAttrs.variableName(False)))
  2782     if unforgeableAttrs.hasChromeOnly():
  2783         unforgeables.append(
  2784             CGIfWrapper(CGGeneric(defineUnforgeables %
  2785                                   unforgeableAttrs.variableName(True)),
  2786                         "nsContentUtils::ThreadsafeIsCallerChrome()"))
  2787     return CGList(unforgeables)
  2790 def InitUnforgeableProperties(descriptor, properties):
  2791     """
  2792     properties is a PropertyArrays instance
  2793     """
  2794     unforgeableAttrs = properties.unforgeableAttrs
  2795     if not unforgeableAttrs.hasNonChromeOnly() and not unforgeableAttrs.hasChromeOnly():
  2796         return ""
  2798     if descriptor.proxy:
  2799         unforgeableProperties = CGGeneric(
  2800             "// Unforgeable properties on proxy-based bindings are stored in an object held\n"
  2801             "// by the interface prototype object.\n"
  2802             "\n")  # BOGUS extra blank line
  2803     else:
  2804         unforgeableProperties = CGWrapper(
  2805             InitUnforgeablePropertiesOnObject(descriptor, "obj", properties, "nullptr"),
  2806             pre=(
  2807                 "// Important: do unforgeable property setup after we have handed\n"
  2808                 "// over ownership of the C++ object to obj as needed, so that if\n"
  2809                 "// we fail and it ends up GCed it won't have problems in the\n"
  2810                 "// finalizer trying to drop its ownership of the C++ object.\n"))
  2811     return CGWrapper(unforgeableProperties, pre="\n").define()
  2814 def AssertInheritanceChain(descriptor):
  2815     asserts = ""
  2816     iface = descriptor.interface
  2817     while iface:
  2818         desc = descriptor.getDescriptor(iface.identifier.name)
  2819         asserts += (
  2820             "  MOZ_ASSERT(static_cast<%s*>(aObject) == \n"
  2821             "             reinterpret_cast<%s*>(aObject));\n" %
  2822             (desc.nativeType, desc.nativeType))
  2823         iface = iface.parent
  2824     asserts += "  MOZ_ASSERT(ToSupportsIsCorrect(aObject));\n"
  2825     return asserts
  2828 def InitMemberSlots(descriptor, wrapperCache):
  2829     """
  2830     Initialize member slots on our JS object if we're supposed to have some.
  2832     Note that this is called after the SetWrapper() call in the
  2833     wrapperCache case, since that can affect how our getters behave
  2834     and we plan to invoke them here.  So if we fail, we need to
  2835     ClearWrapper.
  2836     """
  2837     if not descriptor.interface.hasMembersInSlots():
  2838         return "\n"  # BOGUS blank line only if this returns empty
  2839     if wrapperCache:
  2840         clearWrapper = "  aCache->ClearWrapper();\n"
  2841     else:
  2842         clearWrapper = ""
  2843     return ("if (!UpdateMemberSlots(aCx, obj, aObject)) {\n"
  2844             "%s"
  2845             "  return nullptr;\n"
  2846             "}\n" % clearWrapper)
  2849 class CGWrapWithCacheMethod(CGAbstractMethod):
  2850     """
  2851     Create a wrapper JSObject for a given native that implements nsWrapperCache.
  2853     properties should be a PropertyArrays instance.
  2854     """
  2855     def __init__(self, descriptor, properties):
  2856         assert descriptor.interface.hasInterfacePrototypeObject()
  2857         args = [Argument('JSContext*', 'aCx'),
  2858                 Argument(descriptor.nativeType + '*', 'aObject'),
  2859                 Argument('nsWrapperCache*', 'aCache')]
  2860         CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
  2861         self.properties = properties
  2863     def definition_body(self):
  2864         return fill(
  2865             """
  2866             ${assertion}
  2867               MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
  2868                          "nsISupports must be on our primary inheritance chain");
  2870               JS::Rooted<JSObject*> parent(aCx,
  2871                 GetRealParentObject(aObject,
  2872                                     WrapNativeParent(aCx, aObject->GetParentObject())));
  2873               if (!parent) {
  2874                 return nullptr;
  2877               // That might have ended up wrapping us already, due to the wonders
  2878               // of XBL.  Check for that, and bail out as needed.  Scope so we don't
  2879               // collide with the "obj" we declare in CreateBindingJSObject.
  2881                 JSObject* obj = aCache->GetWrapper();
  2882                 if (obj) {
  2883                   return obj;
  2887               JSAutoCompartment ac(aCx, parent);
  2888               JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, parent));
  2889               JS::Handle<JSObject*> proto = GetProtoObject(aCx, global);
  2890               if (!proto) {
  2891                 return nullptr;
  2894               $*{parent}
  2896               $*{unforgeable}
  2898               aCache->SetWrapper(obj);
  2899               $*{slots}
  2900               return obj;
  2901             """,
  2902             assertion=AssertInheritanceChain(self.descriptor),
  2903             parent=CreateBindingJSObject(self.descriptor, self.properties,
  2904                                          "parent"),
  2905             unforgeable=InitUnforgeableProperties(self.descriptor, self.properties),
  2906             slots=InitMemberSlots(self.descriptor, True))
  2909 class CGWrapMethod(CGAbstractMethod):
  2910     def __init__(self, descriptor):
  2911         # XXX can we wrap if we don't have an interface prototype object?
  2912         assert descriptor.interface.hasInterfacePrototypeObject()
  2913         args = [Argument('JSContext*', 'aCx'),
  2914                 Argument('T*', 'aObject')]
  2915         CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args,
  2916                                   inline=True, templateArgs=["class T"])
  2918     def definition_body(self):
  2919         return "  return Wrap(aCx, aObject, aObject);\n"
  2922 class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
  2923     """
  2924     Create a wrapper JSObject for a given native that does not implement
  2925     nsWrapperCache.
  2927     properties should be a PropertyArrays instance.
  2928     """
  2929     def __init__(self, descriptor, properties):
  2930         # XXX can we wrap if we don't have an interface prototype object?
  2931         assert descriptor.interface.hasInterfacePrototypeObject()
  2932         args = [Argument('JSContext*', 'aCx'),
  2933                 Argument(descriptor.nativeType + '*', 'aObject')]
  2934         if descriptor.nativeOwnership == 'owned':
  2935             args.append(Argument('bool*', 'aTookOwnership'))
  2936         CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
  2937         self.properties = properties
  2939     def definition_body(self):
  2940         return fill(
  2941             """
  2942             ${assertions}
  2943               JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
  2944               JS::Handle<JSObject*> proto = GetProtoObject(aCx, global);
  2945               if (!proto) {
  2946                 return nullptr;
  2949               $*{global_}
  2951               $*{unforgeable}
  2953               $*{slots}
  2954               return obj;
  2955             """,
  2956             assertions=AssertInheritanceChain(self.descriptor),
  2957             global_=CreateBindingJSObject(self.descriptor, self.properties,
  2958                                           "global"),
  2959             unforgeable=InitUnforgeableProperties(self.descriptor, self.properties),
  2960             slots=InitMemberSlots(self.descriptor, False))
  2963 class CGWrapGlobalMethod(CGAbstractMethod):
  2964     """
  2965     Create a wrapper JSObject for a global.  The global must implement
  2966     nsWrapperCache.
  2968     properties should be a PropertyArrays instance.
  2969     """
  2970     def __init__(self, descriptor, properties):
  2971         assert descriptor.interface.hasInterfacePrototypeObject()
  2972         args = [Argument('JSContext*', 'aCx'),
  2973                 Argument(descriptor.nativeType + '*', 'aObject'),
  2974                 Argument('nsWrapperCache*', 'aCache'),
  2975                 Argument('JS::CompartmentOptions&', 'aOptions'),
  2976                 Argument('JSPrincipals*', 'aPrincipal')]
  2977         CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
  2978         self.descriptor = descriptor
  2979         self.properties = properties
  2981     def definition_body(self):
  2982         return fill(
  2983             """
  2984             ${assertions}
  2985               MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
  2986                          "nsISupports must be on our primary inheritance chain");
  2988               JS::Rooted<JSObject*> obj(aCx);
  2989               obj = CreateGlobal<${nativeType}, GetProtoObject>(aCx,
  2990                                                      aObject,
  2991                                                      aCache,
  2992                                                      Class.ToJSClass(),
  2993                                                      aOptions,
  2994                                                      aPrincipal);
  2996               $*{unforgeable}
  2998               $*{slots}
  3000               // XXXkhuey can't do this yet until workers can lazy resolve.
  3001               // JS_FireOnNewGlobalObject(aCx, obj);
  3003               return obj;
  3004             """,
  3005             assertions=AssertInheritanceChain(self.descriptor),
  3006             nativeType=self.descriptor.nativeType,
  3007             unforgeable=InitUnforgeableProperties(self.descriptor, self.properties),
  3008             slots=InitMemberSlots(self.descriptor, True))
  3011 class CGUpdateMemberSlotsMethod(CGAbstractStaticMethod):
  3012     def __init__(self, descriptor):
  3013         args = [Argument('JSContext*', 'aCx'),
  3014                 Argument('JS::Handle<JSObject*>', 'aWrapper'),
  3015                 Argument(descriptor.nativeType + '*', 'aObject')]
  3016         CGAbstractStaticMethod.__init__(self, descriptor, 'UpdateMemberSlots', 'bool', args)
  3018     def definition_body(self):
  3019         body = ("JS::Rooted<JS::Value> temp(aCx);\n"
  3020                 "JSJitGetterCallArgs args(&temp);\n")
  3021         for m in self.descriptor.interface.members:
  3022             if m.isAttr() and m.getExtendedAttribute("StoreInSlot"):
  3023                 body += fill(
  3024                     """
  3026                     static_assert(${slot} < js::shadow::Object::MAX_FIXED_SLOTS,
  3027                                   "Not enough fixed slots to fit '${interface}.${member}'");
  3028                     if (!get_${member}(aCx, aWrapper, aObject, args)) {
  3029                       return false;
  3031                     // Getter handled setting our reserved slots
  3032                     """,
  3033                     slot=memberReservedSlot(m),
  3034                     interface=self.descriptor.interface.identifier.name,
  3035                     member=m.identifier.name)
  3037         body += "\nreturn true;\n"
  3038         return indent(body)
  3041 class CGClearCachedValueMethod(CGAbstractMethod):
  3042     def __init__(self, descriptor, member):
  3043         self.member = member
  3044         # If we're StoreInSlot, we'll need to call the getter
  3045         if member.getExtendedAttribute("StoreInSlot"):
  3046             args = [Argument('JSContext*', 'aCx')]
  3047             returnType = 'bool'
  3048         else:
  3049             args = []
  3050             returnType = 'void'
  3051         args.append(Argument(descriptor.nativeType + '*', 'aObject'))
  3052         name = ("ClearCached%sValue" % MakeNativeName(member.identifier.name))
  3053         CGAbstractMethod.__init__(self, descriptor, name, returnType, args)
  3055     def definition_body(self):
  3056         slotIndex = memberReservedSlot(self.member)
  3057         if self.member.getExtendedAttribute("StoreInSlot"):
  3058             # We have to root things and save the old value in case
  3059             # regetting fails, so we can restore it.
  3060             declObj = "JS::Rooted<JSObject*> obj(aCx);\n"
  3061             noopRetval = " true"
  3062             saveMember = (
  3063                 "JS::Rooted<JS::Value> oldValue(aCx, js::GetReservedSlot(obj, %s));\n" %
  3064                 slotIndex)
  3065             regetMember = fill(
  3066                 """
  3067                 JS::Rooted<JS::Value> temp(aCx);
  3068                 JSJitGetterCallArgs args(&temp);
  3069                 JSAutoCompartment ac(aCx, obj);
  3070                 if (!get_${name}(aCx, obj, aObject, args)) {
  3071                   js::SetReservedSlot(obj, ${slotIndex}, oldValue);
  3072                   nsJSUtils::ReportPendingException(aCx);
  3073                   return false;
  3075                 return true;
  3076                 """,
  3077                 name=self.member.identifier.name,
  3078                 slotIndex=slotIndex)
  3079         else:
  3080             declObj = "JSObject* obj;\n"
  3081             noopRetval = ""
  3082             saveMember = ""
  3083             regetMember = ""
  3085         return indent(fill(
  3086             """
  3087             $*{declObj}
  3088             obj = aObject->GetWrapper();
  3089             if (!obj) {
  3090               return${noopRetval};
  3092             $*{saveMember}
  3093             js::SetReservedSlot(obj, ${slotIndex}, JS::UndefinedValue());
  3094             $*{regetMember}
  3095             """,
  3096             declObj=declObj,
  3097             noopRetval=noopRetval,
  3098             saveMember=saveMember,
  3099             slotIndex=slotIndex,
  3100             regetMember=regetMember))
  3103 class CGIsPermittedMethod(CGAbstractMethod):
  3104     """
  3105     crossOriginGetters/Setters/Methods are sets of names of the relevant members.
  3106     """
  3107     def __init__(self, descriptor, crossOriginGetters, crossOriginSetters,
  3108                  crossOriginMethods):
  3109         self.crossOriginGetters = crossOriginGetters
  3110         self.crossOriginSetters = crossOriginSetters
  3111         self.crossOriginMethods = crossOriginMethods
  3112         args = [Argument("JSFlatString*", "prop"),
  3113                 Argument("jschar", "propFirstChar"),
  3114                 Argument("bool", "set")]
  3115         CGAbstractMethod.__init__(self, descriptor, "IsPermitted", "bool", args,
  3116                                   inline=True)
  3118     def definition_body(self):
  3119         allNames = self.crossOriginGetters | self.crossOriginSetters | self.crossOriginMethods
  3120         readwrite = self.crossOriginGetters & self.crossOriginSetters
  3121         readonly = (self.crossOriginGetters - self.crossOriginSetters) | self.crossOriginMethods
  3122         writeonly = self.crossOriginSetters - self.crossOriginGetters
  3123         cases = {}
  3124         for name in sorted(allNames):
  3125             cond = 'JS_FlatStringEqualsAscii(prop, "%s")' % name
  3126             if name in readonly:
  3127                 cond = "!set && %s" % cond
  3128             elif name in writeonly:
  3129                 cond = "set && %s" % cond
  3130             else:
  3131                 assert name in readwrite
  3132             firstLetter = name[0]
  3133             case = cases.get(firstLetter, CGList([]))
  3134             case.append(CGGeneric("if (%s) {\n"
  3135                                   "  return true;\n"
  3136                                   "}\n" % cond))
  3137             cases[firstLetter] = case
  3138         caseList = []
  3139         for firstLetter in sorted(cases.keys()):
  3140             caseList.append(CGCase("'%s'" % firstLetter, cases[firstLetter]))
  3141         switch = CGSwitch("propFirstChar", caseList)
  3142         return indent(switch.define() + "\nreturn false;\n")
  3144 builtinNames = {
  3145     IDLType.Tags.bool: 'bool',
  3146     IDLType.Tags.int8: 'int8_t',
  3147     IDLType.Tags.int16: 'int16_t',
  3148     IDLType.Tags.int32: 'int32_t',
  3149     IDLType.Tags.int64: 'int64_t',
  3150     IDLType.Tags.uint8: 'uint8_t',
  3151     IDLType.Tags.uint16: 'uint16_t',
  3152     IDLType.Tags.uint32: 'uint32_t',
  3153     IDLType.Tags.uint64: 'uint64_t',
  3154     IDLType.Tags.unrestricted_float: 'float',
  3155     IDLType.Tags.float: 'float',
  3156     IDLType.Tags.unrestricted_double: 'double',
  3157     IDLType.Tags.double: 'double'
  3160 numericSuffixes = {
  3161     IDLType.Tags.int8: '',
  3162     IDLType.Tags.uint8: '',
  3163     IDLType.Tags.int16: '',
  3164     IDLType.Tags.uint16: '',
  3165     IDLType.Tags.int32: '',
  3166     IDLType.Tags.uint32: 'U',
  3167     IDLType.Tags.int64: 'LL',
  3168     IDLType.Tags.uint64: 'ULL',
  3169     IDLType.Tags.unrestricted_float: 'F',
  3170     IDLType.Tags.float: 'F',
  3171     IDLType.Tags.unrestricted_double: '',
  3172     IDLType.Tags.double: ''
  3176 def numericValue(t, v):
  3177     if (t == IDLType.Tags.unrestricted_double or
  3178         t == IDLType.Tags.unrestricted_float):
  3179         typeName = builtinNames[t]
  3180         if v == float("inf"):
  3181             return "mozilla::PositiveInfinity<%s>()" % typeName
  3182         if v == float("-inf"):
  3183             return "mozilla::NegativeInfinity<%s>()" % typeName
  3184         if math.isnan(v):
  3185             return "mozilla::UnspecifiedNaN<%s>()" % typeName
  3186     return "%s%s" % (v, numericSuffixes[t])
  3189 class CastableObjectUnwrapper():
  3190     """
  3191     A class for unwrapping an object named by the "source" argument
  3192     based on the passed-in descriptor and storing it in a variable
  3193     called by the name in the "target" argument.
  3195     codeOnFailure is the code to run if unwrapping fails.
  3197     If isCallbackReturnValue is "JSImpl" and our descriptor is also
  3198     JS-implemented, fall back to just creating the right object if what we
  3199     have isn't one already.
  3201     If allowCrossOriginObj is True, then we'll first do an
  3202     UncheckedUnwrap and then operate on the result.
  3203     """
  3204     def __init__(self, descriptor, source, target, codeOnFailure,
  3205                  exceptionCode=None, isCallbackReturnValue=False,
  3206                  allowCrossOriginObj=False):
  3207         self.substitution = {
  3208             "type": descriptor.nativeType,
  3209             "protoID": "prototypes::id::" + descriptor.name,
  3210             "target": target,
  3211             "codeOnFailure": codeOnFailure,
  3213         if allowCrossOriginObj:
  3214             self.substitution["uncheckedObjDecl"] = (
  3215                 "JS::Rooted<JSObject*> uncheckedObj(cx, js::UncheckedUnwrap(%s));\n" % source)
  3216             self.substitution["source"] = "uncheckedObj"
  3217             xpconnectUnwrap = dedent("""
  3218                 nsresult rv;
  3219                 { // Scope for the JSAutoCompartment, because we only
  3220                   // want to be in that compartment for the UnwrapArg call.
  3221                   JSAutoCompartment ac(cx, ${source});
  3222                   rv = UnwrapArg<${type}>(cx, val, &objPtr, &objRef.ptr, &val);
  3224                 """)
  3225         else:
  3226             self.substitution["uncheckedObjDecl"] = ""
  3227             self.substitution["source"] = source
  3228             xpconnectUnwrap = "nsresult rv = UnwrapArg<${type}>(cx, val, &objPtr, &objRef.ptr, &val);\n"
  3230         if descriptor.hasXPConnectImpls:
  3231             # We don't use xpc_qsUnwrapThis because it will always throw on
  3232             # unwrap failure, whereas we want to control whether we throw or
  3233             # not.
  3234             self.substitution["codeOnFailure"] = string.Template(
  3235                 "${type} *objPtr;\n"
  3236                 "SelfRef objRef;\n"
  3237                 "JS::Rooted<JS::Value> val(cx, JS::ObjectValue(*${source}));\n" +
  3238                 xpconnectUnwrap +
  3239                 "if (NS_FAILED(rv)) {\n"
  3240                 "${indentedCodeOnFailure}"
  3241                 "}\n"
  3242                 "// We should be castable!\n"
  3243                 "MOZ_ASSERT(!objRef.ptr);\n"
  3244                 "// We should have an object, too!\n"
  3245                 "MOZ_ASSERT(objPtr);\n"
  3246                 "${target} = objPtr;\n"
  3247             ).substitute(self.substitution,
  3248                          indentedCodeOnFailure=indent(codeOnFailure))
  3249         elif (isCallbackReturnValue == "JSImpl" and
  3250               descriptor.interface.isJSImplemented()):
  3251             exceptionCode = exceptionCode or codeOnFailure
  3252             self.substitution["codeOnFailure"] = fill(
  3253                 """
  3254                 // Be careful to not wrap random DOM objects here, even if
  3255                 // they're wrapped in opaque security wrappers for some reason.
  3256                 // XXXbz Wish we could check for a JS-implemented object
  3257                 // that already has a content reflection...
  3258                 if (!IsDOMObject(js::UncheckedUnwrap(${source}))) {
  3259                   nsCOMPtr<nsPIDOMWindow> ourWindow;
  3260                   if (!GetWindowForJSImplementedObject(cx, Callback(), getter_AddRefs(ourWindow))) {
  3261                     $*{exceptionCode}
  3263                   JS::Rooted<JSObject*> jsImplSourceObj(cx, ${source});
  3264                   ${target} = new ${type}(jsImplSourceObj, ourWindow);
  3265                 } else {
  3266                   $*{codeOnFailure}
  3268                 """,
  3269                 exceptionCode=exceptionCode,
  3270                 **self.substitution)
  3271         else:
  3272             self.substitution["codeOnFailure"] = codeOnFailure
  3274     def __str__(self):
  3275         substitution = self.substitution.copy()
  3276         substitution["codeOnFailure"] %= {
  3277             'securityError': 'rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO'
  3279         return fill(
  3280             """
  3282               $*{uncheckedObjDecl}
  3283               nsresult rv = UnwrapObject<${protoID}, ${type}>(${source}, ${target});
  3284               if (NS_FAILED(rv)) {
  3285                 $*{codeOnFailure}
  3288             """,
  3289             **substitution)
  3292 class FailureFatalCastableObjectUnwrapper(CastableObjectUnwrapper):
  3293     """
  3294     As CastableObjectUnwrapper, but defaulting to throwing if unwrapping fails
  3295     """
  3296     def __init__(self, descriptor, source, target, exceptionCode,
  3297                  isCallbackReturnValue, sourceDescription):
  3298         CastableObjectUnwrapper.__init__(
  3299             self, descriptor, source, target,
  3300             'ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s", "%s");\n'
  3301             '%s' % (sourceDescription, descriptor.interface.identifier.name,
  3302                     exceptionCode),
  3303             exceptionCode,
  3304             isCallbackReturnValue)
  3307 class CGCallbackTempRoot(CGGeneric):
  3308     def __init__(self, name):
  3309         define = dedent("""
  3310             { // Scope for tempRoot
  3311               JS::Rooted<JSObject*> tempRoot(cx, &${val}.toObject());
  3312               ${declName} = new %s(tempRoot, mozilla::dom::GetIncumbentGlobal());
  3314             """) % name
  3315         CGGeneric.__init__(self, define=define)
  3318 class JSToNativeConversionInfo():
  3319     """
  3320     An object representing information about a JS-to-native conversion.
  3321     """
  3322     def __init__(self, template, declType=None, holderType=None,
  3323                  dealWithOptional=False, declArgs=None,
  3324                  holderArgs=None):
  3325         """
  3326         template: A string representing the conversion code.  This will have
  3327                   template substitution performed on it as follows:
  3329           ${val} is a handle to the JS::Value in question
  3330           ${mutableVal} is a mutable handle to the JS::Value in question
  3331           ${holderName} replaced by the holder's name, if any
  3332           ${declName} replaced by the declaration's name
  3333           ${haveValue} replaced by an expression that evaluates to a boolean
  3334                        for whether we have a JS::Value.  Only used when
  3335                        defaultValue is not None or when True is passed for
  3336                        checkForValue to instantiateJSToNativeConversion.
  3338         declType: A CGThing representing the native C++ type we're converting
  3339                   to.  This is allowed to be None if the conversion code is
  3340                   supposed to be used as-is.
  3342         holderType: A CGThing representing the type of a "holder" which will
  3343                     hold a possible reference to the C++ thing whose type we
  3344                     returned in declType, or  None if no such holder is needed.
  3346         dealWithOptional: A boolean indicating whether the caller has to do
  3347                           optional-argument handling.  This should only be set
  3348                           to true if the JS-to-native conversion is being done
  3349                           for an optional argument or dictionary member with no
  3350                           default value and if the returned template expects
  3351                           both declType and holderType to be wrapped in
  3352                           Optional<>, with ${declName} and ${holderName}
  3353                           adjusted to point to the Value() of the Optional, and
  3354                           Construct() calls to be made on the Optional<>s as
  3355                           needed.
  3357         declArgs: If not None, the arguments to pass to the ${declName}
  3358                   constructor.  These will have template substitution performed
  3359                   on them so you can use things like ${val}.  This is a
  3360                   single string, not a list of strings.
  3362         holderArgs: If not None, the arguments to pass to the ${holderName}
  3363                     constructor.  These will have template substitution
  3364                     performed on them so you can use things like ${val}.
  3365                     This is a single string, not a list of strings.
  3367         ${declName} must be in scope before the code from 'template' is entered.
  3369         If holderType is not None then ${holderName} must be in scope before
  3370         the code from 'template' is entered.
  3371         """
  3372         assert isinstance(template, str)
  3373         assert declType is None or isinstance(declType, CGThing)
  3374         assert holderType is None or isinstance(holderType, CGThing)
  3375         self.template = template
  3376         self.declType = declType
  3377         self.holderType = holderType
  3378         self.dealWithOptional = dealWithOptional
  3379         self.declArgs = declArgs
  3380         self.holderArgs = holderArgs
  3383 def getHandleDefault(defaultValue):
  3384     tag = defaultValue.type.tag()
  3385     if tag in numericSuffixes:
  3386         # Some numeric literals require a suffix to compile without warnings
  3387         return numericValue(tag, defaultValue.value)
  3388     assert tag == IDLType.Tags.bool
  3389     return toStringBool(defaultValue.value)
  3392 def handleDefaultStringValue(defaultValue, method):
  3393     """
  3394     Returns a string which ends up calling 'method' with a (char16_t*, length)
  3395     pair that sets this string default value.  This string is suitable for
  3396     passing as the second argument of handleDefault; in particular it does not
  3397     end with a ';'
  3398     """
  3399     assert defaultValue.type.isDOMString()
  3400     return ("static const char16_t data[] = { %s };\n"
  3401             "%s(data, ArrayLength(data) - 1)" %
  3402             (", ".join(["'" + char + "'" for char in
  3403                         defaultValue.value] + ["0"]),
  3404              method))
  3407 # If this function is modified, modify CGNativeMember.getArg and
  3408 # CGNativeMember.getRetvalInfo accordingly.  The latter cares about the decltype
  3409 # and holdertype we end up using, because it needs to be able to return the code
  3410 # that will convert those to the actual return value of the callback function.
  3411 def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
  3412                                 isDefinitelyObject=False,
  3413                                 isMember=False,
  3414                                 isOptional=False,
  3415                                 invalidEnumValueFatal=True,
  3416                                 defaultValue=None,
  3417                                 treatNullAs="Default",
  3418                                 isEnforceRange=False,
  3419                                 isClamp=False,
  3420                                 isNullOrUndefined=False,
  3421                                 exceptionCode=None,
  3422                                 lenientFloatCode=None,
  3423                                 allowTreatNonCallableAsNull=False,
  3424                                 isCallbackReturnValue=False,
  3425                                 sourceDescription="value"):
  3426     """
  3427     Get a template for converting a JS value to a native object based on the
  3428     given type and descriptor.  If failureCode is given, then we're actually
  3429     testing whether we can convert the argument to the desired type.  That
  3430     means that failures to convert due to the JS value being the wrong type of
  3431     value need to use failureCode instead of throwing exceptions.  Failures to
  3432     convert that are due to JS exceptions (from toString or valueOf methods) or
  3433     out of memory conditions need to throw exceptions no matter what
  3434     failureCode is.  However what actually happens when throwing an exception
  3435     can be controlled by exceptionCode.  The only requirement on that is that
  3436     exceptionCode must end up doing a return, and every return from this
  3437     function must happen via exceptionCode if exceptionCode is not None.
  3439     If isDefinitelyObject is True, that means we know the value
  3440     isObject() and we have no need to recheck that.
  3442     if isMember is not False, we're being converted from a property of some JS
  3443     object, not from an actual method argument, so we can't rely on our jsval
  3444     being rooted or outliving us in any way.  Callers can pass "Dictionary",
  3445     "Variadic", "Sequence", or "OwningUnion" to indicate that the conversion is
  3446     for something that is a dictionary member, a variadic argument, a sequence,
  3447     or an owning union respectively.
  3449     If isOptional is true, then we are doing conversion of an optional
  3450     argument with no default value.
  3452     invalidEnumValueFatal controls whether an invalid enum value conversion
  3453     attempt will throw (if true) or simply return without doing anything (if
  3454     false).
  3456     If defaultValue is not None, it's the IDL default value for this conversion
  3458     If isEnforceRange is true, we're converting an integer and throwing if the
  3459     value is out of range.
  3461     If isClamp is true, we're converting an integer and clamping if the
  3462     value is out of range.
  3464     If lenientFloatCode is not None, it should be used in cases when
  3465     we're a non-finite float that's not unrestricted.
  3467     If allowTreatNonCallableAsNull is true, then [TreatNonCallableAsNull] and
  3468     [TreatNonObjectAsNull] extended attributes on nullable callback functions
  3469     will be honored.
  3471     If isCallbackReturnValue is "JSImpl" or "Callback", then the declType may be
  3472     adjusted to make it easier to return from a callback.  Since that type is
  3473     never directly observable by any consumers of the callback code, this is OK.
  3474     Furthermore, if isCallbackReturnValue is "JSImpl", that affects the behavior
  3475     of the FailureFatalCastableObjectUnwrapper conversion; this is used for
  3476     implementing auto-wrapping of JS-implemented return values from a
  3477     JS-implemented interface.
  3479     sourceDescription is a description of what this JS value represents, to be
  3480     used in error reporting.  Callers should assume that it might get placed in
  3481     the middle of a sentence.  If it ends up at the beginning of a sentence, its
  3482     first character will be automatically uppercased.
  3484     The return value from this function is a JSToNativeConversionInfo.
  3485     """
  3486     # If we have a defaultValue then we're not actually optional for
  3487     # purposes of what we need to be declared as.
  3488     assert defaultValue is None or not isOptional
  3490     # Also, we should not have a defaultValue if we know we're an object
  3491     assert not isDefinitelyObject or defaultValue is None
  3493     # And we can't both be an object and be null or undefined
  3494     assert not isDefinitelyObject or not isNullOrUndefined
  3496     # If exceptionCode is not set, we'll just rethrow the exception we got.
  3497     # Note that we can't just set failureCode to exceptionCode, because setting
  3498     # failureCode will prevent pending exceptions from being set in cases when
  3499     # they really should be!
  3500     if exceptionCode is None:
  3501         exceptionCode = "return false;\n"
  3502     # We often want exceptionCode to be indented, since it often appears in an
  3503     # if body.
  3504     exceptionCodeIndented = CGIndenter(CGGeneric(exceptionCode))
  3506     # Unfortunately, .capitalize() on a string will lowercase things inside the
  3507     # string, which we do not want.
  3508     def firstCap(string):
  3509         return string[0].upper() + string[1:]
  3511     # Helper functions for dealing with failures due to the JS value being the
  3512     # wrong type of value
  3513     def onFailureNotAnObject(failureCode):
  3514         return CGGeneric(
  3515             failureCode or
  3516             ('ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n'
  3517              '%s' % (firstCap(sourceDescription), exceptionCode)))
  3519     def onFailureBadType(failureCode, typeName):
  3520         return CGGeneric(
  3521             failureCode or
  3522             ('ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s", "%s");\n'
  3523              '%s' % (firstCap(sourceDescription), typeName, exceptionCode)))
  3525     def onFailureNotCallable(failureCode):
  3526         return CGGeneric(
  3527             failureCode or
  3528             ('ThrowErrorMessage(cx, MSG_NOT_CALLABLE, "%s");\n'
  3529              '%s' % (firstCap(sourceDescription), exceptionCode)))
  3531     # A helper function for handling default values.  Takes a template
  3532     # body and the C++ code to set the default value and wraps the
  3533     # given template body in handling for the default value.
  3534     def handleDefault(template, setDefault):
  3535         if defaultValue is None:
  3536             return template
  3537         return (
  3538             "if (${haveValue}) {\n" +
  3539             indent(template) +
  3540             "} else {\n" +
  3541             indent(setDefault) +
  3542             "}\n")
  3544     # A helper function for handling null default values.  Much like
  3545     # handleDefault, but checks that the default value, if it exists, is null.
  3546     def handleDefaultNull(template, codeToSetNull):
  3547         if (defaultValue is not None and
  3548             not isinstance(defaultValue, IDLNullValue)):
  3549             raise TypeError("Can't handle non-null default value here")
  3550         return handleDefault(template, codeToSetNull)
  3552     # A helper function for wrapping up the template body for
  3553     # possibly-nullable objecty stuff
  3554     def wrapObjectTemplate(templateBody, type, codeToSetNull, failureCode=None):
  3555         if isNullOrUndefined and type.nullable():
  3556             # Just ignore templateBody and set ourselves to null.
  3557             # Note that we don't have to worry about default values
  3558             # here either, since we already examined this value.
  3559             return codeToSetNull
  3561         if not isDefinitelyObject:
  3562             # Handle the non-object cases by wrapping up the whole
  3563             # thing in an if cascade.
  3564             if type.nullable():
  3565                 elifLine = "} else if (${val}.isNullOrUndefined()) {\n"
  3566                 elifBody = codeToSetNull
  3567             else:
  3568                 elifLine = ""
  3569                 elifBody = ""
  3571             # Note that $${val} below expands to ${val}. This string is
  3572             # used as a template later, and val will be filled in then.
  3573             templateBody = fill(
  3574                 """
  3575                 if ($${val}.isObject()) {
  3576                   $*{templateBody}
  3577                 $*{elifLine}
  3578                   $*{elifBody}
  3579                 } else {
  3580                   $*{failureBody}
  3582                 """,
  3583                 templateBody=templateBody,
  3584                 elifLine=elifLine,
  3585                 elifBody=elifBody,
  3586                 failureBody=onFailureNotAnObject(failureCode).define())
  3588             if type.nullable():
  3589                 templateBody = handleDefaultNull(templateBody, codeToSetNull)
  3590             else:
  3591                 assert defaultValue is None
  3593         return templateBody
  3595     # A helper function for converting things that look like a JSObject*.
  3596     def handleJSObjectType(type, isMember, failureCode):
  3597         if not isMember:
  3598             if isOptional:
  3599                 # We have a specialization of Optional that will use a
  3600                 # Rooted for the storage here.
  3601                 declType = CGGeneric("JS::Handle<JSObject*>")
  3602             else:
  3603                 declType = CGGeneric("JS::Rooted<JSObject*>")
  3604             declArgs = "cx"
  3605         else:
  3606             assert (isMember in
  3607                     ("Sequence", "Variadic", "Dictionary", "OwningUnion", "MozMap"))
  3608             # We'll get traced by the sequence or dictionary or union tracer
  3609             declType = CGGeneric("JSObject*")
  3610             declArgs = None
  3611         templateBody = "${declName} = &${val}.toObject();\n"
  3612         setToNullCode = "${declName} = nullptr;\n"
  3613         template = wrapObjectTemplate(templateBody, type, setToNullCode,
  3614                                       failureCode)
  3615         return JSToNativeConversionInfo(template, declType=declType,
  3616                                         dealWithOptional=isOptional,
  3617                                         declArgs=declArgs)
  3619     assert not (isEnforceRange and isClamp)  # These are mutually exclusive
  3621     if type.isArray():
  3622         raise TypeError("Can't handle array arguments yet")
  3624     if type.isSequence():
  3625         assert not isEnforceRange and not isClamp
  3627         if failureCode is None:
  3628             notSequence = ('ThrowErrorMessage(cx, MSG_NOT_SEQUENCE, "%s");\n'
  3629                            "%s" % (firstCap(sourceDescription), exceptionCode))
  3630         else:
  3631             notSequence = failureCode
  3633         nullable = type.nullable()
  3634         # Be very careful not to change "type": we need it later
  3635         if nullable:
  3636             elementType = type.inner.inner
  3637         else:
  3638             elementType = type.inner
  3640         # We want to use auto arrays if we can, but we have to be careful with
  3641         # reallocation behavior for arrays.  In particular, if we use auto
  3642         # arrays for sequences and have a sequence of elements which are
  3643         # themselves sequences or have sequences as members, we have a problem.
  3644         # In that case, resizing the outermost nsAutoTarray to the right size
  3645         # will memmove its elements, but nsAutoTArrays are not memmovable and
  3646         # hence will end up with pointers to bogus memory, which is bad.  To
  3647         # deal with this, we typically map WebIDL sequences to our Sequence
  3648         # type, which is in fact memmovable.  The one exception is when we're
  3649         # passing in a sequence directly as an argument without any sort of
  3650         # optional or nullable complexity going on.  In that situation, we can
  3651         # use an AutoSequence instead.  We have to keep using Sequence in the
  3652         # nullable and optional cases because we don't want to leak the
  3653         # AutoSequence type to consumers, which would be unavoidable with
  3654         # Nullable<AutoSequence> or Optional<AutoSequence>.
  3655         if isMember or isOptional or nullable or isCallbackReturnValue:
  3656             sequenceClass = "Sequence"
  3657         else:
  3658             sequenceClass = "binding_detail::AutoSequence"
  3660         # XXXbz we can't include the index in the sourceDescription, because
  3661         # we don't really have a way to pass one in dynamically at runtime...
  3662         elementInfo = getJSToNativeConversionInfo(
  3663             elementType, descriptorProvider, isMember="Sequence",
  3664             exceptionCode=exceptionCode, lenientFloatCode=lenientFloatCode,
  3665             isCallbackReturnValue=isCallbackReturnValue,
  3666             sourceDescription="element of %s" % sourceDescription)
  3667         if elementInfo.dealWithOptional:
  3668             raise TypeError("Shouldn't have optional things in sequences")
  3669         if elementInfo.holderType is not None:
  3670             raise TypeError("Shouldn't need holders for sequences")
  3672         typeName = CGTemplatedType(sequenceClass, elementInfo.declType)
  3673         sequenceType = typeName.define()
  3674         if nullable:
  3675             typeName = CGTemplatedType("Nullable", typeName)
  3676             arrayRef = "${declName}.SetValue()"
  3677         else:
  3678             arrayRef = "${declName}"
  3680         elementConversion = string.Template(elementInfo.template).substitute({
  3681                 "val": "temp",
  3682                 "mutableVal": "&temp",
  3683                 "declName": "slot",
  3684                 # We only need holderName here to handle isExternal()
  3685                 # interfaces, which use an internal holder for the
  3686                 # conversion even when forceOwningType ends up true.
  3687                 "holderName": "tempHolder"
  3688             })
  3690         # NOTE: Keep this in sync with variadic conversions as needed
  3691         templateBody = fill(
  3692             """
  3693             JS::ForOfIterator iter(cx);
  3694             if (!iter.init($${val}, JS::ForOfIterator::AllowNonIterable)) {
  3695               $*{exceptionCode}
  3697             if (!iter.valueIsIterable()) {
  3698               $*{notSequence}
  3700             ${sequenceType} &arr = ${arrayRef};
  3701             JS::Rooted<JS::Value> temp(cx);
  3702             while (true) {
  3703               bool done;
  3704               if (!iter.next(&temp, &done)) {
  3705                 $*{exceptionCode}
  3707               if (done) {
  3708                 break;
  3710               ${elementType}* slotPtr = arr.AppendElement();
  3711               if (!slotPtr) {
  3712                 JS_ReportOutOfMemory(cx);
  3713                 $*{exceptionCode}
  3715               ${elementType}& slot = *slotPtr;
  3716               $*{elementConversion}
  3718             """,
  3719             exceptionCode=exceptionCode,
  3720             notSequence=notSequence,
  3721             sequenceType=sequenceType,
  3722             arrayRef=arrayRef,
  3723             elementType=elementInfo.declType.define(),
  3724             elementConversion=elementConversion)
  3726         templateBody = wrapObjectTemplate(templateBody, type,
  3727                                           "${declName}.SetNull();\n", notSequence)
  3728         # Sequence arguments that might contain traceable things need
  3729         # to get traced
  3730         if not isMember and typeNeedsRooting(elementType):
  3731             holderType = CGTemplatedType("SequenceRooter", elementInfo.declType)
  3732             # If our sequence is nullable, this will set the Nullable to be
  3733             # not-null, but that's ok because we make an explicit SetNull() call
  3734             # on it as needed if our JS value is actually null.
  3735             holderArgs = "cx, &%s" % arrayRef
  3736         else:
  3737             holderType = None
  3738             holderArgs = None
  3740         return JSToNativeConversionInfo(templateBody, declType=typeName,
  3741                                         holderType=holderType,
  3742                                         dealWithOptional=isOptional,
  3743                                         holderArgs=holderArgs)
  3745     if type.isMozMap():
  3746         assert not isEnforceRange and not isClamp
  3747         if failureCode is None:
  3748             notMozMap = ('ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n'
  3749                            "%s" % (firstCap(sourceDescription), exceptionCode))
  3750         else:
  3751             notMozMap = failureCode
  3753         nullable = type.nullable()
  3754         # Be very careful not to change "type": we need it later
  3755         if nullable:
  3756             valueType = type.inner.inner
  3757         else:
  3758             valueType = type.inner
  3760         valueInfo = getJSToNativeConversionInfo(
  3761             valueType, descriptorProvider, isMember="MozMap",
  3762             exceptionCode=exceptionCode, lenientFloatCode=lenientFloatCode,
  3763             isCallbackReturnValue=isCallbackReturnValue,
  3764             sourceDescription="value in %s" % sourceDescription)
  3765         if valueInfo.dealWithOptional:
  3766             raise TypeError("Shouldn't have optional things in MozMap")
  3767         if valueInfo.holderType is not None:
  3768             raise TypeError("Shouldn't need holders for MozMap")
  3770         typeName = CGTemplatedType("MozMap", valueInfo.declType)
  3771         mozMapType = typeName.define()
  3772         if nullable:
  3773             typeName = CGTemplatedType("Nullable", typeName)
  3774             mozMapRef = "${declName}.SetValue()"
  3775         else:
  3776             mozMapRef = "${declName}"
  3778         valueConversion = string.Template(valueInfo.template).substitute({
  3779                 "val": "temp",
  3780                 "mutableVal": "&temp",
  3781                 "declName": "slot",
  3782                 # We only need holderName here to handle isExternal()
  3783                 # interfaces, which use an internal holder for the
  3784                 # conversion even when forceOwningType ends up true.
  3785                 "holderName": "tempHolder"
  3786             })
  3788         templateBody = fill(
  3789             """
  3790             ${mozMapType} &mozMap = ${mozMapRef};
  3792             JS::Rooted<JSObject*> mozMapObj(cx, &$${val}.toObject());
  3793             JS::AutoIdArray ids(cx, JS_Enumerate(cx, mozMapObj));
  3794             if (!ids) {
  3795               $*{exceptionCode}
  3797             JS::Rooted<JS::Value> propNameValue(cx);
  3798             JS::Rooted<JS::Value> temp(cx);
  3799             JS::Rooted<jsid> curId(cx);
  3800             for (size_t i = 0; i < ids.length(); ++i) {
  3801               // Make sure we get the value before converting the name, since
  3802               // getting the value can trigger GC but our name is a dependent
  3803               // string.
  3804               curId = ids[i];
  3805               binding_detail::FakeDependentString propName;
  3806               if (!JS_GetPropertyById(cx, mozMapObj, curId, &temp) ||
  3807                   !JS_IdToValue(cx, curId, &propNameValue) ||
  3808                   !ConvertJSValueToString(cx, propNameValue, &propNameValue,
  3809                                           eStringify, eStringify, propName)) {
  3810                 $*{exceptionCode}
  3813               ${valueType}* slotPtr = mozMap.AddEntry(propName);
  3814               if (!slotPtr) {
  3815                 JS_ReportOutOfMemory(cx);
  3816                 $*{exceptionCode}
  3818               ${valueType}& slot = *slotPtr;
  3819               $*{valueConversion}
  3821             """,
  3822             exceptionCode=exceptionCode,
  3823             mozMapType=mozMapType,
  3824             mozMapRef=mozMapRef,
  3825             valueType=valueInfo.declType.define(),
  3826             valueConversion=valueConversion)
  3828         templateBody = wrapObjectTemplate(templateBody, type,
  3829                                           "${declName}.SetNull();\n",
  3830                                           notMozMap)
  3832         declType = typeName
  3833         declArgs = None
  3834         holderType = None
  3835         holderArgs = None
  3836         # MozMap arguments that might contain traceable things need
  3837         # to get traced
  3838         if not isMember and isCallbackReturnValue:
  3839             # Go ahead and just convert directly into our actual return value
  3840             declType = CGWrapper(declType, post="&")
  3841             declArgs = "aRetVal"
  3842         elif not isMember and typeNeedsRooting(valueType):
  3843             holderType = CGTemplatedType("MozMapRooter", valueInfo.declType)
  3844             # If our MozMap is nullable, this will set the Nullable to be
  3845             # not-null, but that's ok because we make an explicit SetNull() call
  3846             # on it as needed if our JS value is actually null.
  3847             holderArgs = "cx, &%s" % mozMapRef
  3849         return JSToNativeConversionInfo(templateBody, declType=declType,
  3850                                         declArgs=declArgs,
  3851                                         holderType=holderType,
  3852                                         dealWithOptional=isOptional,
  3853                                         holderArgs=holderArgs)
  3855     if type.isUnion():
  3856         nullable = type.nullable()
  3857         if nullable:
  3858             type = type.inner
  3860         unionArgumentObj = "${declName}" if isMember else "${holderName}"
  3861         if nullable:
  3862             # If we're a member, we're a Nullable, which hasn't been told it has
  3863             # a value.  Otherwise we're an already-constructed Maybe.
  3864             unionArgumentObj += ".SetValue()" if isMember else ".ref()"
  3866         memberTypes = type.flatMemberTypes
  3867         names = []
  3869         interfaceMemberTypes = filter(lambda t: t.isNonCallbackInterface(), memberTypes)
  3870         if len(interfaceMemberTypes) > 0:
  3871             interfaceObject = []
  3872             for memberType in interfaceMemberTypes:
  3873                 if type.isGeckoInterface():
  3874                     name = memberType.inner.identifier.name
  3875                 else:
  3876                     name = memberType.name
  3877                 interfaceObject.append(
  3878                     CGGeneric("(failed = !%s.TrySetTo%s(cx, ${val}, ${mutableVal}, tryNext)) || !tryNext" %
  3879                               (unionArgumentObj, name)))
  3880                 names.append(name)
  3881             interfaceObject = CGWrapper(CGList(interfaceObject, " ||\n"),
  3882                                         pre="done = ", post=";\n\n", reindent=True)
  3883         else:
  3884             interfaceObject = None
  3886         arrayObjectMemberTypes = filter(lambda t: t.isArray() or t.isSequence(), memberTypes)
  3887         if len(arrayObjectMemberTypes) > 0:
  3888             raise TypeError("Bug 767924: We don't support sequences in unions yet")
  3889         else:
  3890             arrayObject = None
  3892         dateObjectMemberTypes = filter(lambda t: t.isDate(), memberTypes)
  3893         if len(dateObjectMemberTypes) > 0:
  3894             assert len(dateObjectMemberTypes) == 1
  3895             memberType = dateObjectMemberTypes[0]
  3896             name = memberType.name
  3897             dateObject = CGGeneric("%s.SetTo%s(cx, ${val}, ${mutableVal});\n"
  3898                                    "done = true;\n" % (unionArgumentObj, name))
  3899             dateObject = CGIfWrapper(dateObject, "JS_ObjectIsDate(cx, argObj)")
  3900             names.append(name)
  3901         else:
  3902             dateObject = None
  3904         callbackMemberTypes = filter(lambda t: t.isCallback() or t.isCallbackInterface(), memberTypes)
  3905         if len(callbackMemberTypes) > 0:
  3906             assert len(callbackMemberTypes) == 1
  3907             memberType = callbackMemberTypes[0]
  3908             name = memberType.name
  3909             callbackObject = CGGeneric(
  3910                 "done = (failed = !%s.TrySetTo%s(cx, ${val}, ${mutableVal}, tryNext)) || !tryNext;\n" %
  3911                 (unionArgumentObj, name))
  3912             names.append(name)
  3913         else:
  3914             callbackObject = None
  3916         dictionaryMemberTypes = filter(lambda t: t.isDictionary(), memberTypes)
  3917         if len(dictionaryMemberTypes) > 0:
  3918             assert len(dictionaryMemberTypes) == 1
  3919             name = dictionaryMemberTypes[0].inner.identifier.name
  3920             setDictionary = CGGeneric(
  3921                 "done = (failed = !%s.TrySetTo%s(cx, ${val}, ${mutableVal}, tryNext)) || !tryNext;\n" %
  3922                 (unionArgumentObj, name))
  3923             names.append(name)
  3924         else:
  3925             setDictionary = None
  3927         mozMapMemberTypes = filter(lambda t: t.isMozMap(), memberTypes)
  3928         if len(mozMapMemberTypes) > 0:
  3929             raise TypeError("We don't support MozMap in unions yet")
  3931         objectMemberTypes = filter(lambda t: t.isObject(), memberTypes)
  3932         if len(objectMemberTypes) > 0:
  3933             assert len(objectMemberTypes) == 1
  3934             # Very important to NOT construct a temporary Rooted here, since the
  3935             # SetToObject call can call a Rooted constructor and we need to keep
  3936             # stack discipline for Rooted.
  3937             object = CGGeneric("%s.SetToObject(cx, &${val}.toObject());\n"
  3938                                "done = true;\n" % unionArgumentObj)
  3939             names.append(objectMemberTypes[0].name)
  3940         else:
  3941             object = None
  3943         hasObjectTypes = interfaceObject or arrayObject or dateObject or callbackObject or object
  3944         if hasObjectTypes:
  3945             # "object" is not distinguishable from other types
  3946             assert not object or not (interfaceObject or arrayObject or dateObject or callbackObject)
  3947             if arrayObject or dateObject or callbackObject:
  3948                 # An object can be both an array object and a callback or
  3949                 # dictionary, but we shouldn't have both in the union's members
  3950                 # because they are not distinguishable.
  3951                 assert not (arrayObject and callbackObject)
  3952                 templateBody = CGElseChain([arrayObject, dateObject, callbackObject])
  3953             else:
  3954                 templateBody = None
  3955             if interfaceObject:
  3956                 assert not object
  3957                 if templateBody:
  3958                     templateBody = CGIfWrapper(templateBody, "!done")
  3959                 templateBody = CGList([interfaceObject, templateBody])
  3960             else:
  3961                 templateBody = CGList([templateBody, object])
  3963             if dateObject:
  3964                 templateBody.prepend(CGGeneric("JS::Rooted<JSObject*> argObj(cx, &${val}.toObject());\n"))
  3965             templateBody = CGIfWrapper(templateBody, "${val}.isObject()")
  3966         else:
  3967             templateBody = CGGeneric()
  3969         if setDictionary:
  3970             assert not object
  3971             templateBody = CGList([templateBody,
  3972                                    CGIfWrapper(setDictionary, "!done")])
  3974         stringTypes = [t for t in memberTypes if t.isString() or t.isEnum()]
  3975         numericTypes = [t for t in memberTypes if t.isNumeric()]
  3976         booleanTypes = [t for t in memberTypes if t.isBoolean()]
  3977         if stringTypes or numericTypes or booleanTypes:
  3978             assert len(stringTypes) <= 1
  3979             assert len(numericTypes) <= 1
  3980             assert len(booleanTypes) <= 1
  3982             # We will wrap all this stuff in a do { } while (0); so we
  3983             # can use "break" for flow control.
  3984             def getStringOrPrimitiveConversion(memberType):
  3985                 if memberType.isEnum():
  3986                     name = memberType.inner.identifier.name
  3987                 else:
  3988                     name = memberType.name
  3989                 return CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, ${mutableVal}, tryNext)) || !tryNext;\n"
  3990                                  "break;\n" % (unionArgumentObj, name))
  3991             other = CGList([])
  3992             stringConversion = map(getStringOrPrimitiveConversion, stringTypes)
  3993             numericConversion = map(getStringOrPrimitiveConversion, numericTypes)
  3994             booleanConversion = map(getStringOrPrimitiveConversion, booleanTypes)
  3995             if stringConversion:
  3996                 if booleanConversion:
  3997                     other.append(CGIfWrapper(booleanConversion[0],
  3998                                              "${val}.isBoolean()"))
  3999                 if numericConversion:
  4000                     other.append(CGIfWrapper(numericConversion[0],
  4001                                              "${val}.isNumber()"))
  4002                 other.append(stringConversion[0])
  4003             elif numericConversion:
  4004                 if booleanConversion:
  4005                     other.append(CGIfWrapper(booleanConversion[0],
  4006                                              "${val}.isBoolean()"))
  4007                 other.append(numericConversion[0])
  4008             else:
  4009                 assert booleanConversion
  4010                 other.append(booleanConversion[0])
  4012             other = CGWrapper(CGIndenter(other), pre="do {\n", post="} while (0);\n")
  4013             if hasObjectTypes or setDictionary:
  4014                 other = CGWrapper(CGIndenter(other), "{\n", post="}\n")
  4015                 if object:
  4016                     templateBody = CGElseChain([templateBody, other])
  4017                 else:
  4018                     other = CGWrapper(other, pre="if (!done) ")
  4019                     templateBody = CGList([templateBody, other])
  4020             else:
  4021                 assert templateBody.define() == ""
  4022                 templateBody = other
  4023         else:
  4024             other = None
  4026         templateBody = CGWrapper(templateBody, pre="bool done = false, failed = false, tryNext;\n")
  4027         throw = CGGeneric(fill(
  4028             """
  4029             if (failed) {
  4030               $*{exceptionCode}
  4032             if (!done) {
  4033               ThrowErrorMessage(cx, MSG_NOT_IN_UNION, "${desc}", "${names}");
  4034               $*{exceptionCode}
  4036             """,
  4037             exceptionCode=exceptionCode,
  4038             desc=firstCap(sourceDescription),
  4039             names=", ".join(names)))
  4041         templateBody = CGWrapper(CGIndenter(CGList([templateBody, throw])), pre="{\n", post="}\n")
  4043         typeName = CGUnionStruct.unionTypeDecl(type, isMember)
  4044         argumentTypeName = typeName + "Argument"
  4045         if nullable:
  4046             typeName = "Nullable<" + typeName + " >"
  4048         def handleNull(templateBody, setToNullVar, extraConditionForNull=""):
  4049             nullTest = "%s${val}.isNullOrUndefined()" % extraConditionForNull
  4050             return CGIfElseWrapper(nullTest,
  4051                                    CGGeneric("%s.SetNull();\n" % setToNullVar),
  4052                                    templateBody)
  4054         if type.hasNullableType:
  4055             assert not nullable
  4056             # Make sure to handle a null default value here
  4057             if defaultValue and isinstance(defaultValue, IDLNullValue):
  4058                 assert defaultValue.type == type
  4059                 extraConditionForNull = "!(${haveValue}) || "
  4060             else:
  4061                 extraConditionForNull = ""
  4062             templateBody = handleNull(templateBody, unionArgumentObj,
  4063                                       extraConditionForNull=extraConditionForNull)
  4065         declType = CGGeneric(typeName)
  4066         if isMember:
  4067             holderType = None
  4068         else:
  4069             holderType = CGGeneric(argumentTypeName)
  4070             if nullable:
  4071                 holderType = CGTemplatedType("Maybe", holderType)
  4073         # If we're isOptional and not nullable the normal optional handling will
  4074         # handle lazy construction of our holder.  If we're nullable and not
  4075         # isMember we do it all by hand because we do not want our holder
  4076         # constructed if we're null.  But if we're isMember we don't have a
  4077         # holder anyway, so we can do the normal Optional codepath.
  4078         declLoc = "${declName}"
  4079         constructDecl = None
  4080         if nullable:
  4081             if isOptional and not isMember:
  4082                 holderArgs = "${declName}.Value().SetValue()"
  4083                 declType = CGTemplatedType("Optional", declType)
  4084                 constructDecl = CGGeneric("${declName}.Construct();\n")
  4085                 declLoc = "${declName}.Value()"
  4086             else:
  4087                 holderArgs = "${declName}.SetValue()"
  4088             if holderType is not None:
  4089                 constructHolder = CGGeneric("${holderName}.construct(%s);\n" % holderArgs)
  4090             else:
  4091                 constructHolder = None
  4092             # Don't need to pass those args when the holder is being constructed
  4093             holderArgs = None
  4094         else:
  4095             holderArgs = "${declName}"
  4096             constructHolder = None
  4098         if defaultValue and not isinstance(defaultValue, IDLNullValue):
  4099             tag = defaultValue.type.tag()
  4101             if tag in numericSuffixes or tag is IDLType.Tags.bool:
  4102                 defaultStr = getHandleDefault(defaultValue)
  4103                 value = declLoc + (".Value()" if nullable else "")
  4104                 default = CGGeneric("%s.RawSetAs%s() = %s;\n" %
  4105                                     (value, defaultValue.type, defaultStr))
  4106             else:
  4107                 default = CGGeneric(
  4108                     handleDefaultStringValue(
  4109                         defaultValue, "%s.SetStringData" % unionArgumentObj) +
  4110                     ";\n")
  4112             templateBody = CGIfElseWrapper("!(${haveValue})", default, templateBody)
  4114         templateBody = CGList([constructHolder, templateBody])
  4116         if nullable:
  4117             if defaultValue:
  4118                 if isinstance(defaultValue, IDLNullValue):
  4119                     extraConditionForNull = "!(${haveValue}) || "
  4120                 else:
  4121                     extraConditionForNull = "${haveValue} && "
  4122             else:
  4123                 extraConditionForNull = ""
  4124             templateBody = handleNull(templateBody, declLoc,
  4125                                       extraConditionForNull=extraConditionForNull)
  4126         elif (not type.hasNullableType and defaultValue and
  4127               isinstance(defaultValue, IDLNullValue)):
  4128             assert type.hasDictionaryType
  4129             assert defaultValue.type.isDictionary()
  4130             if not isMember and typeNeedsRooting(defaultValue.type):
  4131                 ctorArgs = "cx"
  4132             else:
  4133                 ctorArgs = ""
  4134             initDictionaryWithNull = CGIfWrapper(
  4135                 CGGeneric("return false;\n"),
  4136                 ('!%s.RawSetAs%s(%s).Init(cx, JS::NullHandleValue, "Member of %s")'
  4137                  % (declLoc, getUnionMemberName(defaultValue.type),
  4138                     ctorArgs, type)))
  4139             templateBody = CGIfElseWrapper("!(${haveValue})",
  4140                                            initDictionaryWithNull,
  4141                                            templateBody)
  4143         templateBody = CGList([constructDecl, templateBody])
  4145         return JSToNativeConversionInfo(templateBody.define(),
  4146                                         declType=declType,
  4147                                         holderType=holderType,
  4148                                         holderArgs=holderArgs,
  4149                                         dealWithOptional=isOptional and (not nullable or isMember))
  4151     if type.isGeckoInterface():
  4152         assert not isEnforceRange and not isClamp
  4154         descriptor = descriptorProvider.getDescriptor(
  4155             type.unroll().inner.identifier.name)
  4157         if descriptor.nativeType == 'JSObject':
  4158             # XXXbz Workers code does this sometimes
  4159             assert descriptor.workers
  4160             return handleJSObjectType(type, isMember, failureCode)
  4162         if descriptor.interface.isCallback():
  4163             name = descriptor.interface.identifier.name
  4164             if type.nullable() or isCallbackReturnValue:
  4165                 declType = CGGeneric("nsRefPtr<%s>" % name)
  4166             else:
  4167                 declType = CGGeneric("OwningNonNull<%s>" % name)
  4168             # BOGUS extra blank line here turns out to be at the end of a block:
  4169             conversion = indent(CGCallbackTempRoot(name).define()) + "\n"
  4171             template = wrapObjectTemplate(conversion, type,
  4172                                           "${declName} = nullptr;\n",
  4173                                           failureCode)
  4174             return JSToNativeConversionInfo(template, declType=declType,
  4175                                             dealWithOptional=isOptional)
  4177         # This is an interface that we implement as a concrete class
  4178         # or an XPCOM interface.
  4180         # Allow null pointers for nullable types and old-binding classes, and
  4181         # use an nsRefPtr or raw pointer for callback return values to make
  4182         # them easier to return.
  4183         argIsPointer = (type.nullable() or type.unroll().inner.isExternal() or
  4184                         isCallbackReturnValue)
  4186         # Sequences and non-worker callbacks have to hold a strong ref to the
  4187         # thing being passed down.  Union return values must hold a strong ref
  4188         # because they may be returning an addrefed pointer.
  4189         # Also, callback return values always end up
  4190         # addrefing anyway, so there is no point trying to avoid it here and it
  4191         # makes other things simpler since we can assume the return value is a
  4192         # strong ref.
  4193         forceOwningType = ((descriptor.interface.isCallback() and
  4194                             not descriptor.workers) or
  4195                            isMember or
  4196                            isCallbackReturnValue)
  4198         if forceOwningType and descriptor.nativeOwnership == 'owned':
  4199             raise TypeError("Interface %s has 'owned' nativeOwnership, so we "
  4200                             "don't know how to keep it alive in %s" %
  4201                             (descriptor.interface.identifier.name,
  4202                              sourceDescription))
  4204         typeName = descriptor.nativeType
  4205         typePtr = typeName + "*"
  4207         # Compute a few things:
  4208         #  - declType is the type we want to return as the first element of our
  4209         #    tuple.
  4210         #  - holderType is the type we want to return as the third element
  4211         #    of our tuple.
  4213         # Set up some sensible defaults for these things insofar as we can.
  4214         holderType = None
  4215         if argIsPointer:
  4216             if forceOwningType:
  4217                 declType = "nsRefPtr<" + typeName + ">"
  4218             else:
  4219                 declType = typePtr
  4220         else:
  4221             if forceOwningType:
  4222                 declType = "OwningNonNull<" + typeName + ">"
  4223             else:
  4224                 declType = "NonNull<" + typeName + ">"
  4226         templateBody = ""
  4227         if not descriptor.skipGen and not descriptor.interface.isConsequential() and not descriptor.interface.isExternal():
  4228             if failureCode is not None:
  4229                 templateBody += str(CastableObjectUnwrapper(
  4230                     descriptor,
  4231                     "&${val}.toObject()",
  4232                     "${declName}",
  4233                     failureCode))
  4234             else:
  4235                 templateBody += str(FailureFatalCastableObjectUnwrapper(
  4236                     descriptor,
  4237                     "&${val}.toObject()",
  4238                     "${declName}",
  4239                     exceptionCode,
  4240                     isCallbackReturnValue,
  4241                     firstCap(sourceDescription)))
  4242         elif descriptor.workers:
  4243             return handleJSObjectType(type, isMember, failureCode)
  4244         else:
  4245             # Either external, or new-binding non-castable.  We always have a
  4246             # holder for these, because we don't actually know whether we have
  4247             # to addref when unwrapping or not.  So we just pass an
  4248             # getter_AddRefs(nsRefPtr) to XPConnect and if we'll need a release
  4249             # it'll put a non-null pointer in there.
  4250             if forceOwningType:
  4251                 # Don't return a holderType in this case; our declName
  4252                 # will just own stuff.
  4253                 templateBody += "nsRefPtr<" + typeName + "> ${holderName};\n"
  4254             else:
  4255                 holderType = "nsRefPtr<" + typeName + ">"
  4256             templateBody += (
  4257                 "JS::Rooted<JS::Value> tmpVal(cx, ${val});\n" +
  4258                 typePtr + " tmp;\n"
  4259                 "if (NS_FAILED(UnwrapArg<" + typeName + ">(cx, ${val}, &tmp, static_cast<" + typeName + "**>(getter_AddRefs(${holderName})), &tmpVal))) {\n")
  4260             templateBody += CGIndenter(onFailureBadType(failureCode,
  4261                                                         descriptor.interface.identifier.name)).define()
  4262             templateBody += ("}\n"
  4263                              "MOZ_ASSERT(tmp);\n")
  4265             if not isDefinitelyObject and not forceOwningType:
  4266                 # Our tmpVal will go out of scope, so we can't rely on it
  4267                 # for rooting
  4268                 templateBody += dedent("""
  4269                     if (tmpVal != ${val} && !${holderName}) {
  4270                       // We have to have a strong ref, because we got this off
  4271                       // some random object that might get GCed
  4272                       ${holderName} = tmp;
  4274                     """)
  4276             # And store our tmp, before it goes out of scope.
  4277             templateBody += "${declName} = tmp;\n"
  4279         # Just pass failureCode, not onFailureBadType, here, so we'll report the
  4280         # thing as not an object as opposed to not implementing whatever our
  4281         # interface is.
  4282         templateBody = wrapObjectTemplate(templateBody, type,
  4283                                           "${declName} = nullptr;\n", failureCode)
  4285         declType = CGGeneric(declType)
  4286         if holderType is not None:
  4287             holderType = CGGeneric(holderType)
  4288         return JSToNativeConversionInfo(templateBody,
  4289                                         declType=declType,
  4290                                         holderType=holderType,
  4291                                         dealWithOptional=isOptional)
  4293     if type.isSpiderMonkeyInterface():
  4294         assert not isEnforceRange and not isClamp
  4295         name = type.name
  4296         arrayType = CGGeneric(name)
  4297         declType = arrayType
  4298         if type.nullable():
  4299             declType = CGTemplatedType("Nullable", declType)
  4300             objRef = "${declName}.SetValue()"
  4301         else:
  4302             objRef = "${declName}"
  4304         # Again, this is a bit strange since we are actually building a
  4305         # template string here. ${objRef} and $*{badType} below are filled in
  4306         # right now; $${val} expands to ${val}, to be filled in later.
  4307         template = fill(
  4308             """
  4309             if (!${objRef}.Init(&$${val}.toObject())) {
  4310               $*{badType}
  4313             """,  # BOGUS extra blank line
  4314             objRef=objRef,
  4315             badType=onFailureBadType(failureCode, type.name).define())
  4316         template = wrapObjectTemplate(template, type, "${declName}.SetNull();\n",
  4317                                       failureCode)
  4318         if not isMember:
  4319             # This is a bit annoying.  In a union we don't want to have a
  4320             # holder, since unions don't support that.  But if we're optional we
  4321             # want to have a holder, so that the callee doesn't see
  4322             # Optional<RootedTypedArray<ArrayType> >.  So do a holder if we're
  4323             # optional and use a RootedTypedArray otherwise.
  4324             if isOptional:
  4325                 holderType = CGTemplatedType("TypedArrayRooter", arrayType)
  4326                 # If our typed array is nullable, this will set the Nullable to
  4327                 # be not-null, but that's ok because we make an explicit
  4328                 # SetNull() call on it as needed if our JS value is actually
  4329                 # null.  XXXbz Because "Maybe" takes const refs for constructor
  4330                 # arguments, we can't pass a reference here; have to pass a
  4331                 # pointer.
  4332                 holderArgs = "cx, &%s" % objRef
  4333                 declArgs = None
  4334             else:
  4335                 holderType = None
  4336                 holderArgs = None
  4337                 declType = CGTemplatedType("RootedTypedArray", declType)
  4338                 declArgs = "cx"
  4339         else:
  4340             holderType = None
  4341             holderArgs = None
  4342             declArgs = None
  4343         return JSToNativeConversionInfo(template,
  4344                                         declType=declType,
  4345                                         holderType=holderType,
  4346                                         dealWithOptional=isOptional,
  4347                                         declArgs=declArgs,
  4348                                         holderArgs=holderArgs)
  4350     if type.isDOMString():
  4351         assert not isEnforceRange and not isClamp
  4353         treatAs = {
  4354             "Default": "eStringify",
  4355             "EmptyString": "eEmpty",
  4356             "Null": "eNull",
  4358         if type.nullable():
  4359             # For nullable strings null becomes a null string.
  4360             treatNullAs = "Null"
  4361             # For nullable strings undefined also becomes a null string.
  4362             undefinedBehavior = "eNull"
  4363         else:
  4364             undefinedBehavior = "eStringify"
  4365         nullBehavior = treatAs[treatNullAs]
  4367         def getConversionCode(varName):
  4368             conversionCode = (
  4369                 "if (!ConvertJSValueToString(cx, ${val}, ${mutableVal}, %s, %s, %s)) {\n"
  4370                 "%s"
  4371                 "}\n" % (nullBehavior, undefinedBehavior, varName,
  4372                          exceptionCodeIndented.define()))
  4373             if defaultValue is None:
  4374                 return conversionCode
  4376             if isinstance(defaultValue, IDLNullValue):
  4377                 assert(type.nullable())
  4378                 defaultCode = "%s.SetNull()" % varName
  4379             else:
  4380                 defaultCode = handleDefaultStringValue(defaultValue,
  4381                                                        "%s.SetData" % varName)
  4382             return handleDefault(conversionCode, defaultCode + ";\n")
  4384         if isMember:
  4385             # We have to make a copy, except in the variadic case, because our
  4386             # jsval may well not live as long as our string needs to.
  4387             declType = CGGeneric("nsString")
  4388             if isMember == "Variadic":
  4389                 # The string is kept alive by the argument, so we can just
  4390                 # depend on it.
  4391                 assignString = "${declName}.Rebind(str.Data(), str.Length());\n"
  4392             else:
  4393                 assignString = "${declName} = str;\n"
  4394             return JSToNativeConversionInfo(
  4395                 fill(
  4396                     """
  4398                       binding_detail::FakeDependentString str;
  4399                       $*{convert}
  4400                       $*{assign}
  4403                     """,  # BOGUS extra newline
  4404                     convert=getConversionCode("str"),
  4405                     assign=assignString),
  4406                 declType=declType,
  4407                 dealWithOptional=isOptional)
  4409         if isOptional:
  4410             declType = "Optional<nsAString>"
  4411             holderType = CGGeneric("binding_detail::FakeDependentString")
  4412             conversionCode = ("%s"
  4413                               "${declName} = &${holderName};\n" %
  4414                               getConversionCode("${holderName}"))
  4415         else:
  4416             declType = "binding_detail::FakeDependentString"
  4417             holderType = None
  4418             conversionCode = getConversionCode("${declName}")
  4420         # No need to deal with optional here; we handled it already
  4421         return JSToNativeConversionInfo(
  4422             conversionCode,
  4423             declType=CGGeneric(declType),
  4424             holderType=holderType)
  4426     if type.isByteString():
  4427         assert not isEnforceRange and not isClamp
  4429         nullable = toStringBool(type.nullable())
  4431         conversionCode = (
  4432             "if (!ConvertJSValueToByteString(cx, ${val}, ${mutableVal}, %s, ${declName})) {\n"
  4433             "%s"
  4434             "}\n" % (nullable, exceptionCodeIndented.define()))
  4435         # ByteString arguments cannot have a default value.
  4436         assert defaultValue is None
  4438         return JSToNativeConversionInfo(
  4439             conversionCode,
  4440             declType=CGGeneric("nsCString"),
  4441             dealWithOptional=isOptional)
  4443     if type.isEnum():
  4444         assert not isEnforceRange and not isClamp
  4446         enumName = type.unroll().inner.identifier.name
  4447         declType = CGGeneric(enumName)
  4448         if type.nullable():
  4449             declType = CGTemplatedType("Nullable", declType)
  4450             declType = declType.define()
  4451             enumLoc = "${declName}.SetValue()"
  4452         else:
  4453             enumLoc = "${declName}"
  4454             declType = declType.define()
  4456         if invalidEnumValueFatal:
  4457             handleInvalidEnumValueCode = "MOZ_ASSERT(index >= 0);\n"
  4458         else:
  4459             # invalidEnumValueFatal is false only for attributes.  So we won't
  4460             # have a non-default exceptionCode here unless attribute "arg
  4461             # conversion" code starts passing in an exceptionCode.  At which
  4462             # point we'll need to figure out what that even means.
  4463             assert exceptionCode == "return false;\n"
  4464             handleInvalidEnumValueCode = dedent("""
  4465                 if (index < 0) {
  4466                   return true;
  4468                 """)
  4470         template = fill(
  4471             """
  4473               bool ok;
  4474               int index = FindEnumStringIndex<${invalidEnumValueFatal}>(cx, $${val}, ${values}, "${enumtype}", "${sourceDescription}", &ok);
  4475               if (!ok) {
  4476                 $*{exceptionCode}
  4478               $*{handleInvalidEnumValueCode}
  4479               ${enumLoc} = static_cast<${enumtype}>(index);
  4481             """,
  4482             enumtype=enumName,
  4483             values=enumName + "Values::" + ENUM_ENTRY_VARIABLE_NAME,
  4484             invalidEnumValueFatal=toStringBool(invalidEnumValueFatal),
  4485             handleInvalidEnumValueCode=handleInvalidEnumValueCode,
  4486             exceptionCode=exceptionCode,
  4487             enumLoc=enumLoc,
  4488             sourceDescription=firstCap(sourceDescription))
  4490         setNull = "${declName}.SetNull();\n"
  4492         if type.nullable():
  4493             template = CGIfElseWrapper("${val}.isNullOrUndefined()",
  4494                                        CGGeneric(setNull),
  4495                                        CGGeneric(template)).define()
  4497         if defaultValue is not None:
  4498             if isinstance(defaultValue, IDLNullValue):
  4499                 assert type.nullable()
  4500                 template = handleDefault(template, setNull)
  4501             else:
  4502                 assert(defaultValue.type.tag() == IDLType.Tags.domstring)
  4503                 template = handleDefault(template,
  4504                                          ("%s = %s::%s;\n" %
  4505                                           (enumLoc, enumName,
  4506                                            getEnumValueName(defaultValue.value))))
  4507         return JSToNativeConversionInfo(template, declType=CGGeneric(declType),
  4508                                         dealWithOptional=isOptional)
  4510     if type.isCallback():
  4511         assert not isEnforceRange and not isClamp
  4512         assert not type.treatNonCallableAsNull() or type.nullable()
  4513         assert not type.treatNonObjectAsNull() or type.nullable()
  4514         assert not type.treatNonObjectAsNull() or not type.treatNonCallableAsNull()
  4516         name = type.unroll().identifier.name
  4517         if type.nullable():
  4518             declType = CGGeneric("nsRefPtr<%s>" % name)
  4519         else:
  4520             declType = CGGeneric("OwningNonNull<%s>" % name)
  4521         conversion = indent(CGCallbackTempRoot(name).define())
  4523         if allowTreatNonCallableAsNull and type.treatNonCallableAsNull():
  4524             haveCallable = "JS_ObjectIsCallable(cx, &${val}.toObject())"
  4525             if not isDefinitelyObject:
  4526                 haveCallable = "${val}.isObject() && " + haveCallable
  4527             if defaultValue is not None:
  4528                 assert(isinstance(defaultValue, IDLNullValue))
  4529                 haveCallable = "${haveValue} && " + haveCallable
  4530             template = (
  4531                 ("if (%s) {\n" % haveCallable) +
  4532                 conversion +
  4533                 "} else {\n"
  4534                 "  ${declName} = nullptr;\n"
  4535                 "}\n")
  4536         elif allowTreatNonCallableAsNull and type.treatNonObjectAsNull():
  4537             if not isDefinitelyObject:
  4538                 haveObject = "${val}.isObject()"
  4539                 if defaultValue is not None:
  4540                     assert(isinstance(defaultValue, IDLNullValue))
  4541                     haveObject = "${haveValue} && " + haveObject
  4542                 template = CGIfElseWrapper(haveObject,
  4543                                            CGGeneric(conversion + "\n"),  # BOGUS extra blank line
  4544                                            CGGeneric("${declName} = nullptr;\n")).define()
  4545             else:
  4546                 template = conversion
  4547         else:
  4548             template = wrapObjectTemplate(
  4549                 "if (JS_ObjectIsCallable(cx, &${val}.toObject())) {\n" +
  4550                 conversion +
  4551                 "} else {\n" +
  4552                 indent(onFailureNotCallable(failureCode).define()) +
  4553                 "}\n",
  4554                 type,
  4555                 "${declName} = nullptr;\n",
  4556                 failureCode)
  4557         return JSToNativeConversionInfo(template, declType=declType,
  4558                                         dealWithOptional=isOptional)
  4560     if type.isAny():
  4561         assert not isEnforceRange and not isClamp
  4563         declArgs = None
  4564         if isMember in ("Variadic", "Sequence", "Dictionary", "MozMap"):
  4565             # Rooting is handled by the sequence and dictionary tracers.
  4566             declType = "JS::Value"
  4567         else:
  4568             assert not isMember
  4569             declType = "JS::Rooted<JS::Value>"
  4570             declArgs = "cx"
  4572         assert not isOptional
  4573         templateBody = "${declName} = ${val};\n"
  4574         # We may not have a default value if we're being converted for
  4575         # a setter, say.
  4576         if defaultValue:
  4577             if isinstance(defaultValue, IDLNullValue):
  4578                 defaultHandling = "${declName} = JS::NullValue();\n"
  4579             else:
  4580                 assert isinstance(defaultValue, IDLUndefinedValue)
  4581                 defaultHandling = "${declName} = JS::UndefinedValue();\n"
  4582             templateBody = handleDefault(templateBody, defaultHandling)
  4583         return JSToNativeConversionInfo(templateBody,
  4584                                         declType=CGGeneric(declType),
  4585                                         declArgs=declArgs)
  4587     if type.isObject():
  4588         assert not isEnforceRange and not isClamp
  4589         return handleJSObjectType(type, isMember, failureCode)
  4591     if type.isDictionary():
  4592         # There are no nullable dictionaries
  4593         assert not type.nullable() or isCallbackReturnValue
  4594         # All optional dictionaries always have default values, so we
  4595         # should be able to assume not isOptional here.
  4596         assert not isOptional
  4597         # In the callback return value case we never have to worry
  4598         # about a default value; we always have a value.
  4599         assert not isCallbackReturnValue or defaultValue is None
  4601         typeName = CGDictionary.makeDictionaryName(type.unroll().inner)
  4602         if not isMember and not isCallbackReturnValue:
  4603             # Since we're not a member and not nullable or optional, no one will
  4604             # see our real type, so we can do the fast version of the dictionary
  4605             # that doesn't pre-initialize members.
  4606             typeName = "binding_detail::Fast" + typeName
  4608         declType = CGGeneric(typeName)
  4610         # We do manual default value handling here, because we
  4611         # actually do want a jsval, and we only handle null anyway
  4612         # NOTE: if isNullOrUndefined or isDefinitelyObject are true,
  4613         # we know we have a value, so we don't have to worry about the
  4614         # default value.
  4615         if (not isNullOrUndefined and not isDefinitelyObject and
  4616             defaultValue is not None):
  4617             assert(isinstance(defaultValue, IDLNullValue))
  4618             val = "(${haveValue}) ? ${val} : JS::NullHandleValue"
  4619         else:
  4620             val = "${val}"
  4622         if failureCode is not None:
  4623             if isDefinitelyObject:
  4624                 dictionaryTest = "IsObjectValueConvertibleToDictionary"
  4625             else:
  4626                 dictionaryTest = "IsConvertibleToDictionary"
  4627             # Check that the value we have can in fact be converted to
  4628             # a dictionary, and return failureCode if not.
  4629             template = CGIfWrapper(
  4630                 CGGeneric(failureCode),
  4631                 "!%s(cx, ${val})" % dictionaryTest).define() + "\n"
  4632         else:
  4633             template = ""
  4635         dictLoc = "${declName}"
  4636         if type.nullable():
  4637             dictLoc += ".SetValue()"
  4639         template += ('if (!%s.Init(cx, %s, "%s")) {\n'
  4640                      "%s"
  4641                      "}\n" % (dictLoc, val, firstCap(sourceDescription),
  4642                               exceptionCodeIndented.define()))
  4644         if type.nullable():
  4645             declType = CGTemplatedType("Nullable", declType)
  4646             template = CGIfElseWrapper("${val}.isNullOrUndefined()",
  4647                                        CGGeneric("${declName}.SetNull();\n"),
  4648                                        CGGeneric(template)).define()
  4650         # Dictionary arguments that might contain traceable things need to get
  4651         # traced
  4652         if not isMember and isCallbackReturnValue:
  4653             # Go ahead and just convert directly into our actual return value
  4654             declType = CGWrapper(declType, post="&")
  4655             declArgs = "aRetVal"
  4656         elif not isMember and typeNeedsRooting(type):
  4657             declType = CGTemplatedType("RootedDictionary", declType)
  4658             declArgs = "cx"
  4659         else:
  4660             declArgs = None
  4662         return JSToNativeConversionInfo(template, declType=declType,
  4663                                         declArgs=declArgs)
  4665     if type.isVoid():
  4666         assert not isOptional
  4667         # This one only happens for return values, and its easy: Just
  4668         # ignore the jsval.
  4669         return JSToNativeConversionInfo("")
  4671     if type.isDate():
  4672         assert not isEnforceRange and not isClamp
  4674         declType = CGGeneric("Date")
  4675         if type.nullable():
  4676             declType = CGTemplatedType("Nullable", declType)
  4677             dateVal = "${declName}.SetValue()"
  4678         else:
  4679             dateVal = "${declName}"
  4681         if failureCode is None:
  4682             notDate = ('ThrowErrorMessage(cx, MSG_NOT_DATE, "%s");\n'
  4683                        "%s" % (firstCap(sourceDescription), exceptionCode))
  4684         else:
  4685             notDate = failureCode
  4687         conversion = fill(
  4688             """
  4689             JS::Rooted<JSObject*> possibleDateObject(cx, &$${val}.toObject());
  4690             if (!JS_ObjectIsDate(cx, possibleDateObject) ||
  4691                 !${dateVal}.SetTimeStamp(cx, possibleDateObject)) {
  4692               $*{notDate}
  4694             """,
  4695             dateVal=dateVal,
  4696             notDate=notDate)
  4698         conversion = wrapObjectTemplate(conversion, type,
  4699                                         "${declName}.SetNull();\n", notDate)
  4700         return JSToNativeConversionInfo(conversion,
  4701                                         declType=declType,
  4702                                         dealWithOptional=isOptional)
  4704     if not type.isPrimitive():
  4705         raise TypeError("Need conversion for argument type '%s'" % str(type))
  4707     typeName = builtinNames[type.tag()]
  4709     conversionBehavior = "eDefault"
  4710     if isEnforceRange:
  4711         assert type.isInteger()
  4712         conversionBehavior = "eEnforceRange"
  4713     elif isClamp:
  4714         assert type.isInteger()
  4715         conversionBehavior = "eClamp"
  4717     if type.nullable():
  4718         declType = CGGeneric("Nullable<" + typeName + ">")
  4719         writeLoc = "${declName}.SetValue()"
  4720         readLoc = "${declName}.Value()"
  4721         nullCondition = "${val}.isNullOrUndefined()"
  4722         if defaultValue is not None and isinstance(defaultValue, IDLNullValue):
  4723             nullCondition = "!(${haveValue}) || " + nullCondition
  4724         template = (
  4725             "if (%s) {\n"
  4726             "  ${declName}.SetNull();\n"
  4727             "} else if (!ValueToPrimitive<%s, %s>(cx, ${val}, &%s)) {\n"
  4728             "%s"
  4729             "}\n" % (nullCondition, typeName, conversionBehavior,
  4730                      writeLoc, exceptionCodeIndented.define()))
  4731     else:
  4732         assert(defaultValue is None or
  4733                not isinstance(defaultValue, IDLNullValue))
  4734         writeLoc = "${declName}"
  4735         readLoc = writeLoc
  4736         template = (
  4737             "if (!ValueToPrimitive<%s, %s>(cx, ${val}, &%s)) {\n"
  4738             "%s"
  4739             "}\n" % (typeName, conversionBehavior, writeLoc,
  4740                      exceptionCodeIndented.define()))
  4741         declType = CGGeneric(typeName)
  4743     if type.isFloat() and not type.isUnrestricted():
  4744         if lenientFloatCode is not None:
  4745             nonFiniteCode = lenientFloatCode
  4746         else:
  4747             nonFiniteCode = ('ThrowErrorMessage(cx, MSG_NOT_FINITE, "%s");\n'
  4748                              "%s" % (firstCap(sourceDescription), exceptionCode))
  4749         template = template.rstrip()
  4750         template += fill(
  4751             """
  4752              else if (!mozilla::IsFinite(${readLoc})) {
  4753               // Note: mozilla::IsFinite will do the right thing
  4754               //       when passed a non-finite float too.
  4755               $*{nonFiniteCode}
  4757             """,
  4758             readLoc=readLoc,
  4759             nonFiniteCode=nonFiniteCode)
  4761     if (defaultValue is not None and
  4762         # We already handled IDLNullValue, so just deal with the other ones
  4763         not isinstance(defaultValue, IDLNullValue)):
  4764         tag = defaultValue.type.tag()
  4765         defaultStr = getHandleDefault(defaultValue)
  4766         template = CGIfElseWrapper(
  4767             "${haveValue}",
  4768             CGGeneric(template),
  4769             CGGeneric("%s = %s;\n" % (writeLoc, defaultStr))).define()
  4771     return JSToNativeConversionInfo(template, declType=declType,
  4772                                     dealWithOptional=isOptional)
  4775 def instantiateJSToNativeConversion(info, replacements, checkForValue=False):
  4776     """
  4777     Take a JSToNativeConversionInfo as returned by getJSToNativeConversionInfo
  4778     and a set of replacements as required by the strings in such an object, and
  4779     generate code to convert into stack C++ types.
  4781     If checkForValue is True, then the conversion will get wrapped in
  4782     a check for ${haveValue}.
  4783     """
  4784     templateBody, declType, holderType, dealWithOptional = (
  4785         info.template, info.declType, info.holderType, info.dealWithOptional)
  4787     if dealWithOptional and not checkForValue:
  4788         raise TypeError("Have to deal with optional things, but don't know how")
  4789     if checkForValue and declType is None:
  4790         raise TypeError("Need to predeclare optional things, so they will be "
  4791                         "outside the check for big enough arg count!")
  4793     # We can't precompute our holder constructor arguments, since
  4794     # those might depend on ${declName}, which we change below.  Just
  4795     # compute arguments at the point when we need them as we go.
  4796     def getArgsCGThing(args):
  4797         return CGGeneric(string.Template(args).substitute(replacements))
  4799     result = CGList([])
  4800     # Make a copy of "replacements" since we may be about to start modifying it
  4801     replacements = dict(replacements)
  4802     originalDeclName = replacements["declName"]
  4803     if declType is not None:
  4804         if dealWithOptional:
  4805             replacements["declName"] = "%s.Value()" % originalDeclName
  4806             declType = CGTemplatedType("Optional", declType)
  4807             declCtorArgs = None
  4808         elif info.declArgs is not None:
  4809             declCtorArgs = CGWrapper(getArgsCGThing(info.declArgs),
  4810                                      pre="(", post=")")
  4811         else:
  4812             declCtorArgs = None
  4813         result.append(
  4814             CGList([declType, CGGeneric(" "),
  4815                     CGGeneric(originalDeclName),
  4816                     declCtorArgs, CGGeneric(";\n")]))
  4818     originalHolderName = replacements["holderName"]
  4819     if holderType is not None:
  4820         if dealWithOptional:
  4821             replacements["holderName"] = "%s.ref()" % originalHolderName
  4822             holderType = CGTemplatedType("Maybe", holderType)
  4823             holderCtorArgs = None
  4824         elif info.holderArgs is not None:
  4825             holderCtorArgs = CGWrapper(getArgsCGThing(info.holderArgs),
  4826                                        pre="(", post=")")
  4827         else:
  4828             holderCtorArgs = None
  4829         result.append(
  4830             CGList([holderType, CGGeneric(" "),
  4831                     CGGeneric(originalHolderName),
  4832                     holderCtorArgs, CGGeneric(";\n")]))
  4834     conversion = CGGeneric(
  4835         string.Template(templateBody).substitute(replacements))
  4837     if checkForValue:
  4838         if dealWithOptional:
  4839             declConstruct = CGIndenter(
  4840                 CGGeneric("%s.Construct(%s);\n" %
  4841                           (originalDeclName,
  4842                            getArgsCGThing(info.declArgs).define() if
  4843                            info.declArgs else "")))
  4844             if holderType is not None:
  4845                 holderConstruct = CGIndenter(
  4846                     CGGeneric("%s.construct(%s);\n" %
  4847                               (originalHolderName,
  4848                                getArgsCGThing(info.holderArgs).define() if
  4849                                info.holderArgs else "")))
  4850             else:
  4851                 holderConstruct = None
  4852         else:
  4853             declConstruct = None
  4854             holderConstruct = None
  4856         conversion = CGList([
  4857             CGGeneric(
  4858                 string.Template("if (${haveValue}) {\n").substitute(replacements)),
  4859             declConstruct,
  4860             holderConstruct,
  4861             CGIndenter(conversion),
  4862             CGGeneric("}\n")
  4863         ])
  4865     result.append(conversion)
  4866     return result
  4869 def convertConstIDLValueToJSVal(value):
  4870     if isinstance(value, IDLNullValue):
  4871         return "JS::NullValue()"
  4872     if isinstance(value, IDLUndefinedValue):
  4873         return "JS::UndefinedValue()"
  4874     tag = value.type.tag()
  4875     if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16,
  4876                IDLType.Tags.uint16, IDLType.Tags.int32]:
  4877         return "INT_TO_JSVAL(%s)" % (value.value)
  4878     if tag == IDLType.Tags.uint32:
  4879         return "UINT_TO_JSVAL(%sU)" % (value.value)
  4880     if tag in [IDLType.Tags.int64, IDLType.Tags.uint64]:
  4881         return "DOUBLE_TO_JSVAL(%s)" % numericValue(tag, value.value)
  4882     if tag == IDLType.Tags.bool:
  4883         return "JSVAL_TRUE" if value.value else "JSVAL_FALSE"
  4884     if tag in [IDLType.Tags.float, IDLType.Tags.double]:
  4885         return "DOUBLE_TO_JSVAL(%s)" % (value.value)
  4886     raise TypeError("Const value of unhandled type: %s" % value.type)
  4889 class CGArgumentConverter(CGThing):
  4890     """
  4891     A class that takes an IDL argument object and its index in the
  4892     argument list and generates code to unwrap the argument to the
  4893     right native type.
  4895     argDescription is a description of the argument for error-reporting
  4896     purposes.  Callers should assume that it might get placed in the middle of a
  4897     sentence.  If it ends up at the beginning of a sentence, its first character
  4898     will be automatically uppercased.
  4899     """
  4900     def __init__(self, argument, index, descriptorProvider,
  4901                  argDescription,
  4902                  invalidEnumValueFatal=True, lenientFloatCode=None):
  4903         CGThing.__init__(self)
  4904         self.argument = argument
  4905         self.argDescription = argDescription
  4906         assert(not argument.defaultValue or argument.optional)
  4908         replacer = {
  4909             "index": index,
  4910             "argc": "args.length()"
  4912         self.replacementVariables = {
  4913             "declName": "arg%d" % index,
  4914             "holderName": ("arg%d" % index) + "_holder",
  4915             "obj": "obj"
  4917         self.replacementVariables["val"] = string.Template(
  4918             "args[${index}]").substitute(replacer)
  4919         self.replacementVariables["mutableVal"] = self.replacementVariables["val"]
  4920         haveValueCheck = string.Template(
  4921             "args.hasDefined(${index})").substitute(replacer)
  4922         self.replacementVariables["haveValue"] = haveValueCheck
  4923         self.descriptorProvider = descriptorProvider
  4924         if self.argument.optional and not self.argument.defaultValue:
  4925             self.argcAndIndex = replacer
  4926         else:
  4927             self.argcAndIndex = None
  4928         self.invalidEnumValueFatal = invalidEnumValueFatal
  4929         self.lenientFloatCode = lenientFloatCode
  4931     def define(self):
  4932         typeConversion = getJSToNativeConversionInfo(
  4933             self.argument.type,
  4934             self.descriptorProvider,
  4935             isOptional=(self.argcAndIndex is not None and
  4936                         not self.argument.variadic),
  4937             invalidEnumValueFatal=self.invalidEnumValueFatal,
  4938             defaultValue=self.argument.defaultValue,
  4939             treatNullAs=self.argument.treatNullAs,
  4940             isEnforceRange=self.argument.enforceRange,
  4941             isClamp=self.argument.clamp,
  4942             lenientFloatCode=self.lenientFloatCode,
  4943             isMember="Variadic" if self.argument.variadic else False,
  4944             allowTreatNonCallableAsNull=self.argument.allowTreatNonCallableAsNull(),
  4945             sourceDescription=self.argDescription)
  4947         if not self.argument.variadic:
  4948             return instantiateJSToNativeConversion(
  4949                 typeConversion,
  4950                 self.replacementVariables,
  4951                 self.argcAndIndex is not None).define()
  4953         # Variadic arguments get turned into a sequence.
  4954         if typeConversion.dealWithOptional:
  4955             raise TypeError("Shouldn't have optional things in variadics")
  4956         if typeConversion.holderType is not None:
  4957             raise TypeError("Shouldn't need holders for variadics")
  4959         replacer = dict(self.argcAndIndex, **self.replacementVariables)
  4960         replacer["seqType"] = CGTemplatedType("binding_detail::AutoSequence",
  4961                                               typeConversion.declType).define()
  4962         if typeNeedsRooting(self.argument.type):
  4963             rooterDecl = ("SequenceRooter<%s> ${holderName}(cx, &${declName});\n" %
  4964                           typeConversion.declType.define())
  4965         else:
  4966             rooterDecl = ""
  4967         replacer["elemType"] = typeConversion.declType.define()
  4969         # NOTE: Keep this in sync with sequence conversions as needed
  4970         variadicConversion = string.Template(
  4971             "${seqType} ${declName};\n" +
  4972             rooterDecl +
  4973             dedent("""
  4974                 if (${argc} > ${index}) {
  4975                   if (!${declName}.SetCapacity(${argc} - ${index})) {
  4976                     JS_ReportOutOfMemory(cx);
  4977                     return false;
  4979                   for (uint32_t variadicArg = ${index}; variadicArg < ${argc}; ++variadicArg) {
  4980                     ${elemType}& slot = *${declName}.AppendElement();
  4981                 """)
  4982         ).substitute(replacer)
  4984         val = string.Template("args[variadicArg]").substitute(replacer)
  4985         variadicConversion += indent(
  4986             string.Template(typeConversion.template).substitute({
  4987                 "val": val,
  4988                 "mutableVal": val,
  4989                 "declName": "slot",
  4990                 # We only need holderName here to handle isExternal()
  4991                 # interfaces, which use an internal holder for the
  4992                 # conversion even when forceOwningType ends up true.
  4993                 "holderName": "tempHolder",
  4994                 # Use the same ${obj} as for the variadic arg itself
  4995                 "obj": replacer["obj"]
  4996             }), 4)
  4998         variadicConversion += ("  }\n"
  4999                                "}\n")
  5000         return variadicConversion
  5003 def getMaybeWrapValueFuncForType(type):
  5004     # Callbacks might actually be DOM objects; nothing prevents a page from
  5005     # doing that.
  5006     if type.isCallback() or type.isCallbackInterface() or type.isObject():
  5007         if type.nullable():
  5008             return "MaybeWrapObjectOrNullValue"
  5009         return "MaybeWrapObjectValue"
  5010     # Spidermonkey interfaces are never DOM objects.  Neither are sequences or
  5011     # dictionaries, since those are always plain JS objects.
  5012     if type.isSpiderMonkeyInterface() or type.isDictionary() or type.isSequence():
  5013         if type.nullable():
  5014             return "MaybeWrapNonDOMObjectOrNullValue"
  5015         return "MaybeWrapNonDOMObjectValue"
  5016     if type.isAny():
  5017         return "MaybeWrapValue"
  5019     # For other types, just go ahead an fall back on MaybeWrapValue for now:
  5020     # it's always safe to do, and shouldn't be particularly slow for any of
  5021     # them
  5022     return "MaybeWrapValue"
  5025 sequenceWrapLevel = 0
  5026 mozMapWrapLevel = 0
  5029 def getWrapTemplateForType(type, descriptorProvider, result, successCode,
  5030                            returnsNewObject, exceptionCode, typedArraysAreStructs):
  5031     """
  5032     Reflect a C++ value stored in "result", of IDL type "type" into JS.  The
  5033     "successCode" is the code to run once we have successfully done the
  5034     conversion and must guarantee that execution of the conversion template
  5035     stops once the successCode has executed (e.g. by doing a 'return', or by
  5036     doing a 'break' if the entire conversion template is inside a block that
  5037     the 'break' will exit).
  5039     If typedArraysAreStructs is true, then if the type is a typed array,
  5040     "result" is one of the dom::TypedArray subclasses, not a JSObject*.
  5042     The resulting string should be used with string.Template.  It
  5043     needs the following keys when substituting:
  5045       jsvalHandle: something that can be passed to methods taking a
  5046                    JS::MutableHandle<JS::Value>.  This can be a
  5047                    JS::MutableHandle<JS::Value> or a JS::Rooted<JS::Value>*.
  5048       jsvalRef: something that can have .address() called on it to get a
  5049                 JS::Value* and .set() called on it to set it to a JS::Value.
  5050                 This can be a JS::MutableHandle<JS::Value> or a
  5051                 JS::Rooted<JS::Value>.
  5052       obj: a JS::Handle<JSObject*>.
  5054     Returns (templateString, infallibility of conversion template)
  5055     """
  5056     if successCode is None:
  5057         successCode = "return true;\n"
  5059     def setUndefined():
  5060         return _setValue("", setter="setUndefined")
  5062     def setNull():
  5063         return _setValue("", setter="setNull")
  5065     def setInt32(value):
  5066         return _setValue(value, setter="setInt32")
  5068     def setString(value):
  5069         return _setValue(value, setter="setString")
  5071     def setObject(value, wrapAsType=None):
  5072         return _setValue(value, wrapAsType=wrapAsType, setter="setObject")
  5074     def setObjectOrNull(value, wrapAsType=None):
  5075         return _setValue(value, wrapAsType=wrapAsType, setter="setObjectOrNull")
  5077     def setUint32(value):
  5078         return _setValue(value, setter="setNumber")
  5080     def setDouble(value):
  5081         return _setValue("JS_NumberValue(%s)" % value)
  5083     def setBoolean(value):
  5084         return _setValue(value, setter="setBoolean")
  5086     def _setValue(value, wrapAsType=None, setter="set"):
  5087         """
  5088         Returns the code to set the jsval to value.
  5090         If wrapAsType is not None, then will wrap the resulting value using the
  5091         function that getMaybeWrapValueFuncForType(wrapAsType) returns.
  5092         Otherwise, no wrapping will be done.
  5093         """
  5094         if wrapAsType is None:
  5095             tail = successCode
  5096         else:
  5097             tail = fill(
  5098                 """
  5099                 if (!${maybeWrap}(cx, $${jsvalHandle})) {
  5100                   $*{exceptionCode}
  5102                 $*{successCode}
  5103                 """,
  5104                 maybeWrap=getMaybeWrapValueFuncForType(wrapAsType),
  5105                 exceptionCode=exceptionCode,
  5106                 successCode=successCode)
  5107         return ("${jsvalRef}.%s(%s);\n" % (setter, value)) + tail
  5109     def wrapAndSetPtr(wrapCall, failureCode=None):
  5110         """
  5111         Returns the code to set the jsval by calling "wrapCall". "failureCode"
  5112         is the code to run if calling "wrapCall" fails
  5113         """
  5114         if failureCode is None:
  5115             failureCode = exceptionCode
  5116         return fill(
  5117             """
  5118             if (!${wrapCall}) {
  5119               $*{failureCode}
  5121             $*{successCode}
  5122             """,
  5123             wrapCall=wrapCall,
  5124             failureCode=failureCode,
  5125             successCode=successCode)
  5127     if type is None or type.isVoid():
  5128         return (setUndefined(), True)
  5130     if type.isArray():
  5131         raise TypeError("Can't handle array return values yet")
  5133     if (type.isSequence() or type.isMozMap()) and type.nullable():
  5134         # These are both wrapped in Nullable<>
  5135         recTemplate, recInfall = getWrapTemplateForType(type.inner, descriptorProvider,
  5136                                                         "%s.Value()" % result, successCode,
  5137                                                         returnsNewObject, exceptionCode,
  5138                                                         typedArraysAreStructs)
  5139         code = fill(
  5140             """
  5142             if (${result}.IsNull()) {
  5143               $*{setNull}
  5145             $*{recTemplate}
  5146             """,
  5147             result=result,
  5148         setNull=setNull(),
  5149             recTemplate=recTemplate)
  5150         return code, recInfall
  5152     if type.isSequence():
  5153         # Now do non-nullable sequences.  Our success code is just to break to
  5154         # where we set the element in the array.  Note that we bump the
  5155         # sequenceWrapLevel around this call so that nested sequence conversions
  5156         # will use different iteration variables.
  5157         global sequenceWrapLevel
  5158         index = "sequenceIdx%d" % sequenceWrapLevel
  5159         sequenceWrapLevel += 1
  5160         innerTemplate = wrapForType(
  5161             type.inner, descriptorProvider,
  5163                 'result': "%s[%s]" % (result, index),
  5164                 'successCode': "break;\n",
  5165                 'jsvalRef': "tmp",
  5166                 'jsvalHandle': "&tmp",
  5167                 'returnsNewObject': returnsNewObject,
  5168                 'exceptionCode': exceptionCode,
  5169                 'obj': "returnArray"
  5170             })
  5171         sequenceWrapLevel -= 1
  5172         code = fill(
  5173             """
  5175             uint32_t length = ${result}.Length();
  5176             JS::Rooted<JSObject*> returnArray(cx, JS_NewArrayObject(cx, length));
  5177             if (!returnArray) {
  5178               $*{exceptionCode}
  5180             // Scope for 'tmp'
  5182               JS::Rooted<JS::Value> tmp(cx);
  5183               for (uint32_t ${index} = 0; ${index} < length; ++${index}) {
  5184                 // Control block to let us common up the JS_DefineElement calls when there
  5185                 // are different ways to succeed at wrapping the object.
  5186                 do {
  5187                   $*{innerTemplate}
  5188                 } while (0);
  5189                 if (!JS_DefineElement(cx, returnArray, ${index}, tmp,
  5190                                       nullptr, nullptr, JSPROP_ENUMERATE)) {
  5191                   $*{exceptionCode}
  5195             $*{set}
  5196             """,
  5197             result=result,
  5198             exceptionCode=exceptionCode,
  5199             index=index,
  5200             innerTemplate=innerTemplate,
  5201             set=setObject("*returnArray"))
  5203         return (code, False)
  5205     if type.isMozMap():
  5206         # Now do non-nullable MozMap.  Our success code is just to break to
  5207         # where we define the property on the object.  Note that we bump the
  5208         # mozMapWrapLevel around this call so that nested MozMap conversions
  5209         # will use different temp value names.
  5210         global mozMapWrapLevel
  5211         valueName = "mozMapValue%d" % mozMapWrapLevel
  5212         mozMapWrapLevel += 1
  5213         innerTemplate = wrapForType(
  5214             type.inner, descriptorProvider,
  5216                 'result': valueName,
  5217                 'successCode': "break;\n",
  5218                 'jsvalRef': "tmp",
  5219                 'jsvalHandle': "&tmp",
  5220                 'returnsNewObject': returnsNewObject,
  5221                 'exceptionCode': exceptionCode,
  5222                 'obj': "returnObj"
  5223             })
  5224         mozMapWrapLevel -= 1
  5225         code = fill(
  5226             """
  5228             nsTArray<nsString> keys;
  5229             ${result}.GetKeys(keys);
  5230             JS::Rooted<JSObject*> returnObj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
  5231             if (!returnObj) {
  5232               $*{exceptionCode}
  5234             // Scope for 'tmp'
  5236               JS::Rooted<JS::Value> tmp(cx);
  5237               for (size_t idx = 0; idx < keys.Length(); ++idx) {
  5238                 auto& ${valueName} = ${result}.Get(keys[idx]);
  5239                 // Control block to let us common up the JS_DefineUCProperty calls when there
  5240                 // are different ways to succeed at wrapping the value.
  5241                 do {
  5242                   $*{innerTemplate}
  5243                 } while (0);
  5244                 if (!JS_DefineUCProperty(cx, returnObj, keys[idx].get(),
  5245                                          keys[idx].Length(), tmp,
  5246                                          JS_PropertyStub, JS_StrictPropertyStub,
  5247                                          JSPROP_ENUMERATE)) {
  5248                   $*{exceptionCode}
  5252             $*{set}
  5253             """,
  5254             result=result,
  5255             exceptionCode=exceptionCode,
  5256             valueName=valueName,
  5257             innerTemplate=innerTemplate,
  5258             set=setObject("*returnObj"))
  5260         return (code, False)
  5262     if type.isGeckoInterface() and not type.isCallbackInterface():
  5263         descriptor = descriptorProvider.getDescriptor(type.unroll().inner.identifier.name)
  5264         if type.nullable():
  5265             wrappingCode = ("if (!%s) {\n" % (result) +
  5266                             indent(setNull()) +
  5267                             "}\n")
  5268         else:
  5269             wrappingCode = ""
  5271         if not descriptor.interface.isExternal() and not descriptor.skipGen:
  5272             if descriptor.wrapperCache:
  5273                 assert descriptor.nativeOwnership != 'owned'
  5274                 wrapMethod = "WrapNewBindingObject"
  5275             else:
  5276                 if not returnsNewObject:
  5277                     raise MethodNotNewObjectError(descriptor.interface.identifier.name)
  5278                 if descriptor.nativeOwnership == 'owned':
  5279                     wrapMethod = "WrapNewBindingNonWrapperCachedOwnedObject"
  5280                 else:
  5281                     wrapMethod = "WrapNewBindingNonWrapperCachedObject"
  5282             wrap = "%s(cx, ${obj}, %s, ${jsvalHandle})" % (wrapMethod, result)
  5283             if not descriptor.hasXPConnectImpls:
  5284                 # Can only fail to wrap as a new-binding object
  5285                 # if they already threw an exception.
  5286                 #XXX Assertion disabled for now, see bug 991271.
  5287                 failed = ("MOZ_ASSERT(true || JS_IsExceptionPending(cx));\n" +
  5288                           exceptionCode)
  5289             else:
  5290                 if descriptor.notflattened:
  5291                     raise TypeError("%s has XPConnect impls but not flattened; "
  5292                                     "fallback won't work correctly" %
  5293                                     descriptor.interface.identifier.name)
  5294                 # Try old-style wrapping for bindings which might be XPConnect impls.
  5295                 failed = wrapAndSetPtr("HandleNewBindingWrappingFailure(cx, ${obj}, %s, ${jsvalHandle})" % result)
  5296         else:
  5297             if descriptor.notflattened:
  5298                 getIID = "&NS_GET_IID(%s), " % descriptor.nativeType
  5299             else:
  5300                 getIID = ""
  5301             wrap = "WrapObject(cx, %s, %s${jsvalHandle})" % (result, getIID)
  5302             failed = None
  5304         wrappingCode += wrapAndSetPtr(wrap, failed)
  5305         return (wrappingCode, False)
  5307     if type.isDOMString():
  5308         if type.nullable():
  5309             return (wrapAndSetPtr("xpc::StringToJsval(cx, %s, ${jsvalHandle})" % result), False)
  5310         else:
  5311             return (wrapAndSetPtr("xpc::NonVoidStringToJsval(cx, %s, ${jsvalHandle})" % result), False)
  5313     if type.isByteString():
  5314         if type.nullable():
  5315             return (wrapAndSetPtr("ByteStringToJsval(cx, %s, ${jsvalHandle})" % result), False)
  5316         else:
  5317             return (wrapAndSetPtr("NonVoidByteStringToJsval(cx, %s, ${jsvalHandle})" % result), False)
  5319     if type.isEnum():
  5320         if type.nullable():
  5321             resultLoc = "%s.Value()" % result
  5322         else:
  5323             resultLoc = result
  5324         conversion = fill(
  5325             """
  5327               // Scope for resultStr
  5328               MOZ_ASSERT(uint32_t(${result}) < ArrayLength(${strings}));
  5329               JSString* resultStr = JS_NewStringCopyN(cx, ${strings}[uint32_t(${result})].value, ${strings}[uint32_t(${result})].length);
  5330               if (!resultStr) {
  5331                 $*{exceptionCode}
  5333               $*{setResultStr}
  5335             """,
  5336             result=resultLoc,
  5337             strings=(type.unroll().inner.identifier.name + "Values::" +
  5338                      ENUM_ENTRY_VARIABLE_NAME),
  5339             exceptionCode=exceptionCode,
  5340             setResultStr=setString("resultStr"))
  5342         if type.nullable():
  5343             conversion = CGIfElseWrapper(
  5344                 "%s.IsNull()" % result,
  5345                 CGGeneric(setNull()),
  5346                 CGGeneric(conversion)).define()
  5347         return conversion, False
  5349     if type.isCallback() or type.isCallbackInterface():
  5350         wrapCode = setObject(
  5351             "*GetCallbackFromCallbackObject(%(result)s)",
  5352             wrapAsType=type)
  5353         if type.nullable():
  5354             wrapCode = (
  5355                 "if (%(result)s) {\n" +
  5356                 indent(wrapCode) +
  5357                 "} else {\n" +
  5358                 indent(setNull()) +
  5359                 "}\n")
  5360         wrapCode = wrapCode % {"result": result}
  5361         return wrapCode, False
  5363     if type.isAny():
  5364         # See comments in WrapNewBindingObject explaining why we need
  5365         # to wrap here.
  5366         # NB: _setValue(..., type-that-is-any) calls JS_WrapValue(), so is fallible
  5367         return (_setValue(result, wrapAsType=type), False)
  5369     if (type.isObject() or (type.isSpiderMonkeyInterface() and
  5370                             not typedArraysAreStructs)):
  5371         # See comments in WrapNewBindingObject explaining why we need
  5372         # to wrap here.
  5373         if type.nullable():
  5374             toValue = "%s"
  5375             setter = setObjectOrNull
  5376         else:
  5377             toValue = "*%s"
  5378             setter = setObject
  5379         # NB: setObject{,OrNull}(..., some-object-type) calls JS_WrapValue(), so is fallible
  5380         return (setter(toValue % result, wrapAsType=type), False)
  5382     if not (type.isUnion() or type.isPrimitive() or type.isDictionary() or
  5383             type.isDate() or
  5384             (type.isSpiderMonkeyInterface() and typedArraysAreStructs)):
  5385         raise TypeError("Need to learn to wrap %s" % type)
  5387     if type.nullable():
  5388         recTemplate, recInfal = getWrapTemplateForType(type.inner, descriptorProvider,
  5389                                                        "%s.Value()" % result, successCode,
  5390                                                        returnsNewObject, exceptionCode,
  5391                                                        typedArraysAreStructs)
  5392         return ("if (%s.IsNull()) {\n" % result +
  5393                 indent(setNull()) +
  5394                 "}\n" +
  5395                 recTemplate, recInfal)
  5397     if type.isSpiderMonkeyInterface():
  5398         assert typedArraysAreStructs
  5399         # See comments in WrapNewBindingObject explaining why we need
  5400         # to wrap here.
  5401         # NB: setObject(..., some-object-type) calls JS_WrapValue(), so is fallible
  5402         return (setObject("*%s.Obj()" % result,
  5403                           wrapAsType=type), False)
  5405     if type.isUnion():
  5406         return (wrapAndSetPtr("%s.ToJSVal(cx, ${obj}, ${jsvalHandle})" % result),
  5407                 False)
  5409     if type.isDictionary():
  5410         return (wrapAndSetPtr("%s.ToObject(cx, ${jsvalHandle})" % result),
  5411                 False)
  5413     if type.isDate():
  5414         return (wrapAndSetPtr("%s.ToDateObject(cx, ${jsvalHandle})" % result),
  5415                 False)
  5417     tag = type.tag()
  5419     if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16,
  5420                IDLType.Tags.uint16, IDLType.Tags.int32]:
  5421         return (setInt32("int32_t(%s)" % result), True)
  5423     elif tag in [IDLType.Tags.int64, IDLType.Tags.uint64,
  5424                  IDLType.Tags.unrestricted_float, IDLType.Tags.float,
  5425                  IDLType.Tags.unrestricted_double, IDLType.Tags.double]:
  5426         # XXXbz will cast to double do the "even significand" thing that webidl
  5427         # calls for for 64-bit ints?  Do we care?
  5428         return (setDouble("double(%s)" % result), True)
  5430     elif tag == IDLType.Tags.uint32:
  5431         return (setUint32(result), True)
  5433     elif tag == IDLType.Tags.bool:
  5434         return (setBoolean(result), True)
  5436     else:
  5437         raise TypeError("Need to learn to wrap primitive: %s" % type)
  5440 def wrapForType(type, descriptorProvider, templateValues):
  5441     """
  5442     Reflect a C++ value of IDL type "type" into JS.  TemplateValues is a dict
  5443     that should contain:
  5445       * 'jsvalRef': something that can have .address() called on it to get a
  5446                     JS::Value* and .set() called on it to set it to a JS::Value.
  5447                     This can be a JS::MutableHandle<JS::Value> or a
  5448                     JS::Rooted<JS::Value>.
  5449       * 'jsvalHandle': something that can be passed to methods taking a
  5450                        JS::MutableHandle<JS::Value>.  This can be a
  5451                        JS::MutableHandle<JS::Value> or a JS::Rooted<JS::Value>*.
  5452       * 'obj' (optional): the name of the variable that contains the JSObject to
  5453                           use as a scope when wrapping, if not supplied 'obj'
  5454                           will be used as the name
  5455       * 'result' (optional): the name of the variable in which the C++ value is
  5456                              stored, if not supplied 'result' will be used as
  5457                              the name
  5458       * 'successCode' (optional): the code to run once we have successfully
  5459                                   done the conversion, if not supplied 'return
  5460                                   true;' will be used as the code.  The
  5461                                   successCode must ensure that once it runs no
  5462                                   more of the conversion template will be
  5463                                   executed (e.g. by doing a 'return' or 'break'
  5464                                   as appropriate).
  5465       * 'returnsNewObject' (optional): If true, we're wrapping for the return
  5466                                        value of a [NewObject] method.  Assumed
  5467                                        false if not set.
  5468       * 'exceptionCode' (optional): Code to run when a JS exception is thrown.
  5469                                     The default is "return false;".  The code
  5470                                     passed here must return.
  5471     """
  5472     wrap = getWrapTemplateForType(type, descriptorProvider,
  5473                                   templateValues.get('result', 'result'),
  5474                                   templateValues.get('successCode', None),
  5475                                   templateValues.get('returnsNewObject', False),
  5476                                   templateValues.get('exceptionCode',
  5477                                                      "return false;\n"),
  5478                                   templateValues.get('typedArraysAreStructs',
  5479                                                      False))[0]
  5481     defaultValues = {'obj': 'obj'}
  5482     return string.Template(wrap).substitute(defaultValues, **templateValues)
  5485 def infallibleForMember(member, type, descriptorProvider):
  5486     """
  5487     Determine the fallibility of changing a C++ value of IDL type "type" into
  5488     JS for the given attribute. Apart from returnsNewObject, all the defaults
  5489     are used, since the fallbility does not change based on the boolean values,
  5490     and the template will be discarded.
  5492     CURRENT ASSUMPTIONS:
  5493         We assume that successCode for wrapping up return values cannot contain
  5494         failure conditions.
  5495     """
  5496     return getWrapTemplateForType(type, descriptorProvider, 'result', None,
  5497                                   memberReturnsNewObject(member), "return false;\n",
  5498                                   False)[1]
  5501 def leafTypeNeedsCx(type, retVal):
  5502     return (type.isAny() or type.isObject() or
  5503             (retVal and type.isSpiderMonkeyInterface()))
  5506 def leafTypeNeedsScopeObject(type, retVal):
  5507     return retVal and type.isSpiderMonkeyInterface()
  5510 def leafTypeNeedsRooting(type):
  5511     return leafTypeNeedsCx(type, False) or type.isSpiderMonkeyInterface()
  5514 def typeNeedsRooting(type):
  5515     return typeMatchesLambda(type,
  5516                              lambda t: leafTypeNeedsRooting(t))
  5519 def typeNeedsCx(type, retVal=False):
  5520     return typeMatchesLambda(type,
  5521                              lambda t: leafTypeNeedsCx(t, retVal))
  5524 def typeNeedsScopeObject(type, retVal=False):
  5525     return typeMatchesLambda(type,
  5526                              lambda t: leafTypeNeedsScopeObject(t, retVal))
  5529 def typeMatchesLambda(type, func):
  5530     if type is None:
  5531         return False
  5532     if type.nullable():
  5533         return typeMatchesLambda(type.inner, func)
  5534     if type.isSequence() or type.isMozMap() or type.isArray():
  5535         return typeMatchesLambda(type.inner, func)
  5536     if type.isUnion():
  5537         return any(typeMatchesLambda(t, func) for t in
  5538                    type.unroll().flatMemberTypes)
  5539     if type.isDictionary():
  5540         return dictionaryMatchesLambda(type.inner, func)
  5541     return func(type)
  5544 def dictionaryMatchesLambda(dictionary, func):
  5545     return (any(typeMatchesLambda(m.type, func) for m in dictionary.members) or
  5546             (dictionary.parent and dictionaryMatchesLambda(dictionary.parent, func)))
  5549 # Whenever this is modified, please update CGNativeMember.getRetvalInfo as
  5550 # needed to keep the types compatible.
  5551 def getRetvalDeclarationForType(returnType, descriptorProvider,
  5552                                 resultAlreadyAddRefed,
  5553                                 isMember=False):
  5554     """
  5555     Returns a tuple containing four things:
  5557     1) A CGThing for the type of the return value, or None if there is no need
  5558        for a return value.
  5560     2) A value indicating the kind of ourparam to pass the value as.  Valid
  5561        options are None to not pass as an out param at all, "ref" (to pass a
  5562        reference as an out param), and "ptr" (to pass a pointer as an out
  5563        param).
  5565     3) A CGThing for a tracer for the return value, or None if no tracing is
  5566        needed.
  5568     4) An argument string to pass to the retval declaration
  5569        constructor or None if there are no arguments.
  5570     """
  5571     if returnType is None or returnType.isVoid():
  5572         # Nothing to declare
  5573         return None, None, None, None
  5574     if returnType.isPrimitive() and returnType.tag() in builtinNames:
  5575         result = CGGeneric(builtinNames[returnType.tag()])
  5576         if returnType.nullable():
  5577             result = CGTemplatedType("Nullable", result)
  5578         return result, None, None, None
  5579     if returnType.isDOMString():
  5580         if isMember:
  5581             return CGGeneric("nsString"), "ref", None, None
  5582         return CGGeneric("DOMString"), "ref", None, None
  5583     if returnType.isByteString():
  5584         return CGGeneric("nsCString"), "ref", None, None
  5585     if returnType.isEnum():
  5586         result = CGGeneric(returnType.unroll().inner.identifier.name)
  5587         if returnType.nullable():
  5588             result = CGTemplatedType("Nullable", result)
  5589         return result, None, None, None
  5590     if returnType.isGeckoInterface():
  5591         result = CGGeneric(descriptorProvider.getDescriptor(
  5592             returnType.unroll().inner.identifier.name).nativeType)
  5593         if descriptorProvider.getDescriptor(
  5594                 returnType.unroll().inner.identifier.name).nativeOwnership == 'owned':
  5595             result = CGTemplatedType("nsAutoPtr", result)
  5596         elif resultAlreadyAddRefed:
  5597             result = CGTemplatedType("nsRefPtr", result)
  5598         else:
  5599             result = CGWrapper(result, post="*")
  5600         return result, None, None, None
  5601     if returnType.isCallback():
  5602         name = returnType.unroll().identifier.name
  5603         return CGGeneric("nsRefPtr<%s>" % name), None, None, None
  5604     if returnType.isAny():
  5605         if isMember:
  5606             return CGGeneric("JS::Value"), None, None, None
  5607         return CGGeneric("JS::Rooted<JS::Value>"), "ptr", None, "cx"
  5608     if returnType.isObject() or returnType.isSpiderMonkeyInterface():
  5609         if isMember:
  5610             return CGGeneric("JSObject*"), None, None, None
  5611         return CGGeneric("JS::Rooted<JSObject*>"), "ptr", None, "cx"
  5612     if returnType.isSequence():
  5613         nullable = returnType.nullable()
  5614         if nullable:
  5615             returnType = returnType.inner
  5616         # If our result is already addrefed, use the right type in the
  5617         # sequence argument here.
  5618         result, _, _, _ = getRetvalDeclarationForType(returnType.inner,
  5619                                                       descriptorProvider,
  5620                                                       resultAlreadyAddRefed,
  5621                                                       isMember="Sequence")
  5622         # While we have our inner type, set up our rooter, if needed
  5623         if not isMember and typeNeedsRooting(returnType):
  5624             rooter = CGGeneric("SequenceRooter<%s > resultRooter(cx, &result);\n" %
  5625                                result.define())
  5626         else:
  5627             rooter = None
  5628         result = CGTemplatedType("nsTArray", result)
  5629         if nullable:
  5630             result = CGTemplatedType("Nullable", result)
  5631         return result, "ref", rooter, None
  5632     if returnType.isMozMap():
  5633         nullable = returnType.nullable()
  5634         if nullable:
  5635             returnType = returnType.inner
  5636         # If our result is already addrefed, use the right type in the
  5637         # MozMap argument here.
  5638         result, _, _, _ = getRetvalDeclarationForType(returnType.inner,
  5639                                                       descriptorProvider,
  5640                                                       resultAlreadyAddRefed,
  5641                                                       isMember="MozMap")
  5642         # While we have our inner type, set up our rooter, if needed
  5643         if not isMember and typeNeedsRooting(returnType):
  5644             rooter = CGGeneric("MozMapRooter<%s> resultRooter(cx, &result);\n" %
  5645                                result.define())
  5646         else:
  5647             rooter = None
  5648         result = CGTemplatedType("MozMap", result)
  5649         if nullable:
  5650             result = CGTemplatedType("Nullable", result)
  5651         return result, "ref", rooter, None
  5652     if returnType.isDictionary():
  5653         nullable = returnType.nullable()
  5654         dictName = CGDictionary.makeDictionaryName(returnType.unroll().inner)
  5655         result = CGGeneric(dictName)
  5656         if not isMember and typeNeedsRooting(returnType):
  5657             if nullable:
  5658                 result = CGTemplatedType("NullableRootedDictionary", result)
  5659             else:
  5660                 result = CGTemplatedType("RootedDictionary", result)
  5661             resultArgs = "cx"
  5662         else:
  5663             if nullable:
  5664                 result = CGTemplatedType("Nullable", result)
  5665             resultArgs = None
  5666         return result, "ref", None, resultArgs
  5667     if returnType.isUnion():
  5668         result = CGGeneric(CGUnionStruct.unionTypeName(returnType.unroll(), True))
  5669         if not isMember and typeNeedsRooting(returnType):
  5670             if returnType.nullable():
  5671                 result = CGTemplatedType("NullableRootedUnion", result)
  5672             else:
  5673                 result = CGTemplatedType("RootedUnion", result)
  5674             resultArgs = "cx"
  5675         else:
  5676             if returnType.nullable():
  5677                 result = CGTemplatedType("Nullable", result)
  5678             resultArgs = None
  5679         return result, "ref", None, resultArgs
  5680     if returnType.isDate():
  5681         result = CGGeneric("Date")
  5682         if returnType.nullable():
  5683             result = CGTemplatedType("Nullable", result)
  5684         return result, None, None, None
  5685     raise TypeError("Don't know how to declare return value for %s" %
  5686                     returnType)
  5689 def isResultAlreadyAddRefed(extendedAttributes):
  5690     return 'resultNotAddRefed' not in extendedAttributes
  5693 def needCx(returnType, arguments, extendedAttributes, considerTypes):
  5694     return (considerTypes and
  5695             (typeNeedsCx(returnType, True) or
  5696              any(typeNeedsCx(a.type) for a in arguments)) or
  5697             'implicitJSContext' in extendedAttributes)
  5700 def needScopeObject(returnType, arguments, extendedAttributes,
  5701                     isWrapperCached, considerTypes, isMember):
  5702     """
  5703     isMember should be true if we're dealing with an attribute
  5704     annotated as [StoreInSlot].
  5705     """
  5706     return (considerTypes and not isWrapperCached and
  5707             ((not isMember and typeNeedsScopeObject(returnType, True)) or
  5708              any(typeNeedsScopeObject(a.type) for a in arguments)))
  5711 class CGCallGenerator(CGThing):
  5712     """
  5713     A class to generate an actual call to a C++ object.  Assumes that the C++
  5714     object is stored in a variable whose name is given by the |object| argument.
  5716     errorReport should be a CGThing for an error report or None if no
  5717     error reporting is needed.
  5718     """
  5719     def __init__(self, errorReport, arguments, argsPre, returnType,
  5720                  extendedAttributes, descriptorProvider, nativeMethodName,
  5721                  static, object="self", argsPost=[]):
  5722         CGThing.__init__(self)
  5724         assert errorReport is None or isinstance(errorReport, CGThing)
  5726         isFallible = errorReport is not None
  5728         resultAlreadyAddRefed = isResultAlreadyAddRefed(extendedAttributes)
  5729         result, resultOutParam, resultRooter, resultArgs = \
  5730             getRetvalDeclarationForType(
  5731                 returnType, descriptorProvider, resultAlreadyAddRefed)
  5733         args = CGList([CGGeneric(arg) for arg in argsPre], ", ")
  5734         for a, name in arguments:
  5735             arg = CGGeneric(name)
  5737             # Now constify the things that need it
  5738             def needsConst(a):
  5739                 if a.type.isDictionary():
  5740                     return True
  5741                 if a.type.isSequence():
  5742                     return True
  5743                 if a.type.isMozMap():
  5744                     return True
  5745                 # isObject() types are always a JS::Rooted, whether
  5746                 # nullable or not, and it turns out a const JS::Rooted
  5747                 # is not very helpful at all (in particular, it won't
  5748                 # even convert to a JS::Handle).
  5749                 # XXX bz Well, why not???
  5750                 if a.type.nullable() and not a.type.isObject():
  5751                     return True
  5752                 if a.type.isString():
  5753                     return True
  5754                 if a.optional and not a.defaultValue:
  5755                     # If a.defaultValue, then it's not going to use an Optional,
  5756                     # so doesn't need to be const just due to being optional.
  5757                     # This also covers variadic arguments.
  5758                     return True
  5759                 if a.type.isUnion():
  5760                     return True
  5761                 if a.type.isSpiderMonkeyInterface():
  5762                     return True
  5763                 return False
  5764             if needsConst(a):
  5765                 arg = CGWrapper(arg, pre="Constify(", post=")")
  5766             # And convert NonNull<T> to T&
  5767             if (((a.type.isGeckoInterface() or a.type.isCallback()) and not a.type.nullable()) or
  5768                 a.type.isDOMString()):
  5769                 arg = CGWrapper(arg, pre="NonNullHelper(", post=")")
  5770             args.append(arg)
  5772         # Return values that go in outparams go here
  5773         if resultOutParam is not None:
  5774             if resultOutParam is "ref":
  5775                 args.append(CGGeneric("result"))
  5776             else:
  5777                 assert resultOutParam is "ptr"
  5778                 args.append(CGGeneric("&result"))
  5780         if isFallible:
  5781             args.append(CGGeneric("rv"))
  5782         args.extend(CGGeneric(arg) for arg in argsPost)
  5784         # Build up our actual call
  5785         self.cgRoot = CGList([])
  5787         call = CGGeneric(nativeMethodName)
  5788         if not static:
  5789             call = CGWrapper(call, pre="%s->" % object)
  5790         call = CGList([call, CGWrapper(args, pre="(", post=");\n")])
  5791         if result is not None:
  5792             if resultRooter is not None:
  5793                 self.cgRoot.prepend(resultRooter)
  5794             if resultArgs is not None:
  5795                 resultArgs = "(%s)" % resultArgs
  5796             else:
  5797                 resultArgs = ""
  5798             result = CGWrapper(result, post=(" result%s;\n" % resultArgs))
  5799             self.cgRoot.prepend(result)
  5800             if not resultOutParam:
  5801                 call = CGWrapper(call, pre="result = ")
  5803         call = CGWrapper(call)
  5804         self.cgRoot.append(call)
  5806         if isFallible:
  5807             self.cgRoot.prepend(CGGeneric("ErrorResult rv;\n"))
  5808             self.cgRoot.append(CGGeneric("rv.WouldReportJSException();\n"))
  5809             self.cgRoot.append(CGGeneric("if (rv.Failed()) {\n"))
  5810             self.cgRoot.append(CGIndenter(errorReport))
  5811             self.cgRoot.append(CGGeneric("}\n"))
  5813     def define(self):
  5814         return self.cgRoot.define()
  5817 def getUnionMemberName(type):
  5818     if type.isGeckoInterface():
  5819         return type.inner.identifier.name
  5820     if type.isEnum():
  5821         return type.inner.identifier.name
  5822     if type.isArray() or type.isSequence():
  5823         return str(type)
  5824     return type.name
  5827 class MethodNotNewObjectError(Exception):
  5828     def __init__(self, typename):
  5829         self.typename = typename
  5831 # A counter for making sure that when we're wrapping up things in
  5832 # nested sequences we don't use the same variable name to iterate over
  5833 # different sequences.
  5834 sequenceWrapLevel = 0
  5837 def wrapTypeIntoCurrentCompartment(type, value, isMember=True):
  5838     """
  5839     Take the thing named by "value" and if it contains "any",
  5840     "object", or spidermonkey-interface types inside return a CGThing
  5841     that will wrap them into the current compartment.
  5842     """
  5843     if type.isAny():
  5844         assert not type.nullable()
  5845         if isMember:
  5846             value = "JS::MutableHandle<JS::Value>::fromMarkedLocation(&%s)" % value
  5847         else:
  5848             value = "&" + value
  5849         return CGGeneric("if (!JS_WrapValue(cx, %s)) {\n"
  5850                          "  return false;\n"
  5851                          "}\n" % value)
  5853     if type.isObject():
  5854         if isMember:
  5855             value = "JS::MutableHandle<JSObject*>::fromMarkedLocation(&%s)" % value
  5856         else:
  5857             value = "&" + value
  5858         return CGGeneric("if (!JS_WrapObject(cx, %s)) {\n"
  5859                          "  return false;\n"
  5860                          "}\n" % value)
  5862     if type.isSpiderMonkeyInterface():
  5863         origValue = value
  5864         if type.nullable():
  5865             value = "%s.Value()" % value
  5866         wrapCode = CGGeneric("if (!%s.WrapIntoNewCompartment(cx)) {\n"
  5867                              "  return false;\n"
  5868                              "}\n" % value)
  5869         if type.nullable():
  5870             wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % origValue)
  5871         return wrapCode
  5873     if type.isSequence():
  5874         origValue = value
  5875         origType = type
  5876         if type.nullable():
  5877             type = type.inner
  5878             value = "%s.Value()" % value
  5879         global sequenceWrapLevel
  5880         index = "indexName%d" % sequenceWrapLevel
  5881         sequenceWrapLevel += 1
  5882         wrapElement = wrapTypeIntoCurrentCompartment(type.inner,
  5883                                                      "%s[%s]" % (value, index))
  5884         sequenceWrapLevel -= 1
  5885         if not wrapElement:
  5886             return None
  5887         wrapCode = CGWrapper(CGIndenter(wrapElement),
  5888                              pre=("for (uint32_t %s = 0; %s < %s.Length(); ++%s) {\n" %
  5889                                   (index, index, value, index)),
  5890                              post="}\n")
  5891         if origType.nullable():
  5892             wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % origValue)
  5893         return wrapCode
  5895     if type.isDictionary():
  5896         assert not type.nullable()
  5897         myDict = type.inner
  5898         memberWraps = []
  5899         while myDict:
  5900             for member in myDict.members:
  5901                 memberWrap = wrapArgIntoCurrentCompartment(
  5902                     member,
  5903                     "%s.%s" % (value, CGDictionary.makeMemberName(member.identifier.name)))
  5904                 if memberWrap:
  5905                     memberWraps.append(memberWrap)
  5906             myDict = myDict.parent
  5907         return CGList(memberWraps) if len(memberWraps) != 0 else None
  5909     if type.isUnion():
  5910         memberWraps = []
  5911         if type.nullable():
  5912             type = type.inner
  5913             value = "%s.Value()" % value
  5914         for member in type.flatMemberTypes:
  5915             memberName = getUnionMemberName(member)
  5916             memberWrap = wrapTypeIntoCurrentCompartment(
  5917                 member, "%s.GetAs%s()" % (value, memberName))
  5918             if memberWrap:
  5919                 memberWrap = CGIfWrapper(
  5920                     memberWrap, "%s.Is%s()" % (value, memberName))
  5921                 memberWraps.append(memberWrap)
  5922         return CGList(memberWraps, "else ") if len(memberWraps) != 0 else None
  5924     if (type.isString() or type.isPrimitive() or type.isEnum() or
  5925         type.isGeckoInterface() or type.isCallback() or type.isDate()):
  5926         # All of these don't need wrapping
  5927         return None
  5929     raise TypeError("Unknown type; we don't know how to wrap it in constructor "
  5930                     "arguments: %s" % type)
  5933 def wrapArgIntoCurrentCompartment(arg, value, isMember=True):
  5934     """
  5935     As wrapTypeIntoCurrentCompartment but handles things being optional
  5936     """
  5937     origValue = value
  5938     isOptional = arg.optional and not arg.defaultValue
  5939     if isOptional:
  5940         value = value + ".Value()"
  5941     wrap = wrapTypeIntoCurrentCompartment(arg.type, value, isMember)
  5942     if wrap and isOptional:
  5943         wrap = CGIfWrapper(wrap, "%s.WasPassed()" % origValue)
  5944     return wrap
  5947 class CGPerSignatureCall(CGThing):
  5948     """
  5949     This class handles the guts of generating code for a particular
  5950     call signature.  A call signature consists of four things:
  5952     1) A return type, which can be None to indicate that there is no
  5953        actual return value (e.g. this is an attribute setter) or an
  5954        IDLType if there's an IDL type involved (including |void|).
  5955     2) An argument list, which is allowed to be empty.
  5956     3) A name of a native method to call.
  5957     4) Whether or not this method is static.
  5959     We also need to know whether this is a method or a getter/setter
  5960     to do error reporting correctly.
  5962     The idlNode parameter can be either a method or an attr. We can query
  5963     |idlNode.identifier| in both cases, so we can be agnostic between the two.
  5964     """
  5965     # XXXbz For now each entry in the argument list is either an
  5966     # IDLArgument or a FakeArgument, but longer-term we may want to
  5967     # have ways of flagging things like JSContext* or optional_argc in
  5968     # there.
  5970     def __init__(self, returnType, arguments, nativeMethodName, static,
  5971                  descriptor, idlNode, argConversionStartsAt=0, getter=False,
  5972                  setter=False, isConstructor=False):
  5973         assert idlNode.isMethod() == (not getter and not setter)
  5974         assert idlNode.isAttr() == (getter or setter)
  5975         # Constructors are always static
  5976         assert not isConstructor or static
  5978         CGThing.__init__(self)
  5979         self.returnType = returnType
  5980         self.descriptor = descriptor
  5981         self.idlNode = idlNode
  5982         self.extendedAttributes = descriptor.getExtendedAttributes(idlNode,
  5983                                                                    getter=getter,
  5984                                                                    setter=setter)
  5985         self.arguments = arguments
  5986         self.argCount = len(arguments)
  5987         cgThings = []
  5988         lenientFloatCode = None
  5989         if idlNode.getExtendedAttribute('LenientFloat') is not None:
  5990             if setter:
  5991                 lenientFloatCode = "return true;\n"
  5992             elif idlNode.isMethod():
  5993                 lenientFloatCode = ("args.rval().setUndefined();\n"
  5994                                     "return true;\n")
  5996         argsPre = []
  5997         if static:
  5998             nativeMethodName = "%s::%s" % (descriptor.nativeType,
  5999                                            nativeMethodName)
  6000             # If we're a constructor, "obj" may not be a function, so calling
  6001             # XrayAwareCalleeGlobal() on it is not safe.  Of course in the
  6002             # constructor case either "obj" is an Xray or we're already in the
  6003             # content compartment, not the Xray compartment, so just
  6004             # constructing the GlobalObject from "obj" is fine.
  6005             if isConstructor:
  6006                 objForGlobalObject = "obj"
  6007             else:
  6008                 objForGlobalObject = "xpc::XrayAwareCalleeGlobal(obj)"
  6009             cgThings.append(CGGeneric(fill(
  6010                 """
  6011                 GlobalObject global(cx, ${obj});
  6012                 if (global.Failed()) {
  6013                   return false;
  6016                 """,
  6017                 obj=objForGlobalObject)))
  6018             argsPre.append("global")
  6020         # For JS-implemented interfaces we do not want to base the
  6021         # needsCx decision on the types involved, just on our extended
  6022         # attributes.
  6023         needsCx = needCx(returnType, arguments, self.extendedAttributes,
  6024                          not descriptor.interface.isJSImplemented())
  6025         if needsCx and not (static and descriptor.workers):
  6026             argsPre.append("cx")
  6028         needsUnwrap = False
  6029         argsPost = []
  6030         if isConstructor:
  6031             needsUnwrap = True
  6032             needsUnwrappedVar = False
  6033             unwrappedVar = "obj"
  6034         elif descriptor.interface.isJSImplemented():
  6035             needsUnwrap = True
  6036             needsUnwrappedVar = True
  6037             argsPost.append("js::GetObjectCompartment(unwrappedObj.empty() ? obj : unwrappedObj.ref())")
  6038         elif needScopeObject(returnType, arguments, self.extendedAttributes,
  6039                              descriptor.wrapperCache, True,
  6040                              idlNode.getExtendedAttribute("StoreInSlot")):
  6041             needsUnwrap = True
  6042             needsUnwrappedVar = True
  6043             argsPre.append("unwrappedObj.empty() ? obj : unwrappedObj.ref()")
  6045         if needsUnwrap and needsUnwrappedVar:
  6046             # We cannot assign into obj because it's a Handle, not a
  6047             # MutableHandle, so we need a separate Rooted.
  6048             cgThings.append(CGGeneric("Maybe<JS::Rooted<JSObject*> > unwrappedObj;\n"))
  6049             unwrappedVar = "unwrappedObj.ref()"
  6051         if idlNode.isMethod() and idlNode.isLegacycaller():
  6052             # If we can have legacycaller with identifier, we can't
  6053             # just use the idlNode to determine whether we're
  6054             # generating code for the legacycaller or not.
  6055             assert idlNode.isIdentifierLess()
  6056             # Pass in our thisVal
  6057             argsPre.append("args.thisv()")
  6059         ourName = "%s.%s" % (descriptor.interface.identifier.name,
  6060                              idlNode.identifier.name)
  6061         if idlNode.isMethod():
  6062             argDescription = "argument %(index)d of " + ourName
  6063         elif setter:
  6064             argDescription = "value being assigned to %s" % ourName
  6065         else:
  6066             assert self.argCount == 0
  6068         if needsUnwrap:
  6069             # It's very important that we construct our unwrappedObj, if we need
  6070             # to do it, before we might start setting up Rooted things for our
  6071             # arguments, so that we don't violate the stack discipline Rooted
  6072             # depends on.
  6073             cgThings.append(CGGeneric(
  6074                 "bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);\n"))
  6075             if needsUnwrappedVar:
  6076                 cgThings.append(CGIfWrapper(
  6077                     CGGeneric("unwrappedObj.construct(cx, obj);\n"),
  6078                     "objIsXray"))
  6080         for i in range(argConversionStartsAt, self.argCount):
  6081             cgThings.append(
  6082                 CGArgumentConverter(arguments[i], i, self.descriptor,
  6083                                     argDescription % {"index": i + 1},
  6084                                     invalidEnumValueFatal=not setter,
  6085                                     lenientFloatCode=lenientFloatCode))
  6087         if needsUnwrap:
  6088             # Something depends on having the unwrapped object, so unwrap it now.
  6089             xraySteps = []
  6090             # XXXkhuey we should be able to MOZ_ASSERT that ${obj} is
  6091             # not null.
  6092             xraySteps.append(
  6093                 CGGeneric(string.Template(dedent("""
  6094                     ${obj} = js::CheckedUnwrap(${obj});
  6095                     if (!${obj}) {
  6096                       return false;
  6098                     """)).substitute({'obj': unwrappedVar})))
  6099             if isConstructor:
  6100                 # If we're called via an xray, we need to enter the underlying
  6101                 # object's compartment and then wrap up all of our arguments into
  6102                 # that compartment as needed.  This is all happening after we've
  6103                 # already done the conversions from JS values to WebIDL (C++)
  6104                 # values, so we only need to worry about cases where there are 'any'
  6105                 # or 'object' types, or other things that we represent as actual
  6106                 # JSAPI types, present.  Effectively, we're emulating a
  6107                 # CrossCompartmentWrapper, but working with the C++ types, not the
  6108                 # original list of JS::Values.
  6109                 cgThings.append(CGGeneric("Maybe<JSAutoCompartment> ac;\n"))
  6110                 xraySteps.append(CGGeneric("ac.construct(cx, obj);\n"))
  6111                 xraySteps.extend(
  6112                     wrapArgIntoCurrentCompartment(arg, argname, isMember=False)
  6113                     for arg, argname in self.getArguments())
  6115             cgThings.append(
  6116                 CGIfWrapper(CGList(xraySteps),
  6117                             "objIsXray"))
  6119         cgThings.append(CGCallGenerator(
  6120             self.getErrorReport() if self.isFallible() else None,
  6121             self.getArguments(), argsPre, returnType,
  6122             self.extendedAttributes, descriptor, nativeMethodName,
  6123             static, argsPost=argsPost))
  6124         self.cgRoot = CGList(cgThings)
  6126     def getArguments(self):
  6127         return [(a, "arg" + str(i)) for i, a in enumerate(self.arguments)]
  6129     def isFallible(self):
  6130         return 'infallible' not in self.extendedAttributes
  6132     def wrap_return_value(self):
  6133         returnsNewObject = memberReturnsNewObject(self.idlNode)
  6134         if returnsNewObject:
  6135             # We better be returning addrefed things!
  6136             assert(isResultAlreadyAddRefed(self.extendedAttributes) or
  6137                    # NewObject can return raw pointers to owned objects
  6138                    (self.returnType.isGeckoInterface() and
  6139                     self.descriptor.getDescriptor(self.returnType.unroll().inner.identifier.name).nativeOwnership == 'owned'))
  6141         setSlot = self.idlNode.isAttr() and self.idlNode.slotIndex is not None
  6142         if setSlot:
  6143             # For attributes in slots, we want to do some
  6144             # post-processing once we've wrapped them.
  6145             successCode = "break;\n"
  6146         else:
  6147             successCode = None
  6149         resultTemplateValues = {
  6150             'jsvalRef': 'args.rval()',
  6151             'jsvalHandle': 'args.rval()',
  6152             'returnsNewObject': returnsNewObject,
  6153             'successCode': successCode,
  6154             'obj': "reflector" if setSlot else "obj"
  6156         try:
  6157             wrapCode = wrapForType(self.returnType, self.descriptor, resultTemplateValues)
  6158         except MethodNotNewObjectError, err:
  6159             assert not returnsNewObject
  6160             raise TypeError("%s being returned from non-NewObject method or property %s.%s" %
  6161                             (err.typename,
  6162                              self.descriptor.interface.identifier.name,
  6163                              self.idlNode.identifier.name))
  6164         if setSlot:
  6165             # We need to make sure that our initial wrapping is done in the
  6166             # reflector compartment, but that we finally set args.rval() in the
  6167             # caller compartment.  We also need to make sure that the actual
  6168             # wrapping steps happen inside a do/while that they can break out
  6169             # of.
  6171             # postSteps are the steps that run while we're still in the
  6172             # reflector compartment but after we've finished the initial
  6173             # wrapping into args.rval().
  6174             postSteps = ""
  6175             if self.idlNode.getExtendedAttribute("Frozen"):
  6176                 assert self.idlNode.type.isSequence() or self.idlNode.type.isDictionary()
  6177                 freezeValue = CGGeneric(
  6178                     "JS::Rooted<JSObject*> rvalObj(cx, &args.rval().toObject());\n"
  6179                     "if (!JS_FreezeObject(cx, rvalObj)) {\n"
  6180                     "  return false;\n"
  6181                     "}\n")
  6182                 if self.idlNode.type.nullable():
  6183                     freezeValue = CGIfWrapper(freezeValue,
  6184                                               "args.rval().isObject()")
  6185                 postSteps += freezeValue.define()
  6186             postSteps += ("js::SetReservedSlot(reflector, %s, args.rval());\n" %
  6187                           memberReservedSlot(self.idlNode))
  6188             # For the case of Cached attributes, go ahead and preserve our
  6189             # wrapper if needed.  We need to do this because otherwise the
  6190             # wrapper could get garbage-collected and the cached value would
  6191             # suddenly disappear, but the whole premise of cached values is that
  6192             # they never change without explicit action on someone's part.  We
  6193             # don't do this for StoreInSlot, since those get dealt with during
  6194             # wrapper setup, and failure would involve us trying to clear an
  6195             # already-preserved wrapper.
  6196             if (self.idlNode.getExtendedAttribute("Cached") and
  6197                 self.descriptor.wrapperCache):
  6198                 postSteps += "PreserveWrapper(self);\n"
  6200             wrapCode = fill(
  6201                 """
  6202                 { // Make sure we wrap and store in the slot in reflector's compartment
  6203                   JSAutoCompartment ac(cx, reflector);
  6204                   do { // block we break out of when done wrapping
  6205                     $*{wrapCode}
  6206                   } while (0);
  6207                   $*{postSteps}
  6209                 // And now make sure args.rval() is in the caller compartment
  6210                 return ${maybeWrap}(cx, args.rval());
  6211                 """,
  6212                 wrapCode=wrapCode,
  6213                 postSteps=postSteps,
  6214                 maybeWrap=getMaybeWrapValueFuncForType(self.idlNode.type))
  6215         return wrapCode
  6217     def getErrorReport(self):
  6218         jsImplemented = ""
  6219         if self.descriptor.interface.isJSImplemented():
  6220             jsImplemented = ", true"
  6221         return CGGeneric('return ThrowMethodFailedWithDetails(cx, rv, "%s", "%s"%s);\n'
  6222                          % (self.descriptor.interface.identifier.name,
  6223                             self.idlNode.identifier.name,
  6224                             jsImplemented))
  6226     def define(self):
  6227         return (self.cgRoot.define() + self.wrap_return_value())
  6230 class CGSwitch(CGList):
  6231     """
  6232     A class to generate code for a switch statement.
  6234     Takes three constructor arguments: an expression, a list of cases,
  6235     and an optional default.
  6237     Each case is a CGCase.  The default is a CGThing for the body of
  6238     the default case, if any.
  6239     """
  6240     def __init__(self, expression, cases, default=None):
  6241         CGList.__init__(self, [CGIndenter(c) for c in cases])
  6242         self.prepend(CGGeneric("switch (" + expression + ") {\n"))
  6243         if default is not None:
  6244             self.append(
  6245                 CGIndenter(
  6246                     CGWrapper(
  6247                         CGIndenter(default),
  6248                         pre="default: {\n",
  6249                         post="  break;\n}\n")))
  6251         self.append(CGGeneric("}\n"))
  6254 class CGCase(CGList):
  6255     """
  6256     A class to generate code for a case statement.
  6258     Takes three constructor arguments: an expression, a CGThing for
  6259     the body (allowed to be None if there is no body), and an optional
  6260     argument (defaulting to False) for whether to fall through.
  6261     """
  6262     def __init__(self, expression, body, fallThrough=False):
  6263         CGList.__init__(self, [])
  6264         self.append(CGGeneric("case " + expression + ": {\n"))
  6265         bodyList = CGList([body])
  6266         if fallThrough:
  6267             bodyList.append(CGGeneric("/* Fall through */\n"))
  6268         else:
  6269             bodyList.append(CGGeneric("break;\n"))
  6270         self.append(CGIndenter(bodyList))
  6271         self.append(CGGeneric("}\n"))
  6274 class CGMethodCall(CGThing):
  6275     """
  6276     A class to generate selection of a method signature from a set of
  6277     signatures and generation of a call to that signature.
  6278     """
  6279     def __init__(self, nativeMethodName, static, descriptor, method,
  6280                  isConstructor=False, constructorName=None):
  6281         CGThing.__init__(self)
  6283         if isConstructor:
  6284             assert constructorName is not None
  6285             methodName = constructorName
  6286         else:
  6287             methodName = "%s.%s" % (descriptor.interface.identifier.name, method.identifier.name)
  6288         argDesc = "argument %d of " + methodName
  6290         def requiredArgCount(signature):
  6291             arguments = signature[1]
  6292             if len(arguments) == 0:
  6293                 return 0
  6294             requiredArgs = len(arguments)
  6295             while requiredArgs and arguments[requiredArgs-1].optional:
  6296                 requiredArgs -= 1
  6297             return requiredArgs
  6299         def getPerSignatureCall(signature, argConversionStartsAt=0):
  6300             return CGPerSignatureCall(signature[0], signature[1],
  6301                                       nativeMethodName, static, descriptor,
  6302                                       method,
  6303                                       argConversionStartsAt=argConversionStartsAt,
  6304                                       isConstructor=isConstructor)
  6306         signatures = method.signatures()
  6307         if len(signatures) == 1:
  6308             # Special case: we can just do a per-signature method call
  6309             # here for our one signature and not worry about switching
  6310             # on anything.
  6311             signature = signatures[0]
  6312             self.cgRoot = CGList([CGIndenter(getPerSignatureCall(signature))])
  6313             requiredArgs = requiredArgCount(signature)
  6315             if requiredArgs > 0:
  6316                 code = indent(fill(  # BOGUS extra blank line
  6317                     """
  6319                     if (args.length() < ${requiredArgs}) {
  6320                       return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "${methodName}");
  6322                     """,
  6323                     requiredArgs=requiredArgs,
  6324                     methodName=methodName))
  6325                 self.cgRoot.prepend(CGGeneric(code))
  6326             return
  6328         # Need to find the right overload
  6329         maxArgCount = method.maxArgCount
  6330         allowedArgCounts = method.allowedArgCounts
  6332         argCountCases = []
  6333         for argCountIdx, argCount in enumerate(allowedArgCounts):
  6334             possibleSignatures = method.signaturesForArgCount(argCount)
  6336             # Try to optimize away cases when the next argCount in the list
  6337             # will have the same code as us; if it does, we can fall through to
  6338             # that case.
  6339             if argCountIdx+1 < len(allowedArgCounts):
  6340                 nextPossibleSignatures = \
  6341                     method.signaturesForArgCount(allowedArgCounts[argCountIdx+1])
  6342             else:
  6343                 nextPossibleSignatures = None
  6344             if possibleSignatures == nextPossibleSignatures:
  6345                 # Same set of signatures means we better have the same
  6346                 # distinguishing index.  So we can in fact just fall through to
  6347                 # the next case here.
  6348                 assert (len(possibleSignatures) == 1 or
  6349                         (method.distinguishingIndexForArgCount(argCount) ==
  6350                          method.distinguishingIndexForArgCount(allowedArgCounts[argCountIdx+1])))
  6351                 argCountCases.append(CGCase(str(argCount), None, True))
  6352                 continue
  6354             if len(possibleSignatures) == 1:
  6355                 # easy case!
  6356                 signature = possibleSignatures[0]
  6357                 argCountCases.append(
  6358                     CGCase(str(argCount), getPerSignatureCall(signature)))
  6359                 continue
  6361             distinguishingIndex = method.distinguishingIndexForArgCount(argCount)
  6363             def distinguishingArgument(signature):
  6364                 args = signature[1]
  6365                 if distinguishingIndex < len(args):
  6366                     return args[distinguishingIndex]
  6367                 assert args[-1].variadic
  6368                 return args[-1]
  6370             def distinguishingType(signature):
  6371                 return distinguishingArgument(signature).type
  6373             for sig in possibleSignatures:
  6374                 # We should not have "any" args at distinguishingIndex,
  6375                 # since we have multiple possible signatures remaining,
  6376                 # but "any" is never distinguishable from anything else.
  6377                 assert not distinguishingType(sig).isAny()
  6378                 # We can't handle unions at the distinguishing index.
  6379                 if distinguishingType(sig).isUnion():
  6380                     raise TypeError("No support for unions as distinguishing "
  6381                                     "arguments yet: %s" %
  6382                                     distinguishingArgument(sig).location)
  6383                 # We don't support variadics as the distinguishingArgument yet.
  6384                 # If you want to add support, consider this case:
  6386                 #   void(long... foo);
  6387                 #   void(long bar, Int32Array baz);
  6389                 # in which we have to convert argument 0 to long before picking
  6390                 # an overload... but all the variadic stuff needs to go into a
  6391                 # single array in case we pick that overload, so we have to have
  6392                 # machinery for converting argument 0 to long and then either
  6393                 # placing it in the variadic bit or not.  Or something.  We may
  6394                 # be able to loosen this restriction if the variadic arg is in
  6395                 # fact at distinguishingIndex, perhaps.  Would need to
  6396                 # double-check.
  6397                 if distinguishingArgument(sig).variadic:
  6398                     raise TypeError("No support for variadics as distinguishing "
  6399                                     "arguments yet: %s" %
  6400                                     distinguishingArgument(sig).location)
  6402             # Convert all our arguments up to the distinguishing index.
  6403             # Doesn't matter which of the possible signatures we use, since
  6404             # they all have the same types up to that point; just use
  6405             # possibleSignatures[0]
  6406             caseBody = [CGArgumentConverter(possibleSignatures[0][1][i],
  6407                                             i, descriptor,
  6408                                             argDesc % (i + 1))
  6409                         for i in range(0, distinguishingIndex)]
  6411             # Select the right overload from our set.
  6412             distinguishingArg = "args[%d]" % distinguishingIndex
  6414             def tryCall(signature, indent, isDefinitelyObject=False,
  6415                         isNullOrUndefined=False):
  6416                 assert not isDefinitelyObject or not isNullOrUndefined
  6417                 assert isDefinitelyObject or isNullOrUndefined
  6418                 if isDefinitelyObject:
  6419                     failureCode = "break;\n"
  6420                 else:
  6421                     failureCode = None
  6422                 type = distinguishingType(signature)
  6423                 # The argument at index distinguishingIndex can't possibly be
  6424                 # unset here, because we've already checked that argc is large
  6425                 # enough that we can examine this argument.  But note that we
  6426                 # still want to claim that optional arguments are optional, in
  6427                 # case undefined was passed in.
  6428                 argIsOptional = (distinguishingArgument(signature).optional and
  6429                                  not distinguishingArgument(signature).defaultValue)
  6430                 testCode = instantiateJSToNativeConversion(
  6431                     getJSToNativeConversionInfo(type, descriptor,
  6432                                                 failureCode=failureCode,
  6433                                                 isDefinitelyObject=isDefinitelyObject,
  6434                                                 isNullOrUndefined=isNullOrUndefined,
  6435                                                 isOptional=argIsOptional,
  6436                                                 sourceDescription=(argDesc % (distinguishingIndex + 1))),
  6438                         "declName": "arg%d" % distinguishingIndex,
  6439                         "holderName": ("arg%d" % distinguishingIndex) + "_holder",
  6440                         "val": distinguishingArg,
  6441                         "mutableVal": distinguishingArg,
  6442                         "obj": "obj",
  6443                         "haveValue": "args.hasDefined(%d)" % distinguishingIndex
  6444                     },
  6445                     checkForValue=argIsOptional)
  6446                 caseBody.append(CGIndenter(testCode, indent))
  6448                 # If we got this far, we know we unwrapped to the right
  6449                 # C++ type, so just do the call.  Start conversion with
  6450                 # distinguishingIndex + 1, since we already converted
  6451                 # distinguishingIndex.
  6452                 caseBody.append(CGIndenter(
  6453                     getPerSignatureCall(signature, distinguishingIndex + 1),
  6454                     indent))
  6456             def hasConditionalConversion(type):
  6457                 """
  6458                 Return whether the argument conversion for this type will be
  6459                 conditional on the type of incoming JS value.  For example, for
  6460                 interface types the conversion is conditional on the incoming
  6461                 value being isObject().
  6463                 For the types for which this returns false, we do not have to
  6464                 output extra isUndefined() or isNullOrUndefined() cases, because
  6465                 null/undefined values will just fall through into our
  6466                 unconditional conversion.
  6467                 """
  6468                 if type.isString() or type.isEnum():
  6469                     return False
  6470                 if type.isBoolean():
  6471                     distinguishingTypes = (distinguishingType(s) for s in
  6472                                            possibleSignatures)
  6473                     return any(t.isString() or t.isEnum() or t.isNumeric()
  6474                                for t in distinguishingTypes)
  6475                 if type.isNumeric():
  6476                     distinguishingTypes = (distinguishingType(s) for s in
  6477                                            possibleSignatures)
  6478                     return any(t.isString() or t.isEnum()
  6479                                for t in distinguishingTypes)
  6480                 return True
  6482             def needsNullOrUndefinedCase(type):
  6483                 """
  6484                 Return true if the type needs a special isNullOrUndefined() case
  6485                 """
  6486                 return ((type.nullable() and
  6487                         hasConditionalConversion(type)) or
  6488                         type.isDictionary())
  6490             # First check for undefined and optional distinguishing arguments
  6491             # and output a special branch for that case.  Note that we don't
  6492             # use distinguishingArgument here because we actualy want to
  6493             # exclude variadic arguments.  Also note that we skip this check if
  6494             # we plan to output a isNullOrUndefined() special case for this
  6495             # argument anyway, since that will subsume our isUndefined() check.
  6496             # This is safe, because there can be at most one nullable
  6497             # distinguishing argument, so if we're it we'll definitely get
  6498             # picked up by the nullable handling.  Also, we can skip this check
  6499             # if the argument has an unconditional conversion later on.
  6500             undefSigs = [s for s in possibleSignatures if
  6501                          distinguishingIndex < len(s[1]) and
  6502                          s[1][distinguishingIndex].optional and
  6503                          hasConditionalConversion(s[1][distinguishingIndex].type) and
  6504                          not needsNullOrUndefinedCase(s[1][distinguishingIndex].type)]
  6505             # Can't have multiple signatures with an optional argument at the
  6506             # same index.
  6507             assert len(undefSigs) < 2
  6508             if len(undefSigs) > 0:
  6509                 caseBody.append(CGGeneric("if (%s.isUndefined()) {\n" %
  6510                                           distinguishingArg))
  6511                 tryCall(undefSigs[0], 2, isNullOrUndefined=True)
  6512                 caseBody.append(CGGeneric("}\n"))
  6514             # Next, check for null or undefined.  That means looking for
  6515             # nullable arguments at the distinguishing index and outputting a
  6516             # separate branch for them.  But if the nullable argument has an
  6517             # unconditional conversion, we don't need to do that.  The reason
  6518             # for that is that at most one argument at the distinguishing index
  6519             # is nullable (since two nullable arguments are not
  6520             # distinguishable), and null/undefined values will always fall
  6521             # through to the unconditional conversion we have, if any, since
  6522             # they will fail whatever the conditions on the input value are for
  6523             # our other conversions.
  6524             nullOrUndefSigs = [s for s in possibleSignatures
  6525                                if needsNullOrUndefinedCase(distinguishingType(s))]
  6526             # Can't have multiple nullable types here
  6527             assert len(nullOrUndefSigs) < 2
  6528             if len(nullOrUndefSigs) > 0:
  6529                 caseBody.append(CGGeneric("if (%s.isNullOrUndefined()) {\n" %
  6530                                           distinguishingArg))
  6531                 tryCall(nullOrUndefSigs[0], 2, isNullOrUndefined=True)
  6532                 caseBody.append(CGGeneric("}\n"))
  6534             # Now check for distinguishingArg being various kinds of objects.
  6535             # The spec says to check for the following things in order:
  6536             # 1)  A platform object that's not a platform array object, being
  6537             #     passed to an interface or "object" arg.
  6538             # 2)  A Date object being passed to a Date or "object" arg.
  6539             # 3)  A RegExp object being passed to a RegExp or "object" arg.
  6540             # 4)  A callable object being passed to a callback or "object" arg.
  6541             # 5)  Any non-Date and non-RegExp object being passed to a
  6542             #     array or sequence or callback interface dictionary or
  6543             #     "object" arg.
  6545             # We can can coalesce these five cases together, as long as we make
  6546             # sure to check whether our object works as an interface argument
  6547             # before checking whether it works as an arraylike or dictionary or
  6548             # callback function or callback interface.
  6550             # First grab all the overloads that have a non-callback interface
  6551             # (which includes typed arrays and arraybuffers) at the
  6552             # distinguishing index.  We can also include the ones that have an
  6553             # "object" here, since if those are present no other object-typed
  6554             # argument will be.
  6555             objectSigs = [
  6556                 s for s in possibleSignatures
  6557                 if (distinguishingType(s).isObject() or
  6558                     distinguishingType(s).isNonCallbackInterface())]
  6560             # And all the overloads that take Date
  6561             objectSigs.extend(s for s in possibleSignatures
  6562                               if distinguishingType(s).isDate())
  6564             # And all the overloads that take callbacks
  6565             objectSigs.extend(s for s in possibleSignatures
  6566                               if distinguishingType(s).isCallback())
  6568             # Now append all the overloads that take an array or sequence or
  6569             # dictionary or callback interface:
  6570             objectSigs.extend(s for s in possibleSignatures
  6571                               if (distinguishingType(s).isArray() or
  6572                                   distinguishingType(s).isSequence() or
  6573                                   distinguishingType(s).isDictionary() or
  6574                                   distinguishingType(s).isCallbackInterface()))
  6576             # There might be more than one thing in objectSigs; we need to check
  6577             # which ones we unwrap to.
  6578             if len(objectSigs) > 0:
  6579                 # Here it's enough to guard on our argument being an object. The
  6580                 # code for unwrapping non-callback interfaces, typed arrays,
  6581                 # sequences, arrays, and Dates will just bail out and move on to
  6582                 # the next overload if the object fails to unwrap correctly,
  6583                 # while "object" accepts any object anyway.  We could even not
  6584                 # do the isObject() check up front here, but in cases where we
  6585                 # have multiple object overloads it makes sense to do it only
  6586                 # once instead of for each overload.  That will also allow the
  6587                 # unwrapping test to skip having to do codegen for the
  6588                 # null-or-undefined case, which we already handled above.
  6589                 caseBody.append(CGGeneric("if (%s.isObject()) {\n" %
  6590                                           distinguishingArg))
  6591                 for sig in objectSigs:
  6592                     caseBody.append(CGIndenter(CGGeneric("do {\n")))
  6593                     # Indent by 4, since we need to indent further
  6594                     # than our "do" statement
  6595                     tryCall(sig, 4, isDefinitelyObject=True)
  6596                     caseBody.append(CGIndenter(CGGeneric("} while (0);\n")))
  6598                 caseBody.append(CGGeneric("}\n"))
  6600             # Now we only have to consider booleans, numerics, and strings.  If
  6601             # we only have one of them, then we can just output it.  But if not,
  6602             # then we need to output some of the cases conditionally: if we have
  6603             # a string overload, then boolean and numeric are conditional, and
  6604             # if not then boolean is conditional if we have a numeric overload.
  6605             def findUniqueSignature(filterLambda):
  6606                 sigs = filter(filterLambda, possibleSignatures)
  6607                 assert len(sigs) < 2
  6608                 if len(sigs) > 0:
  6609                     return sigs[0]
  6610                 return None
  6612             stringSignature = findUniqueSignature(
  6613                 lambda s: (distinguishingType(s).isString() or
  6614                            distinguishingType(s).isEnum()))
  6615             numericSignature = findUniqueSignature(
  6616                 lambda s: distinguishingType(s).isNumeric())
  6617             booleanSignature = findUniqueSignature(
  6618                 lambda s: distinguishingType(s).isBoolean())
  6620             if stringSignature or numericSignature:
  6621                 booleanCondition = "%s.isBoolean()"
  6622             else:
  6623                 booleanCondition = None
  6625             if stringSignature:
  6626                 numericCondition = "%s.isNumber()"
  6627             else:
  6628                 numericCondition = None
  6630             def addCase(sig, condition):
  6631                 sigCode = getPerSignatureCall(sig, distinguishingIndex)
  6632                 if condition:
  6633                     sigCode = CGIfWrapper(sigCode,
  6634                                           condition % distinguishingArg)
  6635                 caseBody.append(sigCode)
  6637             if booleanSignature:
  6638                 addCase(booleanSignature, booleanCondition)
  6639             if numericSignature:
  6640                 addCase(numericSignature, numericCondition)
  6641             if stringSignature:
  6642                 addCase(stringSignature, None)
  6644             if (not booleanSignature and not numericSignature and
  6645                 not stringSignature):
  6646                 # Just throw; we have no idea what we're supposed to
  6647                 # do with this.
  6648                 caseBody.append(CGGeneric(
  6649                     'return ThrowErrorMessage(cx, MSG_OVERLOAD_RESOLUTION_FAILED, "%d", "%d", "%s");\n' %
  6650                     (distinguishingIndex + 1, argCount, methodName)))
  6652             argCountCases.append(CGCase(str(argCount), CGList(caseBody)))
  6654         overloadCGThings = []
  6655         overloadCGThings.append(
  6656             CGGeneric("unsigned argcount = std::min(args.length(), %du);\n" %
  6657                       maxArgCount))
  6658         overloadCGThings.append(
  6659             CGSwitch("argcount",
  6660                      argCountCases,
  6661                      # BOGUS extra blank line at end of default block
  6662                      CGGeneric('return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "%s");\n\n' %
  6663                                methodName)))
  6664         overloadCGThings.append(
  6665             CGGeneric('MOZ_CRASH("We have an always-returning default case");\n'
  6666                       'return false;\n'))
  6667         self.cgRoot = CGWrapper(CGIndenter(CGList(overloadCGThings)),
  6668                                 pre="\n")
  6670     def define(self):
  6671         return self.cgRoot.define()
  6674 class CGGetterCall(CGPerSignatureCall):
  6675     """
  6676     A class to generate a native object getter call for a particular IDL
  6677     getter.
  6678     """
  6679     def __init__(self, returnType, nativeMethodName, descriptor, attr):
  6680         CGPerSignatureCall.__init__(self, returnType, [], nativeMethodName,
  6681                                     attr.isStatic(), descriptor, attr,
  6682                                     getter=True)
  6685 class FakeArgument():
  6686     """
  6687     A class that quacks like an IDLArgument.  This is used to make
  6688     setters look like method calls or for special operations.
  6689     """
  6690     def __init__(self, type, interfaceMember, name="arg", allowTreatNonCallableAsNull=False):
  6691         self.type = type
  6692         self.optional = False
  6693         self.variadic = False
  6694         self.defaultValue = None
  6695         self._allowTreatNonCallableAsNull = allowTreatNonCallableAsNull
  6696         self.treatNullAs = interfaceMember.treatNullAs
  6697         if isinstance(interfaceMember, IDLAttribute):
  6698             self.enforceRange = interfaceMember.enforceRange
  6699             self.clamp = interfaceMember.clamp
  6700         else:
  6701             self.enforceRange = False
  6702             self.clamp = False
  6704         class FakeIdentifier():
  6705             def __init__(self):
  6706                 self.name = name
  6707         self.identifier = FakeIdentifier()
  6709     def allowTreatNonCallableAsNull(self):
  6710         return self._allowTreatNonCallableAsNull
  6713 class CGSetterCall(CGPerSignatureCall):
  6714     """
  6715     A class to generate a native object setter call for a particular IDL
  6716     setter.
  6717     """
  6718     def __init__(self, argType, nativeMethodName, descriptor, attr):
  6719         CGPerSignatureCall.__init__(self, None, [FakeArgument(argType, attr, allowTreatNonCallableAsNull=True)],
  6720                                     nativeMethodName, attr.isStatic(),
  6721                                     descriptor, attr, setter=True)
  6723     def wrap_return_value(self):
  6724         attr = self.idlNode
  6725         if self.descriptor.wrapperCache and attr.slotIndex is not None:
  6726             if attr.getExtendedAttribute("StoreInSlot"):
  6727                 args = "cx, self"
  6728             else:
  6729                 args = "self"
  6730             clearSlot = ("ClearCached%sValue(%s);\n" %
  6731                          (MakeNativeName(self.idlNode.identifier.name), args))
  6732         else:
  6733             clearSlot = ""
  6735         # We have no return value
  6736         return ("\n"
  6737                 "%s"
  6738                 "return true;\n" % clearSlot)
  6741 class CGAbstractBindingMethod(CGAbstractStaticMethod):
  6742     """
  6743     Common class to generate the JSNatives for all our methods, getters, and
  6744     setters.  This will generate the function declaration and unwrap the
  6745     |this| object.  Subclasses are expected to override the generate_code
  6746     function to do the rest of the work.  This function should return a
  6747     CGThing which is already properly indented.
  6749     getThisObj should be code for getting a JSObject* for the binding
  6750     object.  If this is None, we will auto-generate code based on
  6751     descriptor to do the right thing.  "" can be passed in if the
  6752     binding object is already stored in 'obj'.
  6754     callArgs should be code for getting a JS::CallArgs into a variable
  6755     called 'args'.  This can be "" if there is already such a variable
  6756     around.
  6758     If allowCrossOriginThis is true, then this-unwrapping will first do an
  6759     UncheckedUnwrap and after that operate on the result.
  6760     """
  6761     def __init__(self, descriptor, name, args, unwrapFailureCode=None,
  6762                  getThisObj=None,
  6763                  callArgs="JS::CallArgs args = JS::CallArgsFromVp(argc, vp);\n",
  6764                  allowCrossOriginThis=False):
  6765         CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args)
  6767         if unwrapFailureCode is None:
  6768             self.unwrapFailureCode = 'return ThrowErrorMessage(cx, MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE, "Value", "%s");\n' % descriptor.interface.identifier.name
  6769         else:
  6770             self.unwrapFailureCode = unwrapFailureCode
  6772         if getThisObj == "":
  6773             self.getThisObj = None
  6774         else:
  6775             if getThisObj is None:
  6776                 if descriptor.interface.isOnGlobalProtoChain():
  6777                     ensureCondition = "!args.thisv().isNullOrUndefined() && !args.thisv().isObject()"
  6778                     getThisObj = "args.thisv().isObject() ? &args.thisv().toObject() : js::GetGlobalForObjectCrossCompartment(&args.callee())"
  6779                 else:
  6780                     ensureCondition = "!args.thisv().isObject()"
  6781                     getThisObj = "&args.thisv().toObject()"
  6782                 unwrapFailureCode = self.unwrapFailureCode % {'securityError': 'false'}
  6783                 ensureThisObj = CGIfWrapper(CGGeneric(unwrapFailureCode),
  6784                                             ensureCondition)
  6785             else:
  6786                 ensureThisObj = None
  6787             self.getThisObj = CGList(
  6788                 [ensureThisObj,
  6789                  CGGeneric("JS::Rooted<JSObject*> obj(cx, %s);\n" %
  6790                            getThisObj)])
  6791         self.callArgs = callArgs
  6792         self.allowCrossOriginThis = allowCrossOriginThis
  6794     def definition_body(self):
  6795         body = self.callArgs
  6796         if self.getThisObj is not None:
  6797             body += self.getThisObj.define() + "\n"
  6798         body += "%s* self;\n" % self.descriptor.nativeType
  6800         # Our descriptor might claim that we're not castable, simply because
  6801         # we're someone's consequential interface.  But for this-unwrapping, we
  6802         # know that we're the real deal.  So fake a descriptor here for
  6803         # consumption by CastableObjectUnwrapper.
  6804         body += str(CastableObjectUnwrapper(
  6805             self.descriptor,
  6806             "obj", "self", self.unwrapFailureCode,
  6807             allowCrossOriginObj=self.allowCrossOriginThis))
  6809         return indent(body) + self.generate_code().define()
  6811     def generate_code(self):
  6812         assert False  # Override me
  6815 class CGAbstractStaticBindingMethod(CGAbstractStaticMethod):
  6816     """
  6817     Common class to generate the JSNatives for all our static methods, getters
  6818     and setters.  This will generate the function declaration and unwrap the
  6819     global object.  Subclasses are expected to override the generate_code
  6820     function to do the rest of the work.  This function should return a
  6821     CGThing which is already properly indented.
  6822     """
  6823     def __init__(self, descriptor, name):
  6824         args = [Argument('JSContext*', 'cx'),
  6825                 Argument('unsigned', 'argc'),
  6826                 Argument('JS::Value*', 'vp')]
  6827         CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args)
  6829     def definition_body(self):
  6830         # Make sure that "obj" is in the same compartment as "cx", since we'll
  6831         # later use it to wrap return values.
  6832         unwrap = indent(dedent("""
  6833             JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  6834             JS::Rooted<JSObject*> obj(cx, &args.callee());
  6836             """))
  6837         return unwrap + self.generate_code().define()
  6839     def generate_code(self):
  6840         assert False  # Override me
  6843 def MakeNativeName(name):
  6844     return name[0].upper() + name[1:]
  6847 class CGGenericMethod(CGAbstractBindingMethod):
  6848     """
  6849     A class for generating the C++ code for an IDL method.
  6851     If allowCrossOriginThis is true, then this-unwrapping will first do an
  6852     UncheckedUnwrap and after that operate on the result.
  6853     """
  6854     def __init__(self, descriptor, allowCrossOriginThis=False):
  6855         args = [Argument('JSContext*', 'cx'),
  6856                 Argument('unsigned', 'argc'),
  6857                 Argument('JS::Value*', 'vp')]
  6858         unwrapFailureCode = (
  6859             'return ThrowInvalidThis(cx, args, GetInvalidThisErrorForMethod(%%(securityError)s), "%s");\n' %
  6860             descriptor.interface.identifier.name)
  6861         name = "genericCrossOriginMethod" if allowCrossOriginThis else "genericMethod"
  6862         CGAbstractBindingMethod.__init__(self, descriptor, name,
  6863                                          args,
  6864                                          unwrapFailureCode=unwrapFailureCode,
  6865                                          allowCrossOriginThis=allowCrossOriginThis)
  6867     def generate_code(self):
  6868         return CGGeneric(indent(dedent("""
  6869             const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
  6870             MOZ_ASSERT(info->type() == JSJitInfo::Method);
  6871             JSJitMethodOp method = info->method;
  6872             return method(cx, obj, self, JSJitMethodCallArgs(args));
  6873             """)))
  6876 class CGSpecializedMethod(CGAbstractStaticMethod):
  6877     """
  6878     A class for generating the C++ code for a specialized method that the JIT
  6879     can call with lower overhead.
  6880     """
  6881     def __init__(self, descriptor, method):
  6882         self.method = method
  6883         name = CppKeywords.checkMethodName(method.identifier.name)
  6884         args = [Argument('JSContext*', 'cx'),
  6885                 Argument('JS::Handle<JSObject*>', 'obj'),
  6886                 Argument('%s*' % descriptor.nativeType, 'self'),
  6887                 Argument('const JSJitMethodCallArgs&', 'args')]
  6888         CGAbstractStaticMethod.__init__(self, descriptor, name, 'bool', args)
  6890     def definition_body(self):
  6891         nativeName = CGSpecializedMethod.makeNativeName(self.descriptor,
  6892                                                         self.method)
  6893         return CGMethodCall(nativeName, self.method.isStatic(), self.descriptor,
  6894                             self.method).define()
  6896     @staticmethod
  6897     def makeNativeName(descriptor, method):
  6898         name = method.identifier.name
  6899         return MakeNativeName(descriptor.binaryNames.get(name, name))
  6902 class CGMethodPromiseWrapper(CGAbstractStaticMethod):
  6903     """
  6904     A class for generating a wrapper around another method that will
  6905     convert exceptions to promises.
  6906     """
  6907     def __init__(self, descriptor, methodToWrap):
  6908         self.method = methodToWrap
  6909         name = self.makeName(methodToWrap.name)
  6910         args = list(methodToWrap.args)
  6911         CGAbstractStaticMethod.__init__(self, descriptor, name, 'bool', args)
  6913     def definition_body(self):
  6914         return indent(fill(
  6915             """
  6916             // Make sure to save the callee before someone maybe messes
  6917             // with rval().
  6918             JS::Rooted<JSObject*> callee(cx, &args.callee());
  6919             bool ok = ${methodName}(${args});
  6920             if (ok) {
  6921               return true;
  6923             return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
  6924                                              args.rval());
  6925             """,
  6926             methodName=self.method.name,
  6927             args=", ".join(arg.name for arg in self.args)))
  6929     @staticmethod
  6930     def makeName(methodName):
  6931         return methodName + "_promiseWrapper"
  6934 class CGJsonifierMethod(CGSpecializedMethod):
  6935     def __init__(self, descriptor, method):
  6936         assert method.isJsonifier()
  6937         CGSpecializedMethod.__init__(self, descriptor, method)
  6939     def definition_body(self):
  6940         ret = dedent("""
  6941             JS::Rooted<JSObject*> result(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
  6942             if (!result) {
  6943               return false;
  6945             """)
  6946         for m in self.descriptor.interface.members:
  6947             if m.isAttr() and not m.isStatic() and m.type.isSerializable():
  6948                 ret += fill(
  6949                     """
  6950                     { // scope for "temp"
  6951                       JS::Rooted<JS::Value> temp(cx);
  6952                       if (!get_${name}(cx, obj, self, JSJitGetterCallArgs(&temp))) {
  6953                         return false;
  6955                       if (!JS_DefineProperty(cx, result, "${name}", temp, JSPROP_ENUMERATE)) {
  6956                         return false;
  6959                     """,
  6960                     name=m.identifier.name)
  6962         ret += ('args.rval().setObject(*result);\n'
  6963                 'return true;\n')
  6964         return indent(ret)
  6967 class CGLegacyCallHook(CGAbstractBindingMethod):
  6968     """
  6969     Call hook for our object
  6970     """
  6971     def __init__(self, descriptor):
  6972         self._legacycaller = descriptor.operations["LegacyCaller"]
  6973         args = [Argument('JSContext*', 'cx'),
  6974                 Argument('unsigned', 'argc'),
  6975                 Argument('JS::Value*', 'vp')]
  6976         # Our "self" is actually the callee in this case, not the thisval.
  6977         CGAbstractBindingMethod.__init__(
  6978             self, descriptor, LEGACYCALLER_HOOK_NAME,
  6979             args, getThisObj="&args.callee()")
  6981     def define(self):
  6982         if not self._legacycaller:
  6983             return ""
  6984         return CGAbstractBindingMethod.define(self)
  6986     def generate_code(self):
  6987         name = self._legacycaller.identifier.name
  6988         nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
  6989         return CGMethodCall(nativeName, False, self.descriptor,
  6990                             self._legacycaller)
  6993 class CGNewResolveHook(CGAbstractBindingMethod):
  6994     """
  6995     NewResolve hook for objects with custom hooks.
  6996     """
  6997     def __init__(self, descriptor):
  6998         assert descriptor.interface.getExtendedAttribute("NeedNewResolve")
  7000         args = [Argument('JSContext*', 'cx'),
  7001                 Argument('JS::Handle<JSObject*>', 'obj'),
  7002                 Argument('JS::Handle<jsid>', 'id'),
  7003                 Argument('JS::MutableHandle<JSObject*>', 'objp')]
  7004         # Our "self" is actually the "obj" argument in this case, not the thisval.
  7005         CGAbstractBindingMethod.__init__(
  7006             self, descriptor, NEWRESOLVE_HOOK_NAME,
  7007             args, getThisObj="", callArgs="")
  7009     def generate_code(self):
  7010         return CGGeneric(indent(dedent("""
  7011             JS::Rooted<JSPropertyDescriptor> desc(cx);
  7012             if (!self->DoNewResolve(cx, obj, id, &desc)) {
  7013               return false;
  7015             if (!desc.object()) {
  7016               return true;
  7018             // If desc.value() is undefined, then the DoNewResolve call
  7019             // has already defined it on the object.  Don't try to also
  7020             // define it.
  7021             if (!desc.value().isUndefined() &&
  7022                 !JS_DefinePropertyById(cx, obj, id, desc.value(),
  7023                                        desc.getter(), desc.setter(),
  7024                                        desc.attributes())) {
  7025               return false;
  7027             objp.set(obj);
  7028             return true;
  7029             """)))
  7031     def definition_body(self):
  7032         if self.descriptor.interface.getExtendedAttribute("Global"):
  7033             # Resolve standard classes
  7034             prefix = indent(dedent("""
  7035                 if (!ResolveGlobal(cx, obj, id, objp)) {
  7036                   return false;
  7038                 if (objp) {
  7039                   return true;
  7042                 """))
  7043         else:
  7044             prefix = ""
  7045         return prefix + CGAbstractBindingMethod.definition_body(self)
  7048 class CGEnumerateHook(CGAbstractBindingMethod):
  7049     """
  7050     Enumerate hook for objects with custom hooks.
  7051     """
  7052     def __init__(self, descriptor):
  7053         assert descriptor.interface.getExtendedAttribute("NeedNewResolve")
  7055         args = [Argument('JSContext*', 'cx'),
  7056                 Argument('JS::Handle<JSObject*>', 'obj')]
  7057         # Our "self" is actually the "obj" argument in this case, not the thisval.
  7058         CGAbstractBindingMethod.__init__(
  7059             self, descriptor, ENUMERATE_HOOK_NAME,
  7060             args, getThisObj="", callArgs="")
  7062     def generate_code(self):
  7063         return CGGeneric(indent(dedent("""
  7064             nsAutoTArray<nsString, 8> names;
  7065             ErrorResult rv;
  7066             self->GetOwnPropertyNames(cx, names, rv);
  7067             rv.WouldReportJSException();
  7068             if (rv.Failed()) {
  7069               return ThrowMethodFailedWithDetails(cx, rv, "%s", "enumerate");
  7071             JS::Rooted<JS::Value> dummy(cx);
  7072             for (uint32_t i = 0; i < names.Length(); ++i) {
  7073               if (!JS_LookupUCProperty(cx, obj, names[i].get(), names[i].Length(), &dummy)) {
  7074                 return false;
  7077             return true;
  7078             """)))
  7080     def definition_body(self):
  7081         if self.descriptor.interface.getExtendedAttribute("Global"):
  7082             # Enumerate standard classes
  7083             prefix = indent(dedent("""
  7084                 if (!EnumerateGlobal(cx, obj)) {
  7085                   return false;
  7088                 """))
  7089         else:
  7090             prefix = ""
  7091         return prefix + CGAbstractBindingMethod.definition_body(self)
  7094 class CppKeywords():
  7095     """
  7096     A class for checking if method names declared in webidl
  7097     are not in conflict with C++ keywords.
  7098     """
  7099     keywords = frozenset([
  7100         'alignas', 'alignof', 'and', 'and_eq', 'asm', 'assert', 'auto', 'bitand', 'bitor', 'bool',
  7101         'break', 'case', 'catch', 'char', 'char16_t', 'char32_t', 'class', 'compl', 'const',
  7102         'constexpr', 'const_cast', 'continue', 'decltype', 'default', 'delete', 'do', 'double',
  7103         'dynamic_cast', 'else', 'enum', 'explicit', 'export', 'extern', 'false', 'final', 'float',
  7104         'for', 'friend', 'goto', 'if', 'inline', 'int', 'long', 'mutable', 'namespace', 'new',
  7105         'noexcept', 'not', 'not_eq', 'nullptr', 'operator', 'or', 'or_eq', 'override', 'private',
  7106         'protected', 'public', 'register', 'reinterpret_cast', 'return', 'short', 'signed',
  7107         'sizeof', 'static', 'static_assert', 'static_cast', 'struct', 'switch', 'template', 'this',
  7108         'thread_local', 'throw', 'true', 'try', 'typedef', 'typeid', 'typename', 'union',
  7109         'unsigned', 'using', 'virtual', 'void', 'volatile', 'wchar_t', 'while', 'xor', 'xor_eq'])
  7111     @staticmethod
  7112     def checkMethodName(name):
  7113         # Double '_' because 'assert' and '_assert' cannot be used in MS2013 compiler.
  7114         # Bug 964892 and bug 963560.
  7115         if name in CppKeywords.keywords:
  7116             name = '_' + name + '_'
  7117         return name
  7120 class CGStaticMethod(CGAbstractStaticBindingMethod):
  7121     """
  7122     A class for generating the C++ code for an IDL static method.
  7123     """
  7124     def __init__(self, descriptor, method):
  7125         self.method = method
  7126         name = method.identifier.name
  7127         CGAbstractStaticBindingMethod.__init__(self, descriptor, name)
  7129     def generate_code(self):
  7130         nativeName = CGSpecializedMethod.makeNativeName(self.descriptor,
  7131                                                         self.method)
  7132         return CGMethodCall(nativeName, True, self.descriptor, self.method)
  7135 class CGGenericGetter(CGAbstractBindingMethod):
  7136     """
  7137     A class for generating the C++ code for an IDL attribute getter.
  7138     """
  7139     def __init__(self, descriptor, lenientThis=False, allowCrossOriginThis=False):
  7140         args = [Argument('JSContext*', 'cx'),
  7141                 Argument('unsigned', 'argc'),
  7142                 Argument('JS::Value*', 'vp')]
  7143         if lenientThis:
  7144             name = "genericLenientGetter"
  7145             unwrapFailureCode = dedent("""
  7146                 MOZ_ASSERT(!JS_IsExceptionPending(cx));
  7147                 if (!ReportLenientThisUnwrappingFailure(cx, &args.callee())) {
  7148                   return false;
  7150                 args.rval().set(JS::UndefinedValue());
  7151                 return true;
  7152                 """)
  7153         else:
  7154             if allowCrossOriginThis:
  7155                 name = "genericCrossOriginGetter"
  7156             else:
  7157                 name = "genericGetter"
  7158             unwrapFailureCode = (
  7159                 'return ThrowInvalidThis(cx, args, GetInvalidThisErrorForGetter(%%(securityError)s), "%s");\n' %
  7160                 descriptor.interface.identifier.name)
  7161         CGAbstractBindingMethod.__init__(self, descriptor, name, args,
  7162                                          unwrapFailureCode,
  7163                                          allowCrossOriginThis=allowCrossOriginThis)
  7165     def generate_code(self):
  7166         return CGGeneric(indent(dedent("""
  7167             const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
  7168             MOZ_ASSERT(info->type() == JSJitInfo::Getter);
  7169             JSJitGetterOp getter = info->getter;
  7170             return getter(cx, obj, self, JSJitGetterCallArgs(args));
  7171             """)))
  7174 class CGSpecializedGetter(CGAbstractStaticMethod):
  7175     """
  7176     A class for generating the code for a specialized attribute getter
  7177     that the JIT can call with lower overhead.
  7178     """
  7179     def __init__(self, descriptor, attr):
  7180         self.attr = attr
  7181         name = 'get_' + attr.identifier.name
  7182         args = [
  7183             Argument('JSContext*', 'cx'),
  7184             Argument('JS::Handle<JSObject*>', 'obj'),
  7185             Argument('%s*' % descriptor.nativeType, 'self'),
  7186             Argument('JSJitGetterCallArgs', 'args')
  7188         CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args)
  7190     def definition_body(self):
  7191         nativeName = CGSpecializedGetter.makeNativeName(self.descriptor,
  7192                                                         self.attr)
  7193         if self.attr.slotIndex is not None:
  7194             if (self.descriptor.hasXPConnectImpls and
  7195                 (self.descriptor.interface.identifier.name != 'Window' or
  7196                  self.attr.identifier.name != 'document')):
  7197                 raise TypeError("Interface '%s' has XPConnect impls, so we "
  7198                                 "can't use our slot for property '%s'!" %
  7199                                 (self.descriptor.interface.identifier.name,
  7200                                  self.attr.identifier.name))
  7201             prefix = indent(fill(
  7202                 """
  7203                 // Have to either root across the getter call or reget after.
  7204                 JS::Rooted<JSObject*> reflector(cx);
  7205                 // Safe to do an unchecked unwrap, since we've gotten this far.
  7206                 // Also make sure to unwrap outer windows, since we want the
  7207                 // real DOM object.
  7208                 reflector = IsDOMObject(obj) ? obj : js::UncheckedUnwrap(obj, /* stopAtOuter = */ false);
  7210                   // Scope for cachedVal
  7211                   JS::Value cachedVal = js::GetReservedSlot(reflector, ${slot});
  7212                   if (!cachedVal.isUndefined()) {
  7213                     args.rval().set(cachedVal);
  7214                     // The cached value is in the compartment of reflector,
  7215                     // so wrap into the caller compartment as needed.
  7216                     return ${maybeWrap}(cx, args.rval());
  7220                 """,
  7221                 slot=memberReservedSlot(self.attr),
  7222                 maybeWrap=getMaybeWrapValueFuncForType(self.attr.type)))
  7223         else:
  7224             prefix = ""
  7226         return (prefix +
  7227                 indent(CGGetterCall(self.attr.type, nativeName,
  7228                                     self.descriptor, self.attr).define()))
  7230     @staticmethod
  7231     def makeNativeName(descriptor, attr):
  7232         name = attr.identifier.name
  7233         nativeName = MakeNativeName(descriptor.binaryNames.get(name, name))
  7234         # resultOutParam does not depend on whether resultAlreadyAddRefed is set
  7235         _, resultOutParam, _, _ = getRetvalDeclarationForType(attr.type,
  7236                                                               descriptor,
  7237                                                               False)
  7238         infallible = ('infallible' in
  7239                       descriptor.getExtendedAttributes(attr, getter=True))
  7240         if resultOutParam or attr.type.nullable() or not infallible:
  7241             nativeName = "Get" + nativeName
  7242         return nativeName
  7245 class CGStaticGetter(CGAbstractStaticBindingMethod):
  7246     """
  7247     A class for generating the C++ code for an IDL static attribute getter.
  7248     """
  7249     def __init__(self, descriptor, attr):
  7250         self.attr = attr
  7251         name = 'get_' + attr.identifier.name
  7252         CGAbstractStaticBindingMethod.__init__(self, descriptor, name)
  7254     def generate_code(self):
  7255         nativeName = CGSpecializedGetter.makeNativeName(self.descriptor,
  7256                                                         self.attr)
  7257         return CGIndenter(CGGetterCall(self.attr.type, nativeName,
  7258                                        self.descriptor, self.attr))
  7261 class CGGenericSetter(CGAbstractBindingMethod):
  7262     """
  7263     A class for generating the C++ code for an IDL attribute setter.
  7264     """
  7265     def __init__(self, descriptor, lenientThis=False, allowCrossOriginThis=False):
  7266         args = [Argument('JSContext*', 'cx'),
  7267                 Argument('unsigned', 'argc'),
  7268                 Argument('JS::Value*', 'vp')]
  7269         if lenientThis:
  7270             name = "genericLenientSetter"
  7271             unwrapFailureCode = dedent("""
  7272                 MOZ_ASSERT(!JS_IsExceptionPending(cx));
  7273                 if (!ReportLenientThisUnwrappingFailure(cx, &args.callee())) {
  7274                   return false;
  7276                 args.rval().set(JS::UndefinedValue());
  7277                 return true;
  7278                 """)
  7279         else:
  7280             if allowCrossOriginThis:
  7281                 name = "genericCrossOriginSetter"
  7282             else:
  7283                 name = "genericSetter"
  7284             unwrapFailureCode = (
  7285                 'return ThrowInvalidThis(cx, args, GetInvalidThisErrorForSetter(%%(securityError)s), "%s");\n' %
  7286                 descriptor.interface.identifier.name)
  7288         CGAbstractBindingMethod.__init__(self, descriptor, name, args,
  7289                                          unwrapFailureCode,
  7290                                          allowCrossOriginThis=allowCrossOriginThis)
  7292     def generate_code(self):
  7293         return CGGeneric(indent(fill(
  7294             """
  7295             if (args.length() == 0) {
  7296               return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "${name} attribute setter");
  7298             const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
  7299             MOZ_ASSERT(info->type() == JSJitInfo::Setter);
  7300             JSJitSetterOp setter = info->setter;
  7301             if (!setter(cx, obj, self, JSJitSetterCallArgs(args))) {
  7302               return false;
  7304             args.rval().set(JSVAL_VOID);
  7305             return true;
  7306             """,
  7307             name=self.descriptor.interface.identifier.name)))
  7310 class CGSpecializedSetter(CGAbstractStaticMethod):
  7311     """
  7312     A class for generating the code for a specialized attribute setter
  7313     that the JIT can call with lower overhead.
  7314     """
  7315     def __init__(self, descriptor, attr):
  7316         self.attr = attr
  7317         name = 'set_' + attr.identifier.name
  7318         args = [Argument('JSContext*', 'cx'),
  7319                 Argument('JS::Handle<JSObject*>', 'obj'),
  7320                 Argument('%s*' % descriptor.nativeType, 'self'),
  7321                 Argument('JSJitSetterCallArgs', 'args')]
  7322         CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args)
  7324     def definition_body(self):
  7325         nativeName = CGSpecializedSetter.makeNativeName(self.descriptor,
  7326                                                         self.attr)
  7327         return CGIndenter(CGSetterCall(self.attr.type, nativeName,
  7328                                        self.descriptor, self.attr)).define()
  7330     @staticmethod
  7331     def makeNativeName(descriptor, attr):
  7332         name = attr.identifier.name
  7333         return "Set" + MakeNativeName(descriptor.binaryNames.get(name, name))
  7336 class CGStaticSetter(CGAbstractStaticBindingMethod):
  7337     """
  7338     A class for generating the C++ code for an IDL static attribute setter.
  7339     """
  7340     def __init__(self, descriptor, attr):
  7341         self.attr = attr
  7342         name = 'set_' + attr.identifier.name
  7343         CGAbstractStaticBindingMethod.__init__(self, descriptor, name)
  7345     def generate_code(self):
  7346         nativeName = CGSpecializedSetter.makeNativeName(self.descriptor,
  7347                                                         self.attr)
  7348         checkForArg = CGGeneric(fill(
  7349             """
  7350             if (args.length() == 0) {
  7351               return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "${name} setter");
  7353             """,
  7354             name=self.attr.identifier.name))
  7355         call = CGSetterCall(self.attr.type, nativeName, self.descriptor,
  7356                             self.attr)
  7357         return CGIndenter(CGList([checkForArg, call]))
  7360 class CGSpecializedForwardingSetter(CGSpecializedSetter):
  7361     """
  7362     A class for generating the code for a specialized attribute setter with
  7363     PutForwards that the JIT can call with lower overhead.
  7364     """
  7365     def __init__(self, descriptor, attr):
  7366         CGSpecializedSetter.__init__(self, descriptor, attr)
  7368     def definition_body(self):
  7369         attrName = self.attr.identifier.name
  7370         forwardToAttrName = self.attr.getExtendedAttribute("PutForwards")[0]
  7371         # JS_GetProperty and JS_SetProperty can only deal with ASCII
  7372         assert all(ord(c) < 128 for c in attrName)
  7373         assert all(ord(c) < 128 for c in forwardToAttrName)
  7374         return indent(fill(
  7375             """
  7376             JS::Rooted<JS::Value> v(cx);
  7377             if (!JS_GetProperty(cx, obj, "${attr}", &v)) {
  7378               return false;
  7381             if (!v.isObject()) {
  7382               return ThrowErrorMessage(cx, MSG_NOT_OBJECT, "${interface}.${attr}");
  7385             JS::Rooted<JSObject*> targetObj(cx, &v.toObject());
  7386             return JS_SetProperty(cx, targetObj, "${forwardToAttrName}", args[0]);
  7387             """,
  7388             attr=attrName,
  7389             interface=self.descriptor.interface.identifier.name,
  7390             forwardToAttrName=forwardToAttrName))
  7393 class CGSpecializedReplaceableSetter(CGSpecializedSetter):
  7394     """
  7395     A class for generating the code for a specialized attribute setter with
  7396     Replaceable that the JIT can call with lower overhead.
  7397     """
  7398     def __init__(self, descriptor, attr):
  7399         CGSpecializedSetter.__init__(self, descriptor, attr)
  7401     def definition_body(self):
  7402         attrName = self.attr.identifier.name
  7403         # JS_DefineProperty can only deal with ASCII
  7404         assert all(ord(c) < 128 for c in attrName)
  7405         return indent('return JS_DefineProperty(cx, obj, "%s", args[0], JSPROP_ENUMERATE);\n' %
  7406                       attrName)
  7409 def memberReturnsNewObject(member):
  7410     return member.getExtendedAttribute("NewObject") is not None
  7413 class CGMemberJITInfo(CGThing):
  7414     """
  7415     A class for generating the JITInfo for a property that points to
  7416     our specialized getter and setter.
  7417     """
  7418     def __init__(self, descriptor, member):
  7419         self.member = member
  7420         self.descriptor = descriptor
  7422     def declare(self):
  7423         return ""
  7425     def defineJitInfo(self, infoName, opName, opType, infallible, movable,
  7426                       aliasSet, hasSlot, slotIndex, returnTypes, args):
  7427         """
  7428         aliasSet is a JSJitInfo::AliasSet value, without the "JSJitInfo::" bit.
  7430         args is None if we don't want to output argTypes for some
  7431         reason (e.g. we have overloads or we're not a method) and
  7432         otherwise an iterable of the arguments for this method.
  7433         """
  7434         assert(not movable or aliasSet != "AliasEverything")  # Can't move write-aliasing things
  7435         assert(not hasSlot or movable)  # Things with slots had better be movable
  7437         def jitInfoInitializer(isTypedMethod):
  7438             initializer = fill(
  7439                 """
  7441                  { ${opName} },
  7442                   prototypes::id::${name},
  7443                   PrototypeTraits<prototypes::id::${name}>::Depth,
  7444                   JSJitInfo::${opType},
  7445                   JSJitInfo::${aliasSet}, /* aliasSet.  Not relevant for setters. */
  7446                   ${returnType},  /* returnType.  Not relevant for setters. */
  7447                   ${isInfallible},  /* isInfallible. False in setters. */
  7448                   ${isMovable},  /* isMovable.  Not relevant for setters. */
  7449                   ${isInSlot},  /* isInSlot.  Only relevant for getters. */
  7450                   ${isTypedMethod},  /* isTypedMethod.  Only relevant for methods. */
  7451                   ${slotIndex}   /* Reserved slot index, if we're stored in a slot, else 0. */
  7453                 """,
  7454                 opName=opName,
  7455                 name=self.descriptor.name,
  7456                 opType=opType,
  7457                 aliasSet=aliasSet,
  7458                 returnType=reduce(CGMemberJITInfo.getSingleReturnType, returnTypes,
  7459                                   ""),
  7460                 isInfallible=toStringBool(infallible),
  7461                 isMovable=toStringBool(movable),
  7462                 isInSlot=toStringBool(hasSlot),
  7463                 isTypedMethod=toStringBool(isTypedMethod),
  7464                 slotIndex=slotIndex)
  7465             return initializer.rstrip()
  7467         if args is not None:
  7468             argTypes = "%s_argTypes" % infoName
  7469             args = [CGMemberJITInfo.getJSArgType(arg.type) for arg in args]
  7470             args.append("JSJitInfo::ArgTypeListEnd")
  7471             argTypesDecl = (
  7472                 "static const JSJitInfo::ArgType %s[] = { %s };\n" %
  7473                 (argTypes, ", ".join(args)))
  7474             return fill(
  7475                 """
  7477                 $*{argTypesDecl}
  7478                 static const JSTypedMethodJitInfo ${infoName} = {
  7479                   ${jitInfo},
  7480                   ${argTypes}
  7481                 };
  7482                 """,
  7483                 argTypesDecl=argTypesDecl,
  7484                 infoName=infoName,
  7485                 jitInfo=jitInfoInitializer(True),
  7486                 argTypes=argTypes)
  7488         return ("\n"
  7489                 "static const JSJitInfo %s = %s;\n"
  7490                 % (infoName, jitInfoInitializer(False)))
  7492     def define(self):
  7493         if self.member.isAttr():
  7494             getterinfo = ("%s_getterinfo" % self.member.identifier.name)
  7495             # We need the cast here because JSJitGetterOp has a "void* self"
  7496             # while we have the right type.
  7497             getter = ("(JSJitGetterOp)get_%s" % self.member.identifier.name)
  7498             getterinfal = "infallible" in self.descriptor.getExtendedAttributes(self.member, getter=True)
  7499             getterconst = (self.member.getExtendedAttribute("SameObject") or
  7500                            self.member.getExtendedAttribute("Constant"))
  7501             getterpure = getterconst or self.member.getExtendedAttribute("Pure")
  7502             if getterconst:
  7503                 aliasSet = "AliasNone"
  7504             elif getterpure:
  7505                 aliasSet = "AliasDOMSets"
  7506             else:
  7507                 aliasSet = "AliasEverything"
  7508             movable = getterpure and getterinfal
  7510             getterinfal = getterinfal and infallibleForMember(self.member, self.member.type, self.descriptor)
  7511             isInSlot = self.member.getExtendedAttribute("StoreInSlot")
  7512             if isInSlot:
  7513                 slotIndex = memberReservedSlot(self.member)
  7514                 # We'll statically assert that this is not too big in
  7515                 # CGUpdateMemberSlotsMethod
  7516             else:
  7517                 slotIndex = "0"
  7519             result = self.defineJitInfo(getterinfo, getter, "Getter",
  7520                                         getterinfal, movable, aliasSet,
  7521                                         isInSlot, slotIndex,
  7522                                         [self.member.type], None)
  7523             if (not self.member.readonly or
  7524                 self.member.getExtendedAttribute("PutForwards") is not None or
  7525                 self.member.getExtendedAttribute("Replaceable") is not None):
  7526                 setterinfo = ("%s_setterinfo" % self.member.identifier.name)
  7527                 # Actually a JSJitSetterOp, but JSJitGetterOp is first in the
  7528                 # union.
  7529                 setter = ("(JSJitGetterOp)set_%s" % self.member.identifier.name)
  7530                 # Setters are always fallible, since they have to do a typed unwrap.
  7531                 result += self.defineJitInfo(setterinfo, setter, "Setter",
  7532                                              False, False, "AliasEverything",
  7533                                              False, "0",
  7534                                              [BuiltinTypes[IDLBuiltinType.Types.void]],
  7535                                              None)
  7536             return result
  7537         if self.member.isMethod():
  7538             methodinfo = ("%s_methodinfo" % self.member.identifier.name)
  7539             name = CppKeywords.checkMethodName(self.member.identifier.name)
  7540             if self.member.returnsPromise():
  7541                 name = CGMethodPromiseWrapper.makeName(name)
  7542             # Actually a JSJitMethodOp, but JSJitGetterOp is first in the union.
  7543             method = ("(JSJitGetterOp)%s" % name)
  7544             methodPure = self.member.getExtendedAttribute("Pure")
  7546             # Methods are infallible if they are infallible, have no arguments
  7547             # to unwrap, and have a return type that's infallible to wrap up for
  7548             # return.
  7549             sigs = self.member.signatures()
  7550             if len(sigs) != 1:
  7551                 # Don't handle overloading.  If there's more than one signature,
  7552                 # one of them must take arguments.
  7553                 methodInfal = False
  7554                 args = None
  7555                 movable = False
  7556             else:
  7557                 sig = sigs[0]
  7558                 # For pure methods, it's OK to set movable to our notion of
  7559                 # infallible on the C++ side, without considering argument
  7560                 # conversions, since argument conversions that can reliably
  7561                 # throw would be effectful anyway and the jit doesn't move
  7562                 # effectful things.
  7563                 hasInfallibleImpl = "infallible" in self.descriptor.getExtendedAttributes(self.member)
  7564                 movable = methodPure and hasInfallibleImpl
  7565                 # XXXbz can we move the smarts about fallibility due to arg
  7566                 # conversions into the JIT, using our new args stuff?
  7567                 if (len(sig[1]) != 0 or
  7568                     not infallibleForMember(self.member, sig[0], self.descriptor)):
  7569                     # We have arguments or our return-value boxing can fail
  7570                     methodInfal = False
  7571                 else:
  7572                     methodInfal = hasInfallibleImpl
  7573                 # For now, only bother to output args if we're pure
  7574                 if methodPure:
  7575                     args = sig[1]
  7576                 else:
  7577                     args = None
  7579             if args is not None:
  7580                 aliasSet = "AliasDOMSets"
  7581             else:
  7582                 aliasSet = "AliasEverything"
  7583             result = self.defineJitInfo(methodinfo, method, "Method",
  7584                                         methodInfal, movable, aliasSet, False, "0",
  7585                                         [s[0] for s in sigs], args)
  7586             return result
  7587         raise TypeError("Illegal member type to CGPropertyJITInfo")
  7589     @staticmethod
  7590     def getJSReturnTypeTag(t):
  7591         if t.nullable():
  7592             # Sometimes it might return null, sometimes not
  7593             return "JSVAL_TYPE_UNKNOWN"
  7594         if t.isVoid():
  7595             # No return, every time
  7596             return "JSVAL_TYPE_UNDEFINED"
  7597         if t.isArray():
  7598             # No idea yet
  7599             assert False
  7600         if t.isSequence():
  7601             return "JSVAL_TYPE_OBJECT"
  7602         if t.isMozMap():
  7603             return "JSVAL_TYPE_OBJECT"
  7604         if t.isGeckoInterface():
  7605             return "JSVAL_TYPE_OBJECT"
  7606         if t.isString():
  7607             return "JSVAL_TYPE_STRING"
  7608         if t.isEnum():
  7609             return "JSVAL_TYPE_STRING"
  7610         if t.isCallback():
  7611             return "JSVAL_TYPE_OBJECT"
  7612         if t.isAny():
  7613             # The whole point is to return various stuff
  7614             return "JSVAL_TYPE_UNKNOWN"
  7615         if t.isObject():
  7616             return "JSVAL_TYPE_OBJECT"
  7617         if t.isSpiderMonkeyInterface():
  7618             return "JSVAL_TYPE_OBJECT"
  7619         if t.isUnion():
  7620             u = t.unroll()
  7621             if u.hasNullableType:
  7622                 # Might be null or not
  7623                 return "JSVAL_TYPE_UNKNOWN"
  7624             return reduce(CGMemberJITInfo.getSingleReturnType,
  7625                           u.flatMemberTypes, "")
  7626         if t.isDictionary():
  7627             return "JSVAL_TYPE_OBJECT"
  7628         if t.isDate():
  7629             return "JSVAL_TYPE_OBJECT"
  7630         if not t.isPrimitive():
  7631             raise TypeError("No idea what type " + str(t) + " is.")
  7632         tag = t.tag()
  7633         if tag == IDLType.Tags.bool:
  7634             return "JSVAL_TYPE_BOOLEAN"
  7635         if tag in [IDLType.Tags.int8, IDLType.Tags.uint8,
  7636                    IDLType.Tags.int16, IDLType.Tags.uint16,
  7637                    IDLType.Tags.int32]:
  7638             return "JSVAL_TYPE_INT32"
  7639         if tag in [IDLType.Tags.int64, IDLType.Tags.uint64,
  7640                    IDLType.Tags.unrestricted_float, IDLType.Tags.float,
  7641                    IDLType.Tags.unrestricted_double, IDLType.Tags.double]:
  7642             # These all use JS_NumberValue, which can return int or double.
  7643             # But TI treats "double" as meaning "int or double", so we're
  7644             # good to return JSVAL_TYPE_DOUBLE here.
  7645             return "JSVAL_TYPE_DOUBLE"
  7646         if tag != IDLType.Tags.uint32:
  7647             raise TypeError("No idea what type " + str(t) + " is.")
  7648         # uint32 is sometimes int and sometimes double.
  7649         return "JSVAL_TYPE_DOUBLE"
  7651     @staticmethod
  7652     def getSingleReturnType(existingType, t):
  7653         type = CGMemberJITInfo.getJSReturnTypeTag(t)
  7654         if existingType == "":
  7655             # First element of the list; just return its type
  7656             return type
  7658         if type == existingType:
  7659             return existingType
  7660         if ((type == "JSVAL_TYPE_DOUBLE" and
  7661              existingType == "JSVAL_TYPE_INT32") or
  7662             (existingType == "JSVAL_TYPE_DOUBLE" and
  7663              type == "JSVAL_TYPE_INT32")):
  7664             # Promote INT32 to DOUBLE as needed
  7665             return "JSVAL_TYPE_DOUBLE"
  7666         # Different types
  7667         return "JSVAL_TYPE_UNKNOWN"
  7669     @staticmethod
  7670     def getJSArgType(t):
  7671         assert not t.isVoid()
  7672         if t.nullable():
  7673             # Sometimes it might return null, sometimes not
  7674             return "JSJitInfo::ArgType(JSJitInfo::Null | %s)" % CGMemberJITInfo.getJSArgType(t.inner)
  7675         if t.isArray():
  7676             # No idea yet
  7677             assert False
  7678         if t.isSequence():
  7679             return "JSJitInfo::Object"
  7680         if t.isGeckoInterface():
  7681             return "JSJitInfo::Object"
  7682         if t.isString():
  7683             return "JSJitInfo::String"
  7684         if t.isEnum():
  7685             return "JSJitInfo::String"
  7686         if t.isCallback():
  7687             return "JSJitInfo::Object"
  7688         if t.isAny():
  7689             # The whole point is to return various stuff
  7690             return "JSJitInfo::Any"
  7691         if t.isObject():
  7692             return "JSJitInfo::Object"
  7693         if t.isSpiderMonkeyInterface():
  7694             return "JSJitInfo::Object"
  7695         if t.isUnion():
  7696             u = t.unroll()
  7697             type = "JSJitInfo::Null" if u.hasNullableType else ""
  7698             return ("JSJitInfo::ArgType(%s)" %
  7699                     reduce(CGMemberJITInfo.getSingleArgType,
  7700                            u.flatMemberTypes, type))
  7701         if t.isDictionary():
  7702             return "JSJitInfo::Object"
  7703         if t.isDate():
  7704             return "JSJitInfo::Object"
  7705         if not t.isPrimitive():
  7706             raise TypeError("No idea what type " + str(t) + " is.")
  7707         tag = t.tag()
  7708         if tag == IDLType.Tags.bool:
  7709             return "JSJitInfo::Boolean"
  7710         if tag in [IDLType.Tags.int8, IDLType.Tags.uint8,
  7711                    IDLType.Tags.int16, IDLType.Tags.uint16,
  7712                    IDLType.Tags.int32]:
  7713             return "JSJitInfo::Integer"
  7714         if tag in [IDLType.Tags.int64, IDLType.Tags.uint64,
  7715                    IDLType.Tags.unrestricted_float, IDLType.Tags.float,
  7716                    IDLType.Tags.unrestricted_double, IDLType.Tags.double]:
  7717             # These all use JS_NumberValue, which can return int or double.
  7718             # But TI treats "double" as meaning "int or double", so we're
  7719             # good to return JSVAL_TYPE_DOUBLE here.
  7720             return "JSJitInfo::Double"
  7721         if tag != IDLType.Tags.uint32:
  7722             raise TypeError("No idea what type " + str(t) + " is.")
  7723         # uint32 is sometimes int and sometimes double.
  7724         return "JSJitInfo::Double"
  7726     @staticmethod
  7727     def getSingleArgType(existingType, t):
  7728         type = CGMemberJITInfo.getJSArgType(t)
  7729         if existingType == "":
  7730             # First element of the list; just return its type
  7731             return type
  7733         if type == existingType:
  7734             return existingType
  7735         return "%s | %s" % (existingType, type)
  7738 class CGStaticMethodJitinfo(CGGeneric):
  7739     """
  7740     A class for generating the JITInfo for a promise-returning static method.
  7741     """
  7742     def __init__(self, method):
  7743         CGGeneric.__init__(
  7744             self,
  7745             "\n"
  7746             "static const JSJitInfo %s_methodinfo = {\n"
  7747             "  { (JSJitGetterOp)%s },\n"
  7748             "  prototypes::id::_ID_Count, 0, JSJitInfo::StaticMethod,\n"
  7749             "  JSJitInfo::AliasEverything, JSVAL_TYPE_MISSING, false, false,\n"
  7750             "  false, false, 0\n"
  7751             "};\n" %
  7752             (method.identifier.name, method.identifier.name))
  7755 def getEnumValueName(value):
  7756     # Some enum values can be empty strings.  Others might have weird
  7757     # characters in them.  Deal with the former by returning "_empty",
  7758     # deal with possible name collisions from that by throwing if the
  7759     # enum value is actually "_empty", and throw on any value
  7760     # containing non-ASCII chars for now. Replace all chars other than
  7761     # [0-9A-Za-z_] with '_'.
  7762     if re.match("[^\x20-\x7E]", value):
  7763         raise SyntaxError('Enum value "' + value + '" contains non-ASCII characters')
  7764     if re.match("^[0-9]", value):
  7765         return '_' + value
  7766     value = re.sub(r'[^0-9A-Za-z_]', '_', value)
  7767     if re.match("^_[A-Z]|__", value):
  7768         raise SyntaxError('Enum value "' + value + '" is reserved by the C++ spec')
  7769     if value == "_empty":
  7770         raise SyntaxError('"_empty" is not an IDL enum value we support yet')
  7771     if value == "":
  7772         return "_empty"
  7773     return MakeNativeName(value)
  7776 class CGEnum(CGThing):
  7777     def __init__(self, enum):
  7778         CGThing.__init__(self)
  7779         self.enum = enum
  7781     def stringsNamespace(self):
  7782         return self.enum.identifier.name + "Values"
  7784     def nEnumStrings(self):
  7785         return len(self.enum.values()) + 1
  7787     def declare(self):
  7788         decl = fill(  # BOGUS extra newline at top
  7789             """
  7791             MOZ_BEGIN_ENUM_CLASS(${name}, uint32_t)
  7792               $*{enums}
  7793             MOZ_END_ENUM_CLASS(${name})
  7794             """,
  7795             name=self.enum.identifier.name,
  7796             enums=",\n".join(map(getEnumValueName, self.enum.values())) + "\n")
  7797         strings = CGNamespace(self.stringsNamespace(),
  7798                               CGGeneric(declare="extern const EnumEntry %s[%d];\n"
  7799                                         % (ENUM_ENTRY_VARIABLE_NAME, self.nEnumStrings())))
  7800         return decl + "\n" + strings.declare()
  7802     def define(self):
  7803         strings = fill(  # BOGUS extra newline at top
  7804             """
  7806             extern const EnumEntry ${name}[${count}] = {
  7807               $*{entries}
  7808               { nullptr, 0 }
  7809             };
  7810             """,
  7811             name=ENUM_ENTRY_VARIABLE_NAME,
  7812             count=self.nEnumStrings(),
  7813             entries=''.join('{"%s", %d},\n' % (val, len(val))
  7814                             for val in self.enum.values()))
  7815         # BOGUS - CGNamespace automatically indents; the extra indent() below causes
  7816         # the output to be indented 4 spaces.
  7817         return CGNamespace(self.stringsNamespace(),
  7818                            CGGeneric(define=indent(strings))).define()
  7820     def deps(self):
  7821         return self.enum.getDeps()
  7824 def getUnionAccessorSignatureType(type, descriptorProvider):
  7825     """
  7826     Returns the types that are used in the getter and setter signatures for
  7827     union types
  7828     """
  7829     if type.isArray():
  7830         raise TypeError("Can't handle array arguments yet")
  7832     if type.isSequence():
  7833         nullable = type.nullable()
  7834         if nullable:
  7835             type = type.inner.inner
  7836         else:
  7837             type = type.inner
  7838         # We don't use the returned template here, so it's OK to just pass no
  7839         # sourceDescription.
  7840         elementInfo = getJSToNativeConversionInfo(type, descriptorProvider,
  7841                                                   isMember="Sequence")
  7842         typeName = CGTemplatedType("Sequence", elementInfo.declType,
  7843                                    isReference=True)
  7844         if nullable:
  7845             typeName = CGTemplatedType("Nullable", typeName, isReference=True)
  7847         return typeName
  7849     if type.isUnion():
  7850         typeName = CGGeneric(type.name)
  7851         if type.nullable():
  7852             typeName = CGTemplatedType("Nullable", typeName, isReference=True)
  7854         return typeName
  7856     if type.isGeckoInterface():
  7857         descriptor = descriptorProvider.getDescriptor(
  7858             type.unroll().inner.identifier.name)
  7859         typeName = CGGeneric(descriptor.nativeType)
  7860         # Allow null pointers for nullable types and old-binding classes
  7861         if type.nullable() or type.unroll().inner.isExternal():
  7862             typeName = CGWrapper(typeName, post="*")
  7863         else:
  7864             typeName = CGWrapper(typeName, post="&")
  7865         return typeName
  7867     if type.isSpiderMonkeyInterface():
  7868         typeName = CGGeneric(type.name)
  7869         if type.nullable():
  7870             typeName = CGTemplatedType("Nullable", typeName)
  7871         return CGWrapper(typeName, post="&")
  7873     if type.isDOMString():
  7874         return CGGeneric("const nsAString&")
  7876     if type.isByteString():
  7877         return CGGeneric("const nsCString&")
  7879     if type.isEnum():
  7880         if type.nullable():
  7881             raise TypeError("We don't support nullable enumerated arguments or "
  7882                             "union members yet")
  7883         return CGGeneric(type.inner.identifier.name)
  7885     if type.isCallback():
  7886         if type.nullable():
  7887             typeName = "%s*"
  7888         else:
  7889             typeName = "%s&"
  7890         return CGGeneric(typeName % type.unroll().identifier.name)
  7892     if type.isAny():
  7893         return CGGeneric("JS::Value")
  7895     if type.isObject():
  7896         return CGGeneric("JSObject*")
  7898     if type.isDictionary():
  7899         return CGGeneric("const %s&" % type.inner.identifier.name)
  7901     if not type.isPrimitive():
  7902         raise TypeError("Need native type for argument type '%s'" % str(type))
  7904     typeName = CGGeneric(builtinNames[type.tag()])
  7905     if type.nullable():
  7906         typeName = CGTemplatedType("Nullable", typeName, isReference=True)
  7907     return typeName
  7910 def getUnionTypeTemplateVars(unionType, type, descriptorProvider,
  7911                              ownsMembers=False):
  7912     # For dictionaries and sequences we need to pass None as the failureCode
  7913     # for getJSToNativeConversionInfo.
  7914     # Also, for dictionaries we would need to handle conversion of
  7915     # null/undefined to the dictionary correctly.
  7916     if type.isSequence():
  7917         raise TypeError("Can't handle sequences in unions")
  7919     name = getUnionMemberName(type)
  7921     # By the time tryNextCode is invoked, we're guaranteed the union has been
  7922     # constructed as some type, since we've been trying to convert into the
  7923     # corresponding member.
  7924     prefix = "" if ownsMembers else "mUnion."
  7925     tryNextCode = ("%sDestroy%s();\n"
  7926                    "tryNext = true;\n"
  7927                    "return true;\n" % (prefix, name))
  7928     conversionInfo = getJSToNativeConversionInfo(
  7929         type, descriptorProvider, failureCode=tryNextCode,
  7930         isDefinitelyObject=not type.isDictionary(),
  7931         isMember=("OwningUnion" if ownsMembers else None),
  7932         sourceDescription="member of %s" % unionType)
  7934     ctorNeedsCx = conversionInfo.declArgs == "cx"
  7935     ctorArgs = "cx" if ctorNeedsCx else ""
  7937     # This is ugly, but UnionMember needs to call a constructor with no
  7938     # arguments so the type can't be const.
  7939     structType = conversionInfo.declType.define()
  7940     if structType.startswith("const "):
  7941         structType = structType[6:]
  7942     externalType = getUnionAccessorSignatureType(type, descriptorProvider).define()
  7944     if type.isObject():
  7945         if ownsMembers:
  7946             body = dedent("""
  7947                 MOZ_ASSERT(mType == eUninitialized);
  7948                 mValue.mObject.SetValue(obj);
  7949                 mType = eObject;
  7950                 """)
  7951         else:
  7952             body = dedent("""
  7953                 MOZ_ASSERT(mUnion.mType == mUnion.eUninitialized);
  7954                 mUnion.mValue.mObject.SetValue(cx, obj);
  7955                 mUnion.mType = mUnion.eObject;
  7956                 """)
  7957         setter = ClassMethod("SetToObject", "void",
  7958                              [Argument("JSContext*", "cx"),
  7959                               Argument("JSObject*", "obj")],
  7960                              inline=True, bodyInHeader=True,
  7961                              body=body)
  7963     else:
  7964         # Important: we need to not have our declName involve
  7965         # maybe-GCing operations.
  7966         jsConversion = string.Template(conversionInfo.template).substitute({
  7967             "val": "value",
  7968             "mutableVal": "pvalue",
  7969             "declName": "memberSlot",
  7970             "holderName": "m" + name + "Holder",
  7971         })
  7972         jsConversion = fill(
  7973             """
  7974             tryNext = false;
  7975             { // scope for memberSlot
  7976               ${structType}& memberSlot = RawSetAs${name}(${ctorArgs});
  7977               $*{jsConversion}
  7979             return true;
  7980             """,
  7981             structType=structType,
  7982             name=name,
  7983             ctorArgs=ctorArgs,
  7984             jsConversion=jsConversion)
  7986         setter = ClassMethod("TrySetTo" + name, "bool",
  7987                              [Argument("JSContext*", "cx"),
  7988                               Argument("JS::Handle<JS::Value>", "value"),
  7989                               Argument("JS::MutableHandle<JS::Value>", "pvalue"),
  7990                               Argument("bool&", "tryNext")],
  7991                              inline=not ownsMembers,
  7992                              bodyInHeader=not ownsMembers,
  7993                              body=jsConversion)
  7995     return {
  7996         "name": name,
  7997         "structType": structType,
  7998         "externalType": externalType,
  7999         "setter": setter,
  8000         "holderType": conversionInfo.holderType.define() if conversionInfo.holderType else None,
  8001         "ctorArgs": ctorArgs,
  8002         "ctorArgList": [Argument("JSContext*", "cx")] if ctorNeedsCx else []
  8006 class CGUnionStruct(CGThing):
  8007     def __init__(self, type, descriptorProvider, ownsMembers=False):
  8008         CGThing.__init__(self)
  8009         self.type = type.unroll()
  8010         self.descriptorProvider = descriptorProvider
  8011         self.ownsMembers = ownsMembers
  8012         self.struct = self.getStruct()
  8014     def declare(self):
  8015         return self.struct.declare()
  8017     def define(self):
  8018         return self.struct.define()
  8020     def getStruct(self):
  8022         members = [ClassMember("mType", "Type", body="eUninitialized"),
  8023                    ClassMember("mValue", "Value")]
  8024         ctor = ClassConstructor([], bodyInHeader=True, visibility="public",
  8025                                 explicit=True)
  8027         methods = []
  8028         enumValues = ["eUninitialized"]
  8029         toJSValCases = [CGCase("eUninitialized", CGGeneric("return false;\n"))]
  8030         destructorCases = [CGCase("eUninitialized", None)]
  8031         assignmentCases = [
  8032             CGCase("eUninitialized",
  8033                    CGGeneric('MOZ_ASSERT(mType == eUninitialized,\n'
  8034                              '           "We need to destroy ourselves?");\n'))]
  8035         traceCases = []
  8036         unionValues = []
  8037         if self.type.hasNullableType:
  8038             enumValues.append("eNull")
  8039             methods.append(ClassMethod("IsNull", "bool", [], const=True, inline=True,
  8040                                        body="return mType == eNull;\n",
  8041                                        bodyInHeader=True))
  8042             methods.append(ClassMethod("SetNull", "void", [], inline=True,
  8043                                        body=("Uninit();\n"
  8044                                              "mType = eNull;\n"),
  8045                                        bodyInHeader=True))
  8046             destructorCases.append(CGCase("eNull", None))
  8047             assignmentCases.append(CGCase("eNull",
  8048                                           CGGeneric("MOZ_ASSERT(mType == eUninitialized);\n"
  8049                                                     "mType = eNull;\n")))
  8050             toJSValCases.append(CGCase("eNull", CGGeneric("rval.setNull();\n"
  8051                                                           "return true;\n")))
  8053         hasObjectType = any(t.isObject() for t in self.type.flatMemberTypes)
  8054         for t in self.type.flatMemberTypes:
  8055             vars = getUnionTypeTemplateVars(self.type,
  8056                                             t, self.descriptorProvider,
  8057                                             ownsMembers=self.ownsMembers)
  8058             if vars["name"] != "Object" or self.ownsMembers:
  8059                 body = fill(
  8060                     """
  8061                     if (mType == e${name}) {
  8062                       return mValue.m${name}.Value();
  8064                     %s
  8065                     mType = e${name};
  8066                     return mValue.m${name}.SetValue(${ctorArgs});
  8067                     """,
  8068                     **vars)
  8070                 # bodyInHeader must be false for return values because they own
  8071                 # their union members and we don't want include headers in
  8072                 # UnionTypes.h just to call Addref/Release
  8073                 methods.append(ClassMethod(
  8074                     "RawSetAs" + vars["name"],
  8075                     vars["structType"] + "&",
  8076                     vars["ctorArgList"],
  8077                     bodyInHeader=not self.ownsMembers,
  8078                     body=body % "MOZ_ASSERT(mType == eUninitialized);"))
  8079                 uninit = "Uninit();"
  8080                 if hasObjectType and not self.ownsMembers:
  8081                     uninit = 'MOZ_ASSERT(mType != eObject, "This will not play well with Rooted");\n' + uninit
  8082                 methods.append(ClassMethod(
  8083                     "SetAs" + vars["name"],
  8084                     vars["structType"] + "&",
  8085                     vars["ctorArgList"],
  8086                     bodyInHeader=not self.ownsMembers,
  8087                     body=body % uninit))
  8088                 if self.ownsMembers:
  8089                     methods.append(vars["setter"])
  8090                     if t.isString():
  8091                         methods.append(
  8092                             ClassMethod("SetStringData", "void",
  8093                                         [Argument("const nsString::char_type*", "aData"),
  8094                                          Argument("nsString::size_type", "aLength")],
  8095                                         inline=True, bodyInHeader=True,
  8096                                         body="RawSetAsString().Assign(aData, aLength);\n"))
  8098             body = fill(
  8099                 """
  8100                 MOZ_ASSERT(Is${name}(), "Wrong type!");
  8101                 mValue.m${name}.Destroy();
  8102                 mType = eUninitialized;
  8103                 """,
  8104                 **vars)
  8105             methods.append(ClassMethod("Destroy" + vars["name"],
  8106                                        "void",
  8107                                        [],
  8108                                        visibility="private",
  8109                                        bodyInHeader=not self.ownsMembers,
  8110                                        body=body))
  8112             body = fill("return mType == e${name};\n", **vars)
  8113             methods.append(ClassMethod("Is" + vars["name"],
  8114                                        "bool",
  8115                                        [],
  8116                                        const=True,
  8117                                        bodyInHeader=True,
  8118                                        body=body))
  8120             body = fill(
  8121                 """
  8122                 MOZ_ASSERT(Is${name}(), "Wrong type!");
  8123                 return const_cast<${structType}&>(mValue.m${name}.Value());
  8124                 """,
  8125                 **vars)
  8126             if self.ownsMembers:
  8127                 getterReturnType = "%s&" % vars["structType"]
  8128             else:
  8129                 getterReturnType = vars["externalType"]
  8130             methods.append(ClassMethod("GetAs" + vars["name"],
  8131                                        getterReturnType,
  8132                                        [],
  8133                                        const=True,
  8134                                        bodyInHeader=True,
  8135                                        body=body))
  8137             unionValues.append(
  8138                 fill("UnionMember<${structType} > m${name}", **vars))
  8139             enumValues.append("e" + vars["name"])
  8141             toJSValCases.append(
  8142                 CGCase("e" + vars["name"],
  8143                        self.getConversionToJS(vars, t)))
  8144             destructorCases.append(
  8145                 CGCase("e" + vars["name"],
  8146                        CGGeneric("Destroy%s();\n" % vars["name"])))
  8147             assignmentCases.append(
  8148                 CGCase("e" + vars["name"],
  8149                        CGGeneric("SetAs%s() = aOther.GetAs%s();\n" %
  8150                                  (vars["name"], vars["name"]))))
  8151             if self.ownsMembers and typeNeedsRooting(t):
  8152                 if t.isObject():
  8153                     traceCases.append(
  8154                         CGCase("e" + vars["name"],
  8155                                CGGeneric('JS_CallObjectTracer(trc, %s, "%s");\n' %
  8156                                          ("&mValue.m" + vars["name"] + ".Value()",
  8157                                           "mValue.m" + vars["name"]))))
  8158                 elif t.isDictionary():
  8159                     traceCases.append(
  8160                         CGCase("e" + vars["name"],
  8161                                CGGeneric("mValue.m%s.Value().TraceDictionary(trc);\n" %
  8162                                          vars["name"])))
  8163                 else:
  8164                     assert t.isSpiderMonkeyInterface()
  8165                     traceCases.append(
  8166                         CGCase("e" + vars["name"],
  8167                                CGGeneric("mValue.m%s.Value().TraceSelf(trc);\n" %
  8168                                          vars["name"])))
  8170         dtor = CGSwitch("mType", destructorCases).define()
  8172         methods.append(ClassMethod("Uninit", "void", [],
  8173                                    visibility="private", body=dtor,
  8174                                    bodyInHeader=not self.ownsMembers,
  8175                                    inline=not self.ownsMembers))
  8177         methods.append(
  8178             ClassMethod(
  8179                 "ToJSVal",
  8180                 "bool",
  8182                     Argument("JSContext*", "cx"),
  8183                     Argument("JS::Handle<JSObject*>", "scopeObj"),
  8184                     Argument("JS::MutableHandle<JS::Value>", "rval")
  8185                 ],
  8186                 body=CGSwitch("mType", toJSValCases,
  8187                               default=CGGeneric("return false;\n")).define(),
  8188                 const=True))
  8190         constructors = [ctor]
  8191         selfName = CGUnionStruct.unionTypeName(self.type, self.ownsMembers)
  8192         if self.ownsMembers:
  8193             if traceCases:
  8194                 # BOGUS blank line in default case
  8195                 traceBody = CGSwitch("mType", traceCases,
  8196                                      default=CGGeneric("\n")).define()
  8197             else:
  8198                 # BOGUS blank line in method
  8199                 traceBody = "\n"
  8200             methods.append(ClassMethod("TraceUnion", "void",
  8201                                        [Argument("JSTracer*", "trc")],
  8202                                        body=traceBody))
  8203             if CGUnionStruct.isUnionCopyConstructible(self.type):
  8204                 constructors.append(
  8205                     ClassConstructor(
  8206                         [Argument("const %s&" % selfName, "aOther")],
  8207                         bodyInHeader=True,
  8208                         visibility="public",
  8209                         explicit=True,
  8210                         body="*this = aOther;\n"))
  8211                 methods.append(ClassMethod(
  8212                     "operator=", "void",
  8213                     [Argument("const %s&" % selfName, "aOther")],
  8214                     body=CGSwitch("aOther.mType", assignmentCases).define()))
  8215                 disallowCopyConstruction = False
  8216             else:
  8217                 disallowCopyConstruction = True
  8218         else:
  8219             disallowCopyConstruction = True
  8221         friend = "  friend class %sArgument;\n" % str(self.type) if not self.ownsMembers else ""
  8222         bases = [ClassBase("AllOwningUnionBase")] if self.ownsMembers else []
  8223         return CGClass(selfName,
  8224                        bases=bases,
  8225                        members=members,
  8226                        constructors=constructors,
  8227                        methods=methods,
  8228                        disallowCopyConstruction=disallowCopyConstruction,
  8229                        extradeclarations=friend,
  8230                        destructor=ClassDestructor(visibility="public",
  8231                                                   body="Uninit();",
  8232                                                   bodyInHeader=True),
  8233                        enums=[ClassEnum("Type", enumValues, visibility="private")],
  8234                        unions=[ClassUnion("Value", unionValues, visibility="private")])
  8236     def getConversionToJS(self, templateVars, type):
  8237         assert not type.nullable()  # flatMemberTypes never has nullable types
  8238         val = "mValue.m%(name)s.Value()" % templateVars
  8239         wrapCode = wrapForType(
  8240             type, self.descriptorProvider,
  8242                 "jsvalRef": "rval",
  8243                 "jsvalHandle": "rval",
  8244                 "obj": "scopeObj",
  8245                 "result": val,
  8246                 "typedArraysAreStructs": True
  8247             })
  8248         return CGGeneric(wrapCode)
  8250     @staticmethod
  8251     def isUnionCopyConstructible(type):
  8252         return all(isTypeCopyConstructible(t) for t in type.flatMemberTypes)
  8254     @staticmethod
  8255     def unionTypeName(type, ownsMembers):
  8256         """
  8257         Returns a string name for this known union type.
  8258         """
  8259         assert type.isUnion() and not type.nullable()
  8260         return ("Owning" if ownsMembers else "") + type.name
  8262     @staticmethod
  8263     def unionTypeDecl(type, ownsMembers):
  8264         """
  8265         Returns a string for declaring this possibly-nullable union type.
  8266         """
  8267         assert type.isUnion()
  8268         nullable = type.nullable()
  8269         if nullable:
  8270             type = type.inner
  8271         decl = CGGeneric(CGUnionStruct.unionTypeName(type, ownsMembers))
  8272         if nullable:
  8273             decl = CGTemplatedType("Nullable", decl)
  8274         return decl.define()
  8277 class CGUnionConversionStruct(CGThing):
  8278     def __init__(self, type, descriptorProvider):
  8279         CGThing.__init__(self)
  8280         self.type = type.unroll()
  8281         self.descriptorProvider = descriptorProvider
  8283     def declare(self):
  8285         structName = str(self.type)
  8286         members = [ClassMember("mUnion", structName + "&",
  8287                                body="const_cast<%s&>(aUnion)" % structName)]
  8288         # Argument needs to be a const ref because that's all Maybe<> allows
  8289         ctor = ClassConstructor([Argument("const %s&" % structName, "aUnion")],
  8290                                 bodyInHeader=True,
  8291                                 visibility="public",
  8292                                 explicit=True)
  8293         methods = []
  8295         if self.type.hasNullableType:
  8296             methods.append(ClassMethod("SetNull", "bool", [],
  8297                                        body=("MOZ_ASSERT(mUnion.mType == mUnion.eUninitialized);\n"
  8298                                              "mUnion.mType = mUnion.eNull;\n"
  8299                                              "return true;\n"),
  8300                                        inline=True, bodyInHeader=True))
  8302         for t in self.type.flatMemberTypes:
  8303             vars = getUnionTypeTemplateVars(self.type,
  8304                                             t, self.descriptorProvider)
  8305             methods.append(vars["setter"])
  8306             if vars["name"] != "Object":
  8307                 body = fill(
  8308                     """
  8309                     MOZ_ASSERT(mUnion.mType == mUnion.eUninitialized);
  8310                     mUnion.mType = mUnion.e${name};
  8311                     return mUnion.mValue.m${name}.SetValue(${ctorArgs});
  8312                     """,
  8313                     **vars)
  8314                 methods.append(ClassMethod("RawSetAs" + vars["name"],
  8315                                            vars["structType"] + "&",
  8316                                            vars["ctorArgList"],
  8317                                            bodyInHeader=True,
  8318                                            body=body,
  8319                                            visibility="private"))
  8320                 if t.isString():
  8321                     methods.append(
  8322                         ClassMethod("SetStringData", "void",
  8323                                     [Argument("const nsDependentString::char_type*", "aData"),
  8324                                      Argument("nsDependentString::size_type", "aLength")],
  8325                                     inline=True, bodyInHeader=True,
  8326                                     body="RawSetAsString().SetData(aData, aLength);\n"))
  8328             if vars["holderType"] is not None:
  8329                 members.append(ClassMember("m%sHolder" % vars["name"],
  8330                                            vars["holderType"]))
  8332         return CGClass(structName + "Argument",
  8333                        members=members,
  8334                        constructors=[ctor],
  8335                        methods=methods,
  8336                        disallowCopyConstruction=True).declare()
  8338     def define(self):
  8339         return "\n"
  8342 class ClassItem:
  8343     """ Use with CGClass """
  8344     def __init__(self, name, visibility):
  8345         self.name = name
  8346         self.visibility = visibility
  8348     def declare(self, cgClass):
  8349         assert False
  8351     def define(self, cgClass):
  8352         assert False
  8355 class ClassBase(ClassItem):
  8356     def __init__(self, name, visibility='public'):
  8357         ClassItem.__init__(self, name, visibility)
  8359     def declare(self, cgClass):
  8360         return '%s %s' % (self.visibility, self.name)
  8362     def define(self, cgClass):
  8363         # Only in the header
  8364         return ''
  8367 class ClassMethod(ClassItem):
  8368     def __init__(self, name, returnType, args, inline=False, static=False,
  8369                  virtual=False, const=False, bodyInHeader=False,
  8370                  templateArgs=None, visibility='public', body=None,
  8371                  breakAfterReturnDecl="\n",
  8372                  breakAfterSelf="\n", override=False):
  8373         """
  8374         override indicates whether to flag the method as MOZ_OVERRIDE
  8375         """
  8376         assert not override or virtual
  8377         assert not (override and static)
  8378         self.returnType = returnType
  8379         self.args = args
  8380         self.inline = inline or bodyInHeader
  8381         self.static = static
  8382         self.virtual = virtual
  8383         self.const = const
  8384         self.bodyInHeader = bodyInHeader
  8385         self.templateArgs = templateArgs
  8386         self.body = body
  8387         self.breakAfterReturnDecl = breakAfterReturnDecl
  8388         self.breakAfterSelf = breakAfterSelf
  8389         self.override = override
  8390         ClassItem.__init__(self, name, visibility)
  8392     def getDecorators(self, declaring):
  8393         decorators = []
  8394         if self.inline:
  8395             decorators.append('inline')
  8396         if declaring:
  8397             if self.static:
  8398                 decorators.append('static')
  8399             if self.virtual:
  8400                 decorators.append('virtual')
  8401         if decorators:
  8402             return ' '.join(decorators) + ' '
  8403         return ''
  8405     def getBody(self):
  8406         # Override me or pass a string to constructor
  8407         assert self.body is not None
  8408         return self.body
  8410     def declare(self, cgClass):
  8411         templateClause = ('template <%s>\n' % ', '.join(self.templateArgs)
  8412                           if self.bodyInHeader and self.templateArgs else '')
  8413         args = ', '.join([a.declare() for a in self.args])
  8414         if self.bodyInHeader:
  8415             body = indent(self.getBody())
  8416             body = '\n{\n' + body + '}\n'
  8417         else:
  8418             body = ';\n'
  8420         return fill(
  8421             "${templateClause}${decorators}${returnType}${breakAfterReturnDecl}"
  8422             "${name}(${args})${const}${override}${body}"
  8423             "${breakAfterSelf}",
  8424             templateClause=templateClause,
  8425             decorators=self.getDecorators(True),
  8426             returnType=self.returnType,
  8427             breakAfterReturnDecl=self.breakAfterReturnDecl,
  8428             name=self.name,
  8429             args=args,
  8430             const=' const' if self.const else '',
  8431             override=' MOZ_OVERRIDE' if self.override else '',
  8432             body=body,
  8433             breakAfterSelf=self.breakAfterSelf)
  8435     def define(self, cgClass):
  8436         if self.bodyInHeader:
  8437             return ''
  8439         templateArgs = cgClass.templateArgs
  8440         if templateArgs:
  8441             if cgClass.templateSpecialization:
  8442                 templateArgs = \
  8443                     templateArgs[len(cgClass.templateSpecialization):]
  8445         if templateArgs:
  8446             templateClause = \
  8447                 'template <%s>\n' % ', '.join([str(a) for a in templateArgs])
  8448         else:
  8449             templateClause = ''
  8451         return fill(
  8452             """
  8453             ${templateClause}${decorators}${returnType}
  8454             ${className}::${name}(${args})${const}
  8456               $*{body}
  8458             """,
  8459             templateClause=templateClause,
  8460             decorators=self.getDecorators(False),
  8461             returnType=self.returnType,
  8462             className=cgClass.getNameString(),
  8463             name=self.name,
  8464             args=', '.join([a.define() for a in self.args]),
  8465             const=' const' if self.const else '',
  8466             body=self.getBody())
  8469 class ClassUsingDeclaration(ClassItem):
  8470     """
  8471     Used for importing a name from a base class into a CGClass
  8473     baseClass is the name of the base class to import the name from
  8475     name is the name to import
  8477     visibility determines the visibility of the name (public,
  8478     protected, private), defaults to public.
  8479     """
  8480     def __init__(self, baseClass, name, visibility='public'):
  8481         self.baseClass = baseClass
  8482         ClassItem.__init__(self, name, visibility)
  8484     def declare(self, cgClass):
  8485         return "using %s::%s;\n\n" % (self.baseClass, self.name)
  8487     def define(self, cgClass):
  8488         return ''
  8491 class ClassConstructor(ClassItem):
  8492     """
  8493     Used for adding a constructor to a CGClass.
  8495     args is a list of Argument objects that are the arguments taken by the
  8496     constructor.
  8498     inline should be True if the constructor should be marked inline.
  8500     bodyInHeader should be True if the body should be placed in the class
  8501     declaration in the header.
  8503     visibility determines the visibility of the constructor (public,
  8504     protected, private), defaults to private.
  8506     explicit should be True if the constructor should be marked explicit.
  8508     baseConstructors is a list of strings containing calls to base constructors,
  8509     defaults to None.
  8511     body contains a string with the code for the constructor, defaults to empty.
  8512     """
  8513     def __init__(self, args, inline=False, bodyInHeader=False,
  8514                  visibility="private", explicit=False, baseConstructors=None,
  8515                  body=""):
  8516         self.args = args
  8517         self.inline = inline or bodyInHeader
  8518         self.bodyInHeader = bodyInHeader
  8519         self.explicit = explicit
  8520         self.baseConstructors = baseConstructors or []
  8521         self.body = body
  8522         ClassItem.__init__(self, None, visibility)
  8524     def getDecorators(self, declaring):
  8525         decorators = []
  8526         if self.explicit:
  8527             decorators.append('explicit')
  8528         if self.inline and declaring:
  8529             decorators.append('inline')
  8530         if decorators:
  8531             return ' '.join(decorators) + ' '
  8532         return ''
  8534     def getInitializationList(self, cgClass):
  8535         items = [str(c) for c in self.baseConstructors]
  8536         for m in cgClass.members:
  8537             if not m.static:
  8538                 initialize = m.body
  8539                 if initialize:
  8540                     items.append(m.name + "(" + initialize + ")")
  8542         if len(items) > 0:
  8543             return '\n  : ' + ',\n    '.join(items)
  8544         return ''
  8546     def getBody(self):
  8547         return self.body
  8549     def declare(self, cgClass):
  8550         args = ', '.join([a.declare() for a in self.args])
  8551         if self.bodyInHeader:
  8552             body = self.getInitializationList(cgClass) + '\n{\n' + indent(self.getBody()) + '}\n'
  8553         else:
  8554             body = ';\n'
  8556         return fill(
  8557             "${decorators}${className}(${args})${body}\n",
  8558             decorators=self.getDecorators(True),
  8559             className=cgClass.getNameString(),
  8560             args=args,
  8561             body=body)
  8563     def define(self, cgClass):
  8564         if self.bodyInHeader:
  8565             return ''
  8567         return fill(
  8568             """
  8569             ${decorators}
  8570             ${className}::${className}(${args})${initializationList}
  8572               $*{body}
  8574             """,
  8575             decorators=self.getDecorators(False),
  8576             className=cgClass.getNameString(),
  8577             args=', '.join([a.define() for a in self.args]),
  8578             initializationList=self.getInitializationList(cgClass),
  8579             body=self.getBody())
  8582 class ClassDestructor(ClassItem):
  8583     """
  8584     Used for adding a destructor to a CGClass.
  8586     inline should be True if the destructor should be marked inline.
  8588     bodyInHeader should be True if the body should be placed in the class
  8589     declaration in the header.
  8591     visibility determines the visibility of the destructor (public,
  8592     protected, private), defaults to private.
  8594     body contains a string with the code for the destructor, defaults to empty.
  8596     virtual determines whether the destructor is virtual, defaults to False.
  8597     """
  8598     def __init__(self, inline=False, bodyInHeader=False,
  8599                  visibility="private", body='', virtual=False):
  8600         self.inline = inline or bodyInHeader
  8601         self.bodyInHeader = bodyInHeader
  8602         self.body = body
  8603         self.virtual = virtual
  8604         ClassItem.__init__(self, None, visibility)
  8606     def getDecorators(self, declaring):
  8607         decorators = []
  8608         if self.virtual and declaring:
  8609             decorators.append('virtual')
  8610         if self.inline and declaring:
  8611             decorators.append('inline')
  8612         if decorators:
  8613             return ' '.join(decorators) + ' '
  8614         return ''
  8616     def getBody(self):
  8617         return self.body
  8619     def declare(self, cgClass):
  8620         if self.bodyInHeader:
  8621             body = '\n{\n' + indent(self.getBody()) + '}\n'
  8622         else:
  8623             body = ';\n'
  8625         return fill(
  8626             "${decorators}~${className}()${body}\n",
  8627             decorators=self.getDecorators(True),
  8628             className=cgClass.getNameString(),
  8629             body=body)
  8631     def define(self, cgClass):
  8632         if self.bodyInHeader:
  8633             return ''
  8634         return fill(
  8635             """
  8636             ${decorators}
  8637             ${className}::~${className}()
  8639               $*{body}
  8641             """,
  8642             decorators=self.getDecorators(False),
  8643             className=cgClass.getNameString(),
  8644             body=self.getBody() or "\n")  # BOGUS extra blank line if empty
  8647 class ClassMember(ClassItem):
  8648     def __init__(self, name, type, visibility="private", static=False,
  8649                  body=None):
  8650         self.type = type
  8651         self.static = static
  8652         self.body = body
  8653         ClassItem.__init__(self, name, visibility)
  8655     def declare(self, cgClass):
  8656         return '%s%s %s;\n' % ('static ' if self.static else '', self.type,
  8657                                self.name)
  8659     def define(self, cgClass):
  8660         if not self.static:
  8661             return ''
  8662         if self.body:
  8663             body = " = " + self.body
  8664         else:
  8665             body = ""
  8666         return '%s %s::%s%s;\n' % (self.type, cgClass.getNameString(),
  8667                                    self.name, body)
  8670 class ClassTypedef(ClassItem):
  8671     def __init__(self, name, type, visibility="public"):
  8672         self.type = type
  8673         ClassItem.__init__(self, name, visibility)
  8675     def declare(self, cgClass):
  8676         return 'typedef %s %s;\n' % (self.type, self.name)
  8678     def define(self, cgClass):
  8679         # Only goes in the header
  8680         return ''
  8683 class ClassEnum(ClassItem):
  8684     def __init__(self, name, entries, values=None, visibility="public"):
  8685         self.entries = entries
  8686         self.values = values
  8687         ClassItem.__init__(self, name, visibility)
  8689     def declare(self, cgClass):
  8690         entries = []
  8691         for i in range(0, len(self.entries)):
  8692             if not self.values or i >= len(self.values):
  8693                 entry = '%s' % self.entries[i]
  8694             else:
  8695                 entry = '%s = %s' % (self.entries[i], self.values[i])
  8696             entries.append(entry)
  8697         name = '' if not self.name else ' ' + self.name
  8698         return 'enum%s\n{\n%s\n};\n' % (name, indent(',\n'.join(entries)))
  8700     def define(self, cgClass):
  8701         # Only goes in the header
  8702         return ''
  8705 class ClassUnion(ClassItem):
  8706     def __init__(self, name, entries, visibility="public"):
  8707         self.entries = [entry + ";\n" for entry in entries]
  8708         ClassItem.__init__(self, name, visibility)
  8710     def declare(self, cgClass):
  8711         return "union %s\n{\n%s\n};\n" % (self.name, indent(''.join(self.entries)))
  8713     def define(self, cgClass):
  8714         # Only goes in the header
  8715         return ''
  8718 class CGClass(CGThing):
  8719     def __init__(self, name, bases=[], members=[], constructors=[],
  8720                  destructor=None, methods=[],
  8721                  typedefs=[], enums=[], unions=[], templateArgs=[],
  8722                  templateSpecialization=[], isStruct=False,
  8723                  disallowCopyConstruction=False, indent='',
  8724                  decorators='',
  8725                  extradeclarations='',
  8726                  extradefinitions=''):
  8727         CGThing.__init__(self)
  8728         self.name = name
  8729         self.bases = bases
  8730         self.members = members
  8731         self.constructors = constructors
  8732         # We store our single destructor in a list, since all of our
  8733         # code wants lists of members.
  8734         self.destructors = [destructor] if destructor else []
  8735         self.methods = methods
  8736         self.typedefs = typedefs
  8737         self.enums = enums
  8738         self.unions = unions
  8739         self.templateArgs = templateArgs
  8740         self.templateSpecialization = templateSpecialization
  8741         self.isStruct = isStruct
  8742         self.disallowCopyConstruction = disallowCopyConstruction
  8743         self.indent = indent
  8744         self.defaultVisibility = 'public' if isStruct else 'private'
  8745         self.decorators = decorators
  8746         self.extradeclarations = extradeclarations
  8747         self.extradefinitions = extradefinitions
  8749     def getNameString(self):
  8750         className = self.name
  8751         if self.templateSpecialization:
  8752             className += '<%s>' % ', '.join([str(a)
  8753                                              for a in self.templateSpecialization])
  8754         return className
  8756     def declare(self):
  8757         result = ''
  8758         if self.templateArgs:
  8759             templateArgs = [a.declare() for a in self.templateArgs]
  8760             templateArgs = templateArgs[len(self.templateSpecialization):]
  8761             result += ('template <%s>\n' %
  8762                        ','.join([str(a) for a in templateArgs]))
  8764         type = 'struct' if self.isStruct else 'class'
  8766         if self.templateSpecialization:
  8767             specialization = \
  8768                 '<%s>' % ', '.join([str(a) for a in self.templateSpecialization])
  8769         else:
  8770             specialization = ''
  8772         myself = '%s %s%s' % (type, self.name, specialization)
  8773         if self.decorators != '':
  8774             myself += " " + self.decorators
  8775         result += myself
  8777         if self.bases:
  8778             inherit = ' : '
  8779             result += inherit
  8780             # Grab our first base
  8781             baseItems = [CGGeneric(b.declare(self)) for b in self.bases]
  8782             bases = baseItems[:1]
  8783             # Indent the rest
  8784             bases.extend(CGIndenter(b, len(myself) + len(inherit))
  8785                          for b in baseItems[1:])
  8786             result += ",\n".join(b.define() for b in bases)
  8788         result += '\n{\n'
  8790         result += self.extradeclarations
  8792         def declareMembers(cgClass, memberList, defaultVisibility):
  8793             members = {'private': [], 'protected': [], 'public': []}
  8795             for member in memberList:
  8796                 members[member.visibility].append(member)
  8798             if defaultVisibility == 'public':
  8799                 order = ['public', 'protected', 'private']
  8800             else:
  8801                 order = ['private', 'protected', 'public']
  8803             result = ''
  8805             lastVisibility = defaultVisibility
  8806             for visibility in order:
  8807                 list = members[visibility]
  8808                 if list:
  8809                     if visibility != lastVisibility:
  8810                         result += visibility + ':\n'
  8811                     for member in list:
  8812                         result += indent(member.declare(cgClass))
  8813                     lastVisibility = visibility
  8814             return (result, lastVisibility)
  8816         if self.disallowCopyConstruction:
  8817             class DisallowedCopyConstructor(object):
  8818                 def __init__(self):
  8819                     self.visibility = "private"
  8821                 def declare(self, cgClass):
  8822                     name = cgClass.getNameString()
  8823                     return ("%s(const %s&) MOZ_DELETE;\n"
  8824                             "void operator=(const %s) MOZ_DELETE;\n" % (name, name, name))
  8826             disallowedCopyConstructors = [DisallowedCopyConstructor()]
  8827         else:
  8828             disallowedCopyConstructors = []
  8830         order = [self.enums, self.unions,
  8831                  self.typedefs, self.members,
  8832                  self.constructors + disallowedCopyConstructors,
  8833                  self.destructors, self.methods]
  8835         lastVisibility = self.defaultVisibility
  8836         pieces = []
  8837         for memberList in order:
  8838             code, lastVisibility = declareMembers(self, memberList, lastVisibility)
  8840             if code:
  8841                 code = code.rstrip() + "\n"  # remove extra blank lines at the end
  8842                 pieces.append(code)
  8844         result += '\n'.join(pieces)
  8845         result += '};\n'
  8846         result = indent(result, len(self.indent))
  8847         return result
  8849     def define(self):
  8850         def defineMembers(cgClass, memberList, itemCount, separator=''):
  8851             result = ''
  8852             for member in memberList:
  8853                 if itemCount != 0:
  8854                     result = result + separator
  8855                 definition = member.define(cgClass)
  8856                 if definition:
  8857                     # Member variables would only produce empty lines here.
  8858                     result += definition
  8859                     itemCount += 1
  8860             return (result, itemCount)
  8862         order = [(self.members, ''), (self.constructors, '\n'),
  8863                  (self.destructors, '\n'), (self.methods, '\n')]
  8865         result = self.extradefinitions
  8866         itemCount = 0
  8867         for memberList, separator in order:
  8868             memberString, itemCount = defineMembers(self, memberList,
  8869                                                     itemCount, separator)
  8870             result = result + memberString
  8871         return result
  8874 class CGResolveOwnProperty(CGAbstractStaticMethod):
  8875     def __init__(self, descriptor):
  8876         args = [Argument('JSContext*', 'cx'),
  8877                 Argument('JS::Handle<JSObject*>', 'wrapper'),
  8878                 Argument('JS::Handle<JSObject*>', 'obj'),
  8879                 Argument('JS::Handle<jsid>', 'id'),
  8880                 Argument('JS::MutableHandle<JSPropertyDescriptor>', 'desc'),
  8882         CGAbstractStaticMethod.__init__(self, descriptor, "ResolveOwnProperty",
  8883                                         "bool", args)
  8885     def definition_body(self):
  8886         # BOGUS extra blank line at end of function
  8887         return "  return js::GetProxyHandler(obj)->getOwnPropertyDescriptor(cx, wrapper, id, desc);\n\n"
  8890 class CGResolveOwnPropertyViaNewresolve(CGAbstractBindingMethod):
  8891     """
  8892     An implementation of Xray ResolveOwnProperty stuff for things that have a
  8893     newresolve hook.
  8894     """
  8895     def __init__(self, descriptor):
  8896         args = [Argument('JSContext*', 'cx'),
  8897                 Argument('JS::Handle<JSObject*>', 'wrapper'),
  8898                 Argument('JS::Handle<JSObject*>', 'obj'),
  8899                 Argument('JS::Handle<jsid>', 'id'),
  8900                 Argument('JS::MutableHandle<JSPropertyDescriptor>', 'desc')]
  8901         CGAbstractBindingMethod.__init__(self, descriptor,
  8902                                          "ResolveOwnPropertyViaNewresolve",
  8903                                          args, getThisObj="",
  8904                                          callArgs="")
  8906     def generate_code(self):
  8907         return CGGeneric(indent(dedent("""
  8909               // Since we're dealing with an Xray, do the resolve on the
  8910               // underlying object first.  That gives it a chance to
  8911               // define properties on the actual object as needed, and
  8912               // then use the fact that it created the objects as a flag
  8913               // to avoid re-resolving the properties if someone deletes
  8914               // them.
  8915               JSAutoCompartment ac(cx, obj);
  8916               JS::Rooted<JSPropertyDescriptor> objDesc(cx);
  8917               if (!self->DoNewResolve(cx, obj, id, &objDesc)) {
  8918                 return false;
  8920               // If desc.value() is undefined, then the DoNewResolve call
  8921               // has already defined the property on the object.  Don't
  8922               // try to also define it.
  8923               if (objDesc.object() &&
  8924                   !objDesc.value().isUndefined() &&
  8925                   !JS_DefinePropertyById(cx, obj, id, objDesc.value(),
  8926                                          objDesc.getter(), objDesc.setter(),
  8927                                          objDesc.attributes())) {
  8928                 return false;
  8931             return self->DoNewResolve(cx, wrapper, id, desc);
  8932             """)))
  8935 class CGEnumerateOwnProperties(CGAbstractStaticMethod):
  8936     def __init__(self, descriptor):
  8937         args = [Argument('JSContext*', 'cx'),
  8938                 Argument('JS::Handle<JSObject*>', 'wrapper'),
  8939                 Argument('JS::Handle<JSObject*>', 'obj'),
  8940                 Argument('JS::AutoIdVector&', 'props')]
  8941         CGAbstractStaticMethod.__init__(self, descriptor,
  8942                                         "EnumerateOwnProperties", "bool", args)
  8944     def definition_body(self):
  8945         # BOGUS extra newline
  8946         return "  return js::GetProxyHandler(obj)->getOwnPropertyNames(cx, wrapper, props);\n\n"
  8949 class CGEnumerateOwnPropertiesViaGetOwnPropertyNames(CGAbstractBindingMethod):
  8950     """
  8951     An implementation of Xray EnumerateOwnProperties stuff for things
  8952     that have a newresolve hook.
  8953     """
  8954     def __init__(self, descriptor):
  8955         args = [Argument('JSContext*', 'cx'),
  8956                 Argument('JS::Handle<JSObject*>', 'wrapper'),
  8957                 Argument('JS::Handle<JSObject*>', 'obj'),
  8958                 Argument('JS::AutoIdVector&', 'props')]
  8959         CGAbstractBindingMethod.__init__(self, descriptor,
  8960                                          "EnumerateOwnPropertiesViaGetOwnPropertyNames",
  8961                                          args, getThisObj="",
  8962                                          callArgs="")
  8964     def generate_code(self):
  8965         return CGIndenter(CGGeneric(dedent("""
  8966             nsAutoTArray<nsString, 8> names;
  8967             ErrorResult rv;
  8968             self->GetOwnPropertyNames(cx, names, rv);
  8969             rv.WouldReportJSException();
  8970             if (rv.Failed()) {
  8971               return ThrowMethodFailedWithDetails(cx, rv, "%s", "enumerate");
  8973             // OK to pass null as "proxy" because it's ignored if
  8974             // shadowPrototypeProperties is true
  8975             return AppendNamedPropertyIds(cx, JS::NullPtr(), names, true, props);
  8976             """)))
  8979 class CGPrototypeTraitsClass(CGClass):
  8980     def __init__(self, descriptor, indent=''):
  8981         templateArgs = [Argument('prototypes::ID', 'PrototypeID')]
  8982         templateSpecialization = ['prototypes::id::' + descriptor.name]
  8983         enums = [ClassEnum('', ['Depth'],
  8984                            [descriptor.interface.inheritanceDepth()])]
  8985         CGClass.__init__(self, 'PrototypeTraits', indent=indent,
  8986                          templateArgs=templateArgs,
  8987                          templateSpecialization=templateSpecialization,
  8988                          enums=enums, isStruct=True)
  8990     def deps(self):
  8991         return set()
  8994 class CGClassForwardDeclare(CGThing):
  8995     def __init__(self, name, isStruct=False):
  8996         CGThing.__init__(self)
  8997         self.name = name
  8998         self.isStruct = isStruct
  9000     def declare(self):
  9001         type = 'struct' if self.isStruct else 'class'
  9002         return '%s %s;\n' % (type, self.name)
  9004     def define(self):
  9005         # Header only
  9006         return ''
  9008     def deps(self):
  9009         return set()
  9012 class CGProxySpecialOperation(CGPerSignatureCall):
  9013     """
  9014     Base class for classes for calling an indexed or named special operation
  9015     (don't use this directly, use the derived classes below).
  9017     If checkFound is False, will just assert that the prop is found instead of
  9018     checking that it is before wrapping the value.
  9019     """
  9020     def __init__(self, descriptor, operation, checkFound=True, argumentMutableValue=None):
  9021         self.checkFound = checkFound
  9023         nativeName = MakeNativeName(descriptor.binaryNames.get(operation, operation))
  9024         operation = descriptor.operations[operation]
  9025         assert len(operation.signatures()) == 1
  9026         signature = operation.signatures()[0]
  9028         returnType, arguments = signature
  9030         # We pass len(arguments) as the final argument so that the
  9031         # CGPerSignatureCall won't do any argument conversion of its own.
  9032         CGPerSignatureCall.__init__(self, returnType, arguments, nativeName,
  9033                                     False, descriptor, operation,
  9034                                     len(arguments))
  9036         if operation.isSetter() or operation.isCreator():
  9037             # arguments[0] is the index or name of the item that we're setting.
  9038             argument = arguments[1]
  9039             info = getJSToNativeConversionInfo(
  9040                 argument.type, descriptor,
  9041                 treatNullAs=argument.treatNullAs,
  9042                 sourceDescription=("value being assigned to %s setter" %
  9043                                    descriptor.interface.identifier.name))
  9044             if argumentMutableValue is None:
  9045                 argumentMutableValue = "desc.value()"
  9046             templateValues = {
  9047                 "declName": argument.identifier.name,
  9048                 "holderName": argument.identifier.name + "_holder",
  9049                 "val": argumentMutableValue,
  9050                 "mutableVal": argumentMutableValue,
  9051                 "obj": "obj"
  9053             self.cgRoot.prepend(instantiateJSToNativeConversion(info, templateValues))
  9054         elif operation.isGetter() or operation.isDeleter():
  9055             self.cgRoot.prepend(CGGeneric("bool found;\n"))
  9057     def getArguments(self):
  9058         args = [(a, a.identifier.name) for a in self.arguments]
  9059         if self.idlNode.isGetter() or self.idlNode.isDeleter():
  9060             args.append((FakeArgument(BuiltinTypes[IDLBuiltinType.Types.boolean],
  9061                                       self.idlNode),
  9062                          "found"))
  9063         return args
  9065     def wrap_return_value(self):
  9066         if not self.idlNode.isGetter() or self.templateValues is None:
  9067             return ""
  9069         wrap = CGGeneric(wrapForType(self.returnType, self.descriptor, self.templateValues))
  9070         if self.checkFound:
  9071             wrap = CGIfWrapper(wrap, "found")
  9072         else:
  9073             wrap = CGList([CGGeneric("MOZ_ASSERT(found);\n"), wrap])
  9074         return "\n" + wrap.define()
  9077 class CGProxyIndexedOperation(CGProxySpecialOperation):
  9078     """
  9079     Class to generate a call to an indexed operation.
  9081     If doUnwrap is False, the caller is responsible for making sure a variable
  9082     named 'self' holds the C++ object somewhere where the code we generate
  9083     will see it.
  9085     If checkFound is False, will just assert that the prop is found instead of
  9086     checking that it is before wrapping the value.
  9087     """
  9088     def __init__(self, descriptor, name, doUnwrap=True, checkFound=True,
  9089                 argumentMutableValue=None):
  9090         self.doUnwrap = doUnwrap
  9091         CGProxySpecialOperation.__init__(self, descriptor, name, checkFound,
  9092                                          argumentMutableValue=argumentMutableValue)
  9094     def define(self):
  9095         # Our first argument is the id we're getting.
  9096         argName = self.arguments[0].identifier.name
  9097         if argName == "index":
  9098             # We already have our index in a variable with that name
  9099             setIndex = ""
  9100         else:
  9101             setIndex = "uint32_t %s = index;\n" % argName
  9102         if self.doUnwrap:
  9103             unwrap = "%s* self = UnwrapProxy(proxy);\n" % self.descriptor.nativeType
  9104         else:
  9105             unwrap = ""
  9106         return (setIndex + unwrap +
  9107                 CGProxySpecialOperation.define(self))
  9110 class CGProxyIndexedGetter(CGProxyIndexedOperation):
  9111     """
  9112     Class to generate a call to an indexed getter. If templateValues is not None
  9113     the returned value will be wrapped with wrapForType using templateValues.
  9115     If doUnwrap is False, the caller is responsible for making sure a variable
  9116     named 'self' holds the C++ object somewhere where the code we generate
  9117     will see it.
  9119     If checkFound is False, will just assert that the prop is found instead of
  9120     checking that it is before wrapping the value.
  9121     """
  9122     def __init__(self, descriptor, templateValues=None, doUnwrap=True,
  9123                  checkFound=True):
  9124         self.templateValues = templateValues
  9125         CGProxyIndexedOperation.__init__(self, descriptor, 'IndexedGetter',
  9126                                          doUnwrap, checkFound)
  9129 class CGProxyIndexedPresenceChecker(CGProxyIndexedGetter):
  9130     """
  9131     Class to generate a call that checks whether an indexed property exists.
  9133     For now, we just delegate to CGProxyIndexedGetter
  9134     """
  9135     def __init__(self, descriptor):
  9136         CGProxyIndexedGetter.__init__(self, descriptor)
  9137         self.cgRoot.append(CGGeneric("(void)result;\n"))
  9140 class CGProxyIndexedSetter(CGProxyIndexedOperation):
  9141     """
  9142     Class to generate a call to an indexed setter.
  9143     """
  9144     def __init__(self, descriptor, argumentMutableValue=None):
  9145         CGProxyIndexedOperation.__init__(self, descriptor, 'IndexedSetter',
  9146                                          argumentMutableValue=argumentMutableValue)
  9149 class CGProxyIndexedDeleter(CGProxyIndexedOperation):
  9150     """
  9151     Class to generate a call to an indexed deleter.
  9152     """
  9153     def __init__(self, descriptor):
  9154         CGProxyIndexedOperation.__init__(self, descriptor, 'IndexedDeleter')
  9157 class CGProxyNamedOperation(CGProxySpecialOperation):
  9158     """
  9159     Class to generate a call to a named operation.
  9161     'value' is the jsval to use for the name; None indicates that it should be
  9162     gotten from the property id.
  9163     """
  9164     def __init__(self, descriptor, name, value=None, argumentMutableValue=None):
  9165         CGProxySpecialOperation.__init__(self, descriptor, name,
  9166                                          argumentMutableValue=argumentMutableValue)
  9167         self.value = value
  9169     def define(self):
  9170         # Our first argument is the id we're getting.
  9171         argName = self.arguments[0].identifier.name
  9172         if argName == "id":
  9173             # deal with the name collision
  9174             idDecl = "JS::Rooted<jsid> id_(cx, id);\n"
  9175             idName = "id_"
  9176         else:
  9177             idDecl = ""
  9178             idName = "id"
  9179         unwrapString = fill(
  9180             """
  9181             if (!ConvertJSValueToString(cx, nameVal, &nameVal,
  9182                                         eStringify, eStringify, ${argName})) {
  9183               return false;
  9185             """,
  9186             argName=argName)
  9187         if self.value is None:
  9188             # We're just using 'id', and if it's an atom we can take a
  9189             # fast path here.
  9190             unwrapString = fill(
  9191                 """
  9192                 if (MOZ_LIKELY(JSID_IS_ATOM(${idName}))) {
  9193                   ${argName}.SetData(js::GetAtomChars(JSID_TO_ATOM(${idName})), js::GetAtomLength(JSID_TO_ATOM(${idName})));
  9194                 } else {
  9195                   nameVal = js::IdToValue(${idName});
  9196                   $*{unwrapString}
  9198                 """,
  9199                 idName=idName,
  9200                 argName=argName,
  9201                 unwrapString=unwrapString)
  9202         else:
  9203             unwrapString = ("nameVal = %s;\n" % self.value) + unwrapString
  9205         # Sadly, we have to set up nameVal even if we have an atom id,
  9206         # because we don't know for sure, and we can end up needing it
  9207         # so it needs to be higher up the stack.  Using a Maybe here
  9208         # seems like probable overkill.
  9209         return fill(
  9210             """
  9211             JS::Rooted<JS::Value> nameVal(cx);
  9212             $*{idDecl}
  9213             binding_detail::FakeDependentString ${argName};
  9214             $*{unwrapString}
  9216             ${nativeType}* self = UnwrapProxy(proxy);
  9217             $*{op}
  9218             """,
  9219             idDecl=idDecl,
  9220             argName=argName,
  9221             unwrapString=unwrapString,
  9222             nativeType=self.descriptor.nativeType,
  9223             op=CGProxySpecialOperation.define(self))
  9226 class CGProxyNamedGetter(CGProxyNamedOperation):
  9227     """
  9228     Class to generate a call to an named getter. If templateValues is not None
  9229     the returned value will be wrapped with wrapForType using templateValues.
  9230     'value' is the jsval to use for the name; None indicates that it should be
  9231     gotten from the property id.
  9232     """
  9233     def __init__(self, descriptor, templateValues=None, value=None):
  9234         self.templateValues = templateValues
  9235         CGProxyNamedOperation.__init__(self, descriptor, 'NamedGetter', value)
  9238 class CGProxyNamedPresenceChecker(CGProxyNamedGetter):
  9239     """
  9240     Class to generate a call that checks whether a named property exists.
  9242     For now, we just delegate to CGProxyNamedGetter
  9243     """
  9244     def __init__(self, descriptor):
  9245         CGProxyNamedGetter.__init__(self, descriptor)
  9246         self.cgRoot.append(CGGeneric("(void)result;\n"))
  9249 class CGProxyNamedSetter(CGProxyNamedOperation):
  9250     """
  9251     Class to generate a call to a named setter.
  9252     """
  9253     def __init__(self, descriptor, argumentMutableValue=None):
  9254         CGProxyNamedOperation.__init__(self, descriptor, 'NamedSetter',
  9255                                        argumentMutableValue=argumentMutableValue)
  9258 class CGProxyNamedDeleter(CGProxyNamedOperation):
  9259     """
  9260     Class to generate a call to a named deleter.
  9261     """
  9262     def __init__(self, descriptor):
  9263         CGProxyNamedOperation.__init__(self, descriptor, 'NamedDeleter')
  9266 class CGProxyIsProxy(CGAbstractMethod):
  9267     def __init__(self, descriptor):
  9268         args = [Argument('JSObject*', 'obj')]
  9269         CGAbstractMethod.__init__(self, descriptor, "IsProxy", "bool", args, alwaysInline=True)
  9271     def declare(self):
  9272         return ""
  9274     def definition_body(self):
  9275         return "  return js::IsProxy(obj) && js::GetProxyHandler(obj) == DOMProxyHandler::getInstance();\n"
  9278 class CGProxyUnwrap(CGAbstractMethod):
  9279     def __init__(self, descriptor):
  9280         args = [Argument('JSObject*', 'obj')]
  9281         CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy", descriptor.nativeType + '*', args, alwaysInline=True)
  9283     def declare(self):
  9284         return ""
  9286     def definition_body(self):
  9287         return indent(fill(
  9288             """
  9289             MOZ_ASSERT(js::IsProxy(obj));
  9290             if (js::GetProxyHandler(obj) != DOMProxyHandler::getInstance()) {
  9291               MOZ_ASSERT(xpc::WrapperFactory::IsXrayWrapper(obj));
  9292               obj = js::UncheckedUnwrap(obj);
  9294             MOZ_ASSERT(IsProxy(obj));
  9295             return static_cast<${type}*>(js::GetProxyPrivate(obj).toPrivate());
  9296             """,
  9297             type=self.descriptor.nativeType))
  9300 class CGDOMJSProxyHandler_getOwnPropDescriptor(ClassMethod):
  9301     def __init__(self, descriptor):
  9302         args = [Argument('JSContext*', 'cx'),
  9303                 Argument('JS::Handle<JSObject*>', 'proxy'),
  9304                 Argument('JS::Handle<jsid>', 'id'),
  9305                 Argument('bool', 'ignoreNamedProps'),
  9306                 Argument('JS::MutableHandle<JSPropertyDescriptor>', 'desc')]
  9307         ClassMethod.__init__(self, "getOwnPropDescriptor", "bool", args,
  9308                              virtual=True, override=True)
  9309         self.descriptor = descriptor
  9311     def getBody(self):
  9312         indexedGetter = self.descriptor.operations['IndexedGetter']
  9313         indexedSetter = self.descriptor.operations['IndexedSetter']
  9315         if self.descriptor.supportsIndexedProperties():
  9316             readonly = toStringBool(indexedSetter is None)
  9317             fillDescriptor = "FillPropertyDescriptor(desc, proxy, %s);\nreturn true;\n" % readonly
  9318             templateValues = {
  9319                 'jsvalRef': 'desc.value()',
  9320                 'jsvalHandle': 'desc.value()',
  9321                 'obj': 'proxy',
  9322                 'successCode': fillDescriptor
  9324             getIndexed = fill(
  9325                 """
  9326                 int32_t index = GetArrayIndexFromId(cx, id);
  9327                 if (IsArrayIndex(index)) {
  9328                   $*{callGetter}
  9331                 """,
  9332                 callGetter=CGProxyIndexedGetter(self.descriptor, templateValues).define())
  9333         else:
  9334             getIndexed = ""
  9336         if UseHolderForUnforgeable(self.descriptor):
  9337             tryHolder = dedent("""
  9338                 if (!JS_GetPropertyDescriptorById(cx, ${holder}, id, desc)) {
  9339                   return false;
  9341                 MOZ_ASSERT_IF(desc.object(), desc.object() == ${holder});
  9342                 """)
  9344             # We don't want to look at the unforgeable holder at all
  9345             # in the xray case; that part got handled already.
  9346             getUnforgeable = fill(
  9347                 """
  9348                 if (!isXray) {
  9349                   $*{callOnUnforgeable}
  9350                   if (desc.object()) {
  9351                     desc.object().set(proxy);
  9352                     return true;
  9356                 """,
  9357                 callOnUnforgeable=CallOnUnforgeableHolder(self.descriptor, tryHolder))
  9358         else:
  9359             getUnforgeable = ""
  9361         if self.descriptor.supportsNamedProperties():
  9362             operations = self.descriptor.operations
  9363             readonly = toStringBool(operations['NamedSetter'] is None)
  9364             enumerable = (
  9365                 "self->NameIsEnumerable(Constify(%s))" %
  9366                 # First [0] means first (and only) signature, [1] means
  9367                 # "arguments" as opposed to return type, [0] means first (and
  9368                 # only) argument.
  9369                 operations['NamedGetter'].signatures()[0][1][0].identifier.name)
  9370             fillDescriptor = (
  9371                 "FillPropertyDescriptor(desc, proxy, %s, %s);\n"
  9372                 "return true;\n" % (readonly, enumerable))
  9373             templateValues = {'jsvalRef': 'desc.value()', 'jsvalHandle': 'desc.value()',
  9374                               'obj': 'proxy', 'successCode': fillDescriptor}
  9375             condition = "!HasPropertyOnPrototype(cx, proxy, id)"
  9376             if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
  9377                 condition = "(!isXray || %s)" % condition
  9378             condition = "!ignoreNamedProps && " + condition
  9379             if self.descriptor.supportsIndexedProperties():
  9380                 condition = "!IsArrayIndex(index) && " + condition
  9381             namedGet = (CGIfWrapper(CGProxyNamedGetter(self.descriptor, templateValues),
  9382                                     condition).define() +
  9383                         "\n")
  9384         else:
  9385             namedGet = ""
  9387         return fill(
  9388             """
  9389             bool isXray = xpc::WrapperFactory::IsXrayWrapper(proxy);
  9390             $*{getIndexed}
  9391             $*{getUnforgeable}
  9392             JS::Rooted<JSObject*> expando(cx);
  9393             if (!isXray && (expando = GetExpandoObject(proxy))) {
  9394               if (!JS_GetPropertyDescriptorById(cx, expando, id, desc)) {
  9395                 return false;
  9397               if (desc.object()) {
  9398                 // Pretend the property lives on the wrapper.
  9399                 desc.object().set(proxy);
  9400                 return true;
  9404             $*{namedGet}
  9405             desc.object().set(nullptr);
  9406             return true;
  9407             """,
  9408             getIndexed=getIndexed,
  9409             getUnforgeable=getUnforgeable,
  9410             namedGet=namedGet)
  9413 class CGDOMJSProxyHandler_defineProperty(ClassMethod):
  9414     def __init__(self, descriptor):
  9415         args = [Argument('JSContext*', 'cx'),
  9416                 Argument('JS::Handle<JSObject*>', 'proxy'),
  9417                 Argument('JS::Handle<jsid>', 'id'),
  9418                 Argument('JS::MutableHandle<JSPropertyDescriptor>', 'desc'),
  9419                 Argument('bool*', 'defined')]
  9420         ClassMethod.__init__(self, "defineProperty", "bool", args, virtual=True, override=True)
  9421         self.descriptor = descriptor
  9423     def getBody(self):
  9424         set = ""
  9426         indexedSetter = self.descriptor.operations['IndexedSetter']
  9427         if indexedSetter:
  9428             if self.descriptor.operations['IndexedCreator'] is not indexedSetter:
  9429                 raise TypeError("Can't handle creator that's different from the setter")
  9430             set += fill(
  9431                 """
  9432                 int32_t index = GetArrayIndexFromId(cx, id);
  9433                 if (IsArrayIndex(index)) {
  9434                   *defined = true;
  9435                   $*{callSetter}
  9436                   return true;
  9438                 """,
  9439                 callSetter=CGProxyIndexedSetter(self.descriptor).define())
  9440         elif self.descriptor.supportsIndexedProperties():
  9441             set += fill(
  9442                 """
  9443                 if (IsArrayIndex(GetArrayIndexFromId(cx, id))) {
  9444                   return js::IsInNonStrictPropertySet(cx) || ThrowErrorMessage(cx, MSG_NO_INDEXED_SETTER, "${name}");
  9446                 """,
  9447                 name=self.descriptor.name)
  9449         if UseHolderForUnforgeable(self.descriptor):
  9450             defineOnUnforgeable = ("bool hasUnforgeable;\n"
  9451                                    "if (!JS_HasPropertyById(cx, ${holder}, id, &hasUnforgeable)) {\n"
  9452                                    "  return false;\n"
  9453                                    "}\n"
  9454                                    "if (hasUnforgeable) {\n"
  9455                                    "  *defined = true;"  # SUPER BOGUS missing newline
  9456                                    "  bool unused;\n"
  9457                                    "  return js_DefineOwnProperty(cx, ${holder}, id, desc, &unused);\n"
  9458                                    "}\n"
  9459                                    "\n")  # BOGUS extra blank line at end of block or method
  9460             set += CallOnUnforgeableHolder(self.descriptor,
  9461                                            defineOnUnforgeable,
  9462                                            "xpc::WrapperFactory::IsXrayWrapper(proxy)")
  9464         namedSetter = self.descriptor.operations['NamedSetter']
  9465         if namedSetter:
  9466             if self.descriptor.operations['NamedCreator'] is not namedSetter:
  9467                 raise TypeError("Can't handle creator that's different from the setter")
  9468             # If we support indexed properties, we won't get down here for
  9469             # indices, so we can just do our setter unconditionally here.
  9470             set += fill(
  9471                 """
  9472                 *defined = true;
  9473                 $*{callSetter}
  9475                 return true;
  9477                 """,  # BOGUS extra blank line at end of method
  9478                 callSetter=CGProxyNamedSetter(self.descriptor).define())
  9479         else:
  9480             if self.descriptor.supportsNamedProperties():
  9481                 set += fill(
  9482                     """
  9483                     $*{presenceChecker}
  9485                     if (found) {
  9486                       return js::IsInNonStrictPropertySet(cx) || ThrowErrorMessage(cx, MSG_NO_NAMED_SETTER, "${name}");
  9488                     """,
  9489                     presenceChecker=CGProxyNamedPresenceChecker(self.descriptor).define(),
  9490                     name=self.descriptor.name)
  9491             set += ("return mozilla::dom::DOMProxyHandler::defineProperty(%s);\n" %
  9492                     ", ".join(a.name for a in self.args))
  9493         return set
  9496 class CGDOMJSProxyHandler_delete(ClassMethod):
  9497     def __init__(self, descriptor):
  9498         args = [Argument('JSContext*', 'cx'),
  9499                 Argument('JS::Handle<JSObject*>', 'proxy'),
  9500                 Argument('JS::Handle<jsid>', 'id'),
  9501                 Argument('bool*', 'bp')]
  9502         ClassMethod.__init__(self, "delete_", "bool", args,
  9503                              virtual=True, override=True)
  9504         self.descriptor = descriptor
  9506     def getBody(self):
  9507         def getDeleterBody(type):
  9508             """
  9509             type should be "Named" or "Indexed"
  9510             """
  9511             assert type in ("Named", "Indexed")
  9512             deleter = self.descriptor.operations[type + 'Deleter']
  9513             if deleter:
  9514                 if (not deleter.signatures()[0][0].isPrimitive() or
  9515                     deleter.signatures()[0][0].nullable() or
  9516                     deleter.signatures()[0][0].tag() != IDLType.Tags.bool):
  9517                     setBp = "*bp = true;\n"
  9518                 else:
  9519                     setBp = dedent("""
  9520                         if (found) {
  9521                           *bp = result;
  9522                         } else {
  9523                           *bp = true;
  9525                         """)
  9526                 body = (eval("CGProxy%sDeleter" % type)(self.descriptor).define() +
  9527                         setBp)
  9528             elif eval("self.descriptor.supports%sProperties()" % type):
  9529                 body = (eval("CGProxy%sPresenceChecker" % type)(self.descriptor).define() +
  9530                         dedent("""
  9531                             if (found) {
  9532                               *bp = false;
  9533                             } else {
  9534                               *bp = true;
  9536                             """))
  9537             else:
  9538                 body = None
  9539             return body
  9541         delete = dedent("""
  9542             MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
  9543                       "Should not have a XrayWrapper here");
  9545             """)
  9547         indexedBody = getDeleterBody("Indexed")
  9548         if indexedBody is not None:
  9549             delete += fill(
  9550                 """
  9551                 int32_t index = GetArrayIndexFromId(cx, id);
  9552                 if (IsArrayIndex(index)) {
  9553                   $*{indexedBody}
  9554                   // We always return here, even if the property was not found
  9555                   return true;
  9557                 """,
  9558                 indexedBody=indexedBody)
  9560         if UseHolderForUnforgeable(self.descriptor):
  9561             unforgeable = dedent("""
  9562                 bool hasUnforgeable;
  9563                 if (!JS_HasPropertyById(cx, ${holder}, id, &hasUnforgeable)) {
  9564                   return false;
  9566                 if (hasUnforgeable) {
  9567                   *bp = false;
  9568                   return true;
  9570                 """)
  9571             delete += CallOnUnforgeableHolder(self.descriptor, unforgeable)
  9572             delete += "\n"
  9574         namedBody = getDeleterBody("Named")
  9575         if namedBody is not None:
  9576             # We always return above for an index id in the case when we support
  9577             # indexed properties, so we can just treat the id as a name
  9578             # unconditionally here.
  9579             delete += (namedBody +
  9580                        "if (found) {\n"
  9581                        "  return true;\n"
  9582                        "}\n\n")  # BOGUS extra blank line
  9583             if not self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
  9584                 delete = CGIfWrapper(CGGeneric(delete),
  9585                                      "!HasPropertyOnPrototype(cx, proxy, id)").define()
  9586         else:
  9587             delete += "\n"  # BOGUS extra blank line
  9589         delete += dedent("""
  9591             return dom::DOMProxyHandler::delete_(cx, proxy, id, bp);
  9592             """)
  9594         return delete
  9597 class CGDOMJSProxyHandler_ownPropNames(ClassMethod):
  9598     def __init__(self, descriptor, ):
  9599         args = [Argument('JSContext*', 'cx'),
  9600                 Argument('JS::Handle<JSObject*>', 'proxy'),
  9601                 Argument('unsigned', 'flags'),
  9602                 Argument('JS::AutoIdVector&', 'props')]
  9603         ClassMethod.__init__(self, "ownPropNames", "bool", args,
  9604                              virtual=True, override=True)
  9605         self.descriptor = descriptor
  9607     def getBody(self):
  9608         # Per spec, we do indices, then named props, then everything else
  9609         if self.descriptor.supportsIndexedProperties():
  9610             addIndices = dedent("""
  9612                 uint32_t length = UnwrapProxy(proxy)->Length();
  9613                 MOZ_ASSERT(int32_t(length) >= 0);
  9614                 for (int32_t i = 0; i < int32_t(length); ++i) {
  9615                   if (!props.append(INT_TO_JSID(i))) {
  9616                     return false;
  9619                 """)
  9620         else:
  9621             addIndices = ""
  9623         if UseHolderForUnforgeable(self.descriptor):
  9624             addUnforgeable = dedent("""
  9625                 if (!js::GetPropertyNames(cx, ${holder}, flags, &props)) {
  9626                   return false;
  9628                 """)
  9629             addUnforgeable = CallOnUnforgeableHolder(self.descriptor,
  9630                                                      addUnforgeable,
  9631                                                      "isXray")
  9632         else:
  9633             addUnforgeable = ""
  9635         if self.descriptor.supportsNamedProperties():
  9636             if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
  9637                 shadow = "!isXray"
  9638             else:
  9639                 shadow = "false"
  9640             addNames = fill(
  9641                 """
  9643                 nsTArray<nsString> names;
  9644                 UnwrapProxy(proxy)->GetSupportedNames(flags, names);
  9645                 if (!AppendNamedPropertyIds(cx, proxy, names, ${shadow}, props)) {
  9646                   return false;
  9648                 """,
  9649                 shadow=shadow)
  9650         else:
  9651             addNames = ""
  9653         return fill(
  9654             """
  9655             bool isXray = xpc::WrapperFactory::IsXrayWrapper(proxy);
  9656             $*{addIndices}
  9657             $*{addUnforgeable}
  9658             $*{addNames}
  9660             JS::Rooted<JSObject*> expando(cx);
  9661             if (!isXray && (expando = DOMProxyHandler::GetExpandoObject(proxy)) &&
  9662                 !js::GetPropertyNames(cx, expando, flags, &props)) {
  9663               return false;
  9666             return true;
  9667             """,
  9668             addIndices=addIndices,
  9669             addUnforgeable=addUnforgeable,
  9670             addNames=addNames)
  9673 class CGDOMJSProxyHandler_hasOwn(ClassMethod):
  9674     def __init__(self, descriptor):
  9675         args = [Argument('JSContext*', 'cx'),
  9676                 Argument('JS::Handle<JSObject*>', 'proxy'),
  9677                 Argument('JS::Handle<jsid>', 'id'),
  9678                 Argument('bool*', 'bp')]
  9679         ClassMethod.__init__(self, "hasOwn", "bool", args,
  9680                              virtual=True, override=True)
  9681         self.descriptor = descriptor
  9683     def getBody(self):
  9684         if self.descriptor.supportsIndexedProperties():
  9685             indexed = fill(
  9686                 """
  9687                 int32_t index = GetArrayIndexFromId(cx, id);
  9688                 if (IsArrayIndex(index)) {
  9689                   $*{presenceChecker}
  9691                   *bp = found;
  9692                   return true;
  9695                 """,
  9696                 presenceChecker=CGProxyIndexedPresenceChecker(self.descriptor).define())
  9697         else:
  9698             indexed = ""
  9700         if UseHolderForUnforgeable(self.descriptor):
  9701             unforgeable = dedent("""
  9702                 bool b = true;
  9703                 bool ok = JS_AlreadyHasOwnPropertyById(cx, ${holder}, id, &b);
  9704                 *bp = !!b;
  9705                 if (!ok || *bp) {
  9706                   return ok;
  9708                 """)
  9709             unforgeable = CallOnUnforgeableHolder(self.descriptor, unforgeable)
  9710         else:
  9711             unforgeable = ""
  9713         if self.descriptor.supportsNamedProperties():
  9714             # If we support indexed properties we always return above for index
  9715             # property names, so no need to check for those here.
  9716             named = (CGProxyNamedPresenceChecker(self.descriptor).define() +
  9717                      "\n" +
  9718                      "*bp = found;\n")
  9719             if not self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
  9720                 # BOGUS extra blank line at end of block
  9721                 named = CGIfWrapper(CGGeneric(named + "return true;\n\n"),
  9722                                     "!HasPropertyOnPrototype(cx, proxy, id)").define()
  9723                 named += "*bp = false;\n"
  9724             else:
  9725                 named += "\n"
  9726         else:
  9727             named = "*bp = false;\n"
  9729         return fill(
  9730             """
  9731             MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
  9732                       "Should not have a XrayWrapper here");
  9734             $*{indexed}
  9735             $*{unforgeable}
  9737             JS::Rooted<JSObject*> expando(cx, GetExpandoObject(proxy));
  9738             if (expando) {
  9739               bool b = true;
  9740               bool ok = JS_HasPropertyById(cx, expando, id, &b);
  9741               *bp = !!b;
  9742               if (!ok || *bp) {
  9743                 return ok;
  9747             $*{named}
  9748             return true;
  9749             """,
  9750             indexed=indexed,
  9751             unforgeable=unforgeable,
  9752             named=named)
  9755 class CGDOMJSProxyHandler_get(ClassMethod):
  9756     def __init__(self, descriptor):
  9757         args = [Argument('JSContext*', 'cx'),
  9758                 Argument('JS::Handle<JSObject*>', 'proxy'),
  9759                 Argument('JS::Handle<JSObject*>', 'receiver'),
  9760                 Argument('JS::Handle<jsid>', 'id'),
  9761                 Argument('JS::MutableHandle<JS::Value>', 'vp')]
  9762         ClassMethod.__init__(self, "get", "bool", args,
  9763                              virtual=True, override=True)
  9764         self.descriptor = descriptor
  9766     def getBody(self):
  9767         getUnforgeableOrExpando = "JS::Rooted<JSObject*> sharedRoot(cx);\n"
  9768         if UseHolderForUnforgeable(self.descriptor):
  9769             hasUnforgeable = dedent("""
  9770                 bool hasUnforgeable;
  9771                 if (!JS_AlreadyHasOwnPropertyById(cx, ${holder}, id, &hasUnforgeable)) {
  9772                   return false;
  9774                 if (hasUnforgeable) {
  9775                   return JS_ForwardGetPropertyTo(cx, ${holder}, id, proxy, vp);
  9777                 """)
  9778             getUnforgeableOrExpando += CallOnUnforgeableHolder(self.descriptor,
  9779                                                                hasUnforgeable,
  9780                                                                useSharedRoot=True)
  9781         getUnforgeableOrExpando += dedent("""
  9782             { // Scope for expando
  9783               JS::Rooted<JSObject*>& expando(sharedRoot);
  9784               expando = DOMProxyHandler::GetExpandoObject(proxy);
  9785               if (expando) {
  9786                 bool hasProp;
  9787                 if (!JS_HasPropertyById(cx, expando, id, &hasProp)) {
  9788                   return false;
  9791                 if (hasProp) {
  9792                   // Forward the get to the expando object, but our receiver is whatever our
  9793                   // receiver is.
  9794                   return JS_ForwardGetPropertyTo(cx, expando, id, receiver, vp);
  9798             """)
  9800         templateValues = {'jsvalRef': 'vp', 'jsvalHandle': 'vp', 'obj': 'proxy'}
  9802         if self.descriptor.supportsIndexedProperties():
  9803             getIndexedOrExpando = fill(
  9804                 """
  9805                 int32_t index = GetArrayIndexFromId(cx, id);
  9806                 if (IsArrayIndex(index)) {
  9807                   $*{callGetter}
  9808                   // Even if we don't have this index, we don't forward the
  9809                   // get on to our expando object.
  9810                 } else {
  9811                   $*{getUnforgeableOrExpando}
  9813                 """,
  9814                 callGetter=CGProxyIndexedGetter(self.descriptor, templateValues).define(),
  9815                 getUnforgeableOrExpando=getUnforgeableOrExpando)
  9816         else:
  9817             getIndexedOrExpando = getUnforgeableOrExpando
  9819         if self.descriptor.supportsNamedProperties():
  9820             getNamed = CGProxyNamedGetter(self.descriptor, templateValues)
  9821             if self.descriptor.supportsIndexedProperties():
  9822                 getNamed = CGIfWrapper(getNamed, "!IsArrayIndex(index)")
  9823             getNamed = getNamed.define() + "\n"
  9824         else:
  9825             getNamed = ""
  9827         getOnPrototype = dedent("""
  9828             bool foundOnPrototype;
  9829             if (!GetPropertyOnPrototype(cx, proxy, id, &foundOnPrototype, vp.address())) {
  9830               return false;
  9833             if (foundOnPrototype) {
  9834               return true;
  9837             """)
  9838         if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
  9839             getNamed = getNamed + getOnPrototype
  9840         else:
  9841             getNamed = getOnPrototype + getNamed
  9843         return fill(
  9844             """
  9845             MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
  9846                         "Should not have a XrayWrapper here");
  9848             $*{indexedOrExpando}
  9850             $*{named}
  9851             vp.setUndefined();
  9852             return true;
  9853             """,
  9854             indexedOrExpando=getIndexedOrExpando,
  9855             named=getNamed)
  9858 class CGDOMJSProxyHandler_setCustom(ClassMethod):
  9859     def __init__(self, descriptor):
  9860         args = [Argument('JSContext*', 'cx'),
  9861                 Argument('JS::Handle<JSObject*>', 'proxy'),
  9862                 Argument('JS::Handle<jsid>', 'id'),
  9863                 Argument('JS::MutableHandle<JS::Value>', 'vp'),
  9864                 Argument('bool*', 'done')]
  9865         ClassMethod.__init__(self, "setCustom", "bool", args, virtual=True, override=True)
  9866         self.descriptor = descriptor
  9868     def getBody(self):
  9869         assertion = ("MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),\n"
  9870                      '           "Should not have a XrayWrapper here");\n')
  9872         # Correctness first. If we have a NamedSetter and [OverrideBuiltins],
  9873         # always call the NamedSetter and never do anything else.
  9874         namedSetter = self.descriptor.operations['NamedSetter']
  9875         if (namedSetter is not None and
  9876             self.descriptor.interface.getExtendedAttribute('OverrideBuiltins')):
  9877             # Check assumptions.
  9878             if self.descriptor.supportsIndexedProperties():
  9879                 raise ValueError("In interface " + self.descriptor.name + ": " +
  9880                                  "Can't cope with [OverrideBuiltins] and an indexed getter")
  9881             if self.descriptor.operations['NamedCreator'] is not namedSetter:
  9882                 raise ValueError("In interface " + self.descriptor.name + ": " +
  9883                                  "Can't cope with named setter that is not also a named creator")
  9884             if UseHolderForUnforgeable(self.descriptor):
  9885                 raise ValueError("In interface " + self.descriptor.name + ": " +
  9886                                  "Can't cope with [OverrideBuiltins] and unforgeable members")
  9888             callSetter = CGProxyNamedSetter(self.descriptor, argumentMutableValue="vp")
  9889             return (assertion +
  9890                     callSetter.define() +
  9891                     "*done = true;\n"
  9892                     "return true;\n")
  9894         # As an optimization, if we are going to call an IndexedSetter, go
  9895         # ahead and call it and have done.
  9896         indexedSetter = self.descriptor.operations['IndexedSetter']
  9897         if indexedSetter is not None:
  9898             if self.descriptor.operations['IndexedCreator'] is not indexedSetter:
  9899                 raise ValueError("In interface " + self.descriptor.name + ": " +
  9900                                  "Can't cope with indexed setter that is not " +
  9901                                  "also an indexed creator")
  9902             setIndexed = fill(
  9903                 """
  9904                 int32_t index = GetArrayIndexFromId(cx, id);
  9905                 if (IsArrayIndex(index)) {
  9906                   $*{callSetter}
  9907                   *done = true;
  9908                   return true;
  9911                 """,
  9912                 callSetter=CGProxyIndexedSetter(self.descriptor,
  9913                                                 argumentMutableValue="vp").define())
  9914         else:
  9915             setIndexed = ""
  9917         return (assertion +
  9918                 setIndexed +
  9919                 "*done = false;\n"
  9920                 "return true;\n")
  9923 class CGDOMJSProxyHandler_className(ClassMethod):
  9924     def __init__(self, descriptor):
  9925         args = [Argument('JSContext*', 'cx'),
  9926                 Argument('JS::Handle<JSObject*>', 'proxy')]
  9927         ClassMethod.__init__(self, "className", "const char*", args,
  9928                              virtual=True, override=True)
  9929         self.descriptor = descriptor
  9931     def getBody(self):
  9932         return 'return "%s";\n' % self.descriptor.name
  9935 class CGDOMJSProxyHandler_finalizeInBackground(ClassMethod):
  9936     def __init__(self, descriptor):
  9937         args = [Argument('JS::Value', 'priv')]
  9938         ClassMethod.__init__(self, "finalizeInBackground", "bool", args,
  9939                              virtual=True, override=True)
  9940         self.descriptor = descriptor
  9942     def getBody(self):
  9943         return "return false;\n"
  9946 class CGDOMJSProxyHandler_finalize(ClassMethod):
  9947     def __init__(self, descriptor):
  9948         args = [Argument('JSFreeOp*', 'fop'), Argument('JSObject*', 'proxy')]
  9949         ClassMethod.__init__(self, "finalize", "void", args,
  9950                              virtual=True, override=True)
  9951         self.descriptor = descriptor
  9953     def getBody(self):
  9954         return ("%s* self = UnwrapProxy(proxy);\n\n" % self.descriptor.nativeType +
  9955                 finalizeHook(self.descriptor, FINALIZE_HOOK_NAME, self.args[0].name).define())
  9958 class CGDOMJSProxyHandler_slice(ClassMethod):
  9959     def __init__(self, descriptor):
  9960         assert descriptor.supportsIndexedProperties()
  9962         args = [Argument('JSContext*', 'cx'),
  9963                 Argument('JS::Handle<JSObject*>', 'proxy'),
  9964                 Argument('uint32_t', 'begin'),
  9965                 Argument('uint32_t', 'end'),
  9966                 Argument('JS::Handle<JSObject*>', 'array')]
  9967         ClassMethod.__init__(self, "slice", "bool", args, virtual=True, override=True)
  9968         self.descriptor = descriptor
  9970     def getBody(self):
  9971         # Just like getOwnPropertyNames we'll assume that we have no holes, so
  9972         # we have all properties from 0 to length.  If that ever changes
  9973         # (unlikely), we'll need to do something a bit more clever with how we
  9974         # forward on to our ancestor.
  9976         templateValues = {
  9977             'jsvalRef': 'temp',
  9978             'jsvalHandle': '&temp',
  9979             'obj': 'proxy',
  9980             'successCode': ("js::UnsafeDefineElement(cx, array, index - begin, temp);\n"
  9981                             "continue;\n")
  9983         get = CGProxyIndexedGetter(self.descriptor, templateValues, False, False).define()
  9985         return fill(
  9986             """
  9987             JS::Rooted<JS::Value> temp(cx);
  9988             MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
  9989                        "Should not have a XrayWrapper here");
  9991             ${nativeType}* self = UnwrapProxy(proxy);
  9992             uint32_t length = self->Length();
  9993             // Compute the end of the indices we'll get ourselves
  9994             uint32_t ourEnd = std::max(begin, std::min(end, length));
  9996             for (uint32_t index = begin; index < ourEnd; ++index) {
  9997               $*{get}
 10000             if (end > ourEnd) {
 10001               JS::Rooted<JSObject*> proto(cx);
 10002               if (!js::GetObjectProto(cx, proxy, &proto)) {
 10003                 return false;
 10005               return js::SliceSlowly(cx, proto, proxy, ourEnd, end, array);
 10008             return true;
 10009             """,
 10010             nativeType=self.descriptor.nativeType,
 10011             get=get)
 10014 class CGDOMJSProxyHandler_getInstance(ClassMethod):
 10015     def __init__(self):
 10016         ClassMethod.__init__(self, "getInstance", "DOMProxyHandler*", [], static=True)
 10018     def getBody(self):
 10019         return dedent("""
 10020             static DOMProxyHandler instance;
 10021             return &instance;
 10022             """)
 10025 class CGDOMJSProxyHandler(CGClass):
 10026     def __init__(self, descriptor):
 10027         assert (descriptor.supportsIndexedProperties() or
 10028                 descriptor.supportsNamedProperties())
 10029         methods = [CGDOMJSProxyHandler_getOwnPropDescriptor(descriptor),
 10030                    CGDOMJSProxyHandler_defineProperty(descriptor),
 10031                    ClassUsingDeclaration("mozilla::dom::DOMProxyHandler",
 10032                                          "defineProperty"),
 10033                    CGDOMJSProxyHandler_ownPropNames(descriptor),
 10034                    CGDOMJSProxyHandler_hasOwn(descriptor),
 10035                    CGDOMJSProxyHandler_get(descriptor),
 10036                    CGDOMJSProxyHandler_className(descriptor),
 10037                    CGDOMJSProxyHandler_finalizeInBackground(descriptor),
 10038                    CGDOMJSProxyHandler_finalize(descriptor),
 10039                    CGDOMJSProxyHandler_getInstance(),
 10040                    CGDOMJSProxyHandler_delete(descriptor)]
 10041         if descriptor.supportsIndexedProperties():
 10042             methods.append(CGDOMJSProxyHandler_slice(descriptor))
 10043         if (descriptor.operations['IndexedSetter'] is not None or
 10044             (descriptor.operations['NamedSetter'] is not None and
 10045              descriptor.interface.getExtendedAttribute('OverrideBuiltins'))):
 10046             methods.append(CGDOMJSProxyHandler_setCustom(descriptor))
 10048         CGClass.__init__(self, 'DOMProxyHandler',
 10049                          bases=[ClassBase('mozilla::dom::DOMProxyHandler')],
 10050                          methods=methods)
 10053 class CGDOMJSProxyHandlerDeclarer(CGThing):
 10054     """
 10055     A class for declaring a DOMProxyHandler.
 10056     """
 10057     def __init__(self, handlerThing):
 10058         self.handlerThing = handlerThing
 10060     def declare(self):
 10061         # Our class declaration should happen when we're defining
 10062         return ""
 10064     def define(self):
 10065         return self.handlerThing.declare()
 10068 class CGDOMJSProxyHandlerDefiner(CGThing):
 10069     """
 10070     A class for defining a DOMProxyHandler.
 10071     """
 10072     def __init__(self, handlerThing):
 10073         self.handlerThing = handlerThing
 10075     def declare(self):
 10076         return ""
 10078     def define(self):
 10079         return self.handlerThing.define()
 10082 def stripTrailingWhitespace(text):
 10083     tail = '\n' if text.endswith('\n') else ''
 10084     lines = text.splitlines()
 10085     return '\n'.join(line.rstrip() for line in lines) + tail
 10088 class CGDescriptor(CGThing):
 10089     def __init__(self, descriptor):
 10090         CGThing.__init__(self)
 10092         assert not descriptor.concrete or descriptor.interface.hasInterfacePrototypeObject()
 10094         if descriptor.nativeOwnership == 'owned' and (
 10095                 descriptor.interface.hasChildInterfaces() or
 10096                 descriptor.interface.parent):
 10097             raise TypeError("Owned interface cannot have a parent or children")
 10099         self._deps = descriptor.interface.getDeps()
 10101         cgThings = []
 10102         cgThings.append(CGGeneric(declare="typedef %s NativeType;\n" %
 10103                                   descriptor.nativeType))
 10104         # These are set to true if at least one non-static
 10105         # method/getter/setter or jsonifier exist on the interface.
 10106         (hasMethod, hasGetter, hasLenientGetter, hasSetter, hasJsonifier,
 10107             hasLenientSetter) = False, False, False, False, False, False
 10108         crossOriginMethods, crossOriginGetters, crossOriginSetters = set(), set(), set()
 10109         for n in descriptor.interface.namedConstructors:
 10110             cgThings.append(CGClassConstructor(descriptor, n,
 10111                                                NamedConstructorName(n)))
 10112         for m in descriptor.interface.members:
 10113             if m.isMethod() and m.identifier.name == 'queryInterface':
 10114                 continue
 10115             if m.isMethod() and m == descriptor.operations['Jsonifier']:
 10116                 hasJsonifier = True
 10117                 hasMethod = descriptor.needsSpecialGenericOps()
 10118                 jsonifierMethod = m
 10119             elif (m.isMethod() and
 10120                   (not m.isIdentifierLess() or m == descriptor.operations['Stringifier'])):
 10121                 if m.isStatic():
 10122                     assert descriptor.interface.hasInterfaceObject
 10123                     cgThings.append(CGStaticMethod(descriptor, m))
 10124                     if m.returnsPromise():
 10125                         cgThings.append(CGStaticMethodJitinfo(m))
 10126                 elif descriptor.interface.hasInterfacePrototypeObject():
 10127                     specializedMethod = CGSpecializedMethod(descriptor, m)
 10128                     cgThings.append(specializedMethod)
 10129                     if m.returnsPromise():
 10130                         cgThings.append(CGMethodPromiseWrapper(descriptor, specializedMethod))
 10131                     cgThings.append(CGMemberJITInfo(descriptor, m))
 10132                     if m.getExtendedAttribute("CrossOriginCallable"):
 10133                         crossOriginMethods.add(m.identifier.name)
 10134                     elif descriptor.needsSpecialGenericOps():
 10135                         hasMethod = True
 10136             elif m.isAttr():
 10137                 if m.stringifier:
 10138                     raise TypeError("Stringifier attributes not supported yet. "
 10139                                     "See bug 824857.\n"
 10140                                     "%s" % m.location)
 10141                 if m.isStatic():
 10142                     assert descriptor.interface.hasInterfaceObject
 10143                     cgThings.append(CGStaticGetter(descriptor, m))
 10144                 elif descriptor.interface.hasInterfacePrototypeObject():
 10145                     cgThings.append(CGSpecializedGetter(descriptor, m))
 10146                     if m.hasLenientThis():
 10147                         hasLenientGetter = True
 10148                     elif m.getExtendedAttribute("CrossOriginReadable"):
 10149                         crossOriginGetters.add(m.identifier.name)
 10150                     elif descriptor.needsSpecialGenericOps():
 10151                         hasGetter = True
 10152                 if not m.readonly:
 10153                     for extAttr in ["PutForwards", "Replaceable"]:
 10154                         if m.getExtendedAttribute(extAttr):
 10155                             raise TypeError("Writable attributes should not "
 10156                                             "have %s specified.\n"
 10157                                             "%s" %
 10158                                             (extAttr, m.location))
 10159                     if m.isStatic():
 10160                         assert descriptor.interface.hasInterfaceObject
 10161                         cgThings.append(CGStaticSetter(descriptor, m))
 10162                     elif descriptor.interface.hasInterfacePrototypeObject():
 10163                         cgThings.append(CGSpecializedSetter(descriptor, m))
 10164                         if m.hasLenientThis():
 10165                             hasLenientSetter = True
 10166                         elif m.getExtendedAttribute("CrossOriginWritable"):
 10167                             crossOriginSetters.add(m.identifier.name)
 10168                         elif descriptor.needsSpecialGenericOps():
 10169                             hasSetter = True
 10170                 elif m.getExtendedAttribute("PutForwards"):
 10171                     cgThings.append(CGSpecializedForwardingSetter(descriptor, m))
 10172                     if m.getExtendedAttribute("CrossOriginWritable"):
 10173                         crossOriginSetters.add(m.identifier.name)
 10174                     elif descriptor.needsSpecialGenericOps():
 10175                         hasSetter = True
 10176                 elif m.getExtendedAttribute("Replaceable"):
 10177                     cgThings.append(CGSpecializedReplaceableSetter(descriptor, m))
 10178                     if descriptor.needsSpecialGenericOps():
 10179                         hasSetter = True
 10180                 if (not m.isStatic() and
 10181                     descriptor.interface.hasInterfacePrototypeObject()):
 10182                     cgThings.append(CGMemberJITInfo(descriptor, m))
 10183         if hasJsonifier:
 10184             cgThings.append(CGJsonifierMethod(descriptor, jsonifierMethod))
 10185             cgThings.append(CGMemberJITInfo(descriptor, jsonifierMethod))
 10186         if hasMethod:
 10187             cgThings.append(CGGenericMethod(descriptor))
 10188         if len(crossOriginMethods):
 10189             cgThings.append(CGGenericMethod(descriptor,
 10190                                             allowCrossOriginThis=True))
 10191         if hasGetter:
 10192             cgThings.append(CGGenericGetter(descriptor))
 10193         if hasLenientGetter:
 10194             cgThings.append(CGGenericGetter(descriptor, lenientThis=True))
 10195         if len(crossOriginGetters):
 10196             cgThings.append(CGGenericGetter(descriptor,
 10197                                             allowCrossOriginThis=True))
 10198         if hasSetter:
 10199             cgThings.append(CGGenericSetter(descriptor))
 10200         if hasLenientSetter:
 10201             cgThings.append(CGGenericSetter(descriptor, lenientThis=True))
 10202         if len(crossOriginSetters):
 10203             cgThings.append(CGGenericSetter(descriptor,
 10204                                             allowCrossOriginThis=True))
 10206         if descriptor.interface.getNavigatorProperty():
 10207             cgThings.append(CGConstructNavigatorObjectHelper(descriptor))
 10208             cgThings.append(CGConstructNavigatorObject(descriptor))
 10210         if descriptor.concrete and not descriptor.proxy:
 10211             if wantsAddProperty(descriptor):
 10212                 cgThings.append(CGAddPropertyHook(descriptor))
 10214             # Always have a finalize hook, regardless of whether the class
 10215             # wants a custom hook.
 10216             cgThings.append(CGClassFinalizeHook(descriptor))
 10218         properties = PropertyArrays(descriptor)
 10219         cgThings.append(CGGeneric(define=str(properties)))
 10220         cgThings.append(CGNativeProperties(descriptor, properties))
 10222         # Set up our Xray callbacks as needed.  Note that we don't need to do
 10223         # it in workers.
 10224         if not descriptor.workers and descriptor.concrete and descriptor.proxy:
 10225             cgThings.append(CGResolveOwnProperty(descriptor))
 10226             cgThings.append(CGEnumerateOwnProperties(descriptor))
 10227         elif descriptor.needsXrayResolveHooks():
 10228             cgThings.append(CGResolveOwnPropertyViaNewresolve(descriptor))
 10229             cgThings.append(CGEnumerateOwnPropertiesViaGetOwnPropertyNames(descriptor))
 10231         # Now that we have our ResolveOwnProperty/EnumerateOwnProperties stuff
 10232         # done, set up our NativePropertyHooks.
 10233         cgThings.append(CGNativePropertyHooks(descriptor, properties))
 10235         if descriptor.interface.hasInterfaceObject():
 10236             cgThings.append(CGClassConstructor(descriptor,
 10237                                                descriptor.interface.ctor()))
 10238             cgThings.append(CGClassHasInstanceHook(descriptor))
 10239             cgThings.append(CGInterfaceObjectJSClass(descriptor, properties))
 10240             if descriptor.needsConstructHookHolder():
 10241                 cgThings.append(CGClassConstructHookHolder(descriptor))
 10242             cgThings.append(CGNamedConstructors(descriptor))
 10244         cgThings.append(CGLegacyCallHook(descriptor))
 10245         if descriptor.interface.getExtendedAttribute("NeedNewResolve"):
 10246             cgThings.append(CGNewResolveHook(descriptor))
 10247             cgThings.append(CGEnumerateHook(descriptor))
 10249         if descriptor.interface.hasInterfacePrototypeObject():
 10250             cgThings.append(CGPrototypeJSClass(descriptor, properties))
 10252         if descriptor.interface.hasInterfaceObject():
 10253             cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
 10255         if ((descriptor.interface.hasInterfaceObject() or descriptor.interface.getNavigatorProperty()) and
 10256             not descriptor.interface.isExternal() and
 10257             descriptor.isExposedConditionally() and
 10258             # Workers stuff is never conditional
 10259             not descriptor.workers):
 10260             cgThings.append(CGConstructorEnabled(descriptor))
 10262         if descriptor.concrete:
 10263             if descriptor.proxy:
 10264                 if descriptor.interface.totalMembersInSlots != 0:
 10265                     raise TypeError("We can't have extra reserved slots for "
 10266                                     "proxy interface %s" %
 10267                                     descriptor.interface.identifier.name)
 10268                 cgThings.append(CGGeneric(fill(
 10269                     """
 10270                     static_assert(IsBaseOf<nsISupports, ${nativeType} >::value,
 10271                                       "We don't support non-nsISupports native classes for "
 10272                                       "proxy-based bindings yet");
 10274                     """,
 10275                     nativeType=descriptor.nativeType)))
 10276                 if not descriptor.wrapperCache:
 10277                     raise TypeError("We need a wrappercache to support expandos for proxy-based "
 10278                                     "bindings (" + descriptor.name + ")")
 10279                 handlerThing = CGDOMJSProxyHandler(descriptor)
 10280                 cgThings.append(CGDOMJSProxyHandlerDeclarer(handlerThing))
 10281                 cgThings.append(CGProxyIsProxy(descriptor))
 10282                 cgThings.append(CGProxyUnwrap(descriptor))
 10283                 cgThings.append(CGDOMJSProxyHandlerDefiner(handlerThing))
 10284                 cgThings.append(CGDOMProxyJSClass(descriptor))
 10285             else:
 10286                 cgThings.append(CGDOMJSClass(descriptor))
 10287                 cgThings.append(CGGetJSClassMethod(descriptor))
 10288                 if descriptor.interface.hasMembersInSlots():
 10289                     if descriptor.interface.hasChildInterfaces():
 10290                         raise TypeError("We don't support members in slots on "
 10291                                         "non-leaf interfaces like %s" %
 10292                                         descriptor.interface.identifier.name)
 10293                     cgThings.append(CGUpdateMemberSlotsMethod(descriptor))
 10295             if descriptor.interface.getExtendedAttribute("Global"):
 10296                 assert descriptor.wrapperCache
 10297                 cgThings.append(CGWrapGlobalMethod(descriptor, properties))
 10298             elif descriptor.wrapperCache:
 10299                 cgThings.append(CGWrapWithCacheMethod(descriptor, properties))
 10300                 cgThings.append(CGWrapMethod(descriptor))
 10301             else:
 10302                 cgThings.append(CGWrapNonWrapperCacheMethod(descriptor,
 10303                                                             properties))
 10305         # If we're not wrappercached, we don't know how to clear our
 10306         # cached values, since we can't get at the JSObject.
 10307         if descriptor.wrapperCache:
 10308             cgThings.extend(CGClearCachedValueMethod(descriptor, m) for
 10309                             m in descriptor.interface.members if
 10310                             m.isAttr() and
 10311                             # Constants should never need clearing!
 10312                             not m.getExtendedAttribute("Constant") and
 10313                             not m.getExtendedAttribute("SameObject") and
 10314                             m.slotIndex is not None)
 10316         # CGCreateInterfaceObjectsMethod needs to come after our
 10317         # CGDOMJSClass, if any.
 10318         cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties))
 10320         # CGGetProtoObjectMethod and CGGetConstructorObjectMethod need
 10321         # to come after CGCreateInterfaceObjectsMethod.
 10322         if descriptor.interface.hasInterfacePrototypeObject():
 10323             cgThings.append(CGGetProtoObjectMethod(descriptor))
 10324         if descriptor.interface.hasInterfaceObject():
 10325             cgThings.append(CGGetConstructorObjectMethod(descriptor))
 10327         # See whether we need we need to generate an IsPermitted method
 10328         if crossOriginGetters or crossOriginSetters or crossOriginMethods:
 10329             cgThings.append(CGIsPermittedMethod(descriptor,
 10330                                                 crossOriginGetters,
 10331                                                 crossOriginSetters,
 10332                                                 crossOriginMethods))
 10334         cgThings = CGList((CGIndenter(t, declareOnly=True) for t in cgThings), "\n")
 10335         cgThings = CGWrapper(cgThings, pre='\n', post='\n')
 10336         self.cgRoot = CGWrapper(CGNamespace(toBindingNamespace(descriptor.name),
 10337                                             cgThings),
 10338                                 post='\n')
 10340     def declare(self):
 10341         return self.cgRoot.declare()
 10343     def define(self):
 10344         return self.cgRoot.define()
 10346     def deps(self):
 10347         return self._deps
 10350 class CGNamespacedEnum(CGThing):
 10351     def __init__(self, namespace, enumName, names, values, comment=""):
 10353         if not values:
 10354             values = []
 10356         # Account for explicit enum values.
 10357         entries = []
 10358         for i in range(0, len(names)):
 10359             if len(values) > i and values[i] is not None:
 10360                 entry = "%s = %s" % (names[i], values[i])
 10361             else:
 10362                 entry = names[i]
 10363             entries.append(entry)
 10365         # Append a Count.
 10366         entries.append('_' + enumName + '_Count')
 10368         # Indent.
 10369         entries = ['  ' + e for e in entries]
 10371         # Build the enum body.
 10372         enumstr = comment + 'enum %s\n{\n%s\n};\n' % (enumName, ',\n'.join(entries))
 10373         curr = CGGeneric(declare=enumstr)
 10375         # Add some whitespace padding.
 10376         curr = CGWrapper(curr, pre='\n', post='\n')
 10378         # Add the namespace.
 10379         curr = CGNamespace(namespace, curr)
 10381         # Add the typedef
 10382         typedef = '\ntypedef %s::%s %s;\n\n' % (namespace, enumName, enumName)
 10383         curr = CGList([curr, CGGeneric(declare=typedef)])
 10385         # Save the result.
 10386         self.node = curr
 10388     def declare(self):
 10389         return self.node.declare()
 10391     def define(self):
 10392         return ""
 10395 class CGDictionary(CGThing):
 10396     def __init__(self, dictionary, descriptorProvider):
 10397         self.dictionary = dictionary
 10398         self.descriptorProvider = descriptorProvider
 10399         self.needToInitIds = len(dictionary.members) > 0
 10400         self.memberInfo = [
 10401             (member,
 10402              getJSToNativeConversionInfo(
 10403                  member.type,
 10404                  descriptorProvider,
 10405                  isEnforceRange=member.enforceRange,
 10406                  isClamp=member.clamp,
 10407                  isMember="Dictionary",
 10408                  isOptional=(not member.defaultValue),
 10409                  defaultValue=member.defaultValue,
 10410                  sourceDescription=("'%s' member of %s" %
 10411                                     (member.identifier.name, dictionary.identifier.name))))
 10412             for member in dictionary.members]
 10414         # If we have a union member containing something in the same
 10415         # file as us, bail: the C++ includes won't work out.
 10416         for member in dictionary.members:
 10417             type = member.type.unroll()
 10418             if type.isUnion():
 10419                 for t in type.flatMemberTypes:
 10420                     if (t.isDictionary() and
 10421                         CGHeaders.getDeclarationFilename(t.inner) ==
 10422                         CGHeaders.getDeclarationFilename(dictionary)):
 10423                         raise TypeError(
 10424                             "Dictionary contains a union that contains a "
 10425                             "dictionary in the same WebIDL file.  This won't "
 10426                             "compile.  Move the inner dictionary to a "
 10427                             "different file.\n%s\n%s" %
 10428                             (t.location, t.inner.location))
 10429         self.structs = self.getStructs()
 10431     def declare(self):
 10432         return self.structs.declare()
 10434     def define(self):
 10435         return self.structs.define()
 10437     def base(self):
 10438         if self.dictionary.parent:
 10439             return self.makeClassName(self.dictionary.parent)
 10440         return "DictionaryBase"
 10442     def initMethod(self):
 10443         body = dedent("""
 10444             // Passing a null JSContext is OK only if we're initing from null,
 10445             // Since in that case we will not have to do any property gets
 10446             MOZ_ASSERT_IF(!cx, val.isNull());
 10447             """)
 10449         if self.needToInitIds:
 10450             body += fill(
 10451                 """
 10452                 ${dictName}Atoms* atomsCache = nullptr;
 10453                 if (cx) {
 10454                   atomsCache = GetAtomCache<${dictName}Atoms>(cx);
 10455                   if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
 10456                     return false;
 10460                 """,
 10461                 dictName=self.makeClassName(self.dictionary))
 10463         if self.dictionary.parent:
 10464             body += fill(
 10465                 """
 10466                 // Per spec, we init the parent's members first
 10467                 if (!${dictName}::Init(cx, val)) {
 10468                   return false;
 10470                 MOZ_ASSERT(IsConvertibleToDictionary(cx, val));
 10472                 """,
 10473                 dictName=self.makeClassName(self.dictionary.parent))
 10474         else:
 10475             body += fill(
 10476                 """
 10477                 if (!IsConvertibleToDictionary(cx, val)) {
 10478                   return ThrowErrorMessage(cx, MSG_NOT_DICTIONARY, sourceDescription);
 10481                 """)
 10483         memberInits = [self.getMemberConversion(m).define()
 10484                        for m in self.memberInfo]
 10485         if memberInits:
 10486             body += fill(
 10487                 """
 10488                 bool isNull = val.isNullOrUndefined();
 10489                 // We only need these if !isNull, in which case we have |cx|.
 10490                 Maybe<JS::Rooted<JSObject *> > object;
 10491                 Maybe<JS::Rooted<JS::Value> > temp;
 10492                 if (!isNull) {
 10493                   object.construct(cx, &val.toObject());
 10494                   temp.construct(cx);
 10496                 $*{memberInits}
 10497                 """,
 10498                 memberInits="\n".join(memberInits))
 10500         body += "return true;\n"
 10502         return ClassMethod("Init", "bool", [
 10503             Argument('JSContext*', 'cx'),
 10504             Argument('JS::Handle<JS::Value>', 'val'),
 10505             Argument('const char*', 'sourceDescription', default='"Value"')
 10506         ], body=body)
 10508     def initFromJSONMethod(self):
 10509         return ClassMethod(
 10510             "Init", "bool",
 10511             [Argument('const nsAString&', 'aJSON')],
 10512             body=dedent("""
 10513                 MOZ_ASSERT(NS_IsMainThread());
 10514                 AutoSafeJSContext cx;
 10515                 JS::Rooted<JS::Value> json(cx);
 10516                 bool ok = ParseJSON(cx, aJSON, &json);
 10517                 NS_ENSURE_TRUE(ok, false);
 10518                 return Init(cx, json);
 10519                 """))
 10521     def toObjectMethod(self):
 10522         body = ""
 10523         if self.needToInitIds:
 10524             body += fill(
 10525                 """
 10526                 ${dictName}Atoms* atomsCache = GetAtomCache<${dictName}Atoms>(cx);
 10527                 if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
 10528                   return false;
 10531                 """,
 10532                 dictName=self.makeClassName(self.dictionary))
 10534         if self.dictionary.parent:
 10535             body += fill(
 10536                 """
 10537                 // Per spec, we define the parent's members first
 10538                 if (!${dictName}::ToObject(cx, rval)) {
 10539                   return false;
 10541                 JS::Rooted<JSObject*> obj(cx, &rval.toObject());
 10543                 """,
 10544                 dictName=self.makeClassName(self.dictionary.parent))
 10545         else:
 10546             body += fill(
 10547                 """
 10548                 JS::Rooted<JSObject*> obj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
 10549                 if (!obj) {
 10550                   return false;
 10552                 rval.set(JS::ObjectValue(*obj));
 10554                 """)
 10556         if self.memberInfo:
 10557             body += "\n".join(self.getMemberDefinition(m).define()
 10558                               for m in self.memberInfo)
 10559         else:
 10560             body += "\n"  # BOGUS extra blank line
 10561         body += "\nreturn true;\n"
 10563         return ClassMethod("ToObject", "bool", [
 10564             Argument('JSContext*', 'cx'),
 10565             Argument('JS::MutableHandle<JS::Value>', 'rval'),
 10566         ], const=True, body=body)
 10568     def initIdsMethod(self):
 10569         assert self.needToInitIds
 10570         idinit = ['!atomsCache->%s.init(cx, "%s")' %
 10571                   (CGDictionary.makeIdName(m.identifier.name),
 10572                    m.identifier.name)
 10573                   for m in self.dictionary.members]
 10574         idinit.reverse()
 10575         body = fill(
 10576             """
 10577             MOZ_ASSERT(!*reinterpret_cast<jsid**>(atomsCache));
 10579             // Initialize these in reverse order so that any failure leaves the first one
 10580             // uninitialized.
 10581             if (${idinit}) {
 10582               return false;
 10584             return true;
 10585             """,
 10586             idinit=" ||\n    ".join(idinit))
 10588         return ClassMethod("InitIds", "bool", [
 10589             Argument("JSContext*", "cx"),
 10590             Argument("%sAtoms*" % self.makeClassName(self.dictionary),
 10591                      "atomsCache"),
 10592         ], static=True, body=body, visibility="private")
 10594     def traceDictionaryMethod(self):
 10595         body = ""
 10596         if self.dictionary.parent:
 10597             cls = self.makeClassName(self.dictionary.parent)
 10598             body += "%s::TraceDictionary(trc);\n" % cls
 10600         memberTraces = [self.getMemberTrace(m)
 10601                         for m in self.dictionary.members
 10602                         if typeNeedsRooting(m.type)]
 10604         if memberTraces:
 10605             body += "\n".join(memberTraces)
 10606         else:
 10607             body += "\n"  # BOGUS extra newline
 10609         return ClassMethod("TraceDictionary", "void", [
 10610             Argument("JSTracer*", "trc"),
 10611         ], body=body)
 10613     def assignmentOperator(self):
 10614         body = CGList([])
 10615         if self.dictionary.parent:
 10616             body.append(CGGeneric(
 10617                 "%s::operator=(aOther);\n" %
 10618                 self.makeClassName(self.dictionary.parent)))
 10619         for m, _ in self.memberInfo:
 10620             memberName = self.makeMemberName(m.identifier.name)
 10621             if not m.defaultValue:
 10622                 memberAssign = CGGeneric(fill(
 10623                     """
 10624                     if (aOther.${name}.WasPassed()) {
 10625                       ${name}.Construct();
 10626                       ${name}.Value() = aOther.${name}.Value();
 10627                     } else {
 10628                       ${name}.Reset();
 10630                     """,
 10631                     name=memberName))
 10632             else:
 10633                 memberAssign = CGGeneric(
 10634                     "%s = aOther.%s;\n" % (memberName, memberName))
 10635             body.append(memberAssign)
 10636         return ClassMethod(
 10637             "operator=", "void",
 10638             [Argument("const %s&" % self.makeClassName(self.dictionary),
 10639                       "aOther")],
 10640             body=body.define() or "\n")  # BOGUS blank line when empty
 10642     def getStructs(self):
 10643         d = self.dictionary
 10644         selfName = self.makeClassName(d)
 10645         members = [ClassMember(self.makeMemberName(m[0].identifier.name),
 10646                                self.getMemberType(m),
 10647                                visibility="public",
 10648                                body=self.getMemberInitializer(m))
 10649                    for m in self.memberInfo]
 10650         ctors = [
 10651             ClassConstructor(
 10652                 [],
 10653                 visibility="public",
 10654                 body=(
 10655                     "// Safe to pass a null context if we pass a null value\n"
 10656                     "Init(nullptr, JS::NullHandleValue);\n")),
 10657             ClassConstructor(
 10658                 [Argument("int", "")],
 10659                 visibility="protected",
 10660                 explicit=True,
 10661                 bodyInHeader=True,
 10662                 body='// Do nothing here; this is used by our "Fast" subclass\n')
 10664         methods = []
 10666         if self.needToInitIds:
 10667             methods.append(self.initIdsMethod())
 10669         methods.append(self.initMethod())
 10670         methods.append(self.initFromJSONMethod())
 10671         try:
 10672             methods.append(self.toObjectMethod())
 10673         except MethodNotNewObjectError:
 10674             # If we can't have a ToObject() because one of our members can only
 10675             # be returned from [NewObject] methods, then just skip generating
 10676             # ToObject().
 10677             pass
 10678         methods.append(self.traceDictionaryMethod())
 10680         if CGDictionary.isDictionaryCopyConstructible(d):
 10681             disallowCopyConstruction = False
 10682             # Note: no base constructors because our operator= will
 10683             # deal with that.
 10684             ctors.append(ClassConstructor([Argument("const %s&" % selfName,
 10685                                                     "aOther")],
 10686                                           bodyInHeader=True,
 10687                                           visibility="public",
 10688                                           explicit=True,
 10689                                           body="*this = aOther;\n"))
 10690             methods.append(self.assignmentOperator())
 10691         else:
 10692             disallowCopyConstruction = True
 10694         struct = CGClass(selfName,
 10695                          bases=[ClassBase(self.base())],
 10696                          members=members,
 10697                          constructors=ctors,
 10698                          methods=methods,
 10699                          isStruct=True,
 10700                          disallowCopyConstruction=disallowCopyConstruction)
 10702         fastDictionaryCtor = ClassConstructor(
 10703             [],
 10704             visibility="public",
 10705             bodyInHeader=True,
 10706             baseConstructors=["%s(42)" % selfName],
 10707             body="// Doesn't matter what int we pass to the parent constructor\n")
 10709         fastStruct = CGClass("Fast" + selfName,
 10710                              bases=[ClassBase(selfName)],
 10711                              constructors=[fastDictionaryCtor],
 10712                              isStruct=True)
 10714         return CGList([struct,
 10715                        CGNamespace('binding_detail', fastStruct)],
 10716                       "\n")
 10718     def deps(self):
 10719         return self.dictionary.getDeps()
 10721     @staticmethod
 10722     def makeDictionaryName(dictionary):
 10723         return dictionary.identifier.name
 10725     def makeClassName(self, dictionary):
 10726         return self.makeDictionaryName(dictionary)
 10728     @staticmethod
 10729     def makeMemberName(name):
 10730         return "m" + name[0].upper() + name[1:]
 10732     def getMemberType(self, memberInfo):
 10733         _, conversionInfo = memberInfo
 10734         # We can't handle having a holderType here
 10735         assert conversionInfo.holderType is None
 10736         declType = conversionInfo.declType
 10737         if conversionInfo.dealWithOptional:
 10738             declType = CGTemplatedType("Optional", declType)
 10739         return declType.define()
 10741     def getMemberConversion(self, memberInfo):
 10742         member, conversionInfo = memberInfo
 10743         replacements = {
 10744             "val": "temp.ref()",
 10745             "mutableVal": "&temp.ref()",
 10746             "declName": self.makeMemberName(member.identifier.name),
 10747             # We need a holder name for external interfaces, but
 10748             # it's scoped down to the conversion so we can just use
 10749             # anything we want.
 10750             "holderName": "holder"
 10752         # We can't handle having a holderType here
 10753         assert conversionInfo.holderType is None
 10754         if conversionInfo.dealWithOptional:
 10755             replacements["declName"] = "(" + replacements["declName"] + ".Value())"
 10756         if member.defaultValue:
 10757             replacements["haveValue"] = "!isNull && !temp.ref().isUndefined()"
 10759         propId = self.makeIdName(member.identifier.name)
 10760         propGet = ("JS_GetPropertyById(cx, object.ref(), atomsCache->%s, &temp.ref())" %
 10761                    propId)
 10763         conversionReplacements = {
 10764             "prop": self.makeMemberName(member.identifier.name),
 10765             "convert": string.Template(conversionInfo.template).substitute(replacements),
 10766             "propGet": propGet
 10768         conversion = ("if (!isNull && !${propGet}) {\n"
 10769                       "  return false;\n"
 10770                       "}\n")
 10771         if member.defaultValue:
 10772             conversion += "${convert}"
 10773         else:
 10774             conversion += (
 10775                 "if (!isNull && !temp.ref().isUndefined()) {\n"
 10776                 "  ${prop}.Construct();\n"
 10777                 "${convert}"
 10778                 "}\n")
 10779             conversionReplacements["convert"] = indent(conversionReplacements["convert"])
 10781         return CGGeneric(
 10782             string.Template(conversion).substitute(conversionReplacements))
 10784     def getMemberDefinition(self, memberInfo):
 10785         member = memberInfo[0]
 10786         declType = memberInfo[1].declType
 10787         memberLoc = self.makeMemberName(member.identifier.name)
 10788         if member.defaultValue:
 10789             memberData = memberLoc
 10790         else:
 10791             # The data is inside the Optional<>
 10792             memberData = "%s.InternalValue()" % memberLoc
 10794         # If you have to change this list (which you shouldn't!), make sure it
 10795         # continues to match the list in test_Object.prototype_props.html
 10796         if (member.identifier.name in
 10797             ["constructor", "toSource", "toString", "toLocaleString", "valueOf",
 10798              "watch", "unwatch", "hasOwnProperty", "isPrototypeOf",
 10799              "propertyIsEnumerable", "__defineGetter__", "__defineSetter__",
 10800              "__lookupGetter__", "__lookupSetter__", "__proto__"]):
 10801             raise TypeError("'%s' member of %s dictionary shadows "
 10802                             "a property of Object.prototype, and Xrays to "
 10803                             "Object can't handle that.\n"
 10804                             "%s" %
 10805                             (member.identifier.name,
 10806                              self.dictionary.identifier.name,
 10807                              member.location))
 10809         propDef = (
 10810             'JS_DefinePropertyById(cx, obj, atomsCache->%s, temp, nullptr, nullptr, JSPROP_ENUMERATE)' %
 10811             self.makeIdName(member.identifier.name))
 10813         innerTemplate = wrapForType(
 10814             member.type, self.descriptorProvider,
 10816                 'result': "currentValue",
 10817                 'successCode': ("if (!%s) {\n"
 10818                                 "  return false;\n"
 10819                                 "}\n"
 10820                                 "break;\n" % propDef),
 10821                 'jsvalRef': "temp",
 10822                 'jsvalHandle': "&temp",
 10823                 'returnsNewObject': False,
 10824                 # 'obj' can just be allowed to be the string "obj", since that
 10825                 # will be our dictionary object, which is presumably itself in
 10826                 # the right scope.
 10827                 'typedArraysAreStructs': True
 10828             })
 10829         conversion = CGGeneric(innerTemplate)
 10830         conversion = CGWrapper(conversion,
 10831                                pre=("JS::Rooted<JS::Value> temp(cx);\n"
 10832                                     "%s const & currentValue = %s;\n" %
 10833                                     (declType.define(), memberData)
 10834                                     ))
 10836         # Now make sure that our successCode can actually break out of the
 10837         # conversion.  This incidentally gives us a scope for 'temp' and
 10838         # 'currentValue'.
 10839         conversion = CGWrapper(
 10840             CGIndenter(conversion),
 10841             pre=("do {\n"
 10842                  "  // block for our 'break' successCode and scope for 'temp' and 'currentValue'\n"),
 10843             post="} while(0);\n")
 10844         if not member.defaultValue:
 10845             # Only do the conversion if we have a value
 10846             conversion = CGIfWrapper(conversion, "%s.WasPassed()" % memberLoc)
 10847         return conversion
 10849     def getMemberTrace(self, member):
 10850         type = member.type
 10851         assert typeNeedsRooting(type)
 10852         memberLoc = self.makeMemberName(member.identifier.name)
 10853         if member.defaultValue:
 10854             memberData = memberLoc
 10855         else:
 10856             # The data is inside the Optional<>
 10857             memberData = "%s.Value()" % memberLoc
 10859         memberName = "%s.%s" % (self.makeClassName(self.dictionary),
 10860                                 memberLoc)
 10862         if type.isObject():
 10863             trace = CGGeneric('JS_CallObjectTracer(trc, %s, "%s");\n' %
 10864                               ("&"+memberData, memberName))
 10865             if type.nullable():
 10866                 trace = CGIfWrapper(trace, memberData)
 10867         elif type.isAny():
 10868             trace = CGGeneric('JS_CallValueTracer(trc, %s, "%s");\n' %
 10869                               ("&"+memberData, memberName))
 10870         elif (type.isSequence() or type.isDictionary() or
 10871               type.isSpiderMonkeyInterface() or type.isUnion()):
 10872             if type.nullable():
 10873                 memberNullable = memberData
 10874                 memberData = "%s.Value()" % memberData
 10875             if type.isSequence():
 10876                 trace = CGGeneric('DoTraceSequence(trc, %s);\n' % memberData)
 10877             elif type.isDictionary():
 10878                 trace = CGGeneric('%s.TraceDictionary(trc);\n' % memberData)
 10879             elif type.isUnion():
 10880                 trace = CGGeneric('%s.TraceUnion(trc);\n' % memberData)
 10881             else:
 10882                 assert type.isSpiderMonkeyInterface()
 10883                 trace = CGGeneric('%s.TraceSelf(trc);\n' % memberData)
 10884             if type.nullable():
 10885                 trace = CGIfWrapper(trace, "!%s.IsNull()" % memberNullable)
 10886         else:
 10887             assert False  # unknown type
 10889         if not member.defaultValue:
 10890             trace = CGIfWrapper(trace, "%s.WasPassed()" % memberLoc)
 10892         return trace.define()
 10894     def getMemberInitializer(self, memberInfo):
 10895         """
 10896         Get the right initializer for the member.  Most members don't need one,
 10897         but we need to pre-initialize 'any' and 'object' that have a default
 10898         value, so they're safe to trace at all times.
 10899         """
 10900         member, _ = memberInfo
 10901         if not member.defaultValue:
 10902             # No default value means no need to set it up front, since it's
 10903             # inside an Optional and won't get traced until it's actually set
 10904             # up.
 10905             return None
 10906         type = member.type
 10907         if type.isAny():
 10908             return "JS::UndefinedValue()"
 10909         if type.isObject():
 10910             return "nullptr"
 10911         return None
 10913     @staticmethod
 10914     def makeIdName(name):
 10915         return name + "_id"
 10917     @staticmethod
 10918     def getDictionaryDependenciesFromType(type):
 10919         if type.isDictionary():
 10920             return set([type.unroll().inner])
 10921         if type.isSequence() or type.isArray():
 10922             return CGDictionary.getDictionaryDependenciesFromType(type.unroll())
 10923         return set()
 10925     @staticmethod
 10926     def getDictionaryDependencies(dictionary):
 10927         deps = set()
 10928         if dictionary.parent:
 10929             deps.add(dictionary.parent)
 10930         for member in dictionary.members:
 10931             deps |= CGDictionary.getDictionaryDependenciesFromType(member.type)
 10932         return deps
 10934     @staticmethod
 10935     def isDictionaryCopyConstructible(dictionary):
 10936         if (dictionary.parent and
 10937             not CGDictionary.isDictionaryCopyConstructible(dictionary.parent)):
 10938             return False
 10939         return all(isTypeCopyConstructible(m.type) for m in dictionary.members)
 10942 class CGRegisterProtos(CGAbstractMethod):
 10943     def __init__(self, config):
 10944         CGAbstractMethod.__init__(self, None, 'Register', 'void',
 10945                                   [Argument('nsScriptNameSpaceManager*', 'aNameSpaceManager')])
 10946         self.config = config
 10948     def _defineMacro(self):
 10949         return dedent("""
 10950             #define REGISTER_PROTO(_dom_class, _ctor_check) \\
 10951               aNameSpaceManager->RegisterDefineDOMInterface(MOZ_UTF16(#_dom_class), _dom_class##Binding::DefineDOMInterface, _ctor_check);
 10952             #define REGISTER_CONSTRUCTOR(_dom_constructor, _dom_class, _ctor_check) \\
 10953               aNameSpaceManager->RegisterDefineDOMInterface(MOZ_UTF16(#_dom_constructor), _dom_class##Binding::DefineDOMInterface, _ctor_check);
 10954             #define REGISTER_NAVIGATOR_CONSTRUCTOR(_prop, _dom_class, _ctor_check) \\
 10955               aNameSpaceManager->RegisterNavigatorDOMConstructor(MOZ_UTF16(_prop), _dom_class##Binding::ConstructNavigatorObject, _ctor_check);
 10956             """)
 10958     def _undefineMacro(self):
 10959         return dedent("""
 10960             #undef REGISTER_CONSTRUCTOR
 10961             #undef REGISTER_PROTO
 10962             #undef REGISTER_NAVIGATOR_CONSTRUCTOR
 10963             """)
 10965     def _registerProtos(self):
 10966         def getCheck(desc):
 10967             if not desc.isExposedConditionally():
 10968                 return "nullptr"
 10969             return "%sBinding::ConstructorEnabled" % desc.name
 10970         lines = []
 10971         for desc in self.config.getDescriptors(hasInterfaceObject=True,
 10972                                                isExternal=False,
 10973                                                workers=False,
 10974                                                register=True):
 10975             lines.append("REGISTER_PROTO(%s, %s);\n" % (desc.name, getCheck(desc)))
 10976             lines.extend("REGISTER_CONSTRUCTOR(%s, %s, %s);\n" % (n.identifier.name, desc.name, getCheck(desc))
 10977                          for n in desc.interface.namedConstructors)
 10978         for desc in self.config.getDescriptors(isNavigatorProperty=True, register=True):
 10979             propName = desc.interface.getNavigatorProperty()
 10980             assert propName
 10981             lines.append('REGISTER_NAVIGATOR_CONSTRUCTOR("%s", %s, %s);\n' % (propName, desc.name, getCheck(desc)))
 10982         return ''.join(lines)
 10984     def definition_body(self):
 10985         return "\n" + self._defineMacro() + "\n" + self._registerProtos() + "\n" + self._undefineMacro()
 10988 def dependencySortObjects(objects, dependencyGetter, nameGetter):
 10989     """
 10990     Sort IDL objects with dependencies on each other such that if A
 10991     depends on B then B will come before A.  This is needed for
 10992     declaring C++ classes in the right order, for example.  Objects
 10993     that have no dependencies are just sorted by name.
 10995     objects should be something that can produce a set of objects
 10996     (e.g. a set, iterator, list, etc).
 10998     dependencyGetter is something that, given an object, should return
 10999     the set of objects it depends on.
 11000     """
 11001     # XXXbz this will fail if we have two webidl files F1 and F2 such that F1
 11002     # declares an object which depends on an object in F2, and F2 declares an
 11003     # object (possibly a different one!) that depends on an object in F1.  The
 11004     # good news is that I expect this to never happen.
 11005     sortedObjects = []
 11006     objects = set(objects)
 11007     while len(objects) != 0:
 11008         # Find the dictionaries that don't depend on anything else
 11009         # anymore and move them over.
 11010         toMove = [o for o in objects if
 11011                   len(dependencyGetter(o) & objects) == 0]
 11012         if len(toMove) == 0:
 11013             raise TypeError("Loop in dependency graph\n" +
 11014                             "\n".join(o.location for o in objects))
 11015         objects = objects - set(toMove)
 11016         sortedObjects.extend(sorted(toMove, key=nameGetter))
 11017     return sortedObjects
 11020 class ForwardDeclarationBuilder:
 11021     """
 11022     Create a canonical representation of a set of namespaced forward
 11023     declarations.
 11024     """
 11025     def __init__(self):
 11026         """
 11027         The set of declarations is represented as a tree of nested namespaces.
 11028         Each tree node has a set of declarations |decls| and a dict |children|.
 11029         Each declaration is a pair consisting of the class name and a boolean
 11030         that is true iff the class is really a struct. |children| maps the
 11031         names of inner namespaces to the declarations in that namespace.
 11032         """
 11033         self.decls = set()
 11034         self.children = {}
 11036     def _listAdd(self, namespaces, name, isStruct=False):
 11037         """
 11038         Add a forward declaration, where |namespaces| is a list of namespaces.
 11039         |name| should not contain any other namespaces.
 11040         """
 11041         if namespaces:
 11042             child = self.children.setdefault(namespaces[0], ForwardDeclarationBuilder())
 11043             child._listAdd(namespaces[1:], name, isStruct)
 11044         else:
 11045             assert '::' not in name
 11046             self.decls.add((name, isStruct))
 11048     def addInMozillaDom(self, name, isStruct=False):
 11049         """
 11050         Add a forward declaration to the mozilla::dom:: namespace. |name| should not
 11051         contain any other namespaces.
 11052         """
 11053         self._listAdd(["mozilla", "dom"], name, isStruct)
 11055     def add(self, nativeType, isStruct=False):
 11056         """
 11057         Add a forward declaration, where |nativeType| is a string containing
 11058         the type and its namespaces, in the usual C++ way.
 11059         """
 11060         components = nativeType.split('::')
 11061         self._listAdd(components[:-1], components[-1], isStruct)
 11063     def _build(self, atTopLevel):
 11064         """
 11065         Return a codegenerator for the forward declarations.
 11066         """
 11067         decls = []
 11068         if self.decls:
 11069             decls.append(CGList([CGClassForwardDeclare(cname, isStruct)
 11070                                  for cname, isStruct in sorted(self.decls)]))
 11071         for namespace, child in sorted(self.children.iteritems()):
 11072             decls.append(CGNamespace(namespace, child._build(atTopLevel=False), declareOnly=True))
 11074         cg = CGList(decls, "\n")
 11075         if not atTopLevel and len(decls) + len(self.decls) > 1:
 11076             cg = CGWrapper(cg, pre='\n', post='\n')
 11077         return cg
 11079     def build(self):
 11080         return self._build(atTopLevel=True)
 11083 class CGForwardDeclarations(CGWrapper):
 11084     """
 11085     Code generate the forward declarations for a header file.
 11086     """
 11087     def __init__(self, config, descriptors, mainCallbacks, workerCallbacks,
 11088                  dictionaries, callbackInterfaces):
 11089         builder = ForwardDeclarationBuilder()
 11091         def forwardDeclareForType(t, workerness='both'):
 11092             t = t.unroll()
 11093             if t.isGeckoInterface():
 11094                 name = t.inner.identifier.name
 11095                 # Find and add the non-worker implementation, if any.
 11096                 if workerness != 'workeronly':
 11097                     try:
 11098                         desc = config.getDescriptor(name, False)
 11099                         builder.add(desc.nativeType)
 11100                     except NoSuchDescriptorError:
 11101                         pass
 11102                 # Find and add the worker implementation, if any.
 11103                 if workerness != 'mainthreadonly':
 11104                     try:
 11105                         desc = config.getDescriptor(name, True)
 11106                         builder.add(desc.nativeType)
 11107                     except NoSuchDescriptorError:
 11108                         pass
 11109             elif t.isCallback():
 11110                 builder.addInMozillaDom(str(t))
 11111             elif t.isDictionary():
 11112                 builder.addInMozillaDom(t.inner.identifier.name, isStruct=True)
 11113             elif t.isCallbackInterface():
 11114                 builder.addInMozillaDom(t.inner.identifier.name)
 11115             elif t.isUnion():
 11116                 # Forward declare both the owning and non-owning version,
 11117                 # since we don't know which one we might want
 11118                 builder.addInMozillaDom(CGUnionStruct.unionTypeName(t, False))
 11119                 builder.addInMozillaDom(CGUnionStruct.unionTypeName(t, True))
 11120             elif t.isMozMap():
 11121                 forwardDeclareForType(t.inner, workerness)
 11122             # Don't need to do anything for void, primitive, string, any or object.
 11123             # There may be some other cases we are missing.
 11125         # Needed for at least Wrap.
 11126         for d in descriptors:
 11127             builder.add(d.nativeType)
 11129         # We just about always need NativePropertyHooks
 11130         builder.addInMozillaDom("NativePropertyHooks")
 11131         builder.addInMozillaDom("ProtoAndIfaceCache")
 11133         for callback in mainCallbacks:
 11134             forwardDeclareForType(callback)
 11135             for t in getTypesFromCallback(callback):
 11136                 forwardDeclareForType(t, workerness='mainthreadonly')
 11138         for callback in workerCallbacks:
 11139             forwardDeclareForType(callback)
 11140             for t in getTypesFromCallback(callback):
 11141                 forwardDeclareForType(t, workerness='workeronly')
 11143         for d in callbackInterfaces:
 11144             builder.add(d.nativeType)
 11145             for t in getTypesFromDescriptor(d):
 11146                 forwardDeclareForType(t)
 11148         for d in dictionaries:
 11149             if len(d.members) > 0:
 11150                 builder.addInMozillaDom(d.identifier.name + "Atoms", isStruct=True)
 11151             for t in getTypesFromDictionary(d):
 11152                 forwardDeclareForType(t)
 11154         CGWrapper.__init__(self, builder.build())
 11157 class CGBindingRoot(CGThing):
 11158     """
 11159     Root codegen class for binding generation. Instantiate the class, and call
 11160     declare or define to generate header or cpp code (respectively).
 11161     """
 11162     def __init__(self, config, prefix, webIDLFile):
 11163         bindingHeaders = {}
 11164         descriptors = config.getDescriptors(webIDLFile=webIDLFile,
 11165                                             hasInterfaceOrInterfacePrototypeObject=True,
 11166                                             skipGen=False)
 11168         def descriptorRequiresPreferences(desc):
 11169             iface = desc.interface
 11170             return any(m.getExtendedAttribute("Pref") for m in iface.members + [iface])
 11172         bindingHeaders["mozilla/Preferences.h"] = any(
 11173             descriptorRequiresPreferences(d) for d in descriptors)
 11174         bindingHeaders["mozilla/dom/NonRefcountedDOMObject.h"] = any(
 11175             d.nativeOwnership == 'owned' for d in descriptors)
 11176         bindingHeaders["mozilla/dom/DOMJSProxyHandler.h"] = any(
 11177             d.concrete and d.proxy for d in descriptors)
 11179         def descriptorHasChromeOnly(desc):
 11180             return (any(isChromeOnly(a) for a in desc.interface.members) or
 11181                     desc.interface.getExtendedAttribute("ChromeOnly") is not None or
 11182                     # JS-implemented interfaces with an interface object get a
 11183                     # chromeonly _create method.
 11184                     (desc.interface.isJSImplemented() and
 11185                      desc.interface.hasInterfaceObject()))
 11187         bindingHeaders["nsContentUtils.h"] = any(
 11188             descriptorHasChromeOnly(d) for d in descriptors)
 11189         # XXXkhuey ugly hack but this is going away soon.
 11190         bindingHeaders['xpcprivate.h'] = webIDLFile.endswith("EventTarget.webidl")
 11191         hasWorkerStuff = len(config.getDescriptors(webIDLFile=webIDLFile,
 11192                                                    workers=True)) != 0
 11193         bindingHeaders["WorkerPrivate.h"] = hasWorkerStuff
 11194         bindingHeaders["nsThreadUtils.h"] = hasWorkerStuff
 11196         dictionaries = config.getDictionaries(webIDLFile=webIDLFile)
 11197         bindingHeaders["nsCxPusher.h"] = dictionaries
 11198         bindingHeaders["AtomList.h"] = any(
 11199             len(dict.members) > 0 for dict in dictionaries)
 11200         mainCallbacks = config.getCallbacks(webIDLFile=webIDLFile,
 11201                                             workers=False)
 11202         workerCallbacks = config.getCallbacks(webIDLFile=webIDLFile,
 11203                                               workers=True)
 11204         callbackDescriptors = config.getDescriptors(webIDLFile=webIDLFile,
 11205                                                     isCallback=True)
 11206         jsImplemented = config.getDescriptors(webIDLFile=webIDLFile,
 11207                                               isJSImplemented=True)
 11208         bindingHeaders["nsPIDOMWindow.h"] = jsImplemented
 11210         def addHeaderBasedOnTypes(header, typeChecker):
 11211             bindingHeaders[header] = (
 11212                 bindingHeaders.get(header, False) or
 11213                 any(map(typeChecker,
 11214                         getAllTypes(descriptors + callbackDescriptors,
 11215                                     dictionaries,
 11216                                     mainCallbacks + workerCallbacks))))
 11218         bindingHeaders["nsDOMQS.h"] = any(d.hasXPConnectImpls for d in descriptors)
 11219         # Only mainthread things can have hasXPConnectImpls
 11220         provider = config.getDescriptorProvider(False)
 11222         def checkForXPConnectImpls(typeInfo):
 11223             type, _, _ = typeInfo
 11224             type = type.unroll()
 11225             while type.isMozMap():
 11226                 type = type.inner.unroll()
 11227             if not type.isInterface() or not type.isGeckoInterface():
 11228                 return False
 11229             try:
 11230                 typeDesc = provider.getDescriptor(type.inner.identifier.name)
 11231             except NoSuchDescriptorError:
 11232                 return False
 11233             return typeDesc.hasXPConnectImpls
 11234         addHeaderBasedOnTypes("nsDOMQS.h", checkForXPConnectImpls)
 11236         def descriptorClearsPropsInSlots(descriptor):
 11237             if not descriptor.wrapperCache:
 11238                 return False
 11239             return any(m.isAttr() and m.getExtendedAttribute("StoreInSlot")
 11240                        for m in descriptor.interface.members)
 11241         bindingHeaders["nsJSUtils.h"] = any(descriptorClearsPropsInSlots(d) for d in descriptors)
 11243         # Do codegen for all the enums
 11244         enums = config.getEnums(webIDLFile)
 11245         cgthings = [CGEnum(e) for e in enums]
 11247         hasCode = (descriptors or callbackDescriptors or dictionaries or
 11248                    mainCallbacks or workerCallbacks)
 11249         bindingHeaders["mozilla/dom/BindingUtils.h"] = hasCode
 11250         bindingHeaders["mozilla/dom/OwningNonNull.h"] = hasCode
 11251         bindingHeaders["mozilla/dom/BindingDeclarations.h"] = (
 11252             not hasCode and enums)
 11254         bindingHeaders["WrapperFactory.h"] = descriptors
 11255         bindingHeaders["mozilla/dom/DOMJSClass.h"] = descriptors
 11257         # Do codegen for all the dictionaries.  We have to be a bit careful
 11258         # here, because we have to generate these in order from least derived
 11259         # to most derived so that class inheritance works out.  We also have to
 11260         # generate members before the dictionary that contains them.
 11261         cgthings.extend([CGDictionary(d, config.getDescriptorProvider(False))
 11262                          for d in
 11263                          dependencySortObjects(dictionaries,
 11264                                                CGDictionary.getDictionaryDependencies,
 11265                                                lambda d: d.identifier.name)])
 11267         # Do codegen for all the callbacks.
 11268         cgthings.extend(CGCallbackFunction(c, config.getDescriptorProvider(False))
 11269                         for c in mainCallbacks)
 11271         cgthings.extend(CGCallbackFunction(c, config.getDescriptorProvider(True))
 11272                         for c in workerCallbacks if c not in mainCallbacks)
 11274         # Do codegen for all the descriptors
 11275         cgthings.extend([CGDescriptor(x) for x in descriptors])
 11277         # Do codegen for all the callback interfaces.  Skip worker callbacks.
 11278         cgthings.extend([CGCallbackInterface(x) for x in callbackDescriptors if
 11279                          not x.workers])
 11281         # Do codegen for JS implemented classes
 11282         def getParentDescriptor(desc):
 11283             if not desc.interface.parent:
 11284                 return set()
 11285             return {desc.getDescriptor(desc.interface.parent.identifier.name)}
 11286         for x in dependencySortObjects(jsImplemented, getParentDescriptor,
 11287                                        lambda d: d.interface.identifier.name):
 11288             cgthings.append(CGCallbackInterface(x))
 11289             cgthings.append(CGJSImplClass(x))
 11291         # And make sure we have the right number of newlines at the end
 11292         curr = CGWrapper(CGList(cgthings, "\n\n"), post="\n\n")
 11294         # Wrap all of that in our namespaces.
 11295         curr = CGNamespace.build(['mozilla', 'dom'],
 11296                                  CGWrapper(curr, pre="\n"))
 11298         curr = CGList([CGForwardDeclarations(config, descriptors,
 11299                                              mainCallbacks, workerCallbacks,
 11300                                              dictionaries,
 11301                                              callbackDescriptors + jsImplemented),
 11302                        curr],
 11303                       "\n")
 11305         # Add header includes.
 11306         bindingHeaders = [header
 11307                           for header, include in bindingHeaders.iteritems()
 11308                           if include]
 11309         declareIncludes = [
 11310             'mozilla/dom/BindingDeclarations.h',
 11311             'mozilla/dom/Nullable.h',
 11312             'mozilla/ErrorResult.h',
 11313             'jspubtd.h',
 11314             'js/RootingAPI.h',
 11316         if jsImplemented:
 11317             declareIncludes.append('nsWeakReference.h')
 11319         curr = CGHeaders(descriptors,
 11320                          dictionaries,
 11321                          mainCallbacks + workerCallbacks,
 11322                          callbackDescriptors,
 11323                          declareIncludes,
 11324                          bindingHeaders,
 11325                          prefix,
 11326                          curr,
 11327                          config,
 11328                          jsImplemented)
 11330         # Add include guards.
 11331         curr = CGIncludeGuard(prefix, curr)
 11333         # Add the auto-generated comment.
 11334         curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
 11336         # Store the final result.
 11337         self.root = curr
 11339     def declare(self):
 11340         return stripTrailingWhitespace(self.root.declare())
 11342     def define(self):
 11343         return stripTrailingWhitespace(self.root.define())
 11345     def deps(self):
 11346         return self.root.deps()
 11349 class CGNativeMember(ClassMethod):
 11350     def __init__(self, descriptorProvider, member, name, signature, extendedAttrs,
 11351                  breakAfter=True, passJSBitsAsNeeded=True, visibility="public",
 11352                  jsObjectsArePtr=False, variadicIsSequence=False):
 11353         """
 11354         If jsObjectsArePtr is true, typed arrays and "object" will be
 11355         passed as JSObject*.
 11357         If passJSBitsAsNeeded is false, we don't automatically pass in a
 11358         JSContext* or a JSObject* based on the return and argument types.  We
 11359         can still pass it based on 'implicitJSContext' annotations.
 11360         """
 11361         self.descriptorProvider = descriptorProvider
 11362         self.member = member
 11363         self.extendedAttrs = extendedAttrs
 11364         self.resultAlreadyAddRefed = isResultAlreadyAddRefed(self.extendedAttrs)
 11365         self.passJSBitsAsNeeded = passJSBitsAsNeeded
 11366         self.jsObjectsArePtr = jsObjectsArePtr
 11367         self.variadicIsSequence = variadicIsSequence
 11368         breakAfterSelf = "\n" if breakAfter else ""
 11369         ClassMethod.__init__(self, name,
 11370                              self.getReturnType(signature[0], False),
 11371                              self.getArgs(signature[0], signature[1]),
 11372                              static=member.isStatic(),
 11373                              # Mark our getters, which are attrs that
 11374                              # have a non-void return type, as const.
 11375                              const=(not member.isStatic() and member.isAttr() and
 11376                                     not signature[0].isVoid()),
 11377                              breakAfterReturnDecl=" ",
 11378                              breakAfterSelf=breakAfterSelf,
 11379                              visibility=visibility)
 11381     def getReturnType(self, type, isMember):
 11382         return self.getRetvalInfo(type, isMember)[0]
 11384     def getRetvalInfo(self, type, isMember):
 11385         """
 11386         Returns a tuple:
 11388         The first element is the type declaration for the retval
 11390         The second element is a default value that can be used on error returns.
 11391         For cases whose behavior depends on isMember, the second element will be
 11392         None if isMember is true.
 11394         The third element is a template for actually returning a value stored in
 11395         "${declName}" and "${holderName}".  This means actually returning it if
 11396         we're not outparam, else assigning to the "retval" outparam.  If
 11397         isMember is true, this can be None, since in that case the caller will
 11398         never examine this value.
 11399         """
 11400         if type.isVoid():
 11401             return "void", "", ""
 11402         if type.isPrimitive() and type.tag() in builtinNames:
 11403             result = CGGeneric(builtinNames[type.tag()])
 11404             defaultReturnArg = "0"
 11405             if type.nullable():
 11406                 result = CGTemplatedType("Nullable", result)
 11407                 defaultReturnArg = ""
 11408             return (result.define(),
 11409                     "%s(%s)" % (result.define(), defaultReturnArg),
 11410                     "return ${declName};\n")
 11411         if type.isDOMString():
 11412             if isMember:
 11413                 # No need for a third element in the isMember case
 11414                 return "nsString", None, None
 11415             # Outparam
 11416             return "void", "", "aRetVal = ${declName};\n"
 11417         if type.isByteString():
 11418             if isMember:
 11419                 # No need for a third element in the isMember case
 11420                 return "nsCString", None, None
 11421             # Outparam
 11422             return "void", "", "aRetVal = ${declName};\n"
 11423         if type.isEnum():
 11424             enumName = type.unroll().inner.identifier.name
 11425             if type.nullable():
 11426                 enumName = CGTemplatedType("Nullable",
 11427                                            CGGeneric(enumName)).define()
 11428                 defaultValue = "%s()" % enumName
 11429             else:
 11430                 defaultValue = "%s(0)" % enumName
 11431             return enumName, defaultValue, "return ${declName};\n"
 11432         if type.isGeckoInterface():
 11433             iface = type.unroll().inner
 11434             result = CGGeneric(self.descriptorProvider.getDescriptor(
 11435                 iface.identifier.name).prettyNativeType)
 11436             if self.resultAlreadyAddRefed:
 11437                 if isMember:
 11438                     holder = "nsRefPtr"
 11439                 else:
 11440                     holder = "already_AddRefed"
 11441                 if memberReturnsNewObject(self.member):
 11442                     warning = ""
 11443                 else:
 11444                     warning = "// Mark this as resultNotAddRefed to return raw pointers\n"
 11445                 result = CGWrapper(result,
 11446                                    pre=("%s%s<" % (warning, holder)),
 11447                                    post=">")
 11448             else:
 11449                 result = CGWrapper(result, post="*")
 11450             # Since we always force an owning type for callback return values,
 11451             # our ${declName} is an OwningNonNull or nsRefPtr.  So we can just
 11452             # .forget() to get our already_AddRefed.
 11453             return result.define(), "nullptr", "return ${declName}.forget();\n"
 11454         if type.isCallback():
 11455             return ("already_AddRefed<%s>" % type.unroll().identifier.name,
 11456                     "nullptr", "return ${declName}.forget();\n")
 11457         if type.isAny():
 11458             if isMember:
 11459                 # No need for a third element in the isMember case
 11460                 return "JS::Value", None, None
 11461             # Outparam
 11462             return "void", "", "aRetVal.set(${declName});\n"
 11464         if type.isObject():
 11465             if isMember:
 11466                 # No need for a third element in the isMember case
 11467                 return "JSObject*", None, None
 11468             return "void", "", "aRetVal.set(${declName});\n"
 11469         if type.isSpiderMonkeyInterface():
 11470             if isMember:
 11471                 # No need for a third element in the isMember case
 11472                 return "JSObject*", None, None
 11473             if type.nullable():
 11474                 returnCode = "${declName}.IsNull() ? nullptr : ${declName}.Value().Obj();\n"
 11475             else:
 11476                 returnCode = "${declName}.Obj();\n"
 11477             return "void", "", "aRetVal.set(%s);\n" % returnCode
 11478         if type.isSequence():
 11479             # If we want to handle sequence-of-sequences return values, we're
 11480             # going to need to fix example codegen to not produce nsTArray<void>
 11481             # for the relevant argument...
 11482             assert not isMember
 11483             # Outparam.
 11484             if type.nullable():
 11485                 returnCode = dedent("""
 11486                     if (${declName}.IsNull()) {
 11487                       aRetVal.SetNull();
 11488                     } else {
 11489                       aRetVal.SetValue().SwapElements(${declName}.Value());
 11491                     """)
 11492             else:
 11493                 returnCode = "aRetVal.SwapElements(${declName});\n"
 11494             return "void", "", returnCode
 11495         if type.isMozMap():
 11496             # If we want to handle MozMap-of-MozMap return values, we're
 11497             # going to need to fix example codegen to not produce MozMap<void>
 11498             # for the relevant argument...
 11499             assert not isMember
 11500             # In this case we convert directly into our outparam to start with
 11501             return "void", "", ""
 11502         if type.isDate():
 11503             result = CGGeneric("Date")
 11504             if type.nullable():
 11505                 result = CGTemplatedType("Nullable", result)
 11506             return (result.define(), "%s()" % result.define(),
 11507                     "return ${declName};\n")
 11508         if type.isDictionary():
 11509             if isMember:
 11510                 # Only the first member of the tuple matters here, but return
 11511                 # bogus values for the others in case someone decides to use
 11512                 # them.
 11513                 return CGDictionary.makeDictionaryName(type.inner), None, None
 11514             # In this case we convert directly into our outparam to start with
 11515             return "void", "", ""
 11516         if type.isUnion():
 11517             if isMember:
 11518                 # Only the first member of the tuple matters here, but return
 11519                 # bogus values for the others in case someone decides to use
 11520                 # them.
 11521                 return CGUnionStruct.unionTypeDecl(type, True), None, None
 11522             # In this case we convert directly into our outparam to start with
 11523             return "void", "", ""
 11525         raise TypeError("Don't know how to declare return value for %s" %
 11526                         type)
 11528     def getArgs(self, returnType, argList):
 11529         args = [self.getArg(arg) for arg in argList]
 11530         # Now the outparams
 11531         if returnType.isDOMString():
 11532             args.append(Argument("nsString&", "aRetVal"))
 11533         elif returnType.isByteString():
 11534             args.append(Argument("nsCString&", "aRetVal"))
 11535         elif returnType.isSequence():
 11536             nullable = returnType.nullable()
 11537             if nullable:
 11538                 returnType = returnType.inner
 11539             # And now the actual underlying type
 11540             elementDecl = self.getReturnType(returnType.inner, True)
 11541             type = CGTemplatedType("nsTArray", CGGeneric(elementDecl))
 11542             if nullable:
 11543                 type = CGTemplatedType("Nullable", type)
 11544             args.append(Argument("%s&" % type.define(), "aRetVal"))
 11545         elif returnType.isMozMap():
 11546             nullable = returnType.nullable()
 11547             if nullable:
 11548                 returnType = returnType.inner
 11549             # And now the actual underlying type
 11550             elementDecl = self.getReturnType(returnType.inner, True)
 11551             type = CGTemplatedType("MozMap", CGGeneric(elementDecl))
 11552             if nullable:
 11553                 type = CGTemplatedType("Nullable", type)
 11554             args.append(Argument("%s&" % type.define(), "aRetVal"))
 11555         elif returnType.isDictionary():
 11556             nullable = returnType.nullable()
 11557             if nullable:
 11558                 returnType = returnType.inner
 11559             dictType = CGGeneric(CGDictionary.makeDictionaryName(returnType.inner))
 11560             if nullable:
 11561                 dictType = CGTemplatedType("Nullable", dictType)
 11562             args.append(Argument("%s&" % dictType.define(), "aRetVal"))
 11563         elif returnType.isUnion():
 11564             args.append(Argument("%s&" %
 11565                                  CGUnionStruct.unionTypeDecl(returnType, True),
 11566                                  "aRetVal"))
 11567         elif returnType.isAny():
 11568             args.append(Argument("JS::MutableHandle<JS::Value>", "aRetVal"))
 11569         elif returnType.isObject() or returnType.isSpiderMonkeyInterface():
 11570             args.append(Argument("JS::MutableHandle<JSObject*>", "aRetVal"))
 11572         # And the ErrorResult
 11573         if 'infallible' not in self.extendedAttrs:
 11574             # Use aRv so it won't conflict with local vars named "rv"
 11575             args.append(Argument("ErrorResult&", "aRv"))
 11576         # The legacycaller thisval
 11577         if self.member.isMethod() and self.member.isLegacycaller():
 11578             # If it has an identifier, we can't deal with it yet
 11579             assert self.member.isIdentifierLess()
 11580             args.insert(0, Argument("JS::Value", "aThisVal"))
 11581         # And jscontext bits.
 11582         if needCx(returnType, argList, self.extendedAttrs,
 11583                   self.passJSBitsAsNeeded):
 11584             args.insert(0, Argument("JSContext*", "cx"))
 11585             if needScopeObject(returnType, argList, self.extendedAttrs,
 11586                                self.descriptorProvider.wrapperCache,
 11587                                self.passJSBitsAsNeeded,
 11588                                self.member.getExtendedAttribute("StoreInSlot")):
 11589                 args.insert(1, Argument("JS::Handle<JSObject*>", "obj"))
 11590         # And if we're static, a global
 11591         if self.member.isStatic():
 11592             args.insert(0, Argument("const GlobalObject&", "global"))
 11593         return args
 11595     def doGetArgType(self, type, optional, isMember):
 11596         """
 11597         The main work of getArgType.  Returns a string type decl, whether this
 11598         is a const ref, as well as whether the type should be wrapped in
 11599         Nullable as needed.
 11601         isMember can be false or one of the strings "Sequence", "Variadic",
 11602                  "MozMap"
 11603         """
 11604         if type.isArray():
 11605             raise TypeError("Can't handle array arguments yet")
 11607         if type.isSequence():
 11608             nullable = type.nullable()
 11609             if nullable:
 11610                 type = type.inner
 11611             elementType = type.inner
 11612             argType = self.getArgType(elementType, False, "Sequence")[0]
 11613             decl = CGTemplatedType("Sequence", argType)
 11614             return decl.define(), True, True
 11616         if type.isMozMap():
 11617             nullable = type.nullable()
 11618             if nullable:
 11619                 type = type.inner
 11620             elementType = type.inner
 11621             argType = self.getArgType(elementType, False, "MozMap")[0]
 11622             decl = CGTemplatedType("MozMap", argType)
 11623             return decl.define(), True, True
 11625         if type.isUnion():
 11626             # unionTypeDecl will handle nullable types, so return False for
 11627             # auto-wrapping in Nullable
 11628             return CGUnionStruct.unionTypeDecl(type, isMember), True, False
 11630         if type.isGeckoInterface() and not type.isCallbackInterface():
 11631             iface = type.unroll().inner
 11632             argIsPointer = type.nullable() or iface.isExternal()
 11633             forceOwningType = iface.isCallback() or isMember
 11634             if argIsPointer:
 11635                 if (optional or isMember) and forceOwningType:
 11636                     typeDecl = "nsRefPtr<%s>"
 11637                 else:
 11638                     typeDecl = "%s*"
 11639             else:
 11640                 if optional or isMember:
 11641                     if forceOwningType:
 11642                         typeDecl = "OwningNonNull<%s>"
 11643                     else:
 11644                         typeDecl = "NonNull<%s>"
 11645                 else:
 11646                     typeDecl = "%s&"
 11647             return ((typeDecl %
 11648                      self.descriptorProvider.getDescriptor(iface.identifier.name).prettyNativeType),
 11649                     False, False)
 11651         if type.isSpiderMonkeyInterface():
 11652             if self.jsObjectsArePtr:
 11653                 return "JSObject*", False, False
 11655             return type.name, True, True
 11657         if type.isDOMString():
 11658             if isMember:
 11659                 declType = "nsString"
 11660             else:
 11661                 declType = "nsAString"
 11662             return declType, True, False
 11664         if type.isByteString():
 11665             declType = "nsCString"
 11666             return declType, True, False
 11668         if type.isEnum():
 11669             return type.unroll().inner.identifier.name, False, True
 11671         if type.isCallback() or type.isCallbackInterface():
 11672             forceOwningType = optional or isMember
 11673             if type.nullable():
 11674                 if forceOwningType:
 11675                     declType = "nsRefPtr<%s>"
 11676                 else:
 11677                     declType = "%s*"
 11678             else:
 11679                 if forceOwningType:
 11680                     declType = "OwningNonNull<%s>"
 11681                 else:
 11682                     declType = "%s&"
 11683             if type.isCallback():
 11684                 name = type.unroll().identifier.name
 11685             else:
 11686                 name = type.unroll().inner.identifier.name
 11687             return declType % name, False, False
 11689         if type.isAny():
 11690             # Don't do the rooting stuff for variadics for now
 11691             if isMember:
 11692                 declType = "JS::Value"
 11693             else:
 11694                 declType = "JS::Handle<JS::Value>"
 11695             return declType, False, False
 11697         if type.isObject():
 11698             if isMember:
 11699                 declType = "JSObject*"
 11700             else:
 11701                 declType = "JS::Handle<JSObject*>"
 11702             return declType, False, False
 11704         if type.isDictionary():
 11705             typeName = CGDictionary.makeDictionaryName(type.inner)
 11706             return typeName, True, True
 11708         if type.isDate():
 11709             return "Date", False, True
 11711         assert type.isPrimitive()
 11713         return builtinNames[type.tag()], False, True
 11715     def getArgType(self, type, optional, isMember):
 11716         """
 11717         Get the type of an argument declaration.  Returns the type CGThing, and
 11718         whether this should be a const ref.
 11720         isMember can be False, "Sequence", or "Variadic"
 11721         """
 11722         decl, ref, handleNullable = self.doGetArgType(type, optional, isMember)
 11723         decl = CGGeneric(decl)
 11724         if handleNullable and type.nullable():
 11725             decl = CGTemplatedType("Nullable", decl)
 11726             ref = True
 11727         if isMember == "Variadic":
 11728             arrayType = "Sequence" if self.variadicIsSequence else "nsTArray"
 11729             decl = CGTemplatedType(arrayType, decl)
 11730             ref = True
 11731         elif optional:
 11732             # Note: All variadic args claim to be optional, but we can just use
 11733             # empty arrays to represent them not being present.
 11734             decl = CGTemplatedType("Optional", decl)
 11735             ref = True
 11736         return (decl, ref)
 11738     def getArg(self, arg):
 11739         """
 11740         Get the full argument declaration for an argument
 11741         """
 11742         decl, ref = self.getArgType(arg.type,
 11743                                     arg.optional and not arg.defaultValue,
 11744                                     "Variadic" if arg.variadic else False)
 11745         if ref:
 11746             decl = CGWrapper(decl, pre="const ", post="&")
 11748         return Argument(decl.define(), arg.identifier.name)
 11751 class CGExampleMethod(CGNativeMember):
 11752     def __init__(self, descriptor, method, signature, isConstructor, breakAfter=True):
 11753         CGNativeMember.__init__(self, descriptor, method,
 11754                                 CGSpecializedMethod.makeNativeName(descriptor,
 11755                                                                    method),
 11756                                 signature,
 11757                                 descriptor.getExtendedAttributes(method),
 11758                                 breakAfter=breakAfter,
 11759                                 variadicIsSequence=True)
 11761     def define(self, cgClass):
 11762         return ''
 11765 class CGExampleGetter(CGNativeMember):
 11766     def __init__(self, descriptor, attr):
 11767         CGNativeMember.__init__(self, descriptor, attr,
 11768                                 CGSpecializedGetter.makeNativeName(descriptor,
 11769                                                                    attr),
 11770                                 (attr.type, []),
 11771                                 descriptor.getExtendedAttributes(attr,
 11772                                                                  getter=True))
 11774     def define(self, cgClass):
 11775         return ''
 11778 class CGExampleSetter(CGNativeMember):
 11779     def __init__(self, descriptor, attr):
 11780         CGNativeMember.__init__(self, descriptor, attr,
 11781                                 CGSpecializedSetter.makeNativeName(descriptor,
 11782                                                                    attr),
 11783                                 (BuiltinTypes[IDLBuiltinType.Types.void],
 11784                                  [FakeArgument(attr.type, attr)]),
 11785                                 descriptor.getExtendedAttributes(attr,
 11786                                                                  setter=True))
 11788     def define(self, cgClass):
 11789         return ''
 11792 class CGBindingImplClass(CGClass):
 11793     """
 11794     Common codegen for generating a C++ implementation of a WebIDL interface
 11795     """
 11796     def __init__(self, descriptor, cgMethod, cgGetter, cgSetter, wantGetParent=True):
 11797         """
 11798         cgMethod, cgGetter and cgSetter are classes used to codegen methods,
 11799         getters and setters.
 11800         """
 11801         self.descriptor = descriptor
 11802         self._deps = descriptor.interface.getDeps()
 11804         iface = descriptor.interface
 11806         self.methodDecls = []
 11808         def appendMethod(m, isConstructor=False):
 11809             sigs = m.signatures()
 11810             for s in sigs[:-1]:
 11811                 # Don't put a blank line after overloads, until we
 11812                 # get to the last one.
 11813                 self.methodDecls.append(cgMethod(descriptor, m, s,
 11814                                                  isConstructor,
 11815                                                  breakAfter=False))
 11816             self.methodDecls.append(cgMethod(descriptor, m, sigs[-1],
 11817                                              isConstructor))
 11819         if iface.ctor():
 11820             appendMethod(iface.ctor(), isConstructor=True)
 11821         for n in iface.namedConstructors:
 11822             appendMethod(n, isConstructor=True)
 11823         for m in iface.members:
 11824             if m.isMethod():
 11825                 if m.isIdentifierLess():
 11826                     continue
 11827                 appendMethod(m)
 11828             elif m.isAttr():
 11829                 self.methodDecls.append(cgGetter(descriptor, m))
 11830                 if not m.readonly:
 11831                     self.methodDecls.append(cgSetter(descriptor, m))
 11833         # Now do the special operations
 11834         def appendSpecialOperation(name, op):
 11835             if op is None:
 11836                 return
 11837             if name == "IndexedCreator" or name == "NamedCreator":
 11838                 # These are identical to the setters
 11839                 return
 11840             assert len(op.signatures()) == 1
 11841             returnType, args = op.signatures()[0]
 11842             # Make a copy of the args, since we plan to modify them.
 11843             args = list(args)
 11844             if op.isGetter() or op.isDeleter():
 11845                 # This is a total hack.  The '&' belongs with the
 11846                 # type, not the name!  But it works, and is simpler
 11847                 # than trying to somehow make this pretty.
 11848                 args.append(FakeArgument(BuiltinTypes[IDLBuiltinType.Types.boolean],
 11849                                          op, name="&found"))
 11850             if name == "Stringifier":
 11851                 if op.isIdentifierLess():
 11852                     # XXXbz I wish we were consistent about our renaming here.
 11853                     name = "Stringify"
 11854                 else:
 11855                     # We already added this method
 11856                     return
 11857             if name == "LegacyCaller":
 11858                 if op.isIdentifierLess():
 11859                     # XXXbz I wish we were consistent about our renaming here.
 11860                     name = "LegacyCall"
 11861                 else:
 11862                     # We already added this method
 11863                     return
 11864             if name == "Jsonifier":
 11865                 # We already added this method
 11866                 return
 11867             self.methodDecls.append(
 11868                 CGNativeMember(descriptor, op,
 11869                                name,
 11870                                (returnType, args),
 11871                                descriptor.getExtendedAttributes(op)))
 11872         # Sort things by name so we get stable ordering in the output.
 11873         ops = descriptor.operations.items()
 11874         ops.sort(key=lambda x: x[0])
 11875         for name, op in ops:
 11876             appendSpecialOperation(name, op)
 11877         # If we support indexed properties, then we need a Length()
 11878         # method so we know which indices are supported.
 11879         if descriptor.supportsIndexedProperties():
 11880             # But we don't need it if we already have an infallible
 11881             # "length" attribute, which we often do.
 11882             haveLengthAttr = any(
 11883                 m for m in iface.members if m.isAttr() and
 11884                 CGSpecializedGetter.makeNativeName(descriptor, m) == "Length")
 11885             if not haveLengthAttr:
 11886                 self.methodDecls.append(
 11887                     CGNativeMember(descriptor, FakeMember(),
 11888                                    "Length",
 11889                                    (BuiltinTypes[IDLBuiltinType.Types.unsigned_long],
 11890                                     []),
 11891                                    {"infallible": True}))
 11892         # And if we support named properties we need to be able to
 11893         # enumerate the supported names and test whether they're enumerable.
 11894         if descriptor.supportsNamedProperties():
 11895             self.methodDecls.append(
 11896                 CGNativeMember(
 11897                     descriptor, FakeMember(),
 11898                     "GetSupportedNames",
 11899                     (IDLSequenceType(None,
 11900                                      BuiltinTypes[IDLBuiltinType.Types.domstring]),
 11901                      # Let's use unsigned long for the type here, though really
 11902                      # it's just a C++ "unsigned"...
 11903                      [FakeArgument(BuiltinTypes[IDLBuiltinType.Types.unsigned_long],
 11904                                    FakeMember(),
 11905                                    name="aFlags")]),
 11906                     {"infallible": True}))
 11907             self.methodDecls.append(
 11908                 CGNativeMember(
 11909                     descriptor, FakeMember(),
 11910                     "NameIsEnumerable",
 11911                     (BuiltinTypes[IDLBuiltinType.Types.boolean],
 11912                      [FakeArgument(BuiltinTypes[IDLBuiltinType.Types.domstring],
 11913                                    FakeMember(),
 11914                                    name="aName")]),
 11915                     { "infallible": True }))
 11917         wrapArgs = [Argument('JSContext*', 'aCx')]
 11918         self.methodDecls.insert(0,
 11919                                 ClassMethod("WrapObject", "JSObject*",
 11920                                             wrapArgs, virtual=descriptor.wrapperCache,
 11921                                             breakAfterReturnDecl=" ",
 11922                                             override=descriptor.wrapperCache,
 11923                                             body=self.getWrapObjectBody()))
 11924         if wantGetParent:
 11925             self.methodDecls.insert(0,
 11926                                     ClassMethod("GetParentObject",
 11927                                                 self.getGetParentObjectReturnType(),
 11928                                                 [], const=True,
 11929                                                 breakAfterReturnDecl=" ",
 11930                                                 body=self.getGetParentObjectBody()))
 11932         # Invoke  CGClass.__init__ in any subclasses afterwards to do the actual codegen.
 11934     def getWrapObjectBody(self):
 11935         return None
 11937     def getGetParentObjectReturnType(self):
 11938         return ("// TODO: return something sensible here, and change the return type\n"
 11939                 "%s*" % self.descriptor.nativeType.split('::')[-1])
 11941     def getGetParentObjectBody(self):
 11942         return None
 11944     def deps(self):
 11945         return self._deps
 11948 class CGExampleClass(CGBindingImplClass):
 11949     """
 11950     Codegen for the actual example class implementation for this descriptor
 11951     """
 11952     def __init__(self, descriptor):
 11953         CGBindingImplClass.__init__(self, descriptor,
 11954                                     CGExampleMethod, CGExampleGetter, CGExampleSetter,
 11955                                     wantGetParent=descriptor.wrapperCache)
 11957         self.refcounted = descriptor.nativeOwnership == "refcounted"
 11959         self.parentIface = descriptor.interface.parent
 11960         if self.parentIface:
 11961             self.parentDesc = descriptor.getDescriptor(
 11962                 self.parentIface.identifier.name)
 11963             bases = [ClassBase(self.nativeLeafName(self.parentDesc))]
 11964         else:
 11965             bases = []
 11966             if self.refcounted:
 11967                 bases.append(ClassBase("nsISupports /* Change nativeOwnership in the binding configuration if you don't want this */"))
 11968                 if descriptor.wrapperCache:
 11969                     bases.append(ClassBase("nsWrapperCache /* Change wrapperCache in the binding configuration if you don't want this */"))
 11970             else:
 11971                 bases.append(ClassBase("NonRefcountedDOMObject"))
 11973         if self.refcounted:
 11974             if self.parentIface:
 11975                 extradeclarations = (
 11976                     "public:\n"
 11977                     "  NS_DECL_ISUPPORTS_INHERITED\n"
 11978                     "  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(%s, %s)\n"
 11979                     "\n" % (self.nativeLeafName(descriptor),
 11980                             self.nativeLeafName(self.parentDesc)))
 11981             else:
 11982                 extradeclarations = (
 11983                     "public:\n"
 11984                     "  NS_DECL_CYCLE_COLLECTING_ISUPPORTS\n"
 11985                     "  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(%s)\n"
 11986                     "\n" % self.nativeLeafName(descriptor))
 11987         else:
 11988             extradeclarations = ""
 11990         if descriptor.interface.hasChildInterfaces():
 11991             decorators = ""
 11992         else:
 11993             decorators = "MOZ_FINAL"
 11995         CGClass.__init__(self, self.nativeLeafName(descriptor),
 11996                          bases=bases,
 11997                          constructors=[ClassConstructor([],
 11998                                                         visibility="public")],
 11999                          destructor=ClassDestructor(visibility="public"),
 12000                          methods=self.methodDecls,
 12001                          decorators=decorators,
 12002                          extradeclarations=extradeclarations)
 12004     def define(self):
 12005         # Just override CGClass and do our own thing
 12006         if self.descriptor.wrapperCache:
 12007             setDOMBinding = "  SetIsDOMBinding();\n"
 12008         else:
 12009             setDOMBinding = ""
 12010         if self.refcounted:
 12011             ctordtor = dedent("""
 12012                 ${nativeType}::${nativeType}()
 12014                 %s}
 12016                 ${nativeType}::~${nativeType}()
 12019                 """) % setDOMBinding
 12020         else:
 12021             ctordtor = dedent("""
 12022                 ${nativeType}::${nativeType}()
 12024                   MOZ_COUNT_CTOR(${nativeType});
 12027                 ${nativeType}::~${nativeType}()
 12029                   MOZ_COUNT_DTOR(${nativeType});
 12031                 """)
 12033         if self.refcounted:
 12034             if self.parentIface:
 12035                 ccImpl = dedent("""
 12037                     NS_IMPL_CYCLE_COLLECTION_INHERITED_0(${nativeType}, ${parentType})
 12038                     NS_IMPL_ADDREF_INHERITED(${nativeType}, ${parentType})
 12039                     NS_IMPL_RELEASE_INHERITED(${nativeType}, ${parentType})
 12040                     NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
 12041                     NS_INTERFACE_MAP_END_INHERITING(${parentType})
 12043                     """)
 12044             else:
 12045                 ccImpl = dedent("""
 12047                     NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(${nativeType})
 12048                     NS_IMPL_CYCLE_COLLECTING_ADDREF(${nativeType})
 12049                     NS_IMPL_CYCLE_COLLECTING_RELEASE(${nativeType})
 12050                     NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
 12051                       NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
 12052                       NS_INTERFACE_MAP_ENTRY(nsISupports)
 12053                     NS_INTERFACE_MAP_END
 12055                     """)
 12056         else:
 12057             ccImpl = ""
 12059         classImpl = ccImpl + ctordtor + "\n" + dedent("""
 12060             JSObject*
 12061             ${nativeType}::WrapObject(JSContext* aCx)
 12063               return ${ifaceName}Binding::Wrap(aCx, this);
 12066             """)
 12067         return string.Template(classImpl).substitute(
 12068             ifaceName=self.descriptor.name,
 12069             nativeType=self.nativeLeafName(self.descriptor),
 12070             parentType=self.nativeLeafName(self.parentDesc) if self.parentIface else "")
 12072     @staticmethod
 12073     def nativeLeafName(descriptor):
 12074         return descriptor.nativeType.split('::')[-1]
 12077 class CGExampleRoot(CGThing):
 12078     """
 12079     Root codegen class for example implementation generation.  Instantiate the
 12080     class and call declare or define to generate header or cpp code,
 12081     respectively.
 12082     """
 12083     def __init__(self, config, interfaceName):
 12084         # Let's assume we're not doing workers stuff
 12085         descriptor = config.getDescriptor(interfaceName, False)
 12087         self.root = CGWrapper(CGExampleClass(descriptor),
 12088                               pre="\n", post="\n")
 12090         self.root = CGNamespace.build(["mozilla", "dom"], self.root)
 12092         self.root = CGList([CGClassForwardDeclare("JSContext", isStruct=True),
 12093                             self.root], "\n")
 12095         # Throw in our #includes
 12096         self.root = CGHeaders([], [], [], [],
 12097                               ["nsWrapperCache.h",
 12098                                "nsCycleCollectionParticipant.h",
 12099                                "mozilla/Attributes.h",
 12100                                "mozilla/ErrorResult.h"],
 12101                               ["mozilla/dom/%s.h" % interfaceName,
 12102                                ("mozilla/dom/%s" %
 12103                                 CGHeaders.getDeclarationFilename(descriptor.interface))], "", self.root)
 12105         # And now some include guards
 12106         self.root = CGIncludeGuard(interfaceName, self.root)
 12108         # And our license block comes before everything else
 12109         self.root = CGWrapper(self.root, pre=dedent("""
 12110             /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 12111             /* vim:set ts=2 sw=2 sts=2 et cindent: */
 12112             /* This Source Code Form is subject to the terms of the Mozilla Public
 12113              * License, v. 2.0. If a copy of the MPL was not distributed with this
 12114              * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 12116             """))
 12118     def declare(self):
 12119         return self.root.declare()
 12121     def define(self):
 12122         return self.root.define()
 12125 def jsImplName(name):
 12126     return name + "JSImpl"
 12129 class CGJSImplMember(CGNativeMember):
 12130     """
 12131     Base class for generating code for the members of the implementation class
 12132     for a JS-implemented WebIDL interface.
 12133     """
 12134     def __init__(self, descriptorProvider, member, name, signature,
 12135                  extendedAttrs, breakAfter=True, passJSBitsAsNeeded=True,
 12136                  visibility="public", jsObjectsArePtr=False,
 12137                  variadicIsSequence=False):
 12138         CGNativeMember.__init__(self, descriptorProvider, member, name,
 12139                                 signature, extendedAttrs, breakAfter=breakAfter,
 12140                                 passJSBitsAsNeeded=passJSBitsAsNeeded,
 12141                                 visibility=visibility,
 12142                                 jsObjectsArePtr=jsObjectsArePtr,
 12143                                 variadicIsSequence=variadicIsSequence)
 12144         self.body = self.getImpl()
 12146     def getArgs(self, returnType, argList):
 12147         args = CGNativeMember.getArgs(self, returnType, argList)
 12148         args.append(Argument("JSCompartment*", "aCompartment", "nullptr"))
 12149         return args
 12152 class CGJSImplMethod(CGJSImplMember):
 12153     """
 12154     Class for generating code for the methods for a JS-implemented WebIDL
 12155     interface.
 12156     """
 12157     def __init__(self, descriptor, method, signature, isConstructor, breakAfter=True):
 12158         self.signature = signature
 12159         self.descriptor = descriptor
 12160         self.isConstructor = isConstructor
 12161         CGJSImplMember.__init__(self, descriptor, method,
 12162                                 CGSpecializedMethod.makeNativeName(descriptor,
 12163                                                                    method),
 12164                                 signature,
 12165                                 descriptor.getExtendedAttributes(method),
 12166                                 breakAfter=breakAfter,
 12167                                 variadicIsSequence=True,
 12168                                 passJSBitsAsNeeded=False)
 12170     def getArgs(self, returnType, argList):
 12171         if self.isConstructor:
 12172             # Skip the JSCompartment bits for constructors; it's handled
 12173             # manually in getImpl.
 12174             return CGNativeMember.getArgs(self, returnType, argList)
 12175         return CGJSImplMember.getArgs(self, returnType, argList)
 12177     def getImpl(self):
 12178         args = self.getArgs(self.signature[0], self.signature[1])
 12179         if not self.isConstructor:
 12180             return 'return mImpl->%s(%s);\n' % (self.name, ", ".join(arg.name for arg in args))
 12182         assert self.descriptor.interface.isJSImplemented()
 12183         if self.name != 'Constructor':
 12184             raise TypeError("Named constructors are not supported for JS implemented WebIDL. See bug 851287.")
 12185         if len(self.signature[1]) != 0:
 12186             # The first two arguments to the constructor implementation are not
 12187             # arguments to the WebIDL constructor, so don't pass them to __Init()
 12188             assert args[0].argType == 'const GlobalObject&'
 12189             assert args[1].argType == 'JSContext*'
 12190             constructorArgs = [arg.name for arg in args[2:]]
 12191             constructorArgs.append("js::GetObjectCompartment(scopeObj)")
 12192             initCall = fill(
 12193                 """
 12194                 // Wrap the object before calling __Init so that __DOM_IMPL__ is available.
 12195                 nsCOMPtr<nsIGlobalObject> globalHolder = do_QueryInterface(window);
 12196                 JS::Rooted<JSObject*> scopeObj(cx, globalHolder->GetGlobalJSObject());
 12197                 MOZ_ASSERT(js::IsObjectInContextCompartment(scopeObj, cx));
 12198                 JS::Rooted<JS::Value> wrappedVal(cx);
 12199                 if (!WrapNewBindingObject(cx, impl, &wrappedVal)) {
 12200                   //XXX Assertion disabled for now, see bug 991271.
 12201                   MOZ_ASSERT(true || JS_IsExceptionPending(cx));
 12202                   aRv.Throw(NS_ERROR_UNEXPECTED);
 12203                   return nullptr;
 12205                 // Initialize the object with the constructor arguments.
 12206                 impl->mImpl->__Init(${args});
 12207                 if (aRv.Failed()) {
 12208                   return nullptr;
 12210                 """,
 12211                 args=", ".join(constructorArgs))
 12212         else:
 12213             initCall = ""
 12214         return genConstructorBody(self.descriptor, initCall)
 12217 def genConstructorBody(descriptor, initCall=""):
 12218     return fill(
 12219         """
 12220         JS::Rooted<JSObject*> jsImplObj(cx);
 12221         nsCOMPtr<nsPIDOMWindow> window =
 12222           ConstructJSImplementation(cx, "${contractId}", global, &jsImplObj, aRv);
 12223         if (aRv.Failed()) {
 12224           return nullptr;
 12226         // Build the C++ implementation.
 12227         nsRefPtr<${implClass}> impl = new ${implClass}(jsImplObj, window);
 12228         $*{initCall}
 12229         return impl.forget();
 12230         """,
 12231         contractId=descriptor.interface.getJSImplementation(),
 12232         implClass=descriptor.name,
 12233         initCall=initCall)
 12236 # We're always fallible
 12237 def callbackGetterName(attr, descriptor):
 12238     return "Get" + MakeNativeName(
 12239         descriptor.binaryNames.get(attr.identifier.name, attr.identifier.name))
 12242 def callbackSetterName(attr, descriptor):
 12243     return "Set" + MakeNativeName(
 12244         descriptor.binaryNames.get(attr.identifier.name, attr.identifier.name))
 12247 class CGJSImplGetter(CGJSImplMember):
 12248     """
 12249     Class for generating code for the getters of attributes for a JS-implemented
 12250     WebIDL interface.
 12251     """
 12252     def __init__(self, descriptor, attr):
 12253         CGJSImplMember.__init__(self, descriptor, attr,
 12254                                 CGSpecializedGetter.makeNativeName(descriptor,
 12255                                                                    attr),
 12256                                 (attr.type, []),
 12257                                 descriptor.getExtendedAttributes(attr,
 12258                                                                  getter=True),
 12259                                 passJSBitsAsNeeded=False)
 12261     def getImpl(self):
 12262         callbackArgs = [arg.name for arg in self.getArgs(self.member.type, [])]
 12263         return 'return mImpl->%s(%s);\n' % (
 12264             callbackGetterName(self.member, self.descriptorProvider),
 12265             ", ".join(callbackArgs))
 12268 class CGJSImplSetter(CGJSImplMember):
 12269     """
 12270     Class for generating code for the setters of attributes for a JS-implemented
 12271     WebIDL interface.
 12272     """
 12273     def __init__(self, descriptor, attr):
 12274         CGJSImplMember.__init__(self, descriptor, attr,
 12275                                 CGSpecializedSetter.makeNativeName(descriptor,
 12276                                                                    attr),
 12277                                 (BuiltinTypes[IDLBuiltinType.Types.void],
 12278                                  [FakeArgument(attr.type, attr)]),
 12279                                 descriptor.getExtendedAttributes(attr,
 12280                                                                  setter=True),
 12281                                 passJSBitsAsNeeded=False)
 12283     def getImpl(self):
 12284         callbackArgs = [arg.name for arg in self.getArgs(BuiltinTypes[IDLBuiltinType.Types.void],
 12285                                                          [FakeArgument(self.member.type, self.member)])]
 12286         return 'mImpl->%s(%s);\n' % (
 12287             callbackSetterName(self.member, self.descriptorProvider),
 12288             ", ".join(callbackArgs))
 12291 class CGJSImplClass(CGBindingImplClass):
 12292     def __init__(self, descriptor):
 12293         CGBindingImplClass.__init__(self, descriptor, CGJSImplMethod, CGJSImplGetter, CGJSImplSetter)
 12295         if descriptor.interface.parent:
 12296             parentClass = descriptor.getDescriptor(
 12297                 descriptor.interface.parent.identifier.name).jsImplParent
 12298             baseClasses = [ClassBase(parentClass)]
 12299             isupportsDecl = "NS_DECL_ISUPPORTS_INHERITED\n"
 12300             ccDecl = ("NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(%s, %s)\n" %
 12301                       (descriptor.name, parentClass))
 12302             constructorBody = dedent("""
 12303                 // Make sure we're an nsWrapperCache already
 12304                 MOZ_ASSERT(static_cast<nsWrapperCache*>(this));
 12305                 // And that our ancestor has called SetIsDOMBinding()
 12306                 MOZ_ASSERT(IsDOMBinding());
 12307                 """)
 12308             extradefinitions = fill(
 12309                 """
 12310                 NS_IMPL_CYCLE_COLLECTION_INHERITED(${ifaceName}, ${parentClass}, mImpl, mParent)
 12311                 NS_IMPL_ADDREF_INHERITED(${ifaceName}, ${parentClass})
 12312                 NS_IMPL_RELEASE_INHERITED(${ifaceName}, ${parentClass})
 12313                 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(${ifaceName})
 12314                 NS_INTERFACE_MAP_END_INHERITING(${parentClass})
 12315                 """,
 12316                 ifaceName=self.descriptor.name,
 12317                 parentClass=parentClass)
 12318         else:
 12319             baseClasses = [ClassBase("nsSupportsWeakReference"),
 12320                            ClassBase("nsWrapperCache")]
 12321             isupportsDecl = "NS_DECL_CYCLE_COLLECTING_ISUPPORTS\n"
 12322             ccDecl = ("NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(%s)\n" %
 12323                       descriptor.name)
 12324             constructorBody = "SetIsDOMBinding();\n"
 12325             extradefinitions = fill(
 12326                 """
 12327                 NS_IMPL_CYCLE_COLLECTION_CLASS(${ifaceName})
 12328                 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(${ifaceName})
 12329                   NS_IMPL_CYCLE_COLLECTION_UNLINK(mImpl)
 12330                   NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
 12331                   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 12332                   tmp->ClearWeakReferences();
 12333                 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 12334                 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(${ifaceName})
 12335                   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImpl)
 12336                   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
 12337                   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 12338                 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 12339                 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(${ifaceName})
 12340                 NS_IMPL_CYCLE_COLLECTING_ADDREF(${ifaceName})
 12341                 NS_IMPL_CYCLE_COLLECTING_RELEASE(${ifaceName})
 12342                 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${ifaceName})
 12343                   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
 12344                   NS_INTERFACE_MAP_ENTRY(nsISupports)
 12345                   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 12346                 NS_INTERFACE_MAP_END
 12347                 """,
 12348                 ifaceName=self.descriptor.name)
 12350         extradeclarations = fill(
 12351             """
 12352             public:
 12353               $*{isupportsDecl}
 12354               $*{ccDecl}
 12356             private:
 12357               nsRefPtr<${jsImplName}> mImpl;
 12358               nsCOMPtr<nsISupports> mParent;
 12360             """,
 12361             isupportsDecl=isupportsDecl,
 12362             ccDecl=ccDecl,
 12363             jsImplName=jsImplName(descriptor.name))
 12365         if descriptor.interface.hasChildInterfaces():
 12366             decorators = ""
 12367             # We need a public virtual destructor our subclasses can use
 12368             destructor = ClassDestructor(virtual=True, visibility="public")
 12369         else:
 12370             decorators = "MOZ_FINAL"
 12371             destructor = None
 12373         baseConstructors = [
 12374             ("mImpl(new %s(aJSImplObject, /* aIncumbentGlobal = */ nullptr))" %
 12375              jsImplName(descriptor.name)),
 12376             "mParent(aParent)"]
 12377         parentInterface = descriptor.interface.parent
 12378         while parentInterface:
 12379             if parentInterface.isJSImplemented():
 12380                 baseConstructors.insert(
 12381                     0, "%s(aJSImplObject, aParent)" % parentClass)
 12382                 break
 12383             parentInterface = parentInterface.parent
 12384         if not parentInterface and descriptor.interface.parent:
 12385             # We only have C++ ancestors, so only pass along the window
 12386             baseConstructors.insert(0,
 12387                                     "%s(aParent)" % parentClass)
 12389         constructor = ClassConstructor(
 12390             [Argument("JS::Handle<JSObject*>", "aJSImplObject"),
 12391              Argument("nsPIDOMWindow*", "aParent")],
 12392             visibility="public",
 12393             baseConstructors=baseConstructors,
 12394             body=constructorBody)
 12396         self.methodDecls.append(
 12397             ClassMethod("_Create",
 12398                         "bool",
 12399                         [Argument("JSContext*", "cx"),
 12400                          Argument("unsigned", "argc"),
 12401                          Argument("JS::Value*", "vp")],
 12402                         static=True,
 12403                         body=self.getCreateFromExistingBody()))
 12405         CGClass.__init__(self, descriptor.name,
 12406                          bases=baseClasses,
 12407                          constructors=[constructor],
 12408                          destructor=destructor,
 12409                          methods=self.methodDecls,
 12410                          decorators=decorators,
 12411                          extradeclarations=extradeclarations,
 12412                          extradefinitions=extradefinitions)
 12414     def getWrapObjectBody(self):
 12415         return fill(
 12416             """
 12417             JS::Rooted<JSObject*> obj(aCx, ${name}Binding::Wrap(aCx, this));
 12418             if (!obj) {
 12419               return nullptr;
 12422             // Now define it on our chrome object
 12423             JSAutoCompartment ac(aCx, mImpl->Callback());
 12424             if (!JS_WrapObject(aCx, &obj)) {
 12425               return nullptr;
 12427             if (!JS_DefineProperty(aCx, mImpl->Callback(), "__DOM_IMPL__", obj, 0)) {
 12428               return nullptr;
 12430             return obj;
 12431             """,
 12432             name=self.descriptor.name)
 12434     def getGetParentObjectReturnType(self):
 12435         return "nsISupports*"
 12437     def getGetParentObjectBody(self):
 12438         return "return mParent;\n"
 12440     def getCreateFromExistingBody(self):
 12441         # XXXbz we could try to get parts of this (e.g. the argument
 12442         # conversions) auto-generated by somehow creating an IDLMethod and
 12443         # adding it to our interface, but we'd still need to special-case the
 12444         # implementation slightly to have it not try to forward to the JS
 12445         # object...
 12446         return fill(
 12447             """
 12448             JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
 12449             if (args.length() < 2) {
 12450               return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "${ifaceName}._create");
 12452             if (!args[0].isObject()) {
 12453               return ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Argument 1 of ${ifaceName}._create");
 12455             if (!args[1].isObject()) {
 12456               return ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Argument 2 of ${ifaceName}._create");
 12459             // GlobalObject will go through wrappers as needed for us, and
 12460             // is simpler than the right UnwrapArg incantation.
 12461             GlobalObject global(cx, &args[0].toObject());
 12462             if (global.Failed()) {
 12463               return false;
 12465             nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global.GetAsSupports());
 12466             if (!window) {
 12467               return ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "Argument 1 of ${ifaceName}._create", "Window");
 12469             JS::Rooted<JSObject*> arg(cx, &args[1].toObject());
 12470             nsRefPtr<${implName}> impl = new ${implName}(arg, window);
 12471             MOZ_ASSERT(js::IsObjectInContextCompartment(arg, cx));
 12472             return WrapNewBindingObject(cx, impl, args.rval());
 12473             """,
 12474             ifaceName=self.descriptor.interface.identifier.name,
 12475             implName=self.descriptor.name)
 12478 def isJSImplementedDescriptor(descriptorProvider):
 12479     return (isinstance(descriptorProvider, Descriptor) and
 12480             descriptorProvider.interface.isJSImplemented())
 12483 class CGCallback(CGClass):
 12484     def __init__(self, idlObject, descriptorProvider, baseName, methods,
 12485                  getters=[], setters=[]):
 12486         self.baseName = baseName
 12487         self._deps = idlObject.getDeps()
 12488         self.idlObject = idlObject
 12489         name = idlObject.identifier.name
 12490         if isJSImplementedDescriptor(descriptorProvider):
 12491             name = jsImplName(name)
 12492         # For our public methods that needThisHandling we want most of the
 12493         # same args and the same return type as what CallbackMember
 12494         # generates.  So we want to take advantage of all its
 12495         # CGNativeMember infrastructure, but that infrastructure can't deal
 12496         # with templates and most especially template arguments.  So just
 12497         # cheat and have CallbackMember compute all those things for us.
 12498         realMethods = []
 12499         for method in methods:
 12500             if not method.needThisHandling:
 12501                 realMethods.append(method)
 12502             else:
 12503                 realMethods.extend(self.getMethodImpls(method))
 12504         realMethods.append(
 12505             ClassMethod("operator==", "bool",
 12506                         [Argument("const %s&" % name, "aOther")],
 12507                         inline=True, bodyInHeader=True,
 12508                         const=True,
 12509                         body=("return %s::operator==(aOther);\n" % baseName)))
 12510         CGClass.__init__(self, name,
 12511                          bases=[ClassBase(baseName)],
 12512                          constructors=self.getConstructors(),
 12513                          methods=realMethods+getters+setters)
 12515     def getConstructors(self):
 12516         if (not self.idlObject.isInterface() and
 12517             not self.idlObject._treatNonObjectAsNull):
 12518             body = "MOZ_ASSERT(JS_ObjectIsCallable(nullptr, mCallback));\n"
 12519         else:
 12520             # Not much we can assert about it, other than not being null, and
 12521             # CallbackObject does that already.
 12522             body = ""
 12523         return [ClassConstructor(
 12524             [Argument("JS::Handle<JSObject*>", "aCallback"),
 12525              Argument("nsIGlobalObject*", "aIncumbentGlobal")],
 12526             bodyInHeader=True,
 12527             visibility="public",
 12528             explicit=True,
 12529             baseConstructors=[
 12530                 "%s(aCallback, aIncumbentGlobal)" % self.baseName,
 12531             ],
 12532             body=body)]
 12534     def getMethodImpls(self, method):
 12535         assert method.needThisHandling
 12536         args = list(method.args)
 12537         # Strip out the JSContext*/JSObject* args
 12538         # that got added.
 12539         assert args[0].name == "cx" and args[0].argType == "JSContext*"
 12540         assert args[1].name == "aThisVal" and args[1].argType == "JS::Handle<JS::Value>"
 12541         args = args[2:]
 12542         # Record the names of all the arguments, so we can use them when we call
 12543         # the private method.
 12544         argnames = [arg.name for arg in args]
 12545         argnamesWithThis = ["s.GetContext()", "thisValJS"] + argnames
 12546         argnamesWithoutThis = ["s.GetContext()", "JS::UndefinedHandleValue"] + argnames
 12547         # Now that we've recorded the argnames for our call to our private
 12548         # method, insert our optional argument for deciding whether the
 12549         # CallSetup should re-throw exceptions on aRv.
 12550         args.append(Argument("ExceptionHandling", "aExceptionHandling",
 12551                              "eReportExceptions"))
 12552         # And now insert our template argument.
 12553         argsWithoutThis = list(args)
 12554         args.insert(0, Argument("const T&",  "thisObjPtr"))
 12555         errorReturn = method.getDefaultRetval()
 12557         setupCall = fill(
 12558             """
 12559             CallSetup s(this, aRv, aExceptionHandling);
 12560             if (!s.GetContext()) {
 12561               aRv.Throw(NS_ERROR_UNEXPECTED);
 12562               return${errorReturn};
 12564             """,
 12565             errorReturn=errorReturn)
 12567         bodyWithThis = fill(
 12568             """
 12569             $*{setupCall}
 12570             JS::Rooted<JSObject*> thisObjJS(s.GetContext(),
 12571               WrapCallThisObject(s.GetContext(), thisObjPtr));
 12572             if (!thisObjJS) {
 12573               aRv.Throw(NS_ERROR_FAILURE);
 12574               return${errorReturn};
 12576             JS::Rooted<JS::Value> thisValJS(s.GetContext(),
 12577                                             JS::ObjectValue(*thisObjJS));
 12578             return ${methodName}(${callArgs});
 12579             """,
 12580             setupCall=setupCall,
 12581             errorReturn=errorReturn,
 12582             methodName=method.name,
 12583             callArgs=", ".join(argnamesWithThis))
 12584         bodyWithoutThis = fill(
 12585             """
 12586             $*{setupCall}
 12587             return ${methodName}(${callArgs});
 12588             """,
 12589             setupCall=setupCall,
 12590             errorReturn=errorReturn,
 12591             methodName=method.name,
 12592             callArgs=", ".join(argnamesWithoutThis))
 12594         return [ClassMethod(method.name, method.returnType, args,
 12595                             bodyInHeader=True,
 12596                             templateArgs=["typename T"],
 12597                             body=bodyWithThis),
 12598                 ClassMethod(method.name, method.returnType, argsWithoutThis,
 12599                             bodyInHeader=True,
 12600                             body=bodyWithoutThis),
 12601                 method]
 12603     def deps(self):
 12604         return self._deps
 12607 class CGCallbackFunction(CGCallback):
 12608     def __init__(self, callback, descriptorProvider):
 12609         self.callback = callback
 12610         CGCallback.__init__(self, callback, descriptorProvider,
 12611                             "CallbackFunction",
 12612                             methods=[CallCallback(callback, descriptorProvider)])
 12614     def getConstructors(self):
 12615         return CGCallback.getConstructors(self) + [
 12616             ClassConstructor(
 12617                 [Argument("CallbackFunction*", "aOther")],
 12618                 bodyInHeader=True,
 12619                 visibility="public",
 12620                 explicit=True,
 12621                 baseConstructors=["CallbackFunction(aOther)"])]
 12624 class CGCallbackInterface(CGCallback):
 12625     def __init__(self, descriptor):
 12626         iface = descriptor.interface
 12627         attrs = [m for m in iface.members if m.isAttr() and not m.isStatic()]
 12628         getters = [CallbackGetter(a, descriptor) for a in attrs]
 12629         setters = [CallbackSetter(a, descriptor) for a in attrs
 12630                    if not a.readonly]
 12631         methods = [m for m in iface.members
 12632                    if m.isMethod() and not m.isStatic() and not m.isIdentifierLess()]
 12633         methods = [CallbackOperation(m, sig, descriptor) for m in methods
 12634                    for sig in m.signatures()]
 12635         if iface.isJSImplemented() and iface.ctor():
 12636             sigs = descriptor.interface.ctor().signatures()
 12637             if len(sigs) != 1:
 12638                 raise TypeError("We only handle one constructor.  See bug 869268.")
 12639             methods.append(CGJSImplInitOperation(sigs[0], descriptor))
 12640         CGCallback.__init__(self, iface, descriptor, "CallbackInterface",
 12641                             methods, getters=getters, setters=setters)
 12644 class FakeMember():
 12645     def __init__(self):
 12646         self.treatNullAs = "Default"
 12648     def isStatic(self):
 12649         return False
 12651     def isAttr(self):
 12652         return False
 12654     def isMethod(self):
 12655         return False
 12657     def getExtendedAttribute(self, name):
 12658         # Claim to be a [NewObject] so we can avoid the "mark this
 12659         # resultNotAddRefed" comments CGNativeMember codegen would
 12660         # otherwise stick in.
 12661         if name == "NewObject":
 12662             return True
 12663         return None
 12666 class CallbackMember(CGNativeMember):
 12667     def __init__(self, sig, name, descriptorProvider, needThisHandling, rethrowContentException=False):
 12668         """
 12669         needThisHandling is True if we need to be able to accept a specified
 12670         thisObj, False otherwise.
 12671         """
 12672         assert not rethrowContentException or not needThisHandling
 12674         self.retvalType = sig[0]
 12675         self.originalSig = sig
 12676         args = sig[1]
 12677         self.argCount = len(args)
 12678         if self.argCount > 0:
 12679             # Check for variadic arguments
 12680             lastArg = args[self.argCount-1]
 12681             if lastArg.variadic:
 12682                 self.argCountStr = ("(%d - 1) + %s.Length()" %
 12683                                     (self.argCount, lastArg.identifier.name))
 12684             else:
 12685                 self.argCountStr = "%d" % self.argCount
 12686         self.needThisHandling = needThisHandling
 12687         # If needThisHandling, we generate ourselves as private and the caller
 12688         # will handle generating public versions that handle the "this" stuff.
 12689         visibility = "private" if needThisHandling else "public"
 12690         self.rethrowContentException = rethrowContentException
 12691         # We don't care, for callback codegen, whether our original member was
 12692         # a method or attribute or whatnot.  Just always pass FakeMember()
 12693         # here.
 12694         CGNativeMember.__init__(self, descriptorProvider, FakeMember(),
 12695                                 name, (self.retvalType, args),
 12696                                 extendedAttrs={},
 12697                                 passJSBitsAsNeeded=False,
 12698                                 visibility=visibility,
 12699                                 jsObjectsArePtr=True)
 12700         # We have to do all the generation of our body now, because
 12701         # the caller relies on us throwing if we can't manage it.
 12702         self.exceptionCode = ("aRv.Throw(NS_ERROR_UNEXPECTED);\n"
 12703                               "return%s;\n" % self.getDefaultRetval())
 12704         self.body = self.getImpl()
 12706     def getImpl(self):
 12707         setupCall = self.getCallSetup()
 12708         declRval = self.getRvalDecl()
 12709         if self.argCount > 0:
 12710             argvDecl = fill(
 12711                 """
 12712                 JS::AutoValueVector argv(cx);
 12713                 if (!argv.resize(${argCount})) {
 12714                   aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
 12715                   return${errorReturn};
 12717                 """,
 12718                 argCount=self.argCountStr,
 12719                 errorReturn=self.getDefaultRetval())
 12720         else:
 12721             # Avoid weird 0-sized arrays
 12722             argvDecl = ""
 12723         convertArgs = self.getArgConversions()
 12724         doCall = self.getCall()
 12725         returnResult = self.getResultConversion()
 12727         return setupCall + declRval + argvDecl + convertArgs + doCall + returnResult
 12729     def getResultConversion(self):
 12730         replacements = {
 12731             "val": "rval",
 12732             "mutableVal": "&rval",
 12733             "holderName": "rvalHolder",
 12734             "declName": "rvalDecl",
 12735             # We actually want to pass in a null scope object here, because
 12736             # wrapping things into our current compartment (that of mCallback)
 12737             # is what we want.
 12738             "obj": "nullptr"
 12741         if isJSImplementedDescriptor(self.descriptorProvider):
 12742             isCallbackReturnValue = "JSImpl"
 12743         else:
 12744             isCallbackReturnValue = "Callback"
 12745         sourceDescription = "return value of %s" % self.getPrettyName()
 12746         convertType = instantiateJSToNativeConversion(
 12747             getJSToNativeConversionInfo(self.retvalType,
 12748                                         self.descriptorProvider,
 12749                                         exceptionCode=self.exceptionCode,
 12750                                         isCallbackReturnValue=isCallbackReturnValue,
 12751                                         sourceDescription=sourceDescription),
 12752             replacements)
 12753         assignRetval = string.Template(
 12754             self.getRetvalInfo(self.retvalType,
 12755                                False)[2]).substitute(replacements)
 12756         type = convertType.define()
 12757         if type == "":
 12758             type = "\n"  # BOGUS extra blank line
 12759         if assignRetval == "":
 12760             assignRetval = "\n"  # BOGUS extra blank line
 12761         return type + assignRetval
 12763     def getArgConversions(self):
 12764         # Just reget the arglist from self.originalSig, because our superclasses
 12765         # just have way to many members they like to clobber, so I can't find a
 12766         # safe member name to store it in.
 12767         argConversions = [self.getArgConversion(i, arg)
 12768                           for i, arg in enumerate(self.originalSig[1])]
 12769         if not argConversions:
 12770             return "\n\n"  # BOGUS extra blank line
 12772         # Do them back to front, so our argc modifications will work
 12773         # correctly, because we examine trailing arguments first.
 12774         argConversions.reverse()
 12775         # Wrap each one in a scope so that any locals it has don't leak out, and
 12776         # also so that we can just "break;" for our successCode.
 12777         argConversions = [CGWrapper(CGIndenter(CGGeneric(c)),
 12778                                     pre="do {\n",
 12779                                     post="} while (0);\n")
 12780                           for c in argConversions]
 12781         if self.argCount > 0:
 12782             argConversions.insert(0, self.getArgcDecl())
 12783         # And slap them together.
 12784         return CGList(argConversions, "\n").define() + "\n"
 12786     def getArgConversion(self, i, arg):
 12787         argval = arg.identifier.name
 12789         if arg.variadic:
 12790             argval = argval + "[idx]"
 12791             jsvalIndex = "%d + idx" % i
 12792         else:
 12793             jsvalIndex = "%d" % i
 12794             if arg.optional and not arg.defaultValue:
 12795                 argval += ".Value()"
 12796         if arg.type.isDOMString():
 12797             # XPConnect string-to-JS conversion wants to mutate the string.  So
 12798             # let's give it a string it can mutate
 12799             # XXXbz if we try to do a sequence of strings, this will kinda fail.
 12800             result = "mutableStr"
 12801             prepend = "nsString mutableStr(%s);\n" % argval
 12802         else:
 12803             result = argval
 12804             prepend = ""
 12806         try:
 12807             conversion = prepend + wrapForType(
 12808                 arg.type, self.descriptorProvider,
 12810                     'result': result,
 12811                     'successCode': "continue;\n" if arg.variadic else "break;\n",
 12812                     'jsvalRef': "argv.handleAt(%s)" % jsvalIndex,
 12813                     'jsvalHandle': "argv.handleAt(%s)" % jsvalIndex,
 12814                     # XXXbz we don't have anything better to use for 'obj',
 12815                     # really...  It's OK to use CallbackPreserveColor because
 12816                     # CallSetup already handled the unmark-gray bits for us.
 12817                     'obj': 'CallbackPreserveColor()',
 12818                     'returnsNewObject': False,
 12819                     'exceptionCode': self.exceptionCode
 12820                 })
 12821         except MethodNotNewObjectError as err:
 12822             raise TypeError("%s being passed as an argument to %s but is not "
 12823                             "wrapper cached, so can't be reliably converted to "
 12824                             "a JS object." %
 12825                             (err.typename, self.getPrettyName()))
 12826         if arg.variadic:
 12827             conversion = fill(
 12828                 """
 12829                 for (uint32_t idx = 0; idx < ${arg}.Length(); ++idx) {
 12830                   $*{conversion}
 12832                 break;
 12833                 """,
 12834                 arg=arg.identifier.name,
 12835                 conversion=conversion)
 12836         elif arg.optional and not arg.defaultValue:
 12837             conversion = fill(
 12838                 """
 12839                 if (${argName}.WasPassed()) {
 12840                   $*{conversion}
 12841                 } else if (argc == ${iPlus1}) {
 12842                   // This is our current trailing argument; reduce argc
 12843                   --argc;
 12844                 } else {
 12845                   argv[${i}] = JS::UndefinedValue();
 12847                 """,
 12848                 argName=arg.identifier.name,
 12849                 conversion=conversion,
 12850                 iPlus1=i + 1,
 12851                 i=i)
 12852         return conversion
 12854     def getDefaultRetval(self):
 12855         default = self.getRetvalInfo(self.retvalType, False)[1]
 12856         if len(default) != 0:
 12857             default = " " + default
 12858         return default
 12860     def getArgs(self, returnType, argList):
 12861         args = CGNativeMember.getArgs(self, returnType, argList)
 12862         if not self.needThisHandling:
 12863             # Since we don't need this handling, we're the actual method that
 12864             # will be called, so we need an aRethrowExceptions argument.
 12865             if self.rethrowContentException:
 12866                 args.append(Argument("JSCompartment*", "aCompartment", "nullptr"))
 12867             else:
 12868                 args.append(Argument("ExceptionHandling", "aExceptionHandling",
 12869                                      "eReportExceptions"))
 12870             return args
 12871         # We want to allow the caller to pass in a "this" value, as
 12872         # well as a JSContext.
 12873         return [Argument("JSContext*", "cx"),
 12874                 Argument("JS::Handle<JS::Value>", "aThisVal")] + args
 12876     def getCallSetup(self):
 12877         if self.needThisHandling:
 12878             # It's been done for us already
 12879             return ""
 12880         callSetup = "CallSetup s(this, aRv"
 12881         if self.rethrowContentException:
 12882             # getArgs doesn't add the aExceptionHandling argument but does add
 12883             # aCompartment for us.
 12884             callSetup += ", eRethrowContentExceptions, aCompartment, /* aIsJSImplementedWebIDL = */ "
 12885             callSetup += toStringBool(isJSImplementedDescriptor(self.descriptorProvider))
 12886         else:
 12887             callSetup += ", aExceptionHandling"
 12888         callSetup += ");\n"
 12889         return fill(
 12890             """
 12891             $*{callSetup}
 12892             JSContext* cx = s.GetContext();
 12893             if (!cx) {
 12894               aRv.Throw(NS_ERROR_UNEXPECTED);
 12895               return${errorReturn};
 12897             """,
 12898             callSetup=callSetup,
 12899             errorReturn=self.getDefaultRetval())
 12901     def getArgcDecl(self):
 12902         return CGGeneric("unsigned argc = %s;\n" % self.argCountStr)
 12904     @staticmethod
 12905     def ensureASCIIName(idlObject):
 12906         type = "attribute" if idlObject.isAttr() else "operation"
 12907         if re.match("[^\x20-\x7E]", idlObject.identifier.name):
 12908             raise SyntaxError('Callback %s name "%s" contains non-ASCII '
 12909                               "characters.  We can't handle that.  %s" %
 12910                               (type, idlObject.identifier.name,
 12911                                idlObject.location))
 12912         if re.match('"', idlObject.identifier.name):
 12913             raise SyntaxError("Callback %s name '%s' contains "
 12914                               "double-quote character.  We can't handle "
 12915                               "that.  %s" %
 12916                               (type, idlObject.identifier.name,
 12917                                idlObject.location))
 12920 class CallbackMethod(CallbackMember):
 12921     def __init__(self, sig, name, descriptorProvider, needThisHandling,
 12922                  rethrowContentException=False):
 12923         CallbackMember.__init__(self, sig, name, descriptorProvider,
 12924                                 needThisHandling, rethrowContentException)
 12926     def getRvalDecl(self):
 12927         return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
 12929     def getCall(self):
 12930         if self.argCount > 0:
 12931             args = "JS::HandleValueArray::subarray(argv, 0, argc)"
 12932         else:
 12933             args = "JS::HandleValueArray::empty()"
 12935         return fill(
 12936             """
 12937             $*{declCallable}
 12938             $*{declThis}
 12939             if (${callGuard}!JS::Call(cx, ${thisVal}, callable,
 12940                           ${args}, &rval)) {
 12941               aRv.Throw(NS_ERROR_UNEXPECTED);
 12942               return${errorReturn};
 12944             """,
 12945             declCallable=self.getCallableDecl(),
 12946             declThis=self.getThisDecl(),
 12947             callGuard=self.getCallGuard(),
 12948             thisVal=self.getThisVal(),
 12949             args=args,
 12950             errorReturn=self.getDefaultRetval())
 12953 class CallCallback(CallbackMethod):
 12954     def __init__(self, callback, descriptorProvider):
 12955         self.callback = callback
 12956         CallbackMethod.__init__(self, callback.signatures()[0], "Call",
 12957                                 descriptorProvider, needThisHandling=True)
 12959     def getThisDecl(self):
 12960         return ""
 12962     def getThisVal(self):
 12963         return "aThisVal"
 12965     def getCallableDecl(self):
 12966         return "JS::Rooted<JS::Value> callable(cx, JS::ObjectValue(*mCallback));\n"
 12968     def getPrettyName(self):
 12969         return self.callback.identifier.name
 12971     def getCallGuard(self):
 12972         if self.callback._treatNonObjectAsNull:
 12973             return "JS_ObjectIsCallable(cx, mCallback) && "
 12974         return ""
 12977 class CallbackOperationBase(CallbackMethod):
 12978     """
 12979     Common class for implementing various callback operations.
 12980     """
 12981     def __init__(self, signature, jsName, nativeName, descriptor, singleOperation, rethrowContentException=False):
 12982         self.singleOperation = singleOperation
 12983         self.methodName = descriptor.binaryNames.get(jsName, jsName)
 12984         CallbackMethod.__init__(self, signature, nativeName, descriptor, singleOperation, rethrowContentException)
 12986     def getThisDecl(self):
 12987         if not self.singleOperation:
 12988             return "JS::Rooted<JS::Value> thisValue(cx, JS::ObjectValue(*mCallback));\n"
 12989         # This relies on getCallableDecl declaring a boolean
 12990         # isCallable in the case when we're a single-operation
 12991         # interface.
 12992         return dedent("""
 12993             JS::Rooted<JS::Value> thisValue(cx, isCallable ? aThisVal.get()
 12994                                                            : JS::ObjectValue(*mCallback));
 12995             """)
 12997     def getThisVal(self):
 12998         return "thisValue"
 13000     def getCallableDecl(self):
 13001         getCallableFromProp = fill(
 13002             """
 13003             if (!GetCallableProperty(cx, "${methodName}", &callable)) {
 13004               aRv.Throw(NS_ERROR_UNEXPECTED);
 13005               return${errorReturn};
 13007             """,
 13008             methodName=self.methodName,
 13009             errorReturn=self.getDefaultRetval())
 13010         if not self.singleOperation:
 13011             return 'JS::Rooted<JS::Value> callable(cx);\n' + getCallableFromProp
 13012         return fill(
 13013             """
 13014             bool isCallable = JS_ObjectIsCallable(cx, mCallback);
 13015             JS::Rooted<JS::Value> callable(cx);
 13016             if (isCallable) {
 13017               callable = JS::ObjectValue(*mCallback);
 13018             } else {
 13019               $*{getCallableFromProp}
 13021             """,
 13022             getCallableFromProp=getCallableFromProp)
 13024     def getCallGuard(self):
 13025         return ""
 13028 class CallbackOperation(CallbackOperationBase):
 13029     """
 13030     Codegen actual WebIDL operations on callback interfaces.
 13031     """
 13032     def __init__(self, method, signature, descriptor):
 13033         self.ensureASCIIName(method)
 13034         self.method = method
 13035         jsName = method.identifier.name
 13036         CallbackOperationBase.__init__(self, signature,
 13037                                        jsName,
 13038                                        MakeNativeName(descriptor.binaryNames.get(jsName, jsName)),
 13039                                        descriptor, descriptor.interface.isSingleOperationInterface(),
 13040                                        rethrowContentException=descriptor.interface.isJSImplemented())
 13042     def getPrettyName(self):
 13043         return "%s.%s" % (self.descriptorProvider.interface.identifier.name,
 13044                           self.method.identifier.name)
 13047 class CallbackAccessor(CallbackMember):
 13048     """
 13049     Shared superclass for CallbackGetter and CallbackSetter.
 13050     """
 13051     def __init__(self, attr, sig, name, descriptor):
 13052         self.ensureASCIIName(attr)
 13053         self.attrName = attr.identifier.name
 13054         CallbackMember.__init__(self, sig, name, descriptor,
 13055                                 needThisHandling=False,
 13056                                 rethrowContentException=descriptor.interface.isJSImplemented())
 13058     def getPrettyName(self):
 13059         return "%s.%s" % (self.descriptorProvider.interface.identifier.name,
 13060                           self.attrName)
 13063 class CallbackGetter(CallbackAccessor):
 13064     def __init__(self, attr, descriptor):
 13065         CallbackAccessor.__init__(self, attr,
 13066                                   (attr.type, []),
 13067                                   callbackGetterName(attr, descriptor),
 13068                                   descriptor)
 13070     def getRvalDecl(self):
 13071         return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
 13073     def getCall(self):
 13074         return fill(
 13075             """
 13076             JS::Rooted<JSObject *> callback(cx, mCallback);
 13077             if (!JS_GetProperty(cx, callback, "${attrName}", &rval)) {
 13078               aRv.Throw(NS_ERROR_UNEXPECTED);
 13079               return${errorReturn};
 13081             """,
 13082             attrName=self.descriptorProvider.binaryNames.get(self.attrName,
 13083                                                              self.attrName),
 13084             errorReturn=self.getDefaultRetval())
 13087 class CallbackSetter(CallbackAccessor):
 13088     def __init__(self, attr, descriptor):
 13089         CallbackAccessor.__init__(self, attr,
 13090                                   (BuiltinTypes[IDLBuiltinType.Types.void],
 13091                                    [FakeArgument(attr.type, attr)]),
 13092                                   callbackSetterName(attr, descriptor),
 13093                                   descriptor)
 13095     def getRvalDecl(self):
 13096         # We don't need an rval
 13097         return ""
 13099     def getCall(self):
 13100         return fill(
 13101             """
 13102             MOZ_ASSERT(argv.length() == 1);
 13103             if (!JS_SetProperty(cx, CallbackPreserveColor(), "${attrName}", argv.handleAt(0))) {
 13104               aRv.Throw(NS_ERROR_UNEXPECTED);
 13105               return${errorReturn};
 13107             """,
 13108             attrName=self.descriptorProvider.binaryNames.get(self.attrName,
 13109                                                              self.attrName),
 13110             errorReturn=self.getDefaultRetval())
 13112     def getArgcDecl(self):
 13113         return None
 13116 class CGJSImplInitOperation(CallbackOperationBase):
 13117     """
 13118     Codegen the __Init() method used to pass along constructor arguments for JS-implemented WebIDL.
 13119     """
 13120     def __init__(self, sig, descriptor):
 13121         assert sig in descriptor.interface.ctor().signatures()
 13122         CallbackOperationBase.__init__(self, (BuiltinTypes[IDLBuiltinType.Types.void], sig[1]),
 13123                                        "__init", "__Init", descriptor, False, True)
 13125     def getPrettyName(self):
 13126         return "__init"
 13129 class GlobalGenRoots():
 13130     """
 13131     Roots for global codegen.
 13133     To generate code, call the method associated with the target, and then
 13134     call the appropriate define/declare method.
 13135     """
 13137     @staticmethod
 13138     def GeneratedAtomList(config):
 13139         # Atom enum
 13140         dictionaries = config.dictionaries
 13142         structs = []
 13144         for dict in dictionaries:
 13145             dictMembers = dict.members
 13146             if len(dictMembers) == 0:
 13147                 continue
 13149             classMembers = [ClassMember(CGDictionary.makeIdName(m.identifier.name),
 13150                                         "InternedStringId",
 13151                                         visibility="public") for m in dictMembers]
 13153             structName = dict.identifier.name + "Atoms"
 13154             structs.append((structName,
 13155                             CGWrapper(CGClass(structName,
 13156                                               bases=None,
 13157                                               isStruct=True,
 13158                                               members=classMembers), post='\n')))
 13160         structs.sort()
 13161         generatedStructs = [struct for structName, struct in structs]
 13162         structNames = [structName for structName, struct in structs]
 13164         mainStruct = CGWrapper(CGClass("PerThreadAtomCache",
 13165                                        bases=[ClassBase(structName) for structName in structNames],
 13166                                        isStruct=True),
 13167                                post='\n')
 13169         structs = CGList(generatedStructs + [mainStruct])
 13171         # Wrap all of that in our namespaces.
 13172         curr = CGNamespace.build(['mozilla', 'dom'],
 13173                                  CGWrapper(structs, pre='\n'))
 13174         curr = CGWrapper(curr, post='\n')
 13176         # Add include statement for InternedStringId.
 13177         declareIncludes = ['mozilla/dom/BindingUtils.h']
 13178         curr = CGHeaders([], [], [], [], declareIncludes, [], 'GeneratedAtomList',
 13179                          curr)
 13181         # Add include guards.
 13182         curr = CGIncludeGuard('GeneratedAtomList', curr)
 13184         # Add the auto-generated comment.
 13185         curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
 13187         # Done.
 13188         return curr
 13190     @staticmethod
 13191     def PrototypeList(config):
 13193         # Prototype ID enum.
 13194         descriptorsWithPrototype = config.getDescriptors(hasInterfacePrototypeObject=True)
 13195         protos = [d.name for d in descriptorsWithPrototype]
 13196         idEnum = CGNamespacedEnum('id', 'ID', ['_ID_Start'] + protos,
 13197                                   [0, '_ID_Start'])
 13198         idEnum = CGList([idEnum])
 13200         # This is only used by DOM worker code, once there are no more consumers
 13201         # of INTERFACE_CHAIN_* this code should be removed.
 13202         def ifaceChainMacro(ifaceCount):
 13203             supplied = [CGGeneric(declare="_iface_" + str(i + 1)) for i in range(ifaceCount)]
 13204             remaining = [CGGeneric(declare="prototypes::id::_ID_Count")] * (config.maxProtoChainLength - ifaceCount)
 13205             macro = CGWrapper(CGList(supplied, ", "),
 13206                               pre="#define INTERFACE_CHAIN_" + str(ifaceCount) + "(",
 13207                               post=") \\\n",
 13208                               declareOnly=True)
 13209             macroContent = CGIndenter(CGList(supplied + remaining, ", \\\n"))
 13210             macroContent = CGIndenter(CGWrapper(macroContent, pre="{ \\\n",
 13211                                                 post=" \\\n}",
 13212                                                 declareOnly=True))
 13213             return CGWrapper(CGList([macro, macroContent]), post="\n\n",
 13214                              declareOnly=True)
 13216         idEnum.append(ifaceChainMacro(1))
 13218         def fieldSizeAssert(amount, jitInfoField, message):
 13219             maxFieldValue = "(uint64_t(1) << (sizeof(((JSJitInfo*)nullptr)->%s) * 8))" % jitInfoField
 13220             return CGGeneric(declare="static_assert(%s < %s, \"%s\");\n\n"
 13221                              % (amount, maxFieldValue, message))
 13223         idEnum.append(fieldSizeAssert("id::_ID_Count", "protoID",
 13224                                       "Too many prototypes!"))
 13226         # Wrap all of that in our namespaces.
 13227         idEnum = CGNamespace.build(['mozilla', 'dom', 'prototypes'],
 13228                                    CGWrapper(idEnum, pre='\n'))
 13229         idEnum = CGWrapper(idEnum, post='\n')
 13231         curr = CGList([CGGeneric(define="#include <stdint.h>\n\n"),
 13232                        idEnum])
 13234         # Let things know the maximum length of the prototype chain.
 13235         maxMacroName = "MAX_PROTOTYPE_CHAIN_LENGTH"
 13236         maxMacro = CGGeneric(declare="#define " + maxMacroName + " " + str(config.maxProtoChainLength))
 13237         curr.append(CGWrapper(maxMacro, post='\n\n'))
 13238         curr.append(fieldSizeAssert(maxMacroName, "depth",
 13239                                     "Some inheritance chain is too long!"))
 13241         # Constructor ID enum.
 13242         constructors = [d.name for d in config.getDescriptors(hasInterfaceObject=True)]
 13243         idEnum = CGNamespacedEnum('id', 'ID', ['_ID_Start'] + constructors,
 13244                                   ['prototypes::id::_ID_Count', '_ID_Start'])
 13246         # Wrap all of that in our namespaces.
 13247         idEnum = CGNamespace.build(['mozilla', 'dom', 'constructors'],
 13248                                    CGWrapper(idEnum, pre='\n'))
 13249         idEnum = CGWrapper(idEnum, post='\n')
 13251         curr.append(idEnum)
 13253         traitsDecls = [CGGeneric(declare=dedent("""
 13254             template <prototypes::ID PrototypeID>
 13255             struct PrototypeTraits;
 13256             """))]
 13257         traitsDecls.extend(CGPrototypeTraitsClass(d) for d in descriptorsWithPrototype)
 13259         ifaceNamesWithProto = [d.interface.identifier.name
 13260                                for d in descriptorsWithPrototype]
 13261         traitsDecls.append(CGStringTable("NamesOfInterfacesWithProtos",
 13262                                          ifaceNamesWithProto))
 13264         traitsDecl = CGNamespace.build(['mozilla', 'dom'],
 13265                                        CGList(traitsDecls))
 13267         curr.append(traitsDecl)
 13269         # Add include guards.
 13270         curr = CGIncludeGuard('PrototypeList', curr)
 13272         # Add the auto-generated comment.
 13273         curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
 13275         # Done.
 13276         return curr
 13278     @staticmethod
 13279     def RegisterBindings(config):
 13281         # TODO - Generate the methods we want
 13282         curr = CGRegisterProtos(config)
 13284         # Wrap all of that in our namespaces.
 13285         curr = CGNamespace.build(['mozilla', 'dom'],
 13286                                  CGWrapper(curr, post='\n'))
 13287         curr = CGWrapper(curr, post='\n')
 13289         # Add the includes
 13290         defineIncludes = [CGHeaders.getDeclarationFilename(desc.interface)
 13291                           for desc in config.getDescriptors(hasInterfaceObject=True,
 13292                                                             workers=False,
 13293                                                             register=True)]
 13294         defineIncludes.append('nsScriptNameSpaceManager.h')
 13295         defineIncludes.extend([CGHeaders.getDeclarationFilename(desc.interface)
 13296                                for desc in config.getDescriptors(isNavigatorProperty=True,
 13297                                                                  workers=False,
 13298                                                                  register=True)])
 13299         curr = CGHeaders([], [], [], [], [], defineIncludes, 'RegisterBindings',
 13300                          curr)
 13302         # Add include guards.
 13303         curr = CGIncludeGuard('RegisterBindings', curr)
 13305         # Done.
 13306         return curr
 13308     @staticmethod
 13309     def UnionTypes(config):
 13311         (includes, implincludes,
 13312          declarations, unions) = UnionTypes(config.getDescriptors(),
 13313                                             config.getDictionaries(),
 13314                                             config.getCallbacks(),
 13315                                             config)
 13316         includes.add("mozilla/dom/OwningNonNull.h")
 13317         includes.add("mozilla/dom/UnionMember.h")
 13318         includes.add("mozilla/dom/BindingDeclarations.h")
 13319         # Need BindingUtils.h for FakeDependentString
 13320         includes.add("mozilla/dom/BindingUtils.h")
 13321         implincludes.add("mozilla/dom/PrimitiveConversions.h")
 13323         # Wrap all of that in our namespaces.
 13324         curr = CGNamespace.build(['mozilla', 'dom'], unions)
 13326         curr = CGWrapper(curr, post='\n')
 13328         namespaces = []
 13329         stack = [CGList([])]
 13330         for clazz, isStruct in sorted(declarations):
 13331             elements = clazz.split("::")
 13332             clazz = CGClassForwardDeclare(elements.pop(), isStruct=isStruct)
 13333             i = 0
 13334             if len(elements) > 0:
 13335                 common = min(len(namespaces), len(elements))
 13336                 while i < common and namespaces[i] == elements[i]:
 13337                     i += 1
 13339             # pop all the namespaces that should be closed
 13340             namespaces = namespaces[:i]
 13342             # add all the namespaces that should be opened
 13343             for j, namespace in enumerate(elements[i:]):
 13344                 namespaces.append(namespace)
 13345                 # every CGNamespace that we add holds a CGList
 13346                 list = CGList([])
 13347                 # add the new namespace to the list on top of the stack
 13348                 stack[i + j].append(CGNamespace(namespace, list))
 13349                 # set the top of the namespace stack to the list of the new
 13350                 # namespace
 13351                 stack[i + j + 1:] = [list]
 13353             stack[len(elements)].append(clazz)
 13355         curr = CGList([stack[0], curr], "\n")
 13357         curr = CGHeaders([], [], [], [], includes, implincludes, 'UnionTypes',
 13358                          curr)
 13360         # Add include guards.
 13361         curr = CGIncludeGuard('UnionTypes', curr)
 13363         # Done.
 13364         return curr
 13366     @staticmethod
 13367     def UnionConversions(config):
 13369         headers, unions = UnionConversions(config.getDescriptors(),
 13370                                            config.getDictionaries(),
 13371                                            config.getCallbacks(),
 13372                                            config)
 13374         # Wrap all of that in our namespaces.
 13375         curr = CGNamespace.build(['mozilla', 'dom'], unions)
 13377         curr = CGWrapper(curr, post='\n')
 13379         headers.update(["nsDebug.h", "mozilla/dom/UnionTypes.h"])
 13380         curr = CGHeaders([], [], [], [], headers, [], 'UnionConversions', curr)
 13382         # Add include guards.
 13383         curr = CGIncludeGuard('UnionConversions', curr)
 13385         # Done.
 13386         return curr
 13389 # Code generator for simple events
 13390 class CGEventGetter(CGNativeMember):
 13391     def __init__(self, descriptor, attr):
 13392         ea = descriptor.getExtendedAttributes(attr, getter=True)
 13393         ea.append('resultNotAddRefed')
 13394         CGNativeMember.__init__(self, descriptor, attr,
 13395                                 CGSpecializedGetter.makeNativeName(descriptor,
 13396                                                                    attr),
 13397                                 (attr.type, []),
 13398                                 ea)
 13399         self.body = self.getMethodBody()
 13401     def getArgs(self, returnType, argList):
 13402         if 'infallible' not in self.extendedAttrs:
 13403             raise TypeError("Event code generator does not support [Throws]!")
 13404         if not self.member.isAttr():
 13405             raise TypeError("Event code generator does not support methods")
 13406         if self.member.isStatic():
 13407             raise TypeError("Event code generators does not support static attributes")
 13408         return CGNativeMember.getArgs(self, returnType, argList)
 13410     def getMethodBody(self):
 13411         type = self.member.type
 13412         memberName = CGDictionary.makeMemberName(self.member.identifier.name)
 13413         if (type.isPrimitive() and type.tag() in builtinNames) or type.isEnum() or type.isGeckoInterface():
 13414             return "return " + memberName + ";\n"
 13415         if type.isDOMString() or type.isByteString():
 13416             return "aRetVal = " + memberName + ";\n"
 13417         if type.isSpiderMonkeyInterface() or type.isObject():
 13418             return fill(
 13419                 """
 13420                 if (${memberName}) {
 13421                   JS::ExposeObjectToActiveJS(${memberName});
 13423                 aRetVal.set(${memberName});
 13424                 return;
 13425                 """,
 13426                 memberName=memberName)
 13427         if type.isAny():
 13428             return fill(
 13429                 """
 13430                 JS::ExposeValueToActiveJS(${memberName});
 13431                 aRetVal.set(${memberName});
 13432                 return;
 13433                 """,
 13434                 memberName=memberName)
 13435         if type.isUnion():
 13436             return "aRetVal = " + memberName + ";\n"
 13437         raise TypeError("Event code generator does not support this type!")
 13439     def declare(self, cgClass):
 13440         if getattr(self.member, "originatingInterface",
 13441                    cgClass.descriptor.interface) != cgClass.descriptor.interface:
 13442             return ""
 13443         return CGNativeMember.declare(self, cgClass)
 13445     def define(self, cgClass):
 13446         if getattr(self.member, "originatingInterface",
 13447                    cgClass.descriptor.interface) != cgClass.descriptor.interface:
 13448             return ""
 13449         return CGNativeMember.define(self, cgClass)
 13452 class CGEventSetter(CGNativeMember):
 13453     def __init__(self):
 13454         raise TypeError("Event code generator does not support setters!")
 13457 class CGEventMethod(CGNativeMember):
 13458     def __init__(self, descriptor, method, signature, isConstructor, breakAfter=True):
 13459         if not isConstructor:
 13460             raise TypeError("Event code generator does not support methods!")
 13461         self.wantsConstructorForNativeCaller = True
 13462         CGNativeMember.__init__(self, descriptor, method,
 13463                                 CGSpecializedMethod.makeNativeName(descriptor,
 13464                                                                    method),
 13465                                 signature,
 13466                                 descriptor.getExtendedAttributes(method),
 13467                                 breakAfter=breakAfter,
 13468                                 variadicIsSequence=True)
 13469         self.originalArgs = list(self.args)
 13471     def getArgs(self, returnType, argList):
 13472         args = [self.getArg(arg) for arg in argList]
 13473         return args
 13475     def getArg(self, arg):
 13476         decl, ref = self.getArgType(arg.type,
 13477                                     arg.optional and not arg.defaultValue,
 13478                                     "Variadic" if arg.variadic else False)
 13479         if ref:
 13480             decl = CGWrapper(decl, pre="const ", post="&")
 13482         name = arg.identifier.name
 13483         name = "a" + name[0].upper() + name[1:]
 13484         return Argument(decl.define(), name)
 13486     def declare(self, cgClass):
 13487         self.args = list(self.originalArgs)
 13488         self.args.insert(0, Argument("mozilla::dom::EventTarget*", "aOwner"))
 13489         constructorForNativeCaller = CGNativeMember.declare(self, cgClass) + "\n"
 13490         self.args = list(self.originalArgs)
 13491         if needCx(None, self.descriptorProvider.interface.members, [], True):
 13492             self.args.insert(0, Argument("JSContext*", "aCx"))
 13493         self.args.insert(0, Argument("const GlobalObject&", "aGlobal"))
 13494         self.args.append(Argument('ErrorResult&', 'aRv'))
 13495         return constructorForNativeCaller + CGNativeMember.declare(self, cgClass)
 13497     def define(self, cgClass):
 13498         self.args = list(self.originalArgs)
 13499         members = ""
 13500         holdJS = ""
 13501         iface = self.descriptorProvider.interface
 13502         while iface.identifier.name != "Event":
 13503             for m in self.descriptorProvider.getDescriptor(iface.identifier.name).interface.members:
 13504                 if m.isAttr():
 13505                     # We initialize all the other member variables in the
 13506                     # Constructor except those ones coming from the Event.
 13507                     if getattr(m, "originatingInterface",
 13508                                cgClass.descriptor.interface).identifier.name == "Event":
 13509                         continue
 13510                     name = CGDictionary.makeMemberName(m.identifier.name)
 13511                     members += "e->%s = %s.%s;\n" % (name, self.args[1].name, name)
 13512                     if m.type.isAny() or m.type.isObject() or m.type.isSpiderMonkeyInterface():
 13513                         holdJS = "mozilla::HoldJSObjects(e.get());\n"
 13514             iface = iface.parent
 13516         self.body = fill(
 13517             """
 13518             nsRefPtr<${nativeType}> e = new ${nativeType}(aOwner);
 13519             bool trusted = e->Init(aOwner);
 13520             e->InitEvent(${eventType}, ${eventInit}.mBubbles, ${eventInit}.mCancelable);
 13521             $*{members}
 13522             e->SetTrusted(trusted);
 13523             $*{holdJS}
 13524             return e.forget();
 13525             """,
 13526             nativeType=self.descriptorProvider.nativeType.split('::')[-1],
 13527             eventType=self.args[0].name,
 13528             eventInit=self.args[1].name,
 13529             members=members,
 13530             holdJS=holdJS)
 13532         self.args.insert(0, Argument("mozilla::dom::EventTarget*", "aOwner"))
 13533         constructorForNativeCaller = CGNativeMember.define(self, cgClass) + "\n"
 13534         self.args = list(self.originalArgs)
 13535         self.body = fill(
 13536             """
 13537             nsCOMPtr<mozilla::dom::EventTarget> owner = do_QueryInterface(aGlobal.GetAsSupports());
 13538             return Constructor(owner, ${arg0}, ${arg1});
 13539             """,
 13540             arg0=self.args[0].name,
 13541             arg1=self.args[1].name)
 13542         if needCx(None, self.descriptorProvider.interface.members, [], True):
 13543             self.args.insert(0, Argument("JSContext*", "aCx"))
 13544         self.args.insert(0, Argument("const GlobalObject&", "aGlobal"))
 13545         self.args.append(Argument('ErrorResult&', 'aRv'))
 13546         return constructorForNativeCaller + CGNativeMember.define(self, cgClass)
 13549 class CGEventClass(CGBindingImplClass):
 13550     """
 13551     Codegen for the actual Event class implementation for this descriptor
 13552     """
 13553     def __init__(self, descriptor):
 13554         CGBindingImplClass.__init__(self, descriptor, CGEventMethod, CGEventGetter, CGEventSetter, False)
 13555         members = []
 13556         for m in descriptor.interface.members:
 13557             if m.isAttr():
 13558                 if getattr(m, "originatingInterface",
 13559                            descriptor.interface) != descriptor.interface:
 13560                     continue
 13561                 if m.type.isPrimitive() and m.type.tag() in builtinNames:
 13562                     nativeType = CGGeneric(builtinNames[m.type.tag()])
 13563                     if m.type.nullable():
 13564                         nativeType = CGTemplatedType("Nullable", nativeType)
 13565                     nativeType = nativeType.define()
 13566                 elif m.type.isEnum():
 13567                     nativeType = m.type.unroll().inner.identifier.name
 13568                     if m.type.nullable():
 13569                         nativeType = CGTemplatedType("Nullable",
 13570                                                      CGGeneric(nativeType)).define()
 13571                 elif m.type.isDOMString():
 13572                     nativeType = "nsString"
 13573                 elif m.type.isByteString():
 13574                     nativeType = "nsCString"
 13575                 elif m.type.isGeckoInterface():
 13576                     iface = m.type.unroll().inner
 13577                     nativeType = self.descriptor.getDescriptor(
 13578                         iface.identifier.name).nativeType
 13579                     # Now trim off unnecessary namespaces
 13580                     nativeType = nativeType.split("::")
 13581                     if nativeType[0] == "mozilla":
 13582                         nativeType.pop(0)
 13583                         if nativeType[0] == "dom":
 13584                             nativeType.pop(0)
 13585                     nativeType = CGWrapper(CGGeneric("::".join(nativeType)), pre="nsRefPtr<", post=">").define()
 13586                 elif m.type.isAny():
 13587                     nativeType = "JS::Heap<JS::Value>"
 13588                 elif m.type.isObject() or m.type.isSpiderMonkeyInterface():
 13589                     nativeType = "JS::Heap<JSObject*>"
 13590                 elif m.type.isUnion():
 13591                     nativeType = CGUnionStruct.unionTypeDecl(m.type, True)
 13592                 else:
 13593                     raise TypeError("Don't know how to declare member of type %s" %
 13594                                     m.type)
 13595                 members.append(ClassMember(CGDictionary.makeMemberName(m.identifier.name),
 13596                                nativeType,
 13597                                visibility="private",
 13598                                body="body"))
 13600         parent = self.descriptor.interface.parent
 13601         self.parentType = self.descriptor.getDescriptor(parent.identifier.name).nativeType.split('::')[-1]
 13602         baseDeclarations = fill(
 13603             """
 13604             public:
 13605               NS_DECL_ISUPPORTS_INHERITED
 13606               NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(${nativeType}, ${parentType})
 13607               virtual ~${nativeType}();
 13608             protected:
 13609               ${nativeType}(mozilla::dom::EventTarget* aOwner);
 13611             """,
 13612             nativeType=self.descriptor.nativeType.split('::')[-1],
 13613             parentType=self.parentType)
 13615         className = descriptor.nativeType.split('::')[-1]
 13616         asConcreteTypeMethod = ClassMethod("As%s" % className,
 13617                                            "%s*" % className,
 13618                                            [],
 13619                                            virtual=True,
 13620                                            body="return this;\n",
 13621                                            breakAfterReturnDecl=" ")
 13623         CGClass.__init__(self, className,
 13624                          bases=[ClassBase(self.parentType)],
 13625                          methods=[asConcreteTypeMethod]+self.methodDecls,
 13626                          members=members,
 13627                          extradeclarations=baseDeclarations)
 13629     def getWrapObjectBody(self):
 13630         return "return %sBinding::Wrap(aCx, this);\n" % self.descriptor.name
 13632     def implTraverse(self):
 13633         retVal = ""
 13634         for m in self.descriptor.interface.members:
 13635             if m.isAttr() and m.type.isGeckoInterface():
 13636                 retVal += ("  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(" +
 13637                            CGDictionary.makeMemberName(m.identifier.name) +
 13638                            ")\n")
 13639         return retVal
 13641     def implUnlink(self):
 13642         retVal = ""
 13643         for m in self.descriptor.interface.members:
 13644             if m.isAttr():
 13645                 name = CGDictionary.makeMemberName(m.identifier.name)
 13646                 if m.type.isGeckoInterface():
 13647                     retVal += "  NS_IMPL_CYCLE_COLLECTION_UNLINK(" + name + ")\n"
 13648                 elif m.type.isAny():
 13649                     retVal += "  tmp->" + name + ".setUndefined();\n"
 13650                 elif m.type.isObject() or m.type.isSpiderMonkeyInterface():
 13651                     retVal += "  tmp->" + name + " = nullptr;\n"
 13652         return retVal
 13654     def implTrace(self):
 13655         retVal = ""
 13656         for m in self.descriptor.interface.members:
 13657             if m.isAttr():
 13658                 name = CGDictionary.makeMemberName(m.identifier.name)
 13659                 if m.type.isAny():
 13660                     retVal += "  NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(" + name + ")\n"
 13661                 elif m.type.isObject() or m.type.isSpiderMonkeyInterface():
 13662                     retVal += "  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(" + name + ")\n"
 13663                 elif typeNeedsRooting(m.type):
 13664                     raise TypeError("Need to implement tracing for event "
 13665                                     "member of type %s" % m.type)
 13666         return retVal
 13668     def define(self):
 13669         dropJS = ""
 13670         for m in self.descriptor.interface.members:
 13671             if m.isAttr():
 13672                 member = CGDictionary.makeMemberName(m.identifier.name)
 13673                 if m.type.isAny():
 13674                     dropJS += member + " = JS::UndefinedValue();\n"
 13675                 elif m.type.isObject() or m.type.isSpiderMonkeyInterface():
 13676                     dropJS += member + " = nullptr;\n"
 13677         if dropJS != "":
 13678             dropJS += "mozilla::DropJSObjects(this);\n"
 13679         # Just override CGClass and do our own thing
 13680         nativeType = self.descriptor.nativeType.split('::')[-1]
 13681         ctorParams = ("aOwner, nullptr, nullptr" if self.parentType == "Event"
 13682                       else "aOwner")
 13684         classImpl = fill(
 13685             """
 13687             NS_IMPL_CYCLE_COLLECTION_CLASS(${nativeType})
 13689             NS_IMPL_ADDREF_INHERITED(${nativeType}, ${parentType})
 13690             NS_IMPL_RELEASE_INHERITED(${nativeType}, ${parentType})
 13692             NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(${nativeType}, ${parentType})
 13693             $*{traverse}
 13694             NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 13696             NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(${nativeType}, ${parentType})
 13697             $*{trace}
 13698             NS_IMPL_CYCLE_COLLECTION_TRACE_END
 13700             NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(${nativeType}, ${parentType})
 13701             $*{unlink}
 13702             NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 13704             NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(${nativeType})
 13705             NS_INTERFACE_MAP_END_INHERITING(${parentType})
 13707             ${nativeType}::${nativeType}(mozilla::dom::EventTarget* aOwner)
 13708               : ${parentType}(${ctorParams})
 13712             ${nativeType}::~${nativeType}()
 13714               $*{dropJS}
 13717             """,
 13718             ifaceName=self.descriptor.name,
 13719             nativeType=nativeType,
 13720             ctorParams=ctorParams,
 13721             parentType=self.parentType,
 13722             traverse=self.implTraverse(),
 13723             unlink=self.implUnlink(),
 13724             trace=self.implTrace(),
 13725             dropJS=dropJS)
 13726         return classImpl + CGBindingImplClass.define(self)
 13729 class CGEventRoot(CGThing):
 13730     def __init__(self, config, interfaceName):
 13731         # Let's assume we're not doing workers stuff, for now
 13732         descriptor = config.getDescriptor(interfaceName, False)
 13734         self.root = CGWrapper(CGEventClass(descriptor),
 13735                               pre="\n", post="\n")
 13737         self.root = CGNamespace.build(["mozilla", "dom"], self.root)
 13739         self.root = CGList([CGClassForwardDeclare("JSContext", isStruct=True),
 13740                             self.root])
 13742         parent = descriptor.interface.parent.identifier.name
 13744         # Throw in our #includes
 13745         self.root = CGHeaders([descriptor], [], [], [],
 13747                                   config.getDescriptor(parent, False).headerFile,
 13748                                   "mozilla/Attributes.h",
 13749                                   "mozilla/ErrorResult.h",
 13750                                   "mozilla/dom/%sBinding.h" % interfaceName,
 13751                                   'mozilla/dom/BindingUtils.h',
 13752                               ],
 13754                                   "%s.h" % interfaceName,
 13755                                   "js/GCAPI.h",
 13756                                   'mozilla/dom/Nullable.h',
 13757                                   'nsDOMQS.h'
 13758                               ],
 13759                               "", self.root)
 13761         # And now some include guards
 13762         self.root = CGIncludeGuard(interfaceName, self.root)
 13764         self.root = CGWrapper(self.root, pre=AUTOGENERATED_WARNING_COMMENT)
 13766         self.root = CGWrapper(self.root, pre=dedent("""
 13767             /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 13768             /* vim:set ts=2 sw=2 sts=2 et cindent: */
 13769             /* This Source Code Form is subject to the terms of the Mozilla Public
 13770              * License, v. 2.0. If a copy of the MPL was not distributed with this
 13771              * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 13773             """))
 13775     def declare(self):
 13776         return self.root.declare()
 13778     def define(self):
 13779         return self.root.define()

mercurial