1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 # You can obtain one at http://mozilla.org/MPL/2.0/.
5 # Common codegen classes.
14 from Configuration
import (
16 MemberIsLegacyUnforgeable
,
17 NoSuchDescriptorError
,
20 getTypesFromDescriptor
,
21 getTypesFromDictionary
,
23 from perfecthash
import PerfectHash
28 IDLDefaultDictionaryValue
,
30 IDLEmptySequenceValue
,
38 AUTOGENERATED_WARNING_COMMENT
= (
39 "/* THIS FILE IS AUTOGENERATED BY Codegen.py - DO NOT EDIT */\n\n"
41 AUTOGENERATED_WITH_SOURCE_WARNING_COMMENT
= (
42 "/* THIS FILE IS AUTOGENERATED FROM %s BY Codegen.py - DO NOT EDIT */\n\n"
44 ADDPROPERTY_HOOK_NAME
= "_addProperty"
45 GETWRAPPERCACHE_HOOK_NAME
= "_getWrapperCache"
46 FINALIZE_HOOK_NAME
= "_finalize"
47 OBJECT_MOVED_HOOK_NAME
= "_objectMoved"
48 CONSTRUCT_HOOK_NAME
= "_constructor"
49 LEGACYCALLER_HOOK_NAME
= "_legacycaller"
50 RESOLVE_HOOK_NAME
= "_resolve"
51 MAY_RESOLVE_HOOK_NAME
= "_mayResolve"
52 NEW_ENUMERATE_HOOK_NAME
= "_newEnumerate"
53 INSTANCE_RESERVED_SLOTS
= 1
55 # This size is arbitrary. It is a power of 2 to make using it as a modulo
56 # operand cheap, and is usually around 1/3-1/5th of the set size (sometimes
57 # smaller for very large sets).
58 GLOBAL_NAMES_PHF_SIZE
= 256
61 def memberReservedSlot(member
, descriptor
):
63 "(DOM_INSTANCE_RESERVED_SLOTS + %d)"
64 % member
.slotIndices
[descriptor
.interface
.identifier
.name
]
68 def memberXrayExpandoReservedSlot(member
, descriptor
):
70 "(xpc::JSSLOT_EXPANDO_COUNT + %d)"
71 % member
.slotIndices
[descriptor
.interface
.identifier
.name
]
75 def mayUseXrayExpandoSlots(descriptor
, attr
):
76 assert not attr
.getExtendedAttribute("NewObject")
77 # For attributes whose type is a Gecko interface we always use
78 # slots on the reflector for caching. Also, for interfaces that
79 # don't want Xrays we obviously never use the Xray expando slot.
80 return descriptor
.wantsXrays
and not attr
.type.isGeckoInterface()
83 def toStringBool(arg
):
85 Converts IDL/Python Boolean (True/False) to C++ Boolean (true/false)
87 return str(not not arg
).lower()
90 def toBindingNamespace(arg
):
91 return arg
+ "_Binding"
94 def isTypeCopyConstructible(type):
95 # Nullable and sequence stuff doesn't affect copy-constructibility
102 or (type.isUnion() and CGUnionStruct
.isUnionCopyConstructible(type))
105 and CGDictionary
.isDictionaryCopyConstructible(type.inner
)
108 # Interface types are only copy-constructible if they're Gecko
109 # interfaces. SpiderMonkey interfaces are not copy-constructible
110 # because of rooting issues.
111 (type.isInterface() and type.isGeckoInterface())
115 class CycleCollectionUnsupported(TypeError):
116 def __init__(self
, message
):
117 TypeError.__init
__(self
, message
)
120 def idlTypeNeedsCycleCollection(type):
121 type = type.unroll() # Takes care of sequences and nullables
123 (type.isPrimitive() and type.tag() in builtinNames
)
124 or type.isUndefined()
129 or type.isSpiderMonkeyInterface()
132 elif type.isCallback() or type.isPromise() or type.isGeckoInterface():
135 return any(idlTypeNeedsCycleCollection(t
) for t
in type.flatMemberTypes
)
136 elif type.isRecord():
137 if idlTypeNeedsCycleCollection(type.inner
):
138 raise CycleCollectionUnsupported(
139 "Cycle collection for type %s is not supported" % type
142 elif type.isDictionary():
143 return CGDictionary
.dictionaryNeedsCycleCollection(type.inner
)
145 raise CycleCollectionUnsupported(
146 "Don't know whether to cycle-collect type %s" % type
150 def idlTypeNeedsCallContext(type, descriptor
=None, allowTreatNonCallableAsNull
=False):
152 Returns whether the given type needs error reporting via a
153 BindingCallContext for JS-to-C++ conversions. This will happen when the
154 conversion can throw an exception due to logic in the IDL spec or
155 Gecko-specific security checks. In particular, a type needs a
156 BindingCallContext if and only if the JS-to-C++ conversion for that type can
157 end up calling ThrowErrorMessage.
159 For some types this depends on the descriptor (e.g. because we do certain
160 checks only for some kinds of interfaces).
162 The allowTreatNonCallableAsNull optimization is there so we can avoid
163 generating an unnecessary BindingCallContext for all the event handler
168 if type.isSequence():
169 # Sequences can always throw "not an object"
172 # treatNonObjectAsNull() and treatNonCallableAsNull() are
173 # only sane things to test on nullable types, so do that now.
175 allowTreatNonCallableAsNull
176 and type.isCallback()
177 and (type.treatNonObjectAsNull() or type.treatNonCallableAsNull())
179 # This can't throw. so never needs a method description.
185 if type.isUndefined():
186 # Clearly doesn't need a method description; we can only get here from
187 # CGHeaders trying to decide whether to include the method description
190 # The float check needs to come before the isPrimitive() check,
191 # because floats are primitives too.
193 # Floats can throw if restricted.
194 return not type.isUnrestricted()
195 if type.isPrimitive() and type.tag() in builtinNames
:
196 # Numbers can throw if enforcing range.
197 return type.hasEnforceRange()
199 # Can throw on invalid value.
202 # Can throw if it's a ByteString
203 return type.isByteString()
205 # JS-implemented interfaces do extra security checks so need a
206 # method description here. If we have no descriptor, this
207 # might be JS-implemented thing, so it will do the security
208 # check and we need the method description.
209 return not descriptor
or descriptor
.interface
.isJSImplemented()
211 # JS-to-Promise conversion won't cause us to throw any
212 # specific exceptions, so does not need a method description.
216 or type.isInterface()
218 or type.isDictionary()
220 or type.isObservableArray()
222 # These can all throw if a primitive is passed in, at the very least.
223 # There are some rare cases when we know we have an object, but those
224 # are not worth the complexity of optimizing for.
226 # Note that we checked the [LegacyTreatNonObjectAsNull] case already when
227 # unwrapping nullables.
230 # Can throw if a type not in the union is passed in.
232 raise TypeError("Don't know whether type '%s' needs a method description" % type)
235 # TryPreserveWrapper uses the addProperty hook to preserve the wrapper of
236 # non-nsISupports cycle collected objects, so if wantsAddProperty is changed
237 # to not cover that case then TryPreserveWrapper will need to be changed.
238 def wantsAddProperty(desc
):
239 return desc
.concrete
and desc
.wrapperCache
and not desc
.isGlobal()
242 def wantsGetWrapperCache(desc
):
244 desc
.concrete
and desc
.wrapperCache
and not desc
.isGlobal() and not desc
.proxy
248 def indent(s
, indentLevel
=2):
252 Weird secret feature: this doesn't indent lines that start with # (such as
253 #include lines or #ifdef/#endif).
256 # We'll want to insert the indent at the beginnings of lines, but we
257 # don't want to indent empty lines.
258 padding
= indentLevel
* " "
261 (padding
+ line
) if line
and line
[0] != "#" else line
262 for line
in s
.split("\n")
267 # dedent() and fill() are often called on the same string multiple
268 # times. We want to memoize their return values so we don't keep
269 # recomputing them all the time.
272 Decorator to memoize a function of one argument. The cache just
279 retval
= cache
.get(arg
)
281 retval
= cache
[arg
] = fn(arg
)
290 Remove all leading whitespace from s, and remove a blank line
293 if s
.startswith("\n"):
295 return textwrap
.dedent(s
)
298 # This works by transforming the fill()-template to an equivalent
300 fill_multiline_substitution_re
= re
.compile(r
"( *)\$\*{(\w+)}(\n)?")
303 find_substitutions
= re
.compile(r
"\${")
307 def compile_fill_template(template
):
309 Helper function for fill(). Given the template string passed to fill(),
310 do the reusable part of template processing and return a pair (t,
311 argModList) that can be used every time fill() is called with that
314 argsModList is list of tuples that represent modifications to be
315 made to args. Each modification has, in order: i) the arg name,
316 ii) the modified name, iii) the indent depth.
319 assert t
.endswith("\n") or "\n" not in t
324 Replaces a line like ' $*{xyz}\n' with '${xyz_n}',
325 where n is the indent depth, and add a corresponding entry to
328 Note that this needs to close over argModList, so it has to be
329 defined inside compile_fill_template().
331 indentation
, name
, nl
= match
.groups()
332 depth
= len(indentation
)
334 # Check that $*{xyz} appears by itself on a line.
335 prev
= match
.string
[: match
.start()]
336 if (prev
and not prev
.endswith("\n")) or nl
is None:
338 "Invalid fill() template: $*{%s} must appear by itself on a line" % name
341 # Now replace this whole line of template with the indented equivalent.
342 modified_name
= name
+ "_" + str(depth
)
343 argModList
.append((name
, modified_name
, depth
))
344 return "${" + modified_name
+ "}"
346 t
= re
.sub(fill_multiline_substitution_re
, replace
, t
)
347 if not re
.search(find_substitutions
, t
):
348 raise TypeError("Using fill() when dedent() would do.")
349 return (string
.Template(t
), argModList
)
352 def fill(template
, **args
):
354 Convenience function for filling in a multiline template.
356 `fill(template, name1=v1, name2=v2)` is a lot like
357 `string.Template(template).substitute({"name1": v1, "name2": v2})`.
359 However, it's shorter, and has a few nice features:
361 * If `template` is indented, fill() automatically dedents it!
362 This makes code using fill() with Python's multiline strings
363 much nicer to look at.
365 * If `template` starts with a blank line, fill() strips it off.
366 (Again, convenient with multiline strings.)
368 * fill() recognizes a special kind of substitution
369 of the form `$*{name}`.
371 Use this to paste in, and automatically indent, multiple lines.
372 (Mnemonic: The `*` is for "multiple lines").
374 A `$*` substitution must appear by itself on a line, with optional
375 preceding indentation (spaces only). The whole line is replaced by the
376 corresponding keyword argument, indented appropriately. If the
377 argument is an empty string, no output is generated, not even a blank
381 t
, argModList
= compile_fill_template(template
)
382 # Now apply argModList to args
383 for name
, modified_name
, depth
in argModList
:
384 if not (args
[name
] == "" or args
[name
].endswith("\n")):
386 "Argument %s with value %r is missing a newline" % (name
, args
[name
])
388 args
[modified_name
] = indent(args
[name
], depth
)
390 return t
.substitute(args
)
395 Abstract base class for things that spit out code.
399 pass # Nothing for now
402 """Produce code for a header file."""
403 assert False # Override me!
406 """Produce code for a cpp file."""
407 assert False # Override me!
410 """Produce the deps for a pp file"""
411 assert False # Override me!
414 class CGStringTable(CGThing
):
416 Generate a function accessor for a WebIDL string table, using the existing
417 concatenated names string and mapping indexes to offsets in that string:
419 const char *accessorName(unsigned int index) {
420 static const uint16_t offsets = { ... };
421 return BindingName(offsets[index]);
424 This is more efficient than the more natural:
426 const char *table[] = {
430 The uint16_t offsets are smaller than the pointer equivalents, and the
431 concatenated string requires no runtime relocations.
434 def __init__(self
, accessorName
, strings
, static
=False):
435 CGThing
.__init
__(self
)
436 self
.accessorName
= accessorName
437 self
.strings
= strings
443 return "const char *%s(unsigned int aIndex);\n" % self
.accessorName
447 for s
in self
.strings
:
448 offsets
.append(BindingNamesOffsetEnum(s
))
451 ${static}const char *${name}(unsigned int aIndex)
453 static const BindingNamesOffset offsets[] = {
456 return BindingName(offsets[aIndex]);
459 static
="static " if self
.static
else "",
460 name
=self
.accessorName
,
461 offsets
="".join("BindingNamesOffset::%s,\n" % o
for o
in offsets
),
465 class CGNativePropertyHooks(CGThing
):
467 Generate a NativePropertyHooks for a given descriptor
470 def __init__(self
, descriptor
, properties
):
471 CGThing
.__init
__(self
)
472 assert descriptor
.wantsXrays
473 self
.descriptor
= descriptor
474 self
.properties
= properties
481 self
.descriptor
.concrete
482 and self
.descriptor
.proxy
483 and not self
.descriptor
.isMaybeCrossOriginObject()
485 if self
.descriptor
.needsXrayNamedDeleterHook():
486 deleteNamedProperty
= "DeleteNamedProperty"
488 deleteNamedProperty
= "nullptr"
489 namedOrIndexed
= fill(
491 const NativeNamedOrIndexedPropertyHooks sNativeNamedOrIndexedPropertyHooks = {
492 binding_detail::ResolveOwnProperty,
493 binding_detail::EnumerateOwnProperties,
494 ${deleteNamedProperty}
497 deleteNamedProperty
=deleteNamedProperty
,
499 namedOrIndexedPointer
= "&sNativeNamedOrIndexedPropertyHooks"
500 elif self
.descriptor
.needsXrayResolveHooks():
501 namedOrIndexed
= dedent(
503 const NativeNamedOrIndexedPropertyHooks sNativeNamedOrIndexedPropertyHooks = {
504 ResolveOwnPropertyViaResolve,
505 EnumerateOwnPropertiesViaGetOwnPropertyNames,
510 namedOrIndexedPointer
= "&sNativeNamedOrIndexedPropertyHooks"
513 namedOrIndexedPointer
= "nullptr"
514 if self
.properties
.hasNonChromeOnly():
515 regular
= "sNativeProperties.Upcast()"
518 if self
.properties
.hasChromeOnly():
519 chrome
= "sChromeOnlyNativeProperties.Upcast()"
522 constructorID
= "constructors::id::"
523 if self
.descriptor
.interface
.hasInterfaceObject():
524 constructorID
+= self
.descriptor
.name
526 constructorID
+= "_ID_Count"
527 prototypeID
= "prototypes::id::"
528 if self
.descriptor
.interface
.hasInterfacePrototypeObject():
529 prototypeID
+= self
.descriptor
.name
531 prototypeID
+= "_ID_Count"
533 if self
.descriptor
.wantsXrayExpandoClass
:
534 expandoClass
= "&sXrayExpandoObjectClass"
536 expandoClass
= "&DefaultXrayExpandoObjectClass"
538 return namedOrIndexed
+ fill(
540 bool sNativePropertiesInited = false;
541 const NativePropertyHooks sNativePropertyHooks = {
542 ${namedOrIndexedPointer},
543 { ${regular}, ${chrome}, &sNativePropertiesInited },
549 namedOrIndexedPointer
=namedOrIndexedPointer
,
552 prototypeID
=prototypeID
,
553 constructorID
=constructorID
,
554 expandoClass
=expandoClass
,
558 def NativePropertyHooks(descriptor
):
560 "&sEmptyNativePropertyHooks"
561 if not descriptor
.wantsXrays
562 else "&sNativePropertyHooks"
566 def DOMClass(descriptor
):
567 protoList
= ["prototypes::id::" + proto
for proto
in descriptor
.prototypeNameChain
]
568 # Pad out the list to the right length with _ID_Count so we
569 # guarantee that all the lists are the same length. _ID_Count
570 # is never the ID of any prototype, so it's safe to use as
573 ["prototypes::id::_ID_Count"]
574 * (descriptor
.config
.maxProtoChainLength
- len(protoList
))
577 if descriptor
.interface
.isSerializable():
578 serializer
= "Serialize"
580 serializer
= "nullptr"
582 if wantsGetWrapperCache(descriptor
):
583 wrapperCacheGetter
= GETWRAPPERCACHE_HOOK_NAME
585 wrapperCacheGetter
= "nullptr"
587 if descriptor
.hasOrdinaryObjectPrototype
:
588 getProto
= "JS::GetRealmObjectPrototypeHandle"
590 getProto
= "GetProtoObjectHandle"
595 std::is_base_of_v<nsISupports, ${nativeType}>,
597 FindAssociatedGlobalForNative<${nativeType}>::Get,
599 GetCCParticipant<${nativeType}>::Get(),
601 ${wrapperCacheGetter}
603 protoChain
=", ".join(protoList
),
604 nativeType
=descriptor
.nativeType
,
605 hooks
=NativePropertyHooks(descriptor
),
606 serializer
=serializer
,
607 wrapperCacheGetter
=wrapperCacheGetter
,
612 def InstanceReservedSlots(descriptor
):
613 slots
= INSTANCE_RESERVED_SLOTS
+ descriptor
.interface
.totalMembersInSlots
614 if descriptor
.isMaybeCrossOriginObject():
615 # We need a slot for the cross-origin holder too.
616 if descriptor
.interface
.hasChildInterfaces():
618 "We don't support non-leaf cross-origin interfaces "
619 "like %s" % descriptor
.interface
.identifier
.name
625 class CGDOMJSClass(CGThing
):
627 Generate a DOMJSClass for a given descriptor
630 def __init__(self
, descriptor
):
631 CGThing
.__init
__(self
)
632 self
.descriptor
= descriptor
639 LEGACYCALLER_HOOK_NAME
640 if self
.descriptor
.operations
["LegacyCaller"]
644 OBJECT_MOVED_HOOK_NAME
if self
.descriptor
.wrapperCache
else "nullptr"
646 slotCount
= InstanceReservedSlots(self
.descriptor
)
647 classFlags
= "JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | "
648 if self
.descriptor
.isGlobal():
650 "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS)"
652 traceHook
= "JS_GlobalObjectTraceHook"
653 reservedSlots
= "JSCLASS_GLOBAL_APPLICATION_SLOTS"
655 classFlags
+= "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount
656 traceHook
= "nullptr"
657 reservedSlots
= slotCount
658 if self
.descriptor
.interface
.hasProbablyShortLivingWrapper():
659 if not self
.descriptor
.wrapperCache
:
661 "Need a wrapper cache to support nursery "
662 "allocation of DOM objects"
664 classFlags
+= " | JSCLASS_SKIP_NURSERY_FINALIZE"
666 if self
.descriptor
.interface
.getExtendedAttribute("NeedResolve"):
667 resolveHook
= RESOLVE_HOOK_NAME
668 mayResolveHook
= MAY_RESOLVE_HOOK_NAME
669 newEnumerateHook
= NEW_ENUMERATE_HOOK_NAME
670 elif self
.descriptor
.isGlobal():
671 resolveHook
= "mozilla::dom::ResolveGlobal"
672 mayResolveHook
= "mozilla::dom::MayResolveGlobal"
673 newEnumerateHook
= "mozilla::dom::EnumerateGlobal"
675 resolveHook
= "nullptr"
676 mayResolveHook
= "nullptr"
677 newEnumerateHook
= "nullptr"
681 static const JSClassOps sClassOps = {
682 ${addProperty}, /* addProperty */
683 nullptr, /* delProperty */
684 nullptr, /* enumerate */
685 ${newEnumerate}, /* newEnumerate */
686 ${resolve}, /* resolve */
687 ${mayResolve}, /* mayResolve */
688 ${finalize}, /* finalize */
690 nullptr, /* construct */
691 ${trace}, /* trace */
694 static const js::ClassExtension sClassExtension = {
695 ${objectMoved} /* objectMovedOp */
698 static const DOMJSClass sClass = {
708 static_assert(${instanceReservedSlots} == DOM_INSTANCE_RESERVED_SLOTS,
709 "Must have the right minimal number of reserved slots.");
710 static_assert(${reservedSlots} >= ${slotCount},
711 "Must have enough reserved slots.");
713 name
=self
.descriptor
.interface
.getClassName(),
715 addProperty
=ADDPROPERTY_HOOK_NAME
716 if wantsAddProperty(self
.descriptor
)
718 newEnumerate
=newEnumerateHook
,
720 mayResolve
=mayResolveHook
,
721 finalize
=FINALIZE_HOOK_NAME
,
724 objectMoved
=objectMovedHook
,
725 descriptor
=DOMClass(self
.descriptor
),
726 instanceReservedSlots
=INSTANCE_RESERVED_SLOTS
,
727 reservedSlots
=reservedSlots
,
732 class CGDOMProxyJSClass(CGThing
):
734 Generate a DOMJSClass for a given proxy descriptor
737 def __init__(self
, descriptor
):
738 CGThing
.__init
__(self
)
739 self
.descriptor
= descriptor
745 slotCount
= InstanceReservedSlots(self
.descriptor
)
746 # We need one reserved slot (DOM_OBJECT_SLOT).
747 flags
= ["JSCLASS_IS_DOMJSCLASS", "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount
]
748 # We don't use an IDL annotation for JSCLASS_EMULATES_UNDEFINED because
749 # we don't want people ever adding that to any interface other than
750 # HTMLAllCollection. So just hardcode it here.
751 if self
.descriptor
.interface
.identifier
.name
== "HTMLAllCollection":
752 flags
.append("JSCLASS_EMULATES_UNDEFINED")
755 static const DOMJSClass sClass = {
756 PROXY_CLASS_DEF("${name}",
761 name
=self
.descriptor
.interface
.identifier
.name
,
762 flags
=" | ".join(flags
),
763 descriptor
=DOMClass(self
.descriptor
),
767 class CGXrayExpandoJSClass(CGThing
):
769 Generate a JSClass for an Xray expando object. This is only
770 needed if we have members in slots (for [Cached] or [StoreInSlot]
774 def __init__(self
, descriptor
):
775 assert descriptor
.interface
.totalMembersInSlots
!= 0
776 assert descriptor
.wantsXrays
777 assert descriptor
.wantsXrayExpandoClass
778 CGThing
.__init
__(self
)
779 self
.descriptor
= descriptor
787 // This may allocate too many slots, because we only really need
788 // slots for our non-interface-typed members that we cache. But
789 // allocating slots only for those would make the slot index
790 // computations much more complicated, so let's do this the simple
792 DEFINE_XRAY_EXPANDO_CLASS(static, sXrayExpandoObjectClass, ${memberSlots});
794 memberSlots
=self
.descriptor
.interface
.totalMembersInSlots
,
798 def PrototypeIDAndDepth(descriptor
):
799 prototypeID
= "prototypes::id::"
800 if descriptor
.interface
.hasInterfacePrototypeObject():
801 prototypeID
+= descriptor
.interface
.identifier
.name
802 depth
= "PrototypeTraits<%s>::Depth" % prototypeID
804 prototypeID
+= "_ID_Count"
806 return (prototypeID
, depth
)
809 def InterfacePrototypeObjectProtoGetter(descriptor
):
811 Returns a tuple with two elements:
813 1) The name of the function to call to get the prototype to use for the
814 interface prototype object as a JSObject*.
816 2) The name of the function to call to get the prototype to use for the
817 interface prototype object as a JS::Handle<JSObject*> or None if no
818 such function exists.
820 parentProtoName
= descriptor
.parentPrototypeName
821 if descriptor
.hasNamedPropertiesObject
:
822 protoGetter
= "GetNamedPropertiesObject"
823 protoHandleGetter
= None
824 elif parentProtoName
is None:
825 if descriptor
.interface
.getExtendedAttribute("ExceptionClass"):
826 protoGetter
= "JS::GetRealmErrorPrototype"
827 elif descriptor
.interface
.isIteratorInterface():
828 protoGetter
= "JS::GetRealmIteratorPrototype"
829 elif descriptor
.interface
.isAsyncIteratorInterface():
830 protoGetter
= "JS::GetRealmAsyncIteratorPrototype"
832 protoGetter
= "JS::GetRealmObjectPrototype"
833 protoHandleGetter
= None
835 prefix
= toBindingNamespace(parentProtoName
)
836 protoGetter
= prefix
+ "::GetProtoObject"
837 protoHandleGetter
= prefix
+ "::GetProtoObjectHandle"
839 return (protoGetter
, protoHandleGetter
)
842 class CGPrototypeJSClass(CGThing
):
843 def __init__(self
, descriptor
, properties
):
844 CGThing
.__init
__(self
)
845 self
.descriptor
= descriptor
846 self
.properties
= properties
849 # We're purely for internal consumption
853 prototypeID
, depth
= PrototypeIDAndDepth(self
.descriptor
)
854 slotCount
= "DOM_INTERFACE_PROTO_SLOTS_BASE"
855 # Globals handle unforgeables directly in Wrap() instead of
858 self
.descriptor
.hasLegacyUnforgeableMembers
859 and not self
.descriptor
.isGlobal()
862 " + 1 /* slot for the JSObject holding the unforgeable properties */"
864 (protoGetter
, _
) = InterfacePrototypeObjectProtoGetter(self
.descriptor
)
866 "eGlobalInterfacePrototype"
867 if self
.descriptor
.isGlobal()
868 else "eInterfacePrototype"
872 static const DOMIfaceAndProtoJSClass sPrototypeClass = {
875 JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(${slotCount}),
888 name
=self
.descriptor
.interface
.getClassName(),
891 hooks
=NativePropertyHooks(self
.descriptor
),
892 prototypeID
=prototypeID
,
894 protoGetter
=protoGetter
,
898 def InterfaceObjectProtoGetter(descriptor
, forXrays
=False):
900 Returns a tuple with two elements:
902 1) The name of the function to call to get the prototype to use for the
903 interface object as a JSObject*.
905 2) The name of the function to call to get the prototype to use for the
906 interface prototype as a JS::Handle<JSObject*> or None if no such
909 parentInterface
= descriptor
.interface
.parent
911 assert not descriptor
.interface
.isNamespace()
912 parentIfaceName
= parentInterface
.identifier
.name
913 parentDesc
= descriptor
.getDescriptor(parentIfaceName
)
914 prefix
= toBindingNamespace(parentDesc
.name
)
915 protoGetter
= prefix
+ "::GetConstructorObject"
916 protoHandleGetter
= prefix
+ "::GetConstructorObjectHandle"
917 elif descriptor
.interface
.isNamespace():
918 if forXrays
or not descriptor
.interface
.getExtendedAttribute("ProtoObjectHack"):
919 protoGetter
= "JS::GetRealmObjectPrototype"
921 protoGetter
= "GetHackedNamespaceProtoObject"
922 protoHandleGetter
= None
924 protoGetter
= "JS::GetRealmFunctionPrototype"
925 protoHandleGetter
= None
926 return (protoGetter
, protoHandleGetter
)
929 class CGNamespaceObjectJSClass(CGThing
):
930 def __init__(self
, descriptor
):
931 CGThing
.__init
__(self
)
932 self
.descriptor
= descriptor
935 # We're purely for internal consumption
939 (protoGetter
, _
) = InterfaceObjectProtoGetter(self
.descriptor
, forXrays
=True)
941 classString
= self
.descriptor
.interface
.getExtendedAttribute("ClassString")
942 if classString
is None:
943 classString
= self
.descriptor
.interface
.identifier
.name
945 classString
= classString
[0]
948 static const DOMIfaceAndProtoJSClass sNamespaceObjectClass = {
951 JSCLASS_IS_DOMIFACEANDPROTOJSCLASS,
958 prototypes::id::_ID_Count,
964 classString
=classString
,
965 hooks
=NativePropertyHooks(self
.descriptor
),
966 protoGetter
=protoGetter
,
970 class CGInterfaceObjectInfo(CGThing
):
971 def __init__(self
, descriptor
):
972 CGThing
.__init
__(self
)
973 self
.descriptor
= descriptor
976 # We're purely for internal consumption
980 if self
.descriptor
.interface
.ctor():
981 ctorname
= CONSTRUCT_HOOK_NAME
983 ctorname
= "ThrowingConstructor"
984 wantsIsInstance
= self
.descriptor
.interface
.hasInterfacePrototypeObject()
986 prototypeID
, depth
= PrototypeIDAndDepth(self
.descriptor
)
987 (protoGetter
, _
) = InterfaceObjectProtoGetter(self
.descriptor
, forXrays
=True)
991 static const DOMInterfaceInfo sInterfaceObjectInfo = {
992 { ${ctorname}, ${hooks} },
1000 hooks
=NativePropertyHooks(self
.descriptor
),
1001 protoGetter
=protoGetter
,
1002 prototypeID
=prototypeID
,
1004 wantsIsInstance
=toStringBool(wantsIsInstance
),
1008 class CGList(CGThing
):
1010 Generate code for a list of GCThings. Just concatenates them together, with
1011 an optional joiner string. "\n" is a common joiner.
1014 def __init__(self
, children
, joiner
=""):
1015 CGThing
.__init
__(self
)
1016 # Make a copy of the kids into a list, because if someone passes in a
1017 # generator we won't be able to both declare and define ourselves, or
1018 # define ourselves more than once!
1019 self
.children
= list(children
)
1020 self
.joiner
= joiner
1022 def append(self
, child
):
1023 self
.children
.append(child
)
1025 def prepend(self
, child
):
1026 self
.children
.insert(0, child
)
1028 def extend(self
, kids
):
1029 self
.children
.extend(kids
)
1031 def join(self
, iterable
):
1032 return self
.joiner
.join(s
for s
in iterable
if len(s
) > 0)
1036 child
.declare() for child
in self
.children
if child
is not None
1040 return self
.join(child
.define() for child
in self
.children
if child
is not None)
1044 for child
in self
.children
:
1047 deps
= deps
.union(child
.deps())
1051 return len(self
.children
)
1054 class CGGeneric(CGThing
):
1056 A class that spits out a fixed string into the codegen. Can spit out a
1057 separate string for the declaration too.
1060 def __init__(self
, define
="", declare
=""):
1061 self
.declareText
= declare
1062 self
.defineText
= define
1065 return self
.declareText
1068 return self
.defineText
1074 class CGIndenter(CGThing
):
1076 A class that takes another CGThing and generates code that indents that
1077 CGThing by some number of spaces. The default indent is two spaces.
1080 def __init__(self
, child
, indentLevel
=2, declareOnly
=False):
1081 assert isinstance(child
, CGThing
)
1082 CGThing
.__init
__(self
)
1084 self
.indentLevel
= indentLevel
1085 self
.declareOnly
= declareOnly
1088 return indent(self
.child
.declare(), self
.indentLevel
)
1091 defn
= self
.child
.define()
1092 if self
.declareOnly
:
1095 return indent(defn
, self
.indentLevel
)
1098 class CGWrapper(CGThing
):
1100 Generic CGThing that wraps other CGThings with pre and post text.
1116 CGThing
.__init
__(self
)
1118 self
.declarePre
= declarePre
or pre
1119 self
.declarePost
= declarePost
or post
1120 self
.definePre
= definePre
or pre
1121 self
.definePost
= definePost
or post
1122 self
.declareOnly
= declareOnly
1123 self
.defineOnly
= defineOnly
1124 self
.reindent
= reindent
1129 decl
= self
.child
.declare()
1131 decl
= self
.reindentString(decl
, self
.declarePre
)
1132 return self
.declarePre
+ decl
+ self
.declarePost
1135 if self
.declareOnly
:
1137 defn
= self
.child
.define()
1139 defn
= self
.reindentString(defn
, self
.definePre
)
1140 return self
.definePre
+ defn
+ self
.definePost
1143 def reindentString(stringToIndent
, widthString
):
1144 # We don't use lineStartDetector because we don't want to
1145 # insert whitespace at the beginning of our _first_ line.
1146 # Use the length of the last line of width string, in case
1147 # it is a multiline string.
1148 lastLineWidth
= len(widthString
.splitlines()[-1])
1149 return stripTrailingWhitespace(
1150 stringToIndent
.replace("\n", "\n" + (" " * lastLineWidth
))
1154 return self
.child
.deps()
1157 class CGIfWrapper(CGList
):
1158 def __init__(self
, child
, condition
):
1163 CGGeneric(condition
), pre
="if (", post
=") {\n", reindent
=True
1171 class CGIfElseWrapper(CGList
):
1172 def __init__(self
, condition
, ifTrue
, ifFalse
):
1177 CGGeneric(condition
), pre
="if (", post
=") {\n", reindent
=True
1180 CGGeneric("} else {\n"),
1181 CGIndenter(ifFalse
),
1187 class CGElseChain(CGThing
):
1189 Concatenate if statements in an if-else-if-else chain.
1192 def __init__(self
, children
):
1193 self
.children
= [c
for c
in children
if c
is not None]
1199 if not self
.children
:
1201 s
= self
.children
[0].define()
1202 assert s
.endswith("\n")
1203 for child
in self
.children
[1:]:
1204 code
= child
.define()
1205 assert code
.startswith("if") or code
.startswith("{")
1206 assert code
.endswith("\n")
1207 s
= s
.rstrip() + " else " + code
1211 class CGTemplatedType(CGWrapper
):
1212 def __init__(self
, templateName
, child
, isConst
=False, isReference
=False):
1213 if isinstance(child
, list):
1214 child
= CGList(child
, ", ")
1215 const
= "const " if isConst
else ""
1216 pre
= "%s%s<" % (const
, templateName
)
1217 ref
= "&" if isReference
else ""
1219 CGWrapper
.__init
__(self
, child
, pre
=pre
, post
=post
)
1222 class CGNamespace(CGThing
):
1224 Generates namespace block that wraps other CGThings.
1227 def __init__(self
, namespace
, child
):
1228 CGThing
.__init
__(self
)
1230 self
.pre
= "namespace %s {\n" % namespace
1231 self
.post
= "} // namespace %s\n" % namespace
1234 decl
= self
.child
.declare()
1235 if len(decl
.strip()) == 0:
1237 return self
.pre
+ decl
+ self
.post
1240 defn
= self
.child
.define()
1241 if len(defn
.strip()) == 0:
1243 return self
.pre
+ defn
+ self
.post
1246 return self
.child
.deps()
1249 def build(namespaces
, child
):
1251 Static helper method to build multiple wrapped namespaces.
1254 return CGWrapper(child
)
1255 return CGNamespace("::".join(namespaces
), child
)
1258 class CGIncludeGuard(CGWrapper
):
1260 Generates include guards for a header.
1263 def __init__(self
, prefix
, child
):
1264 """|prefix| is the filename without the extension."""
1265 define
= "DOM_%s_H_" % prefix
.upper()
1269 declarePre
="#ifndef %s\n#define %s\n\n" % (define
, define
),
1270 declarePost
="\n#endif // %s\n" % define
,
1274 class CGHeaders(CGWrapper
):
1276 Generates the appropriate include statements.
1284 callbackDescriptors
,
1290 jsImplementedDescriptors
=[],
1293 Builds a set of includes to cover |descriptors|.
1295 Also includes the files in |declareIncludes| in the header
1296 file and the files in |defineIncludes| in the .cpp.
1298 |prefix| contains the basename of the file that we generate include
1302 # Determine the filenames for which we need headers.
1303 interfaceDeps
= [d
.interface
for d
in descriptors
]
1305 for iface
in interfaceDeps
:
1307 # We're going to need our parent's prototype, to use as the
1308 # prototype of our prototype object.
1309 ancestors
.append(iface
.parent
)
1310 # And if we have an interface object, we'll need the nearest
1311 # ancestor with an interface object too, so we can use its
1312 # interface object as the proto of our interface object.
1313 if iface
.hasInterfaceObject():
1314 parent
= iface
.parent
1315 while parent
and not parent
.hasInterfaceObject():
1316 parent
= parent
.parent
1318 ancestors
.append(parent
)
1319 interfaceDeps
.extend(ancestors
)
1321 # Include parent interface headers needed for default toJSON code.
1322 jsonInterfaceParents
= []
1323 for desc
in descriptors
:
1324 if not desc
.hasDefaultToJSON
:
1326 parent
= desc
.interface
.parent
1328 parentDesc
= desc
.getDescriptor(parent
.identifier
.name
)
1329 if parentDesc
.hasDefaultToJSON
:
1330 jsonInterfaceParents
.append(parentDesc
.interface
)
1331 parent
= parent
.parent
1332 interfaceDeps
.extend(jsonInterfaceParents
)
1334 bindingIncludes
= set(self
.getDeclarationFilename(d
) for d
in interfaceDeps
)
1336 # Grab all the implementation declaration files we need.
1337 implementationIncludes
= set(
1338 d
.headerFile
for d
in descriptors
if d
.needsHeaderInclude()
1341 # Now find all the things we'll need as arguments because we
1342 # need to wrap or unwrap them.
1343 bindingHeaders
= set()
1344 declareIncludes
= set(declareIncludes
)
1346 def addHeadersForType(typeAndPossibleOriginType
):
1348 Add the relevant headers for this type. We use its origin type, if
1349 passed, to decide what to do with interface types.
1351 t
, originType
= typeAndPossibleOriginType
1352 isFromDictionary
= originType
and originType
.isDictionary()
1353 isFromCallback
= originType
and originType
.isCallback()
1354 # Dictionaries have members that need to be actually
1355 # declared, not just forward-declared.
1356 # Callbacks have nullable union arguments that need to be actually
1357 # declared, not just forward-declared.
1358 if isFromDictionary
:
1359 headerSet
= declareIncludes
1360 elif isFromCallback
and t
.nullable() and t
.isUnion():
1361 headerSet
= declareIncludes
1363 headerSet
= bindingHeaders
1364 # Strip off outer layers and add headers they might require. (This
1365 # is conservative: only nullable non-pointer types need Nullable.h;
1366 # only sequences or observable arrays outside unions need
1367 # ForOfIterator.h; only functions that return, and attributes that
1368 # are, sequences or observable arrays in interfaces need Array.h, &c.)
1371 if idlTypeNeedsCallContext(unrolled
):
1372 bindingHeaders
.add("mozilla/dom/BindingCallContext.h")
1373 if unrolled
.nullable():
1374 headerSet
.add("mozilla/dom/Nullable.h")
1375 elif unrolled
.isSequence() or unrolled
.isObservableArray():
1376 bindingHeaders
.add("js/Array.h")
1377 bindingHeaders
.add("js/ForOfIterator.h")
1378 if unrolled
.isObservableArray():
1379 bindingHeaders
.add("mozilla/dom/ObservableArrayProxyHandler.h")
1382 unrolled
= unrolled
.inner
1383 if unrolled
.isUnion():
1384 headerSet
.add(self
.getUnionDeclarationFilename(config
, unrolled
))
1385 for t
in unrolled
.flatMemberTypes
:
1386 addHeadersForType((t
, None))
1387 elif unrolled
.isPromise():
1388 # See comment in the isInterface() case for why we add
1389 # Promise.h to headerSet, not bindingHeaders.
1390 headerSet
.add("mozilla/dom/Promise.h")
1391 # We need ToJSValue to do the Promise to JS conversion.
1392 bindingHeaders
.add("mozilla/dom/ToJSValue.h")
1393 elif unrolled
.isInterface():
1394 if unrolled
.isSpiderMonkeyInterface():
1395 bindingHeaders
.add("jsfriendapi.h")
1396 if jsImplementedDescriptors
:
1397 # Since we can't forward-declare typed array types
1398 # (because they're typedefs), we have to go ahead and
1399 # just include their header if we need to have functions
1400 # taking references to them declared in that header.
1401 headerSet
= declareIncludes
1402 headerSet
.add("mozilla/dom/TypedArray.h")
1405 typeDesc
= config
.getDescriptor(unrolled
.inner
.identifier
.name
)
1406 except NoSuchDescriptorError
:
1408 # Dictionaries with interface members rely on the
1409 # actual class definition of that interface member
1410 # being visible in the binding header, because they
1411 # store them in RefPtr and have inline
1412 # constructors/destructors.
1414 # XXXbz maybe dictionaries with interface members
1415 # should just have out-of-line constructors and
1417 headerSet
.add(typeDesc
.headerFile
)
1418 elif unrolled
.isDictionary():
1419 headerSet
.add(self
.getDeclarationFilename(unrolled
.inner
))
1420 # And if it needs rooting, we need RootedDictionary too
1421 if typeNeedsRooting(unrolled
):
1422 headerSet
.add("mozilla/dom/RootedDictionary.h")
1423 elif unrolled
.isCallback():
1424 headerSet
.add(self
.getDeclarationFilename(unrolled
.callback
))
1425 elif unrolled
.isFloat() and not unrolled
.isUnrestricted():
1426 # Restricted floats are tested for finiteness
1427 bindingHeaders
.add("mozilla/FloatingPoint.h")
1428 bindingHeaders
.add("mozilla/dom/PrimitiveConversions.h")
1429 elif unrolled
.isEnum():
1430 filename
= self
.getDeclarationFilename(unrolled
.inner
)
1431 declareIncludes
.add(filename
)
1432 elif unrolled
.isPrimitive():
1433 bindingHeaders
.add("mozilla/dom/PrimitiveConversions.h")
1434 elif unrolled
.isRecord():
1435 if isFromDictionary
or jsImplementedDescriptors
:
1436 declareIncludes
.add("mozilla/dom/Record.h")
1438 bindingHeaders
.add("mozilla/dom/Record.h")
1439 # Also add headers for the type the record is
1440 # parametrized over, if needed.
1441 addHeadersForType((t
.inner
, originType
if isFromDictionary
else None))
1443 for t
in getAllTypes(
1444 descriptors
+ callbackDescriptors
, dictionaries
, callbacks
1446 addHeadersForType(t
)
1448 def addHeaderForFunc(func
, desc
):
1451 # Include the right class header, which we can only do
1452 # if this is a class member function.
1453 if desc
is not None and not desc
.headerIsDefault
:
1454 # An explicit header file was provided, assume that we know
1459 # Strip out the function name and convert "::" to "/"
1460 bindingHeaders
.add("/".join(func
.split("::")[:-1]) + ".h")
1462 # Now for non-callback descriptors make sure we include any
1463 # headers needed by Func declarations and other things like that.
1464 for desc
in descriptors
:
1465 # If this is an iterator or an async iterator interface generated
1466 # for a separate iterable interface, skip generating type includes,
1467 # as we have what we need in IterableIterator.h
1469 desc
.interface
.isIteratorInterface()
1470 or desc
.interface
.isAsyncIteratorInterface()
1474 for m
in desc
.interface
.members
:
1475 addHeaderForFunc(PropertyDefiner
.getStringAttr(m
, "Func"), desc
)
1476 staticTypeOverride
= PropertyDefiner
.getStringAttr(
1477 m
, "StaticClassOverride"
1479 if staticTypeOverride
:
1480 bindingHeaders
.add("/".join(staticTypeOverride
.split("::")) + ".h")
1481 # getExtendedAttribute() returns a list, extract the entry.
1482 funcList
= desc
.interface
.getExtendedAttribute("Func")
1483 if funcList
is not None:
1484 addHeaderForFunc(funcList
[0], desc
)
1486 if desc
.interface
.maplikeOrSetlikeOrIterable
:
1487 # We need ToJSValue.h for maplike/setlike type conversions
1488 bindingHeaders
.add("mozilla/dom/ToJSValue.h")
1489 # Add headers for the key and value types of the
1490 # maplike/setlike/iterable, since they'll be needed for
1491 # convenience functions
1492 if desc
.interface
.maplikeOrSetlikeOrIterable
.hasKeyType():
1494 (desc
.interface
.maplikeOrSetlikeOrIterable
.keyType
, None)
1496 if desc
.interface
.maplikeOrSetlikeOrIterable
.hasValueType():
1498 (desc
.interface
.maplikeOrSetlikeOrIterable
.valueType
, None)
1501 for d
in dictionaries
:
1503 declareIncludes
.add(self
.getDeclarationFilename(d
.parent
))
1504 bindingHeaders
.add(self
.getDeclarationFilename(d
))
1506 addHeaderForFunc(PropertyDefiner
.getStringAttr(m
, "Func"), None)
1507 # No need to worry about Func on members of ancestors, because that
1508 # will happen automatically in whatever files those ancestors live
1512 bindingHeaders
.add(self
.getDeclarationFilename(c
))
1514 for c
in callbackDescriptors
:
1515 bindingHeaders
.add(self
.getDeclarationFilename(c
.interface
))
1517 if len(callbacks
) != 0:
1518 # We need CallbackFunction to serve as our parent class
1519 declareIncludes
.add("mozilla/dom/CallbackFunction.h")
1520 # And we need ToJSValue.h so we can wrap "this" objects
1521 declareIncludes
.add("mozilla/dom/ToJSValue.h")
1523 if len(callbackDescriptors
) != 0 or len(jsImplementedDescriptors
) != 0:
1524 # We need CallbackInterface to serve as our parent class
1525 declareIncludes
.add("mozilla/dom/CallbackInterface.h")
1526 # And we need ToJSValue.h so we can wrap "this" objects
1527 declareIncludes
.add("mozilla/dom/ToJSValue.h")
1529 # Also need to include the headers for ancestors of
1530 # JS-implemented interfaces.
1531 for jsImplemented
in jsImplementedDescriptors
:
1532 jsParent
= jsImplemented
.interface
.parent
1534 parentDesc
= jsImplemented
.getDescriptor(jsParent
.identifier
.name
)
1535 declareIncludes
.add(parentDesc
.jsImplParentHeader
)
1537 # Now make sure we're not trying to include the header from inside itself
1538 declareIncludes
.discard(prefix
+ ".h")
1540 # Let the machinery do its thing.
1541 def _includeString(includes
):
1542 def headerName(include
):
1543 # System headers are specified inside angle brackets.
1544 if include
.startswith("<"):
1546 # Non-system headers need to be placed in quotes.
1547 return '"%s"' % include
1549 return "".join(["#include %s\n" % headerName(i
) for i
in includes
]) + "\n"
1554 declarePre
=_includeString(sorted(declareIncludes
)),
1555 definePre
=_includeString(
1560 | implementationIncludes
1566 def getDeclarationFilename(decl
):
1567 # Use our local version of the header, not the exported one, so that
1568 # test bindings, which don't export, will work correctly.
1569 basename
= os
.path
.basename(decl
.filename
)
1570 return basename
.replace(".webidl", "Binding.h")
1573 def getUnionDeclarationFilename(config
, unionType
):
1574 assert unionType
.isUnion()
1575 assert unionType
.unroll() == unionType
1576 # If a union is "defined" in multiple files, it goes in UnionTypes.h.
1577 if len(config
.filenamesPerUnion
[unionType
.name
]) > 1:
1578 return "mozilla/dom/UnionTypes.h"
1579 # If a union is defined by a built-in typedef, it also goes in
1581 assert len(config
.filenamesPerUnion
[unionType
.name
]) == 1
1582 if "<unknown>" in config
.filenamesPerUnion
[unionType
.name
]:
1583 return "mozilla/dom/UnionTypes.h"
1584 return CGHeaders
.getDeclarationFilename(unionType
)
1587 def SortedDictValues(d
):
1589 Returns a list of values from the dict sorted by key.
1591 return [v
for k
, v
in sorted(d
.items())]
1594 def UnionsForFile(config
, webIDLFile
):
1596 Returns a list of union types for all union types that are only used in
1597 webIDLFile. If webIDLFile is None this will return the list of tuples for
1598 union types that are used in more than one WebIDL file.
1600 return config
.unionsPerFilename
.get(webIDLFile
, [])
1603 def UnionTypes(unionTypes
, config
):
1605 The unionTypes argument should be a list of union types. This is typically
1606 the list generated by UnionsForFile.
1608 Returns a tuple containing a set of header filenames to include in
1609 the header for the types in unionTypes, a set of header filenames to
1610 include in the implementation file for the types in unionTypes, a set
1611 of tuples containing a type declaration and a boolean if the type is a
1612 struct for member types of the union, a list of traverse methods,
1613 unlink methods and a list of union types. These last three lists only
1614 contain unique union types.
1619 declarations
= set()
1620 unionStructs
= dict()
1621 traverseMethods
= dict()
1622 unlinkMethods
= dict()
1624 for t
in unionTypes
:
1626 if name
not in unionStructs
:
1627 unionStructs
[name
] = t
1629 def addHeadersForType(f
):
1631 headers
.add("mozilla/dom/Nullable.h")
1632 isSequence
= f
.isSequence()
1634 # Dealing with sequences requires for-of-compatible
1636 implheaders
.add("js/ForOfIterator.h")
1637 # Sequences can always throw "not an object" exceptions.
1638 implheaders
.add("mozilla/dom/BindingCallContext.h")
1639 if typeNeedsRooting(f
):
1640 headers
.add("mozilla/dom/RootedSequence.h")
1642 if idlTypeNeedsCallContext(f
):
1643 implheaders
.add("mozilla/dom/BindingCallContext.h")
1645 headers
.add("mozilla/dom/Promise.h")
1646 # We need ToJSValue to do the Promise to JS conversion.
1647 headers
.add("mozilla/dom/ToJSValue.h")
1648 elif f
.isInterface():
1649 if f
.isSpiderMonkeyInterface():
1650 headers
.add("js/RootingAPI.h")
1651 headers
.add("js/Value.h")
1652 headers
.add("mozilla/dom/TypedArray.h")
1655 typeDesc
= config
.getDescriptor(f
.inner
.identifier
.name
)
1656 except NoSuchDescriptorError
:
1658 if typeDesc
.interface
.isCallback() or isSequence
:
1659 # Callback interfaces always use strong refs, so
1660 # we need to include the right header to be able
1661 # to Release() in our inlined code.
1663 # Similarly, sequences always contain strong
1664 # refs, so we'll need the header to handler
1666 headers
.add(typeDesc
.headerFile
)
1667 elif typeDesc
.interface
.identifier
.name
== "WindowProxy":
1668 # In UnionTypes.h we need to see the declaration of the
1669 # WindowProxyHolder that we use to store the WindowProxy, so
1670 # we have its sizeof and know how big to make our union.
1671 headers
.add(typeDesc
.headerFile
)
1673 declarations
.add((typeDesc
.nativeType
, False))
1674 implheaders
.add(typeDesc
.headerFile
)
1675 elif f
.isDictionary():
1676 # For a dictionary, we need to see its declaration in
1677 # UnionTypes.h so we have its sizeof and know how big to
1679 headers
.add(CGHeaders
.getDeclarationFilename(f
.inner
))
1680 # And if it needs rooting, we need RootedDictionary too
1681 if typeNeedsRooting(f
):
1682 headers
.add("mozilla/dom/RootedDictionary.h")
1683 elif f
.isFloat() and not f
.isUnrestricted():
1684 # Restricted floats are tested for finiteness
1685 implheaders
.add("mozilla/FloatingPoint.h")
1686 implheaders
.add("mozilla/dom/PrimitiveConversions.h")
1688 # Need to see the actual definition of the enum,
1690 headers
.add(CGHeaders
.getDeclarationFilename(f
.inner
))
1691 elif f
.isPrimitive():
1692 implheaders
.add("mozilla/dom/PrimitiveConversions.h")
1693 elif f
.isCallback():
1694 # Callbacks always use strong refs, so we need to include
1695 # the right header to be able to Release() in our inlined
1697 headers
.add(CGHeaders
.getDeclarationFilename(f
.callback
))
1699 headers
.add("mozilla/dom/Record.h")
1700 # And add headers for the type we're parametrized over
1701 addHeadersForType(f
.inner
)
1702 # And if it needs rooting, we need RootedRecord too
1703 if typeNeedsRooting(f
):
1704 headers
.add("mozilla/dom/RootedRecord.h")
1706 implheaders
.add(CGHeaders
.getUnionDeclarationFilename(config
, t
))
1707 for f
in t
.flatMemberTypes
:
1708 assert not f
.nullable()
1709 addHeadersForType(f
)
1711 if idlTypeNeedsCycleCollection(t
):
1713 ("mozilla::dom::%s" % CGUnionStruct
.unionTypeName(t
, True), False)
1715 traverseMethods
[name
] = CGCycleCollectionTraverseForOwningUnionMethod(t
)
1716 unlinkMethods
[name
] = CGCycleCollectionUnlinkForOwningUnionMethod(t
)
1718 # The order of items in CGList is important.
1719 # Since the union structs friend the unlinkMethods, the forward-declaration
1720 # for these methods should come before the class declaration. Otherwise
1721 # some compilers treat the friend declaration as a forward-declaration in
1727 SortedDictValues(traverseMethods
),
1728 SortedDictValues(unlinkMethods
),
1729 SortedDictValues(unionStructs
),
1735 A class for outputting the type and name of an argument
1738 def __init__(self
, argType
, name
, default
=None):
1739 self
.argType
= argType
1741 self
.default
= default
1744 string
= self
.argType
+ " " + self
.name
1745 if self
.default
is not None:
1746 string
+= " = " + self
.default
1750 return self
.argType
+ " " + self
.name
1753 class CGAbstractMethod(CGThing
):
1755 An abstract class for generating code for a method. Subclasses
1756 should override definition_body to create the actual code.
1758 descriptor is the descriptor for the interface the method is associated with
1760 name is the name of the method as a string
1762 returnType is the IDLType of the return value
1764 args is a list of Argument objects
1766 inline should be True to generate an inline method, whose body is
1767 part of the declaration.
1769 alwaysInline should be True to generate an inline method annotated with
1772 static should be True to generate a static method, which only has
1775 If templateArgs is not None it should be a list of strings containing
1776 template arguments, and the function will be templatized using those
1779 canRunScript should be True to generate a MOZ_CAN_RUN_SCRIPT annotation.
1781 signatureOnly should be True to only declare the signature (either in
1782 the header, or if static is True in the cpp file).
1796 signatureOnly
=False,
1798 CGThing
.__init
__(self
)
1799 self
.descriptor
= descriptor
1801 self
.returnType
= returnType
1803 self
.inline
= inline
1804 self
.alwaysInline
= alwaysInline
1805 self
.static
= static
1806 self
.templateArgs
= templateArgs
1807 self
.canRunScript
= canRunScript
1808 self
.signatureOnly
= signatureOnly
1810 def _argstring(self
, declare
):
1811 return ", ".join([a
.declare() if declare
else a
.define() for a
in self
.args
])
1813 def _template(self
):
1814 if self
.templateArgs
is None:
1816 return "template <%s>\n" % ", ".join(self
.templateArgs
)
1818 def _decorators(self
):
1820 if self
.canRunScript
:
1821 decorators
.append("MOZ_CAN_RUN_SCRIPT")
1822 if self
.alwaysInline
:
1823 decorators
.append("MOZ_ALWAYS_INLINE")
1825 decorators
.append("inline")
1827 decorators
.append("static")
1828 decorators
.append(self
.returnType
)
1829 maybeNewline
= " " if self
.inline
else "\n"
1830 return " ".join(decorators
) + maybeNewline
1832 def signature(self
):
1833 return "%s%s%s(%s);\n" % (
1837 self
._argstring
(True),
1844 return self
._define
(True)
1845 return self
.signature()
1847 def indent_body(self
, body
):
1849 Indent the code returned by self.definition_body(). Most classes
1850 simply indent everything two spaces. This is here for
1851 CGRegisterProtos, which needs custom indentation.
1855 def _define(self
, fromDeclare
=False):
1857 self
.definition_prologue(fromDeclare
)
1858 + self
.indent_body(self
.definition_body())
1859 + self
.definition_epilogue()
1863 if self
.signatureOnly
:
1865 # self.static makes us not output anything in the header, so output the signature here.
1866 return self
.signature()
1868 return "" if (self
.inline
and not self
.static
) else self
._define
()
1870 def definition_prologue(self
, fromDeclare
):
1871 error_reporting_label
= self
.error_reporting_label()
1872 if error_reporting_label
:
1873 # We're going to want a BindingCallContext. Rename our JSContext*
1876 while i
< len(self
.args
):
1878 if arg
.argType
== "JSContext*":
1880 self
.args
[i
] = Argument(arg
.argType
, "cx_", arg
.default
)
1883 if i
== len(self
.args
):
1884 raise TypeError("Must have a JSContext* to create a BindingCallContext")
1886 prologue
= "%s%s%s(%s)\n{\n" % (
1890 self
._argstring
(fromDeclare
),
1892 if error_reporting_label
:
1896 BindingCallContext ${cxname}(cx_, ${label});
1899 label
=error_reporting_label
,
1903 profiler_label
= self
.auto_profiler_label()
1905 prologue
+= indent(profiler_label
) + "\n"
1909 def definition_epilogue(self
):
1912 def definition_body(self
):
1913 assert False # Override me!
1916 Override this method to return a pair of (descriptive string, name of a
1917 JSContext* variable) in order to generate a profiler label for this method.
1920 def auto_profiler_label(self
):
1921 return None # Override me!
1924 Override this method to return a string to be used as the label for a
1925 BindingCallContext. If this does not return None, one of the arguments of
1926 this method must be of type 'JSContext*'. Its name will be replaced with
1927 'cx_' and a BindingCallContext named 'cx' will be instantiated with the
1931 def error_reporting_label(self
):
1932 return None # Override me!
1935 class CGAbstractStaticMethod(CGAbstractMethod
):
1937 Abstract base class for codegen of implementation-only (no
1938 declaration) static methods.
1941 def __init__(self
, descriptor
, name
, returnType
, args
, canRunScript
=False):
1942 CGAbstractMethod
.__init
__(
1950 canRunScript
=canRunScript
,
1954 class CGAbstractClassHook(CGAbstractStaticMethod
):
1956 Meant for implementing JSClass hooks, like Finalize or Trace. Does very raw
1957 'this' unwrapping as it assumes that the unwrapped type is always known.
1960 def __init__(self
, descriptor
, name
, returnType
, args
):
1961 CGAbstractStaticMethod
.__init
__(self
, descriptor
, name
, returnType
, args
)
1963 def definition_body_prologue(self
):
1964 return "%s* self = UnwrapPossiblyNotInitializedDOMObject<%s>(obj);\n" % (
1965 self
.descriptor
.nativeType
,
1966 self
.descriptor
.nativeType
,
1969 def definition_body(self
):
1970 return self
.definition_body_prologue() + self
.generate_code()
1972 def generate_code(self
):
1973 assert False # Override me!
1976 class CGAddPropertyHook(CGAbstractClassHook
):
1978 A hook for addProperty, used to preserve our wrapper from GC.
1981 def __init__(self
, descriptor
):
1983 Argument("JSContext*", "cx"),
1984 Argument("JS::Handle<JSObject*>", "obj"),
1985 Argument("JS::Handle<jsid>", "id"),
1986 Argument("JS::Handle<JS::Value>", "val"),
1988 CGAbstractClassHook
.__init
__(
1989 self
, descriptor
, ADDPROPERTY_HOOK_NAME
, "bool", args
1992 def generate_code(self
):
1993 assert self
.descriptor
.wrapperCache
1994 # This hook is also called by TryPreserveWrapper on non-nsISupports
1995 # cycle collected objects, so if addProperty is ever changed to do
1996 # anything more or less than preserve the wrapper, TryPreserveWrapper
1997 # will need to be changed.
2000 // We don't want to preserve if we don't have a wrapper, and we
2001 // obviously can't preserve if we're not initialized.
2002 if (self && self->GetWrapperPreserveColor()) {
2003 PreserveWrapper(self);
2010 class CGGetWrapperCacheHook(CGAbstractClassHook
):
2012 A hook for GetWrapperCache, used by HasReleasedWrapper to get the
2013 nsWrapperCache pointer for a non-nsISupports object.
2016 def __init__(self
, descriptor
):
2017 args
= [Argument("JS::Handle<JSObject*>", "obj")]
2018 CGAbstractClassHook
.__init
__(
2019 self
, descriptor
, GETWRAPPERCACHE_HOOK_NAME
, "nsWrapperCache*", args
2022 def generate_code(self
):
2023 assert self
.descriptor
.wrapperCache
2031 def finalizeHook(descriptor
, hookName
, gcx
, obj
):
2032 finalize
= "JS::SetReservedSlot(%s, DOM_OBJECT_SLOT, JS::UndefinedValue());\n" % obj
2033 if descriptor
.interface
.getExtendedAttribute("LegacyOverrideBuiltIns"):
2036 // Either our proxy created an expando object or not. If it did,
2037 // then we would have preserved ourselves, and hence if we're going
2038 // away so is our C++ object and we should reset its expando value.
2039 // It's possible that in this situation the C++ object's reflector
2040 // pointer has been nulled out, but if not it's pointing to us. If
2041 // our proxy did _not_ create an expando object then it's possible
2042 // that we're no longer the reflector for our C++ object (and
2043 // incremental finalization is finally getting to us), and that in
2044 // the meantime the new reflector has created an expando object.
2045 // In that case we do NOT want to clear the expando pointer in the
2048 // It's important to do this before we ClearWrapper, of course.
2049 JSObject* reflector = self->GetWrapperMaybeDead();
2050 if (!reflector || reflector == ${obj}) {
2051 self->mExpandoAndGeneration.expando = JS::UndefinedValue();
2056 for m
in descriptor
.interface
.members
:
2057 if m
.isAttr() and m
.type.isObservableArray():
2061 JS::Value val = JS::GetReservedSlot(obj, ${slot});
2062 if (!val.isUndefined()) {
2063 JSObject* obj = &val.toObject();
2064 js::SetProxyReservedSlot(obj, OBSERVABLE_ARRAY_DOM_INTERFACE_SLOT, JS::UndefinedValue());
2068 slot
=memberReservedSlot(m
, descriptor
),
2070 if descriptor
.wrapperCache
:
2071 finalize
+= "ClearWrapper(self, self, %s);\n" % obj
2072 if descriptor
.isGlobal():
2073 finalize
+= "mozilla::dom::FinalizeGlobal(%s, %s);\n" % (gcx
, obj
)
2076 if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) {
2077 JS::RemoveAssociatedMemory(${obj}, mallocBytes,
2078 JS::MemoryUse::DOMBinding);
2083 finalize
+= "AddForDeferredFinalization<%s>(self);\n" % descriptor
.nativeType
2084 return CGIfWrapper(CGGeneric(finalize
), "self")
2087 class CGClassFinalizeHook(CGAbstractClassHook
):
2089 A hook for finalize, used to release our native object.
2092 def __init__(self
, descriptor
):
2093 args
= [Argument("JS::GCContext*", "gcx"), Argument("JSObject*", "obj")]
2094 CGAbstractClassHook
.__init
__(self
, descriptor
, FINALIZE_HOOK_NAME
, "void", args
)
2096 def generate_code(self
):
2097 return finalizeHook(
2098 self
.descriptor
, self
.name
, self
.args
[0].name
, self
.args
[1].name
2102 def objectMovedHook(descriptor
, hookName
, obj
, old
):
2103 assert descriptor
.wrapperCache
2107 UpdateWrapper(self, self, ${obj}, ${old});
2117 class CGClassObjectMovedHook(CGAbstractClassHook
):
2119 A hook for objectMovedOp, used to update the wrapper cache when an object it
2123 def __init__(self
, descriptor
):
2124 args
= [Argument("JSObject*", "obj"), Argument("JSObject*", "old")]
2125 CGAbstractClassHook
.__init
__(
2126 self
, descriptor
, OBJECT_MOVED_HOOK_NAME
, "size_t", args
2129 def generate_code(self
):
2130 return objectMovedHook(
2131 self
.descriptor
, self
.name
, self
.args
[0].name
, self
.args
[1].name
2135 def JSNativeArguments():
2137 Argument("JSContext*", "cx"),
2138 Argument("unsigned", "argc"),
2139 Argument("JS::Value*", "vp"),
2143 class CGClassConstructor(CGAbstractStaticMethod
):
2145 JS-visible constructor for our objects
2148 def __init__(self
, descriptor
, ctor
, name
=CONSTRUCT_HOOK_NAME
):
2149 CGAbstractStaticMethod
.__init
__(
2150 self
, descriptor
, name
, "bool", JSNativeArguments()
2157 return CGAbstractStaticMethod
.define(self
)
2159 def definition_body(self
):
2160 return self
.generate_code()
2162 def generate_code(self
):
2163 if self
._ctor
.isHTMLConstructor():
2164 # We better have a prototype object. Otherwise our proto
2165 # id won't make sense.
2166 assert self
.descriptor
.interface
.hasInterfacePrototypeObject()
2167 # We also better have a constructor object, if this is
2169 assert self
.descriptor
.interface
.hasInterfaceObject()
2170 # We can't just pass null for the CreateInterfaceObjects callback,
2171 # because our newTarget might be in a different compartment, in
2172 # which case we'll need to look up constructor objects in that
2176 return HTMLConstructor(cx, argc, vp,
2177 constructors::id::${name},
2178 prototypes::id::${name},
2179 CreateInterfaceObjects);
2181 name
=self
.descriptor
.name
,
2184 # If the interface is already SecureContext, notify getConditionList to skip that check,
2185 # because the constructor won't be exposed in non-secure contexts to start with.
2186 alreadySecureContext
= self
.descriptor
.interface
.getExtendedAttribute(
2190 # We want to throw if any of the conditions returned by getConditionList are false.
2191 conditionsCheck
= ""
2192 rawConditions
= getRawConditionList(
2193 self
._ctor
, "cx", "obj", alreadySecureContext
2195 if len(rawConditions
) > 0:
2196 notConditions
= " ||\n".join("!" + cond
for cond
in rawConditions
)
2197 failedCheckAction
= CGGeneric("return ThrowingConstructor(cx, argc, vp);\n")
2199 CGIfWrapper(failedCheckAction
, notConditions
).define() + "\n"
2202 # Additionally, we want to throw if a caller does a bareword invocation
2203 # of a constructor without |new|.
2204 ctorName
= GetConstructorNameForReporting(self
.descriptor
, self
._ctor
)
2208 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
2209 JS::Rooted<JSObject*> obj(cx, &args.callee());
2211 if (!args.isConstructing()) {
2212 return ThrowConstructorWithoutNew(cx, "${ctorName}");
2215 JS::Rooted<JSObject*> desiredProto(cx);
2216 if (!GetDesiredProto(cx, args,
2217 prototypes::id::${name},
2218 CreateInterfaceObjects,
2223 conditionsCheck
=conditionsCheck
,
2225 name
=self
.descriptor
.name
,
2228 name
= self
._ctor
.identifier
.name
2229 nativeName
= MakeNativeName(self
.descriptor
.binaryNameFor(name
, True))
2230 callGenerator
= CGMethodCall(
2231 nativeName
, True, self
.descriptor
, self
._ctor
, isConstructor
=True
2233 return preamble
+ "\n" + callGenerator
.define()
2235 def auto_profiler_label(self
):
2238 AUTO_PROFILER_LABEL_DYNAMIC_FAST(
2239 "${ctorName}", "constructor", DOM, cx,
2240 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
2242 ctorName
=GetConstructorNameForReporting(self
.descriptor
, self
._ctor
),
2245 def error_reporting_label(self
):
2246 return CGSpecializedMethod
.error_reporting_label_helper(
2247 self
.descriptor
, self
._ctor
, isConstructor
=True
2251 def LegacyFactoryFunctionName(m
):
2252 return "_" + m
.identifier
.name
2255 class CGLegacyFactoryFunctions(CGThing
):
2256 def __init__(self
, descriptor
):
2257 self
.descriptor
= descriptor
2258 CGThing
.__init
__(self
)
2264 if len(self
.descriptor
.interface
.legacyFactoryFunctions
) == 0:
2267 constructorID
= "constructors::id::"
2268 if self
.descriptor
.interface
.hasInterfaceObject():
2269 constructorID
+= self
.descriptor
.name
2271 constructorID
+= "_ID_Count"
2273 legacyFactoryFunctions
= ""
2274 for n
in self
.descriptor
.interface
.legacyFactoryFunctions
:
2275 legacyFactoryFunctions
+= (
2276 '{ "%s", { %s, &sLegacyFactoryFunctionNativePropertyHooks }, %i },\n'
2277 % (n
.identifier
.name
, LegacyFactoryFunctionName(n
), methodLength(n
))
2282 bool sLegacyFactoryFunctionNativePropertiesInited = true;
2283 const NativePropertyHooks sLegacyFactoryFunctionNativePropertyHooks = {
2285 { nullptr, nullptr, &sLegacyFactoryFunctionNativePropertiesInited },
2286 prototypes::id::${name},
2291 static const LegacyFactoryFunction legacyFactoryFunctions[] = {
2292 $*{legacyFactoryFunctions}
2295 name
=self
.descriptor
.name
,
2296 constructorID
=constructorID
,
2297 legacyFactoryFunctions
=legacyFactoryFunctions
,
2301 def isChromeOnly(m
):
2302 return m
.getExtendedAttribute("ChromeOnly")
2305 def prefIdentifier(pref
):
2306 return pref
.replace(".", "_").replace("-", "_")
2309 def prefHeader(pref
):
2310 return "mozilla/StaticPrefs_%s.h" % pref
.partition(".")[0]
2313 def computeGlobalNamesFromExposureSet(exposureSet
):
2314 assert exposureSet
is None or isinstance(exposureSet
, set)
2318 return " | ".join(map(lambda g
: "GlobalNames::%s" % g
, sorted(exposureSet
)))
2323 class MemberCondition
:
2325 An object representing the condition for a member to actually be
2326 exposed. Any of the arguments can be None. If not
2327 None, they should have the following types:
2329 pref: The name of the preference.
2330 func: The name of the function.
2331 secureContext: A bool indicating whether a secure context is required.
2332 nonExposedGlobals: A set of names of globals. Can be empty, in which case
2333 it's treated the same way as None.
2334 trial: The name of the origin trial.
2341 secureContext
=False,
2342 nonExposedGlobals
=None,
2345 assert pref
is None or isinstance(pref
, str)
2346 assert func
is None or isinstance(func
, str)
2347 assert trial
is None or isinstance(trial
, str)
2348 assert isinstance(secureContext
, bool)
2351 identifier
= prefIdentifier(self
.pref
)
2352 self
.prefFuncIndex
= "WebIDLPrefIndex::" + identifier
2354 self
.prefFuncIndex
= "WebIDLPrefIndex::NoPref"
2356 self
.secureContext
= secureContext
2363 self
.func
= toFuncPtr(func
)
2365 self
.nonExposedGlobals
= computeGlobalNamesFromExposureSet(nonExposedGlobals
)
2368 self
.trial
= "OriginTrial::" + trial
2370 self
.trial
= "OriginTrial(0)"
2372 def __eq__(self
, other
):
2374 self
.pref
== other
.pref
2375 and self
.func
== other
.func
2376 and self
.secureContext
== other
.secureContext
2377 and self
.nonExposedGlobals
== other
.nonExposedGlobals
2378 and self
.trial
== other
.trial
2381 def __ne__(self
, other
):
2382 return not self
.__eq
__(other
)
2384 def hasDisablers(self
):
2386 self
.pref
is not None
2387 or self
.secureContext
2388 or self
.func
!= "nullptr"
2389 or self
.nonExposedGlobals
!= "0"
2390 or self
.trial
!= "OriginTrial(0)"
2394 class PropertyDefiner
:
2396 A common superclass for defining things on prototype objects.
2398 Subclasses should implement generateArray to generate the actual arrays of
2399 things we're defining. They should also set self.chrome to the list of
2400 things only exposed to chrome and self.regular to the list of things exposed
2401 to both chrome and web pages.
2404 def __init__(self
, descriptor
, name
):
2405 self
.descriptor
= descriptor
2408 def hasChromeOnly(self
):
2409 return len(self
.chrome
) > 0
2411 def hasNonChromeOnly(self
):
2412 return len(self
.regular
) > 0
2414 def variableName(self
, chrome
):
2416 if self
.hasChromeOnly():
2417 return "sChrome" + self
.name
2419 if self
.hasNonChromeOnly():
2420 return "s" + self
.name
2423 def usedForXrays(self
):
2424 return self
.descriptor
.wantsXrays
2426 def length(self
, chrome
):
2427 return len(self
.chrome
) if chrome
else len(self
.regular
)
2430 # We only need to generate id arrays for things that will end
2431 # up used via ResolveProperty or EnumerateProperties.
2432 str = self
.generateArray(self
.regular
, self
.variableName(False))
2433 if self
.hasChromeOnly():
2434 str += self
.generateArray(self
.chrome
, self
.variableName(True))
2438 def getStringAttr(member
, name
):
2439 attr
= member
.getExtendedAttribute(name
)
2442 # It's a list of strings
2443 assert len(attr
) == 1
2444 assert attr
[0] is not None
2448 def getControllingCondition(interfaceMember
, descriptor
):
2449 interface
= descriptor
.interface
2450 nonExposureSet
= interface
.exposureSet
- interfaceMember
.exposureSet
2452 trial
= PropertyDefiner
.getStringAttr(interfaceMember
, "Trial")
2453 if trial
and interface
.identifier
.name
in ["Window", "Document"]:
2455 "[Trial] not yet supported for %s.%s, see bug 1757935"
2456 % (interface
.identifier
.name
, interfaceMember
.identifier
.name
)
2459 return MemberCondition(
2460 PropertyDefiner
.getStringAttr(interfaceMember
, "Pref"),
2461 PropertyDefiner
.getStringAttr(interfaceMember
, "Func"),
2462 interfaceMember
.getExtendedAttribute("SecureContext") is not None,
2468 def generatePrefableArrayValues(
2475 switchToCondition
=None,
2478 This method generates an array of spec entries for interface members. It returns
2479 a tuple containing the array of spec entries and the maximum of the number of
2480 spec entries per condition.
2482 array is an array of interface members.
2484 descriptor is the descriptor for the interface that array contains members of.
2486 specFormatter is a function that takes a single argument, a tuple,
2487 and returns a string, a spec array entry.
2489 specTerminator is a terminator for the spec array (inserted every time
2490 our controlling pref changes and at the end of the array).
2492 getCondition is a callback function that takes an array entry and
2493 returns the corresponding MemberCondition.
2495 getDataTuple is a callback function that takes an array entry and
2496 returns a tuple suitable to be passed to specFormatter.
2498 switchToCondition is a function that takes a MemberCondition and an array of
2499 previously generated spec entries. If None is passed for this function then all
2500 the interface members should return the same value from getCondition.
2503 def unsupportedSwitchToCondition(condition
, specs
):
2504 # If no specs have been added yet then this is just the first call to
2505 # switchToCondition that we call to avoid putting a specTerminator at the
2506 # front of the list.
2509 raise "Not supported"
2511 if switchToCondition
is None:
2512 switchToCondition
= unsupportedSwitchToCondition
2515 numSpecsInCurPrefable
= 0
2516 maxNumSpecsInPrefable
= 0
2518 # So we won't put a specTerminator at the very front of the list:
2519 lastCondition
= getCondition(array
[0], descriptor
)
2521 switchToCondition(lastCondition
, specs
)
2523 for member
in array
:
2524 curCondition
= getCondition(member
, descriptor
)
2525 if lastCondition
!= curCondition
:
2526 # Terminate previous list
2527 specs
.append(specTerminator
)
2528 if numSpecsInCurPrefable
> maxNumSpecsInPrefable
:
2529 maxNumSpecsInPrefable
= numSpecsInCurPrefable
2530 numSpecsInCurPrefable
= 0
2531 # And switch to our new condition
2532 switchToCondition(curCondition
, specs
)
2533 lastCondition
= curCondition
2534 # And the actual spec
2535 specs
.append(specFormatter(getDataTuple(member
, descriptor
)))
2536 numSpecsInCurPrefable
+= 1
2537 if numSpecsInCurPrefable
> maxNumSpecsInPrefable
:
2538 maxNumSpecsInPrefable
= numSpecsInCurPrefable
2539 specs
.append(specTerminator
)
2541 return (specs
, maxNumSpecsInPrefable
)
2543 def generatePrefableArray(
2554 This method generates our various arrays.
2556 array is an array of interface members as passed to generateArray
2558 name is the name as passed to generateArray
2560 specFormatter is a function that takes a single argument, a tuple,
2561 and returns a string, a spec array entry
2563 specTerminator is a terminator for the spec array (inserted every time
2564 our controlling pref changes and at the end of the array)
2566 specType is the actual typename of our spec
2568 getCondition is a callback function that takes an array entry and
2569 returns the corresponding MemberCondition.
2571 getDataTuple is a callback function that takes an array entry and
2572 returns a tuple suitable to be passed to specFormatter.
2575 # We want to generate a single list of specs, but with specTerminator
2576 # inserted at every point where the pref name controlling the member
2577 # changes. That will make sure the order of the properties as exposed
2578 # on the interface and interface prototype objects does not change when
2579 # pref control is added to members while still allowing us to define all
2580 # the members in the smallest number of JSAPI calls.
2581 assert len(array
) != 0
2586 disablersTemplate
= dedent(
2588 static const PrefableDisablers %s_disablers%d = {
2593 prefableWithDisablersTemplate
= " { &%s_disablers%d, &%s_specs[%d] }"
2594 prefableWithoutDisablersTemplate
= " { nullptr, &%s_specs[%d] }"
2596 def switchToCondition(condition
, specs
):
2597 # Set up pointers to the new sets of specs inside prefableSpecs
2598 if condition
.hasDisablers():
2599 prefableSpecs
.append(
2600 prefableWithDisablersTemplate
% (name
, len(specs
), name
, len(specs
))
2607 condition
.prefFuncIndex
,
2608 condition
.nonExposedGlobals
,
2609 toStringBool(condition
.secureContext
),
2615 prefableSpecs
.append(
2616 prefableWithoutDisablersTemplate
% (name
, len(specs
))
2619 specs
, maxNumSpecsInPrefable
= self
.generatePrefableArrayValues(
2628 prefableSpecs
.append(" { nullptr, nullptr }")
2630 specType
= "const " + specType
2633 static ${specType} ${name}_specs[] = {
2638 static const Prefable<${specType}> ${name}[] = {
2645 disablers
="\n".join(disablers
),
2646 specs
=",\n".join(specs
),
2647 prefableSpecs
=",\n".join(prefableSpecs
),
2650 if self
.usedForXrays():
2654 static_assert(${numPrefableSpecs} <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX,
2655 "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)");
2656 static_assert(${maxNumSpecsInPrefable} <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX,
2657 "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)");
2661 # Minus 1 because there's a list terminator in prefableSpecs.
2662 numPrefableSpecs
=len(prefableSpecs
) - 1,
2663 maxNumSpecsInPrefable
=maxNumSpecsInPrefable
,
2669 # The length of a method is the minimum of the lengths of the
2670 # argument lists of all its overloads.
2671 def overloadLength(arguments
):
2673 while i
> 0 and arguments
[i
- 1].optional
:
2678 def methodLength(method
):
2679 signatures
= method
.signatures()
2680 return min(overloadLength(arguments
) for retType
, arguments
in signatures
)
2683 def clearableCachedAttrs(descriptor
):
2686 for m
in descriptor
.interface
.members
2688 # Constants should never need clearing!
2689 m
.dependsOn
!= "Nothing" and m
.slotIndices
is not None
2693 def MakeClearCachedValueNativeName(member
):
2694 return "ClearCached%sValue" % MakeNativeName(member
.identifier
.name
)
2697 def IDLToCIdentifier(name
):
2698 return name
.replace("-", "_")
2701 def EnumerabilityFlags(member
):
2702 if member
.getExtendedAttribute("NonEnumerable"):
2704 return "JSPROP_ENUMERATE"
2707 class MethodDefiner(PropertyDefiner
):
2709 A class for defining methods on a prototype object.
2712 def __init__(self
, descriptor
, name
, crossOriginOnly
, static
, unforgeable
=False):
2713 assert not (static
and unforgeable
)
2714 PropertyDefiner
.__init
__(self
, descriptor
, name
)
2716 # FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=772822
2717 # We should be able to check for special operations without an
2718 # identifier. For now we check if the name starts with __
2720 # Ignore non-static methods for interfaces without a proto object
2721 if descriptor
.interface
.hasInterfacePrototypeObject() or static
:
2724 for m
in descriptor
.interface
.members
2726 and m
.isStatic() == static
2727 and MemberIsLegacyUnforgeable(m
, descriptor
) == unforgeable
2729 not crossOriginOnly
or m
.getExtendedAttribute("CrossOriginCallable")
2731 and not m
.isIdentifierLess()
2732 and not m
.getExtendedAttribute("Unexposed")
2739 method
= self
.methodData(m
, descriptor
)
2742 method
["nativeName"] = CppKeywords
.checkMethodName(
2743 IDLToCIdentifier(m
.identifier
.name
)
2747 self
.chrome
.append(method
)
2749 self
.regular
.append(method
)
2751 # TODO: Once iterable is implemented, use tiebreak rules instead of
2752 # failing. Also, may be more tiebreak rules to implement once spec bug
2754 # https://www.w3.org/Bugs/Public/show_bug.cgi?id=28592
2755 def hasIterator(methods
, regular
):
2756 return any("@@iterator" in m
.aliases
for m
in methods
) or any(
2757 "@@iterator" == r
["name"] for r
in regular
2760 # Check whether we need to output an @@iterator due to having an indexed
2761 # getter. We only do this while outputting non-static and
2762 # non-unforgeable methods, since the @@iterator function will be
2764 if not static
and not unforgeable
and descriptor
.supportsIndexedProperties():
2765 if hasIterator(methods
, self
.regular
):
2767 "Cannot have indexed getter/attr on "
2768 "interface %s with other members "
2769 "that generate @@iterator, such as "
2770 "maplike/setlike or aliased functions."
2771 % self
.descriptor
.interface
.identifier
.name
2773 self
.regular
.append(
2775 "name": "@@iterator",
2776 "methodInfo": False,
2777 "selfHostedName": "$ArrayValues",
2779 "flags": "0", # Not enumerable, per spec.
2780 "condition": MemberCondition(),
2784 # Generate the keys/values/entries aliases for value iterables.
2785 maplikeOrSetlikeOrIterable
= descriptor
.interface
.maplikeOrSetlikeOrIterable
2789 and maplikeOrSetlikeOrIterable
2790 and maplikeOrSetlikeOrIterable
.isIterable()
2791 and maplikeOrSetlikeOrIterable
.isValueIterator()
2793 # Add our keys/values/entries/forEach
2794 self
.regular
.append(
2797 "methodInfo": False,
2798 "selfHostedName": "ArrayKeys",
2800 "flags": "JSPROP_ENUMERATE",
2801 "condition": PropertyDefiner
.getControllingCondition(
2802 maplikeOrSetlikeOrIterable
, descriptor
2806 self
.regular
.append(
2809 "methodInfo": False,
2810 "selfHostedName": "$ArrayValues",
2812 "flags": "JSPROP_ENUMERATE",
2813 "condition": PropertyDefiner
.getControllingCondition(
2814 maplikeOrSetlikeOrIterable
, descriptor
2818 self
.regular
.append(
2821 "methodInfo": False,
2822 "selfHostedName": "ArrayEntries",
2824 "flags": "JSPROP_ENUMERATE",
2825 "condition": PropertyDefiner
.getControllingCondition(
2826 maplikeOrSetlikeOrIterable
, descriptor
2830 self
.regular
.append(
2833 "methodInfo": False,
2834 "selfHostedName": "ArrayForEach",
2836 "flags": "JSPROP_ENUMERATE",
2837 "condition": PropertyDefiner
.getControllingCondition(
2838 maplikeOrSetlikeOrIterable
, descriptor
2844 stringifier
= descriptor
.operations
["Stringifier"]
2845 if stringifier
and unforgeable
== MemberIsLegacyUnforgeable(
2846 stringifier
, descriptor
2849 "name": GetWebExposedName(stringifier
, descriptor
),
2850 "nativeName": stringifier
.identifier
.name
,
2852 "flags": "JSPROP_ENUMERATE",
2853 "condition": PropertyDefiner
.getControllingCondition(
2854 stringifier
, descriptor
2857 if isChromeOnly(stringifier
):
2858 self
.chrome
.append(toStringDesc
)
2860 self
.regular
.append(toStringDesc
)
2861 if unforgeable
and descriptor
.interface
.getExtendedAttribute(
2864 # Synthesize our valueOf method
2865 self
.regular
.append(
2868 "selfHostedName": "Object_valueOf",
2869 "methodInfo": False,
2871 "flags": "0", # readonly/permanent added automatically.
2872 "condition": MemberCondition(),
2876 if descriptor
.interface
.isJSImplemented():
2878 if descriptor
.interface
.hasInterfaceObject():
2882 "nativeName": ("%s::_Create" % descriptor
.name
),
2883 "methodInfo": False,
2886 "condition": MemberCondition(),
2890 self
.unforgeable
= unforgeable
2893 if not descriptor
.interface
.hasInterfaceObject():
2894 # static methods go on the interface object
2895 assert not self
.hasChromeOnly() and not self
.hasNonChromeOnly()
2897 if not descriptor
.interface
.hasInterfacePrototypeObject():
2898 # non-static methods go on the interface prototype object
2899 assert not self
.hasChromeOnly() and not self
.hasNonChromeOnly()
2902 def methodData(m
, descriptor
, overrideFlags
=None):
2904 "name": m
.identifier
.name
,
2905 "methodInfo": not m
.isStatic(),
2906 "length": methodLength(m
),
2907 "flags": EnumerabilityFlags(m
)
2908 if (overrideFlags
is None)
2910 "condition": PropertyDefiner
.getControllingCondition(m
, descriptor
),
2911 "allowCrossOriginThis": m
.getExtendedAttribute("CrossOriginCallable"),
2912 "returnsPromise": m
.returnsPromise(),
2913 "hasIteratorAlias": "@@iterator" in m
.aliases
,
2917 def formatSpec(fields
):
2918 if fields
[0].startswith("@@"):
2919 fields
= (fields
[0][2:],) + fields
[1:]
2920 return " JS_SYM_FNSPEC(%s, %s, %s, %s, %s, %s)" % fields
2921 return ' JS_FNSPEC("%s", %s, %s, %s, %s, %s)' % fields
2924 def specData(m
, descriptor
, unforgeable
=False):
2925 def flags(m
, unforgeable
):
2926 unforgeable
= " | JSPROP_PERMANENT | JSPROP_READONLY" if unforgeable
else ""
2927 return m
["flags"] + unforgeable
2929 if "selfHostedName" in m
:
2930 selfHostedName
= '"%s"' % m
["selfHostedName"]
2931 assert not m
.get("methodInfo", True)
2932 accessor
= "nullptr"
2935 selfHostedName
= "nullptr"
2936 # When defining symbols, function name may not match symbol name
2937 methodName
= m
.get("methodName", m
["name"])
2938 accessor
= m
.get("nativeName", IDLToCIdentifier(methodName
))
2939 if m
.get("methodInfo", True):
2940 if m
.get("returnsPromise", False):
2941 exceptionPolicy
= "ConvertExceptionsToPromises"
2943 exceptionPolicy
= "ThrowExceptions"
2945 # Cast this in case the methodInfo is a
2946 # JSTypedMethodJitInfo.
2948 "reinterpret_cast<const JSJitInfo*>(&%s_methodinfo)" % accessor
2950 if m
.get("allowCrossOriginThis", False):
2952 "(GenericMethod<CrossOriginThisPolicy, %s>)" % exceptionPolicy
2954 elif descriptor
.interface
.hasDescendantWithCrossOriginMembers
:
2956 "(GenericMethod<MaybeCrossOriginObjectThisPolicy, %s>)"
2959 elif descriptor
.interface
.isOnGlobalProtoChain():
2961 "(GenericMethod<MaybeGlobalThisPolicy, %s>)" % exceptionPolicy
2964 accessor
= "(GenericMethod<NormalThisPolicy, %s>)" % exceptionPolicy
2966 if m
.get("returnsPromise", False):
2967 jitinfo
= "&%s_methodinfo" % accessor
2968 accessor
= "StaticMethodPromiseWrapper"
2977 flags(m
, unforgeable
),
2982 def condition(m
, d
):
2983 return m
["condition"]
2985 def generateArray(self
, array
, name
):
2989 return self
.generatePrefableArray(
2996 functools
.partial(self
.specData
, unforgeable
=self
.unforgeable
),
3000 class AttrDefiner(PropertyDefiner
):
3001 def __init__(self
, descriptor
, name
, crossOriginOnly
, static
, unforgeable
=False):
3002 assert not (static
and unforgeable
)
3003 PropertyDefiner
.__init
__(self
, descriptor
, name
)
3005 # Ignore non-static attributes for interfaces without a proto object
3006 if descriptor
.interface
.hasInterfacePrototypeObject() or static
:
3009 for m
in descriptor
.interface
.members
3011 and m
.isStatic() == static
3012 and MemberIsLegacyUnforgeable(m
, descriptor
) == unforgeable
3015 or m
.getExtendedAttribute("CrossOriginReadable")
3016 or m
.getExtendedAttribute("CrossOriginWritable")
3023 for attr
in idlAttrs
:
3024 attributes
.extend(self
.attrData(attr
, unforgeable
))
3025 self
.chrome
= [m
for m
in attributes
if isChromeOnly(m
["attr"])]
3026 self
.regular
= [m
for m
in attributes
if not isChromeOnly(m
["attr"])]
3027 self
.static
= static
3030 if not descriptor
.interface
.hasInterfaceObject():
3031 # static attributes go on the interface object
3032 assert not self
.hasChromeOnly() and not self
.hasNonChromeOnly()
3034 if not descriptor
.interface
.hasInterfacePrototypeObject():
3035 # non-static attributes go on the interface prototype object
3036 assert not self
.hasChromeOnly() and not self
.hasNonChromeOnly()
3039 def attrData(attr
, unforgeable
=False, overrideFlags
=None):
3040 if overrideFlags
is None:
3041 permanent
= " | JSPROP_PERMANENT" if unforgeable
else ""
3042 flags
= EnumerabilityFlags(attr
) + permanent
3044 flags
= overrideFlags
3046 {"name": name
, "attr": attr
, "flags": flags
}
3047 for name
in [attr
.identifier
.name
] + attr
.bindingAliases
3051 def condition(m
, d
):
3052 return PropertyDefiner
.getControllingCondition(m
["attr"], d
)
3055 def specData(entry
, descriptor
, static
=False, crossOriginOnly
=False):
3057 if crossOriginOnly
and not attr
.getExtendedAttribute("CrossOriginReadable"):
3058 return "nullptr, nullptr"
3060 if attr
.type.isPromise():
3062 "Don't know how to handle "
3063 "static Promise-returning "
3064 "attribute %s.%s" % (descriptor
.name
, attr
.identifier
.name
)
3066 accessor
= "get_" + IDLToCIdentifier(attr
.identifier
.name
)
3069 if attr
.type.isPromise():
3070 exceptionPolicy
= "ConvertExceptionsToPromises"
3072 exceptionPolicy
= "ThrowExceptions"
3074 if attr
.hasLegacyLenientThis():
3075 if attr
.getExtendedAttribute("CrossOriginReadable"):
3077 "Can't handle lenient cross-origin "
3078 "readable attribute %s.%s"
3079 % (descriptor
.name
, attr
.identifier
.name
)
3081 if descriptor
.interface
.hasDescendantWithCrossOriginMembers
:
3083 "GenericGetter<MaybeCrossOriginObjectLenientThisPolicy, %s>"
3088 "GenericGetter<LenientThisPolicy, %s>" % exceptionPolicy
3090 elif attr
.getExtendedAttribute("CrossOriginReadable"):
3092 "GenericGetter<CrossOriginThisPolicy, %s>" % exceptionPolicy
3094 elif descriptor
.interface
.hasDescendantWithCrossOriginMembers
:
3096 "GenericGetter<MaybeCrossOriginObjectThisPolicy, %s>"
3099 elif descriptor
.interface
.isOnGlobalProtoChain():
3101 "GenericGetter<MaybeGlobalThisPolicy, %s>" % exceptionPolicy
3104 accessor
= "GenericGetter<NormalThisPolicy, %s>" % exceptionPolicy
3105 jitinfo
= "&%s_getterinfo" % IDLToCIdentifier(attr
.identifier
.name
)
3106 return "%s, %s" % (accessor
, jitinfo
)
3111 and attr
.getExtendedAttribute("PutForwards") is None
3112 and attr
.getExtendedAttribute("Replaceable") is None
3113 and attr
.getExtendedAttribute("LegacyLenientSetter") is None
3115 return "nullptr, nullptr"
3116 if crossOriginOnly
and not attr
.getExtendedAttribute("CrossOriginWritable"):
3117 return "nullptr, nullptr"
3119 accessor
= "set_" + IDLToCIdentifier(attr
.identifier
.name
)
3122 if attr
.hasLegacyLenientThis():
3123 if attr
.getExtendedAttribute("CrossOriginWritable"):
3125 "Can't handle lenient cross-origin "
3126 "writable attribute %s.%s"
3127 % (descriptor
.name
, attr
.identifier
.name
)
3129 if descriptor
.interface
.hasDescendantWithCrossOriginMembers
:
3131 "GenericSetter<MaybeCrossOriginObjectLenientThisPolicy>"
3134 accessor
= "GenericSetter<LenientThisPolicy>"
3135 elif attr
.getExtendedAttribute("CrossOriginWritable"):
3136 accessor
= "GenericSetter<CrossOriginThisPolicy>"
3137 elif descriptor
.interface
.hasDescendantWithCrossOriginMembers
:
3138 accessor
= "GenericSetter<MaybeCrossOriginObjectThisPolicy>"
3139 elif descriptor
.interface
.isOnGlobalProtoChain():
3140 accessor
= "GenericSetter<MaybeGlobalThisPolicy>"
3142 accessor
= "GenericSetter<NormalThisPolicy>"
3143 jitinfo
= "&%s_setterinfo" % IDLToCIdentifier(attr
.identifier
.name
)
3144 return "%s, %s" % (accessor
, jitinfo
)
3146 name
, attr
, flags
= entry
["name"], entry
["attr"], entry
["flags"]
3147 return (name
, flags
, getter(attr
), setter(attr
))
3150 def formatSpec(fields
):
3151 return ' JSPropertySpec::nativeAccessors("%s", %s, %s, %s)' % fields
3153 def generateArray(self
, array
, name
):
3157 return self
.generatePrefableArray(
3164 functools
.partial(self
.specData
, static
=self
.static
),
3168 class ConstDefiner(PropertyDefiner
):
3170 A class for definining constants on the interface object
3173 def __init__(self
, descriptor
, name
):
3174 PropertyDefiner
.__init
__(self
, descriptor
, name
)
3176 constants
= [m
for m
in descriptor
.interface
.members
if m
.isConst()]
3177 self
.chrome
= [m
for m
in constants
if isChromeOnly(m
)]
3178 self
.regular
= [m
for m
in constants
if not isChromeOnly(m
)]
3180 def generateArray(self
, array
, name
):
3184 def specData(const
, descriptor
):
3185 return (const
.identifier
.name
, convertConstIDLValueToJSVal(const
.value
))
3187 return self
.generatePrefableArray(
3190 lambda fields
: ' { "%s", %s }' % fields
,
3191 " { 0, JS::UndefinedValue() }",
3193 PropertyDefiner
.getControllingCondition
,
3198 class PropertyArrays
:
3199 def __init__(self
, descriptor
, crossOriginOnly
=False):
3200 self
.staticMethods
= MethodDefiner(
3201 descriptor
, "StaticMethods", crossOriginOnly
, static
=True
3203 self
.staticAttrs
= AttrDefiner(
3204 descriptor
, "StaticAttributes", crossOriginOnly
, static
=True
3206 self
.methods
= MethodDefiner(
3207 descriptor
, "Methods", crossOriginOnly
, static
=False
3209 self
.attrs
= AttrDefiner(
3210 descriptor
, "Attributes", crossOriginOnly
, static
=False
3212 self
.unforgeableMethods
= MethodDefiner(
3214 "UnforgeableMethods",
3219 self
.unforgeableAttrs
= AttrDefiner(
3221 "UnforgeableAttributes",
3226 self
.consts
= ConstDefiner(descriptor
, "Constants")
3235 "unforgeableMethods",
3240 def hasChromeOnly(self
):
3241 return any(getattr(self
, a
).hasChromeOnly() for a
in self
.arrayNames())
3243 def hasNonChromeOnly(self
):
3244 return any(getattr(self
, a
).hasNonChromeOnly() for a
in self
.arrayNames())
3248 for array
in self
.arrayNames():
3249 define
+= str(getattr(self
, array
))
3253 class CGConstDefinition(CGThing
):
3255 Given a const member of an interface, return the C++ static const definition
3256 for the member. Should be part of the interface namespace in the header
3260 def __init__(self
, member
):
3263 and member
.value
.type.isPrimitive()
3264 and not member
.value
.type.nullable()
3267 name
= CppKeywords
.checkMethodName(IDLToCIdentifier(member
.identifier
.name
))
3268 tag
= member
.value
.type.tag()
3269 value
= member
.value
.value
3270 if tag
== IDLType
.Tags
.bool:
3271 value
= toStringBool(member
.value
.value
)
3272 self
.const
= "static const %s %s = %s;" % (builtinNames
[tag
], name
, value
)
3284 class CGNativeProperties(CGList
):
3285 def __init__(self
, descriptor
, properties
):
3286 def generateNativeProperties(name
, chrome
):
3288 return p
.hasChromeOnly() if chrome
else p
.hasNonChromeOnly()
3290 nativePropsInts
= []
3291 nativePropsPtrs
= []
3292 nativePropsDuos
= []
3296 for array
in properties
.arrayNames():
3297 propertyArray
= getattr(properties
, array
)
3298 if check(propertyArray
):
3299 varName
= propertyArray
.variableName(chrome
)
3300 bitfields
= "true, %d /* %s */" % (duosOffset
, varName
)
3302 nativePropsInts
.append(CGGeneric(bitfields
))
3304 if propertyArray
.usedForXrays():
3305 ids
= "&%s_propertyInfos[%d]" % (name
, idsOffset
)
3306 idsOffset
+= propertyArray
.length(chrome
)
3309 duo
= "{ %s, %s }" % (varName
, ids
)
3310 nativePropsDuos
.append(CGGeneric(duo
))
3312 bitfields
= "false, 0"
3313 nativePropsInts
.append(CGGeneric(bitfields
))
3315 iteratorAliasIndex
= -1
3316 for index
, item
in enumerate(properties
.methods
.regular
):
3317 if item
.get("hasIteratorAlias"):
3318 iteratorAliasIndex
= index
3320 nativePropsInts
.append(CGGeneric(str(iteratorAliasIndex
)))
3324 CGIndenter(CGList(nativePropsDuos
, ",\n")), pre
="{\n", post
="\n}"
3328 pre
= "static const NativePropertiesN<%d> %s = {\n" % (duosOffset
, name
)
3330 if descriptor
.wantsXrays
:
3333 static uint16_t ${name}_sortedPropertyIndices[${size}];
3334 static PropertyInfo ${name}_propertyInfos[${size}];
3342 if iteratorAliasIndex
> 0:
3343 # The iteratorAliasMethodIndex is a signed integer, so the
3344 # max value it can store is 2^(nbits-1)-1.
3348 static_assert(${iteratorAliasIndex} < 1ull << (CHAR_BIT * sizeof(${name}.iteratorAliasMethodIndex) - 1),
3349 "We have an iterator alias index that is oversized");
3352 iteratorAliasIndex
=iteratorAliasIndex
,
3358 static_assert(${propertyInfoCount} < 1ull << (CHAR_BIT * sizeof(${name}.propertyInfoCount)),
3359 "We have a property info count that is oversized");
3362 propertyInfoCount
=idsOffset
,
3365 nativePropsInts
.append(CGGeneric("%d" % idsOffset
))
3366 nativePropsPtrs
.append(CGGeneric("%s_sortedPropertyIndices" % name
))
3368 nativePropsInts
.append(CGGeneric("0"))
3369 nativePropsPtrs
.append(CGGeneric("nullptr"))
3370 nativeProps
= nativePropsInts
+ nativePropsPtrs
+ nativePropsDuos
3371 return CGWrapper(CGIndenter(CGList(nativeProps
, ",\n")), pre
=pre
, post
=post
)
3373 nativeProperties
= []
3374 if properties
.hasNonChromeOnly():
3375 nativeProperties
.append(
3376 generateNativeProperties("sNativeProperties", False)
3378 if properties
.hasChromeOnly():
3379 nativeProperties
.append(
3380 generateNativeProperties("sChromeOnlyNativeProperties", True)
3383 CGList
.__init
__(self
, nativeProperties
, "\n")
3389 return CGList
.define(self
)
3392 class CGCollectJSONAttributesMethod(CGAbstractMethod
):
3394 Generate the CollectJSONAttributes method for an interface descriptor
3397 def __init__(self
, descriptor
, toJSONMethod
):
3399 Argument("JSContext*", "cx"),
3400 Argument("JS::Handle<JSObject*>", "obj"),
3401 Argument("%s*" % descriptor
.nativeType
, "self"),
3402 Argument("JS::Rooted<JSObject*>&", "result"),
3404 CGAbstractMethod
.__init
__(
3405 self
, descriptor
, "CollectJSONAttributes", "bool", args
, canRunScript
=True
3407 self
.toJSONMethod
= toJSONMethod
3409 def definition_body(self
):
3411 interface
= self
.descriptor
.interface
3412 toJSONCondition
= PropertyDefiner
.getControllingCondition(
3413 self
.toJSONMethod
, self
.descriptor
3415 needUnwrappedObj
= False
3416 for m
in interface
.members
:
3417 if m
.isAttr() and not m
.isStatic() and m
.type.isJSONType():
3418 getAndDefine
= fill(
3420 JS::Rooted<JS::Value> temp(cx);
3421 if (!get_${name}(cx, obj, self, JSJitGetterCallArgs(&temp))) {
3424 if (!JS_DefineProperty(cx, result, "${name}", temp, JSPROP_ENUMERATE)) {
3428 name
=IDLToCIdentifier(m
.identifier
.name
),
3430 # Make sure we don't include things which are supposed to be
3431 # disabled. Things that either don't have disablers or whose
3432 # disablers match the disablers for our toJSON method can't
3433 # possibly be disabled, but other things might be.
3434 condition
= PropertyDefiner
.getControllingCondition(m
, self
.descriptor
)
3435 if condition
.hasDisablers() and condition
!= toJSONCondition
:
3436 needUnwrappedObj
= True
3439 // This is unfortunately a linear scan through sAttributes, but we
3440 // only do it for things which _might_ be disabled, which should
3441 // help keep the performance problems down.
3442 if (IsGetterEnabled(cx, unwrappedObj, (JSJitGetterOp)get_${name}, sAttributes)) {
3446 name
=IDLToCIdentifier(m
.identifier
.name
),
3447 getAndDefine
=getAndDefine
,
3452 { // scope for "temp"
3456 getAndDefine
=getAndDefine
,
3458 ret
+= "return true;\n"
3460 if needUnwrappedObj
:
3461 # If we started allowing cross-origin objects here, we'd need to
3462 # use CheckedUnwrapDynamic and figure out whether it makes sense.
3463 # But in practice no one is trying to add toJSON methods to those,
3464 # so let's just guard against it.
3465 assert not self
.descriptor
.isMaybeCrossOriginObject()
3468 JS::Rooted<JSObject*> unwrappedObj(cx, js::CheckedUnwrapStatic(obj));
3469 if (!unwrappedObj) {
3470 // How did that happen? We managed to get called with that
3471 // object as "this"! Just give up on sanity.
3483 class CGCreateInterfaceObjectsMethod(CGAbstractMethod
):
3485 Generate the CreateInterfaceObjects method for an interface descriptor.
3487 properties should be a PropertyArrays instance.
3491 self
, descriptor
, properties
, haveUnscopables
, haveLegacyWindowAliases
, static
3494 Argument("JSContext*", "aCx"),
3495 Argument("JS::Handle<JSObject*>", "aGlobal"),
3496 Argument("ProtoAndIfaceCache&", "aProtoAndIfaceCache"),
3497 Argument("bool", "aDefineOnGlobal"),
3499 CGAbstractMethod
.__init
__(
3500 self
, descriptor
, "CreateInterfaceObjects", "void", args
, static
=static
3502 self
.properties
= properties
3503 self
.haveUnscopables
= haveUnscopables
3504 self
.haveLegacyWindowAliases
= haveLegacyWindowAliases
3506 def definition_body(self
):
3507 needInterfaceObject
= self
.descriptor
.interface
.hasInterfaceObject()
3508 if needInterfaceObject
:
3509 (protoGetter
, protoHandleGetter
) = InterfaceObjectProtoGetter(
3512 if protoHandleGetter
is None:
3513 getConstructorProto
= "aCx, " + protoGetter
3514 constructorProtoType
= "Rooted"
3516 getConstructorProto
= protoHandleGetter
3517 constructorProtoType
= "Handle"
3519 getConstructorProto
= fill(
3521 JS::${type}<JSObject*> constructorProto(${getConstructorProto}(aCx));
3522 if (!constructorProto) {
3526 type=constructorProtoType
,
3527 getConstructorProto
=getConstructorProto
,
3530 interfaceInfo
= "&sInterfaceObjectInfo"
3532 "&aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::%s)"
3533 % self
.descriptor
.name
3535 getConstructorProto
= CGGeneric(getConstructorProto
)
3536 constructorProto
= "constructorProto"
3538 # We don't have slots to store the legacy factory functions.
3539 assert len(self
.descriptor
.interface
.legacyFactoryFunctions
) == 0
3540 interfaceInfo
= "nullptr"
3541 interfaceCache
= "nullptr"
3542 getConstructorProto
= None
3543 constructorProto
= "nullptr"
3545 if self
.properties
.hasNonChromeOnly():
3546 properties
= "sNativeProperties.Upcast()"
3548 properties
= "nullptr"
3549 if self
.properties
.hasChromeOnly():
3550 chromeProperties
= "sChromeOnlyNativeProperties.Upcast()"
3552 chromeProperties
= "nullptr"
3554 # We use getClassName here. This should be the right thing to pass as
3555 # the name argument to CreateInterfaceObjects. This is generally the
3556 # interface identifier, except for the synthetic interfaces created for
3557 # the default iterator objects. If needInterfaceObject is true then
3558 # we'll use the name to install a property on the global object, so
3559 # there shouldn't be any spaces in the name.
3560 name
= self
.descriptor
.interface
.getClassName()
3561 assert not (needInterfaceObject
and " " in name
)
3563 if self
.descriptor
.interface
.isNamespace():
3564 # If we don't need to create anything, why are we generating this?
3565 assert needInterfaceObject
3569 JS::Heap<JSObject*>* interfaceCache = ${interfaceCache};
3570 dom::CreateNamespaceObject(aCx, aGlobal, ${constructorProto},
3571 sNamespaceObjectClass,
3574 ${chromeProperties},
3575 "${name}", aDefineOnGlobal);
3577 interfaceCache
=interfaceCache
,
3578 constructorProto
=constructorProto
,
3579 properties
=properties
,
3580 chromeProperties
=chromeProperties
,
3585 getConstructorProto
,
3591 needInterfacePrototypeObject
= (
3592 self
.descriptor
.interface
.hasInterfacePrototypeObject()
3595 # If we don't need to create anything, why are we generating this?
3596 assert needInterfaceObject
or needInterfacePrototypeObject
3598 if needInterfacePrototypeObject
:
3599 (protoGetter
, protoHandleGetter
) = InterfacePrototypeObjectProtoGetter(
3602 if protoHandleGetter
is None:
3603 parentProtoType
= "Rooted"
3604 getParentProto
= "aCx, " + protoGetter
3606 parentProtoType
= "Handle"
3607 getParentProto
= protoHandleGetter
3609 getParentProto
= fill(
3611 JS::${type}<JSObject*> parentProto(${getParentProto}(aCx));
3616 type=parentProtoType
,
3617 getParentProto
=getParentProto
,
3620 protoClass
= "&sPrototypeClass"
3622 "&aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::%s)"
3623 % self
.descriptor
.name
3625 parentProto
= "parentProto"
3626 getParentProto
= CGGeneric(getParentProto
)
3628 protoClass
= "nullptr"
3629 protoCache
= "nullptr"
3630 parentProto
= "nullptr"
3631 getParentProto
= None
3633 if self
.descriptor
.interface
.ctor():
3634 constructArgs
= methodLength(self
.descriptor
.interface
.ctor())
3635 isConstructorChromeOnly
= isChromeOnly(self
.descriptor
.interface
.ctor())
3638 isConstructorChromeOnly
= False
3639 if len(self
.descriptor
.interface
.legacyFactoryFunctions
) > 0:
3640 legacyFactoryFunctions
= "Span(legacyFactoryFunctions)"
3642 legacyFactoryFunctions
= "Span<const LegacyFactoryFunction, 0>{}"
3644 isGlobal
= self
.descriptor
.isGlobal() is not None
3646 ensureCaches
= fill(
3648 JS::Heap<JSObject*>* protoCache = ${protoCache};
3649 JS::Heap<JSObject*>* interfaceCache = ${interfaceCache};
3651 protoCache
=protoCache
,
3652 interfaceCache
=interfaceCache
,
3656 dom::CreateInterfaceObjects(aCx, aGlobal, ${parentProto},
3657 ${protoClass}, protoCache,
3658 ${constructorProto}, ${interfaceInfo}, ${constructArgs}, ${isConstructorChromeOnly}, ${legacyFactoryFunctions},
3661 ${chromeProperties},
3662 "${name}", aDefineOnGlobal,
3665 ${legacyWindowAliases});
3667 protoClass
=protoClass
,
3668 parentProto
=parentProto
,
3669 constructorProto
=constructorProto
,
3670 interfaceInfo
=interfaceInfo
,
3671 constructArgs
=constructArgs
,
3672 isConstructorChromeOnly
=toStringBool(isConstructorChromeOnly
),
3673 legacyFactoryFunctions
=legacyFactoryFunctions
,
3674 properties
=properties
,
3675 chromeProperties
=chromeProperties
,
3677 unscopableNames
="unscopableNames" if self
.haveUnscopables
else "nullptr",
3678 isGlobal
=toStringBool(isGlobal
),
3679 legacyWindowAliases
="legacyWindowAliases"
3680 if self
.haveLegacyWindowAliases
3684 # If we fail after here, we must clear interface and prototype caches
3685 # using this code: intermediate failure must not expose the interface in
3686 # partially-constructed state. Note that every case after here needs an
3687 # interface prototype object.
3688 failureCode
= dedent(
3690 *protoCache = nullptr;
3691 if (interfaceCache) {
3692 *interfaceCache = nullptr;
3698 needProtoVar
= False
3701 m
for m
in self
.descriptor
.interface
.members
if m
.isMethod() and m
.aliases
3704 assert needInterfacePrototypeObject
3706 def defineAlias(alias
):
3707 if alias
== "@@iterator" or alias
== "@@asyncIterator":
3711 "JS::GetWellKnownSymbolKey(aCx, JS::SymbolCode::%s)" % name
3713 prop
= "%sId" % name
3714 getSymbolJSID
= CGGeneric(
3716 "JS::Rooted<jsid> ${prop}(aCx, ${symbolJSID});",
3718 symbolJSID
=symbolJSID
,
3721 defineFn
= "JS_DefinePropertyById"
3722 enumFlags
= "0" # Not enumerable, per spec.
3723 elif alias
.startswith("@@"):
3725 "Can't handle any well-known Symbol other than @@iterator and @@asyncIterator"
3728 getSymbolJSID
= None
3729 defineFn
= "JS_DefineProperty"
3730 prop
= '"%s"' % alias
3731 # XXX If we ever create non-enumerable properties that can
3732 # be aliased, we should consider making the aliases
3733 # match the enumerability of the property being aliased.
3734 enumFlags
= "JSPROP_ENUMERATE"
3741 if (!${defineFn}(aCx, proto, ${prop}, aliasedVal, ${enumFlags})) {
3747 enumFlags
=enumFlags
,
3748 failureCode
=failureCode
,
3755 def defineAliasesFor(m
):
3761 if (!JS_GetProperty(aCx, proto, \"${prop}\", &aliasedVal)) {
3765 failureCode
=failureCode
,
3766 prop
=m
.identifier
.name
,
3770 + [defineAlias(alias
) for alias
in sorted(m
.aliases
)]
3773 defineAliases
= CGList(
3778 // Set up aliases on the interface prototype object we just created.
3782 CGGeneric("JS::Rooted<JS::Value> aliasedVal(aCx);\n\n"),
3786 for m
in sorted(aliasedMembers
, key
=lambda m
: m
.identifier
.name
)
3791 defineAliases
= None
3793 # Globals handle unforgeables directly in Wrap() instead of
3796 self
.descriptor
.hasLegacyUnforgeableMembers
3797 and not self
.descriptor
.isGlobal()
3799 assert needInterfacePrototypeObject
3801 # We want to use the same JSClass and prototype as the object we'll
3802 # end up defining the unforgeable properties on in the end, so that
3803 # we can use JS_InitializePropertiesFromCompatibleNativeObject to do
3804 # a fast copy. In the case of proxies that's null, because the
3805 # expando object is a vanilla object, but in the case of other DOM
3806 # objects it's whatever our class is.
3807 if self
.descriptor
.proxy
:
3808 holderClass
= "nullptr"
3809 holderProto
= "nullptr"
3811 holderClass
= "sClass.ToJSClass()"
3812 holderProto
= "proto"
3814 createUnforgeableHolder
= CGGeneric(
3817 JS::Rooted<JSObject*> unforgeableHolder(
3818 aCx, JS_NewObjectWithoutMetadata(aCx, ${holderClass}, ${holderProto}));
3819 if (!unforgeableHolder) {
3823 holderProto
=holderProto
,
3824 holderClass
=holderClass
,
3825 failureCode
=failureCode
,
3828 defineUnforgeables
= InitUnforgeablePropertiesOnHolder(
3829 self
.descriptor
, self
.properties
, failureCode
3831 createUnforgeableHolder
= CGList(
3832 [createUnforgeableHolder
, defineUnforgeables
]
3835 installUnforgeableHolder
= CGGeneric(
3839 JS::SetReservedSlot(*protoCache, DOM_INTERFACE_PROTO_SLOTS_BASE,
3840 JS::ObjectValue(*unforgeableHolder));
3846 unforgeableHolderSetup
= CGList(
3847 [createUnforgeableHolder
, installUnforgeableHolder
], "\n"
3850 unforgeableHolderSetup
= None
3852 # FIXME Unclear whether this is needed for hasOrdinaryObjectPrototype
3854 self
.descriptor
.interface
.isOnGlobalProtoChain()
3855 and needInterfacePrototypeObject
3856 and not self
.descriptor
.hasOrdinaryObjectPrototype
3858 makeProtoPrototypeImmutable
= CGGeneric(
3863 if (!JS_SetImmutablePrototype(aCx, proto, &succeeded)) {
3867 MOZ_ASSERT(succeeded,
3868 "making a fresh prototype object's [[Prototype]] "
3869 "immutable can internally fail, but it should "
3870 "never be unsuccessful");
3873 protoCache
=protoCache
,
3874 failureCode
=failureCode
,
3879 makeProtoPrototypeImmutable
= None
3882 defineProtoVar
= CGGeneric(
3885 JS::AssertObjectIsNotGray(*protoCache);
3886 JS::Handle<JSObject*> proto = JS::Handle<JSObject*>::fromMarkedLocation(protoCache->address());
3891 failureCode
=failureCode
,
3895 defineProtoVar
= None
3897 # ensureCaches needs to come first as it crashes on failure (like OOM).
3898 # We want to make sure that the caches do exist before we try to return
3899 # to the caller, so it can rely on that (and detect other failures by
3900 # checking for null in the caches).
3903 CGGeneric(ensureCaches
),
3905 getConstructorProto
,
3909 unforgeableHolderSetup
,
3910 makeProtoPrototypeImmutable
,
3916 class CGGetProtoObjectHandleMethod(CGAbstractMethod
):
3918 A method for getting the interface prototype object.
3921 def __init__(self
, descriptor
, static
, signatureOnly
=False):
3922 CGAbstractMethod
.__init
__(
3925 "GetProtoObjectHandle",
3926 "JS::Handle<JSObject*>",
3927 [Argument("JSContext*", "aCx")],
3930 signatureOnly
=signatureOnly
,
3933 def definition_body(self
):
3936 /* Get the interface prototype object for this class. This will create the
3937 object as needed. */
3938 return GetPerInterfaceObjectHandle(aCx, prototypes::id::${name},
3939 &CreateInterfaceObjects,
3940 /* aDefineOnGlobal = */ true);
3943 name
=self
.descriptor
.name
,
3947 class CGGetProtoObjectMethod(CGAbstractMethod
):
3949 A method for getting the interface prototype object.
3952 def __init__(self
, descriptor
):
3953 CGAbstractMethod
.__init
__(
3958 [Argument("JSContext*", "aCx")],
3961 def definition_body(self
):
3962 return "return GetProtoObjectHandle(aCx);\n"
3965 class CGGetConstructorObjectHandleMethod(CGAbstractMethod
):
3967 A method for getting the interface constructor object.
3970 def __init__(self
, descriptor
):
3971 CGAbstractMethod
.__init
__(
3974 "GetConstructorObjectHandle",
3975 "JS::Handle<JSObject*>",
3977 Argument("JSContext*", "aCx"),
3978 Argument("bool", "aDefineOnGlobal", "true"),
3983 def definition_body(self
):
3986 /* Get the interface object for this class. This will create the object as
3989 return GetPerInterfaceObjectHandle(aCx, constructors::id::${name},
3990 &CreateInterfaceObjects,
3993 name
=self
.descriptor
.name
,
3997 class CGGetConstructorObjectMethod(CGAbstractMethod
):
3999 A method for getting the interface constructor object.
4002 def __init__(self
, descriptor
):
4003 CGAbstractMethod
.__init
__(
4006 "GetConstructorObject",
4008 [Argument("JSContext*", "aCx")],
4011 def definition_body(self
):
4012 return "return GetConstructorObjectHandle(aCx);\n"
4015 class CGGetNamedPropertiesObjectMethod(CGAbstractStaticMethod
):
4016 def __init__(self
, descriptor
):
4017 args
= [Argument("JSContext*", "aCx")]
4018 CGAbstractStaticMethod
.__init
__(
4019 self
, descriptor
, "GetNamedPropertiesObject", "JSObject*", args
4022 def definition_body(self
):
4023 parentProtoName
= self
.descriptor
.parentPrototypeName
4024 if parentProtoName
is None:
4026 parentProto
= "nullptr"
4028 getParentProto
= fill(
4030 JS::Rooted<JSObject*> parentProto(aCx, ${parent}::GetProtoObjectHandle(aCx));
4035 parent
=toBindingNamespace(parentProtoName
),
4037 parentProto
= "parentProto"
4040 /* Make sure our global is sane. Hopefully we can remove this sometime */
4041 JSObject* global = JS::CurrentGlobalOrNull(aCx);
4042 if (!(JS::GetClass(global)->flags & JSCLASS_DOM_GLOBAL)) {
4046 /* Check to see whether the named properties object has already been created */
4047 ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
4049 JS::Heap<JSObject*>& namedPropertiesObject = protoAndIfaceCache.EntrySlotOrCreate(namedpropertiesobjects::id::${ifaceName});
4050 if (!namedPropertiesObject) {
4052 namedPropertiesObject = ${nativeType}::CreateNamedPropertiesObject(aCx, ${parentProto});
4053 DebugOnly<const DOMIfaceAndProtoJSClass*> clasp =
4054 DOMIfaceAndProtoJSClass::FromJSClass(JS::GetClass(namedPropertiesObject));
4055 MOZ_ASSERT(clasp->mType == eNamedPropertiesObject,
4056 "Expected ${nativeType}::CreateNamedPropertiesObject to return a named properties object");
4057 MOZ_ASSERT(clasp->mNativeHooks,
4058 "The named properties object for ${nativeType} should have NativePropertyHooks.");
4059 MOZ_ASSERT(!clasp->mNativeHooks->mIndexedOrNamedNativeProperties ||
4060 !clasp->mNativeHooks->mIndexedOrNamedNativeProperties->mResolveOwnProperty,
4061 "Shouldn't resolve the properties of the named properties object for ${nativeType} for Xrays.");
4062 MOZ_ASSERT(!clasp->mNativeHooks->mIndexedOrNamedNativeProperties ||
4063 !clasp->mNativeHooks->mIndexedOrNamedNativeProperties->mEnumerateOwnProperties,
4064 "Shouldn't enumerate the properties of the named properties object for ${nativeType} for Xrays.");
4066 return namedPropertiesObject.get();
4068 getParentProto
=getParentProto
,
4069 ifaceName
=self
.descriptor
.name
,
4070 parentProto
=parentProto
,
4071 nativeType
=self
.descriptor
.nativeType
,
4075 def getRawConditionList(idlobj
, cxName
, objName
, ignoreSecureContext
=False):
4077 Get the list of conditions for idlobj (to be used in "is this enabled"
4078 checks). This will be returned as a CGList with " &&\n" as the separator,
4081 objName is the name of the object that we're working with, because some of
4082 our test functions want that.
4084 ignoreSecureContext is used only for constructors in which the WebIDL interface
4085 itself is already marked as [SecureContext]. There is no need to do the work twice.
4088 pref
= idlobj
.getExtendedAttribute("Pref")
4090 assert isinstance(pref
, list) and len(pref
) == 1
4091 conditions
.append("StaticPrefs::%s()" % prefIdentifier(pref
[0]))
4092 if isChromeOnly(idlobj
):
4093 conditions
.append("nsContentUtils::ThreadsafeIsSystemCaller(%s)" % cxName
)
4094 func
= idlobj
.getExtendedAttribute("Func")
4096 assert isinstance(func
, list) and len(func
) == 1
4097 conditions
.append("%s(%s, %s)" % (func
[0], cxName
, objName
))
4098 trial
= idlobj
.getExtendedAttribute("Trial")
4100 assert isinstance(trial
, list) and len(trial
) == 1
4102 "OriginTrials::IsEnabled(%s, %s, OriginTrial::%s)"
4103 % (cxName
, objName
, trial
[0])
4105 if not ignoreSecureContext
and idlobj
.getExtendedAttribute("SecureContext"):
4107 "mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(%s, %s)"
4113 def getConditionList(idlobj
, cxName
, objName
, ignoreSecureContext
=False):
4115 Get the list of conditions from getRawConditionList
4116 See comment on getRawConditionList above for more info about arguments.
4118 The return value is a possibly-empty conjunctive CGList of conditions.
4120 conditions
= getRawConditionList(idlobj
, cxName
, objName
, ignoreSecureContext
)
4121 return CGList((CGGeneric(cond
) for cond
in conditions
), " &&\n")
4124 class CGConstructorEnabled(CGAbstractMethod
):
4126 A method for testing whether we should be exposing this interface object.
4127 This can perform various tests depending on what conditions are specified
4131 def __init__(self
, descriptor
):
4132 CGAbstractMethod
.__init
__(
4135 "ConstructorEnabled",
4137 [Argument("JSContext*", "aCx"), Argument("JS::Handle<JSObject*>", "aObj")],
4140 def definition_body(self
):
4141 body
= CGList([], "\n")
4143 iface
= self
.descriptor
.interface
4145 if not iface
.isExposedInWindow():
4146 exposedInWindowCheck
= dedent(
4148 MOZ_ASSERT(!NS_IsMainThread(), "Why did we even get called?");
4151 body
.append(CGGeneric(exposedInWindowCheck
))
4153 if iface
.isExposedInSomeButNotAllWorkers():
4154 workerGlobals
= sorted(iface
.getWorkerExposureSet())
4155 workerCondition
= CGList(
4157 CGGeneric('strcmp(name, "%s")' % workerGlobal
)
4158 for workerGlobal
in workerGlobals
4162 exposedInWorkerCheck
= fill(
4164 const char* name = JS::GetClass(aObj)->name;
4165 if (${workerCondition}) {
4169 workerCondition
=workerCondition
.define(),
4171 exposedInWorkerCheck
= CGGeneric(exposedInWorkerCheck
)
4172 if iface
.isExposedInWindow():
4173 exposedInWorkerCheck
= CGIfWrapper(
4174 exposedInWorkerCheck
, "!NS_IsMainThread()"
4176 body
.append(exposedInWorkerCheck
)
4178 conditions
= getConditionList(iface
, "aCx", "aObj")
4180 # We should really have some conditions
4181 assert len(body
) or len(conditions
)
4183 conditionsWrapper
= ""
4185 conditionsWrapper
= CGWrapper(
4186 conditions
, pre
="return ", post
=";\n", reindent
=True
4189 conditionsWrapper
= CGGeneric("return true;\n")
4191 body
.append(conditionsWrapper
)
4192 return body
.define()
4195 def StructuredCloneTag(name
):
4196 return "SCTAG_DOM_%s" % name
.upper()
4199 class CGSerializer(CGAbstractStaticMethod
):
4201 Implementation of serialization for things marked [Serializable].
4202 This gets stored in our DOMJSClass, so it can be static.
4204 The caller is expected to pass in the object whose DOMJSClass it
4205 used to get the serializer.
4208 def __init__(self
, descriptor
):
4210 Argument("JSContext*", "aCx"),
4211 Argument("JSStructuredCloneWriter*", "aWriter"),
4212 Argument("JS::Handle<JSObject*>", "aObj"),
4214 CGAbstractStaticMethod
.__init
__(self
, descriptor
, "Serialize", "bool", args
)
4216 def definition_body(self
):
4219 MOZ_ASSERT(IsDOMObject(aObj), "Non-DOM object passed");
4220 MOZ_ASSERT(GetDOMClass(aObj)->mSerializer == &Serialize,
4221 "Wrong object passed");
4222 return JS_WriteUint32Pair(aWriter, ${tag}, 0) &&
4223 UnwrapDOMObject<${type}>(aObj)->WriteStructuredClone(aCx, aWriter);
4225 tag
=StructuredCloneTag(self
.descriptor
.name
),
4226 type=self
.descriptor
.nativeType
,
4230 class CGDeserializer(CGAbstractMethod
):
4232 Implementation of deserialization for things marked [Serializable].
4233 This will need to be accessed from WebIDLSerializable, so can't be static.
4236 def __init__(self
, descriptor
):
4238 Argument("JSContext*", "aCx"),
4239 Argument("nsIGlobalObject*", "aGlobal"),
4240 Argument("JSStructuredCloneReader*", "aReader"),
4242 CGAbstractMethod
.__init
__(self
, descriptor
, "Deserialize", "JSObject*", args
)
4244 def definition_body(self
):
4245 # WrapObject has different signatures depending on whether
4246 # the object is wrappercached.
4247 if self
.descriptor
.wrapperCache
:
4250 result = obj->WrapObject(aCx, nullptr);
4259 if (!obj->WrapObject(aCx, nullptr, &result)) {
4267 // Protect the result from a moving GC in ~RefPtr
4268 JS::Rooted<JSObject*> result(aCx);
4269 { // Scope for the RefPtr
4270 RefPtr<${type}> obj = ${type}::ReadStructuredClone(aCx, aGlobal, aReader);
4278 type=self
.descriptor
.nativeType
,
4283 def CreateBindingJSObject(descriptor
):
4284 objDecl
= "BindingJSObjectCreator<%s> creator(aCx);\n" % descriptor
.nativeType
4286 # We don't always need to root obj, but there are a variety
4287 # of cases where we do, so for simplicity, just always root it.
4288 if descriptor
.proxy
:
4289 if descriptor
.interface
.getExtendedAttribute("LegacyOverrideBuiltIns"):
4290 assert not descriptor
.isMaybeCrossOriginObject()
4293 aObject->mExpandoAndGeneration.expando.setUndefined();
4294 JS::Rooted<JS::Value> expandoValue(aCx, JS::PrivateValue(&aObject->mExpandoAndGeneration));
4295 creator.CreateProxyObject(aCx, &sClass.mBase, DOMProxyHandler::getInstance(),
4296 proto, /* aLazyProto = */ false, aObject,
4297 expandoValue, aReflector);
4301 if descriptor
.isMaybeCrossOriginObject():
4309 creator.CreateProxyObject(aCx, &sClass.mBase, DOMProxyHandler::getInstance(),
4310 ${proto}, /* aLazyProto = */ ${lazyProto},
4311 aObject, JS::UndefinedHandleValue, aReflector);
4314 lazyProto
=lazyProto
,
4319 creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector);
4335 def InitUnforgeablePropertiesOnHolder(
4336 descriptor
, properties
, failureCode
, holderName
="unforgeableHolder"
4339 Define the unforgeable properties on the unforgeable holder for
4340 the interface represented by descriptor.
4342 properties is a PropertyArrays instance.
4346 properties
.unforgeableAttrs
.hasNonChromeOnly()
4347 or properties
.unforgeableAttrs
.hasChromeOnly()
4348 or properties
.unforgeableMethods
.hasNonChromeOnly()
4349 or properties
.unforgeableMethods
.hasChromeOnly()
4354 defineUnforgeableAttrs
= fill(
4356 if (!DefineLegacyUnforgeableAttributes(aCx, ${holderName}, %s)) {
4360 failureCode
=failureCode
,
4361 holderName
=holderName
,
4363 defineUnforgeableMethods
= fill(
4365 if (!DefineLegacyUnforgeableMethods(aCx, ${holderName}, %s)) {
4369 failureCode
=failureCode
,
4370 holderName
=holderName
,
4373 unforgeableMembers
= [
4374 (defineUnforgeableAttrs
, properties
.unforgeableAttrs
),
4375 (defineUnforgeableMethods
, properties
.unforgeableMethods
),
4377 for template
, array
in unforgeableMembers
:
4378 if array
.hasNonChromeOnly():
4379 unforgeables
.append(CGGeneric(template
% array
.variableName(False)))
4380 if array
.hasChromeOnly():
4381 unforgeables
.append(
4383 CGGeneric(template
% array
.variableName(True)),
4384 "nsContentUtils::ThreadsafeIsSystemCaller(aCx)",
4388 if descriptor
.interface
.getExtendedAttribute("LegacyUnforgeable"):
4389 # We do our undefined toPrimitive here, not as a regular property
4390 # because we don't have a concept of value props anywhere in IDL.
4391 unforgeables
.append(
4395 JS::Rooted<JS::PropertyKey> toPrimitive(aCx,
4396 JS::GetWellKnownSymbolKey(aCx, JS::SymbolCode::toPrimitive));
4397 if (!JS_DefinePropertyById(aCx, ${holderName}, toPrimitive,
4398 JS::UndefinedHandleValue,
4399 JSPROP_READONLY | JSPROP_PERMANENT)) {
4403 failureCode
=failureCode
,
4404 holderName
=holderName
,
4409 return CGWrapper(CGList(unforgeables
), pre
="\n")
4412 def CopyUnforgeablePropertiesToInstance(descriptor
, failureCode
):
4414 Copy the unforgeable properties from the unforgeable holder for
4415 this interface to the instance object we have.
4417 assert not descriptor
.isGlobal()
4419 if not descriptor
.hasLegacyUnforgeableMembers
:
4426 // Important: do unforgeable property setup after we have handed
4427 // over ownership of the C++ object to obj as needed, so that if
4428 // we fail and it ends up GCed it won't have problems in the
4429 // finalizer trying to drop its ownership of the C++ object.
4435 # For proxies, we want to define on the expando object, not directly on the
4436 # reflector, so we can make sure we don't get confused by named getters.
4437 if descriptor
.proxy
:
4442 JS::Rooted<JSObject*> expando(aCx,
4443 DOMProxyHandler::EnsureExpandoObject(aCx, aReflector));
4448 failureCode
=failureCode
,
4460 JS::Rooted<JSObject*> unforgeableHolder(aCx,
4461 &JS::GetReservedSlot(canonicalProto, DOM_INTERFACE_PROTO_SLOTS_BASE).toObject());
4462 if (!JS_InitializePropertiesFromCompatibleNativeObject(aCx, ${obj}, unforgeableHolder)) {
4467 failureCode
=failureCode
,
4472 return CGWrapper(CGList(copyCode
), pre
="\n").define()
4475 def AssertInheritanceChain(descriptor
):
4476 # We can skip the reinterpret_cast check for the descriptor's nativeType
4477 # if aObject is a pointer of that type.
4480 static_assert(std::is_same_v<decltype(aObject), ${nativeType}*>);
4482 nativeType
=descriptor
.nativeType
,
4484 iface
= descriptor
.interface
4486 iface
= iface
.parent
4487 desc
= descriptor
.getDescriptor(iface
.identifier
.name
)
4489 "MOZ_ASSERT(static_cast<%s*>(aObject) == \n"
4490 " reinterpret_cast<%s*>(aObject),\n"
4491 ' "Multiple inheritance for %s is broken.");\n'
4492 % (desc
.nativeType
, desc
.nativeType
, desc
.nativeType
)
4494 asserts
+= "MOZ_ASSERT(ToSupportsIsCorrect(aObject));\n"
4498 def InitMemberSlots(descriptor
, failureCode
):
4500 Initialize member slots on our JS object if we're supposed to have some.
4502 Note that this is called after the SetWrapper() call in the
4503 wrapperCache case, since that can affect how our getters behave
4504 and we plan to invoke them here. So if we fail, we need to
4507 if not descriptor
.interface
.hasMembersInSlots():
4511 if (!UpdateMemberSlots(aCx, aReflector, aObject)) {
4515 failureCode
=failureCode
,
4519 def DeclareProto(descriptor
, noGivenProto
=False):
4521 Declare the canonicalProto and proto we have for our wrapping operation.
4523 getCanonical
= dedent(
4525 JS::Handle<JSObject*> ${canonicalProto} = GetProtoObjectHandle(aCx);
4526 if (!${canonicalProto}) {
4533 return fill(getCanonical
, canonicalProto
="proto")
4535 getCanonical
= fill(getCanonical
, canonicalProto
="canonicalProto")
4537 preamble
= getCanonical
+ dedent(
4539 JS::Rooted<JSObject*> proto(aCx);
4542 if descriptor
.isMaybeCrossOriginObject():
4543 return preamble
+ dedent(
4545 MOZ_ASSERT(!aGivenProto,
4546 "Shouldn't have constructors on cross-origin objects");
4547 // Set proto to canonicalProto to avoid preserving our wrapper if
4548 // we don't have to.
4549 proto = canonicalProto;
4553 return preamble
+ dedent(
4556 proto = aGivenProto;
4557 // Unfortunately, while aGivenProto was in the compartment of aCx
4558 // coming in, we changed compartments to that of "parent" so may need
4559 // to wrap the proto here.
4560 if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) {
4561 if (!JS_WrapObject(aCx, &proto)) {
4566 proto = canonicalProto;
4572 class CGWrapWithCacheMethod(CGAbstractMethod
):
4574 Create a wrapper JSObject for a given native that implements nsWrapperCache.
4577 def __init__(self
, descriptor
):
4578 assert descriptor
.interface
.hasInterfacePrototypeObject()
4580 Argument("JSContext*", "aCx"),
4581 Argument(descriptor
.nativeType
+ "*", "aObject"),
4582 Argument("nsWrapperCache*", "aCache"),
4583 Argument("JS::Handle<JSObject*>", "aGivenProto"),
4584 Argument("JS::MutableHandle<JSObject*>", "aReflector"),
4586 CGAbstractMethod
.__init
__(self
, descriptor
, "Wrap", "bool", args
)
4588 def definition_body(self
):
4589 failureCode
= dedent(
4591 aCache->ReleaseWrapper(aObject);
4592 aCache->ClearWrapper();
4597 if self
.descriptor
.proxy
:
4598 finalize
= "DOMProxyHandler::getInstance()->finalize"
4600 finalize
= FINALIZE_HOOK_NAME
4604 static_assert(!std::is_base_of_v<NonRefcountedDOMObject, ${nativeType}>,
4605 "Shouldn't have wrappercached things that are not refcounted.");
4606 $*{assertInheritance}
4607 MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx));
4608 MOZ_ASSERT(!aCache->GetWrapper(),
4609 "You should probably not be using Wrap() directly; use "
4610 "GetOrCreateDOMReflector instead");
4612 MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
4613 "nsISupports must be on our primary inheritance chain");
4615 // If the wrapper cache contains a dead reflector then finalize that
4616 // now, ensuring that the finalizer for the old reflector always
4617 // runs before the new reflector is created and attached. This
4618 // avoids the awkward situation where there are multiple reflector
4619 // objects that contain pointers to the same native.
4621 if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) {
4622 ${finalize}(nullptr /* unused */, oldReflector);
4623 MOZ_ASSERT(!aCache->GetWrapperMaybeDead());
4626 JS::Rooted<JSObject*> global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject()));
4630 MOZ_ASSERT(JS_IsGlobalObject(global));
4631 JS::AssertObjectIsNotGray(global);
4633 // That might have ended up wrapping us already, due to the wonders
4634 // of XBL. Check for that, and bail out as needed.
4635 aReflector.set(aCache->GetWrapper());
4638 AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto);
4643 JSAutoRealm ar(aCx, global);
4648 aCache->SetWrapper(aReflector);
4651 creator.InitializationSucceeded();
4653 MOZ_ASSERT(aCache->GetWrapperPreserveColor() &&
4654 aCache->GetWrapperPreserveColor() == aReflector);
4655 // If proto != canonicalProto, we have to preserve our wrapper;
4656 // otherwise we won't be able to properly recreate it later, since
4657 // we won't know what proto to use. Note that we don't check
4658 // aGivenProto here, since it's entirely possible (and even
4659 // somewhat common) to have a non-null aGivenProto which is the
4660 // same as canonicalProto.
4661 if (proto != canonicalProto) {
4662 PreserveWrapper(aObject);
4667 nativeType
=self
.descriptor
.nativeType
,
4668 assertInheritance
=AssertInheritanceChain(self
.descriptor
),
4669 declareProto
=DeclareProto(self
.descriptor
),
4670 createObject
=CreateBindingJSObject(self
.descriptor
),
4671 unforgeable
=CopyUnforgeablePropertiesToInstance(
4672 self
.descriptor
, failureCode
4674 slots
=InitMemberSlots(self
.descriptor
, failureCode
),
4679 class CGWrapMethod(CGAbstractMethod
):
4680 def __init__(self
, descriptor
):
4681 # XXX can we wrap if we don't have an interface prototype object?
4682 assert descriptor
.interface
.hasInterfacePrototypeObject()
4684 Argument("JSContext*", "aCx"),
4685 Argument("T*", "aObject"),
4686 Argument("JS::Handle<JSObject*>", "aGivenProto"),
4688 CGAbstractMethod
.__init
__(
4695 templateArgs
=["class T"],
4698 def definition_body(self
):
4701 JS::Rooted<JSObject*> reflector(aCx);
4702 return Wrap(aCx, aObject, aObject, aGivenProto, &reflector) ? reflector.get() : nullptr;
4707 class CGWrapNonWrapperCacheMethod(CGAbstractMethod
):
4709 Create a wrapper JSObject for a given native that does not implement
4713 def __init__(self
, descriptor
, static
=False, signatureOnly
=False):
4714 # XXX can we wrap if we don't have an interface prototype object?
4715 assert descriptor
.interface
.hasInterfacePrototypeObject()
4716 self
.noGivenProto
= (
4717 descriptor
.interface
.isIteratorInterface()
4718 or descriptor
.interface
.isAsyncIteratorInterface()
4721 Argument("JSContext*", "aCx"),
4722 Argument(descriptor
.nativeType
+ "*", "aObject"),
4724 if not self
.noGivenProto
:
4725 args
.append(Argument("JS::Handle<JSObject*>", "aGivenProto"))
4726 args
.append(Argument("JS::MutableHandle<JSObject*>", "aReflector"))
4727 CGAbstractMethod
.__init
__(
4734 signatureOnly
=signatureOnly
,
4737 def definition_body(self
):
4738 failureCode
= "return false;\n"
4740 declareProto
= DeclareProto(self
.descriptor
, noGivenProto
=self
.noGivenProto
)
4741 if self
.noGivenProto
:
4742 assertGivenProto
= ""
4744 assertGivenProto
= dedent(
4746 MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx));
4752 $*{assertGivenProto}
4754 JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
4763 creator.InitializationSucceeded();
4766 assertions
=AssertInheritanceChain(self
.descriptor
),
4767 assertGivenProto
=assertGivenProto
,
4768 declareProto
=declareProto
,
4769 createObject
=CreateBindingJSObject(self
.descriptor
),
4770 unforgeable
=CopyUnforgeablePropertiesToInstance(
4771 self
.descriptor
, failureCode
4773 slots
=InitMemberSlots(self
.descriptor
, failureCode
),
4777 class CGWrapGlobalMethod(CGAbstractMethod
):
4779 Create a wrapper JSObject for a global. The global must implement
4782 properties should be a PropertyArrays instance.
4785 def __init__(self
, descriptor
, properties
):
4786 assert descriptor
.interface
.hasInterfacePrototypeObject()
4788 Argument("JSContext*", "aCx"),
4789 Argument(descriptor
.nativeType
+ "*", "aObject"),
4790 Argument("nsWrapperCache*", "aCache"),
4791 Argument("JS::RealmOptions&", "aOptions"),
4792 Argument("JSPrincipals*", "aPrincipal"),
4793 Argument("JS::MutableHandle<JSObject*>", "aReflector"),
4795 CGAbstractMethod
.__init
__(self
, descriptor
, "Wrap", "bool", args
)
4796 self
.descriptor
= descriptor
4797 self
.properties
= properties
4799 def definition_body(self
):
4800 if self
.properties
.hasNonChromeOnly():
4801 properties
= "sNativeProperties.Upcast()"
4803 properties
= "nullptr"
4804 if self
.properties
.hasChromeOnly():
4805 chromeProperties
= "nsContentUtils::ThreadsafeIsSystemCaller(aCx) ? sChromeOnlyNativeProperties.Upcast() : nullptr"
4807 chromeProperties
= "nullptr"
4809 failureCode
= dedent(
4811 aCache->ReleaseWrapper(aObject);
4812 aCache->ClearWrapper();
4817 if self
.descriptor
.hasLegacyUnforgeableMembers
:
4818 unforgeable
= InitUnforgeablePropertiesOnHolder(
4819 self
.descriptor
, self
.properties
, failureCode
, "aReflector"
4824 if self
.descriptor
.hasOrdinaryObjectPrototype
:
4825 getProto
= "JS::GetRealmObjectPrototypeHandle"
4827 getProto
= "GetProtoObjectHandle"
4831 MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
4832 "nsISupports must be on our primary inheritance chain");
4834 if (!CreateGlobal<${nativeType}, ${getProto}>(aCx,
4844 // aReflector is a new global, so has a new realm. Enter it
4845 // before doing anything with it.
4846 JSAutoRealm ar(aCx, aReflector);
4848 if (!DefineProperties(aCx, aReflector, ${properties}, ${chromeProperties})) {
4857 assertions
=AssertInheritanceChain(self
.descriptor
),
4858 nativeType
=self
.descriptor
.nativeType
,
4860 properties
=properties
,
4861 chromeProperties
=chromeProperties
,
4862 failureCode
=failureCode
,
4863 unforgeable
=unforgeable
,
4864 slots
=InitMemberSlots(self
.descriptor
, failureCode
),
4868 class CGUpdateMemberSlotsMethod(CGAbstractStaticMethod
):
4869 def __init__(self
, descriptor
):
4871 Argument("JSContext*", "aCx"),
4872 Argument("JS::Handle<JSObject*>", "aWrapper"),
4873 Argument(descriptor
.nativeType
+ "*", "aObject"),
4875 CGAbstractStaticMethod
.__init
__(
4876 self
, descriptor
, "UpdateMemberSlots", "bool", args
4879 def definition_body(self
):
4880 body
= "JS::Rooted<JS::Value> temp(aCx);\n" "JSJitGetterCallArgs args(&temp);\n"
4881 for m
in self
.descriptor
.interface
.members
:
4882 if m
.isAttr() and m
.getExtendedAttribute("StoreInSlot"):
4883 # Skip doing this for the "window" and "self" attributes on the
4884 # Window interface, because those can't be gotten safely until
4885 # we have hooked it up correctly to the outer window. The
4886 # window code handles doing the get itself.
4887 if self
.descriptor
.interface
.identifier
.name
== "Window" and (
4888 m
.identifier
.name
== "window" or m
.identifier
.name
== "self"
4894 static_assert(${slot} < JS::shadow::Object::MAX_FIXED_SLOTS,
4895 "Not enough fixed slots to fit '${interface}.${member}. Ion's visitGetDOMMemberV/visitGetDOMMemberT assume StoreInSlot things are all in fixed slots.");
4896 if (!get_${member}(aCx, aWrapper, aObject, args)) {
4899 // Getter handled setting our reserved slots
4901 slot
=memberReservedSlot(m
, self
.descriptor
),
4902 interface
=self
.descriptor
.interface
.identifier
.name
,
4903 member
=m
.identifier
.name
,
4906 body
+= "\nreturn true;\n"
4910 class CGClearCachedValueMethod(CGAbstractMethod
):
4911 def __init__(self
, descriptor
, member
):
4912 self
.member
= member
4913 # If we're StoreInSlot, we'll need to call the getter
4914 if member
.getExtendedAttribute("StoreInSlot"):
4915 args
= [Argument("JSContext*", "aCx")]
4920 args
.append(Argument(descriptor
.nativeType
+ "*", "aObject"))
4921 name
= MakeClearCachedValueNativeName(member
)
4922 CGAbstractMethod
.__init
__(self
, descriptor
, name
, returnType
, args
)
4924 def definition_body(self
):
4925 slotIndex
= memberReservedSlot(self
.member
, self
.descriptor
)
4926 if self
.member
.getExtendedAttribute("StoreInSlot"):
4927 # We have to root things and save the old value in case
4928 # regetting fails, so we can restore it.
4929 declObj
= "JS::Rooted<JSObject*> obj(aCx);\n"
4930 noopRetval
= " true"
4932 "JS::Rooted<JS::Value> oldValue(aCx, JS::GetReservedSlot(obj, %s));\n"
4937 JS::Rooted<JS::Value> temp(aCx);
4938 JSJitGetterCallArgs args(&temp);
4939 JSAutoRealm ar(aCx, obj);
4940 if (!get_${name}(aCx, obj, aObject, args)) {
4941 JS::SetReservedSlot(obj, ${slotIndex}, oldValue);
4946 name
=self
.member
.identifier
.name
,
4947 slotIndex
=slotIndex
,
4950 declObj
= "JSObject* obj;\n"
4955 if self
.descriptor
.wantsXrays
:
4956 clearXrayExpandoSlots
= fill(
4958 xpc::ClearXrayExpandoSlots(obj, ${xraySlotIndex});
4960 xraySlotIndex
=memberXrayExpandoReservedSlot(
4961 self
.member
, self
.descriptor
4965 clearXrayExpandoSlots
= ""
4970 obj = aObject->GetWrapper();
4972 return${noopRetval};
4975 JS::SetReservedSlot(obj, ${slotIndex}, JS::UndefinedValue());
4976 $*{clearXrayExpandoSlots}
4980 noopRetval
=noopRetval
,
4981 saveMember
=saveMember
,
4982 slotIndex
=slotIndex
,
4983 clearXrayExpandoSlots
=clearXrayExpandoSlots
,
4984 regetMember
=regetMember
,
4988 class CGCrossOriginProperties(CGThing
):
4989 def __init__(self
, descriptor
):
4991 chromeOnlyAttrs
= []
4993 chromeOnlyMethods
= []
4994 for m
in descriptor
.interface
.members
:
4996 m
.getExtendedAttribute("CrossOriginReadable")
4997 or m
.getExtendedAttribute("CrossOriginWritable")
5001 "Don't know how to deal with static method %s"
5004 if PropertyDefiner
.getControllingCondition(
5008 "Don't know how to deal with disabler for %s"
5011 if len(m
.bindingAliases
) > 0:
5013 "Don't know how to deal with aliases for %s" % m
.identifier
.name
5015 if m
.getExtendedAttribute("ChromeOnly") is not None:
5016 chromeOnlyAttrs
.extend(AttrDefiner
.attrData(m
, overrideFlags
="0"))
5018 attrs
.extend(AttrDefiner
.attrData(m
, overrideFlags
="0"))
5019 elif m
.isMethod() and m
.getExtendedAttribute("CrossOriginCallable"):
5022 "Don't know how to deal with static method %s"
5025 if PropertyDefiner
.getControllingCondition(
5029 "Don't know how to deal with disabler for %s"
5032 if len(m
.aliases
) > 0:
5034 "Don't know how to deal with aliases for %s" % m
.identifier
.name
5036 if m
.getExtendedAttribute("ChromeOnly") is not None:
5037 chromeOnlyMethods
.append(
5038 MethodDefiner
.methodData(
5039 m
, descriptor
, overrideFlags
="JSPROP_READONLY"
5044 MethodDefiner
.methodData(
5045 m
, descriptor
, overrideFlags
="JSPROP_READONLY"
5050 self
.attributeSpecs
, _
= PropertyDefiner
.generatePrefableArrayValues(
5053 AttrDefiner
.formatSpec
,
5055 AttrDefiner
.condition
,
5056 functools
.partial(AttrDefiner
.specData
, crossOriginOnly
=True),
5059 self
.attributeSpecs
= [" JS_PS_END\n"]
5060 if len(methods
) > 0:
5061 self
.methodSpecs
, _
= PropertyDefiner
.generatePrefableArrayValues(
5064 MethodDefiner
.formatSpec
,
5066 MethodDefiner
.condition
,
5067 MethodDefiner
.specData
,
5070 self
.methodSpecs
= [" JS_FS_END\n"]
5072 if len(chromeOnlyAttrs
) > 0:
5074 self
.chromeOnlyAttributeSpecs
,
5076 ) = PropertyDefiner
.generatePrefableArrayValues(
5079 AttrDefiner
.formatSpec
,
5081 AttrDefiner
.condition
,
5082 functools
.partial(AttrDefiner
.specData
, crossOriginOnly
=True),
5085 self
.chromeOnlyAttributeSpecs
= []
5086 if len(chromeOnlyMethods
) > 0:
5087 self
.chromeOnlyMethodSpecs
, _
= PropertyDefiner
.generatePrefableArrayValues(
5090 MethodDefiner
.formatSpec
,
5092 MethodDefiner
.condition
,
5093 MethodDefiner
.specData
,
5096 self
.chromeOnlyMethodSpecs
= []
5101 extern const CrossOriginProperties sCrossOriginProperties;
5106 def defineChromeOnly(name
, specs
, specType
):
5108 return ("", "nullptr")
5109 name
= "sChromeOnlyCrossOrigin" + name
5112 static const ${specType} ${name}[] = {
5118 specs
=",\n".join(specs
),
5120 return (define
, name
)
5122 chromeOnlyAttributes
= defineChromeOnly(
5123 "Attributes", self
.chromeOnlyAttributeSpecs
, "JSPropertySpec"
5125 chromeOnlyMethods
= defineChromeOnly(
5126 "Methods", self
.chromeOnlyMethodSpecs
, "JSFunctionSpec"
5130 static const JSPropertySpec sCrossOriginAttributes[] = {
5133 static const JSFunctionSpec sCrossOriginMethods[] = {
5136 $*{chromeOnlyAttributeSpecs}
5137 $*{chromeOnlyMethodSpecs}
5138 const CrossOriginProperties sCrossOriginProperties = {
5139 sCrossOriginAttributes,
5140 sCrossOriginMethods,
5141 ${chromeOnlyAttributes},
5142 ${chromeOnlyMethods}
5145 attributeSpecs
=",\n".join(self
.attributeSpecs
),
5146 methodSpecs
=",\n".join(self
.methodSpecs
),
5147 chromeOnlyAttributeSpecs
=chromeOnlyAttributes
[0],
5148 chromeOnlyMethodSpecs
=chromeOnlyMethods
[0],
5149 chromeOnlyAttributes
=chromeOnlyAttributes
[1],
5150 chromeOnlyMethods
=chromeOnlyMethods
[1],
5154 class CGCycleCollectionTraverseForOwningUnionMethod(CGAbstractMethod
):
5156 ImplCycleCollectionUnlink for owning union type.
5159 def __init__(self
, type):
5162 Argument("nsCycleCollectionTraversalCallback&", "aCallback"),
5163 Argument("%s&" % CGUnionStruct
.unionTypeName(type, True), "aUnion"),
5164 Argument("const char*", "aName"),
5165 Argument("uint32_t", "aFlags", "0"),
5167 CGAbstractMethod
.__init
__(
5168 self
, None, "ImplCycleCollectionTraverse", "void", args
5172 return self
.type.getDeps()
5174 def definition_body(self
):
5176 getUnionMemberName(t
)
5177 for t
in self
.type.flatMemberTypes
5178 if idlTypeNeedsCycleCollection(t
)
5182 conditionTemplate
= "aUnion.Is%s()"
5183 functionCallTemplate
= (
5184 'ImplCycleCollectionTraverse(aCallback, aUnion.GetAs%s(), "m%s", aFlags);\n'
5188 CGIfWrapper(CGGeneric(functionCallTemplate
% (m
, m
)), conditionTemplate
% m
)
5189 for m
in memberNames
5192 return CGElseChain(ifStaments
).define()
5195 class CGCycleCollectionUnlinkForOwningUnionMethod(CGAbstractMethod
):
5197 ImplCycleCollectionUnlink for owning union type.
5200 def __init__(self
, type):
5202 args
= [Argument("%s&" % CGUnionStruct
.unionTypeName(type, True), "aUnion")]
5203 CGAbstractMethod
.__init
__(self
, None, "ImplCycleCollectionUnlink", "void", args
)
5206 return self
.type.getDeps()
5208 def definition_body(self
):
5209 return "aUnion.Uninit();\n"
5213 IDLType
.Tags
.bool: "bool",
5214 IDLType
.Tags
.int8
: "int8_t",
5215 IDLType
.Tags
.int16
: "int16_t",
5216 IDLType
.Tags
.int32
: "int32_t",
5217 IDLType
.Tags
.int64
: "int64_t",
5218 IDLType
.Tags
.uint8
: "uint8_t",
5219 IDLType
.Tags
.uint16
: "uint16_t",
5220 IDLType
.Tags
.uint32
: "uint32_t",
5221 IDLType
.Tags
.uint64
: "uint64_t",
5222 IDLType
.Tags
.unrestricted_float
: "float",
5223 IDLType
.Tags
.float: "float",
5224 IDLType
.Tags
.unrestricted_double
: "double",
5225 IDLType
.Tags
.double
: "double",
5229 IDLType
.Tags
.int8
: "",
5230 IDLType
.Tags
.uint8
: "",
5231 IDLType
.Tags
.int16
: "",
5232 IDLType
.Tags
.uint16
: "",
5233 IDLType
.Tags
.int32
: "",
5234 IDLType
.Tags
.uint32
: "U",
5235 IDLType
.Tags
.int64
: "LL",
5236 IDLType
.Tags
.uint64
: "ULL",
5237 IDLType
.Tags
.unrestricted_float
: "F",
5238 IDLType
.Tags
.float: "F",
5239 IDLType
.Tags
.unrestricted_double
: "",
5240 IDLType
.Tags
.double
: "",
5244 def numericValue(t
, v
):
5245 if t
== IDLType
.Tags
.unrestricted_double
or t
== IDLType
.Tags
.unrestricted_float
:
5246 typeName
= builtinNames
[t
]
5247 if v
== float("inf"):
5248 return "mozilla::PositiveInfinity<%s>()" % typeName
5249 if v
== float("-inf"):
5250 return "mozilla::NegativeInfinity<%s>()" % typeName
5252 return "mozilla::UnspecifiedNaN<%s>()" % typeName
5253 return "%s%s" % (v
, numericSuffixes
[t
])
5256 class CastableObjectUnwrapper
:
5258 A class for unwrapping an object stored in a JS Value (or
5259 MutableHandle<Value> or Handle<Value>) named by the "source" and
5260 "mutableSource" arguments based on the passed-in descriptor and storing it
5261 in a variable called by the name in the "target" argument. The "source"
5262 argument should be able to produce a Value or Handle<Value>; the
5263 "mutableSource" argument should be able to produce a MutableHandle<Value>
5265 codeOnFailure is the code to run if unwrapping fails.
5267 If isCallbackReturnValue is "JSImpl" and our descriptor is also
5268 JS-implemented, fall back to just creating the right object if what we
5269 have isn't one already.
5280 isCallbackReturnValue
=False,
5282 self
.substitution
= {
5283 "type": descriptor
.nativeType
,
5284 "protoID": "prototypes::id::" + descriptor
.name
,
5286 "codeOnFailure": codeOnFailure
,
5288 "mutableSource": mutableSource
,
5291 if isCallbackReturnValue
== "JSImpl" and descriptor
.interface
.isJSImplemented():
5292 exceptionCode
= exceptionCode
or codeOnFailure
5293 self
.substitution
["codeOnFailure"] = fill(
5295 // Be careful to not wrap random DOM objects here, even if
5296 // they're wrapped in opaque security wrappers for some reason.
5297 // XXXbz Wish we could check for a JS-implemented object
5298 // that already has a content reflection...
5299 if (!IsDOMObject(js::UncheckedUnwrap(&${source}.toObject()))) {
5300 nsCOMPtr<nsIGlobalObject> contentGlobal;
5301 JS::Rooted<JSObject*> callback(cx, CallbackOrNull());
5303 !GetContentGlobalForJSImplementedObject(cx, callback, getter_AddRefs(contentGlobal))) {
5306 JS::Rooted<JSObject*> jsImplSourceObj(cx, &${source}.toObject());
5307 MOZ_RELEASE_ASSERT(!js::IsWrapper(jsImplSourceObj),
5308 "Don't return JS implementations from other compartments");
5309 JS::Rooted<JSObject*> jsImplSourceGlobal(cx, JS::GetNonCCWObjectGlobal(jsImplSourceObj));
5310 ${target} = new ${type}(jsImplSourceObj, jsImplSourceGlobal, contentGlobal);
5315 exceptionCode
=exceptionCode
,
5316 **self
.substitution
,
5319 self
.substitution
["codeOnFailure"] = codeOnFailure
5322 substitution
= self
.substitution
.copy()
5323 substitution
["codeOnFailure"] %= {
5324 "securityError": "rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO"
5329 // Our JSContext should be in the right global to do unwrapping in.
5330 nsresult rv = UnwrapObject<${protoID}, ${type}>(${mutableSource}, ${target}, cx);
5331 if (NS_FAILED(rv)) {
5340 class FailureFatalCastableObjectUnwrapper(CastableObjectUnwrapper
):
5342 As CastableObjectUnwrapper, but defaulting to throwing if unwrapping fails
5352 isCallbackReturnValue
,
5355 CastableObjectUnwrapper
.__init
__(
5361 'cx.ThrowErrorMessage<MSG_DOES_NOT_IMPLEMENT_INTERFACE>("%s", "%s");\n'
5363 % (sourceDescription
, descriptor
.interface
.identifier
.name
, exceptionCode
),
5365 isCallbackReturnValue
,
5369 def getCallbackConversionInfo(
5370 type, idlObject
, isMember
, isCallbackReturnValue
, isOptional
5373 Returns a tuple containing the declType, declArgs, and basic
5374 conversion for the given callback type, with the given callback
5375 idl object in the given context (isMember/isCallbackReturnValue/isOptional).
5377 name
= idlObject
.identifier
.name
5379 # We can't use fast callbacks if isOptional because then we get an
5380 # Optional<RootedCallback> thing, which is not transparent to consumers.
5382 (not isMember
or isMember
== "Union")
5383 and not isCallbackReturnValue
5387 name
= "binding_detail::Fast%s" % name
5389 args
= "&${val}.toObject(), JS::CurrentGlobalOrNull(cx)"
5393 JS::Rooted<JSObject*> tempRoot(cx, &${val}.toObject());
5394 JS::Rooted<JSObject*> tempGlobalRoot(cx, JS::CurrentGlobalOrNull(cx));
5397 args
= "cx, tempRoot, tempGlobalRoot, GetIncumbentGlobal()"
5399 if type.nullable() or isCallbackReturnValue
:
5400 declType
= CGGeneric("RefPtr<%s>" % name
)
5402 declType
= CGGeneric("OwningNonNull<%s>" % name
)
5405 declType
= CGTemplatedType("RootedCallback", declType
)
5412 { // scope for tempRoot and tempGlobalRoot if needed
5414 $${declName} = new ${name}(${args});
5421 return (declType
, declArgs
, conversion
)
5424 class JSToNativeConversionInfo
:
5426 An object representing information about a JS-to-native conversion.
5434 dealWithOptional
=False,
5439 template: A string representing the conversion code. This will have
5440 template substitution performed on it as follows:
5442 ${val} is a handle to the JS::Value in question
5443 ${maybeMutableVal} May be a mutable handle to the JS::Value in
5444 question. This is only OK to use if ${val} is
5445 known to not be undefined.
5446 ${holderName} replaced by the holder's name, if any
5447 ${declName} replaced by the declaration's name
5448 ${haveValue} replaced by an expression that evaluates to a boolean
5449 for whether we have a JS::Value. Only used when
5450 defaultValue is not None or when True is passed for
5451 checkForValue to instantiateJSToNativeConversion.
5452 This expression may not be already-parenthesized, so if
5453 you use it with && or || make sure to put parens
5455 ${passedToJSImpl} replaced by an expression that evaluates to a boolean
5456 for whether this value is being passed to a JS-
5457 implemented interface.
5459 declType: A CGThing representing the native C++ type we're converting
5460 to. This is allowed to be None if the conversion code is
5461 supposed to be used as-is.
5463 holderType: A CGThing representing the type of a "holder" which will
5464 hold a possible reference to the C++ thing whose type we
5465 returned in declType, or None if no such holder is needed.
5467 dealWithOptional: A boolean indicating whether the caller has to do
5468 optional-argument handling. This should only be set
5469 to true if the JS-to-native conversion is being done
5470 for an optional argument or dictionary member with no
5471 default value and if the returned template expects
5472 both declType and holderType to be wrapped in
5473 Optional<>, with ${declName} and ${holderName}
5474 adjusted to point to the Value() of the Optional, and
5475 Construct() calls to be made on the Optional<>s as
5478 declArgs: If not None, the arguments to pass to the ${declName}
5479 constructor. These will have template substitution performed
5480 on them so you can use things like ${val}. This is a
5481 single string, not a list of strings.
5483 holderArgs: If not None, the arguments to pass to the ${holderName}
5484 constructor. These will have template substitution
5485 performed on them so you can use things like ${val}.
5486 This is a single string, not a list of strings.
5488 ${declName} must be in scope before the code from 'template' is entered.
5490 If holderType is not None then ${holderName} must be in scope before
5491 the code from 'template' is entered.
5493 assert isinstance(template
, str)
5494 assert declType
is None or isinstance(declType
, CGThing
)
5495 assert holderType
is None or isinstance(holderType
, CGThing
)
5496 self
.template
= template
5497 self
.declType
= declType
5498 self
.holderType
= holderType
5499 self
.dealWithOptional
= dealWithOptional
5500 self
.declArgs
= declArgs
5501 self
.holderArgs
= holderArgs
5504 def getHandleDefault(defaultValue
):
5505 tag
= defaultValue
.type.tag()
5506 if tag
in numericSuffixes
:
5507 # Some numeric literals require a suffix to compile without warnings
5508 return numericValue(tag
, defaultValue
.value
)
5509 assert tag
== IDLType
.Tags
.bool
5510 return toStringBool(defaultValue
.value
)
5513 def handleDefaultStringValue(defaultValue
, method
):
5515 Returns a string which ends up calling 'method' with a (char_t*, length)
5516 pair that sets this string default value. This string is suitable for
5517 passing as the second argument of handleDefault.
5520 defaultValue
.type.isDOMString()
5521 or defaultValue
.type.isUSVString()
5522 or defaultValue
.type.isUTF8String()
5523 or defaultValue
.type.isByteString()
5525 # There shouldn't be any non-ASCII or embedded nulls in here; if
5526 # it ever sneaks in we will need to think about how to properly
5527 # represent that in the C++.
5528 assert all(ord(c
) < 128 and ord(c
) > 0 for c
in defaultValue
.value
)
5529 if defaultValue
.type.isByteString() or defaultValue
.type.isUTF8String():
5535 ${method}(${prefix}"${value}");
5539 value
=defaultValue
.value
,
5543 def recordKeyType(recordType
):
5544 assert recordType
.keyType
.isString()
5545 if recordType
.keyType
.isByteString() or recordType
.keyType
.isUTF8String():
5550 def recordKeyDeclType(recordType
):
5551 return CGGeneric(recordKeyType(recordType
))
5554 def initializerForType(type):
5556 Get the right initializer for the given type for a data location where we
5557 plan to then initialize it from a JS::Value. Some types need to always be
5558 initialized even before we start the JS::Value-to-IDL-value conversion.
5560 Returns a string or None if no initialization is needed.
5564 # We could probably return CGDictionary.getNonInitializingCtorArg() for the
5565 # dictionary case, but code outside DictionaryBase subclasses can't use
5566 # that, so we can't do it across the board.
5570 # If this function is modified, modify CGNativeMember.getArg and
5571 # CGNativeMember.getRetvalInfo accordingly. The latter cares about the decltype
5572 # and holdertype we end up using, because it needs to be able to return the code
5573 # that will convert those to the actual return value of the callback function.
5574 def getJSToNativeConversionInfo(
5578 isDefinitelyObject
=False,
5581 invalidEnumValueFatal
=True,
5583 isNullOrUndefined
=False,
5584 isKnownMissing
=False,
5586 lenientFloatCode
=None,
5587 allowTreatNonCallableAsNull
=False,
5588 isCallbackReturnValue
=False,
5589 sourceDescription
="value",
5593 Get a template for converting a JS value to a native object based on the
5594 given type and descriptor. If failureCode is given, then we're actually
5595 testing whether we can convert the argument to the desired type. That
5596 means that failures to convert due to the JS value being the wrong type of
5597 value need to use failureCode instead of throwing exceptions. Failures to
5598 convert that are due to JS exceptions (from toString or valueOf methods) or
5599 out of memory conditions need to throw exceptions no matter what
5600 failureCode is. However what actually happens when throwing an exception
5601 can be controlled by exceptionCode. The only requirement on that is that
5602 exceptionCode must end up doing a return, and every return from this
5603 function must happen via exceptionCode if exceptionCode is not None.
5605 If isDefinitelyObject is True, that means we have a value and the value
5606 tests true for isObject(), so we have no need to recheck that.
5608 If isNullOrUndefined is True, that means we have a value and the value
5609 tests true for isNullOrUndefined(), so we have no need to recheck that.
5611 If isKnownMissing is True, that means that we are known-missing, and for
5612 cases when we have a default value we only need to output the default value.
5614 if isMember is not False, we're being converted from a property of some JS
5615 object, not from an actual method argument, so we can't rely on our jsval
5616 being rooted or outliving us in any way. Callers can pass "Dictionary",
5617 "Variadic", "Sequence", "Union", or "OwningUnion" to indicate that the conversion
5618 is for something that is a dictionary member, a variadic argument, a sequence,
5619 an union, or an owning union respectively.
5620 XXX Once we swtich *Rooter to Rooted* for Record and Sequence type entirely,
5621 we could remove "Union" from isMember.
5623 If isOptional is true, then we are doing conversion of an optional
5624 argument with no default value.
5626 invalidEnumValueFatal controls whether an invalid enum value conversion
5627 attempt will throw (if true) or simply return without doing anything (if
5630 If defaultValue is not None, it's the IDL default value for this conversion
5632 If isEnforceRange is true, we're converting an integer and throwing if the
5633 value is out of range.
5635 If isClamp is true, we're converting an integer and clamping if the
5636 value is out of range.
5638 If isAllowShared is false, we're converting a buffer source and throwing if
5639 it is a SharedArrayBuffer or backed by a SharedArrayBuffer.
5641 If lenientFloatCode is not None, it should be used in cases when
5642 we're a non-finite float that's not unrestricted.
5644 If allowTreatNonCallableAsNull is true, then [TreatNonCallableAsNull] and
5645 [LegacyTreatNonObjectAsNull] extended attributes on nullable callback functions
5648 If isCallbackReturnValue is "JSImpl" or "Callback", then the declType may be
5649 adjusted to make it easier to return from a callback. Since that type is
5650 never directly observable by any consumers of the callback code, this is OK.
5651 Furthermore, if isCallbackReturnValue is "JSImpl", that affects the behavior
5652 of the FailureFatalCastableObjectUnwrapper conversion; this is used for
5653 implementing auto-wrapping of JS-implemented return values from a
5654 JS-implemented interface.
5656 sourceDescription is a description of what this JS value represents, to be
5657 used in error reporting. Callers should assume that it might get placed in
5658 the middle of a sentence. If it ends up at the beginning of a sentence, its
5659 first character will be automatically uppercased.
5661 The return value from this function is a JSToNativeConversionInfo.
5663 # If we have a defaultValue then we're not actually optional for
5664 # purposes of what we need to be declared as.
5665 assert defaultValue
is None or not isOptional
5667 # Also, we should not have a defaultValue if we know we're an object
5668 assert not isDefinitelyObject
or defaultValue
is None
5670 # And we can't both be an object and be null or undefined
5671 assert not isDefinitelyObject
or not isNullOrUndefined
5673 isClamp
= type.hasClamp()
5674 isEnforceRange
= type.hasEnforceRange()
5675 isAllowShared
= type.hasAllowShared()
5677 # If exceptionCode is not set, we'll just rethrow the exception we got.
5678 # Note that we can't just set failureCode to exceptionCode, because setting
5679 # failureCode will prevent pending exceptions from being set in cases when
5680 # they really should be!
5681 if exceptionCode
is None:
5682 exceptionCode
= "return false;\n"
5684 # Unfortunately, .capitalize() on a string will lowercase things inside the
5685 # string, which we do not want.
5686 def firstCap(string
):
5687 return string
[0].upper() + string
[1:]
5689 # Helper functions for dealing with failures due to the JS value being the
5690 # wrong type of value
5691 def onFailureNotAnObject(failureCode
):
5695 'cx.ThrowErrorMessage<MSG_NOT_OBJECT>("%s");\n'
5696 "%s" % (firstCap(sourceDescription
), exceptionCode
)
5700 def onFailureBadType(failureCode
, typeName
):
5704 'cx.ThrowErrorMessage<MSG_DOES_NOT_IMPLEMENT_INTERFACE>("%s", "%s");\n'
5705 "%s" % (firstCap(sourceDescription
), typeName
, exceptionCode
)
5709 # It's a failure in the committed-to conversion, not a failure to match up
5710 # to a type, so we don't want to use failureCode in here. We want to just
5711 # throw an exception unconditionally.
5712 def onFailureIsShared():
5714 'cx.ThrowErrorMessage<MSG_TYPEDARRAY_IS_SHARED>("%s");\n'
5715 "%s" % (firstCap(sourceDescription
), exceptionCode
)
5718 def onFailureIsLarge():
5720 'cx.ThrowErrorMessage<MSG_TYPEDARRAY_IS_LARGE>("%s");\n'
5721 "%s" % (firstCap(sourceDescription
), exceptionCode
)
5724 def onFailureIsResizable():
5726 'cx.ThrowErrorMessage<MSG_TYPEDARRAY_IS_RESIZABLE>("%s");\n'
5727 "%s" % (firstCap(sourceDescription
), exceptionCode
)
5730 def onFailureNotCallable(failureCode
):
5734 'cx.ThrowErrorMessage<MSG_NOT_CALLABLE>("%s");\n'
5735 "%s" % (firstCap(sourceDescription
), exceptionCode
)
5739 # A helper function for handling default values. Takes a template
5740 # body and the C++ code to set the default value and wraps the
5741 # given template body in handling for the default value.
5742 def handleDefault(template
, setDefault
):
5743 if defaultValue
is None:
5749 // scope for any temporaries our default value setting needs.
5753 setDefault
=setDefault
,
5757 if ($${haveValue}) {
5763 templateBody
=template
,
5764 setDefault
=setDefault
,
5767 # A helper function for wrapping up the template body for
5768 # possibly-nullable objecty stuff
5769 def wrapObjectTemplate(templateBody
, type, codeToSetNull
, failureCode
=None):
5770 if isNullOrUndefined
and type.nullable():
5771 # Just ignore templateBody and set ourselves to null.
5772 # Note that we don't have to worry about default values
5773 # here either, since we already examined this value.
5774 return codeToSetNull
5776 if not isDefinitelyObject
:
5777 # Handle the non-object cases by wrapping up the whole
5778 # thing in an if cascade.
5780 elifLine
= "} else if (${val}.isNullOrUndefined()) {\n"
5781 elifBody
= codeToSetNull
5786 # Note that $${val} below expands to ${val}. This string is
5787 # used as a template later, and val will be filled in then.
5788 templateBody
= fill(
5790 if ($${val}.isObject()) {
5798 templateBody
=templateBody
,
5801 failureBody
=onFailureNotAnObject(failureCode
).define(),
5804 if isinstance(defaultValue
, IDLNullValue
):
5805 assert type.nullable() # Parser should enforce this
5806 templateBody
= handleDefault(templateBody
, codeToSetNull
)
5807 elif isinstance(defaultValue
, IDLEmptySequenceValue
):
5808 # Our caller will handle it
5811 assert defaultValue
is None
5815 # A helper function for converting things that look like a JSObject*.
5816 def handleJSObjectType(
5817 type, isMember
, failureCode
, exceptionCode
, sourceDescription
5819 if not isMember
or isMember
== "Union":
5821 # We have a specialization of Optional that will use a
5822 # Rooted for the storage here.
5823 declType
= CGGeneric("JS::Handle<JSObject*>")
5825 declType
= CGGeneric("JS::Rooted<JSObject*>")
5828 assert isMember
in (
5835 # We'll get traced by the sequence or dictionary or union tracer
5836 declType
= CGGeneric("JSObject*")
5838 templateBody
= "${declName} = &${val}.toObject();\n"
5840 # For JS-implemented APIs, we refuse to allow passing objects that the
5841 # API consumer does not subsume. The extra parens around
5842 # ($${passedToJSImpl}) suppress unreachable code warnings when
5843 # $${passedToJSImpl} is the literal `false`. But Apple is shipping a
5844 # buggy clang (clang 3.9) in Xcode 8.3, so there even the parens are not
5845 # enough. So we manually disable some warnings in clang.
5847 not isinstance(descriptorProvider
, Descriptor
)
5848 or descriptorProvider
.interface
.isJSImplemented()
5854 #pragma clang diagnostic push
5855 #pragma clang diagnostic ignored "-Wunreachable-code"
5856 #pragma clang diagnostic ignored "-Wunreachable-code-return"
5858 if (($${passedToJSImpl}) && !CallerSubsumes($${val})) {
5859 cx.ThrowErrorMessage<MSG_PERMISSION_DENIED_TO_PASS_ARG>("${sourceDescription}");
5863 #pragma clang diagnostic pop
5866 sourceDescription
=sourceDescription
,
5867 exceptionCode
=exceptionCode
,
5872 setToNullCode
= "${declName} = nullptr;\n"
5873 template
= wrapObjectTemplate(templateBody
, type, setToNullCode
, failureCode
)
5874 return JSToNativeConversionInfo(
5875 template
, declType
=declType
, dealWithOptional
=isOptional
, declArgs
=declArgs
5878 def incrementNestingLevel():
5879 if nestingLevel
== "":
5881 return nestingLevel
+ 1
5883 assert not (isEnforceRange
and isClamp
) # These are mutually exclusive
5885 if type.isSequence() or type.isObservableArray():
5886 assert not isEnforceRange
and not isClamp
and not isAllowShared
5888 if failureCode
is None:
5890 'cx.ThrowErrorMessage<MSG_CONVERSION_ERROR>("%s", "%s");\n'
5893 firstCap(sourceDescription
),
5894 "sequence" if type.isSequence() else "observable array",
5899 notSequence
= failureCode
5901 nullable
= type.nullable()
5902 # Be very careful not to change "type": we need it later
5904 elementType
= type.inner
.inner
5906 elementType
= type.inner
5908 # We want to use auto arrays if we can, but we have to be careful with
5909 # reallocation behavior for arrays. In particular, if we use auto
5910 # arrays for sequences and have a sequence of elements which are
5911 # themselves sequences or have sequences as members, we have a problem.
5912 # In that case, resizing the outermost AutoTArray to the right size
5913 # will memmove its elements, but AutoTArrays are not memmovable and
5914 # hence will end up with pointers to bogus memory, which is bad. To
5915 # deal with this, we typically map WebIDL sequences to our Sequence
5916 # type, which is in fact memmovable. The one exception is when we're
5917 # passing in a sequence directly as an argument without any sort of
5918 # optional or nullable complexity going on. In that situation, we can
5919 # use an AutoSequence instead. We have to keep using Sequence in the
5920 # nullable and optional cases because we don't want to leak the
5921 # AutoSequence type to consumers, which would be unavoidable with
5922 # Nullable<AutoSequence> or Optional<AutoSequence>.
5924 (isMember
and isMember
!= "Union")
5927 or isCallbackReturnValue
5929 sequenceClass
= "Sequence"
5931 sequenceClass
= "binding_detail::AutoSequence"
5933 # XXXbz we can't include the index in the sourceDescription, because
5934 # we don't really have a way to pass one in dynamically at runtime...
5935 elementInfo
= getJSToNativeConversionInfo(
5938 isMember
="Sequence",
5939 exceptionCode
=exceptionCode
,
5940 lenientFloatCode
=lenientFloatCode
,
5941 isCallbackReturnValue
=isCallbackReturnValue
,
5942 sourceDescription
="element of %s" % sourceDescription
,
5943 nestingLevel
=incrementNestingLevel(),
5945 if elementInfo
.dealWithOptional
:
5946 raise TypeError("Shouldn't have optional things in sequences")
5947 if elementInfo
.holderType
is not None:
5948 raise TypeError("Shouldn't need holders for sequences")
5950 typeName
= CGTemplatedType(sequenceClass
, elementInfo
.declType
)
5951 sequenceType
= typeName
.define()
5953 if isMember
== "Union" and typeNeedsRooting(type):
5955 typeName
= CGTemplatedType(
5956 "binding_detail::RootedAutoSequence", elementInfo
.declType
5959 typeName
= CGTemplatedType("Nullable", typeName
)
5962 arrayRef
= "${declName}.SetValue()"
5964 arrayRef
= "${declName}"
5966 elementConversion
= string
.Template(elementInfo
.template
).substitute(
5968 "val": "temp" + str(nestingLevel
),
5969 "maybeMutableVal": "&temp" + str(nestingLevel
),
5970 "declName": "slot" + str(nestingLevel
),
5971 # We only need holderName here to handle isExternal()
5972 # interfaces, which use an internal holder for the
5973 # conversion even when forceOwningType ends up true.
5974 "holderName": "tempHolder" + str(nestingLevel
),
5975 "passedToJSImpl": "${passedToJSImpl}",
5979 elementInitializer
= initializerForType(elementType
)
5980 if elementInitializer
is None:
5981 elementInitializer
= ""
5983 elementInitializer
= elementInitializer
+ ", "
5985 # NOTE: Keep this in sync with variadic conversions as needed
5986 templateBody
= fill(
5988 JS::ForOfIterator iter${nestingLevel}(cx);
5989 if (!iter${nestingLevel}.init($${val}, JS::ForOfIterator::AllowNonIterable)) {
5992 if (!iter${nestingLevel}.valueIsIterable()) {
5995 ${sequenceType} &arr${nestingLevel} = ${arrayRef};
5996 JS::Rooted<JS::Value> temp${nestingLevel}(cx);
5998 bool done${nestingLevel};
5999 if (!iter${nestingLevel}.next(&temp${nestingLevel}, &done${nestingLevel})) {
6002 if (done${nestingLevel}) {
6005 ${elementType}* slotPtr${nestingLevel} = arr${nestingLevel}.AppendElement(${elementInitializer}mozilla::fallible);
6006 if (!slotPtr${nestingLevel}) {
6007 JS_ReportOutOfMemory(cx);
6010 ${elementType}& slot${nestingLevel} = *slotPtr${nestingLevel};
6011 $*{elementConversion}
6014 exceptionCode
=exceptionCode
,
6015 notSequence
=notSequence
,
6016 sequenceType
=sequenceType
,
6018 elementType
=elementInfo
.declType
.define(),
6019 elementConversion
=elementConversion
,
6020 elementInitializer
=elementInitializer
,
6021 nestingLevel
=str(nestingLevel
),
6024 templateBody
= wrapObjectTemplate(
6025 templateBody
, type, "${declName}.SetNull();\n", notSequence
6027 if isinstance(defaultValue
, IDLEmptySequenceValue
):
6029 codeToSetEmpty
= "${declName}.SetValue();\n"
6032 "/* ${declName} array is already empty; nothing to do */\n"
6034 templateBody
= handleDefault(templateBody
, codeToSetEmpty
)
6039 # Sequence arguments that might contain traceable things need
6041 if typeNeedsRooting(elementType
):
6043 holderType
= CGTemplatedType("SequenceRooter", elementInfo
.declType
)
6044 # If our sequence is nullable, this will set the Nullable to be
6045 # not-null, but that's ok because we make an explicit SetNull() call
6046 # on it as needed if our JS value is actually null.
6047 holderArgs
= "cx, &%s" % arrayRef
6048 elif isMember
== "Union":
6051 return JSToNativeConversionInfo(
6055 holderType
=holderType
,
6056 dealWithOptional
=isOptional
,
6057 holderArgs
=holderArgs
,
6061 assert not isEnforceRange
and not isClamp
and not isAllowShared
6062 if failureCode
is None:
6063 notRecord
= 'cx.ThrowErrorMessage<MSG_NOT_OBJECT>("%s");\n' "%s" % (
6064 firstCap(sourceDescription
),
6068 notRecord
= failureCode
6070 nullable
= type.nullable()
6071 # Be very careful not to change "type": we need it later
6073 recordType
= type.inner
6076 valueType
= recordType
.inner
6078 valueInfo
= getJSToNativeConversionInfo(
6082 exceptionCode
=exceptionCode
,
6083 lenientFloatCode
=lenientFloatCode
,
6084 isCallbackReturnValue
=isCallbackReturnValue
,
6085 sourceDescription
="value in %s" % sourceDescription
,
6086 nestingLevel
=incrementNestingLevel(),
6088 if valueInfo
.dealWithOptional
:
6089 raise TypeError("Shouldn't have optional things in record")
6090 if valueInfo
.holderType
is not None:
6091 raise TypeError("Shouldn't need holders for record")
6093 declType
= CGTemplatedType(
6094 "Record", [recordKeyDeclType(recordType
), valueInfo
.declType
]
6096 typeName
= declType
.define()
6098 if isMember
== "Union" and typeNeedsRooting(type):
6100 declType
= CGTemplatedType(
6101 "RootedRecord", [recordKeyDeclType(recordType
), valueInfo
.declType
]
6104 declType
= CGTemplatedType("Nullable", declType
)
6107 recordRef
= "${declName}.SetValue()"
6109 recordRef
= "${declName}"
6111 valueConversion
= string
.Template(valueInfo
.template
).substitute(
6114 "maybeMutableVal": "&temp",
6116 # We only need holderName here to handle isExternal()
6117 # interfaces, which use an internal holder for the
6118 # conversion even when forceOwningType ends up true.
6119 "holderName": "tempHolder",
6120 "passedToJSImpl": "${passedToJSImpl}",
6124 keyType
= recordKeyType(recordType
)
6125 if recordType
.keyType
.isJSString():
6127 "Have do deal with JSString record type, but don't know how"
6129 if recordType
.keyType
.isByteString() or recordType
.keyType
.isUTF8String():
6130 hashKeyType
= "nsCStringHashKey"
6131 if recordType
.keyType
.isByteString():
6132 keyConversionFunction
= "ConvertJSValueToByteString"
6134 keyConversionFunction
= "ConvertJSValueToString"
6137 hashKeyType
= "nsStringHashKey"
6138 if recordType
.keyType
.isDOMString():
6139 keyConversionFunction
= "ConvertJSValueToString"
6141 assert recordType
.keyType
.isUSVString()
6142 keyConversionFunction
= "ConvertJSValueToUSVString"
6144 templateBody
= fill(
6146 auto& recordEntries = ${recordRef}.Entries();
6148 JS::Rooted<JSObject*> recordObj(cx, &$${val}.toObject());
6149 JS::RootedVector<jsid> ids(cx);
6150 if (!js::GetPropertyKeys(cx, recordObj,
6151 JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &ids)) {
6154 if (!recordEntries.SetCapacity(ids.length(), mozilla::fallible)) {
6155 JS_ReportOutOfMemory(cx);
6158 JS::Rooted<JS::Value> propNameValue(cx);
6159 JS::Rooted<JS::Value> temp(cx);
6160 JS::Rooted<jsid> curId(cx);
6161 JS::Rooted<JS::Value> idVal(cx);
6162 // Use a hashset to keep track of ids seen, to avoid
6163 // introducing nasty O(N^2) behavior scanning for them all the
6164 // time. Ideally we'd use a data structure with O(1) lookup
6165 // _and_ ordering for the MozMap, but we don't have one lying
6167 nsTHashtable<${hashKeyType}> idsSeen;
6168 for (size_t i = 0; i < ids.length(); ++i) {
6171 JS::Rooted<mozilla::Maybe<JS::PropertyDescriptor>> desc(cx);
6172 if (!JS_GetOwnPropertyDescriptorById(cx, recordObj, curId,
6177 if (desc.isNothing() || !desc->enumerable()) {
6181 idVal = js::IdToValue(curId);
6182 ${keyType} propName;
6183 // This will just throw if idVal is a Symbol, like the spec says
6185 if (!${keyConversionFunction}(cx, idVal, "key of ${sourceDescription}", propName)) {
6189 if (!JS_GetPropertyById(cx, recordObj, curId, &temp)) {
6193 ${typeName}::EntryType* entry;
6194 if (!idsSeen.EnsureInserted(propName)) {
6195 // Find the existing entry.
6196 auto idx = recordEntries.IndexOf(propName);
6197 MOZ_ASSERT(idx != recordEntries.NoIndex,
6198 "Why is it not found?");
6199 // Now blow it away to make it look like it was just added
6200 // to the array, because it's not obvious that it's
6201 // safe to write to its already-initialized mValue via our
6202 // normal codegen conversions. For example, the value
6203 // could be a union and this would change its type, but
6204 // codegen assumes we won't do that.
6205 entry = recordEntries.ReconstructElementAt(idx);
6207 // Safe to do an infallible append here, because we did a
6208 // SetCapacity above to the right capacity.
6209 entry = recordEntries.AppendElement();
6211 entry->mKey = propName;
6212 ${valueType}& slot = entry->mValue;
6216 exceptionCode
=exceptionCode
,
6217 recordRef
=recordRef
,
6218 hashKeyType
=hashKeyType
,
6220 keyConversionFunction
=keyConversionFunction
,
6221 sourceDescription
=sourceDescription
,
6223 valueType
=valueInfo
.declType
.define(),
6224 valueConversion
=valueConversion
,
6227 templateBody
= wrapObjectTemplate(
6228 templateBody
, type, "${declName}.SetNull();\n", notRecord
6234 # record arguments that might contain traceable things need
6236 if not isMember
and isCallbackReturnValue
:
6237 # Go ahead and just convert directly into our actual return value
6238 declType
= CGWrapper(declType
, post
="&")
6239 declArgs
= "aRetVal"
6240 elif typeNeedsRooting(valueType
):
6242 holderType
= CGTemplatedType(
6243 "RecordRooter", [recordKeyDeclType(recordType
), valueInfo
.declType
]
6245 # If our record is nullable, this will set the Nullable to be
6246 # not-null, but that's ok because we make an explicit SetNull() call
6247 # on it as needed if our JS value is actually null.
6248 holderArgs
= "cx, &%s" % recordRef
6249 elif isMember
== "Union":
6252 return JSToNativeConversionInfo(
6256 holderType
=holderType
,
6257 dealWithOptional
=isOptional
,
6258 holderArgs
=holderArgs
,
6262 nullable
= type.nullable()
6266 isOwningUnion
= (isMember
and isMember
!= "Union") or isCallbackReturnValue
6267 unionArgumentObj
= "${declName}"
6269 if isOptional
and not isOwningUnion
:
6270 unionArgumentObj
+= ".Value()"
6271 # If we're owning, we're a Nullable, which hasn't been told it has
6272 # a value. Otherwise we're an already-constructed Maybe.
6273 unionArgumentObj
+= ".SetValue()"
6275 templateBody
= CGIfWrapper(
6276 CGGeneric(exceptionCode
),
6277 '!%s.Init(cx, ${val}, "%s", ${passedToJSImpl})'
6278 % (unionArgumentObj
, firstCap(sourceDescription
)),
6281 if type.hasNullableType
:
6283 # Make sure to handle a null default value here
6284 if defaultValue
and isinstance(defaultValue
, IDLNullValue
):
6285 assert defaultValue
.type == type
6286 templateBody
= CGIfElseWrapper(
6288 CGGeneric("%s.SetNull();\n" % unionArgumentObj
),
6292 typeName
= CGUnionStruct
.unionTypeDecl(type, isOwningUnion
)
6293 argumentTypeName
= typeName
+ "Argument"
6295 typeName
= "Nullable<" + typeName
+ " >"
6297 declType
= CGGeneric(typeName
)
6301 holderType
= CGGeneric(argumentTypeName
)
6303 holderType
= CGTemplatedType("Maybe", holderType
)
6305 # If we're isOptional and not nullable the normal optional handling will
6306 # handle lazy construction of our holder. If we're nullable and not
6307 # owning we do it all by hand because we do not want our holder
6308 # constructed if we're null. But if we're owning we don't have a
6309 # holder anyway, so we can do the normal Optional codepath.
6310 declLoc
= "${declName}"
6311 constructDecl
= None
6313 if isOptional
and not isOwningUnion
:
6314 declType
= CGTemplatedType("Optional", declType
)
6315 constructDecl
= CGGeneric("${declName}.Construct();\n")
6316 declLoc
= "${declName}.Value()"
6318 if not isMember
and isCallbackReturnValue
:
6319 declType
= CGWrapper(declType
, post
="&")
6320 declArgs
= "aRetVal"
6326 and not isinstance(defaultValue
, IDLNullValue
)
6327 and not isinstance(defaultValue
, IDLDefaultDictionaryValue
)
6329 tag
= defaultValue
.type.tag()
6331 if tag
in numericSuffixes
or tag
is IDLType
.Tags
.bool:
6332 defaultStr
= getHandleDefault(defaultValue
)
6333 # Make sure we actually construct the thing inside the nullable.
6334 value
= declLoc
+ (".SetValue()" if nullable
else "")
6335 name
= getUnionMemberName(defaultValue
.type)
6336 default
= CGGeneric(
6337 "%s.RawSetAs%s() = %s;\n" % (value
, name
, defaultStr
)
6339 elif isinstance(defaultValue
, IDLEmptySequenceValue
):
6340 name
= getUnionMemberName(defaultValue
.type)
6341 # Make sure we actually construct the thing inside the nullable.
6342 value
= declLoc
+ (".SetValue()" if nullable
else "")
6343 if not isOwningUnion
and typeNeedsRooting(defaultValue
.type):
6347 # It's enough to set us to the right type; that will
6348 # create an empty array, which is all we need here.
6349 default
= CGGeneric(
6350 "Unused << %s.RawSetAs%s(%s);\n" % (value
, name
, ctorArgs
)
6352 elif defaultValue
.type.isEnum():
6353 name
= getUnionMemberName(defaultValue
.type)
6354 # Make sure we actually construct the thing inside the nullable.
6355 value
= declLoc
+ (".SetValue()" if nullable
else "")
6356 default
= CGGeneric(
6357 "%s.RawSetAs%s() = %s::%s;\n"
6361 defaultValue
.type.inner
.identifier
.name
,
6362 getEnumValueName(defaultValue
.value
),
6366 default
= CGGeneric(
6367 handleDefaultStringValue(
6368 defaultValue
, "%s.SetStringLiteral" % unionArgumentObj
6372 templateBody
= CGIfElseWrapper("!(${haveValue})", default
, templateBody
)
6375 assert not type.hasNullableType
6377 if isinstance(defaultValue
, IDLNullValue
):
6378 extraConditionForNull
= "!(${haveValue}) || "
6380 extraConditionForNull
= "(${haveValue}) && "
6382 extraConditionForNull
= ""
6384 hasUndefinedType
= any(t
.isUndefined() for t
in type.flatMemberTypes
)
6385 assert not hasUndefinedType
or defaultValue
is None
6388 "${val}.isNull()" if hasUndefinedType
else "${val}.isNullOrUndefined()"
6390 templateBody
= CGIfElseWrapper(
6391 extraConditionForNull
+ nullTest
,
6392 CGGeneric("%s.SetNull();\n" % declLoc
),
6396 not type.hasNullableType
6398 and isinstance(defaultValue
, IDLDefaultDictionaryValue
)
6400 assert type.hasDictionaryType()
6401 assert defaultValue
.type.isDictionary()
6402 if not isOwningUnion
and typeNeedsRooting(defaultValue
.type):
6406 initDictionaryWithNull
= CGIfWrapper(
6407 CGGeneric("return false;\n"),
6409 '!%s.RawSetAs%s(%s).Init(cx, JS::NullHandleValue, "Member of %s")'
6412 getUnionMemberName(defaultValue
.type),
6418 templateBody
= CGIfElseWrapper(
6419 "!(${haveValue})", initDictionaryWithNull
, templateBody
6422 templateBody
= CGList([constructDecl
, templateBody
])
6424 return JSToNativeConversionInfo(
6425 templateBody
.define(),
6428 dealWithOptional
=isOptional
and (not nullable
or isOwningUnion
),
6431 if type.isPromise():
6432 assert not type.nullable()
6433 assert defaultValue
is None
6435 # We always have to hold a strong ref to Promise here, because
6436 # Promise::resolve returns an addrefed thing.
6437 argIsPointer
= isCallbackReturnValue
6439 declType
= CGGeneric("RefPtr<Promise>")
6441 declType
= CGGeneric("OwningNonNull<Promise>")
6443 # Per spec, what we're supposed to do is take the original
6444 # Promise.resolve and call it with the original Promise as this
6445 # value to make a Promise out of whatever value we actually have
6446 # here. The question is which global we should use. There are
6447 # several cases to consider:
6449 # 1) Normal call to API with a Promise argument. This is a case the
6450 # spec covers, and we should be using the current Realm's
6451 # Promise. That means the current compartment.
6452 # 2) Call to API with a Promise argument over Xrays. In practice,
6453 # this sort of thing seems to be used for giving an API
6454 # implementation a way to wait for conclusion of an asyc
6455 # operation, _not_ to expose the Promise to content code. So we
6456 # probably want to allow callers to use such an API in a
6457 # "natural" way, by passing chrome-side promises; indeed, that
6458 # may be all that the caller has to represent their async
6459 # operation. That means we really need to do the
6460 # Promise.resolve() in the caller (chrome) compartment: if we do
6461 # it in the content compartment, we will try to call .then() on
6462 # the chrome promise while in the content compartment, which will
6463 # throw and we'll just get a rejected Promise. Note that this is
6464 # also the reason why a caller who has a chrome Promise
6465 # representing an async operation can't itself convert it to a
6466 # content-side Promise (at least not without some serious
6468 # 3) Promise return value from a callback or callback interface.
6469 # Per spec, this should use the Realm of the callback object. In
6470 # our case, that's the compartment of the underlying callback,
6471 # not the current compartment (which may be the compartment of
6472 # some cross-compartment wrapper around said callback).
6473 # 4) Return value from a JS-implemented interface. In this case we
6474 # have a problem. Our current compartment is the compartment of
6475 # the JS implementation. But if the JS implementation returned
6476 # a page-side Promise (which is a totally sane thing to do, and
6477 # in fact the right thing to do given that this return value is
6478 # going right to content script) then we don't want to
6479 # Promise.resolve with our current compartment Promise, because
6480 # that will wrap it up in a chrome-side Promise, which is
6481 # decidedly _not_ what's desired here. So in that case we
6482 # should really unwrap the return value and use the global of
6483 # the result. CheckedUnwrapStatic should be good enough for that;
6484 # if it fails, then we're failing unwrap while in a
6485 # system-privileged compartment, so presumably we have a dead
6486 # object wrapper. Just error out. Do NOT fall back to using
6487 # the current compartment instead: that will return a
6488 # system-privileged rejected (because getting .then inside
6489 # resolve() failed) Promise to the caller, which they won't be
6490 # able to touch. That's not helpful. If we error out, on the
6491 # other hand, they will get a content-side rejected promise.
6492 # Same thing if the value returned is not even an object.
6493 if isCallbackReturnValue
== "JSImpl":
6494 # Case 4 above. Note that globalObj defaults to the current
6495 # compartment global. Note that we don't use $*{exceptionCode}
6496 # here because that will try to aRv.Throw(NS_ERROR_UNEXPECTED)
6497 # which we don't really want here.
6498 assert exceptionCode
== "aRv.Throw(NS_ERROR_UNEXPECTED);\nreturn nullptr;\n"
6499 getPromiseGlobal
= fill(
6501 if (!$${val}.isObject()) {
6502 aRv.ThrowTypeError<MSG_NOT_OBJECT>("${sourceDescription}");
6505 JSObject* unwrappedVal = js::CheckedUnwrapStatic(&$${val}.toObject());
6506 if (!unwrappedVal) {
6507 // A slight lie, but not much of one, for a dead object wrapper.
6508 aRv.ThrowTypeError<MSG_NOT_OBJECT>("${sourceDescription}");
6511 globalObj = JS::GetNonCCWObjectGlobal(unwrappedVal);
6513 sourceDescription
=sourceDescription
,
6515 elif isCallbackReturnValue
== "Callback":
6516 getPromiseGlobal
= dedent(
6518 // We basically want our entry global here. Play it safe
6519 // and use GetEntryGlobal() to get it, with whatever
6520 // principal-clamping it ends up doing.
6521 globalObj = GetEntryGlobal()->GetGlobalJSObject();
6525 getPromiseGlobal
= dedent(
6527 globalObj = JS::CurrentGlobalOrNull(cx);
6531 templateBody
= fill(
6533 { // Scope for our GlobalObject, FastErrorResult, JSAutoRealm,
6536 JS::Rooted<JSObject*> globalObj(cx);
6537 $*{getPromiseGlobal}
6538 JSAutoRealm ar(cx, globalObj);
6539 GlobalObject promiseGlobal(cx, globalObj);
6540 if (promiseGlobal.Failed()) {
6544 JS::Rooted<JS::Value> valueToResolve(cx, $${val});
6545 if (!JS_WrapValue(cx, &valueToResolve)) {
6548 binding_detail::FastErrorResult promiseRv;
6549 nsCOMPtr<nsIGlobalObject> global =
6550 do_QueryInterface(promiseGlobal.GetAsSupports());
6552 promiseRv.Throw(NS_ERROR_UNEXPECTED);
6553 MOZ_ALWAYS_TRUE(promiseRv.MaybeSetPendingException(cx));
6556 $${declName} = Promise::Resolve(global, cx, valueToResolve,
6558 if (promiseRv.MaybeSetPendingException(cx)) {
6563 getPromiseGlobal
=getPromiseGlobal
,
6564 exceptionCode
=exceptionCode
,
6567 return JSToNativeConversionInfo(
6568 templateBody
, declType
=declType
, dealWithOptional
=isOptional
6571 if type.isGeckoInterface():
6572 assert not isEnforceRange
and not isClamp
and not isAllowShared
6574 descriptor
= descriptorProvider
.getDescriptor(
6575 type.unroll().inner
.identifier
.name
6578 assert descriptor
.nativeType
!= "JSObject"
6580 if descriptor
.interface
.isCallback():
6581 (declType
, declArgs
, conversion
) = getCallbackConversionInfo(
6582 type, descriptor
.interface
, isMember
, isCallbackReturnValue
, isOptional
6584 template
= wrapObjectTemplate(
6585 conversion
, type, "${declName} = nullptr;\n", failureCode
6587 return JSToNativeConversionInfo(
6591 dealWithOptional
=isOptional
,
6594 if descriptor
.interface
.identifier
.name
== "WindowProxy":
6595 declType
= CGGeneric("mozilla::dom::WindowProxyHolder")
6597 declType
= CGTemplatedType("Nullable", declType
)
6598 windowProxyHolderRef
= "${declName}.SetValue()"
6600 windowProxyHolderRef
= "${declName}"
6602 failureCode
= onFailureBadType(
6603 failureCode
, descriptor
.interface
.identifier
.name
6605 templateBody
= fill(
6607 JS::Rooted<JSObject*> source(cx, &$${val}.toObject());
6608 if (NS_FAILED(UnwrapWindowProxyArg(cx, source, ${windowProxyHolderRef}))) {
6612 windowProxyHolderRef
=windowProxyHolderRef
,
6613 onFailure
=failureCode
,
6615 templateBody
= wrapObjectTemplate(
6616 templateBody
, type, "${declName}.SetNull();\n", failureCode
6618 return JSToNativeConversionInfo(
6619 templateBody
, declType
=declType
, dealWithOptional
=isOptional
6622 # This is an interface that we implement as a concrete class
6623 # or an XPCOM interface.
6625 # Allow null pointers for nullable types and old-binding classes, and
6626 # use an RefPtr or raw pointer for callback return values to make
6627 # them easier to return.
6629 type.nullable() or type.unroll().inner
.isExternal() or isCallbackReturnValue
6632 # Sequence and dictionary members, as well as owning unions (which can
6633 # appear here as return values in JS-implemented interfaces) have to
6634 # hold a strong ref to the thing being passed down. Those all set
6637 # Also, callback return values always end up addrefing anyway, so there
6638 # is no point trying to avoid it here and it makes other things simpler
6639 # since we can assume the return value is a strong ref.
6640 assert not descriptor
.interface
.isCallback()
6641 forceOwningType
= (isMember
and isMember
!= "Union") or isCallbackReturnValue
6643 typeName
= descriptor
.nativeType
6644 typePtr
= typeName
+ "*"
6646 # Compute a few things:
6647 # - declType is the type we want to return as the first element of our
6649 # - holderType is the type we want to return as the third element
6652 # Set up some sensible defaults for these things insofar as we can.
6656 declType
= "RefPtr<" + typeName
+ ">"
6661 declType
= "OwningNonNull<" + typeName
+ ">"
6663 declType
= "NonNull<" + typeName
+ ">"
6667 templateBody
+= fill(
6669 static_assert(IsRefcounted<${typeName}>::value, "We can only store refcounted classes.");
6674 if not descriptor
.interface
.isExternal():
6675 if failureCode
is not None:
6676 templateBody
+= str(
6677 CastableObjectUnwrapper(
6680 "${maybeMutableVal}",
6686 templateBody
+= str(
6687 FailureFatalCastableObjectUnwrapper(
6690 "${maybeMutableVal}",
6693 isCallbackReturnValue
,
6694 firstCap(sourceDescription
),
6698 # External interface. We always have a holder for these, because we
6699 # don't actually know whether we have to addref when unwrapping or not.
6700 # So we just pass an getter_AddRefs(RefPtr) to XPConnect and if we'll
6701 # need a release it'll put a non-null pointer in there.
6703 # Don't return a holderType in this case; our declName
6704 # will just own stuff.
6705 templateBody
+= "RefPtr<" + typeName
+ "> ${holderName};\n"
6707 holderType
= "RefPtr<" + typeName
+ ">"
6709 "JS::Rooted<JSObject*> source(cx, &${val}.toObject());\n"
6710 + "if (NS_FAILED(UnwrapArg<"
6712 + ">(cx, source, getter_AddRefs(${holderName})))) {\n"
6714 templateBody
+= CGIndenter(
6715 onFailureBadType(failureCode
, descriptor
.interface
.identifier
.name
)
6717 templateBody
+= "}\n" "MOZ_ASSERT(${holderName});\n"
6719 # And store our value in ${declName}
6720 templateBody
+= "${declName} = ${holderName};\n"
6722 # Just pass failureCode, not onFailureBadType, here, so we'll report
6723 # the thing as not an object as opposed to not implementing whatever
6725 templateBody
= wrapObjectTemplate(
6726 templateBody
, type, "${declName} = nullptr;\n", failureCode
6729 declType
= CGGeneric(declType
)
6730 if holderType
is not None:
6731 holderType
= CGGeneric(holderType
)
6732 return JSToNativeConversionInfo(
6735 holderType
=holderType
,
6736 dealWithOptional
=isOptional
,
6739 if type.isSpiderMonkeyInterface():
6740 assert not isEnforceRange
and not isClamp
6741 name
= type.unroll().name
# unroll() because it may be nullable
6742 interfaceType
= CGGeneric(name
)
6743 declType
= interfaceType
6745 declType
= CGTemplatedType("Nullable", declType
)
6746 objRef
= "${declName}.SetValue()"
6748 objRef
= "${declName}"
6750 # Again, this is a bit strange since we are actually building a
6751 # template string here. ${objRef} and $*{badType} below are filled in
6752 # right now; $${val} expands to ${val}, to be filled in later.
6755 if (!${objRef}.Init(&$${val}.toObject())) {
6760 badType
=onFailureBadType(failureCode
, type.name
).define(),
6762 if type.isBufferSource():
6763 if type.isArrayBuffer():
6764 isSharedMethod
= "JS::IsSharedArrayBufferObject"
6765 isLargeMethod
= "JS::IsLargeArrayBufferMaybeShared"
6766 isResizableMethod
= "JS::IsResizableArrayBufferMaybeShared"
6768 assert type.isArrayBufferView() or type.isTypedArray()
6769 isSharedMethod
= "JS::IsArrayBufferViewShared"
6770 isLargeMethod
= "JS::IsLargeArrayBufferView"
6771 isResizableMethod
= "JS::IsResizableArrayBufferView"
6772 if not isAllowShared
:
6775 if (${isSharedMethod}(${objRef}.Obj())) {
6779 isSharedMethod
=isSharedMethod
,
6781 badType
=onFailureIsShared().define(),
6783 # For now reject large (> 2 GB) ArrayBuffers and ArrayBufferViews.
6784 # Supporting this will require changing dom::TypedArray and
6788 if (${isLargeMethod}(${objRef}.Obj())) {
6792 isLargeMethod
=isLargeMethod
,
6794 badType
=onFailureIsLarge().define(),
6796 # For now reject resizable ArrayBuffers and growable
6797 # SharedArrayBuffers. Supporting this will require changing
6798 # dom::TypedArray and consumers.
6801 if (${isResizableMethod}(${objRef}.Obj())) {
6805 isResizableMethod
=isResizableMethod
,
6807 badType
=onFailureIsResizable().define(),
6809 template
= wrapObjectTemplate(
6810 template
, type, "${declName}.SetNull();\n", failureCode
6812 if not isMember
or isMember
== "Union":
6813 # This is a bit annoying. In a union we don't want to have a
6814 # holder, since unions don't support that. But if we're optional we
6815 # want to have a holder, so that the callee doesn't see
6816 # Optional<RootedSpiderMonkeyInterface<InterfaceType>>. So do a
6817 # holder if we're optional and use a RootedSpiderMonkeyInterface
6820 holderType
= CGTemplatedType(
6821 "SpiderMonkeyInterfaceRooter", interfaceType
6823 # If our SpiderMonkey interface is nullable, this will set the
6824 # Nullable to be not-null, but that's ok because we make an
6825 # explicit SetNull() call on it as needed if our JS value is
6826 # actually null. XXXbz Because "Maybe" takes const refs for
6827 # constructor arguments, we can't pass a reference here; have
6828 # to pass a pointer.
6829 holderArgs
= "cx, &%s" % objRef
6834 declType
= CGTemplatedType("RootedSpiderMonkeyInterface", declType
)
6840 return JSToNativeConversionInfo(
6843 holderType
=holderType
,
6844 dealWithOptional
=isOptional
,
6846 holderArgs
=holderArgs
,
6849 if type.isJSString():
6850 assert not isEnforceRange
and not isClamp
and not isAllowShared
6852 raise TypeError("Nullable JSString not supported")
6856 raise TypeError("JSString not supported as member")
6858 declType
= "JS::Rooted<JSString*>"
6861 raise TypeError("JSString not supported as optional")
6862 templateBody
= fill(
6864 if (!($${declName} = ConvertJSValueToJSString(cx, $${val}))) {
6868 exceptionCode
=exceptionCode
,
6871 if defaultValue
is not None:
6872 assert not isinstance(defaultValue
, IDLNullValue
)
6875 static const char data[] = { ${data} };
6876 $${declName} = JS_NewStringCopyN(cx, data, ArrayLength(data) - 1);
6877 if (!$${declName}) {
6882 ["'" + char
+ "'" for char
in defaultValue
.value
] + ["0"]
6884 exceptionCode
=exceptionCode
,
6887 templateBody
= handleDefault(templateBody
, defaultCode
)
6888 return JSToNativeConversionInfo(
6889 templateBody
, declType
=CGGeneric(declType
), declArgs
=declArgs
6892 if type.isDOMString() or type.isUSVString() or type.isUTF8String():
6893 assert not isEnforceRange
and not isClamp
and not isAllowShared
6896 "Default": "eStringify",
6897 "EmptyString": "eEmpty",
6901 # For nullable strings null becomes a null string.
6902 treatNullAs
= "Null"
6903 # For nullable strings undefined also becomes a null string.
6904 undefinedBehavior
= "eNull"
6906 undefinedBehavior
= "eStringify"
6907 if type.legacyNullToEmptyString
:
6908 treatNullAs
= "EmptyString"
6910 treatNullAs
= "Default"
6911 nullBehavior
= treatAs
[treatNullAs
]
6913 def getConversionCode(varName
):
6915 if type.isUSVString():
6916 normalizeCode
= fill(
6918 if (!NormalizeUSVString(${var})) {
6919 JS_ReportOutOfMemory(cx);
6924 exceptionCode
=exceptionCode
,
6927 conversionCode
= fill(
6929 if (!ConvertJSValueToString(cx, $${val}, ${nullBehavior}, ${undefinedBehavior}, ${varName})) {
6934 nullBehavior
=nullBehavior
,
6935 undefinedBehavior
=undefinedBehavior
,
6937 exceptionCode
=exceptionCode
,
6938 normalizeCode
=normalizeCode
,
6941 if defaultValue
is None:
6942 return conversionCode
6944 if isinstance(defaultValue
, IDLNullValue
):
6945 assert type.nullable()
6946 defaultCode
= "%s.SetIsVoid(true);\n" % varName
6948 defaultCode
= handleDefaultStringValue(
6949 defaultValue
, "%s.AssignLiteral" % varName
6951 return handleDefault(conversionCode
, defaultCode
)
6953 if isMember
and isMember
!= "Union":
6954 # Convert directly into the ns[C]String member we have.
6955 if type.isUTF8String():
6956 declType
= "nsCString"
6958 declType
= "nsString"
6959 return JSToNativeConversionInfo(
6960 getConversionCode("${declName}"),
6961 declType
=CGGeneric(declType
),
6962 dealWithOptional
=isOptional
,
6966 if type.isUTF8String():
6967 declType
= "Optional<nsACString>"
6968 holderType
= CGGeneric("binding_detail::FakeString<char>")
6970 declType
= "Optional<nsAString>"
6971 holderType
= CGGeneric("binding_detail::FakeString<char16_t>")
6972 conversionCode
= "%s" "${declName} = &${holderName};\n" % getConversionCode(
6976 if type.isUTF8String():
6977 declType
= "binding_detail::FakeString<char>"
6979 declType
= "binding_detail::FakeString<char16_t>"
6981 conversionCode
= getConversionCode("${declName}")
6983 # No need to deal with optional here; we handled it already
6984 return JSToNativeConversionInfo(
6985 conversionCode
, declType
=CGGeneric(declType
), holderType
=holderType
6988 if type.isByteString():
6989 assert not isEnforceRange
and not isClamp
and not isAllowShared
6991 nullable
= toStringBool(type.nullable())
6993 conversionCode
= fill(
6995 if (!ConvertJSValueToByteString(cx, $${val}, ${nullable}, "${sourceDescription}", $${declName})) {
7000 sourceDescription
=sourceDescription
,
7001 exceptionCode
=exceptionCode
,
7004 if defaultValue
is not None:
7005 if isinstance(defaultValue
, IDLNullValue
):
7006 assert type.nullable()
7007 defaultCode
= "${declName}.SetIsVoid(true);\n"
7009 defaultCode
= handleDefaultStringValue(
7010 defaultValue
, "${declName}.AssignLiteral"
7012 conversionCode
= handleDefault(conversionCode
, defaultCode
)
7014 return JSToNativeConversionInfo(
7015 conversionCode
, declType
=CGGeneric("nsCString"), dealWithOptional
=isOptional
7019 assert not isEnforceRange
and not isClamp
and not isAllowShared
7021 enumName
= type.unroll().inner
.identifier
.name
7022 declType
= CGGeneric(enumName
)
7024 declType
= CGTemplatedType("Nullable", declType
)
7025 declType
= declType
.define()
7026 enumLoc
= "${declName}.SetValue()"
7028 enumLoc
= "${declName}"
7029 declType
= declType
.define()
7031 if invalidEnumValueFatal
:
7032 handleInvalidEnumValueCode
= "MOZ_ASSERT(index >= 0);\n"
7034 # invalidEnumValueFatal is false only for attributes. So we won't
7035 # have a non-default exceptionCode here unless attribute "arg
7036 # conversion" code starts passing in an exceptionCode. At which
7037 # point we'll need to figure out what that even means.
7038 assert exceptionCode
== "return false;\n"
7039 handleInvalidEnumValueCode
= dedent(
7051 if (!binding_detail::FindEnumStringIndex<${invalidEnumValueFatal}>(cx, $${val},
7052 binding_detail::EnumStrings<${enumtype}>::Values,
7053 "${enumtype}", "${sourceDescription}",
7057 $*{handleInvalidEnumValueCode}
7058 ${enumLoc} = static_cast<${enumtype}>(index);
7062 invalidEnumValueFatal
=toStringBool(invalidEnumValueFatal
),
7063 handleInvalidEnumValueCode
=handleInvalidEnumValueCode
,
7064 exceptionCode
=exceptionCode
,
7066 sourceDescription
=sourceDescription
,
7069 setNull
= "${declName}.SetNull();\n"
7072 template
= CGIfElseWrapper(
7073 "${val}.isNullOrUndefined()", CGGeneric(setNull
), CGGeneric(template
)
7076 if defaultValue
is not None:
7077 if isinstance(defaultValue
, IDLNullValue
):
7078 assert type.nullable()
7079 template
= handleDefault(template
, setNull
)
7081 assert defaultValue
.type.tag() == IDLType
.Tags
.domstring
7082 template
= handleDefault(
7086 % (enumLoc
, enumName
, getEnumValueName(defaultValue
.value
))
7089 return JSToNativeConversionInfo(
7090 template
, declType
=CGGeneric(declType
), dealWithOptional
=isOptional
7093 if type.isCallback():
7094 assert not isEnforceRange
and not isClamp
and not isAllowShared
7095 assert not type.treatNonCallableAsNull() or type.nullable()
7096 assert not type.treatNonObjectAsNull() or type.nullable()
7097 assert not type.treatNonObjectAsNull() or not type.treatNonCallableAsNull()
7099 callback
= type.unroll().callback
7100 name
= callback
.identifier
.name
7101 (declType
, declArgs
, conversion
) = getCallbackConversionInfo(
7102 type, callback
, isMember
, isCallbackReturnValue
, isOptional
7105 if allowTreatNonCallableAsNull
and type.treatNonCallableAsNull():
7106 haveCallable
= "JS::IsCallable(&${val}.toObject())"
7107 if not isDefinitelyObject
:
7108 haveCallable
= "${val}.isObject() && " + haveCallable
7109 if defaultValue
is not None:
7110 assert isinstance(defaultValue
, IDLNullValue
)
7111 haveCallable
= "(${haveValue}) && " + haveCallable
7113 ("if (%s) {\n" % haveCallable
) + conversion
+ "} else {\n"
7114 " ${declName} = nullptr;\n"
7117 elif allowTreatNonCallableAsNull
and type.treatNonObjectAsNull():
7118 if not isDefinitelyObject
:
7119 haveObject
= "${val}.isObject()"
7120 if defaultValue
is not None:
7121 assert isinstance(defaultValue
, IDLNullValue
)
7122 haveObject
= "(${haveValue}) && " + haveObject
7123 template
= CGIfElseWrapper(
7125 CGGeneric(conversion
),
7126 CGGeneric("${declName} = nullptr;\n"),
7129 template
= conversion
7131 template
= wrapObjectTemplate(
7132 "if (JS::IsCallable(&${val}.toObject())) {\n"
7135 + indent(onFailureNotCallable(failureCode
).define())
7138 "${declName} = nullptr;\n",
7141 return JSToNativeConversionInfo(
7142 template
, declType
=declType
, declArgs
=declArgs
, dealWithOptional
=isOptional
7146 assert not isEnforceRange
and not isClamp
and not isAllowShared
7149 if isMember
in ("Variadic", "Sequence", "Dictionary", "Record"):
7150 # Rooting is handled by the sequence and dictionary tracers.
7151 declType
= "JS::Value"
7154 declType
= "JS::Rooted<JS::Value>"
7157 assert not isOptional
7158 templateBody
= "${declName} = ${val};\n"
7160 # For JS-implemented APIs, we refuse to allow passing objects that the
7161 # API consumer does not subsume. The extra parens around
7162 # ($${passedToJSImpl}) suppress unreachable code warnings when
7163 # $${passedToJSImpl} is the literal `false`. But Apple is shipping a
7164 # buggy clang (clang 3.9) in Xcode 8.3, so there even the parens are not
7165 # enough. So we manually disable some warnings in clang.
7167 not isinstance(descriptorProvider
, Descriptor
)
7168 or descriptorProvider
.interface
.isJSImplemented()
7174 #pragma clang diagnostic push
7175 #pragma clang diagnostic ignored "-Wunreachable-code"
7176 #pragma clang diagnostic ignored "-Wunreachable-code-return"
7178 if (($${passedToJSImpl}) && !CallerSubsumes($${val})) {
7179 cx.ThrowErrorMessage<MSG_PERMISSION_DENIED_TO_PASS_ARG>("${sourceDescription}");
7183 #pragma clang diagnostic pop
7186 sourceDescription
=sourceDescription
,
7187 exceptionCode
=exceptionCode
,
7192 # We may not have a default value if we're being converted for
7195 if isinstance(defaultValue
, IDLNullValue
):
7196 defaultHandling
= "${declName} = JS::NullValue();\n"
7198 assert isinstance(defaultValue
, IDLUndefinedValue
)
7199 defaultHandling
= "${declName} = JS::UndefinedValue();\n"
7200 templateBody
= handleDefault(templateBody
, defaultHandling
)
7201 return JSToNativeConversionInfo(
7202 templateBody
, declType
=CGGeneric(declType
), declArgs
=declArgs
7206 assert not isEnforceRange
and not isClamp
and not isAllowShared
7207 return handleJSObjectType(
7208 type, isMember
, failureCode
, exceptionCode
, sourceDescription
7211 if type.isDictionary():
7212 # There are no nullable dictionary-typed arguments or dictionary-typed
7213 # dictionary members.
7216 or isCallbackReturnValue
7217 or (isMember
and isMember
!= "Dictionary")
7219 # All optional dictionary-typed arguments always have default values,
7220 # but dictionary-typed dictionary members can be optional.
7221 assert not isOptional
or isMember
== "Dictionary"
7222 # In the callback return value case we never have to worry
7223 # about a default value; we always have a value.
7224 assert not isCallbackReturnValue
or defaultValue
is None
7226 typeName
= CGDictionary
.makeDictionaryName(type.unroll().inner
)
7227 if (not isMember
or isMember
== "Union") and not isCallbackReturnValue
:
7228 # Since we're not a member and not nullable or optional, no one will
7229 # see our real type, so we can do the fast version of the dictionary
7230 # that doesn't pre-initialize members.
7231 typeName
= "binding_detail::Fast" + typeName
7233 declType
= CGGeneric(typeName
)
7235 # We do manual default value handling here, because we actually do want
7236 # a jsval, and we only handle the default-dictionary case (which we map
7237 # into initialization with the JS value `null`) anyway
7238 # NOTE: if isNullOrUndefined or isDefinitelyObject are true,
7239 # we know we have a value, so we don't have to worry about the
7242 not isNullOrUndefined
7243 and not isDefinitelyObject
7244 and defaultValue
is not None
7246 assert isinstance(defaultValue
, IDLDefaultDictionaryValue
)
7247 # Initializing from JS null does the right thing to give
7248 # us a default-initialized dictionary.
7249 val
= "(${haveValue}) ? ${val} : JS::NullHandleValue"
7253 dictLoc
= "${declName}"
7255 dictLoc
+= ".SetValue()"
7257 if type.unroll().inner
.needsConversionFromJS
:
7258 args
= "cx, %s, " % val
7260 # We can end up in this case if a dictionary that does not need
7261 # conversion from JS has a dictionary-typed member with a default
7264 conversionCode
= fill(
7266 if (!${dictLoc}.Init(${args}"${desc}", $${passedToJSImpl})) {
7272 desc
=firstCap(sourceDescription
),
7273 exceptionCode
=exceptionCode
,
7276 if failureCode
is not None:
7277 # This means we're part of an overload or union conversion, and
7278 # should simply skip stuff if our value is not convertible to
7279 # dictionary, instead of trying and throwing. If we're either
7280 # isDefinitelyObject or isNullOrUndefined then we're convertible to
7281 # dictionary and don't need to check here.
7282 if isDefinitelyObject
or isNullOrUndefined
:
7283 template
= conversionCode
7287 if (!IsConvertibleToDictionary(${val})) {
7293 failureCode
=failureCode
,
7294 conversionCode
=conversionCode
,
7297 template
= conversionCode
7300 declType
= CGTemplatedType("Nullable", declType
)
7301 template
= CGIfElseWrapper(
7302 "${val}.isNullOrUndefined()",
7303 CGGeneric("${declName}.SetNull();\n"),
7304 CGGeneric(template
),
7307 # Dictionary arguments that might contain traceable things need to get
7309 if (not isMember
or isMember
== "Union") and isCallbackReturnValue
:
7310 # Go ahead and just convert directly into our actual return value
7311 declType
= CGWrapper(declType
, post
="&")
7312 declArgs
= "aRetVal"
7313 elif (not isMember
or isMember
== "Union") and typeNeedsRooting(type):
7314 declType
= CGTemplatedType("RootedDictionary", declType
)
7319 return JSToNativeConversionInfo(
7320 template
, declType
=declType
, declArgs
=declArgs
, dealWithOptional
=isOptional
7323 if type.isUndefined():
7324 assert not isOptional
7325 # This one only happens for return values, and its easy: Just
7327 return JSToNativeConversionInfo("")
7329 if not type.isPrimitive():
7330 raise TypeError("Need conversion for argument type '%s'" % str(type))
7332 typeName
= builtinNames
[type.tag()]
7334 conversionBehavior
= "eDefault"
7336 assert type.isInteger()
7337 conversionBehavior
= "eEnforceRange"
7339 assert type.isInteger()
7340 conversionBehavior
= "eClamp"
7344 declType
= CGGeneric("Nullable<" + typeName
+ ">")
7345 writeLoc
= "${declName}.SetValue()"
7346 readLoc
= "${declName}.Value()"
7347 nullCondition
= "${val}.isNullOrUndefined()"
7348 if defaultValue
is not None and isinstance(defaultValue
, IDLNullValue
):
7349 nullCondition
= "!(${haveValue}) || " + nullCondition
7354 ${declName}.SetNull();
7360 if (${nullCondition}) {
7361 $${declName}.SetNull();
7362 } else if (!ValueToPrimitive<${typeName}, ${conversionBehavior}>(cx, $${val}, "${sourceDescription}", &${writeLoc})) {
7366 nullCondition
=nullCondition
,
7368 conversionBehavior
=conversionBehavior
,
7369 sourceDescription
=firstCap(sourceDescription
),
7371 exceptionCode
=exceptionCode
,
7374 assert defaultValue
is None or not isinstance(defaultValue
, IDLNullValue
)
7375 writeLoc
= "${declName}"
7379 if (!ValueToPrimitive<${typeName}, ${conversionBehavior}>(cx, $${val}, "${sourceDescription}", &${writeLoc})) {
7384 conversionBehavior
=conversionBehavior
,
7385 sourceDescription
=firstCap(sourceDescription
),
7387 exceptionCode
=exceptionCode
,
7389 declType
= CGGeneric(typeName
)
7391 if type.isFloat() and not type.isUnrestricted() and not alwaysNull
:
7392 if lenientFloatCode
is not None:
7393 nonFiniteCode
= lenientFloatCode
7395 nonFiniteCode
= 'cx.ThrowErrorMessage<MSG_NOT_FINITE>("%s");\n' "%s" % (
7396 firstCap(sourceDescription
),
7400 # We're appending to an if-block brace, so strip trailing whitespace
7401 # and add an extra space before the else.
7402 template
= template
.rstrip()
7405 else if (!std::isfinite(${readLoc})) {
7410 nonFiniteCode
=nonFiniteCode
,
7414 defaultValue
is not None
7416 # We already handled IDLNullValue, so just deal with the other ones
7417 not isinstance(defaultValue
, IDLNullValue
)
7419 tag
= defaultValue
.type.tag()
7420 defaultStr
= getHandleDefault(defaultValue
)
7421 template
= handleDefault(template
, "%s = %s;\n" % (writeLoc
, defaultStr
))
7423 return JSToNativeConversionInfo(
7424 template
, declType
=declType
, dealWithOptional
=isOptional
7428 def instantiateJSToNativeConversion(info
, replacements
, checkForValue
=False):
7430 Take a JSToNativeConversionInfo as returned by getJSToNativeConversionInfo
7431 and a set of replacements as required by the strings in such an object, and
7432 generate code to convert into stack C++ types.
7434 If checkForValue is True, then the conversion will get wrapped in
7435 a check for ${haveValue}.
7437 templateBody
, declType
, holderType
, dealWithOptional
= (
7441 info
.dealWithOptional
,
7444 if dealWithOptional
and not checkForValue
:
7445 raise TypeError("Have to deal with optional things, but don't know how")
7446 if checkForValue
and declType
is None:
7448 "Need to predeclare optional things, so they will be "
7449 "outside the check for big enough arg count!"
7452 # We can't precompute our holder constructor arguments, since
7453 # those might depend on ${declName}, which we change below. Just
7454 # compute arguments at the point when we need them as we go.
7455 def getArgsCGThing(args
):
7456 return CGGeneric(string
.Template(args
).substitute(replacements
))
7459 # Make a copy of "replacements" since we may be about to start modifying it
7460 replacements
= dict(replacements
)
7461 originalDeclName
= replacements
["declName"]
7462 if declType
is not None:
7463 if dealWithOptional
:
7464 replacements
["declName"] = "%s.Value()" % originalDeclName
7465 declType
= CGTemplatedType("Optional", declType
)
7467 elif info
.declArgs
is not None:
7468 declCtorArgs
= CGWrapper(getArgsCGThing(info
.declArgs
), pre
="(", post
=")")
7476 CGGeneric(originalDeclName
),
7483 originalHolderName
= replacements
["holderName"]
7484 if holderType
is not None:
7485 if dealWithOptional
:
7486 replacements
["holderName"] = "%s.ref()" % originalHolderName
7487 holderType
= CGTemplatedType("Maybe", holderType
)
7488 holderCtorArgs
= None
7489 elif info
.holderArgs
is not None:
7490 holderCtorArgs
= CGWrapper(
7491 getArgsCGThing(info
.holderArgs
), pre
="(", post
=")"
7494 holderCtorArgs
= None
7500 CGGeneric(originalHolderName
),
7507 if "maybeMutableVal" not in replacements
:
7508 replacements
["maybeMutableVal"] = replacements
["val"]
7510 conversion
= CGGeneric(string
.Template(templateBody
).substitute(replacements
))
7513 if dealWithOptional
:
7514 declConstruct
= CGIndenter(
7516 "%s.Construct(%s);\n"
7519 getArgsCGThing(info
.declArgs
).define() if info
.declArgs
else "",
7523 if holderType
is not None:
7524 holderConstruct
= CGIndenter(
7529 getArgsCGThing(info
.holderArgs
).define()
7536 holderConstruct
= None
7538 declConstruct
= None
7539 holderConstruct
= None
7541 conversion
= CGList(
7544 string
.Template("if (${haveValue}) {\n").substitute(replacements
)
7548 CGIndenter(conversion
),
7553 result
.append(conversion
)
7557 def convertConstIDLValueToJSVal(value
):
7558 if isinstance(value
, IDLNullValue
):
7559 return "JS::NullValue()"
7560 if isinstance(value
, IDLUndefinedValue
):
7561 return "JS::UndefinedValue()"
7562 tag
= value
.type.tag()
7567 IDLType
.Tags
.uint16
,
7570 return "JS::Int32Value(%s)" % (value
.value
)
7571 if tag
== IDLType
.Tags
.uint32
:
7572 return "JS::NumberValue(%sU)" % (value
.value
)
7573 if tag
in [IDLType
.Tags
.int64
, IDLType
.Tags
.uint64
]:
7574 return "JS::CanonicalizedDoubleValue(%s)" % numericValue(tag
, value
.value
)
7575 if tag
== IDLType
.Tags
.bool:
7576 return "JS::BooleanValue(%s)" % (toStringBool(value
.value
))
7577 if tag
in [IDLType
.Tags
.float, IDLType
.Tags
.double
]:
7578 return "JS::CanonicalizedDoubleValue(%s)" % (value
.value
)
7579 raise TypeError("Const value of unhandled type: %s" % value
.type)
7582 class CGArgumentConverter(CGThing
):
7584 A class that takes an IDL argument object and its index in the
7585 argument list and generates code to unwrap the argument to the
7588 argDescription is a description of the argument for error-reporting
7589 purposes. Callers should assume that it might get placed in the middle of a
7590 sentence. If it ends up at the beginning of a sentence, its first character
7591 will be automatically uppercased.
7601 invalidEnumValueFatal
=True,
7602 lenientFloatCode
=None,
7604 CGThing
.__init
__(self
)
7605 self
.argument
= argument
7606 self
.argDescription
= argDescription
7607 assert not argument
.defaultValue
or argument
.optional
7609 replacer
= {"index": index
, "argc": "args.length()"}
7610 self
.replacementVariables
= {
7611 "declName": "arg%d" % index
,
7612 "holderName": ("arg%d" % index
) + "_holder",
7614 "passedToJSImpl": toStringBool(
7615 isJSImplementedDescriptor(descriptorProvider
)
7618 # If we have a method generated by the maplike/setlike portion of an
7619 # interface, arguments can possibly be undefined, but will need to be
7620 # converted to the key/value type of the backing object. In this case,
7621 # use .get() instead of direct access to the argument. This won't
7622 # matter for iterable since generated functions for those interface
7623 # don't take arguments.
7624 if member
.isMethod() and member
.isMaplikeOrSetlikeOrIterableMethod():
7625 self
.replacementVariables
["val"] = string
.Template(
7626 "args.get(${index})"
7627 ).substitute(replacer
)
7628 self
.replacementVariables
["maybeMutableVal"] = string
.Template(
7630 ).substitute(replacer
)
7632 self
.replacementVariables
["val"] = string
.Template(
7634 ).substitute(replacer
)
7635 haveValueCheck
= string
.Template("args.hasDefined(${index})").substitute(
7638 self
.replacementVariables
["haveValue"] = haveValueCheck
7639 self
.descriptorProvider
= descriptorProvider
7640 if self
.argument
.canHaveMissingValue():
7641 self
.argcAndIndex
= replacer
7643 self
.argcAndIndex
= None
7644 self
.invalidEnumValueFatal
= invalidEnumValueFatal
7645 self
.lenientFloatCode
= lenientFloatCode
7648 typeConversion
= getJSToNativeConversionInfo(
7650 self
.descriptorProvider
,
7651 isOptional
=(self
.argcAndIndex
is not None and not self
.argument
.variadic
),
7652 invalidEnumValueFatal
=self
.invalidEnumValueFatal
,
7653 defaultValue
=self
.argument
.defaultValue
,
7654 lenientFloatCode
=self
.lenientFloatCode
,
7655 isMember
="Variadic" if self
.argument
.variadic
else False,
7656 allowTreatNonCallableAsNull
=self
.argument
.allowTreatNonCallableAsNull(),
7657 sourceDescription
=self
.argDescription
,
7660 if not self
.argument
.variadic
:
7661 return instantiateJSToNativeConversion(
7662 typeConversion
, self
.replacementVariables
, self
.argcAndIndex
is not None
7665 # Variadic arguments get turned into a sequence.
7666 if typeConversion
.dealWithOptional
:
7667 raise TypeError("Shouldn't have optional things in variadics")
7668 if typeConversion
.holderType
is not None:
7669 raise TypeError("Shouldn't need holders for variadics")
7671 replacer
= dict(self
.argcAndIndex
, **self
.replacementVariables
)
7672 replacer
["seqType"] = CGTemplatedType(
7673 "AutoSequence", typeConversion
.declType
7675 if typeNeedsRooting(self
.argument
.type):
7677 "SequenceRooter<%s> ${holderName}(cx, &${declName});\n"
7678 % typeConversion
.declType
.define()
7682 replacer
["elemType"] = typeConversion
.declType
.define()
7684 replacer
["elementInitializer"] = initializerForType(self
.argument
.type) or ""
7686 # NOTE: Keep this in sync with sequence conversions as needed
7687 variadicConversion
= string
.Template(
7688 "${seqType} ${declName};\n"
7692 if (${argc} > ${index}) {
7693 if (!${declName}.SetCapacity(${argc} - ${index}, mozilla::fallible)) {
7694 JS_ReportOutOfMemory(cx);
7697 for (uint32_t variadicArg = ${index}; variadicArg < ${argc}; ++variadicArg) {
7698 // OK to do infallible append here, since we ensured capacity already.
7699 ${elemType}& slot = *${declName}.AppendElement(${elementInitializer});
7702 ).substitute(replacer
)
7704 val
= string
.Template("args[variadicArg]").substitute(replacer
)
7705 variadicConversion
+= indent(
7706 string
.Template(typeConversion
.template
).substitute(
7709 "maybeMutableVal": val
,
7711 # We only need holderName here to handle isExternal()
7712 # interfaces, which use an internal holder for the
7713 # conversion even when forceOwningType ends up true.
7714 "holderName": "tempHolder",
7715 # Use the same ${obj} as for the variadic arg itself
7716 "obj": replacer
["obj"],
7717 "passedToJSImpl": toStringBool(
7718 isJSImplementedDescriptor(self
.descriptorProvider
)
7725 variadicConversion
+= " }\n" "}\n"
7726 return variadicConversion
7729 def getMaybeWrapValueFuncForType(type):
7730 if type.isJSString():
7731 return "MaybeWrapStringValue"
7732 # Callbacks might actually be DOM objects; nothing prevents a page from
7734 if type.isCallback() or type.isCallbackInterface() or type.isObject():
7736 return "MaybeWrapObjectOrNullValue"
7737 return "MaybeWrapObjectValue"
7738 # SpiderMonkey interfaces are never DOM objects. Neither are sequences or
7739 # dictionaries, since those are always plain JS objects.
7740 if type.isSpiderMonkeyInterface() or type.isDictionary() or type.isSequence():
7742 return "MaybeWrapNonDOMObjectOrNullValue"
7743 return "MaybeWrapNonDOMObjectValue"
7745 return "MaybeWrapValue"
7747 # For other types, just go ahead an fall back on MaybeWrapValue for now:
7748 # it's always safe to do, and shouldn't be particularly slow for any of
7750 return "MaybeWrapValue"
7753 sequenceWrapLevel
= 0
7757 def getWrapTemplateForType(
7764 spiderMonkeyInterfacesAreStructs
,
7765 isConstructorRetval
=False,
7768 Reflect a C++ value stored in "result", of IDL type "type" into JS. The
7769 "successCode" is the code to run once we have successfully done the
7770 conversion and must guarantee that execution of the conversion template
7771 stops once the successCode has executed (e.g. by doing a 'return', or by
7772 doing a 'break' if the entire conversion template is inside a block that
7773 the 'break' will exit).
7775 If spiderMonkeyInterfacesAreStructs is true, then if the type is a
7776 SpiderMonkey interface, "result" is one of the
7777 dom::SpiderMonkeyInterfaceObjectStorage subclasses, not a JSObject*.
7779 The resulting string should be used with string.Template. It
7780 needs the following keys when substituting:
7782 jsvalHandle: something that can be passed to methods taking a
7783 JS::MutableHandle<JS::Value>. This can be a
7784 JS::MutableHandle<JS::Value> or a JS::Rooted<JS::Value>*.
7785 jsvalRef: something that can have .address() called on it to get a
7786 JS::Value* and .set() called on it to set it to a JS::Value.
7787 This can be a JS::MutableHandle<JS::Value> or a
7788 JS::Rooted<JS::Value>.
7789 obj: a JS::Handle<JSObject*>.
7791 Returns (templateString, infallibility of conversion template)
7793 if successCode
is None:
7794 successCode
= "return true;\n"
7797 return _setValue("", setter
="setUndefined")
7800 return _setValue("", setter
="setNull")
7802 def setInt32(value
):
7803 return _setValue(value
, setter
="setInt32")
7805 def setString(value
):
7806 return _setValue(value
, wrapAsType
=type, setter
="setString")
7808 def setObject(value
, wrapAsType
=None):
7809 return _setValue(value
, wrapAsType
=wrapAsType
, setter
="setObject")
7811 def setObjectOrNull(value
, wrapAsType
=None):
7812 return _setValue(value
, wrapAsType
=wrapAsType
, setter
="setObjectOrNull")
7814 def setUint32(value
):
7815 return _setValue(value
, setter
="setNumber")
7817 def setDouble(value
):
7818 return _setValue("JS_NumberValue(%s)" % value
)
7820 def setBoolean(value
):
7821 return _setValue(value
, setter
="setBoolean")
7823 def _setValue(value
, wrapAsType
=None, setter
="set"):
7825 Returns the code to set the jsval to value.
7827 If wrapAsType is not None, then will wrap the resulting value using the
7828 function that getMaybeWrapValueFuncForType(wrapAsType) returns.
7829 Otherwise, no wrapping will be done.
7831 if wrapAsType
is None:
7836 if (!${maybeWrap}(cx, $${jsvalHandle})) {
7841 maybeWrap
=getMaybeWrapValueFuncForType(wrapAsType
),
7842 exceptionCode
=exceptionCode
,
7843 successCode
=successCode
,
7845 return ("${jsvalRef}.%s(%s);\n" % (setter
, value
)) + tail
7847 def wrapAndSetPtr(wrapCall
, failureCode
=None):
7849 Returns the code to set the jsval by calling "wrapCall". "failureCode"
7850 is the code to run if calling "wrapCall" fails
7852 if failureCode
is None:
7853 failureCode
= exceptionCode
7862 failureCode
=failureCode
,
7863 successCode
=successCode
,
7866 if type is None or type.isUndefined():
7867 return (setUndefined(), True)
7869 if (type.isSequence() or type.isRecord()) and type.nullable():
7870 # These are both wrapped in Nullable<>
7871 recTemplate
, recInfall
= getWrapTemplateForType(
7874 "%s.Value()" % result
,
7878 spiderMonkeyInterfacesAreStructs
,
7883 if (${result}.IsNull()) {
7890 recTemplate
=recTemplate
,
7892 return code
, recInfall
7894 if type.isSequence():
7895 # Now do non-nullable sequences. Our success code is just to break to
7896 # where we set the element in the array. Note that we bump the
7897 # sequenceWrapLevel around this call so that nested sequence conversions
7898 # will use different iteration variables.
7899 global sequenceWrapLevel
7900 index
= "sequenceIdx%d" % sequenceWrapLevel
7901 sequenceWrapLevel
+= 1
7902 innerTemplate
= wrapForType(
7906 "result": "%s[%s]" % (result
, index
),
7907 "successCode": "break;\n",
7909 "jsvalHandle": "&tmp",
7910 "returnsNewObject": returnsNewObject
,
7911 "exceptionCode": exceptionCode
,
7912 "obj": "returnArray",
7913 "spiderMonkeyInterfacesAreStructs": spiderMonkeyInterfacesAreStructs
,
7916 sequenceWrapLevel
-= 1
7920 uint32_t length = ${result}.Length();
7921 JS::Rooted<JSObject*> returnArray(cx, JS::NewArrayObject(cx, length));
7927 JS::Rooted<JS::Value> tmp(cx);
7928 for (uint32_t ${index} = 0; ${index} < length; ++${index}) {
7929 // Control block to let us common up the JS_DefineElement calls when there
7930 // are different ways to succeed at wrapping the object.
7934 if (!JS_DefineElement(cx, returnArray, ${index}, tmp,
7935 JSPROP_ENUMERATE)) {
7943 exceptionCode
=exceptionCode
,
7945 innerTemplate
=innerTemplate
,
7946 set=setObject("*returnArray"),
7949 return (code
, False)
7952 # Now do non-nullable record. Our success code is just to break to
7953 # where we define the property on the object. Note that we bump the
7954 # recordWrapLevel around this call so that nested record conversions
7955 # will use different temp value names.
7956 global recordWrapLevel
7957 valueName
= "recordValue%d" % recordWrapLevel
7958 recordWrapLevel
+= 1
7959 innerTemplate
= wrapForType(
7963 "result": valueName
,
7964 "successCode": "break;\n",
7966 "jsvalHandle": "&tmp",
7967 "returnsNewObject": returnsNewObject
,
7968 "exceptionCode": exceptionCode
,
7970 "spiderMonkeyInterfacesAreStructs": spiderMonkeyInterfacesAreStructs
,
7973 recordWrapLevel
-= 1
7974 if type.keyType
.isByteString():
7975 # There is no length-taking JS_DefineProperty. So to keep
7976 # things sane with embedded nulls, we want to byte-inflate
7977 # to an nsAString. The only byte-inflation function we
7978 # have around is AppendASCIItoUTF16, which luckily doesn't
7979 # assert anything about the input being ASCII.
7980 expandedKeyDecl
= "NS_ConvertASCIItoUTF16 expandedKey(entry.mKey);\n"
7981 keyName
= "expandedKey"
7982 elif type.keyType
.isUTF8String():
7983 # We do the same as above for utf8 strings. We could do better if
7984 # we had a DefineProperty API that takes utf-8 property names.
7985 expandedKeyDecl
= "NS_ConvertUTF8toUTF16 expandedKey(entry.mKey);\n"
7986 keyName
= "expandedKey"
7988 expandedKeyDecl
= ""
7989 keyName
= "entry.mKey"
7994 JS::Rooted<JSObject*> returnObj(cx, JS_NewPlainObject(cx));
8000 JS::Rooted<JS::Value> tmp(cx);
8001 for (auto& entry : ${result}.Entries()) {
8002 auto& ${valueName} = entry.mValue;
8003 // Control block to let us common up the JS_DefineUCProperty calls when there
8004 // are different ways to succeed at wrapping the value.
8009 if (!JS_DefineUCProperty(cx, returnObj,
8010 ${keyName}.BeginReading(),
8011 ${keyName}.Length(), tmp,
8012 JSPROP_ENUMERATE)) {
8020 exceptionCode
=exceptionCode
,
8021 valueName
=valueName
,
8022 innerTemplate
=innerTemplate
,
8023 expandedKeyDecl
=expandedKeyDecl
,
8025 set=setObject("*returnObj"),
8028 return (code
, False)
8030 if type.isPromise():
8031 assert not type.nullable()
8032 # The use of ToJSValue here is a bit annoying because the Promise
8033 # version is not inlined. But we can't put an inline version in either
8034 # ToJSValue.h or BindingUtils.h, because Promise.h includes ToJSValue.h
8035 # and that includes BindingUtils.h, so we'd get an include loop if
8036 # either of those headers included Promise.h. And trying to write the
8037 # conversion by hand here is pretty annoying because we have to handle
8038 # the various RefPtr, rawptr, NonNull, etc cases, which ToJSValue will
8039 # handle for us. So just eat the cost of the function call.
8040 return (wrapAndSetPtr("ToJSValue(cx, %s, ${jsvalHandle})" % result
), False)
8042 if type.isGeckoInterface() and not type.isCallbackInterface():
8043 descriptor
= descriptorProvider
.getDescriptor(
8044 type.unroll().inner
.identifier
.name
8047 if descriptor
.interface
.identifier
.name
== "WindowProxy":
8048 template
, infal
= getWrapTemplateForType(
8051 "%s.Value()" % result
,
8055 spiderMonkeyInterfacesAreStructs
,
8058 "if (%s.IsNull()) {\n" % result
8065 wrappingCode
= "if (!%s) {\n" % (result
) + indent(setNull()) + "}\n"
8069 if not descriptor
.interface
.isExternal():
8070 if descriptor
.wrapperCache
:
8071 wrapMethod
= "GetOrCreateDOMReflector"
8072 wrapArgs
= "cx, %s, ${jsvalHandle}" % result
8074 wrapMethod
= "WrapNewBindingNonWrapperCachedObject"
8075 wrapArgs
= "cx, ${obj}, %s, ${jsvalHandle}" % result
8076 if isConstructorRetval
:
8077 wrapArgs
+= ", desiredProto"
8078 wrap
= "%s(%s)" % (wrapMethod
, wrapArgs
)
8079 # Can only fail to wrap as a new-binding object if they already
8080 # threw an exception.
8081 failed
= "MOZ_ASSERT(JS_IsExceptionPending(cx));\n" + exceptionCode
8083 if descriptor
.notflattened
:
8084 getIID
= "&NS_GET_IID(%s), " % descriptor
.nativeType
8087 wrap
= "WrapObject(cx, %s, %s${jsvalHandle})" % (result
, getIID
)
8090 wrappingCode
+= wrapAndSetPtr(wrap
, failed
)
8091 return (wrappingCode
, False)
8093 if type.isJSString():
8094 return (setString(result
), False)
8096 if type.isDOMString() or type.isUSVString():
8099 wrapAndSetPtr("xpc::StringToJsval(cx, %s, ${jsvalHandle})" % result
),
8105 "xpc::NonVoidStringToJsval(cx, %s, ${jsvalHandle})" % result
8110 if type.isByteString():
8113 wrapAndSetPtr("ByteStringToJsval(cx, %s, ${jsvalHandle})" % result
),
8119 "NonVoidByteStringToJsval(cx, %s, ${jsvalHandle})" % result
8124 if type.isUTF8String():
8127 wrapAndSetPtr("UTF8StringToJsval(cx, %s, ${jsvalHandle})" % result
),
8133 "NonVoidUTF8StringToJsval(cx, %s, ${jsvalHandle})" % result
8140 resultLoc
= "%s.Value()" % result
8145 if (!ToJSValue(cx, ${result}, $${jsvalHandle})) {
8151 exceptionCode
=exceptionCode
,
8152 successCode
=successCode
,
8156 conversion
= CGIfElseWrapper(
8157 "%s.IsNull()" % result
, CGGeneric(setNull()), CGGeneric(conversion
)
8159 return conversion
, False
8161 if type.isCallback() or type.isCallbackInterface():
8162 # Callbacks can store null if we nuked the compartments their
8164 wrapCode
= setObjectOrNull(
8165 "GetCallbackFromCallbackObject(cx, %(result)s)", wrapAsType
=type
8169 "if (%(result)s) {\n"
8175 wrapCode
= wrapCode
% {"result": result
}
8176 return wrapCode
, False
8179 # See comments in GetOrCreateDOMReflector explaining why we need
8181 # NB: _setValue(..., type-that-is-any) calls JS_WrapValue(), so is fallible
8182 head
= "JS::ExposeValueToActiveJS(%s);\n" % result
8183 return (head
+ _setValue(result
, wrapAsType
=type), False)
8185 if type.isObject() or (
8186 type.isSpiderMonkeyInterface() and not spiderMonkeyInterfacesAreStructs
8188 # See comments in GetOrCreateDOMReflector explaining why we need
8192 setter
= setObjectOrNull
8194 JS::ExposeObjectToActiveJS(%s);
8203 head
= "JS::ExposeObjectToActiveJS(%s);\n" % result
8204 # NB: setObject{,OrNull}(..., some-object-type) calls JS_WrapValue(), so is fallible
8205 return (head
+ setter(toValue
% result
, wrapAsType
=type), False)
8207 if type.isObservableArray():
8208 # This first argument isn't used at all for now, the attribute getter
8209 # for ObservableArray type are generated in getObservableArrayGetterBody
8215 or type.isPrimitive()
8216 or type.isDictionary()
8217 or (type.isSpiderMonkeyInterface() and spiderMonkeyInterfacesAreStructs
)
8219 raise TypeError("Need to learn to wrap %s" % type)
8222 recTemplate
, recInfal
= getWrapTemplateForType(
8225 "%s.Value()" % result
,
8229 spiderMonkeyInterfacesAreStructs
,
8232 "if (%s.IsNull()) {\n" % result
+ indent(setNull()) + "}\n" + recTemplate
,
8236 if type.isSpiderMonkeyInterface():
8237 assert spiderMonkeyInterfacesAreStructs
8238 # See comments in GetOrCreateDOMReflector explaining why we need
8240 # NB: setObject(..., some-object-type) calls JS_WrapValue(), so is fallible
8241 return (setObject("*%s.Obj()" % result
, wrapAsType
=type), False)
8244 return (wrapAndSetPtr("%s.ToJSVal(cx, ${obj}, ${jsvalHandle})" % result
), False)
8246 if type.isDictionary():
8248 wrapAndSetPtr("%s.ToObjectInternal(cx, ${jsvalHandle})" % result
),
8258 IDLType
.Tags
.uint16
,
8261 return (setInt32("int32_t(%s)" % result
), True)
8265 IDLType
.Tags
.uint64
,
8266 IDLType
.Tags
.unrestricted_float
,
8268 IDLType
.Tags
.unrestricted_double
,
8269 IDLType
.Tags
.double
,
8271 # XXXbz will cast to double do the "even significand" thing that webidl
8272 # calls for for 64-bit ints? Do we care?
8273 return (setDouble("double(%s)" % result
), True)
8275 elif tag
== IDLType
.Tags
.uint32
:
8276 return (setUint32(result
), True)
8278 elif tag
== IDLType
.Tags
.bool:
8279 return (setBoolean(result
), True)
8282 raise TypeError("Need to learn to wrap primitive: %s" % type)
8285 def wrapForType(type, descriptorProvider
, templateValues
):
8287 Reflect a C++ value of IDL type "type" into JS. TemplateValues is a dict
8288 that should contain:
8290 * 'jsvalRef': something that can have .address() called on it to get a
8291 JS::Value* and .set() called on it to set it to a JS::Value.
8292 This can be a JS::MutableHandle<JS::Value> or a
8293 JS::Rooted<JS::Value>.
8294 * 'jsvalHandle': something that can be passed to methods taking a
8295 JS::MutableHandle<JS::Value>. This can be a
8296 JS::MutableHandle<JS::Value> or a JS::Rooted<JS::Value>*.
8297 * 'obj' (optional): the name of the variable that contains the JSObject to
8298 use as a scope when wrapping, if not supplied 'obj'
8299 will be used as the name
8300 * 'result' (optional): the name of the variable in which the C++ value is
8301 stored, if not supplied 'result' will be used as
8303 * 'successCode' (optional): the code to run once we have successfully
8304 done the conversion, if not supplied 'return
8305 true;' will be used as the code. The
8306 successCode must ensure that once it runs no
8307 more of the conversion template will be
8308 executed (e.g. by doing a 'return' or 'break'
8310 * 'returnsNewObject' (optional): If true, we're wrapping for the return
8311 value of a [NewObject] method. Assumed
8313 * 'exceptionCode' (optional): Code to run when a JS exception is thrown.
8314 The default is "return false;". The code
8315 passed here must return.
8316 * 'isConstructorRetval' (optional): If true, we're wrapping a constructor
8319 wrap
= getWrapTemplateForType(
8322 templateValues
.get("result", "result"),
8323 templateValues
.get("successCode", None),
8324 templateValues
.get("returnsNewObject", False),
8325 templateValues
.get("exceptionCode", "return false;\n"),
8326 templateValues
.get("spiderMonkeyInterfacesAreStructs", False),
8327 isConstructorRetval
=templateValues
.get("isConstructorRetval", False),
8330 defaultValues
= {"obj": "obj"}
8331 return string
.Template(wrap
).substitute(defaultValues
, **templateValues
)
8334 def infallibleForMember(member
, type, descriptorProvider
):
8336 Determine the fallibility of changing a C++ value of IDL type "type" into
8337 JS for the given attribute. Apart from returnsNewObject, all the defaults
8338 are used, since the fallbility does not change based on the boolean values,
8339 and the template will be discarded.
8341 CURRENT ASSUMPTIONS:
8342 We assume that successCode for wrapping up return values cannot contain
8345 return getWrapTemplateForType(
8350 memberReturnsNewObject(member
),
8356 def leafTypeNeedsCx(type, retVal
):
8360 or type.isJSString()
8361 or (retVal
and type.isSpiderMonkeyInterface())
8365 def leafTypeNeedsScopeObject(type, retVal
):
8366 return retVal
and type.isSpiderMonkeyInterface()
8369 def leafTypeNeedsRooting(type):
8370 return leafTypeNeedsCx(type, False) or type.isSpiderMonkeyInterface()
8373 def typeNeedsRooting(type):
8374 return typeMatchesLambda(type, lambda t
: leafTypeNeedsRooting(t
))
8377 def typeNeedsCx(type, retVal
=False):
8378 return typeMatchesLambda(type, lambda t
: leafTypeNeedsCx(t
, retVal
))
8381 def typeNeedsScopeObject(type, retVal
=False):
8382 return typeMatchesLambda(type, lambda t
: leafTypeNeedsScopeObject(t
, retVal
))
8385 def typeMatchesLambda(type, func
):
8389 return typeMatchesLambda(type.inner
, func
)
8390 if type.isSequence() or type.isRecord():
8391 return typeMatchesLambda(type.inner
, func
)
8393 return any(typeMatchesLambda(t
, func
) for t
in type.unroll().flatMemberTypes
)
8394 if type.isDictionary():
8395 return dictionaryMatchesLambda(type.inner
, func
)
8399 def dictionaryMatchesLambda(dictionary
, func
):
8400 return any(typeMatchesLambda(m
.type, func
) for m
in dictionary
.members
) or (
8401 dictionary
.parent
and dictionaryMatchesLambda(dictionary
.parent
, func
)
8405 # Whenever this is modified, please update CGNativeMember.getRetvalInfo as
8406 # needed to keep the types compatible.
8407 def getRetvalDeclarationForType(returnType
, descriptorProvider
, isMember
=False):
8409 Returns a tuple containing five things:
8411 1) A CGThing for the type of the return value, or None if there is no need
8414 2) A value indicating the kind of ourparam to pass the value as. Valid
8415 options are None to not pass as an out param at all, "ref" (to pass a
8416 reference as an out param), and "ptr" (to pass a pointer as an out
8419 3) A CGThing for a tracer for the return value, or None if no tracing is
8422 4) An argument string to pass to the retval declaration
8423 constructor or None if there are no arguments.
8425 5) The name of a function that needs to be called with the return value
8426 before using it, or None if no function needs to be called.
8428 if returnType
is None or returnType
.isUndefined():
8429 # Nothing to declare
8430 return None, None, None, None, None
8431 if returnType
.isPrimitive() and returnType
.tag() in builtinNames
:
8432 result
= CGGeneric(builtinNames
[returnType
.tag()])
8433 if returnType
.nullable():
8434 result
= CGTemplatedType("Nullable", result
)
8435 return result
, None, None, None, None
8436 if returnType
.isJSString():
8438 raise TypeError("JSString not supported as return type member")
8439 return CGGeneric("JS::Rooted<JSString*>"), "ptr", None, "cx", None
8440 if returnType
.isDOMString() or returnType
.isUSVString():
8442 return CGGeneric("nsString"), "ref", None, None, None
8443 return CGGeneric("DOMString"), "ref", None, None, None
8444 if returnType
.isByteString() or returnType
.isUTF8String():
8446 return CGGeneric("nsCString"), "ref", None, None, None
8447 return CGGeneric("nsAutoCString"), "ref", None, None, None
8448 if returnType
.isEnum():
8449 result
= CGGeneric(returnType
.unroll().inner
.identifier
.name
)
8450 if returnType
.nullable():
8451 result
= CGTemplatedType("Nullable", result
)
8452 return result
, None, None, None, None
8453 if returnType
.isGeckoInterface() or returnType
.isPromise():
8454 if returnType
.isGeckoInterface():
8455 typeName
= returnType
.unroll().inner
.identifier
.name
8456 if typeName
== "WindowProxy":
8457 result
= CGGeneric("WindowProxyHolder")
8458 if returnType
.nullable():
8459 result
= CGTemplatedType("Nullable", result
)
8460 return result
, None, None, None, None
8462 typeName
= descriptorProvider
.getDescriptor(typeName
).nativeType
8464 typeName
= "Promise"
8467 result
= CGGeneric("StrongPtrForMember<%s>" % typeName
)
8469 conversion
= CGGeneric("StrongOrRawPtr<%s>" % typeName
)
8470 result
= CGGeneric("auto")
8471 return result
, None, None, None, conversion
8472 if returnType
.isCallback():
8473 name
= returnType
.unroll().callback
.identifier
.name
8474 return CGGeneric("RefPtr<%s>" % name
), None, None, None, None
8475 if returnType
.isAny():
8477 return CGGeneric("JS::Value"), None, None, None, None
8478 return CGGeneric("JS::Rooted<JS::Value>"), "ptr", None, "cx", None
8479 if returnType
.isObject() or returnType
.isSpiderMonkeyInterface():
8481 return CGGeneric("JSObject*"), None, None, None, None
8482 return CGGeneric("JS::Rooted<JSObject*>"), "ptr", None, "cx", None
8483 if returnType
.isSequence():
8484 nullable
= returnType
.nullable()
8486 returnType
= returnType
.inner
8487 result
, _
, _
, _
, _
= getRetvalDeclarationForType(
8488 returnType
.inner
, descriptorProvider
, isMember
="Sequence"
8490 # While we have our inner type, set up our rooter, if needed
8491 if not isMember
and typeNeedsRooting(returnType
):
8493 "SequenceRooter<%s > resultRooter(cx, &result);\n" % result
.define()
8497 result
= CGTemplatedType("nsTArray", result
)
8499 result
= CGTemplatedType("Nullable", result
)
8500 return result
, "ref", rooter
, None, None
8501 if returnType
.isRecord():
8502 nullable
= returnType
.nullable()
8504 returnType
= returnType
.inner
8505 result
, _
, _
, _
, _
= getRetvalDeclarationForType(
8506 returnType
.inner
, descriptorProvider
, isMember
="Record"
8508 # While we have our inner type, set up our rooter, if needed
8509 if not isMember
and typeNeedsRooting(returnType
):
8511 "RecordRooter<%s> resultRooter(cx, &result);\n"
8512 % ("nsString, " + result
.define())
8516 result
= CGTemplatedType("Record", [recordKeyDeclType(returnType
), result
])
8518 result
= CGTemplatedType("Nullable", result
)
8519 return result
, "ref", rooter
, None, None
8520 if returnType
.isDictionary():
8521 nullable
= returnType
.nullable()
8522 dictName
= CGDictionary
.makeDictionaryName(returnType
.unroll().inner
)
8523 result
= CGGeneric(dictName
)
8524 if not isMember
and typeNeedsRooting(returnType
):
8526 result
= CGTemplatedType("NullableRootedDictionary", result
)
8528 result
= CGTemplatedType("RootedDictionary", result
)
8532 result
= CGTemplatedType("Nullable", result
)
8534 return result
, "ref", None, resultArgs
, None
8535 if returnType
.isUnion():
8536 result
= CGGeneric(CGUnionStruct
.unionTypeName(returnType
.unroll(), True))
8537 if not isMember
and typeNeedsRooting(returnType
):
8538 if returnType
.nullable():
8539 result
= CGTemplatedType("NullableRootedUnion", result
)
8541 result
= CGTemplatedType("RootedUnion", result
)
8544 if returnType
.nullable():
8545 result
= CGTemplatedType("Nullable", result
)
8547 return result
, "ref", None, resultArgs
, None
8548 raise TypeError("Don't know how to declare return value for %s" % returnType
)
8551 def needCx(returnType
, arguments
, extendedAttributes
, considerTypes
, static
=False):
8556 typeNeedsCx(returnType
, True) or any(typeNeedsCx(a
.type) for a
in arguments
)
8558 or "implicitJSContext" in extendedAttributes
8562 def needScopeObject(
8563 returnType
, arguments
, extendedAttributes
, isWrapperCached
, considerTypes
, isMember
8566 isMember should be true if we're dealing with an attribute
8567 annotated as [StoreInSlot].
8571 and not isWrapperCached
8573 (not isMember
and typeNeedsScopeObject(returnType
, True))
8574 or any(typeNeedsScopeObject(a
.type) for a
in arguments
)
8579 def callerTypeGetterForDescriptor(descriptor
):
8580 if descriptor
.interface
.isExposedInAnyWorker():
8581 systemCallerGetter
= "nsContentUtils::ThreadsafeIsSystemCaller"
8583 systemCallerGetter
= "nsContentUtils::IsSystemCaller"
8584 return "%s(cx) ? CallerType::System : CallerType::NonSystem" % systemCallerGetter
8587 class CGCallGenerator(CGThing
):
8589 A class to generate an actual call to a C++ object. Assumes that the C++
8590 object is stored in a variable whose name is given by the |object| argument.
8592 needsCallerType is a boolean indicating whether the call should receive
8593 a PrincipalType for the caller.
8595 needsErrorResult is a boolean indicating whether the call should be
8596 fallible and thus needs ErrorResult parameter.
8598 resultVar: If the returnType is not void, then the result of the call is
8599 stored in a C++ variable named by resultVar. The caller is responsible for
8600 declaring the result variable. If the caller doesn't care about the result
8601 value, resultVar can be omitted.
8603 context: The context string to pass to MaybeSetPendingException.
8623 CGThing
.__init
__(self
)
8631 ) = getRetvalDeclarationForType(returnType
, descriptor
)
8633 args
= CGList([CGGeneric(arg
) for arg
in argsPre
], ", ")
8634 for a
, name
in arguments
:
8635 arg
= CGGeneric(name
)
8637 # Now constify the things that need it
8639 if a
.type.isDictionary():
8641 if a
.type.isSequence():
8643 if a
.type.isRecord():
8645 # isObject() types are always a JS::Rooted, whether
8646 # nullable or not, and it turns out a const JS::Rooted
8647 # is not very helpful at all (in particular, it won't
8648 # even convert to a JS::Handle).
8649 # XXX bz Well, why not???
8650 if a
.type.nullable() and not a
.type.isObject():
8652 if a
.type.isString():
8654 if a
.canHaveMissingValue():
8655 # This will need an Optional or it's a variadic;
8656 # in both cases it should be const.
8658 if a
.type.isUnion():
8660 if a
.type.isSpiderMonkeyInterface():
8665 arg
= CGWrapper(arg
, pre
="Constify(", post
=")")
8666 # And convert NonNull<T> to T&
8668 (a
.type.isGeckoInterface() or a
.type.isCallback() or a
.type.isPromise())
8669 and not a
.type.nullable()
8670 ) or a
.type.isDOMString():
8671 arg
= CGWrapper(arg
, pre
="NonNullHelper(", post
=")")
8673 # If it's a refcounted object, let the static analysis know it's
8674 # alive for the duration of the call.
8675 if a
.type.isGeckoInterface() or a
.type.isCallback():
8676 arg
= CGWrapper(arg
, pre
="MOZ_KnownLive(", post
=")")
8680 needResultDecl
= False
8682 # Build up our actual call
8683 self
.cgRoot
= CGList([])
8685 # Return values that go in outparams go here
8686 if resultOutParam
is not None:
8687 if resultVar
is None:
8688 needResultDecl
= True
8689 resultVar
= "result"
8690 if resultOutParam
== "ref":
8691 args
.append(CGGeneric(resultVar
))
8693 assert resultOutParam
== "ptr"
8694 args
.append(CGGeneric("&" + resultVar
))
8696 needsSubjectPrincipal
= "needsSubjectPrincipal" in extendedAttributes
8697 if needsSubjectPrincipal
:
8698 needsNonSystemPrincipal
= (
8699 "needsNonSystemSubjectPrincipal" in extendedAttributes
8701 if needsNonSystemPrincipal
:
8702 principalType
= "nsIPrincipal*"
8703 subjectPrincipalArg
= "subjectPrincipal"
8704 checkPrincipal
= dedent(
8706 if (principal->IsSystemPrincipal()) {
8707 principal = nullptr;
8712 principalType
= "NonNull<nsIPrincipal>"
8713 subjectPrincipalArg
= "NonNullHelper(subjectPrincipal)"
8720 ${principalType} subjectPrincipal;
8722 JS::Realm* realm = js::GetContextRealm(cx);
8724 JSPrincipals* principals = JS::GetRealmPrincipals(realm);
8725 nsIPrincipal* principal = nsJSPrincipals::get(principals);
8727 subjectPrincipal = principal;
8730 principalType
=principalType
,
8731 checkPrincipal
=checkPrincipal
,
8736 args
.append(CGGeneric("MOZ_KnownLive(%s)" % subjectPrincipalArg
))
8740 args
.append(CGGeneric("SystemCallerGuarantee()"))
8742 args
.append(CGGeneric(callerTypeGetterForDescriptor(descriptor
)))
8744 canOOM
= "canOOM" in extendedAttributes
8745 if needsErrorResult
:
8746 args
.append(CGGeneric("rv"))
8748 args
.append(CGGeneric("OOMReporter::From(rv)"))
8749 args
.extend(CGGeneric(arg
) for arg
in argsPost
)
8751 call
= CGGeneric(nativeMethodName
)
8753 call
= CGWrapper(call
, pre
="%s->" % object)
8754 call
= CGList([call
, CGWrapper(args
, pre
="(", post
=")")])
8755 if returnType
is None or returnType
.isUndefined() or resultOutParam
is not None:
8756 assert resultConversion
is None
8762 "// NOTE: This assert does NOT call the function.\n"
8763 "static_assert(std::is_void_v<decltype("
8765 post
=')>, "Should be returning void here");',
8771 elif resultConversion
is not None:
8772 call
= CGList([resultConversion
, CGWrapper(call
, pre
="(", post
=")")])
8773 if resultVar
is None and result
is not None:
8774 needResultDecl
= True
8775 resultVar
= "result"
8778 if resultArgs
is not None:
8779 resultArgsStr
= "(%s)" % resultArgs
8782 result
= CGWrapper(result
, post
=(" %s%s" % (resultVar
, resultArgsStr
)))
8783 if resultOutParam
is None and resultArgs
is None:
8784 call
= CGList([result
, CGWrapper(call
, pre
="(", post
=")")])
8786 self
.cgRoot
.append(CGWrapper(result
, post
=";\n"))
8787 if resultOutParam
is None:
8788 call
= CGWrapper(call
, pre
=resultVar
+ " = ")
8789 if resultRooter
is not None:
8790 self
.cgRoot
.append(resultRooter
)
8791 elif result
is not None:
8792 assert resultOutParam
is None
8793 call
= CGWrapper(call
, pre
=resultVar
+ " = ")
8795 call
= CGWrapper(call
, post
=";\n")
8796 self
.cgRoot
.append(call
)
8798 if needsErrorResult
or canOOM
:
8799 self
.cgRoot
.prepend(CGGeneric("FastErrorResult rv;\n"))
8804 if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx, ${context}))) {
8813 self
.cgRoot
.append(CGGeneric("MOZ_ASSERT(!JS_IsExceptionPending(cx));\n"))
8816 return self
.cgRoot
.define()
8819 def getUnionMemberName(type):
8820 # Promises can't be in unions, because they're not distinguishable
8821 # from anything else.
8822 assert not type.isPromise()
8823 if type.isGeckoInterface():
8824 return type.inner
.identifier
.name
8826 return type.inner
.identifier
.name
8830 # A counter for making sure that when we're wrapping up things in
8831 # nested sequences we don't use the same variable name to iterate over
8832 # different sequences.
8833 sequenceWrapLevel
= 0
8837 def wrapTypeIntoCurrentCompartment(type, value
, isMember
=True):
8839 Take the thing named by "value" and if it contains "any",
8840 "object", or spidermonkey-interface types inside return a CGThing
8841 that will wrap them into the current compartment.
8844 assert not type.nullable()
8846 value
= "JS::MutableHandle<JS::Value>::fromMarkedLocation(&%s)" % value
8850 "if (!JS_WrapValue(cx, %s)) {\n" " return false;\n" "}\n" % value
8855 value
= "JS::MutableHandle<JSObject*>::fromMarkedLocation(&%s)" % value
8859 "if (!JS_WrapObject(cx, %s)) {\n" " return false;\n" "}\n" % value
8862 if type.isSpiderMonkeyInterface():
8865 value
= "%s.Value()" % value
8866 wrapCode
= CGGeneric(
8867 "if (!%s.WrapIntoNewCompartment(cx)) {\n" " return false;\n" "}\n" % value
8870 wrapCode
= CGIfWrapper(wrapCode
, "!%s.IsNull()" % origValue
)
8873 if type.isSequence():
8878 value
= "%s.Value()" % value
8879 global sequenceWrapLevel
8880 index
= "indexName%d" % sequenceWrapLevel
8881 sequenceWrapLevel
+= 1
8882 wrapElement
= wrapTypeIntoCurrentCompartment(
8883 type.inner
, "%s[%s]" % (value
, index
)
8885 sequenceWrapLevel
-= 1
8888 wrapCode
= CGWrapper(
8889 CGIndenter(wrapElement
),
8891 "for (uint32_t %s = 0; %s < %s.Length(); ++%s) {\n"
8892 % (index
, index
, value
, index
)
8896 if origType
.nullable():
8897 wrapCode
= CGIfWrapper(wrapCode
, "!%s.IsNull()" % origValue
)
8904 recordRef
= "%s.Value()" % value
8907 global recordWrapLevel
8908 entryRef
= "mapEntry%d" % recordWrapLevel
8909 recordWrapLevel
+= 1
8910 wrapElement
= wrapTypeIntoCurrentCompartment(type.inner
, "%s.mValue" % entryRef
)
8911 recordWrapLevel
-= 1
8914 wrapCode
= CGWrapper(
8915 CGIndenter(wrapElement
),
8916 pre
=("for (auto& %s : %s.Entries()) {\n" % (entryRef
, recordRef
)),
8919 if origType
.nullable():
8920 wrapCode
= CGIfWrapper(wrapCode
, "!%s.IsNull()" % value
)
8923 if type.isDictionary():
8924 assert not type.nullable()
8928 for member
in myDict
.members
:
8929 memberWrap
= wrapArgIntoCurrentCompartment(
8932 % (value
, CGDictionary
.makeMemberName(member
.identifier
.name
)),
8935 memberWraps
.append(memberWrap
)
8936 myDict
= myDict
.parent
8937 return CGList(memberWraps
) if len(memberWraps
) != 0 else None
8943 value
= "%s.Value()" % value
8944 for member
in type.flatMemberTypes
:
8945 memberName
= getUnionMemberName(member
)
8946 memberWrap
= wrapTypeIntoCurrentCompartment(
8947 member
, "%s.GetAs%s()" % (value
, memberName
)
8950 memberWrap
= CGIfWrapper(memberWrap
, "%s.Is%s()" % (value
, memberName
))
8951 memberWraps
.append(memberWrap
)
8952 return CGList(memberWraps
, "else ") if len(memberWraps
) != 0 else None
8957 or type.isPrimitive()
8959 or type.isGeckoInterface()
8960 or type.isCallback()
8963 # All of these don't need wrapping.
8967 "Unknown type; we don't know how to wrap it in constructor "
8968 "arguments: %s" % type
8972 def wrapArgIntoCurrentCompartment(arg
, value
, isMember
=True):
8974 As wrapTypeIntoCurrentCompartment but handles things being optional
8977 isOptional
= arg
.canHaveMissingValue()
8979 value
= value
+ ".Value()"
8980 wrap
= wrapTypeIntoCurrentCompartment(arg
.type, value
, isMember
)
8981 if wrap
and isOptional
:
8982 wrap
= CGIfWrapper(wrap
, "%s.WasPassed()" % origValue
)
8986 def needsCallerType(m
):
8987 return m
.getExtendedAttribute("NeedsCallerType")
8990 class CGPerSignatureCall(CGThing
):
8992 This class handles the guts of generating code for a particular
8993 call signature. A call signature consists of four things:
8995 1) A return type, which can be None to indicate that there is no
8996 actual return value (e.g. this is an attribute setter) or an
8997 IDLType if there's an IDL type involved (including |void|).
8998 2) An argument list, which is allowed to be empty.
8999 3) A name of a native method to call. It is ignored for methods
9000 annotated with the "[WebExtensionStub=...]" extended attribute.
9001 4) Whether or not this method is static. Note that this only controls how
9002 the method is called (|self->nativeMethodName(...)| vs
9003 |nativeMethodName(...)|).
9005 We also need to know whether this is a method or a getter/setter
9006 to do error reporting correctly.
9008 The idlNode parameter can be either a method or an attr. We can query
9009 |idlNode.identifier| in both cases, so we can be agnostic between the two.
9011 dontSetSlot should be set to True if the value should not be cached in a
9012 slot (even if the attribute is marked as StoreInSlot or Cached in the
9015 errorReportingLabel can contain a custom label to use for error reporting.
9016 It will be inserted as is in the code, so if it needs to be a literal
9017 string in C++ it should be quoted.
9019 additionalArgsPre contains additional arguments that are added after the
9020 arguments that CGPerSignatureCall itself adds (JSContext, global, …), and
9021 before the actual arguments.
9024 # XXXbz For now each entry in the argument list is either an
9025 # IDLArgument or a FakeArgument, but longer-term we may want to
9026 # have ways of flagging things like JSContext* or optional_argc in
9037 argConversionStartsAt
=0,
9040 isConstructor
=False,
9041 useCounterName
=None,
9045 extendedAttributes
=None,
9046 errorReportingLabel
=None,
9047 additionalArgsPre
=[],
9049 assert idlNode
.isMethod() == (not getter
and not setter
)
9050 assert idlNode
.isAttr() == (getter
or setter
)
9051 # Constructors are always static
9052 assert not isConstructor
or static
9054 CGThing
.__init
__(self
)
9055 self
.returnType
= returnType
9056 self
.descriptor
= descriptor
9057 self
.idlNode
= idlNode
9058 if extendedAttributes
is None:
9059 extendedAttributes
= descriptor
.getExtendedAttributes(
9060 idlNode
, getter
=getter
, setter
=setter
9062 self
.extendedAttributes
= extendedAttributes
9063 self
.arguments
= arguments
9064 self
.argCount
= len(arguments
)
9065 self
.isConstructor
= isConstructor
9067 not dontSetSlot
and idlNode
.isAttr() and idlNode
.slotIndices
is not None
9071 deprecated
= idlNode
.getExtendedAttribute("Deprecated") or (
9073 and descriptor
.interface
.getExtendedAttribute("Deprecated")
9080 DeprecationWarning(cx, obj, DeprecatedOperations::e%s);
9087 lenientFloatCode
= None
9088 if idlNode
.getExtendedAttribute("LenientFloat") is not None and (
9089 setter
or idlNode
.isMethod()
9095 bool foundNonFiniteFloat = false;
9100 lenientFloatCode
= "foundNonFiniteFloat = true;\n"
9103 if idlNode
.isStatic():
9104 # If we're a constructor, "obj" may not be a function, so calling
9105 # XrayAwareCalleeGlobal() on it is not safe. Of course in the
9106 # constructor case either "obj" is an Xray or we're already in the
9107 # content compartment, not the Xray compartment, so just
9108 # constructing the GlobalObject from "obj" is fine.
9110 objForGlobalObject
= "obj"
9112 objForGlobalObject
= "xpc::XrayAwareCalleeGlobal(obj)"
9117 GlobalObject global(cx, ${obj});
9118 if (global.Failed()) {
9123 obj
=objForGlobalObject
,
9127 argsPre
.append("global")
9129 # For JS-implemented interfaces we do not want to base the
9130 # needsCx decision on the types involved, just on our extended
9131 # attributes. Also, JSContext is not needed for the static case
9132 # since GlobalObject already contains the context.
9136 self
.extendedAttributes
,
9137 not descriptor
.interface
.isJSImplemented(),
9141 argsPre
.append("cx")
9145 runConstructorInCallerCompartment
= descriptor
.interface
.getExtendedAttribute(
9146 "RunConstructorInCallerCompartment"
9148 if isConstructor
and not runConstructorInCallerCompartment
:
9150 needsUnwrappedVar
= False
9151 unwrappedVar
= "obj"
9152 if descriptor
.interface
.isJSImplemented():
9153 # We need the desired proto in our constructor, because the
9154 # constructor will actually construct our reflector.
9155 argsPost
.append("desiredProto")
9156 elif descriptor
.interface
.isJSImplemented():
9157 if not idlNode
.isStatic():
9159 needsUnwrappedVar
= True
9161 "(unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx))"
9163 elif needScopeObject(
9166 self
.extendedAttributes
,
9167 descriptor
.wrapperCache
,
9169 idlNode
.getExtendedAttribute("StoreInSlot"),
9171 # If we ever end up with APIs like this on cross-origin objects,
9172 # figure out how the CheckedUnwrapDynamic bits should work. Chances
9173 # are, just calling it with "cx" is fine... For now, though, just
9174 # assert that it does not matter.
9175 assert not descriptor
.isMaybeCrossOriginObject()
9176 # The scope object should always be from the relevant
9177 # global. Make sure to unwrap it as needed.
9182 JS::Rooted<JSObject*> unwrappedObj(cx, js::CheckedUnwrapStatic(obj));
9183 // Caller should have ensured that "obj" can be unwrapped already.
9184 MOZ_DIAGNOSTIC_ASSERT(unwrappedObj);
9189 argsPre
.append("unwrappedObj")
9191 if needsUnwrap
and needsUnwrappedVar
:
9192 # We cannot assign into obj because it's a Handle, not a
9193 # MutableHandle, so we need a separate Rooted.
9194 cgThings
.append(CGGeneric("Maybe<JS::Rooted<JSObject*> > unwrappedObj;\n"))
9195 unwrappedVar
= "unwrappedObj.ref()"
9197 if idlNode
.isMethod() and idlNode
.isLegacycaller():
9198 # If we can have legacycaller with identifier, we can't
9199 # just use the idlNode to determine whether we're
9200 # generating code for the legacycaller or not.
9201 assert idlNode
.isIdentifierLess()
9202 # Pass in our thisVal
9203 argsPre
.append("args.thisv()")
9205 if idlNode
.isMethod():
9206 argDescription
= "argument %(index)d"
9208 argDescription
= "value being assigned"
9210 assert self
.argCount
== 0
9213 # It's very important that we construct our unwrappedObj, if we need
9214 # to do it, before we might start setting up Rooted things for our
9215 # arguments, so that we don't violate the stack discipline Rooted
9218 CGGeneric("bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);\n")
9220 if needsUnwrappedVar
:
9223 CGGeneric("unwrappedObj.emplace(cx, obj);\n"), "objIsXray"
9227 for i
in range(argConversionStartsAt
, self
.argCount
):
9229 CGArgumentConverter(
9233 argDescription
% {"index": i
+ 1},
9235 invalidEnumValueFatal
=not setter
,
9236 lenientFloatCode
=lenientFloatCode
,
9240 # Now that argument processing is done, enforce the LenientFloat stuff
9241 if lenientFloatCode
:
9243 foundNonFiniteFloatBehavior
= "return true;\n"
9245 assert idlNode
.isMethod()
9246 foundNonFiniteFloatBehavior
= dedent(
9248 args.rval().setUndefined();
9256 if (foundNonFiniteFloat) {
9260 returnSteps
=foundNonFiniteFloatBehavior
,
9266 # Something depends on having the unwrapped object, so unwrap it now.
9268 # XXXkhuey we should be able to MOZ_ASSERT that ${obj} is
9274 // Since our object is an Xray, we can just CheckedUnwrapStatic:
9275 // we know Xrays have no dynamic unwrap behavior.
9276 ${obj} = js::CheckedUnwrapStatic(${obj});
9286 # If we're called via an xray, we need to enter the underlying
9287 # object's compartment and then wrap up all of our arguments into
9288 # that compartment as needed. This is all happening after we've
9289 # already done the conversions from JS values to WebIDL (C++)
9290 # values, so we only need to worry about cases where there are 'any'
9291 # or 'object' types, or other things that we represent as actual
9292 # JSAPI types, present. Effectively, we're emulating a
9293 # CrossCompartmentWrapper, but working with the C++ types, not the
9294 # original list of JS::Values.
9295 cgThings
.append(CGGeneric("Maybe<JSAutoRealm> ar;\n"))
9296 xraySteps
.append(CGGeneric("ar.emplace(cx, obj);\n"))
9301 if (!JS_WrapObject(cx, &desiredProto)) {
9309 wrapArgIntoCurrentCompartment(arg
, argname
, isMember
=False)
9310 for arg
, argname
in self
.getArguments()
9313 cgThings
.append(CGIfWrapper(CGList(xraySteps
), "objIsXray"))
9315 if idlNode
.getExtendedAttribute("CEReactions") is not None and not getter
:
9320 Maybe<AutoCEReaction> ceReaction;
9321 DocGroup* docGroup = self->GetDocGroup();
9323 ceReaction.emplace(docGroup->CustomElementReactionsStack(), cx);
9330 # If this is a method that was generated by a maplike/setlike
9331 # interface, use the maplike/setlike generator to fill in the body.
9332 # Otherwise, use CGCallGenerator to call the native method.
9333 if idlNode
.isMethod() and idlNode
.isMaplikeOrSetlikeOrIterableMethod():
9335 idlNode
.maplikeOrSetlikeOrIterable
.isMaplike()
9336 or idlNode
.maplikeOrSetlikeOrIterable
.isSetlike()
9339 CGMaplikeOrSetlikeMethodGenerator(
9341 idlNode
.maplikeOrSetlikeOrIterable
,
9342 idlNode
.identifier
.name
,
9347 CGIterableMethodGenerator(
9349 idlNode
.identifier
.name
,
9350 self
.getArgumentNames(),
9353 elif idlNode
.isAttr() and idlNode
.type.isObservableArray():
9355 cgThings
.append(CGObservableArraySetterGenerator(descriptor
, idlNode
))
9357 if errorReportingLabel
is None:
9358 context
= GetLabelForErrorReporting(descriptor
, idlNode
, isConstructor
)
9360 context
= context
+ " getter"
9362 context
= context
+ " setter"
9363 # Callee expects a quoted string for the context if
9364 # there's a context.
9365 context
= '"%s"' % context
9367 context
= errorReportingLabel
9369 if idlNode
.isMethod() and idlNode
.getExtendedAttribute("WebExtensionStub"):
9374 ] = self
.processWebExtensionStubAttribute(cgThings
)
9376 args
= self
.getArguments()
9380 self
.needsErrorResult(),
9381 needsCallerType(idlNode
),
9382 isChromeOnly(idlNode
),
9384 argsPre
+ additionalArgsPre
,
9386 self
.extendedAttributes
,
9390 # We know our "self" must be being kept alive; otherwise we have
9391 # a serious problem. In common cases it's just an argument and
9392 # we're MOZ_CAN_RUN_SCRIPT, but in some cases it's on the stack
9393 # and being kept alive via references from JS.
9394 object="MOZ_KnownLive(self)",
9396 resultVar
=resultVar
,
9402 # Generate a telemetry call for when [UseCounter] is used.
9405 SetUseCounter(obj, eUseCounter_${useCounterName});
9407 useCounterName
=useCounterName
,
9411 SetUseCounter(UseCounterWorker::${useCounterName});
9413 useCounterName
=useCounterName
,
9416 if idlNode
.isExposedInWindow() and idlNode
.isExposedInAnyWorker():
9419 if (NS_IsMainThread()) {
9425 windowCode
=windowCode
,
9426 workerCode
=workerCode
,
9428 elif idlNode
.isExposedInWindow():
9430 elif idlNode
.isExposedInAnyWorker():
9433 cgThings
.append(CGGeneric(code
))
9435 self
.cgRoot
= CGList(cgThings
)
9437 def getArgumentNames(self
):
9438 return ["arg" + str(i
) for i
in range(len(self
.arguments
))]
9440 def getArguments(self
):
9441 return list(zip(self
.arguments
, self
.getArgumentNames()))
9443 def processWebExtensionStubAttribute(self
, cgThings
):
9444 nativeMethodName
= "CallWebExtMethod"
9445 stubNameSuffix
= self
.idlNode
.getExtendedAttribute("WebExtensionStub")
9446 if isinstance(stubNameSuffix
, list):
9447 nativeMethodName
+= stubNameSuffix
[0]
9449 argsLength
= len(self
.getArguments())
9450 singleVariadicArg
= argsLength
== 1 and self
.getArguments()[0][0].variadic
9452 # If the method signature does only include a single variadic arguments,
9453 # then `arg0` is already a Sequence of JS values and we can pass that
9454 # to the WebExtensions Stub method as is.
9455 if singleVariadicArg
:
9458 'u"%s"_ns' % self
.idlNode
.identifier
.name
,
9459 "Constify(%s)" % "arg0",
9462 return [nativeMethodName
, argsPre
, args
]
9466 'u"%s"_ns' % self
.idlNode
.identifier
.name
,
9467 "Constify(%s)" % "args_sequence",
9471 # Determine the maximum number of elements of the js values sequence argument,
9472 # skipping the last optional callback argument if any:
9474 # if this WebExtensions API method does expect a last optional callback argument,
9475 # then it is the callback parameter supported for chrome-compatibility
9476 # reasons, and we want it as a separate argument passed to the WebExtension
9477 # stub method and skip it from the js values sequence including all other
9479 maxArgsSequenceLen
= argsLength
9481 lastArg
= self
.getArguments()[argsLength
- 1]
9482 isCallback
= lastArg
[0].type.tag() == IDLType
.Tags
.callback
9483 if isCallback
and lastArg
[0].optional
:
9485 "MOZ_KnownLive(NonNullHelper(Constify(%s)))" % lastArg
[1]
9487 maxArgsSequenceLen
= argsLength
- 1
9494 // Collecting all args js values into the single sequence argument
9495 // passed to the webextensions stub method.
9497 // NOTE: The stub method will receive the original non-normalized js values,
9498 // but those arguments will still be normalized on the main thread by the
9499 // WebExtensions API request handler using the same JSONSchema defnition
9500 // used by the non-webIDL webextensions API bindings.
9501 AutoSequence<JS::Value> args_sequence;
9502 SequenceRooter<JS::Value> args_sequence_holder(cx, &args_sequence);
9504 // maximum number of arguments expected by the WebExtensions API method
9505 // excluding the last optional chrome-compatible callback argument (which
9506 // is being passed to the stub method as a separate additional argument).
9507 uint32_t maxArgsSequenceLen = ${maxArgsSequenceLen};
9509 uint32_t sequenceArgsLen = args.length() <= maxArgsSequenceLen ?
9510 args.length() : maxArgsSequenceLen;
9512 if (sequenceArgsLen > 0) {
9513 if (!args_sequence.SetCapacity(sequenceArgsLen, mozilla::fallible)) {
9514 JS_ReportOutOfMemory(cx);
9517 for (uint32_t argIdx = 0; argIdx < sequenceArgsLen; ++argIdx) {
9518 // OK to do infallible append here, since we ensured capacity already.
9519 JS::Value& slot = *args_sequence.AppendElement();
9520 slot = args[argIdx];
9524 maxArgsSequenceLen
=maxArgsSequenceLen
,
9530 return [nativeMethodName
, argsPre
, args
]
9532 def needsErrorResult(self
):
9533 return "needsErrorResult" in self
.extendedAttributes
9535 def wrap_return_value(self
):
9538 returnsNewObject
= memberReturnsNewObject(self
.idlNode
)
9539 if returnsNewObject
and (
9540 self
.returnType
.isGeckoInterface() or self
.returnType
.isPromise()
9544 static_assert(!std::is_pointer_v<decltype(result)>,
9545 "NewObject implies that we need to keep the object alive with a strong reference.");
9550 # For attributes in slots, we want to do some
9551 # post-processing once we've wrapped them.
9552 successCode
= "break;\n"
9556 resultTemplateValues
= {
9557 "jsvalRef": "args.rval()",
9558 "jsvalHandle": "args.rval()",
9559 "returnsNewObject": returnsNewObject
,
9560 "isConstructorRetval": self
.isConstructor
,
9561 "successCode": successCode
,
9562 # 'obj' in this dictionary is the thing whose compartment we are
9563 # trying to do the to-JS conversion in. We're going to put that
9564 # thing in a variable named "conversionScope" if setSlot is true.
9565 # Otherwise, just use "obj" for lack of anything better.
9566 "obj": "conversionScope" if self
.setSlot
else "obj",
9569 wrapCode
+= wrapForType(self
.returnType
, self
.descriptor
, resultTemplateValues
)
9572 if self
.idlNode
.isStatic():
9574 "Attribute %s.%s is static, so we don't have a useful slot "
9575 "to cache it in, because we don't have support for that on "
9576 "interface objects. See "
9577 "https://bugzilla.mozilla.org/show_bug.cgi?id=1363870"
9579 self
.descriptor
.interface
.identifier
.name
,
9580 self
.idlNode
.identifier
.name
,
9584 # When using a slot on the Xray expando, we need to make sure that
9585 # our initial conversion to a JS::Value is done in the caller
9586 # compartment. When using a slot on our reflector, we want to do
9587 # the conversion in the compartment of that reflector (that is,
9588 # slotStorage). In both cases we want to make sure that we finally
9589 # set up args.rval() to be in the caller compartment. We also need
9590 # to make sure that the conversion steps happen inside a do/while
9591 # that they can break out of on success.
9593 # Of course we always have to wrap the value into the slotStorage
9594 # compartment before we store it in slotStorage.
9596 # postConversionSteps are the steps that run while we're still in
9597 # the compartment we do our conversion in but after we've finished
9598 # the initial conversion into args.rval().
9599 postConversionSteps
= ""
9600 if self
.idlNode
.getExtendedAttribute("Frozen"):
9602 self
.idlNode
.type.isSequence() or self
.idlNode
.type.isDictionary()
9604 freezeValue
= CGGeneric(
9605 "JS::Rooted<JSObject*> rvalObj(cx, &args.rval().toObject());\n"
9606 "if (!JS_FreezeObject(cx, rvalObj)) {\n"
9610 if self
.idlNode
.type.nullable():
9611 freezeValue
= CGIfWrapper(freezeValue
, "args.rval().isObject()")
9612 postConversionSteps
+= freezeValue
.define()
9614 # slotStorageSteps are steps that run once we have entered the
9615 # slotStorage compartment.
9616 slotStorageSteps
= fill(
9618 // Make a copy so that we don't do unnecessary wrapping on args.rval().
9619 JS::Rooted<JS::Value> storedVal(cx, args.rval());
9620 if (!${maybeWrap}(cx, &storedVal)) {
9623 JS::SetReservedSlot(slotStorage, slotIndex, storedVal);
9625 maybeWrap
=getMaybeWrapValueFuncForType(self
.idlNode
.type),
9628 checkForXray
= mayUseXrayExpandoSlots(self
.descriptor
, self
.idlNode
)
9630 # For the case of Cached attributes, go ahead and preserve our
9631 # wrapper if needed. We need to do this because otherwise the
9632 # wrapper could get garbage-collected and the cached value would
9633 # suddenly disappear, but the whole premise of cached values is that
9634 # they never change without explicit action on someone's part. We
9635 # don't do this for StoreInSlot, since those get dealt with during
9636 # wrapper setup, and failure would involve us trying to clear an
9637 # already-preserved wrapper.
9639 self
.idlNode
.getExtendedAttribute("Cached")
9640 and self
.descriptor
.wrapperCache
9642 preserveWrapper
= dedent(
9644 PreserveWrapper(self);
9648 preserveWrapper
= fill(
9651 // In the Xray case we don't need to do this, because getting the
9652 // expando object already preserved our wrapper.
9656 preserveWrapper
=preserveWrapper
,
9658 slotStorageSteps
+= preserveWrapper
9661 # In the Xray case we use the current global as conversion
9662 # scope, as explained in the big compartment/conversion comment
9664 conversionScope
= "isXray ? JS::CurrentGlobalOrNull(cx) : slotStorage"
9666 conversionScope
= "slotStorage"
9671 JS::Rooted<JSObject*> conversionScope(cx, ${conversionScope});
9672 JSAutoRealm ar(cx, conversionScope);
9673 do { // block we break out of when done wrapping
9676 $*{postConversionSteps}
9678 { // And now store things in the realm of our slotStorage.
9679 JSAutoRealm ar(cx, slotStorage);
9680 $*{slotStorageSteps}
9682 // And now make sure args.rval() is in the caller realm.
9683 return ${maybeWrap}(cx, args.rval());
9685 conversionScope
=conversionScope
,
9687 postConversionSteps
=postConversionSteps
,
9688 slotStorageSteps
=slotStorageSteps
,
9689 maybeWrap
=getMaybeWrapValueFuncForType(self
.idlNode
.type),
9694 return self
.cgRoot
.define() + self
.wrap_return_value()
9697 class CGSwitch(CGList
):
9699 A class to generate code for a switch statement.
9701 Takes three constructor arguments: an expression, a list of cases,
9702 and an optional default.
9704 Each case is a CGCase. The default is a CGThing for the body of
9705 the default case, if any.
9708 def __init__(self
, expression
, cases
, default
=None):
9709 CGList
.__init
__(self
, [CGIndenter(c
) for c
in cases
])
9710 self
.prepend(CGGeneric("switch (" + expression
+ ") {\n"))
9711 if default
is not None:
9714 CGWrapper(CGIndenter(default
), pre
="default: {\n", post
="}\n")
9718 self
.append(CGGeneric("}\n"))
9721 class CGCase(CGList
):
9723 A class to generate code for a case statement.
9725 Takes three constructor arguments: an expression, a CGThing for
9726 the body (allowed to be None if there is no body), and an optional
9727 argument for whether add a break, add fallthrough annotation or add nothing
9728 (defaulting to add a break).
9735 def __init__(self
, expression
, body
, breakOrFallthrough
=ADD_BREAK
):
9736 CGList
.__init
__(self
, [])
9739 breakOrFallthrough
== CGCase
.ADD_BREAK
9740 or breakOrFallthrough
== CGCase
.ADD_FALLTHROUGH
9741 or breakOrFallthrough
== CGCase
.DONT_ADD_BREAK
9744 self
.append(CGGeneric("case " + expression
+ ": {\n"))
9745 bodyList
= CGList([body
])
9746 if breakOrFallthrough
== CGCase
.ADD_FALLTHROUGH
:
9747 bodyList
.append(CGGeneric("[[fallthrough]];\n"))
9748 elif breakOrFallthrough
== CGCase
.ADD_BREAK
:
9749 bodyList
.append(CGGeneric("break;\n"))
9750 self
.append(CGIndenter(bodyList
))
9751 self
.append(CGGeneric("}\n"))
9754 class CGMethodCall(CGThing
):
9756 A class to generate selection of a method signature from a set of
9757 signatures and generation of a call to that signature.
9761 self
, nativeMethodName
, static
, descriptor
, method
, isConstructor
=False
9763 CGThing
.__init
__(self
)
9765 methodName
= GetLabelForErrorReporting(descriptor
, method
, isConstructor
)
9766 argDesc
= "argument %d"
9768 if method
.getExtendedAttribute("UseCounter"):
9769 useCounterName
= methodName
.replace(".", "_").replace(" ", "_")
9771 useCounterName
= None
9773 if method
.isStatic():
9774 nativeType
= descriptor
.nativeType
9775 staticTypeOverride
= PropertyDefiner
.getStringAttr(
9776 method
, "StaticClassOverride"
9778 if staticTypeOverride
:
9779 nativeType
= staticTypeOverride
9780 nativeMethodName
= "%s::%s" % (nativeType
, nativeMethodName
)
9782 def requiredArgCount(signature
):
9783 arguments
= signature
[1]
9784 if len(arguments
) == 0:
9786 requiredArgs
= len(arguments
)
9787 while requiredArgs
and arguments
[requiredArgs
- 1].optional
:
9791 def getPerSignatureCall(signature
, argConversionStartsAt
=0):
9792 return CGPerSignatureCall(
9799 argConversionStartsAt
=argConversionStartsAt
,
9800 isConstructor
=isConstructor
,
9801 useCounterName
=useCounterName
,
9804 signatures
= method
.signatures()
9805 if len(signatures
) == 1:
9806 # Special case: we can just do a per-signature method call
9807 # here for our one signature and not worry about switching
9809 signature
= signatures
[0]
9810 self
.cgRoot
= CGList([getPerSignatureCall(signature
)])
9811 requiredArgs
= requiredArgCount(signature
)
9813 # Skip required arguments check for maplike/setlike interfaces, as
9814 # they can have arguments which are not passed, and are treated as
9815 # if undefined had been explicitly passed.
9816 if requiredArgs
> 0 and not method
.isMaplikeOrSetlikeOrIterableMethod():
9819 if (!args.requireAtLeast(cx, "${methodName}", ${requiredArgs})) {
9823 requiredArgs
=requiredArgs
,
9824 methodName
=methodName
,
9826 self
.cgRoot
.prepend(CGGeneric(code
))
9829 # Need to find the right overload
9830 maxArgCount
= method
.maxArgCount
9831 allowedArgCounts
= method
.allowedArgCounts
9834 for argCountIdx
, argCount
in enumerate(allowedArgCounts
):
9835 possibleSignatures
= method
.signaturesForArgCount(argCount
)
9837 # Try to optimize away cases when the next argCount in the list
9838 # will have the same code as us; if it does, we can fall through to
9840 if argCountIdx
+ 1 < len(allowedArgCounts
):
9841 nextPossibleSignatures
= method
.signaturesForArgCount(
9842 allowedArgCounts
[argCountIdx
+ 1]
9845 nextPossibleSignatures
= None
9846 if possibleSignatures
== nextPossibleSignatures
:
9847 # Same set of signatures means we better have the same
9848 # distinguishing index. So we can in fact just fall through to
9849 # the next case here.
9850 assert len(possibleSignatures
) == 1 or (
9851 method
.distinguishingIndexForArgCount(argCount
)
9852 == method
.distinguishingIndexForArgCount(
9853 allowedArgCounts
[argCountIdx
+ 1]
9856 argCountCases
.append(
9857 CGCase(str(argCount
), None, CGCase
.ADD_FALLTHROUGH
)
9861 if len(possibleSignatures
) == 1:
9863 signature
= possibleSignatures
[0]
9864 argCountCases
.append(
9865 CGCase(str(argCount
), getPerSignatureCall(signature
))
9869 distinguishingIndex
= method
.distinguishingIndexForArgCount(argCount
)
9871 def distinguishingArgument(signature
):
9873 if distinguishingIndex
< len(args
):
9874 return args
[distinguishingIndex
]
9875 assert args
[-1].variadic
9878 def distinguishingType(signature
):
9879 return distinguishingArgument(signature
).type
9881 for sig
in possibleSignatures
:
9882 # We should not have "any" args at distinguishingIndex,
9883 # since we have multiple possible signatures remaining,
9884 # but "any" is never distinguishable from anything else.
9885 assert not distinguishingType(sig
).isAny()
9886 # We can't handle unions at the distinguishing index.
9887 if distinguishingType(sig
).isUnion():
9889 "No support for unions as distinguishing "
9890 "arguments yet: %s" % distinguishingArgument(sig
).location
9892 # We don't support variadics as the distinguishingArgument yet.
9893 # If you want to add support, consider this case:
9895 # undefined(long... foo);
9896 # undefined(long bar, Int32Array baz);
9898 # in which we have to convert argument 0 to long before picking
9899 # an overload... but all the variadic stuff needs to go into a
9900 # single array in case we pick that overload, so we have to have
9901 # machinery for converting argument 0 to long and then either
9902 # placing it in the variadic bit or not. Or something. We may
9903 # be able to loosen this restriction if the variadic arg is in
9904 # fact at distinguishingIndex, perhaps. Would need to
9906 if distinguishingArgument(sig
).variadic
:
9908 "No support for variadics as distinguishing "
9909 "arguments yet: %s" % distinguishingArgument(sig
).location
9912 # Convert all our arguments up to the distinguishing index.
9913 # Doesn't matter which of the possible signatures we use, since
9914 # they all have the same types up to that point; just use
9915 # possibleSignatures[0]
9917 CGArgumentConverter(
9918 possibleSignatures
[0][1][i
],
9924 for i
in range(0, distinguishingIndex
)
9927 # Select the right overload from our set.
9928 distinguishingArg
= "args[%d]" % distinguishingIndex
9931 signature
, indent
, isDefinitelyObject
=False, isNullOrUndefined
=False
9933 assert not isDefinitelyObject
or not isNullOrUndefined
9934 assert isDefinitelyObject
or isNullOrUndefined
9935 if isDefinitelyObject
:
9936 failureCode
= "break;\n"
9939 type = distinguishingType(signature
)
9940 # The argument at index distinguishingIndex can't possibly be
9941 # unset here, because we've already checked that argc is large
9942 # enough that we can examine this argument. But note that we
9943 # still want to claim that optional arguments are optional, in
9944 # case undefined was passed in.
9945 argIsOptional
= distinguishingArgument(signature
).canHaveMissingValue()
9946 testCode
= instantiateJSToNativeConversion(
9947 getJSToNativeConversionInfo(
9950 failureCode
=failureCode
,
9951 isDefinitelyObject
=isDefinitelyObject
,
9952 isNullOrUndefined
=isNullOrUndefined
,
9953 isOptional
=argIsOptional
,
9954 sourceDescription
=(argDesc
% (distinguishingIndex
+ 1)),
9957 "declName": "arg%d" % distinguishingIndex
,
9958 "holderName": ("arg%d" % distinguishingIndex
) + "_holder",
9959 "val": distinguishingArg
,
9961 "haveValue": "args.hasDefined(%d)" % distinguishingIndex
,
9962 "passedToJSImpl": toStringBool(
9963 isJSImplementedDescriptor(descriptor
)
9966 checkForValue
=argIsOptional
,
9968 caseBody
.append(CGIndenter(testCode
, indent
))
9970 # If we got this far, we know we unwrapped to the right
9971 # C++ type, so just do the call. Start conversion with
9972 # distinguishingIndex + 1, since we already converted
9973 # distinguishingIndex.
9976 getPerSignatureCall(signature
, distinguishingIndex
+ 1), indent
9980 def hasConditionalConversion(type):
9982 Return whether the argument conversion for this type will be
9983 conditional on the type of incoming JS value. For example, for
9984 interface types the conversion is conditional on the incoming
9985 value being isObject().
9987 For the types for which this returns false, we do not have to
9988 output extra isUndefined() or isNullOrUndefined() cases, because
9989 null/undefined values will just fall through into our
9990 unconditional conversion.
9992 if type.isString() or type.isEnum():
9994 if type.isBoolean():
9995 distinguishingTypes
= (
9996 distinguishingType(s
) for s
in possibleSignatures
9999 t
.isString() or t
.isEnum() or t
.isNumeric()
10000 for t
in distinguishingTypes
10002 if type.isNumeric():
10003 distinguishingTypes
= (
10004 distinguishingType(s
) for s
in possibleSignatures
10006 return any(t
.isString() or t
.isEnum() for t
in distinguishingTypes
)
10009 def needsNullOrUndefinedCase(type):
10011 Return true if the type needs a special isNullOrUndefined() case
10014 type.nullable() and hasConditionalConversion(type)
10015 ) or type.isDictionary()
10017 # First check for undefined and optional distinguishing arguments
10018 # and output a special branch for that case. Note that we don't
10019 # use distinguishingArgument here because we actualy want to
10020 # exclude variadic arguments. Also note that we skip this check if
10021 # we plan to output a isNullOrUndefined() special case for this
10022 # argument anyway, since that will subsume our isUndefined() check.
10023 # This is safe, because there can be at most one nullable
10024 # distinguishing argument, so if we're it we'll definitely get
10025 # picked up by the nullable handling. Also, we can skip this check
10026 # if the argument has an unconditional conversion later on.
10029 for s
in possibleSignatures
10030 if distinguishingIndex
< len(s
[1])
10031 and s
[1][distinguishingIndex
].optional
10032 and hasConditionalConversion(s
[1][distinguishingIndex
].type)
10033 and not needsNullOrUndefinedCase(s
[1][distinguishingIndex
].type)
10035 # Can't have multiple signatures with an optional argument at the
10037 assert len(undefSigs
) < 2
10038 if len(undefSigs
) > 0:
10040 CGGeneric("if (%s.isUndefined()) {\n" % distinguishingArg
)
10042 tryCall(undefSigs
[0], 2, isNullOrUndefined
=True)
10043 caseBody
.append(CGGeneric("}\n"))
10045 # Next, check for null or undefined. That means looking for
10046 # nullable arguments at the distinguishing index and outputting a
10047 # separate branch for them. But if the nullable argument has an
10048 # unconditional conversion, we don't need to do that. The reason
10049 # for that is that at most one argument at the distinguishing index
10050 # is nullable (since two nullable arguments are not
10051 # distinguishable), and null/undefined values will always fall
10052 # through to the unconditional conversion we have, if any, since
10053 # they will fail whatever the conditions on the input value are for
10054 # our other conversions.
10055 nullOrUndefSigs
= [
10057 for s
in possibleSignatures
10058 if needsNullOrUndefinedCase(distinguishingType(s
))
10060 # Can't have multiple nullable types here
10061 assert len(nullOrUndefSigs
) < 2
10062 if len(nullOrUndefSigs
) > 0:
10064 CGGeneric("if (%s.isNullOrUndefined()) {\n" % distinguishingArg
)
10066 tryCall(nullOrUndefSigs
[0], 2, isNullOrUndefined
=True)
10067 caseBody
.append(CGGeneric("}\n"))
10069 # Now check for distinguishingArg being various kinds of objects.
10070 # The spec says to check for the following things in order:
10071 # 1) A platform object that's not a platform array object, being
10072 # passed to an interface or "object" arg.
10073 # 2) A callable object being passed to a callback or "object" arg.
10074 # 3) An iterable object being passed to a sequence arg.
10075 # 4) Any object being passed to a array or callback interface or
10076 # dictionary or "object" arg.
10078 # First grab all the overloads that have a non-callback interface
10079 # (which includes SpiderMonkey interfaces) at the distinguishing
10080 # index. We can also include the ones that have an "object" here,
10081 # since if those are present no other object-typed argument will
10085 for s
in possibleSignatures
10087 distinguishingType(s
).isObject()
10088 or distinguishingType(s
).isNonCallbackInterface()
10092 # And all the overloads that take callbacks
10094 s
for s
in possibleSignatures
if distinguishingType(s
).isCallback()
10097 # And all the overloads that take sequences
10099 s
for s
in possibleSignatures
if distinguishingType(s
).isSequence()
10102 # Now append all the overloads that take a dictionary or callback
10103 # interface or record. There should be only one of these!
10104 genericObjectSigs
= [
10106 for s
in possibleSignatures
10108 distinguishingType(s
).isDictionary()
10109 or distinguishingType(s
).isRecord()
10110 or distinguishingType(s
).isCallbackInterface()
10113 assert len(genericObjectSigs
) <= 1
10114 objectSigs
.extend(genericObjectSigs
)
10116 # There might be more than one thing in objectSigs; we need to check
10117 # which ones we unwrap to.
10118 if len(objectSigs
) > 0:
10119 # Here it's enough to guard on our argument being an object.
10120 # The code for unwrapping non-callback interfaces, spiderMonkey
10121 # interfaces, and sequences will just bail out and move
10122 # on to the next overload if the object fails to unwrap
10123 # correctly, while "object" accepts any object anyway. We
10124 # could even not do the isObject() check up front here, but in
10125 # cases where we have multiple object overloads it makes sense
10126 # to do it only once instead of for each overload. That will
10127 # also allow the unwrapping test to skip having to do codegen
10128 # for the null-or-undefined case, which we already handled
10130 caseBody
.append(CGGeneric("if (%s.isObject()) {\n" % distinguishingArg
))
10131 for sig
in objectSigs
:
10132 caseBody
.append(CGIndenter(CGGeneric("do {\n")))
10133 # Indent by 4, since we need to indent further
10134 # than our "do" statement
10135 tryCall(sig
, 4, isDefinitelyObject
=True)
10136 caseBody
.append(CGIndenter(CGGeneric("} while (false);\n")))
10138 caseBody
.append(CGGeneric("}\n"))
10140 # Now we only have to consider booleans, numerics, and strings. If
10141 # we only have one of them, then we can just output it. But if not,
10142 # then we need to output some of the cases conditionally: if we have
10143 # a string overload, then boolean and numeric are conditional, and
10144 # if not then boolean is conditional if we have a numeric overload.
10145 def findUniqueSignature(filterLambda
):
10146 sigs
= [s
for s
in possibleSignatures
if filterLambda(s
)]
10147 assert len(sigs
) < 2
10152 stringSignature
= findUniqueSignature(
10154 distinguishingType(s
).isString() or distinguishingType(s
).isEnum()
10157 numericSignature
= findUniqueSignature(
10158 lambda s
: distinguishingType(s
).isNumeric()
10160 booleanSignature
= findUniqueSignature(
10161 lambda s
: distinguishingType(s
).isBoolean()
10164 if stringSignature
or numericSignature
:
10165 booleanCondition
= "%s.isBoolean()"
10167 booleanCondition
= None
10169 if stringSignature
:
10170 numericCondition
= "%s.isNumber()"
10172 numericCondition
= None
10174 def addCase(sig
, condition
):
10175 sigCode
= getPerSignatureCall(sig
, distinguishingIndex
)
10177 sigCode
= CGIfWrapper(sigCode
, condition
% distinguishingArg
)
10178 caseBody
.append(sigCode
)
10180 if booleanSignature
:
10181 addCase(booleanSignature
, booleanCondition
)
10182 if numericSignature
:
10183 addCase(numericSignature
, numericCondition
)
10184 if stringSignature
:
10185 addCase(stringSignature
, None)
10187 if not booleanSignature
and not numericSignature
and not stringSignature
:
10188 # Just throw; we have no idea what we're supposed to
10192 'return cx.ThrowErrorMessage<MSG_OVERLOAD_RESOLUTION_FAILED>("%d", "%d");\n'
10193 % (distinguishingIndex
+ 1, argCount
)
10197 argCountCases
.append(CGCase(str(argCount
), CGList(caseBody
)))
10199 overloadCGThings
= []
10200 overloadCGThings
.append(
10202 "unsigned argcount = std::min(args.length(), %du);\n" % maxArgCount
10205 overloadCGThings
.append(
10212 // Using nsPrintfCString here would require including that
10213 // header. Let's not worry about it.
10214 nsAutoCString argCountStr;
10215 argCountStr.AppendPrintf("%u", args.length());
10216 return cx.ThrowErrorMessage<MSG_INVALID_OVERLOAD_ARGCOUNT>(argCountStr.get());
10222 overloadCGThings
.append(
10224 'MOZ_CRASH("We have an always-returning default case");\n'
10228 self
.cgRoot
= CGList(overloadCGThings
)
10231 return self
.cgRoot
.define()
10234 class CGGetterCall(CGPerSignatureCall
):
10236 A class to generate a native object getter call for a particular IDL
10246 errorReportingLabel
=None,
10249 extendedAttributes
=None,
10251 if attr
.getExtendedAttribute("UseCounter"):
10252 useCounterName
= "%s_%s_getter" % (
10253 descriptor
.interface
.identifier
.name
,
10254 attr
.identifier
.name
,
10257 useCounterName
= None
10258 if attr
.isStatic():
10259 nativeMethodName
= "%s::%s" % (descriptor
.nativeType
, nativeMethodName
)
10260 CGPerSignatureCall
.__init
__(
10269 useCounterName
=useCounterName
,
10270 dontSetSlot
=dontSetSlot
,
10271 extendedAttributes
=extendedAttributes
,
10272 errorReportingLabel
=errorReportingLabel
,
10273 additionalArgsPre
=argsPre
,
10277 class FakeIdentifier
:
10278 def __init__(self
, name
):
10282 class FakeArgument
:
10284 A class that quacks like an IDLArgument. This is used to make
10285 setters look like method calls or for special operations.
10288 def __init__(self
, type, name
="arg", allowTreatNonCallableAsNull
=False):
10290 self
.optional
= False
10291 self
.variadic
= False
10292 self
.defaultValue
= None
10293 self
._allowTreatNonCallableAsNull
= allowTreatNonCallableAsNull
10295 self
.identifier
= FakeIdentifier(name
)
10297 def allowTreatNonCallableAsNull(self
):
10298 return self
._allowTreatNonCallableAsNull
10300 def canHaveMissingValue(self
):
10304 class CGSetterCall(CGPerSignatureCall
):
10306 A class to generate a native object setter call for a particular IDL
10316 errorReportingLabel
=None,
10319 if attr
.getExtendedAttribute("UseCounter"):
10320 useCounterName
= "%s_%s_setter" % (
10321 descriptor
.interface
.identifier
.name
,
10322 attr
.identifier
.name
,
10325 useCounterName
= None
10326 if attr
.isStatic():
10327 nativeMethodName
= "%s::%s" % (descriptor
.nativeType
, nativeMethodName
)
10328 CGPerSignatureCall
.__init
__(
10331 [FakeArgument(argType
, allowTreatNonCallableAsNull
=True)],
10337 useCounterName
=useCounterName
,
10338 errorReportingLabel
=errorReportingLabel
,
10339 additionalArgsPre
=argsPre
,
10342 def wrap_return_value(self
):
10343 attr
= self
.idlNode
10345 if self
.descriptor
.wrapperCache
and attr
.slotIndices
is not None:
10346 if attr
.getExtendedAttribute("StoreInSlot"):
10347 clearSlot
= "%s(cx, self);\n" % MakeClearCachedValueNativeName(
10350 elif attr
.getExtendedAttribute("Cached"):
10351 clearSlot
= "%s(self);\n" % MakeClearCachedValueNativeName(self
.idlNode
)
10353 # We have no return value
10354 return "\n" "%s" "return true;\n" % clearSlot
10357 class CGAbstractBindingMethod(CGAbstractStaticMethod
):
10359 Common class to generate some of our class hooks. This will generate the
10360 function declaration, get a reference to the JS object for our binding
10361 object (which might be an argument of the class hook or something we get
10362 from a JS::CallArgs), and unwrap into the right C++ type. Subclasses are
10363 expected to override the generate_code function to do the rest of the work.
10364 This function should return a CGThing which is already properly indented.
10366 getThisObj should be code for getting a JSObject* for the binding
10367 object. "" can be passed in if the binding object is already stored in
10370 callArgs should be code for getting a JS::CallArgs into a variable
10371 called 'args'. This can be "" if there is already such a variable
10372 around or if the body does not need a JS::CallArgs.
10382 callArgs
="JS::CallArgs args = JS::CallArgsFromVp(argc, vp);\n",
10384 CGAbstractStaticMethod
.__init
__(
10385 self
, descriptor
, name
, "bool", args
, canRunScript
=True
10388 # This can't ever happen, because we only use this for class hooks.
10389 self
.unwrapFailureCode
= fill(
10391 MOZ_CRASH("Unexpected object in '${name}' hook");
10397 if getThisObj
== "":
10398 self
.getThisObj
= None
10400 self
.getThisObj
= CGGeneric(
10401 "JS::Rooted<JSObject*> obj(cx, %s);\n" % getThisObj
10403 self
.callArgs
= callArgs
10405 def definition_body(self
):
10406 body
= self
.callArgs
10407 if self
.getThisObj
is not None:
10408 body
+= self
.getThisObj
.define() + "\n"
10409 body
+= "%s* self;\n" % self
.descriptor
.nativeType
10412 JS::Rooted<JS::Value> rootSelf(cx, JS::ObjectValue(*obj));
10417 CastableObjectUnwrapper(
10418 self
.descriptor
, "rootSelf", "&rootSelf", "self", self
.unwrapFailureCode
10422 return body
+ self
.generate_code().define()
10424 def generate_code(self
):
10425 assert False # Override me
10428 class CGAbstractStaticBindingMethod(CGAbstractStaticMethod
):
10430 Common class to generate the JSNatives for all our static methods, getters
10431 and setters. This will generate the function declaration and unwrap the
10432 global object. Subclasses are expected to override the generate_code
10433 function to do the rest of the work. This function should return a
10434 CGThing which is already properly indented.
10437 def __init__(self
, descriptor
, name
):
10438 CGAbstractStaticMethod
.__init
__(
10439 self
, descriptor
, name
, "bool", JSNativeArguments(), canRunScript
=True
10442 def definition_body(self
):
10443 # Make sure that "obj" is in the same compartment as "cx", since we'll
10444 # later use it to wrap return values.
10447 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
10448 JS::Rooted<JSObject*> obj(cx, &args.callee());
10452 return unwrap
+ self
.generate_code().define()
10454 def generate_code(self
):
10455 assert False # Override me
10458 def MakeNativeName(name
):
10459 return name
[0].upper() + IDLToCIdentifier(name
[1:])
10462 def GetWebExposedName(idlObject
, descriptor
):
10463 if idlObject
== descriptor
.operations
["Stringifier"]:
10465 name
= idlObject
.identifier
.name
10466 if name
== "__namedsetter":
10467 return "named setter"
10468 if name
== "__namedgetter":
10469 return "named getter"
10470 if name
== "__indexedsetter":
10471 return "indexed setter"
10472 if name
== "__indexedgetter":
10473 return "indexed getter"
10474 if name
== "__legacycaller":
10475 return "legacy caller"
10479 def GetConstructorNameForReporting(descriptor
, ctor
):
10480 # Figure out the name of our constructor for reporting purposes.
10481 # For unnamed webidl constructors, identifier.name is "constructor" but
10482 # the name JS sees is the interface name; for legacy factory functions
10483 # identifier.name is the actual name.
10484 ctorName
= ctor
.identifier
.name
10485 if ctorName
== "constructor":
10486 return descriptor
.interface
.identifier
.name
10490 def GetLabelForErrorReporting(descriptor
, idlObject
, isConstructor
):
10492 descriptor is the descriptor for the interface involved
10494 idlObject is the method (regular or static), attribute (regular or
10495 static), or constructor (named or not) involved.
10497 isConstructor is true if idlObject is a constructor and false otherwise.
10500 return "%s constructor" % GetConstructorNameForReporting(descriptor
, idlObject
)
10502 namePrefix
= descriptor
.interface
.identifier
.name
10503 name
= GetWebExposedName(idlObject
, descriptor
)
10505 # It's got a space already, so just space-separate.
10506 return "%s %s" % (namePrefix
, name
)
10508 return "%s.%s" % (namePrefix
, name
)
10511 class CGSpecializedMethod(CGAbstractStaticMethod
):
10513 A class for generating the C++ code for a specialized method that the JIT
10514 can call with lower overhead.
10517 def __init__(self
, descriptor
, method
):
10518 self
.method
= method
10519 name
= CppKeywords
.checkMethodName(IDLToCIdentifier(method
.identifier
.name
))
10521 Argument("JSContext*", "cx"),
10522 Argument("JS::Handle<JSObject*>", "obj"),
10523 Argument("void*", "void_self"),
10524 Argument("const JSJitMethodCallArgs&", "args"),
10526 CGAbstractStaticMethod
.__init
__(
10527 self
, descriptor
, name
, "bool", args
, canRunScript
=True
10530 def definition_body(self
):
10531 nativeName
= CGSpecializedMethod
.makeNativeName(self
.descriptor
, self
.method
)
10532 call
= CGMethodCall(
10533 nativeName
, self
.method
.isStatic(), self
.descriptor
, self
.method
10536 if self
.method
.getExtendedAttribute("CrossOriginCallable"):
10537 for signature
in self
.method
.signatures():
10538 # non-undefined signatures would require us to deal with remote proxies for the
10539 # return value here.
10540 if not signature
[0].isUndefined():
10542 "We don't support a method marked as CrossOriginCallable "
10543 "with non-undefined return type"
10545 prototypeID
, _
= PrototypeIDAndDepth(self
.descriptor
)
10548 // CrossOriginThisPolicy::UnwrapThisObject stores a ${nativeType}::RemoteProxy in void_self
10549 // if obj is a proxy with a RemoteObjectProxy handler for the right type, or else it stores
10550 // a ${nativeType}. If we get here from the JIT (without going through UnwrapThisObject) we
10551 // know void_self contains a ${nativeType}; we don't have special cases in the JIT to deal
10552 // with remote object proxies.
10553 if (IsRemoteObjectProxy(obj, ${prototypeID})) {
10554 auto* self = static_cast<${nativeType}::RemoteProxy*>(void_self);
10558 prototypeID
=prototypeID
,
10559 nativeType
=self
.descriptor
.nativeType
,
10562 return prefix
+ fill(
10564 auto* self = static_cast<${nativeType}*>(void_self);
10567 nativeType
=self
.descriptor
.nativeType
,
10571 def auto_profiler_label(self
):
10572 interface_name
= self
.descriptor
.interface
.identifier
.name
10573 method_name
= self
.method
.identifier
.name
10576 AUTO_PROFILER_LABEL_DYNAMIC_FAST(
10577 "${interface_name}", "${method_name}", DOM, cx,
10578 uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) |
10579 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
10581 interface_name
=interface_name
,
10582 method_name
=method_name
,
10586 def should_have_method_description(descriptor
, idlMethod
):
10588 Returns whether the given IDL method (static, non-static, constructor)
10589 should have a method description declaration, for use in error
10592 # If a method has overloads, it needs a method description, because it
10593 # can throw MSG_INVALID_OVERLOAD_ARGCOUNT at the very least.
10594 if len(idlMethod
.signatures()) != 1:
10597 # Methods with only one signature need a method description if one of
10598 # their args needs it.
10599 sig
= idlMethod
.signatures()[0]
10602 idlTypeNeedsCallContext(
10605 allowTreatNonCallableAsNull
=arg
.allowTreatNonCallableAsNull(),
10611 def error_reporting_label_helper(descriptor
, idlMethod
, isConstructor
):
10613 Returns the method description to use for error reporting for the given
10614 IDL method. Used to implement common error_reporting_label() functions
10615 across different classes.
10617 if not CGSpecializedMethod
.should_have_method_description(
10618 descriptor
, idlMethod
10621 return '"%s"' % GetLabelForErrorReporting(descriptor
, idlMethod
, isConstructor
)
10623 def error_reporting_label(self
):
10624 return CGSpecializedMethod
.error_reporting_label_helper(
10625 self
.descriptor
, self
.method
, isConstructor
=False
10629 def makeNativeName(descriptor
, method
):
10630 if method
.underlyingAttr
:
10631 return CGSpecializedGetterCommon
.makeNativeName(
10632 descriptor
, method
.underlyingAttr
10634 name
= method
.identifier
.name
10635 return MakeNativeName(descriptor
.binaryNameFor(name
, method
.isStatic()))
10638 class CGMethodPromiseWrapper(CGAbstractStaticMethod
):
10640 A class for generating a wrapper around another method that will
10641 convert exceptions to promises.
10644 def __init__(self
, descriptor
, methodToWrap
):
10645 self
.method
= methodToWrap
10646 name
= self
.makeName(methodToWrap
.name
)
10647 args
= list(methodToWrap
.args
)
10648 CGAbstractStaticMethod
.__init
__(
10649 self
, descriptor
, name
, "bool", args
, canRunScript
=True
10652 def definition_body(self
):
10655 bool ok = ${methodName}(${args});
10659 return ConvertExceptionToPromise(cx, args.rval());
10661 methodName
=self
.method
.name
,
10662 args
=", ".join(arg
.name
for arg
in self
.args
),
10666 def makeName(methodName
):
10667 return methodName
+ "_promiseWrapper"
10670 class CGDefaultToJSONMethod(CGSpecializedMethod
):
10671 def __init__(self
, descriptor
, method
):
10672 assert method
.isDefaultToJSON()
10673 CGSpecializedMethod
.__init
__(self
, descriptor
, method
)
10675 def definition_body(self
):
10678 auto* self = static_cast<${nativeType}*>(void_self);
10679 JS::Rooted<JSObject*> result(cx, JS_NewPlainObject(cx));
10684 nativeType
=self
.descriptor
.nativeType
,
10687 jsonDescriptors
= [self
.descriptor
]
10688 interface
= self
.descriptor
.interface
.parent
10690 descriptor
= self
.descriptor
.getDescriptor(interface
.identifier
.name
)
10691 if descriptor
.hasDefaultToJSON
:
10692 jsonDescriptors
.append(descriptor
)
10693 interface
= interface
.parent
10695 # Iterate the array in reverse: oldest ancestor first
10696 for descriptor
in jsonDescriptors
[::-1]:
10699 if (!${parentclass}::CollectJSONAttributes(cx, obj, MOZ_KnownLive(self), result)) {
10703 parentclass
=toBindingNamespace(descriptor
.name
),
10705 ret
+= "args.rval().setObject(*result);\n" "return true;\n"
10709 class CGLegacyCallHook(CGAbstractBindingMethod
):
10711 Call hook for our object
10714 def __init__(self
, descriptor
):
10715 self
._legacycaller
= descriptor
.operations
["LegacyCaller"]
10716 # Our "self" is actually the callee in this case, not the thisval.
10717 CGAbstractBindingMethod
.__init
__(
10720 LEGACYCALLER_HOOK_NAME
,
10721 JSNativeArguments(),
10722 getThisObj
="&args.callee()",
10726 if not self
._legacycaller
:
10728 return CGAbstractBindingMethod
.define(self
)
10730 def generate_code(self
):
10731 name
= self
._legacycaller
.identifier
.name
10732 nativeName
= MakeNativeName(self
.descriptor
.binaryNameFor(name
, False))
10733 return CGMethodCall(nativeName
, False, self
.descriptor
, self
._legacycaller
)
10735 def error_reporting_label(self
):
10736 # Should act like methods.
10737 return CGSpecializedMethod
.error_reporting_label_helper(
10738 self
.descriptor
, self
._legacycaller
, isConstructor
=False
10742 class CGResolveHook(CGAbstractClassHook
):
10744 Resolve hook for objects that have the NeedResolve extended attribute.
10747 def __init__(self
, descriptor
):
10748 assert descriptor
.interface
.getExtendedAttribute("NeedResolve")
10751 Argument("JSContext*", "cx"),
10752 Argument("JS::Handle<JSObject*>", "obj"),
10753 Argument("JS::Handle<jsid>", "id"),
10754 Argument("bool*", "resolvedp"),
10756 CGAbstractClassHook
.__init
__(self
, descriptor
, RESOLVE_HOOK_NAME
, "bool", args
)
10758 def generate_code(self
):
10761 JS::Rooted<mozilla::Maybe<JS::PropertyDescriptor>> desc(cx);
10762 if (!self->DoResolve(cx, obj, id, &desc)) {
10765 if (desc.isNothing()) {
10768 // If desc.value() is undefined, then the DoResolve call
10769 // has already defined it on the object. Don't try to also
10771 MOZ_ASSERT(desc->isDataDescriptor());
10772 if (!desc->value().isUndefined()) {
10773 JS::Rooted<JS::PropertyDescriptor> defineDesc(cx, *desc);
10774 defineDesc.setResolving(true);
10775 if (!JS_DefinePropertyById(cx, obj, id, defineDesc)) {
10784 def definition_body(self
):
10785 if self
.descriptor
.isGlobal():
10786 # Resolve standard classes
10789 if (!ResolveGlobal(cx, obj, id, resolvedp)) {
10800 return prefix
+ CGAbstractClassHook
.definition_body(self
)
10803 class CGMayResolveHook(CGAbstractStaticMethod
):
10805 Resolve hook for objects that have the NeedResolve extended attribute.
10808 def __init__(self
, descriptor
):
10809 assert descriptor
.interface
.getExtendedAttribute("NeedResolve")
10812 Argument("const JSAtomState&", "names"),
10813 Argument("jsid", "id"),
10814 Argument("JSObject*", "maybeObj"),
10816 CGAbstractStaticMethod
.__init
__(
10817 self
, descriptor
, MAY_RESOLVE_HOOK_NAME
, "bool", args
10820 def definition_body(self
):
10821 if self
.descriptor
.isGlobal():
10822 # Check whether this would resolve as a standard class.
10825 if (MayResolveGlobal(names, id, maybeObj)) {
10833 return prefix
+ "return %s::MayResolve(id);\n" % self
.descriptor
.nativeType
10836 class CGEnumerateHook(CGAbstractBindingMethod
):
10838 Enumerate hook for objects with custom hooks.
10841 def __init__(self
, descriptor
):
10842 assert descriptor
.interface
.getExtendedAttribute("NeedResolve")
10845 Argument("JSContext*", "cx"),
10846 Argument("JS::Handle<JSObject*>", "obj"),
10847 Argument("JS::MutableHandleVector<jsid>", "properties"),
10848 Argument("bool", "enumerableOnly"),
10850 # Our "self" is actually the "obj" argument in this case, not the thisval.
10851 CGAbstractBindingMethod
.__init
__(
10852 self
, descriptor
, NEW_ENUMERATE_HOOK_NAME
, args
, getThisObj
="", callArgs
=""
10855 def generate_code(self
):
10859 FastErrorResult rv;
10860 self->GetOwnPropertyNames(cx, properties, enumerableOnly, rv);
10861 if (rv.MaybeSetPendingException(cx)) {
10869 def definition_body(self
):
10870 if self
.descriptor
.isGlobal():
10871 # Enumerate standard classes
10874 if (!EnumerateGlobal(cx, obj, properties, enumerableOnly)) {
10882 return prefix
+ CGAbstractBindingMethod
.definition_body(self
)
10887 A class for checking if method names declared in webidl
10888 are not in conflict with C++ keywords.
10891 keywords
= frozenset(
10951 "reinterpret_cast",
10984 def checkMethodName(name
):
10985 # Double '_' because 'assert' and '_assert' cannot be used in MS2013 compiler.
10986 # Bug 964892 and bug 963560.
10987 if name
in CppKeywords
.keywords
:
10988 name
= "_" + name
+ "_"
10992 class CGStaticMethod(CGAbstractStaticBindingMethod
):
10994 A class for generating the C++ code for an IDL static method.
10997 def __init__(self
, descriptor
, method
):
10998 self
.method
= method
10999 name
= CppKeywords
.checkMethodName(IDLToCIdentifier(method
.identifier
.name
))
11000 CGAbstractStaticBindingMethod
.__init
__(self
, descriptor
, name
)
11002 def generate_code(self
):
11003 nativeName
= CGSpecializedMethod
.makeNativeName(self
.descriptor
, self
.method
)
11004 return CGMethodCall(nativeName
, True, self
.descriptor
, self
.method
)
11006 def auto_profiler_label(self
):
11007 interface_name
= self
.descriptor
.interface
.identifier
.name
11008 method_name
= self
.method
.identifier
.name
11011 AUTO_PROFILER_LABEL_DYNAMIC_FAST(
11012 "${interface_name}", "${method_name}", DOM, cx,
11013 uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) |
11014 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
11016 interface_name
=interface_name
,
11017 method_name
=method_name
,
11020 def error_reporting_label(self
):
11021 return CGSpecializedMethod
.error_reporting_label_helper(
11022 self
.descriptor
, self
.method
, isConstructor
=False
11026 class CGSpecializedGetterCommon(CGAbstractStaticMethod
):
11028 A class for generating the code for a specialized attribute getter
11029 that the JIT can call with lower overhead.
11039 errorReportingLabel
=None,
11040 additionalArg
=None,
11042 self
.nativeName
= nativeName
11043 self
.errorReportingLabel
= errorReportingLabel
11044 self
.additionalArgs
= [] if additionalArg
is None else [additionalArg
]
11045 # StoreInSlot attributes have their getters called from Wrap(). We
11046 # really hope they can't run script, and don't want to annotate Wrap()
11047 # methods as doing that anyway, so let's not annotate them as
11048 # MOZ_CAN_RUN_SCRIPT.
11049 CGAbstractStaticMethod
.__init
__(
11054 args
+ self
.additionalArgs
,
11055 canRunScript
=not attr
.getExtendedAttribute("StoreInSlot"),
11058 def definition_body(self
):
11061 auto* self = static_cast<${nativeType}*>(void_self);
11063 nativeType
=self
.descriptor
.nativeType
,
11066 if self
.attr
.isMaplikeOrSetlikeAttr():
11067 assert not self
.attr
.getExtendedAttribute("CrossOriginReadable")
11068 # If the interface is maplike/setlike, there will be one getter
11069 # method for the size property of the backing object. Due to having
11070 # to unpack the backing object from the slot, this requires its own
11072 return prefix
+ getMaplikeOrSetlikeSizeGetterBody(
11073 self
.descriptor
, self
.attr
11076 if self
.attr
.type.isObservableArray():
11077 assert not self
.attr
.getExtendedAttribute("CrossOriginReadable")
11078 # If the attribute is observableArray, due to having to unpack the
11079 # backing object from the slot, this requires its own generator.
11080 return prefix
+ getObservableArrayGetterBody(self
.descriptor
, self
.attr
)
11082 if self
.nativeName
is None:
11083 nativeName
= CGSpecializedGetterCommon
.makeNativeName(
11084 self
.descriptor
, self
.attr
11087 nativeName
= self
.nativeName
11089 type = self
.attr
.type
11090 if self
.attr
.getExtendedAttribute("CrossOriginReadable"):
11092 extendedAttributes
= self
.descriptor
.getExtendedAttributes(
11093 self
.attr
, getter
=True
11096 remoteType
.isGeckoInterface()
11097 and not remoteType
.unroll().inner
.isExternal()
11098 and remoteType
.unroll().inner
.getExtendedAttribute("ChromeOnly") is None
11100 # We'll use a JSObject. It might make more sense to use remoteType's
11101 # RemoteProxy, but it's not easy to construct a type for that from here.
11102 remoteType
= BuiltinTypes
[IDLBuiltinType
.Types
.object]
11103 if "needsErrorResult" not in extendedAttributes
:
11104 extendedAttributes
.append("needsErrorResult")
11105 prototypeID
, _
= PrototypeIDAndDepth(self
.descriptor
)
11109 if (IsRemoteObjectProxy(obj, ${prototypeID})) {
11110 ${nativeType}::RemoteProxy* self = static_cast<${nativeType}::RemoteProxy*>(void_self);
11114 prototypeID
=prototypeID
,
11115 nativeType
=self
.descriptor
.nativeType
,
11121 self
.errorReportingLabel
,
11122 argsPre
=[a
.name
for a
in self
.additionalArgs
],
11124 extendedAttributes
=extendedAttributes
,
11130 if self
.attr
.slotIndices
is not None:
11131 # We're going to store this return value in a slot on some object,
11132 # to cache it. The question is, which object? For dictionary and
11133 # sequence return values, we want to use a slot on the Xray expando
11134 # if we're called via Xrays, and a slot on our reflector otherwise.
11135 # On the other hand, when dealing with some interfacce types
11136 # (e.g. window.document) we want to avoid calling the getter more
11137 # than once. In the case of window.document, it's because the
11138 # getter can start returning null, which would get hidden in the
11139 # non-Xray case by the fact that it's [StoreOnSlot], so the cached
11140 # version is always around.
11142 # The upshot is that we use the reflector slot for any getter whose
11143 # type is a gecko interface, whether we're called via Xrays or not.
11144 # Since [Cached] and [StoreInSlot] cannot be used with "NewObject",
11145 # we know that in the interface type case the returned object is
11146 # wrappercached. So creating Xrays to it is reasonable.
11147 if mayUseXrayExpandoSlots(self
.descriptor
, self
.attr
):
11150 // Have to either root across the getter call or reget after.
11152 JS::Rooted<JSObject*> slotStorage(cx, GetCachedSlotStorageObject(cx, obj, &isXray));
11153 if (!slotStorage) {
11156 const size_t slotIndex = isXray ? ${xraySlotIndex} : ${slotIndex};
11158 xraySlotIndex
=memberXrayExpandoReservedSlot(
11159 self
.attr
, self
.descriptor
11161 slotIndex
=memberReservedSlot(self
.attr
, self
.descriptor
),
11166 // Have to either root across the getter call or reget after.
11167 JS::Rooted<JSObject*> slotStorage(cx, js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false));
11168 MOZ_ASSERT(IsDOMObject(slotStorage));
11169 const size_t slotIndex = ${slotIndex};
11171 slotIndex
=memberReservedSlot(self
.attr
, self
.descriptor
),
11176 MOZ_ASSERT(JSCLASS_RESERVED_SLOTS(JS::GetClass(slotStorage)) > slotIndex);
11178 // Scope for cachedVal
11179 JS::Value cachedVal = JS::GetReservedSlot(slotStorage, slotIndex);
11180 if (!cachedVal.isUndefined()) {
11181 args.rval().set(cachedVal);
11182 // The cached value is in the compartment of slotStorage,
11183 // so wrap into the caller compartment as needed.
11184 return ${maybeWrap}(cx, args.rval());
11189 maybeWrap
=getMaybeWrapValueFuncForType(self
.attr
.type),
11199 self
.errorReportingLabel
,
11200 argsPre
=[a
.name
for a
in self
.additionalArgs
],
11204 def auto_profiler_label(self
, profilerLabel
=None):
11205 if profilerLabel
is None:
11206 profilerLabel
= '"' + self
.attr
.identifier
.name
+ '"'
11207 interface_name
= self
.descriptor
.interface
.identifier
.name
11210 AUTO_PROFILER_LABEL_DYNAMIC_FAST(
11211 "${interface_name}", ${attr_name}, DOM, cx,
11212 uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) |
11213 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
11215 interface_name
=interface_name
,
11216 attr_name
=profilerLabel
,
11219 def error_reporting_label(self
):
11220 # Getters never need a BindingCallContext.
11224 def makeNativeName(descriptor
, attr
):
11225 name
= attr
.identifier
.name
11226 nativeName
= MakeNativeName(descriptor
.binaryNameFor(name
, attr
.isStatic()))
11227 _
, resultOutParam
, _
, _
, _
= getRetvalDeclarationForType(attr
.type, descriptor
)
11228 extendedAttrs
= descriptor
.getExtendedAttributes(attr
, getter
=True)
11229 canFail
= "needsErrorResult" in extendedAttrs
or "canOOM" in extendedAttrs
11230 if resultOutParam
or attr
.type.nullable() or canFail
:
11231 nativeName
= "Get" + nativeName
11235 class CGSpecializedGetter(CGSpecializedGetterCommon
):
11237 A class for generating the code for a specialized attribute getter
11238 that the JIT can call with lower overhead.
11241 def __init__(self
, descriptor
, attr
):
11243 name
= "get_" + IDLToCIdentifier(attr
.identifier
.name
)
11245 Argument("JSContext*", "cx"),
11246 Argument("JS::Handle<JSObject*>", "obj"),
11247 Argument("void*", "void_self"),
11248 Argument("JSJitGetterCallArgs", "args"),
11250 CGSpecializedGetterCommon
.__init
__(self
, descriptor
, name
, None, attr
, args
)
11253 class CGTemplateForSpecializedGetter(CGSpecializedGetterCommon
):
11255 A class for generating the code for a specialized attribute getter
11256 that can be used as the common getter that templated attribute
11257 getters can forward to.
11260 def __init__(self
, descriptor
, template
):
11261 self
.attr
= template
.attr
11262 self
.attrNameString
= template
.attrNameString
11264 Argument("JSContext*", "cx"),
11265 Argument("JS::Handle<JSObject*>", "obj"),
11266 Argument("void*", "void_self"),
11267 Argument("JSJitGetterCallArgs", "args"),
11269 errorDescription
= (
11270 'ErrorDescriptionFor<ErrorFor::getter>{ "%s", attrName }'
11271 % descriptor
.interface
.identifier
.name
11273 CGSpecializedGetterCommon
.__init
__(
11280 errorReportingLabel
=errorDescription
,
11281 additionalArg
=Argument(template
.argument
.type, template
.argument
.name
),
11284 def auto_profiler_label(self
):
11288 const char* attrName = ${attrNameString};
11290 attrNameString
=self
.attrNameString
,
11292 + CGSpecializedGetterCommon
.auto_profiler_label(self
, "attrName")
11296 class CGSpecializedTemplatedGetter(CGAbstractStaticMethod
):
11298 A class for generating the code for a specialized templated attribute
11299 getter that forwards to a common template getter.
11302 def __init__(self
, descriptor
, attr
, template
, additionalArg
):
11304 self
.template
= template
11305 self
.additionalArg
= additionalArg
11306 name
= "get_" + IDLToCIdentifier(attr
.identifier
.name
)
11308 Argument("JSContext*", "cx"),
11309 Argument("JS::Handle<JSObject*>", "obj"),
11310 Argument("void*", "void_self"),
11311 Argument("JSJitGetterCallArgs", "args"),
11313 assert not attr
.getExtendedAttribute("StoreInSlot")
11314 CGAbstractStaticMethod
.__init
__(
11323 def definition_body(self
):
11324 if self
.additionalArg
is None:
11325 additionalArg
= self
.attr
.identifier
.name
11327 additionalArg
= self
.additionalArg
11331 return ${namespace}::${getter}(cx, obj, void_self, args, ${additionalArg});
11333 namespace
=toBindingNamespace(
11334 self
.template
.descriptor
.interface
.identifier
.name
11336 getter
=self
.template
.getter
,
11337 additionalArg
=additionalArg
,
11341 class CGGetterPromiseWrapper(CGAbstractStaticMethod
):
11343 A class for generating a wrapper around another getter that will
11344 convert exceptions to promises.
11347 def __init__(self
, descriptor
, getterToWrap
):
11348 self
.getter
= getterToWrap
11349 name
= self
.makeName(getterToWrap
.name
)
11350 args
= list(getterToWrap
.args
)
11351 CGAbstractStaticMethod
.__init
__(
11352 self
, descriptor
, name
, "bool", args
, canRunScript
=True
11355 def definition_body(self
):
11358 bool ok = ${getterName}(${args});
11362 return ConvertExceptionToPromise(cx, args.rval());
11364 getterName
=self
.getter
.name
,
11365 args
=", ".join(arg
.name
for arg
in self
.args
),
11369 def makeName(getterName
):
11370 return getterName
+ "_promiseWrapper"
11373 class CGStaticGetter(CGAbstractStaticBindingMethod
):
11375 A class for generating the C++ code for an IDL static attribute getter.
11378 def __init__(self
, descriptor
, attr
):
11380 name
= "get_" + IDLToCIdentifier(attr
.identifier
.name
)
11381 CGAbstractStaticBindingMethod
.__init
__(self
, descriptor
, name
)
11383 def generate_code(self
):
11384 nativeName
= CGSpecializedGetterCommon
.makeNativeName(
11385 self
.descriptor
, self
.attr
11387 return CGGetterCall(self
.attr
.type, nativeName
, self
.descriptor
, self
.attr
)
11389 def auto_profiler_label(self
):
11390 interface_name
= self
.descriptor
.interface
.identifier
.name
11391 attr_name
= self
.attr
.identifier
.name
11394 AUTO_PROFILER_LABEL_DYNAMIC_FAST(
11395 "${interface_name}", "${attr_name}", DOM, cx,
11396 uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) |
11397 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
11399 interface_name
=interface_name
,
11400 attr_name
=attr_name
,
11403 def error_reporting_label(self
):
11404 # Getters never need a BindingCallContext.
11408 class CGSpecializedSetterCommon(CGAbstractStaticMethod
):
11410 A class for generating the code for a specialized attribute setter
11411 that the JIT can call with lower overhead.
11421 errorReportingLabel
=None,
11422 additionalArg
=None,
11424 self
.nativeName
= nativeName
11425 self
.errorReportingLabel
= errorReportingLabel
11426 self
.additionalArgs
= [] if additionalArg
is None else [additionalArg
]
11427 CGAbstractStaticMethod
.__init
__(
11432 args
+ self
.additionalArgs
,
11436 def definition_body(self
):
11437 type = self
.attr
.type
11438 call
= CGSetterCall(
11443 self
.errorReportingLabel
,
11444 [a
.name
for a
in self
.additionalArgs
],
11447 if self
.attr
.getExtendedAttribute("CrossOriginWritable"):
11448 if type.isGeckoInterface() and not type.unroll().inner
.isExternal():
11449 # a setter taking a Gecko interface would require us to deal with remote
11450 # proxies for the value here.
11452 "We don't support the setter of %s marked as "
11453 "CrossOriginWritable because it takes a Gecko interface "
11455 self
.attr
.identifier
.name
,
11457 prototypeID
, _
= PrototypeIDAndDepth(self
.descriptor
)
11460 if (IsRemoteObjectProxy(obj, ${prototypeID})) {
11461 auto* self = static_cast<${nativeType}::RemoteProxy*>(void_self);
11465 prototypeID
=prototypeID
,
11466 nativeType
=self
.descriptor
.nativeType
,
11470 return prefix
+ fill(
11472 auto* self = static_cast<${nativeType}*>(void_self);
11475 nativeType
=self
.descriptor
.nativeType
,
11479 def auto_profiler_label(self
, profilerLabel
=None):
11480 interface_name
= self
.descriptor
.interface
.identifier
.name
11481 if profilerLabel
is None:
11482 profilerLabel
= '"' + self
.attr
.identifier
.name
+ '"'
11485 AUTO_PROFILER_LABEL_DYNAMIC_FAST(
11486 "${interface_name}", ${attr_name}, DOM, cx,
11487 uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) |
11488 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
11490 interface_name
=interface_name
,
11491 attr_name
=profilerLabel
,
11495 def error_reporting_label_helper(descriptor
, attr
):
11496 # Setters need a BindingCallContext if the type of the attribute needs
11498 if not idlTypeNeedsCallContext(
11499 attr
.type, descriptor
, allowTreatNonCallableAsNull
=True
11503 GetLabelForErrorReporting(descriptor
, attr
, isConstructor
=False) + " setter"
11506 def error_reporting_label(self
):
11507 errorReportingLabel
= CGSpecializedSetterCommon
.error_reporting_label_helper(
11508 self
.descriptor
, self
.attr
11510 if errorReportingLabel
is None:
11512 if self
.errorReportingLabel
:
11513 return self
.errorReportingLabel
11514 return errorReportingLabel
11517 def makeNativeName(descriptor
, attr
):
11518 name
= attr
.identifier
.name
11519 return "Set" + MakeNativeName(descriptor
.binaryNameFor(name
, attr
.isStatic()))
11522 class CGSpecializedSetter(CGSpecializedSetterCommon
):
11524 A class for generating the code for a specialized attribute setter
11525 that the JIT can call with lower overhead.
11528 def __init__(self
, descriptor
, attr
):
11530 name
= "set_" + IDLToCIdentifier(attr
.identifier
.name
)
11532 Argument("JSContext*", "cx"),
11533 Argument("JS::Handle<JSObject*>", "obj"),
11534 Argument("void*", "void_self"),
11535 Argument("JSJitSetterCallArgs", "args"),
11537 CGSpecializedSetterCommon
.__init
__(
11541 CGSpecializedSetterCommon
.makeNativeName(descriptor
, attr
),
11547 class CGTemplateForSpecializedSetter(CGSpecializedSetterCommon
):
11549 A class for generating the code for a specialized attribute setter
11550 that can be used as the common setter that templated attribute
11551 setters can forward to.
11554 def __init__(self
, descriptor
, template
):
11555 self
.attr
= template
.attr
11556 self
.attrNameString
= template
.attrNameString
11558 Argument("JSContext*", "cx"),
11559 Argument("JS::Handle<JSObject*>", "obj"),
11560 Argument("void*", "void_self"),
11561 Argument("JSJitSetterCallArgs", "args"),
11563 errorDescription
= (
11564 'ErrorDescriptionFor<ErrorFor::setter>{ "%s", attrName }'
11565 % descriptor
.interface
.identifier
.name
11567 CGSpecializedSetterCommon
.__init
__(
11574 errorReportingLabel
=errorDescription
,
11575 additionalArg
=Argument(template
.argument
.type, template
.argument
.name
),
11578 def auto_profiler_label(self
):
11582 const char* attrName = ${attrNameString};
11584 attrNameString
=self
.attrNameString
,
11586 + CGSpecializedSetterCommon
.auto_profiler_label(self
, "attrName")
11590 class CGSpecializedTemplatedSetter(CGAbstractStaticMethod
):
11592 A class for generating the code for a specialized templated attribute
11593 setter that forwards to a common template setter.
11596 def __init__(self
, descriptor
, attr
, template
, additionalArg
):
11598 self
.template
= template
11599 self
.additionalArg
= additionalArg
11600 name
= "set_" + IDLToCIdentifier(attr
.identifier
.name
)
11602 Argument("JSContext*", "cx"),
11603 Argument("JS::Handle<JSObject*>", "obj"),
11604 Argument("void*", "void_self"),
11605 Argument("JSJitSetterCallArgs", "args"),
11607 CGAbstractStaticMethod
.__init
__(
11608 self
, descriptor
, name
, "bool", args
, canRunScript
=True
11611 def definition_body(self
):
11612 additionalArgs
= []
11613 if self
.additionalArg
is None:
11614 additionalArgs
.append(self
.attr
.identifier
.name
)
11616 additionalArgs
.append(self
.additionalArg
)
11620 return ${namespace}::${setter}(cx, obj, void_self, args, ${additionalArgs});
11622 namespace
=toBindingNamespace(
11623 self
.template
.descriptor
.interface
.identifier
.name
11625 setter
=self
.template
.setter
,
11626 additionalArgs
=", ".join(additionalArgs
),
11630 class CGStaticSetter(CGAbstractStaticBindingMethod
):
11632 A class for generating the C++ code for an IDL static attribute setter.
11635 def __init__(self
, descriptor
, attr
):
11637 name
= "set_" + IDLToCIdentifier(attr
.identifier
.name
)
11638 CGAbstractStaticBindingMethod
.__init
__(self
, descriptor
, name
)
11640 def generate_code(self
):
11641 nativeName
= CGSpecializedSetterCommon
.makeNativeName(
11642 self
.descriptor
, self
.attr
11644 checkForArg
= CGGeneric(
11647 if (!args.requireAtLeast(cx, "${name} setter", 1)) {
11651 name
=self
.attr
.identifier
.name
,
11654 call
= CGSetterCall(self
.attr
.type, nativeName
, self
.descriptor
, self
.attr
)
11655 return CGList([checkForArg
, call
])
11657 def auto_profiler_label(self
):
11658 interface_name
= self
.descriptor
.interface
.identifier
.name
11659 attr_name
= self
.attr
.identifier
.name
11662 AUTO_PROFILER_LABEL_DYNAMIC_FAST(
11663 "${interface_name}", "${attr_name}", DOM, cx,
11664 uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) |
11665 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
11667 interface_name
=interface_name
,
11668 attr_name
=attr_name
,
11671 def error_reporting_label(self
):
11672 return CGSpecializedSetterCommon
.error_reporting_label_helper(
11673 self
.descriptor
, self
.attr
11677 class CGSpecializedForwardingSetter(CGSpecializedSetter
):
11679 A class for generating the code for a specialized attribute setter with
11680 PutForwards that the JIT can call with lower overhead.
11683 def __init__(self
, descriptor
, attr
):
11684 CGSpecializedSetter
.__init
__(self
, descriptor
, attr
)
11686 def definition_body(self
):
11687 attrName
= self
.attr
.identifier
.name
11688 forwardToAttrName
= self
.attr
.getExtendedAttribute("PutForwards")[0]
11689 # JS_GetProperty and JS_SetProperty can only deal with ASCII
11690 assert all(ord(c
) < 128 for c
in attrName
)
11691 assert all(ord(c
) < 128 for c
in forwardToAttrName
)
11694 JS::Rooted<JS::Value> v(cx);
11695 if (!JS_GetProperty(cx, obj, "${attr}", &v)) {
11699 if (!v.isObject()) {
11700 return cx.ThrowErrorMessage<MSG_NOT_OBJECT>("${interface}.${attr}");
11703 JS::Rooted<JSObject*> targetObj(cx, &v.toObject());
11704 return JS_SetProperty(cx, targetObj, "${forwardToAttrName}", args[0]);
11707 interface
=self
.descriptor
.interface
.identifier
.name
,
11708 forwardToAttrName
=forwardToAttrName
,
11711 def error_reporting_label(self
):
11712 # We always need to be able to throw.
11714 GetLabelForErrorReporting(self
.descriptor
, self
.attr
, isConstructor
=False)
11719 class CGSpecializedReplaceableSetter(CGSpecializedSetter
):
11721 A class for generating the code for a specialized attribute setter with
11722 Replaceable that the JIT can call with lower overhead.
11725 def __init__(self
, descriptor
, attr
):
11726 CGSpecializedSetter
.__init
__(self
, descriptor
, attr
)
11728 def definition_body(self
):
11729 attrName
= self
.attr
.identifier
.name
11730 # JS_DefineProperty can only deal with ASCII
11731 assert all(ord(c
) < 128 for c
in attrName
)
11733 'return JS_DefineProperty(cx, obj, "%s", args[0], JSPROP_ENUMERATE);\n'
11737 def error_reporting_label(self
):
11738 # We never throw directly.
11742 class CGSpecializedLenientSetter(CGSpecializedSetter
):
11744 A class for generating the code for a specialized attribute setter with
11745 LenientSetter that the JIT can call with lower overhead.
11748 def __init__(self
, descriptor
, attr
):
11749 CGSpecializedSetter
.__init
__(self
, descriptor
, attr
)
11751 def definition_body(self
):
11752 attrName
= self
.attr
.identifier
.name
11753 # JS_DefineProperty can only deal with ASCII
11754 assert all(ord(c
) < 128 for c
in attrName
)
11757 DeprecationWarning(cx, obj, DeprecatedOperations::eLenientSetter);
11762 def error_reporting_label(self
):
11763 # We never throw; that's the whole point.
11767 def memberReturnsNewObject(member
):
11768 return member
.getExtendedAttribute("NewObject") is not None
11771 class CGMemberJITInfo(CGThing
):
11773 A class for generating the JITInfo for a property that points to
11774 our specialized getter and setter.
11777 def __init__(self
, descriptor
, member
):
11778 self
.member
= member
11779 self
.descriptor
= descriptor
11800 aliasSet is a JSJitInfo::AliasSet value, without the "JSJitInfo::" bit.
11802 args is None if we don't want to output argTypes for some
11803 reason (e.g. we have overloads or we're not a method) and
11804 otherwise an iterable of the arguments for this method.
11807 not movable
or aliasSet
!= "AliasEverything"
11808 ) # Can't move write-aliasing things
11810 not alwaysInSlot
or movable
11811 ) # Things always in slots had better be movable
11813 not eliminatable
or aliasSet
!= "AliasEverything"
11814 ) # Can't eliminate write-aliasing things
11816 not alwaysInSlot
or eliminatable
11817 ) # Things always in slots had better be eliminatable
11819 def jitInfoInitializer(isTypedMethod
):
11820 initializer
= fill(
11824 { prototypes::id::${name} },
11825 { PrototypeTraits<prototypes::id::${name}>::Depth },
11826 JSJitInfo::${opType},
11827 JSJitInfo::${aliasSet}, /* aliasSet. Not relevant for setters. */
11828 ${returnType}, /* returnType. Not relevant for setters. */
11829 ${isInfallible}, /* isInfallible. False in setters. */
11830 ${isMovable}, /* isMovable. Not relevant for setters. */
11831 ${isEliminatable}, /* isEliminatable. Not relevant for setters. */
11832 ${isAlwaysInSlot}, /* isAlwaysInSlot. Only relevant for getters. */
11833 ${isLazilyCachedInSlot}, /* isLazilyCachedInSlot. Only relevant for getters. */
11834 ${isTypedMethod}, /* isTypedMethod. Only relevant for methods. */
11835 ${slotIndex} /* Reserved slot index, if we're stored in a slot, else 0. */
11839 name
=self
.descriptor
.name
,
11842 returnType
=functools
.reduce(
11843 CGMemberJITInfo
.getSingleReturnType
, returnTypes
, ""
11845 isInfallible
=toStringBool(infallible
),
11846 isMovable
=toStringBool(movable
),
11847 isEliminatable
=toStringBool(eliminatable
),
11848 isAlwaysInSlot
=toStringBool(alwaysInSlot
),
11849 isLazilyCachedInSlot
=toStringBool(lazilyInSlot
),
11850 isTypedMethod
=toStringBool(isTypedMethod
),
11851 slotIndex
=slotIndex
,
11853 return initializer
.rstrip()
11855 if alwaysInSlot
or lazilyInSlot
:
11858 static_assert(${slotIndex} <= JSJitInfo::maxSlotIndex, "We won't fit");
11859 static_assert(${slotIndex} < ${classReservedSlots}, "There is no slot for us");
11861 slotIndex
=slotIndex
,
11862 classReservedSlots
=INSTANCE_RESERVED_SLOTS
11863 + self
.descriptor
.interface
.totalMembersInSlots
,
11867 if args
is not None:
11868 argTypes
= "%s_argTypes" % infoName
11869 args
= [CGMemberJITInfo
.getJSArgType(arg
.type) for arg
in args
]
11870 args
.append("JSJitInfo::ArgTypeListEnd")
11871 argTypesDecl
= "static const JSJitInfo::ArgType %s[] = { %s };\n" % (
11878 static const JSTypedMethodJitInfo ${infoName} = {
11884 argTypesDecl
=argTypesDecl
,
11886 jitInfo
=indent(jitInfoInitializer(True)),
11888 slotAssert
=slotAssert
,
11891 # Unexposed things are meant to be used from C++ directly, so we make
11892 # their jitinfo non-static. That way C++ can get at it.
11893 if self
.member
.getExtendedAttribute("Unexposed"):
11894 storageClass
= "extern"
11896 storageClass
= "static"
11900 ${storageClass} const JSJitInfo ${infoName} = ${jitInfo};
11903 storageClass
=storageClass
,
11905 jitInfo
=jitInfoInitializer(False),
11906 slotAssert
=slotAssert
,
11910 if self
.member
.isAttr():
11911 getterinfo
= "%s_getterinfo" % IDLToCIdentifier(self
.member
.identifier
.name
)
11912 name
= IDLToCIdentifier(self
.member
.identifier
.name
)
11913 if self
.member
.type.isPromise():
11914 name
= CGGetterPromiseWrapper
.makeName(name
)
11915 getter
= "get_%s" % name
11916 extendedAttrs
= self
.descriptor
.getExtendedAttributes(
11917 self
.member
, getter
=True
11919 getterinfal
= "needsErrorResult" not in extendedAttrs
11921 # At this point getterinfal is true if our getter either can't throw
11922 # at all, or can only throw OOM. In both cases, it's safe to move,
11923 # or dead-code-eliminate, the getter, because throwing OOM is not
11924 # semantically meaningful, so code can't rely on it happening. Note
11925 # that this makes the behavior consistent for OOM thrown from the
11926 # getter itself and OOM thrown from the to-JS conversion of the
11927 # return value (see the "canOOM" and "infallibleForMember" checks
11929 movable
= self
.mayBeMovable() and getterinfal
11930 eliminatable
= self
.mayBeEliminatable() and getterinfal
11931 aliasSet
= self
.aliasSet()
11933 # Now we have to set getterinfal to whether we can _really_ ever
11934 # throw, from the point of view of the JS engine.
11937 and "canOOM" not in extendedAttrs
11938 and infallibleForMember(self
.member
, self
.member
.type, self
.descriptor
)
11940 isAlwaysInSlot
= self
.member
.getExtendedAttribute("StoreInSlot")
11942 if self
.member
.slotIndices
is not None:
11945 or self
.member
.getExtendedAttribute("Cached")
11946 or self
.member
.type.isObservableArray()
11948 isLazilyCachedInSlot
= not isAlwaysInSlot
11949 slotIndex
= memberReservedSlot(self
.member
, self
.descriptor
)
11950 # We'll statically assert that this is not too big in
11951 # CGUpdateMemberSlotsMethod, in the case when
11952 # isAlwaysInSlot is true.
11954 isLazilyCachedInSlot
= False
11957 result
= self
.defineJitInfo(
11966 isLazilyCachedInSlot
,
11968 [self
.member
.type],
11972 not self
.member
.readonly
11973 or self
.member
.getExtendedAttribute("PutForwards") is not None
11974 or self
.member
.getExtendedAttribute("Replaceable") is not None
11975 or self
.member
.getExtendedAttribute("LegacyLenientSetter") is not None
11977 setterinfo
= "%s_setterinfo" % IDLToCIdentifier(
11978 self
.member
.identifier
.name
11980 # Actually a JSJitSetterOp, but JSJitGetterOp is first in the
11982 setter
= "(JSJitGetterOp)set_%s" % IDLToCIdentifier(
11983 self
.member
.identifier
.name
11985 # Setters are always fallible, since they have to do a typed unwrap.
11986 result
+= self
.defineJitInfo(
11997 [BuiltinTypes
[IDLBuiltinType
.Types
.undefined
]],
12001 if self
.member
.isMethod():
12002 methodinfo
= "%s_methodinfo" % IDLToCIdentifier(self
.member
.identifier
.name
)
12003 name
= CppKeywords
.checkMethodName(
12004 IDLToCIdentifier(self
.member
.identifier
.name
)
12006 if self
.member
.returnsPromise():
12007 name
= CGMethodPromiseWrapper
.makeName(name
)
12008 # Actually a JSJitMethodOp, but JSJitGetterOp is first in the union.
12009 method
= "(JSJitGetterOp)%s" % name
12011 # Methods are infallible if they are infallible, have no arguments
12012 # to unwrap, and have a return type that's infallible to wrap up for
12014 sigs
= self
.member
.signatures()
12016 # Don't handle overloading. If there's more than one signature,
12017 # one of them must take arguments.
12018 methodInfal
= False
12021 eliminatable
= False
12024 # For methods that affect nothing, it's OK to set movable to our
12025 # notion of infallible on the C++ side, without considering
12026 # argument conversions, since argument conversions that can
12027 # reliably throw would be effectful anyway and the jit doesn't
12028 # move effectful things.
12029 extendedAttrs
= self
.descriptor
.getExtendedAttributes(self
.member
)
12030 hasInfallibleImpl
= "needsErrorResult" not in extendedAttrs
12031 # At this point hasInfallibleImpl is true if our method either
12032 # can't throw at all, or can only throw OOM. In both cases, it
12033 # may be safe to move, or dead-code-eliminate, the method,
12034 # because throwing OOM is not semantically meaningful, so code
12035 # can't rely on it happening. Note that this makes the behavior
12036 # consistent for OOM thrown from the method itself and OOM
12037 # thrown from the to-JS conversion of the return value (see the
12038 # "canOOM" and "infallibleForMember" checks below).
12039 movable
= self
.mayBeMovable() and hasInfallibleImpl
12040 eliminatable
= self
.mayBeEliminatable() and hasInfallibleImpl
12041 # XXXbz can we move the smarts about fallibility due to arg
12042 # conversions into the JIT, using our new args stuff?
12043 if len(sig
[1]) != 0 or not infallibleForMember(
12044 self
.member
, sig
[0], self
.descriptor
12046 # We have arguments or our return-value boxing can fail
12047 methodInfal
= False
12049 methodInfal
= hasInfallibleImpl
and "canOOM" not in extendedAttrs
12050 # For now, only bother to output args if we're side-effect-free.
12051 if self
.member
.affects
== "Nothing":
12056 aliasSet
= self
.aliasSet()
12057 result
= self
.defineJitInfo(
12068 [s
[0] for s
in sigs
],
12072 raise TypeError("Illegal member type to CGPropertyJITInfo")
12074 def mayBeMovable(self
):
12076 Returns whether this attribute or method may be movable, just
12077 based on Affects/DependsOn annotations.
12079 affects
= self
.member
.affects
12080 dependsOn
= self
.member
.dependsOn
12081 assert affects
in IDLInterfaceMember
.AffectsValues
12082 assert dependsOn
in IDLInterfaceMember
.DependsOnValues
12083 # Things that are DependsOn=DeviceState are not movable, because we
12084 # don't want them coalesced with each other or loop-hoisted, since
12085 # their return value can change even if nothing is going on from our
12087 return affects
== "Nothing" and (
12088 dependsOn
!= "Everything" and dependsOn
!= "DeviceState"
12091 def mayBeEliminatable(self
):
12093 Returns whether this attribute or method may be eliminatable, just
12094 based on Affects/DependsOn annotations.
12096 # dependsOn shouldn't affect this decision at all, except in jitinfo we
12097 # have no way to express "Depends on everything, affects nothing",
12098 # because we only have three alias set values: AliasNone ("depends on
12099 # nothing, affects nothing"), AliasDOMSets ("depends on DOM sets,
12100 # affects nothing"), AliasEverything ("depends on everything, affects
12101 # everything"). So the [Affects=Nothing, DependsOn=Everything] case
12102 # gets encoded as AliasEverything and defineJitInfo asserts that if our
12103 # alias state is AliasEverything then we're not eliminatable (because it
12104 # thinks we might have side-effects at that point). Bug 1155796 is
12105 # tracking possible solutions for this.
12106 affects
= self
.member
.affects
12107 dependsOn
= self
.member
.dependsOn
12108 assert affects
in IDLInterfaceMember
.AffectsValues
12109 assert dependsOn
in IDLInterfaceMember
.DependsOnValues
12110 return affects
== "Nothing" and dependsOn
!= "Everything"
12112 def aliasSet(self
):
12114 Returns the alias set to store in the jitinfo. This may not be the
12115 effective alias set the JIT uses, depending on whether we have enough
12116 information about our args to allow the JIT to prove that effectful
12117 argument conversions won't happen.
12119 dependsOn
= self
.member
.dependsOn
12120 assert dependsOn
in IDLInterfaceMember
.DependsOnValues
12122 if dependsOn
== "Nothing" or dependsOn
== "DeviceState":
12123 assert self
.member
.affects
== "Nothing"
12126 if dependsOn
== "DOMState":
12127 assert self
.member
.affects
== "Nothing"
12128 return "AliasDOMSets"
12130 return "AliasEverything"
12133 def getJSReturnTypeTag(t
):
12135 # Sometimes it might return null, sometimes not
12136 return "JSVAL_TYPE_UNKNOWN"
12137 if t
.isUndefined():
12138 # No return, every time
12139 return "JSVAL_TYPE_UNDEFINED"
12141 return "JSVAL_TYPE_OBJECT"
12143 return "JSVAL_TYPE_OBJECT"
12145 return "JSVAL_TYPE_OBJECT"
12146 if t
.isGeckoInterface():
12147 return "JSVAL_TYPE_OBJECT"
12149 return "JSVAL_TYPE_STRING"
12151 return "JSVAL_TYPE_STRING"
12153 return "JSVAL_TYPE_OBJECT"
12155 # The whole point is to return various stuff
12156 return "JSVAL_TYPE_UNKNOWN"
12158 return "JSVAL_TYPE_OBJECT"
12159 if t
.isSpiderMonkeyInterface():
12160 return "JSVAL_TYPE_OBJECT"
12163 if u
.hasNullableType
:
12164 # Might be null or not
12165 return "JSVAL_TYPE_UNKNOWN"
12166 return functools
.reduce(
12167 CGMemberJITInfo
.getSingleReturnType
, u
.flatMemberTypes
, ""
12169 if t
.isDictionary():
12170 return "JSVAL_TYPE_OBJECT"
12171 if t
.isObservableArray():
12172 return "JSVAL_TYPE_OBJECT"
12173 if not t
.isPrimitive():
12174 raise TypeError("No idea what type " + str(t
) + " is.")
12176 if tag
== IDLType
.Tags
.bool:
12177 return "JSVAL_TYPE_BOOLEAN"
12180 IDLType
.Tags
.uint8
,
12181 IDLType
.Tags
.int16
,
12182 IDLType
.Tags
.uint16
,
12183 IDLType
.Tags
.int32
,
12185 return "JSVAL_TYPE_INT32"
12187 IDLType
.Tags
.int64
,
12188 IDLType
.Tags
.uint64
,
12189 IDLType
.Tags
.unrestricted_float
,
12190 IDLType
.Tags
.float,
12191 IDLType
.Tags
.unrestricted_double
,
12192 IDLType
.Tags
.double
,
12194 # These all use JS_NumberValue, which can return int or double.
12195 # But TI treats "double" as meaning "int or double", so we're
12196 # good to return JSVAL_TYPE_DOUBLE here.
12197 return "JSVAL_TYPE_DOUBLE"
12198 if tag
!= IDLType
.Tags
.uint32
:
12199 raise TypeError("No idea what type " + str(t
) + " is.")
12200 # uint32 is sometimes int and sometimes double.
12201 return "JSVAL_TYPE_DOUBLE"
12204 def getSingleReturnType(existingType
, t
):
12205 type = CGMemberJITInfo
.getJSReturnTypeTag(t
)
12206 if existingType
== "":
12207 # First element of the list; just return its type
12210 if type == existingType
:
12211 return existingType
12212 if (type == "JSVAL_TYPE_DOUBLE" and existingType
== "JSVAL_TYPE_INT32") or (
12213 existingType
== "JSVAL_TYPE_DOUBLE" and type == "JSVAL_TYPE_INT32"
12215 # Promote INT32 to DOUBLE as needed
12216 return "JSVAL_TYPE_DOUBLE"
12218 return "JSVAL_TYPE_UNKNOWN"
12221 def getJSArgType(t
):
12222 assert not t
.isUndefined()
12224 # Sometimes it might return null, sometimes not
12226 "JSJitInfo::ArgType(JSJitInfo::Null | %s)"
12227 % CGMemberJITInfo
.getJSArgType(t
.inner
)
12230 return "JSJitInfo::Object"
12232 return "JSJitInfo::Object"
12233 if t
.isGeckoInterface():
12234 return "JSJitInfo::Object"
12236 return "JSJitInfo::String"
12238 return "JSJitInfo::String"
12240 return "JSJitInfo::Object"
12242 # The whole point is to return various stuff
12243 return "JSJitInfo::Any"
12245 return "JSJitInfo::Object"
12246 if t
.isSpiderMonkeyInterface():
12247 return "JSJitInfo::Object"
12250 type = "JSJitInfo::Null" if u
.hasNullableType
else ""
12251 return "JSJitInfo::ArgType(%s)" % functools
.reduce(
12252 CGMemberJITInfo
.getSingleArgType
, u
.flatMemberTypes
, type
12254 if t
.isDictionary():
12255 return "JSJitInfo::Object"
12256 if not t
.isPrimitive():
12257 raise TypeError("No idea what type " + str(t
) + " is.")
12259 if tag
== IDLType
.Tags
.bool:
12260 return "JSJitInfo::Boolean"
12263 IDLType
.Tags
.uint8
,
12264 IDLType
.Tags
.int16
,
12265 IDLType
.Tags
.uint16
,
12266 IDLType
.Tags
.int32
,
12268 return "JSJitInfo::Integer"
12270 IDLType
.Tags
.int64
,
12271 IDLType
.Tags
.uint64
,
12272 IDLType
.Tags
.unrestricted_float
,
12273 IDLType
.Tags
.float,
12274 IDLType
.Tags
.unrestricted_double
,
12275 IDLType
.Tags
.double
,
12277 # These all use JS_NumberValue, which can return int or double.
12278 # But TI treats "double" as meaning "int or double", so we're
12279 # good to return JSVAL_TYPE_DOUBLE here.
12280 return "JSJitInfo::Double"
12281 if tag
!= IDLType
.Tags
.uint32
:
12282 raise TypeError("No idea what type " + str(t
) + " is.")
12283 # uint32 is sometimes int and sometimes double.
12284 return "JSJitInfo::Double"
12287 def getSingleArgType(existingType
, t
):
12288 type = CGMemberJITInfo
.getJSArgType(t
)
12289 if existingType
== "":
12290 # First element of the list; just return its type
12293 if type == existingType
:
12294 return existingType
12295 return "%s | %s" % (existingType
, type)
12298 class CGStaticMethodJitinfo(CGGeneric
):
12300 A class for generating the JITInfo for a promise-returning static method.
12303 def __init__(self
, method
):
12304 CGGeneric
.__init
__(
12307 "static const JSJitInfo %s_methodinfo = {\n"
12308 " { (JSJitGetterOp)%s },\n"
12309 " { prototypes::id::_ID_Count }, { 0 }, JSJitInfo::StaticMethod,\n"
12310 " JSJitInfo::AliasEverything, JSVAL_TYPE_OBJECT, false, false,\n"
12311 " false, false, 0\n"
12314 IDLToCIdentifier(method
.identifier
.name
),
12315 CppKeywords
.checkMethodName(IDLToCIdentifier(method
.identifier
.name
)),
12320 def getEnumValueName(value
):
12321 # Some enum values can be empty strings. Others might have weird
12322 # characters in them. Deal with the former by returning "_empty",
12323 # deal with possible name collisions from that by throwing if the
12324 # enum value is actually "_empty", and throw on any value
12325 # containing non-ASCII chars for now. Replace all chars other than
12326 # [0-9A-Za-z_] with '_'.
12327 if re
.match("[^\x20-\x7E]", value
):
12328 raise SyntaxError('Enum value "' + value
+ '" contains non-ASCII characters')
12329 if re
.match("^[0-9]", value
):
12330 value
= "_" + value
12331 value
= re
.sub(r
"[^0-9A-Za-z_]", "_", value
)
12332 if re
.match("^_[A-Z]|__", value
):
12333 raise SyntaxError('Enum value "' + value
+ '" is reserved by the C++ spec')
12334 if value
== "_empty":
12335 raise SyntaxError('"_empty" is not an IDL enum value we support yet')
12338 return MakeNativeName(value
)
12341 class CGEnumToJSValue(CGAbstractMethod
):
12342 def __init__(self
, enum
):
12343 enumType
= enum
.identifier
.name
12344 self
.stringsArray
= "binding_detail::EnumStrings<" + enumType
+ ">::Values"
12345 CGAbstractMethod
.__init
__(
12351 Argument("JSContext*", "aCx"),
12352 Argument(enumType
, "aArgument"),
12353 Argument("JS::MutableHandle<JS::Value>", "aValue"),
12357 def definition_body(self
):
12360 MOZ_ASSERT(uint32_t(aArgument) < ArrayLength(${strings}));
12361 JSString* resultStr =
12362 JS_NewStringCopyN(aCx, ${strings}[uint32_t(aArgument)].BeginReading(),
12363 ${strings}[uint32_t(aArgument)].Length());
12367 aValue.setString(resultStr);
12370 strings
=self
.stringsArray
,
12374 class CGEnum(CGThing
):
12375 def __init__(self
, enum
):
12376 CGThing
.__init
__(self
)
12378 strings
= CGNamespace(
12383 template <> struct EnumStrings<${name}> {
12384 static const nsLiteralCString Values[${count}];
12387 name
=self
.enum
.identifier
.name
,
12388 count
=self
.nEnumStrings(),
12392 const nsLiteralCString EnumStrings<${name}>::Values[${count}] = {
12396 name
=self
.enum
.identifier
.name
,
12397 count
=self
.nEnumStrings(),
12398 entries
="".join('"%s"_ns,\n' % val
for val
in self
.enum
.values()),
12402 toJSValue
= CGEnumToJSValue(enum
)
12403 self
.cgThings
= CGList([strings
, toJSValue
], "\n")
12405 def nEnumStrings(self
):
12406 return len(self
.enum
.values())
12409 def underlyingType(enum
):
12410 count
= len(enum
.values())
12415 raise ValueError("Enum " + enum
.identifier
.name
+ " has more than 65536 values")
12420 enum class ${name} : ${ty} {
12424 name
=self
.enum
.identifier
.name
,
12425 ty
=CGEnum
.underlyingType(self
.enum
),
12426 enums
=",\n".join(map(getEnumValueName
, self
.enum
.values())) + ",\n",
12429 return decl
+ "\n" + self
.cgThings
.declare()
12432 return self
.cgThings
.define()
12435 return self
.enum
.getDeps()
12438 class CGMaxContiguousEnumValue(CGThing
):
12439 def __init__(self
, enum
):
12440 CGThing
.__init
__(self
)
12444 enumValues
= self
.enum
.values()
12448 struct MaxContiguousEnumValue<dom::${name}>
12450 static constexpr dom::${name} value = dom::${name}::${maxValue};
12452 static_assert(static_cast<${ty}>(dom::${name}::${minValue}) == 0,
12453 "We rely on this in ContiguousEnumValues");
12454 static_assert(mozilla::ArrayLength(dom::binding_detail::EnumStrings<dom::${name}>::Values) - 1 == UnderlyingValue(value),
12455 "Mismatch between enum strings and enum count");
12458 name
=self
.enum
.identifier
.name
,
12459 ty
=CGEnum
.underlyingType(self
.enum
),
12460 maxValue
=getEnumValueName(enumValues
[-1]),
12461 minValue
=getEnumValueName(enumValues
[0]),
12468 return self
.enum
.getDeps()
12471 def getUnionAccessorSignatureType(type, descriptorProvider
):
12473 Returns the types that are used in the getter and setter signatures for
12476 # Flat member types have already unwrapped nullables.
12477 assert not type.nullable()
12479 # Promise types can never appear in unions, because Promise is not
12480 # distinguishable from anything.
12481 assert not type.isPromise()
12483 if type.isSequence() or type.isRecord():
12484 if type.isSequence():
12485 wrapperType
= "Sequence"
12487 wrapperType
= "Record"
12488 # We don't use the returned template here, so it's OK to just pass no
12489 # sourceDescription.
12490 elementInfo
= getJSToNativeConversionInfo(
12491 type.inner
, descriptorProvider
, isMember
=wrapperType
12493 if wrapperType
== "Sequence":
12494 innerType
= elementInfo
.declType
12496 innerType
= [recordKeyDeclType(type), elementInfo
.declType
]
12498 return CGTemplatedType(wrapperType
, innerType
, isConst
=True, isReference
=True)
12500 # Nested unions are unwrapped automatically into our flatMemberTypes.
12501 assert not type.isUnion()
12503 if type.isGeckoInterface():
12504 descriptor
= descriptorProvider
.getDescriptor(
12505 type.unroll().inner
.identifier
.name
12507 typeName
= CGGeneric(descriptor
.nativeType
)
12508 if not type.unroll().inner
.isExternal():
12509 typeName
= CGWrapper(typeName
, post
="&")
12510 elif descriptor
.interface
.identifier
.name
== "WindowProxy":
12511 typeName
= CGGeneric("WindowProxyHolder const&")
12513 # Allow null pointers for old-binding classes.
12514 typeName
= CGWrapper(typeName
, post
="*")
12517 if type.isSpiderMonkeyInterface():
12518 typeName
= CGGeneric(type.name
)
12519 return CGWrapper(typeName
, post
=" const &")
12521 if type.isJSString():
12522 raise TypeError("JSString not supported in unions")
12524 if type.isDOMString() or type.isUSVString():
12525 return CGGeneric("const nsAString&")
12527 if type.isUTF8String():
12528 return CGGeneric("const nsACString&")
12530 if type.isByteString():
12531 return CGGeneric("const nsCString&")
12534 return CGGeneric(type.inner
.identifier
.name
)
12536 if type.isCallback():
12537 return CGGeneric("%s&" % type.unroll().callback
.identifier
.name
)
12540 return CGGeneric("JS::Value")
12542 if type.isObject():
12543 return CGGeneric("JSObject*")
12545 if type.isDictionary():
12546 return CGGeneric("const %s&" % type.inner
.identifier
.name
)
12548 if not type.isPrimitive():
12549 raise TypeError("Need native type for argument type '%s'" % str(type))
12551 return CGGeneric(builtinNames
[type.tag()])
12554 def getUnionTypeTemplateVars(unionType
, type, descriptorProvider
, isMember
=False):
12555 assert not type.isUndefined()
12556 assert not isMember
or isMember
in ("Union", "OwningUnion")
12558 ownsMembers
= isMember
== "OwningUnion"
12559 name
= getUnionMemberName(type)
12560 holderName
= "m" + name
+ "Holder"
12562 # By the time tryNextCode is invoked, we're guaranteed the union has been
12563 # constructed as some type, since we've been trying to convert into the
12564 # corresponding member.
12565 tryNextCode
= fill(
12574 sourceDescription
= "%s branch of %s" % (type.prettyName(), unionType
.prettyName())
12576 conversionInfo
= getJSToNativeConversionInfo(
12578 descriptorProvider
,
12579 failureCode
=tryNextCode
,
12580 isDefinitelyObject
=not type.isDictionary(),
12582 sourceDescription
=sourceDescription
,
12585 ctorNeedsCx
= conversionInfo
.declArgs
== "cx"
12586 ctorArgs
= "cx" if ctorNeedsCx
else ""
12588 structType
= conversionInfo
.declType
.define()
12589 externalType
= getUnionAccessorSignatureType(type, descriptorProvider
).define()
12591 if type.isObject():
12593 setValue
= "mValue.mObject.SetValue(obj);"
12595 setValue
= "mValue.mObject.SetValue(cx, obj);"
12599 MOZ_ASSERT(mType == eUninitialized);
12606 # It's a bit sketchy to do the security check after setting the value,
12607 # but it keeps the code cleaner and lets us avoid rooting |obj| over the
12608 # call to CallerSubsumes().
12609 body
= body
+ fill(
12611 if (passedToJSImpl && !CallerSubsumes(obj)) {
12612 cx.ThrowErrorMessage<MSG_PERMISSION_DENIED_TO_PASS_ARG>("${sourceDescription}");
12617 sourceDescription
=sourceDescription
,
12625 Argument("BindingCallContext&", "cx"),
12626 Argument("JSObject*", "obj"),
12627 Argument("bool", "passedToJSImpl", default
="false"),
12634 elif type.isDictionary() and not type.inner
.needsConversionFromJS
:
12635 # In this case we are never initialized from JS to start with
12638 # Important: we need to not have our declName involve
12639 # maybe-GCing operations.
12640 jsConversion
= fill(
12641 conversionInfo
.template
,
12643 maybeMutableVal
="value",
12644 declName
="memberSlot",
12645 holderName
=(holderName
if ownsMembers
else "%s.ref()" % holderName
),
12646 passedToJSImpl
="passedToJSImpl",
12649 jsConversion
= fill(
12652 { // scope for memberSlot
12653 ${structType}& memberSlot = RawSetAs${name}(${ctorArgs});
12658 structType
=structType
,
12661 jsConversion
=jsConversion
,
12664 needCallContext
= idlTypeNeedsCallContext(type)
12665 if needCallContext
:
12666 cxType
= "BindingCallContext&"
12668 cxType
= "JSContext*"
12674 Argument(cxType
, "cx"),
12675 Argument("JS::Handle<JS::Value>", "value"),
12676 Argument("bool&", "tryNext"),
12677 Argument("bool", "passedToJSImpl", default
="false"),
12679 visibility
="private",
12683 if needCallContext
:
12684 # Add a method for non-binding uses of unions to allow them to set
12685 # things in the union without providing a call context (though if
12686 # they want good error reporting they'll provide one anyway).
12689 BindingCallContext cx(cx_, nullptr);
12690 return TrySetTo${name}(cx, value, tryNext, passedToJSImpl);
12699 Argument("JSContext*", "cx_"),
12700 Argument("JS::Handle<JS::Value>", "value"),
12701 Argument("bool&", "tryNext"),
12702 Argument("bool", "passedToJSImpl", default
="false"),
12704 visibility
="private",
12711 "structType": structType
,
12712 "externalType": externalType
,
12713 "setters": setters
,
12714 "ctorArgs": ctorArgs
,
12715 "ctorArgList": [Argument("JSContext*", "cx")] if ctorNeedsCx
else [],
12719 def getUnionConversionTemplate(type):
12720 assert type.isUnion()
12721 assert not type.nullable()
12723 memberTypes
= type.flatMemberTypes
12726 interfaceMemberTypes
= [t
for t
in memberTypes
if t
.isNonCallbackInterface()]
12727 if len(interfaceMemberTypes
) > 0:
12728 interfaceObject
= []
12729 for memberType
in interfaceMemberTypes
:
12730 name
= getUnionMemberName(memberType
)
12731 interfaceObject
.append(
12733 "(failed = !TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext"
12737 prettyNames
.append(memberType
.prettyName())
12738 interfaceObject
= CGWrapper(
12739 CGList(interfaceObject
, " ||\n"),
12745 interfaceObject
= None
12747 sequenceObjectMemberTypes
= [t
for t
in memberTypes
if t
.isSequence()]
12748 if len(sequenceObjectMemberTypes
) > 0:
12749 assert len(sequenceObjectMemberTypes
) == 1
12750 memberType
= sequenceObjectMemberTypes
[0]
12751 name
= getUnionMemberName(memberType
)
12752 sequenceObject
= CGGeneric(
12753 "done = (failed = !TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n"
12756 prettyNames
.append(memberType
.prettyName())
12758 sequenceObject
= None
12760 callbackMemberTypes
= [
12761 t
for t
in memberTypes
if t
.isCallback() or t
.isCallbackInterface()
12763 if len(callbackMemberTypes
) > 0:
12764 assert len(callbackMemberTypes
) == 1
12765 memberType
= callbackMemberTypes
[0]
12766 name
= getUnionMemberName(memberType
)
12767 callbackObject
= CGGeneric(
12768 "done = (failed = !TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n"
12771 prettyNames
.append(memberType
.prettyName())
12773 callbackObject
= None
12775 dictionaryMemberTypes
= [t
for t
in memberTypes
if t
.isDictionary()]
12776 if len(dictionaryMemberTypes
) > 0:
12777 assert len(dictionaryMemberTypes
) == 1
12778 memberType
= dictionaryMemberTypes
[0]
12779 name
= getUnionMemberName(memberType
)
12780 setDictionary
= CGGeneric(
12781 "done = (failed = !TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n"
12784 prettyNames
.append(memberType
.prettyName())
12786 setDictionary
= None
12788 recordMemberTypes
= [t
for t
in memberTypes
if t
.isRecord()]
12789 if len(recordMemberTypes
) > 0:
12790 assert len(recordMemberTypes
) == 1
12791 memberType
= recordMemberTypes
[0]
12792 name
= getUnionMemberName(memberType
)
12793 recordObject
= CGGeneric(
12794 "done = (failed = !TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n"
12797 prettyNames
.append(memberType
.prettyName())
12799 recordObject
= None
12801 objectMemberTypes
= [t
for t
in memberTypes
if t
.isObject()]
12802 if len(objectMemberTypes
) > 0:
12803 assert len(objectMemberTypes
) == 1
12804 # Very important to NOT construct a temporary Rooted here, since the
12805 # SetToObject call can call a Rooted constructor and we need to keep
12806 # stack discipline for Rooted.
12807 object = CGGeneric(
12808 "if (!SetToObject(cx, &${val}.toObject(), ${passedToJSImpl})) {\n"
12813 prettyNames
.append(objectMemberTypes
[0].prettyName())
12818 interfaceObject
or sequenceObject
or callbackObject
or object or recordObject
12821 # "object" is not distinguishable from other types
12822 assert not object or not (
12823 interfaceObject
or sequenceObject
or callbackObject
or recordObject
12825 if sequenceObject
or callbackObject
:
12826 # An object can be both an sequence object and a callback or
12827 # dictionary, but we shouldn't have both in the union's members
12828 # because they are not distinguishable.
12829 assert not (sequenceObject
and callbackObject
)
12830 templateBody
= CGElseChain([sequenceObject
, callbackObject
])
12832 templateBody
= None
12833 if interfaceObject
:
12836 templateBody
= CGIfWrapper(templateBody
, "!done")
12837 templateBody
= CGList([interfaceObject
, templateBody
])
12839 templateBody
= CGList([templateBody
, object])
12842 templateBody
= CGList([templateBody
, CGIfWrapper(recordObject
, "!done")])
12844 templateBody
= CGIfWrapper(templateBody
, "${val}.isObject()")
12846 templateBody
= CGGeneric()
12850 templateBody
= CGList([templateBody
, CGIfWrapper(setDictionary
, "!done")])
12852 stringTypes
= [t
for t
in memberTypes
if t
.isString() or t
.isEnum()]
12853 numericTypes
= [t
for t
in memberTypes
if t
.isNumeric()]
12854 booleanTypes
= [t
for t
in memberTypes
if t
.isBoolean()]
12855 if stringTypes
or numericTypes
or booleanTypes
:
12856 assert len(stringTypes
) <= 1
12857 assert len(numericTypes
) <= 1
12858 assert len(booleanTypes
) <= 1
12860 # We will wrap all this stuff in a do { } while (0); so we
12861 # can use "break" for flow control.
12862 def getStringOrPrimitiveConversion(memberType
):
12863 name
= getUnionMemberName(memberType
)
12865 "done = (failed = !TrySetTo%s(cx, ${val}, tryNext)) || !tryNext;\n"
12870 stringConversion
= [getStringOrPrimitiveConversion(t
) for t
in stringTypes
]
12871 numericConversion
= [getStringOrPrimitiveConversion(t
) for t
in numericTypes
]
12872 booleanConversion
= [getStringOrPrimitiveConversion(t
) for t
in booleanTypes
]
12873 if stringConversion
:
12874 if booleanConversion
:
12875 other
.append(CGIfWrapper(booleanConversion
[0], "${val}.isBoolean()"))
12876 if numericConversion
:
12877 other
.append(CGIfWrapper(numericConversion
[0], "${val}.isNumber()"))
12878 other
.append(stringConversion
[0])
12879 elif numericConversion
:
12880 if booleanConversion
:
12881 other
.append(CGIfWrapper(booleanConversion
[0], "${val}.isBoolean()"))
12882 other
.append(numericConversion
[0])
12884 assert booleanConversion
12885 other
.append(booleanConversion
[0])
12887 other
= CGWrapper(CGIndenter(other
), pre
="do {\n", post
="} while (false);\n")
12888 if hasObjectTypes
or setDictionary
:
12889 other
= CGWrapper(CGIndenter(other
), "{\n", post
="}\n")
12891 templateBody
= CGElseChain([templateBody
, other
])
12893 other
= CGWrapper(other
, pre
="if (!done) ")
12894 templateBody
= CGList([templateBody
, other
])
12896 assert templateBody
.define() == ""
12897 templateBody
= other
12901 templateBody
= CGWrapper(
12902 templateBody
, pre
="bool done = false, failed = false, tryNext;\n"
12911 cx.ThrowErrorMessage<MSG_NOT_IN_UNION>(sourceDescription, "${names}");
12915 names
=", ".join(prettyNames
),
12919 templateBody
= CGList([templateBody
, throw
])
12921 hasUndefinedType
= any(t
.isUndefined() for t
in memberTypes
)
12924 # The spec does this before anything else, but we do it after checking
12925 # for null in the case of a nullable union. In practice this shouldn't
12926 # make a difference, but it makes things easier because we first need to
12927 # call Construct on our Maybe<...>, before we can set the union type to
12928 # undefined, and we do that below after checking for null (see the
12929 # 'if nullable:' block below).
12930 if hasUndefinedType
:
12933 CGGeneric("SetUndefined();\n"),
12934 "${val}.isUndefined()",
12938 if type.hasNullableType
:
12940 "${val}.isNull()" if hasUndefinedType
else "${val}.isNullOrUndefined()"
12944 CGGeneric("SetNull();\n"),
12949 if len(elseChain
) > 0:
12950 elseChain
.append(CGWrapper(CGIndenter(templateBody
), pre
="{\n", post
="}\n"))
12951 templateBody
= CGElseChain(elseChain
)
12953 return templateBody
12956 def getUnionInitMethods(type, isOwningUnion
=False):
12957 assert type.isUnion()
12959 template
= getUnionConversionTemplate(type).define()
12963 "passedToJSImpl": "passedToJSImpl",
12968 MOZ_ASSERT(mType == eUninitialized);
12973 conversion
=string
.Template(template
).substitute(replacements
),
12981 Argument("BindingCallContext&", "cx"),
12982 Argument("JS::Handle<JS::Value>", "value"),
12983 Argument("const char*", "sourceDescription", default
='"Value"'),
12984 Argument("bool", "passedToJSImpl", default
="false"),
12986 visibility
="public",
12993 Argument("JSContext*", "cx_"),
12994 Argument("JS::Handle<JS::Value>", "value"),
12995 Argument("const char*", "sourceDescription", default
='"Value"'),
12996 Argument("bool", "passedToJSImpl", default
="false"),
12998 visibility
="public",
13001 BindingCallContext cx(cx_, nullptr);
13002 return Init(cx, value, sourceDescription, passedToJSImpl);
13009 class CGUnionStruct(CGThing
):
13010 def __init__(self
, type, descriptorProvider
, ownsMembers
=False):
13011 CGThing
.__init
__(self
)
13012 self
.type = type.unroll()
13013 self
.descriptorProvider
= descriptorProvider
13014 self
.ownsMembers
= ownsMembers
13015 self
.struct
= self
.getStruct()
13018 return self
.struct
.declare()
13021 return self
.struct
.define()
13024 return self
.type.getDeps()
13026 def getStruct(self
):
13028 ClassMember("mType", "TypeOrUninit", body
="eUninitialized"),
13029 ClassMember("mValue", "Value"),
13031 ctor
= ClassConstructor(
13032 [], bodyInHeader
=True, visibility
="public", explicit
=True
13036 enumValues
= ["eUninitialized"]
13039 "eUninitialized", CGGeneric("return false;\n"), CGCase
.DONT_ADD_BREAK
13042 destructorCases
= [CGCase("eUninitialized", None)]
13043 assignmentCase
= CGCase(
13046 "MOZ_ASSERT(mType == eUninitialized,\n"
13047 ' "We need to destroy ourselves?");\n'
13050 assignmentCases
= [assignmentCase
]
13051 moveCases
= [assignmentCase
]
13055 def addSpecialType(typename
):
13056 enumValue
= "e" + typename
13057 enumValues
.append(enumValue
)
13065 body
="return mType == %s;\n" % enumValue
,
13078 mType = ${enumValue};
13080 enumValue
=enumValue
,
13085 destructorCases
.append(CGCase(enumValue
, None))
13086 assignmentCase
= CGCase(
13091 MOZ_ASSERT(mType == eUninitialized);
13092 mType = ${enumValue};
13094 enumValue
=enumValue
,
13098 assignmentCases
.append(assignmentCase
)
13099 moveCases
.append(assignmentCase
)
13100 toJSValCases
.append(
13106 rval.set${typename}();
13112 CGCase
.DONT_ADD_BREAK
,
13116 if self
.type.hasNullableType
:
13117 addSpecialType("Null")
13119 hasObjectType
= any(t
.isObject() for t
in self
.type.flatMemberTypes
)
13120 skipToJSVal
= False
13121 for t
in self
.type.flatMemberTypes
:
13122 if t
.isUndefined():
13123 addSpecialType("Undefined")
13126 vars = getUnionTypeTemplateVars(
13129 self
.descriptorProvider
,
13130 isMember
="OwningUnion" if self
.ownsMembers
else "Union",
13132 if vars["setters"]:
13133 methods
.extend(vars["setters"])
13134 uninit
= "Uninit();"
13135 if hasObjectType
and not self
.ownsMembers
:
13137 'MOZ_ASSERT(mType != eObject, "This will not play well with Rooted");\n'
13140 if not t
.isObject() or self
.ownsMembers
:
13143 if (mType == e${name}) {
13144 return mValue.m${name}.Value();
13148 return mValue.m${name}.SetValue(${ctorArgs});
13153 # bodyInHeader must be false for return values because they own
13154 # their union members and we don't want include headers in
13155 # UnionTypes.h just to call Addref/Release
13158 "RawSetAs" + vars["name"],
13159 vars["structType"] + "&",
13160 vars["ctorArgList"],
13161 bodyInHeader
=not self
.ownsMembers
,
13162 body
=body
% "MOZ_ASSERT(mType == eUninitialized);",
13168 "SetAs" + vars["name"],
13169 vars["structType"] + "&",
13170 vars["ctorArgList"],
13171 bodyInHeader
=not self
.ownsMembers
,
13172 body
=body
% uninit
,
13177 # Provide a SetStringLiteral() method to support string defaults.
13178 if t
.isByteString() or t
.isUTF8String():
13179 charType
= "const nsCString::char_type"
13181 charType
= "const nsString::char_type"
13188 "SetStringLiteral",
13190 # Hack, but it works...
13191 [Argument(charType
, "(&aData)[N]")],
13194 templateArgs
=["int N"],
13195 body
="RawSetAs%s().AssignLiteral(aData);\n" % t
.name
,
13199 body
= fill("return mType == e${name};\n", **vars)
13202 "Is" + vars["name"],
13213 MOZ_RELEASE_ASSERT(Is${name}(), "Wrong type!");
13214 mValue.m${name}.Destroy();
13215 mType = eUninitialized;
13221 "Destroy" + vars["name"],
13224 visibility
="private",
13225 bodyInHeader
=not self
.ownsMembers
,
13232 MOZ_RELEASE_ASSERT(Is${name}(), "Wrong type!");
13233 return mValue.m${name}.Value();
13237 # The non-const version of GetAs* returns our internal type
13238 getterReturnType
= "%s&" % vars["structType"]
13241 "GetAs" + vars["name"],
13248 # The const version of GetAs* returns our internal type
13249 # for owning unions, but our external type for non-owning
13251 if self
.ownsMembers
:
13252 getterReturnType
= "%s const &" % vars["structType"]
13254 getterReturnType
= vars["externalType"]
13257 "GetAs" + vars["name"],
13266 unionValues
.append(fill("UnionMember<${structType} > m${name}", **vars))
13267 destructorCases
.append(
13268 CGCase("e" + vars["name"], CGGeneric("Destroy%s();\n" % vars["name"]))
13271 enumValues
.append("e" + vars["name"])
13273 conversionToJS
= self
.getConversionToJS(vars, t
)
13275 toJSValCases
.append(
13276 CGCase("e" + vars["name"], conversionToJS
, CGCase
.DONT_ADD_BREAK
)
13281 assignmentCases
.append(
13283 "e" + vars["name"],
13285 "SetAs%s() = aOther.GetAs%s();\n" % (vars["name"], vars["name"])
13291 "e" + vars["name"],
13293 "mType = e%s;\n" % vars["name"]
13294 + "mValue.m%s.SetValue(std::move(aOther.mValue.m%s.Value()));\n"
13295 % (vars["name"], vars["name"])
13299 if self
.ownsMembers
and typeNeedsRooting(t
):
13303 "e" + vars["name"],
13305 'JS::TraceRoot(trc, %s, "%s");\n'
13307 "&mValue.m" + vars["name"] + ".Value()",
13308 "mValue.m" + vars["name"],
13313 elif t
.isDictionary():
13316 "e" + vars["name"],
13318 "mValue.m%s.Value().TraceDictionary(trc);\n"
13323 elif t
.isSequence():
13326 "e" + vars["name"],
13328 "DoTraceSequence(trc, mValue.m%s.Value());\n"
13336 "e" + vars["name"],
13338 "TraceRecord(trc, mValue.m%s.Value());\n" % vars["name"]
13343 assert t
.isSpiderMonkeyInterface()
13346 "e" + vars["name"],
13348 "mValue.m%s.Value().TraceSelf(trc);\n" % vars["name"]
13353 dtor
= CGSwitch("mType", destructorCases
).define()
13355 methods
.extend(getUnionInitMethods(self
.type, isOwningUnion
=self
.ownsMembers
))
13361 visibility
="public",
13363 bodyInHeader
=not self
.ownsMembers
,
13364 inline
=not self
.ownsMembers
,
13368 if not skipToJSVal
:
13374 Argument("JSContext*", "cx"),
13375 Argument("JS::Handle<JSObject*>", "scopeObj"),
13376 Argument("JS::MutableHandle<JS::Value>", "rval"),
13379 "mType", toJSValCases
, default
=CGGeneric("return false;\n")
13385 constructors
= [ctor
]
13386 selfName
= CGUnionStruct
.unionTypeName(self
.type, self
.ownsMembers
)
13387 if self
.ownsMembers
:
13389 traceBody
= CGSwitch(
13390 "mType", traceCases
, default
=CGGeneric("")
13396 [Argument("JSTracer*", "trc")],
13401 op_body
= CGList([])
13402 op_body
.append(CGSwitch("aOther.mType", moveCases
))
13403 constructors
.append(
13405 [Argument("%s&&" % selfName
, "aOther")],
13406 visibility
="public",
13407 body
=op_body
.define(),
13415 [Argument("%s&&" % selfName
, "aOther")],
13416 body
="this->~%s();\nnew (this) %s (std::move(aOther));\nreturn *this;\n"
13417 % (selfName
, selfName
),
13423 MOZ_RELEASE_ASSERT(mType != eUninitialized);
13424 return static_cast<Type>(mType);
13438 if CGUnionStruct
.isUnionCopyConstructible(self
.type):
13439 constructors
.append(
13441 [Argument("const %s&" % selfName
, "aOther")],
13443 visibility
="public",
13445 body
="*this = aOther;\n",
13448 op_body
= CGList([])
13449 op_body
.append(CGSwitch("aOther.mType", assignmentCases
))
13450 op_body
.append(CGGeneric("return *this;\n"))
13455 [Argument("const %s&" % selfName
, "aOther")],
13456 body
=op_body
.define(),
13459 disallowCopyConstruction
= False
13461 disallowCopyConstruction
= True
13463 disallowCopyConstruction
= True
13465 if self
.ownsMembers
and idlTypeNeedsCycleCollection(self
.type):
13467 " friend void ImplCycleCollectionUnlink(%s& aUnion);\n"
13468 % CGUnionStruct
.unionTypeName(self
.type, True)
13473 enumValuesNoUninit
= [x
for x
in enumValues
if x
!= "eUninitialized"]
13478 ClassEnum("TypeOrUninit", enumValues
, visibility
="private"),
13481 enumValuesNoUninit
,
13482 visibility
="public",
13484 values
=["TypeOrUninit::" + x
for x
in enumValuesNoUninit
],
13491 ClassBase("AllOwningUnionBase" if self
.ownsMembers
else "AllUnionBase")
13495 bufferSourceTypes
= [
13496 t
.name
for t
in self
.type.flatMemberTypes
if t
.isBufferSource()
13498 if len(bufferSourceTypes
) > 0:
13499 bases
.append(ClassBase("UnionWithTypedArraysBase"))
13500 memberTypesCount
= len(self
.type.flatMemberTypes
)
13501 if self
.type.hasNullableType
:
13502 memberTypesCount
+= 1
13505 ClassUsingDeclaration(
13506 "ApplyToTypedArrays",
13507 "binding_detail::ApplyToTypedArraysHelper<%s, %s, %s>"
13510 toStringBool(memberTypesCount
> len(bufferSourceTypes
)),
13511 ", ".join(bufferSourceTypes
),
13519 typeAliases
=typeAliases
,
13521 constructors
=constructors
,
13523 disallowCopyConstruction
=disallowCopyConstruction
,
13524 extradeclarations
=friend
,
13525 destructor
=ClassDestructor(
13526 visibility
="public", body
="Uninit();\n", bodyInHeader
=True
13529 unions
=[ClassUnion("Value", unionValues
, visibility
="private")],
13532 def getConversionToJS(self
, templateVars
, type):
13533 if type.isDictionary() and not type.inner
.needsConversionToJS
:
13534 # We won't be able to convert this dictionary to a JS value, nor
13535 # will we need to, since we don't need a ToJSVal method at all.
13538 assert not type.nullable() # flatMemberTypes never has nullable types
13539 val
= "mValue.m%(name)s.Value()" % templateVars
13540 wrapCode
= wrapForType(
13542 self
.descriptorProvider
,
13544 "jsvalRef": "rval",
13545 "jsvalHandle": "rval",
13548 "spiderMonkeyInterfacesAreStructs": True,
13551 return CGGeneric(wrapCode
)
13554 def isUnionCopyConstructible(type):
13555 return all(isTypeCopyConstructible(t
) for t
in type.flatMemberTypes
)
13558 def unionTypeName(type, ownsMembers
):
13560 Returns a string name for this known union type.
13562 assert type.isUnion() and not type.nullable()
13563 return ("Owning" if ownsMembers
else "") + type.name
13566 def unionTypeDecl(type, ownsMembers
):
13568 Returns a string for declaring this possibly-nullable union type.
13570 assert type.isUnion()
13571 nullable
= type.nullable()
13574 decl
= CGGeneric(CGUnionStruct
.unionTypeName(type, ownsMembers
))
13576 decl
= CGTemplatedType("Nullable", decl
)
13577 return decl
.define()
13581 """Use with CGClass"""
13583 def __init__(self
, name
, visibility
):
13585 self
.visibility
= visibility
13587 def declare(self
, cgClass
):
13590 def define(self
, cgClass
):
13594 class ClassBase(ClassItem
):
13595 def __init__(self
, name
, visibility
="public"):
13596 ClassItem
.__init
__(self
, name
, visibility
)
13598 def declare(self
, cgClass
):
13599 return "%s %s" % (self
.visibility
, self
.name
)
13601 def define(self
, cgClass
):
13602 # Only in the header
13606 class ClassMethod(ClassItem
):
13616 bodyInHeader
=False,
13618 visibility
="public",
13620 breakAfterReturnDecl
="\n",
13621 breakAfterSelf
="\n",
13623 canRunScript
=False,
13627 override indicates whether to flag the method as override
13629 assert not override
or virtual
13630 assert not (override
and static
)
13631 self
.returnType
= returnType
13633 self
.inline
= inline
or bodyInHeader
13634 self
.static
= static
13635 self
.virtual
= virtual
13637 self
.bodyInHeader
= bodyInHeader
13638 self
.templateArgs
= templateArgs
13640 self
.breakAfterReturnDecl
= breakAfterReturnDecl
13641 self
.breakAfterSelf
= breakAfterSelf
13642 self
.override
= override
13643 self
.canRunScript
= canRunScript
13644 self
.noDiscard
= noDiscard
13645 ClassItem
.__init
__(self
, name
, visibility
)
13647 def getDecorators(self
, declaring
):
13650 decorators
.append("[[nodiscard]]")
13651 if self
.canRunScript
:
13652 decorators
.append("MOZ_CAN_RUN_SCRIPT")
13654 decorators
.append("inline")
13657 decorators
.append("static")
13658 if self
.virtual
and not self
.override
:
13659 decorators
.append("virtual")
13661 return " ".join(decorators
) + " "
13665 # Override me or pass a string to constructor
13666 assert self
.body
is not None
13669 def declare(self
, cgClass
):
13671 "template <%s>\n" % ", ".join(self
.templateArgs
)
13672 if self
.bodyInHeader
and self
.templateArgs
13675 args
= ", ".join([a
.declare() for a
in self
.args
])
13676 if self
.bodyInHeader
:
13677 body
= indent(self
.getBody())
13678 body
= "\n{\n" + body
+ "}\n"
13683 "${templateClause}${decorators}${returnType}${breakAfterReturnDecl}"
13684 "${name}(${args})${const}${override}${body}"
13685 "${breakAfterSelf}",
13686 templateClause
=templateClause
,
13687 decorators
=self
.getDecorators(True),
13688 returnType
=self
.returnType
,
13689 breakAfterReturnDecl
=self
.breakAfterReturnDecl
,
13692 const
=" const" if self
.const
else "",
13693 override
=" override" if self
.override
else "",
13695 breakAfterSelf
=self
.breakAfterSelf
,
13698 def define(self
, cgClass
):
13699 if self
.bodyInHeader
:
13702 templateArgs
= cgClass
.templateArgs
13704 if cgClass
.templateSpecialization
:
13705 templateArgs
= templateArgs
[len(cgClass
.templateSpecialization
) :]
13708 templateClause
= "template <%s>\n" % ", ".join(
13709 [str(a
) for a
in templateArgs
]
13712 templateClause
= ""
13716 ${templateClause}${decorators}${returnType}
13717 ${className}::${name}(${args})${const}
13722 templateClause
=templateClause
,
13723 decorators
=self
.getDecorators(False),
13724 returnType
=self
.returnType
,
13725 className
=cgClass
.getNameString(),
13727 args
=", ".join([a
.define() for a
in self
.args
]),
13728 const
=" const" if self
.const
else "",
13729 body
=self
.getBody(),
13733 class ClassUsingDeclaration(ClassItem
):
13735 Used for declaring an alias for a type in a CGClass
13737 name is the name of the alias
13739 type is the type to declare an alias of
13741 visibility determines the visibility of the alias (public,
13742 protected, private), defaults to public.
13745 def __init__(self
, name
, type, visibility
="public"):
13747 ClassItem
.__init
__(self
, name
, visibility
)
13749 def declare(self
, cgClass
):
13750 return "using %s = %s;\n\n" % (self
.name
, self
.type)
13752 def define(self
, cgClass
):
13756 class ClassUsingFromBaseDeclaration(ClassItem
):
13758 Used for importing a name from a base class into a CGClass
13760 baseClass is the name of the base class to import the name from
13762 name is the name to import
13764 visibility determines the visibility of the name (public,
13765 protected, private), defaults to public.
13768 def __init__(self
, baseClass
, name
, visibility
="public"):
13769 self
.baseClass
= baseClass
13770 ClassItem
.__init
__(self
, name
, visibility
)
13772 def declare(self
, cgClass
):
13773 return "using %s::%s;\n\n" % (self
.baseClass
, self
.name
)
13775 def define(self
, cgClass
):
13779 class ClassConstructor(ClassItem
):
13781 Used for adding a constructor to a CGClass.
13783 args is a list of Argument objects that are the arguments taken by the
13786 inline should be True if the constructor should be marked inline.
13788 bodyInHeader should be True if the body should be placed in the class
13789 declaration in the header.
13791 default should be True if the definition of the constructor should be
13794 visibility determines the visibility of the constructor (public,
13795 protected, private), defaults to private.
13797 explicit should be True if the constructor should be marked explicit.
13799 baseConstructors is a list of strings containing calls to base constructors,
13802 body contains a string with the code for the constructor, defaults to empty.
13809 bodyInHeader
=False,
13811 visibility
="private",
13814 baseConstructors
=None,
13817 assert not (inline
and constexpr
)
13818 assert not (bodyInHeader
and constexpr
)
13819 assert not (default
and body
)
13821 self
.inline
= inline
or bodyInHeader
13822 self
.bodyInHeader
= bodyInHeader
or constexpr
or default
13823 self
.default
= default
13824 self
.explicit
= explicit
13825 self
.constexpr
= constexpr
13826 self
.baseConstructors
= baseConstructors
or []
13828 ClassItem
.__init
__(self
, None, visibility
)
13830 def getDecorators(self
, declaring
):
13834 decorators
.append("explicit")
13836 decorators
.append("inline")
13838 decorators
.append("constexpr")
13840 return " ".join(decorators
) + " "
13843 def getInitializationList(self
, cgClass
):
13844 items
= [str(c
) for c
in self
.baseConstructors
]
13845 for m
in cgClass
.members
:
13847 initialize
= m
.body
13849 items
.append(m
.name
+ "(" + initialize
+ ")")
13852 return "\n : " + ",\n ".join(items
)
13858 def declare(self
, cgClass
):
13859 args
= ", ".join([a
.declare() for a
in self
.args
])
13860 if self
.bodyInHeader
:
13862 body
= " = default;\n"
13865 self
.getInitializationList(cgClass
)
13867 + indent(self
.getBody())
13874 "${decorators}${className}(${args})${body}\n",
13875 decorators
=self
.getDecorators(True),
13876 className
=cgClass
.getNameString(),
13881 def define(self
, cgClass
):
13882 if self
.bodyInHeader
:
13888 ${className}::${className}(${args})${initializationList}
13893 decorators
=self
.getDecorators(False),
13894 className
=cgClass
.getNameString(),
13895 args
=", ".join([a
.define() for a
in self
.args
]),
13896 initializationList
=self
.getInitializationList(cgClass
),
13897 body
=self
.getBody(),
13901 class ClassDestructor(ClassItem
):
13903 Used for adding a destructor to a CGClass.
13905 inline should be True if the destructor should be marked inline.
13907 bodyInHeader should be True if the body should be placed in the class
13908 declaration in the header.
13910 visibility determines the visibility of the destructor (public,
13911 protected, private), defaults to private.
13913 body contains a string with the code for the destructor, defaults to empty.
13915 virtual determines whether the destructor is virtual, defaults to False.
13921 bodyInHeader
=False,
13922 visibility
="private",
13926 self
.inline
= inline
or bodyInHeader
13927 self
.bodyInHeader
= bodyInHeader
13929 self
.virtual
= virtual
13930 ClassItem
.__init
__(self
, None, visibility
)
13932 def getDecorators(self
, declaring
):
13934 if self
.virtual
and declaring
:
13935 decorators
.append("virtual")
13936 if self
.inline
and declaring
:
13937 decorators
.append("inline")
13939 return " ".join(decorators
) + " "
13945 def declare(self
, cgClass
):
13946 if self
.bodyInHeader
:
13947 body
= "\n{\n" + indent(self
.getBody()) + "}\n"
13952 "${decorators}~${className}()${body}\n",
13953 decorators
=self
.getDecorators(True),
13954 className
=cgClass
.getNameString(),
13958 def define(self
, cgClass
):
13959 if self
.bodyInHeader
:
13964 ${className}::~${className}()
13969 decorators
=self
.getDecorators(False),
13970 className
=cgClass
.getNameString(),
13971 body
=self
.getBody(),
13975 class ClassMember(ClassItem
):
13980 visibility
="private",
13983 hasIgnoreInitCheckFlag
=False,
13986 self
.static
= static
13988 self
.hasIgnoreInitCheckFlag
= hasIgnoreInitCheckFlag
13989 ClassItem
.__init
__(self
, name
, visibility
)
13991 def declare(self
, cgClass
):
13992 return "%s%s%s %s;\n" % (
13993 "static " if self
.static
else "",
13994 "MOZ_INIT_OUTSIDE_CTOR " if self
.hasIgnoreInitCheckFlag
else "",
13999 def define(self
, cgClass
):
14000 if not self
.static
:
14003 body
= " = " + self
.body
14006 return "%s %s::%s%s;\n" % (self
.type, cgClass
.getNameString(), self
.name
, body
)
14009 class ClassEnum(ClassItem
):
14011 self
, name
, entries
, values
=None, visibility
="public", enumClass
=False
14013 self
.entries
= entries
14014 self
.values
= values
14015 self
.enumClass
= enumClass
14016 ClassItem
.__init
__(self
, name
, visibility
)
14018 def declare(self
, cgClass
):
14020 for i
in range(0, len(self
.entries
)):
14021 if not self
.values
or i
>= len(self
.values
):
14022 entry
= "%s" % self
.entries
[i
]
14024 entry
= "%s = %s" % (self
.entries
[i
], self
.values
[i
])
14025 entries
.append(entry
)
14028 self
.enumClass
and decl
.append("class")
14029 self
.name
and decl
.append(self
.name
)
14030 decl
= " ".join(decl
)
14032 return "%s\n{\n%s\n};\n" % (decl
, indent(",\n".join(entries
)))
14034 def define(self
, cgClass
):
14035 # Only goes in the header
14039 class ClassUnion(ClassItem
):
14040 def __init__(self
, name
, entries
, visibility
="public"):
14041 self
.entries
= [entry
+ ";\n" for entry
in entries
]
14042 ClassItem
.__init
__(self
, name
, visibility
)
14044 def declare(self
, cgClass
):
14045 return "union %s\n{\n%s\n};\n" % (self
.name
, indent("".join(self
.entries
)))
14047 def define(self
, cgClass
):
14048 # Only goes in the header
14052 class ClassGroup(ClassItem
):
14053 def __init__(self
, items
):
14055 ClassItem
.__init
__(self
, "", items
[0].visibility
)
14057 def declare(self
, cgClass
):
14060 def define(self
, cgClass
):
14064 class CGClass(CGThing
):
14077 templateSpecialization
=[],
14079 disallowCopyConstruction
=False,
14082 extradeclarations
="",
14083 extradefinitions
="",
14085 CGThing
.__init
__(self
)
14088 self
.typeAliases
= typeAliases
14089 self
.members
= members
14090 self
.constructors
= constructors
14091 # We store our single destructor in a list, since all of our
14092 # code wants lists of members.
14093 self
.destructors
= [destructor
] if destructor
else []
14094 self
.methods
= methods
14096 self
.unions
= unions
14097 self
.templateArgs
= templateArgs
14098 self
.templateSpecialization
= templateSpecialization
14099 self
.isStruct
= isStruct
14100 self
.disallowCopyConstruction
= disallowCopyConstruction
14101 self
.indent
= indent
14102 self
.defaultVisibility
= "public" if isStruct
else "private"
14103 self
.decorators
= decorators
14104 self
.extradeclarations
= extradeclarations
14105 self
.extradefinitions
= extradefinitions
14107 def getNameString(self
):
14108 className
= self
.name
14109 if self
.templateSpecialization
:
14110 className
+= "<%s>" % ", ".join(
14111 [str(a
) for a
in self
.templateSpecialization
]
14116 def flattenClassItemLists(l
):
14118 if isinstance(item
, ClassGroup
):
14119 for inner
in CGClass
.flattenClassItemLists(item
.items
):
14126 if self
.templateArgs
:
14127 templateArgs
= [a
.declare() for a
in self
.templateArgs
]
14128 templateArgs
= templateArgs
[len(self
.templateSpecialization
) :]
14129 result
+= "template <%s>\n" % ",".join([str(a
) for a
in templateArgs
])
14131 type = "struct" if self
.isStruct
else "class"
14133 if self
.templateSpecialization
:
14134 specialization
= "<%s>" % ", ".join(
14135 [str(a
) for a
in self
.templateSpecialization
]
14138 specialization
= ""
14140 myself
= "%s %s%s" % (type, self
.name
, specialization
)
14141 if self
.decorators
!= "":
14142 myself
+= " " + self
.decorators
14148 # Grab our first base
14149 baseItems
= [CGGeneric(b
.declare(self
)) for b
in self
.bases
]
14150 bases
= baseItems
[:1]
14153 CGIndenter(b
, len(myself
) + len(inherit
)) for b
in baseItems
[1:]
14155 result
+= ",\n".join(b
.define() for b
in bases
)
14159 result
+= self
.extradeclarations
14161 def declareMembers(cgClass
, memberList
, defaultVisibility
):
14162 members
= {"private": [], "protected": [], "public": []}
14164 for member
in memberList
:
14165 members
[member
.visibility
].append(member
)
14167 if defaultVisibility
== "public":
14168 order
= ["public", "protected", "private"]
14170 order
= ["private", "protected", "public"]
14174 lastVisibility
= defaultVisibility
14175 for visibility
in order
:
14176 list = members
[visibility
]
14178 for member
in self
.flattenClassItemLists(list):
14179 if member
.visibility
!= lastVisibility
:
14180 result
+= member
.visibility
+ ":\n"
14181 result
+= indent(member
.declare(cgClass
))
14182 lastVisibility
= member
.visibility
14183 return (result
, lastVisibility
)
14185 if self
.disallowCopyConstruction
:
14187 class DisallowedCopyConstructor(object):
14188 def __init__(self
):
14189 self
.visibility
= "private"
14191 def declare(self
, cgClass
):
14192 name
= cgClass
.getNameString()
14194 "%s(const %s&) = delete;\n"
14195 "%s& operator=(const %s&) = delete;\n"
14196 % (name
, name
, name
, name
)
14199 disallowedCopyConstructors
= [DisallowedCopyConstructor()]
14201 disallowedCopyConstructors
= []
14208 self
.constructors
+ disallowedCopyConstructors
,
14213 lastVisibility
= self
.defaultVisibility
14215 for memberList
in order
:
14216 code
, lastVisibility
= declareMembers(self
, memberList
, lastVisibility
)
14219 code
= code
.rstrip() + "\n" # remove extra blank lines at the end
14220 pieces
.append(code
)
14222 result
+= "\n".join(pieces
)
14224 result
= indent(result
, len(self
.indent
))
14228 def defineMembers(cgClass
, memberList
, itemCount
, separator
=""):
14230 for member
in self
.flattenClassItemLists(memberList
):
14232 result
= result
+ separator
14233 definition
= member
.define(cgClass
)
14235 # Member variables would only produce empty lines here.
14236 result
+= definition
14238 return (result
, itemCount
)
14241 (self
.members
, ""),
14242 (self
.constructors
, "\n"),
14243 (self
.destructors
, "\n"),
14244 (self
.methods
, "\n"),
14247 result
= self
.extradefinitions
14249 for memberList
, separator
in order
:
14250 memberString
, itemCount
= defineMembers(
14251 self
, memberList
, itemCount
, separator
14253 result
= result
+ memberString
14257 class CGResolveOwnPropertyViaResolve(CGAbstractBindingMethod
):
14259 An implementation of Xray ResolveOwnProperty stuff for things that have a
14263 def __init__(self
, descriptor
):
14265 Argument("JSContext*", "cx"),
14266 Argument("JS::Handle<JSObject*>", "wrapper"),
14267 Argument("JS::Handle<JSObject*>", "obj"),
14268 Argument("JS::Handle<jsid>", "id"),
14269 Argument("JS::MutableHandle<Maybe<JS::PropertyDescriptor>>", "desc"),
14271 CGAbstractBindingMethod
.__init
__(
14274 "ResolveOwnPropertyViaResolve",
14280 def generate_code(self
):
14285 // Since we're dealing with an Xray, do the resolve on the
14286 // underlying object first. That gives it a chance to
14287 // define properties on the actual object as needed, and
14288 // then use the fact that it created the objects as a flag
14289 // to avoid re-resolving the properties if someone deletes
14291 JSAutoRealm ar(cx, obj);
14292 JS_MarkCrossZoneId(cx, id);
14293 JS::Rooted<mozilla::Maybe<JS::PropertyDescriptor>> objDesc(cx);
14294 if (!self->DoResolve(cx, obj, id, &objDesc)) {
14297 // If desc->value() is undefined, then the DoResolve call
14298 // has already defined the property on the object. Don't
14299 // try to also define it.
14300 if (objDesc.isSome() &&
14301 !objDesc->value().isUndefined()) {
14302 JS::Rooted<JS::PropertyDescriptor> defineDesc(cx, *objDesc);
14303 if (!JS_DefinePropertyById(cx, obj, id, defineDesc)) {
14308 return self->DoResolve(cx, wrapper, id, desc);
14314 class CGEnumerateOwnPropertiesViaGetOwnPropertyNames(CGAbstractBindingMethod
):
14316 An implementation of Xray EnumerateOwnProperties stuff for things
14317 that have a resolve hook.
14320 def __init__(self
, descriptor
):
14322 Argument("JSContext*", "cx"),
14323 Argument("JS::Handle<JSObject*>", "wrapper"),
14324 Argument("JS::Handle<JSObject*>", "obj"),
14325 Argument("JS::MutableHandleVector<jsid>", "props"),
14327 CGAbstractBindingMethod
.__init
__(
14330 "EnumerateOwnPropertiesViaGetOwnPropertyNames",
14336 def generate_code(self
):
14340 FastErrorResult rv;
14341 // This wants all own props, not just enumerable ones.
14342 self->GetOwnPropertyNames(cx, props, false, rv);
14343 if (rv.MaybeSetPendingException(cx)) {
14352 class CGPrototypeTraitsClass(CGClass
):
14353 def __init__(self
, descriptor
, indent
=""):
14354 templateArgs
= [Argument("prototypes::ID", "PrototypeID")]
14355 templateSpecialization
= ["prototypes::id::" + descriptor
.name
]
14356 enums
= [ClassEnum("", ["Depth"], [descriptor
.interface
.inheritanceDepth()])]
14361 templateArgs
=templateArgs
,
14362 templateSpecialization
=templateSpecialization
,
14371 class CGClassForwardDeclare(CGThing
):
14372 def __init__(self
, name
, isStruct
=False):
14373 CGThing
.__init
__(self
)
14375 self
.isStruct
= isStruct
14378 type = "struct" if self
.isStruct
else "class"
14379 return "%s %s;\n" % (type, self
.name
)
14389 class CGProxySpecialOperation(CGPerSignatureCall
):
14391 Base class for classes for calling an indexed or named special operation
14392 (don't use this directly, use the derived classes below).
14394 If checkFound is False, will just assert that the prop is found instead of
14395 checking that it is before wrapping the value.
14397 resultVar: See the docstring for CGCallGenerator.
14399 foundVar: For getters and deleters, the generated code can also set a bool
14400 variable, declared by the caller, if the given indexed or named property
14401 already existed. If the caller wants this, it should pass the name of the
14402 bool variable as the foundVar keyword argument to the constructor. The
14403 caller is responsible for declaring the variable and initializing it to
14412 argumentHandleValue
=None,
14416 self
.checkFound
= checkFound
14417 self
.foundVar
= foundVar
or "found"
14419 nativeName
= MakeNativeName(descriptor
.binaryNameFor(operation
, False))
14420 operation
= descriptor
.operations
[operation
]
14421 assert len(operation
.signatures()) == 1
14422 signature
= operation
.signatures()[0]
14424 returnType
, arguments
= signature
14426 # We pass len(arguments) as the final argument so that the
14427 # CGPerSignatureCall won't do any argument conversion of its own.
14428 CGPerSignatureCall
.__init
__(
14437 resultVar
=resultVar
,
14438 objectName
="proxy",
14441 if operation
.isSetter():
14442 # arguments[0] is the index or name of the item that we're setting.
14443 argument
= arguments
[1]
14444 info
= getJSToNativeConversionInfo(
14447 sourceDescription
=(
14448 "value being assigned to %s setter"
14449 % descriptor
.interface
.identifier
.name
14452 if argumentHandleValue
is None:
14453 argumentHandleValue
= "desc.value()"
14454 rootedValue
= fill(
14456 JS::Rooted<JS::Value> rootedValue(cx, ${argumentHandleValue});
14458 argumentHandleValue
=argumentHandleValue
,
14461 "declName": argument
.identifier
.name
,
14462 "holderName": argument
.identifier
.name
+ "_holder",
14463 "val": argumentHandleValue
,
14464 "maybeMutableVal": "&rootedValue",
14466 "passedToJSImpl": "false",
14468 self
.cgRoot
.prepend(instantiateJSToNativeConversion(info
, templateValues
))
14469 # rootedValue needs to come before the conversion, so we
14470 # need to prepend it last.
14471 self
.cgRoot
.prepend(CGGeneric(rootedValue
))
14472 elif operation
.isGetter() or operation
.isDeleter():
14473 if foundVar
is None:
14474 self
.cgRoot
.prepend(CGGeneric("bool found = false;\n"))
14476 def getArguments(self
):
14477 args
= [(a
, a
.identifier
.name
) for a
in self
.arguments
]
14478 if self
.idlNode
.isGetter() or self
.idlNode
.isDeleter():
14481 FakeArgument(BuiltinTypes
[IDLBuiltinType
.Types
.boolean
]),
14487 def wrap_return_value(self
):
14488 if not self
.idlNode
.isGetter() or self
.templateValues
is None:
14492 wrapForType(self
.returnType
, self
.descriptor
, self
.templateValues
)
14494 if self
.checkFound
:
14495 wrap
= CGIfWrapper(wrap
, self
.foundVar
)
14497 wrap
= CGList([CGGeneric("MOZ_ASSERT(" + self
.foundVar
+ ");\n"), wrap
])
14498 return "\n" + wrap
.define()
14501 class CGProxyIndexedOperation(CGProxySpecialOperation
):
14503 Class to generate a call to an indexed operation.
14505 If doUnwrap is False, the caller is responsible for making sure a variable
14506 named 'self' holds the C++ object somewhere where the code we generate
14509 If checkFound is False, will just assert that the prop is found instead of
14510 checking that it is before wrapping the value.
14512 resultVar: See the docstring for CGCallGenerator.
14514 foundVar: See the docstring for CGProxySpecialOperation.
14523 argumentHandleValue
=None,
14527 self
.doUnwrap
= doUnwrap
14528 CGProxySpecialOperation
.__init
__(
14533 argumentHandleValue
=argumentHandleValue
,
14534 resultVar
=resultVar
,
14539 # Our first argument is the id we're getting.
14540 argName
= self
.arguments
[0].identifier
.name
14541 if argName
== "index":
14542 # We already have our index in a variable with that name
14545 setIndex
= "uint32_t %s = index;\n" % argName
14547 unwrap
= "%s* self = UnwrapProxy(proxy);\n" % self
.descriptor
.nativeType
14550 return setIndex
+ unwrap
+ CGProxySpecialOperation
.define(self
)
14553 class CGProxyIndexedGetter(CGProxyIndexedOperation
):
14555 Class to generate a call to an indexed getter. If templateValues is not None
14556 the returned value will be wrapped with wrapForType using templateValues.
14558 If doUnwrap is False, the caller is responsible for making sure a variable
14559 named 'self' holds the C++ object somewhere where the code we generate
14562 If checkFound is False, will just assert that the prop is found instead of
14563 checking that it is before wrapping the value.
14565 foundVar: See the docstring for CGProxySpecialOperation.
14571 templateValues
=None,
14576 self
.templateValues
= templateValues
14577 CGProxyIndexedOperation
.__init
__(
14578 self
, descriptor
, "IndexedGetter", doUnwrap
, checkFound
, foundVar
=foundVar
14582 class CGProxyIndexedPresenceChecker(CGProxyIndexedGetter
):
14584 Class to generate a call that checks whether an indexed property exists.
14586 For now, we just delegate to CGProxyIndexedGetter
14588 foundVar: See the docstring for CGProxySpecialOperation.
14591 def __init__(self
, descriptor
, foundVar
):
14592 CGProxyIndexedGetter
.__init
__(self
, descriptor
, foundVar
=foundVar
)
14593 self
.cgRoot
.append(CGGeneric("(void)result;\n"))
14596 class CGProxyIndexedSetter(CGProxyIndexedOperation
):
14598 Class to generate a call to an indexed setter.
14601 def __init__(self
, descriptor
, argumentHandleValue
=None):
14602 CGProxyIndexedOperation
.__init
__(
14603 self
, descriptor
, "IndexedSetter", argumentHandleValue
=argumentHandleValue
14607 class CGProxyNamedOperation(CGProxySpecialOperation
):
14609 Class to generate a call to a named operation.
14611 'value' is the jsval to use for the name; None indicates that it should be
14612 gotten from the property id.
14614 resultVar: See the docstring for CGCallGenerator.
14616 foundVar: See the docstring for CGProxySpecialOperation.
14618 tailCode: if we end up with a non-symbol string id, run this code after
14619 we do all our other work.
14627 argumentHandleValue
=None,
14632 CGProxySpecialOperation
.__init
__(
14636 argumentHandleValue
=argumentHandleValue
,
14637 resultVar
=resultVar
,
14641 self
.tailCode
= tailCode
14644 # Our first argument is the id we're getting.
14645 argName
= self
.arguments
[0].identifier
.name
14646 if argName
== "id":
14647 # deal with the name collision
14648 decls
= "JS::Rooted<jsid> id_(cx, id);\n"
14654 decls
+= "FakeString<char16_t> %s;\n" % argName
14658 ${nativeType}* self = UnwrapProxy(proxy);
14662 nativeType
=self
.descriptor
.nativeType
,
14663 op
=CGProxySpecialOperation
.define(self
),
14664 tailCode
=self
.tailCode
,
14667 if self
.value
is None:
14672 if (!ConvertIdToString(cx, ${idName}, ${argName}, isSymbol)) {
14685 # Sadly, we have to set up nameVal even if we have an atom id,
14686 # because we don't know for sure, and we can end up needing it
14687 # so it needs to be higher up the stack. Using a Maybe here
14688 # seems like probable overkill.
14692 JS::Rooted<JS::Value> nameVal(cx, ${value});
14693 if (!nameVal.isSymbol()) {
14694 if (!ConvertJSValueToString(cx, nameVal, eStringify, eStringify,
14708 class CGProxyNamedGetter(CGProxyNamedOperation
):
14710 Class to generate a call to an named getter. If templateValues is not None
14711 the returned value will be wrapped with wrapForType using templateValues.
14712 'value' is the jsval to use for the name; None indicates that it should be
14713 gotten from the property id.
14715 foundVar: See the docstring for CGProxySpecialOperation.
14718 def __init__(self
, descriptor
, templateValues
=None, value
=None, foundVar
=None):
14719 self
.templateValues
= templateValues
14720 CGProxyNamedOperation
.__init
__(
14721 self
, descriptor
, "NamedGetter", value
, foundVar
=foundVar
14725 class CGProxyNamedPresenceChecker(CGProxyNamedGetter
):
14727 Class to generate a call that checks whether a named property exists.
14729 For now, we just delegate to CGProxyNamedGetter
14731 foundVar: See the docstring for CGProxySpecialOperation.
14734 def __init__(self
, descriptor
, foundVar
=None):
14735 CGProxyNamedGetter
.__init
__(self
, descriptor
, foundVar
=foundVar
)
14736 self
.cgRoot
.append(CGGeneric("(void)result;\n"))
14739 class CGProxyNamedSetter(CGProxyNamedOperation
):
14741 Class to generate a call to a named setter.
14744 def __init__(self
, descriptor
, tailCode
, argumentHandleValue
=None):
14745 CGProxyNamedOperation
.__init
__(
14749 argumentHandleValue
=argumentHandleValue
,
14754 class CGProxyNamedDeleter(CGProxyNamedOperation
):
14756 Class to generate a call to a named deleter.
14758 resultVar: See the docstring for CGCallGenerator.
14760 foundVar: See the docstring for CGProxySpecialOperation.
14763 def __init__(self
, descriptor
, resultVar
=None, foundVar
=None):
14764 CGProxyNamedOperation
.__init
__(
14765 self
, descriptor
, "NamedDeleter", resultVar
=resultVar
, foundVar
=foundVar
14769 class CGProxyIsProxy(CGAbstractMethod
):
14770 def __init__(self
, descriptor
):
14771 args
= [Argument("JSObject*", "obj")]
14772 CGAbstractMethod
.__init
__(
14773 self
, descriptor
, "IsProxy", "bool", args
, alwaysInline
=True
14779 def definition_body(self
):
14780 return "return js::IsProxy(obj) && js::GetProxyHandler(obj) == DOMProxyHandler::getInstance();\n"
14783 class CGProxyUnwrap(CGAbstractMethod
):
14784 def __init__(self
, descriptor
):
14785 args
= [Argument("JSObject*", "obj")]
14786 CGAbstractMethod
.__init
__(
14790 descriptor
.nativeType
+ "*",
14798 def definition_body(self
):
14801 MOZ_ASSERT(js::IsProxy(obj));
14802 if (js::GetProxyHandler(obj) != DOMProxyHandler::getInstance()) {
14803 MOZ_ASSERT(xpc::WrapperFactory::IsXrayWrapper(obj));
14804 obj = js::UncheckedUnwrap(obj);
14806 MOZ_ASSERT(IsProxy(obj));
14807 return static_cast<${type}*>(js::GetProxyReservedSlot(obj, DOM_OBJECT_SLOT).toPrivate());
14809 type=self
.descriptor
.nativeType
,
14813 MISSING_PROP_PREF
= "dom.missing_prop_counters.enabled"
14816 def missingPropUseCountersForDescriptor(desc
):
14817 if not desc
.needsMissingPropUseCounters
:
14822 if (StaticPrefs::${pref}() && id.isAtom()) {
14823 CountMaybeMissingProperty(proxy, id);
14827 pref
=prefIdentifier(MISSING_PROP_PREF
),
14831 def findAncestorWithInstrumentedProps(desc
):
14833 Find an ancestor of desc.interface (not including desc.interface
14834 itself) that has instrumented properties on it. May return None
14835 if there is no such ancestor.
14837 ancestor
= desc
.interface
.parent
14839 if ancestor
.getExtendedAttribute("InstrumentedProps"):
14841 ancestor
= ancestor
.parent
14845 class CGCountMaybeMissingProperty(CGAbstractMethod
):
14846 def __init__(self
, descriptor
):
14848 Returns whether we counted the property involved.
14850 CGAbstractMethod
.__init
__(
14853 "CountMaybeMissingProperty",
14856 Argument("JS::Handle<JSObject*>", "proxy"),
14857 Argument("JS::Handle<jsid>", "id"),
14861 def gen_switch(self
, switchDecriptor
):
14863 Generate a switch from the switch descriptor. The descriptor
14864 dictionary must have the following properties:
14866 1) A "precondition" property that contains code to run before the
14867 switch statement. Its value ie a string.
14868 2) A "condition" property for the condition. Its value is a string.
14869 3) A "cases" property. Its value is an object that has property names
14870 corresponding to the case labels. The values of those properties
14871 are either new switch descriptor dictionaries (which will then
14872 generate nested switches) or strings to use for case bodies.
14875 for label
, body
in sorted(switchDecriptor
["cases"].items()):
14876 if isinstance(body
, dict):
14877 body
= self
.gen_switch(body
)
14893 switch (${condition}) {
14897 precondition
=switchDecriptor
["precondition"],
14898 condition
=switchDecriptor
["condition"],
14899 cases
="".join(cases
),
14902 def charSwitch(self
, props
, charIndex
):
14904 Create a switch for the given props, based on the first char where
14905 they start to differ at index charIndex or more. Each prop is a tuple
14906 containing interface name and prop name.
14908 Incoming props should be a sorted list.
14910 if len(props
) == 1:
14911 # We're down to one string: just check whether we match it.
14914 if (JS_LinearStringEqualsLiteral(str, "${name}")) {
14915 counter.emplace(eUseCounter_${iface}_${name});
14918 iface
=self
.descriptor
.name
,
14924 switch
["precondition"] = "StringIdChars chars(nogc, str);\n"
14926 switch
["precondition"] = ""
14928 # Find the first place where we might actually have a difference.
14929 while all(prop
[charIndex
] == props
[0][charIndex
] for prop
in props
):
14932 switch
["condition"] = "chars[%d]" % charIndex
14933 switch
["cases"] = dict()
14934 current_props
= None
14937 while idx
< len(props
):
14938 nextChar
= "'%s'" % props
[idx
][charIndex
]
14939 if nextChar
!= curChar
:
14941 switch
["cases"][curChar
] = self
.charSwitch(
14942 current_props
, charIndex
+ 1
14946 current_props
.append(props
[idx
])
14948 switch
["cases"][curChar
] = self
.charSwitch(current_props
, charIndex
+ 1)
14951 def definition_body(self
):
14952 ancestor
= findAncestorWithInstrumentedProps(self
.descriptor
)
14957 if (${ancestor}_Binding::CountMaybeMissingProperty(proxy, id)) {
14962 ancestor
=ancestor
.identifier
.name
,
14967 instrumentedProps
= self
.descriptor
.instrumentedProps
14968 if not instrumentedProps
:
14969 return body
+ dedent(
14975 lengths
= set(len(prop
) for prop
in instrumentedProps
)
14976 switchDesc
= {"condition": "JS::GetLinearStringLength(str)", "precondition": ""}
14977 switchDesc
["cases"] = dict()
14978 for length
in sorted(lengths
):
14979 switchDesc
["cases"][str(length
)] = self
.charSwitch(
14980 list(sorted(prop
for prop
in instrumentedProps
if len(prop
) == length
)),
14984 return body
+ fill(
14986 MOZ_ASSERT(StaticPrefs::${pref}() && id.isAtom());
14987 Maybe<UseCounter> counter;
14989 // Scope for our no-GC section, so we don't need to rely on SetUseCounter not GCing.
14990 JS::AutoCheckCannotGC nogc;
14991 JSLinearString* str = JS::AtomToLinearString(id.toAtom());
14992 // Don't waste time fetching the chars until we've done the length switch.
14996 SetUseCounter(proxy, *counter);
15002 pref
=prefIdentifier(MISSING_PROP_PREF
),
15003 switch
=self
.gen_switch(switchDesc
),
15007 class CGDOMJSProxyHandler_getOwnPropDescriptor(ClassMethod
):
15008 def __init__(self
, descriptor
):
15010 Argument("JSContext*", "cx"),
15011 Argument("JS::Handle<JSObject*>", "proxy"),
15012 Argument("JS::Handle<jsid>", "id"),
15013 Argument("bool", "ignoreNamedProps"),
15014 Argument("JS::MutableHandle<Maybe<JS::PropertyDescriptor>>", "desc"),
15016 ClassMethod
.__init
__(
15018 "getOwnPropDescriptor",
15025 self
.descriptor
= descriptor
15028 indexedSetter
= self
.descriptor
.operations
["IndexedSetter"]
15030 if self
.descriptor
.isMaybeCrossOriginObject():
15033 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy));
15034 MOZ_ASSERT(IsPlatformObjectSameOrigin(cx, proxy),
15035 "getOwnPropertyDescriptor() and set() should have dealt");
15036 MOZ_ASSERT(js::IsObjectInContextCompartment(proxy, cx),
15037 "getOwnPropertyDescriptor() and set() should have dealt");
15043 xrayDecl
= "bool isXray = xpc::WrapperFactory::IsXrayWrapper(proxy);\n"
15044 xrayCheck
= "!isXray &&"
15046 if self
.descriptor
.supportsIndexedProperties():
15048 "JS::PropertyAttribute::Configurable",
15049 "JS::PropertyAttribute::Enumerable",
15051 if indexedSetter
is not None:
15052 attributes
.append("JS::PropertyAttribute::Writable")
15054 "desc.set(mozilla::Some(JS::PropertyDescriptor::Data(value, { %s })));\nreturn true;\n"
15055 % ", ".join(attributes
)
15058 "jsvalRef": "value",
15059 "jsvalHandle": "&value",
15061 "successCode": setDescriptor
,
15065 uint32_t index = GetArrayIndexFromId(id);
15066 if (IsArrayIndex(index)) {
15067 JS::Rooted<JS::Value> value(cx);
15072 callGetter
=CGProxyIndexedGetter(
15073 self
.descriptor
, templateValues
15079 missingPropUseCounters
= missingPropUseCountersForDescriptor(self
.descriptor
)
15081 if self
.descriptor
.supportsNamedProperties():
15082 operations
= self
.descriptor
.operations
15083 attributes
= ["JS::PropertyAttribute::Configurable"]
15084 if self
.descriptor
.namedPropertiesEnumerable
:
15085 attributes
.append("JS::PropertyAttribute::Enumerable")
15086 if operations
["NamedSetter"] is not None:
15087 attributes
.append("JS::PropertyAttribute::Writable")
15089 "desc.set(mozilla::Some(JS::PropertyDescriptor::Data(value, { %s })));\nreturn true;\n"
15090 % ", ".join(attributes
)
15093 "jsvalRef": "value",
15094 "jsvalHandle": "&value",
15096 "successCode": setDescriptor
,
15099 computeCondition
= dedent(
15102 if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
15105 callNamedGetter = !hasOnProto;
15108 if self
.descriptor
.interface
.getExtendedAttribute("LegacyOverrideBuiltIns"):
15109 computeCondition
= fill(
15112 callNamedGetter = true;
15117 hasOnProto
=computeCondition
,
15120 outerCondition
= "!ignoreNamedProps"
15121 if self
.descriptor
.supportsIndexedProperties():
15122 outerCondition
= "!IsArrayIndex(index) && " + outerCondition
15124 namedGetCode
= CGProxyNamedGetter(self
.descriptor
, templateValues
).define()
15127 bool callNamedGetter = false;
15128 if (${outerCondition}) {
15129 $*{computeCondition}
15131 if (callNamedGetter) {
15132 JS::Rooted<JS::Value> value(cx);
15136 outerCondition
=outerCondition
,
15137 computeCondition
=computeCondition
,
15138 namedGetCode
=namedGetCode
,
15148 $*{missingPropUseCounters}
15149 JS::Rooted<JSObject*> expando(cx);
15150 if (${xrayCheck}(expando = GetExpandoObject(proxy))) {
15151 if (!JS_GetOwnPropertyDescriptorById(cx, expando, id, desc)) {
15154 if (desc.isSome()) {
15164 xrayCheck
=xrayCheck
,
15165 getIndexed
=getIndexed
,
15166 missingPropUseCounters
=missingPropUseCounters
,
15171 class CGDOMJSProxyHandler_defineProperty(ClassMethod
):
15172 def __init__(self
, descriptor
):
15173 # The usual convention is to name the ObjectOpResult out-parameter
15174 # `result`, but that name is a bit overloaded around here.
15176 Argument("JSContext*", "cx_"),
15177 Argument("JS::Handle<JSObject*>", "proxy"),
15178 Argument("JS::Handle<jsid>", "id"),
15179 Argument("JS::Handle<JS::PropertyDescriptor>", "desc"),
15180 Argument("JS::ObjectOpResult&", "opresult"),
15181 Argument("bool*", "done"),
15183 ClassMethod
.__init
__(
15192 self
.descriptor
= descriptor
15197 indexedSetter
= self
.descriptor
.operations
["IndexedSetter"]
15199 error_label
= CGSpecializedMethod
.error_reporting_label_helper(
15200 self
.descriptor
, indexedSetter
, isConstructor
=False
15205 BindingCallContext cx(cx_, ${error_label});
15207 error_label
=error_label
,
15212 JSContext* cx = cx_;
15217 uint32_t index = GetArrayIndexFromId(id);
15218 if (IsArrayIndex(index)) {
15221 // https://webidl.spec.whatwg.org/#legacy-platform-object-defineownproperty
15222 // Step 1.1. The no-indexed-setter case is handled by step 1.2.
15223 if (!desc.isDataDescriptor()) {
15224 return opresult.failNotDataDescriptor();
15228 return opresult.succeed();
15232 callSetter
=CGProxyIndexedSetter(self
.descriptor
).define(),
15234 elif self
.descriptor
.supportsIndexedProperties():
15235 # We allow untrusted content to prevent Xrays from setting a
15236 # property if that property is an indexed property and we have no
15237 # indexed setter. That's how the object would normally behave if
15238 # you tried to set the property on it. That means we don't need to
15239 # do anything special for Xrays here.
15242 if (IsArrayIndex(GetArrayIndexFromId(id))) {
15244 return opresult.failNoIndexedSetter();
15249 namedSetter
= self
.descriptor
.operations
["NamedSetter"]
15251 error_label
= CGSpecializedMethod
.error_reporting_label_helper(
15252 self
.descriptor
, namedSetter
, isConstructor
=False
15257 BindingCallContext cx(cx_, ${error_label});
15259 error_label
=error_label
,
15264 JSContext* cx = cx_;
15267 if self
.descriptor
.hasLegacyUnforgeableMembers
:
15269 "Can't handle a named setter on an interface "
15270 "that has unforgeables. Figure out how that "
15275 // https://webidl.spec.whatwg.org/#legacy-platform-object-defineownproperty
15277 if (!desc.isDataDescriptor()) {
15279 return opresult.failNotDataDescriptor();
15286 return opresult.succeed();
15289 set += CGProxyNamedSetter(self
.descriptor
, tailCode
).define()
15291 # We allow untrusted content to prevent Xrays from setting a
15292 # property if that property is already a named property on the
15293 # object and we have no named setter. That's how the object would
15294 # normally behave if you tried to set the property on it. That
15295 # means we don't need to do anything special for Xrays here.
15296 if self
.descriptor
.supportsNamedProperties():
15299 JSContext* cx = cx_;
15300 bool found = false;
15301 $*{presenceChecker}
15305 return opresult.failNoNamedSetter();
15308 presenceChecker
=CGProxyNamedPresenceChecker(
15309 self
.descriptor
, foundVar
="found"
15312 if self
.descriptor
.isMaybeCrossOriginObject():
15315 MOZ_ASSERT(IsPlatformObjectSameOrigin(cx_, proxy),
15316 "Why did the MaybeCrossOriginObject defineProperty override fail?");
15317 MOZ_ASSERT(js::IsObjectInContextCompartment(proxy, cx_),
15318 "Why did the MaybeCrossOriginObject defineProperty override fail?");
15322 # In all cases we want to tail-call to our base class; we can
15323 # always land here for symbols.
15325 "return mozilla::dom::DOMProxyHandler::defineProperty(%s);\n"
15326 % ", ".join(a
.name
for a
in self
.args
)
15331 def getDeleterBody(descriptor
, type, foundVar
=None):
15333 type should be "Named" or "Indexed"
15335 The possible outcomes:
15336 - an error happened (the emitted code returns false)
15337 - own property not found (foundVar=false, deleteSucceeded=true)
15338 - own property found and deleted (foundVar=true, deleteSucceeded=true)
15339 - own property found but can't be deleted (foundVar=true, deleteSucceeded=false)
15341 assert type in ("Named", "Indexed")
15342 deleter
= descriptor
.operations
[type + "Deleter"]
15344 assert type == "Named"
15345 assert foundVar
is not None
15346 if descriptor
.hasLegacyUnforgeableMembers
:
15348 "Can't handle a deleter on an interface "
15349 "that has unforgeables. Figure out how "
15350 "that should work!"
15352 # See if the deleter method is fallible.
15353 t
= deleter
.signatures()[0][0]
15354 if t
.isPrimitive() and not t
.nullable() and t
.tag() == IDLType
.Tags
.bool:
15355 # The deleter method has a boolean return value. When a
15356 # property is found, the return value indicates whether it
15357 # was successfully deleted.
15360 if (!${foundVar}) {
15361 deleteSucceeded = true;
15367 # No boolean return value: if a property is found,
15368 # deleting it always succeeds.
15369 setDS
= "deleteSucceeded = true;\n"
15372 CGProxyNamedDeleter(
15373 descriptor
, resultVar
="deleteSucceeded", foundVar
=foundVar
15377 elif getattr(descriptor
, "supports%sProperties" % type)():
15378 presenceCheckerClass
= globals()["CGProxy%sPresenceChecker" % type]
15380 if foundVar
is None:
15382 foundDecl
= "bool found = false;\n"
15386 $*{presenceChecker}
15387 deleteSucceeded = !${foundVar};
15389 foundDecl
=foundDecl
,
15390 presenceChecker
=presenceCheckerClass(
15391 descriptor
, foundVar
=foundVar
15400 class CGDeleteNamedProperty(CGAbstractStaticMethod
):
15401 def __init__(self
, descriptor
):
15403 Argument("JSContext*", "cx"),
15404 Argument("JS::Handle<JSObject*>", "xray"),
15405 Argument("JS::Handle<JSObject*>", "proxy"),
15406 Argument("JS::Handle<jsid>", "id"),
15407 Argument("JS::ObjectOpResult&", "opresult"),
15409 CGAbstractStaticMethod
.__init
__(
15410 self
, descriptor
, "DeleteNamedProperty", "bool", args
15413 def definition_body(self
):
15416 MOZ_ASSERT(xpc::WrapperFactory::IsXrayWrapper(xray));
15417 MOZ_ASSERT(js::IsProxy(proxy));
15418 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy));
15419 JSAutoRealm ar(cx, proxy);
15420 bool deleteSucceeded = false;
15421 bool found = false;
15423 if (!found || deleteSucceeded) {
15424 return opresult.succeed();
15426 return opresult.failCantDelete();
15428 namedBody
=getDeleterBody(self
.descriptor
, "Named", foundVar
="found"),
15432 class CGDOMJSProxyHandler_delete(ClassMethod
):
15433 def __init__(self
, descriptor
):
15435 Argument("JSContext*", "cx"),
15436 Argument("JS::Handle<JSObject*>", "proxy"),
15437 Argument("JS::Handle<jsid>", "id"),
15438 Argument("JS::ObjectOpResult&", "opresult"),
15440 ClassMethod
.__init
__(
15441 self
, "delete_", "bool", args
, virtual
=True, override
=True, const
=True
15443 self
.descriptor
= descriptor
15448 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
15449 "Should not have a XrayWrapper here");
15454 if self
.descriptor
.isMaybeCrossOriginObject():
15457 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
15458 return ReportCrossOriginDenial(cx, id, "delete"_ns);
15461 // Safe to enter the Realm of proxy now.
15462 JSAutoRealm ar(cx, proxy);
15463 JS_MarkCrossZoneId(cx, id);
15467 indexedBody
= getDeleterBody(self
.descriptor
, "Indexed")
15468 if indexedBody
is not None:
15469 # Can't handle cross-origin objects here.
15470 assert not self
.descriptor
.isMaybeCrossOriginObject()
15473 uint32_t index = GetArrayIndexFromId(id);
15474 if (IsArrayIndex(index)) {
15475 bool deleteSucceeded;
15477 return deleteSucceeded ? opresult.succeed() : opresult.failCantDelete();
15480 indexedBody
=indexedBody
,
15483 namedBody
= getDeleterBody(self
.descriptor
, "Named", foundVar
="found")
15484 if namedBody
is not None:
15487 // Try named delete only if the named property visibility
15488 // algorithm says the property is visible.
15489 bool tryNamedDelete = true;
15490 { // Scope for expando
15491 JS::Rooted<JSObject*> expando(cx, DOMProxyHandler::GetExpandoObject(proxy));
15494 if (!JS_HasPropertyById(cx, expando, id, &hasProp)) {
15497 tryNamedDelete = !hasProp;
15503 if not self
.descriptor
.interface
.getExtendedAttribute(
15504 "LegacyOverrideBuiltIns"
15508 if (tryNamedDelete) {
15510 if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
15513 tryNamedDelete = !hasOnProto;
15518 # We always return above for an index id in the case when we support
15519 # indexed properties, so we can just treat the id as a name
15520 # unconditionally here.
15523 if (tryNamedDelete) {
15524 bool found = false;
15525 bool deleteSucceeded;
15528 return deleteSucceeded ? opresult.succeed() : opresult.failCantDelete();
15532 namedBody
=namedBody
,
15538 return dom::DOMProxyHandler::delete_(cx, proxy, id, opresult);
15545 class CGDOMJSProxyHandler_ownPropNames(ClassMethod
):
15551 Argument("JSContext*", "cx"),
15552 Argument("JS::Handle<JSObject*>", "proxy"),
15553 Argument("unsigned", "flags"),
15554 Argument("JS::MutableHandleVector<jsid>", "props"),
15556 ClassMethod
.__init
__(
15557 self
, "ownPropNames", "bool", args
, virtual
=True, override
=True, const
=True
15559 self
.descriptor
= descriptor
15562 if self
.descriptor
.isMaybeCrossOriginObject():
15565 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy));
15566 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
15567 if (!(flags & JSITER_HIDDEN)) {
15568 // There are no enumerable cross-origin props, so we're done.
15572 JS::Rooted<JSObject*> holder(cx);
15573 if (!EnsureHolder(cx, proxy, &holder)) {
15577 if (!js::GetPropertyKeys(cx, holder, flags, props)) {
15581 return xpc::AppendCrossOriginWhitelistedPropNames(cx, props);
15588 xrayDecl
= "bool isXray = xpc::WrapperFactory::IsXrayWrapper(proxy);\n"
15589 xrayCheck
= "!isXray &&"
15591 # Per spec, we do indices, then named props, then everything else.
15592 if self
.descriptor
.supportsIndexedProperties():
15593 if self
.descriptor
.lengthNeedsCallerType():
15594 callerType
= callerTypeGetterForDescriptor(self
.descriptor
)
15600 uint32_t length = UnwrapProxy(proxy)->Length(${callerType});
15601 MOZ_ASSERT(int32_t(length) >= 0);
15602 for (int32_t i = 0; i < int32_t(length); ++i) {
15603 if (!props.append(JS::PropertyKey::Int(i))) {
15608 callerType
=callerType
,
15613 if self
.descriptor
.supportsNamedProperties():
15614 if self
.descriptor
.interface
.getExtendedAttribute("LegacyOverrideBuiltIns"):
15619 if self
.descriptor
.supportedNamesNeedCallerType():
15620 callerType
= ", " + callerTypeGetterForDescriptor(self
.descriptor
)
15626 nsTArray<nsString> names;
15627 UnwrapProxy(proxy)->GetSupportedNames(names${callerType});
15628 if (!AppendNamedPropertyIds(cx, proxy, names, ${shadow}, props)) {
15632 callerType
=callerType
,
15635 if not self
.descriptor
.namedPropertiesEnumerable
:
15636 addNames
= CGIfWrapper(
15637 CGGeneric(addNames
), "flags & JSITER_HIDDEN"
15639 addNames
= "\n" + addNames
15643 addExpandoProps
= fill(
15645 JS::Rooted<JSObject*> expando(cx);
15646 if (${xrayCheck}(expando = DOMProxyHandler::GetExpandoObject(proxy)) &&
15647 !js::GetPropertyKeys(cx, expando, flags, props)) {
15651 xrayCheck
=xrayCheck
,
15654 if self
.descriptor
.isMaybeCrossOriginObject():
15655 # We need to enter our compartment (which we might not be
15656 # in right now) to get the expando props.
15657 addExpandoProps
= fill(
15659 { // Scope for accessing the expando.
15660 // Safe to enter our compartment, because IsPlatformObjectSameOrigin tested true.
15661 JSAutoRealm ar(cx, proxy);
15662 $*{addExpandoProps}
15664 for (auto& id : props) {
15665 JS_MarkCrossZoneId(cx, id);
15668 addExpandoProps
=addExpandoProps
,
15677 $*{addExpandoProps}
15682 addIndices
=addIndices
,
15684 addExpandoProps
=addExpandoProps
,
15688 class CGDOMJSProxyHandler_hasOwn(ClassMethod
):
15689 def __init__(self
, descriptor
):
15691 Argument("JSContext*", "cx"),
15692 Argument("JS::Handle<JSObject*>", "proxy"),
15693 Argument("JS::Handle<jsid>", "id"),
15694 Argument("bool*", "bp"),
15696 ClassMethod
.__init
__(
15697 self
, "hasOwn", "bool", args
, virtual
=True, override
=True, const
=True
15699 self
.descriptor
= descriptor
15702 if self
.descriptor
.isMaybeCrossOriginObject():
15703 maybeCrossOrigin
= dedent(
15705 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
15706 // Just hand this off to BaseProxyHandler to do the slow-path thing.
15707 // The BaseProxyHandler code is OK with this happening without entering the
15708 // compartment of "proxy", which is important to get the right answers.
15709 return js::BaseProxyHandler::hasOwn(cx, proxy, id, bp);
15712 // Now safe to enter the Realm of proxy and do the rest of the work there.
15713 JSAutoRealm ar(cx, proxy);
15714 JS_MarkCrossZoneId(cx, id);
15718 maybeCrossOrigin
= ""
15720 if self
.descriptor
.supportsIndexedProperties():
15723 uint32_t index = GetArrayIndexFromId(id);
15724 if (IsArrayIndex(index)) {
15725 bool found = false;
15726 $*{presenceChecker}
15733 presenceChecker
=CGProxyIndexedPresenceChecker(
15734 self
.descriptor
, foundVar
="found"
15740 if self
.descriptor
.supportsNamedProperties():
15741 # If we support indexed properties we always return above for index
15742 # property names, so no need to check for those here.
15745 bool found = false;
15746 $*{presenceChecker}
15750 presenceChecker
=CGProxyNamedPresenceChecker(
15751 self
.descriptor
, foundVar
="found"
15754 if not self
.descriptor
.interface
.getExtendedAttribute(
15755 "LegacyOverrideBuiltIns"
15760 if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
15764 $*{protoLacksProperty}
15768 protoLacksProperty
=named
,
15770 named
+= "*bp = false;\n"
15774 named
= "*bp = false;\n"
15776 missingPropUseCounters
= missingPropUseCountersForDescriptor(self
.descriptor
)
15780 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
15781 "Should not have a XrayWrapper here");
15782 $*{maybeCrossOrigin}
15785 $*{missingPropUseCounters}
15786 JS::Rooted<JSObject*> expando(cx, GetExpandoObject(proxy));
15789 bool ok = JS_HasPropertyById(cx, expando, id, &b);
15799 maybeCrossOrigin
=maybeCrossOrigin
,
15801 missingPropUseCounters
=missingPropUseCounters
,
15806 class CGDOMJSProxyHandler_get(ClassMethod
):
15807 def __init__(self
, descriptor
):
15809 Argument("JSContext*", "cx"),
15810 Argument("JS::Handle<JSObject*>", "proxy"),
15811 Argument("JS::Handle<JS::Value>", "receiver"),
15812 Argument("JS::Handle<jsid>", "id"),
15813 Argument("JS::MutableHandle<JS::Value>", "vp"),
15815 ClassMethod
.__init
__(
15816 self
, "get", "bool", args
, virtual
=True, override
=True, const
=True
15818 self
.descriptor
= descriptor
15821 missingPropUseCounters
= missingPropUseCountersForDescriptor(self
.descriptor
)
15823 getUnforgeableOrExpando
= dedent(
15825 bool expandoHasProp = false;
15826 { // Scope for expando
15827 JS::Rooted<JSObject*> expando(cx, DOMProxyHandler::GetExpandoObject(proxy));
15829 if (!JS_HasPropertyById(cx, expando, id, &expandoHasProp)) {
15833 if (expandoHasProp) {
15834 // Forward the get to the expando object, but our receiver is whatever our
15836 if (!JS_ForwardGetPropertyTo(cx, expando, id, ${receiver}, vp)) {
15845 getOnPrototype
= dedent(
15847 bool foundOnPrototype;
15848 if (!GetPropertyOnPrototype(cx, proxy, ${receiver}, id, &foundOnPrototype, vp)) {
15854 if self
.descriptor
.isMaybeCrossOriginObject():
15855 # We can't handle these for cross-origin objects
15856 assert not self
.descriptor
.supportsIndexedProperties()
15857 assert not self
.descriptor
.supportsNamedProperties()
15861 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
15862 "Should not have a XrayWrapper here");
15864 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
15865 return CrossOriginGet(cx, proxy, receiver, id, vp);
15868 $*{missingPropUseCounters}
15869 { // Scope for the JSAutoRealm accessing expando and prototype.
15870 JSAutoRealm ar(cx, proxy);
15871 JS::Rooted<JS::Value> wrappedReceiver(cx, receiver);
15872 if (!MaybeWrapValue(cx, &wrappedReceiver)) {
15875 JS_MarkCrossZoneId(cx, id);
15877 $*{getUnforgeableOrExpando}
15878 if (!expandoHasProp) {
15880 if (!foundOnPrototype) {
15881 MOZ_ASSERT(vp.isUndefined());
15887 return MaybeWrapValue(cx, vp);
15889 missingPropUseCounters
=missingPropUseCountersForDescriptor(
15892 getUnforgeableOrExpando
=fill(
15893 getUnforgeableOrExpando
, receiver
="wrappedReceiver"
15895 getOnPrototype
=fill(getOnPrototype
, receiver
="wrappedReceiver"),
15898 templateValues
= {"jsvalRef": "vp", "jsvalHandle": "vp", "obj": "proxy"}
15900 getUnforgeableOrExpando
= fill(
15901 getUnforgeableOrExpando
, receiver
="receiver"
15905 if (expandoHasProp) {
15910 if self
.descriptor
.supportsIndexedProperties():
15911 getIndexedOrExpando
= fill(
15913 uint32_t index = GetArrayIndexFromId(id);
15914 if (IsArrayIndex(index)) {
15916 // Even if we don't have this index, we don't forward the
15917 // get on to our expando object.
15919 $*{getUnforgeableOrExpando}
15922 callGetter
=CGProxyIndexedGetter(
15923 self
.descriptor
, templateValues
15925 getUnforgeableOrExpando
=getUnforgeableOrExpando
,
15928 getIndexedOrExpando
= getUnforgeableOrExpando
15930 if self
.descriptor
.supportsNamedProperties():
15931 getNamed
= CGProxyNamedGetter(self
.descriptor
, templateValues
)
15932 if self
.descriptor
.supportsIndexedProperties():
15933 getNamed
= CGIfWrapper(getNamed
, "!IsArrayIndex(index)")
15934 getNamed
= getNamed
.define() + "\n"
15938 getOnPrototype
= fill(getOnPrototype
, receiver
="receiver") + dedent(
15941 if (foundOnPrototype) {
15945 MOZ_ASSERT(vp.isUndefined());
15949 if self
.descriptor
.interface
.getExtendedAttribute("LegacyOverrideBuiltIns"):
15950 getNamedOrOnPrototype
= getNamed
+ getOnPrototype
15952 getNamedOrOnPrototype
= getOnPrototype
+ getNamed
15956 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
15957 "Should not have a XrayWrapper here");
15959 $*{missingPropUseCounters}
15960 $*{indexedOrExpando}
15962 $*{namedOrOnPropotype}
15965 missingPropUseCounters
=missingPropUseCounters
,
15966 indexedOrExpando
=getIndexedOrExpando
,
15967 namedOrOnPropotype
=getNamedOrOnPrototype
,
15971 class CGDOMJSProxyHandler_setCustom(ClassMethod
):
15972 def __init__(self
, descriptor
):
15974 Argument("JSContext*", "cx_"),
15975 Argument("JS::Handle<JSObject*>", "proxy"),
15976 Argument("JS::Handle<jsid>", "id"),
15977 Argument("JS::Handle<JS::Value>", "v"),
15978 Argument("bool*", "done"),
15980 ClassMethod
.__init
__(
15981 self
, "setCustom", "bool", args
, virtual
=True, override
=True, const
=True
15983 self
.descriptor
= descriptor
15987 "MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),\n"
15988 ' "Should not have a XrayWrapper here");\n'
15991 # Correctness first. If we have a NamedSetter and [LegacyOverrideBuiltIns],
15992 # always call the NamedSetter and never do anything else.
15993 namedSetter
= self
.descriptor
.operations
["NamedSetter"]
15994 if namedSetter
is not None and self
.descriptor
.interface
.getExtendedAttribute(
15995 "LegacyOverrideBuiltIns"
15997 # Check assumptions.
15998 if self
.descriptor
.supportsIndexedProperties():
16001 + self
.descriptor
.name
16003 + "Can't cope with [LegacyOverrideBuiltIns] and an indexed getter"
16005 if self
.descriptor
.hasLegacyUnforgeableMembers
:
16008 + self
.descriptor
.name
16010 + "Can't cope with [LegacyOverrideBuiltIns] and unforgeable members"
16019 callSetter
= CGProxyNamedSetter(
16020 self
.descriptor
, tailCode
, argumentHandleValue
="v"
16022 error_label
= CGSpecializedMethod
.error_reporting_label_helper(
16023 self
.descriptor
, namedSetter
, isConstructor
=False
16028 BindingCallContext cx(cx_, ${error_label});
16030 error_label
=error_label
,
16035 JSContext* cx = cx_;
16046 assertion
=assertion
,
16048 callSetter
=callSetter
.define(),
16051 # As an optimization, if we are going to call an IndexedSetter, go
16052 # ahead and call it and have done.
16053 indexedSetter
= self
.descriptor
.operations
["IndexedSetter"]
16054 if indexedSetter
is not None:
16055 error_label
= CGSpecializedMethod
.error_reporting_label_helper(
16056 self
.descriptor
, indexedSetter
, isConstructor
=False
16061 BindingCallContext cx(cx_, ${error_label});
16063 error_label
=error_label
,
16068 JSContext* cx = cx_;
16073 uint32_t index = GetArrayIndexFromId(id);
16074 if (IsArrayIndex(index)) {
16083 callSetter
=CGProxyIndexedSetter(
16084 self
.descriptor
, argumentHandleValue
="v"
16090 return assertion
+ setIndexed
+ "*done = false;\n" "return true;\n"
16093 class CGDOMJSProxyHandler_className(ClassMethod
):
16094 def __init__(self
, descriptor
):
16096 Argument("JSContext*", "cx"),
16097 Argument("JS::Handle<JSObject*>", "proxy"),
16099 ClassMethod
.__init
__(
16108 self
.descriptor
= descriptor
16111 if self
.descriptor
.isMaybeCrossOriginObject():
16112 crossOrigin
= dedent(
16114 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
16127 crossOrigin
=crossOrigin
,
16128 name
=self
.descriptor
.name
,
16132 class CGDOMJSProxyHandler_finalizeInBackground(ClassMethod
):
16133 def __init__(self
, descriptor
):
16134 args
= [Argument("const JS::Value&", "priv")]
16135 ClassMethod
.__init
__(
16137 "finalizeInBackground",
16144 self
.descriptor
= descriptor
16147 return "return false;\n"
16150 class CGDOMJSProxyHandler_finalize(ClassMethod
):
16151 def __init__(self
, descriptor
):
16152 args
= [Argument("JS::GCContext*", "gcx"), Argument("JSObject*", "proxy")]
16153 ClassMethod
.__init
__(
16154 self
, "finalize", "void", args
, virtual
=True, override
=True, const
=True
16156 self
.descriptor
= descriptor
16160 "%s* self = UnwrapPossiblyNotInitializedDOMObject<%s>(proxy);\n"
16161 % (self
.descriptor
.nativeType
, self
.descriptor
.nativeType
)
16164 FINALIZE_HOOK_NAME
,
16170 class CGDOMJSProxyHandler_objectMoved(ClassMethod
):
16171 def __init__(self
, descriptor
):
16172 args
= [Argument("JSObject*", "obj"), Argument("JSObject*", "old")]
16173 ClassMethod
.__init
__(
16174 self
, "objectMoved", "size_t", args
, virtual
=True, override
=True, const
=True
16176 self
.descriptor
= descriptor
16180 "%s* self = UnwrapPossiblyNotInitializedDOMObject<%s>(obj);\n"
16181 % (self
.descriptor
.nativeType
, self
.descriptor
.nativeType
)
16182 ) + objectMovedHook(
16184 OBJECT_MOVED_HOOK_NAME
,
16190 class CGDOMJSProxyHandler_getElements(ClassMethod
):
16191 def __init__(self
, descriptor
):
16192 assert descriptor
.supportsIndexedProperties()
16195 Argument("JSContext*", "cx"),
16196 Argument("JS::Handle<JSObject*>", "proxy"),
16197 Argument("uint32_t", "begin"),
16198 Argument("uint32_t", "end"),
16199 Argument("js::ElementAdder*", "adder"),
16201 ClassMethod
.__init
__(
16202 self
, "getElements", "bool", args
, virtual
=True, override
=True, const
=True
16204 self
.descriptor
= descriptor
16207 # Just like ownPropertyKeys we'll assume that we have no holes, so
16208 # we have all properties from 0 to length. If that ever changes
16209 # (unlikely), we'll need to do something a bit more clever with how we
16210 # forward on to our ancestor.
16213 "jsvalRef": "temp",
16214 "jsvalHandle": "&temp",
16217 "if (!adder->append(cx, temp)) return false;\n" "continue;\n"
16220 get
= CGProxyIndexedGetter(
16221 self
.descriptor
, templateValues
, False, False
16224 if self
.descriptor
.lengthNeedsCallerType():
16225 callerType
= callerTypeGetterForDescriptor(self
.descriptor
)
16231 JS::Rooted<JS::Value> temp(cx);
16232 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
16233 "Should not have a XrayWrapper here");
16235 ${nativeType}* self = UnwrapProxy(proxy);
16236 uint32_t length = self->Length(${callerType});
16237 // Compute the end of the indices we'll get ourselves
16238 uint32_t ourEnd = std::max(begin, std::min(end, length));
16240 for (uint32_t index = begin; index < ourEnd; ++index) {
16244 if (end > ourEnd) {
16245 JS::Rooted<JSObject*> proto(cx);
16246 if (!js::GetObjectProto(cx, proxy, &proto)) {
16249 return js::GetElementsWithAdder(cx, proto, proxy, ourEnd, end, adder);
16254 nativeType
=self
.descriptor
.nativeType
,
16255 callerType
=callerType
,
16260 class CGJSProxyHandler_getInstance(ClassMethod
):
16261 def __init__(self
, type):
16263 ClassMethod
.__init
__(
16264 self
, "getInstance", "const %s*" % self
.type, [], static
=True
16270 static const ${type} instance;
16277 class CGDOMJSProxyHandler_call(ClassMethod
):
16278 def __init__(self
):
16280 Argument("JSContext*", "cx"),
16281 Argument("JS::Handle<JSObject*>", "proxy"),
16282 Argument("const JS::CallArgs&", "args"),
16285 ClassMethod
.__init
__(
16286 self
, "call", "bool", args
, virtual
=True, override
=True, const
=True
16292 return js::ForwardToNative(cx, ${legacyCaller}, args);
16294 legacyCaller
=LEGACYCALLER_HOOK_NAME
,
16298 class CGDOMJSProxyHandler_isCallable(ClassMethod
):
16299 def __init__(self
):
16300 ClassMethod
.__init
__(
16304 [Argument("JSObject*", "obj")],
16318 class CGDOMJSProxyHandler_canNurseryAllocate(ClassMethod
):
16320 Override the default canNurseryAllocate in BaseProxyHandler, for cases when
16321 we should be nursery-allocated.
16324 def __init__(self
):
16325 ClassMethod
.__init
__(
16327 "canNurseryAllocate",
16343 class CGDOMJSProxyHandler_getOwnPropertyDescriptor(ClassMethod
):
16345 Implementation of getOwnPropertyDescriptor. We only use this for
16346 cross-origin objects.
16349 def __init__(self
, descriptor
):
16350 assert descriptor
.isMaybeCrossOriginObject()
16353 Argument("JSContext*", "cx"),
16354 Argument("JS::Handle<JSObject*>", "proxy"),
16355 Argument("JS::Handle<jsid>", "id"),
16356 Argument("JS::MutableHandle<Maybe<JS::PropertyDescriptor>>", "desc"),
16358 ClassMethod
.__init
__(
16360 "getOwnPropertyDescriptor",
16367 self
.descriptor
= descriptor
16372 // Implementation of <https://html.spec.whatwg.org/multipage/history.html#location-getownproperty>.
16373 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy));
16376 if (IsPlatformObjectSameOrigin(cx, proxy)) {
16377 { // Scope so we can wrap our PropertyDescriptor back into
16378 // the caller compartment.
16379 // Enter the Realm of "proxy" so we can work with it.
16380 JSAutoRealm ar(cx, proxy);
16382 JS_MarkCrossZoneId(cx, id);
16384 // The spec messes around with configurability of the returned
16385 // descriptor here, but it's not clear what should actually happen
16386 // here. See <https://github.com/whatwg/html/issues/4157>. For
16387 // now, keep our old behavior and don't do any magic.
16388 if (!dom::DOMProxyHandler::getOwnPropertyDescriptor(cx, proxy, id, desc)) {
16392 return JS_WrapPropertyDescriptor(cx, desc);
16396 if (!CrossOriginGetOwnPropertyHelper(cx, proxy, id, desc)) {
16401 if (desc.isSome()) {
16406 return CrossOriginPropertyFallback(cx, proxy, id, desc);
16411 class CGDOMJSProxyHandler_getSameOriginPrototype(ClassMethod
):
16413 Implementation of getSameOriginPrototype. We only use this for
16414 cross-origin objects.
16417 def __init__(self
, descriptor
):
16418 assert descriptor
.isMaybeCrossOriginObject()
16420 args
= [Argument("JSContext*", "cx")]
16421 ClassMethod
.__init
__(
16423 "getSameOriginPrototype",
16430 self
.descriptor
= descriptor
16435 return GetProtoObjectHandle(cx);
16440 class CGDOMJSProxyHandler_definePropertySameOrigin(ClassMethod
):
16442 Implementation of definePropertySameOrigin. We only use this for
16443 cross-origin objects.
16446 def __init__(self
, descriptor
):
16447 assert descriptor
.isMaybeCrossOriginObject()
16450 Argument("JSContext*", "cx"),
16451 Argument("JS::Handle<JSObject*>", "proxy"),
16452 Argument("JS::Handle<jsid>", "id"),
16453 Argument("JS::Handle<JS::PropertyDescriptor>", "desc"),
16454 Argument("JS::ObjectOpResult&", "result"),
16456 ClassMethod
.__init
__(
16458 "definePropertySameOrigin",
16465 self
.descriptor
= descriptor
16470 return dom::DOMProxyHandler::defineProperty(cx, proxy, id, desc, result);
16475 class CGDOMJSProxyHandler_set(ClassMethod
):
16477 Implementation of set(). We only use this for cross-origin objects.
16480 def __init__(self
, descriptor
):
16481 assert descriptor
.isMaybeCrossOriginObject()
16484 Argument("JSContext*", "cx"),
16485 Argument("JS::Handle<JSObject*>", "proxy"),
16486 Argument("JS::Handle<jsid>", "id"),
16487 Argument("JS::Handle<JS::Value>", "v"),
16488 Argument("JS::Handle<JS::Value>", "receiver"),
16489 Argument("JS::ObjectOpResult&", "result"),
16491 ClassMethod
.__init
__(
16492 self
, "set", "bool", args
, virtual
=True, override
=True, const
=True
16494 self
.descriptor
= descriptor
16499 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
16500 return CrossOriginSet(cx, proxy, id, v, receiver, result);
16503 // Safe to enter the Realm of proxy now, since it's same-origin with us.
16504 JSAutoRealm ar(cx, proxy);
16505 JS::Rooted<JS::Value> wrappedReceiver(cx, receiver);
16506 if (!MaybeWrapValue(cx, &wrappedReceiver)) {
16510 JS::Rooted<JS::Value> wrappedValue(cx, v);
16511 if (!MaybeWrapValue(cx, &wrappedValue)) {
16515 JS_MarkCrossZoneId(cx, id);
16517 return dom::DOMProxyHandler::set(cx, proxy, id, wrappedValue, wrappedReceiver, result);
16522 class CGDOMJSProxyHandler_EnsureHolder(ClassMethod
):
16524 Implementation of EnsureHolder(). We only use this for cross-origin objects.
16527 def __init__(self
, descriptor
):
16529 Argument("JSContext*", "cx"),
16530 Argument("JS::Handle<JSObject*>", "proxy"),
16531 Argument("JS::MutableHandle<JSObject*>", "holder"),
16533 ClassMethod
.__init
__(
16534 self
, "EnsureHolder", "bool", args
, virtual
=True, override
=True, const
=True
16536 self
.descriptor
= descriptor
16541 return EnsureHolder(cx, proxy,
16542 JSCLASS_RESERVED_SLOTS(JS::GetClass(proxy)) - 1,
16543 sCrossOriginProperties, holder);
16548 class CGDOMJSProxyHandler(CGClass
):
16549 def __init__(self
, descriptor
):
16551 descriptor
.supportsIndexedProperties()
16552 or descriptor
.supportsNamedProperties()
16553 or descriptor
.isMaybeCrossOriginObject()
16556 CGDOMJSProxyHandler_getOwnPropDescriptor(descriptor
),
16557 CGDOMJSProxyHandler_defineProperty(descriptor
),
16558 ClassUsingFromBaseDeclaration(
16559 "mozilla::dom::DOMProxyHandler", "defineProperty"
16561 CGDOMJSProxyHandler_ownPropNames(descriptor
),
16562 CGDOMJSProxyHandler_hasOwn(descriptor
),
16563 CGDOMJSProxyHandler_get(descriptor
),
16564 CGDOMJSProxyHandler_className(descriptor
),
16565 CGDOMJSProxyHandler_finalizeInBackground(descriptor
),
16566 CGDOMJSProxyHandler_finalize(descriptor
),
16567 CGJSProxyHandler_getInstance("DOMProxyHandler"),
16568 CGDOMJSProxyHandler_delete(descriptor
),
16571 ClassConstructor([], constexpr
=True, visibility
="public", explicit
=True)
16574 if descriptor
.supportsIndexedProperties():
16575 methods
.append(CGDOMJSProxyHandler_getElements(descriptor
))
16576 if descriptor
.operations
["IndexedSetter"] is not None or (
16577 descriptor
.operations
["NamedSetter"] is not None
16578 and descriptor
.interface
.getExtendedAttribute("LegacyOverrideBuiltIns")
16580 methods
.append(CGDOMJSProxyHandler_setCustom(descriptor
))
16581 if descriptor
.operations
["LegacyCaller"]:
16582 methods
.append(CGDOMJSProxyHandler_call())
16583 methods
.append(CGDOMJSProxyHandler_isCallable())
16584 if descriptor
.interface
.hasProbablyShortLivingWrapper():
16585 if not descriptor
.wrapperCache
:
16587 "Need a wrapper cache to support nursery "
16588 "allocation of DOM objects"
16590 methods
.append(CGDOMJSProxyHandler_canNurseryAllocate())
16591 if descriptor
.wrapperCache
:
16592 methods
.append(CGDOMJSProxyHandler_objectMoved(descriptor
))
16594 if descriptor
.isMaybeCrossOriginObject():
16597 CGDOMJSProxyHandler_getOwnPropertyDescriptor(descriptor
),
16598 CGDOMJSProxyHandler_getSameOriginPrototype(descriptor
),
16599 CGDOMJSProxyHandler_definePropertySameOrigin(descriptor
),
16600 CGDOMJSProxyHandler_set(descriptor
),
16601 CGDOMJSProxyHandler_EnsureHolder(descriptor
),
16602 ClassUsingFromBaseDeclaration(
16603 "MaybeCrossOriginObjectMixins", "EnsureHolder"
16608 if descriptor
.interface
.getExtendedAttribute("LegacyOverrideBuiltIns"):
16609 assert not descriptor
.isMaybeCrossOriginObject()
16610 parentClass
= "ShadowingDOMProxyHandler"
16611 elif descriptor
.isMaybeCrossOriginObject():
16612 parentClass
= "MaybeCrossOriginObject<mozilla::dom::DOMProxyHandler>"
16614 parentClass
= "mozilla::dom::DOMProxyHandler"
16619 bases
=[ClassBase(parentClass
)],
16620 constructors
=constructors
,
16625 class CGDOMJSProxyHandlerDeclarer(CGThing
):
16627 A class for declaring a DOMProxyHandler.
16630 def __init__(self
, handlerThing
):
16631 self
.handlerThing
= handlerThing
16634 # Our class declaration should happen when we're defining
16638 return self
.handlerThing
.declare()
16641 class CGDOMJSProxyHandlerDefiner(CGThing
):
16643 A class for defining a DOMProxyHandler.
16646 def __init__(self
, handlerThing
):
16647 self
.handlerThing
= handlerThing
16653 return self
.handlerThing
.define()
16656 def stripTrailingWhitespace(text
):
16657 tail
= "\n" if text
.endswith("\n") else ""
16658 lines
= text
.splitlines()
16659 return "\n".join(line
.rstrip() for line
in lines
) + tail
16662 class MemberProperties
:
16663 def __init__(self
):
16664 self
.isCrossOriginMethod
= False
16665 self
.isCrossOriginGetter
= False
16666 self
.isCrossOriginSetter
= False
16669 def memberProperties(m
, descriptor
):
16670 props
= MemberProperties()
16672 if not m
.isIdentifierLess() or m
== descriptor
.operations
["Stringifier"]:
16673 if not m
.isStatic() and descriptor
.interface
.hasInterfacePrototypeObject():
16674 if m
.getExtendedAttribute("CrossOriginCallable"):
16675 props
.isCrossOriginMethod
= True
16677 if not m
.isStatic() and descriptor
.interface
.hasInterfacePrototypeObject():
16678 if m
.getExtendedAttribute("CrossOriginReadable"):
16679 props
.isCrossOriginGetter
= True
16681 if not m
.isStatic() and descriptor
.interface
.hasInterfacePrototypeObject():
16682 if m
.getExtendedAttribute("CrossOriginWritable"):
16683 props
.isCrossOriginSetter
= True
16684 elif m
.getExtendedAttribute("PutForwards"):
16685 if m
.getExtendedAttribute("CrossOriginWritable"):
16686 props
.isCrossOriginSetter
= True
16687 elif m
.getExtendedAttribute("Replaceable") or m
.getExtendedAttribute(
16688 "LegacyLenientSetter"
16690 if m
.getExtendedAttribute("CrossOriginWritable"):
16691 props
.isCrossOriginSetter
= True
16696 class CGDescriptor(CGThing
):
16697 def __init__(self
, descriptor
, attributeTemplates
):
16698 CGThing
.__init
__(self
)
16701 not descriptor
.concrete
16702 or descriptor
.interface
.hasInterfacePrototypeObject()
16705 self
._deps
= descriptor
.interface
.getDeps()
16707 iteratorCGThings
= None
16709 descriptor
.interface
.isIterable()
16710 and descriptor
.interface
.maplikeOrSetlikeOrIterable
.isPairIterator()
16711 ) or descriptor
.interface
.isAsyncIterable():
16712 # We need the Wrap function when using the [Async]IterableIterator type, so we want to declare it before we need it. We don't really want to expose it in the header file, so we make it static too.
16713 iteratorCGThings
= []
16715 descriptor
.interface
.maplikeOrSetlikeOrIterable
.iteratorType
.inner
16717 iteratorDescriptor
= descriptor
.getDescriptor(itr_iface
.identifier
.name
)
16718 iteratorCGThings
.append(
16719 CGWrapNonWrapperCacheMethod(
16720 iteratorDescriptor
, static
=True, signatureOnly
=True
16723 iteratorCGThings
= CGList(
16724 (CGIndenter(t
, declareOnly
=True) for t
in iteratorCGThings
), "\n"
16726 iteratorCGThings
= CGWrapper(iteratorCGThings
, pre
="\n", post
="\n")
16727 iteratorCGThings
= CGWrapper(
16729 toBindingNamespace(iteratorDescriptor
.name
), iteratorCGThings
16736 isIteratorInterface
= (
16737 descriptor
.interface
.isIteratorInterface()
16738 or descriptor
.interface
.isAsyncIteratorInterface()
16740 if not isIteratorInterface
:
16742 CGGeneric(declare
="typedef %s NativeType;\n" % descriptor
.nativeType
)
16744 parent
= descriptor
.interface
.parent
16748 "static_assert(IsRefcounted<NativeType>::value == IsRefcounted<%s::NativeType>::value,\n"
16749 ' "Can\'t inherit from an interface with a different ownership model.");\n'
16750 % toBindingNamespace(descriptor
.parentPrototypeName
)
16754 defaultToJSONMethod
= None
16755 needCrossOriginPropertyArrays
= False
16756 unscopableNames
= list()
16758 for n
in descriptor
.interface
.legacyFactoryFunctions
:
16760 CGClassConstructor(descriptor
, n
, LegacyFactoryFunctionName(n
))
16763 if descriptor
.attributeTemplates
is not None:
16764 for template
in descriptor
.attributeTemplates
:
16765 if template
.getter
is not None:
16767 CGTemplateForSpecializedGetter(descriptor
, template
)
16769 if template
.setter
is not None:
16771 CGTemplateForSpecializedSetter(descriptor
, template
)
16774 for m
in descriptor
.interface
.members
:
16775 if m
.isMethod() and m
.identifier
.name
== "QueryInterface":
16778 props
= memberProperties(m
, descriptor
)
16781 if m
.getExtendedAttribute("Unscopable"):
16782 assert not m
.isStatic()
16783 unscopableNames
.append(m
.identifier
.name
)
16784 if m
.isDefaultToJSON():
16785 defaultToJSONMethod
= m
16787 not m
.isIdentifierLess()
16788 or m
== descriptor
.operations
["Stringifier"]
16791 assert descriptor
.interface
.hasInterfaceObject()
16792 cgThings
.append(CGStaticMethod(descriptor
, m
))
16793 if m
.returnsPromise():
16794 cgThings
.append(CGStaticMethodJitinfo(m
))
16795 elif descriptor
.interface
.hasInterfacePrototypeObject():
16796 specializedMethod
= CGSpecializedMethod(descriptor
, m
)
16797 cgThings
.append(specializedMethod
)
16798 if m
.returnsPromise():
16800 CGMethodPromiseWrapper(descriptor
, specializedMethod
)
16802 cgThings
.append(CGMemberJITInfo(descriptor
, m
))
16803 if props
.isCrossOriginMethod
:
16804 needCrossOriginPropertyArrays
= True
16805 # If we've hit the maplike/setlike member itself, go ahead and
16806 # generate its convenience functions.
16807 elif m
.isMaplikeOrSetlike():
16808 cgThings
.append(CGMaplikeOrSetlikeHelperGenerator(descriptor
, m
))
16810 if m
.type.isObservableArray():
16812 CGObservableArrayProxyHandlerGenerator(descriptor
, m
)
16814 cgThings
.append(CGObservableArrayHelperGenerator(descriptor
, m
))
16815 if m
.getExtendedAttribute("Unscopable"):
16816 assert not m
.isStatic()
16817 unscopableNames
.append(m
.identifier
.name
)
16819 assert descriptor
.interface
.hasInterfaceObject()
16820 cgThings
.append(CGStaticGetter(descriptor
, m
))
16821 elif descriptor
.interface
.hasInterfacePrototypeObject():
16822 template
= m
.getExtendedAttribute("BindingTemplate")
16823 if template
is not None:
16824 templateName
= template
[0][0]
16825 additionalArg
= template
[0][1]
16826 if not (m
.type.isPrimitive() or m
.type.isString()):
16828 "We only support primitives or strings on templated attributes. "
16829 "Attribute '%s' on interface '%s' has type '%s' but tries to "
16830 "use template '%s'"
16833 descriptor
.interface
.identifier
.name
,
16838 template
= attributeTemplates
.get(templateName
)
16839 specializedGetter
= CGSpecializedTemplatedGetter(
16840 descriptor
, m
, template
, additionalArg
16843 specializedGetter
= CGSpecializedGetter(descriptor
, m
)
16844 cgThings
.append(specializedGetter
)
16845 if m
.type.isPromise():
16847 CGGetterPromiseWrapper(descriptor
, specializedGetter
)
16849 if props
.isCrossOriginGetter
:
16850 needCrossOriginPropertyArrays
= True
16853 assert descriptor
.interface
.hasInterfaceObject()
16854 cgThings
.append(CGStaticSetter(descriptor
, m
))
16855 elif descriptor
.interface
.hasInterfacePrototypeObject():
16856 template
= m
.getExtendedAttribute("BindingTemplate")
16857 if template
is not None:
16858 if isinstance(template
[0], list):
16859 templateName
= template
[0][0]
16860 additionalArg
= template
[0][1]
16862 templateName
= template
[0]
16863 additionalArg
= None
16864 template
= attributeTemplates
.get(templateName
)
16865 specializedSetter
= CGSpecializedTemplatedSetter(
16866 descriptor
, m
, template
, additionalArg
16869 specializedSetter
= CGSpecializedSetter(descriptor
, m
)
16870 cgThings
.append(specializedSetter
)
16871 if props
.isCrossOriginSetter
:
16872 needCrossOriginPropertyArrays
= True
16873 elif m
.getExtendedAttribute("PutForwards"):
16874 cgThings
.append(CGSpecializedForwardingSetter(descriptor
, m
))
16875 if props
.isCrossOriginSetter
:
16876 needCrossOriginPropertyArrays
= True
16877 elif m
.getExtendedAttribute("Replaceable"):
16878 cgThings
.append(CGSpecializedReplaceableSetter(descriptor
, m
))
16879 elif m
.getExtendedAttribute("LegacyLenientSetter"):
16880 # XXX In this case, we need to add an include for mozilla/dom/Document.h to the generated cpp file.
16881 cgThings
.append(CGSpecializedLenientSetter(descriptor
, m
))
16884 and descriptor
.interface
.hasInterfacePrototypeObject()
16886 cgThings
.append(CGMemberJITInfo(descriptor
, m
))
16887 if m
.isConst() and m
.type.isPrimitive():
16888 cgThings
.append(CGConstDefinition(m
))
16890 if defaultToJSONMethod
:
16891 cgThings
.append(CGDefaultToJSONMethod(descriptor
, defaultToJSONMethod
))
16892 cgThings
.append(CGMemberJITInfo(descriptor
, defaultToJSONMethod
))
16894 if descriptor
.concrete
and not descriptor
.proxy
:
16895 if wantsAddProperty(descriptor
):
16896 cgThings
.append(CGAddPropertyHook(descriptor
))
16898 # Always have a finalize hook, regardless of whether the class
16899 # wants a custom hook.
16900 cgThings
.append(CGClassFinalizeHook(descriptor
))
16902 if wantsGetWrapperCache(descriptor
):
16903 cgThings
.append(CGGetWrapperCacheHook(descriptor
))
16905 if descriptor
.concrete
and descriptor
.wrapperCache
and not descriptor
.proxy
:
16906 cgThings
.append(CGClassObjectMovedHook(descriptor
))
16908 properties
= PropertyArrays(descriptor
)
16909 cgThings
.append(CGGeneric(define
=str(properties
)))
16910 cgThings
.append(CGNativeProperties(descriptor
, properties
))
16912 if defaultToJSONMethod
:
16913 # Now that we know about our property arrays, we can
16914 # output our "collect attribute values" method, which uses those.
16916 CGCollectJSONAttributesMethod(descriptor
, defaultToJSONMethod
)
16919 # Declare our DOMProxyHandler.
16920 if descriptor
.concrete
and descriptor
.proxy
:
16925 static_assert(std::is_base_of_v<nsISupports, ${nativeType}>,
16926 "We don't support non-nsISupports native classes for "
16927 "proxy-based bindings yet");
16930 nativeType
=descriptor
.nativeType
,
16934 if not descriptor
.wrapperCache
:
16936 "We need a wrappercache to support expandos for proxy-based "
16937 "bindings (" + descriptor
.name
+ ")"
16939 handlerThing
= CGDOMJSProxyHandler(descriptor
)
16940 cgThings
.append(CGDOMJSProxyHandlerDeclarer(handlerThing
))
16941 cgThings
.append(CGProxyIsProxy(descriptor
))
16942 cgThings
.append(CGProxyUnwrap(descriptor
))
16944 # Set up our Xray callbacks as needed. This needs to come
16945 # after we have our DOMProxyHandler defined.
16946 if descriptor
.wantsXrays
:
16947 if descriptor
.concrete
and descriptor
.proxy
:
16948 if descriptor
.needsXrayNamedDeleterHook():
16949 cgThings
.append(CGDeleteNamedProperty(descriptor
))
16950 elif descriptor
.needsXrayResolveHooks():
16951 cgThings
.append(CGResolveOwnPropertyViaResolve(descriptor
))
16953 CGEnumerateOwnPropertiesViaGetOwnPropertyNames(descriptor
)
16955 if descriptor
.wantsXrayExpandoClass
:
16956 cgThings
.append(CGXrayExpandoJSClass(descriptor
))
16958 # Now that we have our ResolveOwnProperty/EnumerateOwnProperties stuff
16959 # done, set up our NativePropertyHooks.
16960 cgThings
.append(CGNativePropertyHooks(descriptor
, properties
))
16962 if descriptor
.interface
.isNamespace():
16963 cgThings
.append(CGNamespaceObjectJSClass(descriptor
))
16964 elif descriptor
.interface
.hasInterfaceObject():
16965 cgThings
.append(CGClassConstructor(descriptor
, descriptor
.interface
.ctor()))
16966 cgThings
.append(CGInterfaceObjectInfo(descriptor
))
16967 cgThings
.append(CGLegacyFactoryFunctions(descriptor
))
16969 cgThings
.append(CGLegacyCallHook(descriptor
))
16970 if descriptor
.interface
.getExtendedAttribute("NeedResolve"):
16971 cgThings
.append(CGResolveHook(descriptor
))
16972 cgThings
.append(CGMayResolveHook(descriptor
))
16973 cgThings
.append(CGEnumerateHook(descriptor
))
16975 if descriptor
.hasNamedPropertiesObject
:
16976 cgThings
.append(CGGetNamedPropertiesObjectMethod(descriptor
))
16978 if descriptor
.interface
.hasInterfacePrototypeObject():
16979 cgThings
.append(CGPrototypeJSClass(descriptor
, properties
))
16982 descriptor
.interface
.hasInterfaceObject()
16983 and not descriptor
.interface
.isExternal()
16984 and descriptor
.isExposedConditionally()
16986 cgThings
.append(CGConstructorEnabled(descriptor
))
16989 descriptor
.interface
.hasMembersInSlots()
16990 and descriptor
.interface
.hasChildInterfaces()
16993 "We don't support members in slots on "
16994 "non-leaf interfaces like %s" % descriptor
.interface
.identifier
.name
16997 if descriptor
.needsMissingPropUseCounters
:
16998 cgThings
.append(CGCountMaybeMissingProperty(descriptor
))
17000 if descriptor
.concrete
:
17001 if descriptor
.interface
.isSerializable():
17002 cgThings
.append(CGSerializer(descriptor
))
17003 cgThings
.append(CGDeserializer(descriptor
))
17005 # CGDOMProxyJSClass/CGDOMJSClass need GetProtoObjectHandle, but we don't want to export it for the iterator interfaces, so declare it here.
17006 if isIteratorInterface
:
17008 CGGetProtoObjectHandleMethod(
17009 descriptor
, static
=True, signatureOnly
=True
17013 if descriptor
.proxy
:
17014 cgThings
.append(CGDOMJSProxyHandlerDefiner(handlerThing
))
17015 cgThings
.append(CGDOMProxyJSClass(descriptor
))
17017 cgThings
.append(CGDOMJSClass(descriptor
))
17019 if descriptor
.interface
.hasMembersInSlots():
17020 cgThings
.append(CGUpdateMemberSlotsMethod(descriptor
))
17022 if descriptor
.isGlobal():
17023 assert descriptor
.wrapperCache
17024 cgThings
.append(CGWrapGlobalMethod(descriptor
, properties
))
17025 elif descriptor
.wrapperCache
:
17026 cgThings
.append(CGWrapWithCacheMethod(descriptor
))
17027 cgThings
.append(CGWrapMethod(descriptor
))
17030 CGWrapNonWrapperCacheMethod(descriptor
, static
=isIteratorInterface
)
17033 # If we're not wrappercached, we don't know how to clear our
17034 # cached values, since we can't get at the JSObject.
17035 if descriptor
.wrapperCache
:
17037 CGClearCachedValueMethod(descriptor
, m
)
17038 for m
in clearableCachedAttrs(descriptor
)
17041 haveUnscopables
= (
17042 len(unscopableNames
) != 0
17043 and descriptor
.interface
.hasInterfacePrototypeObject()
17045 if haveUnscopables
:
17049 CGGeneric("static const char* const unscopableNames[] = {"),
17052 [CGGeneric('"%s"' % name
) for name
in unscopableNames
]
17053 + [CGGeneric("nullptr")],
17063 legacyWindowAliases
= descriptor
.interface
.legacyWindowAliases
17064 haveLegacyWindowAliases
= len(legacyWindowAliases
) != 0
17065 if haveLegacyWindowAliases
:
17069 CGGeneric("static const char* const legacyWindowAliases[] = {"),
17073 CGGeneric('"%s"' % name
)
17074 for name
in legacyWindowAliases
17076 + [CGGeneric("nullptr")],
17086 # CGCreateInterfaceObjectsMethod needs to come after our
17087 # CGDOMJSClass and unscopables, if any.
17089 CGCreateInterfaceObjectsMethod(
17093 haveLegacyWindowAliases
,
17094 static
=isIteratorInterface
,
17098 # CGGetProtoObjectMethod and CGGetConstructorObjectMethod need
17099 # to come after CGCreateInterfaceObjectsMethod.
17101 descriptor
.interface
.hasInterfacePrototypeObject()
17102 and not descriptor
.hasOrdinaryObjectPrototype
17105 CGGetProtoObjectHandleMethod(descriptor
, static
=isIteratorInterface
)
17107 if descriptor
.interface
.hasChildInterfaces():
17108 assert not isIteratorInterface
17109 cgThings
.append(CGGetProtoObjectMethod(descriptor
))
17110 if descriptor
.interface
.hasInterfaceObject():
17111 cgThings
.append(CGGetConstructorObjectHandleMethod(descriptor
))
17112 cgThings
.append(CGGetConstructorObjectMethod(descriptor
))
17114 # See whether we need to generate cross-origin property arrays.
17115 if needCrossOriginPropertyArrays
:
17116 cgThings
.append(CGCrossOriginProperties(descriptor
))
17118 cgThings
= CGList((CGIndenter(t
, declareOnly
=True) for t
in cgThings
), "\n")
17119 cgThings
= CGWrapper(cgThings
, pre
="\n", post
="\n")
17120 cgThings
= CGWrapper(
17121 CGNamespace(toBindingNamespace(descriptor
.name
), cgThings
), post
="\n"
17123 self
.cgRoot
= CGList([iteratorCGThings
, cgThings
], "\n")
17126 return self
.cgRoot
.declare()
17129 return self
.cgRoot
.define()
17135 class CGNamespacedEnum(CGThing
):
17136 def __init__(self
, namespace
, enumName
, names
, values
, comment
=""):
17140 # Account for explicit enum values.
17142 for i
in range(0, len(names
)):
17143 if len(values
) > i
and values
[i
] is not None:
17144 entry
= "%s = %s" % (names
[i
], values
[i
])
17147 entries
.append(entry
)
17150 entries
.append("_" + enumName
+ "_Count")
17153 entries
= [" " + e
for e
in entries
]
17155 # Build the enum body.
17156 enumstr
= comment
+ "enum %s : uint16_t\n{\n%s\n};\n" % (
17158 ",\n".join(entries
),
17160 curr
= CGGeneric(declare
=enumstr
)
17162 # Add some whitespace padding.
17163 curr
= CGWrapper(curr
, pre
="\n", post
="\n")
17165 # Add the namespace.
17166 curr
= CGNamespace(namespace
, curr
)
17169 typedef
= "\ntypedef %s::%s %s;\n\n" % (namespace
, enumName
, enumName
)
17170 curr
= CGList([curr
, CGGeneric(declare
=typedef
)])
17176 return self
.node
.declare()
17182 def initIdsClassMethod(identifiers
, atomCacheName
):
17184 '!atomsCache->%s.init(cx, "%s")' % (CGDictionary
.makeIdName(id), id)
17185 for id in identifiers
17190 MOZ_ASSERT(reinterpret_cast<jsid*>(atomsCache)->isVoid());
17192 // Initialize these in reverse order so that any failure leaves the first one
17199 idinit
=" ||\n ".join(idinit
),
17201 return ClassMethod(
17204 [Argument("JSContext*", "cx"), Argument("%s*" % atomCacheName
, "atomsCache")],
17207 visibility
="private",
17211 class CGDictionary(CGThing
):
17212 def __init__(self
, dictionary
, descriptorProvider
):
17213 self
.dictionary
= dictionary
17214 self
.descriptorProvider
= descriptorProvider
17215 self
.needToInitIds
= len(dictionary
.members
) > 0
17216 self
.memberInfo
= [
17219 getJSToNativeConversionInfo(
17221 descriptorProvider
,
17222 isMember
="Dictionary",
17223 isOptional
=member
.canHaveMissingValue(),
17224 isKnownMissing
=not dictionary
.needsConversionFromJS
,
17225 defaultValue
=member
.defaultValue
,
17226 sourceDescription
=self
.getMemberSourceDescription(member
),
17229 for member
in dictionary
.members
17232 # If we have a union member which is going to be declared in a different
17233 # header but contains something that will be declared in the same header
17234 # as us, bail: the C++ includes won't work out.
17235 for member
in dictionary
.members
:
17236 type = member
.type.unroll()
17237 if type.isUnion() and CGHeaders
.getUnionDeclarationFilename(
17238 descriptorProvider
.getConfig(), type
17239 ) != CGHeaders
.getDeclarationFilename(dictionary
):
17240 for t
in type.flatMemberTypes
:
17241 if t
.isDictionary() and CGHeaders
.getDeclarationFilename(
17243 ) == CGHeaders
.getDeclarationFilename(dictionary
):
17245 "Dictionary contains a union that will live in a different "
17246 "header that contains a dictionary from the same header as "
17247 "the original dictionary. This won't compile. Move the "
17248 "inner dictionary to a different Web IDL file to move it "
17249 "to a different header.\n%s\n%s"
17250 % (t
.location
, t
.inner
.location
)
17252 self
.structs
= self
.getStructs()
17255 return self
.structs
.declare()
17258 return self
.structs
.define()
17261 if self
.dictionary
.parent
:
17262 return self
.makeClassName(self
.dictionary
.parent
)
17263 return "DictionaryBase"
17265 def initMethod(self
):
17267 This function outputs the body of the Init() method for the dictionary.
17269 For the most part, this is some bookkeeping for our atoms so
17270 we can avoid atomizing strings all the time, then we just spit
17271 out the getMemberConversion() output for each member,
17272 separated by newlines.
17277 // Passing a null JSContext is OK only if we're initing from null,
17278 // Since in that case we will not have to do any property gets
17279 // Also evaluate isNullOrUndefined in order to avoid false-positive
17280 // checkers by static analysis tools
17281 MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined());
17285 if self
.needToInitIds
:
17288 ${dictName}Atoms* atomsCache = nullptr;
17290 atomsCache = GetAtomCache<${dictName}Atoms>(cx);
17291 if (reinterpret_cast<jsid*>(atomsCache)->isVoid() &&
17292 !InitIds(cx, atomsCache)) {
17298 dictName
=self
.makeClassName(self
.dictionary
),
17301 if self
.dictionary
.parent
:
17304 // Per spec, we init the parent's members first
17305 if (!${dictName}::Init(cx, val)) {
17310 dictName
=self
.makeClassName(self
.dictionary
.parent
),
17315 if (!IsConvertibleToDictionary(val)) {
17316 return cx.ThrowErrorMessage<MSG_CONVERSION_ERROR>(sourceDescription, "dictionary");
17322 memberInits
= [self
.getMemberConversion(m
).define() for m
in self
.memberInfo
]
17326 bool isNull = val.isNullOrUndefined();
17327 // We only need these if !isNull, in which case we have |cx|.
17328 Maybe<JS::Rooted<JSObject *> > object;
17329 Maybe<JS::Rooted<JS::Value> > temp;
17332 object.emplace(cx, &val.toObject());
17337 memberInits
="\n".join(memberInits
),
17340 body
+= "return true;\n"
17342 return ClassMethod(
17346 Argument("BindingCallContext&", "cx"),
17347 Argument("JS::Handle<JS::Value>", "val"),
17348 Argument("const char*", "sourceDescription", default
='"Value"'),
17349 Argument("bool", "passedToJSImpl", default
="false"),
17354 def initWithoutCallContextMethod(self
):
17356 This function outputs the body of an Init() method for the dictionary
17357 that takes just a JSContext*. This is needed for non-binding consumers.
17361 // We don't want to use sourceDescription for our context here;
17362 // that's not really what it's formatted for.
17363 BindingCallContext cx(cx_, nullptr);
17364 return Init(cx, val, sourceDescription, passedToJSImpl);
17367 return ClassMethod(
17371 Argument("JSContext*", "cx_"),
17372 Argument("JS::Handle<JS::Value>", "val"),
17373 Argument("const char*", "sourceDescription", default
='"Value"'),
17374 Argument("bool", "passedToJSImpl", default
="false"),
17379 def simpleInitMethod(self
):
17381 This function outputs the body of the Init() method for the dictionary,
17382 for cases when we are just default-initializing it.
17385 relevantMembers
= [
17387 for m
in self
.memberInfo
17388 # We only need to init the things that can have
17390 if m
[0].optional
and m
[0].defaultValue
17393 # We mostly avoid outputting code that uses cx in our native-to-JS
17394 # conversions, but there is one exception: we may have a
17395 # dictionary-typed member that _does_ generally support conversion from
17396 # JS. If we have such a thing, we can pass it a null JSContext and
17397 # JS::NullHandleValue to default-initialize it, but since the
17398 # native-to-JS templates hardcode `cx` as the JSContext value, we're
17399 # going to need to provide that.
17400 haveMemberThatNeedsCx
= any(
17401 m
[0].type.isDictionary() and m
[0].type.unroll().inner
.needsConversionFromJS
17402 for m
in relevantMembers
17404 if haveMemberThatNeedsCx
:
17407 JSContext* cx = nullptr;
17413 if self
.dictionary
.parent
:
17414 if self
.dictionary
.parent
.needsConversionFromJS
:
17415 args
= "nullptr, JS::NullHandleValue"
17420 // We init the parent's members first
17421 if (!${dictName}::Init(${args})) {
17426 dictName
=self
.makeClassName(self
.dictionary
.parent
),
17431 self
.getMemberConversion(m
, isKnownMissing
=True).define()
17432 for m
in relevantMembers
17439 memberInits
="\n".join(memberInits
),
17442 body
+= "return true;\n"
17444 return ClassMethod(
17448 Argument("const char*", "sourceDescription", default
='"Value"'),
17449 Argument("bool", "passedToJSImpl", default
="false"),
17454 def initFromJSONMethod(self
):
17455 return ClassMethod(
17458 [Argument("const nsAString&", "aJSON")],
17462 JSObject* cleanGlobal = SimpleGlobalObject::Create(SimpleGlobalObject::GlobalType::BindingDetail);
17463 if (!cleanGlobal) {
17466 if (!jsapi.Init(cleanGlobal)) {
17469 JSContext* cx = jsapi.cx();
17470 JS::Rooted<JS::Value> json(cx);
17471 bool ok = ParseJSON(cx, aJSON, &json);
17472 NS_ENSURE_TRUE(ok, false);
17473 return Init(cx, json);
17478 def toJSONMethod(self
):
17479 return ClassMethod(
17482 [Argument("nsAString&", "aJSON")],
17487 JSContext *cx = jsapi.cx();
17488 // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here
17489 // because we'll only be creating objects, in ways that have no
17490 // side-effects, followed by a call to JS::ToJSONMaybeSafely,
17491 // which likewise guarantees no side-effects for the sorts of
17492 // things we will pass it.
17493 JSObject* scope = UnprivilegedJunkScopeOrWorkerGlobal(fallible);
17495 JS_ReportOutOfMemory(cx);
17498 JSAutoRealm ar(cx, scope);
17499 JS::Rooted<JS::Value> val(cx);
17500 if (!ToObjectInternal(cx, &val)) {
17503 JS::Rooted<JSObject*> obj(cx, &val.toObject());
17504 return StringifyToJSON(cx, obj, aJSON);
17510 def toObjectInternalMethod(self
):
17512 if self
.needToInitIds
:
17515 ${dictName}Atoms* atomsCache = GetAtomCache<${dictName}Atoms>(cx);
17516 if (reinterpret_cast<jsid*>(atomsCache)->isVoid() &&
17517 !InitIds(cx, atomsCache)) {
17522 dictName
=self
.makeClassName(self
.dictionary
),
17525 if self
.dictionary
.parent
:
17528 // Per spec, we define the parent's members first
17529 if (!${dictName}::ToObjectInternal(cx, rval)) {
17532 JS::Rooted<JSObject*> obj(cx, &rval.toObject());
17535 dictName
=self
.makeClassName(self
.dictionary
.parent
),
17540 JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx));
17544 rval.set(JS::ObjectValue(*obj));
17549 if self
.memberInfo
:
17551 self
.getMemberDefinition(m
).define() for m
in self
.memberInfo
17553 body
+= "\nreturn true;\n"
17555 return ClassMethod(
17556 "ToObjectInternal",
17559 Argument("JSContext*", "cx"),
17560 Argument("JS::MutableHandle<JS::Value>", "rval"),
17566 def initIdsMethod(self
):
17567 assert self
.needToInitIds
17568 return initIdsClassMethod(
17569 [m
.identifier
.name
for m
in self
.dictionary
.members
],
17570 "%sAtoms" % self
.makeClassName(self
.dictionary
),
17573 def traceDictionaryMethod(self
):
17575 if self
.dictionary
.parent
:
17576 cls
= self
.makeClassName(self
.dictionary
.parent
)
17577 body
+= "%s::TraceDictionary(trc);\n" % cls
17580 self
.getMemberTrace(m
)
17581 for m
in self
.dictionary
.members
17582 if typeNeedsRooting(m
.type)
17586 body
+= "\n".join(memberTraces
)
17588 return ClassMethod(
17592 Argument("JSTracer*", "trc"),
17598 def dictionaryNeedsCycleCollection(dictionary
):
17599 return any(idlTypeNeedsCycleCollection(m
.type) for m
in dictionary
.members
) or (
17601 and CGDictionary
.dictionaryNeedsCycleCollection(dictionary
.parent
)
17604 def traverseForCCMethod(self
):
17606 if self
.dictionary
.parent
and self
.dictionaryNeedsCycleCollection(
17607 self
.dictionary
.parent
17609 cls
= self
.makeClassName(self
.dictionary
.parent
)
17610 body
+= "%s::TraverseForCC(aCallback, aFlags);\n" % cls
17612 for m
, _
in self
.memberInfo
:
17613 if idlTypeNeedsCycleCollection(m
.type):
17614 memberName
= self
.makeMemberName(m
.identifier
.name
)
17616 'ImplCycleCollectionTraverse(aCallback, %s, "%s", aFlags);\n'
17617 % (memberName
, memberName
)
17620 return ClassMethod(
17624 Argument("nsCycleCollectionTraversalCallback&", "aCallback"),
17625 Argument("uint32_t", "aFlags"),
17628 # Inline so we don't pay a codesize hit unless someone actually uses
17629 # this traverse method.
17634 def unlinkForCCMethod(self
):
17636 if self
.dictionary
.parent
and self
.dictionaryNeedsCycleCollection(
17637 self
.dictionary
.parent
17639 cls
= self
.makeClassName(self
.dictionary
.parent
)
17640 body
+= "%s::UnlinkForCC();\n" % cls
17642 for m
, _
in self
.memberInfo
:
17643 if idlTypeNeedsCycleCollection(m
.type):
17644 memberName
= self
.makeMemberName(m
.identifier
.name
)
17645 body
+= "ImplCycleCollectionUnlink(%s);\n" % memberName
17647 return ClassMethod(
17652 # Inline so we don't pay a codesize hit unless someone actually uses
17653 # this unlink method.
17658 def assignmentOperator(self
):
17660 body
.append(CGGeneric("%s::operator=(aOther);\n" % self
.base()))
17662 for m
, _
in self
.memberInfo
:
17663 memberName
= self
.makeMemberName(m
.identifier
.name
)
17664 if m
.canHaveMissingValue():
17665 memberAssign
= CGGeneric(
17669 if (aOther.${name}.WasPassed()) {
17670 ${name}.Construct(aOther.${name}.Value());
17677 memberAssign
= CGGeneric("%s = aOther.%s;\n" % (memberName
, memberName
))
17678 body
.append(memberAssign
)
17679 body
.append(CGGeneric("return *this;\n"))
17680 return ClassMethod(
17682 "%s&" % self
.makeClassName(self
.dictionary
),
17683 [Argument("const %s&" % self
.makeClassName(self
.dictionary
), "aOther")],
17684 body
=body
.define(),
17687 def canHaveEqualsOperator(self
):
17689 m
.type.isString() or m
.type.isPrimitive() for (m
, _
) in self
.memberInfo
17692 def equalsOperator(self
):
17695 for m
, _
in self
.memberInfo
:
17696 memberName
= self
.makeMemberName(m
.identifier
.name
)
17697 memberTest
= CGGeneric(
17700 if (${memberName} != aOther.${memberName}) {
17704 memberName
=memberName
,
17707 body
.append(memberTest
)
17708 body
.append(CGGeneric("return true;\n"))
17709 return ClassMethod(
17712 [Argument("const %s&" % self
.makeClassName(self
.dictionary
), "aOther")],
17714 body
=body
.define(),
17717 def getStructs(self
):
17718 d
= self
.dictionary
17719 selfName
= self
.makeClassName(d
)
17722 self
.makeMemberName(m
[0].identifier
.name
),
17723 self
.getMemberType(m
),
17724 visibility
="public",
17725 body
=self
.getMemberInitializer(m
),
17726 hasIgnoreInitCheckFlag
=True,
17728 for m
in self
.memberInfo
17731 # We always want to init our parent with our non-initializing
17732 # constructor arg, because either we're about to init ourselves (and
17733 # hence our parent) or we don't want any init happening.
17734 baseConstructors
= [
17736 % (self
.makeClassName(d
.parent
), self
.getNonInitializingCtorArg())
17739 baseConstructors
= None
17741 if d
.needsConversionFromJS
:
17742 initArgs
= "nullptr, JS::NullHandleValue"
17748 visibility
="public",
17749 baseConstructors
=baseConstructors
,
17751 "// Safe to pass a null context if we pass a null value\n"
17752 "Init(%s);\n" % initArgs
17756 [Argument("const FastDictionaryInitializer&", "")],
17757 visibility
="public",
17758 baseConstructors
=baseConstructors
,
17761 body
='// Do nothing here; this is used by our "Fast" subclass\n',
17766 if self
.needToInitIds
:
17767 methods
.append(self
.initIdsMethod())
17769 if d
.needsConversionFromJS
:
17770 methods
.append(self
.initMethod())
17771 methods
.append(self
.initWithoutCallContextMethod())
17773 methods
.append(self
.simpleInitMethod())
17775 canBeRepresentedAsJSON
= self
.dictionarySafeToJSONify(d
)
17776 if canBeRepresentedAsJSON
and d
.getExtendedAttribute("GenerateInitFromJSON"):
17777 methods
.append(self
.initFromJSONMethod())
17779 if d
.needsConversionToJS
:
17780 methods
.append(self
.toObjectInternalMethod())
17782 if canBeRepresentedAsJSON
and d
.getExtendedAttribute("GenerateToJSON"):
17783 methods
.append(self
.toJSONMethod())
17785 methods
.append(self
.traceDictionaryMethod())
17788 if self
.dictionaryNeedsCycleCollection(d
):
17789 methods
.append(self
.traverseForCCMethod())
17790 methods
.append(self
.unlinkForCCMethod())
17791 except CycleCollectionUnsupported
:
17792 # We have some member that we don't know how to CC. Don't output
17793 # our cycle collection overloads, so attempts to CC us will fail to
17794 # compile instead of misbehaving.
17799 [Argument("%s&&" % selfName
, "aOther")],
17801 visibility
="public",
17802 baseConstructors
=baseConstructors
,
17806 if CGDictionary
.isDictionaryCopyConstructible(d
):
17807 disallowCopyConstruction
= False
17808 # Note: gcc's -Wextra has a warning against not initializng our
17809 # base explicitly. If we have one. Use our non-initializing base
17810 # constructor to get around that.
17813 [Argument("const %s&" % selfName
, "aOther")],
17815 visibility
="public",
17816 baseConstructors
=baseConstructors
,
17818 body
="*this = aOther;\n",
17821 methods
.append(self
.assignmentOperator())
17823 disallowCopyConstruction
= True
17825 if self
.canHaveEqualsOperator():
17826 methods
.append(self
.equalsOperator())
17830 bases
=[ClassBase(self
.base())],
17832 constructors
=ctors
,
17835 disallowCopyConstruction
=disallowCopyConstruction
,
17838 fastDictionaryCtor
= ClassConstructor(
17840 visibility
="public",
17842 baseConstructors
=["%s(%s)" % (selfName
, self
.getNonInitializingCtorArg())],
17843 body
="// Doesn't matter what int we pass to the parent constructor\n",
17846 fastStruct
= CGClass(
17848 bases
=[ClassBase(selfName
)],
17849 constructors
=[fastDictionaryCtor
],
17853 return CGList([struct
, CGNamespace("binding_detail", fastStruct
)], "\n")
17856 return self
.dictionary
.getDeps()
17859 def makeDictionaryName(dictionary
):
17860 return dictionary
.identifier
.name
17862 def makeClassName(self
, dictionary
):
17863 return self
.makeDictionaryName(dictionary
)
17866 def makeMemberName(name
):
17867 return "m" + name
[0].upper() + IDLToCIdentifier(name
[1:])
17869 def getMemberType(self
, memberInfo
):
17870 member
, conversionInfo
= memberInfo
17871 # We can't handle having a holderType here
17872 assert conversionInfo
.holderType
is None
17874 if member
.getExtendedAttribute("BinaryType"):
17875 return member
.getExtendedAttribute("BinaryType")[0]
17877 declType
= conversionInfo
.declType
17878 if conversionInfo
.dealWithOptional
:
17879 declType
= CGTemplatedType("Optional", declType
)
17880 return declType
.define()
17882 def getMemberConversion(self
, memberInfo
, isKnownMissing
=False):
17884 A function that outputs the initialization of a single dictionary
17885 member from the given dictionary value.
17887 We start with our conversionInfo, which tells us how to
17888 convert a JS::Value to whatever type this member is. We
17889 substiture the template from the conversionInfo with values
17890 that point to our "temp" JS::Value and our member (which is
17891 the C++ value we want to produce). The output is a string of
17892 code to do the conversion. We store this string in
17893 conversionReplacements["convert"].
17895 Now we have three different ways we might use (or skip) this
17896 string of code, depending on whether the value is required,
17897 optional with default value, or optional without default
17898 value. We set up a template in the 'conversion' variable for
17899 exactly how to do this, then substitute into it from the
17900 conversionReplacements dictionary.
17902 member
, conversionInfo
= memberInfo
17904 # We should only be initializing things with default values if
17905 # we're always-missing.
17906 assert not isKnownMissing
or (member
.optional
and member
.defaultValue
)
17909 "declName": self
.makeMemberName(member
.identifier
.name
),
17910 # We need a holder name for external interfaces, but
17911 # it's scoped down to the conversion so we can just use
17912 # anything we want.
17913 "holderName": "holder",
17914 "passedToJSImpl": "passedToJSImpl",
17918 replacements
["val"] = "(JS::NullHandleValue)"
17920 replacements
["val"] = "temp.ref()"
17921 replacements
["maybeMutableVal"] = "temp.ptr()"
17923 # We can't handle having a holderType here
17924 assert conversionInfo
.holderType
is None
17925 if conversionInfo
.dealWithOptional
:
17926 replacements
["declName"] = "(" + replacements
["declName"] + ".Value())"
17927 if member
.defaultValue
:
17929 replacements
["haveValue"] = "false"
17931 replacements
["haveValue"] = "!isNull && !temp->isUndefined()"
17933 propId
= self
.makeIdName(member
.identifier
.name
)
17934 propGet
= "JS_GetPropertyById(cx, *object, atomsCache->%s, temp.ptr())" % propId
17936 conversionReplacements
= {
17937 "prop": self
.makeMemberName(member
.identifier
.name
),
17938 "convert": string
.Template(conversionInfo
.template
).substitute(
17941 "propGet": propGet
,
17943 # The conversion code will only run where a default value or a value passed
17944 # by the author needs to get converted, so we can remember if we have any
17945 # members present here.
17946 conversionReplacements
["convert"] += "mIsAnyMemberPresent = true;\n"
17950 setTempValue
= CGGeneric(
17959 conditions
= getConditionList(member
, "cx", "*object")
17960 if len(conditions
) != 0:
17961 setTempValue
= CGIfElseWrapper(
17962 conditions
.define(),
17964 CGGeneric("temp->setUndefined();\n"),
17966 setTempValue
= CGIfWrapper(setTempValue
, "!isNull")
17967 conversion
= setTempValue
.define()
17969 if member
.defaultValue
:
17970 if member
.type.isUnion() and (
17971 not member
.type.nullable()
17972 or not isinstance(member
.defaultValue
, IDLNullValue
)
17974 # Since this has a default value, it might have been initialized
17975 # already. Go ahead and uninit it before we try to init it
17977 memberName
= self
.makeMemberName(member
.identifier
.name
)
17978 if member
.type.nullable():
17979 conversion
+= fill(
17981 if (!${memberName}.IsNull()) {
17982 ${memberName}.Value().Uninit();
17985 memberName
=memberName
,
17988 conversion
+= "%s.Uninit();\n" % memberName
17989 conversion
+= "${convert}"
17990 elif not conversionInfo
.dealWithOptional
:
17991 # We're required, but have no default value. Make sure
17992 # that we throw if we have no value provided.
17993 conversion
+= dedent(
17995 if (!isNull && !temp->isUndefined()) {
17998 // Don't error out if we have no cx. In that
17999 // situation the caller is default-constructing us and we'll
18000 // just assume they know what they're doing.
18001 return cx.ThrowErrorMessage<MSG_MISSING_REQUIRED_DICTIONARY_MEMBER>("%s");
18004 % self
.getMemberSourceDescription(member
)
18006 conversionReplacements
["convert"] = indent(
18007 conversionReplacements
["convert"]
18011 "if (!isNull && !temp->isUndefined()) {\n"
18012 " ${prop}.Construct();\n"
18016 conversionReplacements
["convert"] = indent(
18017 conversionReplacements
["convert"]
18020 return CGGeneric(string
.Template(conversion
).substitute(conversionReplacements
))
18022 def getMemberDefinition(self
, memberInfo
):
18023 member
= memberInfo
[0]
18024 declType
= memberInfo
[1].declType
18025 memberLoc
= self
.makeMemberName(member
.identifier
.name
)
18026 if not member
.canHaveMissingValue():
18027 memberData
= memberLoc
18029 # The data is inside the Optional<>
18030 memberData
= "%s.InternalValue()" % memberLoc
18032 # If you have to change this list (which you shouldn't!), make sure it
18033 # continues to match the list in test_Object.prototype_props.html
18034 if member
.identifier
.name
in [
18041 "propertyIsEnumerable",
18042 "__defineGetter__",
18043 "__defineSetter__",
18044 "__lookupGetter__",
18045 "__lookupSetter__",
18049 "'%s' member of %s dictionary shadows "
18050 "a property of Object.prototype, and Xrays to "
18051 "Object can't handle that.\n"
18054 member
.identifier
.name
,
18055 self
.dictionary
.identifier
.name
,
18061 "JS_DefinePropertyById(cx, obj, atomsCache->%s, temp, JSPROP_ENUMERATE)"
18062 % self
.makeIdName(member
.identifier
.name
)
18065 innerTemplate
= wrapForType(
18067 self
.descriptorProvider
,
18069 "result": "currentValue",
18071 "if (!%s) {\n" " return false;\n" "}\n" "break;\n" % propDef
18073 "jsvalRef": "temp",
18074 "jsvalHandle": "&temp",
18075 "returnsNewObject": False,
18076 # 'obj' can just be allowed to be the string "obj", since that
18077 # will be our dictionary object, which is presumably itself in
18079 "spiderMonkeyInterfacesAreStructs": True,
18082 conversion
= CGGeneric(innerTemplate
)
18083 conversion
= CGWrapper(
18086 "JS::Rooted<JS::Value> temp(cx);\n"
18087 "%s const & currentValue = %s;\n" % (declType
.define(), memberData
)
18091 # Now make sure that our successCode can actually break out of the
18092 # conversion. This incidentally gives us a scope for 'temp' and
18094 conversion
= CGWrapper(
18095 CGIndenter(conversion
),
18098 " // block for our 'break' successCode and scope for 'temp' and 'currentValue'\n"
18100 post
="} while(false);\n",
18102 if member
.canHaveMissingValue():
18103 # Only do the conversion if we have a value
18104 conversion
= CGIfWrapper(conversion
, "%s.WasPassed()" % memberLoc
)
18105 conditions
= getConditionList(member
, "cx", "obj")
18106 if len(conditions
) != 0:
18107 conversion
= CGIfWrapper(conversion
, conditions
.define())
18110 def getMemberTrace(self
, member
):
18112 assert typeNeedsRooting(type)
18113 memberLoc
= self
.makeMemberName(member
.identifier
.name
)
18114 if not member
.canHaveMissingValue():
18115 memberData
= memberLoc
18117 # The data is inside the Optional<>
18118 memberData
= "%s.Value()" % memberLoc
18120 memberName
= "%s.%s" % (self
.makeClassName(self
.dictionary
), memberLoc
)
18122 if type.isObject():
18124 'JS::TraceRoot(trc, %s, "%s");\n' % ("&" + memberData
, memberName
)
18126 if type.nullable():
18127 trace
= CGIfWrapper(trace
, memberData
)
18130 'JS::TraceRoot(trc, %s, "%s");\n' % ("&" + memberData
, memberName
)
18134 or type.isDictionary()
18135 or type.isSpiderMonkeyInterface()
18139 if type.nullable():
18140 memberNullable
= memberData
18141 memberData
= "%s.Value()" % memberData
18142 if type.isSequence():
18143 trace
= CGGeneric("DoTraceSequence(trc, %s);\n" % memberData
)
18144 elif type.isDictionary():
18145 trace
= CGGeneric("%s.TraceDictionary(trc);\n" % memberData
)
18146 elif type.isUnion():
18147 trace
= CGGeneric("%s.TraceUnion(trc);\n" % memberData
)
18148 elif type.isRecord():
18149 trace
= CGGeneric("TraceRecord(trc, %s);\n" % memberData
)
18151 assert type.isSpiderMonkeyInterface()
18152 trace
= CGGeneric("%s.TraceSelf(trc);\n" % memberData
)
18153 if type.nullable():
18154 trace
= CGIfWrapper(trace
, "!%s.IsNull()" % memberNullable
)
18156 assert False # unknown type
18158 if member
.canHaveMissingValue():
18159 trace
= CGIfWrapper(trace
, "%s.WasPassed()" % memberLoc
)
18161 return trace
.define()
18163 def getMemberInitializer(self
, memberInfo
):
18165 Get the right initializer for the member. Most members don't need one,
18166 but we need to pre-initialize 'object' that have a default value or are
18167 required (and hence are not inside Optional), so they're safe to trace
18168 at all times. And we can optimize a bit for dictionary-typed members.
18170 member
, _
= memberInfo
18171 if member
.canHaveMissingValue():
18172 # Allowed missing value means no need to set it up front, since it's
18173 # inside an Optional and won't get traced until it's actually set
18177 if type.isDictionary():
18178 # When we construct ourselves, we don't want to init our member
18179 # dictionaries. Either we're being constructed-but-not-initialized
18180 # ourselves (and then we don't want to init them) or we're about to
18181 # init ourselves and then we'll init them anyway.
18182 return CGDictionary
.getNonInitializingCtorArg()
18183 return initializerForType(type)
18185 def getMemberSourceDescription(self
, member
):
18186 return "'%s' member of %s" % (
18187 member
.identifier
.name
,
18188 self
.dictionary
.identifier
.name
,
18192 def makeIdName(name
):
18193 return IDLToCIdentifier(name
) + "_id"
18196 def getNonInitializingCtorArg():
18197 return "FastDictionaryInitializer()"
18200 def isDictionaryCopyConstructible(dictionary
):
18201 if dictionary
.parent
and not CGDictionary
.isDictionaryCopyConstructible(
18205 return all(isTypeCopyConstructible(m
.type) for m
in dictionary
.members
)
18208 def typeSafeToJSONify(type):
18210 Determine whether the given type is safe to convert to JSON. The
18211 restriction is that this needs to be safe while in a global controlled
18212 by an adversary, and "safe" means no side-effects when the JS
18213 representation of this type is converted to JSON. That means that we
18214 have to be pretty restrictive about what things we can allow. For
18215 example, "object" is out, because it may have accessor properties on it.
18217 if type.nullable():
18218 # Converting null to JSON is always OK.
18219 return CGDictionary
.typeSafeToJSONify(type.inner
)
18221 if type.isSequence():
18222 # Sequences are arrays we create ourselves, with no holes. They
18223 # should be safe if their contents are safe, as long as we suppress
18224 # invocation of .toJSON on objects.
18225 return CGDictionary
.typeSafeToJSONify(type.inner
)
18228 # OK if everything in it is ok.
18229 return all(CGDictionary
.typeSafeToJSONify(t
) for t
in type.flatMemberTypes
)
18231 if type.isDictionary():
18232 # OK if the dictionary is OK
18233 return CGDictionary
.dictionarySafeToJSONify(type.inner
)
18235 if type.isUndefined() or type.isString() or type.isEnum():
18236 # Strings are always OK.
18239 if type.isPrimitive():
18240 # Primitives (numbers and booleans) are ok, as long as
18241 # they're not unrestricted float/double.
18242 return not type.isFloat() or not type.isUnrestricted()
18244 if type.isRecord():
18245 # Records are okay, as long as the value type is.
18246 # Per spec, only strings are allowed as keys.
18247 return CGDictionary
.typeSafeToJSONify(type.inner
)
18252 def dictionarySafeToJSONify(dictionary
):
18253 # The dictionary itself is OK, so we're good if all our types are.
18254 return all(CGDictionary
.typeSafeToJSONify(m
.type) for m
in dictionary
.members
)
18257 class CGRegisterWorkerBindings(CGAbstractMethod
):
18258 def __init__(self
, config
):
18259 CGAbstractMethod
.__init
__(
18262 "RegisterWorkerBindings",
18264 [Argument("JSContext*", "aCx"), Argument("JS::Handle<JSObject*>", "aObj")],
18266 self
.config
= config
18268 def definition_body(self
):
18269 descriptors
= self
.config
.getDescriptors(
18270 hasInterfaceObject
=True, isExposedInAnyWorker
=True, register
=True
18273 for desc
in descriptors
:
18274 bindingNS
= toBindingNamespace(desc
.name
)
18275 condition
= "!%s::GetConstructorObject(aCx)" % bindingNS
18276 if desc
.isExposedConditionally():
18278 "%s::ConstructorEnabled(aCx, aObj) && " % bindingNS
+ condition
18280 conditions
.append(condition
)
18282 CGIfWrapper(CGGeneric("return false;\n"), condition
)
18283 for condition
in conditions
18285 lines
.append(CGGeneric("return true;\n"))
18286 return CGList(lines
, "\n").define()
18289 class CGRegisterWorkerDebuggerBindings(CGAbstractMethod
):
18290 def __init__(self
, config
):
18291 CGAbstractMethod
.__init
__(
18294 "RegisterWorkerDebuggerBindings",
18296 [Argument("JSContext*", "aCx"), Argument("JS::Handle<JSObject*>", "aObj")],
18298 self
.config
= config
18300 def definition_body(self
):
18301 descriptors
= self
.config
.getDescriptors(
18302 hasInterfaceObject
=True, isExposedInWorkerDebugger
=True, register
=True
18305 for desc
in descriptors
:
18306 bindingNS
= toBindingNamespace(desc
.name
)
18307 condition
= "!%s::GetConstructorObject(aCx)" % bindingNS
18308 if desc
.isExposedConditionally():
18310 "%s::ConstructorEnabled(aCx, aObj) && " % bindingNS
+ condition
18312 conditions
.append(condition
)
18314 CGIfWrapper(CGGeneric("return false;\n"), condition
)
18315 for condition
in conditions
18317 lines
.append(CGGeneric("return true;\n"))
18318 return CGList(lines
, "\n").define()
18321 class CGRegisterWorkletBindings(CGAbstractMethod
):
18322 def __init__(self
, config
):
18323 CGAbstractMethod
.__init
__(
18326 "RegisterWorkletBindings",
18328 [Argument("JSContext*", "aCx"), Argument("JS::Handle<JSObject*>", "aObj")],
18330 self
.config
= config
18332 def definition_body(self
):
18333 descriptors
= self
.config
.getDescriptors(
18334 hasInterfaceObject
=True, isExposedInAnyWorklet
=True, register
=True
18337 for desc
in descriptors
:
18338 bindingNS
= toBindingNamespace(desc
.name
)
18339 condition
= "!%s::GetConstructorObject(aCx)" % bindingNS
18340 if desc
.isExposedConditionally():
18342 "%s::ConstructorEnabled(aCx, aObj) && " % bindingNS
+ condition
18344 conditions
.append(condition
)
18346 CGIfWrapper(CGGeneric("return false;\n"), condition
)
18347 for condition
in conditions
18349 lines
.append(CGGeneric("return true;\n"))
18350 return CGList(lines
, "\n").define()
18353 class CGRegisterShadowRealmBindings(CGAbstractMethod
):
18354 def __init__(self
, config
):
18355 CGAbstractMethod
.__init
__(
18358 "RegisterShadowRealmBindings",
18360 [Argument("JSContext*", "aCx"), Argument("JS::Handle<JSObject*>", "aObj")],
18362 self
.config
= config
18364 def definition_body(self
):
18365 descriptors
= self
.config
.getDescriptors(
18366 hasInterfaceObject
=True, isExposedInShadowRealms
=True, register
=True
18369 for desc
in descriptors
:
18370 bindingNS
= toBindingNamespace(desc
.name
)
18371 condition
= "!%s::GetConstructorObject(aCx)" % bindingNS
18372 if desc
.isExposedConditionally():
18374 "%s::ConstructorEnabled(aCx, aObj) && " % bindingNS
+ condition
18376 conditions
.append(condition
)
18378 CGIfWrapper(CGGeneric("return false;\n"), condition
)
18379 for condition
in conditions
18381 lines
.append(CGGeneric("return true;\n"))
18382 return CGList(lines
, "\n").define()
18385 def BindingNamesOffsetEnum(name
):
18386 return CppKeywords
.checkMethodName(name
.replace(" ", "_"))
18389 class CGGlobalNames(CGGeneric
):
18390 def __init__(self
, names
):
18392 names is expected to be a list of tuples of the name and the descriptor it refers to.
18397 for name
, desc
in names
:
18398 # Generate the entry declaration
18399 # XXX(nika): mCreate & mEnabled require relocations. If we want to
18400 # reduce those, we could move them into separate tables.
18401 nativeEntry
= fill(
18404 /* mNameOffset */ BindingNamesOffset::${nameOffset},
18405 /* mNameLength */ ${nameLength},
18406 /* mConstructorId */ constructors::id::${realname},
18407 /* mCreate */ ${realname}_Binding::CreateInterfaceObjects,
18408 /* mEnabled */ ${enabled}
18411 nameOffset
=BindingNamesOffsetEnum(name
),
18412 nameLength
=len(name
),
18414 realname
=desc
.name
,
18416 "%s_Binding::ConstructorEnabled" % desc
.name
18417 if desc
.isExposedConditionally()
18422 entries
.append((name
.encode(), nativeEntry
))
18424 # Unfortunately, when running tests, we may have no entries.
18425 # PerfectHash will assert if we give it an empty set of entries, so we
18426 # just generate a dummy value.
18427 if len(entries
) == 0:
18428 CGGeneric
.__init
__(
18432 static_assert(false, "No WebIDL global name entries!");
18438 # Build the perfect hash function.
18439 phf
= PerfectHash(entries
, GLOBAL_NAMES_PHF_SIZE
)
18441 # Generate code for the PHF
18442 phfCodegen
= phf
.codegen(
18443 "WebIDLGlobalNameHash::sEntries", "WebIDLNameTableEntry"
18445 entries
= phfCodegen
.gen_entries(lambda e
: e
[1])
18446 getter
= phfCodegen
.gen_jslinearstr_getter(
18447 name
="WebIDLGlobalNameHash::GetEntry",
18448 return_type
="const WebIDLNameTableEntry*",
18449 return_entry
=dedent(
18451 if (JS_LinearStringEqualsAscii(aKey, BindingName(entry.mNameOffset), entry.mNameLength)) {
18461 const uint32_t WebIDLGlobalNameHash::sCount = ${count};
18467 count
=len(phf
.entries
),
18468 strings
="\n".join(strings
) + ";\n",
18472 CGGeneric
.__init
__(self
, define
=define
)
18475 def dependencySortObjects(objects
, dependencyGetter
, nameGetter
):
18477 Sort IDL objects with dependencies on each other such that if A
18478 depends on B then B will come before A. This is needed for
18479 declaring C++ classes in the right order, for example. Objects
18480 that have no dependencies are just sorted by name.
18482 objects should be something that can produce a set of objects
18483 (e.g. a set, iterator, list, etc).
18485 dependencyGetter is something that, given an object, should return
18486 the set of objects it depends on.
18488 # XXXbz this will fail if we have two webidl files F1 and F2 such that F1
18489 # declares an object which depends on an object in F2, and F2 declares an
18490 # object (possibly a different one!) that depends on an object in F1. The
18491 # good news is that I expect this to never happen.
18493 objects
= set(objects
)
18494 while len(objects
) != 0:
18495 # Find the dictionaries that don't depend on anything else
18496 # anymore and move them over.
18497 toMove
= [o
for o
in objects
if len(dependencyGetter(o
) & objects
) == 0]
18498 if len(toMove
) == 0:
18500 "Loop in dependency graph\n" + "\n".join(o
.location
for o
in objects
)
18502 objects
= objects
- set(toMove
)
18503 sortedObjects
.extend(sorted(toMove
, key
=nameGetter
))
18504 return sortedObjects
18507 class ForwardDeclarationBuilder
:
18509 Create a canonical representation of a set of namespaced forward
18513 def __init__(self
):
18515 The set of declarations is represented as a tree of nested namespaces.
18516 Each tree node has a set of declarations |decls| and a dict |children|.
18517 Each declaration is a pair consisting of the class name and a boolean
18518 that is true iff the class is really a struct. |children| maps the
18519 names of inner namespaces to the declarations in that namespace.
18524 def _ensureNonTemplateType(self
, type):
18526 # This is a templated type. We don't really know how to
18527 # forward-declare those, and trying to do it naively is not going to
18528 # go well (e.g. we may have :: characters inside the type we're
18529 # templated on!). Just bail out.
18531 "Attempt to use ForwardDeclarationBuilder on "
18532 "templated type %s. We don't know how to do that "
18536 def _listAdd(self
, namespaces
, name
, isStruct
=False):
18538 Add a forward declaration, where |namespaces| is a list of namespaces.
18539 |name| should not contain any other namespaces.
18542 child
= self
.children
.setdefault(namespaces
[0], ForwardDeclarationBuilder())
18543 child
._listAdd
(namespaces
[1:], name
, isStruct
)
18545 assert "::" not in name
18546 self
.decls
.add((name
, isStruct
))
18548 def addInMozillaDom(self
, name
, isStruct
=False):
18550 Add a forward declaration to the mozilla::dom:: namespace. |name| should not
18551 contain any other namespaces.
18553 self
._ensureNonTemplateType
(name
)
18554 self
._listAdd
(["mozilla", "dom"], name
, isStruct
)
18556 def add(self
, nativeType
, isStruct
=False):
18558 Add a forward declaration, where |nativeType| is a string containing
18559 the type and its namespaces, in the usual C++ way.
18561 self
._ensureNonTemplateType
(nativeType
)
18562 components
= nativeType
.split("::")
18563 self
._listAdd
(components
[:-1], components
[-1], isStruct
)
18565 def _build(self
, atTopLevel
):
18567 Return a codegenerator for the forward declarations.
18574 CGClassForwardDeclare(cname
, isStruct
)
18575 for cname
, isStruct
in sorted(self
.decls
)
18579 for namespace
, child
in sorted(self
.children
.items()):
18580 decls
.append(CGNamespace(namespace
, child
._build
(atTopLevel
=False)))
18582 cg
= CGList(decls
, "\n")
18583 if not atTopLevel
and len(decls
) + len(self
.decls
) > 1:
18584 cg
= CGWrapper(cg
, pre
="\n", post
="\n")
18588 return self
._build
(atTopLevel
=True)
18590 def forwardDeclareForType(self
, t
, config
):
18592 if t
.isGeckoInterface():
18593 name
= t
.inner
.identifier
.name
18595 desc
= config
.getDescriptor(name
)
18596 self
.add(desc
.nativeType
)
18597 except NoSuchDescriptorError
:
18600 # Note: SpiderMonkey interfaces are typedefs, so can't be
18602 elif t
.isPromise():
18603 self
.addInMozillaDom("Promise")
18604 elif t
.isCallback():
18605 self
.addInMozillaDom(t
.callback
.identifier
.name
)
18606 elif t
.isDictionary():
18607 self
.addInMozillaDom(t
.inner
.identifier
.name
, isStruct
=True)
18608 elif t
.isCallbackInterface():
18609 self
.addInMozillaDom(t
.inner
.identifier
.name
)
18611 # Forward declare both the owning and non-owning version,
18612 # since we don't know which one we might want
18613 self
.addInMozillaDom(CGUnionStruct
.unionTypeName(t
, False))
18614 self
.addInMozillaDom(CGUnionStruct
.unionTypeName(t
, True))
18616 self
.forwardDeclareForType(t
.inner
, config
)
18617 # Don't need to do anything for void, primitive, string, any or object.
18618 # There may be some other cases we are missing.
18621 class CGForwardDeclarations(CGWrapper
):
18623 Code generate the forward declarations for a header file.
18624 additionalDeclarations is a list of tuples containing a classname and a
18625 boolean. If the boolean is true we will declare a struct, otherwise we'll
18635 callbackInterfaces
,
18636 additionalDeclarations
=[],
18638 builder
= ForwardDeclarationBuilder()
18640 # Needed for at least Wrap.
18641 for d
in descriptors
:
18642 # If this is a generated iterator interface, we only create these
18643 # in the generated bindings, and don't need to forward declare.
18645 d
.interface
.isIteratorInterface()
18646 or d
.interface
.isAsyncIteratorInterface()
18649 builder
.add(d
.nativeType
)
18650 if d
.interface
.isSerializable():
18651 builder
.add("nsIGlobalObject")
18652 # If we're an interface and we have a maplike/setlike declaration,
18653 # we'll have helper functions exposed to the native side of our
18654 # bindings, which will need to show up in the header. If either of
18655 # our key/value types are interfaces, they'll be passed as
18656 # arguments to helper functions, and they'll need to be forward
18657 # declared in the header.
18658 if d
.interface
.maplikeOrSetlikeOrIterable
:
18659 if d
.interface
.maplikeOrSetlikeOrIterable
.hasKeyType():
18660 builder
.forwardDeclareForType(
18661 d
.interface
.maplikeOrSetlikeOrIterable
.keyType
, config
18663 if d
.interface
.maplikeOrSetlikeOrIterable
.hasValueType():
18664 builder
.forwardDeclareForType(
18665 d
.interface
.maplikeOrSetlikeOrIterable
.valueType
, config
18668 for m
in d
.interface
.members
:
18669 if m
.isAttr() and m
.type.isObservableArray():
18670 builder
.forwardDeclareForType(m
.type, config
)
18672 # We just about always need NativePropertyHooks
18673 builder
.addInMozillaDom("NativePropertyHooks", isStruct
=True)
18674 builder
.addInMozillaDom("ProtoAndIfaceCache")
18676 for callback
in callbacks
:
18677 builder
.addInMozillaDom(callback
.identifier
.name
)
18678 for t
in getTypesFromCallback(callback
):
18679 builder
.forwardDeclareForType(t
, config
)
18681 for d
in callbackInterfaces
:
18682 builder
.add(d
.nativeType
)
18683 builder
.add(d
.nativeType
+ "Atoms", isStruct
=True)
18684 for t
in getTypesFromDescriptor(d
):
18685 builder
.forwardDeclareForType(t
, config
)
18686 if d
.hasCEReactions():
18687 builder
.addInMozillaDom("DocGroup")
18689 for d
in dictionaries
:
18690 if len(d
.members
) > 0:
18691 builder
.addInMozillaDom(d
.identifier
.name
+ "Atoms", isStruct
=True)
18692 for t
in getTypesFromDictionary(d
):
18693 builder
.forwardDeclareForType(t
, config
)
18695 for className
, isStruct
in additionalDeclarations
:
18696 builder
.add(className
, isStruct
=isStruct
)
18698 CGWrapper
.__init
__(self
, builder
.build())
18701 def dependencySortDictionariesAndUnionsAndCallbacks(types
):
18702 def getDependenciesFromType(type):
18703 if type.isDictionary():
18704 return set([type.unroll().inner
])
18705 if type.isSequence():
18706 return getDependenciesFromType(type.unroll())
18708 return set([type.unroll()])
18709 if type.isRecord():
18710 return set([type.unroll().inner
])
18711 if type.isCallback():
18712 return set([type.unroll()])
18715 def getDependencies(unionTypeOrDictionaryOrCallback
):
18716 if isinstance(unionTypeOrDictionaryOrCallback
, IDLDictionary
):
18718 if unionTypeOrDictionaryOrCallback
.parent
:
18719 deps
.add(unionTypeOrDictionaryOrCallback
.parent
)
18720 for member
in unionTypeOrDictionaryOrCallback
.members
:
18721 deps |
= getDependenciesFromType(member
.type)
18725 unionTypeOrDictionaryOrCallback
.isType()
18726 and unionTypeOrDictionaryOrCallback
.isUnion()
18729 for member
in unionTypeOrDictionaryOrCallback
.flatMemberTypes
:
18730 deps |
= getDependenciesFromType(member
)
18733 assert unionTypeOrDictionaryOrCallback
.isCallback()
18736 def getName(unionTypeOrDictionaryOrCallback
):
18737 if isinstance(unionTypeOrDictionaryOrCallback
, IDLDictionary
):
18738 return unionTypeOrDictionaryOrCallback
.identifier
.name
18741 unionTypeOrDictionaryOrCallback
.isType()
18742 and unionTypeOrDictionaryOrCallback
.isUnion()
18744 return unionTypeOrDictionaryOrCallback
.name
18746 assert unionTypeOrDictionaryOrCallback
.isCallback()
18747 return unionTypeOrDictionaryOrCallback
.identifier
.name
18749 return dependencySortObjects(types
, getDependencies
, getName
)
18752 class CGBindingRoot(CGThing
):
18754 Root codegen class for binding generation. Instantiate the class, and call
18755 declare or define to generate header or cpp code (respectively).
18758 def __init__(self
, config
, prefix
, webIDLFile
):
18759 bindingHeaders
= dict.fromkeys(
18760 ("mozilla/dom/NonRefcountedDOMObject.h", "MainThreadUtils.h"), True
18762 bindingDeclareHeaders
= dict.fromkeys(
18764 "mozilla/dom/BindingDeclarations.h",
18765 "mozilla/dom/Nullable.h",
18770 descriptors
= config
.getDescriptors(
18771 webIDLFile
=webIDLFile
, hasInterfaceOrInterfacePrototypeObject
=True
18774 unionTypes
= UnionsForFile(config
, webIDLFile
)
18783 ) = UnionTypes(unionTypes
, config
)
18785 bindingDeclareHeaders
.update(dict.fromkeys(unionHeaders
, True))
18786 bindingHeaders
.update(dict.fromkeys(unionImplheaders
, True))
18787 bindingDeclareHeaders
["mozilla/dom/UnionMember.h"] = len(unionStructs
) > 0
18788 bindingDeclareHeaders
["mozilla/dom/FakeString.h"] = len(unionStructs
) > 0
18789 # BindingUtils.h is only needed for SetToObject.
18790 # If it stops being inlined or stops calling CallerSubsumes
18791 # both this bit and the bit in UnionTypes can be removed.
18792 bindingDeclareHeaders
["mozilla/dom/BindingUtils.h"] = any(
18793 d
.isObject() for t
in unionTypes
for d
in t
.flatMemberTypes
18795 bindingHeaders
["mozilla/dom/IterableIterator.h"] = any(
18797 d
.interface
.isIteratorInterface()
18798 and d
.interface
.maplikeOrSetlikeOrIterable
.isPairIterator()
18800 or d
.interface
.isAsyncIteratorInterface()
18801 or d
.interface
.isIterable()
18802 or d
.interface
.isAsyncIterable()
18803 for d
in descriptors
18806 def memberNeedsSubjectPrincipal(d
, m
):
18809 "needsSubjectPrincipal" in d
.getExtendedAttributes(m
, getter
=True)
18812 and "needsSubjectPrincipal"
18813 in d
.getExtendedAttributes(m
, setter
=True)
18815 return m
.isMethod() and "needsSubjectPrincipal" in d
.getExtendedAttributes(
18820 memberNeedsSubjectPrincipal(d
, m
)
18821 for d
in descriptors
18822 for m
in d
.interface
.members
18824 bindingHeaders
["mozilla/BasePrincipal.h"] = True
18825 bindingHeaders
["nsJSPrincipals.h"] = True
18827 # The conditions for which we generate profiler labels are fairly
18828 # complicated. The check below is a little imprecise to make it simple.
18829 # It includes the profiler header in all cases where it is necessary and
18830 # generates only a few false positives.
18831 bindingHeaders
["mozilla/ProfilerLabels.h"] = any(
18832 # constructor profiler label
18833 d
.interface
.legacyFactoryFunctions
18834 or (d
.interface
.hasInterfaceObject() and d
.interface
.ctor())
18836 # getter/setter profiler labels
18838 # method profiler label
18840 for m
in d
.interface
.members
18842 for d
in descriptors
18845 def descriptorHasCrossOriginProperties(desc
):
18846 def hasCrossOriginProperty(m
):
18847 props
= memberProperties(m
, desc
)
18849 props
.isCrossOriginMethod
18850 or props
.isCrossOriginGetter
18851 or props
.isCrossOriginSetter
18854 return any(hasCrossOriginProperty(m
) for m
in desc
.interface
.members
)
18856 def descriptorHasObservableArrayTypes(desc
):
18857 def hasObservableArrayTypes(m
):
18858 return m
.isAttr() and m
.type.isObservableArray()
18860 return any(hasObservableArrayTypes(m
) for m
in desc
.interface
.members
)
18862 bindingDeclareHeaders
["mozilla/dom/RemoteObjectProxy.h"] = any(
18863 descriptorHasCrossOriginProperties(d
) for d
in descriptors
18865 bindingDeclareHeaders
["jsapi.h"] = any(
18866 descriptorHasCrossOriginProperties(d
)
18867 or descriptorHasObservableArrayTypes(d
)
18868 for d
in descriptors
18870 bindingDeclareHeaders
["js/TypeDecls.h"] = not bindingDeclareHeaders
["jsapi.h"]
18871 bindingDeclareHeaders
["js/RootingAPI.h"] = not bindingDeclareHeaders
["jsapi.h"]
18874 bindingDeclareHeaders
["js/CallAndConstruct.h"] = True
18876 def descriptorHasIteratorAlias(desc
):
18877 def hasIteratorAlias(m
):
18878 return m
.isMethod() and (
18879 ("@@iterator" in m
.aliases
) or ("@@asyncIterator" in m
.aliases
)
18882 return any(hasIteratorAlias(m
) for m
in desc
.interface
.members
)
18884 bindingHeaders
["js/Symbol.h"] = any(
18885 descriptorHasIteratorAlias(d
) for d
in descriptors
18888 bindingHeaders
["js/shadow/Object.h"] = any(
18889 d
.interface
.hasMembersInSlots() for d
in descriptors
18892 # The symbols supplied by this header are used so ubiquitously it's not
18893 # worth the effort delineating the exact dependency, if it can't be done
18894 # *at* the places where their definitions are required.
18895 bindingHeaders
["js/experimental/JitInfo.h"] = True
18897 # JS::GetClass, JS::GetCompartment, JS::GetReservedSlot, and
18898 # JS::SetReservedSlot are also used too many places to restate
18899 # dependency logic.
18900 bindingHeaders
["js/Object.h"] = True
18902 # JS::IsCallable, JS::Call, JS::Construct
18903 bindingHeaders
["js/CallAndConstruct.h"] = True
18905 # JS_IsExceptionPending
18906 bindingHeaders
["js/Exception.h"] = True
18908 # JS::Map{Clear, Delete, Has, Get, Set}
18909 bindingHeaders
["js/MapAndSet.h"] = True
18911 # JS_DefineElement, JS_DefineProperty, JS_DefinePropertyById,
18912 # JS_DefineUCProperty, JS_ForwardGetPropertyTo, JS_GetProperty,
18913 # JS_GetPropertyById, JS_HasPropertyById, JS_SetProperty,
18914 # JS_SetPropertyById
18915 bindingHeaders
["js/PropertyAndElement.h"] = True
18917 # JS_GetOwnPropertyDescriptorById
18918 bindingHeaders
["js/PropertyDescriptor.h"] = True
18920 def descriptorDeprecated(desc
):
18921 iface
= desc
.interface
18923 m
.getExtendedAttribute("Deprecated") for m
in iface
.members
+ [iface
]
18926 bindingHeaders
["mozilla/dom/Document.h"] = any(
18927 descriptorDeprecated(d
) for d
in descriptors
18930 bindingHeaders
["mozilla/dom/DOMJSProxyHandler.h"] = any(
18931 d
.concrete
and d
.proxy
for d
in descriptors
18934 bindingHeaders
["mozilla/dom/ProxyHandlerUtils.h"] = any(
18935 d
.concrete
and d
.proxy
for d
in descriptors
18938 bindingHeaders
["js/String.h"] = any(
18939 d
.needsMissingPropUseCounters
for d
in descriptors
18942 hasCrossOriginObjects
= any(
18943 d
.concrete
and d
.isMaybeCrossOriginObject() for d
in descriptors
18945 bindingHeaders
["mozilla/dom/MaybeCrossOriginObject.h"] = hasCrossOriginObjects
18946 bindingHeaders
["AccessCheck.h"] = hasCrossOriginObjects
18947 hasCEReactions
= any(d
.hasCEReactions() for d
in descriptors
)
18948 bindingHeaders
["mozilla/dom/CustomElementRegistry.h"] = hasCEReactions
18949 bindingHeaders
["mozilla/dom/DocGroup.h"] = hasCEReactions
18951 def descriptorHasChromeOnly(desc
):
18952 ctor
= desc
.interface
.ctor()
18956 isChromeOnly(a
) or needsCallerType(a
)
18957 for a
in desc
.interface
.members
18959 or desc
.interface
.getExtendedAttribute("ChromeOnly") is not None
18961 # JS-implemented interfaces with an interface object get a
18962 # chromeonly _create method. And interfaces with an
18963 # interface object might have a ChromeOnly constructor.
18965 desc
.interface
.hasInterfaceObject()
18967 desc
.interface
.isJSImplemented()
18968 or (ctor
and isChromeOnly(ctor
))
18973 # XXXkhuey ugly hack but this is going away soon.
18974 bindingHeaders
["xpcprivate.h"] = webIDLFile
.endswith("EventTarget.webidl")
18976 hasThreadChecks
= any(d
.hasThreadChecks() for d
in descriptors
)
18977 bindingHeaders
["nsThreadUtils.h"] = hasThreadChecks
18979 dictionaries
= config
.getDictionaries(webIDLFile
)
18981 def dictionaryHasChromeOnly(dictionary
):
18983 if any(isChromeOnly(m
) for m
in dictionary
.members
):
18985 dictionary
= dictionary
.parent
18988 def needsNonSystemPrincipal(member
):
18990 member
.getExtendedAttribute("NeedsSubjectPrincipal") == ["NonSystem"]
18991 or member
.getExtendedAttribute("SetterNeedsSubjectPrincipal")
18993 or member
.getExtendedAttribute("GetterNeedsSubjectPrincipal")
18997 def descriptorNeedsNonSystemPrincipal(d
):
18998 return any(needsNonSystemPrincipal(m
) for m
in d
.interface
.members
)
19000 def descriptorHasPrefDisabler(desc
):
19001 iface
= desc
.interface
19003 PropertyDefiner
.getControllingCondition(m
, desc
).hasDisablers()
19004 for m
in iface
.members
19005 if (m
.isMethod() or m
.isAttr() or m
.isConst())
19008 def addPrefHeaderForObject(bindingHeaders
, obj
):
19010 obj might be a dictionary member or an interface.
19012 if obj
is not None:
19013 pref
= PropertyDefiner
.getStringAttr(obj
, "Pref")
19015 bindingHeaders
[prefHeader(pref
)] = True
19017 def addPrefHeadersForDictionary(bindingHeaders
, dictionary
):
19019 for m
in dictionary
.members
:
19020 addPrefHeaderForObject(bindingHeaders
, m
)
19021 dictionary
= dictionary
.parent
19023 for d
in dictionaries
:
19024 addPrefHeadersForDictionary(bindingHeaders
, d
)
19025 for d
in descriptors
:
19026 interface
= d
.interface
19027 addPrefHeaderForObject(bindingHeaders
, interface
)
19028 addPrefHeaderForObject(bindingHeaders
, interface
.ctor())
19030 bindingHeaders
["mozilla/dom/WebIDLPrefs.h"] = any(
19031 descriptorHasPrefDisabler(d
) for d
in descriptors
19033 bindingHeaders
["nsContentUtils.h"] = (
19034 any(descriptorHasChromeOnly(d
) for d
in descriptors
)
19035 or any(descriptorNeedsNonSystemPrincipal(d
) for d
in descriptors
)
19036 or any(dictionaryHasChromeOnly(d
) for d
in dictionaries
)
19038 hasNonEmptyDictionaries
= any(len(dict.members
) > 0 for dict in dictionaries
)
19039 callbacks
= config
.getCallbacks(webIDLFile
)
19040 callbackDescriptors
= config
.getDescriptors(
19041 webIDLFile
=webIDLFile
, isCallback
=True
19043 jsImplemented
= config
.getDescriptors(
19044 webIDLFile
=webIDLFile
, isJSImplemented
=True
19046 bindingDeclareHeaders
["nsWeakReference.h"] = jsImplemented
19047 bindingDeclareHeaders
["mozilla/dom/PrototypeList.h"] = descriptors
19048 bindingHeaders
["nsIGlobalObject.h"] = jsImplemented
19049 bindingHeaders
["AtomList.h"] = (
19050 hasNonEmptyDictionaries
or jsImplemented
or callbackDescriptors
19053 if callbackDescriptors
:
19054 bindingDeclareHeaders
["mozilla/ErrorResult.h"] = True
19056 def descriptorClearsPropsInSlots(descriptor
):
19057 if not descriptor
.wrapperCache
:
19060 m
.isAttr() and m
.getExtendedAttribute("StoreInSlot")
19061 for m
in descriptor
.interface
.members
19064 bindingHeaders
["nsJSUtils.h"] = any(
19065 descriptorClearsPropsInSlots(d
) for d
in descriptors
19068 # Make sure we can sanely use binding_detail in generated code.
19073 namespace binding_detail {}; // Just to make sure it's known as a namespace
19074 using namespace mozilla::dom::binding_detail;
19080 # Do codegen for all the enums
19081 enums
= config
.getEnums(webIDLFile
)
19082 cgthings
.extend(CGEnum(e
) for e
in enums
)
19083 maxEnumValues
= CGList([CGMaxContiguousEnumValue(e
) for e
in enums
], "\n")
19085 bindingDeclareHeaders
["mozilla/Span.h"] = enums
19086 bindingDeclareHeaders
["mozilla/ArrayUtils.h"] = enums
19087 bindingDeclareHeaders
["mozilla/EnumTypeTraits.h"] = enums
19089 hasCode
= descriptors
or callbackDescriptors
or dictionaries
or callbacks
19090 bindingHeaders
["mozilla/dom/BindingUtils.h"] = hasCode
19091 bindingHeaders
["mozilla/OwningNonNull.h"] = hasCode
19092 bindingHeaders
["<type_traits>"] = hasCode
19093 bindingHeaders
["mozilla/dom/BindingDeclarations.h"] = not hasCode
and enums
19095 bindingHeaders
["WrapperFactory.h"] = descriptors
19096 bindingHeaders
["mozilla/dom/DOMJSClass.h"] = descriptors
19097 bindingHeaders
["mozilla/dom/ScriptSettings.h"] = dictionaries
# AutoJSAPI
19098 # Ensure we see our enums in the generated .cpp file, for the ToJSValue
19099 # method body. Also ensure that we see jsapi.h.
19101 bindingHeaders
[CGHeaders
.getDeclarationFilename(enums
[0])] = True
19102 bindingHeaders
["jsapi.h"] = True
19104 # For things that have [UseCounter] or [InstrumentedProps] or [Trial]
19105 for d
in descriptors
:
19107 if d
.instrumentedProps
:
19108 bindingHeaders
["mozilla/UseCounter.h"] = True
19109 if d
.needsMissingPropUseCounters
:
19110 bindingHeaders
[prefHeader(MISSING_PROP_PREF
)] = True
19111 if d
.interface
.isSerializable():
19112 bindingHeaders
["mozilla/dom/StructuredCloneTags.h"] = True
19114 bindingHeaders
["mozilla/Atomics.h"] = True
19115 bindingHeaders
["mozilla/dom/XrayExpandoClass.h"] = True
19116 if d
.wantsXrayExpandoClass
:
19117 bindingHeaders
["XrayWrapper.h"] = True
19118 for m
in d
.interface
.members
:
19119 if m
.getExtendedAttribute("UseCounter"):
19120 bindingHeaders
["mozilla/UseCounter.h"] = True
19121 if m
.getExtendedAttribute("Trial"):
19122 bindingHeaders
["mozilla/OriginTrials.h"] = True
19124 bindingHeaders
["mozilla/dom/SimpleGlobalObject.h"] = any(
19125 CGDictionary
.dictionarySafeToJSONify(d
) for d
in dictionaries
19128 for ancestor
in (findAncestorWithInstrumentedProps(d
) for d
in descriptors
):
19131 bindingHeaders
[CGHeaders
.getDeclarationFilename(ancestor
)] = True
19133 cgthings
.extend(traverseMethods
)
19134 cgthings
.extend(unlinkMethods
)
19136 # Do codegen for all the dictionaries. We have to be a bit careful
19137 # here, because we have to generate these in order from least derived
19138 # to most derived so that class inheritance works out. We also have to
19139 # generate members before the dictionary that contains them.
19141 for t
in dependencySortDictionariesAndUnionsAndCallbacks(
19142 dictionaries
+ unionStructs
+ callbacks
19144 if t
.isDictionary():
19145 cgthings
.append(CGDictionary(t
, config
))
19147 cgthings
.append(CGUnionStruct(t
, config
))
19148 cgthings
.append(CGUnionStruct(t
, config
, True))
19150 assert t
.isCallback()
19151 cgthings
.append(CGCallbackFunction(t
, config
))
19152 cgthings
.append(CGNamespace("binding_detail", CGFastCallback(t
)))
19154 # Do codegen for all the descriptors
19156 [CGDescriptor(x
, config
.attributeTemplates
) for x
in descriptors
]
19159 # Do codegen for all the callback interfaces.
19160 cgthings
.extend([CGCallbackInterface(x
) for x
in callbackDescriptors
])
19164 CGNamespace("binding_detail", CGFastCallback(x
.interface
))
19165 for x
in callbackDescriptors
19169 # Do codegen for JS implemented classes
19170 def getParentDescriptor(desc
):
19171 if not desc
.interface
.parent
:
19173 return {desc
.getDescriptor(desc
.interface
.parent
.identifier
.name
)}
19175 for x
in dependencySortObjects(
19176 jsImplemented
, getParentDescriptor
, lambda d
: d
.interface
.identifier
.name
19179 CGCallbackInterface(x
, spiderMonkeyInterfacesAreStructs
=True)
19181 cgthings
.append(CGJSImplClass(x
))
19183 # And make sure we have the right number of newlines at the end
19184 curr
= CGWrapper(CGList(cgthings
, "\n\n"), post
="\n\n")
19186 # Wrap all of that in our namespaces.
19188 if len(maxEnumValues
) > 0:
19189 curr
= CGNamespace("dom", CGWrapper(curr
, pre
="\n"))
19190 curr
= CGWrapper(CGList([curr
, maxEnumValues
], "\n\n"), post
="\n\n")
19191 curr
= CGNamespace("mozilla", CGWrapper(curr
, pre
="\n"))
19193 curr
= CGNamespace
.build(["mozilla", "dom"], CGWrapper(curr
, pre
="\n"))
19197 CGForwardDeclarations(
19202 callbackDescriptors
+ jsImplemented
,
19203 additionalDeclarations
=unionDeclarations
,
19210 # Add header includes.
19212 header
for header
, include
in bindingHeaders
.items() if include
19214 bindingDeclareHeaders
= [
19215 header
for header
, include
in bindingDeclareHeaders
.items() if include
19222 callbackDescriptors
,
19223 bindingDeclareHeaders
,
19231 # Add include guards.
19232 curr
= CGIncludeGuard(prefix
, curr
)
19234 # Add the auto-generated comment.
19238 AUTOGENERATED_WITH_SOURCE_WARNING_COMMENT
% os
.path
.basename(webIDLFile
)
19242 # Store the final result.
19246 return stripTrailingWhitespace(self
.root
.declare())
19249 return stripTrailingWhitespace(self
.root
.define())
19252 return self
.root
.deps()
19255 class CGNativeMember(ClassMethod
):
19258 descriptorProvider
,
19264 passJSBitsAsNeeded
=True,
19265 visibility
="public",
19266 spiderMonkeyInterfacesAreStructs
=True,
19267 variadicIsSequence
=False,
19268 resultNotAddRefed
=False,
19271 canRunScript
=False,
19274 If spiderMonkeyInterfacesAreStructs is false, SpiderMonkey interfaces
19275 will be passed as JS::Handle<JSObject*>. If it's true they will be
19276 passed as one of the dom::SpiderMonkeyInterfaceObjectStorage subclasses.
19278 If passJSBitsAsNeeded is false, we don't automatically pass in a
19279 JSContext* or a JSObject* based on the return and argument types. We
19280 can still pass it based on 'implicitJSContext' annotations.
19282 self
.descriptorProvider
= descriptorProvider
19283 self
.member
= member
19284 self
.extendedAttrs
= extendedAttrs
19285 self
.resultAlreadyAddRefed
= not resultNotAddRefed
19286 self
.passJSBitsAsNeeded
= passJSBitsAsNeeded
19287 self
.spiderMonkeyInterfacesAreStructs
= spiderMonkeyInterfacesAreStructs
19288 self
.variadicIsSequence
= variadicIsSequence
19289 breakAfterSelf
= "\n" if breakAfter
else ""
19290 ClassMethod
.__init
__(
19293 self
.getReturnType(signature
[0], False),
19294 self
.getArgs(signature
[0], signature
[1]),
19295 static
=member
.isStatic(),
19296 # Mark our getters, which are attrs that
19297 # have a non-void return type, as const.
19299 not member
.isStatic()
19300 and member
.isAttr()
19301 and not signature
[0].isUndefined()
19303 breakAfterReturnDecl
=" ",
19304 breakAfterSelf
=breakAfterSelf
,
19305 visibility
=visibility
,
19308 canRunScript
=canRunScript
,
19311 def getReturnType(self
, type, isMember
):
19312 return self
.getRetvalInfo(type, isMember
)[0]
19314 def getRetvalInfo(self
, type, isMember
):
19318 The first element is the type declaration for the retval
19320 The second element is a default value that can be used on error returns.
19321 For cases whose behavior depends on isMember, the second element will be
19322 None if isMember is true.
19324 The third element is a template for actually returning a value stored in
19325 "${declName}" and "${holderName}". This means actually returning it if
19326 we're not outparam, else assigning to the "retval" outparam. If
19327 isMember is true, this can be None, since in that case the caller will
19328 never examine this value.
19330 if type.isUndefined():
19331 return "void", "", ""
19332 if type.isPrimitive() and type.tag() in builtinNames
:
19333 result
= CGGeneric(builtinNames
[type.tag()])
19334 defaultReturnArg
= "0"
19335 if type.nullable():
19336 result
= CGTemplatedType("Nullable", result
)
19337 defaultReturnArg
= ""
19340 "%s(%s)" % (result
.define(), defaultReturnArg
),
19341 "return ${declName};\n",
19343 if type.isJSString():
19345 raise TypeError("JSString not supported as return type member")
19347 return "void", "", "aRetVal.set(${declName});\n"
19348 if type.isDOMString() or type.isUSVString():
19350 # No need for a third element in the isMember case
19351 return "nsString", None, None
19353 return "void", "", "aRetVal = ${declName};\n"
19354 if type.isByteString() or type.isUTF8String():
19356 # No need for a third element in the isMember case
19357 return "nsCString", None, None
19359 return "void", "", "aRetVal = ${declName};\n"
19361 enumName
= type.unroll().inner
.identifier
.name
19362 if type.nullable():
19363 enumName
= CGTemplatedType("Nullable", CGGeneric(enumName
)).define()
19364 defaultValue
= "%s()" % enumName
19366 defaultValue
= "%s(0)" % enumName
19367 return enumName
, defaultValue
, "return ${declName};\n"
19368 if type.isGeckoInterface() or type.isPromise():
19369 if type.isGeckoInterface():
19370 iface
= type.unroll().inner
19371 result
= CGGeneric(
19372 self
.descriptorProvider
.getDescriptor(
19373 iface
.identifier
.name
19377 result
= CGGeneric("Promise")
19378 if self
.resultAlreadyAddRefed
:
19382 holder
= "already_AddRefed"
19383 if memberReturnsNewObject(self
.member
) or isMember
:
19386 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"
19387 result
= CGWrapper(result
, pre
=("%s%s<" % (warning
, holder
)), post
=">")
19389 result
= CGWrapper(result
, post
="*")
19390 # Since we always force an owning type for callback return values,
19391 # our ${declName} is an OwningNonNull or RefPtr. So we can just
19392 # .forget() to get our already_AddRefed.
19393 return result
.define(), "nullptr", "return ${declName}.forget();\n"
19394 if type.isCallback():
19396 "already_AddRefed<%s>" % type.unroll().callback
.identifier
.name
,
19398 "return ${declName}.forget();\n",
19402 # No need for a third element in the isMember case
19403 return "JS::Value", None, None
19405 return "void", "", "aRetVal.set(${declName});\n"
19407 if type.isObject():
19409 # No need for a third element in the isMember case
19410 return "JSObject*", None, None
19411 return "void", "", "aRetVal.set(${declName});\n"
19412 if type.isSpiderMonkeyInterface():
19414 # No need for a third element in the isMember case
19415 return "JSObject*", None, None
19416 if type.nullable():
19418 "${declName}.IsNull() ? nullptr : ${declName}.Value().Obj()"
19421 returnCode
= "${declName}.Obj()"
19422 return "void", "", "aRetVal.set(%s);\n" % returnCode
19423 if type.isSequence():
19424 # If we want to handle sequence-of-sequences return values, we're
19425 # going to need to fix example codegen to not produce nsTArray<void>
19426 # for the relevant argument...
19427 assert not isMember
19429 if type.nullable():
19430 returnCode
= dedent(
19432 if (${declName}.IsNull()) {
19435 aRetVal.SetValue() = std::move(${declName}.Value());
19440 returnCode
= "aRetVal = std::move(${declName});\n"
19441 return "void", "", returnCode
19442 if type.isRecord():
19443 # If we want to handle record-of-record return values, we're
19444 # going to need to fix example codegen to not produce record<void>
19445 # for the relevant argument...
19446 assert not isMember
19447 # In this case we convert directly into our outparam to start with
19448 return "void", "", ""
19449 if type.isDictionary():
19451 # Only the first member of the tuple matters here, but return
19452 # bogus values for the others in case someone decides to use
19454 return CGDictionary
.makeDictionaryName(type.inner
), None, None
19455 # In this case we convert directly into our outparam to start with
19456 return "void", "", ""
19459 # Only the first member of the tuple matters here, but return
19460 # bogus values for the others in case someone decides to use
19462 return CGUnionStruct
.unionTypeDecl(type, True), None, None
19463 # In this case we convert directly into our outparam to start with
19464 return "void", "", ""
19466 raise TypeError("Don't know how to declare return value for %s" % type)
19468 def getArgs(self
, returnType
, argList
):
19469 args
= [self
.getArg(arg
) for arg
in argList
]
19470 # Now the outparams
19471 if returnType
.isJSString():
19472 args
.append(Argument("JS::MutableHandle<JSString*>", "aRetVal"))
19473 elif returnType
.isDOMString() or returnType
.isUSVString():
19474 args
.append(Argument("nsString&", "aRetVal"))
19475 elif returnType
.isByteString() or returnType
.isUTF8String():
19476 args
.append(Argument("nsCString&", "aRetVal"))
19477 elif returnType
.isSequence():
19478 nullable
= returnType
.nullable()
19480 returnType
= returnType
.inner
19481 # And now the actual underlying type
19482 elementDecl
= self
.getReturnType(returnType
.inner
, True)
19483 type = CGTemplatedType("nsTArray", CGGeneric(elementDecl
))
19485 type = CGTemplatedType("Nullable", type)
19486 args
.append(Argument("%s&" % type.define(), "aRetVal"))
19487 elif returnType
.isRecord():
19488 nullable
= returnType
.nullable()
19490 returnType
= returnType
.inner
19491 # And now the actual underlying type
19492 elementDecl
= self
.getReturnType(returnType
.inner
, True)
19493 type = CGTemplatedType(
19494 "Record", [recordKeyDeclType(returnType
), CGGeneric(elementDecl
)]
19497 type = CGTemplatedType("Nullable", type)
19498 args
.append(Argument("%s&" % type.define(), "aRetVal"))
19499 elif returnType
.isDictionary():
19500 nullable
= returnType
.nullable()
19502 returnType
= returnType
.inner
19503 dictType
= CGGeneric(CGDictionary
.makeDictionaryName(returnType
.inner
))
19505 dictType
= CGTemplatedType("Nullable", dictType
)
19506 args
.append(Argument("%s&" % dictType
.define(), "aRetVal"))
19507 elif returnType
.isUnion():
19510 "%s&" % CGUnionStruct
.unionTypeDecl(returnType
, True), "aRetVal"
19513 elif returnType
.isAny():
19514 args
.append(Argument("JS::MutableHandle<JS::Value>", "aRetVal"))
19515 elif returnType
.isObject() or returnType
.isSpiderMonkeyInterface():
19516 args
.append(Argument("JS::MutableHandle<JSObject*>", "aRetVal"))
19518 # And the nsIPrincipal
19519 if "needsSubjectPrincipal" in self
.extendedAttrs
:
19520 if "needsNonSystemSubjectPrincipal" in self
.extendedAttrs
:
19521 args
.append(Argument("nsIPrincipal*", "aPrincipal"))
19523 args
.append(Argument("nsIPrincipal&", "aPrincipal"))
19524 # And the caller type, if desired.
19525 if needsCallerType(self
.member
):
19526 args
.append(Argument("CallerType", "aCallerType"))
19527 # And the ErrorResult or OOMReporter
19528 if "needsErrorResult" in self
.extendedAttrs
:
19529 # Use aRv so it won't conflict with local vars named "rv"
19530 args
.append(Argument("ErrorResult&", "aRv"))
19531 elif "canOOM" in self
.extendedAttrs
:
19532 args
.append(Argument("OOMReporter&", "aRv"))
19534 # The legacycaller thisval
19535 if self
.member
.isMethod() and self
.member
.isLegacycaller():
19536 # If it has an identifier, we can't deal with it yet
19537 assert self
.member
.isIdentifierLess()
19538 args
.insert(0, Argument("const JS::Value&", "aThisVal"))
19539 # And jscontext bits.
19543 self
.extendedAttrs
,
19544 self
.passJSBitsAsNeeded
,
19545 self
.member
.isStatic(),
19547 args
.insert(0, Argument("JSContext*", "cx"))
19548 if needScopeObject(
19551 self
.extendedAttrs
,
19552 self
.descriptorProvider
.wrapperCache
,
19553 self
.passJSBitsAsNeeded
,
19554 self
.member
.getExtendedAttribute("StoreInSlot"),
19556 args
.insert(1, Argument("JS::Handle<JSObject*>", "obj"))
19557 # And if we're static, a global
19558 if self
.member
.isStatic():
19559 args
.insert(0, Argument("const GlobalObject&", "global"))
19562 def doGetArgType(self
, type, optional
, isMember
):
19564 The main work of getArgType. Returns a string type decl, whether this
19565 is a const ref, as well as whether the type should be wrapped in
19566 Nullable as needed.
19568 isMember can be false or one of the strings "Sequence", "Variadic",
19571 if type.isSequence():
19572 nullable
= type.nullable()
19575 elementType
= type.inner
19576 argType
= self
.getArgType(elementType
, False, "Sequence")[0]
19577 decl
= CGTemplatedType("Sequence", argType
)
19578 return decl
.define(), True, True
19580 if type.isRecord():
19581 nullable
= type.nullable()
19584 elementType
= type.inner
19585 argType
= self
.getArgType(elementType
, False, "Record")[0]
19586 decl
= CGTemplatedType("Record", [recordKeyDeclType(type), argType
])
19587 return decl
.define(), True, True
19590 # unionTypeDecl will handle nullable types, so return False for
19591 # auto-wrapping in Nullable
19592 return CGUnionStruct
.unionTypeDecl(type, isMember
), True, False
19594 if type.isPromise():
19595 assert not type.nullable()
19596 if optional
or isMember
:
19597 typeDecl
= "OwningNonNull<Promise>"
19599 typeDecl
= "Promise&"
19600 return (typeDecl
, False, False)
19602 if type.isGeckoInterface() and not type.isCallbackInterface():
19603 iface
= type.unroll().inner
19604 if iface
.identifier
.name
== "WindowProxy":
19605 return "WindowProxyHolder", True, False
19607 argIsPointer
= type.nullable() or iface
.isExternal()
19608 forceOwningType
= iface
.isCallback() or isMember
19610 if (optional
or isMember
) and forceOwningType
:
19611 typeDecl
= "RefPtr<%s>"
19615 if optional
or isMember
:
19616 if forceOwningType
:
19617 typeDecl
= "OwningNonNull<%s>"
19619 typeDecl
= "NonNull<%s>"
19625 % self
.descriptorProvider
.getDescriptor(
19626 iface
.identifier
.name
19633 if type.isSpiderMonkeyInterface():
19634 if not self
.spiderMonkeyInterfacesAreStructs
:
19635 return "JS::Handle<JSObject*>", False, False
19637 # Unroll for the name, in case we're nullable.
19638 return type.unroll().name
, True, True
19640 if type.isJSString():
19642 raise TypeError("JSString not supported as member")
19643 return "JS::Handle<JSString*>", False, False
19645 if type.isDOMString() or type.isUSVString():
19647 declType
= "nsString"
19649 declType
= "nsAString"
19650 return declType
, True, False
19652 if type.isByteString() or type.isUTF8String():
19653 # TODO(emilio): Maybe bytestrings could benefit from nsAutoCString
19655 if type.isUTF8String() and not isMember
:
19656 declType
= "nsACString"
19658 declType
= "nsCString"
19659 return declType
, True, False
19662 return type.unroll().inner
.identifier
.name
, False, True
19664 if type.isCallback() or type.isCallbackInterface():
19665 forceOwningType
= optional
or isMember
19666 if type.nullable():
19667 if forceOwningType
:
19668 declType
= "RefPtr<%s>"
19672 if forceOwningType
:
19673 declType
= "OwningNonNull<%s>"
19676 if type.isCallback():
19677 name
= type.unroll().callback
.identifier
.name
19679 name
= type.unroll().inner
.identifier
.name
19680 return declType
% name
, False, False
19683 # Don't do the rooting stuff for variadics for now
19685 declType
= "JS::Value"
19687 declType
= "JS::Handle<JS::Value>"
19688 return declType
, False, False
19690 if type.isObject():
19692 declType
= "JSObject*"
19694 declType
= "JS::Handle<JSObject*>"
19695 return declType
, False, False
19697 if type.isDictionary():
19698 typeName
= CGDictionary
.makeDictionaryName(type.inner
)
19699 return typeName
, True, True
19701 assert type.isPrimitive()
19703 return builtinNames
[type.tag()], False, True
19705 def getArgType(self
, type, optional
, isMember
):
19707 Get the type of an argument declaration. Returns the type CGThing, and
19708 whether this should be a const ref.
19710 isMember can be False, "Sequence", or "Variadic"
19712 decl
, ref
, handleNullable
= self
.doGetArgType(type, optional
, isMember
)
19713 decl
= CGGeneric(decl
)
19714 if handleNullable
and type.nullable():
19715 decl
= CGTemplatedType("Nullable", decl
)
19717 if isMember
== "Variadic":
19718 arrayType
= "Sequence" if self
.variadicIsSequence
else "nsTArray"
19719 decl
= CGTemplatedType(arrayType
, decl
)
19722 # Note: All variadic args claim to be optional, but we can just use
19723 # empty arrays to represent them not being present.
19724 decl
= CGTemplatedType("Optional", decl
)
19728 def getArg(self
, arg
):
19730 Get the full argument declaration for an argument
19732 decl
, ref
= self
.getArgType(
19733 arg
.type, arg
.canHaveMissingValue(), "Variadic" if arg
.variadic
else False
19736 decl
= CGWrapper(decl
, pre
="const ", post
="&")
19738 return Argument(decl
.define(), arg
.identifier
.name
)
19740 def arguments(self
):
19741 return self
.member
.signatures()[0][1]
19744 class CGExampleMethod(CGNativeMember
):
19745 def __init__(self
, descriptor
, method
, signature
, isConstructor
, breakAfter
=True):
19746 CGNativeMember
.__init
__(
19750 CGSpecializedMethod
.makeNativeName(descriptor
, method
),
19752 descriptor
.getExtendedAttributes(method
),
19753 breakAfter
=breakAfter
,
19754 variadicIsSequence
=True,
19757 def declare(self
, cgClass
):
19758 assert self
.member
.isMethod()
19759 # We skip declaring ourselves if this is a maplike/setlike/iterable
19760 # method, because those get implemented automatically by the binding
19761 # machinery, so the implementor of the interface doesn't have to worry
19763 if self
.member
.isMaplikeOrSetlikeOrIterableMethod():
19765 return CGNativeMember
.declare(self
, cgClass
)
19767 def define(self
, cgClass
):
19771 class CGExampleGetter(CGNativeMember
):
19772 def __init__(self
, descriptor
, attr
):
19773 CGNativeMember
.__init
__(
19777 CGSpecializedGetterCommon
.makeNativeName(descriptor
, attr
),
19779 descriptor
.getExtendedAttributes(attr
, getter
=True),
19782 def declare(self
, cgClass
):
19783 assert self
.member
.isAttr()
19784 # We skip declaring ourselves if this is a maplike/setlike attr (in
19785 # practice, "size"), because those get implemented automatically by the
19786 # binding machinery, so the implementor of the interface doesn't have to
19788 if self
.member
.isMaplikeOrSetlikeAttr():
19790 return CGNativeMember
.declare(self
, cgClass
)
19792 def define(self
, cgClass
):
19796 class CGExampleSetter(CGNativeMember
):
19797 def __init__(self
, descriptor
, attr
):
19798 CGNativeMember
.__init
__(
19802 CGSpecializedSetterCommon
.makeNativeName(descriptor
, attr
),
19804 BuiltinTypes
[IDLBuiltinType
.Types
.undefined
],
19805 [FakeArgument(attr
.type)],
19807 descriptor
.getExtendedAttributes(attr
, setter
=True),
19810 def define(self
, cgClass
):
19814 class CGBindingImplClass(CGClass
):
19816 Common codegen for generating a C++ implementation of a WebIDL interface
19825 wantGetParent
=True,
19826 wrapMethodName
="WrapObject",
19827 skipStaticMethods
=False,
19830 cgMethod, cgGetter and cgSetter are classes used to codegen methods,
19831 getters and setters.
19833 self
.descriptor
= descriptor
19834 self
._deps
= descriptor
.interface
.getDeps()
19836 iface
= descriptor
.interface
19838 self
.methodDecls
= []
19840 def appendMethod(m
, isConstructor
=False):
19841 sigs
= m
.signatures()
19842 for s
in sigs
[:-1]:
19843 # Don't put a blank line after overloads, until we
19844 # get to the last one.
19845 self
.methodDecls
.append(
19846 cgMethod(descriptor
, m
, s
, isConstructor
, breakAfter
=False)
19848 self
.methodDecls
.append(cgMethod(descriptor
, m
, sigs
[-1], isConstructor
))
19851 appendMethod(iface
.ctor(), isConstructor
=True)
19852 for n
in iface
.legacyFactoryFunctions
:
19853 appendMethod(n
, isConstructor
=True)
19854 for m
in iface
.members
:
19856 if m
.isIdentifierLess():
19858 if m
.isMaplikeOrSetlikeOrIterableMethod():
19859 # Handled by generated code already
19861 if not m
.isStatic() or not skipStaticMethods
:
19864 if m
.isMaplikeOrSetlikeAttr() or m
.type.isObservableArray():
19865 # Handled by generated code already
19867 self
.methodDecls
.append(cgGetter(descriptor
, m
))
19869 self
.methodDecls
.append(cgSetter(descriptor
, m
))
19871 # Now do the special operations
19872 def appendSpecialOperation(name
, op
):
19875 assert len(op
.signatures()) == 1
19876 returnType
, args
= op
.signatures()[0]
19877 # Make a copy of the args, since we plan to modify them.
19879 if op
.isGetter() or op
.isDeleter():
19880 # This is a total hack. The '&' belongs with the
19881 # type, not the name! But it works, and is simpler
19882 # than trying to somehow make this pretty.
19885 BuiltinTypes
[IDLBuiltinType
.Types
.boolean
], name
="&found"
19888 if name
== "Stringifier":
19889 if op
.isIdentifierLess():
19890 # XXXbz I wish we were consistent about our renaming here.
19893 # We already added this method
19895 if name
== "LegacyCaller":
19896 if op
.isIdentifierLess():
19897 # XXXbz I wish we were consistent about our renaming here.
19898 name
= "LegacyCall"
19900 # We already added this method
19902 self
.methodDecls
.append(
19907 (returnType
, args
),
19908 descriptor
.getExtendedAttributes(op
),
19912 # Sort things by name so we get stable ordering in the output.
19913 ops
= sorted(descriptor
.operations
.items(), key
=lambda x
: x
[0])
19914 for name
, op
in ops
:
19915 appendSpecialOperation(name
, op
)
19916 # If we support indexed properties, then we need a Length()
19917 # method so we know which indices are supported.
19918 if descriptor
.supportsIndexedProperties():
19919 # But we don't need it if we already have an infallible
19920 # "length" attribute, which we often do.
19921 haveLengthAttr
= any(
19923 for m
in iface
.members
19925 and CGSpecializedGetterCommon
.makeNativeName(descriptor
, m
) == "Length"
19927 if not haveLengthAttr
:
19928 self
.methodDecls
.append(
19933 (BuiltinTypes
[IDLBuiltinType
.Types
.unsigned_long
], []),
19937 # And if we support named properties we need to be able to
19938 # enumerate the supported names.
19939 if descriptor
.supportsNamedProperties():
19940 self
.methodDecls
.append(
19944 "GetSupportedNames",
19947 None, BuiltinTypes
[IDLBuiltinType
.Types
.domstring
]
19955 if descriptor
.concrete
:
19957 Argument("JSContext*", "aCx"),
19958 Argument("JS::Handle<JSObject*>", "aGivenProto"),
19960 if not descriptor
.wrapperCache
:
19961 wrapReturnType
= "bool"
19962 wrapArgs
.append(Argument("JS::MutableHandle<JSObject*>", "aReflector"))
19964 wrapReturnType
= "JSObject*"
19965 self
.methodDecls
.insert(
19971 virtual
=descriptor
.wrapperCache
,
19972 breakAfterReturnDecl
=" ",
19973 override
=descriptor
.wrapperCache
,
19974 body
=self
.getWrapObjectBody(),
19977 if descriptor
.hasCEReactions():
19978 self
.methodDecls
.insert(
19985 breakAfterReturnDecl
=" ",
19986 body
=self
.getGetDocGroupBody(),
19990 self
.methodDecls
.insert(
19994 self
.getGetParentObjectReturnType(),
19997 breakAfterReturnDecl
=" ",
19998 body
=self
.getGetParentObjectBody(),
20002 # Invoke CGClass.__init__ in any subclasses afterwards to do the actual codegen.
20004 def getWrapObjectBody(self
):
20007 def getGetParentObjectReturnType(self
):
20008 # The lack of newline before the end of the string is on purpose.
20011 // This should return something that eventually allows finding a
20012 // path to the global this object is associated with. Most simply,
20013 // returning an actual global works.
20014 nsIGlobalObject*"""
20017 def getGetParentObjectBody(self
):
20020 def getGetDocGroupBody(self
):
20027 class CGExampleObservableArrayCallback(CGNativeMember
):
20028 def __init__(self
, descriptor
, attr
, callbackName
):
20029 assert attr
.isAttr()
20030 assert attr
.type.isObservableArray()
20031 CGNativeMember
.__init
__(
20035 self
.makeNativeName(attr
, callbackName
),
20037 BuiltinTypes
[IDLBuiltinType
.Types
.undefined
],
20039 FakeArgument(attr
.type.inner
, "aValue"),
20041 BuiltinTypes
[IDLBuiltinType
.Types
.unsigned_long
], "aIndex"
20045 ["needsErrorResult"],
20048 def declare(self
, cgClass
):
20049 assert self
.member
.isAttr()
20050 assert self
.member
.type.isObservableArray()
20051 return CGNativeMember
.declare(self
, cgClass
)
20053 def define(self
, cgClass
):
20057 def makeNativeName(attr
, callbackName
):
20058 assert attr
.isAttr()
20059 nativeName
= MakeNativeName(attr
.identifier
.name
)
20060 return "On" + callbackName
+ nativeName
20063 class CGExampleClass(CGBindingImplClass
):
20065 Codegen for the actual example class implementation for this descriptor
20068 def __init__(self
, descriptor
):
20069 CGBindingImplClass
.__init
__(
20075 wantGetParent
=descriptor
.wrapperCache
,
20078 self
.parentIface
= descriptor
.interface
.parent
20079 if self
.parentIface
:
20080 self
.parentDesc
= descriptor
.getDescriptor(self
.parentIface
.identifier
.name
)
20081 bases
= [ClassBase(self
.nativeLeafName(self
.parentDesc
))]
20085 "nsISupports /* or NonRefcountedDOMObject if this is a non-refcounted object */"
20088 if descriptor
.wrapperCache
:
20091 "nsWrapperCache /* Change wrapperCache in the binding configuration if you don't want this */"
20095 destructorVisibility
= "protected"
20096 if self
.parentIface
:
20097 extradeclarations
= (
20099 " NS_DECL_ISUPPORTS_INHERITED\n"
20100 " NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(%s, %s)\n"
20103 self
.nativeLeafName(descriptor
),
20104 self
.nativeLeafName(self
.parentDesc
),
20108 extradeclarations
= (
20110 " NS_DECL_CYCLE_COLLECTING_ISUPPORTS\n"
20111 " NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(%s)\n"
20112 "\n" % self
.nativeLeafName(descriptor
)
20115 if descriptor
.interface
.hasChildInterfaces():
20118 decorators
= "final"
20120 for m
in descriptor
.interface
.members
:
20121 if m
.isAttr() and m
.type.isObservableArray():
20122 self
.methodDecls
.append(
20123 CGExampleObservableArrayCallback(descriptor
, m
, "Set")
20125 self
.methodDecls
.append(
20126 CGExampleObservableArrayCallback(descriptor
, m
, "Delete")
20131 self
.nativeLeafName(descriptor
),
20133 constructors
=[ClassConstructor([], visibility
="public")],
20134 destructor
=ClassDestructor(visibility
=destructorVisibility
),
20135 methods
=self
.methodDecls
,
20136 decorators
=decorators
,
20137 extradeclarations
=extradeclarations
,
20141 # Just override CGClass and do our own thing
20142 nativeType
= self
.nativeLeafName(self
.descriptor
)
20146 ${nativeType}::${nativeType}()
20148 // Add |MOZ_COUNT_CTOR(${nativeType});| for a non-refcounted object.
20151 ${nativeType}::~${nativeType}()
20153 // Add |MOZ_COUNT_DTOR(${nativeType});| for a non-refcounted object.
20156 nativeType
=nativeType
,
20159 if self
.parentIface
:
20163 // Only needed for refcounted objects.
20164 # error "If you don't have members that need cycle collection,
20165 # then remove all the cycle collection bits from this
20166 # implementation and the corresponding header. If you do, you
20167 # want NS_IMPL_CYCLE_COLLECTION_INHERITED(${nativeType},
20168 # ${parentType}, your, members, here)"
20169 NS_IMPL_ADDREF_INHERITED(${nativeType}, ${parentType})
20170 NS_IMPL_RELEASE_INHERITED(${nativeType}, ${parentType})
20171 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
20172 NS_INTERFACE_MAP_END_INHERITING(${parentType})
20175 nativeType
=nativeType
,
20176 parentType
=self
.nativeLeafName(self
.parentDesc
),
20182 // Only needed for refcounted objects.
20183 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(${nativeType})
20184 NS_IMPL_CYCLE_COLLECTING_ADDREF(${nativeType})
20185 NS_IMPL_CYCLE_COLLECTING_RELEASE(${nativeType})
20186 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
20187 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
20188 NS_INTERFACE_MAP_ENTRY(nsISupports)
20189 NS_INTERFACE_MAP_END
20192 nativeType
=nativeType
,
20195 classImpl
= ccImpl
+ ctordtor
+ "\n"
20196 if self
.descriptor
.concrete
:
20197 if self
.descriptor
.wrapperCache
:
20199 reflectorPassArg
= ""
20200 returnType
= "JSObject*"
20202 reflectorArg
= ", JS::MutableHandle<JSObject*> aReflector"
20203 reflectorPassArg
= ", aReflector"
20204 returnType
= "bool"
20208 ${nativeType}::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto${reflectorArg})
20210 return ${ifaceName}_Binding::Wrap(aCx, this, aGivenProto${reflectorPassArg});
20214 returnType
=returnType
,
20215 nativeType
=nativeType
,
20216 reflectorArg
=reflectorArg
,
20217 ifaceName
=self
.descriptor
.name
,
20218 reflectorPassArg
=reflectorPassArg
,
20224 def nativeLeafName(descriptor
):
20225 return descriptor
.nativeType
.split("::")[-1]
20228 class CGExampleRoot(CGThing
):
20230 Root codegen class for example implementation generation. Instantiate the
20231 class and call declare or define to generate header or cpp code,
20235 def __init__(self
, config
, interfaceName
):
20236 descriptor
= config
.getDescriptor(interfaceName
)
20238 self
.root
= CGWrapper(CGExampleClass(descriptor
), pre
="\n", post
="\n")
20240 self
.root
= CGNamespace
.build(["mozilla", "dom"], self
.root
)
20242 builder
= ForwardDeclarationBuilder()
20243 if descriptor
.hasCEReactions():
20244 builder
.addInMozillaDom("DocGroup")
20245 for member
in descriptor
.interface
.members
:
20246 if not member
.isAttr() and not member
.isMethod():
20248 if member
.isStatic():
20249 builder
.addInMozillaDom("GlobalObject")
20250 if member
.isAttr():
20251 if not member
.isMaplikeOrSetlikeAttr():
20252 builder
.forwardDeclareForType(member
.type, config
)
20254 assert member
.isMethod()
20255 if not member
.isMaplikeOrSetlikeOrIterableMethod():
20256 for sig
in member
.signatures():
20257 builder
.forwardDeclareForType(sig
[0], config
)
20259 builder
.forwardDeclareForType(arg
.type, config
)
20261 self
.root
= CGList([builder
.build(), self
.root
], "\n")
20263 # Throw in our #includes
20264 self
.root
= CGHeaders(
20270 "nsWrapperCache.h",
20271 "nsCycleCollectionParticipant.h",
20272 "mozilla/Attributes.h",
20273 "mozilla/ErrorResult.h",
20274 "mozilla/dom/BindingDeclarations.h",
20278 "mozilla/dom/%s.h" % interfaceName
,
20281 % CGHeaders
.getDeclarationFilename(descriptor
.interface
)
20288 # And now some include guards
20289 self
.root
= CGIncludeGuard(interfaceName
, self
.root
)
20291 # And our license block comes before everything else
20292 self
.root
= CGWrapper(
20296 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
20297 /* vim:set ts=2 sw=2 sts=2 et cindent: */
20298 /* This Source Code Form is subject to the terms of the Mozilla Public
20299 * License, v. 2.0. If a copy of the MPL was not distributed with this
20300 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
20307 return self
.root
.declare()
20310 return self
.root
.define()
20313 def jsImplName(name
):
20314 return name
+ "JSImpl"
20317 class CGJSImplMember(CGNativeMember
):
20319 Base class for generating code for the members of the implementation class
20320 for a JS-implemented WebIDL interface.
20325 descriptorProvider
,
20331 passJSBitsAsNeeded
=True,
20332 visibility
="public",
20333 variadicIsSequence
=False,
20337 CGNativeMember
.__init
__(
20339 descriptorProvider
,
20344 breakAfter
=breakAfter
,
20345 passJSBitsAsNeeded
=passJSBitsAsNeeded
,
20346 visibility
=visibility
,
20347 variadicIsSequence
=variadicIsSequence
,
20351 self
.body
= self
.getImpl()
20353 def getArgs(self
, returnType
, argList
):
20354 args
= CGNativeMember
.getArgs(self
, returnType
, argList
)
20355 args
.append(Argument("JS::Realm*", "aRealm", "nullptr"))
20359 class CGJSImplMethod(CGJSImplMember
):
20361 Class for generating code for the methods for a JS-implemented WebIDL
20365 def __init__(self
, descriptor
, method
, signature
, isConstructor
, breakAfter
=True):
20366 self
.signature
= signature
20367 self
.descriptor
= descriptor
20368 self
.isConstructor
= isConstructor
20369 CGJSImplMember
.__init
__(
20373 CGSpecializedMethod
.makeNativeName(descriptor
, method
),
20375 descriptor
.getExtendedAttributes(method
),
20376 breakAfter
=breakAfter
,
20377 variadicIsSequence
=True,
20378 passJSBitsAsNeeded
=False,
20381 def getArgs(self
, returnType
, argList
):
20382 if self
.isConstructor
:
20383 # Skip the JS::Compartment bits for constructors; it's handled
20384 # manually in getImpl. But we do need our aGivenProto argument. We
20385 # allow it to be omitted if the default proto is desired.
20386 return CGNativeMember
.getArgs(self
, returnType
, argList
) + [
20387 Argument("JS::Handle<JSObject*>", "aGivenProto", "nullptr")
20389 return CGJSImplMember
.getArgs(self
, returnType
, argList
)
20392 args
= self
.getArgs(self
.signature
[0], self
.signature
[1])
20393 if not self
.isConstructor
:
20394 return "return mImpl->%s(%s);\n" % (
20396 ", ".join(arg
.name
for arg
in args
),
20399 assert self
.descriptor
.interface
.isJSImplemented()
20400 if self
.name
!= "Constructor":
20402 "Legacy factory functions are not supported for JS implemented WebIDL."
20404 if len(self
.signature
[1]) != 0:
20405 # The first two arguments to the constructor implementation are not
20406 # arguments to the WebIDL constructor, so don't pass them to
20407 # __Init(). The last argument is the prototype we're supposed to
20408 # use, and shouldn't get passed to __Init() either.
20409 assert args
[0].argType
== "const GlobalObject&"
20410 assert args
[1].argType
== "JSContext*"
20411 assert args
[-1].argType
== "JS::Handle<JSObject*>"
20412 assert args
[-1].name
== "aGivenProto"
20413 constructorArgs
= [arg
.name
for arg
in args
[2:-1]]
20414 constructorArgs
.append("js::GetNonCCWObjectRealm(scopeObj)")
20417 // Wrap the object before calling __Init so that __DOM_IMPL__ is available.
20418 JS::Rooted<JSObject*> scopeObj(cx, global.Get());
20419 MOZ_ASSERT(js::IsObjectInContextCompartment(scopeObj, cx));
20420 JS::Rooted<JS::Value> wrappedVal(cx);
20421 if (!GetOrCreateDOMReflector(cx, impl, &wrappedVal, aGivenProto)) {
20422 MOZ_ASSERT(JS_IsExceptionPending(cx));
20423 aRv.Throw(NS_ERROR_UNEXPECTED);
20426 // Initialize the object with the constructor arguments.
20427 impl->mImpl->__Init(${args});
20428 if (aRv.Failed()) {
20432 args
=", ".join(constructorArgs
),
20438 RefPtr<${implClass}> impl =
20439 ConstructJSImplementation<${implClass}>("${contractId}", global, aRv);
20440 if (aRv.Failed()) {
20444 return impl.forget();
20446 contractId
=self
.descriptor
.interface
.getJSImplementation(),
20447 implClass
=self
.descriptor
.name
,
20452 # We're always fallible
20453 def callbackGetterName(attr
, descriptor
):
20454 return "Get" + MakeNativeName(
20455 descriptor
.binaryNameFor(attr
.identifier
.name
, attr
.isStatic())
20459 def callbackSetterName(attr
, descriptor
):
20460 return "Set" + MakeNativeName(
20461 descriptor
.binaryNameFor(attr
.identifier
.name
, attr
.isStatic())
20465 class CGJSImplGetter(CGJSImplMember
):
20467 Class for generating code for the getters of attributes for a JS-implemented
20471 def __init__(self
, descriptor
, attr
):
20472 CGJSImplMember
.__init
__(
20476 CGSpecializedGetterCommon
.makeNativeName(descriptor
, attr
),
20478 descriptor
.getExtendedAttributes(attr
, getter
=True),
20479 passJSBitsAsNeeded
=False,
20483 callbackArgs
= [arg
.name
for arg
in self
.getArgs(self
.member
.type, [])]
20484 return "return mImpl->%s(%s);\n" % (
20485 callbackGetterName(self
.member
, self
.descriptorProvider
),
20486 ", ".join(callbackArgs
),
20490 class CGJSImplSetter(CGJSImplMember
):
20492 Class for generating code for the setters of attributes for a JS-implemented
20496 def __init__(self
, descriptor
, attr
):
20497 CGJSImplMember
.__init
__(
20501 CGSpecializedSetterCommon
.makeNativeName(descriptor
, attr
),
20503 BuiltinTypes
[IDLBuiltinType
.Types
.undefined
],
20504 [FakeArgument(attr
.type)],
20506 descriptor
.getExtendedAttributes(attr
, setter
=True),
20507 passJSBitsAsNeeded
=False,
20513 for arg
in self
.getArgs(
20514 BuiltinTypes
[IDLBuiltinType
.Types
.undefined
],
20515 [FakeArgument(self
.member
.type)],
20518 return "mImpl->%s(%s);\n" % (
20519 callbackSetterName(self
.member
, self
.descriptorProvider
),
20520 ", ".join(callbackArgs
),
20524 class CGJSImplClass(CGBindingImplClass
):
20525 def __init__(self
, descriptor
):
20526 CGBindingImplClass
.__init
__(
20532 skipStaticMethods
=True,
20535 if descriptor
.interface
.parent
:
20536 parentClass
= descriptor
.getDescriptor(
20537 descriptor
.interface
.parent
.identifier
.name
20539 baseClasses
= [ClassBase(parentClass
)]
20540 isupportsDecl
= "NS_DECL_ISUPPORTS_INHERITED\n"
20541 ccDecl
= "NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(%s, %s)\n" % (
20545 extradefinitions
= fill(
20547 NS_IMPL_CYCLE_COLLECTION_INHERITED(${ifaceName}, ${parentClass}, mImpl, mParent)
20548 NS_IMPL_ADDREF_INHERITED(${ifaceName}, ${parentClass})
20549 NS_IMPL_RELEASE_INHERITED(${ifaceName}, ${parentClass})
20550 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${ifaceName})
20551 NS_INTERFACE_MAP_END_INHERITING(${parentClass})
20553 ifaceName
=self
.descriptor
.name
,
20554 parentClass
=parentClass
,
20558 ClassBase("nsSupportsWeakReference"),
20559 ClassBase("nsWrapperCache"),
20561 isupportsDecl
= "NS_DECL_CYCLE_COLLECTING_ISUPPORTS\n"
20563 "NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(%s)\n" % descriptor
.name
20565 extradefinitions
= fill(
20567 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(${ifaceName})
20568 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(${ifaceName})
20569 NS_IMPL_CYCLE_COLLECTION_UNLINK(mImpl)
20570 NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
20571 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
20572 tmp->ClearWeakReferences();
20573 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
20574 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(${ifaceName})
20575 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImpl)
20576 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
20577 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
20578 NS_IMPL_CYCLE_COLLECTING_ADDREF(${ifaceName})
20579 NS_IMPL_CYCLE_COLLECTING_RELEASE(${ifaceName})
20580 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${ifaceName})
20581 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
20582 NS_INTERFACE_MAP_ENTRY(nsISupports)
20583 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
20584 NS_INTERFACE_MAP_END
20586 ifaceName
=self
.descriptor
.name
,
20589 extradeclarations
= fill(
20596 RefPtr<${jsImplName}> mImpl;
20597 nsCOMPtr<nsIGlobalObject> mParent;
20600 isupportsDecl
=isupportsDecl
,
20602 jsImplName
=jsImplName(descriptor
.name
),
20605 if descriptor
.interface
.getExtendedAttribute("WantsEventListenerHooks"):
20606 # No need to do too much sanity checking here; the
20607 # generated code will fail to compile if the methods we
20608 # try to overrid aren't on a superclass.
20609 self
.methodDecls
.extend(
20610 self
.getEventHookMethod(parentClass
, "EventListenerAdded")
20612 self
.methodDecls
.extend(
20613 self
.getEventHookMethod(parentClass
, "EventListenerRemoved")
20616 if descriptor
.interface
.hasChildInterfaces():
20618 # We need a protected virtual destructor our subclasses can use
20619 destructor
= ClassDestructor(virtual
=True, visibility
="protected")
20621 decorators
= "final"
20622 destructor
= ClassDestructor(virtual
=False, visibility
="private")
20624 baseConstructors
= [
20626 "mImpl(new %s(nullptr, aJSImplObject, aJSImplGlobal, /* aIncumbentGlobal = */ nullptr))"
20627 % jsImplName(descriptor
.name
)
20629 "mParent(aParent)",
20631 parentInterface
= descriptor
.interface
.parent
20632 while parentInterface
:
20633 if parentInterface
.isJSImplemented():
20634 baseConstructors
.insert(
20635 0, "%s(aJSImplObject, aJSImplGlobal, aParent)" % parentClass
20638 parentInterface
= parentInterface
.parent
20639 if not parentInterface
and descriptor
.interface
.parent
:
20640 # We only have C++ ancestors, so only pass along the window
20641 baseConstructors
.insert(0, "%s(aParent)" % parentClass
)
20643 constructor
= ClassConstructor(
20645 Argument("JS::Handle<JSObject*>", "aJSImplObject"),
20646 Argument("JS::Handle<JSObject*>", "aJSImplGlobal"),
20647 Argument("nsIGlobalObject*", "aParent"),
20649 visibility
="public",
20650 baseConstructors
=baseConstructors
,
20653 self
.methodDecls
.append(
20657 JSNativeArguments(),
20659 body
=self
.getCreateFromExistingBody(),
20667 constructors
=[constructor
],
20668 destructor
=destructor
,
20669 methods
=self
.methodDecls
,
20670 decorators
=decorators
,
20671 extradeclarations
=extradeclarations
,
20672 extradefinitions
=extradefinitions
,
20675 def getWrapObjectBody(self
):
20678 JS::Rooted<JSObject*> obj(aCx, ${name}_Binding::Wrap(aCx, this, aGivenProto));
20683 // Now define it on our chrome object
20684 JSAutoRealm ar(aCx, mImpl->CallbackGlobalOrNull());
20685 if (!JS_WrapObject(aCx, &obj)) {
20688 JS::Rooted<JSObject*> callback(aCx, mImpl->CallbackOrNull());
20689 if (!JS_DefineProperty(aCx, callback, "__DOM_IMPL__", obj, 0)) {
20694 name
=self
.descriptor
.name
,
20697 def getGetParentObjectReturnType(self
):
20698 return "nsISupports*"
20700 def getGetParentObjectBody(self
):
20701 return "return mParent;\n"
20703 def getGetDocGroupBody(self
):
20706 nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mParent);
20710 return window->GetDocGroup();
20714 def getCreateFromExistingBody(self
):
20715 # XXXbz we could try to get parts of this (e.g. the argument
20716 # conversions) auto-generated by somehow creating an IDLMethod and
20717 # adding it to our interface, but we'd still need to special-case the
20718 # implementation slightly to have it not try to forward to the JS
20722 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
20723 if (!args.requireAtLeast(cx, "${ifaceName}._create", 2)) {
20726 BindingCallContext callCx(cx, "${ifaceName}._create");
20727 if (!args[0].isObject()) {
20728 return callCx.ThrowErrorMessage<MSG_NOT_OBJECT>("Argument 1");
20730 if (!args[1].isObject()) {
20731 return callCx.ThrowErrorMessage<MSG_NOT_OBJECT>("Argument 2");
20734 // GlobalObject will go through wrappers as needed for us, and
20735 // is simpler than the right UnwrapArg incantation.
20736 GlobalObject global(cx, &args[0].toObject());
20737 if (global.Failed()) {
20740 nsCOMPtr<nsIGlobalObject> globalHolder = do_QueryInterface(global.GetAsSupports());
20741 MOZ_ASSERT(globalHolder);
20742 JS::Rooted<JSObject*> arg(cx, &args[1].toObject());
20743 JS::Rooted<JSObject*> argGlobal(cx, JS::CurrentGlobalOrNull(cx));
20744 RefPtr<${implName}> impl = new ${implName}(arg, argGlobal, globalHolder);
20745 MOZ_ASSERT(js::IsObjectInContextCompartment(arg, cx));
20746 return GetOrCreateDOMReflector(cx, impl, args.rval());
20748 ifaceName
=self
.descriptor
.interface
.identifier
.name
,
20749 implName
=self
.descriptor
.name
,
20752 def getEventHookMethod(self
, parentClass
, methodName
):
20755 ${parentClass}::${methodName}(aType);
20756 mImpl->${methodName}(Substring(nsDependentAtomString(aType), 2), IgnoreErrors());
20758 parentClass
=parentClass
,
20759 methodName
=methodName
,
20765 [Argument("nsAtom*", "aType")],
20770 ClassUsingFromBaseDeclaration(parentClass
, methodName
),
20774 def isJSImplementedDescriptor(descriptorProvider
):
20776 isinstance(descriptorProvider
, Descriptor
)
20777 and descriptorProvider
.interface
.isJSImplemented()
20781 class CGCallback(CGClass
):
20783 self
, idlObject
, descriptorProvider
, baseName
, methods
, getters
=[], setters
=[]
20785 self
.baseName
= baseName
20786 self
._deps
= idlObject
.getDeps()
20787 self
.idlObject
= idlObject
20788 self
.name
= idlObject
.identifier
.name
20789 if isJSImplementedDescriptor(descriptorProvider
):
20790 self
.name
= jsImplName(self
.name
)
20791 # For our public methods that needThisHandling we want most of the
20792 # same args and the same return type as what CallbackMember
20793 # generates. So we want to take advantage of all its
20794 # CGNativeMember infrastructure, but that infrastructure can't deal
20795 # with templates and most especially template arguments. So just
20796 # cheat and have CallbackMember compute all those things for us.
20798 for method
in methods
:
20799 if not isinstance(method
, CallbackMember
) or not method
.needThisHandling
:
20800 realMethods
.append(method
)
20802 realMethods
.extend(self
.getMethodImpls(method
))
20803 realMethods
.append(
20807 [Argument("const %s&" % self
.name
, "aOther")],
20811 body
=("return %s::operator==(aOther);\n" % baseName
),
20817 bases
=[ClassBase(baseName
)],
20818 constructors
=self
.getConstructors(),
20819 methods
=realMethods
+ getters
+ setters
,
20822 def getConstructors(self
):
20824 not self
.idlObject
.isInterface()
20825 and not self
.idlObject
._treatNonObjectAsNull
20827 body
= "MOZ_ASSERT(JS::IsCallable(mCallback));\n"
20829 # Not much we can assert about it, other than not being null, and
20830 # CallbackObject does that already.
20835 Argument("JSContext*", "aCx"),
20836 Argument("JS::Handle<JSObject*>", "aCallback"),
20837 Argument("JS::Handle<JSObject*>", "aCallbackGlobal"),
20838 Argument("nsIGlobalObject*", "aIncumbentGlobal"),
20841 visibility
="public",
20844 "%s(aCx, aCallback, aCallbackGlobal, aIncumbentGlobal)"
20851 Argument("JSObject*", "aCallback"),
20852 Argument("JSObject*", "aCallbackGlobal"),
20853 Argument("const FastCallbackConstructor&", ""),
20856 visibility
="public",
20859 "%s(aCallback, aCallbackGlobal, FastCallbackConstructor())"
20866 Argument("JSObject*", "aCallback"),
20867 Argument("JSObject*", "aCallbackGlobal"),
20868 Argument("JSObject*", "aAsyncStack"),
20869 Argument("nsIGlobalObject*", "aIncumbentGlobal"),
20872 visibility
="public",
20875 "%s(aCallback, aCallbackGlobal, aAsyncStack, aIncumbentGlobal)"
20882 def getMethodImpls(self
, method
):
20883 assert method
.needThisHandling
20884 args
= list(method
.args
)
20885 # Strip out the BindingCallContext&/JSObject* args
20887 assert args
[0].name
== "cx" and args
[0].argType
== "BindingCallContext&"
20888 assert args
[1].name
== "aThisVal" and args
[1].argType
== "JS::Handle<JS::Value>"
20891 # Now remember which index the ErrorResult argument is at;
20892 # we'll need this below.
20893 assert args
[-1].name
== "aRv" and args
[-1].argType
== "ErrorResult&"
20894 rvIndex
= len(args
) - 1
20895 assert rvIndex
>= 0
20897 # Record the names of all the arguments, so we can use them when we call
20898 # the private method.
20899 argnames
= [arg
.name
for arg
in args
]
20900 argnamesWithThis
= ["s.GetCallContext()", "thisValJS"] + argnames
20901 argnamesWithoutThis
= [
20902 "s.GetCallContext()",
20903 "JS::UndefinedHandleValue",
20905 # Now that we've recorded the argnames for our call to our private
20906 # method, insert our optional argument for the execution reason.
20907 args
.append(Argument("const char*", "aExecutionReason", "nullptr"))
20909 # Make copies of the arg list for the two "without rv" overloads. Note
20910 # that those don't need aExceptionHandling or aRealm arguments because
20911 # those would make not sense anyway: the only sane thing to do with
20912 # exceptions in the "without rv" cases is to report them.
20913 argsWithoutRv
= list(args
)
20914 argsWithoutRv
.pop(rvIndex
)
20915 argsWithoutThisAndRv
= list(argsWithoutRv
)
20917 # Add the potional argument for deciding whether the CallSetup should
20918 # re-throw exceptions on aRv.
20920 Argument("ExceptionHandling", "aExceptionHandling", "eReportExceptions")
20922 # And the argument for communicating when exceptions should really be
20923 # rethrown. In particular, even when aExceptionHandling is
20924 # eRethrowExceptions they won't get rethrown if aRealm is provided
20925 # and its principal doesn't subsume either the callback or the
20927 args
.append(Argument("JS::Realm*", "aRealm", "nullptr"))
20928 # And now insert our template argument.
20929 argsWithoutThis
= list(args
)
20930 args
.insert(0, Argument("const T&", "thisVal"))
20931 argsWithoutRv
.insert(0, Argument("const T&", "thisVal"))
20933 argnamesWithoutThisAndRv
= [arg
.name
for arg
in argsWithoutThisAndRv
]
20934 argnamesWithoutThisAndRv
.insert(rvIndex
, "IgnoreErrors()")
20935 # If we just leave things like that, and have no actual arguments in the
20936 # IDL, we will end up trying to call the templated "without rv" overload
20937 # with "rv" as the thisVal. That's no good. So explicitly append the
20938 # aExceptionHandling and aRealm values we need to end up matching the
20939 # signature of our non-templated "with rv" overload.
20940 argnamesWithoutThisAndRv
.extend(["eReportExceptions", "nullptr"])
20942 argnamesWithoutRv
= [arg
.name
for arg
in argsWithoutRv
]
20943 # Note that we need to insert at rvIndex + 1, since we inserted a
20944 # thisVal arg at the start.
20945 argnamesWithoutRv
.insert(rvIndex
+ 1, "IgnoreErrors()")
20947 errorReturn
= method
.getDefaultRetval()
20951 MOZ_ASSERT(!aRv.Failed(), "Don't pass an already-failed ErrorResult to a callback!");
20952 if (!aExecutionReason) {
20953 aExecutionReason = "${executionReason}";
20955 CallSetup s(this, aRv, aExecutionReason, aExceptionHandling, aRealm);
20956 if (!s.GetContext()) {
20957 MOZ_ASSERT(aRv.Failed());
20958 return${errorReturn};
20961 errorReturn
=errorReturn
,
20962 executionReason
=method
.getPrettyName(),
20965 bodyWithThis
= fill(
20968 JS::Rooted<JS::Value> thisValJS(s.GetContext());
20969 if (!ToJSValue(s.GetContext(), thisVal, &thisValJS)) {
20970 aRv.Throw(NS_ERROR_FAILURE);
20971 return${errorReturn};
20973 return ${methodName}(${callArgs});
20975 setupCall
=setupCall
,
20976 errorReturn
=errorReturn
,
20977 methodName
=method
.name
,
20978 callArgs
=", ".join(argnamesWithThis
),
20980 bodyWithoutThis
= fill(
20983 return ${methodName}(${callArgs});
20985 setupCall
=setupCall
,
20986 errorReturn
=errorReturn
,
20987 methodName
=method
.name
,
20988 callArgs
=", ".join(argnamesWithoutThis
),
20990 bodyWithThisWithoutRv
= fill(
20992 return ${methodName}(${callArgs});
20994 methodName
=method
.name
,
20995 callArgs
=", ".join(argnamesWithoutRv
),
20997 bodyWithoutThisAndRv
= fill(
20999 return ${methodName}(${callArgs});
21001 methodName
=method
.name
,
21002 callArgs
=", ".join(argnamesWithoutThisAndRv
),
21011 templateArgs
=["typename T"],
21013 canRunScript
=method
.canRunScript
,
21020 body
=bodyWithoutThis
,
21021 canRunScript
=method
.canRunScript
,
21028 templateArgs
=["typename T"],
21029 body
=bodyWithThisWithoutRv
,
21030 canRunScript
=method
.canRunScript
,
21035 argsWithoutThisAndRv
,
21037 body
=bodyWithoutThisAndRv
,
21038 canRunScript
=method
.canRunScript
,
21047 class CGCallbackFunction(CGCallback
):
21048 def __init__(self
, callback
, descriptorProvider
):
21049 self
.callback
= callback
21050 if callback
.isConstructor():
21051 methods
= [ConstructCallback(callback
, descriptorProvider
)]
21053 methods
= [CallCallback(callback
, descriptorProvider
)]
21054 CGCallback
.__init
__(
21055 self
, callback
, descriptorProvider
, "CallbackFunction", methods
21058 def getConstructors(self
):
21059 return CGCallback
.getConstructors(self
) + [
21061 [Argument("CallbackFunction*", "aOther")],
21063 visibility
="public",
21065 baseConstructors
=["CallbackFunction(aOther)"],
21070 class CGFastCallback(CGClass
):
21071 def __init__(self
, idlObject
):
21072 self
._deps
= idlObject
.getDeps()
21073 baseName
= idlObject
.identifier
.name
21074 constructor
= ClassConstructor(
21076 Argument("JSObject*", "aCallback"),
21077 Argument("JSObject*", "aCallbackGlobal"),
21080 visibility
="public",
21083 "%s(aCallback, aCallbackGlobal, FastCallbackConstructor())" % baseName
,
21088 traceMethod
= ClassMethod(
21091 [Argument("JSTracer*", "aTracer")],
21094 visibility
="public",
21095 body
="%s::Trace(aTracer);\n" % baseName
,
21097 holdMethod
= ClassMethod(
21098 "FinishSlowJSInitIfMoreThanOneOwner",
21100 [Argument("JSContext*", "aCx")],
21103 visibility
="public",
21104 body
=("%s::FinishSlowJSInitIfMoreThanOneOwner(aCx);\n" % baseName
),
21109 "Fast%s" % baseName
,
21110 bases
=[ClassBase(baseName
)],
21111 constructors
=[constructor
],
21112 methods
=[traceMethod
, holdMethod
],
21119 class CGCallbackInterface(CGCallback
):
21120 def __init__(self
, descriptor
, spiderMonkeyInterfacesAreStructs
=False):
21121 iface
= descriptor
.interface
21124 for m
in iface
.members
21127 and not m
.isStatic()
21128 and (not m
.isMaplikeOrSetlikeAttr() or not iface
.isJSImplemented())
21132 CallbackGetter(a
, descriptor
, spiderMonkeyInterfacesAreStructs
)
21136 CallbackSetter(a
, descriptor
, spiderMonkeyInterfacesAreStructs
)
21142 for m
in iface
.members
21145 and not m
.isStatic()
21146 and not m
.isIdentifierLess()
21148 not m
.isMaplikeOrSetlikeOrIterableMethod()
21149 or not iface
.isJSImplemented()
21154 CallbackOperation(m
, sig
, descriptor
, spiderMonkeyInterfacesAreStructs
)
21156 for sig
in m
.signatures()
21160 if iface
.isJSImplemented() and iface
.ctor():
21161 sigs
= descriptor
.interface
.ctor().signatures()
21163 raise TypeError("We only handle one constructor. See bug 869268.")
21164 methods
.append(CGJSImplInitOperation(sigs
[0], descriptor
))
21168 descriptor
.binaryNameFor(m
.identifier
.name
, m
.isStatic())
21169 for m
in iface
.members
21170 if m
.isAttr() or m
.isMethod()
21173 idlist
.append("__init")
21175 if iface
.isJSImplemented() and iface
.getExtendedAttribute(
21176 "WantsEventListenerHooks"
21178 methods
.append(CGJSImplEventHookOperation(descriptor
, "eventListenerAdded"))
21180 CGJSImplEventHookOperation(descriptor
, "eventListenerRemoved")
21182 idlist
.append("eventListenerAdded")
21183 idlist
.append("eventListenerRemoved")
21185 if len(idlist
) != 0:
21186 methods
.append(initIdsClassMethod(idlist
, iface
.identifier
.name
+ "Atoms"))
21187 CGCallback
.__init
__(
21191 "CallbackInterface",
21199 def __init__(self
, name
=None):
21200 if name
is not None:
21201 self
.identifier
= FakeIdentifier(name
)
21203 def isStatic(self
):
21209 def isMethod(self
):
21212 def getExtendedAttribute(self
, name
):
21213 # Claim to be a [NewObject] so we can avoid the "return a raw pointer"
21214 # comments CGNativeMember codegen would otherwise stick in.
21215 if name
== "NewObject":
21220 class CallbackMember(CGNativeMember
):
21221 # XXXbz It's OK to use CallbackKnownNotGray for wrapScope because
21222 # CallSetup already handled the unmark-gray bits for us. we don't have
21223 # anything better to use for 'obj', really...
21228 descriptorProvider
,
21230 rethrowContentException
=False,
21231 spiderMonkeyInterfacesAreStructs
=False,
21233 canRunScript
=False,
21234 passJSBitsAsNeeded
=False,
21237 needThisHandling is True if we need to be able to accept a specified
21238 thisObj, False otherwise.
21240 assert not rethrowContentException
or not needThisHandling
21242 self
.retvalType
= sig
[0]
21243 self
.originalSig
= sig
21245 self
.argCount
= len(args
)
21246 if self
.argCount
> 0:
21247 # Check for variadic arguments
21248 lastArg
= args
[self
.argCount
- 1]
21249 if lastArg
.variadic
:
21250 self
.argCountStr
= "(%d - 1) + %s.Length()" % (
21252 lastArg
.identifier
.name
,
21255 self
.argCountStr
= "%d" % self
.argCount
21256 self
.needThisHandling
= needThisHandling
21257 # If needThisHandling, we generate ourselves as private and the caller
21258 # will handle generating public versions that handle the "this" stuff.
21259 visibility
= "private" if needThisHandling
else "public"
21260 self
.rethrowContentException
= rethrowContentException
21262 self
.wrapScope
= wrapScope
21263 # We don't care, for callback codegen, whether our original member was
21264 # a method or attribute or whatnot. Just always pass FakeMember()
21266 CGNativeMember
.__init
__(
21268 descriptorProvider
,
21271 (self
.retvalType
, args
),
21272 extendedAttrs
=["needsErrorResult"],
21273 passJSBitsAsNeeded
=passJSBitsAsNeeded
,
21274 visibility
=visibility
,
21275 spiderMonkeyInterfacesAreStructs
=spiderMonkeyInterfacesAreStructs
,
21276 canRunScript
=canRunScript
,
21278 # We have to do all the generation of our body now, because
21279 # the caller relies on us throwing if we can't manage it.
21280 self
.body
= self
.getImpl()
21283 setupCall
= self
.getCallSetup()
21284 declRval
= self
.getRvalDecl()
21285 if self
.argCount
> 0:
21288 JS::RootedVector<JS::Value> argv(cx);
21289 if (!argv.resize(${argCount})) {
21291 return${errorReturn};
21294 argCount
=self
.argCountStr
,
21295 failureCode
=self
.getArgvDeclFailureCode(),
21296 errorReturn
=self
.getDefaultRetval(),
21299 # Avoid weird 0-sized arrays
21301 convertArgs
= self
.getArgConversions()
21302 doCall
= self
.getCall()
21303 returnResult
= self
.getResultConversion()
21305 body
= declRval
+ argvDecl
+ convertArgs
+ doCall
21306 if self
.needsScopeBody():
21307 body
= "{\n" + indent(body
) + "}\n"
21308 return setupCall
+ body
+ returnResult
21310 def needsScopeBody(self
):
21313 def getArgvDeclFailureCode(self
):
21316 // That threw an exception on the JSContext, and our CallSetup will do
21317 // the right thing with that.
21321 def getExceptionCode(self
, forResult
):
21324 aRv.Throw(NS_ERROR_UNEXPECTED);
21325 return${defaultRetval};
21327 defaultRetval
=self
.getDefaultRetval(),
21330 def getResultConversion(
21331 self
, val
="rval", failureCode
=None, isDefinitelyObject
=False, exceptionCode
=None
21335 "holderName": "rvalHolder",
21336 "declName": "rvalDecl",
21337 # We actually want to pass in a null scope object here, because
21338 # wrapping things into our current compartment (that of mCallback)
21341 "passedToJSImpl": "false",
21344 if isJSImplementedDescriptor(self
.descriptorProvider
):
21345 isCallbackReturnValue
= "JSImpl"
21347 isCallbackReturnValue
= "Callback"
21348 sourceDescription
= "return value of %s" % self
.getPrettyName()
21349 convertType
= instantiateJSToNativeConversion(
21350 getJSToNativeConversionInfo(
21352 self
.descriptorProvider
,
21353 failureCode
=failureCode
,
21354 isDefinitelyObject
=isDefinitelyObject
,
21355 exceptionCode
=exceptionCode
or self
.getExceptionCode(forResult
=True),
21356 isCallbackReturnValue
=isCallbackReturnValue
,
21357 # Allow returning a callback type that
21358 # allows non-callable objects.
21359 allowTreatNonCallableAsNull
=True,
21360 sourceDescription
=sourceDescription
,
21364 assignRetval
= string
.Template(
21365 self
.getRetvalInfo(self
.retvalType
, False)[2]
21366 ).substitute(replacements
)
21367 type = convertType
.define()
21368 return type + assignRetval
21370 def getArgConversions(self
):
21371 # Just reget the arglist from self.originalSig, because our superclasses
21372 # just have way to many members they like to clobber, so I can't find a
21373 # safe member name to store it in.
21375 self
.getArgConversion(i
, arg
) for i
, arg
in enumerate(self
.originalSig
[1])
21377 if not argConversions
:
21380 # Do them back to front, so our argc modifications will work
21381 # correctly, because we examine trailing arguments first.
21382 argConversions
.reverse()
21383 # Wrap each one in a scope so that any locals it has don't leak out, and
21384 # also so that we can just "break;" for our successCode.
21386 CGWrapper(CGIndenter(CGGeneric(c
)), pre
="do {\n", post
="} while (false);\n")
21387 for c
in argConversions
21389 if self
.argCount
> 0:
21390 argConversions
.insert(0, self
.getArgcDecl())
21391 # And slap them together.
21392 return CGList(argConversions
, "\n").define() + "\n"
21394 def getArgConversion(self
, i
, arg
):
21395 argval
= arg
.identifier
.name
21398 argval
= argval
+ "[idx]"
21399 jsvalIndex
= "%d + idx" % i
21401 jsvalIndex
= "%d" % i
21402 if arg
.canHaveMissingValue():
21403 argval
+= ".Value()"
21407 wrapScope
= self
.wrapScope
21408 if arg
.type.isUnion() and wrapScope
is None:
21410 "JS::Rooted<JSObject*> callbackObj(cx, CallbackKnownNotGray());\n"
21412 wrapScope
= "callbackObj"
21414 conversion
= prepend
+ wrapForType(
21416 self
.descriptorProvider
,
21419 "successCode": "continue;\n" if arg
.variadic
else "break;\n",
21420 "jsvalRef": "argv[%s]" % jsvalIndex
,
21421 "jsvalHandle": "argv[%s]" % jsvalIndex
,
21423 "returnsNewObject": False,
21424 "exceptionCode": self
.getExceptionCode(forResult
=False),
21425 "spiderMonkeyInterfacesAreStructs": self
.spiderMonkeyInterfacesAreStructs
,
21432 for (uint32_t idx = 0; idx < ${arg}.Length(); ++idx) {
21437 arg
=arg
.identifier
.name
,
21438 conversion
=conversion
,
21440 elif arg
.canHaveMissingValue():
21443 if (${argName}.WasPassed()) {
21445 } else if (argc == ${iPlus1}) {
21446 // This is our current trailing argument; reduce argc
21449 argv[${i}].setUndefined();
21452 argName
=arg
.identifier
.name
,
21453 conversion
=conversion
,
21459 def getDefaultRetval(self
):
21460 default
= self
.getRetvalInfo(self
.retvalType
, False)[1]
21461 if len(default
) != 0:
21462 default
= " " + default
21465 def getArgs(self
, returnType
, argList
):
21466 args
= CGNativeMember
.getArgs(self
, returnType
, argList
)
21467 if not self
.needThisHandling
:
21468 # Since we don't need this handling, we're the actual method that
21469 # will be called, so we need an aRethrowExceptions argument.
21470 if not self
.rethrowContentException
:
21471 args
.append(Argument("const char*", "aExecutionReason", "nullptr"))
21474 "ExceptionHandling", "aExceptionHandling", "eReportExceptions"
21477 args
.append(Argument("JS::Realm*", "aRealm", "nullptr"))
21479 # We want to allow the caller to pass in a "this" value, as
21480 # well as a BindingCallContext.
21482 Argument("BindingCallContext&", "cx"),
21483 Argument("JS::Handle<JS::Value>", "aThisVal"),
21486 def getCallSetup(self
):
21487 if self
.needThisHandling
:
21488 # It's been done for us already
21490 callSetup
= "CallSetup s(this, aRv"
21491 if self
.rethrowContentException
:
21492 # getArgs doesn't add the aExceptionHandling argument but does add
21495 ', "%s", eRethrowContentExceptions, aRealm, /* aIsJSImplementedWebIDL = */ '
21496 % self
.getPrettyName()
21498 callSetup
+= toStringBool(
21499 isJSImplementedDescriptor(self
.descriptorProvider
)
21502 callSetup
+= ', "%s", aExceptionHandling, aRealm' % self
.getPrettyName()
21503 callSetup
+= ");\n"
21507 if (aRv.Failed()) {
21508 return${errorReturn};
21510 MOZ_ASSERT(s.GetContext());
21511 BindingCallContext& cx = s.GetCallContext();
21514 callSetup
=callSetup
,
21515 errorReturn
=self
.getDefaultRetval(),
21518 def getArgcDecl(self
):
21519 return CGGeneric("unsigned argc = %s;\n" % self
.argCountStr
)
21522 def ensureASCIIName(idlObject
):
21523 type = "attribute" if idlObject
.isAttr() else "operation"
21524 if re
.match("[^\x20-\x7E]", idlObject
.identifier
.name
):
21526 'Callback %s name "%s" contains non-ASCII '
21527 "characters. We can't handle that. %s"
21528 % (type, idlObject
.identifier
.name
, idlObject
.location
)
21530 if re
.match('"', idlObject
.identifier
.name
):
21532 "Callback %s name '%s' contains "
21533 "double-quote character. We can't handle "
21534 "that. %s" % (type, idlObject
.identifier
.name
, idlObject
.location
)
21538 class ConstructCallback(CallbackMember
):
21539 def __init__(self
, callback
, descriptorProvider
):
21540 self
.callback
= callback
21541 CallbackMember
.__init
__(
21543 callback
.signatures()[0],
21545 descriptorProvider
,
21546 needThisHandling
=False,
21550 def getRvalDecl(self
):
21551 # Box constructedObj for getJSToNativeConversionInfo().
21552 return "JS::Rooted<JS::Value> rval(cx);\n"
21555 if self
.argCount
> 0:
21556 args
= "JS::HandleValueArray::subarray(argv, 0, argc)"
21558 args
= "JS::HandleValueArray::empty()"
21562 JS::Rooted<JS::Value> constructor(cx, JS::ObjectValue(*mCallback));
21563 JS::Rooted<JSObject*> constructedObj(cx);
21564 if (!JS::Construct(cx, constructor,
21565 ${args}, &constructedObj)) {
21566 aRv.NoteJSContextException(cx);
21567 return${errorReturn};
21569 rval.setObject(*constructedObj);
21572 errorReturn
=self
.getDefaultRetval(),
21575 def getResultConversion(self
):
21576 return CallbackMember
.getResultConversion(self
, isDefinitelyObject
=True)
21578 def getPrettyName(self
):
21579 return self
.callback
.identifier
.name
21582 class CallbackMethod(CallbackMember
):
21587 descriptorProvider
,
21589 rethrowContentException
=False,
21590 spiderMonkeyInterfacesAreStructs
=False,
21591 canRunScript
=False,
21593 CallbackMember
.__init
__(
21597 descriptorProvider
,
21599 rethrowContentException
,
21600 spiderMonkeyInterfacesAreStructs
=spiderMonkeyInterfacesAreStructs
,
21601 canRunScript
=canRunScript
,
21604 def getRvalDecl(self
):
21605 return "JS::Rooted<JS::Value> rval(cx);\n"
21607 def getNoteCallFailed(self
):
21610 aRv.NoteJSContextException(cx);
21611 return${errorReturn};
21613 errorReturn
=self
.getDefaultRetval(),
21617 if self
.argCount
> 0:
21618 args
= "JS::HandleValueArray::subarray(argv, 0, argc)"
21620 args
= "JS::HandleValueArray::empty()"
21626 if (${callGuard}!JS::Call(cx, ${thisVal}, callable,
21631 declCallable
=self
.getCallableDecl(),
21632 declThis
=self
.getThisDecl(),
21633 callGuard
=self
.getCallGuard(),
21634 thisVal
=self
.getThisVal(),
21636 noteError
=self
.getNoteCallFailed(),
21640 class CallCallback(CallbackMethod
):
21641 def __init__(self
, callback
, descriptorProvider
):
21642 self
.callback
= callback
21643 CallbackMethod
.__init
__(
21645 callback
.signatures()[0],
21647 descriptorProvider
,
21648 needThisHandling
=True,
21649 canRunScript
=not callback
.isRunScriptBoundary(),
21652 def getNoteCallFailed(self
):
21653 if self
.retvalType
.isPromise():
21656 // Convert exception to a rejected promise.
21657 // See https://heycam.github.io/webidl/#call-a-user-objects-operation
21658 // step 12 and step 15.5.
21659 return CreateRejectedPromiseFromThrownException(cx, aRv);
21662 return CallbackMethod
.getNoteCallFailed(self
)
21664 def getExceptionCode(self
, forResult
):
21665 # If the result value is a promise, and conversion
21666 # to the promise throws an exception we shouldn't
21667 # try to convert that exception to a promise again.
21668 if self
.retvalType
.isPromise() and not forResult
:
21671 // Convert exception to a rejected promise.
21672 // See https://heycam.github.io/webidl/#call-a-user-objects-operation
21673 // step 10 and step 15.5.
21674 return CreateRejectedPromiseFromThrownException(cx, aRv);
21677 return CallbackMethod
.getExceptionCode(self
, forResult
)
21679 def getThisDecl(self
):
21682 def getThisVal(self
):
21685 def getCallableDecl(self
):
21686 return "JS::Rooted<JS::Value> callable(cx, JS::ObjectValue(*mCallback));\n"
21688 def getPrettyName(self
):
21689 return self
.callback
.identifier
.name
21691 def getCallGuard(self
):
21692 if self
.callback
._treatNonObjectAsNull
:
21693 return "JS::IsCallable(mCallback) && "
21697 class CallbackOperationBase(CallbackMethod
):
21699 Common class for implementing various callback operations.
21709 rethrowContentException
=False,
21710 spiderMonkeyInterfacesAreStructs
=False,
21712 self
.singleOperation
= singleOperation
21713 self
.methodName
= descriptor
.binaryNameFor(jsName
, False)
21714 CallbackMethod
.__init
__(
21720 rethrowContentException
,
21721 spiderMonkeyInterfacesAreStructs
=spiderMonkeyInterfacesAreStructs
,
21724 def getThisDecl(self
):
21725 if not self
.singleOperation
:
21726 return "JS::Rooted<JS::Value> thisValue(cx, JS::ObjectValue(*mCallback));\n"
21727 # This relies on getCallableDecl declaring a boolean
21728 # isCallable in the case when we're a single-operation
21732 JS::Rooted<JS::Value> thisValue(cx, isCallable ? aThisVal.get()
21733 : JS::ObjectValue(*mCallback));
21737 def getThisVal(self
):
21740 def getCallableDecl(self
):
21741 getCallableFromProp
= fill(
21743 ${atomCacheName}* atomsCache = GetAtomCache<${atomCacheName}>(cx);
21744 if ((reinterpret_cast<jsid*>(atomsCache)->isVoid() &&
21745 !InitIds(cx, atomsCache)) ||
21746 !GetCallableProperty(cx, atomsCache->${methodAtomName}, &callable)) {
21747 aRv.Throw(NS_ERROR_UNEXPECTED);
21748 return${errorReturn};
21751 methodAtomName
=CGDictionary
.makeIdName(self
.methodName
),
21752 atomCacheName
=self
.descriptorProvider
.interface
.identifier
.name
+ "Atoms",
21753 errorReturn
=self
.getDefaultRetval(),
21755 if not self
.singleOperation
:
21756 return "JS::Rooted<JS::Value> callable(cx);\n" + getCallableFromProp
21759 bool isCallable = JS::IsCallable(mCallback);
21760 JS::Rooted<JS::Value> callable(cx);
21762 callable = JS::ObjectValue(*mCallback);
21764 $*{getCallableFromProp}
21767 getCallableFromProp
=getCallableFromProp
,
21770 def getCallGuard(self
):
21774 class CallbackOperation(CallbackOperationBase
):
21776 Codegen actual WebIDL operations on callback interfaces.
21779 def __init__(self
, method
, signature
, descriptor
, spiderMonkeyInterfacesAreStructs
):
21780 self
.ensureASCIIName(method
)
21781 self
.method
= method
21782 jsName
= method
.identifier
.name
21783 CallbackOperationBase
.__init
__(
21787 MakeNativeName(descriptor
.binaryNameFor(jsName
, False)),
21789 descriptor
.interface
.isSingleOperationInterface(),
21790 rethrowContentException
=descriptor
.interface
.isJSImplemented(),
21791 spiderMonkeyInterfacesAreStructs
=spiderMonkeyInterfacesAreStructs
,
21794 def getPrettyName(self
):
21796 self
.descriptorProvider
.interface
.identifier
.name
,
21797 self
.method
.identifier
.name
,
21801 class CallbackAccessor(CallbackMember
):
21803 Shared superclass for CallbackGetter and CallbackSetter.
21806 def __init__(self
, attr
, sig
, name
, descriptor
, spiderMonkeyInterfacesAreStructs
):
21807 self
.ensureASCIIName(attr
)
21808 self
.attrName
= attr
.identifier
.name
21809 CallbackMember
.__init
__(
21814 needThisHandling
=False,
21815 rethrowContentException
=descriptor
.interface
.isJSImplemented(),
21816 spiderMonkeyInterfacesAreStructs
=spiderMonkeyInterfacesAreStructs
,
21819 def getPrettyName(self
):
21821 self
.descriptorProvider
.interface
.identifier
.name
,
21826 class CallbackGetter(CallbackAccessor
):
21827 def __init__(self
, attr
, descriptor
, spiderMonkeyInterfacesAreStructs
):
21828 CallbackAccessor
.__init
__(
21832 callbackGetterName(attr
, descriptor
),
21834 spiderMonkeyInterfacesAreStructs
,
21837 def getRvalDecl(self
):
21838 return "JS::Rooted<JS::Value> rval(cx);\n"
21843 JS::Rooted<JSObject *> callback(cx, mCallback);
21844 ${atomCacheName}* atomsCache = GetAtomCache<${atomCacheName}>(cx);
21845 if ((reinterpret_cast<jsid*>(atomsCache)->isVoid()
21846 && !InitIds(cx, atomsCache)) ||
21847 !JS_GetPropertyById(cx, callback, atomsCache->${attrAtomName}, &rval)) {
21848 aRv.Throw(NS_ERROR_UNEXPECTED);
21849 return${errorReturn};
21852 atomCacheName
=self
.descriptorProvider
.interface
.identifier
.name
+ "Atoms",
21853 attrAtomName
=CGDictionary
.makeIdName(
21854 self
.descriptorProvider
.binaryNameFor(self
.attrName
, False)
21856 errorReturn
=self
.getDefaultRetval(),
21860 class CallbackSetter(CallbackAccessor
):
21861 def __init__(self
, attr
, descriptor
, spiderMonkeyInterfacesAreStructs
):
21862 CallbackAccessor
.__init
__(
21866 BuiltinTypes
[IDLBuiltinType
.Types
.undefined
],
21867 [FakeArgument(attr
.type)],
21869 callbackSetterName(attr
, descriptor
),
21871 spiderMonkeyInterfacesAreStructs
,
21874 def getRvalDecl(self
):
21875 # We don't need an rval
21881 MOZ_ASSERT(argv.length() == 1);
21882 JS::Rooted<JSObject*> callback(cx, CallbackKnownNotGray());
21883 ${atomCacheName}* atomsCache = GetAtomCache<${atomCacheName}>(cx);
21884 if ((reinterpret_cast<jsid*>(atomsCache)->isVoid() &&
21885 !InitIds(cx, atomsCache)) ||
21886 !JS_SetPropertyById(cx, callback, atomsCache->${attrAtomName}, argv[0])) {
21887 aRv.Throw(NS_ERROR_UNEXPECTED);
21888 return${errorReturn};
21891 atomCacheName
=self
.descriptorProvider
.interface
.identifier
.name
+ "Atoms",
21892 attrAtomName
=CGDictionary
.makeIdName(
21893 self
.descriptorProvider
.binaryNameFor(self
.attrName
, False)
21895 errorReturn
=self
.getDefaultRetval(),
21898 def getArgcDecl(self
):
21902 class CGJSImplInitOperation(CallbackOperationBase
):
21904 Codegen the __Init() method used to pass along constructor arguments for JS-implemented WebIDL.
21907 def __init__(self
, sig
, descriptor
):
21908 assert sig
in descriptor
.interface
.ctor().signatures()
21909 CallbackOperationBase
.__init
__(
21911 (BuiltinTypes
[IDLBuiltinType
.Types
.undefined
], sig
[1]),
21915 singleOperation
=False,
21916 rethrowContentException
=True,
21917 spiderMonkeyInterfacesAreStructs
=True,
21920 def getPrettyName(self
):
21924 class CGJSImplEventHookOperation(CallbackOperationBase
):
21926 Codegen the hooks on a JS impl for adding/removing event listeners.
21929 def __init__(self
, descriptor
, name
):
21932 CallbackOperationBase
.__init
__(
21935 BuiltinTypes
[IDLBuiltinType
.Types
.undefined
],
21936 [FakeArgument(BuiltinTypes
[IDLBuiltinType
.Types
.domstring
], "aType")],
21939 MakeNativeName(name
),
21941 singleOperation
=False,
21942 rethrowContentException
=False,
21943 spiderMonkeyInterfacesAreStructs
=True,
21946 def getPrettyName(self
):
21950 def getMaplikeOrSetlikeErrorReturn(helperImpl
):
21952 Generate return values based on whether a maplike or setlike generated
21953 method is an interface method (which returns bool) or a helper function
21954 (which uses ErrorResult).
21959 aRv.Throw(NS_ERROR_UNEXPECTED);
21962 % helperImpl
.getDefaultRetval()
21964 return "return false;\n"
21967 def getMaplikeOrSetlikeBackingObject(descriptor
, maplikeOrSetlike
, helperImpl
=None):
21969 Generate code to get/create a JS backing object for a maplike/setlike
21970 declaration from the declaration slot.
21972 func_prefix
= maplikeOrSetlike
.maplikeOrSetlikeOrIterableType
.title()
21975 JS::Rooted<JSObject*> backingObj(cx);
21976 bool created = false;
21977 if (!Get${func_prefix}BackingObject(cx, obj, ${slot}, &backingObj, &created)) {
21981 PreserveWrapper<${selfType}>(self);
21984 slot
=memberReservedSlot(maplikeOrSetlike
, descriptor
),
21985 func_prefix
=func_prefix
,
21986 errorReturn
=getMaplikeOrSetlikeErrorReturn(helperImpl
),
21987 selfType
=descriptor
.nativeType
,
21992 def getMaplikeOrSetlikeSizeGetterBody(descriptor
, attr
):
21994 Creates the body for the size getter method of maplike/setlike interfaces.
21996 # We should only have one declaration attribute currently
21997 assert attr
.identifier
.name
== "size"
21998 assert attr
.isMaplikeOrSetlikeAttr()
22002 uint32_t result = JS::${funcPrefix}Size(cx, backingObj);
22003 MOZ_ASSERT(!JS_IsExceptionPending(cx));
22004 args.rval().setNumber(result);
22007 getBackingObj
=getMaplikeOrSetlikeBackingObject(
22008 descriptor
, attr
.maplikeOrSetlike
22010 funcPrefix
=attr
.maplikeOrSetlike
.prefix
,
22014 class CGMaplikeOrSetlikeMethodGenerator(CGThing
):
22016 Creates methods for maplike/setlike interfaces. It is expected that all
22017 methods will be have a maplike/setlike object attached. Unwrapping/wrapping
22018 will be taken care of by the usual method generation machinery in
22019 CGMethodCall/CGPerSignatureCall. Functionality is filled in here instead of
22020 using CGCallGenerator.
22028 needsValueTypeReturn
=False,
22031 CGThing
.__init
__(self
)
22032 # True if this will be the body of a C++ helper function.
22033 self
.helperImpl
= helperImpl
22034 self
.descriptor
= descriptor
22035 self
.maplikeOrSetlike
= maplikeOrSetlike
22036 self
.cgRoot
= CGList([])
22037 impl_method_name
= methodName
22038 if impl_method_name
[0] == "_":
22039 # double underscore means this is a js-implemented chrome only rw
22040 # function. Truncate the double underscore so calling the right
22041 # underlying JSAPI function still works.
22042 impl_method_name
= impl_method_name
[2:]
22043 self
.cgRoot
.append(
22045 getMaplikeOrSetlikeBackingObject(
22046 self
.descriptor
, self
.maplikeOrSetlike
, self
.helperImpl
22050 self
.returnStmt
= getMaplikeOrSetlikeErrorReturn(self
.helperImpl
)
22052 # Generates required code for the method. Method descriptions included
22053 # in definitions below. Throw if we don't have a method to fill in what
22054 # we're looking for.
22056 methodGenerator
= getattr(self
, impl_method_name
)
22057 except AttributeError:
22059 "Missing %s method definition '%s'"
22060 % (self
.maplikeOrSetlike
.maplikeOrSetlikeType
, methodName
)
22062 # Method generator returns tuple, containing:
22064 # - a list of CGThings representing setup code for preparing to call
22065 # the JS API function
22066 # - a list of arguments needed for the JS API function we're calling
22067 # - list of code CGThings needed for return value conversion.
22068 (setupCode
, arguments
, setResult
) = methodGenerator()
22070 # Create the actual method call, and then wrap it with the code to
22071 # return the value if needed.
22072 funcName
= self
.maplikeOrSetlike
.prefix
+ MakeNativeName(impl_method_name
)
22073 # Append the list of setup code CGThings
22074 self
.cgRoot
.append(CGList(setupCode
))
22075 # Create the JS API call
22078 if (!JS::${funcName}(${args})) {
22084 if needsValueTypeReturn
:
22085 assert self
.helperImpl
and impl_method_name
== "get"
22088 if (result.isUndefined()) {
22089 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
22093 retval
=self
.helperImpl
.getDefaultRetval(),
22096 self
.cgRoot
.append(
22102 args
=", ".join(["cx", "backingObj"] + arguments
),
22103 errorReturn
=self
.returnStmt
,
22108 # Append result conversion
22109 self
.cgRoot
.append(CGList(setResult
))
22111 def mergeTuples(self
, a
, b
):
22113 Expecting to take 2 tuples were all elements are lists, append the lists in
22114 the second tuple to the lists in the first.
22116 return tuple([x
+ y
for x
, y
in zip(a
, b
)])
22118 def appendArgConversion(self
, name
):
22120 Generate code to convert arguments to JS::Values, so they can be
22121 passed into JSAPI functions.
22126 JS::Rooted<JS::Value> ${name}Val(cx);
22127 if (!ToJSValue(cx, ${name}, &${name}Val)) {
22132 errorReturn
=self
.returnStmt
,
22136 def appendKeyArgConversion(self
):
22138 Generates the key argument for methods. Helper functions will use
22139 a RootedVector<JS::Value>, while interface methods have separate JS::Values.
22141 if self
.helperImpl
:
22142 return ([], ["argv[0]"], [])
22143 return ([self
.appendArgConversion("arg0")], ["arg0Val"], [])
22145 def appendKeyAndValueArgConversion(self
):
22147 Generates arguments for methods that require a key and value. Helper
22148 functions will use a RootedVector<JS::Value>, while interface methods have
22149 separate JS::Values.
22151 r
= self
.appendKeyArgConversion()
22152 if self
.helperImpl
:
22153 return self
.mergeTuples(r
, ([], ["argv[1]"], []))
22154 return self
.mergeTuples(
22155 r
, ([self
.appendArgConversion("arg1")], ["arg1Val"], [])
22158 def appendIteratorResult(self
):
22160 Generate code to output JSObject* return values, needed for functions that
22161 return iterators. Iterators cannot currently be wrapped via Xrays. If
22162 something that would return an iterator is called via Xray, fail early.
22164 # TODO: Bug 1173651 - Remove check once bug 1023984 is fixed.
22168 // TODO (Bug 1173651): Xrays currently cannot wrap iterators. Change
22169 // after bug 1023984 is fixed.
22170 if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
22171 JS_ReportErrorASCII(cx, "Xray wrapping of iterators not supported.");
22174 JS::Rooted<JSObject*> result(cx);
22175 JS::Rooted<JS::Value> v(cx);
22180 setResult
= CGGeneric(
22183 result = &v.toObject();
22187 return ([code
], [arguments
], [setResult
])
22189 def appendSelfResult(self
):
22191 Generate code to return the interface object itself.
22196 JS::Rooted<JSObject*> result(cx);
22200 setResult
= CGGeneric(
22207 return ([code
], [], [setResult
])
22209 def appendBoolResult(self
):
22210 if self
.helperImpl
:
22211 return ([CGGeneric("bool retVal;\n")], ["&retVal"], [])
22212 return ([CGGeneric("bool result;\n")], ["&result"], [])
22216 void forEach(callback c, any thisval);
22218 ForEach takes a callback, and a possible value to use as 'this'. The
22219 callback needs to take value, key, and the interface object
22220 implementing maplike/setlike. In order to make sure that the third arg
22221 is our interface object instead of the map/set backing object, we
22222 create a js function with the callback and original object in its
22223 storage slots, then use a helper function in BindingUtils to make sure
22224 the callback is called correctly.
22226 assert not self
.helperImpl
22231 // Create a wrapper function.
22232 JSFunction* func = js::NewFunctionWithReserved(cx, ForEachHandler, 3, 0, nullptr);
22236 JS::Rooted<JSObject*> funcObj(cx, JS_GetFunctionObject(func));
22237 JS::Rooted<JS::Value> funcVal(cx, JS::ObjectValue(*funcObj));
22238 js::SetFunctionNativeReserved(funcObj, FOREACH_CALLBACK_SLOT,
22239 JS::ObjectValue(*arg0));
22240 js::SetFunctionNativeReserved(funcObj, FOREACH_MAPLIKEORSETLIKEOBJ_SLOT,
22241 JS::ObjectValue(*obj));
22246 arguments
= ["funcVal", "arg1"]
22247 return (code
, arguments
, [])
22251 object set(key, value);
22253 Maplike only function, takes key and sets value to it, returns
22254 interface object unless being called from a C++ helper.
22256 assert self
.maplikeOrSetlike
.isMaplike()
22257 r
= self
.appendKeyAndValueArgConversion()
22258 if self
.helperImpl
:
22260 return self
.mergeTuples(r
, self
.appendSelfResult())
22266 Setlike only function, adds value to set, returns interface object
22267 unless being called from a C++ helper
22269 assert self
.maplikeOrSetlike
.isSetlike()
22270 r
= self
.appendKeyArgConversion()
22271 if self
.helperImpl
:
22273 return self
.mergeTuples(r
, self
.appendSelfResult())
22279 Retrieves a value from a backing object based on the key. Returns value
22280 if key is in backing object, undefined otherwise.
22282 assert self
.maplikeOrSetlike
.isMaplike()
22283 r
= self
.appendKeyArgConversion()
22286 # We don't need to create the result variable because it'll be created elsewhere
22287 # for JSObject Get method
22288 if not self
.helperImpl
or not self
.helperImpl
.needsScopeBody():
22293 JS::Rooted<JS::Value> result(cx);
22299 arguments
= ["&result"]
22300 return self
.mergeTuples(r
, (code
, arguments
, []))
22306 Check if an entry exists in the backing object. Returns true if value
22307 exists in backing object, false otherwise.
22309 return self
.mergeTuples(self
.appendKeyArgConversion(), self
.appendBoolResult())
22315 Returns new object iterator with all keys from backing object.
22317 return self
.appendIteratorResult()
22323 Returns new object iterator with all values from backing object.
22325 return self
.appendIteratorResult()
22331 Returns new object iterator with all keys and values from backing
22332 object. Keys will be null for set.
22334 return self
.appendIteratorResult()
22340 Removes all entries from map/set.
22342 return ([], [], [])
22348 Deletes an entry from the backing object. Returns true if value existed
22349 in backing object, false otherwise.
22351 return self
.mergeTuples(self
.appendKeyArgConversion(), self
.appendBoolResult())
22354 return self
.cgRoot
.define()
22357 class CGHelperFunctionGenerator(CallbackMember
):
22359 Generates code to allow C++ to perform operations. Gets a context from the
22360 binding wrapper, turns arguments into JS::Values (via
22361 CallbackMember/CGNativeMember argument conversion), then uses
22362 getCall to generate the body for getting result, and maybe convert the
22363 result into return type (via CallbackMember/CGNativeMember result
22367 class HelperFunction(CGAbstractMethod
):
22369 Generates context retrieval code and rooted JSObject for interface for
22370 method generator to use
22373 def __init__(self
, descriptor
, name
, args
, code
, returnType
):
22375 CGAbstractMethod
.__init
__(self
, descriptor
, name
, returnType
, args
)
22377 def definition_body(self
):
22385 returnType
=BuiltinTypes
[IDLBuiltinType
.Types
.undefined
],
22386 needsResultConversion
=True,
22388 assert returnType
.isType()
22389 self
.needsResultConversion
= needsResultConversion
22391 # Run CallbackMember init function to generate argument conversion code.
22392 # wrapScope is set to 'obj' when generating maplike or setlike helper
22393 # functions, as we don't have access to the CallbackPreserveColor
22395 CallbackMember
.__init
__(
22397 [returnType
, args
],
22402 passJSBitsAsNeeded
=typeNeedsCx(returnType
),
22405 # Wrap CallbackMember body code into a CGAbstractMethod to make
22406 # generation easier.
22407 self
.implMethod
= CGHelperFunctionGenerator
.HelperFunction(
22408 descriptor
, name
, self
.args
, self
.body
, self
.returnType
22411 def getCallSetup(self
):
22412 # If passJSBitsAsNeeded is true, it means the caller will provide a
22413 # JSContext, so we don't need to create JSContext and enter
22414 # UnprivilegedJunkScopeOrWorkerGlobal here.
22415 code
= "MOZ_ASSERT(self);\n"
22416 if not self
.passJSBitsAsNeeded
:
22421 JSContext* cx = jsapi.cx();
22422 // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here because
22423 // all we want is to wrap into _some_ scope and then unwrap to find
22424 // the reflector, and wrapping has no side-effects.
22425 JSObject* scope = UnprivilegedJunkScopeOrWorkerGlobal(fallible);
22427 aRv.Throw(NS_ERROR_UNEXPECTED);
22430 JSAutoRealm tempRealm(cx, scope);
22432 % self
.getDefaultRetval()
22437 JS::Rooted<JS::Value> v(cx);
22438 if(!ToJSValue(cx, self, &v)) {
22439 aRv.Throw(NS_ERROR_UNEXPECTED);
22442 // This is a reflector, but due to trying to name things
22443 // similarly across method generators, it's called obj here.
22444 JS::Rooted<JSObject*> obj(cx);
22445 obj = js::UncheckedUnwrap(&v.toObject(), /* stopAtWindowProxy = */ false);
22447 % self
.getDefaultRetval()
22450 # We'd like wrap the inner code in a scope such that the code can use the
22451 # same realm. So here we are creating the result variable outside of the
22453 if self
.needsScopeBody():
22454 code
+= "JS::Rooted<JS::Value> result(cx);\n"
22458 def getArgs(self
, returnType
, argList
):
22459 # We don't need the context or the value. We'll generate those instead.
22460 args
= CGNativeMember
.getArgs(self
, returnType
, argList
)
22461 # Prepend a pointer to the binding object onto the arguments
22462 return [Argument(self
.descriptorProvider
.nativeType
+ "*", "self")] + args
22464 def needsScopeBody(self
):
22465 return self
.passJSBitsAsNeeded
22467 def getArgvDeclFailureCode(self
):
22468 return "aRv.Throw(NS_ERROR_UNEXPECTED);\n"
22470 def getResultConversion(self
):
22471 if self
.needsResultConversion
:
22473 if self
.needsScopeBody():
22476 if (!JS_WrapValue(cx, &result)) {
22477 aRv.NoteJSContextException(cx);
22483 failureCode
= dedent("aRv.Throw(NS_ERROR_UNEXPECTED);\nreturn nullptr;\n")
22485 exceptionCode
= None
22486 if self
.retvalType
.isPrimitive():
22487 exceptionCode
= dedent(
22488 "aRv.NoteJSContextException(cx);\nreturn%s;\n"
22489 % self
.getDefaultRetval()
22492 return code
+ CallbackMember
.getResultConversion(
22495 failureCode
=failureCode
,
22496 isDefinitelyObject
=True,
22497 exceptionCode
=exceptionCode
,
22500 assignRetval
= string
.Template(
22501 self
.getRetvalInfo(self
.retvalType
, False)[2]
22504 "declName": "retVal",
22507 return assignRetval
22509 def getRvalDecl(self
):
22510 # hack to make sure we put JSAutoRealm inside the body scope
22511 return "JSAutoRealm reflectorRealm(cx, obj);\n"
22513 def getArgcDecl(self
):
22514 # Don't need argc for anything.
22518 assert False # Override me!
22520 def getPrettyName(self
):
22524 return self
.implMethod
.declare()
22527 return self
.implMethod
.define()
22530 class CGMaplikeOrSetlikeHelperFunctionGenerator(CGHelperFunctionGenerator
):
22532 Generates code to allow C++ to perform operations on backing objects. Gets
22533 a context from the binding wrapper, turns arguments into JS::Values (via
22534 CallbackMember/CGNativeMember argument conversion), then uses
22535 CGMaplikeOrSetlikeMethodGenerator to generate the body.
22544 needsValueArg
=False,
22545 needsValueTypeReturn
=False,
22546 needsBoolReturn
=False,
22547 needsResultConversion
=True,
22549 self
.maplikeOrSetlike
= maplikeOrSetlike
22550 self
.needsValueTypeReturn
= needsValueTypeReturn
22554 args
.append(FakeArgument(maplikeOrSetlike
.keyType
, "aKey"))
22557 assert not needsValueTypeReturn
22558 args
.append(FakeArgument(maplikeOrSetlike
.valueType
, "aValue"))
22560 returnType
= BuiltinTypes
[IDLBuiltinType
.Types
.undefined
]
22561 if needsBoolReturn
:
22562 returnType
= BuiltinTypes
[IDLBuiltinType
.Types
.boolean
]
22563 elif needsValueTypeReturn
:
22564 returnType
= maplikeOrSetlike
.valueType
22566 CGHelperFunctionGenerator
.__init
__(
22572 needsResultConversion
,
22576 return CGMaplikeOrSetlikeMethodGenerator(
22577 self
.descriptorProvider
,
22578 self
.maplikeOrSetlike
,
22580 self
.needsValueTypeReturn
,
22585 class CGMaplikeOrSetlikeHelperGenerator(CGNamespace
):
22587 Declares and defines convenience methods for accessing backing objects on
22588 setlike/maplike interface. Generates function signatures, un/packs
22589 backing objects from slot, etc.
22592 def __init__(self
, descriptor
, maplikeOrSetlike
):
22593 self
.descriptor
= descriptor
22594 # Since iterables are folded in with maplike/setlike, make sure we've
22595 # got the right type here.
22596 assert maplikeOrSetlike
.isMaplike() or maplikeOrSetlike
.isSetlike()
22597 self
.maplikeOrSetlike
= maplikeOrSetlike
22598 self
.namespace
= "%sHelpers" % (
22599 self
.maplikeOrSetlike
.maplikeOrSetlikeOrIterableType
.title()
22602 CGMaplikeOrSetlikeHelperFunctionGenerator(
22603 descriptor
, maplikeOrSetlike
, "Clear"
22605 CGMaplikeOrSetlikeHelperFunctionGenerator(
22610 needsBoolReturn
=True,
22611 needsResultConversion
=False,
22613 CGMaplikeOrSetlikeHelperFunctionGenerator(
22618 needsBoolReturn
=True,
22619 needsResultConversion
=False,
22622 if self
.maplikeOrSetlike
.isMaplike():
22623 self
.helpers
.append(
22624 CGMaplikeOrSetlikeHelperFunctionGenerator(
22629 needsValueArg
=True,
22632 self
.helpers
.append(
22633 CGMaplikeOrSetlikeHelperFunctionGenerator(
22638 needsValueTypeReturn
=True,
22642 assert self
.maplikeOrSetlike
.isSetlike()
22643 self
.helpers
.append(
22644 CGMaplikeOrSetlikeHelperFunctionGenerator(
22645 descriptor
, maplikeOrSetlike
, "Add", needsKeyArg
=True
22648 CGNamespace
.__init
__(self
, self
.namespace
, CGList(self
.helpers
))
22651 class CGIterableMethodGenerator(CGGeneric
):
22653 Creates methods for iterable interfaces. Unwrapping/wrapping
22654 will be taken care of by the usual method generation machinery in
22655 CGMethodCall/CGPerSignatureCall. Functionality is filled in here instead of
22656 using CGCallGenerator.
22659 def __init__(self
, descriptor
, methodName
, args
):
22660 if methodName
== "forEach":
22661 assert len(args
) == 2
22663 CGGeneric
.__init
__(
22667 if (!JS::IsCallable(arg0)) {
22668 cx.ThrowErrorMessage<MSG_NOT_CALLABLE>("Argument 1");
22671 JS::RootedValueArray<3> callArgs(cx);
22672 callArgs[2].setObject(*obj);
22673 JS::Rooted<JS::Value> ignoredReturnVal(cx);
22674 auto GetKeyAtIndex = &${selfType}::GetKeyAtIndex;
22675 auto GetValueAtIndex = &${selfType}::GetValueAtIndex;
22676 for (size_t i = 0; i < self->GetIterableLength(); ++i) {
22677 if (!CallIterableGetter(cx, GetValueAtIndex, self, i,
22681 if (!CallIterableGetter(cx, GetKeyAtIndex, self, i,
22685 if (!JS::Call(cx, arg1, arg0, JS::HandleValueArray(callArgs),
22686 &ignoredReturnVal)) {
22691 ifaceName
=descriptor
.interface
.identifier
.name
,
22692 selfType
=descriptor
.nativeType
,
22697 if descriptor
.interface
.isIterable():
22698 assert descriptor
.interface
.maplikeOrSetlikeOrIterable
.isPairIterator()
22699 assert len(args
) == 0
22701 wrap
= f
"{descriptor.interface.identifier.name}Iterator_Binding::Wrap"
22702 iterClass
= f
"mozilla::dom::binding_detail::WrappableIterableIterator<{descriptor.nativeType}, &{wrap}>"
22704 needReturnMethod
= toStringBool(
22705 descriptor
.interface
.maplikeOrSetlikeOrIterable
.getExtendedAttribute(
22706 "GenerateReturnMethod"
22710 wrap
= f
"{descriptor.interface.identifier.name}AsyncIterator_Binding::Wrap"
22711 iterClass
= f
"mozilla::dom::binding_detail::WrappableAsyncIterableIterator<{descriptor.nativeType}, {needReturnMethod}, &{wrap}>"
22713 createIterator
= fill(
22715 typedef ${iterClass} itrType;
22716 RefPtr<itrType> result(new itrType(self,
22717 itrType::IteratorType::${itrMethod}));
22719 iterClass
=iterClass
,
22720 itrMethod
=methodName
.title(),
22723 if descriptor
.interface
.isAsyncIterable():
22724 args
.append("initError")
22725 createIterator
= fill(
22729 ErrorResult initError;
22730 self->InitAsyncIteratorData(result->Data(), itrType::IteratorType::${itrMethod}, ${args});
22731 if (initError.MaybeSetPendingException(cx, "Asynchronous iterator initialization steps for ${ifaceName} failed")) {
22736 createIterator
=createIterator
,
22737 itrMethod
=methodName
.title(),
22738 args
=", ".join(args
),
22739 ifaceName
=descriptor
.interface
.identifier
.name
,
22742 CGGeneric
.__init
__(self
, createIterator
)
22745 def getObservableArrayBackingObject(descriptor
, attr
, errorReturn
="return false;\n"):
22747 Generate code to get/create a JS backing list for an observableArray attribute
22748 from the declaration slot.
22750 assert attr
.isAttr()
22751 assert attr
.type.isObservableArray()
22753 # GetObservableArrayBackingObject may return a wrapped object for Xrays, so
22754 # when we create it we need to unwrap it to store the interface in the
22758 JS::Rooted<JSObject*> backingObj(cx);
22759 bool created = false;
22760 if (!GetObservableArrayBackingObject(cx, obj, ${slot},
22761 &backingObj, &created, ${namespace}::ObservableArrayProxyHandler::getInstance(),
22766 PreserveWrapper(self);
22769 namespace
=toBindingNamespace(MakeNativeName(attr
.identifier
.name
)),
22770 slot
=memberReservedSlot(attr
, descriptor
),
22771 errorReturn
=errorReturn
,
22772 selfType
=descriptor
.nativeType
,
22776 def getObservableArrayGetterBody(descriptor
, attr
):
22778 Creates the body for the getter method of an observableArray attribute.
22780 assert attr
.type.isObservableArray()
22784 MOZ_ASSERT(!JS_IsExceptionPending(cx));
22785 args.rval().setObject(*backingObj);
22788 getBackingObj
=getObservableArrayBackingObject(descriptor
, attr
),
22792 class CGObservableArrayProxyHandler_callback(ClassMethod
):
22794 Base class for declaring and defining the hook methods for ObservableArrayProxyHandler
22795 subclasses to get the interface native object from backing object and calls
22796 its On{Set|Delete}* callback.
22798 * 'callbackType': "Set" or "Delete".
22799 * 'invalidTypeFatal' (optional): If True, we don't expect the type
22800 conversion would fail, so generate the
22801 assertion code if type conversion fails.
22805 self
, descriptor
, attr
, name
, args
, callbackType
, invalidTypeFatal
=False
22807 assert attr
.isAttr()
22808 assert attr
.type.isObservableArray()
22809 assert callbackType
in ["Set", "Delete"]
22810 self
.descriptor
= descriptor
22812 self
.innertype
= attr
.type.inner
22813 self
.callbackType
= callbackType
22814 self
.invalidTypeFatal
= invalidTypeFatal
22815 ClassMethod
.__init
__(
22820 visibility
="protected",
22826 def preConversion(self
):
22828 The code to run before the conversion steps.
22832 def preCallback(self
):
22834 The code to run before calling the callback.
22838 def postCallback(self
):
22840 The code to run after calling the callback, all subclasses should override
22841 this to generate the return values.
22843 assert False # Override me!
22849 MOZ_ASSERT_UNREACHABLE("The item in ObservableArray backing list is not ${innertype}?");
22852 innertype
=self
.innertype
,
22854 if self
.invalidTypeFatal
22857 convertType
= instantiateJSToNativeConversion(
22858 getJSToNativeConversionInfo(
22861 sourceDescription
="Element in ObservableArray backing list",
22862 exceptionCode
=exceptionCode
,
22865 "declName": "decl",
22866 "holderName": "holder",
22870 callbackArgs
= ["decl", "aIndex", "rv"]
22871 if typeNeedsCx(self
.innertype
):
22872 callbackArgs
.insert(0, "cx")
22875 MOZ_ASSERT(IsObservableArrayProxy(aProxy));
22878 BindingCallContext cx(aCx, "ObservableArray ${name}");
22882 JS::Value val = js::GetProxyReservedSlot(aProxy, OBSERVABLE_ARRAY_DOM_INTERFACE_SLOT);
22883 auto* interface = static_cast<${ifaceType}*>(val.toPrivate());
22884 MOZ_ASSERT(interface);
22887 MOZ_KnownLive(interface)->${methodName}(${callbackArgs});
22890 preConversion
=self
.preConversion(),
22892 convertType
=convertType
.define(),
22893 preCallback
=self
.preCallback(),
22894 ifaceType
=self
.descriptor
.nativeType
,
22895 methodName
="On%s%s"
22896 % (self
.callbackType
, MakeNativeName(self
.attr
.identifier
.name
)),
22897 callbackArgs
=", ".join(callbackArgs
),
22898 postCallback
=self
.postCallback(),
22902 class CGObservableArrayProxyHandler_OnDeleteItem(
22903 CGObservableArrayProxyHandler_callback
22906 Declares and defines the hook methods for ObservableArrayProxyHandler
22907 subclasses to get the interface native object from backing object and calls
22908 its OnDelete* callback.
22911 def __init__(self
, descriptor
, attr
):
22913 Argument("JSContext*", "aCx"),
22914 Argument("JS::Handle<JSObject*>", "aProxy"),
22915 Argument("JS::Handle<JS::Value>", "aValue"),
22916 Argument("uint32_t", "aIndex"),
22918 CGObservableArrayProxyHandler_callback
.__init
__(
22928 def postCallback(self
):
22931 return !rv.MaybeSetPendingException(cx);
22936 class CGObservableArrayProxyHandler_SetIndexedValue(
22937 CGObservableArrayProxyHandler_callback
22940 Declares and defines the hook methods for ObservableArrayProxyHandler
22941 subclasses to run the setting the indexed value steps.
22944 def __init__(self
, descriptor
, attr
):
22946 Argument("JSContext*", "aCx"),
22947 Argument("JS::Handle<JSObject*>", "aProxy"),
22948 Argument("JS::Handle<JSObject*>", "aBackingList"),
22949 Argument("uint32_t", "aIndex"),
22950 Argument("JS::Handle<JS::Value>", "aValue"),
22951 Argument("JS::ObjectOpResult&", "aResult"),
22953 CGObservableArrayProxyHandler_callback
.__init
__(
22962 def preConversion(self
):
22966 if (!JS::GetArrayLength(aCx, aBackingList, &oldLen)) {
22970 if (aIndex > oldLen) {
22971 return aResult.failBadIndex();
22976 def preCallback(self
):
22979 if (aIndex < oldLen) {
22980 JS::Rooted<JS::Value> value(aCx);
22981 if (!JS_GetElement(aCx, aBackingList, aIndex, &value)) {
22985 if (!OnDeleteItem(aCx, aProxy, value, aIndex)) {
22993 def postCallback(self
):
22996 if (rv.MaybeSetPendingException(cx)) {
23000 if (!JS_SetElement(aCx, aBackingList, aIndex, aValue)) {
23004 return aResult.succeed();
23009 class CGObservableArrayProxyHandler(CGThing
):
23011 A class for declaring a ObservableArrayProxyHandler.
23014 def __init__(self
, descriptor
, attr
):
23015 assert attr
.isAttr()
23016 assert attr
.type.isObservableArray()
23018 # The item stored in backing object should always be converted successfully.
23019 CGObservableArrayProxyHandler_OnDeleteItem(descriptor
, attr
),
23020 CGObservableArrayProxyHandler_SetIndexedValue(descriptor
, attr
),
23021 CGJSProxyHandler_getInstance("ObservableArrayProxyHandler"),
23023 parentClass
= "mozilla::dom::ObservableArrayProxyHandler"
23024 self
.proxyHandler
= CGClass(
23025 "ObservableArrayProxyHandler",
23026 bases
=[ClassBase(parentClass
)],
23032 # Our class declaration should happen when we're defining
23036 return self
.proxyHandler
.declare() + "\n" + self
.proxyHandler
.define()
23039 class CGObservableArrayProxyHandlerGenerator(CGNamespace
):
23041 Declares and defines convenience methods for accessing backing list objects
23042 for observable array attribute. Generates function signatures, un/packs
23043 backing list objects from slot, etc.
23046 def __init__(self
, descriptor
, attr
):
23047 assert attr
.isAttr()
23048 assert attr
.type.isObservableArray()
23049 namespace
= toBindingNamespace(MakeNativeName(attr
.identifier
.name
))
23050 proxyHandler
= CGObservableArrayProxyHandler(descriptor
, attr
)
23051 CGNamespace
.__init
__(self
, namespace
, proxyHandler
)
23054 class CGObservableArraySetterGenerator(CGGeneric
):
23056 Creates setter for an observableArray attributes.
23059 def __init__(self
, descriptor
, attr
):
23060 assert attr
.isAttr()
23061 assert attr
.type.isObservableArray()
23062 getBackingObject
= getObservableArrayBackingObject(descriptor
, attr
)
23063 setElement
= dedent(
23065 if (!JS_SetElement(cx, backingObj, i, val)) {
23070 conversion
= wrapForType(
23074 "result": "arg0.ElementAt(i)",
23075 "successCode": setElement
,
23077 "jsvalHandle": "&val",
23080 CGGeneric
.__init
__(
23084 if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
23085 JS_ReportErrorASCII(cx, "Accessing from Xray wrapper is not supported.");
23089 ${getBackingObject}
23090 const ObservableArrayProxyHandler* handler = GetObservableArrayProxyHandler(backingObj);
23091 if (!handler->SetLength(cx, backingObj, 0)) {
23095 JS::Rooted<JS::Value> val(cx);
23096 for (size_t i = 0; i < arg0.Length(); i++) {
23100 conversion
=conversion
,
23101 getBackingObject
=getBackingObject
,
23106 class CGObservableArrayHelperFunctionGenerator(CGHelperFunctionGenerator
):
23108 Generates code to allow C++ to perform operations on backing objects. Gets
23109 a context from the binding wrapper, turns arguments into JS::Values (via
23110 CallbackMember/CGNativeMember argument conversion), then uses
23111 MethodBodyGenerator to generate the body.
23114 class MethodBodyGenerator(CGThing
):
23116 Creates methods body for observable array attribute. It is expected that all
23117 methods will be have a maplike/setlike object attached. Unwrapping/wrapping
23118 will be taken care of by the usual method generation machinery in
23119 CGMethodCall/CGPerSignatureCall. Functionality is filled in here instead of
23120 using CGCallGenerator.
23131 assert attr
.isAttr()
23132 assert attr
.type.isObservableArray()
23134 CGThing
.__init
__(self
)
23135 self
.helperGenerator
= helperGenerator
23136 self
.cgRoot
= CGList([])
23138 self
.cgRoot
.append(
23140 getObservableArrayBackingObject(
23145 aRv.Throw(NS_ERROR_UNEXPECTED);
23148 % helperGenerator
.getDefaultRetval()
23154 # Generates required code for the method. Method descriptions included
23155 # in definitions below. Throw if we don't have a method to fill in what
23156 # we're looking for.
23158 methodGenerator
= getattr(self
, methodName
)
23159 except AttributeError:
23161 "Missing observable array method definition '%s'" % methodName
23163 # Method generator returns tuple, containing:
23165 # - a list of CGThings representing setup code for preparing to call
23166 # the JS API function
23167 # - JS API function name
23168 # - a list of arguments needed for the JS API function we're calling
23169 # - a list of CGThings representing code needed before return.
23170 (setupCode
, funcName
, arguments
, returnCode
) = methodGenerator()
23172 # Append the list of setup code CGThings
23173 self
.cgRoot
.append(CGList(setupCode
))
23174 # Create the JS API call
23176 arguments
.insert(0, "aIndex")
23177 self
.cgRoot
.append(
23182 aRv.MightThrowJSException();
23183 if (!${funcName}(${args})) {
23184 aRv.StealExceptionFromJSContext(cx);
23189 args
=", ".join(["cx", "backingObj"] + arguments
),
23190 retval
=helperGenerator
.getDefaultRetval(),
23195 # Append code before return
23196 self
.cgRoot
.append(CGList(returnCode
))
23198 def elementat(self
):
23200 if not self
.helperGenerator
.needsScopeBody():
23201 setupCode
.append(CGGeneric("JS::Rooted<JS::Value> result(cx);\n"))
23206 if (result.isUndefined()) {
23207 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
23211 retval
=self
.helperGenerator
.getDefaultRetval(),
23215 return (setupCode
, "JS_GetElement", ["&result"], returnCode
)
23217 def replaceelementat(self
):
23223 aRv.MightThrowJSException();
23224 if (!JS::GetArrayLength(cx, backingObj, &length)) {
23225 aRv.StealExceptionFromJSContext(cx);
23228 if (aIndex > length) {
23229 aRv.ThrowRangeError("Invalid index");
23233 retval
=self
.helperGenerator
.getDefaultRetval(),
23237 return (setupCode
, "JS_SetElement", ["argv[0]"], [])
23239 def appendelement(self
):
23245 aRv.MightThrowJSException();
23246 if (!JS::GetArrayLength(cx, backingObj, &length)) {
23247 aRv.StealExceptionFromJSContext(cx);
23251 retval
=self
.helperGenerator
.getDefaultRetval(),
23255 return (setupCode
, "JS_SetElement", ["length", "argv[0]"], [])
23257 def removelastelement(self
):
23263 aRv.MightThrowJSException();
23264 if (!JS::GetArrayLength(cx, backingObj, &length)) {
23265 aRv.StealExceptionFromJSContext(cx);
23269 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
23273 retval
=self
.helperGenerator
.getDefaultRetval(),
23277 return (setupCode
, "JS::SetArrayLength", ["length - 1"], [])
23281 [CGGeneric("uint32_t retVal;\n")],
23282 "JS::GetArrayLength",
23288 return self
.cgRoot
.define()
23295 returnType
=BuiltinTypes
[IDLBuiltinType
.Types
.undefined
],
23296 needsResultConversion
=True,
23297 needsIndexArg
=False,
23298 needsValueArg
=False,
23300 assert attr
.isAttr()
23301 assert attr
.type.isObservableArray()
23303 self
.needsIndexArg
= needsIndexArg
23307 args
.append(FakeArgument(attr
.type.inner
, "aValue"))
23309 CGHelperFunctionGenerator
.__init
__(
23315 needsResultConversion
,
23318 def getArgs(self
, returnType
, argList
):
23319 if self
.needsIndexArg
:
23321 FakeArgument(BuiltinTypes
[IDLBuiltinType
.Types
.unsigned_long
], "aIndex")
23323 return CGHelperFunctionGenerator
.getArgs(self
, returnType
, argList
)
23326 return CGObservableArrayHelperFunctionGenerator
.MethodBodyGenerator(
23327 self
.descriptorProvider
,
23331 self
.needsIndexArg
,
23335 class CGObservableArrayHelperGenerator(CGNamespace
):
23337 Declares and defines convenience methods for accessing backing object for
23338 observable array type. Generates function signatures, un/packs
23339 backing objects from slot, etc.
23342 def __init__(self
, descriptor
, attr
):
23343 assert attr
.isAttr()
23344 assert attr
.type.isObservableArray()
23346 namespace
= "%sHelpers" % MakeNativeName(attr
.identifier
.name
)
23348 CGObservableArrayHelperFunctionGenerator(
23352 returnType
=attr
.type.inner
,
23353 needsIndexArg
=True,
23355 CGObservableArrayHelperFunctionGenerator(
23358 "ReplaceElementAt",
23359 needsIndexArg
=True,
23360 needsValueArg
=True,
23362 CGObservableArrayHelperFunctionGenerator(
23366 needsValueArg
=True,
23368 CGObservableArrayHelperFunctionGenerator(
23371 "RemoveLastElement",
23373 CGObservableArrayHelperFunctionGenerator(
23377 returnType
=BuiltinTypes
[IDLBuiltinType
.Types
.unsigned_long
],
23378 needsResultConversion
=False,
23381 CGNamespace
.__init
__(self
, namespace
, CGList(helpers
, "\n"))
23384 class GlobalGenRoots
:
23386 Roots for global codegen.
23388 To generate code, call the method associated with the target, and then
23389 call the appropriate define/declare method.
23393 def GeneratedAtomList(config
):
23395 dictionaries
= config
.dictionaries
23399 def memberToAtomCacheMember(binaryNameFor
, m
):
23400 binaryMemberName
= binaryNameFor(m
)
23401 return ClassMember(
23402 CGDictionary
.makeIdName(binaryMemberName
),
23404 visibility
="public",
23407 def buildAtomCacheStructure(idlobj
, binaryNameFor
, members
):
23408 classMembers
= [memberToAtomCacheMember(binaryNameFor
, m
) for m
in members
]
23409 structName
= idlobj
.identifier
.name
+ "Atoms"
23414 structName
, bases
=None, isStruct
=True, members
=classMembers
23420 for dict in dictionaries
:
23421 if len(dict.members
) == 0:
23425 buildAtomCacheStructure(dict, lambda m
: m
.identifier
.name
, dict.members
)
23428 for d
in config
.getDescriptors(isJSImplemented
=True) + config
.getDescriptors(
23431 members
= [m
for m
in d
.interface
.members
if m
.isAttr() or m
.isMethod()]
23432 if d
.interface
.isJSImplemented() and d
.interface
.ctor():
23433 # We'll have an __init() method.
23434 members
.append(FakeMember("__init"))
23435 if d
.interface
.isJSImplemented() and d
.interface
.getExtendedAttribute(
23436 "WantsEventListenerHooks"
23438 members
.append(FakeMember("eventListenerAdded"))
23439 members
.append(FakeMember("eventListenerRemoved"))
23440 if len(members
) == 0:
23444 buildAtomCacheStructure(
23446 lambda m
: d
.binaryNameFor(m
.identifier
.name
, m
.isStatic()),
23452 generatedStructs
= [struct
for structName
, struct
in structs
]
23453 structNames
= [structName
for structName
, struct
in structs
]
23455 mainStruct
= CGWrapper(
23457 "PerThreadAtomCache",
23458 bases
=[ClassBase(structName
) for structName
in structNames
],
23464 structs
= CGList(generatedStructs
+ [mainStruct
])
23466 # Wrap all of that in our namespaces.
23467 curr
= CGNamespace
.build(["mozilla", "dom"], CGWrapper(structs
, pre
="\n"))
23468 curr
= CGWrapper(curr
, post
="\n")
23470 # Add include statement for PinnedStringId.
23471 declareIncludes
= ["mozilla/dom/PinnedStringId.h"]
23472 curr
= CGHeaders([], [], [], [], declareIncludes
, [], "GeneratedAtomList", curr
)
23474 # Add include guards.
23475 curr
= CGIncludeGuard("GeneratedAtomList", curr
)
23477 # Add the auto-generated comment.
23478 curr
= CGWrapper(curr
, pre
=AUTOGENERATED_WARNING_COMMENT
)
23484 def GeneratedEventList(config
):
23485 eventList
= CGList([])
23486 for generatedEvent
in config
.generatedEvents
:
23488 CGGeneric(declare
=("GENERATED_EVENT(%s)\n" % generatedEvent
))
23493 def PrototypeList(config
):
23494 # Prototype ID enum.
23495 descriptorsWithPrototype
= config
.getDescriptors(
23496 hasInterfacePrototypeObject
=True
23498 protos
= [d
.name
for d
in descriptorsWithPrototype
]
23499 idEnum
= CGNamespacedEnum("id", "ID", ["_ID_Start"] + protos
, [0, "_ID_Start"])
23500 idEnum
= CGList([idEnum
])
23502 def fieldSizeAssert(amount
, jitInfoField
, message
):
23504 "(uint64_t(1) << (sizeof(std::declval<JSJitInfo>().%s) * 8))"
23508 define
='static_assert(%s < %s, "%s");\n\n'
23509 % (amount
, maxFieldValue
, message
)
23513 fieldSizeAssert("id::_ID_Count", "protoID", "Too many prototypes!")
23516 # Wrap all of that in our namespaces.
23517 idEnum
= CGNamespace
.build(
23518 ["mozilla", "dom", "prototypes"], CGWrapper(idEnum
, pre
="\n")
23520 idEnum
= CGWrapper(idEnum
, post
="\n")
23524 CGGeneric(define
="#include <stdint.h>\n"),
23525 CGGeneric(define
="#include <type_traits>\n\n"),
23526 CGGeneric(define
='#include "js/experimental/JitInfo.h"\n\n'),
23527 CGGeneric(define
='#include "mozilla/dom/BindingNames.h"\n\n'),
23528 CGGeneric(define
='#include "mozilla/dom/PrototypeList.h"\n\n'),
23533 # Let things know the maximum length of the prototype chain.
23534 maxMacroName
= "MAX_PROTOTYPE_CHAIN_LENGTH"
23535 maxMacro
= CGGeneric(
23536 declare
="#define " + maxMacroName
+ " " + str(config
.maxProtoChainLength
)
23538 curr
.append(CGWrapper(maxMacro
, post
="\n\n"))
23541 maxMacroName
, "depth", "Some inheritance chain is too long!"
23545 # Constructor ID enum.
23546 constructors
= [d
.name
for d
in config
.getDescriptors(hasInterfaceObject
=True)]
23547 idEnum
= CGNamespacedEnum(
23550 ["_ID_Start"] + constructors
,
23551 ["prototypes::id::_ID_Count", "_ID_Start"],
23554 # Wrap all of that in our namespaces.
23555 idEnum
= CGNamespace
.build(
23556 ["mozilla", "dom", "constructors"], CGWrapper(idEnum
, pre
="\n")
23558 idEnum
= CGWrapper(idEnum
, post
="\n")
23560 curr
.append(idEnum
)
23562 # Named properties object enum.
23563 namedPropertiesObjects
= [
23564 d
.name
for d
in config
.getDescriptors(hasNamedPropertiesObject
=True)
23566 idEnum
= CGNamespacedEnum(
23569 ["_ID_Start"] + namedPropertiesObjects
,
23570 ["constructors::id::_ID_Count", "_ID_Start"],
23573 # Wrap all of that in our namespaces.
23574 idEnum
= CGNamespace
.build(
23575 ["mozilla", "dom", "namedpropertiesobjects"], CGWrapper(idEnum
, pre
="\n")
23577 idEnum
= CGWrapper(idEnum
, post
="\n")
23579 curr
.append(idEnum
)
23585 template <prototypes::ID PrototypeID>
23586 struct PrototypeTraits;
23591 traitsDecls
.extend(CGPrototypeTraitsClass(d
) for d
in descriptorsWithPrototype
)
23593 ifaceNamesWithProto
= [
23594 d
.interface
.getClassName() for d
in descriptorsWithPrototype
23596 traitsDecls
.append(
23597 CGStringTable("NamesOfInterfacesWithProtos", ifaceNamesWithProto
)
23600 traitsDecl
= CGNamespace
.build(["mozilla", "dom"], CGList(traitsDecls
))
23602 curr
.append(traitsDecl
)
23604 # Add include guards.
23605 curr
= CGIncludeGuard("PrototypeList", curr
)
23607 # Add the auto-generated comment.
23608 curr
= CGWrapper(curr
, pre
=AUTOGENERATED_WARNING_COMMENT
)
23614 def BindingNames(config
):
23617 enum class BindingNamesOffset : uint16_t {
23621 namespace binding_detail {
23622 extern const char sBindingNames[];
23623 } // namespace binding_detail
23625 MOZ_ALWAYS_INLINE const char* BindingName(BindingNamesOffset aOffset) {
23626 return binding_detail::sBindingNames + static_cast<size_t>(aOffset);
23629 enumValues
="".join(
23630 "%s = %i,\n" % (BindingNamesOffsetEnum(n
), o
)
23631 for (n
, o
) in config
.namesStringOffsets
23636 namespace binding_detail {
23638 const char sBindingNames[] = {
23642 } // namespace binding_detail
23644 // Making this enum bigger than a uint16_t has consequences on the size
23645 // of some structs (eg. WebIDLNameTableEntry) and tables. We should try
23647 static_assert(EnumTypeFitsWithin<BindingNamesOffset, uint16_t>::value,
23650 namesString
=' "\\0"\n'.join(
23651 '/* %5i */ "%s"' % (o
, n
) for (n
, o
) in config
.namesStringOffsets
23656 curr
= CGGeneric(declare
=declare
, define
=define
)
23657 curr
= CGWrapper(curr
, pre
="\n", post
="\n")
23659 curr
= CGNamespace
.build(["mozilla", "dom"], curr
)
23660 curr
= CGWrapper(curr
, post
="\n")
23667 ["<stddef.h>", "<stdint.h>", "mozilla/Attributes.h"],
23668 ["mozilla/dom/BindingNames.h", "mozilla/EnumTypeTraits.h"],
23673 # Add include guards.
23674 curr
= CGIncludeGuard("BindingNames", curr
)
23680 def RegisterBindings(config
):
23681 curr
= CGNamespace
.build(
23682 ["mozilla", "dom"], CGGlobalNames(config
.windowGlobalNames
)
23684 curr
= CGWrapper(curr
, post
="\n")
23688 CGHeaders
.getDeclarationFilename(desc
.interface
)
23689 for desc
in config
.getDescriptors(
23690 hasInterfaceObject
=True, isExposedInWindow
=True, register
=True
23693 defineIncludes
.append("mozilla/dom/BindingNames.h")
23694 defineIncludes
.append("mozilla/dom/WebIDLGlobalNameHash.h")
23695 defineIncludes
.append("mozilla/dom/PrototypeList.h")
23696 defineIncludes
.append("mozilla/PerfectHash.h")
23697 defineIncludes
.append("js/String.h")
23698 curr
= CGHeaders([], [], [], [], [], defineIncludes
, "RegisterBindings", curr
)
23700 # Add include guards.
23701 curr
= CGIncludeGuard("RegisterBindings", curr
)
23707 def RegisterWorkerBindings(config
):
23708 curr
= CGRegisterWorkerBindings(config
)
23710 # Wrap all of that in our namespaces.
23711 curr
= CGNamespace
.build(["mozilla", "dom"], CGWrapper(curr
, post
="\n"))
23712 curr
= CGWrapper(curr
, post
="\n")
23716 CGHeaders
.getDeclarationFilename(desc
.interface
)
23717 for desc
in config
.getDescriptors(
23718 hasInterfaceObject
=True, register
=True, isExposedInAnyWorker
=True
23723 [], [], [], [], [], defineIncludes
, "RegisterWorkerBindings", curr
23726 # Add include guards.
23727 curr
= CGIncludeGuard("RegisterWorkerBindings", curr
)
23733 def RegisterWorkerDebuggerBindings(config
):
23734 curr
= CGRegisterWorkerDebuggerBindings(config
)
23736 # Wrap all of that in our namespaces.
23737 curr
= CGNamespace
.build(["mozilla", "dom"], CGWrapper(curr
, post
="\n"))
23738 curr
= CGWrapper(curr
, post
="\n")
23742 CGHeaders
.getDeclarationFilename(desc
.interface
)
23743 for desc
in config
.getDescriptors(
23744 hasInterfaceObject
=True, register
=True, isExposedInWorkerDebugger
=True
23749 [], [], [], [], [], defineIncludes
, "RegisterWorkerDebuggerBindings", curr
23752 # Add include guards.
23753 curr
= CGIncludeGuard("RegisterWorkerDebuggerBindings", curr
)
23759 def RegisterWorkletBindings(config
):
23760 curr
= CGRegisterWorkletBindings(config
)
23762 # Wrap all of that in our namespaces.
23763 curr
= CGNamespace
.build(["mozilla", "dom"], CGWrapper(curr
, post
="\n"))
23764 curr
= CGWrapper(curr
, post
="\n")
23768 CGHeaders
.getDeclarationFilename(desc
.interface
)
23769 for desc
in config
.getDescriptors(
23770 hasInterfaceObject
=True, register
=True, isExposedInAnyWorklet
=True
23775 [], [], [], [], [], defineIncludes
, "RegisterWorkletBindings", curr
23778 # Add include guards.
23779 curr
= CGIncludeGuard("RegisterWorkletBindings", curr
)
23785 def RegisterShadowRealmBindings(config
):
23786 curr
= CGRegisterShadowRealmBindings(config
)
23788 # Wrap all of that in our namespaces.
23789 curr
= CGNamespace
.build(["mozilla", "dom"], CGWrapper(curr
, post
="\n"))
23790 curr
= CGWrapper(curr
, post
="\n")
23794 CGHeaders
.getDeclarationFilename(desc
.interface
)
23795 for desc
in config
.getDescriptors(
23796 hasInterfaceObject
=True, register
=True, isExposedInShadowRealms
=True
23801 [], [], [], [], [], defineIncludes
, "RegisterShadowRealmBindings", curr
23804 # Add include guards.
23805 curr
= CGIncludeGuard("RegisterShadowRealmBindings", curr
)
23811 def UnionTypes(config
):
23812 unionTypes
= UnionsForFile(config
, None)
23820 ) = UnionTypes(unionTypes
, config
)
23822 unionStructs
= dependencySortDictionariesAndUnionsAndCallbacks(unionStructs
)
23827 + [CGUnionStruct(t
, config
) for t
in unionStructs
]
23828 + [CGUnionStruct(t
, config
, True) for t
in unionStructs
],
23832 includes
.add("mozilla/OwningNonNull.h")
23833 includes
.add("mozilla/dom/UnionMember.h")
23834 includes
.add("mozilla/dom/BindingDeclarations.h")
23835 # BindingUtils.h is only needed for SetToObject.
23836 # If it stops being inlined or stops calling CallerSubsumes
23837 # both this bit and the bit in CGBindingRoot can be removed.
23838 includes
.add("mozilla/dom/BindingUtils.h")
23840 # Wrap all of that in our namespaces.
23841 curr
= CGNamespace
.build(["mozilla", "dom"], unions
)
23843 curr
= CGWrapper(curr
, post
="\n")
23845 builder
= ForwardDeclarationBuilder()
23846 for className
, isStruct
in declarations
:
23847 builder
.add(className
, isStruct
=isStruct
)
23849 curr
= CGList([builder
.build(), curr
], "\n")
23851 curr
= CGHeaders([], [], [], [], includes
, implincludes
, "UnionTypes", curr
)
23853 # Add include guards.
23854 curr
= CGIncludeGuard("UnionTypes", curr
)
23860 def WebIDLPrefs(config
):
23862 headers
= set(["mozilla/dom/WebIDLPrefs.h"])
23863 for d
in config
.getDescriptors(hasInterfaceOrInterfacePrototypeObject
=True):
23864 for m
in d
.interface
.members
:
23865 pref
= PropertyDefiner
.getStringAttr(m
, "Pref")
23867 headers
.add(prefHeader(pref
))
23868 prefs
.add((pref
, prefIdentifier(pref
)))
23869 prefs
= sorted(prefs
)
23872 enum class WebIDLPrefIndex : uint8_t {
23876 typedef bool (*WebIDLPrefFunc)();
23877 extern const WebIDLPrefFunc sWebIDLPrefs[${len}];
23879 prefs
=",\n".join(map(lambda p
: "// " + p
[0] + "\n" + p
[1], prefs
)) + "\n",
23880 len=len(prefs
) + 1,
23884 const WebIDLPrefFunc sWebIDLPrefs[] = {
23890 map(lambda p
: "// " + p
[0] + "\nStaticPrefs::" + p
[1], prefs
)
23894 prefFunctions
= CGGeneric(declare
=declare
, define
=define
)
23896 # Wrap all of that in our namespaces.
23897 curr
= CGNamespace
.build(["mozilla", "dom"], prefFunctions
)
23899 curr
= CGWrapper(curr
, post
="\n")
23901 curr
= CGHeaders([], [], [], [], [], headers
, "WebIDLPrefs", curr
)
23903 # Add include guards.
23904 curr
= CGIncludeGuard("WebIDLPrefs", curr
)
23910 def WebIDLSerializable(config
):
23911 # We need a declaration of StructuredCloneTags in the header.
23912 declareIncludes
= set(
23914 "mozilla/dom/DOMJSClass.h",
23915 "mozilla/dom/StructuredCloneTags.h",
23919 defineIncludes
= set(
23920 ["mozilla/dom/WebIDLSerializable.h", "mozilla/PerfectHash.h"]
23923 for d
in config
.getDescriptors(isSerializable
=True):
23924 names
.append(d
.name
)
23925 defineIncludes
.add(CGHeaders
.getDeclarationFilename(d
.interface
))
23927 if len(names
) == 0:
23928 # We can't really create a PerfectHash out of this, but also there's
23929 # not much point to this file if we have no [Serializable] objects.
23930 # Just spit out an empty file.
23931 return CGIncludeGuard("WebIDLSerializable", CGGeneric(""))
23933 # If we had a lot of serializable things, it might be worth it to use a
23934 # PerfectHash here, or an array ordered by sctag value and binary
23935 # search. But setting those up would require knowing in this python
23936 # code the values of the various SCTAG_DOM_*. We could hardcode them
23937 # here and add static asserts that the values are right, or switch to
23938 # code-generating StructuredCloneTags.h or something. But in practice,
23939 # there's a pretty small number of serializable interfaces, and just
23940 # doing a linear walk is fine. It's not obviously worse than the
23941 # if-cascade we used to have. Let's just make sure we notice if we do
23942 # end up with a lot of serializable things here.
23944 # Also, in practice it looks like compilers compile this linear walk to
23945 # an out-of-bounds check followed by a direct index into an array, by
23946 # basically making a second copy of this array ordered by tag, with the
23947 # holes filled in. Again, worth checking whether this still happens if
23948 # we have too many serializable things.
23949 if len(names
) > 20:
23951 "We now have %s serializable interfaces. "
23952 "Double-check that the compiler is still "
23953 "generating a jump table." % len(names
)
23957 # Make sure we have stable ordering.
23958 for name
in sorted(names
):
23959 exposedGlobals
= computeGlobalNamesFromExposureSet(d
.interface
.exposureSet
)
23960 # Strip off trailing newline to make our formatting look right.
23966 /* mDeserialize */ ${name}_Binding::Deserialize,
23967 /* mExposedGlobals */ ${exposedGlobals},
23970 tag
=StructuredCloneTag(name
),
23972 exposedGlobals
=exposedGlobals
,
23978 Maybe<std::pair<uint16_t, WebIDLDeserializer>> LookupDeserializer(StructuredCloneTags aTag);
23983 struct WebIDLSerializableEntry {
23984 StructuredCloneTags mTag;
23985 WebIDLDeserializer mDeserialize;
23986 uint16_t mExposedGlobals;
23989 static const WebIDLSerializableEntry sEntries[] = {
23993 Maybe<std::pair<uint16_t, WebIDLDeserializer>> LookupDeserializer(StructuredCloneTags aTag) {
23994 for (auto& entry : sEntries) {
23995 if (entry.mTag == aTag) {
23996 return Some(std::pair(entry.mExposedGlobals, entry.mDeserialize));
24002 entries
=",\n".join(entries
) + "\n",
24005 code
= CGGeneric(declare
=declare
, define
=define
)
24007 # Wrap all of that in our namespaces.
24008 curr
= CGNamespace
.build(["mozilla", "dom"], code
)
24010 curr
= CGWrapper(curr
, post
="\n")
24013 [], [], [], [], declareIncludes
, defineIncludes
, "WebIDLSerializable", curr
24016 # Add include guards.
24017 curr
= CGIncludeGuard("WebIDLSerializable", curr
)
24023 # Code generator for simple events
24024 class CGEventGetter(CGNativeMember
):
24025 def __init__(self
, descriptor
, attr
):
24026 ea
= descriptor
.getExtendedAttributes(attr
, getter
=True)
24027 CGNativeMember
.__init
__(
24031 CGSpecializedGetterCommon
.makeNativeName(descriptor
, attr
),
24034 resultNotAddRefed
=not attr
.type.isSequence(),
24036 self
.body
= self
.getMethodBody()
24038 def getArgs(self
, returnType
, argList
):
24039 if "needsErrorResult" in self
.extendedAttrs
:
24040 raise TypeError("Event code generator does not support [Throws]!")
24041 if "canOOM" in self
.extendedAttrs
:
24042 raise TypeError("Event code generator does not support [CanOOM]!")
24043 if not self
.member
.isAttr():
24044 raise TypeError("Event code generator does not support methods")
24045 if self
.member
.isStatic():
24046 raise TypeError("Event code generators does not support static attributes")
24047 return CGNativeMember
.getArgs(self
, returnType
, argList
)
24049 def getMethodBody(self
):
24050 type = self
.member
.type
24051 memberName
= CGDictionary
.makeMemberName(self
.member
.identifier
.name
)
24053 (type.isPrimitive() and type.tag() in builtinNames
)
24055 or type.isPromise()
24056 or type.isGeckoInterface()
24058 return "return " + memberName
+ ";\n"
24059 if type.isJSString():
24060 # https://bugzilla.mozilla.org/show_bug.cgi?id=1580167
24061 raise TypeError("JSString not supported as member of a generated event")
24064 or type.isByteString()
24065 or type.isUSVString()
24066 or type.isUTF8String()
24068 return "aRetVal = " + memberName
+ ";\n"
24069 if type.isSpiderMonkeyInterface() or type.isObject():
24072 if (${memberName}) {
24073 JS::ExposeObjectToActiveJS(${memberName});
24075 aRetVal.set(${memberName});
24078 memberName
=memberName
,
24083 ${selfName}(aRetVal);
24085 selfName
=self
.name
,
24088 return "aRetVal = " + memberName
+ ";\n"
24089 if type.isSequence():
24090 if type.nullable():
24094 + ".IsNull()) { aRetVal.SetNull(); } else { aRetVal.SetValue("
24096 + ".Value().Clone()); }\n"
24099 return "aRetVal = " + memberName
+ ".Clone();\n"
24100 if type.isDictionary():
24101 return "aRetVal = " + memberName
+ ";\n"
24102 raise TypeError("Event code generator does not support this type!")
24104 def declare(self
, cgClass
):
24106 getattr(self
.member
, "originatingInterface", cgClass
.descriptor
.interface
)
24107 != cgClass
.descriptor
.interface
24110 return CGNativeMember
.declare(self
, cgClass
)
24112 def define(self
, cgClass
):
24114 getattr(self
.member
, "originatingInterface", cgClass
.descriptor
.interface
)
24115 != cgClass
.descriptor
.interface
24118 return CGNativeMember
.define(self
, cgClass
)
24121 class CGEventSetter(CGNativeMember
):
24122 def __init__(self
):
24123 raise TypeError("Event code generator does not support setters!")
24126 class CGEventMethod(CGNativeMember
):
24127 def __init__(self
, descriptor
, method
, signature
, isConstructor
, breakAfter
=True):
24128 self
.isInit
= False
24130 CGNativeMember
.__init
__(
24134 CGSpecializedMethod
.makeNativeName(descriptor
, method
),
24136 descriptor
.getExtendedAttributes(method
),
24137 breakAfter
=breakAfter
,
24138 variadicIsSequence
=True,
24140 self
.originalArgs
= list(self
.args
)
24142 iface
= descriptor
.interface
24143 allowed
= isConstructor
24144 if not allowed
and iface
.getExtendedAttribute("LegacyEventInit"):
24145 # Allow it, only if it fits the initFooEvent profile exactly
24146 # We could check the arg types but it's not worth the effort.
24148 method
.identifier
.name
== "init" + iface
.identifier
.name
24149 and signature
[1][0].type.isDOMString()
24150 and signature
[1][1].type.isBoolean()
24151 and signature
[1][2].type.isBoolean()
24153 # -3 on the left to ignore the type, bubbles, and cancelable parameters
24154 # -1 on the right to ignore the .trusted property which bleeds through
24155 # here because it is [Unforgeable].
24156 len(signature
[1]) - 3
24157 == len([x
for x
in iface
.members
if x
.isAttr()]) - 1
24163 raise TypeError("Event code generator does not support methods!")
24165 def getArgs(self
, returnType
, argList
):
24166 args
= [self
.getArg(arg
) for arg
in argList
]
24169 def getArg(self
, arg
):
24170 decl
, ref
= self
.getArgType(
24171 arg
.type, arg
.canHaveMissingValue(), "Variadic" if arg
.variadic
else False
24174 decl
= CGWrapper(decl
, pre
="const ", post
="&")
24176 name
= arg
.identifier
.name
24177 name
= "a" + name
[0].upper() + name
[1:]
24178 return Argument(decl
.define(), name
)
24180 def declare(self
, cgClass
):
24182 constructorForNativeCaller
= ""
24184 self
.args
= list(self
.originalArgs
)
24185 self
.args
.insert(0, Argument("mozilla::dom::EventTarget*", "aOwner"))
24186 constructorForNativeCaller
= CGNativeMember
.declare(self
, cgClass
)
24188 self
.args
= list(self
.originalArgs
)
24189 if needCx(None, self
.arguments(), [], considerTypes
=True, static
=True):
24190 self
.args
.insert(0, Argument("JSContext*", "aCx"))
24191 if not self
.isInit
:
24192 self
.args
.insert(0, Argument("const GlobalObject&", "aGlobal"))
24194 return constructorForNativeCaller
+ CGNativeMember
.declare(self
, cgClass
)
24196 def defineInit(self
, cgClass
):
24197 iface
= self
.descriptorProvider
.interface
24199 while iface
.identifier
.name
!= "Event":
24200 i
= 3 # Skip the boilerplate args: type, bubble,s cancelable.
24201 for m
in iface
.members
:
24203 # We need to initialize all the member variables that do
24204 # not come from Event.
24206 getattr(m
, "originatingInterface", iface
).identifier
.name
24210 name
= CGDictionary
.makeMemberName(m
.identifier
.name
)
24211 members
+= "%s = %s;\n" % (name
, self
.args
[i
].name
)
24213 iface
= iface
.parent
24217 InitEvent(${typeArg}, ${bubblesArg}, ${cancelableArg});
24220 typeArg
=self
.args
[0].name
,
24221 bubblesArg
=self
.args
[1].name
,
24222 cancelableArg
=self
.args
[2].name
,
24226 return CGNativeMember
.define(self
, cgClass
)
24228 def define(self
, cgClass
):
24229 self
.args
= list(self
.originalArgs
)
24231 return self
.defineInit(cgClass
)
24234 iface
= self
.descriptorProvider
.interface
24235 while iface
.identifier
.name
!= "Event":
24236 for m
in self
.descriptorProvider
.getDescriptor(
24237 iface
.identifier
.name
24238 ).interface
.members
:
24240 # We initialize all the other member variables in the
24241 # Constructor except those ones coming from the Event.
24244 m
, "originatingInterface", cgClass
.descriptor
.interface
24249 name
= CGDictionary
.makeMemberName(m
.identifier
.name
)
24250 if m
.type.isSequence():
24251 # For sequences we may not be able to do a simple
24252 # assignment because the underlying types may not match.
24253 # For example, the argument can be a
24254 # Sequence<OwningNonNull<SomeInterface>> while our
24255 # member is an nsTArray<RefPtr<SomeInterface>>. So
24256 # use AppendElements, which is actually a template on
24257 # the incoming type on nsTArray and does the right thing
24260 source
= "%s.%s" % (self
.args
[1].name
, name
)
24261 sequenceCopy
= "e->%s.AppendElements(%s);\n"
24262 if m
.type.nullable():
24263 sequenceCopy
= CGIfWrapper(
24264 CGGeneric(sequenceCopy
), "!%s.IsNull()" % source
24266 target
+= ".SetValue()"
24267 source
+= ".Value()"
24268 members
+= sequenceCopy
% (target
, source
)
24269 elif m
.type.isSpiderMonkeyInterface():
24270 srcname
= "%s.%s" % (self
.args
[1].name
, name
)
24271 if m
.type.nullable():
24274 if (${srcname}.IsNull()) {
24275 e->${varname} = nullptr;
24277 e->${varname} = ${srcname}.Value().Obj();
24286 e->${varname}.set(${srcname}.Obj());
24292 members
+= "e->%s = %s.%s;\n" % (name
, self
.args
[1].name
, name
)
24295 or m
.type.isObject()
24296 or m
.type.isSpiderMonkeyInterface()
24298 holdJS
= "mozilla::HoldJSObjects(e.get());\n"
24299 iface
= iface
.parent
24303 RefPtr<${nativeType}> e = new ${nativeType}(aOwner);
24304 bool trusted = e->Init(aOwner);
24305 e->InitEvent(${eventType}, ${eventInit}.mBubbles, ${eventInit}.mCancelable);
24307 e->SetTrusted(trusted);
24308 e->SetComposed(${eventInit}.mComposed);
24312 nativeType
=self
.descriptorProvider
.nativeType
.split("::")[-1],
24313 eventType
=self
.args
[0].name
,
24314 eventInit
=self
.args
[1].name
,
24319 self
.args
.insert(0, Argument("mozilla::dom::EventTarget*", "aOwner"))
24320 constructorForNativeCaller
= CGNativeMember
.define(self
, cgClass
) + "\n"
24321 self
.args
= list(self
.originalArgs
)
24324 nsCOMPtr<mozilla::dom::EventTarget> owner = do_QueryInterface(aGlobal.GetAsSupports());
24325 return Constructor(owner, ${arg0}, ${arg1});
24327 arg0
=self
.args
[0].name
,
24328 arg1
=self
.args
[1].name
,
24330 if needCx(None, self
.arguments(), [], considerTypes
=True, static
=True):
24331 self
.args
.insert(0, Argument("JSContext*", "aCx"))
24332 self
.args
.insert(0, Argument("const GlobalObject&", "aGlobal"))
24333 return constructorForNativeCaller
+ CGNativeMember
.define(self
, cgClass
)
24336 class CGEventClass(CGBindingImplClass
):
24338 Codegen for the actual Event class implementation for this descriptor
24341 def __init__(self
, descriptor
):
24342 CGBindingImplClass
.__init
__(
24349 "WrapObjectInternal",
24353 self
.membersNeedingCC
= []
24354 self
.membersNeedingTrace
= []
24356 for m
in descriptor
.interface
.members
:
24358 getattr(m
, "originatingInterface", descriptor
.interface
)
24359 != descriptor
.interface
24365 self
.membersNeedingTrace
.append(m
)
24366 # Add a getter that doesn't need a JSContext. Note that we
24367 # don't need to do this if our originating interface is not
24368 # the descriptor's interface, because in that case we
24369 # wouldn't generate the getter that _does_ need a JSContext
24371 extraMethods
.append(
24373 CGSpecializedGetterCommon
.makeNativeName(descriptor
, m
),
24375 [Argument("JS::MutableHandle<JS::Value>", "aRetVal")],
24379 JS::ExposeValueToActiveJS(${memberName});
24380 aRetVal.set(${memberName});
24382 memberName
=CGDictionary
.makeMemberName(
24388 elif m
.type.isObject() or m
.type.isSpiderMonkeyInterface():
24389 self
.membersNeedingTrace
.append(m
)
24390 elif typeNeedsRooting(m
.type):
24392 "Need to implement tracing for event member of type %s" % m
.type
24394 elif idlTypeNeedsCycleCollection(m
.type):
24395 self
.membersNeedingCC
.append(m
)
24397 nativeType
= self
.getNativeTypeForIDLType(m
.type).define()
24400 CGDictionary
.makeMemberName(m
.identifier
.name
),
24402 visibility
="private",
24407 parent
= self
.descriptor
.interface
.parent
24408 self
.parentType
= self
.descriptor
.getDescriptor(
24409 parent
.identifier
.name
24410 ).nativeType
.split("::")[-1]
24411 self
.nativeType
= self
.descriptor
.nativeType
.split("::")[-1]
24414 isupportsDecl
= fill(
24416 NS_DECL_ISUPPORTS_INHERITED
24417 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(${nativeType}, ${parentType})
24419 nativeType
=self
.nativeType
,
24420 parentType
=self
.parentType
,
24423 isupportsDecl
= fill(
24425 NS_INLINE_DECL_REFCOUNTING_INHERITED(${nativeType}, ${parentType})
24427 nativeType
=self
.nativeType
,
24428 parentType
=self
.parentType
,
24431 baseDeclarations
= fill(
24437 virtual ~${nativeType}();
24438 explicit ${nativeType}(mozilla::dom::EventTarget* aOwner);
24441 isupportsDecl
=isupportsDecl
,
24442 nativeType
=self
.nativeType
,
24443 parentType
=self
.parentType
,
24446 className
= self
.nativeType
24447 asConcreteTypeMethod
= ClassMethod(
24448 "As%s" % className
,
24452 body
="return this;\n",
24453 breakAfterReturnDecl
=" ",
24456 extraMethods
.append(asConcreteTypeMethod
)
24461 bases
=[ClassBase(self
.parentType
)],
24462 methods
=extraMethods
+ self
.methodDecls
,
24464 extradeclarations
=baseDeclarations
,
24467 def getWrapObjectBody(self
):
24469 "return %s_Binding::Wrap(aCx, this, aGivenProto);\n" % self
.descriptor
.name
24473 return len(self
.membersNeedingCC
) != 0 or len(self
.membersNeedingTrace
) != 0
24475 def implTraverse(self
):
24477 for m
in self
.membersNeedingCC
:
24479 " NS_IMPL_CYCLE_COLLECTION_TRAVERSE(%s)\n"
24480 % CGDictionary
.makeMemberName(m
.identifier
.name
)
24484 def implUnlink(self
):
24486 for m
in self
.membersNeedingCC
:
24488 " NS_IMPL_CYCLE_COLLECTION_UNLINK(%s)\n"
24489 % CGDictionary
.makeMemberName(m
.identifier
.name
)
24491 for m
in self
.membersNeedingTrace
:
24492 name
= CGDictionary
.makeMemberName(m
.identifier
.name
)
24494 retVal
+= " tmp->" + name
+ ".setUndefined();\n"
24495 elif m
.type.isObject() or m
.type.isSpiderMonkeyInterface():
24496 retVal
+= " tmp->" + name
+ " = nullptr;\n"
24498 raise TypeError("Unknown traceable member type %s" % m
.type)
24501 def implTrace(self
):
24503 for m
in self
.membersNeedingTrace
:
24505 " NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(%s)\n"
24506 % CGDictionary
.makeMemberName(m
.identifier
.name
)
24511 for m
in self
.membersNeedingTrace
:
24513 m
.type.isAny() or m
.type.isObject() or m
.type.isSpiderMonkeyInterface()
24515 raise TypeError("Unknown traceable member type %s" % m
.type)
24517 if len(self
.membersNeedingTrace
) > 0:
24518 dropJS
= "mozilla::DropJSObjects(this);\n"
24521 # Just override CGClass and do our own thing
24523 "aOwner, nullptr, nullptr" if self
.parentType
== "Event" else "aOwner"
24530 NS_IMPL_CYCLE_COLLECTION_CLASS(${nativeType})
24532 NS_IMPL_ADDREF_INHERITED(${nativeType}, ${parentType})
24533 NS_IMPL_RELEASE_INHERITED(${nativeType}, ${parentType})
24535 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(${nativeType}, ${parentType})
24537 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
24539 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(${nativeType}, ${parentType})
24541 NS_IMPL_CYCLE_COLLECTION_TRACE_END
24543 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(${nativeType}, ${parentType})
24545 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
24547 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
24548 NS_INTERFACE_MAP_END_INHERITING(${parentType})
24550 nativeType
=self
.nativeType
,
24551 parentType
=self
.parentType
,
24552 traverse
=self
.implTraverse(),
24553 unlink
=self
.implUnlink(),
24554 trace
=self
.implTrace(),
24562 ${nativeType}::${nativeType}(mozilla::dom::EventTarget* aOwner)
24563 : ${parentType}(${ctorParams})
24567 ${nativeType}::~${nativeType}()
24573 nativeType
=self
.nativeType
,
24574 ctorParams
=ctorParams
,
24575 parentType
=self
.parentType
,
24579 return classImpl
+ CGBindingImplClass
.define(self
)
24581 def getNativeTypeForIDLType(self
, type):
24582 if type.isPrimitive() and type.tag() in builtinNames
:
24583 nativeType
= CGGeneric(builtinNames
[type.tag()])
24584 if type.nullable():
24585 nativeType
= CGTemplatedType("Nullable", nativeType
)
24586 elif type.isEnum():
24587 nativeType
= CGGeneric(type.unroll().inner
.identifier
.name
)
24588 if type.nullable():
24589 nativeType
= CGTemplatedType("Nullable", nativeType
)
24590 elif type.isJSString():
24591 nativeType
= CGGeneric("JS::Heap<JSString*>")
24592 elif type.isDOMString() or type.isUSVString():
24593 nativeType
= CGGeneric("nsString")
24594 elif type.isByteString() or type.isUTF8String():
24595 nativeType
= CGGeneric("nsCString")
24596 elif type.isPromise():
24597 nativeType
= CGGeneric("RefPtr<Promise>")
24598 elif type.isDictionary():
24599 if typeNeedsRooting(type):
24601 "We don't support event members that are dictionary types "
24602 "that need rooting (%s)" % type
24604 nativeType
= CGGeneric(CGDictionary
.makeDictionaryName(type.unroll().inner
))
24605 if type.nullable():
24606 nativeType
= CGTemplatedType("Nullable", nativeType
)
24607 elif type.isGeckoInterface():
24608 iface
= type.unroll().inner
24609 nativeType
= self
.descriptor
.getDescriptor(iface
.identifier
.name
).nativeType
24610 # Now trim off unnecessary namespaces
24611 nativeType
= nativeType
.split("::")
24612 if nativeType
[0] == "mozilla":
24614 if nativeType
[0] == "dom":
24616 nativeType
= CGWrapper(
24617 CGGeneric("::".join(nativeType
)), pre
="RefPtr<", post
=">"
24620 nativeType
= CGGeneric("JS::Heap<JS::Value>")
24621 elif type.isObject() or type.isSpiderMonkeyInterface():
24622 nativeType
= CGGeneric("JS::Heap<JSObject*>")
24623 elif type.isUnion():
24624 nativeType
= CGGeneric(CGUnionStruct
.unionTypeDecl(type, True))
24625 elif type.isSequence():
24626 if type.nullable():
24627 innerType
= type.inner
.inner
24629 innerType
= type.inner
24631 not innerType
.isPrimitive()
24632 and not innerType
.isEnum()
24633 and not innerType
.isDOMString()
24634 and not innerType
.isByteString()
24635 and not innerType
.isUTF8String()
24636 and not innerType
.isPromise()
24637 and not innerType
.isGeckoInterface()
24640 "Don't know how to properly manage GC/CC for "
24641 "event member of type %s" % type
24643 nativeType
= CGTemplatedType(
24644 "nsTArray", self
.getNativeTypeForIDLType(innerType
)
24646 if type.nullable():
24647 nativeType
= CGTemplatedType("Nullable", nativeType
)
24649 raise TypeError("Don't know how to declare event member of type %s" % type)
24653 class CGEventRoot(CGThing
):
24654 def __init__(self
, config
, interfaceName
):
24655 descriptor
= config
.getDescriptor(interfaceName
)
24657 self
.root
= CGWrapper(CGEventClass(descriptor
), pre
="\n", post
="\n")
24659 self
.root
= CGNamespace
.build(["mozilla", "dom"], self
.root
)
24661 self
.root
= CGList(
24662 [CGClassForwardDeclare("JSContext", isStruct
=True), self
.root
]
24665 parent
= descriptor
.interface
.parent
.identifier
.name
24667 # Throw in our #includes
24668 self
.root
= CGHeaders(
24674 config
.getDescriptor(parent
).headerFile
,
24675 "mozilla/Attributes.h",
24676 "mozilla/dom/%sBinding.h" % interfaceName
,
24677 "mozilla/dom/BindingUtils.h",
24680 "%s.h" % interfaceName
,
24682 "mozilla/HoldDropJSObjects.h",
24683 "mozilla/dom/Nullable.h",
24690 # And now some include guards
24691 self
.root
= CGIncludeGuard(interfaceName
, self
.root
)
24693 self
.root
= CGWrapper(
24696 AUTOGENERATED_WITH_SOURCE_WARNING_COMMENT
24697 % os
.path
.basename(descriptor
.interface
.filename
)
24701 self
.root
= CGWrapper(
24705 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
24706 /* vim:set ts=2 sw=2 sts=2 et cindent: */
24707 /* This Source Code Form is subject to the terms of the Mozilla Public
24708 * License, v. 2.0. If a copy of the MPL was not distributed with this
24709 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
24716 return self
.root
.declare()
24719 return self
.root
.define()