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/.
4
5# Common codegen classes.
6
7import os
8import re
9import string
10import math
11import textwrap
12import functools
13
14from WebIDL import BuiltinTypes, IDLBuiltinType, IDLNullValue, IDLSequenceType, IDLType, IDLAttribute, IDLInterfaceMember, IDLUndefinedValue, IDLEmptySequenceValue, IDLDictionary
15from Configuration import NoSuchDescriptorError, getTypesFromDescriptor, getTypesFromDictionary, getTypesFromCallback, getAllTypes, Descriptor, MemberIsUnforgeable, iteratorNativeType
16
17AUTOGENERATED_WARNING_COMMENT = \
18    "/* THIS FILE IS AUTOGENERATED BY Codegen.py - DO NOT EDIT */\n\n"
19AUTOGENERATED_WITH_SOURCE_WARNING_COMMENT = \
20    "/* THIS FILE IS AUTOGENERATED FROM %s BY Codegen.py - DO NOT EDIT */\n\n"
21ADDPROPERTY_HOOK_NAME = '_addProperty'
22FINALIZE_HOOK_NAME = '_finalize'
23OBJECT_MOVED_HOOK_NAME = '_objectMoved'
24CONSTRUCT_HOOK_NAME = '_constructor'
25LEGACYCALLER_HOOK_NAME = '_legacycaller'
26HASINSTANCE_HOOK_NAME = '_hasInstance'
27RESOLVE_HOOK_NAME = '_resolve'
28MAY_RESOLVE_HOOK_NAME = '_mayResolve'
29ENUMERATE_HOOK_NAME = '_enumerate'
30ENUM_ENTRY_VARIABLE_NAME = 'strings'
31INSTANCE_RESERVED_SLOTS = 1
32
33
34def memberReservedSlot(member, descriptor):
35    return ("(DOM_INSTANCE_RESERVED_SLOTS + %d)" %
36            member.slotIndices[descriptor.interface.identifier.name])
37
38
39def memberXrayExpandoReservedSlot(member, descriptor):
40    return ("(xpc::JSSLOT_EXPANDO_COUNT + %d)" %
41            member.slotIndices[descriptor.interface.identifier.name])
42
43
44def mayUseXrayExpandoSlots(descriptor, attr):
45    assert not attr.getExtendedAttribute("NewObject")
46    # For attributes whose type is a Gecko interface we always use
47    # slots on the reflector for caching.  Also, for interfaces that
48    # don't want Xrays we obviously never use the Xray expando slot.
49    return descriptor.wantsXrays and not attr.type.isGeckoInterface()
50
51
52def toStringBool(arg):
53    return str(not not arg).lower()
54
55
56def toBindingNamespace(arg):
57    return arg + "Binding"
58
59
60def isTypeCopyConstructible(type):
61    # Nullable and sequence stuff doesn't affect copy-constructibility
62    type = type.unroll()
63    return (type.isPrimitive() or type.isString() or type.isEnum() or
64            (type.isUnion() and
65             CGUnionStruct.isUnionCopyConstructible(type)) or
66            (type.isDictionary() and
67             CGDictionary.isDictionaryCopyConstructible(type.inner)) or
68            # Interface types are only copy-constructible if they're Gecko
69            # interfaces.  SpiderMonkey interfaces are not copy-constructible
70            # because of rooting issues.
71            (type.isInterface() and type.isGeckoInterface()))
72
73
74def idlTypeNeedsCycleCollection(type):
75    type = type.unroll()  # Takes care of sequences and nullables
76    if ((type.isPrimitive() and type.tag() in builtinNames) or
77        type.isEnum() or
78        type.isString() or
79        type.isAny() or
80        type.isObject() or
81        type.isSpiderMonkeyInterface()):
82        return False
83    elif type.isCallback() or type.isGeckoInterface():
84        return True
85    elif type.isUnion():
86        return any(idlTypeNeedsCycleCollection(t) for t in type.flatMemberTypes)
87    elif type.isMozMap():
88        if idlTypeNeedsCycleCollection(type.inner):
89            raise TypeError("Cycle collection for type %s is not supported" % type)
90        return False
91    elif type.isDictionary():
92        if any(idlTypeNeedsCycleCollection(m.type) for m in type.inner.members):
93            raise TypeError("Cycle collection for type %s is not supported" % type)
94        return False
95    else:
96        raise TypeError("Don't know whether to cycle-collect type %s" % type)
97
98
99def wantsAddProperty(desc):
100    return (desc.concrete and desc.wrapperCache and not desc.isGlobal())
101
102
103# We'll want to insert the indent at the beginnings of lines, but we
104# don't want to indent empty lines.  So only indent lines that have a
105# non-newline character on them.
106lineStartDetector = re.compile("^(?=[^\n#])", re.MULTILINE)
107
108
109def indent(s, indentLevel=2):
110    """
111    Indent C++ code.
112
113    Weird secret feature: this doesn't indent lines that start with # (such as
114    #include lines or #ifdef/#endif).
115    """
116    if s == "":
117        return s
118    return re.sub(lineStartDetector, indentLevel * " ", s)
119
120
121# dedent() and fill() are often called on the same string multiple
122# times.  We want to memoize their return values so we don't keep
123# recomputing them all the time.
124def memoize(fn):
125    """
126    Decorator to memoize a function of one argument.  The cache just
127    grows without bound.
128    """
129    cache = {}
130
131    @functools.wraps(fn)
132    def wrapper(arg):
133        retval = cache.get(arg)
134        if retval is None:
135            retval = cache[arg] = fn(arg)
136        return retval
137    return wrapper
138
139
140@memoize
141def dedent(s):
142    """
143    Remove all leading whitespace from s, and remove a blank line
144    at the beginning.
145    """
146    if s.startswith('\n'):
147        s = s[1:]
148    return textwrap.dedent(s)
149
150
151# This works by transforming the fill()-template to an equivalent
152# string.Template.
153fill_multiline_substitution_re = re.compile(r"( *)\$\*{(\w+)}(\n)?")
154
155
156find_substitutions = re.compile(r"\${")
157
158
159@memoize
160def compile_fill_template(template):
161    """
162    Helper function for fill().  Given the template string passed to fill(),
163    do the reusable part of template processing and return a pair (t,
164    argModList) that can be used every time fill() is called with that
165    template argument.
166
167    argsModList is list of tuples that represent modifications to be
168    made to args.  Each modification has, in order: i) the arg name,
169    ii) the modified name, iii) the indent depth.
170    """
171    t = dedent(template)
172    assert t.endswith("\n") or "\n" not in t
173    argModList = []
174
175    def replace(match):
176        """
177        Replaces a line like '  $*{xyz}\n' with '${xyz_n}',
178        where n is the indent depth, and add a corresponding entry to
179        argModList.
180
181        Note that this needs to close over argModList, so it has to be
182        defined inside compile_fill_template().
183        """
184        indentation, name, nl = match.groups()
185        depth = len(indentation)
186
187        # Check that $*{xyz} appears by itself on a line.
188        prev = match.string[:match.start()]
189        if (prev and not prev.endswith("\n")) or nl is None:
190            raise ValueError("Invalid fill() template: $*{%s} must appear by itself on a line" % name)
191
192        # Now replace this whole line of template with the indented equivalent.
193        modified_name = name + "_" + str(depth)
194        argModList.append((name, modified_name, depth))
195        return "${" + modified_name + "}"
196
197    t = re.sub(fill_multiline_substitution_re, replace, t)
198    if not re.search(find_substitutions, t):
199        raise TypeError("Using fill() when dedent() would do.")
200    return (string.Template(t), argModList)
201
202
203def fill(template, **args):
204    """
205    Convenience function for filling in a multiline template.
206
207    `fill(template, name1=v1, name2=v2)` is a lot like
208    `string.Template(template).substitute({"name1": v1, "name2": v2})`.
209
210    However, it's shorter, and has a few nice features:
211
212      * If `template` is indented, fill() automatically dedents it!
213        This makes code using fill() with Python's multiline strings
214        much nicer to look at.
215
216      * If `template` starts with a blank line, fill() strips it off.
217        (Again, convenient with multiline strings.)
218
219      * fill() recognizes a special kind of substitution
220        of the form `$*{name}`.
221
222        Use this to paste in, and automatically indent, multiple lines.
223        (Mnemonic: The `*` is for "multiple lines").
224
225        A `$*` substitution must appear by itself on a line, with optional
226        preceding indentation (spaces only). The whole line is replaced by the
227        corresponding keyword argument, indented appropriately.  If the
228        argument is an empty string, no output is generated, not even a blank
229        line.
230    """
231
232    t, argModList = compile_fill_template(template)
233    # Now apply argModList to args
234    for (name, modified_name, depth) in argModList:
235        if not (args[name] == "" or args[name].endswith("\n")):
236            raise ValueError("Argument %s with value %r is missing a newline" % (name, args[name]))
237        args[modified_name] = indent(args[name], depth)
238
239    return t.substitute(args)
240
241
242class CGThing():
243    """
244    Abstract base class for things that spit out code.
245    """
246    def __init__(self):
247        pass  # Nothing for now
248
249    def declare(self):
250        """Produce code for a header file."""
251        assert False  # Override me!
252
253    def define(self):
254        """Produce code for a cpp file."""
255        assert False  # Override me!
256
257    def deps(self):
258        """Produce the deps for a pp file"""
259        assert False  # Override me!
260
261
262class CGStringTable(CGThing):
263    """
264    Generate a string table for the given strings with a function accessor:
265
266    const char *accessorName(unsigned int index) {
267      static const char table[] = "...";
268      static const uint16_t indices = { ... };
269      return &table[indices[index]];
270    }
271
272    This is more efficient than the more natural:
273
274    const char *table[] = {
275      ...
276    };
277
278    The uint16_t indices are smaller than the pointer equivalents, and the
279    string table requires no runtime relocations.
280    """
281    def __init__(self, accessorName, strings):
282        CGThing.__init__(self)
283        self.accessorName = accessorName
284        self.strings = strings
285
286    def declare(self):
287        return "extern const char *%s(unsigned int aIndex);\n" % self.accessorName
288
289    def define(self):
290        table = ' "\\0" '.join('"%s"' % s for s in self.strings)
291        indices = []
292        currentIndex = 0
293        for s in self.strings:
294            indices.append(currentIndex)
295            currentIndex += len(s) + 1  # for the null terminator
296        return fill(
297            """
298            const char *${name}(unsigned int aIndex)
299            {
300              static const char table[] = ${table};
301              static const uint16_t indices[] = { ${indices} };
302              static_assert(${currentIndex} <= UINT16_MAX, "string table overflow!");
303              return &table[indices[aIndex]];
304            }
305            """,
306            name=self.accessorName,
307            table=table,
308            indices=", ".join("%d" % index for index in indices),
309            currentIndex=currentIndex)
310
311
312class CGNativePropertyHooks(CGThing):
313    """
314    Generate a NativePropertyHooks for a given descriptor
315    """
316    def __init__(self, descriptor, properties):
317        CGThing.__init__(self)
318        self.descriptor = descriptor
319        self.properties = properties
320
321    def declare(self):
322        if not self.descriptor.wantsXrays:
323            return ""
324        return dedent("""
325            // We declare this as an array so that retrieving a pointer to this
326            // binding's property hooks only requires compile/link-time resolvable
327            // address arithmetic.  Declaring it as a pointer instead would require
328            // doing a run-time load to fetch a pointer to this binding's property
329            // hooks.  And then structures which embedded a pointer to this structure
330            // would require a run-time load for proper initialization, which would
331            // then induce static constructors.  Lots of static constructors.
332            extern const NativePropertyHooks sNativePropertyHooks[];
333            """)
334
335    def define(self):
336        if not self.descriptor.wantsXrays:
337            return ""
338        deleteNamedProperty = "nullptr"
339        if self.descriptor.concrete and self.descriptor.proxy:
340            resolveOwnProperty = "ResolveOwnProperty"
341            enumerateOwnProperties = "EnumerateOwnProperties"
342            if self.descriptor.needsXrayNamedDeleterHook():
343                deleteNamedProperty = "DeleteNamedProperty"
344        elif self.descriptor.needsXrayResolveHooks():
345            resolveOwnProperty = "ResolveOwnPropertyViaResolve"
346            enumerateOwnProperties = "EnumerateOwnPropertiesViaGetOwnPropertyNames"
347        else:
348            resolveOwnProperty = "nullptr"
349            enumerateOwnProperties = "nullptr"
350        if self.properties.hasNonChromeOnly():
351            regular = "sNativeProperties.Upcast()"
352        else:
353            regular = "nullptr"
354        if self.properties.hasChromeOnly():
355            chrome = "sChromeOnlyNativeProperties.Upcast()"
356        else:
357            chrome = "nullptr"
358        constructorID = "constructors::id::"
359        if self.descriptor.interface.hasInterfaceObject():
360            constructorID += self.descriptor.name
361        else:
362            constructorID += "_ID_Count"
363        prototypeID = "prototypes::id::"
364        if self.descriptor.interface.hasInterfacePrototypeObject():
365            prototypeID += self.descriptor.name
366        else:
367            prototypeID += "_ID_Count"
368        parentProtoName = self.descriptor.parentPrototypeName
369        parentHooks = (toBindingNamespace(parentProtoName) + "::sNativePropertyHooks"
370                       if parentProtoName else 'nullptr')
371
372        if self.descriptor.wantsXrayExpandoClass:
373            expandoClass = "&sXrayExpandoObjectClass"
374        else:
375            expandoClass = "&DefaultXrayExpandoObjectClass"
376
377        return fill(
378            """
379            const NativePropertyHooks sNativePropertyHooks[] = { {
380              ${resolveOwnProperty},
381              ${enumerateOwnProperties},
382              ${deleteNamedProperty},
383              { ${regular}, ${chrome} },
384              ${prototypeID},
385              ${constructorID},
386              ${parentHooks},
387              ${expandoClass}
388            } };
389            """,
390            resolveOwnProperty=resolveOwnProperty,
391            enumerateOwnProperties=enumerateOwnProperties,
392            deleteNamedProperty=deleteNamedProperty,
393            regular=regular,
394            chrome=chrome,
395            prototypeID=prototypeID,
396            constructorID=constructorID,
397            parentHooks=parentHooks,
398            expandoClass=expandoClass)
399
400
401def NativePropertyHooks(descriptor):
402    return "&sEmptyNativePropertyHooks" if not descriptor.wantsXrays else "sNativePropertyHooks"
403
404
405def DOMClass(descriptor):
406    protoList = ['prototypes::id::' + proto for proto in descriptor.prototypeNameChain]
407    # Pad out the list to the right length with _ID_Count so we
408    # guarantee that all the lists are the same length.  _ID_Count
409    # is never the ID of any prototype, so it's safe to use as
410    # padding.
411    protoList.extend(['prototypes::id::_ID_Count'] * (descriptor.config.maxProtoChainLength - len(protoList)))
412
413    return fill(
414        """
415          { ${protoChain} },
416          IsBaseOf<nsISupports, ${nativeType} >::value,
417          ${hooks},
418          FindAssociatedGlobalForNative<${nativeType}>::Get,
419          GetProtoObjectHandle,
420          GetCCParticipant<${nativeType}>::Get()
421        """,
422        protoChain=', '.join(protoList),
423        nativeType=descriptor.nativeType,
424        hooks=NativePropertyHooks(descriptor))
425
426
427class CGDOMJSClass(CGThing):
428    """
429    Generate a DOMJSClass for a given descriptor
430    """
431    def __init__(self, descriptor):
432        CGThing.__init__(self)
433        self.descriptor = descriptor
434
435    def declare(self):
436        return ""
437
438    def define(self):
439        callHook = LEGACYCALLER_HOOK_NAME if self.descriptor.operations["LegacyCaller"] else 'nullptr'
440        objectMovedHook = OBJECT_MOVED_HOOK_NAME if self.descriptor.wrapperCache else 'nullptr'
441        slotCount = INSTANCE_RESERVED_SLOTS + self.descriptor.interface.totalMembersInSlots
442        classFlags = "JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | "
443        if self.descriptor.isGlobal():
444            classFlags += "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS)"
445            traceHook = "JS_GlobalObjectTraceHook"
446            reservedSlots = "JSCLASS_GLOBAL_APPLICATION_SLOTS"
447        else:
448            classFlags += "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount
449            traceHook = 'nullptr'
450            reservedSlots = slotCount
451        if self.descriptor.interface.isProbablyShortLivingObject():
452            classFlags += " | JSCLASS_SKIP_NURSERY_FINALIZE"
453        if self.descriptor.interface.getExtendedAttribute("NeedResolve"):
454            resolveHook = RESOLVE_HOOK_NAME
455            mayResolveHook = MAY_RESOLVE_HOOK_NAME
456            enumerateHook = ENUMERATE_HOOK_NAME
457        elif self.descriptor.isGlobal():
458            resolveHook = "mozilla::dom::ResolveGlobal"
459            mayResolveHook = "mozilla::dom::MayResolveGlobal"
460            enumerateHook = "mozilla::dom::EnumerateGlobal"
461        else:
462            resolveHook = "nullptr"
463            mayResolveHook = "nullptr"
464            enumerateHook = "nullptr"
465
466        return fill(
467            """
468            static const js::ClassOps sClassOps = {
469              ${addProperty}, /* addProperty */
470              nullptr,               /* delProperty */
471              nullptr,               /* getProperty */
472              nullptr,               /* setProperty */
473              ${enumerate}, /* enumerate */
474              ${resolve}, /* resolve */
475              ${mayResolve}, /* mayResolve */
476              ${finalize}, /* finalize */
477              ${call}, /* call */
478              nullptr,               /* hasInstance */
479              nullptr,               /* construct */
480              ${trace}, /* trace */
481            };
482
483            static const js::ClassExtension sClassExtension = {
484              nullptr, /* weakmapKeyDelegateOp */
485              ${objectMoved} /* objectMovedOp */
486            };
487
488            static const DOMJSClass sClass = {
489              { "${name}",
490                ${flags},
491                &sClassOps,
492                JS_NULL_CLASS_SPEC,
493                &sClassExtension,
494                JS_NULL_OBJECT_OPS
495              },
496              $*{descriptor}
497            };
498            static_assert(${instanceReservedSlots} == DOM_INSTANCE_RESERVED_SLOTS,
499                          "Must have the right minimal number of reserved slots.");
500            static_assert(${reservedSlots} >= ${slotCount},
501                          "Must have enough reserved slots.");
502            """,
503            name=self.descriptor.interface.identifier.name,
504            flags=classFlags,
505            addProperty=ADDPROPERTY_HOOK_NAME if wantsAddProperty(self.descriptor) else 'nullptr',
506            enumerate=enumerateHook,
507            resolve=resolveHook,
508            mayResolve=mayResolveHook,
509            finalize=FINALIZE_HOOK_NAME,
510            call=callHook,
511            trace=traceHook,
512            objectMoved=objectMovedHook,
513            descriptor=DOMClass(self.descriptor),
514            instanceReservedSlots=INSTANCE_RESERVED_SLOTS,
515            reservedSlots=reservedSlots,
516            slotCount=slotCount)
517
518
519class CGDOMProxyJSClass(CGThing):
520    """
521    Generate a DOMJSClass for a given proxy descriptor
522    """
523    def __init__(self, descriptor):
524        CGThing.__init__(self)
525        self.descriptor = descriptor
526
527    def declare(self):
528        return ""
529
530    def define(self):
531        flags = ["JSCLASS_IS_DOMJSCLASS"]
532        # We don't use an IDL annotation for JSCLASS_EMULATES_UNDEFINED because
533        # we don't want people ever adding that to any interface other than
534        # HTMLAllCollection.  So just hardcode it here.
535        if self.descriptor.interface.identifier.name == "HTMLAllCollection":
536            flags.append("JSCLASS_EMULATES_UNDEFINED")
537        objectMovedHook = OBJECT_MOVED_HOOK_NAME if self.descriptor.wrapperCache else 'nullptr'
538        return fill(
539            """
540            static const js::ClassExtension sClassExtension = PROXY_MAKE_EXT(
541                ${objectMoved}
542            );
543
544            static const DOMJSClass sClass = {
545              PROXY_CLASS_WITH_EXT("${name}",
546                                   ${flags},
547                                   &sClassExtension),
548              $*{descriptor}
549            };
550            """,
551            name=self.descriptor.interface.identifier.name,
552            flags=" | ".join(flags),
553            objectMoved=objectMovedHook,
554            descriptor=DOMClass(self.descriptor))
555
556
557class CGXrayExpandoJSClass(CGThing):
558    """
559    Generate a JSClass for an Xray expando object.  This is only
560    needed if we have members in slots (for [Cached] or [StoreInSlot]
561    stuff).
562    """
563    def __init__(self, descriptor):
564        assert descriptor.interface.totalMembersInSlots != 0
565        assert descriptor.wantsXrays
566        assert descriptor.wantsXrayExpandoClass
567        CGThing.__init__(self)
568        self.descriptor = descriptor;
569
570    def declare(self):
571        return ""
572
573    def define(self):
574        return fill(
575            """
576            // This may allocate too many slots, because we only really need
577            // slots for our non-interface-typed members that we cache.  But
578            // allocating slots only for those would make the slot index
579            // computations much more complicated, so let's do this the simple
580            // way for now.
581            DEFINE_XRAY_EXPANDO_CLASS(static, sXrayExpandoObjectClass, ${memberSlots});
582            """,
583            memberSlots=self.descriptor.interface.totalMembersInSlots)
584
585
586def PrototypeIDAndDepth(descriptor):
587    prototypeID = "prototypes::id::"
588    if descriptor.interface.hasInterfacePrototypeObject():
589        prototypeID += descriptor.interface.identifier.name
590        depth = "PrototypeTraits<%s>::Depth" % prototypeID
591    else:
592        prototypeID += "_ID_Count"
593        depth = "0"
594    return (prototypeID, depth)
595
596
597def InterfacePrototypeObjectProtoGetter(descriptor):
598    """
599    Returns a tuple with two elements:
600
601        1) The name of the function to call to get the prototype to use for the
602           interface prototype object as a JSObject*.
603
604        2) The name of the function to call to get the prototype to use for the
605           interface prototype object as a JS::Handle<JSObject*> or None if no
606           such function exists.
607    """
608    parentProtoName = descriptor.parentPrototypeName
609    if descriptor.hasNamedPropertiesObject:
610        protoGetter = "GetNamedPropertiesObject"
611        protoHandleGetter = None
612    elif parentProtoName is None:
613        if descriptor.interface.getExtendedAttribute("ArrayClass"):
614            protoGetter = "JS::GetRealmArrayPrototype"
615        elif descriptor.interface.getExtendedAttribute("ExceptionClass"):
616            protoGetter = "JS::GetRealmErrorPrototype"
617        elif descriptor.interface.isIteratorInterface():
618            protoGetter = "JS::GetRealmIteratorPrototype"
619        else:
620            protoGetter = "JS::GetRealmObjectPrototype"
621        protoHandleGetter = None
622    else:
623        prefix = toBindingNamespace(parentProtoName)
624        protoGetter = prefix + "::GetProtoObject"
625        protoHandleGetter = prefix + "::GetProtoObjectHandle"
626
627    return (protoGetter, protoHandleGetter)
628
629
630class CGPrototypeJSClass(CGThing):
631    def __init__(self, descriptor, properties):
632        CGThing.__init__(self)
633        self.descriptor = descriptor
634        self.properties = properties
635
636    def declare(self):
637        # We're purely for internal consumption
638        return ""
639
640    def define(self):
641        prototypeID, depth = PrototypeIDAndDepth(self.descriptor)
642        slotCount = "DOM_INTERFACE_PROTO_SLOTS_BASE"
643        # Globals handle unforgeables directly in Wrap() instead of
644        # via a holder.
645        if (self.descriptor.hasUnforgeableMembers and
646            not self.descriptor.isGlobal()):
647            slotCount += " + 1 /* slot for the JSObject holding the unforgeable properties */"
648        (protoGetter, _) = InterfacePrototypeObjectProtoGetter(self.descriptor)
649        type = "eGlobalInterfacePrototype" if self.descriptor.isGlobal() else "eInterfacePrototype"
650        return fill(
651            """
652            static const DOMIfaceAndProtoJSClass sPrototypeClass = {
653              {
654                "${name}Prototype",
655                JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(${slotCount}),
656                JS_NULL_CLASS_OPS,
657                JS_NULL_CLASS_SPEC,
658                JS_NULL_CLASS_EXT,
659                JS_NULL_OBJECT_OPS
660              },
661              ${type},
662              false,
663              ${prototypeID},
664              ${depth},
665              ${hooks},
666              "[object ${name}Prototype]",
667              ${protoGetter}
668            };
669            """,
670            name=self.descriptor.interface.identifier.name,
671            slotCount=slotCount,
672            type=type,
673            hooks=NativePropertyHooks(self.descriptor),
674            prototypeID=prototypeID,
675            depth=depth,
676            protoGetter=protoGetter)
677
678
679def NeedsGeneratedHasInstance(descriptor):
680    assert descriptor.interface.hasInterfaceObject()
681    return descriptor.hasXPConnectImpls or descriptor.interface.isConsequential()
682
683
684def InterfaceObjectProtoGetter(descriptor, forXrays=False):
685    """
686    Returns a tuple with two elements:
687
688        1) The name of the function to call to get the prototype to use for the
689           interface object as a JSObject*.
690
691        2) The name of the function to call to get the prototype to use for the
692           interface prototype as a JS::Handle<JSObject*> or None if no such
693           function exists.
694    """
695    parentInterface = descriptor.interface.parent
696    if parentInterface:
697        assert not descriptor.interface.isNamespace()
698        parentIfaceName = parentInterface.identifier.name
699        parentDesc = descriptor.getDescriptor(parentIfaceName)
700        prefix = toBindingNamespace(parentDesc.name)
701        protoGetter = prefix + "::GetConstructorObject"
702        protoHandleGetter = prefix + "::GetConstructorObjectHandle"
703    elif descriptor.interface.isNamespace():
704        if (forXrays or
705            not descriptor.interface.getExtendedAttribute("ProtoObjectHack")):
706            protoGetter = "JS::GetRealmObjectPrototype"
707        else:
708            protoGetter = "binding_detail::GetHackedNamespaceProtoObject"
709        protoHandleGetter = None
710    else:
711        protoGetter = "JS::GetRealmFunctionPrototype"
712        protoHandleGetter = None
713    return (protoGetter, protoHandleGetter)
714
715
716class CGInterfaceObjectJSClass(CGThing):
717    def __init__(self, descriptor, properties):
718        CGThing.__init__(self)
719        self.descriptor = descriptor
720        self.properties = properties
721
722    def declare(self):
723        # We're purely for internal consumption
724        return ""
725
726    def define(self):
727        if self.descriptor.interface.ctor():
728            assert not self.descriptor.interface.isNamespace()
729            ctorname = CONSTRUCT_HOOK_NAME
730        elif self.descriptor.interface.isNamespace():
731            ctorname = "nullptr"
732        else:
733            ctorname = "ThrowingConstructor"
734        needsHasInstance = (
735            not NeedsGeneratedHasInstance(self.descriptor) and
736            self.descriptor.interface.hasInterfacePrototypeObject())
737
738        prototypeID, depth = PrototypeIDAndDepth(self.descriptor)
739        slotCount = "DOM_INTERFACE_SLOTS_BASE"
740        if len(self.descriptor.interface.namedConstructors) > 0:
741            slotCount += (" + %i /* slots for the named constructors */" %
742                          len(self.descriptor.interface.namedConstructors))
743        (protoGetter, _) = InterfaceObjectProtoGetter(self.descriptor,
744                                                      forXrays=True)
745
746        if ctorname == "ThrowingConstructor":
747            ret = ""
748            classOpsPtr = "&sBoringInterfaceObjectClassClassOps"
749        elif ctorname == "nullptr":
750            ret = ""
751            classOpsPtr = "JS_NULL_CLASS_OPS"
752        else:
753            ret = fill(
754                """
755                static const js::ClassOps sInterfaceObjectClassOps = {
756                    nullptr,               /* addProperty */
757                    nullptr,               /* delProperty */
758                    nullptr,               /* getProperty */
759                    nullptr,               /* setProperty */
760                    nullptr,               /* enumerate */
761                    nullptr,               /* resolve */
762                    nullptr,               /* mayResolve */
763                    nullptr,               /* finalize */
764                    ${ctorname}, /* call */
765                    nullptr,               /* hasInstance */
766                    ${ctorname}, /* construct */
767                    nullptr,               /* trace */
768                };
769
770                """,
771                ctorname=ctorname)
772            classOpsPtr = "&sInterfaceObjectClassOps"
773
774        if self.descriptor.interface.isNamespace():
775            classString = self.descriptor.interface.getExtendedAttribute("ClassString")
776            if classString is None:
777                classString = "Object"
778            else:
779                classString = classString[0]
780            toStringResult = "[object %s]" % classString
781            objectOps = "JS_NULL_OBJECT_OPS"
782        else:
783            classString = "Function"
784            toStringResult = ("function %s() {\\n    [native code]\\n}" %
785                              self.descriptor.interface.identifier.name)
786            # We need non-default ObjectOps so we can actually make
787            # use of our toStringResult.
788            objectOps = "&sInterfaceObjectClassObjectOps"
789
790        ret = ret + fill(
791            """
792            static const DOMIfaceAndProtoJSClass sInterfaceObjectClass = {
793              {
794                "${classString}",
795                JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(${slotCount}),
796                ${classOpsPtr},
797                JS_NULL_CLASS_SPEC,
798                JS_NULL_CLASS_EXT,
799                ${objectOps}
800              },
801              eInterface,
802              ${needsHasInstance},
803              ${prototypeID},
804              ${depth},
805              ${hooks},
806              "${toStringResult}",
807              ${protoGetter}
808            };
809            """,
810            classString=classString,
811            slotCount=slotCount,
812            classOpsPtr=classOpsPtr,
813            hooks=NativePropertyHooks(self.descriptor),
814            objectOps=objectOps,
815            needsHasInstance=toStringBool(needsHasInstance),
816            prototypeID=prototypeID,
817            depth=depth,
818            toStringResult=toStringResult,
819            protoGetter=protoGetter)
820        return ret
821
822class CGList(CGThing):
823    """
824    Generate code for a list of GCThings.  Just concatenates them together, with
825    an optional joiner string.  "\n" is a common joiner.
826    """
827    def __init__(self, children, joiner=""):
828        CGThing.__init__(self)
829        # Make a copy of the kids into a list, because if someone passes in a
830        # generator we won't be able to both declare and define ourselves, or
831        # define ourselves more than once!
832        self.children = list(children)
833        self.joiner = joiner
834
835    def append(self, child):
836        self.children.append(child)
837
838    def prepend(self, child):
839        self.children.insert(0, child)
840
841    def extend(self, kids):
842        self.children.extend(kids)
843
844    def join(self, iterable):
845        return self.joiner.join(s for s in iterable if len(s) > 0)
846
847    def declare(self):
848        return self.join(child.declare() for child in self.children if child is not None)
849
850    def define(self):
851        return self.join(child.define() for child in self.children if child is not None)
852
853    def deps(self):
854        deps = set()
855        for child in self.children:
856            if child is None:
857                continue
858            deps = deps.union(child.deps())
859        return deps
860
861    def __len__(self):
862        return len(self.children)
863
864
865class CGGeneric(CGThing):
866    """
867    A class that spits out a fixed string into the codegen.  Can spit out a
868    separate string for the declaration too.
869    """
870    def __init__(self, define="", declare=""):
871        self.declareText = declare
872        self.defineText = define
873
874    def declare(self):
875        return self.declareText
876
877    def define(self):
878        return self.defineText
879
880    def deps(self):
881        return set()
882
883
884class CGIndenter(CGThing):
885    """
886    A class that takes another CGThing and generates code that indents that
887    CGThing by some number of spaces.  The default indent is two spaces.
888    """
889    def __init__(self, child, indentLevel=2, declareOnly=False):
890        assert isinstance(child, CGThing)
891        CGThing.__init__(self)
892        self.child = child
893        self.indentLevel = indentLevel
894        self.declareOnly = declareOnly
895
896    def declare(self):
897        return indent(self.child.declare(), self.indentLevel)
898
899    def define(self):
900        defn = self.child.define()
901        if self.declareOnly:
902            return defn
903        else:
904            return indent(defn, self.indentLevel)
905
906
907class CGWrapper(CGThing):
908    """
909    Generic CGThing that wraps other CGThings with pre and post text.
910    """
911    def __init__(self, child, pre="", post="", declarePre=None,
912                 declarePost=None, definePre=None, definePost=None,
913                 declareOnly=False, defineOnly=False, reindent=False):
914        CGThing.__init__(self)
915        self.child = child
916        self.declarePre = declarePre or pre
917        self.declarePost = declarePost or post
918        self.definePre = definePre or pre
919        self.definePost = definePost or post
920        self.declareOnly = declareOnly
921        self.defineOnly = defineOnly
922        self.reindent = reindent
923
924    def declare(self):
925        if self.defineOnly:
926            return ''
927        decl = self.child.declare()
928        if self.reindent:
929            decl = self.reindentString(decl, self.declarePre)
930        return self.declarePre + decl + self.declarePost
931
932    def define(self):
933        if self.declareOnly:
934            return ''
935        defn = self.child.define()
936        if self.reindent:
937            defn = self.reindentString(defn, self.definePre)
938        return self.definePre + defn + self.definePost
939
940    @staticmethod
941    def reindentString(stringToIndent, widthString):
942        # We don't use lineStartDetector because we don't want to
943        # insert whitespace at the beginning of our _first_ line.
944        # Use the length of the last line of width string, in case
945        # it is a multiline string.
946        lastLineWidth = len(widthString.splitlines()[-1])
947        return stripTrailingWhitespace(
948            stringToIndent.replace("\n", "\n" + (" " * lastLineWidth)))
949
950    def deps(self):
951        return self.child.deps()
952
953
954class CGIfWrapper(CGList):
955    def __init__(self, child, condition):
956        CGList.__init__(self, [
957            CGWrapper(CGGeneric(condition), pre="if (", post=") {\n", reindent=True),
958            CGIndenter(child),
959            CGGeneric("}\n")
960        ])
961
962
963class CGIfElseWrapper(CGList):
964    def __init__(self, condition, ifTrue, ifFalse):
965        CGList.__init__(self, [
966            CGWrapper(CGGeneric(condition), pre="if (", post=") {\n", reindent=True),
967            CGIndenter(ifTrue),
968            CGGeneric("} else {\n"),
969            CGIndenter(ifFalse),
970            CGGeneric("}\n")
971        ])
972
973
974class CGElseChain(CGThing):
975    """
976    Concatenate if statements in an if-else-if-else chain.
977    """
978    def __init__(self, children):
979        self.children = [c for c in children if c is not None]
980
981    def declare(self):
982        assert False
983
984    def define(self):
985        if not self.children:
986            return ""
987        s = self.children[0].define()
988        assert s.endswith("\n")
989        for child in self.children[1:]:
990            code = child.define()
991            assert code.startswith("if") or code.startswith("{")
992            assert code.endswith("\n")
993            s = s.rstrip() + " else " + code
994        return s
995
996
997class CGTemplatedType(CGWrapper):
998    def __init__(self, templateName, child, isConst=False, isReference=False):
999        const = "const " if isConst else ""
1000        pre = "%s%s<" % (const, templateName)
1001        ref = "&" if isReference else ""
1002        post = ">%s" % ref
1003        CGWrapper.__init__(self, child, pre=pre, post=post)
1004
1005
1006class CGNamespace(CGWrapper):
1007    def __init__(self, namespace, child, declareOnly=False):
1008        pre = "namespace %s {\n" % namespace
1009        post = "} // namespace %s\n" % namespace
1010        CGWrapper.__init__(self, child, pre=pre, post=post,
1011                           declareOnly=declareOnly)
1012
1013    @staticmethod
1014    def build(namespaces, child, declareOnly=False):
1015        """
1016        Static helper method to build multiple wrapped namespaces.
1017        """
1018        if not namespaces:
1019            return CGWrapper(child, declareOnly=declareOnly)
1020        inner = CGNamespace.build(namespaces[1:], child, declareOnly=declareOnly)
1021        return CGNamespace(namespaces[0], inner, declareOnly=declareOnly)
1022
1023
1024class CGIncludeGuard(CGWrapper):
1025    """
1026    Generates include guards for a header.
1027    """
1028    def __init__(self, prefix, child):
1029        """|prefix| is the filename without the extension."""
1030        define = 'mozilla_dom_%s_h' % prefix
1031        CGWrapper.__init__(self, child,
1032                           declarePre='#ifndef %s\n#define %s\n\n' % (define, define),
1033                           declarePost='\n#endif // %s\n' % define)
1034
1035
1036class CGHeaders(CGWrapper):
1037    """
1038    Generates the appropriate include statements.
1039    """
1040    def __init__(self, descriptors, dictionaries, callbacks,
1041                 callbackDescriptors,
1042                 declareIncludes, defineIncludes, prefix, child,
1043                 config=None, jsImplementedDescriptors=[]):
1044        """
1045        Builds a set of includes to cover |descriptors|.
1046
1047        Also includes the files in |declareIncludes| in the header
1048        file and the files in |defineIncludes| in the .cpp.
1049
1050        |prefix| contains the basename of the file that we generate include
1051        statements for.
1052        """
1053
1054        # Determine the filenames for which we need headers.
1055        interfaceDeps = [d.interface for d in descriptors]
1056        ancestors = []
1057        for iface in interfaceDeps:
1058            if iface.parent:
1059                # We're going to need our parent's prototype, to use as the
1060                # prototype of our prototype object.
1061                ancestors.append(iface.parent)
1062                # And if we have an interface object, we'll need the nearest
1063                # ancestor with an interface object too, so we can use its
1064                # interface object as the proto of our interface object.
1065                if iface.hasInterfaceObject():
1066                    parent = iface.parent
1067                    while parent and not parent.hasInterfaceObject():
1068                        parent = parent.parent
1069                    if parent:
1070                        ancestors.append(parent)
1071        interfaceDeps.extend(ancestors)
1072        bindingIncludes = set(self.getDeclarationFilename(d) for d in interfaceDeps)
1073
1074        # Grab all the implementation declaration files we need.
1075        implementationIncludes = set(d.headerFile for d in descriptors if d.needsHeaderInclude())
1076
1077        # Grab the includes for checking hasInstance
1078        interfacesImplementingSelf = set()
1079        for d in descriptors:
1080            interfacesImplementingSelf |= d.interface.interfacesImplementingSelf
1081        implementationIncludes |= set(self.getDeclarationFilename(i) for i in
1082                                      interfacesImplementingSelf)
1083
1084        # Grab the includes for the things that involve XPCOM interfaces
1085        hasInstanceIncludes = set("nsIDOM" + d.interface.identifier.name + ".h" for d
1086                                  in descriptors if
1087                                  d.interface.hasInterfaceObject() and
1088                                  NeedsGeneratedHasInstance(d) and
1089                                  d.interface.hasInterfacePrototypeObject())
1090        if len(hasInstanceIncludes) > 0:
1091            hasInstanceIncludes.add("nsContentUtils.h")
1092
1093        # Now find all the things we'll need as arguments because we
1094        # need to wrap or unwrap them.
1095        bindingHeaders = set()
1096        declareIncludes = set(declareIncludes)
1097
1098        def addHeadersForType((t, dictionary)):
1099            """
1100            Add the relevant headers for this type.  We use dictionary, if
1101            passed, to decide what to do with interface types.
1102            """
1103            # Dictionaries have members that need to be actually
1104            # declared, not just forward-declared.
1105            if dictionary:
1106                headerSet = declareIncludes
1107            else:
1108                headerSet = bindingHeaders
1109            if t.nullable():
1110                # Need to make sure that Nullable as a dictionary
1111                # member works.
1112                headerSet.add("mozilla/dom/Nullable.h")
1113            unrolled = t.unroll()
1114            if unrolled.isUnion():
1115                headerSet.add(self.getUnionDeclarationFilename(config, unrolled))
1116                bindingHeaders.add("mozilla/dom/UnionConversions.h")
1117            elif unrolled.isDate():
1118                if dictionary or jsImplementedDescriptors:
1119                    declareIncludes.add("mozilla/dom/Date.h")
1120                else:
1121                    bindingHeaders.add("mozilla/dom/Date.h")
1122            elif unrolled.isInterface():
1123                if unrolled.isSpiderMonkeyInterface():
1124                    bindingHeaders.add("jsfriendapi.h")
1125                    if jsImplementedDescriptors:
1126                        # Since we can't forward-declare typed array types
1127                        # (because they're typedefs), we have to go ahead and
1128                        # just include their header if we need to have functions
1129                        # taking references to them declared in that header.
1130                        headerSet = declareIncludes
1131                    headerSet.add("mozilla/dom/TypedArray.h")
1132                else:
1133                    try:
1134                        typeDesc = config.getDescriptor(unrolled.inner.identifier.name)
1135                    except NoSuchDescriptorError:
1136                        return
1137                    # Dictionaries with interface members rely on the
1138                    # actual class definition of that interface member
1139                    # being visible in the binding header, because they
1140                    # store them in RefPtr and have inline
1141                    # constructors/destructors.
1142                    #
1143                    # XXXbz maybe dictionaries with interface members
1144                    # should just have out-of-line constructors and
1145                    # destructors?
1146                    headerSet.add(typeDesc.headerFile)
1147            elif unrolled.isDictionary():
1148                headerSet.add(self.getDeclarationFilename(unrolled.inner))
1149            elif unrolled.isCallback():
1150                headerSet.add(self.getDeclarationFilename(unrolled.callback))
1151            elif unrolled.isFloat() and not unrolled.isUnrestricted():
1152                # Restricted floats are tested for finiteness
1153                bindingHeaders.add("mozilla/FloatingPoint.h")
1154                bindingHeaders.add("mozilla/dom/PrimitiveConversions.h")
1155            elif unrolled.isEnum():
1156                filename = self.getDeclarationFilename(unrolled.inner)
1157                declareIncludes.add(filename)
1158            elif unrolled.isPrimitive():
1159                bindingHeaders.add("mozilla/dom/PrimitiveConversions.h")
1160            elif unrolled.isMozMap():
1161                if dictionary or jsImplementedDescriptors:
1162                    declareIncludes.add("mozilla/dom/MozMap.h")
1163                else:
1164                    bindingHeaders.add("mozilla/dom/MozMap.h")
1165                # Also add headers for the type the MozMap is
1166                # parametrized over, if needed.
1167                addHeadersForType((t.inner, dictionary))
1168
1169        map(addHeadersForType,
1170            getAllTypes(descriptors + callbackDescriptors, dictionaries,
1171                        callbacks))
1172
1173        # Now make sure we're not trying to include the header from inside itself
1174        declareIncludes.discard(prefix + ".h")
1175
1176        def addHeaderForFunc(func, desc):
1177            if func is None:
1178                return
1179            # Include the right class header, which we can only do
1180            # if this is a class member function.
1181            if desc is not None and not desc.headerIsDefault:
1182                # An explicit header file was provided, assume that we know
1183                # what we're doing.
1184                return
1185
1186            if "::" in func:
1187                # Strip out the function name and convert "::" to "/"
1188                bindingHeaders.add("/".join(func.split("::")[:-1]) + ".h")
1189
1190        # Now for non-callback descriptors make sure we include any
1191        # headers needed by Func declarations and other things like that.
1192        for desc in descriptors:
1193            # If this is an iterator interface generated for a seperate
1194            # iterable interface, skip generating type includes, as we have
1195            # what we need in IterableIterator.h
1196            if desc.interface.isExternal() or desc.interface.isIteratorInterface():
1197                continue
1198
1199            for m in desc.interface.members:
1200                addHeaderForFunc(PropertyDefiner.getStringAttr(m, "Func"), desc)
1201                staticTypeOverride = PropertyDefiner.getStringAttr(m, "StaticClassOverride")
1202                if staticTypeOverride:
1203                    bindingHeaders.add("/".join(staticTypeOverride.split("::")) + ".h")
1204            # getExtendedAttribute() returns a list, extract the entry.
1205            funcList = desc.interface.getExtendedAttribute("Func")
1206            if funcList is not None:
1207                addHeaderForFunc(funcList[0], desc)
1208
1209            if desc.interface.maplikeOrSetlikeOrIterable:
1210                # We need ToJSValue.h for maplike/setlike type conversions
1211                bindingHeaders.add("mozilla/dom/ToJSValue.h")
1212                # Add headers for the key and value types of the
1213                # maplike/setlike/iterable, since they'll be needed for
1214                # convenience functions
1215                if desc.interface.maplikeOrSetlikeOrIterable.hasKeyType():
1216                    addHeadersForType((desc.interface.maplikeOrSetlikeOrIterable.keyType,
1217                                       None))
1218                if desc.interface.maplikeOrSetlikeOrIterable.hasValueType():
1219                    addHeadersForType((desc.interface.maplikeOrSetlikeOrIterable.valueType,
1220                                       None))
1221
1222        for d in dictionaries:
1223            if d.parent:
1224                declareIncludes.add(self.getDeclarationFilename(d.parent))
1225            bindingHeaders.add(self.getDeclarationFilename(d))
1226            for m in d.members:
1227                addHeaderForFunc(PropertyDefiner.getStringAttr(m, "Func"),
1228                                 None)
1229            # No need to worry about Func on members of ancestors, because that
1230            # will happen automatically in whatever files those ancestors live
1231            # in.
1232
1233        for c in callbacks:
1234            bindingHeaders.add(self.getDeclarationFilename(c))
1235
1236        for c in callbackDescriptors:
1237            bindingHeaders.add(self.getDeclarationFilename(c.interface))
1238
1239        if len(callbacks) != 0:
1240            # We need CallbackFunction to serve as our parent class
1241            declareIncludes.add("mozilla/dom/CallbackFunction.h")
1242            # And we need ToJSValue.h so we can wrap "this" objects
1243            declareIncludes.add("mozilla/dom/ToJSValue.h")
1244
1245        if len(callbackDescriptors) != 0 or len(jsImplementedDescriptors) != 0:
1246            # We need CallbackInterface to serve as our parent class
1247            declareIncludes.add("mozilla/dom/CallbackInterface.h")
1248            # And we need ToJSValue.h so we can wrap "this" objects
1249            declareIncludes.add("mozilla/dom/ToJSValue.h")
1250
1251        # Also need to include the headers for ancestors of
1252        # JS-implemented interfaces.
1253        for jsImplemented in jsImplementedDescriptors:
1254            jsParent = jsImplemented.interface.parent
1255            if jsParent:
1256                parentDesc = jsImplemented.getDescriptor(jsParent.identifier.name)
1257                declareIncludes.add(parentDesc.jsImplParentHeader)
1258
1259        # Let the machinery do its thing.
1260        def _includeString(includes):
1261            return ''.join(['#include "%s"\n' % i for i in includes]) + '\n'
1262        CGWrapper.__init__(self, child,
1263                           declarePre=_includeString(sorted(declareIncludes)),
1264                           definePre=_includeString(sorted(set(defineIncludes) |
1265                                                           bindingIncludes |
1266                                                           bindingHeaders |
1267                                                           hasInstanceIncludes |
1268                                                           implementationIncludes)))
1269
1270    @staticmethod
1271    def getDeclarationFilename(decl):
1272        # Use our local version of the header, not the exported one, so that
1273        # test bindings, which don't export, will work correctly.
1274        basename = os.path.basename(decl.filename())
1275        return basename.replace('.webidl', 'Binding.h')
1276
1277    @staticmethod
1278    def getUnionDeclarationFilename(config, unionType):
1279        assert unionType.isUnion()
1280        assert unionType.unroll() == unionType
1281        # If a union is "defined" in multiple files, it goes in UnionTypes.h.
1282        if len(config.filenamesPerUnion[unionType.name]) > 1:
1283            return "mozilla/dom/UnionTypes.h"
1284        # If a union is defined by a built-in typedef, it also goes in
1285        # UnionTypes.h.
1286        assert len(config.filenamesPerUnion[unionType.name]) == 1
1287        if "<unknown>" in config.filenamesPerUnion[unionType.name]:
1288            return "mozilla/dom/UnionTypes.h"
1289        return CGHeaders.getDeclarationFilename(unionType)
1290
1291
1292def SortedDictValues(d):
1293    """
1294    Returns a list of values from the dict sorted by key.
1295    """
1296    return [v for k, v in sorted(d.items())]
1297
1298
1299def UnionsForFile(config, webIDLFile):
1300    """
1301    Returns a list of union types for all union types that are only used in
1302    webIDLFile. If webIDLFile is None this will return the list of tuples for
1303    union types that are used in more than one WebIDL file.
1304    """
1305    return config.unionsPerFilename.get(webIDLFile, [])
1306
1307
1308def UnionTypes(unionTypes, config):
1309    """
1310    The unionTypes argument should be a list of union types. This is typically
1311    the list generated by UnionsForFile.
1312
1313    Returns a tuple containing a set of header filenames to include in
1314    the header for the types in unionTypes, a set of header filenames to
1315    include in the implementation file for the types in unionTypes, a set
1316    of tuples containing a type declaration and a boolean if the type is a
1317    struct for member types of the union, a list of traverse methods,
1318    unlink methods and a list of union types. These last three lists only
1319    contain unique union types.
1320    """
1321
1322    headers = set()
1323    implheaders = set()
1324    declarations = set()
1325    unionStructs = dict()
1326    traverseMethods = dict()
1327    unlinkMethods = dict()
1328
1329    for t in unionTypes:
1330        name = str(t)
1331        if name not in unionStructs:
1332            unionStructs[name] = t
1333
1334            def addHeadersForType(f):
1335                if f.nullable():
1336                    headers.add("mozilla/dom/Nullable.h")
1337                isSequence = f.isSequence()
1338                f = f.unroll()
1339                if f.isInterface():
1340                    if f.isSpiderMonkeyInterface():
1341                        headers.add("jsfriendapi.h")
1342                        headers.add("mozilla/dom/TypedArray.h")
1343                    else:
1344                        try:
1345                            typeDesc = config.getDescriptor(f.inner.identifier.name)
1346                        except NoSuchDescriptorError:
1347                            return
1348                        if typeDesc.interface.isCallback() or isSequence:
1349                            # Callback interfaces always use strong refs, so
1350                            # we need to include the right header to be able
1351                            # to Release() in our inlined code.
1352                            #
1353                            # Similarly, sequences always contain strong
1354                            # refs, so we'll need the header to handler
1355                            # those.
1356                            headers.add(typeDesc.headerFile)
1357                        else:
1358                            declarations.add((typeDesc.nativeType, False))
1359                            implheaders.add(typeDesc.headerFile)
1360                elif f.isDictionary():
1361                    # For a dictionary, we need to see its declaration in
1362                    # UnionTypes.h so we have its sizeof and know how big to
1363                    # make our union.
1364                    headers.add(CGHeaders.getDeclarationFilename(f.inner))
1365                    # And if it needs rooting, we need RootedDictionary too
1366                    if typeNeedsRooting(f):
1367                        headers.add("mozilla/dom/RootedDictionary.h")
1368                elif f.isEnum():
1369                    # Need to see the actual definition of the enum,
1370                    # unfortunately.
1371                    headers.add(CGHeaders.getDeclarationFilename(f.inner))
1372                elif f.isCallback():
1373                    # Callbacks always use strong refs, so we need to include
1374                    # the right header to be able to Release() in our inlined
1375                    # code.
1376                    headers.add(CGHeaders.getDeclarationFilename(f.callback))
1377                elif f.isMozMap():
1378                    headers.add("mozilla/dom/MozMap.h")
1379                    # And add headers for the type we're parametrized over
1380                    addHeadersForType(f.inner)
1381
1382            implheaders.add(CGHeaders.getUnionDeclarationFilename(config, t))
1383            for f in t.flatMemberTypes:
1384                assert not f.nullable()
1385                addHeadersForType(f)
1386
1387            if idlTypeNeedsCycleCollection(t):
1388                declarations.add(("mozilla::dom::%s" % CGUnionStruct.unionTypeName(t, True), False))
1389                traverseMethods[name] = CGCycleCollectionTraverseForOwningUnionMethod(t)
1390                unlinkMethods[name] = CGCycleCollectionUnlinkForOwningUnionMethod(t)
1391
1392    # The order of items in CGList is important.
1393    # Since the union structs friend the unlinkMethods, the forward-declaration
1394    # for these methods should come before the class declaration. Otherwise
1395    # some compilers treat the friend declaration as a forward-declaration in
1396    # the class scope.
1397    return (headers, implheaders, declarations,
1398            SortedDictValues(traverseMethods), SortedDictValues(unlinkMethods),
1399            SortedDictValues(unionStructs))
1400
1401
1402def UnionConversions(unionTypes, config):
1403    """
1404    The unionTypes argument should be a list of tuples, each containing two
1405    elements: a union type and a descriptor. This is typically the list
1406    generated by UnionsForFile.
1407
1408    Returns a tuple containing a list of headers and a CGThing to declare all
1409    union argument conversion helper structs.
1410    """
1411    headers = set()
1412    unionConversions = dict()
1413
1414    for t in unionTypes:
1415        name = str(t)
1416        if name not in unionConversions:
1417            unionConversions[name] = CGUnionConversionStruct(t, config)
1418
1419            def addHeadersForType(f):
1420                f = f.unroll()
1421                if f.isInterface():
1422                    if f.isSpiderMonkeyInterface():
1423                        headers.add("jsfriendapi.h")
1424                        headers.add("mozilla/dom/TypedArray.h")
1425                    elif f.inner.isExternal():
1426                        try:
1427                            typeDesc = config.getDescriptor(f.inner.identifier.name)
1428                        except NoSuchDescriptorError:
1429                            return
1430                        headers.add(typeDesc.headerFile)
1431                    else:
1432                        headers.add(CGHeaders.getDeclarationFilename(f.inner))
1433                elif f.isDictionary():
1434                    headers.add(CGHeaders.getDeclarationFilename(f.inner))
1435                elif f.isPrimitive():
1436                    headers.add("mozilla/dom/PrimitiveConversions.h")
1437                elif f.isMozMap():
1438                    headers.add("mozilla/dom/MozMap.h")
1439                    # And the internal type of the MozMap
1440                    addHeadersForType(f.inner)
1441
1442            # We plan to include UnionTypes.h no matter what, so it's
1443            # OK if we throw it into the set here.
1444            headers.add(CGHeaders.getUnionDeclarationFilename(config, t))
1445
1446            for f in t.flatMemberTypes:
1447                addHeadersForType(f)
1448
1449    return (headers,
1450            CGWrapper(CGList(SortedDictValues(unionConversions), "\n"),
1451                      post="\n\n"))
1452
1453
1454class Argument():
1455    """
1456    A class for outputting the type and name of an argument
1457    """
1458    def __init__(self, argType, name, default=None):
1459        self.argType = argType
1460        self.name = name
1461        self.default = default
1462
1463    def declare(self):
1464        string = self.argType + ' ' + self.name
1465        if self.default is not None:
1466            string += " = " + self.default
1467        return string
1468
1469    def define(self):
1470        return self.argType + ' ' + self.name
1471
1472
1473class CGAbstractMethod(CGThing):
1474    """
1475    An abstract class for generating code for a method.  Subclasses
1476    should override definition_body to create the actual code.
1477
1478    descriptor is the descriptor for the interface the method is associated with
1479
1480    name is the name of the method as a string
1481
1482    returnType is the IDLType of the return value
1483
1484    args is a list of Argument objects
1485
1486    inline should be True to generate an inline method, whose body is
1487    part of the declaration.
1488
1489    alwaysInline should be True to generate an inline method annotated with
1490    MOZ_ALWAYS_INLINE.
1491
1492    static should be True to generate a static method, which only has
1493    a definition.
1494
1495    If templateArgs is not None it should be a list of strings containing
1496    template arguments, and the function will be templatized using those
1497    arguments.
1498    """
1499    def __init__(self, descriptor, name, returnType, args, inline=False, alwaysInline=False, static=False, templateArgs=None):
1500        CGThing.__init__(self)
1501        self.descriptor = descriptor
1502        self.name = name
1503        self.returnType = returnType
1504        self.args = args
1505        self.inline = inline
1506        self.alwaysInline = alwaysInline
1507        self.static = static
1508        self.templateArgs = templateArgs
1509
1510    def _argstring(self, declare):
1511        return ', '.join([a.declare() if declare else a.define() for a in self.args])
1512
1513    def _template(self):
1514        if self.templateArgs is None:
1515            return ''
1516        return 'template <%s>\n' % ', '.join(self.templateArgs)
1517
1518    def _decorators(self):
1519        decorators = []
1520        if self.alwaysInline:
1521            decorators.append('MOZ_ALWAYS_INLINE')
1522        elif self.inline:
1523            decorators.append('inline')
1524        if self.static:
1525            decorators.append('static')
1526        decorators.append(self.returnType)
1527        maybeNewline = " " if self.inline else "\n"
1528        return ' '.join(decorators) + maybeNewline
1529
1530    def declare(self):
1531        if self.inline:
1532            return self._define(True)
1533        return "%s%s%s(%s);\n" % (self._template(), self._decorators(), self.name, self._argstring(True))
1534
1535    def indent_body(self, body):
1536        """
1537        Indent the code returned by self.definition_body(). Most classes
1538        simply indent everything two spaces. This is here for
1539        CGRegisterProtos, which needs custom indentation.
1540        """
1541        return indent(body)
1542
1543    def _define(self, fromDeclare=False):
1544        return (self.definition_prologue(fromDeclare) +
1545                self.indent_body(self.definition_body()) +
1546                self.definition_epilogue())
1547
1548    def define(self):
1549        return "" if self.inline else self._define()
1550
1551    def definition_prologue(self, fromDeclare):
1552        return "%s%s%s(%s)\n{\n" % (self._template(), self._decorators(),
1553                                    self.name, self._argstring(fromDeclare))
1554
1555    def definition_epilogue(self):
1556        return "}\n"
1557
1558    def definition_body(self):
1559        assert False  # Override me!
1560
1561
1562class CGAbstractStaticMethod(CGAbstractMethod):
1563    """
1564    Abstract base class for codegen of implementation-only (no
1565    declaration) static methods.
1566    """
1567    def __init__(self, descriptor, name, returnType, args):
1568        CGAbstractMethod.__init__(self, descriptor, name, returnType, args,
1569                                  inline=False, static=True)
1570
1571    def declare(self):
1572        # We only have implementation
1573        return ""
1574
1575
1576class CGAbstractClassHook(CGAbstractStaticMethod):
1577    """
1578    Meant for implementing JSClass hooks, like Finalize or Trace. Does very raw
1579    'this' unwrapping as it assumes that the unwrapped type is always known.
1580    """
1581    def __init__(self, descriptor, name, returnType, args):
1582        CGAbstractStaticMethod.__init__(self, descriptor, name, returnType,
1583                                        args)
1584
1585    def definition_body_prologue(self):
1586        return ("%s* self = UnwrapPossiblyNotInitializedDOMObject<%s>(obj);\n" %
1587                (self.descriptor.nativeType, self.descriptor.nativeType))
1588
1589    def definition_body(self):
1590        return self.definition_body_prologue() + self.generate_code()
1591
1592    def generate_code(self):
1593        assert False  # Override me!
1594
1595
1596class CGGetJSClassMethod(CGAbstractMethod):
1597    def __init__(self, descriptor):
1598        CGAbstractMethod.__init__(self, descriptor, 'GetJSClass', 'const JSClass*',
1599                                  [])
1600
1601    def definition_body(self):
1602        return "return sClass.ToJSClass();\n"
1603
1604
1605class CGAddPropertyHook(CGAbstractClassHook):
1606    """
1607    A hook for addProperty, used to preserve our wrapper from GC.
1608    """
1609    def __init__(self, descriptor):
1610        args = [Argument('JSContext*', 'cx'),
1611                Argument('JS::Handle<JSObject*>', 'obj'),
1612                Argument('JS::Handle<jsid>', 'id'),
1613                Argument('JS::Handle<JS::Value>', 'val')]
1614        CGAbstractClassHook.__init__(self, descriptor, ADDPROPERTY_HOOK_NAME,
1615                                     'bool', args)
1616
1617    def generate_code(self):
1618        assert self.descriptor.wrapperCache
1619        return dedent("""
1620            // We don't want to preserve if we don't have a wrapper, and we
1621            // obviously can't preserve if we're not initialized.
1622            if (self && self->GetWrapperPreserveColor()) {
1623              PreserveWrapper(self);
1624            }
1625            return true;
1626            """)
1627
1628
1629def finalizeHook(descriptor, hookName, freeOp):
1630    finalize = ""
1631    if descriptor.wrapperCache:
1632        finalize += "ClearWrapper(self, self);\n"
1633    if descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
1634        finalize += "self->mExpandoAndGeneration.expando = JS::UndefinedValue();\n"
1635    if descriptor.isGlobal():
1636        finalize += "mozilla::dom::FinalizeGlobal(CastToJSFreeOp(%s), obj);\n" % freeOp
1637    finalize += ("AddForDeferredFinalization<%s>(self);\n" %
1638                 descriptor.nativeType)
1639    return CGIfWrapper(CGGeneric(finalize), "self")
1640
1641
1642class CGClassFinalizeHook(CGAbstractClassHook):
1643    """
1644    A hook for finalize, used to release our native object.
1645    """
1646    def __init__(self, descriptor):
1647        args = [Argument('js::FreeOp*', 'fop'), Argument('JSObject*', 'obj')]
1648        CGAbstractClassHook.__init__(self, descriptor, FINALIZE_HOOK_NAME,
1649                                     'void', args)
1650
1651    def generate_code(self):
1652        return finalizeHook(self.descriptor, self.name, self.args[0].name).define()
1653
1654
1655class CGClassObjectMovedHook(CGAbstractClassHook):
1656    """
1657    A hook for objectMovedOp, used to update the wrapper cache when an object it
1658    is holding moves.
1659    """
1660    def __init__(self, descriptor):
1661        args = [Argument('JSObject*', 'obj'), Argument('const JSObject*', 'old')]
1662        CGAbstractClassHook.__init__(self, descriptor, OBJECT_MOVED_HOOK_NAME,
1663                                     'void', args)
1664
1665    def generate_code(self):
1666        assert self.descriptor.wrapperCache
1667        return CGIfWrapper(CGGeneric("UpdateWrapper(self, self, obj, old);\n"),
1668                           "self").define()
1669
1670
1671def JSNativeArguments():
1672    return [Argument('JSContext*', 'cx'),
1673            Argument('unsigned', 'argc'),
1674            Argument('JS::Value*', 'vp')]
1675
1676
1677class CGClassConstructor(CGAbstractStaticMethod):
1678    """
1679    JS-visible constructor for our objects
1680    """
1681    def __init__(self, descriptor, ctor, name=CONSTRUCT_HOOK_NAME):
1682        CGAbstractStaticMethod.__init__(self, descriptor, name, 'bool',
1683                                        JSNativeArguments())
1684        self._ctor = ctor
1685
1686    def define(self):
1687        if not self._ctor:
1688            return ""
1689        return CGAbstractStaticMethod.define(self)
1690
1691    def definition_body(self):
1692        return self.generate_code()
1693
1694    def generate_code(self):
1695        # [ChromeOnly] interfaces may only be constructed by chrome.
1696        chromeOnlyCheck = ""
1697        if isChromeOnly(self._ctor):
1698            chromeOnlyCheck = dedent("""
1699                if (!nsContentUtils::ThreadsafeIsCallerChrome()) {
1700                  return ThrowingConstructor(cx, argc, vp);
1701                }
1702
1703                """)
1704
1705        # Additionally, we want to throw if a caller does a bareword invocation
1706        # of a constructor without |new|. We don't enforce this for chrome in
1707        # realease builds to avoid the addon compat fallout of making that
1708        # change. See bug 916644.
1709        #
1710        # Figure out the name of our constructor for error reporting purposes.
1711        # For unnamed webidl constructors, identifier.name is "constructor" but
1712        # the name JS sees is the interface name; for named constructors
1713        # identifier.name is the actual name.
1714        name = self._ctor.identifier.name
1715        if name != "constructor":
1716            ctorName = name
1717        else:
1718            ctorName = self.descriptor.interface.identifier.name
1719
1720        preamble = fill(
1721            """
1722            JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
1723            JS::Rooted<JSObject*> obj(cx, &args.callee());
1724            $*{chromeOnlyCheck}
1725            if (!args.isConstructing()) {
1726              // XXXbz wish I could get the name from the callee instead of
1727              // Adding more relocations
1728              return ThrowConstructorWithoutNew(cx, "${ctorName}");
1729            }
1730            JS::Rooted<JSObject*> desiredProto(cx);
1731            if (!GetDesiredProto(cx, args, &desiredProto)) {
1732              return false;
1733            }
1734            """,
1735            chromeOnlyCheck=chromeOnlyCheck,
1736            ctorName=ctorName)
1737
1738        name = self._ctor.identifier.name
1739        nativeName = MakeNativeName(self.descriptor.binaryNameFor(name))
1740        callGenerator = CGMethodCall(nativeName, True, self.descriptor,
1741                                     self._ctor, isConstructor=True,
1742                                     constructorName=ctorName)
1743        return preamble + "\n" + callGenerator.define()
1744
1745
1746# Encapsulate the constructor in a helper method to share genConstructorBody with CGJSImplMethod.
1747class CGConstructNavigatorObject(CGAbstractMethod):
1748    """
1749    Construct a new JS-implemented WebIDL DOM object, for use on navigator.
1750    """
1751    def __init__(self, descriptor):
1752        args = [Argument('JSContext*', 'cx'),
1753                Argument('JS::Handle<JSObject*>', 'obj'),
1754                Argument('ErrorResult&', 'aRv')]
1755        rtype = 'already_AddRefed<%s>' % descriptor.name
1756        CGAbstractMethod.__init__(self, descriptor, "ConstructNavigatorObject",
1757                                  rtype, args)
1758
1759    def definition_body(self):
1760        if not self.descriptor.interface.isJSImplemented():
1761            raise TypeError("Only JS-implemented classes are currently supported "
1762                            "on navigator. See bug 856820.")
1763
1764        return dedent(
1765            """
1766            GlobalObject global(cx, obj);
1767            if (global.Failed()) {
1768              aRv.Throw(NS_ERROR_FAILURE);
1769              return nullptr;
1770            }
1771            """) + genConstructorBody(self.descriptor)
1772
1773
1774def NamedConstructorName(m):
1775    return '_' + m.identifier.name
1776
1777
1778class CGNamedConstructors(CGThing):
1779    def __init__(self, descriptor):
1780        self.descriptor = descriptor
1781        CGThing.__init__(self)
1782
1783    def declare(self):
1784        return ""
1785
1786    def define(self):
1787        if len(self.descriptor.interface.namedConstructors) == 0:
1788            return ""
1789
1790        constructorID = "constructors::id::"
1791        if self.descriptor.interface.hasInterfaceObject():
1792            constructorID += self.descriptor.name
1793        else:
1794            constructorID += "_ID_Count"
1795
1796        namedConstructors = ""
1797        for n in self.descriptor.interface.namedConstructors:
1798            namedConstructors += (
1799                "{ \"%s\", { %s, &sNamedConstructorNativePropertyHooks }, %i },\n" %
1800                (n.identifier.name, NamedConstructorName(n), methodLength(n)))
1801
1802        return fill(
1803            """
1804            const NativePropertyHooks sNamedConstructorNativePropertyHooks = {
1805                nullptr,
1806                nullptr,
1807                nullptr,
1808                { nullptr, nullptr },
1809                prototypes::id::${name},
1810                ${constructorID},
1811                nullptr
1812            };
1813
1814            static const NamedConstructor namedConstructors[] = {
1815              $*{namedConstructors}
1816              { nullptr, { nullptr, nullptr }, 0 }
1817            };
1818            """,
1819            name=self.descriptor.name,
1820            constructorID=constructorID,
1821            namedConstructors=namedConstructors)
1822
1823
1824class CGHasInstanceHook(CGAbstractStaticMethod):
1825    def __init__(self, descriptor):
1826        args = [Argument('JSContext*', 'cx'),
1827                Argument('unsigned', 'argc'),
1828                Argument('JS::Value*', 'vp')]
1829        assert descriptor.interface.hasInterfaceObject()
1830        assert NeedsGeneratedHasInstance(descriptor)
1831        CGAbstractStaticMethod.__init__(self, descriptor, HASINSTANCE_HOOK_NAME,
1832                                        'bool', args)
1833
1834    def define(self):
1835        return CGAbstractStaticMethod.define(self)
1836
1837    def definition_body(self):
1838        return self.generate_code()
1839
1840    def generate_code(self):
1841        header = dedent("""
1842            JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
1843            if (!args.get(0).isObject()) {
1844              args.rval().setBoolean(false);
1845              return true;
1846            }
1847
1848            JS::Rooted<JSObject*> instance(cx, &args[0].toObject());
1849            """)
1850        if self.descriptor.interface.hasInterfacePrototypeObject():
1851            return (
1852                header +
1853                fill(
1854                    """
1855
1856                    static_assert(IsBaseOf<nsISupports, ${nativeType}>::value,
1857                                  "HasInstance only works for nsISupports-based classes.");
1858
1859                    bool ok = InterfaceHasInstance(cx, argc, vp);
1860                    if (!ok || args.rval().toBoolean()) {
1861                      return ok;
1862                    }
1863
1864                    // FIXME Limit this to chrome by checking xpc::AccessCheck::isChrome(obj).
1865                    nsCOMPtr<nsISupports> native =
1866                      xpc::UnwrapReflectorToISupports(js::UncheckedUnwrap(instance, /* stopAtWindowProxy = */ false));
1867                    nsCOMPtr<nsIDOM${name}> qiResult = do_QueryInterface(native);
1868                    args.rval().setBoolean(!!qiResult);
1869                    return true;
1870                    """,
1871                    nativeType=self.descriptor.nativeType,
1872                    name=self.descriptor.interface.identifier.name))
1873
1874        hasInstanceCode = dedent("""
1875
1876            const DOMJSClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance, /* stopAtWindowProxy = */ false));
1877            if (!domClass) {
1878              // Not a DOM object, so certainly not an instance of this interface
1879              args.rval().setBoolean(false);
1880              return true;
1881            }
1882            """)
1883        if self.descriptor.interface.identifier.name == "ChromeWindow":
1884            setRval = "args.rval().setBoolean(UnwrapDOMObject<nsGlobalWindow>(js::UncheckedUnwrap(instance, /* stopAtWindowProxy = */ false))->IsChromeWindow())"
1885        else:
1886            setRval = "args.rval().setBoolean(true)"
1887        # Sort interaces implementing self by name so we get stable output.
1888        for iface in sorted(self.descriptor.interface.interfacesImplementingSelf,
1889                            key=lambda iface: iface.identifier.name):
1890            hasInstanceCode += fill(
1891                """
1892
1893                if (domClass->mInterfaceChain[PrototypeTraits<prototypes::id::${name}>::Depth] == prototypes::id::${name}) {
1894                  ${setRval};
1895                  return true;
1896                }
1897                """,
1898                name=iface.identifier.name,
1899                setRval=setRval)
1900        hasInstanceCode += ("args.rval().setBoolean(false);\n"
1901                            "return true;\n")
1902        return header + hasInstanceCode
1903
1904
1905def isChromeOnly(m):
1906    return m.getExtendedAttribute("ChromeOnly")
1907
1908
1909class MemberCondition:
1910    """
1911    An object representing the condition for a member to actually be
1912    exposed.  Any of the arguments can be None.  If not
1913    None, they should have the following types:
1914
1915    pref: The name of the preference.
1916    func: The name of the function.
1917    secureContext: A bool indicating whether a secure context is required.
1918    nonExposedGlobals: A set of names of globals.  Can be empty, in which case
1919                       it's treated the same way as None.
1920    """
1921    def __init__(self, pref=None, func=None, secureContext=False,
1922                 nonExposedGlobals=None):
1923        assert pref is None or isinstance(pref, str)
1924        assert func is None or isinstance(func, str)
1925        assert isinstance(secureContext, bool)
1926        assert nonExposedGlobals is None or isinstance(nonExposedGlobals, set)
1927        self.pref = pref
1928        self.secureContext = secureContext
1929
1930        def toFuncPtr(val):
1931            if val is None:
1932                return "nullptr"
1933            return "&" + val
1934        self.func = toFuncPtr(func)
1935
1936        if nonExposedGlobals:
1937            # Nonempty set
1938            self.nonExposedGlobals = " | ".join(
1939                map(lambda g: "GlobalNames::%s" % g,
1940                    sorted(nonExposedGlobals)))
1941        else:
1942            self.nonExposedGlobals = "0"
1943
1944    def __eq__(self, other):
1945        return (self.pref == other.pref and self.func == other.func and
1946                self.secureContext == other.secureContext and
1947                self.nonExposedGlobals == other.nonExposedGlobals)
1948
1949    def __ne__(self, other):
1950        return not self.__eq__(other)
1951
1952    def hasDisablers(self):
1953        return (self.pref is not None or
1954                self.secureContext or
1955                self.func != "nullptr" or
1956                self.nonExposedGlobals != "0")
1957
1958
1959class PropertyDefiner:
1960    """
1961    A common superclass for defining things on prototype objects.
1962
1963    Subclasses should implement generateArray to generate the actual arrays of
1964    things we're defining.  They should also set self.chrome to the list of
1965    things only exposed to chrome and self.regular to the list of things exposed
1966    to both chrome and web pages.
1967    """
1968    def __init__(self, descriptor, name):
1969        self.descriptor = descriptor
1970        self.name = name
1971        # self.prefCacheData will store an array of (prefname, bool*)
1972        # pairs for our bool var caches.  generateArray will fill it
1973        # in as needed.
1974        self.prefCacheData = []
1975
1976    def hasChromeOnly(self):
1977        return len(self.chrome) > 0
1978
1979    def hasNonChromeOnly(self):
1980        return len(self.regular) > 0
1981
1982    def variableName(self, chrome):
1983        if chrome:
1984            if self.hasChromeOnly():
1985                return "sChrome" + self.name
1986        else:
1987            if self.hasNonChromeOnly():
1988                return "s" + self.name
1989        return "nullptr"
1990
1991    def usedForXrays(self):
1992        return self.descriptor.wantsXrays
1993
1994    def __str__(self):
1995        # We only need to generate id arrays for things that will end
1996        # up used via ResolveProperty or EnumerateProperties.
1997        str = self.generateArray(self.regular, self.variableName(False),
1998                                 self.usedForXrays())
1999        if self.hasChromeOnly():
2000            str += self.generateArray(self.chrome, self.variableName(True),
2001                                      self.usedForXrays())
2002        return str
2003
2004    @staticmethod
2005    def getStringAttr(member, name):
2006        attr = member.getExtendedAttribute(name)
2007        if attr is None:
2008            return None
2009        # It's a list of strings
2010        assert len(attr) == 1
2011        assert attr[0] is not None
2012        return attr[0]
2013
2014    @staticmethod
2015    def getControllingCondition(interfaceMember, descriptor):
2016        interface = descriptor.interface
2017        nonExposureSet = interface.exposureSet - interfaceMember.exposureSet
2018
2019        return MemberCondition(
2020            PropertyDefiner.getStringAttr(interfaceMember,
2021                                          "Pref"),
2022            PropertyDefiner.getStringAttr(interfaceMember,
2023                                          "Func"),
2024            interfaceMember.getExtendedAttribute("SecureContext") is not None,
2025            nonExposureSet)
2026
2027    def generatePrefableArray(self, array, name, specFormatter, specTerminator,
2028                              specType, getCondition, getDataTuple, doIdArrays):
2029        """
2030        This method generates our various arrays.
2031
2032        array is an array of interface members as passed to generateArray
2033
2034        name is the name as passed to generateArray
2035
2036        specFormatter is a function that takes a single argument, a tuple,
2037          and returns a string, a spec array entry
2038
2039        specTerminator is a terminator for the spec array (inserted every time
2040          our controlling pref changes and at the end of the array)
2041
2042        specType is the actual typename of our spec
2043
2044        getCondition is a callback function that takes an array entry and
2045          returns the corresponding MemberCondition.
2046
2047        getDataTuple is a callback function that takes an array entry and
2048          returns a tuple suitable to be passed to specFormatter.
2049        """
2050
2051        # We want to generate a single list of specs, but with specTerminator
2052        # inserted at every point where the pref name controlling the member
2053        # changes.  That will make sure the order of the properties as exposed
2054        # on the interface and interface prototype objects does not change when
2055        # pref control is added to members while still allowing us to define all
2056        # the members in the smallest number of JSAPI calls.
2057        assert len(array) != 0
2058        # So we won't put a specTerminator at the very front of the list:
2059        lastCondition = getCondition(array[0], self.descriptor)
2060
2061        specs = []
2062        disablers = []
2063        prefableSpecs = []
2064
2065        disablersTemplate = dedent(
2066            """
2067            static PrefableDisablers %s_disablers%d = {
2068              true, %s, %s, %s
2069            };
2070            """)
2071        prefableWithDisablersTemplate = '  { &%s_disablers%d, &%s_specs[%d] }'
2072        prefableWithoutDisablersTemplate = '  { nullptr, &%s_specs[%d] }'
2073        prefCacheTemplate = '&%s[%d].disablers->enabled'
2074
2075        def switchToCondition(props, condition):
2076            # Remember the info about where our pref-controlled
2077            # booleans live.
2078            if condition.pref is not None:
2079                props.prefCacheData.append(
2080                    (condition.pref,
2081                     prefCacheTemplate % (name, len(prefableSpecs))))
2082            # Set up pointers to the new sets of specs inside prefableSpecs
2083            if condition.hasDisablers():
2084                prefableSpecs.append(prefableWithDisablersTemplate %
2085                                     (name, len(specs), name, len(specs)))
2086                disablers.append(disablersTemplate %
2087                                 (name, len(specs),
2088                                  toStringBool(condition.secureContext),
2089                                  condition.nonExposedGlobals,
2090                                  condition.func))
2091            else:
2092                prefableSpecs.append(prefableWithoutDisablersTemplate %
2093                                     (name, len(specs)))
2094
2095        switchToCondition(self, lastCondition)
2096
2097        for member in array:
2098            curCondition = getCondition(member, self.descriptor)
2099            if lastCondition != curCondition:
2100                # Terminate previous list
2101                specs.append(specTerminator)
2102                # And switch to our new condition
2103                switchToCondition(self, curCondition)
2104                lastCondition = curCondition
2105            # And the actual spec
2106            specs.append(specFormatter(getDataTuple(member)))
2107        specs.append(specTerminator)
2108        prefableSpecs.append("  { nullptr, nullptr }")
2109
2110        specType = "const " + specType
2111        arrays = fill(
2112            """
2113            static ${specType} ${name}_specs[] = {
2114            ${specs}
2115            };
2116
2117            ${disablers}
2118            // Can't be const because the pref-enabled boolean needs to be writable
2119            static Prefable<${specType}> ${name}[] = {
2120            ${prefableSpecs}
2121            };
2122
2123            """,
2124            specType=specType,
2125            name=name,
2126            disablers='\n'.join(disablers),
2127            specs=',\n'.join(specs),
2128            prefableSpecs=',\n'.join(prefableSpecs))
2129        if doIdArrays:
2130            arrays += "static jsid %s_ids[%i];\n\n" % (name, len(specs))
2131        return arrays
2132
2133
2134# The length of a method is the minimum of the lengths of the
2135# argument lists of all its overloads.
2136def overloadLength(arguments):
2137    i = len(arguments)
2138    while i > 0 and arguments[i - 1].optional:
2139        i -= 1
2140    return i
2141
2142
2143def methodLength(method):
2144    signatures = method.signatures()
2145    return min(overloadLength(arguments) for retType, arguments in signatures)
2146
2147
2148def clearableCachedAttrs(descriptor):
2149    return (m for m in descriptor.interface.members if
2150            m.isAttr() and
2151            # Constants should never need clearing!
2152            m.dependsOn != "Nothing" and
2153            m.slotIndices is not None)
2154
2155
2156def MakeClearCachedValueNativeName(member):
2157    return "ClearCached%sValue" % MakeNativeName(member.identifier.name)
2158
2159
2160def MakeJSImplClearCachedValueNativeName(member):
2161    return "_" + MakeClearCachedValueNativeName(member)
2162
2163
2164def IDLToCIdentifier(name):
2165    return name.replace("-", "_")
2166
2167
2168class MethodDefiner(PropertyDefiner):
2169    """
2170    A class for defining methods on a prototype object.
2171    """
2172    def __init__(self, descriptor, name, static, unforgeable=False):
2173        assert not (static and unforgeable)
2174        PropertyDefiner.__init__(self, descriptor, name)
2175
2176        # FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=772822
2177        #       We should be able to check for special operations without an
2178        #       identifier. For now we check if the name starts with __
2179
2180        # Ignore non-static methods for interfaces without a proto object
2181        if descriptor.interface.hasInterfacePrototypeObject() or static:
2182            methods = [m for m in descriptor.interface.members if
2183                       m.isMethod() and m.isStatic() == static and
2184                       MemberIsUnforgeable(m, descriptor) == unforgeable and
2185                       not m.isIdentifierLess()]
2186        else:
2187            methods = []
2188        self.chrome = []
2189        self.regular = []
2190        for m in methods:
2191            if m.identifier.name == 'queryInterface':
2192                if m.isStatic():
2193                    raise TypeError("Legacy queryInterface member shouldn't be static")
2194                signatures = m.signatures()
2195
2196                def argTypeIsIID(arg):
2197                    return arg.type.inner.isExternal() and arg.type.inner.identifier.name == 'IID'
2198                if len(signatures) > 1 or len(signatures[0][1]) > 1 or not argTypeIsIID(signatures[0][1][0]):
2199                    raise TypeError("There should be only one queryInterface method with 1 argument of type IID")
2200
2201                # Make sure to not stick QueryInterface on abstract interfaces that
2202                # have hasXPConnectImpls (like EventTarget).  So only put it on
2203                # interfaces that are concrete and all of whose ancestors are abstract.
2204                def allAncestorsAbstract(iface):
2205                    if not iface.parent:
2206                        return True
2207                    desc = self.descriptor.getDescriptor(iface.parent.identifier.name)
2208                    if desc.concrete:
2209                        return False
2210                    return allAncestorsAbstract(iface.parent)
2211                if (not self.descriptor.interface.hasInterfacePrototypeObject() or
2212                    not self.descriptor.concrete or
2213                    not allAncestorsAbstract(self.descriptor.interface)):
2214                    raise TypeError("QueryInterface is only supported on "
2215                                    "interfaces that are concrete and all "
2216                                    "of whose ancestors are abstract: " +
2217                                    self.descriptor.name)
2218                condition = "WantsQueryInterface<%s>::Enabled" % descriptor.nativeType
2219                self.regular.append({
2220                    "name": 'QueryInterface',
2221                    "methodInfo": False,
2222                    "length": 1,
2223                    "flags": "0",
2224                    "condition": MemberCondition(func=condition)
2225                })
2226                continue
2227
2228            # Iterable methods should be enumerable, maplike/setlike methods
2229            # should not.
2230            isMaplikeOrSetlikeMethod = (m.isMaplikeOrSetlikeOrIterableMethod() and
2231                                        (m.maplikeOrSetlikeOrIterable.isMaplike() or
2232                                         m.maplikeOrSetlikeOrIterable.isSetlike()))
2233            method = {
2234                "name": m.identifier.name,
2235                "methodInfo": not m.isStatic(),
2236                "length": methodLength(m),
2237                # Methods generated for a maplike/setlike declaration are not
2238                # enumerable.
2239                "flags": "JSPROP_ENUMERATE" if not isMaplikeOrSetlikeMethod else "0",
2240                "condition": PropertyDefiner.getControllingCondition(m, descriptor),
2241                "allowCrossOriginThis": m.getExtendedAttribute("CrossOriginCallable"),
2242                "returnsPromise": m.returnsPromise(),
2243                "hasIteratorAlias": "@@iterator" in m.aliases
2244            }
2245
2246            if m.isStatic():
2247                method["nativeName"] = CppKeywords.checkMethodName(IDLToCIdentifier(m.identifier.name))
2248
2249            if isChromeOnly(m):
2250                self.chrome.append(method)
2251            else:
2252                self.regular.append(method)
2253
2254        # TODO: Once iterable is implemented, use tiebreak rules instead of
2255        # failing. Also, may be more tiebreak rules to implement once spec bug
2256        # is resolved.
2257        # https://www.w3.org/Bugs/Public/show_bug.cgi?id=28592
2258        def hasIterator(methods, regular):
2259            return (any("@@iterator" in m.aliases for m in methods) or
2260                    any("@@iterator" == r["name"] for r in regular))
2261
2262        # Check whether we need to output an @@iterator due to having an indexed
2263        # getter.  We only do this while outputting non-static and
2264        # non-unforgeable methods, since the @@iterator function will be
2265        # neither.
2266        if (not static and
2267            not unforgeable and
2268            descriptor.supportsIndexedProperties()):
2269            if hasIterator(methods, self.regular):
2270                raise TypeError("Cannot have indexed getter/attr on "
2271                                "interface %s with other members "
2272                                "that generate @@iterator, such as "
2273                                "maplike/setlike or aliased functions." %
2274                                self.descriptor.interface.identifier.name)
2275            self.regular.append({
2276                "name": "@@iterator",
2277                "methodInfo": False,
2278                "selfHostedName": "ArrayValues",
2279                "length": 0,
2280                "flags": "JSPROP_ENUMERATE",
2281                "condition": MemberCondition()
2282            })
2283
2284        if (static and
2285            not unforgeable and
2286            descriptor.interface.hasInterfaceObject() and
2287            NeedsGeneratedHasInstance(descriptor)):
2288            self.regular.append({
2289                "name": "@@hasInstance",
2290                "methodInfo": False,
2291                "nativeName": HASINSTANCE_HOOK_NAME,
2292                "length": 1,
2293                # Flags match those of Function[Symbol.hasInstance]
2294                "flags": "JSPROP_READONLY | JSPROP_PERMANENT",
2295                "condition": MemberCondition()
2296            })
2297
2298        # Generate the keys/values/entries aliases for value iterables.
2299        maplikeOrSetlikeOrIterable = descriptor.interface.maplikeOrSetlikeOrIterable
2300        if (not static and
2301            not unforgeable and
2302            maplikeOrSetlikeOrIterable and
2303            maplikeOrSetlikeOrIterable.isIterable() and
2304            maplikeOrSetlikeOrIterable.isValueIterator()):
2305            # Add our keys/values/entries/forEach
2306            self.regular.append({
2307                "name": "keys",
2308                "methodInfo": False,
2309                "selfHostedName": "ArrayKeys",
2310                "length": 0,
2311                "flags": "JSPROP_ENUMERATE",
2312                "condition": PropertyDefiner.getControllingCondition(m,
2313                                                                     descriptor)
2314            })
2315            self.regular.append({
2316                "name": "values",
2317                "methodInfo": False,
2318                "selfHostedName": "ArrayValues",
2319                "length": 0,
2320                "flags": "JSPROP_ENUMERATE",
2321                "condition": PropertyDefiner.getControllingCondition(m,
2322                                                                     descriptor)
2323            })
2324            self.regular.append({
2325                "name": "entries",
2326                "methodInfo": False,
2327                "selfHostedName": "ArrayEntries",
2328                "length": 0,
2329                "flags": "JSPROP_ENUMERATE",
2330                "condition": PropertyDefiner.getControllingCondition(m,
2331                                                                     descriptor)
2332            })
2333            self.regular.append({
2334                "name": "forEach",
2335                "methodInfo": False,
2336                "selfHostedName": "ArrayForEach",
2337                "length": 1,
2338                "flags": "JSPROP_ENUMERATE",
2339                "condition": PropertyDefiner.getControllingCondition(m,
2340                                                                     descriptor)
2341            })
2342
2343        if not static:
2344            stringifier = descriptor.operations['Stringifier']
2345            if (stringifier and
2346                unforgeable == MemberIsUnforgeable(stringifier, descriptor)):
2347                toStringDesc = {
2348                    "name": "toString",
2349                    "nativeName": stringifier.identifier.name,
2350                    "length": 0,
2351                    "flags": "JSPROP_ENUMERATE",
2352                    "condition": PropertyDefiner.getControllingCondition(stringifier, descriptor)
2353                }
2354                if isChromeOnly(stringifier):
2355                    self.chrome.append(toStringDesc)
2356                else:
2357                    self.regular.append(toStringDesc)
2358            jsonifier = descriptor.operations['Jsonifier']
2359            if (jsonifier and
2360                unforgeable == MemberIsUnforgeable(jsonifier, descriptor)):
2361                toJSONDesc = {
2362                    "name": "toJSON",
2363                    "nativeName": jsonifier.identifier.name,
2364                    "length": 0,
2365                    "flags": "JSPROP_ENUMERATE",
2366                    "condition": PropertyDefiner.getControllingCondition(jsonifier, descriptor)
2367                }
2368                if isChromeOnly(jsonifier):
2369                    self.chrome.append(toJSONDesc)
2370                else:
2371                    self.regular.append(toJSONDesc)
2372            if (unforgeable and
2373                descriptor.interface.getExtendedAttribute("Unforgeable")):
2374                # Synthesize our valueOf method
2375                self.regular.append({
2376                    "name": 'valueOf',
2377                    "nativeName": "UnforgeableValueOf",
2378                    "methodInfo": False,
2379                    "length": 0,
2380                    "flags": "JSPROP_ENUMERATE",  # readonly/permanent added
2381                                                  # automatically.
2382                    "condition": MemberCondition()
2383                })
2384
2385        if descriptor.interface.isJSImplemented():
2386            if static:
2387                if descriptor.interface.hasInterfaceObject():
2388                    self.chrome.append({
2389                        "name": '_create',
2390                        "nativeName": ("%s::_Create" % descriptor.name),
2391                        "methodInfo": False,
2392                        "length": 2,
2393                        "flags": "0",
2394                        "condition": MemberCondition()
2395                    })
2396            else:
2397                for m in clearableCachedAttrs(descriptor):
2398                    attrName = MakeNativeName(m.identifier.name)
2399                    self.chrome.append({
2400                        "name": "_clearCached%sValue" % attrName,
2401                        "nativeName": MakeJSImplClearCachedValueNativeName(m),
2402                        "methodInfo": False,
2403                        "length": "0",
2404                        "flags": "0",
2405                        "condition": MemberCondition()
2406                    })
2407
2408        self.unforgeable = unforgeable
2409
2410        if static:
2411            if not descriptor.interface.hasInterfaceObject():
2412                # static methods go on the interface object
2413                assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
2414        else:
2415            if not descriptor.interface.hasInterfacePrototypeObject():
2416                # non-static methods go on the interface prototype object
2417                assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
2418
2419    def generateArray(self, array, name, doIdArrays):
2420        if len(array) == 0:
2421            return ""
2422
2423        def condition(m, d):
2424            return m["condition"]
2425
2426        def flags(m):
2427            unforgeable = " | JSPROP_PERMANENT | JSPROP_READONLY" if self.unforgeable else ""
2428            return m["flags"] + unforgeable
2429
2430        def specData(m):
2431            if "selfHostedName" in m:
2432                selfHostedName = '"%s"' % m["selfHostedName"]
2433                assert not m.get("methodInfo", True)
2434                accessor = "nullptr"
2435                jitinfo = "nullptr"
2436            else:
2437                selfHostedName = "nullptr"
2438                # When defining symbols, function name may not match symbol name
2439                methodName = m.get("methodName", m["name"])
2440                accessor = m.get("nativeName", IDLToCIdentifier(methodName))
2441                if m.get("methodInfo", True):
2442                    # Cast this in case the methodInfo is a
2443                    # JSTypedMethodJitInfo.
2444                    jitinfo = ("reinterpret_cast<const JSJitInfo*>(&%s_methodinfo)" % accessor)
2445                    if m.get("allowCrossOriginThis", False):
2446                        if m.get("returnsPromise", False):
2447                            raise TypeError("%s returns a Promise but should "
2448                                            "be allowed cross-origin?" %
2449                                            accessor)
2450                        accessor = "genericCrossOriginMethod"
2451                    elif self.descriptor.needsSpecialGenericOps():
2452                        if m.get("returnsPromise", False):
2453                            accessor = "genericPromiseReturningMethod"
2454                        else:
2455                            accessor = "genericMethod"
2456                    elif m.get("returnsPromise", False):
2457                        accessor = "GenericPromiseReturningBindingMethod"
2458                    else:
2459                        accessor = "GenericBindingMethod"
2460                else:
2461                    if m.get("returnsPromise", False):
2462                        jitinfo = "&%s_methodinfo" % accessor
2463                        accessor = "StaticMethodPromiseWrapper"
2464                    else:
2465                        jitinfo = "nullptr"
2466
2467            return (m["name"], accessor, jitinfo, m["length"], flags(m), selfHostedName)
2468
2469        def formatSpec(fields):
2470            if fields[0].startswith("@@"):
2471                fields = (fields[0][2:],) + fields[1:]
2472                return '  JS_SYM_FNSPEC(%s, %s, %s, %s, %s, %s)' % fields
2473            return '  JS_FNSPEC("%s", %s, %s, %s, %s, %s)' % fields
2474
2475        return self.generatePrefableArray(
2476            array, name,
2477            formatSpec,
2478            '  JS_FS_END',
2479            'JSFunctionSpec',
2480            condition, specData, doIdArrays)
2481
2482
2483def IsCrossOriginWritable(attr, descriptor):
2484    """
2485    Return whether the IDLAttribute in question is cross-origin writable on the
2486    interface represented by descriptor.  This is needed to handle the fact that
2487    some, but not all, interfaces implementing URLUtils want a cross-origin
2488    writable .href.
2489    """
2490    crossOriginWritable = attr.getExtendedAttribute("CrossOriginWritable")
2491    if not crossOriginWritable:
2492        return False
2493    if crossOriginWritable is True:
2494        return True
2495    assert (isinstance(crossOriginWritable, list) and
2496            len(crossOriginWritable) == 1)
2497    return crossOriginWritable[0] == descriptor.interface.identifier.name
2498
2499def isNonExposedNavigatorObjectGetter(attr, descriptor):
2500    return (attr.navigatorObjectGetter and
2501            not descriptor.getDescriptor(attr.type.inner.identifier.name).register)
2502
2503class AttrDefiner(PropertyDefiner):
2504    def __init__(self, descriptor, name, static, unforgeable=False):
2505        assert not (static and unforgeable)
2506        PropertyDefiner.__init__(self, descriptor, name)
2507        self.name = name
2508        # Ignore non-static attributes for interfaces without a proto object
2509        if descriptor.interface.hasInterfacePrototypeObject() or static:
2510            attributes = [m for m in descriptor.interface.members if
2511                          m.isAttr() and m.isStatic() == static and
2512                          MemberIsUnforgeable(m, descriptor) == unforgeable and
2513                          not isNonExposedNavigatorObjectGetter(m, descriptor)]
2514        else:
2515            attributes = []
2516        self.chrome = [m for m in attributes if isChromeOnly(m)]
2517        self.regular = [m for m in attributes if not isChromeOnly(m)]
2518        self.static = static
2519        self.unforgeable = unforgeable
2520
2521        if static:
2522            if not descriptor.interface.hasInterfaceObject():
2523                # static attributes go on the interface object
2524                assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
2525        else:
2526            if not descriptor.interface.hasInterfacePrototypeObject():
2527                # non-static attributes go on the interface prototype object
2528                assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
2529
2530    def generateArray(self, array, name, doIdArrays):
2531        if len(array) == 0:
2532            return ""
2533
2534        def flags(attr):
2535            unforgeable = " | JSPROP_PERMANENT" if self.unforgeable else ""
2536            # Attributes generated as part of a maplike/setlike declaration are
2537            # not enumerable.
2538            enumerable = " | JSPROP_ENUMERATE" if not attr.isMaplikeOrSetlikeAttr() else ""
2539            return ("JSPROP_SHARED" + enumerable + unforgeable)
2540
2541        def getter(attr):
2542            if self.static:
2543                accessor = 'get_' + IDLToCIdentifier(attr.identifier.name)
2544                jitinfo = "nullptr"
2545            else:
2546                if attr.hasLenientThis():
2547                    accessor = "genericLenientGetter"
2548                elif attr.getExtendedAttribute("CrossOriginReadable"):
2549                    accessor = "genericCrossOriginGetter"
2550                elif self.descriptor.needsSpecialGenericOps():
2551                    accessor = "genericGetter"
2552                else:
2553                    accessor = "GenericBindingGetter"
2554                jitinfo = ("&%s_getterinfo" %
2555                           IDLToCIdentifier(attr.identifier.name))
2556            return "{ { %s, %s } }" % \
2557                   (accessor, jitinfo)
2558
2559        def setter(attr):
2560            if (attr.readonly and
2561                attr.getExtendedAttribute("PutForwards") is None and
2562                attr.getExtendedAttribute("Replaceable") is None and
2563                attr.getExtendedAttribute("LenientSetter") is None):
2564                return "JSNATIVE_WRAPPER(nullptr)"
2565            if self.static:
2566                accessor = 'set_' + IDLToCIdentifier(attr.identifier.name)
2567                jitinfo = "nullptr"
2568            else:
2569                if attr.hasLenientThis():
2570                    accessor = "genericLenientSetter"
2571                elif IsCrossOriginWritable(attr, self.descriptor):
2572                    accessor = "genericCrossOriginSetter"
2573                elif self.descriptor.needsSpecialGenericOps():
2574                    accessor = "genericSetter"
2575                else:
2576                    accessor = "GenericBindingSetter"
2577                jitinfo = "&%s_setterinfo" % IDLToCIdentifier(attr.identifier.name)
2578            return "{ { %s, %s } }" % \
2579                   (accessor, jitinfo)
2580
2581        def specData(attr):
2582            return (attr.identifier.name, flags(attr), getter(attr),
2583                    setter(attr))
2584
2585        return self.generatePrefableArray(
2586            array, name,
2587            lambda fields: '  { "%s", %s, { { %s, %s } } }' % fields,
2588            '  JS_PS_END',
2589            'JSPropertySpec',
2590            PropertyDefiner.getControllingCondition, specData, doIdArrays)
2591
2592
2593class ConstDefiner(PropertyDefiner):
2594    """
2595    A class for definining constants on the interface object
2596    """
2597    def __init__(self, descriptor, name):
2598        PropertyDefiner.__init__(self, descriptor, name)
2599        self.name = name
2600        constants = [m for m in descriptor.interface.members if m.isConst()]
2601        self.chrome = [m for m in constants if isChromeOnly(m)]
2602        self.regular = [m for m in constants if not isChromeOnly(m)]
2603
2604    def generateArray(self, array, name, doIdArrays):
2605        if len(array) == 0:
2606            return ""
2607
2608        def specData(const):
2609            return (const.identifier.name,
2610                    convertConstIDLValueToJSVal(const.value))
2611
2612        return self.generatePrefableArray(
2613            array, name,
2614            lambda fields: '  { "%s", %s }' % fields,
2615            '  { 0, JS::UndefinedValue() }',
2616            'ConstantSpec',
2617            PropertyDefiner.getControllingCondition, specData, doIdArrays)
2618
2619
2620class PropertyArrays():
2621    def __init__(self, descriptor):
2622        self.staticMethods = MethodDefiner(descriptor, "StaticMethods",
2623                                           static=True)
2624        self.staticAttrs = AttrDefiner(descriptor, "StaticAttributes",
2625                                       static=True)
2626        self.methods = MethodDefiner(descriptor, "Methods", static=False)
2627        self.attrs = AttrDefiner(descriptor, "Attributes", static=False)
2628        self.unforgeableMethods = MethodDefiner(descriptor, "UnforgeableMethods",
2629                                                static=False, unforgeable=True)
2630        self.unforgeableAttrs = AttrDefiner(descriptor, "UnforgeableAttributes",
2631                                            static=False, unforgeable=True)
2632        self.consts = ConstDefiner(descriptor, "Constants")
2633
2634    @staticmethod
2635    def arrayNames():
2636        return ["staticMethods", "staticAttrs", "methods", "attrs",
2637                "unforgeableMethods", "unforgeableAttrs", "consts"]
2638
2639    def hasChromeOnly(self):
2640        return any(getattr(self, a).hasChromeOnly() for a in self.arrayNames())
2641
2642    def hasNonChromeOnly(self):
2643        return any(getattr(self, a).hasNonChromeOnly() for a in self.arrayNames())
2644
2645    def __str__(self):
2646        define = ""
2647        for array in self.arrayNames():
2648            define += str(getattr(self, array))
2649        return define
2650
2651
2652class CGNativeProperties(CGList):
2653    def __init__(self, descriptor, properties):
2654        def generateNativeProperties(name, chrome):
2655            def check(p):
2656                return p.hasChromeOnly() if chrome else p.hasNonChromeOnly()
2657
2658            nativePropsInts = []
2659            nativePropsTrios = []
2660
2661            iteratorAliasIndex = -1
2662            for index, item in enumerate(properties.methods.regular):
2663                if item.get("hasIteratorAlias"):
2664                    iteratorAliasIndex = index
2665                    break
2666            nativePropsInts.append(CGGeneric(str(iteratorAliasIndex)))
2667
2668            offset = 0
2669            for array in properties.arrayNames():
2670                propertyArray = getattr(properties, array)
2671                if check(propertyArray):
2672                    varName = propertyArray.variableName(chrome)
2673                    bitfields = "true,  %d /* %s */" % (offset, varName)
2674                    offset += 1
2675                    nativePropsInts.append(CGGeneric(bitfields))
2676
2677                    if propertyArray.usedForXrays():
2678                        ids = "%(name)s_ids"
2679                    else:
2680                        ids = "nullptr"
2681                    trio = "{ %(name)s, " + ids + ", %(name)s_specs }"
2682                    trio = trio % {'name': varName}
2683                    nativePropsTrios.append(CGGeneric(trio))
2684                else:
2685                    bitfields = "false, 0"
2686                    nativePropsInts.append(CGGeneric(bitfields))
2687
2688            nativePropsTrios = \
2689                [CGWrapper(CGIndenter(CGList(nativePropsTrios, ",\n")),
2690                           pre='{\n', post='\n}')]
2691            nativeProps = nativePropsInts + nativePropsTrios
2692            pre = ("static const NativePropertiesN<%d> %s = {\n" %
2693                   (offset, name))
2694            return CGWrapper(CGIndenter(CGList(nativeProps, ",\n")),
2695                             pre=pre, post="\n};\n")
2696
2697        nativeProperties = []
2698        if properties.hasNonChromeOnly():
2699            nativeProperties.append(
2700                generateNativeProperties("sNativeProperties", False))
2701        if properties.hasChromeOnly():
2702            nativeProperties.append(
2703                generateNativeProperties("sChromeOnlyNativeProperties", True))
2704
2705        CGList.__init__(self, nativeProperties, "\n")
2706
2707    def declare(self):
2708        return ""
2709
2710    def define(self):
2711        return CGList.define(self)
2712
2713
2714class CGJsonifyAttributesMethod(CGAbstractMethod):
2715    """
2716    Generate the JsonifyAttributes method for an interface descriptor
2717    """
2718    def __init__(self, descriptor):
2719        args = [Argument('JSContext*', 'aCx'),
2720                Argument('JS::Handle<JSObject*>', 'obj'),
2721                Argument('%s*' % descriptor.nativeType, 'self'),
2722                Argument('JS::Rooted<JSObject*>&', 'aResult')]
2723        CGAbstractMethod.__init__(self, descriptor, 'JsonifyAttributes', 'bool', args)
2724
2725    def definition_body(self):
2726        ret = ''
2727        interface = self.descriptor.interface
2728        for m in interface.members:
2729            if m.isAttr() and not m.isStatic() and m.type.isSerializable():
2730                ret += fill(
2731                    """
2732                    { // scope for "temp"
2733                      JS::Rooted<JS::Value> temp(aCx);
2734                      if (!get_${name}(aCx, obj, self, JSJitGetterCallArgs(&temp))) {
2735                        return false;
2736                      }
2737                      if (!JS_DefineProperty(aCx, aResult, "${name}", temp, JSPROP_ENUMERATE)) {
2738                        return false;
2739                      }
2740                    }
2741                    """,
2742                    name=IDLToCIdentifier(m.identifier.name))
2743        ret += 'return true;\n'
2744        return ret
2745
2746
2747class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
2748    """
2749    Generate the CreateInterfaceObjects method for an interface descriptor.
2750
2751    properties should be a PropertyArrays instance.
2752    """
2753    def __init__(self, descriptor, properties, haveUnscopables):
2754        args = [Argument('JSContext*', 'aCx'),
2755                Argument('JS::Handle<JSObject*>', 'aGlobal'),
2756                Argument('ProtoAndIfaceCache&', 'aProtoAndIfaceCache'),
2757                Argument('bool', 'aDefineOnGlobal')]
2758        CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args)
2759        self.properties = properties
2760        self.haveUnscopables = haveUnscopables
2761
2762    def definition_body(self):
2763        (protoGetter, protoHandleGetter) = InterfacePrototypeObjectProtoGetter(self.descriptor)
2764        if protoHandleGetter is None:
2765            parentProtoType = "Rooted"
2766            getParentProto = "aCx, " + protoGetter
2767        else:
2768            parentProtoType = "Handle"
2769            getParentProto = protoHandleGetter
2770        getParentProto = getParentProto + "(aCx)"
2771
2772        (protoGetter, protoHandleGetter) = InterfaceObjectProtoGetter(self.descriptor)
2773        if protoHandleGetter is None:
2774            getConstructorProto = "aCx, " + protoGetter
2775            constructorProtoType = "Rooted"
2776        else:
2777            getConstructorProto = protoHandleGetter
2778            constructorProtoType = "Handle"
2779        getConstructorProto += "(aCx)"
2780
2781        needInterfaceObject = self.descriptor.interface.hasInterfaceObject()
2782        needInterfacePrototypeObject = self.descriptor.interface.hasInterfacePrototypeObject()
2783
2784        # if we don't need to create anything, why are we generating this?
2785        assert needInterfaceObject or needInterfacePrototypeObject
2786
2787        getParentProto = fill(
2788            """
2789            JS::${type}<JSObject*> parentProto(${getParentProto});
2790            if (!parentProto) {
2791              return;
2792            }
2793            """,
2794            type=parentProtoType,
2795            getParentProto=getParentProto)
2796
2797        getConstructorProto = fill(
2798            """
2799            JS::${type}<JSObject*> constructorProto(${getConstructorProto});
2800            if (!constructorProto) {
2801              return;
2802            }
2803            """,
2804            type=constructorProtoType,
2805            getConstructorProto=getConstructorProto)
2806
2807        idsToInit = []
2808        # There is no need to init any IDs in bindings that don't want Xrays.
2809        if self.descriptor.wantsXrays:
2810            for var in self.properties.arrayNames():
2811                props = getattr(self.properties, var)
2812                # We only have non-chrome ids to init if we have no chrome ids.
2813                if props.hasChromeOnly():
2814                    idsToInit.append(props.variableName(True))
2815                if props.hasNonChromeOnly():
2816                    idsToInit.append(props.variableName(False))
2817        if len(idsToInit) > 0:
2818            initIdCalls = ["!InitIds(aCx, %s, %s_ids)" % (varname, varname)
2819                           for varname in idsToInit]
2820            idsInitedFlag = CGGeneric("static bool sIdsInited = false;\n")
2821            setFlag = CGGeneric("sIdsInited = true;\n")
2822            initIdConditionals = [CGIfWrapper(CGGeneric("return;\n"), call)
2823                                  for call in initIdCalls]
2824            initIds = CGList([idsInitedFlag,
2825                              CGIfWrapper(CGList(initIdConditionals + [setFlag]),
2826                                          "!sIdsInited && NS_IsMainThread()")])
2827        else:
2828            initIds = None
2829
2830        prefCacheData = []
2831        for var in self.properties.arrayNames():
2832            props = getattr(self.properties, var)
2833            prefCacheData.extend(props.prefCacheData)
2834        if len(prefCacheData) != 0:
2835            prefCacheData = [
2836                CGGeneric('Preferences::AddBoolVarCache(%s, "%s");\n' % (ptr, pref))
2837                for pref, ptr in prefCacheData]
2838            prefCache = CGWrapper(CGIndenter(CGList(prefCacheData)),
2839                                  pre=("static bool sPrefCachesInited = false;\n"
2840                                       "if (!sPrefCachesInited && NS_IsMainThread()) {\n"
2841                                       "  sPrefCachesInited = true;\n"),
2842                                  post="}\n")
2843        else:
2844            prefCache = None
2845
2846        if self.descriptor.interface.ctor():
2847            constructArgs = methodLength(self.descriptor.interface.ctor())
2848        else:
2849            constructArgs = 0
2850        if len(self.descriptor.interface.namedConstructors) > 0:
2851            namedConstructors = "namedConstructors"
2852        else:
2853            namedConstructors = "nullptr"
2854
2855        if needInterfacePrototypeObject:
2856            protoClass = "&sPrototypeClass.mBase"
2857            protoCache = "&aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::%s)" % self.descriptor.name
2858            parentProto = "parentProto"
2859            getParentProto = CGGeneric(getParentProto)
2860        else:
2861            protoClass = "nullptr"
2862            protoCache = "nullptr"
2863            parentProto = "nullptr"
2864            getParentProto = None
2865
2866        if needInterfaceObject:
2867            interfaceClass = "&sInterfaceObjectClass.mBase"
2868            interfaceCache = "&aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::%s)" % self.descriptor.name
2869            getConstructorProto = CGGeneric(getConstructorProto)
2870            constructorProto = "constructorProto"
2871        else:
2872            # We don't have slots to store the named constructors.
2873            assert len(self.descriptor.interface.namedConstructors) == 0
2874            interfaceClass = "nullptr"
2875            interfaceCache = "nullptr"
2876            getConstructorProto = None
2877            constructorProto = "nullptr"
2878
2879        isGlobal = self.descriptor.isGlobal() is not None
2880        if self.properties.hasNonChromeOnly():
2881            properties = "sNativeProperties.Upcast()"
2882        else:
2883            properties = "nullptr"
2884        if self.properties.hasChromeOnly():
2885            chromeProperties = "nsContentUtils::ThreadsafeIsCallerChrome() ? sChromeOnlyNativeProperties.Upcast() : nullptr"
2886        else:
2887            chromeProperties = "nullptr"
2888
2889        call = fill(
2890            """
2891            JS::Heap<JSObject*>* protoCache = ${protoCache};
2892            JS::Heap<JSObject*>* interfaceCache = ${interfaceCache};
2893            dom::CreateInterfaceObjects(aCx, aGlobal, ${parentProto},
2894                                        ${protoClass}, protoCache,
2895                                        ${constructorProto}, ${interfaceClass}, ${constructArgs}, ${namedConstructors},
2896                                        interfaceCache,
2897                                        ${properties},
2898                                        ${chromeProperties},
2899                                        ${name}, aDefineOnGlobal,
2900                                        ${unscopableNames},
2901                                        ${isGlobal});
2902            """,
2903            protoClass=protoClass,
2904            parentProto=parentProto,
2905            protoCache=protoCache,
2906            constructorProto=constructorProto,
2907            interfaceClass=interfaceClass,
2908            constructArgs=constructArgs,
2909            namedConstructors=namedConstructors,
2910            interfaceCache=interfaceCache,
2911            properties=properties,
2912            chromeProperties=chromeProperties,
2913            name='"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "nullptr",
2914            unscopableNames="unscopableNames" if self.haveUnscopables else "nullptr",
2915            isGlobal=toStringBool(isGlobal))
2916
2917        # If we fail after here, we must clear interface and prototype caches
2918        # using this code: intermediate failure must not expose the interface in
2919        # partially-constructed state.  Note that every case after here needs an
2920        # interface prototype object.
2921        failureCode = dedent(
2922            """
2923            *protoCache = nullptr;
2924            if (interfaceCache) {
2925              *interfaceCache = nullptr;
2926            }
2927            return;
2928            """)
2929
2930        aliasedMembers = [m for m in self.descriptor.interface.members if m.isMethod() and m.aliases]
2931        if aliasedMembers:
2932            assert needInterfacePrototypeObject
2933
2934            def defineAlias(alias):
2935                if alias == "@@iterator":
2936                    symbolJSID = "SYMBOL_TO_JSID(JS::GetWellKnownSymbol(aCx, JS::SymbolCode::iterator))"
2937                    getSymbolJSID = CGGeneric(fill("JS::Rooted<jsid> iteratorId(aCx, ${symbolJSID});",
2938                                                   symbolJSID=symbolJSID))
2939                    defineFn = "JS_DefinePropertyById"
2940                    prop = "iteratorId"
2941                elif alias.startswith("@@"):
2942                    raise TypeError("Can't handle any well-known Symbol other than @@iterator")
2943                else:
2944                    getSymbolJSID = None
2945                    defineFn = "JS_DefineProperty"
2946                    prop = '"%s"' % alias
2947                return CGList([
2948                    getSymbolJSID,
2949                    # XXX If we ever create non-enumerable properties that can
2950                    #     be aliased, we should consider making the aliases
2951                    #     match the enumerability of the property being aliased.
2952                    CGGeneric(fill(
2953                        """
2954                        if (!${defineFn}(aCx, proto, ${prop}, aliasedVal, JSPROP_ENUMERATE)) {
2955                          $*{failureCode}
2956                        }
2957                        """,
2958                        defineFn=defineFn,
2959                        prop=prop,
2960                        failureCode=failureCode))
2961                ], "\n")
2962
2963            def defineAliasesFor(m):
2964                return CGList([
2965                    CGGeneric(fill(
2966                        """
2967                        if (!JS_GetProperty(aCx, proto, \"${prop}\", &aliasedVal)) {
2968                          $*{failureCode}
2969                        }
2970                        """,
2971                        failureCode=failureCode,
2972                        prop=m.identifier.name))
2973                ] + [defineAlias(alias) for alias in sorted(m.aliases)])
2974
2975            defineAliases = CGList([
2976                CGGeneric(fill("""
2977                    // Set up aliases on the interface prototype object we just created.
2978                    JS::Handle<JSObject*> proto = GetProtoObjectHandle(aCx);
2979                    if (!proto) {
2980                      $*{failureCode}
2981                    }
2982
2983                    """,
2984                    failureCode=failureCode)),
2985                CGGeneric("JS::Rooted<JS::Value> aliasedVal(aCx);\n\n")
2986            ] + [defineAliasesFor(m) for m in sorted(aliasedMembers)])
2987        else:
2988            defineAliases = None
2989
2990        # Globals handle unforgeables directly in Wrap() instead of
2991        # via a holder.
2992        if self.descriptor.hasUnforgeableMembers and not self.descriptor.isGlobal():
2993            assert needInterfacePrototypeObject
2994
2995            # We want to use the same JSClass and prototype as the object we'll
2996            # end up defining the unforgeable properties on in the end, so that
2997            # we can use JS_InitializePropertiesFromCompatibleNativeObject to do
2998            # a fast copy.  In the case of proxies that's null, because the
2999            # expando object is a vanilla object, but in the case of other DOM
3000            # objects it's whatever our class is.
3001            if self.descriptor.proxy:
3002                holderClass = "nullptr"
3003                holderProto = "nullptr"
3004            else:
3005                holderClass = "sClass.ToJSClass()"
3006                holderProto = "*protoCache"
3007            createUnforgeableHolder = CGGeneric(fill(
3008                """
3009                JS::Rooted<JSObject*> unforgeableHolder(aCx);
3010                {
3011                  JS::Rooted<JSObject*> holderProto(aCx, ${holderProto});
3012                  unforgeableHolder = JS_NewObjectWithoutMetadata(aCx, ${holderClass}, holderProto);
3013                  if (!unforgeableHolder) {
3014                    $*{failureCode}
3015                  }
3016                }
3017                """,
3018                holderProto=holderProto,
3019                holderClass=holderClass,
3020                failureCode=failureCode))
3021            defineUnforgeables = InitUnforgeablePropertiesOnHolder(self.descriptor,
3022                                                                   self.properties,
3023                                                                   failureCode)
3024            createUnforgeableHolder = CGList(
3025                [createUnforgeableHolder, defineUnforgeables])
3026
3027            installUnforgeableHolder = CGGeneric(dedent(
3028                """
3029                if (*protoCache) {
3030                  js::SetReservedSlot(*protoCache, DOM_INTERFACE_PROTO_SLOTS_BASE,
3031                                      JS::ObjectValue(*unforgeableHolder));
3032                }
3033                """))
3034
3035            unforgeableHolderSetup = CGList(
3036                [createUnforgeableHolder, installUnforgeableHolder], "\n")
3037        else:
3038            unforgeableHolderSetup = None
3039
3040        if self.descriptor.name == "Promise":
3041            speciesSetup = CGGeneric(fill(
3042                """
3043                #ifndef SPIDERMONKEY_PROMISE
3044                JS::Rooted<JSObject*> promiseConstructor(aCx, *interfaceCache);
3045                JS::Rooted<jsid> species(aCx,
3046                  SYMBOL_TO_JSID(JS::GetWellKnownSymbol(aCx, JS::SymbolCode::species)));
3047                if (!JS_DefinePropertyById(aCx, promiseConstructor, species, JS::UndefinedHandleValue,
3048                                           JSPROP_SHARED, Promise::PromiseSpecies, nullptr)) {
3049                  $*{failureCode}
3050                }
3051                #endif // SPIDERMONKEY_PROMISE
3052                """,
3053                failureCode=failureCode))
3054        else:
3055            speciesSetup = None
3056
3057        if (self.descriptor.interface.isOnGlobalProtoChain() and
3058            needInterfacePrototypeObject):
3059            makeProtoPrototypeImmutable = CGGeneric(fill(
3060                """
3061                if (*${protoCache}) {
3062                  bool succeeded;
3063                  JS::Handle<JSObject*> prot = GetProtoObjectHandle(aCx);
3064                  if (!JS_SetImmutablePrototype(aCx, prot, &succeeded)) {
3065                    $*{failureCode}
3066                  }
3067
3068                  MOZ_ASSERT(succeeded,
3069                             "making a fresh prototype object's [[Prototype]] "
3070                             "immutable can internally fail, but it should "
3071                             "never be unsuccessful");
3072                }
3073                """,
3074                protoCache=protoCache,
3075                failureCode=failureCode))
3076        else:
3077            makeProtoPrototypeImmutable = None
3078
3079        return CGList(
3080            [getParentProto, getConstructorProto, initIds,
3081             prefCache, CGGeneric(call), defineAliases, unforgeableHolderSetup,
3082             speciesSetup, makeProtoPrototypeImmutable],
3083            "\n").define()
3084
3085
3086class CGGetPerInterfaceObject(CGAbstractMethod):
3087    """
3088    A method for getting a per-interface object (a prototype object or interface
3089    constructor object).
3090    """
3091    def __init__(self, descriptor, name, idPrefix="", extraArgs=[]):
3092        args = [Argument('JSContext*', 'aCx')] + extraArgs
3093        CGAbstractMethod.__init__(self, descriptor, name,
3094                                  'JS::Handle<JSObject*>', args)
3095        self.id = idPrefix + "id::" + self.descriptor.name
3096
3097    def definition_body(self):
3098        return fill(
3099            """
3100            /* Make sure our global is sane.  Hopefully we can remove this sometime */
3101            JSObject* global = JS::CurrentGlobalOrNull(aCx);
3102            if (!(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL)) {
3103              return nullptr;
3104            }
3105
3106            /* Check to see whether the interface objects are already installed */
3107            ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
3108            if (!protoAndIfaceCache.EntrySlotIfExists(${id})) {
3109              JS::Rooted<JSObject*> rootedGlobal(aCx, global);
3110              CreateInterfaceObjects(aCx, rootedGlobal, protoAndIfaceCache, aDefineOnGlobal);
3111            }
3112
3113            /*
3114             * The object might _still_ be null, but that's OK.
3115             *
3116             * Calling fromMarkedLocation() is safe because protoAndIfaceCache is
3117             * traced by TraceProtoAndIfaceCache() and its contents are never
3118             * changed after they have been set.
3119             *
3120             * Calling address() avoids the read read barrier that does gray
3121             * unmarking, but it's not possible for the object to be gray here.
3122             */
3123
3124            const JS::Heap<JSObject*>& entrySlot = protoAndIfaceCache.EntrySlotMustExist(${id});
3125            MOZ_ASSERT_IF(entrySlot, !JS::ObjectIsMarkedGray(entrySlot));
3126            return JS::Handle<JSObject*>::fromMarkedLocation(entrySlot.address());
3127            """,
3128            id=self.id)
3129
3130
3131class CGGetProtoObjectHandleMethod(CGGetPerInterfaceObject):
3132    """
3133    A method for getting the interface prototype object.
3134    """
3135    def __init__(self, descriptor):
3136        CGGetPerInterfaceObject.__init__(self, descriptor, "GetProtoObjectHandle",
3137                                         "prototypes::")
3138
3139    def definition_body(self):
3140        return dedent("""
3141            /* Get the interface prototype object for this class.  This will create the
3142               object as needed. */
3143            bool aDefineOnGlobal = true;
3144
3145            """) + CGGetPerInterfaceObject.definition_body(self)
3146
3147
3148class CGGetProtoObjectMethod(CGAbstractMethod):
3149    """
3150    A method for getting the interface prototype object.
3151    """
3152    def __init__(self, descriptor):
3153        CGAbstractMethod.__init__(
3154            self, descriptor, "GetProtoObject", "JSObject*",
3155            [Argument('JSContext*', 'aCx')])
3156
3157    def definition_body(self):
3158        return "return GetProtoObjectHandle(aCx);\n"
3159
3160
3161class CGGetConstructorObjectHandleMethod(CGGetPerInterfaceObject):
3162    """
3163    A method for getting the interface constructor object.
3164    """
3165    def __init__(self, descriptor):
3166        CGGetPerInterfaceObject.__init__(
3167            self, descriptor, "GetConstructorObjectHandle",
3168            "constructors::",
3169            extraArgs=[Argument("bool", "aDefineOnGlobal", "true")])
3170
3171    def definition_body(self):
3172        return dedent("""
3173            /* Get the interface object for this class.  This will create the object as
3174               needed. */
3175
3176            """) + CGGetPerInterfaceObject.definition_body(self)
3177
3178
3179class CGGetConstructorObjectMethod(CGAbstractMethod):
3180    """
3181    A method for getting the interface constructor object.
3182    """
3183    def __init__(self, descriptor):
3184        CGAbstractMethod.__init__(
3185            self, descriptor, "GetConstructorObject", "JSObject*",
3186            [Argument('JSContext*', 'aCx')])
3187
3188    def definition_body(self):
3189        return "return GetConstructorObjectHandle(aCx);\n"
3190
3191
3192class CGGetNamedPropertiesObjectMethod(CGAbstractStaticMethod):
3193    def __init__(self, descriptor):
3194        args = [Argument('JSContext*', 'aCx')]
3195        CGAbstractStaticMethod.__init__(self, descriptor,
3196                                        'GetNamedPropertiesObject',
3197                                        'JSObject*', args)
3198
3199    def definition_body(self):
3200        parentProtoName = self.descriptor.parentPrototypeName
3201        if parentProtoName is None:
3202            getParentProto = ""
3203            parentProto = "nullptr"
3204        else:
3205            getParentProto = fill(
3206                """
3207                JS::Rooted<JSObject*> parentProto(aCx, ${parent}::GetProtoObjectHandle(aCx));
3208                if (!parentProto) {
3209                  return nullptr;
3210                }
3211                """,
3212                parent=toBindingNamespace(parentProtoName))
3213            parentProto = "parentProto"
3214        return fill(
3215            """
3216            /* Make sure our global is sane.  Hopefully we can remove this sometime */
3217            JSObject* global = JS::CurrentGlobalOrNull(aCx);
3218            if (!(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL)) {
3219              return nullptr;
3220            }
3221
3222            /* Check to see whether the named properties object has already been created */
3223            ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
3224
3225            JS::Heap<JSObject*>& namedPropertiesObject = protoAndIfaceCache.EntrySlotOrCreate(namedpropertiesobjects::id::${ifaceName});
3226            if (!namedPropertiesObject) {
3227              $*{getParentProto}
3228              namedPropertiesObject = ${nativeType}::CreateNamedPropertiesObject(aCx, ${parentProto});
3229              DebugOnly<const DOMIfaceAndProtoJSClass*> clasp =
3230                DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(namedPropertiesObject));
3231              MOZ_ASSERT(clasp->mType == eNamedPropertiesObject,
3232                         "Expected ${nativeType}::CreateNamedPropertiesObject to return a named properties object");
3233              MOZ_ASSERT(clasp->mNativeHooks,
3234                         "The named properties object for ${nativeType} should have NativePropertyHooks.");
3235              MOZ_ASSERT(clasp->mNativeHooks->mResolveOwnProperty,
3236                         "Don't know how to resolve the properties of the named properties object for ${nativeType}.");
3237              MOZ_ASSERT(clasp->mNativeHooks->mEnumerateOwnProperties,
3238                         "Don't know how to enumerate the properties of the named properties object for ${nativeType}.");
3239            }
3240            return namedPropertiesObject.get();
3241            """,
3242            getParentProto=getParentProto,
3243            ifaceName=self.descriptor.name,
3244            parentProto=parentProto,
3245            nativeType=self.descriptor.nativeType)
3246
3247
3248class CGDefineDOMInterfaceMethod(CGAbstractMethod):
3249    """
3250    A method for resolve hooks to try to lazily define the interface object for
3251    a given interface.
3252    """
3253    def __init__(self, descriptor):
3254        args = [Argument('JSContext*', 'aCx'),
3255                Argument('JS::Handle<JSObject*>', 'aGlobal'),
3256                Argument('JS::Handle<jsid>', 'id'),
3257                Argument('bool', 'aDefineOnGlobal')]
3258        CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'JSObject*', args)
3259
3260    def definition_body(self):
3261        if len(self.descriptor.interface.namedConstructors) > 0:
3262            getConstructor = dedent("""
3263                JSObject* interfaceObject = GetConstructorObjectHandle(aCx, aDefineOnGlobal);
3264                if (!interfaceObject) {
3265                  return nullptr;
3266                }
3267                for (unsigned slot = DOM_INTERFACE_SLOTS_BASE; slot < JSCLASS_RESERVED_SLOTS(&sInterfaceObjectClass.mBase); ++slot) {
3268                  JSObject* constructor = &js::GetReservedSlot(interfaceObject, slot).toObject();
3269                  if (JS_GetFunctionId(JS_GetObjectFunction(constructor)) == JSID_TO_STRING(id)) {
3270                    return constructor;
3271                  }
3272                }
3273                return interfaceObject;
3274                """)
3275        else:
3276            getConstructor = "return GetConstructorObjectHandle(aCx, aDefineOnGlobal);\n"
3277        return getConstructor
3278
3279
3280def getConditionList(idlobj, cxName, objName):
3281    """
3282    Get the list of conditions for idlobj (to be used in "is this enabled"
3283    checks).  This will be returned as a CGList with " &&\n" as the separator,
3284    for readability.
3285
3286    objName is the name of the object that we're working with, because some of
3287    our test functions want that.
3288    """
3289    conditions = []
3290    pref = idlobj.getExtendedAttribute("Pref")
3291    if pref:
3292        assert isinstance(pref, list) and len(pref) == 1
3293        conditions.append('Preferences::GetBool("%s")' % pref[0])
3294    if idlobj.getExtendedAttribute("ChromeOnly"):
3295        conditions.append("nsContentUtils::ThreadsafeIsCallerChrome()")
3296    func = idlobj.getExtendedAttribute("Func")
3297    if func:
3298        assert isinstance(func, list) and len(func) == 1
3299        conditions.append("%s(%s, %s)" % (func[0], cxName, objName))
3300    if idlobj.getExtendedAttribute("SecureContext"):
3301        conditions.append("mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(%s, %s)" % (cxName, objName))
3302
3303    return CGList((CGGeneric(cond) for cond in conditions), " &&\n")
3304
3305
3306class CGConstructorEnabled(CGAbstractMethod):
3307    """
3308    A method for testing whether we should be exposing this interface
3309    object or navigator property.  This can perform various tests
3310    depending on what conditions are specified on the interface.
3311    """
3312    def __init__(self, descriptor):
3313        CGAbstractMethod.__init__(self, descriptor,
3314                                  'ConstructorEnabled', 'bool',
3315                                  [Argument("JSContext*", "aCx"),
3316                                   Argument("JS::Handle<JSObject*>", "aObj")])
3317
3318    def definition_body(self):
3319        body = CGList([], "\n")
3320
3321        iface = self.descriptor.interface
3322
3323        if not iface.isExposedOnMainThread():
3324            exposedInWindowCheck = dedent(
3325                """
3326                MOZ_ASSERT(!NS_IsMainThread(), "Why did we even get called?");
3327                """)
3328            body.append(CGGeneric(exposedInWindowCheck))
3329
3330        if iface.isExposedInSomeButNotAllWorkers():
3331            workerGlobals = sorted(iface.getWorkerExposureSet())
3332            workerCondition = CGList((CGGeneric('strcmp(name, "%s")' % workerGlobal)
3333                                      for workerGlobal in workerGlobals), " && ")
3334            exposedInWorkerCheck = fill(
3335                """
3336                const char* name = js::GetObjectClass(aObj)->name;
3337                if (${workerCondition}) {
3338                  return false;
3339                }
3340                """, workerCondition=workerCondition.define())
3341            exposedInWorkerCheck = CGGeneric(exposedInWorkerCheck)
3342            if iface.isExposedOnMainThread():
3343                exposedInWorkerCheck = CGIfWrapper(exposedInWorkerCheck,
3344                                                   "!NS_IsMainThread()")
3345            body.append(exposedInWorkerCheck)
3346
3347        conditions = getConditionList(iface, "aCx", "aObj")
3348
3349        # We should really have some conditions
3350        assert len(body) or len(conditions)
3351
3352        conditionsWrapper = ""
3353        if len(conditions):
3354            conditionsWrapper = CGWrapper(conditions,
3355                                          pre="return ",
3356                                          post=";\n",
3357                                          reindent=True)
3358        else:
3359            conditionsWrapper = CGGeneric("return true;\n")
3360
3361        body.append(conditionsWrapper)
3362        return body.define()
3363
3364
3365def CreateBindingJSObject(descriptor, properties):
3366    objDecl = "BindingJSObjectCreator<%s> creator(aCx);\n" % descriptor.nativeType
3367
3368    # We don't always need to root obj, but there are a variety
3369    # of cases where we do, so for simplicity, just always root it.
3370    if descriptor.proxy:
3371        create = dedent(
3372            """
3373            creator.CreateProxyObject(aCx, &sClass.mBase, DOMProxyHandler::getInstance(),
3374                                      proto, aObject, aReflector);
3375            if (!aReflector) {
3376              return false;
3377            }
3378
3379            """)
3380        if descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
3381            create += dedent("""
3382                js::SetProxyExtra(aReflector, JSPROXYSLOT_EXPANDO,
3383                                  JS::PrivateValue(&aObject->mExpandoAndGeneration));
3384
3385                """)
3386    else:
3387        create = dedent(
3388            """
3389            creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector);
3390            if (!aReflector) {
3391              return false;
3392            }
3393            """)
3394    return objDecl + create
3395
3396
3397def InitUnforgeablePropertiesOnHolder(descriptor, properties, failureCode,
3398                                      holderName="unforgeableHolder"):
3399    """
3400    Define the unforgeable properties on the unforgeable holder for
3401    the interface represented by descriptor.
3402
3403    properties is a PropertyArrays instance.
3404
3405    """
3406    assert (properties.unforgeableAttrs.hasNonChromeOnly() or
3407            properties.unforgeableAttrs.hasChromeOnly() or
3408            properties.unforgeableMethods.hasNonChromeOnly() or
3409            properties.unforgeableMethods.hasChromeOnly())
3410
3411    unforgeables = []
3412
3413    defineUnforgeableAttrs = fill(
3414        """
3415        if (!DefineUnforgeableAttributes(aCx, ${holderName}, %s)) {
3416          $*{failureCode}
3417        }
3418        """,
3419        failureCode=failureCode,
3420        holderName=holderName)
3421    defineUnforgeableMethods = fill(
3422        """
3423        if (!DefineUnforgeableMethods(aCx, ${holderName}, %s)) {
3424          $*{failureCode}
3425        }
3426        """,
3427        failureCode=failureCode,
3428        holderName=holderName)
3429
3430    unforgeableMembers = [
3431        (defineUnforgeableAttrs, properties.unforgeableAttrs),
3432        (defineUnforgeableMethods, properties.unforgeableMethods)
3433    ]
3434    for (template, array) in unforgeableMembers:
3435        if array.hasNonChromeOnly():
3436            unforgeables.append(CGGeneric(template % array.variableName(False)))
3437        if array.hasChromeOnly():
3438            unforgeables.append(
3439                CGIfWrapper(CGGeneric(template % array.variableName(True)),
3440                            "nsContentUtils::ThreadsafeIsCallerChrome()"))
3441
3442    if descriptor.interface.getExtendedAttribute("Unforgeable"):
3443        # We do our undefined toJSON and toPrimitive here, not as a regular
3444        # property because we don't have a concept of value props anywhere in
3445        # IDL.
3446        unforgeables.append(CGGeneric(fill(
3447            """
3448            JS::RootedId toPrimitive(aCx,
3449              SYMBOL_TO_JSID(JS::GetWellKnownSymbol(aCx, JS::SymbolCode::toPrimitive)));
3450            if (!JS_DefinePropertyById(aCx, ${holderName}, toPrimitive,
3451                                       JS::UndefinedHandleValue,
3452                                       JSPROP_READONLY | JSPROP_PERMANENT) ||
3453                !JS_DefineProperty(aCx, ${holderName}, "toJSON",
3454                                   JS::UndefinedHandleValue,
3455                                   JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT)) {
3456              $*{failureCode}
3457            }
3458            """,
3459            failureCode=failureCode,
3460            holderName=holderName)))
3461
3462    return CGWrapper(CGList(unforgeables), pre="\n")
3463
3464
3465def CopyUnforgeablePropertiesToInstance(descriptor, failureCode):
3466    """
3467    Copy the unforgeable properties from the unforgeable holder for
3468    this interface to the instance object we have.
3469    """
3470    assert not descriptor.isGlobal();
3471
3472    if not descriptor.hasUnforgeableMembers:
3473        return ""
3474
3475    copyCode = [
3476        CGGeneric(dedent(
3477            """
3478            // Important: do unforgeable property setup after we have handed
3479            // over ownership of the C++ object to obj as needed, so that if
3480            // we fail and it ends up GCed it won't have problems in the
3481            // finalizer trying to drop its ownership of the C++ object.
3482            """))
3483    ]
3484
3485    # For proxies, we want to define on the expando object, not directly on the
3486    # reflector, so we can make sure we don't get confused by named getters.
3487    if descriptor.proxy:
3488        copyCode.append(CGGeneric(fill(
3489            """
3490            JS::Rooted<JSObject*> expando(aCx,
3491              DOMProxyHandler::EnsureExpandoObject(aCx, aReflector));
3492            if (!expando) {
3493              $*{failureCode}
3494            }
3495            """,
3496            failureCode=failureCode)))
3497        obj = "expando"
3498    else:
3499        obj = "aReflector"
3500
3501    copyCode.append(CGGeneric(fill(
3502        """
3503        JS::Rooted<JSObject*> unforgeableHolder(aCx,
3504          &js::GetReservedSlot(canonicalProto, DOM_INTERFACE_PROTO_SLOTS_BASE).toObject());
3505        if (!JS_InitializePropertiesFromCompatibleNativeObject(aCx, ${obj}, unforgeableHolder)) {
3506          $*{failureCode}
3507        }
3508        """,
3509        obj=obj,
3510        failureCode=failureCode)))
3511
3512    return CGWrapper(CGList(copyCode), pre="\n").define()
3513
3514
3515def AssertInheritanceChain(descriptor):
3516    asserts = ""
3517    iface = descriptor.interface
3518    while iface:
3519        desc = descriptor.getDescriptor(iface.identifier.name)
3520        asserts += (
3521            "MOZ_ASSERT(static_cast<%s*>(aObject) == \n"
3522            "           reinterpret_cast<%s*>(aObject),\n"
3523            "           \"Multiple inheritance for %s is broken.\");\n" %
3524            (desc.nativeType, desc.nativeType, desc.nativeType))
3525        iface = iface.parent
3526    asserts += "MOZ_ASSERT(ToSupportsIsCorrect(aObject));\n"
3527    return asserts
3528
3529
3530def InitMemberSlots(descriptor, failureCode):
3531    """
3532    Initialize member slots on our JS object if we're supposed to have some.
3533
3534    Note that this is called after the SetWrapper() call in the
3535    wrapperCache case, since that can affect how our getters behave
3536    and we plan to invoke them here.  So if we fail, we need to
3537    ClearWrapper.
3538    """
3539    if not descriptor.interface.hasMembersInSlots():
3540        return ""
3541    return fill(
3542        """
3543        if (!UpdateMemberSlots(aCx, aReflector, aObject)) {
3544          $*{failureCode}
3545        }
3546        """,
3547        failureCode=failureCode)
3548
3549
3550def SetImmutablePrototype(descriptor, failureCode):
3551    if not descriptor.hasNonOrdinaryGetPrototypeOf():
3552        return ""
3553
3554    return fill(
3555        """
3556        bool succeeded;
3557        if (!JS_SetImmutablePrototype(aCx, aReflector, &succeeded)) {
3558          ${failureCode}
3559        }
3560        MOZ_ASSERT(succeeded,
3561                   "Making a fresh reflector instance have an immutable "
3562                   "prototype can internally fail, but it should never be "
3563                   "unsuccessful");
3564        """,
3565        failureCode=failureCode)
3566
3567
3568def DeclareProto():
3569    """
3570    Declare the canonicalProto and proto we have for our wrapping operation.
3571    """
3572    return dedent(
3573        """
3574        JS::Handle<JSObject*> canonicalProto = GetProtoObjectHandle(aCx);
3575        if (!canonicalProto) {
3576          return false;
3577        }
3578        JS::Rooted<JSObject*> proto(aCx);
3579        if (aGivenProto) {
3580          proto = aGivenProto;
3581          // Unfortunately, while aGivenProto was in the compartment of aCx
3582          // coming in, we changed compartments to that of "parent" so may need
3583          // to wrap the proto here.
3584          if (js::GetContextCompartment(aCx) != js::GetObjectCompartment(proto)) {
3585            if (!JS_WrapObject(aCx, &proto)) {
3586              return false;
3587            }
3588          }
3589        } else {
3590          proto = canonicalProto;
3591        }
3592        """)
3593
3594
3595class CGWrapWithCacheMethod(CGAbstractMethod):
3596    """
3597    Create a wrapper JSObject for a given native that implements nsWrapperCache.
3598
3599    properties should be a PropertyArrays instance.
3600    """
3601    def __init__(self, descriptor, properties):
3602        assert descriptor.interface.hasInterfacePrototypeObject()
3603        args = [Argument('JSContext*', 'aCx'),
3604                Argument(descriptor.nativeType + '*', 'aObject'),
3605                Argument('nsWrapperCache*', 'aCache'),
3606                Argument('JS::Handle<JSObject*>', 'aGivenProto'),
3607                Argument('JS::MutableHandle<JSObject*>', 'aReflector')]
3608        CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'bool', args)
3609        self.properties = properties
3610
3611    def definition_body(self):
3612        if self.descriptor.proxy:
3613            preserveWrapper = dedent(
3614                """
3615                // For DOM proxies, the only reliable way to preserve the wrapper
3616                // is to force creation of the expando object.
3617                JS::Rooted<JSObject*> unused(aCx,
3618                  DOMProxyHandler::EnsureExpandoObject(aCx, aReflector));
3619                """)
3620        else:
3621            preserveWrapper = "PreserveWrapper(aObject);\n"
3622
3623        failureCode = dedent(
3624            """
3625            aCache->ReleaseWrapper(aObject);
3626            aCache->ClearWrapper();
3627            return false;
3628            """)
3629
3630        return fill(
3631            """
3632            $*{assertInheritance}
3633            MOZ_ASSERT(!aCache->GetWrapper(),
3634                       "You should probably not be using Wrap() directly; use "
3635                       "GetOrCreateDOMReflector instead");
3636
3637            MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
3638                       "nsISupports must be on our primary inheritance chain");
3639
3640            JS::Rooted<JSObject*> global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject()));
3641            if (!global) {
3642              return false;
3643            }
3644            MOZ_ASSERT(JS_IsGlobalObject(global));
3645            MOZ_ASSERT(!JS::ObjectIsMarkedGray(global));
3646
3647            // That might have ended up wrapping us already, due to the wonders
3648            // of XBL.  Check for that, and bail out as needed.
3649            aReflector.set(aCache->GetWrapper());
3650            if (aReflector) {
3651            #ifdef DEBUG
3652              binding_detail::AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto);
3653            #endif // DEBUG
3654              return true;
3655            }
3656
3657            JSAutoCompartment ac(aCx, global);
3658            $*{declareProto}
3659
3660            $*{createObject}
3661
3662            aCache->SetWrapper(aReflector);
3663            $*{unforgeable}
3664            $*{slots}
3665            $*{setImmutablePrototype}
3666            creator.InitializationSucceeded();
3667
3668            MOZ_ASSERT(aCache->GetWrapperPreserveColor() &&
3669                       aCache->GetWrapperPreserveColor() == aReflector);
3670            // If proto != canonicalProto, we have to preserve our wrapper;
3671            // otherwise we won't be able to properly recreate it later, since
3672            // we won't know what proto to use.  Note that we don't check
3673            // aGivenProto here, since it's entirely possible (and even
3674            // somewhat common) to have a non-null aGivenProto which is the
3675            // same as canonicalProto.
3676            if (proto != canonicalProto) {
3677              $*{preserveWrapper}
3678            }
3679
3680            return true;
3681            """,
3682            assertInheritance=AssertInheritanceChain(self.descriptor),
3683            declareProto=DeclareProto(),
3684            createObject=CreateBindingJSObject(self.descriptor, self.properties),
3685            unforgeable=CopyUnforgeablePropertiesToInstance(self.descriptor,
3686                                                            failureCode),
3687            slots=InitMemberSlots(self.descriptor, failureCode),
3688            setImmutablePrototype=SetImmutablePrototype(self.descriptor,
3689                                                        failureCode),
3690            preserveWrapper=preserveWrapper)
3691
3692
3693class CGWrapMethod(CGAbstractMethod):
3694    def __init__(self, descriptor):
3695        # XXX can we wrap if we don't have an interface prototype object?
3696        assert descriptor.interface.hasInterfacePrototypeObject()
3697        args = [Argument('JSContext*', 'aCx'),
3698                Argument('T*', 'aObject'),
3699                Argument('JS::Handle<JSObject*>', 'aGivenProto')]
3700        CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args,
3701                                  inline=True, templateArgs=["class T"])
3702
3703    def definition_body(self):
3704        return dedent("""
3705            JS::Rooted<JSObject*> reflector(aCx);
3706            return Wrap(aCx, aObject, aObject, aGivenProto, &reflector) ? reflector.get() : nullptr;
3707            """)
3708
3709
3710class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
3711    """
3712    Create a wrapper JSObject for a given native that does not implement
3713    nsWrapperCache.
3714
3715    properties should be a PropertyArrays instance.
3716    """
3717    def __init__(self, descriptor, properties):
3718        # XXX can we wrap if we don't have an interface prototype object?
3719        assert descriptor.interface.hasInterfacePrototypeObject()
3720        args = [Argument('JSContext*', 'aCx'),
3721                Argument(descriptor.nativeType + '*', 'aObject'),
3722                Argument('JS::Handle<JSObject*>', 'aGivenProto'),
3723                Argument('JS::MutableHandle<JSObject*>', 'aReflector')]
3724        CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'bool', args)
3725        self.properties = properties
3726
3727    def definition_body(self):
3728        failureCode = "return false;\n"
3729
3730        return fill(
3731            """
3732            $*{assertions}
3733
3734            JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
3735            $*{declareProto}
3736
3737            $*{createObject}
3738
3739            $*{unforgeable}
3740
3741            $*{slots}
3742
3743            $*{setImmutablePrototype}
3744            creator.InitializationSucceeded();
3745            return true;
3746            """,
3747            assertions=AssertInheritanceChain(self.descriptor),
3748            declareProto=DeclareProto(),
3749            createObject=CreateBindingJSObject(self.descriptor, self.properties),
3750            unforgeable=CopyUnforgeablePropertiesToInstance(self.descriptor,
3751                                                            failureCode),
3752            slots=InitMemberSlots(self.descriptor, failureCode),
3753            setImmutablePrototype=SetImmutablePrototype(self.descriptor,
3754                                                        failureCode))
3755
3756
3757class CGWrapGlobalMethod(CGAbstractMethod):
3758    """
3759    Create a wrapper JSObject for a global.  The global must implement
3760    nsWrapperCache.
3761
3762    properties should be a PropertyArrays instance.
3763    """
3764    def __init__(self, descriptor, properties):
3765        assert descriptor.interface.hasInterfacePrototypeObject()
3766        args = [Argument('JSContext*', 'aCx'),
3767                Argument(descriptor.nativeType + '*', 'aObject'),
3768                Argument('nsWrapperCache*', 'aCache'),
3769                Argument('JS::CompartmentOptions&', 'aOptions'),
3770                Argument('JSPrincipals*', 'aPrincipal'),
3771                Argument('bool', 'aInitStandardClasses'),
3772                Argument('JS::MutableHandle<JSObject*>', 'aReflector')]
3773        CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'bool', args)
3774        self.descriptor = descriptor
3775        self.properties = properties
3776
3777    def definition_body(self):
3778        if self.properties.hasNonChromeOnly():
3779            properties = "sNativeProperties.Upcast()"
3780        else:
3781            properties = "nullptr"
3782        if self.properties.hasChromeOnly():
3783            chromeProperties = "nsContentUtils::ThreadsafeIsCallerChrome() ? sChromeOnlyNativeProperties.Upcast() : nullptr"
3784        else:
3785            chromeProperties = "nullptr"
3786
3787        failureCode = dedent(
3788            """
3789            aCache->ReleaseWrapper(aObject);
3790            aCache->ClearWrapper();
3791            return false;
3792            """);
3793
3794        if self.descriptor.hasUnforgeableMembers:
3795            unforgeable = InitUnforgeablePropertiesOnHolder(
3796                self.descriptor, self.properties, failureCode,
3797                "aReflector").define();
3798        else:
3799            unforgeable = ""
3800
3801        return fill(
3802            """
3803            $*{assertions}
3804            MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
3805                       "nsISupports must be on our primary inheritance chain");
3806
3807            if (!CreateGlobal<${nativeType}, GetProtoObjectHandle>(aCx,
3808                                             aObject,
3809                                             aCache,
3810                                             sClass.ToJSClass(),
3811                                             aOptions,
3812                                             aPrincipal,
3813                                             aInitStandardClasses,
3814                                             aReflector)) {
3815              $*{failureCode}
3816            }
3817
3818            // aReflector is a new global, so has a new compartment.  Enter it
3819            // before doing anything with it.
3820            JSAutoCompartment ac(aCx, aReflector);
3821
3822            if (!DefineProperties(aCx, aReflector, ${properties}, ${chromeProperties})) {
3823              $*{failureCode}
3824            }
3825            $*{unforgeable}
3826
3827            $*{slots}
3828
3829            return true;
3830            """,
3831            assertions=AssertInheritanceChain(self.descriptor),
3832            nativeType=self.descriptor.nativeType,
3833            properties=properties,
3834            chromeProperties=chromeProperties,
3835            failureCode=failureCode,
3836            unforgeable=unforgeable,
3837            slots=InitMemberSlots(self.descriptor, failureCode))
3838
3839
3840class CGUpdateMemberSlotsMethod(CGAbstractStaticMethod):
3841    def __init__(self, descriptor):
3842        args = [Argument('JSContext*', 'aCx'),
3843                Argument('JS::Handle<JSObject*>', 'aWrapper'),
3844                Argument(descriptor.nativeType + '*', 'aObject')]
3845        CGAbstractStaticMethod.__init__(self, descriptor, 'UpdateMemberSlots', 'bool', args)
3846
3847    def definition_body(self):
3848        body = ("JS::Rooted<JS::Value> temp(aCx);\n"
3849                "JSJitGetterCallArgs args(&temp);\n")
3850        for m in self.descriptor.interface.members:
3851            if m.isAttr() and m.getExtendedAttribute("StoreInSlot"):
3852                # Skip doing this for the "window" and "self" attributes on the
3853                # Window interface, because those can't be gotten safely until
3854                # we have hooked it up correctly to the outer window.  The
3855                # window code handles doing the get itself.
3856                if (self.descriptor.interface.identifier.name == "Window" and
3857                    (m.identifier.name == "window" or m.identifier.name == "self")):
3858                    continue
3859                body += fill(
3860                    """
3861
3862                    if (!get_${member}(aCx, aWrapper, aObject, args)) {
3863                      return false;
3864                    }
3865                    // Getter handled setting our reserved slots
3866                    """,
3867                    member=m.identifier.name)
3868
3869        body += "\nreturn true;\n"
3870        return body
3871
3872
3873class CGClearCachedValueMethod(CGAbstractMethod):
3874    def __init__(self, descriptor, member):
3875        self.member = member
3876        # If we're StoreInSlot, we'll need to call the getter
3877        if member.getExtendedAttribute("StoreInSlot"):
3878            args = [Argument('JSContext*', 'aCx')]
3879            returnType = 'bool'
3880        else:
3881            args = []
3882            returnType = 'void'
3883        args.append(Argument(descriptor.nativeType + '*', 'aObject'))
3884        name = MakeClearCachedValueNativeName(member)
3885        CGAbstractMethod.__init__(self, descriptor, name, returnType, args)
3886
3887    def definition_body(self):
3888        slotIndex = memberReservedSlot(self.member, self.descriptor)
3889        if self.member.getExtendedAttribute("StoreInSlot"):
3890            # We have to root things and save the old value in case
3891            # regetting fails, so we can restore it.
3892            declObj = "JS::Rooted<JSObject*> obj(aCx);\n"
3893            noopRetval = " true"
3894            saveMember = (
3895                "JS::Rooted<JS::Value> oldValue(aCx, js::GetReservedSlot(obj, %s));\n" %
3896                slotIndex)
3897            regetMember = fill(
3898                """
3899                JS::Rooted<JS::Value> temp(aCx);
3900                JSJitGetterCallArgs args(&temp);
3901                JSAutoCompartment ac(aCx, obj);
3902                if (!get_${name}(aCx, obj, aObject, args)) {
3903                  js::SetReservedSlot(obj, ${slotIndex}, oldValue);
3904                  return false;
3905                }
3906                return true;
3907                """,
3908                name=self.member.identifier.name,
3909                slotIndex=slotIndex)
3910        else:
3911            declObj = "JSObject* obj;\n"
3912            noopRetval = ""
3913            saveMember = ""
3914            regetMember = ""
3915
3916        if self.descriptor.wantsXrays:
3917            clearXrayExpandoSlots = fill(
3918                """
3919                xpc::ClearXrayExpandoSlots(obj, ${xraySlotIndex});
3920                """,
3921                xraySlotIndex=memberXrayExpandoReservedSlot(self.member,
3922                                                            self.descriptor))
3923        else :
3924            clearXrayExpandoSlots = ""
3925
3926        return fill(
3927            """
3928            $*{declObj}
3929            obj = aObject->GetWrapper();
3930            if (!obj) {
3931              return${noopRetval};
3932            }
3933            $*{saveMember}
3934            js::SetReservedSlot(obj, ${slotIndex}, JS::UndefinedValue());
3935            $*{clearXrayExpandoSlots}
3936            $*{regetMember}
3937            """,
3938            declObj=declObj,
3939            noopRetval=noopRetval,
3940            saveMember=saveMember,
3941            slotIndex=slotIndex,
3942            clearXrayExpandoSlots=clearXrayExpandoSlots,
3943            regetMember=regetMember)
3944
3945
3946class CGIsPermittedMethod(CGAbstractMethod):
3947    """
3948    crossOriginGetters/Setters/Methods are sets of names of the relevant members.
3949    """
3950    def __init__(self, descriptor, crossOriginGetters, crossOriginSetters,
3951                 crossOriginMethods):
3952        self.crossOriginGetters = crossOriginGetters
3953        self.crossOriginSetters = crossOriginSetters
3954        self.crossOriginMethods = crossOriginMethods
3955        args = [Argument("JSFlatString*", "prop"),
3956                Argument("char16_t", "propFirstChar"),
3957                Argument("bool", "set")]
3958        CGAbstractMethod.__init__(self, descriptor, "IsPermitted", "bool", args,
3959                                  inline=True)
3960
3961    def definition_body(self):
3962        allNames = self.crossOriginGetters | self.crossOriginSetters | self.crossOriginMethods
3963        readwrite = self.crossOriginGetters & self.crossOriginSetters
3964        readonly = (self.crossOriginGetters - self.crossOriginSetters) | self.crossOriginMethods
3965        writeonly = self.crossOriginSetters - self.crossOriginGetters
3966        cases = {}
3967        for name in sorted(allNames):
3968            cond = 'JS_FlatStringEqualsAscii(prop, "%s")' % name
3969            if name in readonly:
3970                cond = "!set && %s" % cond
3971            elif name in writeonly:
3972                cond = "set && %s" % cond
3973            else:
3974                assert name in readwrite
3975            firstLetter = name[0]
3976            case = cases.get(firstLetter, CGList([]))
3977            case.append(CGGeneric("if (%s) {\n"
3978                                  "  return true;\n"
3979                                  "}\n" % cond))
3980            cases[firstLetter] = case
3981        caseList = []
3982        for firstLetter in sorted(cases.keys()):
3983            caseList.append(CGCase("'%s'" % firstLetter, cases[firstLetter]))
3984        switch = CGSwitch("propFirstChar", caseList)
3985        return switch.define() + "\nreturn false;\n"
3986
3987
3988class CGCycleCollectionTraverseForOwningUnionMethod(CGAbstractMethod):
3989    """
3990    ImplCycleCollectionUnlink for owning union type.
3991    """
3992    def __init__(self, type):
3993        self.type = type
3994        args = [Argument("nsCycleCollectionTraversalCallback&", "aCallback"),
3995                Argument("%s&" % CGUnionStruct.unionTypeName(type, True), "aUnion"),
3996                Argument("const char*", "aName"),
3997                Argument("uint32_t", "aFlags", "0")]
3998        CGAbstractMethod.__init__(self, None, "ImplCycleCollectionTraverse", "void", args)
3999
4000    def deps(self):
4001        return self.type.getDeps()
4002
4003    def definition_body(self):
4004        memberNames = [getUnionMemberName(t)
4005                       for t in self.type.flatMemberTypes
4006                       if idlTypeNeedsCycleCollection(t)]
4007        assert memberNames
4008
4009        conditionTemplate = 'aUnion.Is%s()'
4010        functionCallTemplate = 'ImplCycleCollectionTraverse(aCallback, aUnion.GetAs%s(), "m%s", aFlags);\n'
4011
4012        ifStaments = (CGIfWrapper(CGGeneric(functionCallTemplate % (m, m)),
4013                                  conditionTemplate % m)
4014                      for m in memberNames)
4015
4016        return CGElseChain(ifStaments).define()
4017
4018
4019class CGCycleCollectionUnlinkForOwningUnionMethod(CGAbstractMethod):
4020    """
4021    ImplCycleCollectionUnlink for owning union type.
4022    """
4023    def __init__(self, type):
4024        self.type = type
4025        args = [Argument("%s&" % CGUnionStruct.unionTypeName(type, True), "aUnion")]
4026        CGAbstractMethod.__init__(self, None, "ImplCycleCollectionUnlink", "void", args)
4027
4028    def deps(self):
4029        return self.type.getDeps()
4030
4031    def definition_body(self):
4032        return "aUnion.Uninit();\n"
4033
4034
4035builtinNames = {
4036    IDLType.Tags.bool: 'bool',
4037    IDLType.Tags.int8: 'int8_t',
4038    IDLType.Tags.int16: 'int16_t',
4039    IDLType.Tags.int32: 'int32_t',
4040    IDLType.Tags.int64: 'int64_t',
4041    IDLType.Tags.uint8: 'uint8_t',
4042    IDLType.Tags.uint16: 'uint16_t',
4043    IDLType.Tags.uint32: 'uint32_t',
4044    IDLType.Tags.uint64: 'uint64_t',
4045    IDLType.Tags.unrestricted_float: 'float',
4046    IDLType.Tags.float: 'float',
4047    IDLType.Tags.unrestricted_double: 'double',
4048    IDLType.Tags.double: 'double'
4049}
4050
4051numericSuffixes = {
4052    IDLType.Tags.int8: '',
4053    IDLType.Tags.uint8: '',
4054    IDLType.Tags.int16: '',
4055    IDLType.Tags.uint16: '',
4056    IDLType.Tags.int32: '',
4057    IDLType.Tags.uint32: 'U',
4058    IDLType.Tags.int64: 'LL',
4059    IDLType.Tags.uint64: 'ULL',
4060    IDLType.Tags.unrestricted_float: 'F',
4061    IDLType.Tags.float: 'F',
4062    IDLType.Tags.unrestricted_double: '',
4063    IDLType.Tags.double: ''
4064}
4065
4066
4067def numericValue(t, v):
4068    if (t == IDLType.Tags.unrestricted_double or
4069        t == IDLType.Tags.unrestricted_float):
4070        typeName = builtinNames[t]
4071        if v == float("inf"):
4072            return "mozilla::PositiveInfinity<%s>()" % typeName
4073        if v == float("-inf"):
4074            return "mozilla::NegativeInfinity<%s>()" % typeName
4075        if math.isnan(v):
4076            return "mozilla::UnspecifiedNaN<%s>()" % typeName
4077    return "%s%s" % (v, numericSuffixes[t])
4078
4079
4080class CastableObjectUnwrapper():
4081    """
4082    A class for unwrapping an object stored in a JS Value (or
4083    MutableHandle<Value> or Handle<Value>) named by the "source" and
4084    "mutableSource" arguments based on the passed-in descriptor and storing it
4085    in a variable called by the name in the "target" argument.  The "source"
4086    argument should be able to produce a Value or Handle<Value>; the
4087    "mutableSource" argument should be able to produce a MutableHandle<Value>
4088
4089    codeOnFailure is the code to run if unwrapping fails.
4090
4091    If isCallbackReturnValue is "JSImpl" and our descriptor is also
4092    JS-implemented, fall back to just creating the right object if what we
4093    have isn't one already.
4094
4095    If allowCrossOriginObj is True, then we'll first do an
4096    UncheckedUnwrap and then operate on the result.
4097    """
4098    def __init__(self, descriptor, source, mutableSource, target, codeOnFailure,
4099                 exceptionCode=None, isCallbackReturnValue=False,
4100                 allowCrossOriginObj=False):
4101        self.substitution = {
4102            "type": descriptor.nativeType,
4103            "protoID": "prototypes::id::" + descriptor.name,
4104            "target": target,
4105            "codeOnFailure": codeOnFailure,
4106        }
4107        # Supporting both the "cross origin object" case and the "has
4108        # XPConnect impls" case at the same time is a pain, so let's
4109        # not do that.  That allows us to assume that our source is
4110        # always a Handle or MutableHandle.
4111        if allowCrossOriginObj and descriptor.hasXPConnectImpls:
4112            raise TypeError("Interface %s both allows a cross-origin 'this' "
4113                            "and has XPConnect impls.  We don't support that" %
4114                            descriptor.name)
4115        if allowCrossOriginObj:
4116            self.substitution["uncheckedObjDecl"] = fill(
4117                """
4118                JS::Rooted<JSObject*> maybeUncheckedObj(cx, &${source}.toObject());
4119                """,
4120                source=source)
4121            self.substitution["uncheckedObjGet"] = fill(
4122                """
4123                if (xpc::WrapperFactory::IsXrayWrapper(maybeUncheckedObj)) {
4124                  maybeUncheckedObj = js::UncheckedUnwrap(maybeUncheckedObj);
4125                } else {
4126                  maybeUncheckedObj = js::CheckedUnwrap(maybeUncheckedObj);
4127                  if (!maybeUncheckedObj) {
4128                    $*{codeOnFailure}
4129                  }
4130                }
4131                """,
4132                codeOnFailure=(codeOnFailure % { 'securityError': 'true'}))
4133            self.substitution["source"] = "maybeUncheckedObj"
4134            self.substitution["mutableSource"] = "&maybeUncheckedObj"
4135            # No need to set up xpconnectUnwrap, since it won't be
4136            # used in the allowCrossOriginObj case.
4137        else:
4138            self.substitution["uncheckedObjDecl"] = ""
4139            self.substitution["uncheckedObjGet"] = ""
4140            self.substitution["source"] = source
4141            self.substitution["mutableSource"] = mutableSource
4142            xpconnectUnwrap = (
4143                "nsresult rv = UnwrapXPConnect<${type}>(cx, ${mutableSource}, getter_AddRefs(objPtr));\n")
4144
4145        if descriptor.hasXPConnectImpls:
4146            self.substitution["codeOnFailure"] = string.Template(
4147                "RefPtr<${type}> objPtr;\n" +
4148                xpconnectUnwrap +
4149                "if (NS_FAILED(rv)) {\n"
4150                "${indentedCodeOnFailure}"
4151                "}\n"
4152                "// We should have an object\n"
4153                "MOZ_ASSERT(objPtr);\n"
4154                "${target} = objPtr;\n"
4155            ).substitute(self.substitution,
4156                         indentedCodeOnFailure=indent(codeOnFailure))
4157        elif (isCallbackReturnValue == "JSImpl" and
4158              descriptor.interface.isJSImplemented()):
4159            exceptionCode = exceptionCode or codeOnFailure
4160            self.substitution["codeOnFailure"] = fill(
4161                """
4162                // Be careful to not wrap random DOM objects here, even if
4163                // they're wrapped in opaque security wrappers for some reason.
4164                // XXXbz Wish we could check for a JS-implemented object
4165                // that already has a content reflection...
4166                if (!IsDOMObject(js::UncheckedUnwrap(&${source}.toObject()))) {
4167                  nsCOMPtr<nsIGlobalObject> contentGlobal;
4168                  if (!GetContentGlobalForJSImplementedObject(cx, Callback(), getter_AddRefs(contentGlobal))) {
4169                    $*{exceptionCode}
4170                  }
4171                  JS::Rooted<JSObject*> jsImplSourceObj(cx, &${source}.toObject());
4172                  ${target} = new ${type}(jsImplSourceObj, contentGlobal);
4173                } else {
4174                  $*{codeOnFailure}
4175                }
4176                """,
4177                exceptionCode=exceptionCode,
4178                **self.substitution)
4179        else:
4180            self.substitution["codeOnFailure"] = codeOnFailure
4181
4182    def __str__(self):
4183        substitution = self.substitution.copy()
4184        substitution["codeOnFailure"] %= {
4185            'securityError': 'rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO'
4186        }
4187        return fill(
4188            """
4189            $*{uncheckedObjDecl}
4190            {
4191              $*{uncheckedObjGet}
4192              nsresult rv = UnwrapObject<${protoID}, ${type}>(${mutableSource}, ${target});
4193              if (NS_FAILED(rv)) {
4194                $*{codeOnFailure}
4195              }
4196            }
4197            """,
4198            **substitution)
4199
4200
4201class FailureFatalCastableObjectUnwrapper(CastableObjectUnwrapper):
4202    """
4203    As CastableObjectUnwrapper, but defaulting to throwing if unwrapping fails
4204    """
4205    def __init__(self, descriptor, source, mutableSource, target, exceptionCode,
4206                 isCallbackReturnValue, sourceDescription):
4207        CastableObjectUnwrapper.__init__(
4208            self, descriptor, source, mutableSource, target,
4209            'ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s", "%s");\n'
4210            '%s' % (sourceDescription, descriptor.interface.identifier.name,
4211                    exceptionCode),
4212            exceptionCode,
4213            isCallbackReturnValue)
4214
4215
4216class CGCallbackTempRoot(CGGeneric):
4217    def __init__(self, name):
4218        define = dedent("""
4219            { // Scope for tempRoot
4220              JS::Rooted<JSObject*> tempRoot(cx, &${val}.toObject());
4221              ${declName} = new %s(cx, tempRoot, mozilla::dom::GetIncumbentGlobal());
4222            }
4223            """) % name
4224        CGGeneric.__init__(self, define=define)
4225
4226
4227def getCallbackConversionInfo(type, idlObject, isMember, isCallbackReturnValue,
4228                              isOptional):
4229    """
4230    Returns a tuple containing the declType, declArgs, and basic
4231    conversion for the given callback type, with the given callback
4232    idl object in the given context (isMember/isCallbackReturnValue/isOptional).
4233    """
4234    name = idlObject.identifier.name
4235
4236    # We can't use fast callbacks if isOptional because then we get an
4237    # Optional<RootedCallback> thing, which is not transparent to consumers.
4238    useFastCallback = (not isMember and not isCallbackReturnValue and
4239                       not isOptional)
4240    if useFastCallback:
4241        name = "binding_detail::Fast%s" % name
4242
4243    if type.nullable() or isCallbackReturnValue:
4244        declType = CGGeneric("RefPtr<%s>" % name)
4245    else:
4246        declType = CGGeneric("OwningNonNull<%s>" % name)
4247
4248    if useFastCallback:
4249        declType = CGTemplatedType("RootedCallback", declType)
4250        declArgs = "cx"
4251    else:
4252        declArgs = None
4253
4254    conversion = indent(CGCallbackTempRoot(name).define())
4255    return (declType, declArgs, conversion)
4256
4257
4258class JSToNativeConversionInfo():
4259    """
4260    An object representing information about a JS-to-native conversion.
4261    """
4262    def __init__(self, template, declType=None, holderType=None,
4263                 dealWithOptional=False, declArgs=None,
4264                 holderArgs=None):
4265        """
4266        template: A string representing the conversion code.  This will have
4267                  template substitution performed on it as follows:
4268
4269          ${val} is a handle to the JS::Value in question
4270          ${maybeMutableVal} May be a mutable handle to the JS::Value in
4271                             question. This is only OK to use if ${val} is
4272                             known to not be undefined.
4273          ${holderName} replaced by the holder's name, if any
4274          ${declName} replaced by the declaration's name
4275          ${haveValue} replaced by an expression that evaluates to a boolean
4276                       for whether we have a JS::Value.  Only used when
4277                       defaultValue is not None or when True is passed for
4278                       checkForValue to instantiateJSToNativeConversion.
4279          ${passedToJSImpl} replaced by an expression that evaluates to a boolean
4280                            for whether this value is being passed to a JS-
4281                            implemented interface.
4282
4283        declType: A CGThing representing the native C++ type we're converting
4284                  to.  This is allowed to be None if the conversion code is
4285                  supposed to be used as-is.
4286
4287        holderType: A CGThing representing the type of a "holder" which will
4288                    hold a possible reference to the C++ thing whose type we
4289                    returned in declType, or  None if no such holder is needed.
4290
4291        dealWithOptional: A boolean indicating whether the caller has to do
4292                          optional-argument handling.  This should only be set
4293                          to true if the JS-to-native conversion is being done
4294                          for an optional argument or dictionary member with no
4295                          default value and if the returned template expects
4296                          both declType and holderType to be wrapped in
4297                          Optional<>, with ${declName} and ${holderName}
4298                          adjusted to point to the Value() of the Optional, and
4299                          Construct() calls to be made on the Optional<>s as
4300                          needed.
4301
4302        declArgs: If not None, the arguments to pass to the ${declName}
4303                  constructor.  These will have template substitution performed
4304                  on them so you can use things like ${val}.  This is a
4305                  single string, not a list of strings.
4306
4307        holderArgs: If not None, the arguments to pass to the ${holderName}
4308                    constructor.  These will have template substitution
4309                    performed on them so you can use things like ${val}.
4310                    This is a single string, not a list of strings.
4311
4312        ${declName} must be in scope before the code from 'template' is entered.
4313
4314        If holderType is not None then ${holderName} must be in scope before
4315        the code from 'template' is entered.
4316        """
4317        assert isinstance(template, str)
4318        assert declType is None or isinstance(declType, CGThing)
4319        assert holderType is None or isinstance(holderType, CGThing)
4320        self.template = template
4321        self.declType = declType
4322        self.holderType = holderType
4323        self.dealWithOptional = dealWithOptional
4324        self.declArgs = declArgs
4325        self.holderArgs = holderArgs
4326
4327
4328def getHandleDefault(defaultValue):
4329    tag = defaultValue.type.tag()
4330    if tag in numericSuffixes:
4331        # Some numeric literals require a suffix to compile without warnings
4332        return numericValue(tag, defaultValue.value)
4333    assert tag == IDLType.Tags.bool
4334    return toStringBool(defaultValue.value)
4335
4336
4337def handleDefaultStringValue(defaultValue, method):
4338    """
4339    Returns a string which ends up calling 'method' with a (char_t*, length)
4340    pair that sets this string default value.  This string is suitable for
4341    passing as the second argument of handleDefault; in particular it does not
4342    end with a ';'
4343    """
4344    assert defaultValue.type.isDOMString() or defaultValue.type.isByteString()
4345    return ("static const %(char_t)s data[] = { %(data)s };\n"
4346            "%(method)s(data, ArrayLength(data) - 1)") % {
4347                'char_t': "char" if defaultValue.type.isByteString() else "char16_t",
4348                'method': method,
4349                'data': ", ".join(["'" + char + "'" for char in
4350                                   defaultValue.value] + ["0"])
4351            }
4352
4353
4354# If this function is modified, modify CGNativeMember.getArg and
4355# CGNativeMember.getRetvalInfo accordingly.  The latter cares about the decltype
4356# and holdertype we end up using, because it needs to be able to return the code
4357# that will convert those to the actual return value of the callback function.
4358def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
4359                                isDefinitelyObject=False,
4360                                isMember=False,
4361                                isOptional=False,
4362                                invalidEnumValueFatal=True,
4363                                defaultValue=None,
4364                                treatNullAs="Default",
4365                                isEnforceRange=False,
4366                                isClamp=False,
4367                                isNullOrUndefined=False,
4368                                exceptionCode=None,
4369                                lenientFloatCode=None,
4370                                allowTreatNonCallableAsNull=False,
4371                                isCallbackReturnValue=False,
4372                                sourceDescription="value",
4373                                nestingLevel=""):
4374    """
4375    Get a template for converting a JS value to a native object based on the
4376    given type and descriptor.  If failureCode is given, then we're actually
4377    testing whether we can convert the argument to the desired type.  That
4378    means that failures to convert due to the JS value being the wrong type of
4379    value need to use failureCode instead of throwing exceptions.  Failures to
4380    convert that are due to JS exceptions (from toString or valueOf methods) or
4381    out of memory conditions need to throw exceptions no matter what
4382    failureCode is.  However what actually happens when throwing an exception
4383    can be controlled by exceptionCode.  The only requirement on that is that
4384    exceptionCode must end up doing a return, and every return from this
4385    function must happen via exceptionCode if exceptionCode is not None.
4386
4387    If isDefinitelyObject is True, that means we know the value
4388    isObject() and we have no need to recheck that.
4389
4390    if isMember is not False, we're being converted from a property of some JS
4391    object, not from an actual method argument, so we can't rely on our jsval
4392    being rooted or outliving us in any way.  Callers can pass "Dictionary",
4393    "Variadic", "Sequence", or "OwningUnion" to indicate that the conversion is
4394    for something that is a dictionary member, a variadic argument, a sequence,
4395    or an owning union respectively.
4396
4397    If isOptional is true, then we are doing conversion of an optional
4398    argument with no default value.
4399
4400    invalidEnumValueFatal controls whether an invalid enum value conversion
4401    attempt will throw (if true) or simply return without doing anything (if
4402    false).
4403
4404    If defaultValue is not None, it's the IDL default value for this conversion
4405
4406    If isEnforceRange is true, we're converting an integer and throwing if the
4407    value is out of range.
4408
4409    If isClamp is true, we're converting an integer and clamping if the
4410    value is out of range.
4411
4412    If lenientFloatCode is not None, it should be used in cases when
4413    we're a non-finite float that's not unrestricted.
4414
4415    If allowTreatNonCallableAsNull is true, then [TreatNonCallableAsNull] and
4416    [TreatNonObjectAsNull] extended attributes on nullable callback functions
4417    will be honored.
4418
4419    If isCallbackReturnValue is "JSImpl" or "Callback", then the declType may be
4420    adjusted to make it easier to return from a callback.  Since that type is
4421    never directly observable by any consumers of the callback code, this is OK.
4422    Furthermore, if isCallbackReturnValue is "JSImpl", that affects the behavior
4423    of the FailureFatalCastableObjectUnwrapper conversion; this is used for
4424    implementing auto-wrapping of JS-implemented return values from a
4425    JS-implemented interface.
4426
4427    sourceDescription is a description of what this JS value represents, to be
4428    used in error reporting.  Callers should assume that it might get placed in
4429    the middle of a sentence.  If it ends up at the beginning of a sentence, its
4430    first character will be automatically uppercased.
4431
4432    The return value from this function is a JSToNativeConversionInfo.
4433    """
4434    # If we have a defaultValue then we're not actually optional for
4435    # purposes of what we need to be declared as.
4436    assert defaultValue is None or not isOptional
4437
4438    # Also, we should not have a defaultValue if we know we're an object
4439    assert not isDefinitelyObject or defaultValue is None
4440
4441    # And we can't both be an object and be null or undefined
4442    assert not isDefinitelyObject or not isNullOrUndefined
4443
4444    # If exceptionCode is not set, we'll just rethrow the exception we got.
4445    # Note that we can't just set failureCode to exceptionCode, because setting
4446    # failureCode will prevent pending exceptions from being set in cases when
4447    # they really should be!
4448    if exceptionCode is None:
4449        exceptionCode = "return false;\n"
4450
4451    # Unfortunately, .capitalize() on a string will lowercase things inside the
4452    # string, which we do not want.
4453    def firstCap(string):
4454        return string[0].upper() + string[1:]
4455
4456    # Helper functions for dealing with failures due to the JS value being the
4457    # wrong type of value
4458    def onFailureNotAnObject(failureCode):
4459        return CGGeneric(
4460            failureCode or
4461            ('ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n'
4462             '%s' % (firstCap(sourceDescription), exceptionCode)))
4463
4464    def onFailureBadType(failureCode, typeName):
4465        return CGGeneric(
4466            failureCode or
4467            ('ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s", "%s");\n'
4468             '%s' % (firstCap(sourceDescription), typeName, exceptionCode)))
4469
4470    def onFailureNotCallable(failureCode):
4471        return CGGeneric(
4472            failureCode or
4473            ('ThrowErrorMessage(cx, MSG_NOT_CALLABLE, "%s");\n'
4474             '%s' % (firstCap(sourceDescription), exceptionCode)))
4475
4476    # A helper function for handling default values.  Takes a template
4477    # body and the C++ code to set the default value and wraps the
4478    # given template body in handling for the default value.
4479    def handleDefault(template, setDefault):
4480        if defaultValue is None:
4481            return template
4482        return (
4483            "if (${haveValue}) {\n" +
4484            indent(template) +
4485            "} else {\n" +
4486            indent(setDefault) +
4487            "}\n")
4488
4489    # A helper function for wrapping up the template body for
4490    # possibly-nullable objecty stuff
4491    def wrapObjectTemplate(templateBody, type, codeToSetNull, failureCode=None):
4492        if isNullOrUndefined and type.nullable():
4493            # Just ignore templateBody and set ourselves to null.
4494            # Note that we don't have to worry about default values
4495            # here either, since we already examined this value.
4496            return codeToSetNull
4497
4498        if not isDefinitelyObject:
4499            # Handle the non-object cases by wrapping up the whole
4500            # thing in an if cascade.
4501            if type.nullable():
4502                elifLine = "} else if (${val}.isNullOrUndefined()) {\n"
4503                elifBody = codeToSetNull
4504            else:
4505                elifLine = ""
4506                elifBody = ""
4507
4508            # Note that $${val} below expands to ${val}. This string is
4509            # used as a template later, and val will be filled in then.
4510            templateBody = fill(
4511                """
4512                if ($${val}.isObject()) {
4513                  $*{templateBody}
4514                $*{elifLine}
4515                  $*{elifBody}
4516                } else {
4517                  $*{failureBody}
4518                }
4519                """,
4520                templateBody=templateBody,
4521                elifLine=elifLine,
4522                elifBody=elifBody,
4523                failureBody=onFailureNotAnObject(failureCode).define())
4524
4525            if isinstance(defaultValue, IDLNullValue):
4526                assert type.nullable()  # Parser should enforce this
4527                templateBody = handleDefault(templateBody, codeToSetNull)
4528            elif isinstance(defaultValue, IDLEmptySequenceValue):
4529                # Our caller will handle it
4530                pass
4531            else:
4532                assert defaultValue is None
4533
4534        return templateBody
4535
4536    # A helper function for converting things that look like a JSObject*.
4537    def handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription):
4538        if not isMember:
4539            if isOptional:
4540                # We have a specialization of Optional that will use a
4541                # Rooted for the storage here.
4542                declType = CGGeneric("JS::Handle<JSObject*>")
4543            else:
4544                declType = CGGeneric("JS::Rooted<JSObject*>")
4545            declArgs = "cx"
4546        else:
4547            assert (isMember in
4548                    ("Sequence", "Variadic", "Dictionary", "OwningUnion", "MozMap"))
4549            # We'll get traced by the sequence or dictionary or union tracer
4550            declType = CGGeneric("JSObject*")
4551            declArgs = None
4552        templateBody = "${declName} = &${val}.toObject();\n"
4553
4554        # For JS-implemented APIs, we refuse to allow passing objects that the
4555        # API consumer does not subsume. The extra parens around
4556        # ($${passedToJSImpl}) suppress unreachable code warnings when
4557        # $${passedToJSImpl} is the literal `false`.
4558        if not isinstance(descriptorProvider, Descriptor) or descriptorProvider.interface.isJSImplemented():
4559            templateBody = fill(
4560                """
4561                if (($${passedToJSImpl}) && !CallerSubsumes($${val})) {
4562                  ThrowErrorMessage(cx, MSG_PERMISSION_DENIED_TO_PASS_ARG, "${sourceDescription}");
4563                  $*{exceptionCode}
4564                }
4565                """,
4566                sourceDescription=sourceDescription,
4567                exceptionCode=exceptionCode) + templateBody
4568
4569        setToNullCode = "${declName} = nullptr;\n"
4570        template = wrapObjectTemplate(templateBody, type, setToNullCode,
4571                                      failureCode)
4572        return JSToNativeConversionInfo(template, declType=declType,
4573                                        dealWithOptional=isOptional,
4574                                        declArgs=declArgs)
4575
4576    def incrementNestingLevel():
4577        if nestingLevel is "":
4578            return 1
4579        return nestingLevel + 1
4580
4581    assert not (isEnforceRange and isClamp)  # These are mutually exclusive
4582
4583    if type.isSequence():
4584        assert not isEnforceRange and not isClamp
4585
4586        if failureCode is None:
4587            notSequence = ('ThrowErrorMessage(cx, MSG_NOT_SEQUENCE, "%s");\n'
4588                           "%s" % (firstCap(sourceDescription), exceptionCode))
4589        else:
4590            notSequence = failureCode
4591
4592        nullable = type.nullable()
4593        # Be very careful not to change "type": we need it later
4594        if nullable:
4595            elementType = type.inner.inner
4596        else:
4597            elementType = type.inner
4598
4599        # We want to use auto arrays if we can, but we have to be careful with
4600        # reallocation behavior for arrays.  In particular, if we use auto
4601        # arrays for sequences and have a sequence of elements which are
4602        # themselves sequences or have sequences as members, we have a problem.
4603        # In that case, resizing the outermost AutoTArray to the right size
4604        # will memmove its elements, but AutoTArrays are not memmovable and
4605        # hence will end up with pointers to bogus memory, which is bad.  To
4606        # deal with this, we typically map WebIDL sequences to our Sequence
4607        # type, which is in fact memmovable.  The one exception is when we're
4608        # passing in a sequence directly as an argument without any sort of
4609        # optional or nullable complexity going on.  In that situation, we can
4610        # use an AutoSequence instead.  We have to keep using Sequence in the
4611        # nullable and optional cases because we don't want to leak the
4612        # AutoSequence type to consumers, which would be unavoidable with
4613        # Nullable<AutoSequence> or Optional<AutoSequence>.
4614        if isMember or isOptional or nullable or isCallbackReturnValue:
4615            sequenceClass = "Sequence"
4616        else:
4617            sequenceClass = "binding_detail::AutoSequence"
4618
4619        # XXXbz we can't include the index in the sourceDescription, because
4620        # we don't really have a way to pass one in dynamically at runtime...
4621        elementInfo = getJSToNativeConversionInfo(
4622            elementType, descriptorProvider, isMember="Sequence",
4623            exceptionCode=exceptionCode, lenientFloatCode=lenientFloatCode,
4624            isCallbackReturnValue=isCallbackReturnValue,
4625            sourceDescription="element of %s" % sourceDescription,
4626            nestingLevel=incrementNestingLevel())
4627        if elementInfo.dealWithOptional:
4628            raise TypeError("Shouldn't have optional things in sequences")
4629        if elementInfo.holderType is not None:
4630            raise TypeError("Shouldn't need holders for sequences")
4631
4632        typeName = CGTemplatedType(sequenceClass, elementInfo.declType)
4633        sequenceType = typeName.define()
4634        if nullable:
4635            typeName = CGTemplatedType("Nullable", typeName)
4636            arrayRef = "${declName}.SetValue()"
4637        else:
4638            arrayRef = "${declName}"
4639
4640        elementConversion = string.Template(elementInfo.template).substitute({
4641            "val": "temp" + str(nestingLevel),
4642            "maybeMutableVal": "&temp" + str(nestingLevel),
4643            "declName": "slot" + str(nestingLevel),
4644            # We only need holderName here to handle isExternal()
4645            # interfaces, which use an internal holder for the
4646            # conversion even when forceOwningType ends up true.
4647            "holderName": "tempHolder" + str(nestingLevel),
4648            "passedToJSImpl": "${passedToJSImpl}"
4649        })
4650
4651        # NOTE: Keep this in sync with variadic conversions as needed
4652        templateBody = fill(
4653            """
4654            JS::ForOfIterator iter${nestingLevel}(cx);
4655            if (!iter${nestingLevel}.init($${val}, JS::ForOfIterator::AllowNonIterable)) {
4656              $*{exceptionCode}
4657            }
4658            if (!iter${nestingLevel}.valueIsIterable()) {
4659              $*{notSequence}
4660            }
4661            ${sequenceType} &arr${nestingLevel} = ${arrayRef};
4662            JS::Rooted<JS::Value> temp${nestingLevel}(cx);
4663            while (true) {
4664              bool done${nestingLevel};
4665              if (!iter${nestingLevel}.next(&temp${nestingLevel}, &done${nestingLevel})) {
4666                $*{exceptionCode}
4667              }
4668              if (done${nestingLevel}) {
4669                break;
4670              }
4671              ${elementType}* slotPtr${nestingLevel} = arr${nestingLevel}.AppendElement(mozilla::fallible);
4672              if (!slotPtr${nestingLevel}) {
4673                JS_ReportOutOfMemory(cx);
4674                $*{exceptionCode}
4675              }
4676              ${elementType}& slot${nestingLevel} = *slotPtr${nestingLevel};
4677              $*{elementConversion}
4678            }
4679            """,
4680            exceptionCode=exceptionCode,
4681            notSequence=notSequence,
4682            sequenceType=sequenceType,
4683            arrayRef=arrayRef,
4684            elementType=elementInfo.declType.define(),
4685            elementConversion=elementConversion,
4686            nestingLevel=str(nestingLevel))
4687
4688        templateBody = wrapObjectTemplate(templateBody, type,
4689                                          "${declName}.SetNull();\n", notSequence)
4690        if isinstance(defaultValue, IDLEmptySequenceValue):
4691            if type.nullable():
4692                codeToSetEmpty = "${declName}.SetValue();\n"
4693            else:
4694                codeToSetEmpty = "/* Array is already empty; nothing to do */\n"
4695            templateBody = handleDefault(templateBody, codeToSetEmpty)
4696
4697        # Sequence arguments that might contain traceable things need
4698        # to get traced
4699        if not isMember and typeNeedsRooting(elementType):
4700            holderType = CGTemplatedType("SequenceRooter", elementInfo.declType)
4701            # If our sequence is nullable, this will set the Nullable to be
4702            # not-null, but that's ok because we make an explicit SetNull() call
4703            # on it as needed if our JS value is actually null.
4704            holderArgs = "cx, &%s" % arrayRef
4705        else:
4706            holderType = None
4707            holderArgs = None
4708
4709        return JSToNativeConversionInfo(templateBody, declType=typeName,
4710                                        holderType=holderType,
4711                                        dealWithOptional=isOptional,
4712                                        holderArgs=holderArgs)
4713
4714    if type.isMozMap():
4715        assert not isEnforceRange and not isClamp
4716        if failureCode is None:
4717            notMozMap = ('ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n'
4718                         "%s" % (firstCap(sourceDescription), exceptionCode))
4719        else:
4720            notMozMap = failureCode
4721
4722        nullable = type.nullable()
4723        # Be very careful not to change "type": we need it later
4724        if nullable:
4725            valueType = type.inner.inner
4726        else:
4727            valueType = type.inner
4728
4729        valueInfo = getJSToNativeConversionInfo(
4730            valueType, descriptorProvider, isMember="MozMap",
4731            exceptionCode=exceptionCode, lenientFloatCode=lenientFloatCode,
4732            isCallbackReturnValue=isCallbackReturnValue,
4733            sourceDescription="value in %s" % sourceDescription,
4734            nestingLevel=incrementNestingLevel())
4735        if valueInfo.dealWithOptional:
4736            raise TypeError("Shouldn't have optional things in MozMap")
4737        if valueInfo.holderType is not None:
4738            raise TypeError("Shouldn't need holders for MozMap")
4739
4740        typeName = CGTemplatedType("MozMap", valueInfo.declType)
4741        mozMapType = typeName.define()
4742        if nullable:
4743            typeName = CGTemplatedType("Nullable", typeName)
4744            mozMapRef = "${declName}.SetValue()"
4745        else:
4746            mozMapRef = "${declName}"
4747
4748        valueConversion = string.Template(valueInfo.template).substitute({
4749            "val": "temp",
4750            "maybeMutableVal": "&temp",
4751            "declName": "slot",
4752            # We only need holderName here to handle isExternal()
4753            # interfaces, which use an internal holder for the
4754            # conversion even when forceOwningType ends up true.
4755            "holderName": "tempHolder",
4756            "passedToJSImpl": "${passedToJSImpl}"
4757        })
4758
4759        templateBody = fill(
4760            """
4761            ${mozMapType} &mozMap = ${mozMapRef};
4762
4763            JS::Rooted<JSObject*> mozMapObj(cx, &$${val}.toObject());
4764            JS::Rooted<JS::IdVector> ids(cx, JS::IdVector(cx));
4765            if (!JS_Enumerate(cx, mozMapObj, &ids)) {
4766              $*{exceptionCode}
4767            }
4768            JS::Rooted<JS::Value> propNameValue(cx);
4769            JS::Rooted<JS::Value> temp(cx);
4770            JS::Rooted<jsid> curId(cx);
4771            for (size_t i = 0; i < ids.length(); ++i) {
4772              // Make sure we get the value before converting the name, since
4773              // getting the value can trigger GC but our name is a dependent
4774              // string.
4775              curId = ids[i];
4776              binding_detail::FakeString propName;
4777              bool isSymbol;
4778              if (!ConvertIdToString(cx, curId, propName, isSymbol) ||
4779                  (!isSymbol && !JS_GetPropertyById(cx, mozMapObj, curId, &temp))) {
4780                $*{exceptionCode}
4781              }
4782              if (isSymbol) {
4783                continue;
4784              }
4785
4786              ${valueType}* slotPtr = mozMap.AddEntry(propName);
4787              if (!slotPtr) {
4788                JS_ReportOutOfMemory(cx);
4789                $*{exceptionCode}
4790              }
4791              ${valueType}& slot = *slotPtr;
4792              $*{valueConversion}
4793            }
4794            """,
4795            exceptionCode=exceptionCode,
4796            mozMapType=mozMapType,
4797            mozMapRef=mozMapRef,
4798            valueType=valueInfo.declType.define(),
4799            valueConversion=valueConversion)
4800
4801        templateBody = wrapObjectTemplate(templateBody, type,
4802                                          "${declName}.SetNull();\n",
4803                                          notMozMap)
4804
4805        declType = typeName
4806        declArgs = None
4807        holderType = None
4808        holderArgs = None
4809        # MozMap arguments that might contain traceable things need
4810        # to get traced
4811        if not isMember and isCallbackReturnValue:
4812            # Go ahead and just convert directly into our actual return value
4813            declType = CGWrapper(declType, post="&")
4814            declArgs = "aRetVal"
4815        elif not isMember and typeNeedsRooting(valueType):
4816            holderType = CGTemplatedType("MozMapRooter", valueInfo.declType)
4817            # If our MozMap is nullable, this will set the Nullable to be
4818            # not-null, but that's ok because we make an explicit SetNull() call
4819            # on it as needed if our JS value is actually null.
4820            holderArgs = "cx, &%s" % mozMapRef
4821
4822        return JSToNativeConversionInfo(templateBody, declType=declType,
4823                                        declArgs=declArgs,
4824                                        holderType=holderType,
4825                                        dealWithOptional=isOptional,
4826                                        holderArgs=holderArgs)
4827
4828    if type.isUnion():
4829        nullable = type.nullable()
4830        if nullable:
4831            type = type.inner
4832
4833        isOwningUnion = isMember or isCallbackReturnValue
4834        unionArgumentObj = "${declName}" if isOwningUnion else "${holderName}"
4835        if nullable:
4836            # If we're owning, we're a Nullable, which hasn't been told it has
4837            # a value.  Otherwise we're an already-constructed Maybe.
4838            unionArgumentObj += ".SetValue()" if isOwningUnion else ".ref()"
4839
4840        memberTypes = type.flatMemberTypes
4841        names = []
4842
4843        interfaceMemberTypes = filter(lambda t: t.isNonCallbackInterface(), memberTypes)
4844        if len(interfaceMemberTypes) > 0:
4845            interfaceObject = []
4846            for memberType in interfaceMemberTypes:
4847                name = getUnionMemberName(memberType)
4848                interfaceObject.append(
4849                    CGGeneric("(failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext" %
4850                              (unionArgumentObj, name)))
4851                names.append(name)
4852            interfaceObject = CGWrapper(CGList(interfaceObject, " ||\n"),
4853                                        pre="done = ", post=";\n\n", reindent=True)
4854        else:
4855            interfaceObject = None
4856
4857        sequenceObjectMemberTypes = filter(lambda t: t.isSequence(), memberTypes)
4858        if len(sequenceObjectMemberTypes) > 0:
4859            assert len(sequenceObjectMemberTypes) == 1
4860            name = getUnionMemberName(sequenceObjectMemberTypes[0])
4861            sequenceObject = CGGeneric(
4862                "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
4863                (unionArgumentObj, name))
4864            names.append(name)
4865        else:
4866            sequenceObject = None
4867
4868        dateObjectMemberTypes = filter(lambda t: t.isDate(), memberTypes)
4869        if len(dateObjectMemberTypes) > 0:
4870            assert len(dateObjectMemberTypes) == 1
4871            memberType = dateObjectMemberTypes[0]
4872            name = getUnionMemberName(memberType)
4873            dateObject = CGGeneric("%s.SetTo%s(cx, ${val});\n"
4874                                   "done = true;\n" % (unionArgumentObj, name))
4875            dateObject = CGIfWrapper(dateObject, "JS_ObjectIsDate(cx, argObj)")
4876            names.append(name)
4877        else:
4878            dateObject = None
4879
4880        callbackMemberTypes = filter(lambda t: t.isCallback() or t.isCallbackInterface(), memberTypes)
4881        if len(callbackMemberTypes) > 0:
4882            assert len(callbackMemberTypes) == 1
4883            memberType = callbackMemberTypes[0]
4884            name = getUnionMemberName(memberType)
4885            callbackObject = CGGeneric(
4886                "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
4887                (unionArgumentObj, name))
4888            names.append(name)
4889        else:
4890            callbackObject = None
4891
4892        dictionaryMemberTypes = filter(lambda t: t.isDictionary(), memberTypes)
4893        if len(dictionaryMemberTypes) > 0:
4894            assert len(dictionaryMemberTypes) == 1
4895            name = getUnionMemberName(dictionaryMemberTypes[0])
4896            setDictionary = CGGeneric(
4897                "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
4898                (unionArgumentObj, name))
4899            names.append(name)
4900        else:
4901            setDictionary = None
4902
4903        mozMapMemberTypes = filter(lambda t: t.isMozMap(), memberTypes)
4904        if len(mozMapMemberTypes) > 0:
4905            assert len(mozMapMemberTypes) == 1
4906            name = getUnionMemberName(mozMapMemberTypes[0])
4907            mozMapObject = CGGeneric(
4908                "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
4909                (unionArgumentObj, name))
4910            names.append(name)
4911        else:
4912            mozMapObject = None
4913
4914        objectMemberTypes = filter(lambda t: t.isObject(), memberTypes)
4915        if len(objectMemberTypes) > 0:
4916            assert len(objectMemberTypes) == 1
4917            # Very important to NOT construct a temporary Rooted here, since the
4918            # SetToObject call can call a Rooted constructor and we need to keep
4919            # stack discipline for Rooted.
4920            object = CGGeneric("if (!%s.SetToObject(cx, &${val}.toObject(), ${passedToJSImpl})) {\n"
4921                               "%s"
4922                               "}\n"
4923                               "done = true;\n" % (unionArgumentObj, indent(exceptionCode)))
4924            names.append(objectMemberTypes[0].name)
4925        else:
4926            object = None
4927
4928        hasObjectTypes = interfaceObject or sequenceObject or dateObject or callbackObject or object or mozMapObject
4929        if hasObjectTypes:
4930            # "object" is not distinguishable from other types
4931            assert not object or not (interfaceObject or sequenceObject or dateObject or callbackObject or mozMapObject)
4932            if sequenceObject or dateObject or callbackObject:
4933                # An object can be both an sequence object and a callback or
4934                # dictionary, but we shouldn't have both in the union's members
4935                # because they are not distinguishable.
4936                assert not (sequenceObject and callbackObject)
4937                templateBody = CGElseChain([sequenceObject, dateObject, callbackObject])
4938            else:
4939                templateBody = None
4940            if interfaceObject:
4941                assert not object
4942                if templateBody:
4943                    templateBody = CGIfWrapper(templateBody, "!done")
4944                templateBody = CGList([interfaceObject, templateBody])
4945            else:
4946                templateBody = CGList([templateBody, object])
4947
4948            if dateObject:
4949                templateBody.prepend(CGGeneric("JS::Rooted<JSObject*> argObj(cx, &${val}.toObject());\n"))
4950
4951            if mozMapObject:
4952                templateBody = CGList([templateBody,
4953                                       CGIfWrapper(mozMapObject, "!done")])
4954
4955            templateBody = CGIfWrapper(templateBody, "${val}.isObject()")
4956        else:
4957            templateBody = CGGeneric()
4958
4959        if setDictionary:
4960            assert not object
4961            templateBody = CGList([templateBody,
4962                                   CGIfWrapper(setDictionary, "!done")])
4963
4964        stringTypes = [t for t in memberTypes if t.isString() or t.isEnum()]
4965        numericTypes = [t for t in memberTypes if t.isNumeric()]
4966        booleanTypes = [t for t in memberTypes if t.isBoolean()]
4967        if stringTypes or numericTypes or booleanTypes:
4968            assert len(stringTypes) <= 1
4969            assert len(numericTypes) <= 1
4970            assert len(booleanTypes) <= 1
4971
4972            # We will wrap all this stuff in a do { } while (0); so we
4973            # can use "break" for flow control.
4974            def getStringOrPrimitiveConversion(memberType):
4975                name = getUnionMemberName(memberType)
4976                return CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext;\n"
4977                                 "break;\n" % (unionArgumentObj, name))
4978            other = CGList([])
4979            stringConversion = map(getStringOrPrimitiveConversion, stringTypes)
4980            numericConversion = map(getStringOrPrimitiveConversion, numericTypes)
4981            booleanConversion = map(getStringOrPrimitiveConversion, booleanTypes)
4982            if stringConversion:
4983                if booleanConversion:
4984                    other.append(CGIfWrapper(booleanConversion[0],
4985                                             "${val}.isBoolean()"))
4986                if numericConversion:
4987                    other.append(CGIfWrapper(numericConversion[0],
4988                                             "${val}.isNumber()"))
4989                other.append(stringConversion[0])
4990            elif numericConversion:
4991                if booleanConversion:
4992                    other.append(CGIfWrapper(booleanConversion[0],
4993                                             "${val}.isBoolean()"))
4994                other.append(numericConversion[0])
4995            else:
4996                assert booleanConversion
4997                other.append(booleanConversion[0])
4998
4999            other = CGWrapper(CGIndenter(other), pre="do {\n", post="} while (0);\n")
5000            if hasObjectTypes or setDictionary:
5001                other = CGWrapper(CGIndenter(other), "{\n", post="}\n")
5002                if object:
5003                    templateBody = CGElseChain([templateBody, other])
5004                else:
5005                    other = CGWrapper(other, pre="if (!done) ")
5006                    templateBody = CGList([templateBody, other])
5007            else:
5008                assert templateBody.define() == ""
5009                templateBody = other
5010        else:
5011            other = None
5012
5013        templateBody = CGWrapper(templateBody, pre="bool done = false, failed = false, tryNext;\n")
5014        throw = CGGeneric(fill(
5015            """
5016            if (failed) {
5017              $*{exceptionCode}
5018            }
5019            if (!done) {
5020              ThrowErrorMessage(cx, MSG_NOT_IN_UNION, "${desc}", "${names}");
5021              $*{exceptionCode}
5022            }
5023            """,
5024            exceptionCode=exceptionCode,
5025            desc=firstCap(sourceDescription),
5026            names=", ".join(names)))
5027
5028        templateBody = CGWrapper(CGIndenter(CGList([templateBody, throw])), pre="{\n", post="}\n")
5029
5030        typeName = CGUnionStruct.unionTypeDecl(type, isOwningUnion)
5031        argumentTypeName = typeName + "Argument"
5032        if nullable:
5033            typeName = "Nullable<" + typeName + " >"
5034
5035        def handleNull(templateBody, setToNullVar, extraConditionForNull=""):
5036            nullTest = "%s${val}.isNullOrUndefined()" % extraConditionForNull
5037            return CGIfElseWrapper(nullTest,
5038                                   CGGeneric("%s.SetNull();\n" % setToNullVar),
5039                                   templateBody)
5040
5041        if type.hasNullableType:
5042            assert not nullable
5043            # Make sure to handle a null default value here
5044            if defaultValue and isinstance(defaultValue, IDLNullValue):
5045                assert defaultValue.type == type
5046                extraConditionForNull = "!(${haveValue}) || "
5047            else:
5048                extraConditionForNull = ""
5049            templateBody = handleNull(templateBody, unionArgumentObj,
5050                                      extraConditionForNull=extraConditionForNull)
5051
5052        declType = CGGeneric(typeName)
5053        if isOwningUnion:
5054            holderType = None
5055        else:
5056            holderType = CGGeneric(argumentTypeName)
5057            if nullable:
5058                holderType = CGTemplatedType("Maybe", holderType)
5059
5060        # If we're isOptional and not nullable the normal optional handling will
5061        # handle lazy construction of our holder.  If we're nullable and not
5062        # owning we do it all by hand because we do not want our holder
5063        # constructed if we're null.  But if we're owning we don't have a
5064        # holder anyway, so we can do the normal Optional codepath.
5065        declLoc = "${declName}"
5066        constructDecl = None
5067        if nullable:
5068            if isOptional and not isOwningUnion:
5069                holderArgs = "${declName}.Value().SetValue()"
5070                declType = CGTemplatedType("Optional", declType)
5071                constructDecl = CGGeneric("${declName}.Construct();\n")
5072                declLoc = "${declName}.Value()"
5073            else:
5074                holderArgs = "${declName}.SetValue()"
5075            if holderType is not None:
5076                constructHolder = CGGeneric("${holderName}.emplace(%s);\n" % holderArgs)
5077            else:
5078                constructHolder = None
5079            # Don't need to pass those args when the holder is being constructed
5080            holderArgs = None
5081        else:
5082            holderArgs = "${declName}"
5083            constructHolder = None
5084
5085        if not isMember and isCallbackReturnValue:
5086            declType = CGWrapper(declType, post="&")
5087            declArgs = "aRetVal"
5088        else:
5089            declArgs = None
5090
5091        if defaultValue and not isinstance(defaultValue, IDLNullValue):
5092            tag = defaultValue.type.tag()
5093
5094            if tag in numericSuffixes or tag is IDLType.Tags.bool:
5095                defaultStr = getHandleDefault(defaultValue)
5096                # Make sure we actually construct the thing inside the nullable.
5097                value = declLoc + (".SetValue()" if nullable else "")
5098                name = getUnionMemberName(defaultValue.type)
5099                default = CGGeneric("%s.RawSetAs%s() = %s;\n" %
5100                                    (value, name, defaultStr))
5101            elif isinstance(defaultValue, IDLEmptySequenceValue):
5102                name = getUnionMemberName(defaultValue.type)
5103                # Make sure we actually construct the thing inside the nullable.
5104                value = declLoc + (".SetValue()" if nullable else "")
5105                # It's enough to set us to the right type; that will
5106                # create an empty array, which is all we need here.
5107                default = CGGeneric("%s.RawSetAs%s();\n" %
5108                                    (value, name))
5109            elif defaultValue.type.isEnum():
5110                name = getUnionMemberName(defaultValue.type)
5111                # Make sure we actually construct the thing inside the nullable.
5112                value = declLoc + (".SetValue()" if nullable else "")
5113                default = CGGeneric(
5114                    "%s.RawSetAs%s() = %s::%s;\n" %
5115                    (value, name,
5116                     defaultValue.type.inner.identifier.name,
5117                     getEnumValueName(defaultValue.value)))
5118            else:
5119                default = CGGeneric(
5120                    handleDefaultStringValue(
5121                        defaultValue, "%s.SetStringData" % unionArgumentObj) +
5122                    ";\n")
5123
5124            templateBody = CGIfElseWrapper("!(${haveValue})", default, templateBody)
5125
5126        templateBody = CGList([constructHolder, templateBody])
5127
5128        if nullable:
5129            if defaultValue:
5130                if isinstance(defaultValue, IDLNullValue):
5131                    extraConditionForNull = "!(${haveValue}) || "
5132                else:
5133                    extraConditionForNull = "${haveValue} && "
5134            else:
5135                extraConditionForNull = ""
5136            templateBody = handleNull(templateBody, declLoc,
5137                                      extraConditionForNull=extraConditionForNull)
5138        elif (not type.hasNullableType and defaultValue and
5139              isinstance(defaultValue, IDLNullValue)):
5140            assert type.hasDictionaryType()
5141            assert defaultValue.type.isDictionary()
5142            if not isOwningUnion and typeNeedsRooting(defaultValue.type):
5143                ctorArgs = "cx"
5144            else:
5145                ctorArgs = ""
5146            initDictionaryWithNull = CGIfWrapper(
5147                CGGeneric("return false;\n"),
5148                ('!%s.RawSetAs%s(%s).Init(cx, JS::NullHandleValue, "Member of %s")'
5149                 % (declLoc, getUnionMemberName(defaultValue.type),
5150                    ctorArgs, type)))
5151            templateBody = CGIfElseWrapper("!(${haveValue})",
5152                                           initDictionaryWithNull,
5153                                           templateBody)
5154
5155        templateBody = CGList([constructDecl, templateBody])
5156
5157        return JSToNativeConversionInfo(templateBody.define(),
5158                                        declType=declType,
5159                                        declArgs=declArgs,
5160                                        holderType=holderType,
5161                                        holderArgs=holderArgs,
5162                                        dealWithOptional=isOptional and (not nullable or isOwningUnion))
5163
5164    if type.isGeckoInterface():
5165        assert not isEnforceRange and not isClamp
5166
5167        descriptor = descriptorProvider.getDescriptor(
5168            type.unroll().inner.identifier.name)
5169
5170        assert descriptor.nativeType != 'JSObject'
5171
5172        if descriptor.interface.isCallback():
5173            (declType, declArgs,
5174             conversion) = getCallbackConversionInfo(type, descriptor.interface,
5175                                                     isMember,
5176                                                     isCallbackReturnValue,
5177                                                     isOptional)
5178            template = wrapObjectTemplate(conversion, type,
5179                                          "${declName} = nullptr;\n",
5180                                          failureCode)
5181            return JSToNativeConversionInfo(template, declType=declType,
5182                                            declArgs=declArgs,
5183                                            dealWithOptional=isOptional)
5184
5185        # This is an interface that we implement as a concrete class
5186        # or an XPCOM interface.
5187
5188        # Allow null pointers for nullable types and old-binding classes, and
5189        # use an RefPtr or raw pointer for callback return values to make
5190        # them easier to return.
5191        argIsPointer = (type.nullable() or type.unroll().inner.isExternal() or
5192                        isCallbackReturnValue)
5193
5194        # Sequence and dictionary members, as well as owning unions (which can
5195        # appear here as return values in JS-implemented interfaces) have to
5196        # hold a strong ref to the thing being passed down.  Those all set
5197        # isMember.
5198        #
5199        # Also, callback return values always end up addrefing anyway, so there
5200        # is no point trying to avoid it here and it makes other things simpler
5201        # since we can assume the return value is a strong ref.
5202        #
5203        # Finally, promises need to hold a strong ref because that's what
5204        # Promise.resolve returns.
5205        assert not descriptor.interface.isCallback()
5206        isPromise = descriptor.interface.identifier.name == "Promise"
5207        forceOwningType = isMember or isCallbackReturnValue or isPromise
5208
5209        typeName = descriptor.nativeType
5210        typePtr = typeName + "*"
5211
5212        # Compute a few things:
5213        #  - declType is the type we want to return as the first element of our
5214        #    tuple.
5215        #  - holderType is the type we want to return as the third element
5216        #    of our tuple.
5217
5218        # Set up some sensible defaults for these things insofar as we can.
5219        holderType = None
5220        if argIsPointer:
5221            if forceOwningType:
5222                declType = "RefPtr<" + typeName + ">"
5223            else:
5224                declType = typePtr
5225        else:
5226            if forceOwningType:
5227                declType = "OwningNonNull<" + typeName + ">"
5228            else:
5229                declType = "NonNull<" + typeName + ">"
5230
5231        templateBody = ""
5232        if forceOwningType:
5233            templateBody += 'static_assert(IsRefcounted<%s>::value, "We can only store refcounted classes.");' % typeName
5234
5235        if isPromise:
5236            # Per spec, what we're supposed to do is take the original
5237            # Promise.resolve and call it with the original Promise as this
5238            # value to make a Promise out of whatever value we actually have
5239            # here.  The question is which global we should use.  There are
5240            # several cases to consider:
5241            #
5242            # 1) Normal call to API with a Promise argument.  This is a case the
5243            #    spec covers, and we should be using the current Realm's
5244            #    Promise.  That means the current compartment.
5245            # 2) Call to API with a Promise argument over Xrays.  In practice,
5246            #    this sort of thing seems to be used for giving an API
5247            #    implementation a way to wait for conclusion of an asyc
5248            #    operation, _not_ to expose the Promise to content code.  So we
5249            #    probably want to allow callers to use such an API in a
5250            #    "natural" way, by passing chrome-side promises; indeed, that
5251            #    may be all that the caller has to represent their async
5252            #    operation.  That means we really need to do the
5253            #    Promise.resolve() in the caller (chrome) compartment: if we do
5254            #    it in the content compartment, we will try to call .then() on
5255            #    the chrome promise while in the content compartment, which will
5256            #    throw and we'll just get a rejected Promise.  Note that this is
5257            #    also the reason why a caller who has a chrome Promise
5258            #    representing an async operation can't itself convert it to a
5259            #    content-side Promise (at least not without some serious
5260            #    gyrations).
5261            # 3) Promise return value from a callback or callback interface.
5262            #    This is in theory a case the spec covers but in practice it
5263            #    really doesn't define behavior here because it doesn't define
5264            #    what Realm we're in after the callback returns, which is when
5265            #    the argument conversion happens.  We will use the current
5266            #    compartment, which is the compartment of the callable (which
5267            #    may itself be a cross-compartment wrapper itself), which makes
5268            #    as much sense as anything else. In practice, such an API would
5269            #    once again be providing a Promise to signal completion of an
5270            #    operation, which would then not be exposed to anyone other than
5271            #    our own implementation code.
5272            # 4) Return value from a JS-implemented interface.  In this case we
5273            #    have a problem.  Our current compartment is the compartment of
5274            #    the JS implementation.  But if the JS implementation returned
5275            #    a page-side Promise (which is a totally sane thing to do, and
5276            #    in fact the right thing to do given that this return value is
5277            #    going right to content script) then we don't want to
5278            #    Promise.resolve with our current compartment Promise, because
5279            #    that will wrap it up in a chrome-side Promise, which is
5280            #    decidedly _not_ what's desired here.  So in that case we
5281            #    should really unwrap the return value and use the global of
5282            #    the result.  CheckedUnwrap should be good enough for that; if
5283            #    it fails, then we're failing unwrap while in a
5284            #    system-privileged compartment, so presumably we have a dead
5285            #    object wrapper.  Just error out.  Do NOT fall back to using
5286            #    the current compartment instead: that will return a
5287            #    system-privileged rejected (because getting .then inside
5288            #    resolve() failed) Promise to the caller, which they won't be
5289            #    able to touch.  That's not helpful.  If we error out, on the
5290            #    other hand, they will get a content-side rejected promise.
5291            #    Same thing if the value returned is not even an object.
5292            if isCallbackReturnValue == "JSImpl":
5293                # Case 4 above.  Note that globalObj defaults to the current
5294                # compartment global.  Note that we don't use $*{exceptionCode}
5295                # here because that will try to aRv.Throw(NS_ERROR_UNEXPECTED)
5296                # which we don't really want here.
5297                assert exceptionCode == "aRv.Throw(NS_ERROR_UNEXPECTED);\nreturn nullptr;\n"
5298                getPromiseGlobal = fill(
5299                    """
5300                    if (!$${val}.isObject()) {
5301                      aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_LITERAL_STRING("${sourceDescription}"));
5302                      return nullptr;
5303                    }
5304                    JSObject* unwrappedVal = js::CheckedUnwrap(&$${val}.toObject());
5305                    if (!unwrappedVal) {
5306                      // A slight lie, but not much of one, for a dead object wrapper.
5307                      aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_LITERAL_STRING("${sourceDescription}"));
5308                      return nullptr;
5309                    }
5310                    globalObj = js::GetGlobalForObjectCrossCompartment(unwrappedVal);
5311                    """,
5312                    sourceDescription=sourceDescription)
5313            else:
5314                getPromiseGlobal = ""
5315
5316            templateBody = fill(
5317                """
5318                { // Scope for our GlobalObject, FastErrorResult, JSAutoCompartment,
5319                  // etc.
5320
5321                  JS::Rooted<JSObject*> globalObj(cx, JS::CurrentGlobalOrNull(cx));
5322                  $*{getPromiseGlobal}
5323                  JSAutoCompartment ac(cx, globalObj);
5324                  GlobalObject promiseGlobal(cx, globalObj);
5325                  if (promiseGlobal.Failed()) {
5326                    $*{exceptionCode}
5327                  }
5328
5329                  JS::Rooted<JS::Value> valueToResolve(cx, $${val});
5330                  if (!JS_WrapValue(cx, &valueToResolve)) {
5331                    $*{exceptionCode}
5332                  }
5333                  binding_detail::FastErrorResult promiseRv;
5334                #ifdef SPIDERMONKEY_PROMISE
5335                  nsCOMPtr<nsIGlobalObject> global =
5336                    do_QueryInterface(promiseGlobal.GetAsSupports());
5337                  if (!global) {
5338                    promiseRv.Throw(NS_ERROR_UNEXPECTED);
5339                    promiseRv.MaybeSetPendingException(cx);
5340                    $*{exceptionCode}
5341                  }
5342                  $${declName} = Promise::Resolve(global, cx, valueToResolve,
5343                                                  promiseRv);
5344                  if (promiseRv.MaybeSetPendingException(cx)) {
5345                    $*{exceptionCode}
5346                  }
5347                #else
5348                  JS::Handle<JSObject*> promiseCtor =
5349                    PromiseBinding::GetConstructorObjectHandle(cx);
5350                  if (!promiseCtor) {
5351                    $*{exceptionCode}
5352                  }
5353                  JS::Rooted<JS::Value> resolveThisv(cx, JS::ObjectValue(*promiseCtor));
5354                  JS::Rooted<JS::Value> resolveResult(cx);
5355                  Promise::Resolve(promiseGlobal, resolveThisv, valueToResolve,
5356                                   &resolveResult, promiseRv);
5357                  if (promiseRv.MaybeSetPendingException(cx)) {
5358                    $*{exceptionCode}
5359                  }
5360                  nsresult unwrapRv = UNWRAP_OBJECT(Promise, &resolveResult.toObject(), $${declName});
5361                  if (NS_FAILED(unwrapRv)) { // Quite odd
5362                    promiseRv.Throw(unwrapRv);
5363                    promiseRv.MaybeSetPendingException(cx);
5364                    $*{exceptionCode}
5365                  }
5366                #endif // SPIDERMONKEY_PROMISE
5367                }
5368                """,
5369                getPromiseGlobal=getPromiseGlobal,
5370                exceptionCode=exceptionCode)
5371        elif not descriptor.interface.isConsequential() and not descriptor.interface.isExternal():
5372            if failureCode is not None:
5373                templateBody += str(CastableObjectUnwrapper(
5374                    descriptor,
5375                    "${val}",
5376                    "${maybeMutableVal}",
5377                    "${declName}",
5378                    failureCode))
5379            else:
5380                templateBody += str(FailureFatalCastableObjectUnwrapper(
5381                    descriptor,
5382                    "${val}",
5383                    "${maybeMutableVal}",
5384                    "${declName}",
5385                    exceptionCode,
5386                    isCallbackReturnValue,
5387                    firstCap(sourceDescription)))
5388        else:
5389            # Either external, or new-binding non-castable.  We always have a
5390            # holder for these, because we don't actually know whether we have
5391            # to addref when unwrapping or not.  So we just pass an
5392            # getter_AddRefs(RefPtr) to XPConnect and if we'll need a release
5393            # it'll put a non-null pointer in there.
5394            if forceOwningType:
5395                # Don't return a holderType in this case; our declName
5396                # will just own stuff.
5397                templateBody += "RefPtr<" + typeName + "> ${holderName};\n"
5398            else:
5399                holderType = "RefPtr<" + typeName + ">"
5400            templateBody += (
5401                "JS::Rooted<JSObject*> source(cx, &${val}.toObject());\n" +
5402                "if (NS_FAILED(UnwrapArg<" + typeName + ">(source, getter_AddRefs(${holderName})))) {\n")
5403            templateBody += CGIndenter(onFailureBadType(failureCode,
5404                                                        descriptor.interface.identifier.name)).define()
5405            templateBody += ("}\n"
5406                             "MOZ_ASSERT(${holderName});\n")
5407
5408            # And store our value in ${declName}
5409            templateBody += "${declName} = ${holderName};\n"
5410
5411        if isPromise:
5412            if type.nullable():
5413                codeToSetNull = "${declName} = nullptr;\n"
5414                templateBody = CGIfElseWrapper(
5415                    "${val}.isNullOrUndefined()",
5416                    CGGeneric(codeToSetNull),
5417                    CGGeneric(templateBody)).define()
5418                if isinstance(defaultValue, IDLNullValue):
5419                    templateBody = handleDefault(templateBody, codeToSetNull)
5420            else:
5421                assert defaultValue is None
5422        else:
5423            # Just pass failureCode, not onFailureBadType, here, so we'll report
5424            # the thing as not an object as opposed to not implementing whatever
5425            # our interface is.
5426            templateBody = wrapObjectTemplate(templateBody, type,
5427                                              "${declName} = nullptr;\n",
5428                                              failureCode)
5429
5430        declType = CGGeneric(declType)
5431        if holderType is not None:
5432            holderType = CGGeneric(holderType)
5433        return JSToNativeConversionInfo(templateBody,
5434                                        declType=declType,
5435                                        holderType=holderType,
5436                                        dealWithOptional=isOptional)
5437
5438    if type.isSpiderMonkeyInterface():
5439        assert not isEnforceRange and not isClamp
5440        name = type.unroll().name  # unroll() because it may be nullable
5441        arrayType = CGGeneric(name)
5442        declType = arrayType
5443        if type.nullable():
5444            declType = CGTemplatedType("Nullable", declType)
5445            objRef = "${declName}.SetValue()"
5446        else:
5447            objRef = "${declName}"
5448
5449        # Again, this is a bit strange since we are actually building a
5450        # template string here. ${objRef} and $*{badType} below are filled in
5451        # right now; $${val} expands to ${val}, to be filled in later.
5452        template = fill(
5453            """
5454            if (!${objRef}.Init(&$${val}.toObject())) {
5455              $*{badType}
5456            }
5457            """,
5458            objRef=objRef,
5459            badType=onFailureBadType(failureCode, type.name).define())
5460        template = wrapObjectTemplate(template, type, "${declName}.SetNull();\n",
5461                                      failureCode)
5462        if not isMember:
5463            # This is a bit annoying.  In a union we don't want to have a
5464            # holder, since unions don't support that.  But if we're optional we
5465            # want to have a holder, so that the callee doesn't see
5466            # Optional<RootedTypedArray<ArrayType> >.  So do a holder if we're
5467            # optional and use a RootedTypedArray otherwise.
5468            if isOptional:
5469                holderType = CGTemplatedType("TypedArrayRooter", arrayType)
5470                # If our typed array is nullable, this will set the Nullable to
5471                # be not-null, but that's ok because we make an explicit
5472                # SetNull() call on it as needed if our JS value is actually
5473                # null.  XXXbz Because "Maybe" takes const refs for constructor
5474                # arguments, we can't pass a reference here; have to pass a
5475                # pointer.
5476                holderArgs = "cx, &%s" % objRef
5477                declArgs = None
5478            else:
5479                holderType = None
5480                holderArgs = None
5481                declType = CGTemplatedType("RootedTypedArray", declType)
5482                declArgs = "cx"
5483        else:
5484            holderType = None
5485            holderArgs = None
5486            declArgs = None
5487        return JSToNativeConversionInfo(template,
5488                                        declType=declType,
5489                                        holderType=holderType,
5490                                        dealWithOptional=isOptional,
5491                                        declArgs=declArgs,
5492                                        holderArgs=holderArgs)
5493
5494    if type.isDOMString() or type.isUSVString():
5495        assert not isEnforceRange and not isClamp
5496
5497        treatAs = {
5498            "Default": "eStringify",
5499            "EmptyString": "eEmpty",
5500            "Null": "eNull",
5501        }
5502        if type.nullable():
5503            # For nullable strings null becomes a null string.
5504            treatNullAs = "Null"
5505            # For nullable strings undefined also becomes a null string.
5506            undefinedBehavior = "eNull"
5507        else:
5508            undefinedBehavior = "eStringify"
5509        nullBehavior = treatAs[treatNullAs]
5510
5511        def getConversionCode(varName):
5512            normalizeCode = ""
5513            if type.isUSVString():
5514                normalizeCode = "NormalizeUSVString(cx, %s);\n" % varName
5515
5516            conversionCode = fill("""
5517                if (!ConvertJSValueToString(cx, $${val}, ${nullBehavior}, ${undefinedBehavior}, ${varName})) {
5518                  $*{exceptionCode}
5519                }
5520                $*{normalizeCode}
5521                """
5522                ,
5523                nullBehavior=nullBehavior,
5524                undefinedBehavior=undefinedBehavior,
5525                varName=varName,
5526                exceptionCode=exceptionCode,
5527                normalizeCode=normalizeCode)
5528
5529            if defaultValue is None:
5530                return conversionCode
5531
5532            if isinstance(defaultValue, IDLNullValue):
5533                assert(type.nullable())
5534                defaultCode = "%s.SetIsVoid(true)" % varName
5535            else:
5536                defaultCode = handleDefaultStringValue(defaultValue,
5537                                                       "%s.Rebind" % varName)
5538            return handleDefault(conversionCode, defaultCode + ";\n")
5539
5540        if isMember:
5541            # Convert directly into the nsString member we have.
5542            declType = CGGeneric("nsString")
5543            return JSToNativeConversionInfo(
5544                getConversionCode("${declName}"),
5545                declType=declType,
5546                dealWithOptional=isOptional)
5547
5548        if isOptional:
5549            declType = "Optional<nsAString>"
5550            holderType = CGGeneric("binding_detail::FakeString")
5551            conversionCode = ("%s"
5552                              "${declName} = &${holderName};\n" %
5553                              getConversionCode("${holderName}"))
5554        else:
5555            declType = "binding_detail::FakeString"
5556            holderType = None
5557            conversionCode = getConversionCode("${declName}")
5558
5559        # No need to deal with optional here; we handled it already
5560        return JSToNativeConversionInfo(
5561            conversionCode,
5562            declType=CGGeneric(declType),
5563            holderType=holderType)
5564
5565    if type.isByteString():
5566        assert not isEnforceRange and not isClamp
5567
5568        nullable = toStringBool(type.nullable())
5569
5570        conversionCode = fill("""
5571            if (!ConvertJSValueToByteString(cx, $${val}, ${nullable}, $${declName})) {
5572              $*{exceptionCode}
5573            }
5574            """,
5575            nullable=nullable,
5576            exceptionCode=exceptionCode)
5577
5578        if defaultValue is not None:
5579            if isinstance(defaultValue, IDLNullValue):
5580                assert(type.nullable())
5581                defaultCode = "${declName}.SetIsVoid(true)"
5582            else:
5583                defaultCode = handleDefaultStringValue(defaultValue,
5584                                                       "${declName}.Rebind")
5585            conversionCode = handleDefault(conversionCode, defaultCode + ";\n")
5586
5587        return JSToNativeConversionInfo(
5588            conversionCode,
5589            declType=CGGeneric("nsCString"),
5590            dealWithOptional=isOptional)
5591
5592    if type.isEnum():
5593        assert not isEnforceRange and not isClamp
5594
5595        enumName = type.unroll().inner.identifier.name
5596        declType = CGGeneric(enumName)
5597        if type.nullable():
5598            declType = CGTemplatedType("Nullable", declType)
5599            declType = declType.define()
5600            enumLoc = "${declName}.SetValue()"
5601        else:
5602            enumLoc = "${declName}"
5603            declType = declType.define()
5604
5605        if invalidEnumValueFatal:
5606            handleInvalidEnumValueCode = "MOZ_ASSERT(index >= 0);\n"
5607        else:
5608            # invalidEnumValueFatal is false only for attributes.  So we won't
5609            # have a non-default exceptionCode here unless attribute "arg
5610            # conversion" code starts passing in an exceptionCode.  At which
5611            # point we'll need to figure out what that even means.
5612            assert exceptionCode == "return false;\n"
5613            handleInvalidEnumValueCode = dedent("""
5614                if (index < 0) {
5615                  return true;
5616                }
5617                """)
5618
5619        template = fill(
5620            """
5621            {
5622              int index;
5623              if (!FindEnumStringIndex<${invalidEnumValueFatal}>(cx, $${val}, ${values}, "${enumtype}", "${sourceDescription}", &index)) {
5624                $*{exceptionCode}
5625              }
5626              $*{handleInvalidEnumValueCode}
5627              ${enumLoc} = static_cast<${enumtype}>(index);
5628            }
5629            """,
5630            enumtype=enumName,
5631            values=enumName + "Values::" + ENUM_ENTRY_VARIABLE_NAME,
5632            invalidEnumValueFatal=toStringBool(invalidEnumValueFatal),
5633            handleInvalidEnumValueCode=handleInvalidEnumValueCode,
5634            exceptionCode=exceptionCode,
5635            enumLoc=enumLoc,
5636            sourceDescription=firstCap(sourceDescription))
5637
5638        setNull = "${declName}.SetNull();\n"
5639
5640        if type.nullable():
5641            template = CGIfElseWrapper("${val}.isNullOrUndefined()",
5642                                       CGGeneric(setNull),
5643                                       CGGeneric(template)).define()
5644
5645        if defaultValue is not None:
5646            if isinstance(defaultValue, IDLNullValue):
5647                assert type.nullable()
5648                template = handleDefault(template, setNull)
5649            else:
5650                assert(defaultValue.type.tag() == IDLType.Tags.domstring)
5651                template = handleDefault(template,
5652                                         ("%s = %s::%s;\n" %
5653                                          (enumLoc, enumName,
5654                                           getEnumValueName(defaultValue.value))))
5655        return JSToNativeConversionInfo(template, declType=CGGeneric(declType),
5656                                        dealWithOptional=isOptional)
5657
5658    if type.isCallback():
5659        assert not isEnforceRange and not isClamp
5660        assert not type.treatNonCallableAsNull() or type.nullable()
5661        assert not type.treatNonObjectAsNull() or type.nullable()
5662        assert not type.treatNonObjectAsNull() or not type.treatNonCallableAsNull()
5663
5664        callback = type.unroll().callback
5665        name = callback.identifier.name
5666        (declType, declArgs,
5667         conversion) = getCallbackConversionInfo(type, callback, isMember,
5668                                                 isCallbackReturnValue,
5669                                                 isOptional)
5670
5671        if allowTreatNonCallableAsNull and type.treatNonCallableAsNull():
5672            haveCallable = "JS::IsCallable(&${val}.toObject())"
5673            if not isDefinitelyObject:
5674                haveCallable = "${val}.isObject() && " + haveCallable
5675            if defaultValue is not None:
5676                assert(isinstance(defaultValue, IDLNullValue))
5677                haveCallable = "${haveValue} && " + haveCallable
5678            template = (
5679                ("if (%s) {\n" % haveCallable) +
5680                conversion +
5681                "} else {\n"
5682                "  ${declName} = nullptr;\n"
5683                "}\n")
5684        elif allowTreatNonCallableAsNull and type.treatNonObjectAsNull():
5685            if not isDefinitelyObject:
5686                haveObject = "${val}.isObject()"
5687                if defaultValue is not None:
5688                    assert(isinstance(defaultValue, IDLNullValue))
5689                    haveObject = "${haveValue} && " + haveObject
5690                template = CGIfElseWrapper(haveObject,
5691                                           CGGeneric(conversion),
5692                                           CGGeneric("${declName} = nullptr;\n")).define()
5693            else:
5694                template = conversion
5695        else:
5696            template = wrapObjectTemplate(
5697                "if (JS::IsCallable(&${val}.toObject())) {\n" +
5698                conversion +
5699                "} else {\n" +
5700                indent(onFailureNotCallable(failureCode).define()) +
5701                "}\n",
5702                type,
5703                "${declName} = nullptr;\n",
5704                failureCode)
5705        return JSToNativeConversionInfo(template, declType=declType,
5706                                        declArgs=declArgs,
5707                                        dealWithOptional=isOptional)
5708
5709    if type.isAny():
5710        assert not isEnforceRange and not isClamp
5711
5712        declArgs = None
5713        if isMember in ("Variadic", "Sequence", "Dictionary", "MozMap"):
5714            # Rooting is handled by the sequence and dictionary tracers.
5715            declType = "JS::Value"
5716        else:
5717            assert not isMember
5718            declType = "JS::Rooted<JS::Value>"
5719            declArgs = "cx"
5720
5721        assert not isOptional
5722        templateBody = "${declName} = ${val};\n"
5723
5724        # For JS-implemented APIs, we refuse to allow passing objects that the
5725        # API consumer does not subsume. The extra parens around
5726        # ($${passedToJSImpl}) suppress unreachable code warnings when
5727        # $${passedToJSImpl} is the literal `false`.
5728        if not isinstance(descriptorProvider, Descriptor) or descriptorProvider.interface.isJSImplemented():
5729            templateBody = fill(
5730                """
5731                if (($${passedToJSImpl}) && !CallerSubsumes($${val})) {
5732                  ThrowErrorMessage(cx, MSG_PERMISSION_DENIED_TO_PASS_ARG, "${sourceDescription}");
5733                  $*{exceptionCode}
5734                }
5735                """,
5736                sourceDescription=sourceDescription,
5737                exceptionCode=exceptionCode) + templateBody
5738
5739        # We may not have a default value if we're being converted for
5740        # a setter, say.
5741        if defaultValue:
5742            if isinstance(defaultValue, IDLNullValue):
5743                defaultHandling = "${declName} = JS::NullValue();\n"
5744            else:
5745                assert isinstance(defaultValue, IDLUndefinedValue)
5746                defaultHandling = "${declName} = JS::UndefinedValue();\n"
5747            templateBody = handleDefault(templateBody, defaultHandling)
5748        return JSToNativeConversionInfo(templateBody,
5749                                        declType=CGGeneric(declType),
5750                                        declArgs=declArgs)
5751
5752    if type.isObject():
5753        assert not isEnforceRange and not isClamp
5754        return handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription)
5755
5756    if type.isDictionary():
5757        # There are no nullable dictionaries
5758        assert not type.nullable() or isCallbackReturnValue
5759        # All optional dictionaries always have default values, so we
5760        # should be able to assume not isOptional here.
5761        assert not isOptional
5762        # In the callback return value case we never have to worry
5763        # about a default value; we always have a value.
5764        assert not isCallbackReturnValue or defaultValue is None
5765
5766        typeName = CGDictionary.makeDictionaryName(type.unroll().inner)
5767        if not isMember and not isCallbackReturnValue:
5768            # Since we're not a member and not nullable or optional, no one will
5769            # see our real type, so we can do the fast version of the dictionary
5770            # that doesn't pre-initialize members.
5771            typeName = "binding_detail::Fast" + typeName
5772
5773        declType = CGGeneric(typeName)
5774
5775        # We do manual default value handling here, because we
5776        # actually do want a jsval, and we only handle null anyway
5777        # NOTE: if isNullOrUndefined or isDefinitelyObject are true,
5778        # we know we have a value, so we don't have to worry about the
5779        # default value.
5780        if (not isNullOrUndefined and not isDefinitelyObject and
5781            defaultValue is not None):
5782            assert(isinstance(defaultValue, IDLNullValue))
5783            val = "(${haveValue}) ? ${val} : JS::NullHandleValue"
5784        else:
5785            val = "${val}"
5786
5787        dictLoc = "${declName}"
5788        if type.nullable():
5789            dictLoc += ".SetValue()"
5790
5791        conversionCode = fill("""
5792            if (!${dictLoc}.Init(cx, ${val},  "${desc}", $${passedToJSImpl})) {
5793              $*{exceptionCode}
5794            }
5795            """,
5796            dictLoc=dictLoc,
5797            val=val,
5798            desc=firstCap(sourceDescription),
5799            exceptionCode=exceptionCode)
5800
5801        if failureCode is not None:
5802            if isDefinitelyObject:
5803                dictionaryTest = "IsObjectValueConvertibleToDictionary"
5804            else:
5805                dictionaryTest = "IsConvertibleToDictionary"
5806
5807            template = fill("""
5808                { // scope for isConvertible
5809                  bool isConvertible;
5810                  if (!${testConvertible}(cx, ${val}, &isConvertible)) {
5811                    $*{exceptionCode}
5812                  }
5813                  if (!isConvertible) {
5814                    $*{failureCode}
5815                  }
5816
5817                  $*{conversionCode}
5818                }
5819
5820                """,
5821                testConvertible=dictionaryTest,
5822                val=val,
5823                exceptionCode=exceptionCode,
5824                failureCode=failureCode,
5825                conversionCode=conversionCode)
5826        else:
5827            template = conversionCode
5828
5829        if type.nullable():
5830            declType = CGTemplatedType("Nullable", declType)
5831            template = CGIfElseWrapper("${val}.isNullOrUndefined()",
5832                                       CGGeneric("${declName}.SetNull();\n"),
5833                                       CGGeneric(template)).define()
5834
5835        # Dictionary arguments that might contain traceable things need to get
5836        # traced
5837        if not isMember and isCallbackReturnValue:
5838            # Go ahead and just convert directly into our actual return value
5839            declType = CGWrapper(declType, post="&")
5840            declArgs = "aRetVal"
5841        elif not isMember and typeNeedsRooting(type):
5842            declType = CGTemplatedType("RootedDictionary", declType)
5843            declArgs = "cx"
5844        else:
5845            declArgs = None
5846
5847        return JSToNativeConversionInfo(template, declType=declType,
5848                                        declArgs=declArgs)
5849
5850    if type.isVoid():
5851        assert not isOptional
5852        # This one only happens for return values, and its easy: Just
5853        # ignore the jsval.
5854        return JSToNativeConversionInfo("")
5855
5856    if type.isDate():
5857        assert not isEnforceRange and not isClamp
5858
5859        declType = CGGeneric("Date")
5860        if type.nullable():
5861            declType = CGTemplatedType("Nullable", declType)
5862            dateVal = "${declName}.SetValue()"
5863        else:
5864            dateVal = "${declName}"
5865
5866        if failureCode is None:
5867            notDate = ('ThrowErrorMessage(cx, MSG_NOT_DATE, "%s");\n'
5868                       "%s" % (firstCap(sourceDescription), exceptionCode))
5869        else:
5870            notDate = failureCode
5871
5872        conversion = fill(
5873            """
5874            JS::Rooted<JSObject*> possibleDateObject(cx, &$${val}.toObject());
5875            { // scope for isDate
5876              bool isDate;
5877              if (!JS_ObjectIsDate(cx, possibleDateObject, &isDate)) {
5878                $*{exceptionCode}
5879              }
5880              if (!isDate) {
5881                $*{notDate}
5882              }
5883              if (!${dateVal}.SetTimeStamp(cx, possibleDateObject)) {
5884                $*{exceptionCode}
5885              }
5886            }
5887            """,
5888            exceptionCode=exceptionCode,
5889            dateVal=dateVal,
5890            notDate=notDate)
5891
5892        conversion = wrapObjectTemplate(conversion, type,
5893                                        "${declName}.SetNull();\n", notDate)
5894        return JSToNativeConversionInfo(conversion,
5895                                        declType=declType,
5896                                        dealWithOptional=isOptional)
5897
5898    if not type.isPrimitive():
5899        raise TypeError("Need conversion for argument type '%s'" % str(type))
5900
5901    typeName = builtinNames[type.tag()]
5902
5903    conversionBehavior = "eDefault"
5904    if isEnforceRange:
5905        assert type.isInteger()
5906        conversionBehavior = "eEnforceRange"
5907    elif isClamp:
5908        assert type.isInteger()
5909        conversionBehavior = "eClamp"
5910
5911    if type.nullable():
5912        declType = CGGeneric("Nullable<" + typeName + ">")
5913        writeLoc = "${declName}.SetValue()"
5914        readLoc = "${declName}.Value()"
5915        nullCondition = "${val}.isNullOrUndefined()"
5916        if defaultValue is not None and isinstance(defaultValue, IDLNullValue):
5917            nullCondition = "!(${haveValue}) || " + nullCondition
5918        template = fill("""
5919            if (${nullCondition}) {
5920              $${declName}.SetNull();
5921            } else if (!ValueToPrimitive<${typeName}, ${conversionBehavior}>(cx, $${val}, &${writeLoc})) {
5922              $*{exceptionCode}
5923            }
5924            """,
5925            nullCondition=nullCondition,
5926            typeName=typeName,
5927            conversionBehavior=conversionBehavior,
5928            writeLoc=writeLoc,
5929            exceptionCode=exceptionCode)
5930    else:
5931        assert(defaultValue is None or
5932               not isinstance(defaultValue, IDLNullValue))
5933        writeLoc = "${declName}"
5934        readLoc = writeLoc
5935        template = fill("""
5936            if (!ValueToPrimitive<${typeName}, ${conversionBehavior}>(cx, $${val}, &${writeLoc})) {
5937              $*{exceptionCode}
5938            }
5939            """,
5940            typeName=typeName,
5941            conversionBehavior=conversionBehavior,
5942            writeLoc=writeLoc,
5943            exceptionCode=exceptionCode)
5944        declType = CGGeneric(typeName)
5945
5946    if type.isFloat() and not type.isUnrestricted():
5947        if lenientFloatCode is not None:
5948            nonFiniteCode = lenientFloatCode
5949        else:
5950            nonFiniteCode = ('ThrowErrorMessage(cx, MSG_NOT_FINITE, "%s");\n'
5951                             "%s" % (firstCap(sourceDescription), exceptionCode))
5952
5953        # We're appending to an if-block brace, so strip trailing whitespace
5954        # and add an extra space before the else.
5955        template = template.rstrip()
5956        template += fill("""
5957             else if (!mozilla::IsFinite(${readLoc})) {
5958              $*{nonFiniteCode}
5959            }
5960            """,
5961            readLoc=readLoc,
5962            nonFiniteCode=nonFiniteCode)
5963
5964    if (defaultValue is not None and
5965        # We already handled IDLNullValue, so just deal with the other ones
5966        not isinstance(defaultValue, IDLNullValue)):
5967        tag = defaultValue.type.tag()
5968        defaultStr = getHandleDefault(defaultValue)
5969        template = CGIfElseWrapper(
5970            "${haveValue}",
5971            CGGeneric(template),
5972            CGGeneric("%s = %s;\n" % (writeLoc, defaultStr))).define()
5973
5974    return JSToNativeConversionInfo(template, declType=declType,
5975                                    dealWithOptional=isOptional)
5976
5977
5978def instantiateJSToNativeConversion(info, replacements, checkForValue=False):
5979    """
5980    Take a JSToNativeConversionInfo as returned by getJSToNativeConversionInfo
5981    and a set of replacements as required by the strings in such an object, and
5982    generate code to convert into stack C++ types.
5983
5984    If checkForValue is True, then the conversion will get wrapped in
5985    a check for ${haveValue}.
5986    """
5987    templateBody, declType, holderType, dealWithOptional = (
5988        info.template, info.declType, info.holderType, info.dealWithOptional)
5989
5990    if dealWithOptional and not checkForValue:
5991        raise TypeError("Have to deal with optional things, but don't know how")
5992    if checkForValue and declType is None:
5993        raise TypeError("Need to predeclare optional things, so they will be "
5994                        "outside the check for big enough arg count!")
5995
5996    # We can't precompute our holder constructor arguments, since
5997    # those might depend on ${declName}, which we change below.  Just
5998    # compute arguments at the point when we need them as we go.
5999    def getArgsCGThing(args):
6000        return CGGeneric(string.Template(args).substitute(replacements))
6001
6002    result = CGList([])
6003    # Make a copy of "replacements" since we may be about to start modifying it
6004    replacements = dict(replacements)
6005    originalDeclName = replacements["declName"]
6006    if declType is not None:
6007        if dealWithOptional:
6008            replacements["declName"] = "%s.Value()" % originalDeclName
6009            declType = CGTemplatedType("Optional", declType)
6010            declCtorArgs = None
6011        elif info.declArgs is not None:
6012            declCtorArgs = CGWrapper(getArgsCGThing(info.declArgs),
6013                                     pre="(", post=")")
6014        else:
6015            declCtorArgs = None
6016        result.append(
6017            CGList([declType, CGGeneric(" "),
6018                    CGGeneric(originalDeclName),
6019                    declCtorArgs, CGGeneric(";\n")]))
6020
6021    originalHolderName = replacements["holderName"]
6022    if holderType is not None:
6023        if dealWithOptional:
6024            replacements["holderName"] = "%s.ref()" % originalHolderName
6025            holderType = CGTemplatedType("Maybe", holderType)
6026            holderCtorArgs = None
6027        elif info.holderArgs is not None:
6028            holderCtorArgs = CGWrapper(getArgsCGThing(info.holderArgs),
6029                                       pre="(", post=")")
6030        else:
6031            holderCtorArgs = None
6032        result.append(
6033            CGList([holderType, CGGeneric(" "),
6034                    CGGeneric(originalHolderName),
6035                    holderCtorArgs, CGGeneric(";\n")]))
6036
6037    if "maybeMutableVal" not in replacements:
6038        replacements["maybeMutableVal"] = replacements["val"]
6039
6040    conversion = CGGeneric(
6041        string.Template(templateBody).substitute(replacements))
6042
6043    if checkForValue:
6044        if dealWithOptional:
6045            declConstruct = CGIndenter(
6046                CGGeneric("%s.Construct(%s);\n" %
6047                          (originalDeclName,
6048                           getArgsCGThing(info.declArgs).define() if
6049                           info.declArgs else "")))
6050            if holderType is not None:
6051                holderConstruct = CGIndenter(
6052                    CGGeneric("%s.emplace(%s);\n" %
6053                              (originalHolderName,
6054                               getArgsCGThing(info.holderArgs).define() if
6055                               info.holderArgs else "")))
6056            else:
6057                holderConstruct = None
6058        else:
6059            declConstruct = None
6060            holderConstruct = None
6061
6062        conversion = CGList([
6063            CGGeneric(
6064                string.Template("if (${haveValue}) {\n").substitute(replacements)),
6065            declConstruct,
6066            holderConstruct,
6067            CGIndenter(conversion),
6068            CGGeneric("}\n")
6069        ])
6070
6071    result.append(conversion)
6072    return result
6073
6074
6075def convertConstIDLValueToJSVal(value):
6076    if isinstance(value, IDLNullValue):
6077        return "JS::NullValue()"
6078    if isinstance(value, IDLUndefinedValue):
6079        return "JS::UndefinedValue()"
6080    tag = value.type.tag()
6081    if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16,
6082               IDLType.Tags.uint16, IDLType.Tags.int32]:
6083        return "JS::Int32Value(%s)" % (value.value)
6084    if tag == IDLType.Tags.uint32:
6085        return "JS::NumberValue(%sU)" % (value.value)
6086    if tag in [IDLType.Tags.int64, IDLType.Tags.uint64]:
6087        return "JS::CanonicalizedDoubleValue(%s)" % numericValue(tag, value.value)
6088    if tag == IDLType.Tags.bool:
6089        return "JS::BooleanValue(true)" if value.value else "JS::BooleanValue(false)"
6090    if tag in [IDLType.Tags.float, IDLType.Tags.double]:
6091        return "JS::CanonicalizedDoubleValue(%s)" % (value.value)
6092    raise TypeError("Const value of unhandled type: %s" % value.type)
6093
6094
6095class CGArgumentConverter(CGThing):
6096    """
6097    A class that takes an IDL argument object and its index in the
6098    argument list and generates code to unwrap the argument to the
6099    right native type.
6100
6101    argDescription is a description of the argument for error-reporting
6102    purposes.  Callers should assume that it might get placed in the middle of a
6103    sentence.  If it ends up at the beginning of a sentence, its first character
6104    will be automatically uppercased.
6105    """
6106    def __init__(self, argument, index, descriptorProvider,
6107                 argDescription, member,
6108                 invalidEnumValueFatal=True, lenientFloatCode=None):
6109        CGThing.__init__(self)
6110        self.argument = argument
6111        self.argDescription = argDescription
6112        assert(not argument.defaultValue or argument.optional)
6113
6114        replacer = {
6115            "index": index,
6116            "argc": "args.length()"
6117        }
6118        self.replacementVariables = {
6119            "declName": "arg%d" % index,
6120            "holderName": ("arg%d" % index) + "_holder",
6121            "obj": "obj",
6122            "passedToJSImpl": toStringBool(isJSImplementedDescriptor(descriptorProvider))
6123        }
6124        # If we have a method generated by the maplike/setlike portion of an
6125        # interface, arguments can possibly be undefined, but will need to be
6126        # converted to the key/value type of the backing object. In this case,
6127        # use .get() instead of direct access to the argument. This won't
6128        # matter for iterable since generated functions for those interface
6129        # don't take arguments.
6130        if member.isMethod() and member.isMaplikeOrSetlikeOrIterableMethod():
6131            self.replacementVariables["val"] = string.Template(
6132                "args.get(${index})").substitute(replacer)
6133            self.replacementVariables["maybeMutableVal"] = string.Template(
6134                "args[${index}]").substitute(replacer)
6135        else:
6136            self.replacementVariables["val"] = string.Template(
6137                "args[${index}]").substitute(replacer)
6138        haveValueCheck = string.Template(
6139            "args.hasDefined(${index})").substitute(replacer)
6140        self.replacementVariables["haveValue"] = haveValueCheck
6141        self.descriptorProvider = descriptorProvider
6142        if self.argument.canHaveMissingValue():
6143            self.argcAndIndex = replacer
6144        else:
6145            self.argcAndIndex = None
6146        self.invalidEnumValueFatal = invalidEnumValueFatal
6147        self.lenientFloatCode = lenientFloatCode
6148
6149    def define(self):
6150        typeConversion = getJSToNativeConversionInfo(
6151            self.argument.type,
6152            self.descriptorProvider,
6153            isOptional=(self.argcAndIndex is not None and
6154                        not self.argument.variadic),
6155            invalidEnumValueFatal=self.invalidEnumValueFatal,
6156            defaultValue=self.argument.defaultValue,
6157            treatNullAs=self.argument.treatNullAs,
6158            isEnforceRange=self.argument.enforceRange,
6159            isClamp=self.argument.clamp,
6160            lenientFloatCode=self.lenientFloatCode,
6161            isMember="Variadic" if self.argument.variadic else False,
6162            allowTreatNonCallableAsNull=self.argument.allowTreatNonCallableAsNull(),
6163            sourceDescription=self.argDescription)
6164
6165        if not self.argument.variadic:
6166            return instantiateJSToNativeConversion(
6167                typeConversion,
6168                self.replacementVariables,
6169                self.argcAndIndex is not None).define()
6170
6171        # Variadic arguments get turned into a sequence.
6172        if typeConversion.dealWithOptional:
6173            raise TypeError("Shouldn't have optional things in variadics")
6174        if typeConversion.holderType is not None:
6175            raise TypeError("Shouldn't need holders for variadics")
6176
6177        replacer = dict(self.argcAndIndex, **self.replacementVariables)
6178        replacer["seqType"] = CGTemplatedType("binding_detail::AutoSequence",
6179                                              typeConversion.declType).define()
6180        if typeNeedsRooting(self.argument.type):
6181            rooterDecl = ("SequenceRooter<%s> ${holderName}(cx, &${declName});\n" %
6182                          typeConversion.declType.define())
6183        else:
6184            rooterDecl = ""
6185        replacer["elemType"] = typeConversion.declType.define()
6186
6187        # NOTE: Keep this in sync with sequence conversions as needed
6188        variadicConversion = string.Template(
6189            "${seqType} ${declName};\n" +
6190            rooterDecl +
6191            dedent("""
6192                if (${argc} > ${index}) {
6193                  if (!${declName}.SetCapacity(${argc} - ${index}, mozilla::fallible)) {
6194                    JS_ReportOutOfMemory(cx);
6195                    return false;
6196                  }
6197                  for (uint32_t variadicArg = ${index}; variadicArg < ${argc}; ++variadicArg) {
6198                    ${elemType}& slot = *${declName}.AppendElement(mozilla::fallible);
6199                """)
6200        ).substitute(replacer)
6201
6202        val = string.Template("args[variadicArg]").substitute(replacer)
6203        variadicConversion += indent(
6204            string.Template(typeConversion.template).substitute({
6205                "val": val,
6206                "maybeMutableVal": val,
6207                "declName": "slot",
6208                # We only need holderName here to handle isExternal()
6209                # interfaces, which use an internal holder for the
6210                # conversion even when forceOwningType ends up true.
6211                "holderName": "tempHolder",
6212                # Use the same ${obj} as for the variadic arg itself
6213                "obj": replacer["obj"],
6214                "passedToJSImpl": toStringBool(isJSImplementedDescriptor(self.descriptorProvider))
6215            }), 4)
6216
6217        variadicConversion += ("  }\n"
6218                               "}\n")
6219        return variadicConversion
6220
6221
6222def getMaybeWrapValueFuncForType(type):
6223    # Callbacks might actually be DOM objects; nothing prevents a page from
6224    # doing that.
6225    if type.isCallback() or type.isCallbackInterface() or type.isObject():
6226        if type.nullable():
6227            return "MaybeWrapObjectOrNullValue"
6228        return "MaybeWrapObjectValue"
6229    # Spidermonkey interfaces are never DOM objects.  Neither are sequences or
6230    # dictionaries, since those are always plain JS objects.
6231    if type.isSpiderMonkeyInterface() or type.isDictionary() or type.isSequence():
6232        if type.nullable():
6233            return "MaybeWrapNonDOMObjectOrNullValue"
6234        return "MaybeWrapNonDOMObjectValue"
6235    if type.isAny():
6236        return "MaybeWrapValue"
6237
6238    # For other types, just go ahead an fall back on MaybeWrapValue for now:
6239    # it's always safe to do, and shouldn't be particularly slow for any of
6240    # them
6241    return "MaybeWrapValue"
6242
6243
6244sequenceWrapLevel = 0
6245mozMapWrapLevel = 0
6246
6247
6248def getWrapTemplateForType(type, descriptorProvider, result, successCode,
6249                           returnsNewObject, exceptionCode, typedArraysAreStructs,
6250                           isConstructorRetval=False):
6251    """
6252    Reflect a C++ value stored in "result", of IDL type "type" into JS.  The
6253    "successCode" is the code to run once we have successfully done the
6254    conversion and must guarantee that execution of the conversion template
6255    stops once the successCode has executed (e.g. by doing a 'return', or by
6256    doing a 'break' if the entire conversion template is inside a block that
6257    the 'break' will exit).
6258
6259    If typedArraysAreStructs is true, then if the type is a typed array,
6260    "result" is one of the dom::TypedArray subclasses, not a JSObject*.
6261
6262    The resulting string should be used with string.Template.  It
6263    needs the following keys when substituting:
6264
6265      jsvalHandle: something that can be passed to methods taking a
6266                   JS::MutableHandle<JS::Value>.  This can be a
6267                   JS::MutableHandle<JS::Value> or a JS::Rooted<JS::Value>*.
6268      jsvalRef: something that can have .address() called on it to get a
6269                JS::Value* and .set() called on it to set it to a JS::Value.
6270                This can be a JS::MutableHandle<JS::Value> or a
6271                JS::Rooted<JS::Value>.
6272      obj: a JS::Handle<JSObject*>.
6273
6274    Returns (templateString, infallibility of conversion template)
6275    """
6276    if successCode is None:
6277        successCode = "return true;\n"
6278
6279    def setUndefined():
6280        return _setValue("", setter="setUndefined")
6281
6282    def setNull():
6283        return _setValue("", setter="setNull")
6284
6285    def setInt32(value):
6286        return _setValue(value, setter="setInt32")
6287
6288    def setString(value):
6289        return _setValue(value, setter="setString")
6290
6291    def setObject(value, wrapAsType=None):
6292        return _setValue(value, wrapAsType=wrapAsType, setter="setObject")
6293
6294    def setObjectOrNull(value, wrapAsType=None):
6295        return _setValue(value, wrapAsType=wrapAsType, setter="setObjectOrNull")
6296
6297    def setUint32(value):
6298        return _setValue(value, setter="setNumber")
6299
6300    def setDouble(value):
6301        return _setValue("JS_NumberValue(%s)" % value)
6302
6303    def setBoolean(value):
6304        return _setValue(value, setter="setBoolean")
6305
6306    def _setValue(value, wrapAsType=None, setter="set"):
6307        """
6308        Returns the code to set the jsval to value.
6309
6310        If wrapAsType is not None, then will wrap the resulting value using the
6311        function that getMaybeWrapValueFuncForType(wrapAsType) returns.
6312        Otherwise, no wrapping will be done.
6313        """
6314        if wrapAsType is None:
6315            tail = successCode
6316        else:
6317            tail = fill(
6318                """
6319                if (!${maybeWrap}(cx, $${jsvalHandle})) {
6320                  $*{exceptionCode}
6321                }
6322                $*{successCode}
6323                """,
6324                maybeWrap=getMaybeWrapValueFuncForType(wrapAsType),
6325                exceptionCode=exceptionCode,
6326                successCode=successCode)
6327        return ("${jsvalRef}.%s(%s);\n" % (setter, value)) + tail
6328
6329    def wrapAndSetPtr(wrapCall, failureCode=None):
6330        """
6331        Returns the code to set the jsval by calling "wrapCall". "failureCode"
6332        is the code to run if calling "wrapCall" fails
6333        """
6334        if failureCode is None:
6335            failureCode = exceptionCode
6336        return fill(
6337            """
6338            if (!${wrapCall}) {
6339              $*{failureCode}
6340            }
6341            $*{successCode}
6342            """,
6343            wrapCall=wrapCall,
6344            failureCode=failureCode,
6345            successCode=successCode)
6346
6347    if type is None or type.isVoid():
6348        return (setUndefined(), True)
6349
6350    if (type.isSequence() or type.isMozMap()) and type.nullable():
6351        # These are both wrapped in Nullable<>
6352        recTemplate, recInfall = getWrapTemplateForType(type.inner, descriptorProvider,
6353                                                        "%s.Value()" % result, successCode,
6354                                                        returnsNewObject, exceptionCode,
6355                                                        typedArraysAreStructs)
6356        code = fill(
6357            """
6358
6359            if (${result}.IsNull()) {
6360              $*{setNull}
6361            }
6362            $*{recTemplate}
6363            """,
6364            result=result,
6365            setNull=setNull(),
6366            recTemplate=recTemplate)
6367        return code, recInfall
6368
6369    if type.isSequence():
6370        # Now do non-nullable sequences.  Our success code is just to break to
6371        # where we set the element in the array.  Note that we bump the
6372        # sequenceWrapLevel around this call so that nested sequence conversions
6373        # will use different iteration variables.
6374        global sequenceWrapLevel
6375        index = "sequenceIdx%d" % sequenceWrapLevel
6376        sequenceWrapLevel += 1
6377        innerTemplate = wrapForType(
6378            type.inner, descriptorProvider,
6379            {
6380                'result': "%s[%s]" % (result, index),
6381                'successCode': "break;\n",
6382                'jsvalRef': "tmp",
6383                'jsvalHandle': "&tmp",
6384                'returnsNewObject': returnsNewObject,
6385                'exceptionCode': exceptionCode,
6386                'obj': "returnArray",
6387                'typedArraysAreStructs': typedArraysAreStructs
6388            })
6389        sequenceWrapLevel -= 1
6390        code = fill(
6391            """
6392
6393            uint32_t length = ${result}.Length();
6394            JS::Rooted<JSObject*> returnArray(cx, JS_NewArrayObject(cx, length));
6395            if (!returnArray) {
6396              $*{exceptionCode}
6397            }
6398            // Scope for 'tmp'
6399            {
6400              JS::Rooted<JS::Value> tmp(cx);
6401              for (uint32_t ${index} = 0; ${index} < length; ++${index}) {
6402                // Control block to let us common up the JS_DefineElement calls when there
6403                // are different ways to succeed at wrapping the object.
6404                do {
6405                  $*{innerTemplate}
6406                } while (0);
6407                if (!JS_DefineElement(cx, returnArray, ${index}, tmp,
6408                                      JSPROP_ENUMERATE)) {
6409                  $*{exceptionCode}
6410                }
6411              }
6412            }
6413            $*{set}
6414            """,
6415            result=result,
6416            exceptionCode=exceptionCode,
6417            index=index,
6418            innerTemplate=innerTemplate,
6419            set=setObject("*returnArray"))
6420
6421        return (code, False)
6422
6423    if type.isMozMap():
6424        # Now do non-nullable MozMap.  Our success code is just to break to
6425        # where we define the property on the object.  Note that we bump the
6426        # mozMapWrapLevel around this call so that nested MozMap conversions
6427        # will use different temp value names.
6428        global mozMapWrapLevel
6429        valueName = "mozMapValue%d" % mozMapWrapLevel
6430        mozMapWrapLevel += 1
6431        innerTemplate = wrapForType(
6432            type.inner, descriptorProvider,
6433            {
6434                'result': valueName,
6435                'successCode': "break;\n",
6436                'jsvalRef': "tmp",
6437                'jsvalHandle': "&tmp",
6438                'returnsNewObject': returnsNewObject,
6439                'exceptionCode': exceptionCode,
6440                'obj': "returnObj",
6441                'typedArraysAreStructs': typedArraysAreStructs
6442            })
6443        mozMapWrapLevel -= 1
6444        code = fill(
6445            """
6446
6447            nsTArray<nsString> keys;
6448            ${result}.GetKeys(keys);
6449            JS::Rooted<JSObject*> returnObj(cx, JS_NewPlainObject(cx));
6450            if (!returnObj) {
6451              $*{exceptionCode}
6452            }
6453            // Scope for 'tmp'
6454            {
6455              JS::Rooted<JS::Value> tmp(cx);
6456              for (size_t idx = 0; idx < keys.Length(); ++idx) {
6457                auto& ${valueName} = ${result}.Get(keys[idx]);
6458                // Control block to let us common up the JS_DefineUCProperty calls when there
6459                // are different ways to succeed at wrapping the value.
6460                do {
6461                  $*{innerTemplate}
6462                } while (0);
6463                if (!JS_DefineUCProperty(cx, returnObj, keys[idx].get(),
6464                                         keys[idx].Length(), tmp,
6465                                         JSPROP_ENUMERATE)) {
6466                  $*{exceptionCode}
6467                }
6468              }
6469            }
6470            $*{set}
6471            """,
6472            result=result,
6473            exceptionCode=exceptionCode,
6474            valueName=valueName,
6475            innerTemplate=innerTemplate,
6476            set=setObject("*returnObj"))
6477
6478        return (code, False)
6479
6480    if type.isGeckoInterface() and not type.isCallbackInterface():
6481        descriptor = descriptorProvider.getDescriptor(type.unroll().inner.identifier.name)
6482        if type.nullable():
6483            wrappingCode = ("if (!%s) {\n" % (result) +
6484                            indent(setNull()) +
6485                            "}\n")
6486        else:
6487            wrappingCode = ""
6488
6489        if not descriptor.interface.isExternal():
6490            if descriptor.wrapperCache:
6491                wrapMethod = "GetOrCreateDOMReflector"
6492                wrapArgs = "cx, %s, ${jsvalHandle}" % result
6493            else:
6494                # Hack: the "Promise" interface is OK to return from
6495                # non-newobject things even when it's not wrappercached; that
6496                # happens when using SpiderMonkey promises, and the WrapObject()
6497                # method will just return the existing reflector, which is just
6498                # not stored in a wrappercache.
6499                if (not returnsNewObject and
6500                    descriptor.interface.identifier.name != "Promise"):
6501                    raise MethodNotNewObjectError(descriptor.interface.identifier.name)
6502                wrapMethod = "WrapNewBindingNonWrapperCachedObject"
6503                wrapArgs = "cx, ${obj}, %s, ${jsvalHandle}" % result
6504            if isConstructorRetval:
6505                wrapArgs += ", desiredProto"
6506            wrap = "%s(%s)" % (wrapMethod, wrapArgs)
6507            if not descriptor.hasXPConnectImpls:
6508                # Can only fail to wrap as a new-binding object
6509                # if they already threw an exception.
6510                # XXX Assertion disabled for now, see bug 991271.
6511                failed = ("MOZ_ASSERT(true || JS_IsExceptionPending(cx));\n" +
6512                          exceptionCode)
6513            else:
6514                if descriptor.notflattened:
6515                    raise TypeError("%s has XPConnect impls but not flattened; "
6516                                    "fallback won't work correctly" %
6517                                    descriptor.interface.identifier.name)
6518                # Try old-style wrapping for bindings which might be XPConnect impls.
6519                failed = wrapAndSetPtr("HandleNewBindingWrappingFailure(cx, ${obj}, %s, ${jsvalHandle})" % result)
6520        else:
6521            if descriptor.notflattened:
6522                getIID = "&NS_GET_IID(%s), " % descriptor.nativeType
6523            else:
6524                getIID = ""
6525            wrap = "WrapObject(cx, %s, %s${jsvalHandle})" % (result, getIID)
6526            failed = None
6527
6528        wrappingCode += wrapAndSetPtr(wrap, failed)
6529        return (wrappingCode, False)
6530
6531    if type.isDOMString() or type.isUSVString():
6532        if type.nullable():
6533            return (wrapAndSetPtr("xpc::StringToJsval(cx, %s, ${jsvalHandle})" % result), False)
6534        else:
6535            return (wrapAndSetPtr("xpc::NonVoidStringToJsval(cx, %s, ${jsvalHandle})" % result), False)
6536
6537    if type.isByteString():
6538        if type.nullable():
6539            return (wrapAndSetPtr("ByteStringToJsval(cx, %s, ${jsvalHandle})" % result), False)
6540        else:
6541            return (wrapAndSetPtr("NonVoidByteStringToJsval(cx, %s, ${jsvalHandle})" % result), False)
6542
6543    if type.isEnum():
6544        if type.nullable():
6545            resultLoc = "%s.Value()" % result
6546        else:
6547            resultLoc = result
6548        conversion = fill(
6549            """
6550            if (!ToJSValue(cx, ${result}, $${jsvalHandle})) {
6551              $*{exceptionCode}
6552            }
6553            $*{successCode}
6554            """,
6555            result=resultLoc,
6556            exceptionCode=exceptionCode,
6557            successCode=successCode)
6558
6559        if type.nullable():
6560            conversion = CGIfElseWrapper(
6561                "%s.IsNull()" % result,
6562                CGGeneric(setNull()),
6563                CGGeneric(conversion)).define()
6564        return conversion, False
6565
6566    if type.isCallback() or type.isCallbackInterface():
6567        wrapCode = setObject(
6568            "*GetCallbackFromCallbackObject(%(result)s)",
6569            wrapAsType=type)
6570        if type.nullable():
6571            wrapCode = (
6572                "if (%(result)s) {\n" +
6573                indent(wrapCode) +
6574                "} else {\n" +
6575                indent(setNull()) +
6576                "}\n")
6577        wrapCode = wrapCode % {"result": result}
6578        return wrapCode, False
6579
6580    if type.isAny():
6581        # See comments in GetOrCreateDOMReflector explaining why we need
6582        # to wrap here.
6583        # NB: _setValue(..., type-that-is-any) calls JS_WrapValue(), so is fallible
6584        head = "JS::ExposeValueToActiveJS(%s);\n" % result
6585        return (head + _setValue(result, wrapAsType=type), False)
6586
6587    if (type.isObject() or (type.isSpiderMonkeyInterface() and
6588                            not typedArraysAreStructs)):
6589        # See comments in GetOrCreateDOMReflector explaining why we need
6590        # to wrap here.
6591        if type.nullable():
6592            toValue = "%s"
6593            setter = setObjectOrNull
6594            head = """if (%s) {
6595              JS::ExposeObjectToActiveJS(%s);
6596            }
6597            """ % (result, result)
6598        else:
6599            toValue = "*%s"
6600            setter = setObject
6601            head = "JS::ExposeObjectToActiveJS(%s);\n" % result
6602        # NB: setObject{,OrNull}(..., some-object-type) calls JS_WrapValue(), so is fallible
6603        return (head + setter(toValue % result, wrapAsType=type), False)
6604
6605    if not (type.isUnion() or type.isPrimitive() or type.isDictionary() or
6606            type.isDate() or
6607            (type.isSpiderMonkeyInterface() and typedArraysAreStructs)):
6608        raise TypeError("Need to learn to wrap %s" % type)
6609
6610    if type.nullable():
6611        recTemplate, recInfal = getWrapTemplateForType(type.inner, descriptorProvider,
6612                                                       "%s.Value()" % result, successCode,
6613                                                       returnsNewObject, exceptionCode,
6614                                                       typedArraysAreStructs)
6615        return ("if (%s.IsNull()) {\n" % result +
6616                indent(setNull()) +
6617                "}\n" +
6618                recTemplate, recInfal)
6619
6620    if type.isSpiderMonkeyInterface():
6621        assert typedArraysAreStructs
6622        # See comments in GetOrCreateDOMReflector explaining why we need
6623        # to wrap here.
6624        # NB: setObject(..., some-object-type) calls JS_WrapValue(), so is fallible
6625        return (setObject("*%s.Obj()" % result,
6626                          wrapAsType=type), False)
6627
6628    if type.isUnion():
6629        return (wrapAndSetPtr("%s.ToJSVal(cx, ${obj}, ${jsvalHandle})" % result),
6630                False)
6631
6632    if type.isDictionary():
6633        return (wrapAndSetPtr("%s.ToObjectInternal(cx, ${jsvalHandle})" % result),
6634                False)
6635
6636    if type.isDate():
6637        return (wrapAndSetPtr("%s.ToDateObject(cx, ${jsvalHandle})" % result),
6638                False)
6639
6640    tag = type.tag()
6641
6642    if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16,
6643               IDLType.Tags.uint16, IDLType.Tags.int32]:
6644        return (setInt32("int32_t(%s)" % result), True)
6645
6646    elif tag in [IDLType.Tags.int64, IDLType.Tags.uint64,
6647                 IDLType.Tags.unrestricted_float, IDLType.Tags.float,
6648                 IDLType.Tags.unrestricted_double, IDLType.Tags.double]:
6649        # XXXbz will cast to double do the "even significand" thing that webidl
6650        # calls for for 64-bit ints?  Do we care?
6651        return (setDouble("double(%s)" % result), True)
6652
6653    elif tag == IDLType.Tags.uint32:
6654        return (setUint32(result), True)
6655
6656    elif tag == IDLType.Tags.bool:
6657        return (setBoolean(result), True)
6658
6659    else:
6660        raise TypeError("Need to learn to wrap primitive: %s" % type)
6661
6662
6663def wrapForType(type, descriptorProvider, templateValues):
6664    """
6665    Reflect a C++ value of IDL type "type" into JS.  TemplateValues is a dict
6666    that should contain:
6667
6668      * 'jsvalRef': something that can have .address() called on it to get a
6669                    JS::Value* and .set() called on it to set it to a JS::Value.
6670                    This can be a JS::MutableHandle<JS::Value> or a
6671                    JS::Rooted<JS::Value>.
6672      * 'jsvalHandle': something that can be passed to methods taking a
6673                       JS::MutableHandle<JS::Value>.  This can be a
6674                       JS::MutableHandle<JS::Value> or a JS::Rooted<JS::Value>*.
6675      * 'obj' (optional): the name of the variable that contains the JSObject to
6676                          use as a scope when wrapping, if not supplied 'obj'
6677                          will be used as the name
6678      * 'result' (optional): the name of the variable in which the C++ value is
6679                             stored, if not supplied 'result' will be used as
6680                             the name
6681      * 'successCode' (optional): the code to run once we have successfully
6682                                  done the conversion, if not supplied 'return
6683                                  true;' will be used as the code.  The
6684                                  successCode must ensure that once it runs no
6685                                  more of the conversion template will be
6686                                  executed (e.g. by doing a 'return' or 'break'
6687                                  as appropriate).
6688      * 'returnsNewObject' (optional): If true, we're wrapping for the return
6689                                       value of a [NewObject] method.  Assumed
6690                                       false if not set.
6691      * 'exceptionCode' (optional): Code to run when a JS exception is thrown.
6692                                    The default is "return false;".  The code
6693                                    passed here must return.
6694      * 'isConstructorRetval' (optional): If true, we're wrapping a constructor
6695                                          return value.
6696    """
6697    wrap = getWrapTemplateForType(
6698        type, descriptorProvider,
6699        templateValues.get('result', 'result'),
6700        templateValues.get('successCode', None),
6701        templateValues.get('returnsNewObject', False),
6702        templateValues.get('exceptionCode', "return false;\n"),
6703        templateValues.get('typedArraysAreStructs', False),
6704        isConstructorRetval=templateValues.get('isConstructorRetval', False))[0]
6705
6706    defaultValues = {'obj': 'obj'}
6707    return string.Template(wrap).substitute(defaultValues, **templateValues)
6708
6709
6710def infallibleForMember(member, type, descriptorProvider):
6711    """
6712    Determine the fallibility of changing a C++ value of IDL type "type" into
6713    JS for the given attribute. Apart from returnsNewObject, all the defaults
6714    are used, since the fallbility does not change based on the boolean values,
6715    and the template will be discarded.
6716
6717    CURRENT ASSUMPTIONS:
6718        We assume that successCode for wrapping up return values cannot contain
6719        failure conditions.
6720    """
6721    return getWrapTemplateForType(type, descriptorProvider, 'result', None,
6722                                  memberReturnsNewObject(member), "return false;\n",
6723                                  False)[1]
6724
6725
6726def leafTypeNeedsCx(type, retVal):
6727    return (type.isAny() or type.isObject() or
6728            (retVal and type.isSpiderMonkeyInterface()))
6729
6730
6731def leafTypeNeedsScopeObject(type, retVal):
6732    return retVal and type.isSpiderMonkeyInterface()
6733
6734
6735def leafTypeNeedsRooting(type):
6736    return leafTypeNeedsCx(type, False) or type.isSpiderMonkeyInterface()
6737
6738
6739def typeNeedsRooting(type):
6740    return typeMatchesLambda(type,
6741                             lambda t: leafTypeNeedsRooting(t))
6742
6743
6744def typeNeedsCx(type, retVal=False):
6745    return typeMatchesLambda(type,
6746                             lambda t: leafTypeNeedsCx(t, retVal))
6747
6748
6749def typeNeedsScopeObject(type, retVal=False):
6750    return typeMatchesLambda(type,
6751                             lambda t: leafTypeNeedsScopeObject(t, retVal))
6752
6753
6754def typeMatchesLambda(type, func):
6755    if type is None:
6756        return False
6757    if type.nullable():
6758        return typeMatchesLambda(type.inner, func)
6759    if type.isSequence() or type.isMozMap():
6760        return typeMatchesLambda(type.inner, func)
6761    if type.isUnion():
6762        return any(typeMatchesLambda(t, func) for t in
6763                   type.unroll().flatMemberTypes)
6764    if type.isDictionary():
6765        return dictionaryMatchesLambda(type.inner, func)
6766    return func(type)
6767
6768
6769def dictionaryMatchesLambda(dictionary, func):
6770    return (any(typeMatchesLambda(m.type, func) for m in dictionary.members) or
6771            (dictionary.parent and dictionaryMatchesLambda(dictionary.parent, func)))
6772
6773
6774# Whenever this is modified, please update CGNativeMember.getRetvalInfo as
6775# needed to keep the types compatible.
6776def getRetvalDeclarationForType(returnType, descriptorProvider,
6777                                isMember=False):
6778    """
6779    Returns a tuple containing five things:
6780
6781    1) A CGThing for the type of the return value, or None if there is no need
6782       for a return value.
6783
6784    2) A value indicating the kind of ourparam to pass the value as.  Valid
6785       options are None to not pass as an out param at all, "ref" (to pass a
6786       reference as an out param), and "ptr" (to pass a pointer as an out
6787       param).
6788
6789    3) A CGThing for a tracer for the return value, or None if no tracing is
6790       needed.
6791
6792    4) An argument string to pass to the retval declaration
6793       constructor or None if there are no arguments.
6794
6795    5) The name of a function that needs to be called with the return value
6796       before using it, or None if no function needs to be called.
6797    """
6798    if returnType is None or returnType.isVoid():
6799        # Nothing to declare
6800        return None, None, None, None, None
6801    if returnType.isPrimitive() and returnType.tag() in builtinNames:
6802        result = CGGeneric(builtinNames[returnType.tag()])
6803        if returnType.nullable():
6804            result = CGTemplatedType("Nullable", result)
6805        return result, None, None, None, None
6806    if returnType.isDOMString() or returnType.isUSVString():
6807        if isMember:
6808            return CGGeneric("nsString"), "ref", None, None, None
6809        return CGGeneric("DOMString"), "ref", None, None, None
6810    if returnType.isByteString():
6811        return CGGeneric("nsCString"), "ref", None, None, None
6812    if returnType.isEnum():
6813        result = CGGeneric(returnType.unroll().inner.identifier.name)
6814        if returnType.nullable():
6815            result = CGTemplatedType("Nullable", result)
6816        return result, None, None, None, None
6817    if returnType.isGeckoInterface():
6818        result = CGGeneric(descriptorProvider.getDescriptor(
6819            returnType.unroll().inner.identifier.name).nativeType)
6820        conversion = None
6821        if isMember:
6822            result = CGGeneric("StrongPtrForMember<%s>::Type" % result.define())
6823        else:
6824            conversion = CGGeneric("StrongOrRawPtr<%s>" % result.define())
6825            result = CGGeneric("auto")
6826        return result, None, None, None, conversion
6827    if returnType.isCallback():
6828        name = returnType.unroll().callback.identifier.name
6829        return CGGeneric("RefPtr<%s>" % name), None, None, None, None
6830    if returnType.isAny():
6831        if isMember:
6832            return CGGeneric("JS::Value"), None, None, None, None
6833        return CGGeneric("JS::Rooted<JS::Value>"), "ptr", None, "cx", None
6834    if returnType.isObject() or returnType.isSpiderMonkeyInterface():
6835        if isMember:
6836            return CGGeneric("JSObject*"), None, None, None, None
6837        return CGGeneric("JS::Rooted<JSObject*>"), "ptr", None, "cx", None
6838    if returnType.isSequence():
6839        nullable = returnType.nullable()
6840        if nullable:
6841            returnType = returnType.inner
6842        result, _, _, _, _ = getRetvalDeclarationForType(returnType.inner,
6843                                                         descriptorProvider,
6844                                                         isMember="Sequence")
6845        # While we have our inner type, set up our rooter, if needed
6846        if not isMember and typeNeedsRooting(returnType):
6847            rooter = CGGeneric("SequenceRooter<%s > resultRooter(cx, &result);\n" %
6848                               result.define())
6849        else:
6850            rooter = None
6851        result = CGTemplatedType("nsTArray", result)
6852        if nullable:
6853            result = CGTemplatedType("Nullable", result)
6854        return result, "ref", rooter, None, None
6855    if returnType.isMozMap():
6856        nullable = returnType.nullable()
6857        if nullable:
6858            returnType = returnType.inner
6859        result, _, _, _, _ = getRetvalDeclarationForType(returnType.inner,
6860                                                         descriptorProvider,
6861                                                         isMember="MozMap")
6862        # While we have our inner type, set up our rooter, if needed
6863        if not isMember and typeNeedsRooting(returnType):
6864            rooter = CGGeneric("MozMapRooter<%s> resultRooter(cx, &result);\n" %
6865                               result.define())
6866        else:
6867            rooter = None
6868        result = CGTemplatedType("MozMap", result)
6869        if nullable:
6870            result = CGTemplatedType("Nullable", result)
6871        return result, "ref", rooter, None, None
6872    if returnType.isDictionary():
6873        nullable = returnType.nullable()
6874        dictName = CGDictionary.makeDictionaryName(returnType.unroll().inner)
6875        result = CGGeneric(dictName)
6876        if not isMember and typeNeedsRooting(returnType):
6877            if nullable:
6878                result = CGTemplatedType("NullableRootedDictionary", result)
6879            else:
6880                result = CGTemplatedType("RootedDictionary", result)
6881            resultArgs = "cx"
6882        else:
6883            if nullable:
6884                result = CGTemplatedType("Nullable", result)
6885            resultArgs = None
6886        return result, "ref", None, resultArgs, None
6887    if returnType.isUnion():
6888        result = CGGeneric(CGUnionStruct.unionTypeName(returnType.unroll(), True))
6889        if not isMember and typeNeedsRooting(returnType):
6890            if returnType.nullable():
6891                result = CGTemplatedType("NullableRootedUnion", result)
6892            else:
6893                result = CGTemplatedType("RootedUnion", result)
6894            resultArgs = "cx"
6895        else:
6896            if returnType.nullable():
6897                result = CGTemplatedType("Nullable", result)
6898            resultArgs = None
6899        return result, "ref", None, resultArgs, None
6900    if returnType.isDate():
6901        result = CGGeneric("Date")
6902        if returnType.nullable():
6903            result = CGTemplatedType("Nullable", result)
6904        return result, None, None, None, None
6905    raise TypeError("Don't know how to declare return value for %s" %
6906                    returnType)
6907
6908
6909def needCx(returnType, arguments, extendedAttributes, considerTypes,
6910           static=False):
6911    return (not static and considerTypes and
6912            (typeNeedsCx(returnType, True) or
6913             any(typeNeedsCx(a.type) for a in arguments)) or
6914            'implicitJSContext' in extendedAttributes)
6915
6916
6917def needScopeObject(returnType, arguments, extendedAttributes,
6918                    isWrapperCached, considerTypes, isMember):
6919    """
6920    isMember should be true if we're dealing with an attribute
6921    annotated as [StoreInSlot].
6922    """
6923    return (considerTypes and not isWrapperCached and
6924            ((not isMember and typeNeedsScopeObject(returnType, True)) or
6925             any(typeNeedsScopeObject(a.type) for a in arguments)))
6926
6927
6928class CGCallGenerator(CGThing):
6929    """
6930    A class to generate an actual call to a C++ object.  Assumes that the C++
6931    object is stored in a variable whose name is given by the |object| argument.
6932
6933    needsSubjectPrincipal is a boolean indicating whether the call should
6934    receive the subject nsIPrincipal as argument.
6935
6936    needsCallerType is a boolean indicating whether the call should receive
6937    a PrincipalType for the caller.
6938
6939    isFallible is a boolean indicating whether the call should be fallible.
6940
6941    resultVar: If the returnType is not void, then the result of the call is
6942    stored in a C++ variable named by resultVar. The caller is responsible for
6943    declaring the result variable. If the caller doesn't care about the result
6944    value, resultVar can be omitted.
6945    """
6946    def __init__(self, isFallible, needsSubjectPrincipal, needsCallerType,
6947                 arguments, argsPre, returnType, extendedAttributes, descriptor,
6948                 nativeMethodName, static, object="self", argsPost=[],
6949                 resultVar=None):
6950        CGThing.__init__(self)
6951
6952        result, resultOutParam, resultRooter, resultArgs, resultConversion = \
6953            getRetvalDeclarationForType(returnType, descriptor)
6954
6955        args = CGList([CGGeneric(arg) for arg in argsPre], ", ")
6956        for a, name in arguments:
6957            arg = CGGeneric(name)
6958
6959            # Now constify the things that need it
6960            def needsConst(a):
6961                if a.type.isDictionary():
6962                    return True
6963                if a.type.isSequence():
6964                    return True
6965                if a.type.isMozMap():
6966                    return True
6967                # isObject() types are always a JS::Rooted, whether
6968                # nullable or not, and it turns out a const JS::Rooted
6969                # is not very helpful at all (in particular, it won't
6970                # even convert to a JS::Handle).
6971                # XXX bz Well, why not???
6972                if a.type.nullable() and not a.type.isObject():
6973                    return True
6974                if a.type.isString():
6975                    return True
6976                if a.canHaveMissingValue():
6977                    # This will need an Optional or it's a variadic;
6978                    # in both cases it should be const.
6979                    return True
6980                if a.type.isUnion():
6981                    return True
6982                if a.type.isSpiderMonkeyInterface():
6983                    return True
6984                return False
6985            if needsConst(a):
6986                arg = CGWrapper(arg, pre="Constify(", post=")")
6987            # And convert NonNull<T> to T&
6988            if (((a.type.isGeckoInterface() or a.type.isCallback()) and not a.type.nullable()) or
6989                a.type.isDOMString()):
6990                arg = CGWrapper(arg, pre="NonNullHelper(", post=")")
6991            args.append(arg)
6992
6993        needResultDecl = False
6994
6995        # Return values that go in outparams go here
6996        if resultOutParam is not None:
6997            if resultVar is None:
6998                needResultDecl = True
6999                resultVar = "result"
7000            if resultOutParam == "ref":
7001                args.append(CGGeneric(resultVar))
7002            else:
7003                assert resultOutParam == "ptr"
7004                args.append(CGGeneric("&" + resultVar))
7005
7006        if needsSubjectPrincipal:
7007            args.append(CGGeneric("subjectPrincipal"))
7008
7009        if needsCallerType:
7010            args.append(CGGeneric("callerType"))
7011
7012        if isFallible:
7013            args.append(CGGeneric("rv"))
7014        args.extend(CGGeneric(arg) for arg in argsPost)
7015
7016        # Build up our actual call
7017        self.cgRoot = CGList([])
7018
7019        call = CGGeneric(nativeMethodName)
7020        if not static:
7021            call = CGWrapper(call, pre="%s->" % object)
7022        call = CGList([call, CGWrapper(args, pre="(", post=")")])
7023        if resultConversion is not None:
7024            call = CGList([resultConversion, CGWrapper(call, pre="(", post=")")])
7025        if resultVar is None and result is not None:
7026            needResultDecl = True
7027            resultVar = "result"
7028
7029        if needResultDecl:
7030            if resultRooter is not None:
7031                self.cgRoot.prepend(resultRooter)
7032            if resultArgs is not None:
7033                resultArgsStr = "(%s)" % resultArgs
7034            else:
7035                resultArgsStr = ""
7036            result = CGWrapper(result, post=(" %s%s" % (resultVar, resultArgsStr)))
7037            if resultOutParam is None and resultArgs is None:
7038                call = CGList([result, CGWrapper(call, pre="(", post=")")])
7039            else:
7040                self.cgRoot.prepend(CGWrapper(result, post=";\n"))
7041                if resultOutParam is None:
7042                    call = CGWrapper(call, pre=resultVar + " = ")
7043        elif result is not None:
7044            assert resultOutParam is None
7045            call = CGWrapper(call, pre=resultVar + " = ")
7046
7047        call = CGWrapper(call, post=";\n")
7048        self.cgRoot.append(call)
7049
7050        if needsSubjectPrincipal:
7051            getPrincipal = dedent(
7052                """
7053                JSCompartment* compartment = js::GetContextCompartment(cx);
7054                MOZ_ASSERT(compartment);
7055                JSPrincipals* principals = JS_GetCompartmentPrincipals(compartment);
7056                """)
7057
7058            if descriptor.interface.isExposedInAnyWorker():
7059                self.cgRoot.prepend(CGGeneric(fill(
7060                    """
7061                    Maybe<nsIPrincipal*> subjectPrincipal;
7062                    if (NS_IsMainThread()) {
7063                      $*{getPrincipal}
7064                      subjectPrincipal.emplace(nsJSPrincipals::get(principals));
7065                    }
7066                    """,
7067                    getPrincipal=getPrincipal)))
7068            else:
7069                self.cgRoot.prepend(CGGeneric(fill(
7070                    """
7071                    $*{getPrincipal}
7072                    // Initializing a nonnull is pretty darn annoying...
7073                    NonNull<nsIPrincipal> subjectPrincipal;
7074                    subjectPrincipal = static_cast<nsIPrincipal*>(nsJSPrincipals::get(principals));
7075                    """,
7076                    getPrincipal=getPrincipal)))
7077
7078        if needsCallerType:
7079            # Note that we do not want to use
7080            # IsCallerChrome/ThreadsafeIsCallerChrome directly because those
7081            # will pull in the check for UniversalXPConnect, which we ideally
7082            # don't want to have in the new thing we're doing here.  If not
7083            # NS_IsMainThread(), though, we'll go ahead and call
7084            # ThreasafeIsCallerChrome(), since that won't mess with
7085            # UnivesalXPConnect and we don't want to worry about the right
7086            # worker includes here.
7087            callerCheck = CGGeneric("callerType = nsContentUtils::IsSystemPrincipal(nsContentUtils::SubjectPrincipal()) ? CallerType::System : CallerType::NonSystem;\n")
7088            if descriptor.interface.isExposedInAnyWorker():
7089                callerCheck = CGIfElseWrapper(
7090                    "NS_IsMainThread()",
7091                    callerCheck,
7092                    CGGeneric("callerType = nsContentUtils::ThreadsafeIsCallerChrome() ? CallerType::System : CallerType::NonSystem;\n"));
7093            self.cgRoot.prepend(callerCheck)
7094            self.cgRoot.prepend(CGGeneric("CallerType callerType;\n"))
7095
7096        if isFallible:
7097            self.cgRoot.prepend(CGGeneric("binding_detail::FastErrorResult rv;\n"))
7098            self.cgRoot.append(CGGeneric(dedent(
7099                """
7100                if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx))) {
7101                  return false;
7102                }
7103                """)))
7104
7105        self.cgRoot.append(CGGeneric("MOZ_ASSERT(!JS_IsExceptionPending(cx));\n"))
7106
7107    def define(self):
7108        return self.cgRoot.define()
7109
7110
7111def getUnionMemberName(type):
7112    if type.isGeckoInterface():
7113        return type.inner.identifier.name
7114    if type.isEnum():
7115        return type.inner.identifier.name
7116    return type.name
7117
7118
7119class MethodNotNewObjectError(Exception):
7120    def __init__(self, typename):
7121        self.typename = typename
7122
7123# A counter for making sure that when we're wrapping up things in
7124# nested sequences we don't use the same variable name to iterate over
7125# different sequences.
7126sequenceWrapLevel = 0
7127mapWrapLevel = 0
7128
7129
7130def wrapTypeIntoCurrentCompartment(type, value, isMember=True):
7131    """
7132    Take the thing named by "value" and if it contains "any",
7133    "object", or spidermonkey-interface types inside return a CGThing
7134    that will wrap them into the current compartment.
7135    """
7136    if type.isAny():
7137        assert not type.nullable()
7138        if isMember:
7139            value = "JS::MutableHandle<JS::Value>::fromMarkedLocation(&%s)" % value
7140        else:
7141            value = "&" + value
7142        return CGGeneric("if (!JS_WrapValue(cx, %s)) {\n"
7143                         "  return false;\n"
7144                         "}\n" % value)
7145
7146    if type.isObject():
7147        if isMember:
7148            value = "JS::MutableHandle<JSObject*>::fromMarkedLocation(&%s)" % value
7149        else:
7150            value = "&" + value
7151        return CGGeneric("if (!JS_WrapObject(cx, %s)) {\n"
7152                         "  return false;\n"
7153                         "}\n" % value)
7154
7155    if type.isSpiderMonkeyInterface():
7156        origValue = value
7157        if type.nullable():
7158            value = "%s.Value()" % value
7159        wrapCode = CGGeneric("if (!%s.WrapIntoNewCompartment(cx)) {\n"
7160                             "  return false;\n"
7161                             "}\n" % value)
7162        if type.nullable():
7163            wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % origValue)
7164        return wrapCode
7165
7166    if type.isSequence():
7167        origValue = value
7168        origType = type
7169        if type.nullable():
7170            type = type.inner
7171            value = "%s.Value()" % value
7172        global sequenceWrapLevel
7173        index = "indexName%d" % sequenceWrapLevel
7174        sequenceWrapLevel += 1
7175        wrapElement = wrapTypeIntoCurrentCompartment(type.inner,
7176                                                     "%s[%s]" % (value, index))
7177        sequenceWrapLevel -= 1
7178        if not wrapElement:
7179            return None
7180        wrapCode = CGWrapper(CGIndenter(wrapElement),
7181                             pre=("for (uint32_t %s = 0; %s < %s.Length(); ++%s) {\n" %
7182                                  (index, index, value, index)),
7183                             post="}\n")
7184        if origType.nullable():
7185            wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % origValue)
7186        return wrapCode
7187
7188    if type.isMozMap():
7189        origValue = value
7190        origType = type
7191        if type.nullable():
7192            type = type.inner
7193            value = "%s.Value()" % value
7194        global mapWrapLevel
7195        key = "mapName%d" % mapWrapLevel
7196        mapWrapLevel += 1
7197        wrapElement = wrapTypeIntoCurrentCompartment(type.inner,
7198                                                     "%s.Get(%sKeys[%sIndex])" % (value, key, key))
7199        mapWrapLevel -= 1
7200        if not wrapElement:
7201            return None
7202        wrapCode = CGWrapper(CGIndenter(wrapElement),
7203                             pre=("""
7204                                  nsTArray<nsString> %sKeys;
7205                                  %s.GetKeys(%sKeys);
7206                                  for (uint32_t %sIndex = 0; %sIndex < %sKeys.Length(); ++%sIndex) {
7207                                  """ % (key, value, key, key, key, key, key)),
7208                             post="}\n")
7209        if origType.nullable():
7210            wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % origValue)
7211        return wrapCode
7212
7213    if type.isDictionary():
7214        assert not type.nullable()
7215        myDict = type.inner
7216        memberWraps = []
7217        while myDict:
7218            for member in myDict.members:
7219                memberWrap = wrapArgIntoCurrentCompartment(
7220                    member,
7221                    "%s.%s" % (value, CGDictionary.makeMemberName(member.identifier.name)))
7222                if memberWrap:
7223                    memberWraps.append(memberWrap)
7224            myDict = myDict.parent
7225        return CGList(memberWraps) if len(memberWraps) != 0 else None
7226
7227    if type.isUnion():
7228        memberWraps = []
7229        if type.nullable():
7230            type = type.inner
7231            value = "%s.Value()" % value
7232        for member in type.flatMemberTypes:
7233            memberName = getUnionMemberName(member)
7234            memberWrap = wrapTypeIntoCurrentCompartment(
7235                member, "%s.GetAs%s()" % (value, memberName))
7236            if memberWrap:
7237                memberWrap = CGIfWrapper(
7238                    memberWrap, "%s.Is%s()" % (value, memberName))
7239                memberWraps.append(memberWrap)
7240        return CGList(memberWraps, "else ") if len(memberWraps) != 0 else None
7241
7242    if (type.isString() or type.isPrimitive() or type.isEnum() or
7243        type.isGeckoInterface() or type.isCallback() or type.isDate()):
7244        # All of these don't need wrapping
7245        return None
7246
7247    raise TypeError("Unknown type; we don't know how to wrap it in constructor "
7248                    "arguments: %s" % type)
7249
7250
7251def wrapArgIntoCurrentCompartment(arg, value, isMember=True):
7252    """
7253    As wrapTypeIntoCurrentCompartment but handles things being optional
7254    """
7255    origValue = value
7256    isOptional = arg.canHaveMissingValue()
7257    if isOptional:
7258        value = value + ".Value()"
7259    wrap = wrapTypeIntoCurrentCompartment(arg.type, value, isMember)
7260    if wrap and isOptional:
7261        wrap = CGIfWrapper(wrap, "%s.WasPassed()" % origValue)
7262    return wrap
7263
7264
7265def needsContainsHack(m):
7266    return m.getExtendedAttribute("ReturnValueNeedsContainsHack")
7267
7268def needsCallerType(m):
7269    return m.getExtendedAttribute("NeedsCallerType")
7270
7271class CGPerSignatureCall(CGThing):
7272    """
7273    This class handles the guts of generating code for a particular
7274    call signature.  A call signature consists of four things:
7275
7276    1) A return type, which can be None to indicate that there is no
7277       actual return value (e.g. this is an attribute setter) or an
7278       IDLType if there's an IDL type involved (including |void|).
7279    2) An argument list, which is allowed to be empty.
7280    3) A name of a native method to call.
7281    4) Whether or not this method is static. Note that this only controls how
7282       the method is called (|self->nativeMethodName(...)| vs
7283       |nativeMethodName(...)|).
7284
7285    We also need to know whether this is a method or a getter/setter
7286    to do error reporting correctly.
7287
7288    The idlNode parameter can be either a method or an attr. We can query
7289    |idlNode.identifier| in both cases, so we can be agnostic between the two.
7290    """
7291    # XXXbz For now each entry in the argument list is either an
7292    # IDLArgument or a FakeArgument, but longer-term we may want to
7293    # have ways of flagging things like JSContext* or optional_argc in
7294    # there.
7295
7296    def __init__(self, returnType, arguments, nativeMethodName, static,
7297                 descriptor, idlNode, argConversionStartsAt=0, getter=False,
7298                 setter=False, isConstructor=False, useCounterName=None,
7299                 resultVar=None):
7300        assert idlNode.isMethod() == (not getter and not setter)
7301        assert idlNode.isAttr() == (getter or setter)
7302        # Constructors are always static
7303        assert not isConstructor or static
7304
7305        CGThing.__init__(self)
7306        self.returnType = returnType
7307        self.descriptor = descriptor
7308        self.idlNode = idlNode
7309        self.extendedAttributes = descriptor.getExtendedAttributes(idlNode,
7310                                                                   getter=getter,
7311                                                                   setter=setter)
7312        self.arguments = arguments
7313        self.argCount = len(arguments)
7314        self.isConstructor = isConstructor
7315        cgThings = []
7316
7317        # Here, we check if the current getter, setter, method, interface or
7318        # inherited interfaces have the UnsafeInPrerendering extended attribute
7319        # and if so, we add a check to make sure it is safe.
7320        if (idlNode.getExtendedAttribute("UnsafeInPrerendering") or
7321            descriptor.interface.getExtendedAttribute("UnsafeInPrerendering") or
7322            any(i.getExtendedAttribute("UnsafeInPrerendering")
7323                for i in descriptor.interface.getInheritedInterfaces())):
7324                cgThings.append(CGGeneric(dedent(
7325                    """
7326                    if (!mozilla::dom::EnforceNotInPrerendering(cx, obj)) {
7327                        // Return false from the JSNative in order to trigger
7328                        // an uncatchable exception.
7329                        MOZ_ASSERT(!JS_IsExceptionPending(cx));
7330                        return false;
7331                    }
7332                    """)))
7333
7334        deprecated = (idlNode.getExtendedAttribute("Deprecated") or
7335                      (idlNode.isStatic() and descriptor.interface.getExtendedAttribute("Deprecated")))
7336        if deprecated:
7337            cgThings.append(CGGeneric(dedent(
7338                """
7339                DeprecationWarning(cx, obj, nsIDocument::e%s);
7340                """ % deprecated[0])))
7341
7342        lenientFloatCode = None
7343        if (idlNode.getExtendedAttribute('LenientFloat') is not None and
7344            (setter or idlNode.isMethod())):
7345            cgThings.append(CGGeneric(dedent(
7346                """
7347                bool foundNonFiniteFloat = false;
7348                """)))
7349            lenientFloatCode = "foundNonFiniteFloat = true;\n"
7350
7351        argsPre = []
7352        if idlNode.isStatic():
7353            # If we're a constructor, "obj" may not be a function, so calling
7354            # XrayAwareCalleeGlobal() on it is not safe.  Of course in the
7355            # constructor case either "obj" is an Xray or we're already in the
7356            # content compartment, not the Xray compartment, so just
7357            # constructing the GlobalObject from "obj" is fine.
7358            if isConstructor:
7359                objForGlobalObject = "obj"
7360            else:
7361                objForGlobalObject = "xpc::XrayAwareCalleeGlobal(obj)"
7362            cgThings.append(CGGeneric(fill(
7363                """
7364                GlobalObject global(cx, ${obj});
7365                if (global.Failed()) {
7366                  return false;
7367                }
7368
7369                """,
7370                obj=objForGlobalObject)))
7371            argsPre.append("global")
7372
7373        # For JS-implemented interfaces we do not want to base the
7374        # needsCx decision on the types involved, just on our extended
7375        # attributes. Also, JSContext is not needed for the static case
7376        # since GlobalObject already contains the context.
7377        needsCx = needCx(returnType, arguments, self.extendedAttributes,
7378                         not descriptor.interface.isJSImplemented(), static)
7379        if needsCx:
7380            argsPre.append("cx")
7381
7382        # Hack for making Promise.prototype.then work well over Xrays.
7383        if (not idlNode.isStatic() and
7384            descriptor.name == "Promise" and
7385            idlNode.isMethod() and
7386            idlNode.identifier.name == "then"):
7387            cgThings.append(CGGeneric(dedent(
7388                """
7389                JS::Rooted<JSObject*> calleeGlobal(cx, xpc::XrayAwareCalleeGlobal(&args.callee()));
7390                """)))
7391            argsPre.append("calleeGlobal")
7392
7393        needsUnwrap = False
7394        argsPost = []
7395        if isConstructor:
7396            if descriptor.name == "Promise":
7397                # Hack for Promise for now: pass in our desired proto so the
7398                # implementation can create the reflector with the right proto.
7399                argsPost.append("desiredProto")
7400                # Also, we do not want to enter the content compartment when the
7401                # Promise constructor is called via Xrays, because we want to
7402                # create our callback functions that we will hand to our caller
7403                # in the Xray compartment.  The reason we want to do that is the
7404                # following situation, over Xrays:
7405                #
7406                #   contentWindow.Promise.race([Promise.resolve(5)])
7407                #
7408                # Ideally this would work.  Internally, race() does a
7409                # contentWindow.Promise.resolve() on everything in the array.
7410                # Per spec, to support subclassing,
7411                # contentWindow.Promise.resolve has to do:
7412                #
7413                #   var resolve, reject;
7414                #   var p = new contentWindow.Promise(function(a, b) {
7415                #    resolve = a;
7416                #    reject = b;
7417                #  });
7418                #  resolve(arg);
7419                #  return p;
7420                #
7421                # where "arg" is, in this case, the chrome-side return value of
7422                # Promise.resolve(5).  But if the "resolve" function in that
7423                # case were created in the content compartment, then calling it
7424                # would wrap "arg" in an opaque wrapper, and that function tries
7425                # to get .then off the argument, which would throw.  So we need
7426                # to create the "resolve" function in the chrome compartment,
7427                # and hence want to be running the entire Promise constructor
7428                # (which creates that function) in the chrome compartment in
7429                # this case. So don't set needsUnwrap here.
7430            else:
7431                needsUnwrap = True
7432                needsUnwrappedVar = False
7433                unwrappedVar = "obj"
7434        elif descriptor.interface.isJSImplemented():
7435            if not idlNode.isStatic():
7436                needsUnwrap = True
7437                needsUnwrappedVar = True
7438                argsPost.append("js::GetObjectCompartment(unwrappedObj ? *unwrappedObj : obj)")
7439        elif needScopeObject(returnType, arguments, self.extendedAttributes,
7440                             descriptor.wrapperCache, True,
7441                             idlNode.getExtendedAttribute("StoreInSlot")):
7442            needsUnwrap = True
7443            needsUnwrappedVar = True
7444            argsPre.append("unwrappedObj ? *unwrappedObj : obj")
7445
7446        if idlNode.isStatic() and not isConstructor and descriptor.name == "Promise":
7447            # Hack for Promise for now: pass in the "this" value to
7448            # Promise static methods.
7449            argsPre.append("args.thisv()")
7450
7451        if needsUnwrap and needsUnwrappedVar:
7452            # We cannot assign into obj because it's a Handle, not a
7453            # MutableHandle, so we need a separate Rooted.
7454            cgThings.append(CGGeneric("Maybe<JS::Rooted<JSObject*> > unwrappedObj;\n"))
7455            unwrappedVar = "unwrappedObj.ref()"
7456
7457        if idlNode.isMethod() and idlNode.isLegacycaller():
7458            # If we can have legacycaller with identifier, we can't
7459            # just use the idlNode to determine whether we're
7460            # generating code for the legacycaller or not.
7461            assert idlNode.isIdentifierLess()
7462            # Pass in our thisVal
7463            argsPre.append("args.thisv()")
7464
7465        ourName = "%s.%s" % (descriptor.interface.identifier.name,
7466                             idlNode.identifier.name)
7467        if idlNode.isMethod():
7468            argDescription = "argument %(index)d of " + ourName
7469        elif setter:
7470            argDescription = "value being assigned to %s" % ourName
7471        else:
7472            assert self.argCount == 0
7473
7474        if needsUnwrap:
7475            # It's very important that we construct our unwrappedObj, if we need
7476            # to do it, before we might start setting up Rooted things for our
7477            # arguments, so that we don't violate the stack discipline Rooted
7478            # depends on.
7479            cgThings.append(CGGeneric(
7480                "bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);\n"))
7481            if needsUnwrappedVar:
7482                cgThings.append(CGIfWrapper(
7483                    CGGeneric("unwrappedObj.emplace(cx, obj);\n"),
7484                    "objIsXray"))
7485
7486        for i in range(argConversionStartsAt, self.argCount):
7487            cgThings.append(
7488                CGArgumentConverter(arguments[i], i, self.descriptor,
7489                                    argDescription % {"index": i + 1},
7490                                    idlNode, invalidEnumValueFatal=not setter,
7491                                    lenientFloatCode=lenientFloatCode))
7492
7493        # Now that argument processing is done, enforce the LenientFloat stuff
7494        if lenientFloatCode:
7495            if setter:
7496                foundNonFiniteFloatBehavior = "return true;\n"
7497            else:
7498                assert idlNode.isMethod()
7499                foundNonFiniteFloatBehavior = dedent(
7500                    """
7501                    args.rval().setUndefined();
7502                    return true;
7503                    """)
7504            cgThings.append(CGGeneric(fill(
7505                """
7506                if (foundNonFiniteFloat) {
7507                  $*{returnSteps}
7508                }
7509                """,
7510                returnSteps=foundNonFiniteFloatBehavior)))
7511
7512        if needsUnwrap:
7513            # Something depends on having the unwrapped object, so unwrap it now.
7514            xraySteps = []
7515            # XXXkhuey we should be able to MOZ_ASSERT that ${obj} is
7516            # not null.
7517            xraySteps.append(
7518                CGGeneric(fill(
7519                    """
7520                    ${obj} = js::CheckedUnwrap(${obj});
7521                    if (!${obj}) {
7522                      return false;
7523                    }
7524                    """,
7525                    obj=unwrappedVar)))
7526            if isConstructor:
7527                # If we're called via an xray, we need to enter the underlying
7528                # object's compartment and then wrap up all of our arguments into
7529                # that compartment as needed.  This is all happening after we've
7530                # already done the conversions from JS values to WebIDL (C++)
7531                # values, so we only need to worry about cases where there are 'any'
7532                # or 'object' types, or other things that we represent as actual
7533                # JSAPI types, present.  Effectively, we're emulating a
7534                # CrossCompartmentWrapper, but working with the C++ types, not the
7535                # original list of JS::Values.
7536                cgThings.append(CGGeneric("Maybe<JSAutoCompartment> ac;\n"))
7537                xraySteps.append(CGGeneric("ac.emplace(cx, obj);\n"))
7538                xraySteps.append(CGGeneric(dedent(
7539                    """
7540                    if (!JS_WrapObject(cx, &desiredProto)) {
7541                      return false;
7542                    }
7543                    """)))
7544                xraySteps.extend(
7545                    wrapArgIntoCurrentCompartment(arg, argname, isMember=False)
7546                    for arg, argname in self.getArguments())
7547
7548            cgThings.append(
7549                CGIfWrapper(CGList(xraySteps),
7550                            "objIsXray"))
7551
7552        # If this is a method that was generated by a maplike/setlike
7553        # interface, use the maplike/setlike generator to fill in the body.
7554        # Otherwise, use CGCallGenerator to call the native method.
7555        if idlNode.isMethod() and idlNode.isMaplikeOrSetlikeOrIterableMethod():
7556            if (idlNode.maplikeOrSetlikeOrIterable.isMaplike() or
7557                idlNode.maplikeOrSetlikeOrIterable.isSetlike()):
7558                cgThings.append(CGMaplikeOrSetlikeMethodGenerator(descriptor,
7559                                                                  idlNode.maplikeOrSetlikeOrIterable,
7560                                                                  idlNode.identifier.name))
7561            else:
7562                cgThings.append(CGIterableMethodGenerator(descriptor,
7563                                                          idlNode.maplikeOrSetlikeOrIterable,
7564                                                          idlNode.identifier.name))
7565        else:
7566            cgThings.append(CGCallGenerator(
7567                self.isFallible(),
7568                idlNode.getExtendedAttribute('NeedsSubjectPrincipal'),
7569                needsCallerType(idlNode),
7570                self.getArguments(), argsPre, returnType,
7571                self.extendedAttributes, descriptor,
7572                nativeMethodName,
7573                static, argsPost=argsPost, resultVar=resultVar))
7574
7575        if useCounterName:
7576            # Generate a telemetry call for when [UseCounter] is used.
7577            code = "SetDocumentAndPageUseCounter(cx, obj, eUseCounter_%s);\n" % useCounterName
7578            cgThings.append(CGGeneric(code))
7579
7580        self.cgRoot = CGList(cgThings)
7581
7582    def getArguments(self):
7583        return [(a, "arg" + str(i)) for i, a in enumerate(self.arguments)]
7584
7585    def isFallible(self):
7586        return 'infallible' not in self.extendedAttributes
7587
7588    def wrap_return_value(self):
7589        wrapCode = ""
7590
7591        returnsNewObject = memberReturnsNewObject(self.idlNode)
7592        if (returnsNewObject and
7593            self.returnType.isGeckoInterface()):
7594            wrapCode += dedent(
7595                """
7596                static_assert(!IsPointer<decltype(result)>::value,
7597                              "NewObject implies that we need to keep the object alive with a strong reference.");
7598                """)
7599
7600        setSlot = self.idlNode.isAttr() and self.idlNode.slotIndices is not None
7601        if setSlot:
7602            # For attributes in slots, we want to do some
7603            # post-processing once we've wrapped them.
7604            successCode = "break;\n"
7605        else:
7606            successCode = None
7607
7608        resultTemplateValues = {
7609            'jsvalRef': 'args.rval()',
7610            'jsvalHandle': 'args.rval()',
7611            'returnsNewObject': returnsNewObject,
7612            'isConstructorRetval': self.isConstructor,
7613            'successCode': successCode,
7614            # 'obj' in this dictionary is the thing whose compartment we are
7615            # trying to do the to-JS conversion in.  We're going to put that
7616            # thing in a variable named "conversionScope" if setSlot is true.
7617            # Otherwise, just use "obj" for lack of anything better.
7618            'obj': "conversionScope" if setSlot else "obj"
7619        }
7620        try:
7621            wrapCode += wrapForType(self.returnType, self.descriptor, resultTemplateValues)
7622        except MethodNotNewObjectError, err:
7623            assert not returnsNewObject
7624            raise TypeError("%s being returned from non-NewObject method or property %s.%s" %
7625                            (err.typename,
7626                             self.descriptor.interface.identifier.name,
7627                             self.idlNode.identifier.name))
7628        if setSlot:
7629            # When using a slot on the Xray expando, we need to make sure that
7630            # our initial conversion to a JS::Value is done in the caller
7631            # compartment.  When using a slot on our reflector, we want to do
7632            # the conversion in the compartment of that reflector (that is,
7633            # slotStorage).  In both cases we want to make sure that we finally
7634            # set up args.rval() to be in the caller compartment.  We also need
7635            # to make sure that the conversion steps happen inside a do/while
7636            # that they can break out of on success.
7637            #
7638            # Of course we always have to wrap the value into the slotStorage
7639            # compartment before we store it in slotStorage.
7640
7641            # postConversionSteps are the steps that run while we're still in
7642            # the compartment we do our conversion in but after we've finished
7643            # the initial conversion into args.rval().
7644            postConversionSteps = ""
7645            if needsContainsHack(self.idlNode):
7646                # Define a .contains on the object that has the same value as
7647                # .includes; needed for backwards compat in extensions as we
7648                # migrate some DOMStringLists to FrozenArray.
7649                postConversionSteps += dedent(
7650                    """
7651                    if (args.rval().isObject() && nsContentUtils::ThreadsafeIsCallerChrome()) {
7652                      JS::Rooted<JSObject*> rvalObj(cx, &args.rval().toObject());
7653                      JS::Rooted<JS::Value> includesVal(cx);
7654                      if (!JS_GetProperty(cx, rvalObj, "includes", &includesVal) ||
7655                          !JS_DefineProperty(cx, rvalObj, "contains", includesVal, JSPROP_ENUMERATE)) {
7656                        return false;
7657                      }
7658                    }
7659
7660                    """)
7661            if self.idlNode.getExtendedAttribute("Frozen"):
7662                assert self.idlNode.type.isSequence() or self.idlNode.type.isDictionary()
7663                freezeValue = CGGeneric(
7664                    "JS::Rooted<JSObject*> rvalObj(cx, &args.rval().toObject());\n"
7665                    "if (!JS_FreezeObject(cx, rvalObj)) {\n"
7666                    "  return false;\n"
7667                    "}\n")
7668                if self.idlNode.type.nullable():
7669                    freezeValue = CGIfWrapper(freezeValue,
7670                                              "args.rval().isObject()")
7671                postConversionSteps += freezeValue.define()
7672
7673            # slotStorageSteps are steps that run once we have entered the
7674            # slotStorage compartment.
7675            slotStorageSteps= fill(
7676                """
7677                // Make a copy so that we don't do unnecessary wrapping on args.rval().
7678                JS::Rooted<JS::Value> storedVal(cx, args.rval());
7679                if (!${maybeWrap}(cx, &storedVal)) {
7680                  return false;
7681                }
7682                js::SetReservedSlot(slotStorage, slotIndex, storedVal);
7683                """,
7684                maybeWrap=getMaybeWrapValueFuncForType(self.idlNode.type))
7685
7686            checkForXray = mayUseXrayExpandoSlots(self.descriptor, self.idlNode)
7687
7688            # For the case of Cached attributes, go ahead and preserve our
7689            # wrapper if needed.  We need to do this because otherwise the
7690            # wrapper could get garbage-collected and the cached value would
7691            # suddenly disappear, but the whole premise of cached values is that
7692            # they never change without explicit action on someone's part.  We
7693            # don't do this for StoreInSlot, since those get dealt with during
7694            # wrapper setup, and failure would involve us trying to clear an
7695            # already-preserved wrapper.
7696            if (self.idlNode.getExtendedAttribute("Cached") and
7697                self.descriptor.wrapperCache):
7698                preserveWrapper = dedent(
7699                    """
7700                    PreserveWrapper(self);
7701                    """)
7702                if checkForXray:
7703                    preserveWrapper = fill(
7704                        """
7705                        if (!isXray) {
7706                          // In the Xray case we don't need to do this, because getting the
7707                          // expando object already preserved our wrapper.
7708                          $*{preserveWrapper}
7709                        }
7710                        """,
7711                        preserveWrapper=preserveWrapper)
7712                slotStorageSteps += preserveWrapper
7713
7714            if checkForXray:
7715                conversionScope = "isXray ? obj : slotStorage"
7716            else:
7717                conversionScope = "slotStorage"
7718
7719            wrapCode = fill(
7720                """
7721                {
7722                  JS::Rooted<JSObject*> conversionScope(cx, ${conversionScope});
7723                  JSAutoCompartment ac(cx, conversionScope);
7724                  do { // block we break out of when done wrapping
7725                    $*{wrapCode}
7726                  } while (0);
7727                  $*{postConversionSteps}
7728                }
7729                { // And now store things in the compartment of our slotStorage.
7730                  JSAutoCompartment ac(cx, slotStorage);
7731                  $*{slotStorageSteps}
7732                }
7733                // And now make sure args.rval() is in the caller compartment
7734                return ${maybeWrap}(cx, args.rval());
7735                """,
7736                conversionScope=conversionScope,
7737                wrapCode=wrapCode,
7738                postConversionSteps=postConversionSteps,
7739                slotStorageSteps=slotStorageSteps,
7740                maybeWrap=getMaybeWrapValueFuncForType(self.idlNode.type))
7741        return wrapCode
7742
7743    def define(self):
7744        return (self.cgRoot.define() + self.wrap_return_value())
7745
7746
7747class CGSwitch(CGList):
7748    """
7749    A class to generate code for a switch statement.
7750
7751    Takes three constructor arguments: an expression, a list of cases,
7752    and an optional default.
7753
7754    Each case is a CGCase.  The default is a CGThing for the body of
7755    the default case, if any.
7756    """
7757    def __init__(self, expression, cases, default=None):
7758        CGList.__init__(self, [CGIndenter(c) for c in cases])
7759        self.prepend(CGGeneric("switch (" + expression + ") {\n"))
7760        if default is not None:
7761            self.append(
7762                CGIndenter(
7763                    CGWrapper(
7764                        CGIndenter(default),
7765                        pre="default: {\n",
7766                        post="  break;\n}\n")))
7767
7768        self.append(CGGeneric("}\n"))
7769
7770
7771class CGCase(CGList):
7772    """
7773    A class to generate code for a case statement.
7774
7775    Takes three constructor arguments: an expression, a CGThing for
7776    the body (allowed to be None if there is no body), and an optional
7777    argument (defaulting to False) for whether to fall through.
7778    """
7779    def __init__(self, expression, body, fallThrough=False):
7780        CGList.__init__(self, [])
7781        self.append(CGGeneric("case " + expression + ": {\n"))
7782        bodyList = CGList([body])
7783        if fallThrough:
7784            bodyList.append(CGGeneric("MOZ_FALLTHROUGH;\n"))
7785        else:
7786            bodyList.append(CGGeneric("break;\n"))
7787        self.append(CGIndenter(bodyList))
7788        self.append(CGGeneric("}\n"))
7789
7790
7791class CGMethodCall(CGThing):
7792    """
7793    A class to generate selection of a method signature from a set of
7794    signatures and generation of a call to that signature.
7795    """
7796    def __init__(self, nativeMethodName, static, descriptor, method,
7797                 isConstructor=False, constructorName=None):
7798        CGThing.__init__(self)
7799
7800        if isConstructor:
7801            assert constructorName is not None
7802            methodName = constructorName
7803        else:
7804            methodName = "%s.%s" % (descriptor.interface.identifier.name, method.identifier.name)
7805        argDesc = "argument %d of " + methodName
7806
7807        if method.getExtendedAttribute("UseCounter"):
7808            useCounterName = methodName.replace(".", "_")
7809        else:
7810            useCounterName = None
7811
7812        if method.isStatic():
7813            nativeType = descriptor.nativeType
7814            staticTypeOverride = PropertyDefiner.getStringAttr(method, "StaticClassOverride")
7815            if (staticTypeOverride):
7816                nativeType = staticTypeOverride
7817            nativeMethodName = "%s::%s" % (nativeType, nativeMethodName)
7818
7819        def requiredArgCount(signature):
7820            arguments = signature[1]
7821            if len(arguments) == 0:
7822                return 0
7823            requiredArgs = len(arguments)
7824            while requiredArgs and arguments[requiredArgs-1].optional:
7825                requiredArgs -= 1
7826            return requiredArgs
7827
7828        def getPerSignatureCall(signature, argConversionStartsAt=0):
7829            return CGPerSignatureCall(signature[0], signature[1],
7830                                      nativeMethodName, static, descriptor,
7831                                      method,
7832                                      argConversionStartsAt=argConversionStartsAt,
7833                                      isConstructor=isConstructor,
7834                                      useCounterName=useCounterName)
7835
7836        signatures = method.signatures()
7837        if len(signatures) == 1:
7838            # Special case: we can just do a per-signature method call
7839            # here for our one signature and not worry about switching
7840            # on anything.
7841            signature = signatures[0]
7842            self.cgRoot = CGList([getPerSignatureCall(signature)])
7843            requiredArgs = requiredArgCount(signature)
7844
7845            # Skip required arguments check for maplike/setlike interfaces, as
7846            # they can have arguments which are not passed, and are treated as
7847            # if undefined had been explicitly passed.
7848            if requiredArgs > 0 and not method.isMaplikeOrSetlikeOrIterableMethod():
7849                code = fill(
7850                    """
7851                    if (MOZ_UNLIKELY(args.length() < ${requiredArgs})) {
7852                      return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "${methodName}");
7853                    }
7854                    """,
7855                    requiredArgs=requiredArgs,
7856                    methodName=methodName)
7857                self.cgRoot.prepend(CGGeneric(code))
7858            return
7859
7860        # Need to find the right overload
7861        maxArgCount = method.maxArgCount
7862        allowedArgCounts = method.allowedArgCounts
7863
7864        argCountCases = []
7865        for argCountIdx, argCount in enumerate(allowedArgCounts):
7866            possibleSignatures = method.signaturesForArgCount(argCount)
7867
7868            # Try to optimize away cases when the next argCount in the list
7869            # will have the same code as us; if it does, we can fall through to
7870            # that case.
7871            if argCountIdx+1 < len(allowedArgCounts):
7872                nextPossibleSignatures = method.signaturesForArgCount(allowedArgCounts[argCountIdx+1])
7873            else:
7874                nextPossibleSignatures = None
7875            if possibleSignatures == nextPossibleSignatures:
7876                # Same set of signatures means we better have the same
7877                # distinguishing index.  So we can in fact just fall through to
7878                # the next case here.
7879                assert (len(possibleSignatures) == 1 or
7880                        (method.distinguishingIndexForArgCount(argCount) ==
7881                         method.distinguishingIndexForArgCount(allowedArgCounts[argCountIdx+1])))
7882                argCountCases.append(CGCase(str(argCount), None, True))
7883                continue
7884
7885            if len(possibleSignatures) == 1:
7886                # easy case!
7887                signature = possibleSignatures[0]
7888                argCountCases.append(
7889                    CGCase(str(argCount), getPerSignatureCall(signature)))
7890                continue
7891
7892            distinguishingIndex = method.distinguishingIndexForArgCount(argCount)
7893
7894            def distinguishingArgument(signature):
7895                args = signature[1]
7896                if distinguishingIndex < len(args):
7897                    return args[distinguishingIndex]
7898                assert args[-1].variadic
7899                return args[-1]
7900
7901            def distinguishingType(signature):
7902                return distinguishingArgument(signature).type
7903
7904            for sig in possibleSignatures:
7905                # We should not have "any" args at distinguishingIndex,
7906                # since we have multiple possible signatures remaining,
7907                # but "any" is never distinguishable from anything else.
7908                assert not distinguishingType(sig).isAny()
7909                # We can't handle unions at the distinguishing index.
7910                if distinguishingType(sig).isUnion():
7911                    raise TypeError("No support for unions as distinguishing "
7912                                    "arguments yet: %s" %
7913                                    distinguishingArgument(sig).location)
7914                # We don't support variadics as the distinguishingArgument yet.
7915                # If you want to add support, consider this case:
7916                #
7917                #   void(long... foo);
7918                #   void(long bar, Int32Array baz);
7919                #
7920                # in which we have to convert argument 0 to long before picking
7921                # an overload... but all the variadic stuff needs to go into a
7922                # single array in case we pick that overload, so we have to have
7923                # machinery for converting argument 0 to long and then either
7924                # placing it in the variadic bit or not.  Or something.  We may
7925                # be able to loosen this restriction if the variadic arg is in
7926                # fact at distinguishingIndex, perhaps.  Would need to
7927                # double-check.
7928                if distinguishingArgument(sig).variadic:
7929                    raise TypeError("No support for variadics as distinguishing "
7930                                    "arguments yet: %s" %
7931                                    distinguishingArgument(sig).location)
7932
7933            # Convert all our arguments up to the distinguishing index.
7934            # Doesn't matter which of the possible signatures we use, since
7935            # they all have the same types up to that point; just use
7936            # possibleSignatures[0]
7937            caseBody = [CGArgumentConverter(possibleSignatures[0][1][i],
7938                                            i, descriptor,
7939                                            argDesc % (i + 1), method)
7940                        for i in range(0, distinguishingIndex)]
7941
7942            # Select the right overload from our set.
7943            distinguishingArg = "args[%d]" % distinguishingIndex
7944
7945            def tryCall(signature, indent, isDefinitelyObject=False,
7946                        isNullOrUndefined=False):
7947                assert not isDefinitelyObject or not isNullOrUndefined
7948                assert isDefinitelyObject or isNullOrUndefined
7949                if isDefinitelyObject:
7950                    failureCode = "break;\n"
7951                else:
7952                    failureCode = None
7953                type = distinguishingType(signature)
7954                # The argument at index distinguishingIndex can't possibly be
7955                # unset here, because we've already checked that argc is large
7956                # enough that we can examine this argument.  But note that we
7957                # still want to claim that optional arguments are optional, in
7958                # case undefined was passed in.
7959                argIsOptional = distinguishingArgument(signature).canHaveMissingValue()
7960                testCode = instantiateJSToNativeConversion(
7961                    getJSToNativeConversionInfo(type, descriptor,
7962                                                failureCode=failureCode,
7963                                                isDefinitelyObject=isDefinitelyObject,
7964                                                isNullOrUndefined=isNullOrUndefined,
7965                                                isOptional=argIsOptional,
7966                                                sourceDescription=(argDesc % (distinguishingIndex + 1))),
7967                    {
7968                        "declName": "arg%d" % distinguishingIndex,
7969                        "holderName": ("arg%d" % distinguishingIndex) + "_holder",
7970                        "val": distinguishingArg,
7971                        "obj": "obj",
7972                        "haveValue": "args.hasDefined(%d)" % distinguishingIndex,
7973                        "passedToJSImpl": toStringBool(isJSImplementedDescriptor(descriptor))
7974                    },
7975                    checkForValue=argIsOptional)
7976                caseBody.append(CGIndenter(testCode, indent))
7977
7978                # If we got this far, we know we unwrapped to the right
7979                # C++ type, so just do the call.  Start conversion with
7980                # distinguishingIndex + 1, since we already converted
7981                # distinguishingIndex.
7982                caseBody.append(CGIndenter(
7983                    getPerSignatureCall(signature, distinguishingIndex + 1),
7984                    indent))
7985
7986            def hasConditionalConversion(type):
7987                """
7988                Return whether the argument conversion for this type will be
7989                conditional on the type of incoming JS value.  For example, for
7990                interface types the conversion is conditional on the incoming
7991                value being isObject().
7992
7993                For the types for which this returns false, we do not have to
7994                output extra isUndefined() or isNullOrUndefined() cases, because
7995                null/undefined values will just fall through into our
7996                unconditional conversion.
7997                """
7998                if type.isString() or type.isEnum():
7999                    return False
8000                if type.isBoolean():
8001                    distinguishingTypes = (distinguishingType(s) for s in
8002                                           possibleSignatures)
8003                    return any(t.isString() or t.isEnum() or t.isNumeric()
8004                               for t in distinguishingTypes)
8005                if type.isNumeric():
8006                    distinguishingTypes = (distinguishingType(s) for s in
8007                                           possibleSignatures)
8008                    return any(t.isString() or t.isEnum()
8009                               for t in distinguishingTypes)
8010                return True
8011
8012            def needsNullOrUndefinedCase(type):
8013                """
8014                Return true if the type needs a special isNullOrUndefined() case
8015                """
8016                return ((type.nullable() and
8017                        hasConditionalConversion(type)) or
8018                        type.isDictionary())
8019
8020            # First check for undefined and optional distinguishing arguments
8021            # and output a special branch for that case.  Note that we don't
8022            # use distinguishingArgument here because we actualy want to
8023            # exclude variadic arguments.  Also note that we skip this check if
8024            # we plan to output a isNullOrUndefined() special case for this
8025            # argument anyway, since that will subsume our isUndefined() check.
8026            # This is safe, because there can be at most one nullable
8027            # distinguishing argument, so if we're it we'll definitely get
8028            # picked up by the nullable handling.  Also, we can skip this check
8029            # if the argument has an unconditional conversion later on.
8030            undefSigs = [s for s in possibleSignatures if
8031                         distinguishingIndex < len(s[1]) and
8032                         s[1][distinguishingIndex].optional and
8033                         hasConditionalConversion(s[1][distinguishingIndex].type) and
8034                         not needsNullOrUndefinedCase(s[1][distinguishingIndex].type)]
8035            # Can't have multiple signatures with an optional argument at the
8036            # same index.
8037            assert len(undefSigs) < 2
8038            if len(undefSigs) > 0:
8039                caseBody.append(CGGeneric("if (%s.isUndefined()) {\n" %
8040                                          distinguishingArg))
8041                tryCall(undefSigs[0], 2, isNullOrUndefined=True)
8042                caseBody.append(CGGeneric("}\n"))
8043
8044            # Next, check for null or undefined.  That means looking for
8045            # nullable arguments at the distinguishing index and outputting a
8046            # separate branch for them.  But if the nullable argument has an
8047            # unconditional conversion, we don't need to do that.  The reason
8048            # for that is that at most one argument at the distinguishing index
8049            # is nullable (since two nullable arguments are not
8050            # distinguishable), and null/undefined values will always fall
8051            # through to the unconditional conversion we have, if any, since
8052            # they will fail whatever the conditions on the input value are for
8053            # our other conversions.
8054            nullOrUndefSigs = [s for s in possibleSignatures
8055                               if needsNullOrUndefinedCase(distinguishingType(s))]
8056            # Can't have multiple nullable types here
8057            assert len(nullOrUndefSigs) < 2
8058            if len(nullOrUndefSigs) > 0:
8059                caseBody.append(CGGeneric("if (%s.isNullOrUndefined()) {\n" %
8060                                          distinguishingArg))
8061                tryCall(nullOrUndefSigs[0], 2, isNullOrUndefined=True)
8062                caseBody.append(CGGeneric("}\n"))
8063
8064            # Now check for distinguishingArg being various kinds of objects.
8065            # The spec says to check for the following things in order:
8066            # 1)  A platform object that's not a platform array object, being
8067            #     passed to an interface or "object" arg.
8068            # 2)  A Date object being passed to a Date or "object" arg.
8069            # 3)  A RegExp object being passed to a RegExp or "object" arg.
8070            # 4)  A callable object being passed to a callback or "object" arg.
8071            # 5)  An iterable object being passed to a sequence arg.
8072            # 6)  Any non-Date and non-RegExp object being passed to a
8073            #     array or callback interface or dictionary or
8074            #     "object" arg.
8075
8076            # First grab all the overloads that have a non-callback interface
8077            # (which includes typed arrays and arraybuffers) at the
8078            # distinguishing index.  We can also include the ones that have an
8079            # "object" here, since if those are present no other object-typed
8080            # argument will be.
8081            objectSigs = [
8082                s for s in possibleSignatures
8083                if (distinguishingType(s).isObject() or
8084                    distinguishingType(s).isNonCallbackInterface())]
8085
8086            # And all the overloads that take Date
8087            objectSigs.extend(s for s in possibleSignatures
8088                              if distinguishingType(s).isDate())
8089
8090            # And all the overloads that take callbacks
8091            objectSigs.extend(s for s in possibleSignatures
8092                              if distinguishingType(s).isCallback())
8093
8094            # And all the overloads that take sequences
8095            objectSigs.extend(s for s in possibleSignatures
8096                              if distinguishingType(s).isSequence())
8097
8098            # Now append all the overloads that take a dictionary or callback
8099            # interface or MozMap.  There should be only one of these!
8100            genericObjectSigs = [
8101                s for s in possibleSignatures
8102                if (distinguishingType(s).isDictionary() or
8103                    distinguishingType(s).isMozMap() or
8104                    distinguishingType(s).isCallbackInterface())]
8105            assert len(genericObjectSigs) <= 1
8106            objectSigs.extend(genericObjectSigs)
8107
8108            # There might be more than one thing in objectSigs; we need to check
8109            # which ones we unwrap to.
8110            if len(objectSigs) > 0:
8111                # Here it's enough to guard on our argument being an object. The
8112                # code for unwrapping non-callback interfaces, typed arrays,
8113                # sequences, and Dates will just bail out and move on to
8114                # the next overload if the object fails to unwrap correctly,
8115                # while "object" accepts any object anyway.  We could even not
8116                # do the isObject() check up front here, but in cases where we
8117                # have multiple object overloads it makes sense to do it only
8118                # once instead of for each overload.  That will also allow the
8119                # unwrapping test to skip having to do codegen for the
8120                # null-or-undefined case, which we already handled above.
8121                caseBody.append(CGGeneric("if (%s.isObject()) {\n" %
8122                                          distinguishingArg))
8123                for sig in objectSigs:
8124                    caseBody.append(CGIndenter(CGGeneric("do {\n")))
8125                    # Indent by 4, since we need to indent further
8126                    # than our "do" statement
8127                    tryCall(sig, 4, isDefinitelyObject=True)
8128                    caseBody.append(CGIndenter(CGGeneric("} while (0);\n")))
8129
8130                caseBody.append(CGGeneric("}\n"))
8131
8132            # Now we only have to consider booleans, numerics, and strings.  If
8133            # we only have one of them, then we can just output it.  But if not,
8134            # then we need to output some of the cases conditionally: if we have
8135            # a string overload, then boolean and numeric are conditional, and
8136            # if not then boolean is conditional if we have a numeric overload.
8137            def findUniqueSignature(filterLambda):
8138                sigs = filter(filterLambda, possibleSignatures)
8139                assert len(sigs) < 2
8140                if len(sigs) > 0:
8141                    return sigs[0]
8142                return None
8143
8144            stringSignature = findUniqueSignature(
8145                lambda s: (distinguishingType(s).isString() or
8146                           distinguishingType(s).isEnum()))
8147            numericSignature = findUniqueSignature(
8148                lambda s: distinguishingType(s).isNumeric())
8149            booleanSignature = findUniqueSignature(
8150                lambda s: distinguishingType(s).isBoolean())
8151
8152            if stringSignature or numericSignature:
8153                booleanCondition = "%s.isBoolean()"
8154            else:
8155                booleanCondition = None
8156
8157            if stringSignature:
8158                numericCondition = "%s.isNumber()"
8159            else:
8160                numericCondition = None
8161
8162            def addCase(sig, condition):
8163                sigCode = getPerSignatureCall(sig, distinguishingIndex)
8164                if condition:
8165                    sigCode = CGIfWrapper(sigCode,
8166                                          condition % distinguishingArg)
8167                caseBody.append(sigCode)
8168
8169            if booleanSignature:
8170                addCase(booleanSignature, booleanCondition)
8171            if numericSignature:
8172                addCase(numericSignature, numericCondition)
8173            if stringSignature:
8174                addCase(stringSignature, None)
8175
8176            if (not booleanSignature and not numericSignature and
8177                not stringSignature):
8178                # Just throw; we have no idea what we're supposed to
8179                # do with this.
8180                caseBody.append(CGGeneric(
8181                    'return ThrowErrorMessage(cx, MSG_OVERLOAD_RESOLUTION_FAILED, "%d", "%d", "%s");\n' %
8182                    (distinguishingIndex + 1, argCount, methodName)))
8183
8184            argCountCases.append(CGCase(str(argCount), CGList(caseBody)))
8185
8186        overloadCGThings = []
8187        overloadCGThings.append(
8188            CGGeneric("unsigned argcount = std::min(args.length(), %du);\n" %
8189                      maxArgCount))
8190        overloadCGThings.append(
8191            CGSwitch("argcount",
8192                     argCountCases,
8193                     CGGeneric('return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "%s");\n' %
8194                               methodName)))
8195        overloadCGThings.append(
8196            CGGeneric('MOZ_CRASH("We have an always-returning default case");\n'
8197                      'return false;\n'))
8198        self.cgRoot = CGList(overloadCGThings)
8199
8200    def define(self):
8201        return self.cgRoot.define()
8202
8203
8204class CGGetterCall(CGPerSignatureCall):
8205    """
8206    A class to generate a native object getter call for a particular IDL
8207    getter.
8208    """
8209    def __init__(self, returnType, nativeMethodName, descriptor, attr):
8210        if attr.getExtendedAttribute("UseCounter"):
8211            useCounterName = "%s_%s_getter" % (descriptor.interface.identifier.name,
8212                                               attr.identifier.name)
8213        else:
8214            useCounterName = None
8215        if attr.isStatic():
8216            nativeMethodName = "%s::%s" % (descriptor.nativeType, nativeMethodName)
8217        CGPerSignatureCall.__init__(self, returnType, [], nativeMethodName,
8218                                    attr.isStatic(), descriptor, attr,
8219                                    getter=True, useCounterName=useCounterName)
8220
8221
8222class CGNavigatorGetterCall(CGPerSignatureCall):
8223    """
8224    A class to generate a native object getter call for an IDL getter for a
8225    property generated by NavigatorProperty.
8226    """
8227    def __init__(self, returnType, _, descriptor, attr):
8228        nativeMethodName = "%s::ConstructNavigatorObject" % (toBindingNamespace(returnType.inner.identifier.name))
8229        CGPerSignatureCall.__init__(self, returnType, [], nativeMethodName,
8230                                    True, descriptor, attr, getter=True)
8231
8232    def getArguments(self):
8233        # The navigator object should be associated with the global of
8234        # the navigator it's coming from, which will be the global of
8235        # the object whose slot it gets cached in.  That's stored in
8236        # "slotStorage".
8237        return [(FakeArgument(BuiltinTypes[IDLBuiltinType.Types.object],
8238                              self.idlNode),
8239                 "slotStorage")]
8240
8241
8242class FakeIdentifier():
8243    def __init__(self, name):
8244        self.name = name
8245
8246
8247class FakeArgument():
8248    """
8249    A class that quacks like an IDLArgument.  This is used to make
8250    setters look like method calls or for special operations.
8251    """
8252    def __init__(self, type, interfaceMember, name="arg", allowTreatNonCallableAsNull=False):
8253        self.type = type
8254        self.optional = False
8255        self.variadic = False
8256        self.defaultValue = None
8257        self._allowTreatNonCallableAsNull = allowTreatNonCallableAsNull
8258        # For FakeArguments generated by maplike/setlike convenience functions,
8259        # we won't have an interfaceMember to pass in.
8260        if interfaceMember:
8261            self.treatNullAs = interfaceMember.treatNullAs
8262        else:
8263            self.treatNullAs = "Default"
8264        if isinstance(interfaceMember, IDLAttribute):
8265            self.enforceRange = interfaceMember.enforceRange
8266            self.clamp = interfaceMember.clamp
8267        else:
8268            self.enforceRange = False
8269            self.clamp = False
8270
8271        self.identifier = FakeIdentifier(name)
8272
8273    def allowTreatNonCallableAsNull(self):
8274        return self._allowTreatNonCallableAsNull
8275
8276    def canHaveMissingValue(self):
8277        return False
8278
8279
8280class CGSetterCall(CGPerSignatureCall):
8281    """
8282    A class to generate a native object setter call for a particular IDL
8283    setter.
8284    """
8285    def __init__(self, argType, nativeMethodName, descriptor, attr):
8286        if attr.getExtendedAttribute("UseCounter"):
8287            useCounterName = "%s_%s_setter" % (descriptor.interface.identifier.name,
8288                                               attr.identifier.name)
8289        else:
8290            useCounterName = None
8291        if attr.isStatic():
8292            nativeMethodName = "%s::%s" % (descriptor.nativeType, nativeMethodName)
8293        CGPerSignatureCall.__init__(self, None,
8294                                    [FakeArgument(argType, attr, allowTreatNonCallableAsNull=True)],
8295                                    nativeMethodName, attr.isStatic(),
8296                                    descriptor, attr, setter=True, useCounterName=useCounterName)
8297
8298    def wrap_return_value(self):
8299        attr = self.idlNode
8300        if self.descriptor.wrapperCache and attr.slotIndices is not None:
8301            if attr.getExtendedAttribute("StoreInSlot"):
8302                args = "cx, self"
8303            else:
8304                args = "self"
8305            clearSlot = ("%s(%s);\n" %
8306                         (MakeClearCachedValueNativeName(self.idlNode), args))
8307        else:
8308            clearSlot = ""
8309
8310        # We have no return value
8311        return ("\n"
8312                "%s"
8313                "return true;\n" % clearSlot)
8314
8315
8316class CGAbstractBindingMethod(CGAbstractStaticMethod):
8317    """
8318    Common class to generate the JSNatives for all our methods, getters, and
8319    setters.  This will generate the function declaration and unwrap the
8320    |this| object.  Subclasses are expected to override the generate_code
8321    function to do the rest of the work.  This function should return a
8322    CGThing which is already properly indented.
8323
8324    getThisObj should be code for getting a JSObject* for the binding
8325    object.  If this is None, we will auto-generate code based on
8326    descriptor to do the right thing.  "" can be passed in if the
8327    binding object is already stored in 'obj'.
8328
8329    callArgs should be code for getting a JS::CallArgs into a variable
8330    called 'args'.  This can be "" if there is already such a variable
8331    around.
8332
8333    If allowCrossOriginThis is true, then this-unwrapping will first do an
8334    UncheckedUnwrap and after that operate on the result.
8335    """
8336    def __init__(self, descriptor, name, args, unwrapFailureCode=None,
8337                 getThisObj=None,
8338                 callArgs="JS::CallArgs args = JS::CallArgsFromVp(argc, vp);\n",
8339                 allowCrossOriginThis=False):
8340        CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args)
8341
8342        if unwrapFailureCode is None:
8343            self.unwrapFailureCode = 'return ThrowErrorMessage(cx, MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE, "Value", "%s");\n' % descriptor.interface.identifier.name
8344        else:
8345            self.unwrapFailureCode = unwrapFailureCode
8346
8347        if getThisObj == "":
8348            self.getThisObj = None
8349        else:
8350            if getThisObj is None:
8351                if descriptor.interface.isOnGlobalProtoChain():
8352                    ensureCondition = "!args.thisv().isNullOrUndefined() && !args.thisv().isObject()"
8353                    getThisObj = "args.thisv().isObject() ? &args.thisv().toObject() : js::GetGlobalForObjectCrossCompartment(&args.callee())"
8354                else:
8355                    ensureCondition = "!args.thisv().isObject()"
8356                    getThisObj = "&args.thisv().toObject()"
8357                unwrapFailureCode = self.unwrapFailureCode % {'securityError': 'false'}
8358                ensureThisObj = CGIfWrapper(CGGeneric(unwrapFailureCode),
8359                                            ensureCondition)
8360            else:
8361                ensureThisObj = None
8362            self.getThisObj = CGList(
8363                [ensureThisObj,
8364                 CGGeneric("JS::Rooted<JSObject*> obj(cx, %s);\n" %
8365                           getThisObj)])
8366        self.callArgs = callArgs
8367        self.allowCrossOriginThis = allowCrossOriginThis
8368
8369    def definition_body(self):
8370        body = self.callArgs
8371        if self.getThisObj is not None:
8372            body += self.getThisObj.define() + "\n"
8373        body += "%s* self;\n" % self.descriptor.nativeType
8374        body += dedent(
8375            """
8376            JS::Rooted<JS::Value> rootSelf(cx, JS::ObjectValue(*obj));
8377            """)
8378
8379        # Our descriptor might claim that we're not castable, simply because
8380        # we're someone's consequential interface.  But for this-unwrapping, we
8381        # know that we're the real deal.  So fake a descriptor here for
8382        # consumption by CastableObjectUnwrapper.
8383        body += str(CastableObjectUnwrapper(
8384            self.descriptor,
8385            "rootSelf",
8386            "&rootSelf",
8387            "self",
8388            self.unwrapFailureCode,
8389            allowCrossOriginObj=self.allowCrossOriginThis))
8390
8391        return body + self.generate_code().define()
8392
8393    def generate_code(self):
8394        assert False  # Override me
8395
8396
8397class CGAbstractStaticBindingMethod(CGAbstractStaticMethod):
8398    """
8399    Common class to generate the JSNatives for all our static methods, getters
8400    and setters.  This will generate the function declaration and unwrap the
8401    global object.  Subclasses are expected to override the generate_code
8402    function to do the rest of the work.  This function should return a
8403    CGThing which is already properly indented.
8404    """
8405    def __init__(self, descriptor, name):
8406        CGAbstractStaticMethod.__init__(self, descriptor, name, "bool",
8407                                        JSNativeArguments())
8408
8409    def definition_body(self):
8410        # Make sure that "obj" is in the same compartment as "cx", since we'll
8411        # later use it to wrap return values.
8412        unwrap = dedent("""
8413            JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
8414            JS::Rooted<JSObject*> obj(cx, &args.callee());
8415
8416            """)
8417        return unwrap + self.generate_code().define()
8418
8419    def generate_code(self):
8420        assert False  # Override me
8421
8422
8423def MakeNativeName(name):
8424    return name[0].upper() + IDLToCIdentifier(name[1:])
8425
8426
8427class CGGenericMethod(CGAbstractBindingMethod):
8428    """
8429    A class for generating the C++ code for an IDL method.
8430
8431    If allowCrossOriginThis is true, then this-unwrapping will first do an
8432    UncheckedUnwrap and after that operate on the result.
8433    """
8434    def __init__(self, descriptor, allowCrossOriginThis=False):
8435        unwrapFailureCode = (
8436            'return ThrowInvalidThis(cx, args, %%(securityError)s, "%s");\n' %
8437            descriptor.interface.identifier.name)
8438        name = "genericCrossOriginMethod" if allowCrossOriginThis else "genericMethod"
8439        CGAbstractBindingMethod.__init__(self, descriptor, name,
8440                                         JSNativeArguments(),
8441                                         unwrapFailureCode=unwrapFailureCode,
8442                                         allowCrossOriginThis=allowCrossOriginThis)
8443
8444    def generate_code(self):
8445        return CGGeneric(dedent("""
8446            const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
8447            MOZ_ASSERT(info->type() == JSJitInfo::Method);
8448            JSJitMethodOp method = info->method;
8449            bool ok = method(cx, obj, self, JSJitMethodCallArgs(args));
8450            #ifdef DEBUG
8451            if (ok) {
8452              AssertReturnTypeMatchesJitinfo(info, args.rval());
8453            }
8454            #endif
8455            return ok;
8456            """))
8457
8458
8459class CGGenericPromiseReturningMethod(CGAbstractBindingMethod):
8460    """
8461    A class for generating the C++ code for an IDL method that returns a Promise.
8462
8463    Does not handle cross-origin this.
8464    """
8465    def __init__(self, descriptor):
8466        unwrapFailureCode = dedent("""
8467            ThrowInvalidThis(cx, args, %%(securityError)s, "%s");\n
8468            return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
8469                                             args.rval());\n""" %
8470                                   descriptor.interface.identifier.name)
8471
8472        name = "genericPromiseReturningMethod"
8473        customCallArgs = dedent("""
8474            JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
8475            // Make sure to save the callee before someone maybe messes with rval().
8476            JS::Rooted<JSObject*> callee(cx, &args.callee());
8477        """)
8478
8479        CGAbstractBindingMethod.__init__(self, descriptor, name,
8480                                         JSNativeArguments(),
8481                                         callArgs=customCallArgs,
8482                                         unwrapFailureCode=unwrapFailureCode)
8483
8484    def generate_code(self):
8485        return CGGeneric(dedent("""
8486            const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
8487            MOZ_ASSERT(info->type() == JSJitInfo::Method);
8488            JSJitMethodOp method = info->method;
8489            bool ok = method(cx, obj, self, JSJitMethodCallArgs(args));
8490            if (ok) {
8491            #ifdef DEBUG
8492              AssertReturnTypeMatchesJitinfo(info, args.rval());
8493            #endif
8494              return true;
8495            }
8496
8497            MOZ_ASSERT(info->returnType() == JSVAL_TYPE_OBJECT);
8498            return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
8499                                             args.rval());
8500            """))
8501
8502
8503class CGSpecializedMethod(CGAbstractStaticMethod):
8504    """
8505    A class for generating the C++ code for a specialized method that the JIT
8506    can call with lower overhead.
8507    """
8508    def __init__(self, descriptor, method):
8509        self.method = method
8510        name = CppKeywords.checkMethodName(IDLToCIdentifier(method.identifier.name))
8511        args = [Argument('JSContext*', 'cx'),
8512                Argument('JS::Handle<JSObject*>', 'obj'),
8513                Argument('%s*' % descriptor.nativeType, 'self'),
8514                Argument('const JSJitMethodCallArgs&', 'args')]
8515        CGAbstractStaticMethod.__init__(self, descriptor, name, 'bool', args)
8516
8517    def definition_body(self):
8518        nativeName = CGSpecializedMethod.makeNativeName(self.descriptor,
8519                                                        self.method)
8520        return CGMethodCall(nativeName, self.method.isStatic(), self.descriptor,
8521                            self.method).define()
8522
8523    @staticmethod
8524    def makeNativeName(descriptor, method):
8525        name = method.identifier.name
8526        return MakeNativeName(descriptor.binaryNameFor(name))
8527
8528
8529class CGMethodPromiseWrapper(CGAbstractStaticMethod):
8530    """
8531    A class for generating a wrapper around another method that will
8532    convert exceptions to promises.
8533    """
8534    def __init__(self, descriptor, methodToWrap):
8535        self.method = methodToWrap
8536        name = self.makeName(methodToWrap.name)
8537        args = list(methodToWrap.args)
8538        CGAbstractStaticMethod.__init__(self, descriptor, name, 'bool', args)
8539
8540    def definition_body(self):
8541        return fill(
8542            """
8543            // Make sure to save the callee before someone maybe messes
8544            // with rval().
8545            JS::Rooted<JSObject*> callee(cx, &args.callee());
8546            bool ok = ${methodName}(${args});
8547            if (ok) {
8548              return true;
8549            }
8550            return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
8551                                             args.rval());
8552            """,
8553            methodName=self.method.name,
8554            args=", ".join(arg.name for arg in self.args))
8555
8556    @staticmethod
8557    def makeName(methodName):
8558        return methodName + "_promiseWrapper"
8559
8560
8561class CGJsonifierMethod(CGSpecializedMethod):
8562    def __init__(self, descriptor, method):
8563        assert method.isJsonifier()
8564        CGSpecializedMethod.__init__(self, descriptor, method)
8565
8566    def definition_body(self):
8567        ret = dedent("""
8568            JS::Rooted<JSObject*> result(cx, JS_NewPlainObject(cx));
8569            if (!result) {
8570              return false;
8571            }
8572            """)
8573
8574        jsonDescriptors = [self.descriptor]
8575        interface = self.descriptor.interface.parent
8576        while interface:
8577            descriptor = self.descriptor.getDescriptor(interface.identifier.name)
8578            if descriptor.operations['Jsonifier']:
8579                jsonDescriptors.append(descriptor)
8580            interface = interface.parent
8581
8582        # Iterate the array in reverse: oldest ancestor first
8583        for descriptor in jsonDescriptors[::-1]:
8584            ret += fill(
8585                """
8586                if (!${parentclass}::JsonifyAttributes(cx, obj, self, result)) {
8587                  return false;
8588                }
8589                """,
8590                parentclass=toBindingNamespace(descriptor.name)
8591                )
8592        ret += ('args.rval().setObject(*result);\n'
8593                'return true;\n')
8594        return ret
8595
8596
8597class CGLegacyCallHook(CGAbstractBindingMethod):
8598    """
8599    Call hook for our object
8600    """
8601    def __init__(self, descriptor):
8602        self._legacycaller = descriptor.operations["LegacyCaller"]
8603        # Our "self" is actually the callee in this case, not the thisval.
8604        CGAbstractBindingMethod.__init__(
8605            self, descriptor, LEGACYCALLER_HOOK_NAME,
8606            JSNativeArguments(), getThisObj="&args.callee()")
8607
8608    def define(self):
8609        if not self._legacycaller:
8610            return ""
8611        return CGAbstractBindingMethod.define(self)
8612
8613    def generate_code(self):
8614        name = self._legacycaller.identifier.name
8615        nativeName = MakeNativeName(self.descriptor.binaryNameFor(name))
8616        return CGMethodCall(nativeName, False, self.descriptor,
8617                            self._legacycaller)
8618
8619
8620class CGResolveHook(CGAbstractClassHook):
8621    """
8622    Resolve hook for objects that have the NeedResolve extended attribute.
8623    """
8624    def __init__(self, descriptor):
8625        assert descriptor.interface.getExtendedAttribute("NeedResolve")
8626
8627        args = [Argument('JSContext*', 'cx'),
8628                Argument('JS::Handle<JSObject*>', 'obj'),
8629                Argument('JS::Handle<jsid>', 'id'),
8630                Argument('bool*', 'resolvedp')]
8631        CGAbstractClassHook.__init__(self, descriptor, RESOLVE_HOOK_NAME,
8632                                     "bool", args)
8633
8634    def generate_code(self):
8635        return dedent("""
8636            JS::Rooted<JS::PropertyDescriptor> desc(cx);
8637            if (!self->DoResolve(cx, obj, id, &desc)) {
8638              return false;
8639            }
8640            if (!desc.object()) {
8641              return true;
8642            }
8643            // If desc.value() is undefined, then the DoResolve call
8644            // has already defined it on the object.  Don't try to also
8645            // define it.
8646            if (!desc.value().isUndefined()) {
8647              desc.attributesRef() |= JSPROP_RESOLVING;
8648              if (!JS_DefinePropertyById(cx, obj, id, desc)) {
8649                return false;
8650              }
8651            }
8652            *resolvedp = true;
8653            return true;
8654            """)
8655
8656    def definition_body(self):
8657        if self.descriptor.isGlobal():
8658            # Resolve standard classes
8659            prefix = dedent("""
8660                if (!ResolveGlobal(cx, obj, id, resolvedp)) {
8661                  return false;
8662                }
8663                if (*resolvedp) {
8664                  return true;
8665                }
8666
8667                """)
8668        else:
8669            prefix = ""
8670        return prefix + CGAbstractClassHook.definition_body(self)
8671
8672
8673class CGMayResolveHook(CGAbstractStaticMethod):
8674    """
8675    Resolve hook for objects that have the NeedResolve extended attribute.
8676    """
8677    def __init__(self, descriptor):
8678        assert descriptor.interface.getExtendedAttribute("NeedResolve")
8679
8680        args = [Argument('const JSAtomState&', 'names'),
8681                Argument('jsid', 'id'),
8682                Argument('JSObject*', 'maybeObj')]
8683        CGAbstractStaticMethod.__init__(self, descriptor, MAY_RESOLVE_HOOK_NAME,
8684                                        "bool", args)
8685
8686    def definition_body(self):
8687        if self.descriptor.isGlobal():
8688            # Check whether this would resolve as a standard class.
8689            prefix = dedent("""
8690                if (MayResolveGlobal(names, id, maybeObj)) {
8691                  return true;
8692                }
8693
8694                """)
8695        else:
8696            prefix = ""
8697        return (prefix +
8698                "return %s::MayResolve(id);\n" % self.descriptor.nativeType)
8699
8700
8701class CGEnumerateHook(CGAbstractBindingMethod):
8702    """
8703    Enumerate hook for objects with custom hooks.
8704    """
8705    def __init__(self, descriptor):
8706        assert descriptor.interface.getExtendedAttribute("NeedResolve")
8707
8708        args = [Argument('JSContext*', 'cx'),
8709                Argument('JS::Handle<JSObject*>', 'obj')]
8710        # Our "self" is actually the "obj" argument in this case, not the thisval.
8711        CGAbstractBindingMethod.__init__(
8712            self, descriptor, ENUMERATE_HOOK_NAME,
8713            args, getThisObj="", callArgs="")
8714
8715    def generate_code(self):
8716        return CGGeneric(dedent("""
8717            AutoTArray<nsString, 8> names;
8718            binding_detail::FastErrorResult rv;
8719            self->GetOwnPropertyNames(cx, names, rv);
8720            if (rv.MaybeSetPendingException(cx)) {
8721              return false;
8722            }
8723            bool dummy;
8724            for (uint32_t i = 0; i < names.Length(); ++i) {
8725              if (!JS_HasUCProperty(cx, obj, names[i].get(), names[i].Length(), &dummy)) {
8726                return false;
8727              }
8728            }
8729            return true;
8730            """))
8731
8732    def definition_body(self):
8733        if self.descriptor.isGlobal():
8734            # Enumerate standard classes
8735            prefix = dedent("""
8736                if (!EnumerateGlobal(cx, obj)) {
8737                  return false;
8738                }
8739
8740                """)
8741        else:
8742            prefix = ""
8743        return prefix + CGAbstractBindingMethod.definition_body(self)
8744
8745
8746class CppKeywords():
8747    """
8748    A class for checking if method names declared in webidl
8749    are not in conflict with C++ keywords.
8750    """
8751    keywords = frozenset([
8752        'alignas', 'alignof', 'and', 'and_eq', 'asm', 'assert', 'auto', 'bitand', 'bitor', 'bool',
8753        'break', 'case', 'catch', 'char', 'char16_t', 'char32_t', 'class', 'compl', 'const',
8754        'constexpr', 'const_cast', 'continue', 'decltype', 'default', 'delete', 'do', 'double',
8755        'dynamic_cast', 'else', 'enum', 'explicit', 'export', 'extern', 'false', 'final', 'float',
8756        'for', 'friend', 'goto', 'if', 'inline', 'int', 'long', 'mutable', 'namespace', 'new',
8757        'noexcept', 'not', 'not_eq', 'nullptr', 'operator', 'or', 'or_eq', 'override', 'private',
8758        'protected', 'public', 'register', 'reinterpret_cast', 'return', 'short', 'signed',
8759        'sizeof', 'static', 'static_assert', 'static_cast', 'struct', 'switch', 'template', 'this',
8760        'thread_local', 'throw', 'true', 'try', 'typedef', 'typeid', 'typename', 'union',
8761        'unsigned', 'using', 'virtual', 'void', 'volatile', 'wchar_t', 'while', 'xor', 'xor_eq'])
8762
8763    @staticmethod
8764    def checkMethodName(name):
8765        # Double '_' because 'assert' and '_assert' cannot be used in MS2013 compiler.
8766        # Bug 964892 and bug 963560.
8767        if name in CppKeywords.keywords:
8768            name = '_' + name + '_'
8769        return name
8770
8771
8772class CGStaticMethod(CGAbstractStaticBindingMethod):
8773    """
8774    A class for generating the C++ code for an IDL static method.
8775    """
8776    def __init__(self, descriptor, method):
8777        self.method = method
8778        name = CppKeywords.checkMethodName(IDLToCIdentifier(method.identifier.name))
8779        CGAbstractStaticBindingMethod.__init__(self, descriptor, name)
8780
8781    def generate_code(self):
8782        nativeName = CGSpecializedMethod.makeNativeName(self.descriptor,
8783                                                        self.method)
8784        return CGMethodCall(nativeName, True, self.descriptor, self.method)
8785
8786
8787class CGGenericGetter(CGAbstractBindingMethod):
8788    """
8789    A class for generating the C++ code for an IDL attribute getter.
8790    """
8791    def __init__(self, descriptor, lenientThis=False, allowCrossOriginThis=False):
8792        if lenientThis:
8793            name = "genericLenientGetter"
8794            unwrapFailureCode = dedent("""
8795                MOZ_ASSERT(!JS_IsExceptionPending(cx));
8796                if (!ReportLenientThisUnwrappingFailure(cx, &args.callee())) {
8797                  return false;
8798                }
8799                args.rval().set(JS::UndefinedValue());
8800                return true;
8801                """)
8802        else:
8803            if allowCrossOriginThis:
8804                name = "genericCrossOriginGetter"
8805            else:
8806                name = "genericGetter"
8807            unwrapFailureCode = (
8808                'return ThrowInvalidThis(cx, args, %%(securityError)s, "%s");\n' %
8809                descriptor.interface.identifier.name)
8810        CGAbstractBindingMethod.__init__(self, descriptor, name, JSNativeArguments(),
8811                                         unwrapFailureCode,
8812                                         allowCrossOriginThis=allowCrossOriginThis)
8813
8814    def generate_code(self):
8815        return CGGeneric(dedent("""
8816            const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
8817            MOZ_ASSERT(info->type() == JSJitInfo::Getter);
8818            JSJitGetterOp getter = info->getter;
8819            bool ok = getter(cx, obj, self, JSJitGetterCallArgs(args));
8820            #ifdef DEBUG
8821            if (ok) {
8822              AssertReturnTypeMatchesJitinfo(info, args.rval());
8823            }
8824            #endif
8825            return ok;
8826            """))
8827
8828
8829class CGSpecializedGetter(CGAbstractStaticMethod):
8830    """
8831    A class for generating the code for a specialized attribute getter
8832    that the JIT can call with lower overhead.
8833    """
8834    def __init__(self, descriptor, attr):
8835        self.attr = attr
8836        name = 'get_' + IDLToCIdentifier(attr.identifier.name)
8837        args = [
8838            Argument('JSContext*', 'cx'),
8839            Argument('JS::Handle<JSObject*>', 'obj'),
8840            Argument('%s*' % descriptor.nativeType, 'self'),
8841            Argument('JSJitGetterCallArgs', 'args')
8842        ]
8843        CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args)
8844
8845    def definition_body(self):
8846        if self.attr.isMaplikeOrSetlikeAttr():
8847            # If the interface is maplike/setlike, there will be one getter
8848            # method for the size property of the backing object. Due to having
8849            # to unpack the backing object from the slot, this requires its own
8850            # generator.
8851            return getMaplikeOrSetlikeSizeGetterBody(self.descriptor, self.attr)
8852        nativeName = CGSpecializedGetter.makeNativeName(self.descriptor,
8853                                                        self.attr)
8854        if self.attr.slotIndices is not None:
8855            if self.descriptor.hasXPConnectImpls:
8856                raise TypeError("Interface '%s' has XPConnect impls, so we "
8857                                "can't use our slot for property '%s'!" %
8858                                (self.descriptor.interface.identifier.name,
8859                                 self.attr.identifier.name))
8860
8861            # We're going to store this return value in a slot on some object,
8862            # to cache it.  The question is, which object?  For dictionary and
8863            # sequence return values, we want to use a slot on the Xray expando
8864            # if we're called via Xrays, and a slot on our reflector otherwise.
8865            # On the other hand, when dealing with some interfacce types
8866            # (navigator properties, window.document) we want to avoid calling
8867            # the getter more than once.  In the case of navigator properties
8868            # that's because the getter actually creates a new object each time.
8869            # In the case of window.document, it's because the getter can start
8870            # returning null, which would get hidden in he non-Xray case by the
8871            # fact that it's [StoreOnSlot], so the cached version is always
8872            # around.
8873            #
8874            # The upshot is that we use the reflector slot for any getter whose
8875            # type is a gecko interface, whether we're called via Xrays or not.
8876            # Since [Cached] and [StoreInSlot] cannot be used with "NewObject",
8877            # we know that in the interface type case the returned object is
8878            # wrappercached.  So creating Xrays to it is reasonable.
8879            if mayUseXrayExpandoSlots(self.descriptor, self.attr):
8880                prefix = fill(
8881                    """
8882                    // Have to either root across the getter call or reget after.
8883                    bool isXray;
8884                    JS::Rooted<JSObject*> slotStorage(cx, GetCachedSlotStorageObject(cx, obj, &isXray));
8885                    if (!slotStorage) {
8886                      return false;
8887                    }
8888                    const size_t slotIndex = isXray ? ${xraySlotIndex} : ${slotIndex};
8889                    """,
8890                    xraySlotIndex=memberXrayExpandoReservedSlot(self.attr,
8891                                                                self.descriptor),
8892                    slotIndex=memberReservedSlot(self.attr, self.descriptor))
8893            else:
8894                prefix = fill(
8895                    """
8896                    // Have to either root across the getter call or reget after.
8897                    JS::Rooted<JSObject*> slotStorage(cx, js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false));
8898                    MOZ_ASSERT(IsDOMObject(slotStorage));
8899                    const size_t slotIndex = ${slotIndex};
8900                    """,
8901                    slotIndex=memberReservedSlot(self.attr, self.descriptor))
8902
8903            prefix += fill(
8904                """
8905                MOZ_ASSERT(JSCLASS_RESERVED_SLOTS(js::GetObjectClass(slotStorage)) > slotIndex);
8906                {
8907                  // Scope for cachedVal
8908                  JS::Value cachedVal = js::GetReservedSlot(slotStorage, slotIndex);
8909                  if (!cachedVal.isUndefined()) {
8910                    args.rval().set(cachedVal);
8911                    // The cached value is in the compartment of slotStorage,
8912                    // so wrap into the caller compartment as needed.
8913                    return ${maybeWrap}(cx, args.rval());
8914                  }
8915                }
8916
8917                """,
8918                maybeWrap=getMaybeWrapValueFuncForType(self.attr.type))
8919        else:
8920            prefix = ""
8921
8922        if self.attr.navigatorObjectGetter:
8923            cgGetterCall = CGNavigatorGetterCall
8924        else:
8925            cgGetterCall = CGGetterCall
8926        return (prefix +
8927                cgGetterCall(self.attr.type, nativeName,
8928                             self.descriptor, self.attr).define())
8929
8930    @staticmethod
8931    def makeNativeName(descriptor, attr):
8932        name = attr.identifier.name
8933        nativeName = MakeNativeName(descriptor.binaryNameFor(name))
8934        _, resultOutParam, _, _, _ = getRetvalDeclarationForType(attr.type,
8935                                                                 descriptor)
8936        infallible = ('infallible' in
8937                      descriptor.getExtendedAttributes(attr, getter=True))
8938        if resultOutParam or attr.type.nullable() or not infallible:
8939            nativeName = "Get" + nativeName
8940        return nativeName
8941
8942
8943class CGStaticGetter(CGAbstractStaticBindingMethod):
8944    """
8945    A class for generating the C++ code for an IDL static attribute getter.
8946    """
8947    def __init__(self, descriptor, attr):
8948        self.attr = attr
8949        name = 'get_' + IDLToCIdentifier(attr.identifier.name)
8950        CGAbstractStaticBindingMethod.__init__(self, descriptor, name)
8951
8952    def generate_code(self):
8953        nativeName = CGSpecializedGetter.makeNativeName(self.descriptor,
8954                                                        self.attr)
8955        return CGGetterCall(self.attr.type, nativeName, self.descriptor,
8956                            self.attr)
8957
8958
8959class CGGenericSetter(CGAbstractBindingMethod):
8960    """
8961    A class for generating the C++ code for an IDL attribute setter.
8962    """
8963    def __init__(self, descriptor, lenientThis=False, allowCrossOriginThis=False):
8964        if lenientThis:
8965            name = "genericLenientSetter"
8966            unwrapFailureCode = dedent("""
8967                MOZ_ASSERT(!JS_IsExceptionPending(cx));
8968                if (!ReportLenientThisUnwrappingFailure(cx, &args.callee())) {
8969                  return false;
8970                }
8971                args.rval().set(JS::UndefinedValue());
8972                return true;
8973                """)
8974        else:
8975            if allowCrossOriginThis:
8976                name = "genericCrossOriginSetter"
8977            else:
8978                name = "genericSetter"
8979            unwrapFailureCode = (
8980                'return ThrowInvalidThis(cx, args, %%(securityError)s, "%s");\n' %
8981                descriptor.interface.identifier.name)
8982
8983        CGAbstractBindingMethod.__init__(self, descriptor, name, JSNativeArguments(),
8984                                         unwrapFailureCode,
8985                                         allowCrossOriginThis=allowCrossOriginThis)
8986
8987    def generate_code(self):
8988        return CGGeneric(fill(
8989            """
8990            if (args.length() == 0) {
8991              return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "${name} attribute setter");
8992            }
8993            const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
8994            MOZ_ASSERT(info->type() == JSJitInfo::Setter);
8995            JSJitSetterOp setter = info->setter;
8996            if (!setter(cx, obj, self, JSJitSetterCallArgs(args))) {
8997              return false;
8998            }
8999            args.rval().setUndefined();
9000            #ifdef DEBUG
9001            AssertReturnTypeMatchesJitinfo(info, args.rval());
9002            #endif
9003            return true;
9004            """,
9005            name=self.descriptor.interface.identifier.name))
9006
9007
9008class CGSpecializedSetter(CGAbstractStaticMethod):
9009    """
9010    A class for generating the code for a specialized attribute setter
9011    that the JIT can call with lower overhead.
9012    """
9013    def __init__(self, descriptor, attr):
9014        self.attr = attr
9015        name = 'set_' + IDLToCIdentifier(attr.identifier.name)
9016        args = [Argument('JSContext*', 'cx'),
9017                Argument('JS::Handle<JSObject*>', 'obj'),
9018                Argument('%s*' % descriptor.nativeType, 'self'),
9019                Argument('JSJitSetterCallArgs', 'args')]
9020        CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args)
9021
9022    def definition_body(self):
9023        nativeName = CGSpecializedSetter.makeNativeName(self.descriptor,
9024                                                        self.attr)
9025        return CGSetterCall(self.attr.type, nativeName, self.descriptor,
9026                            self.attr).define()
9027
9028    @staticmethod
9029    def makeNativeName(descriptor, attr):
9030        name = attr.identifier.name
9031        return "Set" + MakeNativeName(descriptor.binaryNameFor(name))
9032
9033
9034class CGStaticSetter(CGAbstractStaticBindingMethod):
9035    """
9036    A class for generating the C++ code for an IDL static attribute setter.
9037    """
9038    def __init__(self, descriptor, attr):
9039        self.attr = attr
9040        name = 'set_' + IDLToCIdentifier(attr.identifier.name)
9041        CGAbstractStaticBindingMethod.__init__(self, descriptor, name)
9042
9043    def generate_code(self):
9044        nativeName = CGSpecializedSetter.makeNativeName(self.descriptor,
9045                                                        self.attr)
9046        checkForArg = CGGeneric(fill(
9047            """
9048            if (args.length() == 0) {
9049              return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "${name} setter");
9050            }
9051            """,
9052            name=self.attr.identifier.name))
9053        call = CGSetterCall(self.attr.type, nativeName, self.descriptor,
9054                            self.attr)
9055        return CGList([checkForArg, call])
9056
9057
9058class CGSpecializedForwardingSetter(CGSpecializedSetter):
9059    """
9060    A class for generating the code for a specialized attribute setter with
9061    PutForwards that the JIT can call with lower overhead.
9062    """
9063    def __init__(self, descriptor, attr):
9064        CGSpecializedSetter.__init__(self, descriptor, attr)
9065
9066    def definition_body(self):
9067        attrName = self.attr.identifier.name
9068        forwardToAttrName = self.attr.getExtendedAttribute("PutForwards")[0]
9069        # JS_GetProperty and JS_SetProperty can only deal with ASCII
9070        assert all(ord(c) < 128 for c in attrName)
9071        assert all(ord(c) < 128 for c in forwardToAttrName)
9072        return fill(
9073            """
9074            JS::Rooted<JS::Value> v(cx);
9075            if (!JS_GetProperty(cx, obj, "${attr}", &v)) {
9076              return false;
9077            }
9078
9079            if (!v.isObject()) {
9080              return ThrowErrorMessage(cx, MSG_NOT_OBJECT, "${interface}.${attr}");
9081            }
9082
9083            JS::Rooted<JSObject*> targetObj(cx, &v.toObject());
9084            return JS_SetProperty(cx, targetObj, "${forwardToAttrName}", args[0]);
9085            """,
9086            attr=attrName,
9087            interface=self.descriptor.interface.identifier.name,
9088            forwardToAttrName=forwardToAttrName)
9089
9090
9091class CGSpecializedReplaceableSetter(CGSpecializedSetter):
9092    """
9093    A class for generating the code for a specialized attribute setter with
9094    Replaceable that the JIT can call with lower overhead.
9095    """
9096    def __init__(self, descriptor, attr):
9097        CGSpecializedSetter.__init__(self, descriptor, attr)
9098
9099    def definition_body(self):
9100        attrName = self.attr.identifier.name
9101        # JS_DefineProperty can only deal with ASCII
9102        assert all(ord(c) < 128 for c in attrName)
9103        return ('return JS_DefineProperty(cx, obj, "%s", args[0], JSPROP_ENUMERATE);\n' %
9104                attrName)
9105
9106
9107class CGSpecializedLenientSetter(CGSpecializedSetter):
9108    """
9109    A class for generating the code for a specialized attribute setter with
9110    LenientSetter that the JIT can call with lower overhead.
9111    """
9112    def __init__(self, descriptor, attr):
9113        CGSpecializedSetter.__init__(self, descriptor, attr)
9114
9115    def definition_body(self):
9116        attrName = self.attr.identifier.name
9117        # JS_DefineProperty can only deal with ASCII
9118        assert all(ord(c) < 128 for c in attrName)
9119        return dedent("""
9120            DeprecationWarning(cx, obj, nsIDocument::eLenientSetter);
9121            return true;
9122            """)
9123
9124
9125def memberReturnsNewObject(member):
9126    return member.getExtendedAttribute("NewObject") is not None
9127
9128
9129class CGMemberJITInfo(CGThing):
9130    """
9131    A class for generating the JITInfo for a property that points to
9132    our specialized getter and setter.
9133    """
9134    def __init__(self, descriptor, member):
9135        self.member = member
9136        self.descriptor = descriptor
9137
9138    def declare(self):
9139        return ""
9140
9141    def defineJitInfo(self, infoName, opName, opType, infallible, movable,
9142                      eliminatable, aliasSet, alwaysInSlot, lazilyInSlot,
9143                      slotIndex, returnTypes, args):
9144        """
9145        aliasSet is a JSJitInfo::AliasSet value, without the "JSJitInfo::" bit.
9146
9147        args is None if we don't want to output argTypes for some
9148        reason (e.g. we have overloads or we're not a method) and
9149        otherwise an iterable of the arguments for this method.
9150        """
9151        assert(not movable or aliasSet != "AliasEverything")  # Can't move write-aliasing things
9152        assert(not alwaysInSlot or movable)  # Things always in slots had better be movable
9153        assert(not eliminatable or aliasSet != "AliasEverything")  # Can't eliminate write-aliasing things
9154        assert(not alwaysInSlot or eliminatable)  # Things always in slots had better be eliminatable
9155
9156        def jitInfoInitializer(isTypedMethod):
9157            initializer = fill(
9158                """
9159                {
9160                  { ${opName} },
9161                  { prototypes::id::${name} },
9162                  { PrototypeTraits<prototypes::id::${name}>::Depth },
9163                  JSJitInfo::${opType},
9164                  JSJitInfo::${aliasSet}, /* aliasSet.  Not relevant for setters. */
9165                  ${returnType},  /* returnType.  Not relevant for setters. */
9166                  ${isInfallible},  /* isInfallible. False in setters. */
9167                  ${isMovable},  /* isMovable.  Not relevant for setters. */
9168                  ${isEliminatable}, /* isEliminatable.  Not relevant for setters. */
9169                  ${isAlwaysInSlot}, /* isAlwaysInSlot.  Only relevant for getters. */
9170                  ${isLazilyCachedInSlot}, /* isLazilyCachedInSlot.  Only relevant for getters. */
9171                  ${isTypedMethod},  /* isTypedMethod.  Only relevant for methods. */
9172                  ${slotIndex}   /* Reserved slot index, if we're stored in a slot, else 0. */
9173                }
9174                """,
9175                opName=opName,
9176                name=self.descriptor.name,
9177                opType=opType,
9178                aliasSet=aliasSet,
9179                returnType=reduce(CGMemberJITInfo.getSingleReturnType, returnTypes,
9180                                  ""),
9181                isInfallible=toStringBool(infallible),
9182                isMovable=toStringBool(movable),
9183                isEliminatable=toStringBool(eliminatable),
9184                isAlwaysInSlot=toStringBool(alwaysInSlot),
9185                isLazilyCachedInSlot=toStringBool(lazilyInSlot),
9186                isTypedMethod=toStringBool(isTypedMethod),
9187                slotIndex=slotIndex)
9188            return initializer.rstrip()
9189
9190        slotAssert = fill(
9191            """
9192            static_assert(${slotIndex} <= JSJitInfo::maxSlotIndex, "We won't fit");
9193            static_assert(${slotIndex} < ${classReservedSlots}, "There is no slot for us");
9194            """,
9195            slotIndex=slotIndex,
9196            classReservedSlots=INSTANCE_RESERVED_SLOTS + self.descriptor.interface.totalMembersInSlots)
9197        if args is not None:
9198            argTypes = "%s_argTypes" % infoName
9199            args = [CGMemberJITInfo.getJSArgType(arg.type) for arg in args]
9200            args.append("JSJitInfo::ArgTypeListEnd")
9201            argTypesDecl = (
9202                "static const JSJitInfo::ArgType %s[] = { %s };\n" %
9203                (argTypes, ", ".join(args)))
9204            return fill(
9205                """
9206                $*{argTypesDecl}
9207                static const JSTypedMethodJitInfo ${infoName} = {
9208                ${jitInfo},
9209                  ${argTypes}
9210                };
9211                $*{slotAssert}
9212                """,
9213                argTypesDecl=argTypesDecl,
9214                infoName=infoName,
9215                jitInfo=indent(jitInfoInitializer(True)),
9216                argTypes=argTypes,
9217                slotAssert=slotAssert)
9218
9219        return fill(
9220            """
9221            static const JSJitInfo ${infoName} = ${jitInfo};
9222            $*{slotAssert}
9223            """,
9224            infoName=infoName,
9225            jitInfo=jitInfoInitializer(False),
9226            slotAssert=slotAssert)
9227
9228    def define(self):
9229        if self.member.isAttr():
9230            getterinfo = ("%s_getterinfo" %
9231                          IDLToCIdentifier(self.member.identifier.name))
9232            # We need the cast here because JSJitGetterOp has a "void* self"
9233            # while we have the right type.
9234            getter = ("(JSJitGetterOp)get_%s" %
9235                      IDLToCIdentifier(self.member.identifier.name))
9236            getterinfal = "infallible" in self.descriptor.getExtendedAttributes(self.member, getter=True)
9237
9238            movable = self.mayBeMovable() and getterinfal
9239            eliminatable = self.mayBeEliminatable() and getterinfal
9240            aliasSet = self.aliasSet()
9241
9242            getterinfal = getterinfal and infallibleForMember(self.member, self.member.type, self.descriptor)
9243            isAlwaysInSlot = self.member.getExtendedAttribute("StoreInSlot")
9244            if self.member.slotIndices is not None:
9245                assert isAlwaysInSlot or self.member.getExtendedAttribute("Cached")
9246                isLazilyCachedInSlot = not isAlwaysInSlot
9247                slotIndex = memberReservedSlot(self.member, self.descriptor)
9248                # We'll statically assert that this is not too big in
9249                # CGUpdateMemberSlotsMethod, in the case when
9250                # isAlwaysInSlot is true.
9251            else:
9252                isLazilyCachedInSlot = False
9253                slotIndex = "0"
9254
9255            result = self.defineJitInfo(getterinfo, getter, "Getter",
9256                                        getterinfal, movable, eliminatable,
9257                                        aliasSet, isAlwaysInSlot,
9258                                        isLazilyCachedInSlot, slotIndex,
9259                                        [self.member.type], None)
9260            if (not self.member.readonly or
9261                self.member.getExtendedAttribute("PutForwards") is not None or
9262                self.member.getExtendedAttribute("Replaceable") is not None or
9263                self.member.getExtendedAttribute("LenientSetter") is not None):
9264                setterinfo = ("%s_setterinfo" %
9265                              IDLToCIdentifier(self.member.identifier.name))
9266                # Actually a JSJitSetterOp, but JSJitGetterOp is first in the
9267                # union.
9268                setter = ("(JSJitGetterOp)set_%s" %
9269                          IDLToCIdentifier(self.member.identifier.name))
9270                # Setters are always fallible, since they have to do a typed unwrap.
9271                result += self.defineJitInfo(setterinfo, setter, "Setter",
9272                                             False, False, False, "AliasEverything",
9273                                             False, False, "0",
9274                                             [BuiltinTypes[IDLBuiltinType.Types.void]],
9275                                             None)
9276            return result
9277        if self.member.isMethod():
9278            methodinfo = ("%s_methodinfo" %
9279                          IDLToCIdentifier(self.member.identifier.name))
9280            name = CppKeywords.checkMethodName(
9281                IDLToCIdentifier(self.member.identifier.name))
9282            if self.member.returnsPromise():
9283                name = CGMethodPromiseWrapper.makeName(name)
9284            # Actually a JSJitMethodOp, but JSJitGetterOp is first in the union.
9285            method = ("(JSJitGetterOp)%s" % name)
9286
9287            # Methods are infallible if they are infallible, have no arguments
9288            # to unwrap, and have a return type that's infallible to wrap up for
9289            # return.
9290            sigs = self.member.signatures()
9291            if len(sigs) != 1:
9292                # Don't handle overloading.  If there's more than one signature,
9293                # one of them must take arguments.
9294                methodInfal = False
9295                args = None
9296                movable = False
9297                eliminatable = False
9298            else:
9299                sig = sigs[0]
9300                # For methods that affect nothing, it's OK to set movable to our
9301                # notion of infallible on the C++ side, without considering
9302                # argument conversions, since argument conversions that can
9303                # reliably throw would be effectful anyway and the jit doesn't
9304                # move effectful things.
9305                hasInfallibleImpl = "infallible" in self.descriptor.getExtendedAttributes(self.member)
9306                movable = self.mayBeMovable() and hasInfallibleImpl
9307                eliminatable = self.mayBeEliminatable() and hasInfallibleImpl
9308                # XXXbz can we move the smarts about fallibility due to arg
9309                # conversions into the JIT, using our new args stuff?
9310                if (len(sig[1]) != 0 or
9311                    not infallibleForMember(self.member, sig[0], self.descriptor)):
9312                    # We have arguments or our return-value boxing can fail
9313                    methodInfal = False
9314                else:
9315                    methodInfal = hasInfallibleImpl
9316                # For now, only bother to output args if we're side-effect-free.
9317                if self.member.affects == "Nothing":
9318                    args = sig[1]
9319                else:
9320                    args = None
9321
9322            aliasSet = self.aliasSet()
9323            result = self.defineJitInfo(methodinfo, method, "Method",
9324                                        methodInfal, movable, eliminatable,
9325                                        aliasSet, False, False, "0",
9326                                        [s[0] for s in sigs], args)
9327            return result
9328        raise TypeError("Illegal member type to CGPropertyJITInfo")
9329
9330    def mayBeMovable(self):
9331        """
9332        Returns whether this attribute or method may be movable, just
9333        based on Affects/DependsOn annotations.
9334        """
9335        affects = self.member.affects
9336        dependsOn = self.member.dependsOn
9337        assert affects in IDLInterfaceMember.AffectsValues
9338        assert dependsOn in IDLInterfaceMember.DependsOnValues
9339        # Things that are DependsOn=DeviceState are not movable, because we
9340        # don't want them coalesced with each other or loop-hoisted, since
9341        # their return value can change even if nothing is going on from our
9342        # point of view.
9343        return (affects == "Nothing" and
9344                (dependsOn != "Everything" and dependsOn != "DeviceState"))
9345
9346    def mayBeEliminatable(self):
9347        """
9348        Returns whether this attribute or method may be eliminatable, just
9349        based on Affects/DependsOn annotations.
9350        """
9351        # dependsOn shouldn't affect this decision at all, except in jitinfo we
9352        # have no way to express "Depends on everything, affects nothing",
9353        # because we only have three alias set values: AliasNone ("depends on
9354        # nothing, affects nothing"), AliasDOMSets ("depends on DOM sets,
9355        # affects nothing"), AliasEverything ("depends on everything, affects
9356        # everything").  So the [Affects=Nothing, DependsOn=Everything] case
9357        # gets encoded as AliasEverything and defineJitInfo asserts that if our
9358        # alias state is AliasEverything then we're not eliminatable (because it
9359        # thinks we might have side-effects at that point).  Bug 1155796 is
9360        # tracking possible solutions for this.
9361        affects = self.member.affects
9362        dependsOn = self.member.dependsOn
9363        assert affects in IDLInterfaceMember.AffectsValues
9364        assert dependsOn in IDLInterfaceMember.DependsOnValues
9365        return affects == "Nothing" and dependsOn != "Everything"
9366
9367    def aliasSet(self):
9368        """
9369        Returns the alias set to store in the jitinfo.  This may not be the
9370        effective alias set the JIT uses, depending on whether we have enough
9371        information about our args to allow the JIT to prove that effectful
9372        argument conversions won't happen.
9373        """
9374        dependsOn = self.member.dependsOn
9375        assert dependsOn in IDLInterfaceMember.DependsOnValues
9376
9377        if dependsOn == "Nothing" or dependsOn == "DeviceState":
9378            assert self.member.affects == "Nothing"
9379            return "AliasNone"
9380
9381        if dependsOn == "DOMState":
9382            assert self.member.affects == "Nothing"
9383            return "AliasDOMSets"
9384
9385        return "AliasEverything"
9386
9387    @staticmethod
9388    def getJSReturnTypeTag(t):
9389        if t.nullable():
9390            # Sometimes it might return null, sometimes not
9391            return "JSVAL_TYPE_UNKNOWN"
9392        if t.isVoid():
9393            # No return, every time
9394            return "JSVAL_TYPE_UNDEFINED"
9395        if t.isSequence():
9396            return "JSVAL_TYPE_OBJECT"
9397        if t.isMozMap():
9398            return "JSVAL_TYPE_OBJECT"
9399        if t.isGeckoInterface():
9400            return "JSVAL_TYPE_OBJECT"
9401        if t.isString():
9402            return "JSVAL_TYPE_STRING"
9403        if t.isEnum():
9404            return "JSVAL_TYPE_STRING"
9405        if t.isCallback():
9406            return "JSVAL_TYPE_OBJECT"
9407        if t.isAny():
9408            # The whole point is to return various stuff
9409            return "JSVAL_TYPE_UNKNOWN"
9410        if t.isObject():
9411            return "JSVAL_TYPE_OBJECT"
9412        if t.isSpiderMonkeyInterface():
9413            return "JSVAL_TYPE_OBJECT"
9414        if t.isUnion():
9415            u = t.unroll()
9416            if u.hasNullableType:
9417                # Might be null or not
9418                return "JSVAL_TYPE_UNKNOWN"
9419            return reduce(CGMemberJITInfo.getSingleReturnType,
9420                          u.flatMemberTypes, "")
9421        if t.isDictionary():
9422            return "JSVAL_TYPE_OBJECT"
9423        if t.isDate():
9424            return "JSVAL_TYPE_OBJECT"
9425        if not t.isPrimitive():
9426            raise TypeError("No idea what type " + str(t) + " is.")
9427        tag = t.tag()
9428        if tag == IDLType.Tags.bool:
9429            return "JSVAL_TYPE_BOOLEAN"
9430        if tag in [IDLType.Tags.int8, IDLType.Tags.uint8,
9431                   IDLType.Tags.int16, IDLType.Tags.uint16,
9432                   IDLType.Tags.int32]:
9433            return "JSVAL_TYPE_INT32"
9434        if tag in [IDLType.Tags.int64, IDLType.Tags.uint64,
9435                   IDLType.Tags.unrestricted_float, IDLType.Tags.float,
9436                   IDLType.Tags.unrestricted_double, IDLType.Tags.double]:
9437            # These all use JS_NumberValue, which can return int or double.
9438            # But TI treats "double" as meaning "int or double", so we're
9439            # good to return JSVAL_TYPE_DOUBLE here.
9440            return "JSVAL_TYPE_DOUBLE"
9441        if tag != IDLType.Tags.uint32:
9442            raise TypeError("No idea what type " + str(t) + " is.")
9443        # uint32 is sometimes int and sometimes double.
9444        return "JSVAL_TYPE_DOUBLE"
9445
9446    @staticmethod
9447    def getSingleReturnType(existingType, t):
9448        type = CGMemberJITInfo.getJSReturnTypeTag(t)
9449        if existingType == "":
9450            # First element of the list; just return its type
9451            return type
9452
9453        if type == existingType:
9454            return existingType
9455        if ((type == "JSVAL_TYPE_DOUBLE" and
9456             existingType == "JSVAL_TYPE_INT32") or
9457            (existingType == "JSVAL_TYPE_DOUBLE" and
9458             type == "JSVAL_TYPE_INT32")):
9459            # Promote INT32 to DOUBLE as needed
9460            return "JSVAL_TYPE_DOUBLE"
9461        # Different types
9462        return "JSVAL_TYPE_UNKNOWN"
9463
9464    @staticmethod
9465    def getJSArgType(t):
9466        assert not t.isVoid()
9467        if t.nullable():
9468            # Sometimes it might return null, sometimes not
9469            return "JSJitInfo::ArgType(JSJitInfo::Null | %s)" % CGMemberJITInfo.getJSArgType(t.inner)
9470        if t.isSequence():
9471            return "JSJitInfo::Object"
9472        if t.isGeckoInterface():
9473            return "JSJitInfo::Object"
9474        if t.isString():
9475            return "JSJitInfo::String"
9476        if t.isEnum():
9477            return "JSJitInfo::String"
9478        if t.isCallback():
9479            return "JSJitInfo::Object"
9480        if t.isAny():
9481            # The whole point is to return various stuff
9482            return "JSJitInfo::Any"
9483        if t.isObject():
9484            return "JSJitInfo::Object"
9485        if t.isSpiderMonkeyInterface():
9486            return "JSJitInfo::Object"
9487        if t.isUnion():
9488            u = t.unroll()
9489            type = "JSJitInfo::Null" if u.hasNullableType else ""
9490            return ("JSJitInfo::ArgType(%s)" %
9491                    reduce(CGMemberJITInfo.getSingleArgType,
9492                           u.flatMemberTypes, type))
9493        if t.isDictionary():
9494            return "JSJitInfo::Object"
9495        if t.isDate():
9496            return "JSJitInfo::Object"
9497        if not t.isPrimitive():
9498            raise TypeError("No idea what type " + str(t) + " is.")
9499        tag = t.tag()
9500        if tag == IDLType.Tags.bool:
9501            return "JSJitInfo::Boolean"
9502        if tag in [IDLType.Tags.int8, IDLType.Tags.uint8,
9503                   IDLType.Tags.int16, IDLType.Tags.uint16,
9504                   IDLType.Tags.int32]:
9505            return "JSJitInfo::Integer"
9506        if tag in [IDLType.Tags.int64, IDLType.Tags.uint64,
9507                   IDLType.Tags.unrestricted_float, IDLType.Tags.float,
9508                   IDLType.Tags.unrestricted_double, IDLType.Tags.double]:
9509            # These all use JS_NumberValue, which can return int or double.
9510            # But TI treats "double" as meaning "int or double", so we're
9511            # good to return JSVAL_TYPE_DOUBLE here.
9512            return "JSJitInfo::Double"
9513        if tag != IDLType.Tags.uint32:
9514            raise TypeError("No idea what type " + str(t) + " is.")
9515        # uint32 is sometimes int and sometimes double.
9516        return "JSJitInfo::Double"
9517
9518    @staticmethod
9519    def getSingleArgType(existingType, t):
9520        type = CGMemberJITInfo.getJSArgType(t)
9521        if existingType == "":
9522            # First element of the list; just return its type
9523            return type
9524
9525        if type == existingType:
9526            return existingType
9527        return "%s | %s" % (existingType, type)
9528
9529
9530class CGStaticMethodJitinfo(CGGeneric):
9531    """
9532    A class for generating the JITInfo for a promise-returning static method.
9533    """
9534    def __init__(self, method):
9535        CGGeneric.__init__(
9536            self,
9537            "\n"
9538            "static const JSJitInfo %s_methodinfo = {\n"
9539            "  { (JSJitGetterOp)%s },\n"
9540            "  { prototypes::id::_ID_Count }, { 0 }, JSJitInfo::StaticMethod,\n"
9541            "  JSJitInfo::AliasEverything, JSVAL_TYPE_MISSING, false, false,\n"
9542            "  false, false, 0\n"
9543            "};\n" %
9544            (IDLToCIdentifier(method.identifier.name),
9545             CppKeywords.checkMethodName(
9546                 IDLToCIdentifier(method.identifier.name))))
9547
9548
9549def getEnumValueName(value):
9550    # Some enum values can be empty strings.  Others might have weird
9551    # characters in them.  Deal with the former by returning "_empty",
9552    # deal with possible name collisions from that by throwing if the
9553    # enum value is actually "_empty", and throw on any value
9554    # containing non-ASCII chars for now. Replace all chars other than
9555    # [0-9A-Za-z_] with '_'.
9556    if re.match("[^\x20-\x7E]", value):
9557        raise SyntaxError('Enum value "' + value + '" contains non-ASCII characters')
9558    if re.match("^[0-9]", value):
9559        return '_' + value
9560    value = re.sub(r'[^0-9A-Za-z_]', '_', value)
9561    if re.match("^_[A-Z]|__", value):
9562        raise SyntaxError('Enum value "' + value + '" is reserved by the C++ spec')
9563    if value == "_empty":
9564        raise SyntaxError('"_empty" is not an IDL enum value we support yet')
9565    if value == "":
9566        return "_empty"
9567    nativeName = MakeNativeName(value)
9568    if nativeName == "EndGuard_":
9569        raise SyntaxError('Enum value "' + value + '" cannot be used because it'
9570                          ' collides with our internal EndGuard_ value.  Please'
9571                          ' rename our internal EndGuard_ to something else')
9572    return nativeName
9573
9574class CGEnumToJSValue(CGAbstractMethod):
9575    def __init__(self, enum):
9576        enumType = enum.identifier.name
9577        self.stringsArray = enumType + "Values::" + ENUM_ENTRY_VARIABLE_NAME
9578        CGAbstractMethod.__init__(self, None, "ToJSValue", "bool",
9579                                  [Argument("JSContext*", "aCx"),
9580                                   Argument(enumType, "aArgument"),
9581                                   Argument("JS::MutableHandle<JS::Value>",
9582                                            "aValue")])
9583
9584    def definition_body(self):
9585        return fill(
9586            """
9587            MOZ_ASSERT(uint32_t(aArgument) < ArrayLength(${strings}));
9588            JSString* resultStr =
9589              JS_NewStringCopyN(aCx, ${strings}[uint32_t(aArgument)].value,
9590                                ${strings}[uint32_t(aArgument)].length);
9591            if (!resultStr) {
9592              return false;
9593            }
9594            aValue.setString(resultStr);
9595            return true;
9596            """,
9597            strings=self.stringsArray)
9598
9599
9600class CGEnum(CGThing):
9601    def __init__(self, enum):
9602        CGThing.__init__(self)
9603        self.enum = enum
9604        strings = CGNamespace(
9605            self.stringsNamespace(),
9606            CGGeneric(declare=("extern const EnumEntry %s[%d];\n" %
9607                               (ENUM_ENTRY_VARIABLE_NAME, self.nEnumStrings())),
9608                      define=fill(
9609                          """
9610                          extern const EnumEntry ${name}[${count}] = {
9611                            $*{entries}
9612                            { nullptr, 0 }
9613                          };
9614                          """,
9615                          name=ENUM_ENTRY_VARIABLE_NAME,
9616                          count=self.nEnumStrings(),
9617                          entries=''.join('{"%s", %d},\n' % (val, len(val))
9618                                          for val in self.enum.values()))))
9619        toJSValue = CGEnumToJSValue(enum)
9620        self.cgThings = CGList([strings, toJSValue], "\n")
9621
9622    def stringsNamespace(self):
9623        return self.enum.identifier.name + "Values"
9624
9625    def nEnumStrings(self):
9626        return len(self.enum.values()) + 1
9627
9628    def declare(self):
9629        decl = fill(
9630            """
9631            enum class ${name} : uint32_t {
9632              $*{enums}
9633              EndGuard_
9634            };
9635            """,
9636            name=self.enum.identifier.name,
9637            enums=",\n".join(map(getEnumValueName, self.enum.values())) + ",\n")
9638        strings = CGNamespace(self.stringsNamespace(),
9639                              CGGeneric(declare="extern const EnumEntry %s[%d];\n"
9640                                        % (ENUM_ENTRY_VARIABLE_NAME, self.nEnumStrings())))
9641        return decl + "\n" + self.cgThings.declare()
9642
9643    def define(self):
9644        return self.cgThings.define()
9645
9646    def deps(self):
9647        return self.enum.getDeps()
9648
9649
9650def getUnionAccessorSignatureType(type, descriptorProvider):
9651    """
9652    Returns the types that are used in the getter and setter signatures for
9653    union types
9654    """
9655    # Flat member types have already unwrapped nullables.
9656    assert not type.nullable()
9657
9658    if type.isSequence() or type.isMozMap():
9659        if type.isSequence():
9660            wrapperType = "Sequence"
9661        else:
9662            wrapperType = "MozMap"
9663        # We don't use the returned template here, so it's OK to just pass no
9664        # sourceDescription.
9665        elementInfo = getJSToNativeConversionInfo(type.inner,
9666                                                  descriptorProvider,
9667                                                  isMember=wrapperType)
9668        return CGTemplatedType(wrapperType, elementInfo.declType,
9669                               isConst=True, isReference=True)
9670
9671    # Nested unions are unwrapped automatically into our flatMemberTypes.
9672    assert not type.isUnion()
9673
9674    if type.isGeckoInterface():
9675        descriptor = descriptorProvider.getDescriptor(
9676            type.unroll().inner.identifier.name)
9677        typeName = CGGeneric(descriptor.nativeType)
9678        # Allow null pointers for old-binding classes.
9679        if type.unroll().inner.isExternal():
9680            typeName = CGWrapper(typeName, post="*")
9681        else:
9682            typeName = CGWrapper(typeName, post="&")
9683        return typeName
9684
9685    if type.isSpiderMonkeyInterface():
9686        typeName = CGGeneric(type.name)
9687        return CGWrapper(typeName, post=" const &")
9688
9689    if type.isDOMString() or type.isUSVString():
9690        return CGGeneric("const nsAString&")
9691
9692    if type.isByteString():
9693        return CGGeneric("const nsCString&")
9694
9695    if type.isEnum():
9696        return CGGeneric(type.inner.identifier.name)
9697
9698    if type.isCallback():
9699        return CGGeneric("%s&" % type.unroll().callback.identifier.name)
9700
9701    if type.isAny():
9702        return CGGeneric("JS::Value")
9703
9704    if type.isObject():
9705        return CGGeneric("JSObject*")
9706
9707    if type.isDictionary():
9708        return CGGeneric("const %s&" % type.inner.identifier.name)
9709
9710    if not type.isPrimitive():
9711        raise TypeError("Need native type for argument type '%s'" % str(type))
9712
9713    return CGGeneric(builtinNames[type.tag()])
9714
9715
9716def getUnionTypeTemplateVars(unionType, type, descriptorProvider,
9717                             ownsMembers=False):
9718    name = getUnionMemberName(type)
9719    holderName = "m" + name + "Holder"
9720
9721    # By the time tryNextCode is invoked, we're guaranteed the union has been
9722    # constructed as some type, since we've been trying to convert into the
9723    # corresponding member.
9724    prefix = "" if ownsMembers else "mUnion."
9725    tryNextCode = ("$*{destroyHolder}\n"
9726                   "%sDestroy%s();\n"
9727                   "tryNext = true;\n"
9728                   "return true;\n" % (prefix, name))
9729
9730    conversionInfo = getJSToNativeConversionInfo(
9731        type, descriptorProvider, failureCode=tryNextCode,
9732        isDefinitelyObject=not type.isDictionary(),
9733        isMember=("OwningUnion" if ownsMembers else None),
9734        sourceDescription="member of %s" % unionType)
9735
9736    if conversionInfo.holderType is not None:
9737        assert not ownsMembers
9738        destroyHolder = "%s.reset();\n" % holderName
9739    else:
9740        destroyHolder = ""
9741
9742    ctorNeedsCx = conversionInfo.declArgs == "cx"
9743    ctorArgs = "cx" if ctorNeedsCx else ""
9744
9745    structType = conversionInfo.declType.define()
9746    externalType = getUnionAccessorSignatureType(type, descriptorProvider).define()
9747
9748    if type.isObject():
9749        if ownsMembers:
9750            body = dedent("""
9751                MOZ_ASSERT(mType == eUninitialized);
9752                mValue.mObject.SetValue(obj);
9753                mType = eObject;
9754                """)
9755        else:
9756            body = dedent("""
9757                MOZ_ASSERT(mUnion.mType == mUnion.eUninitialized);
9758                mUnion.mValue.mObject.SetValue(cx, obj);
9759                mUnion.mType = mUnion.eObject;
9760                """)
9761
9762        # It's a bit sketchy to do the security check after setting the value,
9763        # but it keeps the code cleaner and lets us avoid rooting |obj| over the
9764        # call to CallerSubsumes().
9765        body = body + dedent("""
9766            if (passedToJSImpl && !CallerSubsumes(obj)) {
9767              ThrowErrorMessage(cx, MSG_PERMISSION_DENIED_TO_PASS_ARG, "%s");
9768              return false;
9769            }
9770            return true;
9771            """)
9772
9773        setter = ClassMethod("SetToObject", "bool",
9774                             [Argument("JSContext*", "cx"),
9775                              Argument("JSObject*", "obj"),
9776                              Argument("bool", "passedToJSImpl", default="false")],
9777                             inline=True, bodyInHeader=True,
9778                             body=body)
9779
9780    else:
9781        # Important: we need to not have our declName involve
9782        # maybe-GCing operations.
9783        if conversionInfo.holderType is not None:
9784            holderArgs = conversionInfo.holderArgs
9785            if holderArgs is None:
9786                holderArgs = ""
9787            initHolder = "%s.emplace(%s);\n" % (holderName, holderArgs)
9788        else:
9789            initHolder = ""
9790
9791        jsConversion = fill(
9792            initHolder + conversionInfo.template,
9793            val="value",
9794            maybeMutableVal="value",
9795            declName="memberSlot",
9796            holderName=(holderName if ownsMembers else "%s.ref()" % holderName),
9797            destroyHolder=destroyHolder,
9798            passedToJSImpl="passedToJSImpl")
9799
9800        jsConversion = fill(
9801            """
9802            tryNext = false;
9803            { // scope for memberSlot
9804              ${structType}& memberSlot = RawSetAs${name}(${ctorArgs});
9805              $*{jsConversion}
9806            }
9807            return true;
9808            """,
9809            structType=structType,
9810            name=name,
9811            ctorArgs=ctorArgs,
9812            jsConversion=jsConversion)
9813
9814        if ownsMembers:
9815            handleType = "JS::Handle<JS::Value>"
9816        else:
9817            handleType = "JS::MutableHandle<JS::Value>"
9818
9819        setter = ClassMethod("TrySetTo" + name, "bool",
9820                             [Argument("JSContext*", "cx"),
9821                              Argument(handleType, "value"),
9822                              Argument("bool&", "tryNext"),
9823                              Argument("bool", "passedToJSImpl", default="false")],
9824                             inline=not ownsMembers,
9825                             bodyInHeader=not ownsMembers,
9826                             body=jsConversion)
9827
9828    return {
9829        "name": name,
9830        "structType": structType,
9831        "externalType": externalType,
9832        "setter": setter,
9833        "holderType": conversionInfo.holderType.define() if conversionInfo.holderType else None,
9834        "ctorArgs": ctorArgs,
9835        "ctorArgList": [Argument("JSContext*", "cx")] if ctorNeedsCx else []
9836    }
9837
9838
9839class CGUnionStruct(CGThing):
9840    def __init__(self, type, descriptorProvider, ownsMembers=False):
9841        CGThing.__init__(self)
9842        self.type = type.unroll()
9843        self.descriptorProvider = descriptorProvider
9844        self.ownsMembers = ownsMembers
9845        self.struct = self.getStruct()
9846
9847    def declare(self):
9848        return self.struct.declare()
9849
9850    def define(self):
9851        return self.struct.define()
9852
9853    def deps(self):
9854        return self.type.getDeps()
9855
9856    def getStruct(self):
9857
9858        members = [ClassMember("mType", "Type", body="eUninitialized"),
9859                   ClassMember("mValue", "Value")]
9860        ctor = ClassConstructor([], bodyInHeader=True, visibility="public",
9861                                explicit=True)
9862
9863        methods = []
9864        enumValues = ["eUninitialized"]
9865        toJSValCases = [CGCase("eUninitialized", CGGeneric("return false;\n"))]
9866        destructorCases = [CGCase("eUninitialized", None)]
9867        assignmentCases = [
9868            CGCase("eUninitialized",
9869                   CGGeneric('MOZ_ASSERT(mType == eUninitialized,\n'
9870                             '           "We need to destroy ourselves?");\n'))]
9871        traceCases = []
9872        unionValues = []
9873        if self.type.hasNullableType:
9874            enumValues.append("eNull")
9875            methods.append(ClassMethod("IsNull", "bool", [], const=True, inline=True,
9876                                       body="return mType == eNull;\n",
9877                                       bodyInHeader=True))
9878            methods.append(ClassMethod("SetNull", "void", [], inline=True,
9879                                       body=("Uninit();\n"
9880                                             "mType = eNull;\n"),
9881                                       bodyInHeader=True))
9882            destructorCases.append(CGCase("eNull", None))
9883            assignmentCases.append(CGCase("eNull",
9884                                          CGGeneric("MOZ_ASSERT(mType == eUninitialized);\n"
9885                                                    "mType = eNull;\n")))
9886            toJSValCases.append(CGCase("eNull", CGGeneric("rval.setNull();\n"
9887                                                          "return true;\n")))
9888
9889        hasObjectType = any(t.isObject() for t in self.type.flatMemberTypes)
9890        for t in self.type.flatMemberTypes:
9891            vars = getUnionTypeTemplateVars(self.type,
9892                                            t, self.descriptorProvider,
9893                                            ownsMembers=self.ownsMembers)
9894            if vars["name"] != "Object" or self.ownsMembers:
9895                body = fill(
9896                    """
9897                    if (mType == e${name}) {
9898                      return mValue.m${name}.Value();
9899                    }
9900                    %s
9901                    mType = e${name};
9902                    return mValue.m${name}.SetValue(${ctorArgs});
9903                    """,
9904                    **vars)
9905
9906                # bodyInHeader must be false for return values because they own
9907                # their union members and we don't want include headers in
9908                # UnionTypes.h just to call Addref/Release
9909                methods.append(ClassMethod(
9910                    "RawSetAs" + vars["name"],
9911                    vars["structType"] + "&",
9912                    vars["ctorArgList"],
9913                    bodyInHeader=not self.ownsMembers,
9914                    body=body % "MOZ_ASSERT(mType == eUninitialized);"))
9915                uninit = "Uninit();"
9916                if hasObjectType and not self.ownsMembers:
9917                    uninit = 'MOZ_ASSERT(mType != eObject, "This will not play well with Rooted");\n' + uninit
9918                methods.append(ClassMethod(
9919                    "SetAs" + vars["name"],
9920                    vars["structType"] + "&",
9921                    vars["ctorArgList"],
9922                    bodyInHeader=not self.ownsMembers,
9923                    body=body % uninit))
9924                if self.ownsMembers:
9925                    methods.append(vars["setter"])
9926                    # Provide a SetStringData() method to support string defaults.
9927                    if t.isByteString():
9928                        methods.append(
9929                            ClassMethod("SetStringData", "void",
9930                                        [Argument("const nsCString::char_type*", "aData"),
9931                                         Argument("nsCString::size_type", "aLength")],
9932                                        inline=True, bodyInHeader=True,
9933                                        body="RawSetAs%s().Assign(aData, aLength);\n" % t.name))
9934                    elif t.isString():
9935                        methods.append(
9936                            ClassMethod("SetStringData", "void",
9937                                        [Argument("const nsString::char_type*", "aData"),
9938                                         Argument("nsString::size_type", "aLength")],
9939                                        inline=True, bodyInHeader=True,
9940                                        body="RawSetAs%s().Assign(aData, aLength);\n" % t.name))
9941
9942            body = fill(
9943                """
9944                MOZ_ASSERT(Is${name}(), "Wrong type!");
9945                mValue.m${name}.Destroy();
9946                mType = eUninitialized;
9947                """,
9948                **vars)
9949            methods.append(ClassMethod("Destroy" + vars["name"],
9950                                       "void",
9951                                       [],
9952                                       visibility="private",
9953                                       bodyInHeader=not self.ownsMembers,
9954                                       body=body))
9955
9956            body = fill("return mType == e${name};\n", **vars)
9957            methods.append(ClassMethod("Is" + vars["name"],
9958                                       "bool",
9959                                       [],
9960                                       const=True,
9961                                       bodyInHeader=True,
9962                                       body=body))
9963
9964            body = fill(
9965                """
9966                MOZ_ASSERT(Is${name}(), "Wrong type!");
9967                return mValue.m${name}.Value();
9968                """,
9969                **vars)
9970            # The non-const version of GetAs* returns our internal type
9971            getterReturnType = "%s&" % vars["structType"]
9972            methods.append(ClassMethod("GetAs" + vars["name"],
9973                                       getterReturnType,
9974                                       [],
9975                                       bodyInHeader=True,
9976                                       body=body))
9977            # The const version of GetAs* returns our internal type
9978            # for owning unions, but our external type for non-owning
9979            # ones.
9980            if self.ownsMembers:
9981                getterReturnType = "%s const &" % vars["structType"]
9982            else:
9983                getterReturnType = vars["externalType"]
9984            methods.append(ClassMethod("GetAs" + vars["name"],
9985                                       getterReturnType,
9986                                       [],
9987                                       const=True,
9988                                       bodyInHeader=True,
9989                                       body=body))
9990
9991            unionValues.append(
9992                fill("UnionMember<${structType} > m${name}", **vars))
9993            enumValues.append("e" + vars["name"])
9994
9995            skipToJSVal = False
9996            try:
9997                toJSValCases.append(
9998                    CGCase("e" + vars["name"],
9999                           self.getConversionToJS(vars, t)))
10000            except MethodNotNewObjectError:
10001                # If we can't have a ToJSVal() because one of our members can
10002                # only be returned from [NewObject] methods, then just skip
10003                # generating ToJSVal.
10004                skipToJSVal = True
10005            destructorCases.append(
10006                CGCase("e" + vars["name"],
10007                       CGGeneric("Destroy%s();\n" % vars["name"])))
10008            assignmentCases.append(
10009                CGCase("e" + vars["name"],
10010                       CGGeneric("SetAs%s() = aOther.GetAs%s();\n" %
10011                                 (vars["name"], vars["name"]))))
10012            if self.ownsMembers and typeNeedsRooting(t):
10013                if t.isObject():
10014                    traceCases.append(
10015                        CGCase("e" + vars["name"],
10016                               CGGeneric('JS::UnsafeTraceRoot(trc, %s, "%s");\n' %
10017                                         ("&mValue.m" + vars["name"] + ".Value()",
10018                                          "mValue.m" + vars["name"]))))
10019                elif t.isDictionary():
10020                    traceCases.append(
10021                        CGCase("e" + vars["name"],
10022                               CGGeneric("mValue.m%s.Value().TraceDictionary(trc);\n" %
10023                                         vars["name"])))
10024                elif t.isSequence():
10025                    traceCases.append(
10026                        CGCase("e" + vars["name"],
10027                               CGGeneric("DoTraceSequence(trc, mValue.m%s.Value());\n" %
10028                                         vars["name"])))
10029                elif t.isMozMap():
10030                    traceCases.append(
10031                        CGCase("e" + vars["name"],
10032                               CGGeneric("TraceMozMap(trc, mValue.m%s.Value());\n" %
10033                                         vars["name"])))
10034                else:
10035                    assert t.isSpiderMonkeyInterface()
10036                    traceCases.append(
10037                        CGCase("e" + vars["name"],
10038                               CGGeneric("mValue.m%s.Value().TraceSelf(trc);\n" %
10039                                         vars["name"])))
10040
10041        dtor = CGSwitch("mType", destructorCases).define()
10042
10043        methods.append(ClassMethod("Uninit", "void", [],
10044                                   visibility="public", body=dtor,
10045                                   bodyInHeader=not self.ownsMembers,
10046                                   inline=not self.ownsMembers))
10047
10048        if not skipToJSVal:
10049            methods.append(
10050                ClassMethod(
10051                    "ToJSVal",
10052                    "bool",
10053                    [
10054                        Argument("JSContext*", "cx"),
10055                        Argument("JS::Handle<JSObject*>", "scopeObj"),
10056                        Argument("JS::MutableHandle<JS::Value>", "rval")
10057                    ],
10058                    body=CGSwitch("mType", toJSValCases,
10059                                  default=CGGeneric("return false;\n")).define() + "\nreturn false;\n",
10060                    const=True))
10061
10062        constructors = [ctor]
10063        selfName = CGUnionStruct.unionTypeName(self.type, self.ownsMembers)
10064        if self.ownsMembers:
10065            if traceCases:
10066                traceBody = CGSwitch("mType", traceCases,
10067                                     default=CGGeneric("")).define()
10068            else:
10069                traceBody = ""
10070            methods.append(ClassMethod("TraceUnion", "void",
10071                                       [Argument("JSTracer*", "trc")],
10072                                       body=traceBody))
10073            if CGUnionStruct.isUnionCopyConstructible(self.type):
10074                constructors.append(
10075                    ClassConstructor(
10076                        [Argument("const %s&" % selfName, "aOther")],
10077                        bodyInHeader=True,
10078                        visibility="public",
10079                        explicit=True,
10080                        body="*this = aOther;\n"))
10081                methods.append(ClassMethod(
10082                    "operator=", "void",
10083                    [Argument("const %s&" % selfName, "aOther")],
10084                    body=CGSwitch("aOther.mType", assignmentCases).define()))
10085                disallowCopyConstruction = False
10086            else:
10087                disallowCopyConstruction = True
10088        else:
10089            disallowCopyConstruction = True
10090
10091        if self.ownsMembers:
10092            friend = "  friend void ImplCycleCollectionUnlink(%s& aUnion);\n" % CGUnionStruct.unionTypeName(self.type, True)
10093        else:
10094            friend = "  friend class %sArgument;\n" % str(self.type)
10095
10096        bases = [ClassBase("AllOwningUnionBase")] if self.ownsMembers else []
10097        return CGClass(selfName,
10098                       bases=bases,
10099                       members=members,
10100                       constructors=constructors,
10101                       methods=methods,
10102                       disallowCopyConstruction=disallowCopyConstruction,
10103                       extradeclarations=friend,
10104                       destructor=ClassDestructor(visibility="public",
10105                                                  body="Uninit();\n",
10106                                                  bodyInHeader=True),
10107                       enums=[ClassEnum("Type", enumValues, visibility="private")],
10108                       unions=[ClassUnion("Value", unionValues, visibility="private")])
10109
10110    def getConversionToJS(self, templateVars, type):
10111        assert not type.nullable()  # flatMemberTypes never has nullable types
10112        val = "mValue.m%(name)s.Value()" % templateVars
10113        wrapCode = wrapForType(
10114            type, self.descriptorProvider,
10115            {
10116                "jsvalRef": "rval",
10117                "jsvalHandle": "rval",
10118                "obj": "scopeObj",
10119                "result": val,
10120                "typedArraysAreStructs": True
10121            })
10122        return CGGeneric(wrapCode)
10123
10124    @staticmethod
10125    def isUnionCopyConstructible(type):
10126        return all(isTypeCopyConstructible(t) for t in type.flatMemberTypes)
10127
10128    @staticmethod
10129    def unionTypeName(type, ownsMembers):
10130        """
10131        Returns a string name for this known union type.
10132        """
10133        assert type.isUnion() and not type.nullable()
10134        return ("Owning" if ownsMembers else "") + type.name
10135
10136    @staticmethod
10137    def unionTypeDecl(type, ownsMembers):
10138        """
10139        Returns a string for declaring this possibly-nullable union type.
10140        """
10141        assert type.isUnion()
10142        nullable = type.nullable()
10143        if nullable:
10144            type = type.inner
10145        decl = CGGeneric(CGUnionStruct.unionTypeName(type, ownsMembers))
10146        if nullable:
10147            decl = CGTemplatedType("Nullable", decl)
10148        return decl.define()
10149
10150
10151class CGUnionConversionStruct(CGThing):
10152    def __init__(self, type, descriptorProvider):
10153        CGThing.__init__(self)
10154        self.type = type.unroll()
10155        self.descriptorProvider = descriptorProvider
10156
10157    def declare(self):
10158
10159        structName = str(self.type)
10160        members = [ClassMember("mUnion", structName + "&",
10161                               body="const_cast<%s&>(aUnion)" % structName)]
10162        # Argument needs to be a const ref because that's all Maybe<> allows
10163        ctor = ClassConstructor([Argument("const %s&" % structName, "aUnion")],
10164                                bodyInHeader=True,
10165                                visibility="public",
10166                                explicit=True)
10167        methods = []
10168
10169        if self.type.hasNullableType:
10170            methods.append(ClassMethod("SetNull", "bool", [],
10171                                       body=("MOZ_ASSERT(mUnion.mType == mUnion.eUninitialized);\n"
10172                                             "mUnion.mType = mUnion.eNull;\n"
10173                                             "return true;\n"),
10174                                       inline=True, bodyInHeader=True))
10175
10176        for t in self.type.flatMemberTypes:
10177            vars = getUnionTypeTemplateVars(self.type,
10178                                            t, self.descriptorProvider)
10179            methods.append(vars["setter"])
10180            if vars["name"] != "Object":
10181                body = fill(
10182                    """
10183                    MOZ_ASSERT(mUnion.mType == mUnion.eUninitialized);
10184                    mUnion.mType = mUnion.e${name};
10185                    return mUnion.mValue.m${name}.SetValue(${ctorArgs});
10186                    """,
10187                    **vars)
10188                methods.append(ClassMethod("RawSetAs" + vars["name"],
10189                                           vars["structType"] + "&",
10190                                           vars["ctorArgList"],
10191                                           bodyInHeader=True,
10192                                           body=body,
10193                                           visibility="private"))
10194                # Provide a SetStringData() method to support string defaults.
10195                if t.isByteString():
10196                    methods.append(
10197                        ClassMethod("SetStringData", "void",
10198                                    [Argument("const nsDependentCString::char_type*", "aData"),
10199                                     Argument("nsDependentCString::size_type", "aLength")],
10200                                    inline=True, bodyInHeader=True,
10201                                    body="RawSetAs%s().Rebind(aData, aLength);\n" % t.name))
10202                elif t.isString():
10203                    methods.append(
10204                        ClassMethod("SetStringData", "void",
10205                                    [Argument("const nsDependentString::char_type*", "aData"),
10206                                     Argument("nsDependentString::size_type", "aLength")],
10207                                    inline=True, bodyInHeader=True,
10208                                    body="RawSetAs%s().Rebind(aData, aLength);\n" % t.name))
10209
10210            if vars["holderType"] is not None:
10211                holderType = CGTemplatedType("Maybe",
10212                                             CGGeneric(vars["holderType"])).define()
10213                members.append(ClassMember("m%sHolder" % vars["name"],
10214                                           holderType))
10215
10216        return CGClass(structName + "Argument",
10217                       members=members,
10218                       constructors=[ctor],
10219                       methods=methods,
10220                       disallowCopyConstruction=True).declare()
10221
10222    def define(self):
10223        return ""
10224
10225    def deps(self):
10226        return set()
10227
10228
10229class ClassItem:
10230    """ Use with CGClass """
10231    def __init__(self, name, visibility):
10232        self.name = name
10233        self.visibility = visibility
10234
10235    def declare(self, cgClass):
10236        assert False
10237
10238    def define(self, cgClass):
10239        assert False
10240
10241
10242class ClassBase(ClassItem):
10243    def __init__(self, name, visibility='public'):
10244        ClassItem.__init__(self, name, visibility)
10245
10246    def declare(self, cgClass):
10247        return '%s %s' % (self.visibility, self.name)
10248
10249    def define(self, cgClass):
10250        # Only in the header
10251        return ''
10252
10253
10254class ClassMethod(ClassItem):
10255    def __init__(self, name, returnType, args, inline=False, static=False,
10256                 virtual=False, const=False, bodyInHeader=False,
10257                 templateArgs=None, visibility='public', body=None,
10258                 breakAfterReturnDecl="\n",
10259                 breakAfterSelf="\n", override=False):
10260        """
10261        override indicates whether to flag the method as override
10262        """
10263        assert not override or virtual
10264        assert not (override and static)
10265        self.returnType = returnType
10266        self.args = args
10267        self.inline = inline or bodyInHeader
10268        self.static = static
10269        self.virtual = virtual
10270        self.const = const
10271        self.bodyInHeader = bodyInHeader
10272        self.templateArgs = templateArgs
10273        self.body = body
10274        self.breakAfterReturnDecl = breakAfterReturnDecl
10275        self.breakAfterSelf = breakAfterSelf
10276        self.override = override
10277        ClassItem.__init__(self, name, visibility)
10278
10279    def getDecorators(self, declaring):
10280        decorators = []
10281        if self.inline:
10282            decorators.append('inline')
10283        if declaring:
10284            if self.static:
10285                decorators.append('static')
10286            if self.virtual:
10287                decorators.append('virtual')
10288        if decorators:
10289            return ' '.join(decorators) + ' '
10290        return ''
10291
10292    def getBody(self):
10293        # Override me or pass a string to constructor
10294        assert self.body is not None
10295        return self.body
10296
10297    def declare(self, cgClass):
10298        templateClause = ('template <%s>\n' % ', '.join(self.templateArgs)
10299                          if self.bodyInHeader and self.templateArgs else '')
10300        args = ', '.join([a.declare() for a in self.args])
10301        if self.bodyInHeader:
10302            body = indent(self.getBody())
10303            body = '\n{\n' + body + '}\n'
10304        else:
10305            body = ';\n'
10306
10307        return fill(
10308            "${templateClause}${decorators}${returnType}${breakAfterReturnDecl}"
10309            "${name}(${args})${const}${override}${body}"
10310            "${breakAfterSelf}",
10311            templateClause=templateClause,
10312            decorators=self.getDecorators(True),
10313            returnType=self.returnType,
10314            breakAfterReturnDecl=self.breakAfterReturnDecl,
10315            name=self.name,
10316            args=args,
10317            const=' const' if self.const else '',
10318            override=' override' if self.override else '',
10319            body=body,
10320            breakAfterSelf=self.breakAfterSelf)
10321
10322    def define(self, cgClass):
10323        if self.bodyInHeader:
10324            return ''
10325
10326        templateArgs = cgClass.templateArgs
10327        if templateArgs:
10328            if cgClass.templateSpecialization:
10329                templateArgs = \
10330                    templateArgs[len(cgClass.templateSpecialization):]
10331
10332        if templateArgs:
10333            templateClause = \
10334                'template <%s>\n' % ', '.join([str(a) for a in templateArgs])
10335        else:
10336            templateClause = ''
10337
10338        return fill(
10339            """
10340            ${templateClause}${decorators}${returnType}
10341            ${className}::${name}(${args})${const}
10342            {
10343              $*{body}
10344            }
10345            """,
10346            templateClause=templateClause,
10347            decorators=self.getDecorators(False),
10348            returnType=self.returnType,
10349            className=cgClass.getNameString(),
10350            name=self.name,
10351            args=', '.join([a.define() for a in self.args]),
10352            const=' const' if self.const else '',
10353            body=self.getBody())
10354
10355
10356class ClassUsingDeclaration(ClassItem):
10357    """
10358    Used for importing a name from a base class into a CGClass
10359
10360    baseClass is the name of the base class to import the name from
10361
10362    name is the name to import
10363
10364    visibility determines the visibility of the name (public,
10365    protected, private), defaults to public.
10366    """
10367    def __init__(self, baseClass, name, visibility='public'):
10368        self.baseClass = baseClass
10369        ClassItem.__init__(self, name, visibility)
10370
10371    def declare(self, cgClass):
10372        return "using %s::%s;\n\n" % (self.baseClass, self.name)
10373
10374    def define(self, cgClass):
10375        return ''
10376
10377
10378class ClassConstructor(ClassItem):
10379    """
10380    Used for adding a constructor to a CGClass.
10381
10382    args is a list of Argument objects that are the arguments taken by the
10383    constructor.
10384
10385    inline should be True if the constructor should be marked inline.
10386
10387    bodyInHeader should be True if the body should be placed in the class
10388    declaration in the header.
10389
10390    visibility determines the visibility of the constructor (public,
10391    protected, private), defaults to private.
10392
10393    explicit should be True if the constructor should be marked explicit.
10394
10395    baseConstructors is a list of strings containing calls to base constructors,
10396    defaults to None.
10397
10398    body contains a string with the code for the constructor, defaults to empty.
10399    """
10400    def __init__(self, args, inline=False, bodyInHeader=False,
10401                 visibility="private", explicit=False, constexpr=False, baseConstructors=None,
10402                 body=""):
10403        assert not (inline and constexpr)
10404        assert not (bodyInHeader and constexpr)
10405        self.args = args
10406        self.inline = inline or bodyInHeader
10407        self.bodyInHeader = bodyInHeader or constexpr
10408        self.explicit = explicit
10409        self.constexpr = constexpr
10410        self.baseConstructors = baseConstructors or []
10411        self.body = body
10412        ClassItem.__init__(self, None, visibility)
10413
10414    def getDecorators(self, declaring):
10415        decorators = []
10416        if self.explicit:
10417            decorators.append('explicit')
10418        if self.inline and declaring:
10419            decorators.append('inline')
10420        if self.constexpr and declaring:
10421            decorators.append('constexpr')
10422        if decorators:
10423            return ' '.join(decorators) + ' '
10424        return ''
10425
10426    def getInitializationList(self, cgClass):
10427        items = [str(c) for c in self.baseConstructors]
10428        for m in cgClass.members:
10429            if not m.static:
10430                initialize = m.body
10431                if initialize:
10432                    items.append(m.name + "(" + initialize + ")")
10433
10434        if len(items) > 0:
10435            return '\n  : ' + ',\n    '.join(items)
10436        return ''
10437
10438    def getBody(self):
10439        return self.body
10440
10441    def declare(self, cgClass):
10442        args = ', '.join([a.declare() for a in self.args])
10443        if self.bodyInHeader:
10444            body = self.getInitializationList(cgClass) + '\n{\n' + indent(self.getBody()) + '}\n'
10445        else:
10446            body = ';\n'
10447
10448        return fill(
10449            "${decorators}${className}(${args})${body}\n",
10450            decorators=self.getDecorators(True),
10451            className=cgClass.getNameString(),
10452            args=args,
10453            body=body)
10454
10455    def define(self, cgClass):
10456        if self.bodyInHeader:
10457            return ''
10458
10459        return fill(
10460            """
10461            ${decorators}
10462            ${className}::${className}(${args})${initializationList}
10463            {
10464              $*{body}
10465            }
10466            """,
10467            decorators=self.getDecorators(False),
10468            className=cgClass.getNameString(),
10469            args=', '.join([a.define() for a in self.args]),
10470            initializationList=self.getInitializationList(cgClass),
10471            body=self.getBody())
10472
10473
10474class ClassDestructor(ClassItem):
10475    """
10476    Used for adding a destructor to a CGClass.
10477
10478    inline should be True if the destructor should be marked inline.
10479
10480    bodyInHeader should be True if the body should be placed in the class
10481    declaration in the header.
10482
10483    visibility determines the visibility of the destructor (public,
10484    protected, private), defaults to private.
10485
10486    body contains a string with the code for the destructor, defaults to empty.
10487
10488    virtual determines whether the destructor is virtual, defaults to False.
10489    """
10490    def __init__(self, inline=False, bodyInHeader=False,
10491                 visibility="private", body='', virtual=False):
10492        self.inline = inline or bodyInHeader
10493        self.bodyInHeader = bodyInHeader
10494        self.body = body
10495        self.virtual = virtual
10496        ClassItem.__init__(self, None, visibility)
10497
10498    def getDecorators(self, declaring):
10499        decorators = []
10500        if self.virtual and declaring:
10501            decorators.append('virtual')
10502        if self.inline and declaring:
10503            decorators.append('inline')
10504        if decorators:
10505            return ' '.join(decorators) + ' '
10506        return ''
10507
10508    def getBody(self):
10509        return self.body
10510
10511    def declare(self, cgClass):
10512        if self.bodyInHeader:
10513            body = '\n{\n' + indent(self.getBody()) + '}\n'
10514        else:
10515            body = ';\n'
10516
10517        return fill(
10518            "${decorators}~${className}()${body}\n",
10519            decorators=self.getDecorators(True),
10520            className=cgClass.getNameString(),
10521            body=body)
10522
10523    def define(self, cgClass):
10524        if self.bodyInHeader:
10525            return ''
10526        return fill(
10527            """
10528            ${decorators}
10529            ${className}::~${className}()
10530            {
10531              $*{body}
10532            }
10533            """,
10534            decorators=self.getDecorators(False),
10535            className=cgClass.getNameString(),
10536            body=self.getBody())
10537
10538
10539class ClassMember(ClassItem):
10540    def __init__(self, name, type, visibility="private", static=False,
10541                 body=None, hasIgnoreInitCheckFlag=False):
10542        self.type = type
10543        self.static = static
10544        self.body = body
10545        self.hasIgnoreInitCheckFlag = hasIgnoreInitCheckFlag;
10546        ClassItem.__init__(self, name, visibility)
10547
10548    def declare(self, cgClass):
10549        return '%s%s%s %s;\n' % ('static ' if self.static else '',
10550                                 'MOZ_INIT_OUTSIDE_CTOR '
10551                                 if self.hasIgnoreInitCheckFlag else '',
10552                                 self.type, self.name)
10553
10554    def define(self, cgClass):
10555        if not self.static:
10556            return ''
10557        if self.body:
10558            body = " = " + self.body
10559        else:
10560            body = ""
10561        return '%s %s::%s%s;\n' % (self.type, cgClass.getNameString(),
10562                                   self.name, body)
10563
10564
10565class ClassTypedef(ClassItem):
10566    def __init__(self, name, type, visibility="public"):
10567        self.type = type
10568        ClassItem.__init__(self, name, visibility)
10569
10570    def declare(self, cgClass):
10571        return 'typedef %s %s;\n' % (self.type, self.name)
10572
10573    def define(self, cgClass):
10574        # Only goes in the header
10575        return ''
10576
10577
10578class ClassEnum(ClassItem):
10579    def __init__(self, name, entries, values=None, visibility="public"):
10580        self.entries = entries
10581        self.values = values
10582        ClassItem.__init__(self, name, visibility)
10583
10584    def declare(self, cgClass):
10585        entries = []
10586        for i in range(0, len(self.entries)):
10587            if not self.values or i >= len(self.values):
10588                entry = '%s' % self.entries[i]
10589            else:
10590                entry = '%s = %s' % (self.entries[i], self.values[i])
10591            entries.append(entry)
10592        name = '' if not self.name else ' ' + self.name
10593        return 'enum%s\n{\n%s\n};\n' % (name, indent(',\n'.join(entries)))
10594
10595    def define(self, cgClass):
10596        # Only goes in the header
10597        return ''
10598
10599
10600class ClassUnion(ClassItem):
10601    def __init__(self, name, entries, visibility="public"):
10602        self.entries = [entry + ";\n" for entry in entries]
10603        ClassItem.__init__(self, name, visibility)
10604
10605    def declare(self, cgClass):
10606        return "union %s\n{\n%s\n};\n" % (self.name, indent(''.join(self.entries)))
10607
10608    def define(self, cgClass):
10609        # Only goes in the header
10610        return ''
10611
10612
10613class CGClass(CGThing):
10614    def __init__(self, name, bases=[], members=[], constructors=[],
10615                 destructor=None, methods=[],
10616                 typedefs=[], enums=[], unions=[], templateArgs=[],
10617                 templateSpecialization=[], isStruct=False,
10618                 disallowCopyConstruction=False, indent='',
10619                 decorators='',
10620                 extradeclarations='',
10621                 extradefinitions=''):
10622        CGThing.__init__(self)
10623        self.name = name
10624        self.bases = bases
10625        self.members = members
10626        self.constructors = constructors
10627        # We store our single destructor in a list, since all of our
10628        # code wants lists of members.
10629        self.destructors = [destructor] if destructor else []
10630        self.methods = methods
10631        self.typedefs = typedefs
10632        self.enums = enums
10633        self.unions = unions
10634        self.templateArgs = templateArgs
10635        self.templateSpecialization = templateSpecialization
10636        self.isStruct = isStruct
10637        self.disallowCopyConstruction = disallowCopyConstruction
10638        self.indent = indent
10639        self.defaultVisibility = 'public' if isStruct else 'private'
10640        self.decorators = decorators
10641        self.extradeclarations = extradeclarations
10642        self.extradefinitions = extradefinitions
10643
10644    def getNameString(self):
10645        className = self.name
10646        if self.templateSpecialization:
10647            className += '<%s>' % ', '.join([str(a)
10648                                             for a in self.templateSpecialization])
10649        return className
10650
10651    def declare(self):
10652        result = ''
10653        if self.templateArgs:
10654            templateArgs = [a.declare() for a in self.templateArgs]
10655            templateArgs = templateArgs[len(self.templateSpecialization):]
10656            result += ('template <%s>\n' %
10657                       ','.join([str(a) for a in templateArgs]))
10658
10659        type = 'struct' if self.isStruct else 'class'
10660
10661        if self.templateSpecialization:
10662            specialization = \
10663                '<%s>' % ', '.join([str(a) for a in self.templateSpecialization])
10664        else:
10665            specialization = ''
10666
10667        myself = '%s %s%s' % (type, self.name, specialization)
10668        if self.decorators != '':
10669            myself += " " + self.decorators
10670        result += myself
10671
10672        if self.bases:
10673            inherit = ' : '
10674            result += inherit
10675            # Grab our first base
10676            baseItems = [CGGeneric(b.declare(self)) for b in self.bases]
10677            bases = baseItems[:1]
10678            # Indent the rest
10679            bases.extend(CGIndenter(b, len(myself) + len(inherit))
10680                         for b in baseItems[1:])
10681            result += ",\n".join(b.define() for b in bases)
10682
10683        result += '\n{\n'
10684
10685        result += self.extradeclarations
10686
10687        def declareMembers(cgClass, memberList, defaultVisibility):
10688            members = {'private': [], 'protected': [], 'public': []}
10689
10690            for member in memberList:
10691                members[member.visibility].append(member)
10692
10693            if defaultVisibility == 'public':
10694                order = ['public', 'protected', 'private']
10695            else:
10696                order = ['private', 'protected', 'public']
10697
10698            result = ''
10699
10700            lastVisibility = defaultVisibility
10701            for visibility in order:
10702                list = members[visibility]
10703                if list:
10704                    if visibility != lastVisibility:
10705                        result += visibility + ':\n'
10706                    for member in list:
10707                        result += indent(member.declare(cgClass))
10708                    lastVisibility = visibility
10709            return (result, lastVisibility)
10710
10711        if self.disallowCopyConstruction:
10712            class DisallowedCopyConstructor(object):
10713                def __init__(self):
10714                    self.visibility = "private"
10715
10716                def declare(self, cgClass):
10717                    name = cgClass.getNameString()
10718                    return ("%s(const %s&) = delete;\n"
10719                            "void operator=(const %s&) = delete;\n" % (name, name, name))
10720
10721            disallowedCopyConstructors = [DisallowedCopyConstructor()]
10722        else:
10723            disallowedCopyConstructors = []
10724
10725        order = [self.enums, self.unions,
10726                 self.typedefs, self.members,
10727                 self.constructors + disallowedCopyConstructors,
10728                 self.destructors, self.methods]
10729
10730        lastVisibility = self.defaultVisibility
10731        pieces = []
10732        for memberList in order:
10733            code, lastVisibility = declareMembers(self, memberList, lastVisibility)
10734
10735            if code:
10736                code = code.rstrip() + "\n"  # remove extra blank lines at the end
10737                pieces.append(code)
10738
10739        result += '\n'.join(pieces)
10740        result += '};\n'
10741        result = indent(result, len(self.indent))
10742        return result
10743
10744    def define(self):
10745        def defineMembers(cgClass, memberList, itemCount, separator=''):
10746            result = ''
10747            for member in memberList:
10748                if itemCount != 0:
10749                    result = result + separator
10750                definition = member.define(cgClass)
10751                if definition:
10752                    # Member variables would only produce empty lines here.
10753                    result += definition
10754                    itemCount += 1
10755            return (result, itemCount)
10756
10757        order = [(self.members, ''), (self.constructors, '\n'),
10758                 (self.destructors, '\n'), (self.methods, '\n')]
10759
10760        result = self.extradefinitions
10761        itemCount = 0
10762        for memberList, separator in order:
10763            memberString, itemCount = defineMembers(self, memberList,
10764                                                    itemCount, separator)
10765            result = result + memberString
10766        return result
10767
10768
10769class CGResolveOwnProperty(CGAbstractStaticMethod):
10770    def __init__(self, descriptor):
10771        args = [Argument('JSContext*', 'cx'),
10772                Argument('JS::Handle<JSObject*>', 'wrapper'),
10773                Argument('JS::Handle<JSObject*>', 'obj'),
10774                Argument('JS::Handle<jsid>', 'id'),
10775                Argument('JS::MutableHandle<JS::PropertyDescriptor>', 'desc'),
10776                ]
10777        CGAbstractStaticMethod.__init__(self, descriptor, "ResolveOwnProperty",
10778                                        "bool", args)
10779
10780    def definition_body(self):
10781        return "return js::GetProxyHandler(obj)->getOwnPropertyDescriptor(cx, wrapper, id, desc);\n"
10782
10783
10784class CGResolveOwnPropertyViaResolve(CGAbstractBindingMethod):
10785    """
10786    An implementation of Xray ResolveOwnProperty stuff for things that have a
10787    resolve hook.
10788    """
10789    def __init__(self, descriptor):
10790        args = [Argument('JSContext*', 'cx'),
10791                Argument('JS::Handle<JSObject*>', 'wrapper'),
10792                Argument('JS::Handle<JSObject*>', 'obj'),
10793                Argument('JS::Handle<jsid>', 'id'),
10794                Argument('JS::MutableHandle<JS::PropertyDescriptor>', 'desc')]
10795        CGAbstractBindingMethod.__init__(self, descriptor,
10796                                         "ResolveOwnPropertyViaResolve",
10797                                         args, getThisObj="",
10798                                         callArgs="")
10799
10800    def generate_code(self):
10801        return CGGeneric(dedent("""
10802            {
10803              // Since we're dealing with an Xray, do the resolve on the
10804              // underlying object first.  That gives it a chance to
10805              // define properties on the actual object as needed, and
10806              // then use the fact that it created the objects as a flag
10807              // to avoid re-resolving the properties if someone deletes
10808              // them.
10809              JSAutoCompartment ac(cx, obj);
10810              JS::Rooted<JS::PropertyDescriptor> objDesc(cx);
10811              if (!self->DoResolve(cx, obj, id, &objDesc)) {
10812                return false;
10813              }
10814              // If desc.value() is undefined, then the DoResolve call
10815              // has already defined the property on the object.  Don't
10816              // try to also define it.
10817              if (objDesc.object() &&
10818                  !objDesc.value().isUndefined() &&
10819                  !JS_DefinePropertyById(cx, obj, id, objDesc)) {
10820                return false;
10821              }
10822            }
10823            return self->DoResolve(cx, wrapper, id, desc);
10824            """))
10825
10826
10827class CGEnumerateOwnProperties(CGAbstractStaticMethod):
10828    def __init__(self, descriptor):
10829        args = [Argument('JSContext*', 'cx'),
10830                Argument('JS::Handle<JSObject*>', 'wrapper'),
10831                Argument('JS::Handle<JSObject*>', 'obj'),
10832                Argument('JS::AutoIdVector&', 'props')]
10833        CGAbstractStaticMethod.__init__(self, descriptor,
10834                                        "EnumerateOwnProperties", "bool", args)
10835
10836    def definition_body(self):
10837        return "return js::GetProxyHandler(obj)->ownPropertyKeys(cx, wrapper, props);\n"
10838
10839
10840class CGEnumerateOwnPropertiesViaGetOwnPropertyNames(CGAbstractBindingMethod):
10841    """
10842    An implementation of Xray EnumerateOwnProperties stuff for things
10843    that have a resolve hook.
10844    """
10845    def __init__(self, descriptor):
10846        args = [Argument('JSContext*', 'cx'),
10847                Argument('JS::Handle<JSObject*>', 'wrapper'),
10848                Argument('JS::Handle<JSObject*>', 'obj'),
10849                Argument('JS::AutoIdVector&', 'props')]
10850        CGAbstractBindingMethod.__init__(self, descriptor,
10851                                         "EnumerateOwnPropertiesViaGetOwnPropertyNames",
10852                                         args, getThisObj="",
10853                                         callArgs="")
10854
10855    def generate_code(self):
10856        return CGGeneric(dedent("""
10857            AutoTArray<nsString, 8> names;
10858            binding_detail::FastErrorResult rv;
10859            self->GetOwnPropertyNames(cx, names, rv);
10860            if (rv.MaybeSetPendingException(cx)) {
10861              return false;
10862            }
10863            // OK to pass null as "proxy" because it's ignored if
10864            // shadowPrototypeProperties is true
10865            return AppendNamedPropertyIds(cx, nullptr, names, true, props);
10866            """))
10867
10868
10869class CGPrototypeTraitsClass(CGClass):
10870    def __init__(self, descriptor, indent=''):
10871        templateArgs = [Argument('prototypes::ID', 'PrototypeID')]
10872        templateSpecialization = ['prototypes::id::' + descriptor.name]
10873        enums = [ClassEnum('', ['Depth'],
10874                           [descriptor.interface.inheritanceDepth()])]
10875        CGClass.__init__(self, 'PrototypeTraits', indent=indent,
10876                         templateArgs=templateArgs,
10877                         templateSpecialization=templateSpecialization,
10878                         enums=enums, isStruct=True)
10879
10880    def deps(self):
10881        return set()
10882
10883
10884class CGClassForwardDeclare(CGThing):
10885    def __init__(self, name, isStruct=False):
10886        CGThing.__init__(self)
10887        self.name = name
10888        self.isStruct = isStruct
10889
10890    def declare(self):
10891        type = 'struct' if self.isStruct else 'class'
10892        return '%s %s;\n' % (type, self.name)
10893
10894    def define(self):
10895        # Header only
10896        return ''
10897
10898    def deps(self):
10899        return set()
10900
10901
10902class CGProxySpecialOperation(CGPerSignatureCall):
10903    """
10904    Base class for classes for calling an indexed or named special operation
10905    (don't use this directly, use the derived classes below).
10906
10907    If checkFound is False, will just assert that the prop is found instead of
10908    checking that it is before wrapping the value.
10909
10910    resultVar: See the docstring for CGCallGenerator.
10911
10912    foundVar: For getters and deleters, the generated code can also set a bool
10913    variable, declared by the caller, if the given indexed or named property
10914    already existed. If the caller wants this, it should pass the name of the
10915    bool variable as the foundVar keyword argument to the constructor. The
10916    caller is responsible for declaring the variable and initializing it to
10917    false.
10918    """
10919    def __init__(self, descriptor, operation, checkFound=True,
10920                 argumentHandleValue=None, resultVar=None, foundVar=None):
10921        self.checkFound = checkFound
10922        self.foundVar = foundVar or "found"
10923
10924        nativeName = MakeNativeName(descriptor.binaryNameFor(operation))
10925        operation = descriptor.operations[operation]
10926        assert len(operation.signatures()) == 1
10927        signature = operation.signatures()[0]
10928
10929        returnType, arguments = signature
10930
10931        # We pass len(arguments) as the final argument so that the
10932        # CGPerSignatureCall won't do any argument conversion of its own.
10933        CGPerSignatureCall.__init__(self, returnType, arguments, nativeName,
10934                                    False, descriptor, operation,
10935                                    len(arguments), resultVar=resultVar)
10936
10937        if operation.isSetter() or operation.isCreator():
10938            # arguments[0] is the index or name of the item that we're setting.
10939            argument = arguments[1]
10940            info = getJSToNativeConversionInfo(
10941                argument.type, descriptor,
10942                treatNullAs=argument.treatNullAs,
10943                sourceDescription=("value being assigned to %s setter" %
10944                                   descriptor.interface.identifier.name))
10945            if argumentHandleValue is None:
10946                argumentHandleValue = "desc.value()"
10947            rootedValue = fill(
10948                """
10949                JS::Rooted<JS::Value> rootedValue(cx, ${argumentHandleValue});
10950                """,
10951                argumentHandleValue = argumentHandleValue)
10952            templateValues = {
10953                "declName": argument.identifier.name,
10954                "holderName": argument.identifier.name + "_holder",
10955                "val": argumentHandleValue,
10956                "maybeMutableVal": "&rootedValue",
10957                "obj": "obj",
10958                "passedToJSImpl": "false"
10959            }
10960            self.cgRoot.prepend(instantiateJSToNativeConversion(info, templateValues))
10961            # rootedValue needs to come before the conversion, so we
10962            # need to prepend it last.
10963            self.cgRoot.prepend(CGGeneric(rootedValue))
10964        elif operation.isGetter() or operation.isDeleter():
10965            if foundVar is None:
10966                self.cgRoot.prepend(CGGeneric("bool found = false;\n"))
10967
10968    def getArguments(self):
10969        args = [(a, a.identifier.name) for a in self.arguments]
10970        if self.idlNode.isGetter() or self.idlNode.isDeleter():
10971            args.append((FakeArgument(BuiltinTypes[IDLBuiltinType.Types.boolean],
10972                                      self.idlNode),
10973                         self.foundVar))
10974        return args
10975
10976    def wrap_return_value(self):
10977        if not self.idlNode.isGetter() or self.templateValues is None:
10978            return ""
10979
10980        wrap = CGGeneric(wrapForType(self.returnType, self.descriptor, self.templateValues))
10981        if self.checkFound:
10982            wrap = CGIfWrapper(wrap, self.foundVar)
10983        else:
10984            wrap = CGList([CGGeneric("MOZ_ASSERT(" + self.foundVar + ");\n"), wrap])
10985        return "\n" + wrap.define()
10986
10987
10988class CGProxyIndexedOperation(CGProxySpecialOperation):
10989    """
10990    Class to generate a call to an indexed operation.
10991
10992    If doUnwrap is False, the caller is responsible for making sure a variable
10993    named 'self' holds the C++ object somewhere where the code we generate
10994    will see it.
10995
10996    If checkFound is False, will just assert that the prop is found instead of
10997    checking that it is before wrapping the value.
10998
10999    resultVar: See the docstring for CGCallGenerator.
11000
11001    foundVar: See the docstring for CGProxySpecialOperation.
11002    """
11003    def __init__(self, descriptor, name, doUnwrap=True, checkFound=True,
11004                 argumentHandleValue=None, resultVar=None, foundVar=None):
11005        self.doUnwrap = doUnwrap
11006        CGProxySpecialOperation.__init__(self, descriptor, name, checkFound,
11007                                         argumentHandleValue=argumentHandleValue,
11008                                         resultVar=resultVar,
11009                                         foundVar=foundVar)
11010
11011    def define(self):
11012        # Our first argument is the id we're getting.
11013        argName = self.arguments[0].identifier.name
11014        if argName == "index":
11015            # We already have our index in a variable with that name
11016            setIndex = ""
11017        else:
11018            setIndex = "uint32_t %s = index;\n" % argName
11019        if self.doUnwrap:
11020            unwrap = "%s* self = UnwrapProxy(proxy);\n" % self.descriptor.nativeType
11021        else:
11022            unwrap = ""
11023        return (setIndex + unwrap +
11024                CGProxySpecialOperation.define(self))
11025
11026
11027class CGProxyIndexedGetter(CGProxyIndexedOperation):
11028    """
11029    Class to generate a call to an indexed getter. If templateValues is not None
11030    the returned value will be wrapped with wrapForType using templateValues.
11031
11032    If doUnwrap is False, the caller is responsible for making sure a variable
11033    named 'self' holds the C++ object somewhere where the code we generate
11034    will see it.
11035
11036    If checkFound is False, will just assert that the prop is found instead of
11037    checking that it is before wrapping the value.
11038
11039    foundVar: See the docstring for CGProxySpecialOperation.
11040    """
11041    def __init__(self, descriptor, templateValues=None, doUnwrap=True,
11042                 checkFound=True, foundVar=None):
11043        self.templateValues = templateValues
11044        CGProxyIndexedOperation.__init__(self, descriptor, 'IndexedGetter',
11045                                         doUnwrap, checkFound, foundVar=foundVar)
11046
11047
11048class CGProxyIndexedPresenceChecker(CGProxyIndexedGetter):
11049    """
11050    Class to generate a call that checks whether an indexed property exists.
11051
11052    For now, we just delegate to CGProxyIndexedGetter
11053
11054    foundVar: See the docstring for CGProxySpecialOperation.
11055    """
11056    def __init__(self, descriptor, foundVar):
11057        CGProxyIndexedGetter.__init__(self, descriptor, foundVar=foundVar)
11058        self.cgRoot.append(CGGeneric("(void)result;\n"))
11059
11060
11061class CGProxyIndexedSetter(CGProxyIndexedOperation):
11062    """
11063    Class to generate a call to an indexed setter.
11064    """
11065    def __init__(self, descriptor, argumentHandleValue=None):
11066        CGProxyIndexedOperation.__init__(self, descriptor, 'IndexedSetter',
11067                                         argumentHandleValue=argumentHandleValue)
11068
11069
11070class CGProxyNamedOperation(CGProxySpecialOperation):
11071    """
11072    Class to generate a call to a named operation.
11073
11074    'value' is the jsval to use for the name; None indicates that it should be
11075    gotten from the property id.
11076
11077    resultVar: See the docstring for CGCallGenerator.
11078
11079    foundVar: See the docstring for CGProxySpecialOperation.
11080    """
11081    def __init__(self, descriptor, name, value=None, argumentHandleValue=None,
11082                 resultVar=None, foundVar=None):
11083        CGProxySpecialOperation.__init__(self, descriptor, name,
11084                                         argumentHandleValue=argumentHandleValue,
11085                                         resultVar=resultVar,
11086                                         foundVar=foundVar)
11087        self.value = value
11088
11089    def define(self):
11090        # Our first argument is the id we're getting.
11091        argName = self.arguments[0].identifier.name
11092        if argName == "id":
11093            # deal with the name collision
11094            decls = "JS::Rooted<jsid> id_(cx, id);\n"
11095            idName = "id_"
11096        else:
11097            decls = ""
11098            idName = "id"
11099
11100        decls += "binding_detail::FakeString %s;\n" % argName
11101
11102        main = fill(
11103            """
11104            ${nativeType}* self = UnwrapProxy(proxy);
11105            $*{op}
11106            """,
11107            nativeType=self.descriptor.nativeType,
11108            op=CGProxySpecialOperation.define(self))
11109
11110        if self.value is None:
11111            return fill(
11112                """
11113                $*{decls}
11114                bool isSymbol;
11115                if (!ConvertIdToString(cx, ${idName}, ${argName}, isSymbol)) {
11116                  return false;
11117                }
11118                if (!isSymbol) {
11119                  $*{main}
11120                }
11121                """,
11122                decls=decls,
11123                idName=idName,
11124                argName=argName,
11125                main=main)
11126
11127        # Sadly, we have to set up nameVal even if we have an atom id,
11128        # because we don't know for sure, and we can end up needing it
11129        # so it needs to be higher up the stack.  Using a Maybe here
11130        # seems like probable overkill.
11131        return fill(
11132            """
11133            $*{decls}
11134            JS::Rooted<JS::Value> nameVal(cx, ${value});
11135            if (!nameVal.isSymbol()) {
11136              if (!ConvertJSValueToString(cx, nameVal, eStringify, eStringify,
11137                                          ${argName})) {
11138                return false;
11139              }
11140              $*{main}
11141            }
11142            """,
11143            decls=decls,
11144            value=self.value,
11145            argName=argName,
11146            main=main)
11147
11148
11149class CGProxyNamedGetter(CGProxyNamedOperation):
11150    """
11151    Class to generate a call to an named getter. If templateValues is not None
11152    the returned value will be wrapped with wrapForType using templateValues.
11153    'value' is the jsval to use for the name; None indicates that it should be
11154    gotten from the property id.
11155
11156    foundVar: See the docstring for CGProxySpecialOperation.
11157    """
11158    def __init__(self, descriptor, templateValues=None, value=None,
11159                 foundVar=None):
11160        self.templateValues = templateValues
11161        CGProxyNamedOperation.__init__(self, descriptor, 'NamedGetter', value,
11162                                       foundVar=foundVar)
11163
11164
11165class CGProxyNamedPresenceChecker(CGProxyNamedGetter):
11166    """
11167    Class to generate a call that checks whether a named property exists.
11168
11169    For now, we just delegate to CGProxyNamedGetter
11170
11171    foundVar: See the docstring for CGProxySpecialOperation.
11172    """
11173    def __init__(self, descriptor, foundVar=None):
11174        CGProxyNamedGetter.__init__(self, descriptor, foundVar=foundVar)
11175        self.cgRoot.append(CGGeneric("(void)result;\n"))
11176
11177
11178class CGProxyNamedSetter(CGProxyNamedOperation):
11179    """
11180    Class to generate a call to a named setter.
11181    """
11182    def __init__(self, descriptor, argumentHandleValue=None):
11183        CGProxyNamedOperation.__init__(self, descriptor, 'NamedSetter',
11184                                       argumentHandleValue=argumentHandleValue)
11185
11186
11187class CGProxyNamedDeleter(CGProxyNamedOperation):
11188    """
11189    Class to generate a call to a named deleter.
11190
11191    resultVar: See the docstring for CGCallGenerator.
11192
11193    foundVar: See the docstring for CGProxySpecialOperation.
11194    """
11195    def __init__(self, descriptor, resultVar=None, foundVar=None):
11196        CGProxyNamedOperation.__init__(self, descriptor, 'NamedDeleter',
11197                                       resultVar=resultVar,
11198                                       foundVar=foundVar)
11199
11200
11201class CGProxyIsProxy(CGAbstractMethod):
11202    def __init__(self, descriptor):
11203        args = [Argument('JSObject*', 'obj')]
11204        CGAbstractMethod.__init__(self, descriptor, "IsProxy", "bool", args, alwaysInline=True)
11205
11206    def declare(self):
11207        return ""
11208
11209    def definition_body(self):
11210        return "return js::IsProxy(obj) && js::GetProxyHandler(obj) == DOMProxyHandler::getInstance();\n"
11211
11212
11213class CGProxyUnwrap(CGAbstractMethod):
11214    def __init__(self, descriptor):
11215        args = [Argument('JSObject*', 'obj')]
11216        CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy", descriptor.nativeType + '*', args, alwaysInline=True)
11217
11218    def declare(self):
11219        return ""
11220
11221    def definition_body(self):
11222        return fill(
11223            """
11224            MOZ_ASSERT(js::IsProxy(obj));
11225            if (js::GetProxyHandler(obj) != DOMProxyHandler::getInstance()) {
11226              MOZ_ASSERT(xpc::WrapperFactory::IsXrayWrapper(obj));
11227              obj = js::UncheckedUnwrap(obj);
11228            }
11229            MOZ_ASSERT(IsProxy(obj));
11230            return static_cast<${type}*>(js::GetProxyPrivate(obj).toPrivate());
11231            """,
11232            type=self.descriptor.nativeType)
11233
11234
11235class CGDOMJSProxyHandler_getOwnPropDescriptor(ClassMethod):
11236    def __init__(self, descriptor):
11237        args = [Argument('JSContext*', 'cx'),
11238                Argument('JS::Handle<JSObject*>', 'proxy'),
11239                Argument('JS::Handle<jsid>', 'id'),
11240                Argument('bool', 'ignoreNamedProps'),
11241                Argument('JS::MutableHandle<JS::PropertyDescriptor>', 'desc')]
11242        ClassMethod.__init__(self, "getOwnPropDescriptor", "bool", args,
11243                             virtual=True, override=True, const=True)
11244        self.descriptor = descriptor
11245
11246    def getBody(self):
11247        indexedGetter = self.descriptor.operations['IndexedGetter']
11248        indexedSetter = self.descriptor.operations['IndexedSetter']
11249
11250        if self.descriptor.supportsIndexedProperties():
11251            readonly = toStringBool(indexedSetter is None)
11252            fillDescriptor = "FillPropertyDescriptor(desc, proxy, %s);\nreturn true;\n" % readonly
11253            templateValues = {
11254                'jsvalRef': 'desc.value()',
11255                'jsvalHandle': 'desc.value()',
11256                'obj': 'proxy',
11257                'successCode': fillDescriptor
11258            }
11259            getIndexed = fill(
11260                """
11261                uint32_t index = GetArrayIndexFromId(cx, id);
11262                if (IsArrayIndex(index)) {
11263                  $*{callGetter}
11264                }
11265
11266                """,
11267                callGetter=CGProxyIndexedGetter(self.descriptor, templateValues).define())
11268        else:
11269            getIndexed = ""
11270
11271        if self.descriptor.supportsNamedProperties():
11272            operations = self.descriptor.operations
11273            readonly = toStringBool(operations['NamedSetter'] is None)
11274            fillDescriptor = (
11275                "FillPropertyDescriptor(desc, proxy, %s, %s);\n"
11276                "return true;\n" %
11277                (readonly,
11278                 toStringBool(self.descriptor.namedPropertiesEnumerable)))
11279            templateValues = {'jsvalRef': 'desc.value()', 'jsvalHandle': 'desc.value()',
11280                              'obj': 'proxy', 'successCode': fillDescriptor}
11281
11282            computeCondition = dedent("""
11283                bool hasOnProto;
11284                if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
11285                  return false;
11286                }
11287                callNamedGetter = !hasOnProto;
11288                """)
11289            if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
11290                computeCondition = fill(
11291                    """
11292                    if (!isXray) {
11293                      callNamedGetter = true;
11294                    } else {
11295                      $*{hasOnProto}
11296                    }
11297                    """,
11298                    hasOnProto=computeCondition)
11299
11300            outerCondition = "!ignoreNamedProps"
11301            if self.descriptor.supportsIndexedProperties():
11302                outerCondition = "!IsArrayIndex(index) && " + outerCondition
11303
11304            namedGetCode = CGProxyNamedGetter(self.descriptor,
11305                                              templateValues).define()
11306            namedGet = fill("""
11307                bool callNamedGetter = false;
11308                if (${outerCondition}) {
11309                  $*{computeCondition}
11310                }
11311                if (callNamedGetter) {
11312                  $*{namedGetCode}
11313                }
11314                """,
11315                            outerCondition=outerCondition,
11316                            computeCondition=computeCondition,
11317                            namedGetCode=namedGetCode)
11318            namedGet += "\n"
11319        else:
11320            namedGet = ""
11321
11322        return fill(
11323            """
11324            bool isXray = xpc::WrapperFactory::IsXrayWrapper(proxy);
11325            $*{getIndexed}
11326            JS::Rooted<JSObject*> expando(cx);
11327            if (!isXray && (expando = GetExpandoObject(proxy))) {
11328              if (!JS_GetOwnPropertyDescriptorById(cx, expando, id, desc)) {
11329                return false;
11330              }
11331              if (desc.object()) {
11332                // Pretend the property lives on the wrapper.
11333                desc.object().set(proxy);
11334                return true;
11335              }
11336            }
11337
11338            $*{namedGet}
11339            desc.object().set(nullptr);
11340            return true;
11341            """,
11342            getIndexed=getIndexed,
11343            namedGet=namedGet)
11344
11345
11346class CGDOMJSProxyHandler_defineProperty(ClassMethod):
11347    def __init__(self, descriptor):
11348        # The usual convention is to name the ObjectOpResult out-parameter
11349        # `result`, but that name is a bit overloaded around here.
11350        args = [Argument('JSContext*', 'cx'),
11351                Argument('JS::Handle<JSObject*>', 'proxy'),
11352                Argument('JS::Handle<jsid>', 'id'),
11353                Argument('JS::Handle<JS::PropertyDescriptor>', 'desc'),
11354                Argument('JS::ObjectOpResult&', 'opresult'),
11355                Argument('bool*', 'defined')]
11356        ClassMethod.__init__(self, "defineProperty", "bool", args, virtual=True, override=True, const=True)
11357        self.descriptor = descriptor
11358
11359    def getBody(self):
11360        set = ""
11361
11362        indexedSetter = self.descriptor.operations['IndexedSetter']
11363        if indexedSetter:
11364            if self.descriptor.operations['IndexedCreator'] is not indexedSetter:
11365                raise TypeError("Can't handle creator that's different from the setter")
11366            set += fill(
11367                """
11368                uint32_t index = GetArrayIndexFromId(cx, id);
11369                if (IsArrayIndex(index)) {
11370                  *defined = true;
11371                  $*{callSetter}
11372                  return opresult.succeed();
11373                }
11374                """,
11375                callSetter=CGProxyIndexedSetter(self.descriptor).define())
11376        elif self.descriptor.supportsIndexedProperties():
11377            # We allow untrusted content to prevent Xrays from setting a
11378            # property if that property is an indexed property and we have no
11379            # indexed setter.  That's how the object would normally behave if
11380            # you tried to set the property on it.  That means we don't need to
11381            # do anything special for Xrays here.
11382            set += dedent(
11383                """
11384                if (IsArrayIndex(GetArrayIndexFromId(cx, id))) {
11385                  *defined = true;
11386                  return opresult.failNoIndexedSetter();
11387                }
11388                """)
11389
11390        namedSetter = self.descriptor.operations['NamedSetter']
11391        if namedSetter:
11392            if self.descriptor.hasUnforgeableMembers:
11393                raise TypeError("Can't handle a named setter on an interface "
11394                                "that has unforgeables.  Figure out how that "
11395                                "should work!")
11396            if self.descriptor.operations['NamedCreator'] is not namedSetter:
11397                raise TypeError("Can't handle creator that's different from the setter")
11398            # If we support indexed properties, we won't get down here for
11399            # indices, so we can just do our setter unconditionally here.
11400            set += fill(
11401                """
11402                *defined = true;
11403                $*{callSetter}
11404
11405                return opresult.succeed();
11406                """,
11407                callSetter=CGProxyNamedSetter(self.descriptor).define())
11408        else:
11409            # We allow untrusted content to prevent Xrays from setting a
11410            # property if that property is already a named property on the
11411            # object and we have no named setter.  That's how the object would
11412            # normally behave if you tried to set the property on it.  That
11413            # means we don't need to do anything special for Xrays here.
11414            if self.descriptor.supportsNamedProperties():
11415                set += fill(
11416                    """
11417                    bool found = false;
11418                    $*{presenceChecker}
11419
11420                    if (found) {
11421                      *defined = true;
11422                      return opresult.failNoNamedSetter();
11423                    }
11424                    """,
11425                    presenceChecker=CGProxyNamedPresenceChecker(self.descriptor, foundVar="found").define())
11426            set += ("return mozilla::dom::DOMProxyHandler::defineProperty(%s);\n" %
11427                    ", ".join(a.name for a in self.args))
11428        return set
11429
11430
11431def getDeleterBody(descriptor, type, foundVar=None):
11432    """
11433    type should be "Named" or "Indexed"
11434
11435    The possible outcomes:
11436    - an error happened                       (the emitted code returns false)
11437    - own property not found                  (foundVar=false, deleteSucceeded=true)
11438    - own property found and deleted          (foundVar=true,  deleteSucceeded=true)
11439    - own property found but can't be deleted (foundVar=true,  deleteSucceeded=false)
11440    """
11441    assert type in ("Named", "Indexed")
11442    deleter = descriptor.operations[type + 'Deleter']
11443    if deleter:
11444        assert type == "Named"
11445        assert foundVar is not None
11446        if descriptor.hasUnforgeableMembers:
11447            raise TypeError("Can't handle a deleter on an interface "
11448                            "that has unforgeables.  Figure out how "
11449                            "that should work!")
11450        # See if the deleter method is fallible.
11451        t = deleter.signatures()[0][0]
11452        if t.isPrimitive() and not t.nullable() and t.tag() == IDLType.Tags.bool:
11453            # The deleter method has a boolean return value. When a
11454            # property is found, the return value indicates whether it
11455            # was successfully deleted.
11456            setDS = fill(
11457                """
11458                if (!${foundVar}) {
11459                  deleteSucceeded = true;
11460                }
11461                """,
11462                foundVar=foundVar)
11463        else:
11464            # No boolean return value: if a property is found,
11465            # deleting it always succeeds.
11466            setDS = "deleteSucceeded = true;\n"
11467
11468        body = (CGProxyNamedDeleter(descriptor,
11469                                    resultVar="deleteSucceeded",
11470                                    foundVar=foundVar).define() +
11471                setDS)
11472    elif getattr(descriptor, "supports%sProperties" % type)():
11473        presenceCheckerClass = globals()["CGProxy%sPresenceChecker" % type]
11474        foundDecl = ""
11475        if foundVar is None:
11476            foundVar = "found"
11477            foundDecl = "bool found = false;\n"
11478        body = fill(
11479            """
11480            $*{foundDecl}
11481            $*{presenceChecker}
11482            deleteSucceeded = !${foundVar};
11483            """,
11484            foundDecl=foundDecl,
11485            presenceChecker=presenceCheckerClass(descriptor, foundVar=foundVar).define(),
11486            foundVar=foundVar)
11487    else:
11488        body = None
11489    return body
11490
11491
11492class CGDeleteNamedProperty(CGAbstractStaticMethod):
11493    def __init__(self, descriptor):
11494        args = [Argument('JSContext*', 'cx'),
11495                Argument('JS::Handle<JSObject*>', 'xray'),
11496                Argument('JS::Handle<JSObject*>', 'proxy'),
11497                Argument('JS::Handle<jsid>', 'id'),
11498                Argument('JS::ObjectOpResult&', 'opresult')]
11499        CGAbstractStaticMethod.__init__(self, descriptor, "DeleteNamedProperty",
11500                                        "bool", args)
11501
11502    def definition_body(self):
11503        return fill(
11504            """
11505            MOZ_ASSERT(xpc::WrapperFactory::IsXrayWrapper(xray));
11506            MOZ_ASSERT(js::IsProxy(proxy));
11507            MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy));
11508            JSAutoCompartment ac(cx, proxy);
11509            bool deleteSucceeded;
11510            bool found = false;
11511            $*{namedBody}
11512            if (!found || deleteSucceeded) {
11513              return opresult.succeed();
11514            }
11515            return opresult.failCantDelete();
11516            """,
11517            namedBody=getDeleterBody(self.descriptor, "Named", foundVar="found"))
11518
11519
11520class CGDOMJSProxyHandler_delete(ClassMethod):
11521    def __init__(self, descriptor):
11522        args = [Argument('JSContext*', 'cx'),
11523                Argument('JS::Handle<JSObject*>', 'proxy'),
11524                Argument('JS::Handle<jsid>', 'id'),
11525                Argument('JS::ObjectOpResult&', 'opresult')]
11526        ClassMethod.__init__(self, "delete_", "bool", args,
11527                             virtual=True, override=True, const=True)
11528        self.descriptor = descriptor
11529
11530    def getBody(self):
11531        delete = dedent("""
11532            MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
11533                      "Should not have a XrayWrapper here");
11534
11535            """)
11536
11537        indexedBody = getDeleterBody(self.descriptor, "Indexed")
11538        if indexedBody is not None:
11539            delete += fill(
11540                """
11541                uint32_t index = GetArrayIndexFromId(cx, id);
11542                if (IsArrayIndex(index)) {
11543                  bool deleteSucceeded;
11544                  $*{indexedBody}
11545                  return deleteSucceeded ? opresult.succeed() : opresult.failCantDelete();
11546                }
11547                """,
11548                indexedBody=indexedBody)
11549
11550        namedBody = getDeleterBody(self.descriptor, "Named", foundVar="found")
11551        if namedBody is not None:
11552            delete += dedent(
11553                """
11554                // Try named delete only if the named property visibility
11555                // algorithm says the property is visible.
11556                bool tryNamedDelete = true;
11557                { // Scope for expando
11558                  JS::Rooted<JSObject*> expando(cx, DOMProxyHandler::GetExpandoObject(proxy));
11559                  if (expando) {
11560                    bool hasProp;
11561                    if (!JS_HasPropertyById(cx, expando, id, &hasProp)) {
11562                      return false;
11563                    }
11564                    tryNamedDelete = !hasProp;
11565                  }
11566                }
11567                """)
11568
11569            if not self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
11570                delete += dedent(
11571                    """
11572                    if (tryNamedDelete) {
11573                      bool hasOnProto;
11574                      if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
11575                        return false;
11576                      }
11577                      tryNamedDelete = !hasOnProto;
11578                    }
11579                    """)
11580
11581            # We always return above for an index id in the case when we support
11582            # indexed properties, so we can just treat the id as a name
11583            # unconditionally here.
11584            delete += fill(
11585                """
11586                if (tryNamedDelete) {
11587                  bool found = false;
11588                  bool deleteSucceeded;
11589                  $*{namedBody}
11590                  if (found) {
11591                    return deleteSucceeded ? opresult.succeed() : opresult.failCantDelete();
11592                  }
11593                }
11594                """,
11595                namedBody=namedBody)
11596
11597        delete += dedent("""
11598
11599            return dom::DOMProxyHandler::delete_(cx, proxy, id, opresult);
11600            """)
11601
11602        return delete
11603
11604
11605class CGDOMJSProxyHandler_ownPropNames(ClassMethod):
11606    def __init__(self, descriptor, ):
11607        args = [Argument('JSContext*', 'cx'),
11608                Argument('JS::Handle<JSObject*>', 'proxy'),
11609                Argument('unsigned', 'flags'),
11610                Argument('JS::AutoIdVector&', 'props')]
11611        ClassMethod.__init__(self, "ownPropNames", "bool", args,
11612                             virtual=True, override=True, const=True)
11613        self.descriptor = descriptor
11614
11615    def getBody(self):
11616        # Per spec, we do indices, then named props, then everything else
11617        if self.descriptor.supportsIndexedProperties():
11618            addIndices = dedent("""
11619
11620                uint32_t length = UnwrapProxy(proxy)->Length();
11621                MOZ_ASSERT(int32_t(length) >= 0);
11622                for (int32_t i = 0; i < int32_t(length); ++i) {
11623                  if (!props.append(INT_TO_JSID(i))) {
11624                    return false;
11625                  }
11626                }
11627                """)
11628        else:
11629            addIndices = ""
11630
11631        if self.descriptor.supportsNamedProperties():
11632            if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
11633                shadow = "!isXray"
11634            else:
11635                shadow = "false"
11636            addNames = fill(
11637                """
11638                nsTArray<nsString> names;
11639                UnwrapProxy(proxy)->GetSupportedNames(names);
11640                if (!AppendNamedPropertyIds(cx, proxy, names, ${shadow}, props)) {
11641                  return false;
11642                }
11643                """,
11644                shadow=shadow)
11645            if not self.descriptor.namedPropertiesEnumerable:
11646                addNames = CGIfWrapper(CGGeneric(addNames),
11647                                       "flags & JSITER_HIDDEN").define()
11648            addNames = "\n" + addNames
11649        else:
11650            addNames = ""
11651
11652        return fill(
11653            """
11654            bool isXray = xpc::WrapperFactory::IsXrayWrapper(proxy);
11655            $*{addIndices}
11656            $*{addNames}
11657
11658            JS::Rooted<JSObject*> expando(cx);
11659            if (!isXray && (expando = DOMProxyHandler::GetExpandoObject(proxy)) &&
11660                !js::GetPropertyKeys(cx, expando, flags, &props)) {
11661              return false;
11662            }
11663
11664            return true;
11665            """,
11666            addIndices=addIndices,
11667            addNames=addNames)
11668
11669
11670class CGDOMJSProxyHandler_hasOwn(ClassMethod):
11671    def __init__(self, descriptor):
11672        args = [Argument('JSContext*', 'cx'),
11673                Argument('JS::Handle<JSObject*>', 'proxy'),
11674                Argument('JS::Handle<jsid>', 'id'),
11675                Argument('bool*', 'bp')]
11676        ClassMethod.__init__(self, "hasOwn", "bool", args,
11677                             virtual=True, override=True, const=True)
11678        self.descriptor = descriptor
11679
11680    def getBody(self):
11681        if self.descriptor.supportsIndexedProperties():
11682            indexed = fill(
11683                """
11684                uint32_t index = GetArrayIndexFromId(cx, id);
11685                if (IsArrayIndex(index)) {
11686                  bool found = false;
11687                  $*{presenceChecker}
11688
11689                  *bp = found;
11690                  return true;
11691                }
11692
11693                """,
11694                presenceChecker=CGProxyIndexedPresenceChecker(self.descriptor, foundVar="found").define())
11695        else:
11696            indexed = ""
11697
11698        if self.descriptor.supportsNamedProperties():
11699            # If we support indexed properties we always return above for index
11700            # property names, so no need to check for those here.
11701            named = fill(
11702                """
11703                bool found = false;
11704                $*{presenceChecker}
11705
11706                *bp = found;
11707                """,
11708                presenceChecker=CGProxyNamedPresenceChecker(self.descriptor, foundVar="found").define())
11709            if not self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
11710                named = fill(
11711                    """
11712                    bool hasOnProto;
11713                    if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
11714                      return false;
11715                    }
11716                    if (!hasOnProto) {
11717                      $*{protoLacksProperty}
11718                      return true;
11719                    }
11720                    """,
11721                    protoLacksProperty=named)
11722                named += "*bp = false;\n"
11723            else:
11724                named += "\n"
11725        else:
11726            named = "*bp = false;\n"
11727
11728        return fill(
11729            """
11730            MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
11731                      "Should not have a XrayWrapper here");
11732
11733            $*{indexed}
11734
11735            JS::Rooted<JSObject*> expando(cx, GetExpandoObject(proxy));
11736            if (expando) {
11737              bool b = true;
11738              bool ok = JS_HasPropertyById(cx, expando, id, &b);
11739              *bp = !!b;
11740              if (!ok || *bp) {
11741                return ok;
11742              }
11743            }
11744
11745            $*{named}
11746            return true;
11747            """,
11748            indexed=indexed,
11749            named=named)
11750
11751
11752class CGDOMJSProxyHandler_get(ClassMethod):
11753    def __init__(self, descriptor):
11754        args = [Argument('JSContext*', 'cx'),
11755                Argument('JS::Handle<JSObject*>', 'proxy'),
11756                Argument('JS::Handle<JS::Value>', 'receiver'),
11757                Argument('JS::Handle<jsid>', 'id'),
11758                Argument('JS::MutableHandle<JS::Value>', 'vp')]
11759        ClassMethod.__init__(self, "get", "bool", args,
11760                             virtual=True, override=True, const=True)
11761        self.descriptor = descriptor
11762
11763    def getBody(self):
11764        getUnforgeableOrExpando = dedent("""
11765            { // Scope for expando
11766              JS::Rooted<JSObject*> expando(cx, DOMProxyHandler::GetExpandoObject(proxy));
11767              if (expando) {
11768                bool hasProp;
11769                if (!JS_HasPropertyById(cx, expando, id, &hasProp)) {
11770                  return false;
11771                }
11772
11773                if (hasProp) {
11774                  // Forward the get to the expando object, but our receiver is whatever our
11775                  // receiver is.
11776                  return JS_ForwardGetPropertyTo(cx, expando, id, receiver, vp);
11777                }
11778              }
11779            }
11780            """)
11781
11782        templateValues = {'jsvalRef': 'vp', 'jsvalHandle': 'vp', 'obj': 'proxy'}
11783
11784        if self.descriptor.supportsIndexedProperties():
11785            getIndexedOrExpando = fill(
11786                """
11787                uint32_t index = GetArrayIndexFromId(cx, id);
11788                if (IsArrayIndex(index)) {
11789                  $*{callGetter}
11790                  // Even if we don't have this index, we don't forward the
11791                  // get on to our expando object.
11792                } else {
11793                  $*{getUnforgeableOrExpando}
11794                }
11795                """,
11796                callGetter=CGProxyIndexedGetter(self.descriptor, templateValues).define(),
11797                getUnforgeableOrExpando=getUnforgeableOrExpando)
11798        else:
11799            getIndexedOrExpando = getUnforgeableOrExpando
11800
11801        if self.descriptor.supportsNamedProperties():
11802            getNamed = CGProxyNamedGetter(self.descriptor, templateValues)
11803            if self.descriptor.supportsIndexedProperties():
11804                getNamed = CGIfWrapper(getNamed, "!IsArrayIndex(index)")
11805            getNamed = getNamed.define() + "\n"
11806        else:
11807            getNamed = ""
11808
11809        getOnPrototype = dedent("""
11810            bool foundOnPrototype;
11811            if (!GetPropertyOnPrototype(cx, proxy, receiver, id, &foundOnPrototype, vp)) {
11812              return false;
11813            }
11814
11815            if (foundOnPrototype) {
11816              return true;
11817            }
11818
11819            """)
11820        if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
11821            getNamed = getNamed + getOnPrototype
11822        else:
11823            getNamed = getOnPrototype + getNamed
11824
11825        return fill(
11826            """
11827            MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
11828                        "Should not have a XrayWrapper here");
11829
11830            $*{indexedOrExpando}
11831
11832            $*{named}
11833            vp.setUndefined();
11834            return true;
11835            """,
11836            indexedOrExpando=getIndexedOrExpando,
11837            named=getNamed)
11838
11839
11840class CGDOMJSProxyHandler_setCustom(ClassMethod):
11841    def __init__(self, descriptor):
11842        args = [Argument('JSContext*', 'cx'),
11843                Argument('JS::Handle<JSObject*>', 'proxy'),
11844                Argument('JS::Handle<jsid>', 'id'),
11845                Argument('JS::Handle<JS::Value>', 'v'),
11846                Argument('bool*', 'done')]
11847        ClassMethod.__init__(self, "setCustom", "bool", args, virtual=True, override=True, const=True)
11848        self.descriptor = descriptor
11849
11850    def getBody(self):
11851        assertion = ("MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),\n"
11852                     '           "Should not have a XrayWrapper here");\n')
11853
11854        # Correctness first. If we have a NamedSetter and [OverrideBuiltins],
11855        # always call the NamedSetter and never do anything else.
11856        namedSetter = self.descriptor.operations['NamedSetter']
11857        if (namedSetter is not None and
11858            self.descriptor.interface.getExtendedAttribute('OverrideBuiltins')):
11859            # Check assumptions.
11860            if self.descriptor.supportsIndexedProperties():
11861                raise ValueError("In interface " + self.descriptor.name + ": " +
11862                                 "Can't cope with [OverrideBuiltins] and an indexed getter")
11863            if self.descriptor.operations['NamedCreator'] is not namedSetter:
11864                raise ValueError("In interface " + self.descriptor.name + ": " +
11865                                 "Can't cope with named setter that is not also a named creator")
11866            if self.descriptor.hasUnforgeableMembers:
11867                raise ValueError("In interface " + self.descriptor.name + ": " +
11868                                 "Can't cope with [OverrideBuiltins] and unforgeable members")
11869
11870            callSetter = CGProxyNamedSetter(self.descriptor, argumentHandleValue="v")
11871            return (assertion +
11872                    callSetter.define() +
11873                    "*done = true;\n"
11874                    "return true;\n")
11875
11876        # As an optimization, if we are going to call an IndexedSetter, go
11877        # ahead and call it and have done.
11878        indexedSetter = self.descriptor.operations['IndexedSetter']
11879        if indexedSetter is not None:
11880            if self.descriptor.operations['IndexedCreator'] is not indexedSetter:
11881                raise ValueError("In interface " + self.descriptor.name + ": " +
11882                                 "Can't cope with indexed setter that is not " +
11883                                 "also an indexed creator")
11884            setIndexed = fill(
11885                """
11886                uint32_t index = GetArrayIndexFromId(cx, id);
11887                if (IsArrayIndex(index)) {
11888                  $*{callSetter}
11889                  *done = true;
11890                  return true;
11891                }
11892
11893                """,
11894                callSetter=CGProxyIndexedSetter(self.descriptor,
11895                                                argumentHandleValue="v").define())
11896        else:
11897            setIndexed = ""
11898
11899        return (assertion +
11900                setIndexed +
11901                "*done = false;\n"
11902                "return true;\n")
11903
11904
11905class CGDOMJSProxyHandler_className(ClassMethod):
11906    def __init__(self, descriptor):
11907        args = [Argument('JSContext*', 'cx'),
11908                Argument('JS::Handle<JSObject*>', 'proxy')]
11909        ClassMethod.__init__(self, "className", "const char*", args,
11910                             virtual=True, override=True, const=True)
11911        self.descriptor = descriptor
11912
11913    def getBody(self):
11914        return 'return "%s";\n' % self.descriptor.name
11915
11916
11917class CGDOMJSProxyHandler_finalizeInBackground(ClassMethod):
11918    def __init__(self, descriptor):
11919        args = [Argument('const JS::Value&', 'priv')]
11920        ClassMethod.__init__(self, "finalizeInBackground", "bool", args,
11921                             virtual=True, override=True, const=True)
11922        self.descriptor = descriptor
11923
11924    def getBody(self):
11925        return "return false;\n"
11926
11927
11928class CGDOMJSProxyHandler_finalize(ClassMethod):
11929    def __init__(self, descriptor):
11930        args = [Argument('JSFreeOp*', 'fop'), Argument('JSObject*', 'proxy')]
11931        ClassMethod.__init__(self, "finalize", "void", args,
11932                             virtual=True, override=True, const=True)
11933        self.descriptor = descriptor
11934
11935    def getBody(self):
11936        return (("%s* self = UnwrapPossiblyNotInitializedDOMObject<%s>(proxy);\n" %
11937                 (self.descriptor.nativeType, self.descriptor.nativeType)) +
11938                finalizeHook(self.descriptor, FINALIZE_HOOK_NAME, self.args[0].name).define())
11939
11940
11941class CGDOMJSProxyHandler_getElements(ClassMethod):
11942    def __init__(self, descriptor):
11943        assert descriptor.supportsIndexedProperties()
11944
11945        args = [Argument('JSContext*', 'cx'),
11946                Argument('JS::Handle<JSObject*>', 'proxy'),
11947                Argument('uint32_t', 'begin'),
11948                Argument('uint32_t', 'end'),
11949                Argument('js::ElementAdder*', 'adder')]
11950        ClassMethod.__init__(self, "getElements", "bool", args, virtual=True, override=True, const=True)
11951        self.descriptor = descriptor
11952
11953    def getBody(self):
11954        # Just like ownPropertyKeys we'll assume that we have no holes, so
11955        # we have all properties from 0 to length.  If that ever changes
11956        # (unlikely), we'll need to do something a bit more clever with how we
11957        # forward on to our ancestor.
11958
11959        templateValues = {
11960            'jsvalRef': 'temp',
11961            'jsvalHandle': '&temp',
11962            'obj': 'proxy',
11963            'successCode': ("if (!adder->append(cx, temp)) return false;\n"
11964                            "continue;\n")
11965        }
11966        get = CGProxyIndexedGetter(self.descriptor, templateValues, False, False).define()
11967
11968        return fill(
11969            """
11970            JS::Rooted<JS::Value> temp(cx);
11971            MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
11972                       "Should not have a XrayWrapper here");
11973
11974            ${nativeType}* self = UnwrapProxy(proxy);
11975            uint32_t length = self->Length();
11976            // Compute the end of the indices we'll get ourselves
11977            uint32_t ourEnd = std::max(begin, std::min(end, length));
11978
11979            for (uint32_t index = begin; index < ourEnd; ++index) {
11980              $*{get}
11981            }
11982
11983            if (end > ourEnd) {
11984              JS::Rooted<JSObject*> proto(cx);
11985              if (!js::GetObjectProto(cx, proxy, &proto)) {
11986                return false;
11987              }
11988              return js::GetElementsWithAdder(cx, proto, proxy, ourEnd, end, adder);
11989            }
11990
11991            return true;
11992            """,
11993            nativeType=self.descriptor.nativeType,
11994            get=get)
11995
11996
11997class CGDOMJSProxyHandler_getInstance(ClassMethod):
11998    def __init__(self):
11999        ClassMethod.__init__(self, "getInstance", "const DOMProxyHandler*", [], static=True)
12000
12001    def getBody(self):
12002        return dedent("""
12003            static const DOMProxyHandler instance;
12004            return &instance;
12005            """)
12006
12007
12008class CGDOMJSProxyHandler_getPrototypeIfOrdinary(ClassMethod):
12009    def __init__(self):
12010        args = [Argument('JSContext*', 'cx'),
12011                Argument('JS::Handle<JSObject*>', 'proxy'),
12012                Argument('bool*', 'isOrdinary'),
12013                Argument('JS::MutableHandle<JSObject*>', 'proto')]
12014
12015        ClassMethod.__init__(self, "getPrototypeIfOrdinary", "bool", args,
12016                             virtual=True, override=True, const=True)
12017
12018    def getBody(self):
12019        return dedent("""
12020            *isOrdinary = false;
12021            return true;
12022            """)
12023
12024
12025class CGDOMJSProxyHandler_call(ClassMethod):
12026    def __init__(self):
12027        args = [Argument('JSContext*', 'cx'),
12028                Argument('JS::Handle<JSObject*>', 'proxy'),
12029                Argument('const JS::CallArgs&', 'args')]
12030
12031        ClassMethod.__init__(self, "call", "bool", args, virtual=True, override=True, const=True)
12032
12033    def getBody(self):
12034        return fill(
12035            """
12036            return js::ForwardToNative(cx, ${legacyCaller}, args);
12037            """,
12038            legacyCaller=LEGACYCALLER_HOOK_NAME)
12039
12040
12041class CGDOMJSProxyHandler_isCallable(ClassMethod):
12042    def __init__(self):
12043        ClassMethod.__init__(self, "isCallable", "bool",
12044                             [Argument('JSObject*', 'obj')],
12045                             virtual=True, override=True, const=True)
12046
12047    def getBody(self):
12048        return dedent("""
12049            return true;
12050        """)
12051
12052
12053class CGDOMJSProxyHandler(CGClass):
12054    def __init__(self, descriptor):
12055        assert (descriptor.supportsIndexedProperties() or
12056                descriptor.supportsNamedProperties() or
12057                descriptor.hasNonOrdinaryGetPrototypeOf())
12058        methods = [CGDOMJSProxyHandler_getOwnPropDescriptor(descriptor),
12059                   CGDOMJSProxyHandler_defineProperty(descriptor),
12060                   ClassUsingDeclaration("mozilla::dom::DOMProxyHandler",
12061                                         "defineProperty"),
12062                   CGDOMJSProxyHandler_ownPropNames(descriptor),
12063                   CGDOMJSProxyHandler_hasOwn(descriptor),
12064                   CGDOMJSProxyHandler_get(descriptor),
12065                   CGDOMJSProxyHandler_className(descriptor),
12066                   CGDOMJSProxyHandler_finalizeInBackground(descriptor),
12067                   CGDOMJSProxyHandler_finalize(descriptor),
12068                   CGDOMJSProxyHandler_getInstance(),
12069                   CGDOMJSProxyHandler_delete(descriptor)]
12070        constructors = [
12071            ClassConstructor(
12072                [],
12073                constexpr=True,
12074                visibility="public",
12075                explicit=True)
12076        ]
12077
12078        if descriptor.supportsIndexedProperties():
12079            methods.append(CGDOMJSProxyHandler_getElements(descriptor))
12080        if (descriptor.operations['IndexedSetter'] is not None or
12081            (descriptor.operations['NamedSetter'] is not None and
12082             descriptor.interface.getExtendedAttribute('OverrideBuiltins'))):
12083            methods.append(CGDOMJSProxyHandler_setCustom(descriptor))
12084        if descriptor.hasNonOrdinaryGetPrototypeOf():
12085            methods.append(CGDOMJSProxyHandler_getPrototypeIfOrdinary())
12086        if descriptor.operations['LegacyCaller']:
12087            methods.append(CGDOMJSProxyHandler_call())
12088            methods.append(CGDOMJSProxyHandler_isCallable())
12089
12090        if descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
12091            parentClass = 'ShadowingDOMProxyHandler'
12092        else:
12093            parentClass = 'mozilla::dom::DOMProxyHandler'
12094
12095        CGClass.__init__(self, 'DOMProxyHandler',
12096                         bases=[ClassBase(parentClass)],
12097                         constructors=constructors,
12098                         methods=methods)
12099
12100
12101class CGDOMJSProxyHandlerDeclarer(CGThing):
12102    """
12103    A class for declaring a DOMProxyHandler.
12104    """
12105    def __init__(self, handlerThing):
12106        self.handlerThing = handlerThing
12107
12108    def declare(self):
12109        # Our class declaration should happen when we're defining
12110        return ""
12111
12112    def define(self):
12113        return self.handlerThing.declare()
12114
12115
12116class CGDOMJSProxyHandlerDefiner(CGThing):
12117    """
12118    A class for defining a DOMProxyHandler.
12119    """
12120    def __init__(self, handlerThing):
12121        self.handlerThing = handlerThing
12122
12123    def declare(self):
12124        return ""
12125
12126    def define(self):
12127        return self.handlerThing.define()
12128
12129
12130def stripTrailingWhitespace(text):
12131    tail = '\n' if text.endswith('\n') else ''
12132    lines = text.splitlines()
12133    return '\n'.join(line.rstrip() for line in lines) + tail
12134
12135
12136class MemberProperties:
12137    def __init__(self):
12138        self.isGenericMethod = False
12139        self.isCrossOriginMethod = False
12140        self.isPromiseReturningMethod = False
12141        self.isGenericGetter = False
12142        self.isLenientGetter = False
12143        self.isCrossOriginGetter = False
12144        self.isGenericSetter = False
12145        self.isLenientSetter = False
12146        self.isCrossOriginSetter = False
12147        self.isJsonifier = False
12148
12149
12150def memberProperties(m, descriptor):
12151    props = MemberProperties()
12152    if m.isMethod():
12153        if m == descriptor.operations['Jsonifier']:
12154            props.isGenericMethod = descriptor.needsSpecialGenericOps()
12155            props.isJsonifier = True
12156        elif (not m.isIdentifierLess() or m == descriptor.operations['Stringifier']):
12157            if not m.isStatic() and descriptor.interface.hasInterfacePrototypeObject():
12158                if descriptor.needsSpecialGenericOps():
12159                    if m.returnsPromise():
12160                        props.isPromiseReturningMethod = True
12161                    else:
12162                        props.isGenericMethod = True
12163                if m.getExtendedAttribute("CrossOriginCallable"):
12164                    props.isCrossOriginMethod = True
12165    elif m.isAttr():
12166        if not m.isStatic() and descriptor.interface.hasInterfacePrototypeObject():
12167            if m.hasLenientThis():
12168                props.isLenientGetter = True
12169            elif m.getExtendedAttribute("CrossOriginReadable"):
12170                props.isCrossOriginGetter = True
12171            elif descriptor.needsSpecialGenericOps():
12172                props.isGenericGetter = True
12173        if not m.readonly:
12174            if not m.isStatic() and descriptor.interface.hasInterfacePrototypeObject():
12175                if m.hasLenientThis():
12176                    props.isLenientSetter = True
12177                elif IsCrossOriginWritable(m, descriptor):
12178                    props.isCrossOriginSetter = True
12179                elif descriptor.needsSpecialGenericOps():
12180                    props.isGenericSetter = True
12181        elif m.getExtendedAttribute("PutForwards"):
12182            if IsCrossOriginWritable(m, descriptor):
12183                props.isCrossOriginSetter = True
12184            elif descriptor.needsSpecialGenericOps():
12185                props.isGenericSetter = True
12186        elif (m.getExtendedAttribute("Replaceable") or
12187              m.getExtendedAttribute("LenientSetter")):
12188            if descriptor.needsSpecialGenericOps():
12189                props.isGenericSetter = True
12190
12191    return props
12192
12193
12194class CGDescriptor(CGThing):
12195    def __init__(self, descriptor):
12196        CGThing.__init__(self)
12197
12198        assert not descriptor.concrete or descriptor.interface.hasInterfacePrototypeObject()
12199
12200        self._deps = descriptor.interface.getDeps()
12201
12202        cgThings = []
12203        cgThings.append(CGGeneric(declare="typedef %s NativeType;\n" %
12204                                  descriptor.nativeType))
12205        parent = descriptor.interface.parent
12206        if parent:
12207            cgThings.append(CGGeneric("static_assert(IsRefcounted<NativeType>::value == IsRefcounted<%s::NativeType>::value,\n"
12208                                      "              \"Can't inherit from an interface with a different ownership model.\");\n" %
12209                                      toBindingNamespace(descriptor.parentPrototypeName)))
12210
12211        # These are set to true if at least one non-static
12212        # method/getter/setter or jsonifier exist on the interface.
12213        (hasMethod, hasGetter, hasLenientGetter, hasSetter, hasLenientSetter,
12214            hasPromiseReturningMethod) = False, False, False, False, False, False
12215        jsonifierMethod = None
12216        crossOriginMethods, crossOriginGetters, crossOriginSetters = set(), set(), set()
12217        unscopableNames = list()
12218        for n in descriptor.interface.namedConstructors:
12219            cgThings.append(CGClassConstructor(descriptor, n,
12220                                               NamedConstructorName(n)))
12221        for m in descriptor.interface.members:
12222            if m.isMethod() and m.identifier.name == 'queryInterface':
12223                continue
12224
12225            props = memberProperties(m, descriptor)
12226
12227            if m.isMethod():
12228                if m.getExtendedAttribute("Unscopable"):
12229                    assert not m.isStatic()
12230                    unscopableNames.append(m.identifier.name)
12231                if props.isJsonifier:
12232                    jsonifierMethod = m
12233                elif not m.isIdentifierLess() or m == descriptor.operations['Stringifier']:
12234                    if m.isStatic():
12235                        assert descriptor.interface.hasInterfaceObject()
12236                        cgThings.append(CGStaticMethod(descriptor, m))
12237                        if m.returnsPromise():
12238                            cgThings.append(CGStaticMethodJitinfo(m))
12239                    elif descriptor.interface.hasInterfacePrototypeObject():
12240                        specializedMethod = CGSpecializedMethod(descriptor, m)
12241                        cgThings.append(specializedMethod)
12242                        if m.returnsPromise():
12243                            cgThings.append(CGMethodPromiseWrapper(descriptor, specializedMethod))
12244                        cgThings.append(CGMemberJITInfo(descriptor, m))
12245                        if props.isCrossOriginMethod:
12246                            crossOriginMethods.add(m.identifier.name)
12247            # If we've hit the maplike/setlike member itself, go ahead and
12248            # generate its convenience functions.
12249            elif m.isMaplikeOrSetlike():
12250                cgThings.append(CGMaplikeOrSetlikeHelperGenerator(descriptor, m))
12251            elif m.isAttr():
12252                if m.stringifier:
12253                    raise TypeError("Stringifier attributes not supported yet. "
12254                                    "See bug 824857.\n"
12255                                    "%s" % m.location)
12256                if m.getExtendedAttribute("Unscopable"):
12257                    assert not m.isStatic()
12258                    unscopableNames.append(m.identifier.name)
12259                if m.isStatic():
12260                    assert descriptor.interface.hasInterfaceObject()
12261                    cgThings.append(CGStaticGetter(descriptor, m))
12262                elif descriptor.interface.hasInterfacePrototypeObject():
12263                    if isNonExposedNavigatorObjectGetter(m, descriptor):
12264                        continue
12265                    cgThings.append(CGSpecializedGetter(descriptor, m))
12266                    if props.isCrossOriginGetter:
12267                        crossOriginGetters.add(m.identifier.name)
12268                if not m.readonly:
12269                    if m.isStatic():
12270                        assert descriptor.interface.hasInterfaceObject()
12271                        cgThings.append(CGStaticSetter(descriptor, m))
12272                    elif descriptor.interface.hasInterfacePrototypeObject():
12273                        cgThings.append(CGSpecializedSetter(descriptor, m))
12274                        if props.isCrossOriginSetter:
12275                            crossOriginSetters.add(m.identifier.name)
12276                elif m.getExtendedAttribute("PutForwards"):
12277                    cgThings.append(CGSpecializedForwardingSetter(descriptor, m))
12278                    if props.isCrossOriginSetter:
12279                        crossOriginSetters.add(m.identifier.name)
12280                elif m.getExtendedAttribute("Replaceable"):
12281                    cgThings.append(CGSpecializedReplaceableSetter(descriptor, m))
12282                elif m.getExtendedAttribute("LenientSetter"):
12283                    cgThings.append(CGSpecializedLenientSetter(descriptor, m))
12284                if (not m.isStatic() and
12285                    descriptor.interface.hasInterfacePrototypeObject()):
12286                    cgThings.append(CGMemberJITInfo(descriptor, m))
12287
12288            hasMethod = hasMethod or props.isGenericMethod
12289            hasPromiseReturningMethod = (hasPromiseReturningMethod or
12290                                         props.isPromiseReturningMethod)
12291            hasGetter = hasGetter or props.isGenericGetter
12292            hasLenientGetter = hasLenientGetter or props.isLenientGetter
12293            hasSetter = hasSetter or props.isGenericSetter
12294            hasLenientSetter = hasLenientSetter or props.isLenientSetter
12295
12296        if jsonifierMethod:
12297            cgThings.append(CGJsonifyAttributesMethod(descriptor))
12298            cgThings.append(CGJsonifierMethod(descriptor, jsonifierMethod))
12299            cgThings.append(CGMemberJITInfo(descriptor, jsonifierMethod))
12300        if hasMethod:
12301            cgThings.append(CGGenericMethod(descriptor))
12302        if hasPromiseReturningMethod:
12303            cgThings.append(CGGenericPromiseReturningMethod(descriptor))
12304        if len(crossOriginMethods):
12305            cgThings.append(CGGenericMethod(descriptor,
12306                                            allowCrossOriginThis=True))
12307        if hasGetter:
12308            cgThings.append(CGGenericGetter(descriptor))
12309        if hasLenientGetter:
12310            cgThings.append(CGGenericGetter(descriptor, lenientThis=True))
12311        if len(crossOriginGetters):
12312            cgThings.append(CGGenericGetter(descriptor,
12313                                            allowCrossOriginThis=True))
12314        if hasSetter:
12315            cgThings.append(CGGenericSetter(descriptor))
12316        if hasLenientSetter:
12317            cgThings.append(CGGenericSetter(descriptor, lenientThis=True))
12318        if len(crossOriginSetters):
12319            cgThings.append(CGGenericSetter(descriptor,
12320                                            allowCrossOriginThis=True))
12321
12322        if descriptor.interface.isNavigatorProperty():
12323            cgThings.append(CGConstructNavigatorObject(descriptor))
12324
12325        if descriptor.concrete and not descriptor.proxy:
12326            if wantsAddProperty(descriptor):
12327                cgThings.append(CGAddPropertyHook(descriptor))
12328
12329            # Always have a finalize hook, regardless of whether the class
12330            # wants a custom hook.
12331            cgThings.append(CGClassFinalizeHook(descriptor))
12332
12333        if descriptor.concrete and descriptor.wrapperCache:
12334            cgThings.append(CGClassObjectMovedHook(descriptor))
12335
12336        # Generate the _ClearCachedFooValue methods before the property arrays that use them.
12337        if descriptor.interface.isJSImplemented():
12338            for m in clearableCachedAttrs(descriptor):
12339                cgThings.append(CGJSImplClearCachedValueMethod(descriptor, m))
12340
12341        # Need to output our generated hasinstance bits before
12342        # PropertyArrays tries to use them.
12343        if (descriptor.interface.hasInterfaceObject() and
12344            NeedsGeneratedHasInstance(descriptor)):
12345            cgThings.append(CGHasInstanceHook(descriptor))
12346
12347        properties = PropertyArrays(descriptor)
12348        cgThings.append(CGGeneric(define=str(properties)))
12349        cgThings.append(CGNativeProperties(descriptor, properties))
12350
12351        if descriptor.interface.hasInterfaceObject():
12352            cgThings.append(CGClassConstructor(descriptor,
12353                                               descriptor.interface.ctor()))
12354            cgThings.append(CGInterfaceObjectJSClass(descriptor, properties))
12355            cgThings.append(CGNamedConstructors(descriptor))
12356
12357        cgThings.append(CGLegacyCallHook(descriptor))
12358        if descriptor.interface.getExtendedAttribute("NeedResolve"):
12359            cgThings.append(CGResolveHook(descriptor))
12360            cgThings.append(CGMayResolveHook(descriptor))
12361            cgThings.append(CGEnumerateHook(descriptor))
12362
12363        if descriptor.hasNamedPropertiesObject:
12364            cgThings.append(CGGetNamedPropertiesObjectMethod(descriptor))
12365
12366        if descriptor.interface.hasInterfacePrototypeObject():
12367            cgThings.append(CGPrototypeJSClass(descriptor, properties))
12368
12369        if ((descriptor.interface.hasInterfaceObject() or descriptor.interface.isNavigatorProperty()) and
12370            not descriptor.interface.isExternal() and
12371            descriptor.isExposedConditionally()):
12372            cgThings.append(CGConstructorEnabled(descriptor))
12373
12374        if descriptor.registersGlobalNamesOnWindow:
12375            cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
12376
12377        if (descriptor.interface.hasMembersInSlots() and
12378            descriptor.interface.hasChildInterfaces()):
12379            raise TypeError("We don't support members in slots on "
12380                            "non-leaf interfaces like %s" %
12381                            descriptor.interface.identifier.name)
12382
12383        if descriptor.concrete:
12384            if descriptor.proxy:
12385                if descriptor.interface.totalMembersInSlots != 0:
12386                    raise TypeError("We can't have extra reserved slots for "
12387                                    "proxy interface %s" %
12388                                    descriptor.interface.identifier.name)
12389                cgThings.append(CGGeneric(fill(
12390                    """
12391                    static_assert(IsBaseOf<nsISupports, ${nativeType} >::value,
12392                                      "We don't support non-nsISupports native classes for "
12393                                      "proxy-based bindings yet");
12394
12395                    """,
12396                    nativeType=descriptor.nativeType)))
12397                if not descriptor.wrapperCache:
12398                    raise TypeError("We need a wrappercache to support expandos for proxy-based "
12399                                    "bindings (" + descriptor.name + ")")
12400                handlerThing = CGDOMJSProxyHandler(descriptor)
12401                cgThings.append(CGDOMJSProxyHandlerDeclarer(handlerThing))
12402                cgThings.append(CGProxyIsProxy(descriptor))
12403                cgThings.append(CGProxyUnwrap(descriptor))
12404                cgThings.append(CGDOMJSProxyHandlerDefiner(handlerThing))
12405                cgThings.append(CGDOMProxyJSClass(descriptor))
12406            else:
12407                cgThings.append(CGDOMJSClass(descriptor))
12408                cgThings.append(CGGetJSClassMethod(descriptor))
12409                if descriptor.interface.hasMembersInSlots():
12410                    cgThings.append(CGUpdateMemberSlotsMethod(descriptor))
12411
12412            if descriptor.isGlobal():
12413                assert descriptor.wrapperCache
12414                cgThings.append(CGWrapGlobalMethod(descriptor, properties))
12415            elif descriptor.wrapperCache:
12416                cgThings.append(CGWrapWithCacheMethod(descriptor, properties))
12417                cgThings.append(CGWrapMethod(descriptor))
12418            else:
12419                cgThings.append(CGWrapNonWrapperCacheMethod(descriptor,
12420                                                            properties))
12421
12422        # Set up our Xray callbacks as needed.  This needs to come
12423        # after we have our DOMProxyHandler defined.
12424        if descriptor.wantsXrays:
12425            if descriptor.concrete and descriptor.proxy:
12426                cgThings.append(CGResolveOwnProperty(descriptor))
12427                cgThings.append(CGEnumerateOwnProperties(descriptor))
12428                if descriptor.needsXrayNamedDeleterHook():
12429                    cgThings.append(CGDeleteNamedProperty(descriptor))
12430            elif descriptor.needsXrayResolveHooks():
12431                cgThings.append(CGResolveOwnPropertyViaResolve(descriptor))
12432                cgThings.append(CGEnumerateOwnPropertiesViaGetOwnPropertyNames(descriptor))
12433            if descriptor.wantsXrayExpandoClass:
12434                cgThings.append(CGXrayExpandoJSClass(descriptor))
12435
12436        # Now that we have our ResolveOwnProperty/EnumerateOwnProperties stuff
12437        # done, set up our NativePropertyHooks.
12438        cgThings.append(CGNativePropertyHooks(descriptor, properties))
12439
12440        # If we're not wrappercached, we don't know how to clear our
12441        # cached values, since we can't get at the JSObject.
12442        if descriptor.wrapperCache:
12443            cgThings.extend(CGClearCachedValueMethod(descriptor, m) for
12444                            m in clearableCachedAttrs(descriptor))
12445
12446        haveUnscopables = (len(unscopableNames) != 0 and
12447                           descriptor.interface.hasInterfacePrototypeObject())
12448        if haveUnscopables:
12449            cgThings.append(
12450                CGList([CGGeneric("static const char* const unscopableNames[] = {"),
12451                        CGIndenter(CGList([CGGeneric('"%s"' % name) for
12452                                           name in unscopableNames] +
12453                                          [CGGeneric("nullptr")], ",\n")),
12454                        CGGeneric("};\n")], "\n"))
12455
12456        # CGCreateInterfaceObjectsMethod needs to come after our
12457        # CGDOMJSClass and unscopables, if any.
12458        cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties,
12459                                                       haveUnscopables))
12460
12461        # CGGetProtoObjectMethod and CGGetConstructorObjectMethod need
12462        # to come after CGCreateInterfaceObjectsMethod.
12463        if descriptor.interface.hasInterfacePrototypeObject():
12464            cgThings.append(CGGetProtoObjectHandleMethod(descriptor))
12465            if descriptor.interface.hasChildInterfaces():
12466                cgThings.append(CGGetProtoObjectMethod(descriptor))
12467        if descriptor.interface.hasInterfaceObject():
12468            cgThings.append(CGGetConstructorObjectHandleMethod(descriptor))
12469            cgThings.append(CGGetConstructorObjectMethod(descriptor))
12470
12471        # See whether we need we need to generate an IsPermitted method
12472        if crossOriginGetters or crossOriginSetters or crossOriginMethods:
12473            cgThings.append(CGIsPermittedMethod(descriptor,
12474                                                crossOriginGetters,
12475                                                crossOriginSetters,
12476                                                crossOriginMethods))
12477
12478        cgThings = CGList((CGIndenter(t, declareOnly=True) for t in cgThings), "\n")
12479        cgThings = CGWrapper(cgThings, pre='\n', post='\n')
12480        self.cgRoot = CGWrapper(CGNamespace(toBindingNamespace(descriptor.name),
12481                                            cgThings),
12482                                post='\n')
12483
12484    def declare(self):
12485        return self.cgRoot.declare()
12486
12487    def define(self):
12488        return self.cgRoot.define()
12489
12490    def deps(self):
12491        return self._deps
12492
12493
12494class CGNamespacedEnum(CGThing):
12495    def __init__(self, namespace, enumName, names, values, comment=""):
12496
12497        if not values:
12498            values = []
12499
12500        # Account for explicit enum values.
12501        entries = []
12502        for i in range(0, len(names)):
12503            if len(values) > i and values[i] is not None:
12504                entry = "%s = %s" % (names[i], values[i])
12505            else:
12506                entry = names[i]
12507            entries.append(entry)
12508
12509        # Append a Count.
12510        entries.append('_' + enumName + '_Count')
12511
12512        # Indent.
12513        entries = ['  ' + e for e in entries]
12514
12515        # Build the enum body.
12516        enumstr = comment + 'enum %s : uint16_t\n{\n%s\n};\n' % (enumName, ',\n'.join(entries))
12517        curr = CGGeneric(declare=enumstr)
12518
12519        # Add some whitespace padding.
12520        curr = CGWrapper(curr, pre='\n', post='\n')
12521
12522        # Add the namespace.
12523        curr = CGNamespace(namespace, curr)
12524
12525        # Add the typedef
12526        typedef = '\ntypedef %s::%s %s;\n\n' % (namespace, enumName, enumName)
12527        curr = CGList([curr, CGGeneric(declare=typedef)])
12528
12529        # Save the result.
12530        self.node = curr
12531
12532    def declare(self):
12533        return self.node.declare()
12534
12535    def define(self):
12536        return ""
12537
12538
12539def initIdsClassMethod(identifiers, atomCacheName):
12540    idinit = ['!atomsCache->%s.init(cx, "%s")' %
12541              (CGDictionary.makeIdName(id),
12542               id)
12543              for id in identifiers]
12544    idinit.reverse()
12545    body = fill(
12546        """
12547        MOZ_ASSERT(!*reinterpret_cast<jsid**>(atomsCache));
12548
12549        // Initialize these in reverse order so that any failure leaves the first one
12550        // uninitialized.
12551        if (${idinit}) {
12552          return false;
12553        }
12554        return true;
12555        """,
12556        idinit=" ||\n    ".join(idinit))
12557    return ClassMethod("InitIds", "bool", [
12558        Argument("JSContext*", "cx"),
12559        Argument("%s*" % atomCacheName, "atomsCache")
12560    ], static=True, body=body, visibility="private")
12561
12562
12563class CGDictionary(CGThing):
12564    def __init__(self, dictionary, descriptorProvider):
12565        self.dictionary = dictionary
12566        self.descriptorProvider = descriptorProvider
12567        self.needToInitIds = len(dictionary.members) > 0
12568        self.memberInfo = [
12569            (member,
12570             getJSToNativeConversionInfo(
12571                 member.type,
12572                 descriptorProvider,
12573                 isEnforceRange=member.enforceRange,
12574                 isClamp=member.clamp,
12575                 isMember="Dictionary",
12576                 isOptional=member.canHaveMissingValue(),
12577                 defaultValue=member.defaultValue,
12578                 sourceDescription=self.getMemberSourceDescription(member)))
12579            for member in dictionary.members]
12580
12581        # If we have a union member containing something in the same
12582        # file as us, bail: the C++ includes won't work out.
12583        for member in dictionary.members:
12584            type = member.type.unroll()
12585            if type.isUnion():
12586                for t in type.flatMemberTypes:
12587                    if (t.isDictionary() and
12588                        CGHeaders.getDeclarationFilename(t.inner) ==
12589                        CGHeaders.getDeclarationFilename(dictionary)):
12590                        raise TypeError(
12591                            "Dictionary contains a union that contains a "
12592                            "dictionary in the same WebIDL file.  This won't "
12593                            "compile.  Move the inner dictionary to a "
12594                            "different file.\n%s\n%s" %
12595                            (t.location, t.inner.location))
12596        self.structs = self.getStructs()
12597
12598    def declare(self):
12599        return self.structs.declare()
12600
12601    def define(self):
12602        return self.structs.define()
12603
12604    def base(self):
12605        if self.dictionary.parent:
12606            return self.makeClassName(self.dictionary.parent)
12607        return "DictionaryBase"
12608
12609    def initMethod(self):
12610        """
12611        This function outputs the body of the Init() method for the dictionary.
12612
12613        For the most part, this is some bookkeeping for our atoms so
12614        we can avoid atomizing strings all the time, then we just spit
12615        out the getMemberConversion() output for each member,
12616        separated by newlines.
12617
12618        """
12619        body = dedent("""
12620            // Passing a null JSContext is OK only if we're initing from null,
12621            // Since in that case we will not have to do any property gets
12622            MOZ_ASSERT_IF(!cx, val.isNull());
12623            """)
12624
12625        if self.needToInitIds:
12626            body += fill(
12627                """
12628                ${dictName}Atoms* atomsCache = nullptr;
12629                if (cx) {
12630                  atomsCache = GetAtomCache<${dictName}Atoms>(cx);
12631                  if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
12632                    return false;
12633                  }
12634                }
12635
12636                """,
12637                dictName=self.makeClassName(self.dictionary))
12638
12639        if self.dictionary.parent:
12640            body += fill(
12641                """
12642                // Per spec, we init the parent's members first
12643                if (!${dictName}::Init(cx, val)) {
12644                  return false;
12645                }
12646
12647                """,
12648                dictName=self.makeClassName(self.dictionary.parent))
12649        else:
12650            body += dedent(
12651                """
12652                { // scope for isConvertible
12653                  bool isConvertible;
12654                  if (!IsConvertibleToDictionary(cx, val, &isConvertible)) {
12655                    return false;
12656                  }
12657                  if (!isConvertible) {
12658                    return ThrowErrorMessage(cx, MSG_NOT_DICTIONARY, sourceDescription);
12659                  }
12660                }
12661
12662                """)
12663
12664        memberInits = [self.getMemberConversion(m).define()
12665                       for m in self.memberInfo]
12666        if memberInits:
12667            body += fill(
12668                """
12669                bool isNull = val.isNullOrUndefined();
12670                // We only need these if !isNull, in which case we have |cx|.
12671                Maybe<JS::Rooted<JSObject *> > object;
12672                Maybe<JS::Rooted<JS::Value> > temp;
12673                if (!isNull) {
12674                  MOZ_ASSERT(cx);
12675                  object.emplace(cx, &val.toObject());
12676                  temp.emplace(cx);
12677                }
12678                $*{memberInits}
12679                """,
12680                memberInits="\n".join(memberInits))
12681
12682        body += "return true;\n"
12683
12684        return ClassMethod("Init", "bool", [
12685            Argument('JSContext*', 'cx'),
12686            Argument('JS::Handle<JS::Value>', 'val'),
12687            Argument('const char*', 'sourceDescription', default='"Value"'),
12688            Argument('bool', 'passedToJSImpl', default='false')
12689        ], body=body)
12690
12691    def initFromJSONMethod(self):
12692        return ClassMethod(
12693            "Init", "bool",
12694            [Argument('const nsAString&', 'aJSON')],
12695            body=dedent("""
12696                AutoJSAPI jsapi;
12697                JSObject* cleanGlobal = SimpleGlobalObject::Create(SimpleGlobalObject::GlobalType::BindingDetail);
12698                if (!cleanGlobal) {
12699                  return false;
12700                }
12701                if (!jsapi.Init(cleanGlobal)) {
12702                  return false;
12703                }
12704                JSContext* cx = jsapi.cx();
12705                JS::Rooted<JS::Value> json(cx);
12706                bool ok = ParseJSON(cx, aJSON, &json);
12707                NS_ENSURE_TRUE(ok, false);
12708                return Init(cx, json);
12709                """))
12710
12711    def toJSONMethod(self):
12712        return ClassMethod(
12713            "ToJSON", "bool",
12714            [Argument('nsAString&', 'aJSON')],
12715            body=dedent("""
12716                AutoJSAPI jsapi;
12717                jsapi.Init();
12718                JSContext *cx = jsapi.cx();
12719                // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here
12720                // because we'll only be creating objects, in ways that have no
12721                // side-effects, followed by a call to JS::ToJSONMaybeSafely,
12722                // which likewise guarantees no side-effects for the sorts of
12723                // things we will pass it.
12724                JSAutoCompartment ac(cx, binding_detail::UnprivilegedJunkScopeOrWorkerGlobal());
12725                JS::Rooted<JS::Value> val(cx);
12726                if (!ToObjectInternal(cx, &val)) {
12727                  return false;
12728                }
12729                JS::Rooted<JSObject*> obj(cx, &val.toObject());
12730                return StringifyToJSON(cx, obj, aJSON);
12731            """), const=True)
12732
12733    def toObjectInternalMethod(self):
12734        body = ""
12735        if self.needToInitIds:
12736            body += fill(
12737                """
12738                ${dictName}Atoms* atomsCache = GetAtomCache<${dictName}Atoms>(cx);
12739                if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) {
12740                  return false;
12741                }
12742
12743                """,
12744                dictName=self.makeClassName(self.dictionary))
12745
12746        if self.dictionary.parent:
12747            body += fill(
12748                """
12749                // Per spec, we define the parent's members first
12750                if (!${dictName}::ToObjectInternal(cx, rval)) {
12751                  return false;
12752                }
12753                JS::Rooted<JSObject*> obj(cx, &rval.toObject());
12754
12755                """,
12756                dictName=self.makeClassName(self.dictionary.parent))
12757        else:
12758            body += dedent(
12759                """
12760                JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx));
12761                if (!obj) {
12762                  return false;
12763                }
12764                rval.set(JS::ObjectValue(*obj));
12765
12766                """)
12767
12768        if self.memberInfo:
12769            body += "\n".join(self.getMemberDefinition(m).define()
12770                              for m in self.memberInfo)
12771        body += "\nreturn true;\n"
12772
12773        return ClassMethod("ToObjectInternal", "bool", [
12774            Argument('JSContext*', 'cx'),
12775            Argument('JS::MutableHandle<JS::Value>', 'rval'),
12776        ], const=True, body=body)
12777
12778    def initIdsMethod(self):
12779        assert self.needToInitIds
12780        return initIdsClassMethod([m.identifier.name for m in self.dictionary.members],
12781                                  "%sAtoms" % self.makeClassName(self.dictionary))
12782
12783    def traceDictionaryMethod(self):
12784        body = ""
12785        if self.dictionary.parent:
12786            cls = self.makeClassName(self.dictionary.parent)
12787            body += "%s::TraceDictionary(trc);\n" % cls
12788
12789        memberTraces = [self.getMemberTrace(m)
12790                        for m in self.dictionary.members
12791                        if typeNeedsRooting(m.type)]
12792
12793        if memberTraces:
12794            body += "\n".join(memberTraces)
12795
12796        return ClassMethod("TraceDictionary", "void", [
12797            Argument("JSTracer*", "trc"),
12798        ], body=body)
12799
12800    def assignmentOperator(self):
12801        body = CGList([])
12802        if self.dictionary.parent:
12803            body.append(CGGeneric(
12804                "%s::operator=(aOther);\n" %
12805                self.makeClassName(self.dictionary.parent)))
12806        for m, _ in self.memberInfo:
12807            memberName = self.makeMemberName(m.identifier.name)
12808            if m.canHaveMissingValue():
12809                memberAssign = CGGeneric(fill(
12810                    """
12811                    ${name}.Reset();
12812                    if (aOther.${name}.WasPassed()) {
12813                      ${name}.Construct(aOther.${name}.Value());
12814                    }
12815                    """,
12816                    name=memberName))
12817            else:
12818                memberAssign = CGGeneric(
12819                    "%s = aOther.%s;\n" % (memberName, memberName))
12820            body.append(memberAssign)
12821        return ClassMethod(
12822            "operator=", "void",
12823            [Argument("const %s&" % self.makeClassName(self.dictionary),
12824                      "aOther")],
12825            body=body.define())
12826
12827    def getStructs(self):
12828        d = self.dictionary
12829        selfName = self.makeClassName(d)
12830        members = [ClassMember(self.makeMemberName(m[0].identifier.name),
12831                               self.getMemberType(m),
12832                               visibility="public",
12833                               body=self.getMemberInitializer(m),
12834                               hasIgnoreInitCheckFlag=True)
12835                   for m in self.memberInfo]
12836        if d.parent:
12837            # We always want to init our parent with our non-initializing
12838            # constructor arg, because either we're about to init ourselves (and
12839            # hence our parent) or we don't want any init happening.
12840            baseConstructors = [
12841                "%s(%s)" % (self.makeClassName(d.parent),
12842                            self.getNonInitializingCtorArg())
12843            ]
12844        else:
12845            baseConstructors = None
12846        ctors = [
12847            ClassConstructor(
12848                [],
12849                visibility="public",
12850                baseConstructors=baseConstructors,
12851                body=(
12852                    "// Safe to pass a null context if we pass a null value\n"
12853                    "Init(nullptr, JS::NullHandleValue);\n")),
12854            ClassConstructor(
12855                [Argument("const FastDictionaryInitializer&", "")],
12856                visibility="public",
12857                baseConstructors=baseConstructors,
12858                explicit=True,
12859                bodyInHeader=True,
12860                body='// Do nothing here; this is used by our "Fast" subclass\n')
12861        ]
12862        methods = []
12863
12864        if self.needToInitIds:
12865            methods.append(self.initIdsMethod())
12866
12867        methods.append(self.initMethod())
12868        canBeRepresentedAsJSON = self.dictionarySafeToJSONify(self.dictionary)
12869        if canBeRepresentedAsJSON:
12870            methods.append(self.initFromJSONMethod())
12871        try:
12872            methods.append(self.toObjectInternalMethod())
12873            if canBeRepresentedAsJSON:
12874                methods.append(self.toJSONMethod())
12875        except MethodNotNewObjectError:
12876            # If we can't have a ToObjectInternal() because one of our members
12877            # can only be returned from [NewObject] methods, then just skip
12878            # generating ToObjectInternal() and ToJSON (since the latter depens
12879            # on the former).
12880            pass
12881        methods.append(self.traceDictionaryMethod())
12882
12883        if CGDictionary.isDictionaryCopyConstructible(d):
12884            disallowCopyConstruction = False
12885            # Note: no base constructors because our operator= will
12886            # deal with that.
12887            ctors.append(ClassConstructor([Argument("const %s&" % selfName,
12888                                                    "aOther")],
12889                                          bodyInHeader=True,
12890                                          visibility="public",
12891                                          explicit=True,
12892                                          body="*this = aOther;\n"))
12893            methods.append(self.assignmentOperator())
12894        else:
12895            disallowCopyConstruction = True
12896
12897        struct = CGClass(selfName,
12898                         bases=[ClassBase(self.base())],
12899                         members=members,
12900                         constructors=ctors,
12901                         methods=methods,
12902                         isStruct=True,
12903                         disallowCopyConstruction=disallowCopyConstruction)
12904
12905        fastDictionaryCtor = ClassConstructor(
12906            [],
12907            visibility="public",
12908            bodyInHeader=True,
12909            baseConstructors=["%s(%s)" %
12910                              (selfName,
12911                               self.getNonInitializingCtorArg())],
12912            body="// Doesn't matter what int we pass to the parent constructor\n")
12913
12914        fastStruct = CGClass("Fast" + selfName,
12915                             bases=[ClassBase(selfName)],
12916                             constructors=[fastDictionaryCtor],
12917                             isStruct=True)
12918
12919        return CGList([struct,
12920                       CGNamespace('binding_detail', fastStruct)],
12921                      "\n")
12922
12923    def deps(self):
12924        return self.dictionary.getDeps()
12925
12926    @staticmethod
12927    def makeDictionaryName(dictionary):
12928        return dictionary.identifier.name
12929
12930    def makeClassName(self, dictionary):
12931        return self.makeDictionaryName(dictionary)
12932
12933    @staticmethod
12934    def makeMemberName(name):
12935        return "m" + name[0].upper() + IDLToCIdentifier(name[1:])
12936
12937    def getMemberType(self, memberInfo):
12938        _, conversionInfo = memberInfo
12939        # We can't handle having a holderType here
12940        assert conversionInfo.holderType is None
12941        declType = conversionInfo.declType
12942        if conversionInfo.dealWithOptional:
12943            declType = CGTemplatedType("Optional", declType)
12944        return declType.define()
12945
12946    def getMemberConversion(self, memberInfo):
12947        """
12948        A function that outputs the initialization of a single dictionary
12949        member from the given dictionary value.
12950
12951        We start with our conversionInfo, which tells us how to
12952        convert a JS::Value to whatever type this member is.  We
12953        substiture the template from the conversionInfo with values
12954        that point to our "temp" JS::Value and our member (which is
12955        the C++ value we want to produce).  The output is a string of
12956        code to do the conversion.  We store this string in
12957        conversionReplacements["convert"].
12958
12959        Now we have three different ways we might use (or skip) this
12960        string of code, depending on whether the value is required,
12961        optional with default value, or optional without default
12962        value.  We set up a template in the 'conversion' variable for
12963        exactly how to do this, then substitute into it from the
12964        conversionReplacements dictionary.
12965        """
12966        member, conversionInfo = memberInfo
12967        replacements = {
12968            "val": "temp.ref()",
12969            "maybeMutableVal": "temp.ptr()",
12970            "declName": self.makeMemberName(member.identifier.name),
12971            # We need a holder name for external interfaces, but
12972            # it's scoped down to the conversion so we can just use
12973            # anything we want.
12974            "holderName": "holder",
12975            "passedToJSImpl": "passedToJSImpl"
12976        }
12977        # We can't handle having a holderType here
12978        assert conversionInfo.holderType is None
12979        if conversionInfo.dealWithOptional:
12980            replacements["declName"] = "(" + replacements["declName"] + ".Value())"
12981        if member.defaultValue:
12982            replacements["haveValue"] = "!isNull && !temp->isUndefined()"
12983
12984        propId = self.makeIdName(member.identifier.name)
12985        propGet = ("JS_GetPropertyById(cx, *object, atomsCache->%s, temp.ptr())" %
12986                   propId)
12987
12988        conversionReplacements = {
12989            "prop": self.makeMemberName(member.identifier.name),
12990            "convert": string.Template(conversionInfo.template).substitute(replacements),
12991            "propGet": propGet
12992        }
12993        # The conversion code will only run where a default value or a value passed
12994        # by the author needs to get converted, so we can remember if we have any
12995        # members present here.
12996        conversionReplacements["convert"] += "mIsAnyMemberPresent = true;\n"
12997        setTempValue = CGGeneric(dedent(
12998            """
12999            if (!${propGet}) {
13000              return false;
13001            }
13002            """))
13003        conditions = getConditionList(member, "cx", "*object")
13004        if len(conditions) != 0:
13005            setTempValue = CGIfElseWrapper(conditions.define(),
13006                                           setTempValue,
13007                                           CGGeneric("temp->setUndefined();\n"))
13008        setTempValue = CGIfWrapper(setTempValue, "!isNull")
13009        conversion = setTempValue.define()
13010        if member.defaultValue:
13011            if (member.type.isUnion() and
13012                (not member.type.nullable() or
13013                 not isinstance(member.defaultValue, IDLNullValue))):
13014                # Since this has a default value, it might have been initialized
13015                # already.  Go ahead and uninit it before we try to init it
13016                # again.
13017                memberName = self.makeMemberName(member.identifier.name)
13018                if member.type.nullable():
13019                    conversion += fill(
13020                        """
13021                        if (!${memberName}.IsNull()) {
13022                          ${memberName}.Value().Uninit();
13023                        }
13024                        """,
13025                        memberName=memberName)
13026                else:
13027                    conversion += "%s.Uninit();\n" % memberName
13028            conversion += "${convert}"
13029        elif not conversionInfo.dealWithOptional:
13030            # We're required, but have no default value.  Make sure
13031            # that we throw if we have no value provided.
13032            conversion += dedent(
13033                """
13034                if (!isNull && !temp->isUndefined()) {
13035                ${convert}
13036                } else if (cx) {
13037                  // Don't error out if we have no cx.  In that
13038                  // situation the caller is default-constructing us and we'll
13039                  // just assume they know what they're doing.
13040                  return ThrowErrorMessage(cx, MSG_MISSING_REQUIRED_DICTIONARY_MEMBER,
13041                                           "%s");
13042                }
13043                """ % self.getMemberSourceDescription(member))
13044            conversionReplacements["convert"] = indent(conversionReplacements["convert"]).rstrip()
13045        else:
13046            conversion += (
13047                "if (!isNull && !temp->isUndefined()) {\n"
13048                "  ${prop}.Construct();\n"
13049                "${convert}"
13050                "}\n")
13051            conversionReplacements["convert"] = indent(conversionReplacements["convert"])
13052
13053        return CGGeneric(
13054            string.Template(conversion).substitute(conversionReplacements))
13055
13056    def getMemberDefinition(self, memberInfo):
13057        member = memberInfo[0]
13058        declType = memberInfo[1].declType
13059        memberLoc = self.makeMemberName(member.identifier.name)
13060        if not member.canHaveMissingValue():
13061            memberData = memberLoc
13062        else:
13063            # The data is inside the Optional<>
13064            memberData = "%s.InternalValue()" % memberLoc
13065
13066        # If you have to change this list (which you shouldn't!), make sure it
13067        # continues to match the list in test_Object.prototype_props.html
13068        if (member.identifier.name in
13069            ["constructor", "toSource", "toString", "toLocaleString", "valueOf",
13070             "watch", "unwatch", "hasOwnProperty", "isPrototypeOf",
13071             "propertyIsEnumerable", "__defineGetter__", "__defineSetter__",
13072             "__lookupGetter__", "__lookupSetter__", "__proto__"]):
13073            raise TypeError("'%s' member of %s dictionary shadows "
13074                            "a property of Object.prototype, and Xrays to "
13075                            "Object can't handle that.\n"
13076                            "%s" %
13077                            (member.identifier.name,
13078                             self.dictionary.identifier.name,
13079                             member.location))
13080
13081        propDef = (
13082            'JS_DefinePropertyById(cx, obj, atomsCache->%s, temp, JSPROP_ENUMERATE)' %
13083            self.makeIdName(member.identifier.name))
13084
13085        innerTemplate = wrapForType(
13086            member.type, self.descriptorProvider,
13087            {
13088                'result': "currentValue",
13089                'successCode': ("if (!%s) {\n"
13090                                "  return false;\n"
13091                                "}\n"
13092                                "break;\n" % propDef),
13093                'jsvalRef': "temp",
13094                'jsvalHandle': "&temp",
13095                'returnsNewObject': False,
13096                # 'obj' can just be allowed to be the string "obj", since that
13097                # will be our dictionary object, which is presumably itself in
13098                # the right scope.
13099                'typedArraysAreStructs': True
13100            })
13101        conversion = CGGeneric(innerTemplate)
13102        conversion = CGWrapper(conversion,
13103                               pre=("JS::Rooted<JS::Value> temp(cx);\n"
13104                                    "%s const & currentValue = %s;\n" %
13105                                    (declType.define(), memberData)
13106                                    ))
13107
13108        # Now make sure that our successCode can actually break out of the
13109        # conversion.  This incidentally gives us a scope for 'temp' and
13110        # 'currentValue'.
13111        conversion = CGWrapper(
13112            CGIndenter(conversion),
13113            pre=("do {\n"
13114                 "  // block for our 'break' successCode and scope for 'temp' and 'currentValue'\n"),
13115            post="} while(0);\n")
13116        if member.canHaveMissingValue():
13117            # Only do the conversion if we have a value
13118            conversion = CGIfWrapper(conversion, "%s.WasPassed()" % memberLoc)
13119        conditions = getConditionList(member, "cx", "obj")
13120        if len(conditions) != 0:
13121            conversion = CGIfWrapper(conversion, conditions.define())
13122        return conversion
13123
13124    def getMemberTrace(self, member):
13125        type = member.type
13126        assert typeNeedsRooting(type)
13127        memberLoc = self.makeMemberName(member.identifier.name)
13128        if not member.canHaveMissingValue():
13129            memberData = memberLoc
13130        else:
13131            # The data is inside the Optional<>
13132            memberData = "%s.Value()" % memberLoc
13133
13134        memberName = "%s.%s" % (self.makeClassName(self.dictionary),
13135                                memberLoc)
13136
13137        if type.isObject():
13138            trace = CGGeneric('JS::UnsafeTraceRoot(trc, %s, "%s");\n' %
13139                              ("&"+memberData, memberName))
13140            if type.nullable():
13141                trace = CGIfWrapper(trace, memberData)
13142        elif type.isAny():
13143            trace = CGGeneric('JS::UnsafeTraceRoot(trc, %s, "%s");\n' %
13144                              ("&"+memberData, memberName))
13145        elif (type.isSequence() or type.isDictionary() or
13146              type.isSpiderMonkeyInterface() or type.isUnion()):
13147            if type.nullable():
13148                memberNullable = memberData
13149                memberData = "%s.Value()" % memberData
13150            if type.isSequence():
13151                trace = CGGeneric('DoTraceSequence(trc, %s);\n' % memberData)
13152            elif type.isDictionary():
13153                trace = CGGeneric('%s.TraceDictionary(trc);\n' % memberData)
13154            elif type.isUnion():
13155                trace = CGGeneric('%s.TraceUnion(trc);\n' % memberData)
13156            else:
13157                assert type.isSpiderMonkeyInterface()
13158                trace = CGGeneric('%s.TraceSelf(trc);\n' % memberData)
13159            if type.nullable():
13160                trace = CGIfWrapper(trace, "!%s.IsNull()" % memberNullable)
13161        elif type.isMozMap():
13162            # If you implement this, add a MozMap<object> to
13163            # TestInterfaceJSDictionary and test it in test_bug1036214.html
13164            # to make sure we end up with the correct security properties.
13165            assert False
13166        else:
13167            assert False  # unknown type
13168
13169        if member.canHaveMissingValue():
13170            trace = CGIfWrapper(trace, "%s.WasPassed()" % memberLoc)
13171
13172        return trace.define()
13173
13174    def getMemberInitializer(self, memberInfo):
13175        """
13176        Get the right initializer for the member.  Most members don't need one,
13177        but we need to pre-initialize 'any' and 'object' that have a default
13178        value, so they're safe to trace at all times.
13179        """
13180        member, _ = memberInfo
13181        if member.canHaveMissingValue():
13182            # Allowed missing value means no need to set it up front, since it's
13183            # inside an Optional and won't get traced until it's actually set
13184            # up.
13185            return None
13186        type = member.type
13187        if type.isAny():
13188            return "JS::UndefinedValue()"
13189        if type.isObject():
13190            return "nullptr"
13191        if type.isDictionary():
13192            # When we construct ourselves, we don't want to init our member
13193            # dictionaries.  Either we're being constructed-but-not-initialized
13194            # ourselves (and then we don't want to init them) or we're about to
13195            # init ourselves and then we'll init them anyway.
13196            return CGDictionary.getNonInitializingCtorArg()
13197        return None
13198
13199    def getMemberSourceDescription(self, member):
13200        return ("'%s' member of %s" %
13201                (member.identifier.name, self.dictionary.identifier.name))
13202
13203    @staticmethod
13204    def makeIdName(name):
13205        return IDLToCIdentifier(name) + "_id"
13206
13207    @staticmethod
13208    def getNonInitializingCtorArg():
13209        return "FastDictionaryInitializer()"
13210
13211    @staticmethod
13212    def isDictionaryCopyConstructible(dictionary):
13213        if (dictionary.parent and
13214            not CGDictionary.isDictionaryCopyConstructible(dictionary.parent)):
13215            return False
13216        return all(isTypeCopyConstructible(m.type) for m in dictionary.members)
13217
13218    @staticmethod
13219    def typeSafeToJSONify(type):
13220        """
13221        Determine whether the given type is safe to convert to JSON.  The
13222        restriction is that this needs to be safe while in a global controlled
13223        by an adversary, and "safe" means no side-effects when the JS
13224        representation of this type is converted to JSON.  That means that we
13225        have to be pretty restrictive about what things we can allow.  For
13226        example, "object" is out, because it may have accessor properties on it.
13227        """
13228        if type.nullable():
13229            # Converting null to JSON is always OK.
13230            return CGDictionary.typeSafeToJSONify(type.inner)
13231
13232        if type.isSequence():
13233            # Sequences are arrays we create ourselves, with no holes.  They
13234            # should be safe if their contents are safe, as long as we suppress
13235            # invocation of .toJSON on objects.
13236            return CGDictionary.typeSafeToJSONify(type.inner)
13237
13238        if type.isUnion():
13239            # OK if everything in it is ok.
13240            return all(CGDictionary.typeSafeToJSONify(t)
13241                       for t in type.flatMemberTypes)
13242
13243        if type.isDictionary():
13244            # OK if the dictionary is OK
13245            return CGDictionary.dictionarySafeToJSONify(type.inner)
13246
13247        if type.isString() or type.isEnum():
13248            # Strings are always OK.
13249            return True
13250
13251        if type.isPrimitive():
13252            # Primitives (numbers and booleans) are ok, as long as
13253            # they're not unrestricted float/double.
13254            return not type.isFloat() or not type.isUnrestricted()
13255
13256        return False
13257
13258    @staticmethod
13259    def dictionarySafeToJSONify(dictionary):
13260        # The dictionary itself is OK, so we're good if all our types are.
13261        return all(CGDictionary.typeSafeToJSONify(m.type)
13262                   for m in dictionary.members)
13263
13264
13265class CGRegisterWorkerBindings(CGAbstractMethod):
13266    def __init__(self, config):
13267        CGAbstractMethod.__init__(self, None, 'RegisterWorkerBindings', 'bool',
13268                                  [Argument('JSContext*', 'aCx'),
13269                                   Argument('JS::Handle<JSObject*>', 'aObj')])
13270        self.config = config
13271
13272    def definition_body(self):
13273        descriptors = self.config.getDescriptors(hasInterfaceObject=True,
13274                                                 isExposedInAnyWorker=True,
13275                                                 register=True)
13276        conditions = []
13277        for desc in descriptors:
13278            bindingNS = toBindingNamespace(desc.name)
13279            condition = "!%s::GetConstructorObject(aCx)" % bindingNS
13280            if desc.isExposedConditionally():
13281                condition = (
13282                    "%s::ConstructorEnabled(aCx, aObj) && " % bindingNS
13283                    + condition)
13284            conditions.append(condition)
13285        lines = [CGIfWrapper(CGGeneric("return false;\n"), condition) for
13286                 condition in conditions]
13287        lines.append(CGGeneric("return true;\n"))
13288        return CGList(lines, "\n").define()
13289
13290class CGRegisterWorkerDebuggerBindings(CGAbstractMethod):
13291    def __init__(self, config):
13292        CGAbstractMethod.__init__(self, None, 'RegisterWorkerDebuggerBindings', 'bool',
13293                                  [Argument('JSContext*', 'aCx'),
13294                                   Argument('JS::Handle<JSObject*>', 'aObj')])
13295        self.config = config
13296
13297    def definition_body(self):
13298        descriptors = self.config.getDescriptors(hasInterfaceObject=True,
13299                                                 isExposedInWorkerDebugger=True,
13300                                                 register=True)
13301        conditions = []
13302        for desc in descriptors:
13303            bindingNS = toBindingNamespace(desc.name)
13304            condition = "!%s::GetConstructorObject(aCx)" % bindingNS
13305            if desc.isExposedConditionally():
13306                condition = (
13307                    "%s::ConstructorEnabled(aCx, aObj) && " % bindingNS
13308                    + condition)
13309            conditions.append(condition)
13310        lines = [CGIfWrapper(CGGeneric("return false;\n"), condition) for
13311                 condition in conditions]
13312        lines.append(CGGeneric("return true;\n"))
13313        return CGList(lines, "\n").define()
13314
13315class CGRegisterWorkletBindings(CGAbstractMethod):
13316    def __init__(self, config):
13317        CGAbstractMethod.__init__(self, None, 'RegisterWorkletBindings', 'bool',
13318                                  [Argument('JSContext*', 'aCx'),
13319                                   Argument('JS::Handle<JSObject*>', 'aObj')])
13320        self.config = config
13321
13322    def definition_body(self):
13323        descriptors = self.config.getDescriptors(hasInterfaceObject=True,
13324                                                 isExposedInAnyWorklet=True,
13325                                                 register=True)
13326        conditions = []
13327        for desc in descriptors:
13328            bindingNS = toBindingNamespace(desc.name)
13329            condition = "!%s::GetConstructorObject(aCx)" % bindingNS
13330            if desc.isExposedConditionally():
13331                condition = (
13332                    "%s::ConstructorEnabled(aCx, aObj) && " % bindingNS
13333                    + condition)
13334            conditions.append(condition)
13335        lines = [CGIfWrapper(CGGeneric("return false;\n"), condition) for
13336                 condition in conditions]
13337        lines.append(CGGeneric("return true;\n"))
13338        return CGList(lines, "\n").define()
13339
13340class CGResolveSystemBinding(CGAbstractMethod):
13341    def __init__(self, config):
13342        CGAbstractMethod.__init__(self, None, 'ResolveSystemBinding', 'bool',
13343                                  [Argument('JSContext*', 'aCx'),
13344                                   Argument('JS::Handle<JSObject*>', 'aObj'),
13345                                   Argument('JS::Handle<jsid>', 'aId'),
13346                                   Argument('bool*', 'aResolvedp')])
13347        self.config = config
13348
13349    def definition_body(self):
13350        descriptors = self.config.getDescriptors(hasInterfaceObject=True,
13351                                                 isExposedInSystemGlobals=True,
13352                                                 register=True)
13353
13354        def descNameToId(name):
13355            return "s%s_id" % name
13356        jsidNames = [descNameToId(desc.name) for desc in descriptors]
13357        jsidDecls = CGList(CGGeneric("static jsid %s;\n" % name)
13358                           for name in jsidNames)
13359
13360        jsidInits = CGList(
13361            (CGIfWrapper(
13362                CGGeneric("return false;\n"),
13363                '!AtomizeAndPinJSString(aCx, %s, "%s")' %
13364                (descNameToId(desc.name), desc.interface.identifier.name))
13365             for desc in descriptors),
13366            "\n")
13367        jsidInits.append(CGGeneric("idsInited = true;\n"))
13368        jsidInits = CGIfWrapper(jsidInits, "!idsInited")
13369        jsidInits = CGList([CGGeneric("static bool idsInited = false;\n"),
13370                            jsidInits])
13371
13372        definitions = CGList([], "\n")
13373        for desc in descriptors:
13374            bindingNS = toBindingNamespace(desc.name)
13375            defineCode = "!%s::GetConstructorObject(aCx)" % bindingNS
13376            defineCode = CGIfWrapper(CGGeneric("return false;\n"), defineCode)
13377            defineCode = CGList([defineCode,
13378                                 CGGeneric("*aResolvedp = true;\n")])
13379
13380            condition = "JSID_IS_VOID(aId) || aId == %s" % descNameToId(desc.name)
13381            if desc.isExposedConditionally():
13382                condition = "(%s) && %s::ConstructorEnabled(aCx, aObj)" % (condition, bindingNS)
13383
13384            definitions.append(CGIfWrapper(defineCode, condition))
13385
13386        return CGList([CGGeneric("MOZ_ASSERT(NS_IsMainThread());\n"),
13387                       jsidDecls,
13388                       jsidInits,
13389                       definitions,
13390                       CGGeneric("return true;\n")],
13391                      "\n").define()
13392
13393
13394def getGlobalNames(config):
13395    names = []
13396    for desc in config.getDescriptors(registersGlobalNamesOnWindow=True):
13397        names.append((desc.name, desc))
13398        names.extend((n.identifier.name, desc) for n in desc.interface.namedConstructors)
13399    return names
13400
13401class CGGlobalNamesString(CGGeneric):
13402    def __init__(self, config):
13403        globalNames = getGlobalNames(config)
13404        currentOffset = 0
13405        strings = []
13406        for (name, _) in globalNames:
13407            strings.append('/* %i */ "%s\\0"' % (currentOffset, name))
13408            currentOffset += len(name) + 1 # Add trailing null.
13409        define = fill("""
13410            const uint32_t WebIDLGlobalNameHash::sCount = ${count};
13411
13412            const char WebIDLGlobalNameHash::sNames[] =
13413              $*{strings}
13414
13415            """,
13416            count=len(globalNames),
13417            strings="\n".join(strings) + ";\n")
13418
13419        CGGeneric.__init__(self, define=define)
13420
13421
13422class CGRegisterGlobalNames(CGAbstractMethod):
13423    def __init__(self, config):
13424        CGAbstractMethod.__init__(self, None, 'RegisterWebIDLGlobalNames',
13425                                  'void', [])
13426        self.config = config
13427
13428    def definition_body(self):
13429        def getCheck(desc):
13430            if not desc.isExposedConditionally():
13431                return "nullptr"
13432            return "%sBinding::ConstructorEnabled" % desc.name
13433
13434        define = ""
13435        currentOffset = 0
13436        for (name, desc) in getGlobalNames(self.config):
13437            length = len(name)
13438            define += "WebIDLGlobalNameHash::Register(%i, %i, %sBinding::DefineDOMInterface, %s);\n" % (currentOffset, length, desc.name, getCheck(desc))
13439            currentOffset += length + 1 # Add trailing null.
13440        return define
13441
13442
13443def dependencySortObjects(objects, dependencyGetter, nameGetter):
13444    """
13445    Sort IDL objects with dependencies on each other such that if A
13446    depends on B then B will come before A.  This is needed for
13447    declaring C++ classes in the right order, for example.  Objects
13448    that have no dependencies are just sorted by name.
13449
13450    objects should be something that can produce a set of objects
13451    (e.g. a set, iterator, list, etc).
13452
13453    dependencyGetter is something that, given an object, should return
13454    the set of objects it depends on.
13455    """
13456    # XXXbz this will fail if we have two webidl files F1 and F2 such that F1
13457    # declares an object which depends on an object in F2, and F2 declares an
13458    # object (possibly a different one!) that depends on an object in F1.  The
13459    # good news is that I expect this to never happen.
13460    sortedObjects = []
13461    objects = set(objects)
13462    while len(objects) != 0:
13463        # Find the dictionaries that don't depend on anything else
13464        # anymore and move them over.
13465        toMove = [o for o in objects if
13466                  len(dependencyGetter(o) & objects) == 0]
13467        if len(toMove) == 0:
13468            raise TypeError("Loop in dependency graph\n" +
13469                            "\n".join(o.location for o in objects))
13470        objects = objects - set(toMove)
13471        sortedObjects.extend(sorted(toMove, key=nameGetter))
13472    return sortedObjects
13473
13474
13475class ForwardDeclarationBuilder:
13476    """
13477    Create a canonical representation of a set of namespaced forward
13478    declarations.
13479    """
13480    def __init__(self):
13481        """
13482        The set of declarations is represented as a tree of nested namespaces.
13483        Each tree node has a set of declarations |decls| and a dict |children|.
13484        Each declaration is a pair consisting of the class name and a boolean
13485        that is true iff the class is really a struct. |children| maps the
13486        names of inner namespaces to the declarations in that namespace.
13487        """
13488        self.decls = set()
13489        self.children = {}
13490
13491    def _ensureNonTemplateType(self, type):
13492        if "<" in type:
13493            # This is a templated type.  We don't really know how to
13494            # forward-declare those, and trying to do it naively is not going to
13495            # go well (e.g. we may have :: characters inside the type we're
13496            # templated on!).  Just bail out.
13497            raise TypeError("Attempt to use ForwardDeclarationBuilder on "
13498                            "templated type %s.  We don't know how to do that "
13499                            "yet." % type)
13500
13501    def _listAdd(self, namespaces, name, isStruct=False):
13502        """
13503        Add a forward declaration, where |namespaces| is a list of namespaces.
13504        |name| should not contain any other namespaces.
13505        """
13506        if namespaces:
13507            child = self.children.setdefault(namespaces[0], ForwardDeclarationBuilder())
13508            child._listAdd(namespaces[1:], name, isStruct)
13509        else:
13510            assert '::' not in name
13511            self.decls.add((name, isStruct))
13512
13513    def addInMozillaDom(self, name, isStruct=False):
13514        """
13515        Add a forward declaration to the mozilla::dom:: namespace. |name| should not
13516        contain any other namespaces.
13517        """
13518        self._ensureNonTemplateType(name);
13519        self._listAdd(["mozilla", "dom"], name, isStruct)
13520
13521    def add(self, nativeType, isStruct=False):
13522        """
13523        Add a forward declaration, where |nativeType| is a string containing
13524        the type and its namespaces, in the usual C++ way.
13525        """
13526        self._ensureNonTemplateType(nativeType);
13527        components = nativeType.split('::')
13528        self._listAdd(components[:-1], components[-1], isStruct)
13529
13530    def _build(self, atTopLevel):
13531        """
13532        Return a codegenerator for the forward declarations.
13533        """
13534        decls = []
13535        if self.decls:
13536            decls.append(CGList([CGClassForwardDeclare(cname, isStruct)
13537                                 for cname, isStruct in sorted(self.decls)]))
13538        for namespace, child in sorted(self.children.iteritems()):
13539            decls.append(CGNamespace(namespace, child._build(atTopLevel=False), declareOnly=True))
13540
13541        cg = CGList(decls, "\n")
13542        if not atTopLevel and len(decls) + len(self.decls) > 1:
13543            cg = CGWrapper(cg, pre='\n', post='\n')
13544        return cg
13545
13546    def build(self):
13547        return self._build(atTopLevel=True)
13548
13549    def forwardDeclareForType(self, t, config):
13550        t = t.unroll()
13551        if t.isGeckoInterface():
13552            name = t.inner.identifier.name
13553            try:
13554                desc = config.getDescriptor(name)
13555                self.add(desc.nativeType)
13556            except NoSuchDescriptorError:
13557                pass
13558
13559        # Note: Spidermonkey interfaces are typedefs, so can't be
13560        # forward-declared
13561        elif t.isCallback():
13562            self.addInMozillaDom(t.callback.identifier.name)
13563        elif t.isDictionary():
13564            self.addInMozillaDom(t.inner.identifier.name, isStruct=True)
13565        elif t.isCallbackInterface():
13566            self.addInMozillaDom(t.inner.identifier.name)
13567        elif t.isUnion():
13568            # Forward declare both the owning and non-owning version,
13569            # since we don't know which one we might want
13570            self.addInMozillaDom(CGUnionStruct.unionTypeName(t, False))
13571            self.addInMozillaDom(CGUnionStruct.unionTypeName(t, True))
13572        elif t.isMozMap():
13573            self.forwardDeclareForType(t.inner, config)
13574        # Don't need to do anything for void, primitive, string, any or object.
13575        # There may be some other cases we are missing.
13576
13577
13578class CGForwardDeclarations(CGWrapper):
13579    """
13580    Code generate the forward declarations for a header file.
13581    additionalDeclarations is a list of tuples containing a classname and a
13582    boolean. If the boolean is true we will declare a struct, otherwise we'll
13583    declare a class.
13584    """
13585    def __init__(self, config, descriptors, callbacks,
13586                 dictionaries, callbackInterfaces, additionalDeclarations=[]):
13587        builder = ForwardDeclarationBuilder()
13588
13589        # Needed for at least Wrap.
13590        for d in descriptors:
13591            # If this is a generated iterator interface, we only create these
13592            # in the generated bindings, and don't need to forward declare.
13593            if d.interface.isIteratorInterface():
13594                continue
13595            builder.add(d.nativeType)
13596            # If we're an interface and we have a maplike/setlike declaration,
13597            # we'll have helper functions exposed to the native side of our
13598            # bindings, which will need to show up in the header. If either of
13599            # our key/value types are interfaces, they'll be passed as
13600            # arguments to helper functions, and they'll need to be forward
13601            # declared in the header.
13602            if d.interface.maplikeOrSetlikeOrIterable:
13603                if d.interface.maplikeOrSetlikeOrIterable.hasKeyType():
13604                    builder.forwardDeclareForType(d.interface.maplikeOrSetlikeOrIterable.keyType,
13605                                                  config)
13606                if d.interface.maplikeOrSetlikeOrIterable.hasValueType():
13607                    builder.forwardDeclareForType(d.interface.maplikeOrSetlikeOrIterable.valueType,
13608                                                  config)
13609
13610        # We just about always need NativePropertyHooks
13611        builder.addInMozillaDom("NativePropertyHooks", isStruct=True)
13612        builder.addInMozillaDom("ProtoAndIfaceCache")
13613        # Add the atoms cache type, even if we don't need it.
13614        for d in descriptors:
13615            # Iterators have native types that are template classes, so
13616            # creating an 'Atoms' cache type doesn't work for them, and is one
13617            # of the cases where we don't need it anyways.
13618            if d.interface.isIteratorInterface():
13619                continue
13620            builder.add(d.nativeType + "Atoms", isStruct=True)
13621
13622        for callback in callbacks:
13623            builder.addInMozillaDom(callback.identifier.name)
13624            for t in getTypesFromCallback(callback):
13625                builder.forwardDeclareForType(t, config)
13626
13627        for d in callbackInterfaces:
13628            builder.add(d.nativeType)
13629            builder.add(d.nativeType + "Atoms", isStruct=True)
13630            for t in getTypesFromDescriptor(d):
13631                builder.forwardDeclareForType(t, config)
13632
13633        for d in dictionaries:
13634            if len(d.members) > 0:
13635                builder.addInMozillaDom(d.identifier.name + "Atoms", isStruct=True)
13636            for t in getTypesFromDictionary(d):
13637                builder.forwardDeclareForType(t, config)
13638
13639        for className, isStruct in additionalDeclarations:
13640            builder.add(className, isStruct=isStruct)
13641
13642        CGWrapper.__init__(self, builder.build())
13643
13644
13645class CGBindingRoot(CGThing):
13646    """
13647    Root codegen class for binding generation. Instantiate the class, and call
13648    declare or define to generate header or cpp code (respectively).
13649    """
13650    def __init__(self, config, prefix, webIDLFile):
13651        bindingHeaders = dict.fromkeys((
13652            'mozilla/dom/NonRefcountedDOMObject.h',
13653            ),
13654            True)
13655        bindingDeclareHeaders = dict.fromkeys((
13656            'mozilla/dom/BindingDeclarations.h',
13657            'mozilla/dom/Nullable.h',
13658            'mozilla/ErrorResult.h',
13659            ),
13660            True)
13661
13662        descriptors = config.getDescriptors(webIDLFile=webIDLFile,
13663                                            hasInterfaceOrInterfacePrototypeObject=True)
13664
13665        unionTypes = UnionsForFile(config, webIDLFile)
13666
13667        (unionHeaders, unionImplheaders, unionDeclarations, traverseMethods,
13668         unlinkMethods, unionStructs) = UnionTypes(unionTypes, config)
13669
13670        bindingDeclareHeaders.update(dict.fromkeys(unionHeaders, True))
13671        bindingHeaders.update(dict.fromkeys(unionImplheaders, True))
13672        bindingDeclareHeaders["mozilla/dom/UnionMember.h"] = len(unionStructs) > 0
13673        bindingDeclareHeaders["mozilla/dom/FakeString.h"] = len(unionStructs) > 0
13674        # BindingUtils.h is only needed for SetToObject.
13675        # If it stops being inlined or stops calling CallerSubsumes
13676        # both this bit and the bit in UnionTypes can be removed.
13677        bindingDeclareHeaders["mozilla/dom/BindingUtils.h"] = any(d.isObject() for t in unionTypes
13678                                                                  for d in t.flatMemberTypes)
13679        bindingDeclareHeaders["mozilla/dom/IterableIterator.h"] = any(d.interface.isIteratorInterface() or
13680                                                                      d.interface.isIterable() for d in descriptors)
13681
13682        def descriptorHasCrossOriginProperties(desc):
13683            def hasCrossOriginProperty(m):
13684                props = memberProperties(m, desc)
13685                return (props.isCrossOriginMethod or
13686                        props.isCrossOriginGetter or
13687                        props.isCrossOriginSetter)
13688
13689            return any(hasCrossOriginProperty(m) for m in desc.interface.members)
13690
13691        bindingDeclareHeaders["jsapi.h"] = any(descriptorHasCrossOriginProperties(d) for d in descriptors)
13692        bindingDeclareHeaders["jspubtd.h"] = not bindingDeclareHeaders["jsapi.h"]
13693        bindingDeclareHeaders["js/RootingAPI.h"] = not bindingDeclareHeaders["jsapi.h"]
13694
13695        def descriptorRequiresPreferences(desc):
13696            iface = desc.interface
13697            return any(m.getExtendedAttribute("Pref") for m in iface.members + [iface])
13698
13699        def descriptorDeprecated(desc):
13700            iface = desc.interface
13701            return any(m.getExtendedAttribute("Deprecated") for m in iface.members + [iface])
13702
13703        bindingHeaders["nsIDocument.h"] = any(
13704            descriptorDeprecated(d) for d in descriptors)
13705        bindingHeaders["mozilla/Preferences.h"] = any(
13706            descriptorRequiresPreferences(d) for d in descriptors)
13707        bindingHeaders["mozilla/dom/DOMJSProxyHandler.h"] = any(
13708            d.concrete and d.proxy for d in descriptors)
13709
13710        def descriptorHasChromeOnly(desc):
13711            ctor = desc.interface.ctor()
13712
13713            return (any(isChromeOnly(a) or needsContainsHack(a) or
13714                        needsCallerType(a)
13715                        for a in desc.interface.members) or
13716                    desc.interface.getExtendedAttribute("ChromeOnly") is not None or
13717                    # JS-implemented interfaces with an interface object get a
13718                    # chromeonly _create method.  And interfaces with an
13719                    # interface object might have a ChromeOnly constructor.
13720                    (desc.interface.hasInterfaceObject() and
13721                     (desc.interface.isJSImplemented() or
13722                      (ctor and isChromeOnly(ctor)))) or
13723                    # JS-implemented interfaces with clearable cached
13724                    # attrs have chromeonly _clearFoo methods.
13725                    (desc.interface.isJSImplemented() and
13726                     any(clearableCachedAttrs(desc))))
13727
13728        # XXXkhuey ugly hack but this is going away soon.
13729        bindingHeaders['xpcprivate.h'] = webIDLFile.endswith("EventTarget.webidl")
13730
13731        hasThreadChecks = any(d.hasThreadChecks() for d in descriptors)
13732        bindingHeaders["nsThreadUtils.h"] = hasThreadChecks
13733
13734        dictionaries = config.getDictionaries(webIDLFile)
13735
13736        def dictionaryHasChromeOnly(dictionary):
13737            while dictionary:
13738                if (any(isChromeOnly(m) for m in dictionary.members)):
13739                    return True
13740                dictionary = dictionary.parent
13741            return False
13742
13743        bindingHeaders["nsContentUtils.h"] = (
13744            any(descriptorHasChromeOnly(d) for d in descriptors) or
13745            any(dictionaryHasChromeOnly(d) for d in dictionaries))
13746        hasNonEmptyDictionaries = any(
13747            len(dict.members) > 0 for dict in dictionaries)
13748        callbacks = config.getCallbacks(webIDLFile)
13749        callbackDescriptors = config.getDescriptors(webIDLFile=webIDLFile,
13750                                                    isCallback=True)
13751        jsImplemented = config.getDescriptors(webIDLFile=webIDLFile,
13752                                              isJSImplemented=True)
13753        bindingDeclareHeaders["nsWeakReference.h"] = jsImplemented
13754        bindingHeaders["nsIGlobalObject.h"] = jsImplemented
13755        bindingHeaders["AtomList.h"] = hasNonEmptyDictionaries or jsImplemented or callbackDescriptors
13756
13757        def descriptorClearsPropsInSlots(descriptor):
13758            if not descriptor.wrapperCache:
13759                return False
13760            return any(m.isAttr() and m.getExtendedAttribute("StoreInSlot")
13761                       for m in descriptor.interface.members)
13762        bindingHeaders["nsJSUtils.h"] = any(descriptorClearsPropsInSlots(d) for d in descriptors)
13763
13764        # Do codegen for all the enums
13765        enums = config.getEnums(webIDLFile)
13766        cgthings = [CGEnum(e) for e in enums]
13767
13768        hasCode = (descriptors or callbackDescriptors or dictionaries or
13769                   callbacks)
13770        bindingHeaders["mozilla/dom/BindingUtils.h"] = hasCode
13771        bindingHeaders["mozilla/OwningNonNull.h"] = hasCode
13772        bindingHeaders["mozilla/dom/BindingDeclarations.h"] = (
13773            not hasCode and enums)
13774
13775        bindingHeaders["WrapperFactory.h"] = descriptors
13776        bindingHeaders["mozilla/dom/DOMJSClass.h"] = descriptors
13777        bindingHeaders["mozilla/dom/ScriptSettings.h"] = dictionaries  # AutoJSAPI
13778        # Ensure we see our enums in the generated .cpp file, for the ToJSValue
13779        # method body.  Also ensure that we see jsapi.h.
13780        if enums:
13781            bindingHeaders[CGHeaders.getDeclarationFilename(enums[0])] = True
13782            bindingHeaders["jsapi.h"] = True
13783
13784        # For things that have [UseCounter]
13785        def descriptorRequiresTelemetry(desc):
13786            iface = desc.interface
13787            return any(m.getExtendedAttribute("UseCounter") for m in iface.members)
13788        bindingHeaders["mozilla/UseCounter.h"] = any(
13789            descriptorRequiresTelemetry(d) for d in descriptors)
13790        bindingHeaders["mozilla/dom/SimpleGlobalObject.h"] = any(
13791            CGDictionary.dictionarySafeToJSONify(d) for d in dictionaries)
13792        bindingHeaders["XrayWrapper.h"] = any(
13793            d.wantsXrays and d.wantsXrayExpandoClass for d in descriptors)
13794        bindingHeaders["mozilla/dom/XrayExpandoClass.h"] = any(
13795            d.wantsXrays for d in descriptors)
13796
13797        cgthings.extend(traverseMethods)
13798        cgthings.extend(unlinkMethods)
13799
13800        # Do codegen for all the dictionaries.  We have to be a bit careful
13801        # here, because we have to generate these in order from least derived
13802        # to most derived so that class inheritance works out.  We also have to
13803        # generate members before the dictionary that contains them.
13804
13805        def getDependenciesFromType(type):
13806            if type.isDictionary():
13807                return set([type.unroll().inner])
13808            if type.isSequence():
13809                return getDependenciesFromType(type.unroll())
13810            if type.isUnion():
13811                return set([type.unroll()])
13812            return set()
13813
13814        def getDependencies(unionTypeOrDictionary):
13815            if isinstance(unionTypeOrDictionary, IDLDictionary):
13816                deps = set()
13817                if unionTypeOrDictionary.parent:
13818                    deps.add(unionTypeOrDictionary.parent)
13819                for member in unionTypeOrDictionary.members:
13820                    deps |= getDependenciesFromType(member.type)
13821                return deps
13822
13823            assert unionTypeOrDictionary.isType() and unionTypeOrDictionary.isUnion()
13824            deps = set()
13825            for member in unionTypeOrDictionary.flatMemberTypes:
13826                deps |= getDependenciesFromType(member)
13827            return deps
13828
13829        def getName(unionTypeOrDictionary):
13830            if isinstance(unionTypeOrDictionary, IDLDictionary):
13831                return unionTypeOrDictionary.identifier.name
13832
13833            assert unionTypeOrDictionary.isType() and unionTypeOrDictionary.isUnion()
13834            return unionTypeOrDictionary.name
13835
13836        for t in dependencySortObjects(dictionaries + unionStructs, getDependencies, getName):
13837            if t.isDictionary():
13838                cgthings.append(CGDictionary(t, config))
13839            else:
13840                assert t.isUnion()
13841                cgthings.append(CGUnionStruct(t, config))
13842                cgthings.append(CGUnionStruct(t, config, True))
13843
13844        # Do codegen for all the callbacks.
13845        cgthings.extend(CGCallbackFunction(c, config) for c in callbacks)
13846
13847        cgthings.extend([CGNamespace('binding_detail', CGFastCallback(c))
13848                         for c in callbacks])
13849
13850        # Do codegen for all the descriptors
13851        cgthings.extend([CGDescriptor(x) for x in descriptors])
13852
13853        # Do codegen for all the callback interfaces.
13854        cgthings.extend([CGCallbackInterface(x) for x in callbackDescriptors])
13855
13856        cgthings.extend([CGNamespace('binding_detail',
13857                                     CGFastCallback(x.interface))
13858                         for x in callbackDescriptors])
13859
13860        # Do codegen for JS implemented classes
13861        def getParentDescriptor(desc):
13862            if not desc.interface.parent:
13863                return set()
13864            return {desc.getDescriptor(desc.interface.parent.identifier.name)}
13865        for x in dependencySortObjects(jsImplemented, getParentDescriptor,
13866                                       lambda d: d.interface.identifier.name):
13867            cgthings.append(CGCallbackInterface(x, typedArraysAreStructs=True))
13868            cgthings.append(CGJSImplClass(x))
13869
13870        # And make sure we have the right number of newlines at the end
13871        curr = CGWrapper(CGList(cgthings, "\n\n"), post="\n\n")
13872
13873        # Wrap all of that in our namespaces.
13874        curr = CGNamespace.build(['mozilla', 'dom'],
13875                                 CGWrapper(curr, pre="\n"))
13876
13877        curr = CGList([CGForwardDeclarations(config, descriptors,
13878                                             callbacks,
13879                                             dictionaries,
13880                                             callbackDescriptors + jsImplemented,
13881                                             additionalDeclarations=unionDeclarations),
13882                       curr],
13883                      "\n")
13884
13885        # Add header includes.
13886        bindingHeaders = [header
13887                          for header, include in bindingHeaders.iteritems()
13888                          if include]
13889        bindingDeclareHeaders = [header
13890                                 for header, include in bindingDeclareHeaders.iteritems()
13891                                 if include]
13892
13893        curr = CGHeaders(descriptors,
13894                         dictionaries,
13895                         callbacks,
13896                         callbackDescriptors,
13897                         bindingDeclareHeaders,
13898                         bindingHeaders,
13899                         prefix,
13900                         curr,
13901                         config,
13902                         jsImplemented)
13903
13904        # Add include guards.
13905        curr = CGIncludeGuard(prefix, curr)
13906
13907        # Add the auto-generated comment.
13908        curr = CGWrapper(
13909            curr,
13910            pre=(AUTOGENERATED_WITH_SOURCE_WARNING_COMMENT %
13911                 os.path.basename(webIDLFile)))
13912
13913        # Store the final result.
13914        self.root = curr
13915
13916    def declare(self):
13917        return stripTrailingWhitespace(self.root.declare())
13918
13919    def define(self):
13920        return stripTrailingWhitespace(self.root.define())
13921
13922    def deps(self):
13923        return self.root.deps()
13924
13925
13926class CGNativeMember(ClassMethod):
13927    def __init__(self, descriptorProvider, member, name, signature, extendedAttrs,
13928                 breakAfter=True, passJSBitsAsNeeded=True, visibility="public",
13929                 typedArraysAreStructs=True, variadicIsSequence=False,
13930                 resultNotAddRefed=False,
13931                 virtual=False,
13932                 override=False):
13933        """
13934        If typedArraysAreStructs is false, typed arrays will be passed as
13935        JS::Handle<JSObject*>.  If it's true they will be passed as one of the
13936        dom::TypedArray subclasses.
13937
13938        If passJSBitsAsNeeded is false, we don't automatically pass in a
13939        JSContext* or a JSObject* based on the return and argument types.  We
13940        can still pass it based on 'implicitJSContext' annotations.
13941        """
13942        self.descriptorProvider = descriptorProvider
13943        self.member = member
13944        self.extendedAttrs = extendedAttrs
13945        self.resultAlreadyAddRefed = not resultNotAddRefed
13946        self.passJSBitsAsNeeded = passJSBitsAsNeeded
13947        self.typedArraysAreStructs = typedArraysAreStructs
13948        self.variadicIsSequence = variadicIsSequence
13949        breakAfterSelf = "\n" if breakAfter else ""
13950        ClassMethod.__init__(self, name,
13951                             self.getReturnType(signature[0], False),
13952                             self.getArgs(signature[0], signature[1]),
13953                             static=member.isStatic(),
13954                             # Mark our getters, which are attrs that
13955                             # have a non-void return type, as const.
13956                             const=(not member.isStatic() and member.isAttr() and
13957                                    not signature[0].isVoid()),
13958                             breakAfterReturnDecl=" ",
13959                             breakAfterSelf=breakAfterSelf,
13960                             visibility=visibility,
13961                             virtual=virtual,
13962                             override=override)
13963
13964    def getReturnType(self, type, isMember):
13965        return self.getRetvalInfo(type, isMember)[0]
13966
13967    def getRetvalInfo(self, type, isMember):
13968        """
13969        Returns a tuple:
13970
13971        The first element is the type declaration for the retval
13972
13973        The second element is a default value that can be used on error returns.
13974        For cases whose behavior depends on isMember, the second element will be
13975        None if isMember is true.
13976
13977        The third element is a template for actually returning a value stored in
13978        "${declName}" and "${holderName}".  This means actually returning it if
13979        we're not outparam, else assigning to the "retval" outparam.  If
13980        isMember is true, this can be None, since in that case the caller will
13981        never examine this value.
13982        """
13983        if type.isVoid():
13984            return "void", "", ""
13985        if type.isPrimitive() and type.tag() in builtinNames:
13986            result = CGGeneric(builtinNames[type.tag()])
13987            defaultReturnArg = "0"
13988            if type.nullable():
13989                result = CGTemplatedType("Nullable", result)
13990                defaultReturnArg = ""
13991            return (result.define(),
13992                    "%s(%s)" % (result.define(), defaultReturnArg),
13993                    "return ${declName};\n")
13994        if type.isDOMString() or type.isUSVString():
13995            if isMember:
13996                # No need for a third element in the isMember case
13997                return "nsString", None, None
13998            # Outparam
13999            return "void", "", "aRetVal = ${declName};\n"
14000        if type.isByteString():
14001            if isMember:
14002                # No need for a third element in the isMember case
14003                return "nsCString", None, None
14004            # Outparam
14005            return "void", "", "aRetVal = ${declName};\n"
14006        if type.isEnum():
14007            enumName = type.unroll().inner.identifier.name
14008            if type.nullable():
14009                enumName = CGTemplatedType("Nullable",
14010                                           CGGeneric(enumName)).define()
14011                defaultValue = "%s()" % enumName
14012            else:
14013                defaultValue = "%s(0)" % enumName
14014            return enumName, defaultValue, "return ${declName};\n"
14015        if type.isGeckoInterface():
14016            iface = type.unroll().inner
14017            result = CGGeneric(self.descriptorProvider.getDescriptor(
14018                iface.identifier.name).prettyNativeType)
14019            if self.resultAlreadyAddRefed:
14020                if isMember:
14021                    holder = "RefPtr"
14022                else:
14023                    holder = "already_AddRefed"
14024                if memberReturnsNewObject(self.member) or isMember:
14025                    warning = ""
14026                else:
14027                    warning = "// Return a raw pointer here to avoid refcounting, but make sure it's safe (the object should be kept alive by the callee).\n"
14028                result = CGWrapper(result,
14029                                   pre=("%s%s<" % (warning, holder)),
14030                                   post=">")
14031            else:
14032                result = CGWrapper(result, post="*")
14033            # Since we always force an owning type for callback return values,
14034            # our ${declName} is an OwningNonNull or RefPtr.  So we can just
14035            # .forget() to get our already_AddRefed.
14036            return result.define(), "nullptr", "return ${declName}.forget();\n"
14037        if type.isCallback():
14038            return ("already_AddRefed<%s>" % type.unroll().callback.identifier.name,
14039                    "nullptr", "return ${declName}.forget();\n")
14040        if type.isAny():
14041            if isMember:
14042                # No need for a third element in the isMember case
14043                return "JS::Value", None, None
14044            # Outparam
14045            return "void", "", "aRetVal.set(${declName});\n"
14046
14047        if type.isObject():
14048            if isMember:
14049                # No need for a third element in the isMember case
14050                return "JSObject*", None, None
14051            return "void", "", "aRetVal.set(${declName});\n"
14052        if type.isSpiderMonkeyInterface():
14053            if isMember:
14054                # No need for a third element in the isMember case
14055                return "JSObject*", None, None
14056            if type.nullable():
14057                returnCode = "${declName}.IsNull() ? nullptr : ${declName}.Value().Obj()"
14058            else:
14059                returnCode = "${declName}.Obj()"
14060            return "void", "", "aRetVal.set(%s);\n" % returnCode
14061        if type.isSequence():
14062            # If we want to handle sequence-of-sequences return values, we're
14063            # going to need to fix example codegen to not produce nsTArray<void>
14064            # for the relevant argument...
14065            assert not isMember
14066            # Outparam.
14067            if type.nullable():
14068                returnCode = dedent("""
14069                    if (${declName}.IsNull()) {
14070                      aRetVal.SetNull();
14071                    } else {
14072                      aRetVal.SetValue().SwapElements(${declName}.Value());
14073                    }
14074                    """)
14075            else:
14076                returnCode = "aRetVal.SwapElements(${declName});\n"
14077            return "void", "", returnCode
14078        if type.isMozMap():
14079            # If we want to handle MozMap-of-MozMap return values, we're
14080            # going to need to fix example codegen to not produce MozMap<void>
14081            # for the relevant argument...
14082            assert not isMember
14083            # In this case we convert directly into our outparam to start with
14084            return "void", "", ""
14085        if type.isDate():
14086            result = CGGeneric("Date")
14087            if type.nullable():
14088                result = CGTemplatedType("Nullable", result)
14089            return (result.define(), "%s()" % result.define(),
14090                    "return ${declName};\n")
14091        if type.isDictionary():
14092            if isMember:
14093                # Only the first member of the tuple matters here, but return
14094                # bogus values for the others in case someone decides to use
14095                # them.
14096                return CGDictionary.makeDictionaryName(type.inner), None, None
14097            # In this case we convert directly into our outparam to start with
14098            return "void", "", ""
14099        if type.isUnion():
14100            if isMember:
14101                # Only the first member of the tuple matters here, but return
14102                # bogus values for the others in case someone decides to use
14103                # them.
14104                return CGUnionStruct.unionTypeDecl(type, True), None, None
14105            # In this case we convert directly into our outparam to start with
14106            return "void", "", ""
14107
14108        raise TypeError("Don't know how to declare return value for %s" %
14109                        type)
14110
14111    def getArgs(self, returnType, argList):
14112        args = [self.getArg(arg) for arg in argList]
14113        # Now the outparams
14114        if returnType.isDOMString() or returnType.isUSVString():
14115            args.append(Argument("nsString&", "aRetVal"))
14116        elif returnType.isByteString():
14117            args.append(Argument("nsCString&", "aRetVal"))
14118        elif returnType.isSequence():
14119            nullable = returnType.nullable()
14120            if nullable:
14121                returnType = returnType.inner
14122            # And now the actual underlying type
14123            elementDecl = self.getReturnType(returnType.inner, True)
14124            type = CGTemplatedType("nsTArray", CGGeneric(elementDecl))
14125            if nullable:
14126                type = CGTemplatedType("Nullable", type)
14127            args.append(Argument("%s&" % type.define(), "aRetVal"))
14128        elif returnType.isMozMap():
14129            nullable = returnType.nullable()
14130            if nullable:
14131                returnType = returnType.inner
14132            # And now the actual underlying type
14133            elementDecl = self.getReturnType(returnType.inner, True)
14134            type = CGTemplatedType("MozMap", CGGeneric(elementDecl))
14135            if nullable:
14136                type = CGTemplatedType("Nullable", type)
14137            args.append(Argument("%s&" % type.define(), "aRetVal"))
14138        elif returnType.isDictionary():
14139            nullable = returnType.nullable()
14140            if nullable:
14141                returnType = returnType.inner
14142            dictType = CGGeneric(CGDictionary.makeDictionaryName(returnType.inner))
14143            if nullable:
14144                dictType = CGTemplatedType("Nullable", dictType)
14145            args.append(Argument("%s&" % dictType.define(), "aRetVal"))
14146        elif returnType.isUnion():
14147            args.append(Argument("%s&" %
14148                                 CGUnionStruct.unionTypeDecl(returnType, True),
14149                                 "aRetVal"))
14150        elif returnType.isAny():
14151            args.append(Argument("JS::MutableHandle<JS::Value>", "aRetVal"))
14152        elif returnType.isObject() or returnType.isSpiderMonkeyInterface():
14153            args.append(Argument("JS::MutableHandle<JSObject*>", "aRetVal"))
14154
14155        # And the nsIPrincipal
14156        if self.member.getExtendedAttribute('NeedsSubjectPrincipal'):
14157            # Cheat and assume self.descriptorProvider is a descriptor
14158            if self.descriptorProvider.interface.isExposedInAnyWorker():
14159                args.append(Argument("Maybe<nsIPrincipal*>", "aSubjectPrincipal"))
14160            else:
14161                args.append(Argument("nsIPrincipal&", "aPrincipal"))
14162        # And the caller type, if desired.
14163        if needsCallerType(self.member):
14164            args.append(Argument("CallerType", "aCallerType"))
14165        # And the ErrorResult
14166        if 'infallible' not in self.extendedAttrs:
14167            # Use aRv so it won't conflict with local vars named "rv"
14168            args.append(Argument("ErrorResult&", "aRv"))
14169        # The legacycaller thisval
14170        if self.member.isMethod() and self.member.isLegacycaller():
14171            # If it has an identifier, we can't deal with it yet
14172            assert self.member.isIdentifierLess()
14173            args.insert(0, Argument("const JS::Value&", "aThisVal"))
14174        # And jscontext bits.
14175        if needCx(returnType, argList, self.extendedAttrs,
14176                  self.passJSBitsAsNeeded, self.member.isStatic()):
14177            args.insert(0, Argument("JSContext*", "cx"))
14178            if needScopeObject(returnType, argList, self.extendedAttrs,
14179                               self.descriptorProvider.wrapperCache,
14180                               self.passJSBitsAsNeeded,
14181                               self.member.getExtendedAttribute("StoreInSlot")):
14182                args.insert(1, Argument("JS::Handle<JSObject*>", "obj"))
14183        # And if we're static, a global
14184        if self.member.isStatic():
14185            args.insert(0, Argument("const GlobalObject&", "global"))
14186        return args
14187
14188    def doGetArgType(self, type, optional, isMember):
14189        """
14190        The main work of getArgType.  Returns a string type decl, whether this
14191        is a const ref, as well as whether the type should be wrapped in
14192        Nullable as needed.
14193
14194        isMember can be false or one of the strings "Sequence", "Variadic",
14195                 "MozMap"
14196        """
14197        if type.isSequence():
14198            nullable = type.nullable()
14199            if nullable:
14200                type = type.inner
14201            elementType = type.inner
14202            argType = self.getArgType(elementType, False, "Sequence")[0]
14203            decl = CGTemplatedType("Sequence", argType)
14204            return decl.define(), True, True
14205
14206        if type.isMozMap():
14207            nullable = type.nullable()
14208            if nullable:
14209                type = type.inner
14210            elementType = type.inner
14211            argType = self.getArgType(elementType, False, "MozMap")[0]
14212            decl = CGTemplatedType("MozMap", argType)
14213            return decl.define(), True, True
14214
14215        if type.isUnion():
14216            # unionTypeDecl will handle nullable types, so return False for
14217            # auto-wrapping in Nullable
14218            return CGUnionStruct.unionTypeDecl(type, isMember), True, False
14219
14220        if type.isGeckoInterface() and not type.isCallbackInterface():
14221            iface = type.unroll().inner
14222            argIsPointer = type.nullable() or iface.isExternal()
14223            forceOwningType = (iface.isCallback() or isMember or
14224                               iface.identifier.name == "Promise")
14225            if argIsPointer:
14226                if (optional or isMember) and forceOwningType:
14227                    typeDecl = "RefPtr<%s>"
14228                else:
14229                    typeDecl = "%s*"
14230            else:
14231                if optional or isMember:
14232                    if forceOwningType:
14233                        typeDecl = "OwningNonNull<%s>"
14234                    else:
14235                        typeDecl = "NonNull<%s>"
14236                else:
14237                    typeDecl = "%s&"
14238            return ((typeDecl %
14239                     self.descriptorProvider.getDescriptor(iface.identifier.name).prettyNativeType),
14240                    False, False)
14241
14242        if type.isSpiderMonkeyInterface():
14243            if not self.typedArraysAreStructs:
14244                return "JS::Handle<JSObject*>", False, False
14245
14246            # Unroll for the name, in case we're nullable.
14247            return type.unroll().name, True, True
14248
14249        if type.isDOMString() or type.isUSVString():
14250            if isMember:
14251                declType = "nsString"
14252            else:
14253                declType = "nsAString"
14254            return declType, True, False
14255
14256        if type.isByteString():
14257            declType = "nsCString"
14258            return declType, True, False
14259
14260        if type.isEnum():
14261            return type.unroll().inner.identifier.name, False, True
14262
14263        if type.isCallback() or type.isCallbackInterface():
14264            forceOwningType = optional or isMember
14265            if type.nullable():
14266                if forceOwningType:
14267                    declType = "RefPtr<%s>"
14268                else:
14269                    declType = "%s*"
14270            else:
14271                if forceOwningType:
14272                    declType = "OwningNonNull<%s>"
14273                else:
14274                    declType = "%s&"
14275            if type.isCallback():
14276                name = type.unroll().callback.identifier.name
14277            else:
14278                name = type.unroll().inner.identifier.name
14279            return declType % name, False, False
14280
14281        if type.isAny():
14282            # Don't do the rooting stuff for variadics for now
14283            if isMember:
14284                declType = "JS::Value"
14285            else:
14286                declType = "JS::Handle<JS::Value>"
14287            return declType, False, False
14288
14289        if type.isObject():
14290            if isMember:
14291                declType = "JSObject*"
14292            else:
14293                declType = "JS::Handle<JSObject*>"
14294            return declType, False, False
14295
14296        if type.isDictionary():
14297            typeName = CGDictionary.makeDictionaryName(type.inner)
14298            return typeName, True, True
14299
14300        if type.isDate():
14301            return "Date", False, True
14302
14303        assert type.isPrimitive()
14304
14305        return builtinNames[type.tag()], False, True
14306
14307    def getArgType(self, type, optional, isMember):
14308        """
14309        Get the type of an argument declaration.  Returns the type CGThing, and
14310        whether this should be a const ref.
14311
14312        isMember can be False, "Sequence", or "Variadic"
14313        """
14314        decl, ref, handleNullable = self.doGetArgType(type, optional, isMember)
14315        decl = CGGeneric(decl)
14316        if handleNullable and type.nullable():
14317            decl = CGTemplatedType("Nullable", decl)
14318            ref = True
14319        if isMember == "Variadic":
14320            arrayType = "Sequence" if self.variadicIsSequence else "nsTArray"
14321            decl = CGTemplatedType(arrayType, decl)
14322            ref = True
14323        elif optional:
14324            # Note: All variadic args claim to be optional, but we can just use
14325            # empty arrays to represent them not being present.
14326            decl = CGTemplatedType("Optional", decl)
14327            ref = True
14328        return (decl, ref)
14329
14330    def getArg(self, arg):
14331        """
14332        Get the full argument declaration for an argument
14333        """
14334        decl, ref = self.getArgType(arg.type, arg.canHaveMissingValue(),
14335                                    "Variadic" if arg.variadic else False)
14336        if ref:
14337            decl = CGWrapper(decl, pre="const ", post="&")
14338
14339        return Argument(decl.define(), arg.identifier.name)
14340
14341    def arguments(self):
14342        return self.member.signatures()[0][1]
14343
14344
14345class CGExampleMethod(CGNativeMember):
14346    def __init__(self, descriptor, method, signature, isConstructor, breakAfter=True):
14347        CGNativeMember.__init__(self, descriptor, method,
14348                                CGSpecializedMethod.makeNativeName(descriptor,
14349                                                                   method),
14350                                signature,
14351                                descriptor.getExtendedAttributes(method),
14352                                breakAfter=breakAfter,
14353                                variadicIsSequence=True)
14354
14355    def declare(self, cgClass):
14356        assert self.member.isMethod()
14357        # We skip declaring ourselves if this is a maplike/setlike/iterable
14358        # method, because those get implemented automatically by the binding
14359        # machinery, so the implementor of the interface doesn't have to worry
14360        # about it.
14361        if self.member.isMaplikeOrSetlikeOrIterableMethod():
14362            return ''
14363        return CGNativeMember.declare(self, cgClass);
14364
14365    def define(self, cgClass):
14366        return ''
14367
14368
14369class CGExampleGetter(CGNativeMember):
14370    def __init__(self, descriptor, attr):
14371        CGNativeMember.__init__(self, descriptor, attr,
14372                                CGSpecializedGetter.makeNativeName(descriptor,
14373                                                                   attr),
14374                                (attr.type, []),
14375                                descriptor.getExtendedAttributes(attr,
14376                                                                 getter=True))
14377
14378    def declare(self, cgClass):
14379        assert self.member.isAttr()
14380        # We skip declaring ourselves if this is a maplike/setlike attr (in
14381        # practice, "size"), because those get implemented automatically by the
14382        # binding machinery, so the implementor of the interface doesn't have to
14383        # worry about it.
14384        if self.member.isMaplikeOrSetlikeAttr():
14385            return ''
14386        return CGNativeMember.declare(self, cgClass);
14387
14388    def define(self, cgClass):
14389        return ''
14390
14391
14392class CGExampleSetter(CGNativeMember):
14393    def __init__(self, descriptor, attr):
14394        CGNativeMember.__init__(self, descriptor, attr,
14395                                CGSpecializedSetter.makeNativeName(descriptor,
14396                                                                   attr),
14397                                (BuiltinTypes[IDLBuiltinType.Types.void],
14398                                 [FakeArgument(attr.type, attr)]),
14399                                descriptor.getExtendedAttributes(attr,
14400                                                                 setter=True))
14401
14402    def define(self, cgClass):
14403        return ''
14404
14405
14406class CGBindingImplClass(CGClass):
14407    """
14408    Common codegen for generating a C++ implementation of a WebIDL interface
14409    """
14410    def __init__(self, descriptor, cgMethod, cgGetter, cgSetter, wantGetParent=True, wrapMethodName="WrapObject", skipStaticMethods=False):
14411        """
14412        cgMethod, cgGetter and cgSetter are classes used to codegen methods,
14413        getters and setters.
14414        """
14415        self.descriptor = descriptor
14416        self._deps = descriptor.interface.getDeps()
14417
14418        iface = descriptor.interface
14419
14420        self.methodDecls = []
14421
14422        def appendMethod(m, isConstructor=False):
14423            sigs = m.signatures()
14424            for s in sigs[:-1]:
14425                # Don't put a blank line after overloads, until we
14426                # get to the last one.
14427                self.methodDecls.append(cgMethod(descriptor, m, s,
14428                                                 isConstructor,
14429                                                 breakAfter=False))
14430            self.methodDecls.append(cgMethod(descriptor, m, sigs[-1],
14431                                             isConstructor))
14432
14433        if iface.ctor():
14434            appendMethod(iface.ctor(), isConstructor=True)
14435        for n in iface.namedConstructors:
14436            appendMethod(n, isConstructor=True)
14437        for m in iface.members:
14438            if m.isMethod():
14439                if m.isIdentifierLess():
14440                    continue
14441                if not m.isStatic() or not skipStaticMethods:
14442                    appendMethod(m)
14443            elif m.isAttr():
14444                self.methodDecls.append(cgGetter(descriptor, m))
14445                if not m.readonly:
14446                    self.methodDecls.append(cgSetter(descriptor, m))
14447
14448        # Now do the special operations
14449        def appendSpecialOperation(name, op):
14450            if op is None:
14451                return
14452            if name == "IndexedCreator" or name == "NamedCreator":
14453                # These are identical to the setters
14454                return
14455            assert len(op.signatures()) == 1
14456            returnType, args = op.signatures()[0]
14457            # Make a copy of the args, since we plan to modify them.
14458            args = list(args)
14459            if op.isGetter() or op.isDeleter():
14460                # This is a total hack.  The '&' belongs with the
14461                # type, not the name!  But it works, and is simpler
14462                # than trying to somehow make this pretty.
14463                args.append(FakeArgument(BuiltinTypes[IDLBuiltinType.Types.boolean],
14464                                         op, name="&found"))
14465            if name == "Stringifier":
14466                if op.isIdentifierLess():
14467                    # XXXbz I wish we were consistent about our renaming here.
14468                    name = "Stringify"
14469                else:
14470                    # We already added this method
14471                    return
14472            if name == "LegacyCaller":
14473                if op.isIdentifierLess():
14474                    # XXXbz I wish we were consistent about our renaming here.
14475                    name = "LegacyCall"
14476                else:
14477                    # We already added this method
14478                    return
14479            if name == "Jsonifier":
14480                # We already added this method
14481                return
14482            self.methodDecls.append(
14483                CGNativeMember(descriptor, op,
14484                               name,
14485                               (returnType, args),
14486                               descriptor.getExtendedAttributes(op)))
14487        # Sort things by name so we get stable ordering in the output.
14488        ops = descriptor.operations.items()
14489        ops.sort(key=lambda x: x[0])
14490        for name, op in ops:
14491            appendSpecialOperation(name, op)
14492        # If we support indexed properties, then we need a Length()
14493        # method so we know which indices are supported.
14494        if descriptor.supportsIndexedProperties():
14495            # But we don't need it if we already have an infallible
14496            # "length" attribute, which we often do.
14497            haveLengthAttr = any(
14498                m for m in iface.members if m.isAttr() and
14499                CGSpecializedGetter.makeNativeName(descriptor, m) == "Length")
14500            if not haveLengthAttr:
14501                self.methodDecls.append(
14502                    CGNativeMember(descriptor, FakeMember(),
14503                                   "Length",
14504                                   (BuiltinTypes[IDLBuiltinType.Types.unsigned_long],
14505                                    []),
14506                                   {"infallible": True}))
14507        # And if we support named properties we need to be able to
14508        # enumerate the supported names.
14509        if descriptor.supportsNamedProperties():
14510            self.methodDecls.append(
14511                CGNativeMember(
14512                    descriptor, FakeMember(),
14513                    "GetSupportedNames",
14514                    (IDLSequenceType(None,
14515                                     BuiltinTypes[IDLBuiltinType.Types.domstring]),
14516                     []),
14517                    {"infallible": True}))
14518
14519        wrapArgs = [Argument('JSContext*', 'aCx'),
14520                    Argument('JS::Handle<JSObject*>', 'aGivenProto')]
14521        if not descriptor.wrapperCache:
14522            wrapReturnType = "bool"
14523            wrapArgs.append(Argument('JS::MutableHandle<JSObject*>',
14524                                     'aReflector'))
14525        else:
14526            wrapReturnType = "JSObject*"
14527        self.methodDecls.insert(0,
14528                                ClassMethod(wrapMethodName, wrapReturnType,
14529                                            wrapArgs, virtual=descriptor.wrapperCache,
14530                                            breakAfterReturnDecl=" ",
14531                                            override=descriptor.wrapperCache,
14532                                            body=self.getWrapObjectBody()))
14533        if wantGetParent:
14534            self.methodDecls.insert(0,
14535                                    ClassMethod("GetParentObject",
14536                                                self.getGetParentObjectReturnType(),
14537                                                [], const=True,
14538                                                breakAfterReturnDecl=" ",
14539                                                body=self.getGetParentObjectBody()))
14540
14541        # Invoke  CGClass.__init__ in any subclasses afterwards to do the actual codegen.
14542
14543    def getWrapObjectBody(self):
14544        return None
14545
14546    def getGetParentObjectReturnType(self):
14547        return ("// TODO: return something sensible here, and change the return type\n"
14548                "%s*" % self.descriptor.nativeType.split('::')[-1])
14549
14550    def getGetParentObjectBody(self):
14551        return None
14552
14553    def deps(self):
14554        return self._deps
14555
14556
14557class CGExampleClass(CGBindingImplClass):
14558    """
14559    Codegen for the actual example class implementation for this descriptor
14560    """
14561    def __init__(self, descriptor):
14562        CGBindingImplClass.__init__(self, descriptor,
14563                                    CGExampleMethod, CGExampleGetter, CGExampleSetter,
14564                                    wantGetParent=descriptor.wrapperCache)
14565
14566        self.parentIface = descriptor.interface.parent
14567        if self.parentIface:
14568            self.parentDesc = descriptor.getDescriptor(
14569                self.parentIface.identifier.name)
14570            bases = [ClassBase(self.nativeLeafName(self.parentDesc))]
14571        else:
14572            bases = [ClassBase("nsISupports /* or NonRefcountedDOMObject if this is a non-refcounted object */")]
14573            if descriptor.wrapperCache:
14574                bases.append(ClassBase("nsWrapperCache /* Change wrapperCache in the binding configuration if you don't want this */"))
14575
14576        destructorVisibility = "protected"
14577        if self.parentIface:
14578            extradeclarations = (
14579                "public:\n"
14580                "  NS_DECL_ISUPPORTS_INHERITED\n"
14581                "  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(%s, %s)\n"
14582                "\n" % (self.nativeLeafName(descriptor),
14583                        self.nativeLeafName(self.parentDesc)))
14584        else:
14585            extradeclarations = (
14586                "public:\n"
14587                "  NS_DECL_CYCLE_COLLECTING_ISUPPORTS\n"
14588                "  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(%s)\n"
14589                "\n" % self.nativeLeafName(descriptor))
14590
14591        if descriptor.interface.hasChildInterfaces():
14592            decorators = ""
14593        else:
14594            decorators = "final"
14595
14596        CGClass.__init__(self, self.nativeLeafName(descriptor),
14597                         bases=bases,
14598                         constructors=[ClassConstructor([],
14599                                                        visibility="public")],
14600                         destructor=ClassDestructor(visibility=destructorVisibility),
14601                         methods=self.methodDecls,
14602                         decorators=decorators,
14603                         extradeclarations=extradeclarations)
14604
14605    def define(self):
14606        # Just override CGClass and do our own thing
14607        ctordtor = dedent("""
14608            ${nativeType}::${nativeType}()
14609            {
14610                // Add |MOZ_COUNT_CTOR(${nativeType});| for a non-refcounted object.
14611            }
14612
14613            ${nativeType}::~${nativeType}()
14614            {
14615                // Add |MOZ_COUNT_DTOR(${nativeType});| for a non-refcounted object.
14616            }
14617            """)
14618
14619        if self.parentIface:
14620            ccImpl = dedent("""
14621
14622                // Only needed for refcounted objects.
14623                # error "If you don't have members that need cycle collection,
14624                # then remove all the cycle collection bits from this
14625                # implementation and the corresponding header.  If you do, you
14626                # want NS_IMPL_CYCLE_COLLECTION_INHERITED(${nativeType},
14627                # ${parentType}, your, members, here)"
14628                NS_IMPL_ADDREF_INHERITED(${nativeType}, ${parentType})
14629                NS_IMPL_RELEASE_INHERITED(${nativeType}, ${parentType})
14630                NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
14631                NS_INTERFACE_MAP_END_INHERITING(${parentType})
14632
14633                """)
14634        else:
14635            ccImpl = dedent("""
14636
14637                // Only needed for refcounted objects.
14638                NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(${nativeType})
14639                NS_IMPL_CYCLE_COLLECTING_ADDREF(${nativeType})
14640                NS_IMPL_CYCLE_COLLECTING_RELEASE(${nativeType})
14641                NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
14642                  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
14643                  NS_INTERFACE_MAP_ENTRY(nsISupports)
14644                NS_INTERFACE_MAP_END
14645
14646                """)
14647
14648        if self.descriptor.wrapperCache:
14649            reflectorArg = ""
14650            reflectorPassArg = ""
14651            returnType = "JSObject*"
14652        else:
14653            reflectorArg = ", JS::MutableHandle<JSObject*> aReflector"
14654            reflectorPassArg = ", aReflector"
14655            returnType = "bool"
14656        classImpl = ccImpl + ctordtor + "\n" + dedent("""
14657            ${returnType}
14658            ${nativeType}::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto${reflectorArg})
14659            {
14660              return ${ifaceName}Binding::Wrap(aCx, this, aGivenProto${reflectorPassArg});
14661            }
14662
14663            """)
14664        return string.Template(classImpl).substitute(
14665            ifaceName=self.descriptor.name,
14666            nativeType=self.nativeLeafName(self.descriptor),
14667            parentType=self.nativeLeafName(self.parentDesc) if self.parentIface else "",
14668            returnType=returnType,
14669            reflectorArg=reflectorArg,
14670            reflectorPassArg=reflectorPassArg)
14671
14672    @staticmethod
14673    def nativeLeafName(descriptor):
14674        return descriptor.nativeType.split('::')[-1]
14675
14676
14677class CGExampleRoot(CGThing):
14678    """
14679    Root codegen class for example implementation generation.  Instantiate the
14680    class and call declare or define to generate header or cpp code,
14681    respectively.
14682    """
14683    def __init__(self, config, interfaceName):
14684        descriptor = config.getDescriptor(interfaceName)
14685
14686        self.root = CGWrapper(CGExampleClass(descriptor),
14687                              pre="\n", post="\n")
14688
14689        self.root = CGNamespace.build(["mozilla", "dom"], self.root)
14690
14691        builder = ForwardDeclarationBuilder()
14692        for member in descriptor.interface.members:
14693            if not member.isAttr() and not member.isMethod():
14694                continue
14695            if member.isStatic():
14696                builder.addInMozillaDom("GlobalObject")
14697            if member.isAttr() and not member.isMaplikeOrSetlikeAttr():
14698                builder.forwardDeclareForType(member.type, config)
14699            else:
14700                assert member.isMethod()
14701                if not member.isMaplikeOrSetlikeOrIterableMethod():
14702                    for sig in member.signatures():
14703                        builder.forwardDeclareForType(sig[0], config)
14704                        for arg in sig[1]:
14705                            builder.forwardDeclareForType(arg.type, config)
14706
14707        self.root = CGList([builder.build(),
14708                            self.root], "\n")
14709
14710        # Throw in our #includes
14711        self.root = CGHeaders([], [], [], [],
14712                              ["nsWrapperCache.h",
14713                               "nsCycleCollectionParticipant.h",
14714                               "mozilla/Attributes.h",
14715                               "mozilla/ErrorResult.h",
14716                               "mozilla/dom/BindingDeclarations.h",
14717                               "js/TypeDecls.h"],
14718                              ["mozilla/dom/%s.h" % interfaceName,
14719                               ("mozilla/dom/%s" %
14720                                CGHeaders.getDeclarationFilename(descriptor.interface))], "", self.root)
14721
14722        # And now some include guards
14723        self.root = CGIncludeGuard(interfaceName, self.root)
14724
14725        # And our license block comes before everything else
14726        self.root = CGWrapper(self.root, pre=dedent("""
14727            /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
14728            /* vim:set ts=2 sw=2 sts=2 et cindent: */
14729            /* This Source Code Form is subject to the terms of the Mozilla Public
14730             * License, v. 2.0. If a copy of the MPL was not distributed with this
14731             * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
14732
14733            """))
14734
14735    def declare(self):
14736        return self.root.declare()
14737
14738    def define(self):
14739        return self.root.define()
14740
14741
14742def jsImplName(name):
14743    return name + "JSImpl"
14744
14745
14746class CGJSImplMember(CGNativeMember):
14747    """
14748    Base class for generating code for the members of the implementation class
14749    for a JS-implemented WebIDL interface.
14750    """
14751    def __init__(self, descriptorProvider, member, name, signature,
14752                 extendedAttrs, breakAfter=True, passJSBitsAsNeeded=True,
14753                 visibility="public", variadicIsSequence=False,
14754                 virtual=False, override=False):
14755        CGNativeMember.__init__(self, descriptorProvider, member, name,
14756                                signature, extendedAttrs, breakAfter=breakAfter,
14757                                passJSBitsAsNeeded=passJSBitsAsNeeded,
14758                                visibility=visibility,
14759                                variadicIsSequence=variadicIsSequence,
14760                                virtual=virtual,
14761                                override=override)
14762        self.body = self.getImpl()
14763
14764    def getArgs(self, returnType, argList):
14765        args = CGNativeMember.getArgs(self, returnType, argList)
14766        args.append(Argument("JSCompartment*", "aCompartment", "nullptr"))
14767        return args
14768
14769
14770class CGJSImplMethod(CGJSImplMember):
14771    """
14772    Class for generating code for the methods for a JS-implemented WebIDL
14773    interface.
14774    """
14775    def __init__(self, descriptor, method, signature, isConstructor, breakAfter=True):
14776        virtual = False
14777        override = False
14778        if (method.identifier.name == "eventListenerWasAdded" or
14779            method.identifier.name == "eventListenerWasRemoved"):
14780            virtual = True
14781            override = True
14782
14783        self.signature = signature
14784        self.descriptor = descriptor
14785        self.isConstructor = isConstructor
14786        CGJSImplMember.__init__(self, descriptor, method,
14787                                CGSpecializedMethod.makeNativeName(descriptor,
14788                                                                   method),
14789                                signature,
14790                                descriptor.getExtendedAttributes(method),
14791                                breakAfter=breakAfter,
14792                                variadicIsSequence=True,
14793                                passJSBitsAsNeeded=False,
14794                                virtual=virtual,
14795                                override=override)
14796
14797    def getArgs(self, returnType, argList):
14798        if self.isConstructor:
14799            # Skip the JSCompartment bits for constructors; it's handled
14800            # manually in getImpl.
14801            return CGNativeMember.getArgs(self, returnType, argList)
14802        return CGJSImplMember.getArgs(self, returnType, argList)
14803
14804    def getImpl(self):
14805        args = self.getArgs(self.signature[0], self.signature[1])
14806        if not self.isConstructor:
14807            return 'return mImpl->%s(%s);\n' % (self.name, ", ".join(arg.name for arg in args))
14808
14809        assert self.descriptor.interface.isJSImplemented()
14810        if self.name != 'Constructor':
14811            raise TypeError("Named constructors are not supported for JS implemented WebIDL. See bug 851287.")
14812        if len(self.signature[1]) != 0:
14813            # The first two arguments to the constructor implementation are not
14814            # arguments to the WebIDL constructor, so don't pass them to __Init()
14815            assert args[0].argType == 'const GlobalObject&'
14816            assert args[1].argType == 'JSContext*'
14817            constructorArgs = [arg.name for arg in args[2:]]
14818            constructorArgs.append("js::GetObjectCompartment(scopeObj)")
14819            initCall = fill(
14820                """
14821                // Wrap the object before calling __Init so that __DOM_IMPL__ is available.
14822                JS::Rooted<JSObject*> scopeObj(cx, globalHolder->GetGlobalJSObject());
14823                MOZ_ASSERT(js::IsObjectInContextCompartment(scopeObj, cx));
14824                JS::Rooted<JS::Value> wrappedVal(cx);
14825                if (!GetOrCreateDOMReflector(cx, impl, &wrappedVal)) {
14826                  //XXX Assertion disabled for now, see bug 991271.
14827                  MOZ_ASSERT(true || JS_IsExceptionPending(cx));
14828                  aRv.Throw(NS_ERROR_UNEXPECTED);
14829                  return nullptr;
14830                }
14831                // Initialize the object with the constructor arguments.
14832                impl->mImpl->__Init(${args});
14833                if (aRv.Failed()) {
14834                  return nullptr;
14835                }
14836                """,
14837                args=", ".join(constructorArgs))
14838        else:
14839            initCall = ""
14840        return genConstructorBody(self.descriptor, initCall)
14841
14842
14843def genConstructorBody(descriptor, initCall=""):
14844    return fill(
14845        """
14846        JS::Rooted<JSObject*> jsImplObj(cx);
14847        nsCOMPtr<nsIGlobalObject> globalHolder =
14848          ConstructJSImplementation("${contractId}", global, &jsImplObj, aRv);
14849        if (aRv.Failed()) {
14850          return nullptr;
14851        }
14852        // Build the C++ implementation.
14853        RefPtr<${implClass}> impl = new ${implClass}(jsImplObj, globalHolder);
14854        $*{initCall}
14855        return impl.forget();
14856        """,
14857        contractId=descriptor.interface.getJSImplementation(),
14858        implClass=descriptor.name,
14859        initCall=initCall)
14860
14861
14862# We're always fallible
14863def callbackGetterName(attr, descriptor):
14864    return "Get" + MakeNativeName(
14865        descriptor.binaryNameFor(attr.identifier.name))
14866
14867
14868def callbackSetterName(attr, descriptor):
14869    return "Set" + MakeNativeName(
14870        descriptor.binaryNameFor(attr.identifier.name))
14871
14872
14873class CGJSImplClearCachedValueMethod(CGAbstractBindingMethod):
14874    def __init__(self, descriptor, attr):
14875        if attr.getExtendedAttribute("StoreInSlot"):
14876            raise TypeError("[StoreInSlot] is not supported for JS-implemented WebIDL. See bug 1056325.")
14877
14878        CGAbstractBindingMethod.__init__(self, descriptor,
14879                                         MakeJSImplClearCachedValueNativeName(attr),
14880                                         JSNativeArguments())
14881        self.attr = attr
14882
14883    def generate_code(self):
14884        return CGGeneric(fill(
14885            """
14886            ${bindingNamespace}::${fnName}(self);
14887            args.rval().setUndefined();
14888            return true;
14889            """,
14890            bindingNamespace=toBindingNamespace(self.descriptor.name),
14891            fnName=MakeClearCachedValueNativeName(self.attr)))
14892
14893
14894class CGJSImplGetter(CGJSImplMember):
14895    """
14896    Class for generating code for the getters of attributes for a JS-implemented
14897    WebIDL interface.
14898    """
14899    def __init__(self, descriptor, attr):
14900        CGJSImplMember.__init__(self, descriptor, attr,
14901                                CGSpecializedGetter.makeNativeName(descriptor,
14902                                                                   attr),
14903                                (attr.type, []),
14904                                descriptor.getExtendedAttributes(attr,
14905                                                                 getter=True),
14906                                passJSBitsAsNeeded=False)
14907
14908    def getImpl(self):
14909        callbackArgs = [arg.name for arg in self.getArgs(self.member.type, [])]
14910        return 'return mImpl->%s(%s);\n' % (
14911            callbackGetterName(self.member, self.descriptorProvider),
14912            ", ".join(callbackArgs))
14913
14914
14915class CGJSImplSetter(CGJSImplMember):
14916    """
14917    Class for generating code for the setters of attributes for a JS-implemented
14918    WebIDL interface.
14919    """
14920    def __init__(self, descriptor, attr):
14921        CGJSImplMember.__init__(self, descriptor, attr,
14922                                CGSpecializedSetter.makeNativeName(descriptor,
14923                                                                   attr),
14924                                (BuiltinTypes[IDLBuiltinType.Types.void],
14925                                 [FakeArgument(attr.type, attr)]),
14926                                descriptor.getExtendedAttributes(attr,
14927                                                                 setter=True),
14928                                passJSBitsAsNeeded=False)
14929
14930    def getImpl(self):
14931        callbackArgs = [arg.name for arg in self.getArgs(BuiltinTypes[IDLBuiltinType.Types.void],
14932                                                         [FakeArgument(self.member.type, self.member)])]
14933        return 'mImpl->%s(%s);\n' % (
14934            callbackSetterName(self.member, self.descriptorProvider),
14935            ", ".join(callbackArgs))
14936
14937
14938class CGJSImplClass(CGBindingImplClass):
14939    def __init__(self, descriptor):
14940        CGBindingImplClass.__init__(self, descriptor, CGJSImplMethod, CGJSImplGetter, CGJSImplSetter, skipStaticMethods=True)
14941
14942        if descriptor.interface.parent:
14943            parentClass = descriptor.getDescriptor(
14944                descriptor.interface.parent.identifier.name).jsImplParent
14945            baseClasses = [ClassBase(parentClass)]
14946            isupportsDecl = "NS_DECL_ISUPPORTS_INHERITED\n"
14947            ccDecl = ("NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(%s, %s)\n" %
14948                      (descriptor.name, parentClass))
14949            constructorBody = dedent("""
14950                // Make sure we're an nsWrapperCache already
14951                MOZ_ASSERT(static_cast<nsWrapperCache*>(this));
14952                // And that our ancestor has not called SetIsNotDOMBinding()
14953                MOZ_ASSERT(IsDOMBinding());
14954                """)
14955            extradefinitions = fill(
14956                """
14957                NS_IMPL_CYCLE_COLLECTION_INHERITED(${ifaceName}, ${parentClass}, mImpl, mParent)
14958                NS_IMPL_ADDREF_INHERITED(${ifaceName}, ${parentClass})
14959                NS_IMPL_RELEASE_INHERITED(${ifaceName}, ${parentClass})
14960                NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(${ifaceName})
14961                NS_INTERFACE_MAP_END_INHERITING(${parentClass})
14962                """,
14963                ifaceName=self.descriptor.name,
14964                parentClass=parentClass)
14965        else:
14966            baseClasses = [ClassBase("nsSupportsWeakReference"),
14967                           ClassBase("nsWrapperCache")]
14968            isupportsDecl = "NS_DECL_CYCLE_COLLECTING_ISUPPORTS\n"
14969            ccDecl = ("NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(%s)\n" %
14970                      descriptor.name)
14971            extradefinitions = fill(
14972                """
14973                NS_IMPL_CYCLE_COLLECTION_CLASS(${ifaceName})
14974                NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(${ifaceName})
14975                  NS_IMPL_CYCLE_COLLECTION_UNLINK(mImpl)
14976                  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
14977                  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
14978                  tmp->ClearWeakReferences();
14979                NS_IMPL_CYCLE_COLLECTION_UNLINK_END
14980                NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(${ifaceName})
14981                  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImpl)
14982                  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
14983                  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
14984                NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
14985                NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(${ifaceName})
14986                NS_IMPL_CYCLE_COLLECTING_ADDREF(${ifaceName})
14987                NS_IMPL_CYCLE_COLLECTING_RELEASE(${ifaceName})
14988                NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${ifaceName})
14989                  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
14990                  NS_INTERFACE_MAP_ENTRY(nsISupports)
14991                  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
14992                NS_INTERFACE_MAP_END
14993                """,
14994                ifaceName=self.descriptor.name)
14995
14996        extradeclarations = fill(
14997            """
14998            public:
14999              $*{isupportsDecl}
15000              $*{ccDecl}
15001
15002            private:
15003              RefPtr<${jsImplName}> mImpl;
15004              nsCOMPtr<nsISupports> mParent;
15005
15006            """,
15007            isupportsDecl=isupportsDecl,
15008            ccDecl=ccDecl,
15009            jsImplName=jsImplName(descriptor.name))
15010
15011        if descriptor.interface.hasChildInterfaces():
15012            decorators = ""
15013            # We need a protected virtual destructor our subclasses can use
15014            destructor = ClassDestructor(virtual=True, visibility="protected")
15015        else:
15016            decorators = "final"
15017            destructor = ClassDestructor(virtual=False, visibility="private")
15018
15019        baseConstructors = [
15020            ("mImpl(new %s(nullptr, aJSImplObject, /* aIncumbentGlobal = */ nullptr))" %
15021             jsImplName(descriptor.name)),
15022            "mParent(aParent)"]
15023        parentInterface = descriptor.interface.parent
15024        while parentInterface:
15025            if parentInterface.isJSImplemented():
15026                baseConstructors.insert(
15027                    0, "%s(aJSImplObject, aParent)" % parentClass)
15028                break
15029            parentInterface = parentInterface.parent
15030        if not parentInterface and descriptor.interface.parent:
15031            # We only have C++ ancestors, so only pass along the window
15032            baseConstructors.insert(0,
15033                                    "%s(aParent)" % parentClass)
15034
15035        constructor = ClassConstructor(
15036            [Argument("JS::Handle<JSObject*>", "aJSImplObject"),
15037             Argument("nsIGlobalObject*", "aParent")],
15038            visibility="public",
15039            baseConstructors=baseConstructors)
15040
15041        self.methodDecls.append(
15042            ClassMethod("_Create",
15043                        "bool",
15044                        JSNativeArguments(),
15045                        static=True,
15046                        body=self.getCreateFromExistingBody()))
15047
15048        CGClass.__init__(self, descriptor.name,
15049                         bases=baseClasses,
15050                         constructors=[constructor],
15051                         destructor=destructor,
15052                         methods=self.methodDecls,
15053                         decorators=decorators,
15054                         extradeclarations=extradeclarations,
15055                         extradefinitions=extradefinitions)
15056
15057    def getWrapObjectBody(self):
15058        return fill(
15059            """
15060            JS::Rooted<JSObject*> obj(aCx, ${name}Binding::Wrap(aCx, this, aGivenProto));
15061            if (!obj) {
15062              return nullptr;
15063            }
15064
15065            // Now define it on our chrome object
15066            JSAutoCompartment ac(aCx, mImpl->Callback());
15067            if (!JS_WrapObject(aCx, &obj)) {
15068              return nullptr;
15069            }
15070            if (!JS_DefineProperty(aCx, mImpl->Callback(), "__DOM_IMPL__", obj, 0)) {
15071              return nullptr;
15072            }
15073            return obj;
15074            """,
15075            name=self.descriptor.name)
15076
15077    def getGetParentObjectReturnType(self):
15078        return "nsISupports*"
15079
15080    def getGetParentObjectBody(self):
15081        return "return mParent;\n"
15082
15083    def getCreateFromExistingBody(self):
15084        # XXXbz we could try to get parts of this (e.g. the argument
15085        # conversions) auto-generated by somehow creating an IDLMethod and
15086        # adding it to our interface, but we'd still need to special-case the
15087        # implementation slightly to have it not try to forward to the JS
15088        # object...
15089        return fill(
15090            """
15091            JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
15092            if (args.length() < 2) {
15093              return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "${ifaceName}._create");
15094            }
15095            if (!args[0].isObject()) {
15096              return ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Argument 1 of ${ifaceName}._create");
15097            }
15098            if (!args[1].isObject()) {
15099              return ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Argument 2 of ${ifaceName}._create");
15100            }
15101
15102            // GlobalObject will go through wrappers as needed for us, and
15103            // is simpler than the right UnwrapArg incantation.
15104            GlobalObject global(cx, &args[0].toObject());
15105            if (global.Failed()) {
15106              return false;
15107            }
15108            nsCOMPtr<nsIGlobalObject> globalHolder = do_QueryInterface(global.GetAsSupports());
15109            MOZ_ASSERT(globalHolder);
15110            JS::Rooted<JSObject*> arg(cx, &args[1].toObject());
15111            RefPtr<${implName}> impl = new ${implName}(arg, globalHolder);
15112            MOZ_ASSERT(js::IsObjectInContextCompartment(arg, cx));
15113            return GetOrCreateDOMReflector(cx, impl, args.rval());
15114            """,
15115            ifaceName=self.descriptor.interface.identifier.name,
15116            implName=self.descriptor.name)
15117
15118
15119def isJSImplementedDescriptor(descriptorProvider):
15120    return (isinstance(descriptorProvider, Descriptor) and
15121            descriptorProvider.interface.isJSImplemented())
15122
15123
15124class CGCallback(CGClass):
15125    def __init__(self, idlObject, descriptorProvider, baseName, methods,
15126                 getters=[], setters=[]):
15127        self.baseName = baseName
15128        self._deps = idlObject.getDeps()
15129        self.idlObject = idlObject
15130        self.name = idlObject.identifier.name
15131        if isJSImplementedDescriptor(descriptorProvider):
15132            self.name = jsImplName(self.name)
15133        # For our public methods that needThisHandling we want most of the
15134        # same args and the same return type as what CallbackMember
15135        # generates.  So we want to take advantage of all its
15136        # CGNativeMember infrastructure, but that infrastructure can't deal
15137        # with templates and most especially template arguments.  So just
15138        # cheat and have CallbackMember compute all those things for us.
15139        realMethods = []
15140        for method in methods:
15141            if not isinstance(method, CallbackMember) or not method.needThisHandling:
15142                realMethods.append(method)
15143            else:
15144                realMethods.extend(self.getMethodImpls(method))
15145        realMethods.append(
15146            ClassMethod("operator==", "bool",
15147                        [Argument("const %s&" % self.name, "aOther")],
15148                        inline=True, bodyInHeader=True,
15149                        const=True,
15150                        body=("return %s::operator==(aOther);\n" % baseName)))
15151        CGClass.__init__(self, self.name,
15152                         bases=[ClassBase(baseName)],
15153                         constructors=self.getConstructors(),
15154                         methods=realMethods+getters+setters)
15155
15156    def getConstructors(self):
15157        if (not self.idlObject.isInterface() and
15158            not self.idlObject._treatNonObjectAsNull):
15159            body = "MOZ_ASSERT(JS::IsCallable(mCallback));\n"
15160        else:
15161            # Not much we can assert about it, other than not being null, and
15162            # CallbackObject does that already.
15163            body = ""
15164        return [
15165            ClassConstructor(
15166                [Argument("JSContext*", "aCx"),
15167                 Argument("JS::Handle<JSObject*>", "aCallback"),
15168                 Argument("nsIGlobalObject*", "aIncumbentGlobal")],
15169                bodyInHeader=True,
15170                visibility="public",
15171                explicit=True,
15172                baseConstructors=[
15173                    "%s(aCx, aCallback, aIncumbentGlobal)" % self.baseName,
15174                ],
15175                body=body),
15176            ClassConstructor(
15177                [Argument("JSContext*", "aCx"),
15178                 Argument("JS::Handle<JSObject*>", "aCallback"),
15179                 Argument("nsIGlobalObject*", "aIncumbentGlobal"),
15180                 Argument("const FastCallbackConstructor&", "")],
15181                bodyInHeader=True,
15182                visibility="public",
15183                explicit=True,
15184                baseConstructors=[
15185                    "%s(aCx, aCallback, aIncumbentGlobal, FastCallbackConstructor())" % self.baseName,
15186                ],
15187                body=body),
15188            ClassConstructor(
15189                [Argument("JS::Handle<JSObject*>", "aCallback"),
15190                 Argument("JS::Handle<JSObject*>", "aAsyncStack"),
15191                 Argument("nsIGlobalObject*", "aIncumbentGlobal")],
15192                bodyInHeader=True,
15193                visibility="public",
15194                explicit=True,
15195                baseConstructors=[
15196                    "%s(aCallback, aAsyncStack, aIncumbentGlobal)" % self.baseName,
15197                ],
15198                body=body)]
15199
15200    def getMethodImpls(self, method):
15201        assert method.needThisHandling
15202        args = list(method.args)
15203        # Strip out the JSContext*/JSObject* args
15204        # that got added.
15205        assert args[0].name == "cx" and args[0].argType == "JSContext*"
15206        assert args[1].name == "aThisVal" and args[1].argType == "JS::Handle<JS::Value>"
15207        args = args[2:]
15208
15209        # Now remember which index the ErrorResult argument is at;
15210        # we'll need this below.
15211        assert args[-1].name == "aRv" and args[-1].argType == "ErrorResult&"
15212        rvIndex = len(args) - 1
15213        assert rvIndex >= 0
15214
15215        # Record the names of all the arguments, so we can use them when we call
15216        # the private method.
15217        argnames = [arg.name for arg in args]
15218        argnamesWithThis = ["s.GetContext()", "thisValJS"] + argnames
15219        argnamesWithoutThis = ["s.GetContext()", "JS::UndefinedHandleValue"] + argnames
15220        # Now that we've recorded the argnames for our call to our private
15221        # method, insert our optional argument for the execution reason.
15222        args.append(Argument("const char*", "aExecutionReason",
15223                             "nullptr"))
15224
15225        # Make copies of the arg list for the two "without rv" overloads.  Note
15226        # that those don't need aExceptionHandling or aCompartment arguments
15227        # because those would make not sense anyway: the only sane thing to do
15228        # with exceptions in the "without rv" cases is to report them.
15229        argsWithoutRv = list(args)
15230        argsWithoutRv.pop(rvIndex)
15231        argsWithoutThisAndRv = list(argsWithoutRv)
15232
15233        # Add the potional argument for deciding whether the CallSetup should
15234        # re-throw exceptions on aRv.
15235        args.append(Argument("ExceptionHandling", "aExceptionHandling",
15236                             "eReportExceptions"))
15237        # And the argument for communicating when exceptions should really be
15238        # rethrown.  In particular, even when aExceptionHandling is
15239        # eRethrowExceptions they won't get rethrown if aCompartment is provided
15240        # and its principal doesn't subsume either the callback or the
15241        # exception.
15242        args.append(Argument("JSCompartment*", "aCompartment", "nullptr"))
15243        # And now insert our template argument.
15244        argsWithoutThis = list(args)
15245        args.insert(0, Argument("const T&",  "thisVal"))
15246        argsWithoutRv.insert(0, Argument("const T&",  "thisVal"))
15247
15248        argnamesWithoutThisAndRv = [arg.name for arg in argsWithoutThisAndRv]
15249        argnamesWithoutThisAndRv.insert(rvIndex, "rv");
15250        # If we just leave things like that, and have no actual arguments in the
15251        # IDL, we will end up trying to call the templated "without rv" overload
15252        # with "rv" as the thisVal.  That's no good.  So explicitly append the
15253        # aExceptionHandling and aCompartment values we need to end up matching
15254        # the signature of our non-templated "with rv" overload.
15255        argnamesWithoutThisAndRv.extend(["eReportExceptions", "nullptr"])
15256
15257        argnamesWithoutRv = [arg.name for arg in argsWithoutRv]
15258        # Note that we need to insert at rvIndex + 1, since we inserted a
15259        # thisVal arg at the start.
15260        argnamesWithoutRv.insert(rvIndex + 1, "rv")
15261
15262        errorReturn = method.getDefaultRetval()
15263
15264        setupCall = fill(
15265            """
15266            if (!aExecutionReason) {
15267              aExecutionReason = "${executionReason}";
15268            }
15269            CallSetup s(this, aRv, aExecutionReason, aExceptionHandling, aCompartment);
15270            if (!s.GetContext()) {
15271              MOZ_ASSERT(aRv.Failed());
15272              return${errorReturn};
15273            }
15274            """,
15275            errorReturn=errorReturn,
15276            executionReason=method.getPrettyName())
15277
15278        bodyWithThis = fill(
15279            """
15280            $*{setupCall}
15281            JS::Rooted<JS::Value> thisValJS(s.GetContext());
15282            if (!ToJSValue(s.GetContext(), thisVal, &thisValJS)) {
15283              aRv.Throw(NS_ERROR_FAILURE);
15284              return${errorReturn};
15285            }
15286            return ${methodName}(${callArgs});
15287            """,
15288            setupCall=setupCall,
15289            errorReturn=errorReturn,
15290            methodName=method.name,
15291            callArgs=", ".join(argnamesWithThis))
15292        bodyWithoutThis = fill(
15293            """
15294            $*{setupCall}
15295            return ${methodName}(${callArgs});
15296            """,
15297            setupCall=setupCall,
15298            errorReturn=errorReturn,
15299            methodName=method.name,
15300            callArgs=", ".join(argnamesWithoutThis))
15301        bodyWithThisWithoutRv = fill(
15302            """
15303            IgnoredErrorResult rv;
15304            return ${methodName}(${callArgs});
15305            """,
15306            methodName=method.name,
15307            callArgs=", ".join(argnamesWithoutRv))
15308        bodyWithoutThisAndRv = fill(
15309            """
15310            IgnoredErrorResult rv;
15311            return ${methodName}(${callArgs});
15312            """,
15313            methodName=method.name,
15314            callArgs=", ".join(argnamesWithoutThisAndRv))
15315
15316        return [ClassMethod(method.name, method.returnType, args,
15317                            bodyInHeader=True,
15318                            templateArgs=["typename T"],
15319                            body=bodyWithThis),
15320                ClassMethod(method.name, method.returnType, argsWithoutThis,
15321                            bodyInHeader=True,
15322                            body=bodyWithoutThis),
15323                ClassMethod(method.name, method.returnType, argsWithoutRv,
15324                            bodyInHeader=True,
15325                            templateArgs=["typename T"],
15326                            body=bodyWithThisWithoutRv),
15327                ClassMethod(method.name, method.returnType, argsWithoutThisAndRv,
15328                            bodyInHeader=True,
15329                            body=bodyWithoutThisAndRv),
15330                method]
15331
15332    def deps(self):
15333        return self._deps
15334
15335
15336class CGCallbackFunction(CGCallback):
15337    def __init__(self, callback, descriptorProvider):
15338        self.callback = callback
15339        CGCallback.__init__(self, callback, descriptorProvider,
15340                            "CallbackFunction",
15341                            methods=[CallCallback(callback, descriptorProvider)])
15342
15343    def getConstructors(self):
15344        return CGCallback.getConstructors(self) + [
15345            ClassConstructor(
15346                [Argument("CallbackFunction*", "aOther")],
15347                bodyInHeader=True,
15348                visibility="public",
15349                explicit=True,
15350                baseConstructors=["CallbackFunction(aOther)"])]
15351
15352
15353class CGFastCallback(CGClass):
15354    def __init__(self, idlObject):
15355        self._deps = idlObject.getDeps()
15356        baseName = idlObject.identifier.name
15357        constructor = ClassConstructor(
15358            [Argument("JSContext*", "aCx"),
15359             Argument("JS::Handle<JSObject*>", "aCallback"),
15360             Argument("nsIGlobalObject*", "aIncumbentGlobal")],
15361            bodyInHeader=True,
15362            visibility="public",
15363            explicit=True,
15364            baseConstructors=[
15365                "%s(aCx, aCallback, aIncumbentGlobal, FastCallbackConstructor())" %
15366                baseName,
15367            ],
15368            body="")
15369
15370        traceMethod = ClassMethod("Trace", "void",
15371                                  [Argument("JSTracer*", "aTracer")],
15372                                  inline=True,
15373                                  bodyInHeader=True,
15374                                  visibility="public",
15375                                  body="%s::Trace(aTracer);\n" % baseName)
15376        holdMethod = ClassMethod("HoldJSObjectsIfMoreThanOneOwner", "void",
15377                                 [],
15378                                 inline=True,
15379                                 bodyInHeader=True,
15380                                 visibility="public",
15381                                 body=(
15382                                     "%s::HoldJSObjectsIfMoreThanOneOwner();\n" %
15383                                     baseName))
15384
15385        CGClass.__init__(self, "Fast%s" % baseName,
15386                         bases=[ClassBase(baseName)],
15387                         constructors=[constructor],
15388                         methods=[traceMethod, holdMethod])
15389
15390    def deps(self):
15391        return self._deps
15392
15393
15394class CGCallbackInterface(CGCallback):
15395    def __init__(self, descriptor, typedArraysAreStructs=False):
15396        iface = descriptor.interface
15397        attrs = [m for m in iface.members if m.isAttr() and not m.isStatic()]
15398        getters = [CallbackGetter(a, descriptor, typedArraysAreStructs)
15399                   for a in attrs]
15400        setters = [CallbackSetter(a, descriptor, typedArraysAreStructs)
15401                   for a in attrs if not a.readonly]
15402        methods = [m for m in iface.members
15403                   if m.isMethod() and not m.isStatic() and not m.isIdentifierLess()]
15404        methods = [CallbackOperation(m, sig, descriptor, typedArraysAreStructs)
15405                   for m in methods for sig in m.signatures()]
15406        if iface.isJSImplemented() and iface.ctor():
15407            sigs = descriptor.interface.ctor().signatures()
15408            if len(sigs) != 1:
15409                raise TypeError("We only handle one constructor.  See bug 869268.")
15410            methods.append(CGJSImplInitOperation(sigs[0], descriptor))
15411        if any(m.isAttr() or m.isMethod() for m in iface.members) or (iface.isJSImplemented() and iface.ctor()):
15412            methods.append(initIdsClassMethod([descriptor.binaryNameFor(m.identifier.name)
15413                                               for m in iface.members
15414                                               if m.isAttr() or m.isMethod()] +
15415                                              (["__init"] if iface.isJSImplemented() and iface.ctor() else []),
15416                                              iface.identifier.name + "Atoms"))
15417        CGCallback.__init__(self, iface, descriptor, "CallbackInterface",
15418                            methods, getters=getters, setters=setters)
15419
15420
15421class FakeMember():
15422    def __init__(self, name=None):
15423        self.treatNullAs = "Default"
15424        if name is not None:
15425            self.identifier = FakeIdentifier(name)
15426
15427    def isStatic(self):
15428        return False
15429
15430    def isAttr(self):
15431        return False
15432
15433    def isMethod(self):
15434        return False
15435
15436    def getExtendedAttribute(self, name):
15437        # Claim to be a [NewObject] so we can avoid the "return a raw pointer"
15438        # comments CGNativeMember codegen would otherwise stick in.
15439        if name == "NewObject":
15440            return True
15441        return None
15442
15443
15444class CallbackMember(CGNativeMember):
15445    # XXXbz It's OK to use CallbackKnownNotGray for wrapScope because
15446    # CallSetup already handled the unmark-gray bits for us. we don't have
15447    # anything better to use for 'obj', really...
15448    def __init__(self, sig, name, descriptorProvider, needThisHandling,
15449                 rethrowContentException=False, typedArraysAreStructs=False,
15450                 wrapScope='CallbackKnownNotGray()'):
15451        """
15452        needThisHandling is True if we need to be able to accept a specified
15453        thisObj, False otherwise.
15454        """
15455        assert not rethrowContentException or not needThisHandling
15456
15457        self.retvalType = sig[0]
15458        self.originalSig = sig
15459        args = sig[1]
15460        self.argCount = len(args)
15461        if self.argCount > 0:
15462            # Check for variadic arguments
15463            lastArg = args[self.argCount-1]
15464            if lastArg.variadic:
15465                self.argCountStr = ("(%d - 1) + %s.Length()" %
15466                                    (self.argCount, lastArg.identifier.name))
15467            else:
15468                self.argCountStr = "%d" % self.argCount
15469        self.needThisHandling = needThisHandling
15470        # If needThisHandling, we generate ourselves as private and the caller
15471        # will handle generating public versions that handle the "this" stuff.
15472        visibility = "private" if needThisHandling else "public"
15473        self.rethrowContentException = rethrowContentException
15474
15475        self.wrapScope = wrapScope
15476        # We don't care, for callback codegen, whether our original member was
15477        # a method or attribute or whatnot.  Just always pass FakeMember()
15478        # here.
15479        CGNativeMember.__init__(self, descriptorProvider, FakeMember(),
15480                                name, (self.retvalType, args),
15481                                extendedAttrs={},
15482                                passJSBitsAsNeeded=False,
15483                                visibility=visibility,
15484                                typedArraysAreStructs=typedArraysAreStructs)
15485        # We have to do all the generation of our body now, because
15486        # the caller relies on us throwing if we can't manage it.
15487        self.exceptionCode = ("aRv.Throw(NS_ERROR_UNEXPECTED);\n"
15488                              "return%s;\n" % self.getDefaultRetval())
15489        self.body = self.getImpl()
15490
15491    def getImpl(self):
15492        setupCall = self.getCallSetup()
15493        declRval = self.getRvalDecl()
15494        if self.argCount > 0:
15495            argvDecl = fill(
15496                """
15497                JS::AutoValueVector argv(cx);
15498                if (!argv.resize(${argCount})) {
15499                  aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
15500                  return${errorReturn};
15501                }
15502                """,
15503                argCount=self.argCountStr,
15504                errorReturn=self.getDefaultRetval())
15505        else:
15506            # Avoid weird 0-sized arrays
15507            argvDecl = ""
15508        convertArgs = self.getArgConversions()
15509        doCall = self.getCall()
15510        returnResult = self.getResultConversion()
15511
15512        return setupCall + declRval + argvDecl + convertArgs + doCall + returnResult
15513
15514    def getResultConversion(self):
15515        replacements = {
15516            "val": "rval",
15517            "holderName": "rvalHolder",
15518            "declName": "rvalDecl",
15519            # We actually want to pass in a null scope object here, because
15520            # wrapping things into our current compartment (that of mCallback)
15521            # is what we want.
15522            "obj": "nullptr",
15523            "passedToJSImpl": "false"
15524        }
15525
15526        if isJSImplementedDescriptor(self.descriptorProvider):
15527            isCallbackReturnValue = "JSImpl"
15528        else:
15529            isCallbackReturnValue = "Callback"
15530        sourceDescription = "return value of %s" % self.getPrettyName()
15531        convertType = instantiateJSToNativeConversion(
15532            getJSToNativeConversionInfo(self.retvalType,
15533                                        self.descriptorProvider,
15534                                        exceptionCode=self.exceptionCode,
15535                                        isCallbackReturnValue=isCallbackReturnValue,
15536                                        # Allow returning a callback type that
15537                                        # allows non-callable objects.
15538                                        allowTreatNonCallableAsNull=True,
15539                                        sourceDescription=sourceDescription),
15540            replacements)
15541        assignRetval = string.Template(
15542            self.getRetvalInfo(self.retvalType,
15543                               False)[2]).substitute(replacements)
15544        type = convertType.define()
15545        return type + assignRetval
15546
15547    def getArgConversions(self):
15548        # Just reget the arglist from self.originalSig, because our superclasses
15549        # just have way to many members they like to clobber, so I can't find a
15550        # safe member name to store it in.
15551        argConversions = [self.getArgConversion(i, arg)
15552                          for i, arg in enumerate(self.originalSig[1])]
15553        if not argConversions:
15554            return "\n"
15555
15556        # Do them back to front, so our argc modifications will work
15557        # correctly, because we examine trailing arguments first.
15558        argConversions.reverse()
15559        # Wrap each one in a scope so that any locals it has don't leak out, and
15560        # also so that we can just "break;" for our successCode.
15561        argConversions = [CGWrapper(CGIndenter(CGGeneric(c)),
15562                                    pre="do {\n",
15563                                    post="} while (0);\n")
15564                          for c in argConversions]
15565        if self.argCount > 0:
15566            argConversions.insert(0, self.getArgcDecl())
15567        # And slap them together.
15568        return CGList(argConversions, "\n").define() + "\n"
15569
15570    def getArgConversion(self, i, arg):
15571        argval = arg.identifier.name
15572
15573        if arg.variadic:
15574            argval = argval + "[idx]"
15575            jsvalIndex = "%d + idx" % i
15576        else:
15577            jsvalIndex = "%d" % i
15578            if arg.canHaveMissingValue():
15579                argval += ".Value()"
15580        if arg.type.isDOMString():
15581            # XPConnect string-to-JS conversion wants to mutate the string.  So
15582            # let's give it a string it can mutate
15583            # XXXbz if we try to do a sequence of strings, this will kinda fail.
15584            result = "mutableStr"
15585            prepend = "nsString mutableStr(%s);\n" % argval
15586        else:
15587            result = argval
15588            prepend = ""
15589
15590        try:
15591            conversion = prepend + wrapForType(
15592                arg.type, self.descriptorProvider,
15593                {
15594                    'result': result,
15595                    'successCode': "continue;\n" if arg.variadic else "break;\n",
15596                    'jsvalRef': "argv[%s]" % jsvalIndex,
15597                    'jsvalHandle': "argv[%s]" % jsvalIndex,
15598                    'obj': self.wrapScope,
15599                    'returnsNewObject': False,
15600                    'exceptionCode': self.exceptionCode,
15601                    'typedArraysAreStructs': self.typedArraysAreStructs
15602                })
15603        except MethodNotNewObjectError as err:
15604            raise TypeError("%s being passed as an argument to %s but is not "
15605                            "wrapper cached, so can't be reliably converted to "
15606                            "a JS object." %
15607                            (err.typename, self.getPrettyName()))
15608        if arg.variadic:
15609            conversion = fill(
15610                """
15611                for (uint32_t idx = 0; idx < ${arg}.Length(); ++idx) {
15612                  $*{conversion}
15613                }
15614                break;
15615                """,
15616                arg=arg.identifier.name,
15617                conversion=conversion)
15618        elif arg.canHaveMissingValue():
15619            conversion = fill(
15620                """
15621                if (${argName}.WasPassed()) {
15622                  $*{conversion}
15623                } else if (argc == ${iPlus1}) {
15624                  // This is our current trailing argument; reduce argc
15625                  --argc;
15626                } else {
15627                  argv[${i}].setUndefined();
15628                }
15629                """,
15630                argName=arg.identifier.name,
15631                conversion=conversion,
15632                iPlus1=i + 1,
15633                i=i)
15634        return conversion
15635
15636    def getDefaultRetval(self):
15637        default = self.getRetvalInfo(self.retvalType, False)[1]
15638        if len(default) != 0:
15639            default = " " + default
15640        return default
15641
15642    def getArgs(self, returnType, argList):
15643        args = CGNativeMember.getArgs(self, returnType, argList)
15644        if not self.needThisHandling:
15645            # Since we don't need this handling, we're the actual method that
15646            # will be called, so we need an aRethrowExceptions argument.
15647            if not self.rethrowContentException:
15648                args.append(Argument("const char*", "aExecutionReason",
15649                                     "nullptr"))
15650                args.append(Argument("ExceptionHandling", "aExceptionHandling",
15651                                     "eReportExceptions"))
15652            args.append(Argument("JSCompartment*", "aCompartment", "nullptr"))
15653            return args
15654        # We want to allow the caller to pass in a "this" value, as
15655        # well as a JSContext.
15656        return [Argument("JSContext*", "cx"),
15657                Argument("JS::Handle<JS::Value>", "aThisVal")] + args
15658
15659    def getCallSetup(self):
15660        if self.needThisHandling:
15661            # It's been done for us already
15662            return ""
15663        callSetup = "CallSetup s(this, aRv"
15664        if self.rethrowContentException:
15665            # getArgs doesn't add the aExceptionHandling argument but does add
15666            # aCompartment for us.
15667            callSetup += ', "%s", eRethrowContentExceptions, aCompartment, /* aIsJSImplementedWebIDL = */ ' % self.getPrettyName()
15668            callSetup += toStringBool(isJSImplementedDescriptor(self.descriptorProvider))
15669        else:
15670            callSetup += ', "%s", aExceptionHandling, aCompartment' % self.getPrettyName()
15671        callSetup += ");\n"
15672        return fill(
15673            """
15674            $*{callSetup}
15675            JSContext* cx = s.GetContext();
15676            if (!cx) {
15677              MOZ_ASSERT(aRv.Failed());
15678              return${errorReturn};
15679            }
15680            """,
15681            callSetup=callSetup,
15682            errorReturn=self.getDefaultRetval())
15683
15684    def getArgcDecl(self):
15685        return CGGeneric("unsigned argc = %s;\n" % self.argCountStr)
15686
15687    @staticmethod
15688    def ensureASCIIName(idlObject):
15689        type = "attribute" if idlObject.isAttr() else "operation"
15690        if re.match("[^\x20-\x7E]", idlObject.identifier.name):
15691            raise SyntaxError('Callback %s name "%s" contains non-ASCII '
15692                              "characters.  We can't handle that.  %s" %
15693                              (type, idlObject.identifier.name,
15694                               idlObject.location))
15695        if re.match('"', idlObject.identifier.name):
15696            raise SyntaxError("Callback %s name '%s' contains "
15697                              "double-quote character.  We can't handle "
15698                              "that.  %s" %
15699                              (type, idlObject.identifier.name,
15700                               idlObject.location))
15701
15702
15703class CallbackMethod(CallbackMember):
15704    def __init__(self, sig, name, descriptorProvider, needThisHandling,
15705                 rethrowContentException=False, typedArraysAreStructs=False):
15706        CallbackMember.__init__(self, sig, name, descriptorProvider,
15707                                needThisHandling, rethrowContentException,
15708                                typedArraysAreStructs=typedArraysAreStructs)
15709
15710    def getRvalDecl(self):
15711        return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
15712
15713    def getCall(self):
15714        if self.argCount > 0:
15715            args = "JS::HandleValueArray::subarray(argv, 0, argc)"
15716        else:
15717            args = "JS::HandleValueArray::empty()"
15718
15719        return fill(
15720            """
15721            $*{declCallable}
15722            $*{declThis}
15723            if (${callGuard}!JS::Call(cx, ${thisVal}, callable,
15724                          ${args}, &rval)) {
15725              aRv.NoteJSContextException(cx);
15726              return${errorReturn};
15727            }
15728            """,
15729            declCallable=self.getCallableDecl(),
15730            declThis=self.getThisDecl(),
15731            callGuard=self.getCallGuard(),
15732            thisVal=self.getThisVal(),
15733            args=args,
15734            errorReturn=self.getDefaultRetval())
15735
15736
15737class CallCallback(CallbackMethod):
15738    def __init__(self, callback, descriptorProvider):
15739        self.callback = callback
15740        CallbackMethod.__init__(self, callback.signatures()[0], "Call",
15741                                descriptorProvider, needThisHandling=True)
15742
15743    def getThisDecl(self):
15744        return ""
15745
15746    def getThisVal(self):
15747        return "aThisVal"
15748
15749    def getCallableDecl(self):
15750        return "JS::Rooted<JS::Value> callable(cx, JS::ObjectValue(*mCallback));\n"
15751
15752    def getPrettyName(self):
15753        return self.callback.identifier.name
15754
15755    def getCallGuard(self):
15756        if self.callback._treatNonObjectAsNull:
15757            return "JS::IsCallable(mCallback) && "
15758        return ""
15759
15760
15761class CallbackOperationBase(CallbackMethod):
15762    """
15763    Common class for implementing various callback operations.
15764    """
15765    def __init__(self, signature, jsName, nativeName, descriptor,
15766                 singleOperation, rethrowContentException=False,
15767                 typedArraysAreStructs=False):
15768        self.singleOperation = singleOperation
15769        self.methodName = descriptor.binaryNameFor(jsName)
15770        CallbackMethod.__init__(self, signature, nativeName, descriptor,
15771                                singleOperation, rethrowContentException,
15772                                typedArraysAreStructs=typedArraysAreStructs)
15773
15774    def getThisDecl(self):
15775        if not self.singleOperation:
15776            return "JS::Rooted<JS::Value> thisValue(cx, JS::ObjectValue(*mCallback));\n"
15777        # This relies on getCallableDecl declaring a boolean
15778        # isCallable in the case when we're a single-operation
15779        # interface.
15780        return dedent("""
15781            JS::Rooted<JS::Value> thisValue(cx, isCallable ? aThisVal.get()
15782                                                           : JS::ObjectValue(*mCallback));
15783            """)
15784
15785    def getThisVal(self):
15786        return "thisValue"
15787
15788    def getCallableDecl(self):
15789        getCallableFromProp = fill(
15790            """
15791            ${atomCacheName}* atomsCache = GetAtomCache<${atomCacheName}>(cx);
15792            if ((!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) ||
15793                !GetCallableProperty(cx, atomsCache->${methodAtomName}, &callable)) {
15794              aRv.Throw(NS_ERROR_UNEXPECTED);
15795              return${errorReturn};
15796            }
15797            """,
15798            methodAtomName=CGDictionary.makeIdName(self.methodName),
15799            atomCacheName=self.descriptorProvider.interface.identifier.name + "Atoms",
15800            errorReturn=self.getDefaultRetval())
15801        if not self.singleOperation:
15802            return 'JS::Rooted<JS::Value> callable(cx);\n' + getCallableFromProp
15803        return fill(
15804            """
15805            bool isCallable = JS::IsCallable(mCallback);
15806            JS::Rooted<JS::Value> callable(cx);
15807            if (isCallable) {
15808              callable = JS::ObjectValue(*mCallback);
15809            } else {
15810              $*{getCallableFromProp}
15811            }
15812            """,
15813            getCallableFromProp=getCallableFromProp)
15814
15815    def getCallGuard(self):
15816        return ""
15817
15818
15819class CallbackOperation(CallbackOperationBase):
15820    """
15821    Codegen actual WebIDL operations on callback interfaces.
15822    """
15823    def __init__(self, method, signature, descriptor, typedArraysAreStructs):
15824        self.ensureASCIIName(method)
15825        self.method = method
15826        jsName = method.identifier.name
15827        CallbackOperationBase.__init__(self, signature,
15828                                       jsName,
15829                                       MakeNativeName(descriptor.binaryNameFor(jsName)),
15830                                       descriptor, descriptor.interface.isSingleOperationInterface(),
15831                                       rethrowContentException=descriptor.interface.isJSImplemented(),
15832                                       typedArraysAreStructs=typedArraysAreStructs)
15833
15834    def getPrettyName(self):
15835        return "%s.%s" % (self.descriptorProvider.interface.identifier.name,
15836                          self.method.identifier.name)
15837
15838
15839class CallbackAccessor(CallbackMember):
15840    """
15841    Shared superclass for CallbackGetter and CallbackSetter.
15842    """
15843    def __init__(self, attr, sig, name, descriptor, typedArraysAreStructs):
15844        self.ensureASCIIName(attr)
15845        self.attrName = attr.identifier.name
15846        CallbackMember.__init__(self, sig, name, descriptor,
15847                                needThisHandling=False,
15848                                rethrowContentException=descriptor.interface.isJSImplemented(),
15849                                typedArraysAreStructs=typedArraysAreStructs)
15850
15851    def getPrettyName(self):
15852        return "%s.%s" % (self.descriptorProvider.interface.identifier.name,
15853                          self.attrName)
15854
15855
15856class CallbackGetter(CallbackAccessor):
15857    def __init__(self, attr, descriptor, typedArraysAreStructs):
15858        CallbackAccessor.__init__(self, attr,
15859                                  (attr.type, []),
15860                                  callbackGetterName(attr, descriptor),
15861                                  descriptor,
15862                                  typedArraysAreStructs)
15863
15864    def getRvalDecl(self):
15865        return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
15866
15867    def getCall(self):
15868        return fill(
15869            """
15870            JS::Rooted<JSObject *> callback(cx, mCallback);
15871            ${atomCacheName}* atomsCache = GetAtomCache<${atomCacheName}>(cx);
15872            if ((!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) ||
15873                !JS_GetPropertyById(cx, callback, atomsCache->${attrAtomName}, &rval)) {
15874              aRv.Throw(NS_ERROR_UNEXPECTED);
15875              return${errorReturn};
15876            }
15877            """,
15878            atomCacheName=self.descriptorProvider.interface.identifier.name + "Atoms",
15879            attrAtomName=CGDictionary.makeIdName(self.descriptorProvider.binaryNameFor(self.attrName)),
15880            errorReturn=self.getDefaultRetval())
15881
15882
15883class CallbackSetter(CallbackAccessor):
15884    def __init__(self, attr, descriptor, typedArraysAreStructs):
15885        CallbackAccessor.__init__(self, attr,
15886                                  (BuiltinTypes[IDLBuiltinType.Types.void],
15887                                   [FakeArgument(attr.type, attr)]),
15888                                  callbackSetterName(attr, descriptor),
15889                                  descriptor, typedArraysAreStructs)
15890
15891    def getRvalDecl(self):
15892        # We don't need an rval
15893        return ""
15894
15895    def getCall(self):
15896        return fill(
15897            """
15898            MOZ_ASSERT(argv.length() == 1);
15899            ${atomCacheName}* atomsCache = GetAtomCache<${atomCacheName}>(cx);
15900            if ((!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) ||
15901                !JS_SetPropertyById(cx, CallbackKnownNotGray(), atomsCache->${attrAtomName}, argv[0])) {
15902              aRv.Throw(NS_ERROR_UNEXPECTED);
15903              return${errorReturn};
15904            }
15905            """,
15906            atomCacheName=self.descriptorProvider.interface.identifier.name + "Atoms",
15907            attrAtomName=CGDictionary.makeIdName(self.descriptorProvider.binaryNameFor(self.attrName)),
15908            errorReturn=self.getDefaultRetval())
15909
15910    def getArgcDecl(self):
15911        return None
15912
15913
15914class CGJSImplInitOperation(CallbackOperationBase):
15915    """
15916    Codegen the __Init() method used to pass along constructor arguments for JS-implemented WebIDL.
15917    """
15918    def __init__(self, sig, descriptor):
15919        assert sig in descriptor.interface.ctor().signatures()
15920        CallbackOperationBase.__init__(self, (BuiltinTypes[IDLBuiltinType.Types.void], sig[1]),
15921                                       "__init", "__Init", descriptor,
15922                                       singleOperation=False,
15923                                       rethrowContentException=True,
15924                                       typedArraysAreStructs=True)
15925
15926    def getPrettyName(self):
15927        return "__init"
15928
15929
15930def getMaplikeOrSetlikeErrorReturn(helperImpl):
15931    """
15932    Generate return values based on whether a maplike or setlike generated
15933    method is an interface method (which returns bool) or a helper function
15934    (which uses ErrorResult).
15935    """
15936    if helperImpl:
15937        return dedent(
15938            """
15939            aRv.Throw(NS_ERROR_UNEXPECTED);
15940            return%s;
15941            """ % helperImpl.getDefaultRetval())
15942    return "return false;\n"
15943
15944
15945def getMaplikeOrSetlikeBackingObject(descriptor, maplikeOrSetlike, helperImpl=None):
15946    """
15947    Generate code to get/create a JS backing object for a maplike/setlike
15948    declaration from the declaration slot.
15949    """
15950    func_prefix = maplikeOrSetlike.maplikeOrSetlikeOrIterableType.title()
15951    ret = fill(
15952        """
15953        JS::Rooted<JSObject*> backingObj(cx);
15954        bool created = false;
15955        if (!Get${func_prefix}BackingObject(cx, obj, ${slot}, &backingObj, &created)) {
15956          $*{errorReturn}
15957        }
15958        if (created) {
15959          PreserveWrapper<${selfType}>(self);
15960        }
15961        """,
15962        slot=memberReservedSlot(maplikeOrSetlike, descriptor),
15963        func_prefix=func_prefix,
15964        errorReturn=getMaplikeOrSetlikeErrorReturn(helperImpl),
15965        selfType=descriptor.nativeType)
15966    return ret
15967
15968
15969def getMaplikeOrSetlikeSizeGetterBody(descriptor, attr):
15970    """
15971    Creates the body for the size getter method of maplike/setlike interfaces.
15972    """
15973    # We should only have one declaration attribute currently
15974    assert attr.identifier.name == "size"
15975    assert attr.isMaplikeOrSetlikeAttr()
15976    return fill(
15977        """
15978        $*{getBackingObj}
15979        uint32_t result = JS::${funcPrefix}Size(cx, backingObj);
15980        MOZ_ASSERT(!JS_IsExceptionPending(cx));
15981        args.rval().setNumber(result);
15982        return true;
15983        """,
15984        getBackingObj=getMaplikeOrSetlikeBackingObject(descriptor,
15985                                                       attr.maplikeOrSetlike),
15986        funcPrefix=attr.maplikeOrSetlike.prefix)
15987
15988
15989class CGMaplikeOrSetlikeMethodGenerator(CGThing):
15990    """
15991    Creates methods for maplike/setlike interfaces. It is expected that all
15992    methods will be have a maplike/setlike object attached. Unwrapping/wrapping
15993    will be taken care of by the usual method generation machinery in
15994    CGMethodCall/CGPerSignatureCall. Functionality is filled in here instead of
15995    using CGCallGenerator.
15996    """
15997    def __init__(self, descriptor, maplikeOrSetlike, methodName,
15998                 helperImpl=None):
15999        CGThing.__init__(self)
16000        # True if this will be the body of a C++ helper function.
16001        self.helperImpl = helperImpl
16002        self.descriptor = descriptor
16003        self.maplikeOrSetlike = maplikeOrSetlike
16004        self.cgRoot = CGList([])
16005        impl_method_name = methodName
16006        if impl_method_name[0] == "_":
16007            # double underscore means this is a js-implemented chrome only rw
16008            # function. Truncate the double underscore so calling the right
16009            # underlying JSAPI function still works.
16010            impl_method_name = impl_method_name[2:]
16011        self.cgRoot.append(CGGeneric(
16012            getMaplikeOrSetlikeBackingObject(self.descriptor,
16013                                             self.maplikeOrSetlike,
16014                                             self.helperImpl)))
16015        self.returnStmt = getMaplikeOrSetlikeErrorReturn(self.helperImpl)
16016
16017        # Generates required code for the method. Method descriptions included
16018        # in definitions below. Throw if we don't have a method to fill in what
16019        # we're looking for.
16020        try:
16021            methodGenerator = getattr(self, impl_method_name)
16022        except AttributeError:
16023            raise TypeError("Missing %s method definition '%s'" %
16024                            (self.maplikeOrSetlike.maplikeOrSetlikeType,
16025                             methodName))
16026        # Method generator returns tuple, containing:
16027        #
16028        # - a list of CGThings representing setup code for preparing to call
16029        #   the JS API function
16030        # - a list of arguments needed for the JS API function we're calling
16031        # - list of code CGThings needed for return value conversion.
16032        (setupCode, arguments, setResult) = methodGenerator()
16033
16034        # Create the actual method call, and then wrap it with the code to
16035        # return the value if needed.
16036        funcName = (self.maplikeOrSetlike.prefix +
16037                    MakeNativeName(impl_method_name))
16038        # Append the list of setup code CGThings
16039        self.cgRoot.append(CGList(setupCode))
16040        # Create the JS API call
16041        self.cgRoot.append(CGWrapper(
16042            CGGeneric(fill(
16043                """
16044                if (!JS::${funcName}(${args})) {
16045                  $*{errorReturn}
16046                }
16047                """,
16048                funcName=funcName,
16049                args=", ".join(["cx", "backingObj"] + arguments),
16050                errorReturn=self.returnStmt))))
16051        # Append result conversion
16052        self.cgRoot.append(CGList(setResult))
16053
16054    def mergeTuples(self, a, b):
16055        """
16056        Expecting to take 2 tuples were all elements are lists, append the lists in
16057        the second tuple to the lists in the first.
16058        """
16059        return tuple([x + y for x, y in zip(a, b)])
16060
16061    def appendArgConversion(self, name):
16062        """
16063        Generate code to convert arguments to JS::Values, so they can be
16064        passed into JSAPI functions.
16065        """
16066        return CGGeneric(fill(
16067            """
16068            JS::Rooted<JS::Value> ${name}Val(cx);
16069            if (!ToJSValue(cx, ${name}, &${name}Val)) {
16070              $*{errorReturn}
16071            }
16072            """,
16073            name=name,
16074            errorReturn=self.returnStmt))
16075
16076    def appendKeyArgConversion(self):
16077        """
16078        Generates the key argument for methods. Helper functions will use
16079        an AutoValueVector, while interface methods have seperate JS::Values.
16080        """
16081        if self.helperImpl:
16082            return ([], ["argv[0]"], [])
16083        return ([self.appendArgConversion("arg0")], ["arg0Val"], [])
16084
16085    def appendKeyAndValueArgConversion(self):
16086        """
16087        Generates arguments for methods that require a key and value. Helper
16088        functions will use an AutoValueVector, while interface methods have
16089        seperate JS::Values.
16090        """
16091        r = self.appendKeyArgConversion()
16092        if self.helperImpl:
16093            return self.mergeTuples(r, ([], ["argv[1]"], []))
16094        return self.mergeTuples(r, ([self.appendArgConversion("arg1")],
16095                                    ["arg1Val"],
16096                                    []))
16097
16098    def appendIteratorResult(self):
16099        """
16100        Generate code to output JSObject* return values, needed for functions that
16101        return iterators. Iterators cannot currently be wrapped via Xrays. If
16102        something that would return an iterator is called via Xray, fail early.
16103        """
16104        # TODO: Bug 1173651 - Remove check once bug 1023984 is fixed.
16105        code = CGGeneric(dedent(
16106            """
16107            // TODO (Bug 1173651): Xrays currently cannot wrap iterators. Change
16108            // after bug 1023984 is fixed.
16109            if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
16110              JS_ReportErrorASCII(cx, "Xray wrapping of iterators not supported.");
16111              return false;
16112            }
16113            JS::Rooted<JSObject*> result(cx);
16114            JS::Rooted<JS::Value> v(cx);
16115            """))
16116        arguments = "&v"
16117        setResult = CGGeneric(dedent(
16118            """
16119            result = &v.toObject();
16120            """))
16121        return ([code], [arguments], [setResult])
16122
16123    def appendSelfResult(self):
16124        """
16125        Generate code to return the interface object itself.
16126        """
16127        code = CGGeneric(dedent(
16128            """
16129            JS::Rooted<JSObject*> result(cx);
16130            """))
16131        setResult = CGGeneric(dedent(
16132            """
16133            result = obj;
16134            """))
16135        return ([code], [], [setResult])
16136
16137    def appendBoolResult(self):
16138        if self.helperImpl:
16139            return ([CGGeneric()], ["&aRetVal"], [])
16140        return ([CGGeneric("bool result;\n")], ["&result"], [])
16141
16142    def forEach(self):
16143        """
16144        void forEach(callback c, any thisval);
16145
16146        ForEach takes a callback, and a possible value to use as 'this'. The
16147        callback needs to take value, key, and the interface object
16148        implementing maplike/setlike. In order to make sure that the third arg
16149        is our interface object instead of the map/set backing object, we
16150        create a js function with the callback and original object in its
16151        storage slots, then use a helper function in BindingUtils to make sure
16152        the callback is called correctly.
16153        """
16154        assert(not self.helperImpl)
16155        code = [CGGeneric(dedent(
16156            """
16157            // Create a wrapper function.
16158            JSFunction* func = js::NewFunctionWithReserved(cx, ForEachHandler, 3, 0, nullptr);
16159            if (!func) {
16160              return false;
16161            }
16162            JS::Rooted<JSObject*> funcObj(cx, JS_GetFunctionObject(func));
16163            JS::Rooted<JS::Value> funcVal(cx, JS::ObjectValue(*funcObj));
16164            js::SetFunctionNativeReserved(funcObj, FOREACH_CALLBACK_SLOT,
16165                                          JS::ObjectValue(*arg0));
16166            js::SetFunctionNativeReserved(funcObj, FOREACH_MAPLIKEORSETLIKEOBJ_SLOT,
16167                                          JS::ObjectValue(*obj));
16168            """))]
16169        arguments = ["funcVal", "arg1"]
16170        return (code, arguments, [])
16171
16172    def set(self):
16173        """
16174        object set(key, value);
16175
16176        Maplike only function, takes key and sets value to it, returns
16177        interface object unless being called from a C++ helper.
16178        """
16179        assert self.maplikeOrSetlike.isMaplike()
16180        r = self.appendKeyAndValueArgConversion()
16181        if self.helperImpl:
16182            return r
16183        return self.mergeTuples(r, self.appendSelfResult())
16184
16185    def add(self):
16186        """
16187        object add(value);
16188
16189        Setlike only function, adds value to set, returns interface object
16190        unless being called from a C++ helper
16191        """
16192        assert self.maplikeOrSetlike.isSetlike()
16193        r = self.appendKeyArgConversion()
16194        if self.helperImpl:
16195            return r
16196        return self.mergeTuples(r, self.appendSelfResult())
16197
16198    def get(self):
16199        """
16200        type? get(key);
16201
16202        Retrieves a value from a backing object based on the key. Returns value
16203        if key is in backing object, undefined otherwise.
16204        """
16205        assert self.maplikeOrSetlike.isMaplike()
16206        r = self.appendKeyArgConversion()
16207        code = [CGGeneric(dedent(
16208            """
16209            JS::Rooted<JS::Value> result(cx);
16210            """))]
16211        arguments = ["&result"]
16212        return self.mergeTuples(r, (code, arguments, []))
16213
16214    def has(self):
16215        """
16216        bool has(key);
16217
16218        Check if an entry exists in the backing object. Returns true if value
16219        exists in backing object, false otherwise.
16220        """
16221        return self.mergeTuples(self.appendKeyArgConversion(),
16222                                self.appendBoolResult())
16223
16224    def keys(self):
16225        """
16226        object keys();
16227
16228        Returns new object iterator with all keys from backing object.
16229        """
16230        return self.appendIteratorResult()
16231
16232    def values(self):
16233        """
16234        object values();
16235
16236        Returns new object iterator with all values from backing object.
16237        """
16238        return self.appendIteratorResult()
16239
16240    def entries(self):
16241        """
16242        object entries();
16243
16244        Returns new object iterator with all keys and values from backing
16245        object. Keys will be null for set.
16246        """
16247        return self.appendIteratorResult()
16248
16249    def clear(self):
16250        """
16251        void clear();
16252
16253        Removes all entries from map/set.
16254        """
16255        return ([], [], [])
16256
16257    def delete(self):
16258        """
16259        bool delete(key);
16260
16261        Deletes an entry from the backing object. Returns true if value existed
16262        in backing object, false otherwise.
16263        """
16264        return self.mergeTuples(self.appendKeyArgConversion(),
16265                                self.appendBoolResult())
16266
16267    def define(self):
16268        return self.cgRoot.define()
16269
16270
16271class CGMaplikeOrSetlikeHelperFunctionGenerator(CallbackMember):
16272    """
16273    Generates code to allow C++ to perform operations on backing objects. Gets
16274    a context from the binding wrapper, turns arguments into JS::Values (via
16275    CallbackMember/CGNativeMember argument conversion), then uses
16276    CGMaplikeOrSetlikeMethodGenerator to generate the body.
16277
16278    """
16279
16280    class HelperFunction(CGAbstractMethod):
16281        """
16282        Generates context retrieval code and rooted JSObject for interface for
16283        CGMaplikeOrSetlikeMethodGenerator to use
16284        """
16285        def __init__(self, descriptor, name, args, code, needsBoolReturn=False):
16286            self.code = code
16287            CGAbstractMethod.__init__(self, descriptor, name,
16288                                      "bool" if needsBoolReturn else "void",
16289                                      args)
16290
16291        def definition_body(self):
16292            return self.code
16293
16294    def __init__(self, descriptor, maplikeOrSetlike, name, needsKeyArg=False,
16295                 needsValueArg=False, needsBoolReturn=False):
16296        args = []
16297        self.maplikeOrSetlike = maplikeOrSetlike
16298        self.needsBoolReturn = needsBoolReturn
16299        if needsKeyArg:
16300            args.append(FakeArgument(maplikeOrSetlike.keyType, None, 'aKey'))
16301        if needsValueArg:
16302            assert needsKeyArg
16303            args.append(FakeArgument(maplikeOrSetlike.valueType, None, 'aValue'))
16304        # Run CallbackMember init function to generate argument conversion code.
16305        # wrapScope is set to 'obj' when generating maplike or setlike helper
16306        # functions, as we don't have access to the CallbackPreserveColor
16307        # method.
16308        CallbackMember.__init__(self,
16309                                [BuiltinTypes[IDLBuiltinType.Types.void], args],
16310                                name, descriptor, False,
16311                                wrapScope='obj')
16312        # Wrap CallbackMember body code into a CGAbstractMethod to make
16313        # generation easier.
16314        self.implMethod = CGMaplikeOrSetlikeHelperFunctionGenerator.HelperFunction(
16315            descriptor, name, self.args, self.body, needsBoolReturn)
16316
16317    def getCallSetup(self):
16318        return dedent(
16319            """
16320            MOZ_ASSERT(self);
16321            AutoJSAPI jsapi;
16322            jsapi.Init();
16323            JSContext* cx = jsapi.cx();
16324            // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here because
16325            // all we want is to wrap into _some_ scope and then unwrap to find
16326            // the reflector, and wrapping has no side-effects.
16327            JSAutoCompartment tempCompartment(cx, binding_detail::UnprivilegedJunkScopeOrWorkerGlobal());
16328            JS::Rooted<JS::Value> v(cx);
16329            if(!ToJSValue(cx, self, &v)) {
16330              aRv.Throw(NS_ERROR_UNEXPECTED);
16331              return%s;
16332            }
16333            // This is a reflector, but due to trying to name things
16334            // similarly across method generators, it's called obj here.
16335            JS::Rooted<JSObject*> obj(cx);
16336            obj = js::UncheckedUnwrap(&v.toObject(), /* stopAtWindowProxy = */ false);
16337            JSAutoCompartment reflectorCompartment(cx, obj);
16338            """ % self.getDefaultRetval())
16339
16340    def getArgs(self, returnType, argList):
16341        # We don't need the context or the value. We'll generate those instead.
16342        args = CGNativeMember.getArgs(self, returnType, argList)
16343        # Prepend a pointer to the binding object onto the arguments
16344        return [Argument(self.descriptorProvider.nativeType + "*", "self")] + args
16345
16346    def getResultConversion(self):
16347        if self.needsBoolReturn:
16348            return "return aRetVal;\n"
16349        return "return;\n"
16350
16351    def getRvalDecl(self):
16352        if self.needsBoolReturn:
16353            return "bool aRetVal;\n"
16354        return ""
16355
16356    def getArgcDecl(self):
16357        # Don't need argc for anything.
16358        return None
16359
16360    def getDefaultRetval(self):
16361        if self.needsBoolReturn:
16362            return " false"
16363        return ""
16364
16365    def getCall(self):
16366        return CGMaplikeOrSetlikeMethodGenerator(self.descriptorProvider,
16367                                                 self.maplikeOrSetlike,
16368                                                 self.name.lower(),
16369                                                 helperImpl=self).define()
16370
16371    def getPrettyName(self):
16372        return self.name
16373
16374    def declare(self):
16375        return self.implMethod.declare()
16376
16377    def define(self):
16378        return self.implMethod.define()
16379
16380
16381class CGMaplikeOrSetlikeHelperGenerator(CGNamespace):
16382    """
16383    Declares and defines convenience methods for accessing backing objects on
16384    setlike/maplike interface. Generates function signatures, un/packs
16385    backing objects from slot, etc.
16386    """
16387    def __init__(self, descriptor, maplikeOrSetlike):
16388        self.descriptor = descriptor
16389        # Since iterables are folded in with maplike/setlike, make sure we've
16390        # got the right type here.
16391        assert maplikeOrSetlike.isMaplike() or maplikeOrSetlike.isSetlike()
16392        self.maplikeOrSetlike = maplikeOrSetlike
16393        self.namespace = "%sHelpers" % (self.maplikeOrSetlike.maplikeOrSetlikeOrIterableType.title())
16394        self.helpers = [
16395            CGMaplikeOrSetlikeHelperFunctionGenerator(descriptor,
16396                                                      maplikeOrSetlike,
16397                                                      "Clear"),
16398            CGMaplikeOrSetlikeHelperFunctionGenerator(descriptor,
16399                                                      maplikeOrSetlike,
16400                                                      "Delete",
16401                                                      needsKeyArg=True,
16402                                                      needsBoolReturn=True),
16403            CGMaplikeOrSetlikeHelperFunctionGenerator(descriptor,
16404                                                      maplikeOrSetlike,
16405                                                      "Has",
16406                                                      needsKeyArg=True,
16407                                                      needsBoolReturn=True)]
16408        if self.maplikeOrSetlike.isMaplike():
16409            self.helpers.append(
16410                CGMaplikeOrSetlikeHelperFunctionGenerator(descriptor,
16411                                                          maplikeOrSetlike,
16412                                                          "Set",
16413                                                          needsKeyArg=True,
16414                                                          needsValueArg=True))
16415        else:
16416            assert(self.maplikeOrSetlike.isSetlike())
16417            self.helpers.append(
16418                CGMaplikeOrSetlikeHelperFunctionGenerator(descriptor,
16419                                                          maplikeOrSetlike,
16420                                                          "Add",
16421                                                          needsKeyArg=True))
16422        CGNamespace.__init__(self, self.namespace, CGList(self.helpers))
16423
16424
16425class CGIterableMethodGenerator(CGGeneric):
16426    """
16427    Creates methods for iterable interfaces. Unwrapping/wrapping
16428    will be taken care of by the usual method generation machinery in
16429    CGMethodCall/CGPerSignatureCall. Functionality is filled in here instead of
16430    using CGCallGenerator.
16431    """
16432    def __init__(self, descriptor, iterable, methodName):
16433        if methodName == "forEach":
16434            CGGeneric.__init__(self, fill(
16435                """
16436                if (!JS::IsCallable(arg0)) {
16437                  ThrowErrorMessage(cx, MSG_NOT_CALLABLE, "Argument 1 of ${ifaceName}.forEach");
16438                  return false;
16439                }
16440                JS::AutoValueArray<3> callArgs(cx);
16441                callArgs[2].setObject(*obj);
16442                JS::Rooted<JS::Value> ignoredReturnVal(cx);
16443                for (size_t i = 0; i < self->GetIterableLength(); ++i) {
16444                  if (!ToJSValue(cx, self->GetValueAtIndex(i), callArgs[0])) {
16445                    return false;
16446                  }
16447                  if (!ToJSValue(cx, self->GetKeyAtIndex(i), callArgs[1])) {
16448                    return false;
16449                  }
16450                  if (!JS::Call(cx, arg1, arg0, JS::HandleValueArray(callArgs),
16451                                &ignoredReturnVal)) {
16452                    return false;
16453                  }
16454                }
16455                """,
16456                ifaceName=descriptor.interface.identifier.name))
16457            return
16458        CGGeneric.__init__(self, fill(
16459            """
16460            typedef ${iterClass} itrType;
16461            RefPtr<itrType> result(new itrType(self,
16462                                                 itrType::IterableIteratorType::${itrMethod},
16463                                                 &${ifaceName}IteratorBinding::Wrap));
16464            """,
16465            iterClass=iteratorNativeType(descriptor),
16466            ifaceName=descriptor.interface.identifier.name,
16467            itrMethod=methodName.title()))
16468
16469
16470class GlobalGenRoots():
16471    """
16472    Roots for global codegen.
16473
16474    To generate code, call the method associated with the target, and then
16475    call the appropriate define/declare method.
16476    """
16477
16478    @staticmethod
16479    def GeneratedAtomList(config):
16480        # Atom enum
16481        dictionaries = config.dictionaries
16482
16483        structs = []
16484
16485        def memberToAtomCacheMember(binaryNameFor, m):
16486            binaryMemberName = binaryNameFor(m.identifier.name)
16487            return ClassMember(CGDictionary.makeIdName(binaryMemberName),
16488                               "PinnedStringId", visibility="public")
16489
16490        def buildAtomCacheStructure(idlobj, binaryNameFor, members):
16491            classMembers = [memberToAtomCacheMember(binaryNameFor, m)
16492                            for m in members]
16493            structName = idlobj.identifier.name + "Atoms"
16494            return (structName,
16495                    CGWrapper(CGClass(structName,
16496                                      bases=None,
16497                                      isStruct=True,
16498                                      members=classMembers), post='\n'))
16499
16500        for dict in dictionaries:
16501            if len(dict.members) == 0:
16502                continue
16503
16504            structs.append(buildAtomCacheStructure(dict, lambda x: x, dict.members))
16505
16506        for d in (config.getDescriptors(isJSImplemented=True) +
16507                  config.getDescriptors(isCallback=True)):
16508            members = [m for m in d.interface.members if m.isAttr() or m.isMethod()]
16509            if d.interface.isJSImplemented() and d.interface.ctor():
16510                # We'll have an __init() method.
16511                members.append(FakeMember('__init'))
16512            if len(members) == 0:
16513                continue
16514
16515            structs.append(buildAtomCacheStructure(d.interface,
16516                                                   lambda x: d.binaryNameFor(x),
16517                                                   members))
16518
16519        structs.sort()
16520        generatedStructs = [struct for structName, struct in structs]
16521        structNames = [structName for structName, struct in structs]
16522
16523        mainStruct = CGWrapper(CGClass("PerThreadAtomCache",
16524                                       bases=[ClassBase(structName) for structName in structNames],
16525                                       isStruct=True),
16526                               post='\n')
16527
16528        structs = CGList(generatedStructs + [mainStruct])
16529
16530        # Wrap all of that in our namespaces.
16531        curr = CGNamespace.build(['mozilla', 'dom'],
16532                                 CGWrapper(structs, pre='\n'))
16533        curr = CGWrapper(curr, post='\n')
16534
16535        # Add include statement for PinnedStringId.
16536        declareIncludes = ['mozilla/dom/BindingUtils.h']
16537        curr = CGHeaders([], [], [], [], declareIncludes, [], 'GeneratedAtomList',
16538                         curr)
16539
16540        # Add include guards.
16541        curr = CGIncludeGuard('GeneratedAtomList', curr)
16542
16543        # Add the auto-generated comment.
16544        curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
16545
16546        # Done.
16547        return curr
16548
16549    @staticmethod
16550    def GeneratedEventList(config):
16551        eventList = CGList([])
16552        for generatedEvent in config.generatedEvents:
16553            eventList.append(CGGeneric(declare=("GENERATED_EVENT(%s)\n" % generatedEvent)))
16554        return eventList
16555
16556    @staticmethod
16557    def PrototypeList(config):
16558
16559        # Prototype ID enum.
16560        descriptorsWithPrototype = config.getDescriptors(hasInterfacePrototypeObject=True)
16561        protos = [d.name for d in descriptorsWithPrototype]
16562        idEnum = CGNamespacedEnum('id', 'ID', ['_ID_Start'] + protos,
16563                                  [0, '_ID_Start'])
16564        idEnum = CGList([idEnum])
16565
16566        def fieldSizeAssert(amount, jitInfoField, message):
16567            maxFieldValue = "(uint64_t(1) << (sizeof(((JSJitInfo*)nullptr)->%s) * 8))" % jitInfoField
16568            return CGGeneric(declare="static_assert(%s < %s, \"%s\");\n\n"
16569                             % (amount, maxFieldValue, message))
16570
16571        idEnum.append(fieldSizeAssert("id::_ID_Count", "protoID",
16572                                      "Too many prototypes!"))
16573
16574        # Wrap all of that in our namespaces.
16575        idEnum = CGNamespace.build(['mozilla', 'dom', 'prototypes'],
16576                                   CGWrapper(idEnum, pre='\n'))
16577        idEnum = CGWrapper(idEnum, post='\n')
16578
16579        curr = CGList([CGGeneric(define="#include <stdint.h>\n\n"),
16580                       idEnum])
16581
16582        # Let things know the maximum length of the prototype chain.
16583        maxMacroName = "MAX_PROTOTYPE_CHAIN_LENGTH"
16584        maxMacro = CGGeneric(declare="#define " + maxMacroName + " " + str(config.maxProtoChainLength))
16585        curr.append(CGWrapper(maxMacro, post='\n\n'))
16586        curr.append(fieldSizeAssert(maxMacroName, "depth",
16587                                    "Some inheritance chain is too long!"))
16588
16589        # Constructor ID enum.
16590        constructors = [d.name for d in config.getDescriptors(hasInterfaceObject=True)]
16591        idEnum = CGNamespacedEnum('id', 'ID', ['_ID_Start'] + constructors,
16592                                  ['prototypes::id::_ID_Count', '_ID_Start'])
16593
16594        # Wrap all of that in our namespaces.
16595        idEnum = CGNamespace.build(['mozilla', 'dom', 'constructors'],
16596                                   CGWrapper(idEnum, pre='\n'))
16597        idEnum = CGWrapper(idEnum, post='\n')
16598
16599        curr.append(idEnum)
16600
16601        # Named properties object enum.
16602        namedPropertiesObjects = [d.name for d in config.getDescriptors(hasNamedPropertiesObject=True)]
16603        idEnum = CGNamespacedEnum('id', 'ID', ['_ID_Start'] + namedPropertiesObjects,
16604                                  ['constructors::id::_ID_Count', '_ID_Start'])
16605
16606        # Wrap all of that in our namespaces.
16607        idEnum = CGNamespace.build(['mozilla', 'dom', 'namedpropertiesobjects'],
16608                                   CGWrapper(idEnum, pre='\n'))
16609        idEnum = CGWrapper(idEnum, post='\n')
16610
16611        curr.append(idEnum)
16612
16613        traitsDecls = [CGGeneric(declare=dedent("""
16614            template <prototypes::ID PrototypeID>
16615            struct PrototypeTraits;
16616            """))]
16617        traitsDecls.extend(CGPrototypeTraitsClass(d) for d in descriptorsWithPrototype)
16618
16619        ifaceNamesWithProto = [d.interface.identifier.name
16620                               for d in descriptorsWithPrototype]
16621        traitsDecls.append(CGStringTable("NamesOfInterfacesWithProtos",
16622                                         ifaceNamesWithProto))
16623
16624        traitsDecl = CGNamespace.build(['mozilla', 'dom'],
16625                                       CGList(traitsDecls))
16626
16627        curr.append(traitsDecl)
16628
16629        # Add include guards.
16630        curr = CGIncludeGuard('PrototypeList', curr)
16631
16632        # Add the auto-generated comment.
16633        curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
16634
16635        # Done.
16636        return curr
16637
16638    @staticmethod
16639    def RegisterBindings(config):
16640
16641        curr = CGList([CGGlobalNamesString(config), CGRegisterGlobalNames(config)])
16642
16643        # Wrap all of that in our namespaces.
16644        curr = CGNamespace.build(['mozilla', 'dom'],
16645                                 CGWrapper(curr, post='\n'))
16646        curr = CGWrapper(curr, post='\n')
16647
16648        # Add the includes
16649        defineIncludes = [CGHeaders.getDeclarationFilename(desc.interface)
16650                          for desc in config.getDescriptors(hasInterfaceObject=True,
16651                                                            isExposedInWindow=True,
16652                                                            register=True)]
16653        defineIncludes.append('mozilla/dom/WebIDLGlobalNameHash.h')
16654        defineIncludes.extend([CGHeaders.getDeclarationFilename(desc.interface)
16655                               for desc in config.getDescriptors(isNavigatorProperty=True,
16656                                                                 register=True)])
16657        curr = CGHeaders([], [], [], [], [], defineIncludes, 'RegisterBindings',
16658                         curr)
16659
16660        # Add include guards.
16661        curr = CGIncludeGuard('RegisterBindings', curr)
16662
16663        # Done.
16664        return curr
16665
16666    @staticmethod
16667    def RegisterWorkerBindings(config):
16668
16669        curr = CGRegisterWorkerBindings(config)
16670
16671        # Wrap all of that in our namespaces.
16672        curr = CGNamespace.build(['mozilla', 'dom'],
16673                                 CGWrapper(curr, post='\n'))
16674        curr = CGWrapper(curr, post='\n')
16675
16676        # Add the includes
16677        defineIncludes = [CGHeaders.getDeclarationFilename(desc.interface)
16678                          for desc in config.getDescriptors(hasInterfaceObject=True,
16679                                                            register=True,
16680                                                            isExposedInAnyWorker=True)]
16681
16682        curr = CGHeaders([], [], [], [], [], defineIncludes,
16683                         'RegisterWorkerBindings', curr)
16684
16685        # Add include guards.
16686        curr = CGIncludeGuard('RegisterWorkerBindings', curr)
16687
16688        # Done.
16689        return curr
16690
16691    @staticmethod
16692    def RegisterWorkerDebuggerBindings(config):
16693
16694        curr = CGRegisterWorkerDebuggerBindings(config)
16695
16696        # Wrap all of that in our namespaces.
16697        curr = CGNamespace.build(['mozilla', 'dom'],
16698                                 CGWrapper(curr, post='\n'))
16699        curr = CGWrapper(curr, post='\n')
16700
16701        # Add the includes
16702        defineIncludes = [CGHeaders.getDeclarationFilename(desc.interface)
16703                          for desc in config.getDescriptors(hasInterfaceObject=True,
16704                                                            register=True,
16705                                                            isExposedInWorkerDebugger=True)]
16706
16707        curr = CGHeaders([], [], [], [], [], defineIncludes,
16708                         'RegisterWorkerDebuggerBindings', curr)
16709
16710        # Add include guards.
16711        curr = CGIncludeGuard('RegisterWorkerDebuggerBindings', curr)
16712
16713        # Done.
16714        return curr
16715
16716    @staticmethod
16717    def RegisterWorkletBindings(config):
16718
16719        curr = CGRegisterWorkletBindings(config)
16720
16721        # Wrap all of that in our namespaces.
16722        curr = CGNamespace.build(['mozilla', 'dom'],
16723                                 CGWrapper(curr, post='\n'))
16724        curr = CGWrapper(curr, post='\n')
16725
16726        # Add the includes
16727        defineIncludes = [CGHeaders.getDeclarationFilename(desc.interface)
16728                          for desc in config.getDescriptors(hasInterfaceObject=True,
16729                                                            register=True,
16730                                                            isExposedInAnyWorklet=True)]
16731
16732        curr = CGHeaders([], [], [], [], [], defineIncludes,
16733                         'RegisterWorkletBindings', curr)
16734
16735        # Add include guards.
16736        curr = CGIncludeGuard('RegisterWorkletBindings', curr)
16737
16738        # Done.
16739        return curr
16740
16741    @staticmethod
16742    def ResolveSystemBinding(config):
16743
16744        curr = CGResolveSystemBinding(config)
16745
16746        # Wrap all of that in our namespaces.
16747        curr = CGNamespace.build(['mozilla', 'dom'],
16748                                 CGWrapper(curr, post='\n'))
16749        curr = CGWrapper(curr, post='\n')
16750
16751        # Add the includes
16752        defineIncludes = [CGHeaders.getDeclarationFilename(desc.interface)
16753                          for desc in config.getDescriptors(hasInterfaceObject=True,
16754                                                            register=True,
16755                                                            isExposedInSystemGlobals=True)]
16756        defineIncludes.append("nsThreadUtils.h")  # For NS_IsMainThread
16757        defineIncludes.append("js/Id.h")  # For jsid
16758        defineIncludes.append("mozilla/dom/BindingUtils.h")  # AtomizeAndPinJSString
16759
16760        curr = CGHeaders([], [], [], [], [], defineIncludes,
16761                         'ResolveSystemBinding', curr)
16762
16763        # Add include guards.
16764        curr = CGIncludeGuard('ResolveSystemBinding', curr)
16765
16766        # Done.
16767        return curr
16768
16769    @staticmethod
16770    def UnionTypes(config):
16771        unionTypes = UnionsForFile(config, None)
16772        (includes, implincludes, declarations,
16773         traverseMethods, unlinkMethods,
16774         unionStructs) = UnionTypes(unionTypes, config)
16775
16776        unions = CGList(traverseMethods +
16777                        unlinkMethods +
16778                        [CGUnionStruct(t, config) for t in unionStructs] +
16779                        [CGUnionStruct(t, config, True) for t in unionStructs],
16780                        "\n")
16781
16782        includes.add("mozilla/OwningNonNull.h")
16783        includes.add("mozilla/dom/UnionMember.h")
16784        includes.add("mozilla/dom/BindingDeclarations.h")
16785        # BindingUtils.h is only needed for SetToObject.
16786        # If it stops being inlined or stops calling CallerSubsumes
16787        # both this bit and the bit in CGBindingRoot can be removed.
16788        includes.add("mozilla/dom/BindingUtils.h")
16789        implincludes.add("mozilla/dom/PrimitiveConversions.h")
16790
16791        # Wrap all of that in our namespaces.
16792        curr = CGNamespace.build(['mozilla', 'dom'], unions)
16793
16794        curr = CGWrapper(curr, post='\n')
16795
16796        builder = ForwardDeclarationBuilder()
16797        for className, isStruct in declarations:
16798            builder.add(className, isStruct=isStruct)
16799
16800        curr = CGList([builder.build(), curr], "\n")
16801
16802        curr = CGHeaders([], [], [], [], includes, implincludes, 'UnionTypes',
16803                         curr)
16804
16805        # Add include guards.
16806        curr = CGIncludeGuard('UnionTypes', curr)
16807
16808        # Done.
16809        return curr
16810
16811    @staticmethod
16812    def UnionConversions(config):
16813        unionTypes = []
16814        for l in config.unionsPerFilename.itervalues():
16815            unionTypes.extend(l)
16816        unionTypes.sort(key=lambda u: u.name)
16817        headers, unions = UnionConversions(unionTypes,
16818                                           config)
16819
16820        # Wrap all of that in our namespaces.
16821        curr = CGNamespace.build(['mozilla', 'dom'], unions)
16822
16823        curr = CGWrapper(curr, post='\n')
16824
16825        headers.update(["nsDebug.h", "mozilla/dom/UnionTypes.h"])
16826        curr = CGHeaders([], [], [], [], headers, [], 'UnionConversions', curr)
16827
16828        # Add include guards.
16829        curr = CGIncludeGuard('UnionConversions', curr)
16830
16831        # Done.
16832        return curr
16833
16834
16835# Code generator for simple events
16836class CGEventGetter(CGNativeMember):
16837    def __init__(self, descriptor, attr):
16838        ea = descriptor.getExtendedAttributes(attr, getter=True)
16839        CGNativeMember.__init__(self, descriptor, attr,
16840                                CGSpecializedGetter.makeNativeName(descriptor,
16841                                                                   attr),
16842                                (attr.type, []),
16843                                ea,
16844                                resultNotAddRefed=not attr.type.isSequence())
16845        self.body = self.getMethodBody()
16846
16847    def getArgs(self, returnType, argList):
16848        if 'infallible' not in self.extendedAttrs:
16849            raise TypeError("Event code generator does not support [Throws]!")
16850        if not self.member.isAttr():
16851            raise TypeError("Event code generator does not support methods")
16852        if self.member.isStatic():
16853            raise TypeError("Event code generators does not support static attributes")
16854        return CGNativeMember.getArgs(self, returnType, argList)
16855
16856    def getMethodBody(self):
16857        type = self.member.type
16858        memberName = CGDictionary.makeMemberName(self.member.identifier.name)
16859        if (type.isPrimitive() and type.tag() in builtinNames) or type.isEnum() or type.isGeckoInterface():
16860            return "return " + memberName + ";\n"
16861        if type.isDOMString() or type.isByteString() or type.isUSVString():
16862            return "aRetVal = " + memberName + ";\n"
16863        if type.isSpiderMonkeyInterface() or type.isObject():
16864            return fill(
16865                """
16866                if (${memberName}) {
16867                  JS::ExposeObjectToActiveJS(${memberName});
16868                }
16869                aRetVal.set(${memberName});
16870                return;
16871                """,
16872                memberName=memberName)
16873        if type.isAny():
16874            return fill(
16875                """
16876                ${selfName}(aRetVal);
16877                """,
16878                selfName=self.name)
16879        if type.isUnion():
16880            return "aRetVal = " + memberName + ";\n"
16881        if type.isSequence():
16882            return "aRetVal = " + memberName + ";\n"
16883        raise TypeError("Event code generator does not support this type!")
16884
16885    def declare(self, cgClass):
16886        if getattr(self.member, "originatingInterface",
16887                   cgClass.descriptor.interface) != cgClass.descriptor.interface:
16888            return ""
16889        return CGNativeMember.declare(self, cgClass)
16890
16891    def define(self, cgClass):
16892        if getattr(self.member, "originatingInterface",
16893                   cgClass.descriptor.interface) != cgClass.descriptor.interface:
16894            return ""
16895        return CGNativeMember.define(self, cgClass)
16896
16897
16898class CGEventSetter(CGNativeMember):
16899    def __init__(self):
16900        raise TypeError("Event code generator does not support setters!")
16901
16902
16903class CGEventMethod(CGNativeMember):
16904    def __init__(self, descriptor, method, signature, isConstructor, breakAfter=True):
16905        self.isInit = False
16906
16907        CGNativeMember.__init__(self, descriptor, method,
16908                                CGSpecializedMethod.makeNativeName(descriptor,
16909                                                                   method),
16910                                signature,
16911                                descriptor.getExtendedAttributes(method),
16912                                breakAfter=breakAfter,
16913                                variadicIsSequence=True)
16914        self.originalArgs = list(self.args)
16915
16916        iface = descriptor.interface
16917        allowed = isConstructor
16918        if not allowed and iface.getExtendedAttribute("LegacyEventInit"):
16919            # Allow it, only if it fits the initFooEvent profile exactly
16920            # We could check the arg types but it's not worth the effort.
16921            if (method.identifier.name == "init" + iface.identifier.name and
16922                signature[1][0].type.isDOMString() and
16923                signature[1][1].type.isBoolean() and
16924                signature[1][2].type.isBoolean() and
16925                # -3 on the left to ignore the type, bubbles, and cancelable parameters
16926                # -1 on the right to ignore the .trusted property which bleeds through
16927                # here because it is [Unforgeable].
16928                len(signature[1]) - 3 == len(filter(lambda x: x.isAttr(), iface.members)) - 1):
16929                allowed = True
16930                self.isInit = True
16931
16932        if not allowed:
16933            raise TypeError("Event code generator does not support methods!")
16934
16935    def getArgs(self, returnType, argList):
16936        args = [self.getArg(arg) for arg in argList]
16937        return args
16938
16939    def getArg(self, arg):
16940        decl, ref = self.getArgType(arg.type,
16941                                    arg.canHaveMissingValue(),
16942                                    "Variadic" if arg.variadic else False)
16943        if ref:
16944            decl = CGWrapper(decl, pre="const ", post="&")
16945
16946        name = arg.identifier.name
16947        name = "a" + name[0].upper() + name[1:]
16948        return Argument(decl.define(), name)
16949
16950    def declare(self, cgClass):
16951        if self.isInit:
16952            constructorForNativeCaller = ""
16953        else:
16954            self.args = list(self.originalArgs)
16955            self.args.insert(0, Argument("mozilla::dom::EventTarget*", "aOwner"))
16956            constructorForNativeCaller = CGNativeMember.declare(self, cgClass)
16957
16958        self.args = list(self.originalArgs)
16959        if needCx(None, self.arguments(), [], considerTypes=True, static=True):
16960            self.args.insert(0, Argument("JSContext*", "aCx"))
16961        if not self.isInit:
16962            self.args.insert(0, Argument("const GlobalObject&", "aGlobal"))
16963            self.args.append(Argument('ErrorResult&', 'aRv'))
16964        return constructorForNativeCaller + CGNativeMember.declare(self, cgClass)
16965
16966    def defineInit(self, cgClass):
16967        iface = self.descriptorProvider.interface
16968        members = ""
16969        while iface.identifier.name != "Event":
16970            i = 3  # Skip the boilerplate args: type, bubble,s cancelable.
16971            for m in iface.members:
16972                if m.isAttr():
16973                    # We need to initialize all the member variables that do
16974                    # not come from Event.
16975                    if getattr(m, "originatingInterface",
16976                               iface).identifier.name == "Event":
16977                        continue
16978                    name = CGDictionary.makeMemberName(m.identifier.name)
16979                    members += "%s = %s;\n" % (name, self.args[i].name)
16980                    i += 1
16981            iface = iface.parent
16982
16983        self.body = fill(
16984            """
16985            InitEvent(${typeArg}, ${bubblesArg}, ${cancelableArg});
16986            ${members}
16987            """,
16988            typeArg=self.args[0].name,
16989            bubblesArg=self.args[1].name,
16990            cancelableArg=self.args[2].name,
16991            members=members)
16992
16993        return CGNativeMember.define(self, cgClass)
16994
16995    def define(self, cgClass):
16996        self.args = list(self.originalArgs)
16997        if self.isInit:
16998            return self.defineInit(cgClass)
16999        members = ""
17000        holdJS = ""
17001        iface = self.descriptorProvider.interface
17002        while iface.identifier.name != "Event":
17003            for m in self.descriptorProvider.getDescriptor(iface.identifier.name).interface.members:
17004                if m.isAttr():
17005                    # We initialize all the other member variables in the
17006                    # Constructor except those ones coming from the Event.
17007                    if getattr(m, "originatingInterface",
17008                               cgClass.descriptor.interface).identifier.name == "Event":
17009                        continue
17010                    name = CGDictionary.makeMemberName(m.identifier.name)
17011                    if m.type.isSequence():
17012                        # For sequences we may not be able to do a simple
17013                        # assignment because the underlying types may not match.
17014                        # For example, the argument can be a
17015                        # Sequence<OwningNonNull<SomeInterface>> while our
17016                        # member is an nsTArray<RefPtr<SomeInterface>>.  So
17017                        # use AppendElements, which is actually a template on
17018                        # the incoming type on nsTArray and does the right thing
17019                        # for this case.
17020                        target = name
17021                        source = "%s.%s" % (self.args[1].name, name)
17022                        sequenceCopy = "e->%s.AppendElements(%s);\n"
17023                        if m.type.nullable():
17024                            sequenceCopy = CGIfWrapper(
17025                                CGGeneric(sequenceCopy),
17026                                "!%s.IsNull()" % source).define()
17027                            target += ".SetValue()"
17028                            source += ".Value()"
17029                        members += sequenceCopy % (target, source)
17030                    elif m.type.isSpiderMonkeyInterface():
17031                        srcname = "%s.%s" % (self.args[1].name, name)
17032                        if m.type.nullable():
17033                            members += fill(
17034                                """
17035                                if (${srcname}.IsNull()) {
17036                                  e->${varname} = nullptr;
17037                                } else {
17038                                  e->${varname} = ${srcname}.Value().Obj();
17039                                }
17040                                """,
17041                                varname=name,
17042                                srcname=srcname)
17043                        else:
17044                            members += fill(
17045                                """
17046                                e->${varname}.set(${srcname}.Obj());
17047                                """,
17048                                varname=name, srcname=srcname)
17049                    else:
17050                        members += "e->%s = %s.%s;\n" % (name, self.args[1].name, name)
17051                    if m.type.isAny() or m.type.isObject() or m.type.isSpiderMonkeyInterface():
17052                        holdJS = "mozilla::HoldJSObjects(e.get());\n"
17053            iface = iface.parent
17054
17055        self.body = fill(
17056            """
17057            RefPtr<${nativeType}> e = new ${nativeType}(aOwner);
17058            bool trusted = e->Init(aOwner);
17059            e->InitEvent(${eventType}, ${eventInit}.mBubbles, ${eventInit}.mCancelable);
17060            $*{members}
17061            e->SetTrusted(trusted);
17062            e->SetComposed(${eventInit}.mComposed);
17063            $*{holdJS}
17064            return e.forget();
17065            """,
17066            nativeType=self.descriptorProvider.nativeType.split('::')[-1],
17067            eventType=self.args[0].name,
17068            eventInit=self.args[1].name,
17069            members=members,
17070            holdJS=holdJS)
17071
17072        self.args.insert(0, Argument("mozilla::dom::EventTarget*", "aOwner"))
17073        constructorForNativeCaller = CGNativeMember.define(self, cgClass) + "\n"
17074        self.args = list(self.originalArgs)
17075        self.body = fill(
17076            """
17077            nsCOMPtr<mozilla::dom::EventTarget> owner = do_QueryInterface(aGlobal.GetAsSupports());
17078            return Constructor(owner, ${arg0}, ${arg1});
17079            """,
17080            arg0=self.args[0].name,
17081            arg1=self.args[1].name)
17082        if needCx(None, self.arguments(), [], considerTypes=True, static=True):
17083            self.args.insert(0, Argument("JSContext*", "aCx"))
17084        self.args.insert(0, Argument("const GlobalObject&", "aGlobal"))
17085        self.args.append(Argument('ErrorResult&', 'aRv'))
17086        return constructorForNativeCaller + CGNativeMember.define(self, cgClass)
17087
17088
17089class CGEventClass(CGBindingImplClass):
17090    """
17091    Codegen for the actual Event class implementation for this descriptor
17092    """
17093    def __init__(self, descriptor):
17094        CGBindingImplClass.__init__(self, descriptor, CGEventMethod, CGEventGetter, CGEventSetter, False, "WrapObjectInternal")
17095        members = []
17096        extraMethods = []
17097        for m in descriptor.interface.members:
17098            if m.isAttr():
17099                if m.type.isAny():
17100                    # Add a getter that doesn't need a JSContext.  Note that we
17101                    # don't need to do this if our originating interface is not
17102                    # the descriptor's interface, because in that case we
17103                    # wouldn't generate the getter that _does_ need a JSContext
17104                    # either.
17105                    extraMethods.append(
17106                        ClassMethod(
17107                            CGSpecializedGetter.makeNativeName(descriptor, m),
17108                            "void",
17109                            [Argument("JS::MutableHandle<JS::Value>",
17110                                      "aRetVal")],
17111                            const=True,
17112                            body=fill(
17113                                """
17114                                JS::ExposeValueToActiveJS(${memberName});
17115                                aRetVal.set(${memberName});
17116                                """,
17117                                memberName=CGDictionary.makeMemberName(m.identifier.name))))
17118                if getattr(m, "originatingInterface",
17119                           descriptor.interface) != descriptor.interface:
17120                    continue
17121                nativeType = self.getNativeTypeForIDLType(m.type).define()
17122                members.append(ClassMember(CGDictionary.makeMemberName(m.identifier.name),
17123                               nativeType,
17124                               visibility="private",
17125                               body="body"))
17126
17127        parent = self.descriptor.interface.parent
17128        self.parentType = self.descriptor.getDescriptor(parent.identifier.name).nativeType.split('::')[-1]
17129        baseDeclarations = fill(
17130            """
17131            public:
17132              NS_DECL_ISUPPORTS_INHERITED
17133              NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(${nativeType}, ${parentType})
17134            protected:
17135              virtual ~${nativeType}();
17136              explicit ${nativeType}(mozilla::dom::EventTarget* aOwner);
17137
17138            """,
17139            nativeType=self.descriptor.nativeType.split('::')[-1],
17140            parentType=self.parentType)
17141
17142        className = descriptor.nativeType.split('::')[-1]
17143        asConcreteTypeMethod = ClassMethod("As%s" % className,
17144                                           "%s*" % className,
17145                                           [],
17146                                           virtual=True,
17147                                           body="return this;\n",
17148                                           breakAfterReturnDecl=" ",
17149                                           override=True)
17150        extraMethods.append(asConcreteTypeMethod)
17151
17152        CGClass.__init__(self, className,
17153                         bases=[ClassBase(self.parentType)],
17154                         methods=extraMethods+self.methodDecls,
17155                         members=members,
17156                         extradeclarations=baseDeclarations)
17157
17158    def getWrapObjectBody(self):
17159        return "return %sBinding::Wrap(aCx, this, aGivenProto);\n" % self.descriptor.name
17160
17161    def implTraverse(self):
17162        retVal = ""
17163        for m in self.descriptor.interface.members:
17164            # Unroll the type so we pick up sequences of interfaces too.
17165            if m.isAttr() and idlTypeNeedsCycleCollection(m.type):
17166                retVal += ("  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(" +
17167                           CGDictionary.makeMemberName(m.identifier.name) +
17168                           ")\n")
17169        return retVal
17170
17171    def implUnlink(self):
17172        retVal = ""
17173        for m in self.descriptor.interface.members:
17174            if m.isAttr():
17175                name = CGDictionary.makeMemberName(m.identifier.name)
17176                # Unroll the type so we pick up sequences of interfaces too.
17177                if idlTypeNeedsCycleCollection(m.type):
17178                    retVal += "  NS_IMPL_CYCLE_COLLECTION_UNLINK(" + name + ")\n"
17179                elif m.type.isAny():
17180                    retVal += "  tmp->" + name + ".setUndefined();\n"
17181                elif m.type.isObject() or m.type.isSpiderMonkeyInterface():
17182                    retVal += "  tmp->" + name + " = nullptr;\n"
17183        return retVal
17184
17185    def implTrace(self):
17186        retVal = ""
17187        for m in self.descriptor.interface.members:
17188            if m.isAttr():
17189                name = CGDictionary.makeMemberName(m.identifier.name)
17190                if m.type.isAny() or m.type.isObject() or m.type.isSpiderMonkeyInterface():
17191                    retVal += "  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(" + name + ")\n"
17192                elif typeNeedsRooting(m.type):
17193                    raise TypeError("Need to implement tracing for event "
17194                                    "member of type %s" % m.type)
17195        return retVal
17196
17197    def define(self):
17198        dropJS = ""
17199        for m in self.descriptor.interface.members:
17200            if m.isAttr():
17201                member = CGDictionary.makeMemberName(m.identifier.name)
17202                if m.type.isAny():
17203                    dropJS += member + " = JS::UndefinedValue();\n"
17204                elif m.type.isObject() or m.type.isSpiderMonkeyInterface():
17205                    dropJS += member + " = nullptr;\n"
17206        if dropJS != "":
17207            dropJS += "mozilla::DropJSObjects(this);\n"
17208        # Just override CGClass and do our own thing
17209        nativeType = self.descriptor.nativeType.split('::')[-1]
17210        ctorParams = ("aOwner, nullptr, nullptr" if self.parentType == "Event"
17211                      else "aOwner")
17212
17213        classImpl = fill(
17214            """
17215
17216            NS_IMPL_CYCLE_COLLECTION_CLASS(${nativeType})
17217
17218            NS_IMPL_ADDREF_INHERITED(${nativeType}, ${parentType})
17219            NS_IMPL_RELEASE_INHERITED(${nativeType}, ${parentType})
17220
17221            NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(${nativeType}, ${parentType})
17222            $*{traverse}
17223            NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
17224
17225            NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(${nativeType}, ${parentType})
17226            $*{trace}
17227            NS_IMPL_CYCLE_COLLECTION_TRACE_END
17228
17229            NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(${nativeType}, ${parentType})
17230            $*{unlink}
17231            NS_IMPL_CYCLE_COLLECTION_UNLINK_END
17232
17233            NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(${nativeType})
17234            NS_INTERFACE_MAP_END_INHERITING(${parentType})
17235
17236            ${nativeType}::${nativeType}(mozilla::dom::EventTarget* aOwner)
17237              : ${parentType}(${ctorParams})
17238            {
17239            }
17240
17241            ${nativeType}::~${nativeType}()
17242            {
17243              $*{dropJS}
17244            }
17245
17246            """,
17247            ifaceName=self.descriptor.name,
17248            nativeType=nativeType,
17249            ctorParams=ctorParams,
17250            parentType=self.parentType,
17251            traverse=self.implTraverse(),
17252            unlink=self.implUnlink(),
17253            trace=self.implTrace(),
17254            dropJS=dropJS)
17255        return classImpl + CGBindingImplClass.define(self)
17256
17257    def getNativeTypeForIDLType(self, type):
17258        if type.isPrimitive() and type.tag() in builtinNames:
17259            nativeType = CGGeneric(builtinNames[type.tag()])
17260            if type.nullable():
17261                nativeType = CGTemplatedType("Nullable", nativeType)
17262        elif type.isEnum():
17263            nativeType = CGGeneric(type.unroll().inner.identifier.name)
17264            if type.nullable():
17265                nativeType = CGTemplatedType("Nullable", nativeType)
17266        elif type.isDOMString() or type.isUSVString():
17267            nativeType = CGGeneric("nsString")
17268        elif type.isByteString():
17269            nativeType = CGGeneric("nsCString")
17270        elif type.isGeckoInterface():
17271            iface = type.unroll().inner
17272            nativeType = self.descriptor.getDescriptor(
17273                iface.identifier.name).nativeType
17274            # Now trim off unnecessary namespaces
17275            nativeType = nativeType.split("::")
17276            if nativeType[0] == "mozilla":
17277                nativeType.pop(0)
17278                if nativeType[0] == "dom":
17279                    nativeType.pop(0)
17280            nativeType = CGWrapper(CGGeneric("::".join(nativeType)), pre="RefPtr<", post=">")
17281        elif type.isAny():
17282            nativeType = CGGeneric("JS::Heap<JS::Value>")
17283        elif type.isObject() or type.isSpiderMonkeyInterface():
17284            nativeType = CGGeneric("JS::Heap<JSObject*>")
17285        elif type.isUnion():
17286            nativeType = CGGeneric(CGUnionStruct.unionTypeDecl(type, True))
17287        elif type.isSequence():
17288            if type.nullable():
17289                innerType = type.inner.inner
17290            else:
17291                innerType = type.inner
17292            if (not innerType.isPrimitive() and not innerType.isEnum() and
17293                not innerType.isDOMString() and not innerType.isByteString() and
17294                not innerType.isGeckoInterface()):
17295                raise TypeError("Don't know how to properly manage GC/CC for "
17296                                "event member of type %s" %
17297                                type)
17298            nativeType = CGTemplatedType(
17299                "nsTArray",
17300                self.getNativeTypeForIDLType(innerType))
17301            if type.nullable():
17302                nativeType = CGTemplatedType("Nullable", nativeType)
17303        else:
17304            raise TypeError("Don't know how to declare event member of type %s" %
17305                            type)
17306        return nativeType
17307
17308
17309class CGEventRoot(CGThing):
17310    def __init__(self, config, interfaceName):
17311        descriptor = config.getDescriptor(interfaceName)
17312
17313        self.root = CGWrapper(CGEventClass(descriptor),
17314                              pre="\n", post="\n")
17315
17316        self.root = CGNamespace.build(["mozilla", "dom"], self.root)
17317
17318        self.root = CGList([CGClassForwardDeclare("JSContext", isStruct=True),
17319                            self.root])
17320
17321        parent = descriptor.interface.parent.identifier.name
17322
17323        # Throw in our #includes
17324        self.root = CGHeaders(
17325            [descriptor],
17326            [],
17327            [],
17328            [],
17329            [
17330                config.getDescriptor(parent).headerFile,
17331                "mozilla/Attributes.h",
17332                "mozilla/ErrorResult.h",
17333                "mozilla/dom/%sBinding.h" % interfaceName,
17334                'mozilla/dom/BindingUtils.h',
17335                ],
17336            [
17337                "%s.h" % interfaceName,
17338                "js/GCAPI.h",
17339                'mozilla/dom/Nullable.h',
17340            ],
17341            "", self.root, config)
17342
17343        # And now some include guards
17344        self.root = CGIncludeGuard(interfaceName, self.root)
17345
17346        self.root = CGWrapper(
17347            self.root,
17348            pre=(AUTOGENERATED_WITH_SOURCE_WARNING_COMMENT %
17349                 os.path.basename(descriptor.interface.filename())))
17350
17351        self.root = CGWrapper(self.root, pre=dedent("""
17352            /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
17353            /* vim:set ts=2 sw=2 sts=2 et cindent: */
17354            /* This Source Code Form is subject to the terms of the Mozilla Public
17355             * License, v. 2.0. If a copy of the MPL was not distributed with this
17356             * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
17357
17358            """))
17359
17360    def declare(self):
17361        return self.root.declare()
17362
17363    def define(self):
17364        return self.root.define()
17365