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.
9 from operator
import attrgetter
15 from Configuration
import (
17 MemberIsLegacyUnforgeable
,
18 NoSuchDescriptorError
,
21 getTypesFromDescriptor
,
22 getTypesFromDictionary
,
24 from perfecthash
import PerfectHash
29 IDLDefaultDictionaryValue
,
31 IDLEmptySequenceValue
,
39 AUTOGENERATED_WARNING_COMMENT
= (
40 "/* THIS FILE IS AUTOGENERATED BY Codegen.py - DO NOT EDIT */\n\n"
42 AUTOGENERATED_WITH_SOURCE_WARNING_COMMENT
= (
43 "/* THIS FILE IS AUTOGENERATED FROM %s BY Codegen.py - DO NOT EDIT */\n\n"
45 ADDPROPERTY_HOOK_NAME
= "_addProperty"
46 GETWRAPPERCACHE_HOOK_NAME
= "_getWrapperCache"
47 FINALIZE_HOOK_NAME
= "_finalize"
48 OBJECT_MOVED_HOOK_NAME
= "_objectMoved"
49 CONSTRUCT_HOOK_NAME
= "_constructor"
50 LEGACYCALLER_HOOK_NAME
= "_legacycaller"
51 RESOLVE_HOOK_NAME
= "_resolve"
52 MAY_RESOLVE_HOOK_NAME
= "_mayResolve"
53 NEW_ENUMERATE_HOOK_NAME
= "_newEnumerate"
54 INSTANCE_RESERVED_SLOTS
= 1
56 # This size is arbitrary. It is a power of 2 to make using it as a modulo
57 # operand cheap, and is usually around 1/3-1/5th of the set size (sometimes
58 # smaller for very large sets).
59 GLOBAL_NAMES_PHF_SIZE
= 256
62 def reservedSlot(slotIndex
, forXray
):
63 base
= "DOM_EXPANDO_RESERVED_SLOTS" if forXray
else "DOM_INSTANCE_RESERVED_SLOTS"
64 return "(%s + %d)" % (base
, slotIndex
)
67 def getSlotIndex(member
, descriptor
):
68 slotIndex
= member
.slotIndices
[descriptor
.interface
.identifier
.name
]
69 return slotIndex
[0] if isinstance(slotIndex
, tuple) else slotIndex
72 def memberReservedSlot(member
, descriptor
):
73 return reservedSlot(getSlotIndex(member
, descriptor
), False)
76 def memberXrayExpandoReservedSlot(member
, descriptor
):
77 return reservedSlot(getSlotIndex(member
, descriptor
), True)
80 def mayUseXrayExpandoSlots(descriptor
, attr
):
81 assert not attr
.getExtendedAttribute("NewObject")
82 # For attributes whose type is a Gecko interface we always use
83 # slots on the reflector for caching. Also, for interfaces that
84 # don't want Xrays we obviously never use the Xray expando slot.
85 return descriptor
.wantsXrays
and not attr
.type.isGeckoInterface()
88 def reflectedHTMLAttributesArrayIndex(descriptor
, attr
):
89 slots
= attr
.slotIndices
[descriptor
.interface
.identifier
.name
]
93 def getReflectedHTMLAttributesIface(descriptor
):
94 iface
= descriptor
.interface
96 if iface
.reflectedHTMLAttributesReturningFrozenArray
:
102 def toStringBool(arg
):
104 Converts IDL/Python Boolean (True/False) to C++ Boolean (true/false)
106 return str(not not arg
).lower()
109 def toBindingNamespace(arg
):
110 return arg
+ "_Binding"
113 def isTypeCopyConstructible(type):
114 # Nullable and sequence stuff doesn't affect copy-constructibility
118 or type.isPrimitive()
121 or (type.isUnion() and CGUnionStruct
.isUnionCopyConstructible(type))
124 and CGDictionary
.isDictionaryCopyConstructible(type.inner
)
127 # Interface types are only copy-constructible if they're Gecko
128 # interfaces. SpiderMonkey interfaces are not copy-constructible
129 # because of rooting issues.
130 (type.isInterface() and type.isGeckoInterface())
134 class CycleCollectionUnsupported(TypeError):
135 def __init__(self
, message
):
136 TypeError.__init
__(self
, message
)
139 def idlTypeNeedsCycleCollection(type):
140 type = type.unroll() # Takes care of sequences and nullables
142 (type.isPrimitive() and type.tag() in builtinNames
)
143 or type.isUndefined()
148 or type.isSpiderMonkeyInterface()
151 elif type.isCallback() or type.isPromise() or type.isGeckoInterface():
154 return any(idlTypeNeedsCycleCollection(t
) for t
in type.flatMemberTypes
)
155 elif type.isRecord():
156 if idlTypeNeedsCycleCollection(type.inner
):
157 raise CycleCollectionUnsupported(
158 "Cycle collection for type %s is not supported" % type
161 elif type.isDictionary():
162 return CGDictionary
.dictionaryNeedsCycleCollection(type.inner
)
164 raise CycleCollectionUnsupported(
165 "Don't know whether to cycle-collect type %s" % type
169 def idlTypeNeedsCallContext(type, descriptor
=None, allowTreatNonCallableAsNull
=False):
171 Returns whether the given type needs error reporting via a
172 BindingCallContext for JS-to-C++ conversions. This will happen when the
173 conversion can throw an exception due to logic in the IDL spec or
174 Gecko-specific security checks. In particular, a type needs a
175 BindingCallContext if and only if the JS-to-C++ conversion for that type can
176 end up calling ThrowErrorMessage.
178 For some types this depends on the descriptor (e.g. because we do certain
179 checks only for some kinds of interfaces).
181 The allowTreatNonCallableAsNull optimization is there so we can avoid
182 generating an unnecessary BindingCallContext for all the event handler
187 if type.isSequence():
188 # Sequences can always throw "not an object"
191 # treatNonObjectAsNull() and treatNonCallableAsNull() are
192 # only sane things to test on nullable types, so do that now.
194 allowTreatNonCallableAsNull
195 and type.isCallback()
196 and (type.treatNonObjectAsNull() or type.treatNonCallableAsNull())
198 # This can't throw. so never needs a method description.
204 if type.isUndefined():
205 # Clearly doesn't need a method description; we can only get here from
206 # CGHeaders trying to decide whether to include the method description
209 # The float check needs to come before the isPrimitive() check,
210 # because floats are primitives too.
212 # Floats can throw if restricted.
213 return not type.isUnrestricted()
214 if type.isPrimitive() and type.tag() in builtinNames
:
215 # Numbers can throw if enforcing range.
216 return type.hasEnforceRange()
218 # Can throw on invalid value.
221 # Can throw if it's a ByteString
222 return type.isByteString()
224 # JS-implemented interfaces do extra security checks so need a
225 # method description here. If we have no descriptor, this
226 # might be JS-implemented thing, so it will do the security
227 # check and we need the method description.
228 return not descriptor
or descriptor
.interface
.isJSImplemented()
230 # JS-to-Promise conversion won't cause us to throw any
231 # specific exceptions, so does not need a method description.
235 or type.isInterface()
237 or type.isDictionary()
239 or type.isObservableArray()
241 # These can all throw if a primitive is passed in, at the very least.
242 # There are some rare cases when we know we have an object, but those
243 # are not worth the complexity of optimizing for.
245 # Note that we checked the [LegacyTreatNonObjectAsNull] case already when
246 # unwrapping nullables.
249 # Can throw if a type not in the union is passed in.
251 raise TypeError("Don't know whether type '%s' needs a method description" % type)
254 # TryPreserveWrapper uses the addProperty hook to preserve the wrapper of
255 # non-nsISupports cycle collected objects, so if wantsAddProperty is changed
256 # to not cover that case then TryPreserveWrapper will need to be changed.
257 def wantsAddProperty(desc
):
258 return desc
.concrete
and desc
.wrapperCache
and not desc
.isGlobal()
261 def wantsGetWrapperCache(desc
):
263 desc
.concrete
and desc
.wrapperCache
and not desc
.isGlobal() and not desc
.proxy
267 def indent(s
, indentLevel
=2):
271 Weird secret feature: this doesn't indent lines that start with # (such as
272 #include lines or #ifdef/#endif).
275 # We'll want to insert the indent at the beginnings of lines, but we
276 # don't want to indent empty lines.
277 padding
= indentLevel
* " "
280 (padding
+ line
) if line
and line
[0] != "#" else line
281 for line
in s
.split("\n")
286 # dedent() and fill() are often called on the same string multiple
287 # times. We want to memoize their return values so we don't keep
288 # recomputing them all the time.
291 Decorator to memoize a function of one argument. The cache just
298 retval
= cache
.get(arg
)
300 retval
= cache
[arg
] = fn(arg
)
309 Remove all leading whitespace from s, and remove a blank line
312 if s
.startswith("\n"):
314 return textwrap
.dedent(s
)
317 # This works by transforming the fill()-template to an equivalent
319 fill_multiline_substitution_re
= re
.compile(r
"( *)\$\*{(\w+)}(\n)?")
322 find_substitutions
= re
.compile(r
"\${")
326 def compile_fill_template(template
):
328 Helper function for fill(). Given the template string passed to fill(),
329 do the reusable part of template processing and return a pair (t,
330 argModList) that can be used every time fill() is called with that
333 argsModList is list of tuples that represent modifications to be
334 made to args. Each modification has, in order: i) the arg name,
335 ii) the modified name, iii) the indent depth.
338 assert t
.endswith("\n") or "\n" not in t
343 Replaces a line like ' $*{xyz}\n' with '${xyz_n}',
344 where n is the indent depth, and add a corresponding entry to
347 Note that this needs to close over argModList, so it has to be
348 defined inside compile_fill_template().
350 indentation
, name
, nl
= match
.groups()
351 depth
= len(indentation
)
353 # Check that $*{xyz} appears by itself on a line.
354 prev
= match
.string
[: match
.start()]
355 if (prev
and not prev
.endswith("\n")) or nl
is None:
357 "Invalid fill() template: $*{%s} must appear by itself on a line" % name
360 # Now replace this whole line of template with the indented equivalent.
361 modified_name
= name
+ "_" + str(depth
)
362 argModList
.append((name
, modified_name
, depth
))
363 return "${" + modified_name
+ "}"
365 t
= re
.sub(fill_multiline_substitution_re
, replace
, t
)
366 if not re
.search(find_substitutions
, t
):
367 raise TypeError("Using fill() when dedent() would do.")
368 return (string
.Template(t
), argModList
)
371 def fill(template
, **args
):
373 Convenience function for filling in a multiline template.
375 `fill(template, name1=v1, name2=v2)` is a lot like
376 `string.Template(template).substitute({"name1": v1, "name2": v2})`.
378 However, it's shorter, and has a few nice features:
380 * If `template` is indented, fill() automatically dedents it!
381 This makes code using fill() with Python's multiline strings
382 much nicer to look at.
384 * If `template` starts with a blank line, fill() strips it off.
385 (Again, convenient with multiline strings.)
387 * fill() recognizes a special kind of substitution
388 of the form `$*{name}`.
390 Use this to paste in, and automatically indent, multiple lines.
391 (Mnemonic: The `*` is for "multiple lines").
393 A `$*` substitution must appear by itself on a line, with optional
394 preceding indentation (spaces only). The whole line is replaced by the
395 corresponding keyword argument, indented appropriately. If the
396 argument is an empty string, no output is generated, not even a blank
400 t
, argModList
= compile_fill_template(template
)
401 # Now apply argModList to args
402 for name
, modified_name
, depth
in argModList
:
403 if not (args
[name
] == "" or args
[name
].endswith("\n")):
405 "Argument %s with value %r is missing a newline" % (name
, args
[name
])
407 args
[modified_name
] = indent(args
[name
], depth
)
409 return t
.substitute(args
)
414 Abstract base class for things that spit out code.
418 pass # Nothing for now
421 """Produce code for a header file."""
422 assert False # Override me!
425 """Produce code for a cpp file."""
426 assert False # Override me!
429 """Produce the deps for a pp file"""
430 assert False # Override me!
433 class CGStringTable(CGThing
):
435 Generate a function accessor for a WebIDL string table, using the existing
436 concatenated names string and mapping indexes to offsets in that string:
438 const char *accessorName(unsigned int index) {
439 static const uint16_t offsets = { ... };
440 return BindingName(offsets[index]);
443 This is more efficient than the more natural:
445 const char *table[] = {
449 The uint16_t offsets are smaller than the pointer equivalents, and the
450 concatenated string requires no runtime relocations.
453 def __init__(self
, accessorName
, strings
, static
=False):
454 CGThing
.__init
__(self
)
455 self
.accessorName
= accessorName
456 self
.strings
= strings
462 return "const char *%s(unsigned int aIndex);\n" % self
.accessorName
466 for s
in self
.strings
:
467 offsets
.append(BindingNamesOffsetEnum(s
))
470 ${static}const char *${name}(unsigned int aIndex)
472 static const BindingNamesOffset offsets[] = {
475 return BindingName(offsets[aIndex]);
478 static
="static " if self
.static
else "",
479 name
=self
.accessorName
,
480 offsets
="".join("BindingNamesOffset::%s,\n" % o
for o
in offsets
),
484 class CGNativePropertyHooks(CGThing
):
486 Generate a NativePropertyHooks for a given descriptor
489 def __init__(self
, descriptor
, properties
):
490 CGThing
.__init
__(self
)
491 assert descriptor
.wantsXrays
492 self
.descriptor
= descriptor
493 self
.properties
= properties
500 self
.descriptor
.concrete
501 and self
.descriptor
.proxy
502 and not self
.descriptor
.isMaybeCrossOriginObject()
504 if self
.descriptor
.needsXrayNamedDeleterHook():
505 deleteNamedProperty
= "DeleteNamedProperty"
507 deleteNamedProperty
= "nullptr"
508 namedOrIndexed
= fill(
510 const NativeNamedOrIndexedPropertyHooks sNativeNamedOrIndexedPropertyHooks = {
511 binding_detail::ResolveOwnProperty,
512 binding_detail::EnumerateOwnProperties,
513 ${deleteNamedProperty}
516 deleteNamedProperty
=deleteNamedProperty
,
518 namedOrIndexedPointer
= "&sNativeNamedOrIndexedPropertyHooks"
519 elif self
.descriptor
.needsXrayResolveHooks():
520 namedOrIndexed
= dedent(
522 const NativeNamedOrIndexedPropertyHooks sNativeNamedOrIndexedPropertyHooks = {
523 ResolveOwnPropertyViaResolve,
524 EnumerateOwnPropertiesViaGetOwnPropertyNames,
529 namedOrIndexedPointer
= "&sNativeNamedOrIndexedPropertyHooks"
532 namedOrIndexedPointer
= "nullptr"
533 if self
.properties
.hasNonChromeOnly():
534 regular
= "sNativeProperties.Upcast()"
537 if self
.properties
.hasChromeOnly():
538 chrome
= "sChromeOnlyNativeProperties.Upcast()"
541 constructorID
= "constructors::id::"
542 if self
.descriptor
.interface
.hasInterfaceObject():
543 constructorID
+= self
.descriptor
.name
545 constructorID
+= "_ID_Count"
546 prototypeID
= "prototypes::id::"
547 if self
.descriptor
.interface
.hasInterfacePrototypeObject():
548 prototypeID
+= self
.descriptor
.name
550 prototypeID
+= "_ID_Count"
552 if self
.descriptor
.wantsXrayExpandoClass
:
553 expandoClass
= "&sXrayExpandoObjectClass"
555 expandoClass
= "&DefaultXrayExpandoObjectClass"
557 return namedOrIndexed
+ fill(
559 bool sNativePropertiesInited = false;
560 const NativePropertyHooks sNativePropertyHooks = {
561 ${namedOrIndexedPointer},
562 { ${regular}, ${chrome}, &sNativePropertiesInited },
568 namedOrIndexedPointer
=namedOrIndexedPointer
,
571 prototypeID
=prototypeID
,
572 constructorID
=constructorID
,
573 expandoClass
=expandoClass
,
577 def NativePropertyHooks(descriptor
):
579 "&sEmptyNativePropertyHooks"
580 if not descriptor
.wantsXrays
581 else "&sNativePropertyHooks"
585 def DOMClass(descriptor
):
586 protoList
= ["prototypes::id::" + proto
for proto
in descriptor
.prototypeNameChain
]
587 # Pad out the list to the right length with _ID_Count so we
588 # guarantee that all the lists are the same length. _ID_Count
589 # is never the ID of any prototype, so it's safe to use as
592 ["prototypes::id::_ID_Count"]
593 * (descriptor
.config
.maxProtoChainLength
- len(protoList
))
596 if descriptor
.interface
.isSerializable():
597 serializer
= "Serialize"
599 serializer
= "nullptr"
601 if wantsGetWrapperCache(descriptor
):
602 wrapperCacheGetter
= GETWRAPPERCACHE_HOOK_NAME
604 wrapperCacheGetter
= "nullptr"
606 if descriptor
.hasOrdinaryObjectPrototype():
607 getProto
= "JS::GetRealmObjectPrototypeHandle"
609 getProto
= "GetProtoObjectHandle"
614 std::is_base_of_v<nsISupports, ${nativeType}>,
616 FindAssociatedGlobalForNative<${nativeType}>::Get,
618 GetCCParticipant<${nativeType}>::Get(),
620 ${wrapperCacheGetter}
622 protoChain
=", ".join(protoList
),
623 nativeType
=descriptor
.nativeType
,
624 hooks
=NativePropertyHooks(descriptor
),
625 serializer
=serializer
,
626 wrapperCacheGetter
=wrapperCacheGetter
,
631 def InstanceReservedSlots(descriptor
):
632 slots
= INSTANCE_RESERVED_SLOTS
+ descriptor
.interface
.totalMembersInSlots
633 if descriptor
.isMaybeCrossOriginObject():
634 # We need a slot for the cross-origin holder too.
635 if descriptor
.interface
.hasChildInterfaces():
637 "We don't support non-leaf cross-origin interfaces "
638 "like %s" % descriptor
.interface
.identifier
.name
644 class CGDOMJSClass(CGThing
):
646 Generate a DOMJSClass for a given descriptor
649 def __init__(self
, descriptor
):
650 CGThing
.__init
__(self
)
651 self
.descriptor
= descriptor
658 LEGACYCALLER_HOOK_NAME
659 if self
.descriptor
.operations
["LegacyCaller"]
663 OBJECT_MOVED_HOOK_NAME
if self
.descriptor
.wrapperCache
else "nullptr"
665 slotCount
= InstanceReservedSlots(self
.descriptor
)
666 classFlags
= "JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | "
667 if self
.descriptor
.isGlobal():
669 "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS)"
671 traceHook
= "JS_GlobalObjectTraceHook"
672 reservedSlots
= "JSCLASS_GLOBAL_APPLICATION_SLOTS"
674 classFlags
+= "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount
675 iface
= getReflectedHTMLAttributesIface(self
.descriptor
)
678 "%s::ReflectedHTMLAttributeSlots::Trace"
679 % toBindingNamespace(iface
.identifier
.name
)
682 traceHook
= "nullptr"
683 reservedSlots
= slotCount
684 if self
.descriptor
.interface
.hasProbablyShortLivingWrapper():
685 if not self
.descriptor
.wrapperCache
:
687 "Need a wrapper cache to support nursery "
688 "allocation of DOM objects"
690 classFlags
+= " | JSCLASS_SKIP_NURSERY_FINALIZE"
692 if self
.descriptor
.interface
.getExtendedAttribute("NeedResolve"):
693 resolveHook
= RESOLVE_HOOK_NAME
694 mayResolveHook
= MAY_RESOLVE_HOOK_NAME
695 newEnumerateHook
= NEW_ENUMERATE_HOOK_NAME
696 elif self
.descriptor
.isGlobal():
697 resolveHook
= "mozilla::dom::ResolveGlobal"
698 mayResolveHook
= "mozilla::dom::MayResolveGlobal"
699 newEnumerateHook
= "mozilla::dom::EnumerateGlobal"
701 resolveHook
= "nullptr"
702 mayResolveHook
= "nullptr"
703 newEnumerateHook
= "nullptr"
707 static const JSClassOps sClassOps = {
708 ${addProperty}, /* addProperty */
709 nullptr, /* delProperty */
710 nullptr, /* enumerate */
711 ${newEnumerate}, /* newEnumerate */
712 ${resolve}, /* resolve */
713 ${mayResolve}, /* mayResolve */
714 ${finalize}, /* finalize */
716 nullptr, /* construct */
717 ${trace}, /* trace */
720 static const js::ClassExtension sClassExtension = {
721 ${objectMoved} /* objectMovedOp */
724 static const DOMJSClass sClass = {
734 static_assert(${instanceReservedSlots} == DOM_INSTANCE_RESERVED_SLOTS,
735 "Must have the right minimal number of reserved slots.");
736 static_assert(${reservedSlots} >= ${slotCount},
737 "Must have enough reserved slots.");
739 name
=self
.descriptor
.interface
.getClassName(),
742 ADDPROPERTY_HOOK_NAME
743 if wantsAddProperty(self
.descriptor
)
746 newEnumerate
=newEnumerateHook
,
748 mayResolve
=mayResolveHook
,
749 finalize
=FINALIZE_HOOK_NAME
,
752 objectMoved
=objectMovedHook
,
753 descriptor
=DOMClass(self
.descriptor
),
754 instanceReservedSlots
=INSTANCE_RESERVED_SLOTS
,
755 reservedSlots
=reservedSlots
,
760 class CGDOMProxyJSClass(CGThing
):
762 Generate a DOMJSClass for a given proxy descriptor
765 def __init__(self
, descriptor
):
766 CGThing
.__init
__(self
)
767 self
.descriptor
= descriptor
773 slotCount
= InstanceReservedSlots(self
.descriptor
)
774 # We need one reserved slot (DOM_OBJECT_SLOT).
775 flags
= ["JSCLASS_IS_DOMJSCLASS", "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount
]
776 # We don't use an IDL annotation for JSCLASS_EMULATES_UNDEFINED because
777 # we don't want people ever adding that to any interface other than
778 # HTMLAllCollection. So just hardcode it here.
779 if self
.descriptor
.interface
.identifier
.name
== "HTMLAllCollection":
780 flags
.append("JSCLASS_EMULATES_UNDEFINED")
783 static const DOMJSClass sClass = {
784 PROXY_CLASS_DEF("${name}",
789 name
=self
.descriptor
.interface
.identifier
.name
,
790 flags
=" | ".join(flags
),
791 descriptor
=DOMClass(self
.descriptor
),
795 class CGXrayExpandoJSClass(CGThing
):
797 Generate a JSClass for an Xray expando object. This is only
798 needed if we have members in slots (for [Cached] or [StoreInSlot]
802 def __init__(self
, descriptor
):
803 assert descriptor
.interface
.totalMembersInSlots
!= 0
804 assert descriptor
.wantsXrays
805 assert descriptor
.wantsXrayExpandoClass
806 CGThing
.__init
__(self
)
807 self
.descriptor
= descriptor
813 iface
= getReflectedHTMLAttributesIface(self
.descriptor
)
816 "&%s::ReflectedHTMLAttributeSlots::sXrayExpandoObjectClassOps"
817 % toBindingNamespace(iface
.identifier
.name
)
820 ops
= "&xpc::XrayExpandoObjectClassOps"
823 // This may allocate too many slots, because we only really need
824 // slots for our non-interface-typed members that we cache. But
825 // allocating slots only for those would make the slot index
826 // computations much more complicated, so let's do this the simple
828 DEFINE_XRAY_EXPANDO_CLASS_WITH_OPS(static, sXrayExpandoObjectClass, ${memberSlots},
831 memberSlots
=self
.descriptor
.interface
.totalMembersInSlots
,
836 def PrototypeIDAndDepth(descriptor
):
837 prototypeID
= "prototypes::id::"
838 if descriptor
.interface
.hasInterfacePrototypeObject():
839 prototypeID
+= descriptor
.interface
.identifier
.name
840 depth
= "PrototypeTraits<%s>::Depth" % prototypeID
842 prototypeID
+= "_ID_Count"
844 return (prototypeID
, depth
)
847 def InterfacePrototypeObjectProtoGetter(descriptor
):
849 Returns a tuple with two elements:
851 1) The name of the function to call to get the prototype to use for the
852 interface prototype object as a JSObject*.
854 2) The name of the function to call to get the prototype to use for the
855 interface prototype object as a JS::Handle<JSObject*> or None if no
856 such function exists.
858 parentProtoName
= descriptor
.parentPrototypeName
859 if descriptor
.hasNamedPropertiesObject
:
860 protoGetter
= "GetNamedPropertiesObject"
861 protoHandleGetter
= None
862 elif parentProtoName
is None:
863 protoHandleGetter
= None
864 if descriptor
.interface
.getExtendedAttribute("ExceptionClass"):
865 protoGetter
= "JS::GetRealmErrorPrototype"
866 elif descriptor
.interface
.isIteratorInterface():
867 protoGetter
= "JS::GetRealmIteratorPrototype"
868 elif descriptor
.interface
.isAsyncIteratorInterface():
869 protoGetter
= "JS::GetRealmAsyncIteratorPrototype"
871 protoGetter
= "JS::GetRealmObjectPrototype"
872 protoHandleGetter
= "JS::GetRealmObjectPrototypeHandle"
874 prefix
= toBindingNamespace(parentProtoName
)
875 protoGetter
= prefix
+ "::GetProtoObject"
876 protoHandleGetter
= prefix
+ "::GetProtoObjectHandle"
878 return (protoGetter
, protoHandleGetter
)
881 class CGPrototypeJSClass(CGThing
):
882 def __init__(self
, descriptor
, properties
):
883 CGThing
.__init
__(self
)
884 self
.descriptor
= descriptor
885 self
.properties
= properties
888 # We're purely for internal consumption
892 prototypeID
, depth
= PrototypeIDAndDepth(self
.descriptor
)
893 slotCount
= "DOM_INTERFACE_PROTO_SLOTS_BASE"
894 # Globals handle unforgeables directly in Wrap() instead of
897 self
.descriptor
.hasLegacyUnforgeableMembers
898 and not self
.descriptor
.isGlobal()
901 " + 1 /* slot for the JSObject holding the unforgeable properties */"
903 (protoGetter
, _
) = InterfacePrototypeObjectProtoGetter(self
.descriptor
)
905 "eGlobalInterfacePrototype"
906 if self
.descriptor
.isGlobal()
907 else "eInterfacePrototype"
911 static const DOMIfaceAndProtoJSClass sPrototypeClass = {
914 JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(${slotCount}),
927 name
=self
.descriptor
.interface
.getClassName(),
930 hooks
=NativePropertyHooks(self
.descriptor
),
931 prototypeID
=prototypeID
,
933 protoGetter
=protoGetter
,
937 def InterfaceObjectProtoGetter(descriptor
):
939 Returns the name of the function to call to get the prototype to use for the
940 interface object's prototype as a JS::Handle<JSObject*>.
942 assert not descriptor
.interface
.isNamespace()
943 parentInterface
= descriptor
.interface
.parent
945 parentIfaceName
= parentInterface
.identifier
.name
946 parentDesc
= descriptor
.getDescriptor(parentIfaceName
)
947 prefix
= toBindingNamespace(parentDesc
.name
)
948 protoHandleGetter
= prefix
+ "::GetConstructorObjectHandle"
950 protoHandleGetter
= "JS::GetRealmFunctionPrototypeHandle"
951 return protoHandleGetter
954 class CGNamespaceObjectJSClass(CGThing
):
955 def __init__(self
, descriptor
):
956 CGThing
.__init
__(self
)
957 self
.descriptor
= descriptor
960 # We're purely for internal consumption
964 classString
= self
.descriptor
.interface
.getExtendedAttribute("ClassString")
965 if classString
is None:
966 classString
= self
.descriptor
.interface
.identifier
.name
968 classString
= classString
[0]
971 static const DOMIfaceAndProtoJSClass sNamespaceObjectClass = {
974 JSCLASS_IS_DOMIFACEANDPROTOJSCLASS,
981 prototypes::id::_ID_Count,
984 // This isn't strictly following the spec (see
985 // https://console.spec.whatwg.org/#ref-for-dfn-namespace-object),
986 // but should be ok for Xrays.
987 JS::GetRealmObjectPrototype
990 classString
=classString
,
991 hooks
=NativePropertyHooks(self
.descriptor
),
995 class CGInterfaceObjectInfo(CGThing
):
996 def __init__(self
, descriptor
):
997 CGThing
.__init
__(self
)
998 self
.descriptor
= descriptor
1001 # We're purely for internal consumption
1005 if self
.descriptor
.interface
.ctor():
1006 ctorname
= CONSTRUCT_HOOK_NAME
1007 constructorArgs
= methodLength(self
.descriptor
.interface
.ctor())
1009 ctorname
= "ThrowingConstructor"
1011 constructorName
= self
.descriptor
.interface
.getClassName()
1012 wantsIsInstance
= self
.descriptor
.interface
.hasInterfacePrototypeObject()
1014 prototypeID
, depth
= PrototypeIDAndDepth(self
.descriptor
)
1015 protoHandleGetter
= InterfaceObjectProtoGetter(self
.descriptor
)
1019 static const DOMInterfaceInfo sInterfaceObjectInfo = {
1020 { ${ctorname}, ${hooks} },
1021 ${protoHandleGetter},
1026 "${constructorName}",
1030 hooks
=NativePropertyHooks(self
.descriptor
),
1031 protoHandleGetter
=protoHandleGetter
,
1033 prototypeID
=prototypeID
,
1034 wantsIsInstance
=toStringBool(wantsIsInstance
),
1035 constructorArgs
=constructorArgs
,
1036 constructorName
=constructorName
,
1040 class CGList(CGThing
):
1042 Generate code for a list of GCThings. Just concatenates them together, with
1043 an optional joiner string. "\n" is a common joiner.
1046 def __init__(self
, children
, joiner
=""):
1047 CGThing
.__init
__(self
)
1048 # Make a copy of the kids into a list, because if someone passes in a
1049 # generator we won't be able to both declare and define ourselves, or
1050 # define ourselves more than once!
1051 self
.children
= list(children
)
1052 self
.joiner
= joiner
1054 def append(self
, child
):
1055 self
.children
.append(child
)
1057 def prepend(self
, child
):
1058 self
.children
.insert(0, child
)
1060 def extend(self
, kids
):
1061 self
.children
.extend(kids
)
1063 def join(self
, iterable
):
1064 return self
.joiner
.join(s
for s
in iterable
if len(s
) > 0)
1068 child
.declare() for child
in self
.children
if child
is not None
1072 return self
.join(child
.define() for child
in self
.children
if child
is not None)
1076 for child
in self
.children
:
1079 deps
= deps
.union(child
.deps())
1083 return len(self
.children
)
1086 class CGGeneric(CGThing
):
1088 A class that spits out a fixed string into the codegen. Can spit out a
1089 separate string for the declaration too.
1092 def __init__(self
, define
="", declare
=""):
1093 self
.declareText
= declare
1094 self
.defineText
= define
1097 return self
.declareText
1100 return self
.defineText
1106 class CGIndenter(CGThing
):
1108 A class that takes another CGThing and generates code that indents that
1109 CGThing by some number of spaces. The default indent is two spaces.
1112 def __init__(self
, child
, indentLevel
=2, declareOnly
=False):
1113 assert isinstance(child
, CGThing
)
1114 CGThing
.__init
__(self
)
1116 self
.indentLevel
= indentLevel
1117 self
.declareOnly
= declareOnly
1120 return indent(self
.child
.declare(), self
.indentLevel
)
1123 defn
= self
.child
.define()
1124 if self
.declareOnly
:
1127 return indent(defn
, self
.indentLevel
)
1130 class CGWrapper(CGThing
):
1132 Generic CGThing that wraps other CGThings with pre and post text.
1148 CGThing
.__init
__(self
)
1150 self
.declarePre
= declarePre
or pre
1151 self
.declarePost
= declarePost
or post
1152 self
.definePre
= definePre
or pre
1153 self
.definePost
= definePost
or post
1154 self
.declareOnly
= declareOnly
1155 self
.defineOnly
= defineOnly
1156 self
.reindent
= reindent
1161 decl
= self
.child
.declare()
1163 decl
= self
.reindentString(decl
, self
.declarePre
)
1164 return self
.declarePre
+ decl
+ self
.declarePost
1167 if self
.declareOnly
:
1169 defn
= self
.child
.define()
1171 defn
= self
.reindentString(defn
, self
.definePre
)
1172 return self
.definePre
+ defn
+ self
.definePost
1175 def reindentString(stringToIndent
, widthString
):
1176 # We don't use lineStartDetector because we don't want to
1177 # insert whitespace at the beginning of our _first_ line.
1178 # Use the length of the last line of width string, in case
1179 # it is a multiline string.
1180 lastLineWidth
= len(widthString
.splitlines()[-1])
1181 return stripTrailingWhitespace(
1182 stringToIndent
.replace("\n", "\n" + (" " * lastLineWidth
))
1186 return self
.child
.deps()
1189 class CGIfWrapper(CGList
):
1190 def __init__(self
, child
, condition
):
1195 CGGeneric(condition
), pre
="if (", post
=") {\n", reindent
=True
1203 class CGIfElseWrapper(CGList
):
1204 def __init__(self
, condition
, ifTrue
, ifFalse
):
1209 CGGeneric(condition
), pre
="if (", post
=") {\n", reindent
=True
1212 CGGeneric("} else {\n"),
1213 CGIndenter(ifFalse
),
1219 class CGElseChain(CGThing
):
1221 Concatenate if statements in an if-else-if-else chain.
1224 def __init__(self
, children
):
1225 self
.children
= [c
for c
in children
if c
is not None]
1231 if not self
.children
:
1233 s
= self
.children
[0].define()
1234 assert s
.endswith("\n")
1235 for child
in self
.children
[1:]:
1236 code
= child
.define()
1237 assert code
.startswith("if") or code
.startswith("{")
1238 assert code
.endswith("\n")
1239 s
= s
.rstrip() + " else " + code
1243 class CGTemplatedType(CGWrapper
):
1244 def __init__(self
, templateName
, child
, isConst
=False, isReference
=False):
1245 if isinstance(child
, list):
1246 child
= CGList(child
, ", ")
1247 const
= "const " if isConst
else ""
1248 pre
= "%s%s<" % (const
, templateName
)
1249 ref
= "&" if isReference
else ""
1251 CGWrapper
.__init
__(self
, child
, pre
=pre
, post
=post
)
1254 class CGNamespace(CGThing
):
1256 Generates namespace block that wraps other CGThings.
1259 def __init__(self
, namespace
, child
):
1260 CGThing
.__init
__(self
)
1262 self
.pre
= "namespace %s {\n" % namespace
1263 self
.post
= "} // namespace %s\n" % namespace
1266 decl
= self
.child
.declare()
1267 if len(decl
.strip()) == 0:
1269 return self
.pre
+ decl
+ self
.post
1272 defn
= self
.child
.define()
1273 if len(defn
.strip()) == 0:
1275 return self
.pre
+ defn
+ self
.post
1278 return self
.child
.deps()
1281 def build(namespaces
, child
):
1283 Static helper method to build multiple wrapped namespaces.
1286 return CGWrapper(child
)
1287 return CGNamespace("::".join(namespaces
), child
)
1290 class CGIncludeGuard(CGWrapper
):
1292 Generates include guards for a header.
1295 def __init__(self
, prefix
, child
):
1296 """|prefix| is the filename without the extension."""
1297 define
= "DOM_%s_H_" % prefix
.upper()
1301 declarePre
="#ifndef %s\n#define %s\n\n" % (define
, define
),
1302 declarePost
="\n#endif // %s\n" % define
,
1306 class CGHeaders(CGWrapper
):
1308 Generates the appropriate include statements.
1316 callbackDescriptors
,
1322 jsImplementedDescriptors
=[],
1325 Builds a set of includes to cover |descriptors|.
1327 Also includes the files in |declareIncludes| in the header
1328 file and the files in |defineIncludes| in the .cpp.
1330 |prefix| contains the basename of the file that we generate include
1334 # Determine the filenames for which we need headers.
1335 interfaceDeps
= [d
.interface
for d
in descriptors
]
1337 for iface
in interfaceDeps
:
1339 # We're going to need our parent's prototype, to use as the
1340 # prototype of our prototype object.
1341 ancestors
.append(iface
.parent
)
1342 # And if we have an interface object, we'll need the nearest
1343 # ancestor with an interface object too, so we can use its
1344 # interface object as the proto of our interface object.
1345 if iface
.hasInterfaceObject():
1346 parent
= iface
.parent
1347 while parent
and not parent
.hasInterfaceObject():
1348 parent
= parent
.parent
1350 ancestors
.append(parent
)
1351 interfaceDeps
.extend(ancestors
)
1353 # Include parent interface headers needed for default toJSON code.
1354 jsonInterfaceParents
= []
1355 for desc
in descriptors
:
1356 if not desc
.hasDefaultToJSON
:
1358 parent
= desc
.interface
.parent
1360 parentDesc
= desc
.getDescriptor(parent
.identifier
.name
)
1361 if parentDesc
.hasDefaultToJSON
:
1362 jsonInterfaceParents
.append(parentDesc
.interface
)
1363 parent
= parent
.parent
1364 interfaceDeps
.extend(jsonInterfaceParents
)
1366 bindingIncludes
= set(self
.getDeclarationFilename(d
) for d
in interfaceDeps
)
1368 # Grab all the implementation declaration files we need.
1369 implementationIncludes
= set(
1370 d
.headerFile
for d
in descriptors
if d
.needsHeaderInclude()
1373 # Now find all the things we'll need as arguments because we
1374 # need to wrap or unwrap them.
1375 bindingHeaders
= set()
1376 declareIncludes
= set(declareIncludes
)
1378 def addHeadersForType(typeAndPossibleOriginType
):
1380 Add the relevant headers for this type. We use its origin type, if
1381 passed, to decide what to do with interface types.
1383 t
, originType
= typeAndPossibleOriginType
1384 isFromDictionary
= originType
and originType
.isDictionary()
1385 isFromCallback
= originType
and originType
.isCallback()
1386 # Dictionaries have members that need to be actually
1387 # declared, not just forward-declared.
1388 # Callbacks have nullable union arguments that need to be actually
1389 # declared, not just forward-declared.
1390 if isFromDictionary
:
1391 headerSet
= declareIncludes
1392 elif isFromCallback
and t
.nullable() and t
.isUnion():
1393 headerSet
= declareIncludes
1395 headerSet
= bindingHeaders
1396 # Strip off outer layers and add headers they might require. (This
1397 # is conservative: only nullable non-pointer types need Nullable.h;
1398 # only sequences or observable arrays outside unions need
1399 # ForOfIterator.h; only functions that return, and attributes that
1400 # are, sequences or observable arrays in interfaces need Array.h, &c.)
1403 if idlTypeNeedsCallContext(unrolled
):
1404 bindingHeaders
.add("mozilla/dom/BindingCallContext.h")
1405 if unrolled
.nullable():
1406 headerSet
.add("mozilla/dom/Nullable.h")
1407 elif unrolled
.isSequence() or unrolled
.isObservableArray():
1408 bindingHeaders
.add("js/Array.h")
1409 bindingHeaders
.add("js/ForOfIterator.h")
1410 if unrolled
.isObservableArray():
1411 bindingHeaders
.add("mozilla/dom/ObservableArrayProxyHandler.h")
1414 unrolled
= unrolled
.inner
1415 if unrolled
.isUnion():
1416 headerSet
.add(self
.getUnionDeclarationFilename(config
, unrolled
))
1417 for t
in unrolled
.flatMemberTypes
:
1418 addHeadersForType((t
, None))
1419 elif unrolled
.isPromise():
1420 # See comment in the isInterface() case for why we add
1421 # Promise.h to headerSet, not bindingHeaders.
1422 headerSet
.add("mozilla/dom/Promise.h")
1423 # We need ToJSValue to do the Promise to JS conversion.
1424 bindingHeaders
.add("mozilla/dom/ToJSValue.h")
1425 elif unrolled
.isInterface():
1426 if unrolled
.isSpiderMonkeyInterface():
1427 bindingHeaders
.add("jsfriendapi.h")
1428 if jsImplementedDescriptors
:
1429 # Since we can't forward-declare typed array types
1430 # (because they're typedefs), we have to go ahead and
1431 # just include their header if we need to have functions
1432 # taking references to them declared in that header.
1433 headerSet
= declareIncludes
1434 headerSet
.add("mozilla/dom/TypedArray.h")
1437 typeDesc
= config
.getDescriptor(unrolled
.inner
.identifier
.name
)
1438 except NoSuchDescriptorError
:
1440 # Dictionaries with interface members rely on the
1441 # actual class definition of that interface member
1442 # being visible in the binding header, because they
1443 # store them in RefPtr and have inline
1444 # constructors/destructors.
1446 # XXXbz maybe dictionaries with interface members
1447 # should just have out-of-line constructors and
1449 headerSet
.add(typeDesc
.headerFile
)
1450 elif unrolled
.isDictionary():
1451 headerSet
.add(self
.getDeclarationFilename(unrolled
.inner
))
1452 # And if it needs rooting, we need RootedDictionary too
1453 if typeNeedsRooting(unrolled
):
1454 headerSet
.add("mozilla/dom/RootedDictionary.h")
1455 elif unrolled
.isCallback():
1456 headerSet
.add(self
.getDeclarationFilename(unrolled
.callback
))
1457 elif unrolled
.isFloat() and not unrolled
.isUnrestricted():
1458 # Restricted floats are tested for finiteness
1459 bindingHeaders
.add("mozilla/FloatingPoint.h")
1460 bindingHeaders
.add("mozilla/dom/PrimitiveConversions.h")
1461 elif unrolled
.isEnum():
1462 filename
= self
.getDeclarationFilename(unrolled
.inner
)
1463 declareIncludes
.add(filename
)
1464 elif unrolled
.isPrimitive():
1465 bindingHeaders
.add("mozilla/dom/PrimitiveConversions.h")
1466 elif unrolled
.isRecord():
1467 if isFromDictionary
or jsImplementedDescriptors
:
1468 declareIncludes
.add("mozilla/dom/Record.h")
1470 bindingHeaders
.add("mozilla/dom/Record.h")
1471 # Also add headers for the type the record is
1472 # parametrized over, if needed.
1473 addHeadersForType((t
.inner
, originType
if isFromDictionary
else None))
1475 for t
in getAllTypes(
1476 descriptors
+ callbackDescriptors
, dictionaries
, callbacks
1478 addHeadersForType(t
)
1480 def addHeaderForFunc(func
, desc
):
1483 # Include the right class header, which we can only do
1484 # if this is a class member function.
1485 if desc
is not None and not desc
.headerIsDefault
:
1486 # An explicit header file was provided, assume that we know
1491 # Strip out the function name and convert "::" to "/"
1492 bindingHeaders
.add("/".join(func
.split("::")[:-1]) + ".h")
1494 # Now for non-callback descriptors make sure we include any
1495 # headers needed by Func declarations and other things like that.
1496 for desc
in descriptors
:
1497 # If this is an iterator or an async iterator interface generated
1498 # for a separate iterable interface, skip generating type includes,
1499 # as we have what we need in IterableIterator.h
1501 desc
.interface
.isIteratorInterface()
1502 or desc
.interface
.isAsyncIteratorInterface()
1506 for m
in desc
.interface
.members
:
1507 addHeaderForFunc(PropertyDefiner
.getStringAttr(m
, "Func"), desc
)
1508 staticTypeOverride
= PropertyDefiner
.getStringAttr(
1509 m
, "StaticClassOverride"
1511 if staticTypeOverride
:
1512 bindingHeaders
.add("/".join(staticTypeOverride
.split("::")) + ".h")
1513 # getExtendedAttribute() returns a list, extract the entry.
1514 funcList
= desc
.interface
.getExtendedAttribute("Func")
1515 if funcList
is not None:
1516 addHeaderForFunc(funcList
[0], desc
)
1518 if desc
.interface
.maplikeOrSetlikeOrIterable
:
1519 # We need ToJSValue.h for maplike/setlike type conversions
1520 bindingHeaders
.add("mozilla/dom/ToJSValue.h")
1521 # Add headers for the key and value types of the
1522 # maplike/setlike/iterable, since they'll be needed for
1523 # convenience functions
1524 if desc
.interface
.maplikeOrSetlikeOrIterable
.hasKeyType():
1526 (desc
.interface
.maplikeOrSetlikeOrIterable
.keyType
, None)
1528 if desc
.interface
.maplikeOrSetlikeOrIterable
.hasValueType():
1530 (desc
.interface
.maplikeOrSetlikeOrIterable
.valueType
, None)
1533 for d
in dictionaries
:
1535 declareIncludes
.add(self
.getDeclarationFilename(d
.parent
))
1536 bindingHeaders
.add(self
.getDeclarationFilename(d
))
1538 addHeaderForFunc(PropertyDefiner
.getStringAttr(m
, "Func"), None)
1539 # No need to worry about Func on members of ancestors, because that
1540 # will happen automatically in whatever files those ancestors live
1544 bindingHeaders
.add(self
.getDeclarationFilename(c
))
1546 for c
in callbackDescriptors
:
1547 bindingHeaders
.add(self
.getDeclarationFilename(c
.interface
))
1549 if len(callbacks
) != 0:
1550 # We need CallbackFunction to serve as our parent class
1551 declareIncludes
.add("mozilla/dom/CallbackFunction.h")
1552 # And we need ToJSValue.h so we can wrap "this" objects
1553 declareIncludes
.add("mozilla/dom/ToJSValue.h")
1555 if len(callbackDescriptors
) != 0 or len(jsImplementedDescriptors
) != 0:
1556 # We need CallbackInterface to serve as our parent class
1557 declareIncludes
.add("mozilla/dom/CallbackInterface.h")
1558 # And we need ToJSValue.h so we can wrap "this" objects
1559 declareIncludes
.add("mozilla/dom/ToJSValue.h")
1561 # Also need to include the headers for ancestors of
1562 # JS-implemented interfaces.
1563 for jsImplemented
in jsImplementedDescriptors
:
1564 jsParent
= jsImplemented
.interface
.parent
1566 parentDesc
= jsImplemented
.getDescriptor(jsParent
.identifier
.name
)
1567 declareIncludes
.add(parentDesc
.jsImplParentHeader
)
1569 # Now make sure we're not trying to include the header from inside itself
1570 declareIncludes
.discard(prefix
+ ".h")
1572 # Let the machinery do its thing.
1573 def _includeString(includes
):
1574 def headerName(include
):
1575 # System headers are specified inside angle brackets.
1576 if include
.startswith("<"):
1578 # Non-system headers need to be placed in quotes.
1579 return '"%s"' % include
1581 return "".join(["#include %s\n" % headerName(i
) for i
in includes
]) + "\n"
1586 declarePre
=_includeString(sorted(declareIncludes
)),
1587 definePre
=_includeString(
1592 | implementationIncludes
1598 def getDeclarationFilename(decl
):
1599 # Use our local version of the header, not the exported one, so that
1600 # test bindings, which don't export, will work correctly.
1601 basename
= os
.path
.basename(decl
.filename
)
1602 return basename
.replace(".webidl", "Binding.h")
1605 def getUnionDeclarationFilename(config
, unionType
):
1606 assert unionType
.isUnion()
1607 assert unionType
.unroll() == unionType
1608 # If a union is "defined" in multiple files, it goes in UnionTypes.h.
1609 if len(config
.filenamesPerUnion
[unionType
.name
]) > 1:
1610 return "mozilla/dom/UnionTypes.h"
1611 # If a union is defined by a built-in typedef, it also goes in
1613 assert len(config
.filenamesPerUnion
[unionType
.name
]) == 1
1614 if "<unknown>" in config
.filenamesPerUnion
[unionType
.name
]:
1615 return "mozilla/dom/UnionTypes.h"
1616 return CGHeaders
.getDeclarationFilename(unionType
)
1619 def SortedDictValues(d
):
1621 Returns a list of values from the dict sorted by key.
1623 return [v
for k
, v
in sorted(d
.items())]
1626 def UnionsForFile(config
, webIDLFile
):
1628 Returns a list of union types for all union types that are only used in
1629 webIDLFile. If webIDLFile is None this will return the list of tuples for
1630 union types that are used in more than one WebIDL file.
1632 return config
.unionsPerFilename
.get(webIDLFile
, [])
1635 def UnionTypes(unionTypes
, config
):
1637 The unionTypes argument should be a list of union types. This is typically
1638 the list generated by UnionsForFile.
1640 Returns a tuple containing a set of header filenames to include in
1641 the header for the types in unionTypes, a set of header filenames to
1642 include in the implementation file for the types in unionTypes, a set
1643 of tuples containing a type declaration and a boolean if the type is a
1644 struct for member types of the union, a list of traverse methods,
1645 unlink methods and a list of union types. These last three lists only
1646 contain unique union types.
1651 declarations
= set()
1652 unionStructs
= dict()
1653 traverseMethods
= dict()
1654 unlinkMethods
= dict()
1656 for t
in unionTypes
:
1658 if name
not in unionStructs
:
1659 unionStructs
[name
] = t
1661 def addHeadersForType(f
):
1663 headers
.add("mozilla/dom/Nullable.h")
1664 isSequence
= f
.isSequence()
1666 # Dealing with sequences requires for-of-compatible
1668 implheaders
.add("js/ForOfIterator.h")
1669 # Sequences can always throw "not an object" exceptions.
1670 implheaders
.add("mozilla/dom/BindingCallContext.h")
1671 if typeNeedsRooting(f
):
1672 headers
.add("mozilla/dom/RootedSequence.h")
1674 if idlTypeNeedsCallContext(f
):
1675 implheaders
.add("mozilla/dom/BindingCallContext.h")
1677 headers
.add("mozilla/dom/Promise.h")
1678 # We need ToJSValue to do the Promise to JS conversion.
1679 headers
.add("mozilla/dom/ToJSValue.h")
1680 elif f
.isInterface():
1681 if f
.isSpiderMonkeyInterface():
1682 headers
.add("js/RootingAPI.h")
1683 headers
.add("js/Value.h")
1684 headers
.add("mozilla/dom/TypedArray.h")
1687 typeDesc
= config
.getDescriptor(f
.inner
.identifier
.name
)
1688 except NoSuchDescriptorError
:
1690 if typeDesc
.interface
.isCallback() or isSequence
:
1691 # Callback interfaces always use strong refs, so
1692 # we need to include the right header to be able
1693 # to Release() in our inlined code.
1695 # Similarly, sequences always contain strong
1696 # refs, so we'll need the header to handler
1698 headers
.add(typeDesc
.headerFile
)
1699 elif typeDesc
.interface
.identifier
.name
== "WindowProxy":
1700 # In UnionTypes.h we need to see the declaration of the
1701 # WindowProxyHolder that we use to store the WindowProxy, so
1702 # we have its sizeof and know how big to make our union.
1703 headers
.add(typeDesc
.headerFile
)
1705 declarations
.add((typeDesc
.nativeType
, False))
1706 implheaders
.add(typeDesc
.headerFile
)
1707 elif f
.isDictionary():
1708 # For a dictionary, we need to see its declaration in
1709 # UnionTypes.h so we have its sizeof and know how big to
1711 headers
.add(CGHeaders
.getDeclarationFilename(f
.inner
))
1712 # And if it needs rooting, we need RootedDictionary too
1713 if typeNeedsRooting(f
):
1714 headers
.add("mozilla/dom/RootedDictionary.h")
1715 elif f
.isFloat() and not f
.isUnrestricted():
1716 # Restricted floats are tested for finiteness
1717 implheaders
.add("mozilla/FloatingPoint.h")
1718 implheaders
.add("mozilla/dom/PrimitiveConversions.h")
1720 # Need to see the actual definition of the enum,
1722 headers
.add(CGHeaders
.getDeclarationFilename(f
.inner
))
1723 elif f
.isPrimitive():
1724 implheaders
.add("mozilla/dom/PrimitiveConversions.h")
1725 elif f
.isCallback():
1726 # Callbacks always use strong refs, so we need to include
1727 # the right header to be able to Release() in our inlined
1729 headers
.add(CGHeaders
.getDeclarationFilename(f
.callback
))
1731 headers
.add("mozilla/dom/Record.h")
1732 # And add headers for the type we're parametrized over
1733 addHeadersForType(f
.inner
)
1734 # And if it needs rooting, we need RootedRecord too
1735 if typeNeedsRooting(f
):
1736 headers
.add("mozilla/dom/RootedRecord.h")
1738 implheaders
.add(CGHeaders
.getUnionDeclarationFilename(config
, t
))
1739 for f
in t
.flatMemberTypes
:
1740 assert not f
.nullable()
1741 addHeadersForType(f
)
1743 if idlTypeNeedsCycleCollection(t
):
1745 ("mozilla::dom::%s" % CGUnionStruct
.unionTypeName(t
, True), False)
1747 traverseMethods
[name
] = CGCycleCollectionTraverseForOwningUnionMethod(t
)
1748 unlinkMethods
[name
] = CGCycleCollectionUnlinkForOwningUnionMethod(t
)
1750 # The order of items in CGList is important.
1751 # Since the union structs friend the unlinkMethods, the forward-declaration
1752 # for these methods should come before the class declaration. Otherwise
1753 # some compilers treat the friend declaration as a forward-declaration in
1759 SortedDictValues(traverseMethods
),
1760 SortedDictValues(unlinkMethods
),
1761 SortedDictValues(unionStructs
),
1767 A class for outputting the type and name of an argument
1770 def __init__(self
, argType
, name
, default
=None):
1771 self
.argType
= argType
1773 self
.default
= default
1776 string
= self
.argType
+ " " + self
.name
1777 if self
.default
is not None:
1778 string
+= " = " + self
.default
1782 return self
.argType
+ " " + self
.name
1785 class CGAbstractMethod(CGThing
):
1787 An abstract class for generating code for a method. Subclasses
1788 should override definition_body to create the actual code.
1790 descriptor is the descriptor for the interface the method is associated with
1792 name is the name of the method as a string
1794 returnType is the IDLType of the return value
1796 args is a list of Argument objects
1798 inline should be True to generate an inline method, whose body is
1799 part of the declaration.
1801 alwaysInline should be True to generate an inline method annotated with
1804 static should be True to generate a static method, which only has
1807 If templateArgs is not None it should be a list of strings containing
1808 template arguments, and the function will be templatized using those
1811 canRunScript should be True to generate a MOZ_CAN_RUN_SCRIPT annotation.
1813 signatureOnly should be True to only declare the signature (either in
1814 the header, or if static is True in the cpp file).
1828 signatureOnly
=False,
1830 CGThing
.__init
__(self
)
1831 self
.descriptor
= descriptor
1833 self
.returnType
= returnType
1835 self
.inline
= inline
1836 self
.alwaysInline
= alwaysInline
1837 self
.static
= static
1838 self
.templateArgs
= templateArgs
1839 self
.canRunScript
= canRunScript
1840 self
.signatureOnly
= signatureOnly
1842 def _argstring(self
, declare
):
1843 return ", ".join([a
.declare() if declare
else a
.define() for a
in self
.args
])
1845 def _template(self
):
1846 if self
.templateArgs
is None:
1848 return "template <%s>\n" % ", ".join(self
.templateArgs
)
1850 def _decorators(self
):
1852 if self
.canRunScript
:
1853 decorators
.append("MOZ_CAN_RUN_SCRIPT")
1854 if self
.alwaysInline
:
1855 decorators
.append("MOZ_ALWAYS_INLINE")
1857 decorators
.append("inline")
1859 decorators
.append("static")
1860 decorators
.append(self
.returnType
)
1861 maybeNewline
= " " if self
.inline
else "\n"
1862 return " ".join(decorators
) + maybeNewline
1864 def signature(self
):
1865 return "%s%s%s(%s);\n" % (
1869 self
._argstring
(True),
1876 return self
._define
(True)
1877 return self
.signature()
1879 def indent_body(self
, body
):
1881 Indent the code returned by self.definition_body(). Most classes
1882 simply indent everything two spaces. This is here for
1883 CGRegisterProtos, which needs custom indentation.
1887 def _define(self
, fromDeclare
=False):
1889 self
.definition_prologue(fromDeclare
)
1890 + self
.indent_body(self
.definition_body())
1891 + self
.definition_epilogue()
1895 if self
.signatureOnly
:
1897 # self.static makes us not output anything in the header, so output the signature here.
1898 return self
.signature()
1900 return "" if (self
.inline
and not self
.static
) else self
._define
()
1902 def definition_prologue(self
, fromDeclare
):
1903 error_reporting_label
= self
.error_reporting_label()
1904 if error_reporting_label
:
1905 # We're going to want a BindingCallContext. Rename our JSContext*
1908 while i
< len(self
.args
):
1910 if arg
.argType
== "JSContext*":
1912 self
.args
[i
] = Argument(arg
.argType
, "cx_", arg
.default
)
1915 if i
== len(self
.args
):
1916 raise TypeError("Must have a JSContext* to create a BindingCallContext")
1918 prologue
= "%s%s%s(%s)\n{\n" % (
1922 self
._argstring
(fromDeclare
),
1924 if error_reporting_label
:
1928 BindingCallContext ${cxname}(cx_, ${label});
1931 label
=error_reporting_label
,
1935 profiler_label
= self
.auto_profiler_label()
1937 prologue
+= indent(profiler_label
) + "\n"
1941 def definition_epilogue(self
):
1944 def definition_body(self
):
1945 assert False # Override me!
1948 Override this method to return a pair of (descriptive string, name of a
1949 JSContext* variable) in order to generate a profiler label for this method.
1952 def auto_profiler_label(self
):
1953 return None # Override me!
1956 Override this method to return a string to be used as the label for a
1957 BindingCallContext. If this does not return None, one of the arguments of
1958 this method must be of type 'JSContext*'. Its name will be replaced with
1959 'cx_' and a BindingCallContext named 'cx' will be instantiated with the
1963 def error_reporting_label(self
):
1964 return None # Override me!
1967 class CGAbstractStaticMethod(CGAbstractMethod
):
1969 Abstract base class for codegen of implementation-only (no
1970 declaration) static methods.
1973 def __init__(self
, descriptor
, name
, returnType
, args
, canRunScript
=False):
1974 CGAbstractMethod
.__init
__(
1982 canRunScript
=canRunScript
,
1986 class CGAbstractClassHook(CGAbstractStaticMethod
):
1988 Meant for implementing JSClass hooks, like Finalize or Trace. Does very raw
1989 'this' unwrapping as it assumes that the unwrapped type is always known.
1992 def __init__(self
, descriptor
, name
, returnType
, args
):
1993 CGAbstractStaticMethod
.__init
__(self
, descriptor
, name
, returnType
, args
)
1995 def definition_body_prologue(self
):
1996 return "%s* self = UnwrapPossiblyNotInitializedDOMObject<%s>(obj);\n" % (
1997 self
.descriptor
.nativeType
,
1998 self
.descriptor
.nativeType
,
2001 def definition_body(self
):
2002 return self
.definition_body_prologue() + self
.generate_code()
2004 def generate_code(self
):
2005 assert False # Override me!
2008 class CGAddPropertyHook(CGAbstractClassHook
):
2010 A hook for addProperty, used to preserve our wrapper from GC.
2013 def __init__(self
, descriptor
):
2015 Argument("JSContext*", "cx"),
2016 Argument("JS::Handle<JSObject*>", "obj"),
2017 Argument("JS::Handle<jsid>", "id"),
2018 Argument("JS::Handle<JS::Value>", "val"),
2020 CGAbstractClassHook
.__init
__(
2021 self
, descriptor
, ADDPROPERTY_HOOK_NAME
, "bool", args
2024 def generate_code(self
):
2025 assert self
.descriptor
.wrapperCache
2026 # This hook is also called by TryPreserveWrapper on non-nsISupports
2027 # cycle collected objects, so if addProperty is ever changed to do
2028 # anything more or less than preserve the wrapper, TryPreserveWrapper
2029 # will need to be changed.
2032 // We don't want to preserve if we don't have a wrapper, and we
2033 // obviously can't preserve if we're not initialized.
2034 if (self && self->GetWrapperPreserveColor()) {
2035 PreserveWrapper(self);
2042 class CGGetWrapperCacheHook(CGAbstractClassHook
):
2044 A hook for GetWrapperCache, used by HasReleasedWrapper to get the
2045 nsWrapperCache pointer for a non-nsISupports object.
2048 def __init__(self
, descriptor
):
2049 args
= [Argument("JS::Handle<JSObject*>", "obj")]
2050 CGAbstractClassHook
.__init
__(
2051 self
, descriptor
, GETWRAPPERCACHE_HOOK_NAME
, "nsWrapperCache*", args
2054 def generate_code(self
):
2055 assert self
.descriptor
.wrapperCache
2063 class CGDefineHTMLAttributeSlots(CGThing
):
2065 Function to get the slots object for reflected HTML attributes that return
2066 a FrozenArray<Element> value.
2069 def __init__(self
, descriptor
):
2070 self
.descriptor
= descriptor
2071 CGThing
.__init
__(self
)
2074 atts
= self
.descriptor
.interface
.reflectedHTMLAttributesReturningFrozenArray
2077 using ReflectedHTMLAttributeSlots = binding_detail::ReflectedHTMLAttributeSlots<${slotIndex}, ${xraySlotIndex}, ${arrayLength}>;
2079 slotIndex
=reservedSlot(atts
.slotIndex
, False),
2080 xraySlotIndex
=reservedSlot(atts
.slotIndex
, True),
2081 arrayLength
=atts
.totalMembersInSlots
,
2088 def finalizeHook(descriptor
, hookName
, gcx
, obj
):
2089 finalize
= "JS::SetReservedSlot(%s, DOM_OBJECT_SLOT, JS::UndefinedValue());\n" % obj
2090 if descriptor
.interface
.getExtendedAttribute("LegacyOverrideBuiltIns"):
2093 // Either our proxy created an expando object or not. If it did,
2094 // then we would have preserved ourselves, and hence if we're going
2095 // away so is our C++ object and we should reset its expando value.
2096 // It's possible that in this situation the C++ object's reflector
2097 // pointer has been nulled out, but if not it's pointing to us. If
2098 // our proxy did _not_ create an expando object then it's possible
2099 // that we're no longer the reflector for our C++ object (and
2100 // incremental finalization is finally getting to us), and that in
2101 // the meantime the new reflector has created an expando object.
2102 // In that case we do NOT want to clear the expando pointer in the
2105 // It's important to do this before we ClearWrapper, of course.
2106 JSObject* reflector = self->GetWrapperMaybeDead();
2107 if (!reflector || reflector == ${obj}) {
2108 self->mExpandoAndGeneration.expando = JS::UndefinedValue();
2113 for m
in descriptor
.interface
.members
:
2114 if m
.isAttr() and m
.type.isObservableArray():
2118 JS::Value val = JS::GetReservedSlot(obj, ${slot});
2119 if (!val.isUndefined()) {
2120 JSObject* obj = &val.toObject();
2121 js::SetProxyReservedSlot(obj, OBSERVABLE_ARRAY_DOM_INTERFACE_SLOT, JS::UndefinedValue());
2125 slot
=memberReservedSlot(m
, descriptor
),
2127 iface
= getReflectedHTMLAttributesIface(descriptor
)
2129 finalize
+= "%s::ReflectedHTMLAttributeSlots::Finalize(%s);\n" % (
2130 toBindingNamespace(iface
.identifier
.name
),
2133 if descriptor
.wrapperCache
:
2134 finalize
+= "ClearWrapper(self, self, %s);\n" % obj
2135 if descriptor
.isGlobal():
2136 finalize
+= "mozilla::dom::FinalizeGlobal(%s, %s);\n" % (gcx
, obj
)
2139 if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) {
2140 JS::RemoveAssociatedMemory(${obj}, mallocBytes,
2141 JS::MemoryUse::DOMBinding);
2146 finalize
+= "AddForDeferredFinalization<%s>(self);\n" % descriptor
.nativeType
2147 return CGIfWrapper(CGGeneric(finalize
), "self")
2150 class CGClassFinalizeHook(CGAbstractClassHook
):
2152 A hook for finalize, used to release our native object.
2155 def __init__(self
, descriptor
):
2156 args
= [Argument("JS::GCContext*", "gcx"), Argument("JSObject*", "obj")]
2157 CGAbstractClassHook
.__init
__(self
, descriptor
, FINALIZE_HOOK_NAME
, "void", args
)
2159 def generate_code(self
):
2160 return finalizeHook(
2161 self
.descriptor
, self
.name
, self
.args
[0].name
, self
.args
[1].name
2165 def objectMovedHook(descriptor
, hookName
, obj
, old
):
2166 assert descriptor
.wrapperCache
2170 UpdateWrapper(self, self, ${obj}, ${old});
2180 class CGClassObjectMovedHook(CGAbstractClassHook
):
2182 A hook for objectMovedOp, used to update the wrapper cache when an object it
2186 def __init__(self
, descriptor
):
2187 args
= [Argument("JSObject*", "obj"), Argument("JSObject*", "old")]
2188 CGAbstractClassHook
.__init
__(
2189 self
, descriptor
, OBJECT_MOVED_HOOK_NAME
, "size_t", args
2192 def generate_code(self
):
2193 return objectMovedHook(
2194 self
.descriptor
, self
.name
, self
.args
[0].name
, self
.args
[1].name
2198 def JSNativeArguments():
2200 Argument("JSContext*", "cx"),
2201 Argument("unsigned", "argc"),
2202 Argument("JS::Value*", "vp"),
2206 class CGClassConstructor(CGAbstractStaticMethod
):
2208 JS-visible constructor for our objects
2211 def __init__(self
, descriptor
, ctor
, name
=CONSTRUCT_HOOK_NAME
):
2212 CGAbstractStaticMethod
.__init
__(
2213 self
, descriptor
, name
, "bool", JSNativeArguments()
2220 return CGAbstractStaticMethod
.define(self
)
2222 def definition_body(self
):
2223 return self
.generate_code()
2225 def generate_code(self
):
2226 if self
._ctor
.isHTMLConstructor():
2227 # We better have a prototype object. Otherwise our proto
2228 # id won't make sense.
2229 assert self
.descriptor
.interface
.hasInterfacePrototypeObject()
2230 # We also better have a constructor object, if this is
2232 assert self
.descriptor
.interface
.hasInterfaceObject()
2233 # We can't just pass null for the CreateInterfaceObjects callback,
2234 # because our newTarget might be in a different compartment, in
2235 # which case we'll need to look up constructor objects in that
2239 return HTMLConstructor(cx, argc, vp,
2240 constructors::id::${name},
2241 prototypes::id::${name},
2242 CreateInterfaceObjects);
2244 name
=self
.descriptor
.name
,
2247 # If the interface is already SecureContext, notify getConditionList to skip that check,
2248 # because the constructor won't be exposed in non-secure contexts to start with.
2249 alreadySecureContext
= self
.descriptor
.interface
.getExtendedAttribute(
2253 # We want to throw if any of the conditions returned by getConditionList are false.
2254 conditionsCheck
= ""
2255 rawConditions
= getRawConditionList(
2256 self
._ctor
, "cx", "obj", alreadySecureContext
2258 if len(rawConditions
) > 0:
2259 notConditions
= " ||\n".join("!" + cond
for cond
in rawConditions
)
2260 failedCheckAction
= CGGeneric("return ThrowingConstructor(cx, argc, vp);\n")
2262 CGIfWrapper(failedCheckAction
, notConditions
).define() + "\n"
2265 # Additionally, we want to throw if a caller does a bareword invocation
2266 # of a constructor without |new|.
2267 ctorName
= GetConstructorNameForReporting(self
.descriptor
, self
._ctor
)
2271 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
2272 JS::Rooted<JSObject*> obj(cx, &args.callee());
2274 if (!args.isConstructing()) {
2275 return ThrowConstructorWithoutNew(cx, "${ctorName}");
2278 JS::Rooted<JSObject*> desiredProto(cx);
2279 if (!GetDesiredProto(cx, args,
2280 prototypes::id::${name},
2281 CreateInterfaceObjects,
2286 conditionsCheck
=conditionsCheck
,
2288 name
=self
.descriptor
.name
,
2291 name
= self
._ctor
.identifier
.name
2292 nativeName
= MakeNativeName(self
.descriptor
.binaryNameFor(name
, True))
2293 callGenerator
= CGMethodCall(
2294 nativeName
, True, self
.descriptor
, self
._ctor
, isConstructor
=True
2296 return preamble
+ "\n" + callGenerator
.define()
2298 def auto_profiler_label(self
):
2301 AUTO_PROFILER_LABEL_DYNAMIC_FAST(
2302 "${ctorName}", "constructor", DOM, cx,
2303 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
2305 ctorName
=GetConstructorNameForReporting(self
.descriptor
, self
._ctor
),
2308 def error_reporting_label(self
):
2309 return CGSpecializedMethod
.error_reporting_label_helper(
2310 self
.descriptor
, self
._ctor
, isConstructor
=True
2314 def LegacyFactoryFunctionName(m
):
2315 return "_" + m
.identifier
.name
2318 class CGLegacyFactoryFunctions(CGThing
):
2319 def __init__(self
, descriptor
):
2320 self
.descriptor
= descriptor
2321 CGThing
.__init
__(self
)
2327 if len(self
.descriptor
.interface
.legacyFactoryFunctions
) == 0:
2330 constructorID
= "constructors::id::"
2331 if self
.descriptor
.interface
.hasInterfaceObject():
2332 constructorID
+= self
.descriptor
.name
2334 constructorID
+= "_ID_Count"
2336 legacyFactoryFunctions
= ""
2337 for n
in self
.descriptor
.interface
.legacyFactoryFunctions
:
2338 legacyFactoryFunctions
+= (
2339 '{ "%s", { %s, &sLegacyFactoryFunctionNativePropertyHooks }, %i },\n'
2340 % (n
.identifier
.name
, LegacyFactoryFunctionName(n
), methodLength(n
))
2345 bool sLegacyFactoryFunctionNativePropertiesInited = true;
2346 const NativePropertyHooks sLegacyFactoryFunctionNativePropertyHooks = {
2348 { nullptr, nullptr, &sLegacyFactoryFunctionNativePropertiesInited },
2349 prototypes::id::${name},
2354 static const LegacyFactoryFunction legacyFactoryFunctions[] = {
2355 $*{legacyFactoryFunctions}
2358 name
=self
.descriptor
.name
,
2359 constructorID
=constructorID
,
2360 legacyFactoryFunctions
=legacyFactoryFunctions
,
2364 def isChromeOnly(m
):
2365 return m
.getExtendedAttribute("ChromeOnly")
2368 def prefIdentifier(pref
):
2369 return pref
.replace(".", "_").replace("-", "_")
2372 def prefHeader(pref
):
2373 return "mozilla/StaticPrefs_%s.h" % pref
.partition(".")[0]
2376 def computeGlobalNamesFromExposureSet(exposureSet
):
2377 assert exposureSet
is None or isinstance(exposureSet
, set)
2381 return " | ".join(map(lambda g
: "GlobalNames::%s" % g
, sorted(exposureSet
)))
2386 class MemberCondition
:
2388 An object representing the condition for a member to actually be
2389 exposed. Any of the arguments can be None. If not
2390 None, they should have the following types:
2392 pref: The name of the preference.
2393 func: The name of the function.
2394 secureContext: A bool indicating whether a secure context is required.
2395 nonExposedGlobals: A set of names of globals. Can be empty, in which case
2396 it's treated the same way as None.
2397 trial: The name of the origin trial.
2404 secureContext
=False,
2405 nonExposedGlobals
=None,
2408 assert pref
is None or isinstance(pref
, str)
2409 assert func
is None or isinstance(func
, str)
2410 assert trial
is None or isinstance(trial
, str)
2411 assert isinstance(secureContext
, bool)
2414 identifier
= prefIdentifier(self
.pref
)
2415 self
.prefFuncIndex
= "WebIDLPrefIndex::" + identifier
2417 self
.prefFuncIndex
= "WebIDLPrefIndex::NoPref"
2419 self
.secureContext
= secureContext
2426 self
.func
= toFuncPtr(func
)
2428 self
.nonExposedGlobals
= computeGlobalNamesFromExposureSet(nonExposedGlobals
)
2431 self
.trial
= "OriginTrial::" + trial
2433 self
.trial
= "OriginTrial(0)"
2435 def __eq__(self
, other
):
2437 self
.pref
== other
.pref
2438 and self
.func
== other
.func
2439 and self
.secureContext
== other
.secureContext
2440 and self
.nonExposedGlobals
== other
.nonExposedGlobals
2441 and self
.trial
== other
.trial
2444 def __ne__(self
, other
):
2445 return not self
.__eq
__(other
)
2447 def hasDisablers(self
):
2449 self
.pref
is not None
2450 or self
.secureContext
2451 or self
.func
!= "nullptr"
2452 or self
.nonExposedGlobals
!= "0"
2453 or self
.trial
!= "OriginTrial(0)"
2457 class PropertyDefiner
:
2459 A common superclass for defining things on prototype objects.
2461 Subclasses should implement generateArray to generate the actual arrays of
2462 things we're defining. They should also set self.chrome to the list of
2463 things only exposed to chrome and self.regular to the list of things exposed
2464 to both chrome and web pages.
2467 def __init__(self
, descriptor
, name
):
2468 self
.descriptor
= descriptor
2471 def hasChromeOnly(self
):
2472 return len(self
.chrome
) > 0
2474 def hasNonChromeOnly(self
):
2475 return len(self
.regular
) > 0
2477 def variableName(self
, chrome
):
2479 if self
.hasChromeOnly():
2480 return "sChrome" + self
.name
2482 if self
.hasNonChromeOnly():
2483 return "s" + self
.name
2486 def usedForXrays(self
):
2487 return self
.descriptor
.wantsXrays
2489 def length(self
, chrome
):
2490 return len(self
.chrome
) if chrome
else len(self
.regular
)
2493 # We only need to generate id arrays for things that will end
2494 # up used via ResolveProperty or EnumerateProperties.
2495 str = self
.generateArray(self
.regular
, self
.variableName(False))
2496 if self
.hasChromeOnly():
2497 str += self
.generateArray(self
.chrome
, self
.variableName(True))
2501 def getStringAttr(member
, name
):
2502 attr
= member
.getExtendedAttribute(name
)
2505 # It's a list of strings
2506 assert len(attr
) == 1
2507 assert attr
[0] is not None
2511 def getControllingCondition(interfaceMember
, descriptor
):
2512 interface
= descriptor
.interface
2513 nonExposureSet
= interface
.exposureSet
- interfaceMember
.exposureSet
2515 trial
= PropertyDefiner
.getStringAttr(interfaceMember
, "Trial")
2516 if trial
and interface
.identifier
.name
in ["Window", "Document"]:
2518 "[Trial] not yet supported for %s.%s, see bug 1757935"
2519 % (interface
.identifier
.name
, interfaceMember
.identifier
.name
)
2522 return MemberCondition(
2523 PropertyDefiner
.getStringAttr(interfaceMember
, "Pref"),
2524 PropertyDefiner
.getStringAttr(interfaceMember
, "Func"),
2525 interfaceMember
.getExtendedAttribute("SecureContext") is not None,
2531 def generatePrefableArrayValues(
2538 switchToCondition
=None,
2541 This method generates an array of spec entries for interface members. It returns
2542 a tuple containing the array of spec entries and the maximum of the number of
2543 spec entries per condition.
2545 array is an array of interface members.
2547 descriptor is the descriptor for the interface that array contains members of.
2549 specFormatter is a function that takes a single argument, a tuple,
2550 and returns a string, a spec array entry.
2552 specTerminator is a terminator for the spec array (inserted every time
2553 our controlling pref changes and at the end of the array).
2555 getCondition is a callback function that takes an array entry and
2556 returns the corresponding MemberCondition.
2558 getDataTuple is a callback function that takes an array entry and
2559 returns a tuple suitable to be passed to specFormatter.
2561 switchToCondition is a function that takes a MemberCondition and an array of
2562 previously generated spec entries. If None is passed for this function then all
2563 the interface members should return the same value from getCondition.
2566 def unsupportedSwitchToCondition(condition
, specs
):
2567 # If no specs have been added yet then this is just the first call to
2568 # switchToCondition that we call to avoid putting a specTerminator at the
2569 # front of the list.
2572 raise "Not supported"
2574 if switchToCondition
is None:
2575 switchToCondition
= unsupportedSwitchToCondition
2578 numSpecsInCurPrefable
= 0
2579 maxNumSpecsInPrefable
= 0
2581 # So we won't put a specTerminator at the very front of the list:
2582 lastCondition
= getCondition(array
[0], descriptor
)
2584 switchToCondition(lastCondition
, specs
)
2586 for member
in array
:
2587 curCondition
= getCondition(member
, descriptor
)
2588 if lastCondition
!= curCondition
:
2589 # Terminate previous list
2590 specs
.append(specTerminator
)
2591 if numSpecsInCurPrefable
> maxNumSpecsInPrefable
:
2592 maxNumSpecsInPrefable
= numSpecsInCurPrefable
2593 numSpecsInCurPrefable
= 0
2594 # And switch to our new condition
2595 switchToCondition(curCondition
, specs
)
2596 lastCondition
= curCondition
2597 # And the actual spec
2598 specs
.append(specFormatter(getDataTuple(member
, descriptor
)))
2599 numSpecsInCurPrefable
+= 1
2600 if numSpecsInCurPrefable
> maxNumSpecsInPrefable
:
2601 maxNumSpecsInPrefable
= numSpecsInCurPrefable
2602 specs
.append(specTerminator
)
2604 return (specs
, maxNumSpecsInPrefable
)
2606 def generatePrefableArray(
2617 This method generates our various arrays.
2619 array is an array of interface members as passed to generateArray
2621 name is the name as passed to generateArray
2623 specFormatter is a function that takes a single argument, a tuple,
2624 and returns a string, a spec array entry
2626 specTerminator is a terminator for the spec array (inserted every time
2627 our controlling pref changes and at the end of the array)
2629 specType is the actual typename of our spec
2631 getCondition is a callback function that takes an array entry and
2632 returns the corresponding MemberCondition.
2634 getDataTuple is a callback function that takes an array entry and
2635 returns a tuple suitable to be passed to specFormatter.
2638 # We want to generate a single list of specs, but with specTerminator
2639 # inserted at every point where the pref name controlling the member
2640 # changes. That will make sure the order of the properties as exposed
2641 # on the interface and interface prototype objects does not change when
2642 # pref control is added to members while still allowing us to define all
2643 # the members in the smallest number of JSAPI calls.
2644 assert len(array
) != 0
2649 disablersTemplate
= dedent(
2651 static const PrefableDisablers %s_disablers%d = {
2656 prefableWithDisablersTemplate
= " { &%s_disablers%d, &%s_specs[%d] }"
2657 prefableWithoutDisablersTemplate
= " { nullptr, &%s_specs[%d] }"
2659 def switchToCondition(condition
, specs
):
2660 # Set up pointers to the new sets of specs inside prefableSpecs
2661 if condition
.hasDisablers():
2662 prefableSpecs
.append(
2663 prefableWithDisablersTemplate
% (name
, len(specs
), name
, len(specs
))
2670 condition
.prefFuncIndex
,
2671 condition
.nonExposedGlobals
,
2672 toStringBool(condition
.secureContext
),
2678 prefableSpecs
.append(
2679 prefableWithoutDisablersTemplate
% (name
, len(specs
))
2682 specs
, maxNumSpecsInPrefable
= self
.generatePrefableArrayValues(
2691 prefableSpecs
.append(" { nullptr, nullptr }")
2693 specType
= "const " + specType
2696 MOZ_GLOBINIT static ${specType} ${name}_specs[] = {
2701 static const Prefable<${specType}> ${name}[] = {
2708 disablers
="\n".join(disablers
),
2709 specs
=",\n".join(specs
),
2710 prefableSpecs
=",\n".join(prefableSpecs
),
2713 if self
.usedForXrays():
2717 static_assert(${numPrefableSpecs} <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX,
2718 "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)");
2719 static_assert(${maxNumSpecsInPrefable} <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX,
2720 "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)");
2724 # Minus 1 because there's a list terminator in prefableSpecs.
2725 numPrefableSpecs
=len(prefableSpecs
) - 1,
2726 maxNumSpecsInPrefable
=maxNumSpecsInPrefable
,
2732 # The length of a method is the minimum of the lengths of the
2733 # argument lists of all its overloads.
2734 def overloadLength(arguments
):
2736 while i
> 0 and arguments
[i
- 1].optional
:
2741 def methodLength(method
):
2742 signatures
= method
.signatures()
2743 return min(overloadLength(arguments
) for retType
, arguments
in signatures
)
2746 def clearableCachedAttrs(descriptor
):
2749 for m
in descriptor
.interface
.members
2751 # Constants should never need clearing!
2752 m
.dependsOn
!= "Nothing" and m
.slotIndices
is not None
2756 def MakeClearCachedValueNativeName(member
):
2757 return "ClearCached%sValue" % MakeNativeName(member
.identifier
.name
)
2760 def IDLToCIdentifier(name
):
2761 return name
.replace("-", "_")
2764 def EnumerabilityFlags(member
):
2765 if member
.getExtendedAttribute("NonEnumerable"):
2767 return "JSPROP_ENUMERATE"
2770 class MethodDefiner(PropertyDefiner
):
2772 A class for defining methods on a prototype object.
2775 def __init__(self
, descriptor
, name
, crossOriginOnly
, static
, unforgeable
=False):
2776 assert not (static
and unforgeable
)
2777 PropertyDefiner
.__init
__(self
, descriptor
, name
)
2779 # FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=772822
2780 # We should be able to check for special operations without an
2781 # identifier. For now we check if the name starts with __
2783 # Ignore non-static methods for interfaces without a proto object
2784 if descriptor
.interface
.hasInterfacePrototypeObject() or static
:
2787 for m
in descriptor
.interface
.members
2789 and m
.isStatic() == static
2790 and MemberIsLegacyUnforgeable(m
, descriptor
) == unforgeable
2792 not crossOriginOnly
or m
.getExtendedAttribute("CrossOriginCallable")
2794 and not m
.isIdentifierLess()
2795 and not m
.getExtendedAttribute("Unexposed")
2802 method
= self
.methodData(m
, descriptor
)
2805 method
["nativeName"] = CppKeywords
.checkMethodName(
2806 IDLToCIdentifier(m
.identifier
.name
)
2810 self
.chrome
.append(method
)
2812 self
.regular
.append(method
)
2814 # TODO: Once iterable is implemented, use tiebreak rules instead of
2815 # failing. Also, may be more tiebreak rules to implement once spec bug
2817 # https://www.w3.org/Bugs/Public/show_bug.cgi?id=28592
2818 def hasIterator(methods
, regular
):
2819 return any("@@iterator" in m
.aliases
for m
in methods
) or any(
2820 "@@iterator" == r
["name"] for r
in regular
2823 # Check whether we need to output an @@iterator due to having an indexed
2824 # getter. We only do this while outputting non-static and
2825 # non-unforgeable methods, since the @@iterator function will be
2827 if not static
and not unforgeable
and descriptor
.supportsIndexedProperties():
2828 if hasIterator(methods
, self
.regular
):
2830 "Cannot have indexed getter/attr on "
2831 "interface %s with other members "
2832 "that generate @@iterator, such as "
2833 "maplike/setlike or aliased functions."
2834 % self
.descriptor
.interface
.identifier
.name
2836 self
.regular
.append(
2838 "name": "@@iterator",
2839 "methodInfo": False,
2840 "selfHostedName": "$ArrayValues",
2842 "flags": "0", # Not enumerable, per spec.
2843 "condition": MemberCondition(),
2847 # Generate the keys/values/entries aliases for value iterables.
2848 maplikeOrSetlikeOrIterable
= descriptor
.interface
.maplikeOrSetlikeOrIterable
2852 and maplikeOrSetlikeOrIterable
2853 and maplikeOrSetlikeOrIterable
.isIterable()
2854 and maplikeOrSetlikeOrIterable
.isValueIterator()
2856 # Add our keys/values/entries/forEach
2857 self
.regular
.append(
2860 "methodInfo": False,
2861 "selfHostedName": "ArrayKeys",
2863 "flags": "JSPROP_ENUMERATE",
2864 "condition": PropertyDefiner
.getControllingCondition(
2865 maplikeOrSetlikeOrIterable
, descriptor
2869 self
.regular
.append(
2872 "methodInfo": False,
2873 "selfHostedName": "$ArrayValues",
2875 "flags": "JSPROP_ENUMERATE",
2876 "condition": PropertyDefiner
.getControllingCondition(
2877 maplikeOrSetlikeOrIterable
, descriptor
2881 self
.regular
.append(
2884 "methodInfo": False,
2885 "selfHostedName": "ArrayEntries",
2887 "flags": "JSPROP_ENUMERATE",
2888 "condition": PropertyDefiner
.getControllingCondition(
2889 maplikeOrSetlikeOrIterable
, descriptor
2893 self
.regular
.append(
2896 "methodInfo": False,
2897 "selfHostedName": "ArrayForEach",
2899 "flags": "JSPROP_ENUMERATE",
2900 "condition": PropertyDefiner
.getControllingCondition(
2901 maplikeOrSetlikeOrIterable
, descriptor
2907 stringifier
= descriptor
.operations
["Stringifier"]
2908 if stringifier
and unforgeable
== MemberIsLegacyUnforgeable(
2909 stringifier
, descriptor
2912 "name": GetWebExposedName(stringifier
, descriptor
),
2913 "nativeName": stringifier
.identifier
.name
,
2915 "flags": "JSPROP_ENUMERATE",
2916 "condition": PropertyDefiner
.getControllingCondition(
2917 stringifier
, descriptor
2920 if isChromeOnly(stringifier
):
2921 self
.chrome
.append(toStringDesc
)
2923 self
.regular
.append(toStringDesc
)
2924 if unforgeable
and descriptor
.interface
.getExtendedAttribute(
2927 # Synthesize our valueOf method
2928 self
.regular
.append(
2931 "selfHostedName": "Object_valueOf",
2932 "methodInfo": False,
2934 "flags": "0", # readonly/permanent added automatically.
2935 "condition": MemberCondition(),
2939 if descriptor
.interface
.isJSImplemented():
2941 if descriptor
.interface
.hasInterfaceObject():
2945 "nativeName": ("%s::_Create" % descriptor
.name
),
2946 "methodInfo": False,
2949 "condition": MemberCondition(),
2953 self
.unforgeable
= unforgeable
2956 if not descriptor
.interface
.hasInterfaceObject():
2957 # static methods go on the interface object
2958 assert not self
.hasChromeOnly() and not self
.hasNonChromeOnly()
2960 if not descriptor
.interface
.hasInterfacePrototypeObject():
2961 # non-static methods go on the interface prototype object
2962 assert not self
.hasChromeOnly() and not self
.hasNonChromeOnly()
2965 def methodData(m
, descriptor
, overrideFlags
=None):
2967 "name": m
.identifier
.name
,
2968 "methodInfo": not m
.isStatic(),
2969 "length": methodLength(m
),
2971 EnumerabilityFlags(m
) if (overrideFlags
is None) else overrideFlags
2973 "condition": PropertyDefiner
.getControllingCondition(m
, descriptor
),
2974 "allowCrossOriginThis": m
.getExtendedAttribute("CrossOriginCallable"),
2975 "returnsPromise": m
.returnsPromise(),
2976 "hasIteratorAlias": "@@iterator" in m
.aliases
,
2980 def formatSpec(fields
):
2981 if fields
[0].startswith("@@"):
2982 fields
= (fields
[0][2:],) + fields
[1:]
2983 return " JS_SYM_FNSPEC(%s, %s, %s, %s, %s, %s)" % fields
2984 return ' JS_FNSPEC("%s", %s, %s, %s, %s, %s)' % fields
2987 def specData(m
, descriptor
, unforgeable
=False):
2988 def flags(m
, unforgeable
):
2989 unforgeable
= " | JSPROP_PERMANENT | JSPROP_READONLY" if unforgeable
else ""
2990 return m
["flags"] + unforgeable
2992 if "selfHostedName" in m
:
2993 selfHostedName
= '"%s"' % m
["selfHostedName"]
2994 assert not m
.get("methodInfo", True)
2995 accessor
= "nullptr"
2998 selfHostedName
= "nullptr"
2999 # When defining symbols, function name may not match symbol name
3000 methodName
= m
.get("methodName", m
["name"])
3001 accessor
= m
.get("nativeName", IDLToCIdentifier(methodName
))
3002 if m
.get("methodInfo", True):
3003 if m
.get("returnsPromise", False):
3004 exceptionPolicy
= "ConvertExceptionsToPromises"
3006 exceptionPolicy
= "ThrowExceptions"
3008 # Cast this in case the methodInfo is a
3009 # JSTypedMethodJitInfo.
3011 "reinterpret_cast<const JSJitInfo*>(&%s_methodinfo)" % accessor
3013 if m
.get("allowCrossOriginThis", False):
3015 "(GenericMethod<CrossOriginThisPolicy, %s>)" % exceptionPolicy
3017 elif descriptor
.interface
.hasDescendantWithCrossOriginMembers
:
3019 "(GenericMethod<MaybeCrossOriginObjectThisPolicy, %s>)"
3022 elif descriptor
.interface
.isOnGlobalProtoChain():
3024 "(GenericMethod<MaybeGlobalThisPolicy, %s>)" % exceptionPolicy
3027 accessor
= "(GenericMethod<NormalThisPolicy, %s>)" % exceptionPolicy
3029 if m
.get("returnsPromise", False):
3030 jitinfo
= "&%s_methodinfo" % accessor
3031 accessor
= "StaticMethodPromiseWrapper"
3040 flags(m
, unforgeable
),
3045 def condition(m
, d
):
3046 return m
["condition"]
3048 def generateArray(self
, array
, name
):
3052 return self
.generatePrefableArray(
3059 functools
.partial(self
.specData
, unforgeable
=self
.unforgeable
),
3063 class AttrDefiner(PropertyDefiner
):
3064 def __init__(self
, descriptor
, name
, crossOriginOnly
, static
, unforgeable
=False):
3065 assert not (static
and unforgeable
)
3066 PropertyDefiner
.__init
__(self
, descriptor
, name
)
3068 # Ignore non-static attributes for interfaces without a proto object
3069 if descriptor
.interface
.hasInterfacePrototypeObject() or static
:
3072 for m
in descriptor
.interface
.members
3074 and m
.isStatic() == static
3075 and MemberIsLegacyUnforgeable(m
, descriptor
) == unforgeable
3078 or m
.getExtendedAttribute("CrossOriginReadable")
3079 or m
.getExtendedAttribute("CrossOriginWritable")
3086 for attr
in idlAttrs
:
3087 attributes
.extend(self
.attrData(attr
, unforgeable
))
3088 self
.chrome
= [m
for m
in attributes
if isChromeOnly(m
["attr"])]
3089 self
.regular
= [m
for m
in attributes
if not isChromeOnly(m
["attr"])]
3090 self
.static
= static
3093 if not descriptor
.interface
.hasInterfaceObject():
3094 # static attributes go on the interface object
3095 assert not self
.hasChromeOnly() and not self
.hasNonChromeOnly()
3097 if not descriptor
.interface
.hasInterfacePrototypeObject():
3098 # non-static attributes go on the interface prototype object
3099 assert not self
.hasChromeOnly() and not self
.hasNonChromeOnly()
3102 def attrData(attr
, unforgeable
=False, overrideFlags
=None):
3103 if overrideFlags
is None:
3104 permanent
= " | JSPROP_PERMANENT" if unforgeable
else ""
3105 flags
= EnumerabilityFlags(attr
) + permanent
3107 flags
= overrideFlags
3109 {"name": name
, "attr": attr
, "flags": flags
}
3110 for name
in [attr
.identifier
.name
] + attr
.bindingAliases
3114 def condition(m
, d
):
3115 return PropertyDefiner
.getControllingCondition(m
["attr"], d
)
3118 def specData(entry
, descriptor
, static
=False, crossOriginOnly
=False):
3120 if crossOriginOnly
and not attr
.getExtendedAttribute("CrossOriginReadable"):
3121 return "nullptr, nullptr"
3123 if attr
.type.isPromise():
3125 "Don't know how to handle "
3126 "static Promise-returning "
3127 "attribute %s.%s" % (descriptor
.name
, attr
.identifier
.name
)
3129 accessor
= "get_" + IDLToCIdentifier(attr
.identifier
.name
)
3132 if attr
.type.isPromise():
3133 exceptionPolicy
= "ConvertExceptionsToPromises"
3135 exceptionPolicy
= "ThrowExceptions"
3137 if attr
.hasLegacyLenientThis():
3138 if attr
.getExtendedAttribute("CrossOriginReadable"):
3140 "Can't handle lenient cross-origin "
3141 "readable attribute %s.%s"
3142 % (descriptor
.name
, attr
.identifier
.name
)
3144 if descriptor
.interface
.hasDescendantWithCrossOriginMembers
:
3146 "GenericGetter<MaybeCrossOriginObjectLenientThisPolicy, %s>"
3151 "GenericGetter<LenientThisPolicy, %s>" % exceptionPolicy
3153 elif attr
.getExtendedAttribute("CrossOriginReadable"):
3155 "GenericGetter<CrossOriginThisPolicy, %s>" % exceptionPolicy
3157 elif descriptor
.interface
.hasDescendantWithCrossOriginMembers
:
3159 "GenericGetter<MaybeCrossOriginObjectThisPolicy, %s>"
3162 elif descriptor
.interface
.isOnGlobalProtoChain():
3164 "GenericGetter<MaybeGlobalThisPolicy, %s>" % exceptionPolicy
3167 accessor
= "GenericGetter<NormalThisPolicy, %s>" % exceptionPolicy
3168 jitinfo
= "&%s_getterinfo" % IDLToCIdentifier(attr
.identifier
.name
)
3169 return "%s, %s" % (accessor
, jitinfo
)
3174 and attr
.getExtendedAttribute("PutForwards") is None
3175 and attr
.getExtendedAttribute("Replaceable") is None
3176 and attr
.getExtendedAttribute("LegacyLenientSetter") is None
3178 return "nullptr, nullptr"
3179 if crossOriginOnly
and not attr
.getExtendedAttribute("CrossOriginWritable"):
3180 return "nullptr, nullptr"
3182 accessor
= "set_" + IDLToCIdentifier(attr
.identifier
.name
)
3185 if attr
.hasLegacyLenientThis():
3186 if attr
.getExtendedAttribute("CrossOriginWritable"):
3188 "Can't handle lenient cross-origin "
3189 "writable attribute %s.%s"
3190 % (descriptor
.name
, attr
.identifier
.name
)
3192 if descriptor
.interface
.hasDescendantWithCrossOriginMembers
:
3194 "GenericSetter<MaybeCrossOriginObjectLenientThisPolicy>"
3197 accessor
= "GenericSetter<LenientThisPolicy>"
3198 elif attr
.getExtendedAttribute("CrossOriginWritable"):
3199 accessor
= "GenericSetter<CrossOriginThisPolicy>"
3200 elif descriptor
.interface
.hasDescendantWithCrossOriginMembers
:
3201 accessor
= "GenericSetter<MaybeCrossOriginObjectThisPolicy>"
3202 elif descriptor
.interface
.isOnGlobalProtoChain():
3203 accessor
= "GenericSetter<MaybeGlobalThisPolicy>"
3205 accessor
= "GenericSetter<NormalThisPolicy>"
3206 jitinfo
= "&%s_setterinfo" % IDLToCIdentifier(attr
.identifier
.name
)
3207 return "%s, %s" % (accessor
, jitinfo
)
3209 name
, attr
, flags
= entry
["name"], entry
["attr"], entry
["flags"]
3210 return (name
, flags
, getter(attr
), setter(attr
))
3213 def formatSpec(fields
):
3214 return ' JSPropertySpec::nativeAccessors("%s", %s, %s, %s)' % fields
3216 def generateArray(self
, array
, name
):
3220 return self
.generatePrefableArray(
3227 functools
.partial(self
.specData
, static
=self
.static
),
3231 class ConstDefiner(PropertyDefiner
):
3233 A class for definining constants on the interface object
3236 def __init__(self
, descriptor
, name
):
3237 PropertyDefiner
.__init
__(self
, descriptor
, name
)
3239 constants
= [m
for m
in descriptor
.interface
.members
if m
.isConst()]
3240 self
.chrome
= [m
for m
in constants
if isChromeOnly(m
)]
3241 self
.regular
= [m
for m
in constants
if not isChromeOnly(m
)]
3243 def generateArray(self
, array
, name
):
3247 def specData(const
, descriptor
):
3248 return (const
.identifier
.name
, convertConstIDLValueToJSVal(const
.value
))
3250 return self
.generatePrefableArray(
3253 lambda fields
: ' { "%s", %s }' % fields
,
3254 " { 0, JS::UndefinedValue() }",
3256 PropertyDefiner
.getControllingCondition
,
3261 class PropertyArrays
:
3262 def __init__(self
, descriptor
, crossOriginOnly
=False):
3263 self
.staticMethods
= MethodDefiner(
3264 descriptor
, "StaticMethods", crossOriginOnly
, static
=True
3266 self
.staticAttrs
= AttrDefiner(
3267 descriptor
, "StaticAttributes", crossOriginOnly
, static
=True
3269 self
.methods
= MethodDefiner(
3270 descriptor
, "Methods", crossOriginOnly
, static
=False
3272 self
.attrs
= AttrDefiner(
3273 descriptor
, "Attributes", crossOriginOnly
, static
=False
3275 self
.unforgeableMethods
= MethodDefiner(
3277 "UnforgeableMethods",
3282 self
.unforgeableAttrs
= AttrDefiner(
3284 "UnforgeableAttributes",
3289 self
.consts
= ConstDefiner(descriptor
, "Constants")
3298 "unforgeableMethods",
3303 def hasChromeOnly(self
):
3304 return any(getattr(self
, a
).hasChromeOnly() for a
in self
.arrayNames())
3306 def hasNonChromeOnly(self
):
3307 return any(getattr(self
, a
).hasNonChromeOnly() for a
in self
.arrayNames())
3311 for array
in self
.arrayNames():
3312 define
+= str(getattr(self
, array
))
3316 class CGConstDefinition(CGThing
):
3318 Given a const member of an interface, return the C++ static const definition
3319 for the member. Should be part of the interface namespace in the header
3323 def __init__(self
, member
):
3326 and member
.value
.type.isPrimitive()
3327 and not member
.value
.type.nullable()
3330 name
= CppKeywords
.checkMethodName(IDLToCIdentifier(member
.identifier
.name
))
3331 tag
= member
.value
.type.tag()
3332 value
= member
.value
.value
3333 if tag
== IDLType
.Tags
.bool:
3334 value
= toStringBool(member
.value
.value
)
3335 self
.const
= "static const %s %s = %s;" % (builtinNames
[tag
], name
, value
)
3347 class CGNativeProperties(CGList
):
3348 def __init__(self
, descriptor
, properties
):
3349 def generateNativeProperties(name
, chrome
):
3351 return p
.hasChromeOnly() if chrome
else p
.hasNonChromeOnly()
3353 nativePropsInts
= []
3354 nativePropsPtrs
= []
3355 nativePropsDuos
= []
3359 for array
in properties
.arrayNames():
3360 propertyArray
= getattr(properties
, array
)
3361 if check(propertyArray
):
3362 varName
= propertyArray
.variableName(chrome
)
3363 bitfields
= "true, %d /* %s */" % (duosOffset
, varName
)
3365 nativePropsInts
.append(CGGeneric(bitfields
))
3367 if propertyArray
.usedForXrays():
3368 ids
= "&%s_propertyInfos[%d]" % (name
, idsOffset
)
3369 idsOffset
+= propertyArray
.length(chrome
)
3372 duo
= "{ %s, %s }" % (varName
, ids
)
3373 nativePropsDuos
.append(CGGeneric(duo
))
3375 bitfields
= "false, 0"
3376 nativePropsInts
.append(CGGeneric(bitfields
))
3378 iteratorAliasIndex
= -1
3379 for index
, item
in enumerate(properties
.methods
.regular
):
3380 if item
.get("hasIteratorAlias"):
3381 iteratorAliasIndex
= index
3383 nativePropsInts
.append(CGGeneric(str(iteratorAliasIndex
)))
3387 CGIndenter(CGList(nativePropsDuos
, ",\n")), pre
="{\n", post
="\n}"
3391 pre
= "static const NativePropertiesN<%d> %s = {\n" % (duosOffset
, name
)
3393 if descriptor
.wantsXrays
:
3396 static uint16_t ${name}_sortedPropertyIndices[${size}];
3397 static PropertyInfo ${name}_propertyInfos[${size}];
3405 if iteratorAliasIndex
> 0:
3406 # The iteratorAliasMethodIndex is a signed integer, so the
3407 # max value it can store is 2^(nbits-1)-1.
3411 static_assert(${iteratorAliasIndex} < 1ull << (CHAR_BIT * sizeof(${name}.iteratorAliasMethodIndex) - 1),
3412 "We have an iterator alias index that is oversized");
3415 iteratorAliasIndex
=iteratorAliasIndex
,
3421 static_assert(${propertyInfoCount} < 1ull << (CHAR_BIT * sizeof(${name}.propertyInfoCount)),
3422 "We have a property info count that is oversized");
3425 propertyInfoCount
=idsOffset
,
3428 nativePropsInts
.append(CGGeneric("%d" % idsOffset
))
3429 nativePropsPtrs
.append(CGGeneric("%s_sortedPropertyIndices" % name
))
3431 nativePropsInts
.append(CGGeneric("0"))
3432 nativePropsPtrs
.append(CGGeneric("nullptr"))
3433 nativeProps
= nativePropsInts
+ nativePropsPtrs
+ nativePropsDuos
3434 return CGWrapper(CGIndenter(CGList(nativeProps
, ",\n")), pre
=pre
, post
=post
)
3436 nativeProperties
= []
3437 if properties
.hasNonChromeOnly():
3438 nativeProperties
.append(
3439 generateNativeProperties("sNativeProperties", False)
3441 if properties
.hasChromeOnly():
3442 nativeProperties
.append(
3443 generateNativeProperties("sChromeOnlyNativeProperties", True)
3446 CGList
.__init
__(self
, nativeProperties
, "\n")
3452 return CGList
.define(self
)
3455 class CGCollectJSONAttributesMethod(CGAbstractMethod
):
3457 Generate the CollectJSONAttributes method for an interface descriptor
3460 def __init__(self
, descriptor
, toJSONMethod
):
3462 Argument("JSContext*", "cx"),
3463 Argument("JS::Handle<JSObject*>", "obj"),
3464 Argument("%s*" % descriptor
.nativeType
, "self"),
3465 Argument("JS::Rooted<JSObject*>&", "result"),
3467 CGAbstractMethod
.__init
__(
3468 self
, descriptor
, "CollectJSONAttributes", "bool", args
, canRunScript
=True
3470 self
.toJSONMethod
= toJSONMethod
3472 def definition_body(self
):
3474 interface
= self
.descriptor
.interface
3475 toJSONCondition
= PropertyDefiner
.getControllingCondition(
3476 self
.toJSONMethod
, self
.descriptor
3478 needUnwrappedObj
= False
3479 for m
in interface
.members
:
3480 if m
.isAttr() and not m
.isStatic() and m
.type.isJSONType():
3481 getAndDefine
= fill(
3483 JS::Rooted<JS::Value> temp(cx);
3484 if (!get_${name}(cx, obj, self, JSJitGetterCallArgs(&temp))) {
3487 if (!JS_DefineProperty(cx, result, "${name}", temp, JSPROP_ENUMERATE)) {
3491 name
=IDLToCIdentifier(m
.identifier
.name
),
3493 # Make sure we don't include things which are supposed to be
3494 # disabled. Things that either don't have disablers or whose
3495 # disablers match the disablers for our toJSON method can't
3496 # possibly be disabled, but other things might be.
3497 condition
= PropertyDefiner
.getControllingCondition(m
, self
.descriptor
)
3498 if condition
.hasDisablers() and condition
!= toJSONCondition
:
3499 needUnwrappedObj
= True
3502 // This is unfortunately a linear scan through sAttributes, but we
3503 // only do it for things which _might_ be disabled, which should
3504 // help keep the performance problems down.
3505 if (IsGetterEnabled(cx, unwrappedObj, (JSJitGetterOp)get_${name}, sAttributes)) {
3509 name
=IDLToCIdentifier(m
.identifier
.name
),
3510 getAndDefine
=getAndDefine
,
3515 { // scope for "temp"
3519 getAndDefine
=getAndDefine
,
3521 ret
+= "return true;\n"
3523 if needUnwrappedObj
:
3524 # If we started allowing cross-origin objects here, we'd need to
3525 # use CheckedUnwrapDynamic and figure out whether it makes sense.
3526 # But in practice no one is trying to add toJSON methods to those,
3527 # so let's just guard against it.
3528 assert not self
.descriptor
.isMaybeCrossOriginObject()
3531 JS::Rooted<JSObject*> unwrappedObj(cx, js::CheckedUnwrapStatic(obj));
3532 if (!unwrappedObj) {
3533 // How did that happen? We managed to get called with that
3534 // object as "this"! Just give up on sanity.
3546 class CGCreateInterfaceObjectsMethod(CGAbstractMethod
):
3548 Generate the CreateInterfaceObjects method for an interface descriptor.
3550 properties should be a PropertyArrays instance.
3554 self
, descriptor
, properties
, haveUnscopables
, haveLegacyWindowAliases
, static
3557 Argument("JSContext*", "aCx"),
3558 Argument("JS::Handle<JSObject*>", "aGlobal"),
3559 Argument("ProtoAndIfaceCache&", "aProtoAndIfaceCache"),
3560 Argument("DefineInterfaceProperty", "aDefineOnGlobal"),
3562 CGAbstractMethod
.__init
__(
3563 self
, descriptor
, "CreateInterfaceObjects", "void", args
, static
=static
3565 self
.properties
= properties
3566 self
.haveUnscopables
= haveUnscopables
3567 self
.haveLegacyWindowAliases
= haveLegacyWindowAliases
3569 def definition_body(self
):
3570 needInterfaceObject
= self
.descriptor
.interface
.hasInterfaceObject()
3571 if needInterfaceObject
and self
.descriptor
.isExposedConditionally():
3572 # This code might be called when we're trying to create an object
3573 # in a non-system compartment, for example when system code is
3574 # calling a constructor through Xrays. In that case we do want to
3575 # create an interface object in the non-system compartment, but we
3576 # don't want to expose the name on the non-system global if the
3577 # interface itself is marked as ChromeOnly.
3579 "ShouldExpose<%s::ConstructorEnabled>(aCx, aGlobal, aDefineOnGlobal)"
3580 % toBindingNamespace(self
.descriptor
.name
)
3583 defineOnGlobal
= "aDefineOnGlobal != DefineInterfaceProperty::No"
3584 if needInterfaceObject
:
3585 if self
.descriptor
.interface
.isNamespace():
3586 if self
.descriptor
.interface
.getExtendedAttribute("ProtoObjectHack"):
3587 getConstructorProto
= "GetHackedNamespaceProtoObject"
3589 getConstructorProto
= "JS::GetRealmObjectPrototype"
3590 getConstructorProto
= "aCx, " + getConstructorProto
3591 constructorProtoType
= "Rooted"
3593 getConstructorProto
= InterfaceObjectProtoGetter(self
.descriptor
)
3594 constructorProtoType
= "Handle"
3596 getConstructorProto
= fill(
3598 JS::${type}<JSObject*> constructorProto(${getConstructorProto}(aCx));
3599 if (!constructorProto) {
3603 type=constructorProtoType
,
3604 getConstructorProto
=getConstructorProto
,
3607 interfaceInfo
= "&sInterfaceObjectInfo"
3609 "&aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::%s)"
3610 % self
.descriptor
.name
3612 getConstructorProto
= CGGeneric(getConstructorProto
)
3613 constructorProto
= "constructorProto"
3615 # We don't have slots to store the legacy factory functions.
3616 assert len(self
.descriptor
.interface
.legacyFactoryFunctions
) == 0
3617 interfaceInfo
= "nullptr"
3618 interfaceCache
= "nullptr"
3619 getConstructorProto
= None
3620 constructorProto
= "nullptr"
3622 if self
.properties
.hasNonChromeOnly():
3623 properties
= "sNativeProperties.Upcast()"
3625 properties
= "nullptr"
3626 if self
.properties
.hasChromeOnly():
3627 chromeProperties
= "sChromeOnlyNativeProperties.Upcast()"
3629 chromeProperties
= "nullptr"
3631 # We use getClassName here. This should be the right thing to pass as
3632 # the name argument to CreateInterfaceObjects. This is generally the
3633 # interface identifier, except for the synthetic interfaces created for
3634 # the default iterator objects. If needInterfaceObject is true then
3635 # we'll use the name to install a property on the global object, so
3636 # there shouldn't be any spaces in the name.
3637 name
= self
.descriptor
.interface
.getClassName()
3638 assert not (needInterfaceObject
and " " in name
)
3640 if self
.descriptor
.interface
.isNamespace():
3641 # If we don't need to create anything, why are we generating this?
3642 assert needInterfaceObject
3646 JS::Heap<JSObject*>* interfaceCache = ${interfaceCache};
3647 dom::CreateNamespaceObject(aCx, aGlobal, ${constructorProto},
3648 sNamespaceObjectClass,
3651 ${chromeProperties},
3655 interfaceCache
=interfaceCache
,
3656 constructorProto
=constructorProto
,
3657 properties
=properties
,
3658 chromeProperties
=chromeProperties
,
3660 defineOnGlobal
=defineOnGlobal
,
3664 getConstructorProto
,
3670 needInterfacePrototypeObject
= (
3671 self
.descriptor
.interface
.hasInterfacePrototypeObject()
3674 # If we don't need to create anything, why are we generating this?
3675 assert needInterfaceObject
or needInterfacePrototypeObject
3677 if needInterfacePrototypeObject
:
3678 (protoGetter
, protoHandleGetter
) = InterfacePrototypeObjectProtoGetter(
3681 if protoHandleGetter
is None:
3682 parentProtoType
= "Rooted"
3683 getParentProto
= "aCx, " + protoGetter
3685 parentProtoType
= "Handle"
3686 getParentProto
= protoHandleGetter
3688 getParentProto
= fill(
3690 JS::${type}<JSObject*> parentProto(${getParentProto}(aCx));
3695 type=parentProtoType
,
3696 getParentProto
=getParentProto
,
3699 protoClass
= "&sPrototypeClass"
3701 "&aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::%s)"
3702 % self
.descriptor
.name
3704 parentProto
= "parentProto"
3705 getParentProto
= CGGeneric(getParentProto
)
3707 protoClass
= "nullptr"
3708 protoCache
= "nullptr"
3709 parentProto
= "nullptr"
3710 getParentProto
= None
3712 if self
.descriptor
.interface
.ctor():
3713 constructArgs
= methodLength(self
.descriptor
.interface
.ctor())
3714 isConstructorChromeOnly
= isChromeOnly(self
.descriptor
.interface
.ctor())
3717 isConstructorChromeOnly
= False
3718 if len(self
.descriptor
.interface
.legacyFactoryFunctions
) > 0:
3719 legacyFactoryFunctions
= "Span(legacyFactoryFunctions)"
3721 legacyFactoryFunctions
= "Span<const LegacyFactoryFunction, 0>{}"
3723 isGlobal
= self
.descriptor
.isGlobal() is not None
3725 ensureCaches
= fill(
3727 JS::Heap<JSObject*>* protoCache = ${protoCache};
3728 JS::Heap<JSObject*>* interfaceCache = ${interfaceCache};
3730 protoCache
=protoCache
,
3731 interfaceCache
=interfaceCache
,
3735 dom::CreateInterfaceObjects(aCx, aGlobal, ${parentProto},
3736 ${protoClass}, protoCache,
3737 ${constructorProto}, ${interfaceInfo}, ${constructArgs}, ${isConstructorChromeOnly}, ${legacyFactoryFunctions},
3740 ${chromeProperties},
3745 ${legacyWindowAliases});
3747 protoClass
=protoClass
,
3748 parentProto
=parentProto
,
3749 constructorProto
=constructorProto
,
3750 interfaceInfo
=interfaceInfo
,
3751 constructArgs
=constructArgs
,
3752 isConstructorChromeOnly
=toStringBool(isConstructorChromeOnly
),
3753 legacyFactoryFunctions
=legacyFactoryFunctions
,
3754 properties
=properties
,
3755 chromeProperties
=chromeProperties
,
3757 defineOnGlobal
=defineOnGlobal
,
3758 unscopableNames
="unscopableNames" if self
.haveUnscopables
else "nullptr",
3759 isGlobal
=toStringBool(isGlobal
),
3760 legacyWindowAliases
=(
3761 "legacyWindowAliases" if self
.haveLegacyWindowAliases
else "nullptr"
3765 # If we fail after here, we must clear interface and prototype caches
3766 # using this code: intermediate failure must not expose the interface in
3767 # partially-constructed state. Note that every case after here needs an
3768 # interface prototype object.
3769 failureCode
= dedent(
3771 *protoCache = nullptr;
3772 if (interfaceCache) {
3773 *interfaceCache = nullptr;
3779 needProtoVar
= False
3782 m
for m
in self
.descriptor
.interface
.members
if m
.isMethod() and m
.aliases
3785 assert needInterfacePrototypeObject
3787 def defineAlias(alias
):
3788 if alias
== "@@iterator" or alias
== "@@asyncIterator":
3792 "JS::GetWellKnownSymbolKey(aCx, JS::SymbolCode::%s)" % name
3794 prop
= "%sId" % name
3795 getSymbolJSID
= CGGeneric(
3797 "JS::Rooted<jsid> ${prop}(aCx, ${symbolJSID});",
3799 symbolJSID
=symbolJSID
,
3802 defineFn
= "JS_DefinePropertyById"
3803 enumFlags
= "0" # Not enumerable, per spec.
3804 elif alias
.startswith("@@"):
3806 "Can't handle any well-known Symbol other than @@iterator and @@asyncIterator"
3809 getSymbolJSID
= None
3810 defineFn
= "JS_DefineProperty"
3811 prop
= '"%s"' % alias
3812 # XXX If we ever create non-enumerable properties that can
3813 # be aliased, we should consider making the aliases
3814 # match the enumerability of the property being aliased.
3815 enumFlags
= "JSPROP_ENUMERATE"
3822 if (!${defineFn}(aCx, proto, ${prop}, aliasedVal, ${enumFlags})) {
3828 enumFlags
=enumFlags
,
3829 failureCode
=failureCode
,
3836 def defineAliasesFor(m
):
3842 if (!JS_GetProperty(aCx, proto, \"${prop}\", &aliasedVal)) {
3846 failureCode
=failureCode
,
3847 prop
=m
.identifier
.name
,
3851 + [defineAlias(alias
) for alias
in sorted(m
.aliases
)]
3854 defineAliases
= CGList(
3859 // Set up aliases on the interface prototype object we just created.
3863 CGGeneric("JS::Rooted<JS::Value> aliasedVal(aCx);\n\n"),
3867 for m
in sorted(aliasedMembers
, key
=lambda m
: m
.identifier
.name
)
3872 defineAliases
= None
3874 # Globals handle unforgeables directly in Wrap() instead of
3877 self
.descriptor
.hasLegacyUnforgeableMembers
3878 and not self
.descriptor
.isGlobal()
3880 assert needInterfacePrototypeObject
3882 # We want to use the same JSClass and prototype as the object we'll
3883 # end up defining the unforgeable properties on in the end, so that
3884 # we can use JS_InitializePropertiesFromCompatibleNativeObject to do
3885 # a fast copy. In the case of proxies that's null, because the
3886 # expando object is a vanilla object, but in the case of other DOM
3887 # objects it's whatever our class is.
3888 if self
.descriptor
.proxy
:
3889 holderClass
= "nullptr"
3890 holderProto
= "nullptr"
3892 holderClass
= "sClass.ToJSClass()"
3893 holderProto
= "proto"
3895 createUnforgeableHolder
= CGGeneric(
3898 JS::Rooted<JSObject*> unforgeableHolder(
3899 aCx, JS_NewObjectWithoutMetadata(aCx, ${holderClass}, ${holderProto}));
3900 if (!unforgeableHolder) {
3904 holderProto
=holderProto
,
3905 holderClass
=holderClass
,
3906 failureCode
=failureCode
,
3909 defineUnforgeables
= InitUnforgeablePropertiesOnHolder(
3910 self
.descriptor
, self
.properties
, failureCode
3912 createUnforgeableHolder
= CGList(
3913 [createUnforgeableHolder
, defineUnforgeables
]
3916 installUnforgeableHolder
= CGGeneric(
3920 JS::SetReservedSlot(*protoCache, DOM_INTERFACE_PROTO_SLOTS_BASE,
3921 JS::ObjectValue(*unforgeableHolder));
3927 unforgeableHolderSetup
= CGList(
3928 [createUnforgeableHolder
, installUnforgeableHolder
], "\n"
3931 unforgeableHolderSetup
= None
3934 self
.descriptor
.interface
.isOnGlobalProtoChain()
3935 and needInterfacePrototypeObject
3937 makeProtoPrototypeImmutable
= CGGeneric(
3942 if (!JS_SetImmutablePrototype(aCx, proto, &succeeded)) {
3946 MOZ_ASSERT(succeeded,
3947 "making a fresh prototype object's [[Prototype]] "
3948 "immutable can internally fail, but it should "
3949 "never be unsuccessful");
3952 protoCache
=protoCache
,
3953 failureCode
=failureCode
,
3958 makeProtoPrototypeImmutable
= None
3961 defineProtoVar
= CGGeneric(
3964 JS::AssertObjectIsNotGray(*protoCache);
3965 JS::Handle<JSObject*> proto = JS::Handle<JSObject*>::fromMarkedLocation(protoCache->unsafeAddress());
3970 failureCode
=failureCode
,
3974 defineProtoVar
= None
3976 # ensureCaches needs to come first as it crashes on failure (like OOM).
3977 # We want to make sure that the caches do exist before we try to return
3978 # to the caller, so it can rely on that (and detect other failures by
3979 # checking for null in the caches).
3982 CGGeneric(ensureCaches
),
3984 getConstructorProto
,
3988 unforgeableHolderSetup
,
3989 makeProtoPrototypeImmutable
,
3995 class CGCreateAndDefineOnGlobalMethod(CGAbstractMethod
):
3997 A method for creating the interface or namespace object and defining
3998 properties for it on the global.
4001 def __init__(self
, descriptor
):
4002 CGAbstractMethod
.__init
__(
4005 "CreateAndDefineOnGlobal",
4008 Argument("JSContext*", "aCx"),
4013 def definition_body(self
):
4016 // Get the interface or namespace object for this class. This will
4017 // create the object as needed and always define the properties for
4018 // it on the global. The caller should make sure the interface or
4019 // namespace is exposed on the global before calling this.
4020 return GetPerInterfaceObjectHandle(aCx, constructors::id::${name},
4021 &CreateInterfaceObjects,
4022 DefineInterfaceProperty::Always);
4025 name
=self
.descriptor
.name
,
4029 class CGGetProtoObjectHandleMethod(CGAbstractMethod
):
4031 A method for getting the interface prototype object.
4034 def __init__(self
, descriptor
, static
, signatureOnly
=False):
4035 CGAbstractMethod
.__init
__(
4038 "GetProtoObjectHandle",
4039 "JS::Handle<JSObject*>",
4040 [Argument("JSContext*", "aCx")],
4042 signatureOnly
=signatureOnly
,
4045 def definition_body(self
):
4048 /* Get the interface prototype object for this class. This will create the
4049 object as needed. */
4050 return GetPerInterfaceObjectHandle(aCx, prototypes::id::${name},
4051 &CreateInterfaceObjects,
4052 DefineInterfaceProperty::CheckExposure);
4055 name
=self
.descriptor
.name
,
4059 class CGGetProtoObjectMethod(CGAbstractMethod
):
4061 A method for getting the interface prototype object.
4064 def __init__(self
, descriptor
):
4065 CGAbstractMethod
.__init
__(
4070 [Argument("JSContext*", "aCx")],
4073 def definition_body(self
):
4074 return "return GetProtoObjectHandle(aCx);\n"
4077 class CGGetConstructorObjectHandleMethod(CGAbstractMethod
):
4079 A method for getting the interface constructor object.
4082 def __init__(self
, descriptor
):
4083 CGAbstractMethod
.__init
__(
4086 "GetConstructorObjectHandle",
4087 "JS::Handle<JSObject*>",
4089 Argument("JSContext*", "aCx"),
4093 def definition_body(self
):
4096 /* Get the interface object for this class. This will create the object as
4099 return GetPerInterfaceObjectHandle(aCx, constructors::id::${name},
4100 &CreateInterfaceObjects,
4101 DefineInterfaceProperty::CheckExposure);
4103 name
=self
.descriptor
.name
,
4107 class CGGetNamedPropertiesObjectMethod(CGAbstractStaticMethod
):
4108 def __init__(self
, descriptor
):
4109 args
= [Argument("JSContext*", "aCx")]
4110 CGAbstractStaticMethod
.__init
__(
4111 self
, descriptor
, "GetNamedPropertiesObject", "JSObject*", args
4114 def definition_body(self
):
4115 parentProtoName
= self
.descriptor
.parentPrototypeName
4116 if parentProtoName
is None:
4118 parentProto
= "nullptr"
4120 getParentProto
= fill(
4122 JS::Rooted<JSObject*> parentProto(aCx, ${parent}::GetProtoObjectHandle(aCx));
4127 parent
=toBindingNamespace(parentProtoName
),
4129 parentProto
= "parentProto"
4132 /* Make sure our global is sane. Hopefully we can remove this sometime */
4133 JSObject* global = JS::CurrentGlobalOrNull(aCx);
4134 if (!(JS::GetClass(global)->flags & JSCLASS_DOM_GLOBAL)) {
4138 /* Check to see whether the named properties object has already been created */
4139 ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
4141 JS::Heap<JSObject*>& namedPropertiesObject = protoAndIfaceCache.EntrySlotOrCreate(namedpropertiesobjects::id::${ifaceName});
4142 if (!namedPropertiesObject) {
4144 namedPropertiesObject = ${nativeType}::CreateNamedPropertiesObject(aCx, ${parentProto});
4145 DebugOnly<const DOMIfaceAndProtoJSClass*> clasp =
4146 DOMIfaceAndProtoJSClass::FromJSClass(JS::GetClass(namedPropertiesObject));
4147 MOZ_ASSERT(clasp->mType == eNamedPropertiesObject,
4148 "Expected ${nativeType}::CreateNamedPropertiesObject to return a named properties object");
4149 MOZ_ASSERT(clasp->mNativeHooks,
4150 "The named properties object for ${nativeType} should have NativePropertyHooks.");
4151 MOZ_ASSERT(!clasp->mNativeHooks->mIndexedOrNamedNativeProperties ||
4152 !clasp->mNativeHooks->mIndexedOrNamedNativeProperties->mResolveOwnProperty,
4153 "Shouldn't resolve the properties of the named properties object for ${nativeType} for Xrays.");
4154 MOZ_ASSERT(!clasp->mNativeHooks->mIndexedOrNamedNativeProperties ||
4155 !clasp->mNativeHooks->mIndexedOrNamedNativeProperties->mEnumerateOwnProperties,
4156 "Shouldn't enumerate the properties of the named properties object for ${nativeType} for Xrays.");
4158 return namedPropertiesObject.get();
4160 getParentProto
=getParentProto
,
4161 ifaceName
=self
.descriptor
.name
,
4162 parentProto
=parentProto
,
4163 nativeType
=self
.descriptor
.nativeType
,
4167 def getRawConditionList(idlobj
, cxName
, objName
, ignoreSecureContext
=False):
4169 Get the list of conditions for idlobj (to be used in "is this enabled"
4170 checks). This will be returned as a CGList with " &&\n" as the separator,
4173 objName is the name of the object that we're working with, because some of
4174 our test functions want that.
4176 ignoreSecureContext is used only for constructors in which the WebIDL interface
4177 itself is already marked as [SecureContext]. There is no need to do the work twice.
4180 pref
= idlobj
.getExtendedAttribute("Pref")
4182 assert isinstance(pref
, list) and len(pref
) == 1
4183 conditions
.append("StaticPrefs::%s()" % prefIdentifier(pref
[0]))
4184 if isChromeOnly(idlobj
):
4185 conditions
.append("nsContentUtils::ThreadsafeIsSystemCaller(%s)" % cxName
)
4186 func
= idlobj
.getExtendedAttribute("Func")
4188 assert isinstance(func
, list) and len(func
) == 1
4189 conditions
.append("%s(%s, %s)" % (func
[0], cxName
, objName
))
4190 trial
= idlobj
.getExtendedAttribute("Trial")
4192 assert isinstance(trial
, list) and len(trial
) == 1
4194 "OriginTrials::IsEnabled(%s, %s, OriginTrial::%s)"
4195 % (cxName
, objName
, trial
[0])
4197 if not ignoreSecureContext
and idlobj
.getExtendedAttribute("SecureContext"):
4199 "mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(%s, %s)"
4205 def getConditionList(idlobj
, cxName
, objName
, ignoreSecureContext
=False):
4207 Get the list of conditions from getRawConditionList
4208 See comment on getRawConditionList above for more info about arguments.
4210 The return value is a possibly-empty conjunctive CGList of conditions.
4212 conditions
= getRawConditionList(idlobj
, cxName
, objName
, ignoreSecureContext
)
4213 return CGList((CGGeneric(cond
) for cond
in conditions
), " &&\n")
4216 class CGConstructorEnabled(CGAbstractMethod
):
4218 A method for testing whether we should be exposing this interface object.
4219 This can perform various tests depending on what conditions are specified
4223 def __init__(self
, descriptor
):
4224 CGAbstractMethod
.__init
__(
4227 "ConstructorEnabled",
4229 [Argument("JSContext*", "aCx"), Argument("JS::Handle<JSObject*>", "aObj")],
4232 def definition_body(self
):
4233 body
= CGList([], "\n")
4235 iface
= self
.descriptor
.interface
4237 if not iface
.isExposedInWindow():
4238 exposedInWindowCheck
= dedent(
4240 MOZ_ASSERT(!NS_IsMainThread(), "Why did we even get called?");
4243 body
.append(CGGeneric(exposedInWindowCheck
))
4245 if iface
.isExposedInSomeButNotAllWorkers():
4246 workerGlobals
= sorted(iface
.getWorkerExposureSet())
4247 workerCondition
= CGList(
4249 CGGeneric('strcmp(name, "%s")' % workerGlobal
)
4250 for workerGlobal
in workerGlobals
4254 exposedInWorkerCheck
= fill(
4256 const char* name = JS::GetClass(aObj)->name;
4257 if (${workerCondition}) {
4261 workerCondition
=workerCondition
.define(),
4263 exposedInWorkerCheck
= CGGeneric(exposedInWorkerCheck
)
4264 if iface
.isExposedInWindow():
4265 exposedInWorkerCheck
= CGIfWrapper(
4266 exposedInWorkerCheck
, "!NS_IsMainThread()"
4268 body
.append(exposedInWorkerCheck
)
4270 conditions
= getConditionList(iface
, "aCx", "aObj")
4272 # We should really have some conditions
4273 assert len(body
) or len(conditions
)
4275 conditionsWrapper
= ""
4277 conditionsWrapper
= CGWrapper(
4278 conditions
, pre
="return ", post
=";\n", reindent
=True
4281 conditionsWrapper
= CGGeneric("return true;\n")
4283 body
.append(conditionsWrapper
)
4284 return body
.define()
4287 def StructuredCloneTag(name
):
4288 return "SCTAG_DOM_%s" % name
.upper()
4291 class CGSerializer(CGAbstractStaticMethod
):
4293 Implementation of serialization for things marked [Serializable].
4294 This gets stored in our DOMJSClass, so it can be static.
4296 The caller is expected to pass in the object whose DOMJSClass it
4297 used to get the serializer.
4300 def __init__(self
, descriptor
):
4302 Argument("JSContext*", "aCx"),
4303 Argument("JSStructuredCloneWriter*", "aWriter"),
4304 Argument("JS::Handle<JSObject*>", "aObj"),
4306 CGAbstractStaticMethod
.__init
__(self
, descriptor
, "Serialize", "bool", args
)
4308 def definition_body(self
):
4311 MOZ_ASSERT(IsDOMObject(aObj), "Non-DOM object passed");
4312 MOZ_ASSERT(GetDOMClass(aObj)->mSerializer == &Serialize,
4313 "Wrong object passed");
4314 return JS_WriteUint32Pair(aWriter, ${tag}, 0) &&
4315 UnwrapDOMObject<${type}>(aObj)->WriteStructuredClone(aCx, aWriter);
4317 tag
=StructuredCloneTag(self
.descriptor
.name
),
4318 type=self
.descriptor
.nativeType
,
4322 class CGDeserializer(CGAbstractMethod
):
4324 Implementation of deserialization for things marked [Serializable].
4325 This will need to be accessed from WebIDLSerializable, so can't be static.
4328 def __init__(self
, descriptor
):
4330 Argument("JSContext*", "aCx"),
4331 Argument("nsIGlobalObject*", "aGlobal"),
4332 Argument("JSStructuredCloneReader*", "aReader"),
4334 CGAbstractMethod
.__init
__(self
, descriptor
, "Deserialize", "JSObject*", args
)
4336 def definition_body(self
):
4337 # WrapObject has different signatures depending on whether
4338 # the object is wrappercached.
4339 if self
.descriptor
.wrapperCache
:
4342 result = obj->WrapObject(aCx, nullptr);
4351 if (!obj->WrapObject(aCx, nullptr, &result)) {
4359 // Protect the result from a moving GC in ~RefPtr
4360 JS::Rooted<JSObject*> result(aCx);
4361 { // Scope for the RefPtr
4362 RefPtr<${type}> obj = ${type}::ReadStructuredClone(aCx, aGlobal, aReader);
4370 type=self
.descriptor
.nativeType
,
4375 def CreateBindingJSObject(descriptor
):
4376 objDecl
= "BindingJSObjectCreator<%s> creator(aCx);\n" % descriptor
.nativeType
4378 # We don't always need to root obj, but there are a variety
4379 # of cases where we do, so for simplicity, just always root it.
4380 if descriptor
.proxy
:
4381 if descriptor
.interface
.getExtendedAttribute("LegacyOverrideBuiltIns"):
4382 assert not descriptor
.isMaybeCrossOriginObject()
4385 aObject->mExpandoAndGeneration.expando.setUndefined();
4386 JS::Rooted<JS::Value> expandoValue(aCx, JS::PrivateValue(&aObject->mExpandoAndGeneration));
4387 creator.CreateProxyObject(aCx, &sClass.mBase, DOMProxyHandler::getInstance(),
4388 proto, /* aLazyProto = */ false, aObject,
4389 expandoValue, aReflector);
4393 if descriptor
.isMaybeCrossOriginObject():
4401 creator.CreateProxyObject(aCx, &sClass.mBase, DOMProxyHandler::getInstance(),
4402 ${proto}, /* aLazyProto = */ ${lazyProto},
4403 aObject, JS::UndefinedHandleValue, aReflector);
4406 lazyProto
=lazyProto
,
4411 creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector);
4427 def InitUnforgeablePropertiesOnHolder(
4428 descriptor
, properties
, failureCode
, holderName
="unforgeableHolder"
4431 Define the unforgeable properties on the unforgeable holder for
4432 the interface represented by descriptor.
4434 properties is a PropertyArrays instance.
4438 properties
.unforgeableAttrs
.hasNonChromeOnly()
4439 or properties
.unforgeableAttrs
.hasChromeOnly()
4440 or properties
.unforgeableMethods
.hasNonChromeOnly()
4441 or properties
.unforgeableMethods
.hasChromeOnly()
4446 defineUnforgeableAttrs
= fill(
4448 if (!DefineLegacyUnforgeableAttributes(aCx, ${holderName}, %s)) {
4452 failureCode
=failureCode
,
4453 holderName
=holderName
,
4455 defineUnforgeableMethods
= fill(
4457 if (!DefineLegacyUnforgeableMethods(aCx, ${holderName}, %s)) {
4461 failureCode
=failureCode
,
4462 holderName
=holderName
,
4465 unforgeableMembers
= [
4466 (defineUnforgeableAttrs
, properties
.unforgeableAttrs
),
4467 (defineUnforgeableMethods
, properties
.unforgeableMethods
),
4469 for template
, array
in unforgeableMembers
:
4470 if array
.hasNonChromeOnly():
4471 unforgeables
.append(CGGeneric(template
% array
.variableName(False)))
4472 if array
.hasChromeOnly():
4473 unforgeables
.append(
4475 CGGeneric(template
% array
.variableName(True)),
4476 "nsContentUtils::ThreadsafeIsSystemCaller(aCx)",
4480 if descriptor
.interface
.getExtendedAttribute("LegacyUnforgeable"):
4481 # We do our undefined toPrimitive here, not as a regular property
4482 # because we don't have a concept of value props anywhere in IDL.
4483 unforgeables
.append(
4487 JS::Rooted<JS::PropertyKey> toPrimitive(aCx,
4488 JS::GetWellKnownSymbolKey(aCx, JS::SymbolCode::toPrimitive));
4489 if (!JS_DefinePropertyById(aCx, ${holderName}, toPrimitive,
4490 JS::UndefinedHandleValue,
4491 JSPROP_READONLY | JSPROP_PERMANENT)) {
4495 failureCode
=failureCode
,
4496 holderName
=holderName
,
4501 return CGWrapper(CGList(unforgeables
), pre
="\n")
4504 def CopyUnforgeablePropertiesToInstance(descriptor
, failureCode
):
4506 Copy the unforgeable properties from the unforgeable holder for
4507 this interface to the instance object we have.
4509 assert not descriptor
.isGlobal()
4511 if not descriptor
.hasLegacyUnforgeableMembers
:
4518 // Important: do unforgeable property setup after we have handed
4519 // over ownership of the C++ object to obj as needed, so that if
4520 // we fail and it ends up GCed it won't have problems in the
4521 // finalizer trying to drop its ownership of the C++ object.
4527 # For proxies, we want to define on the expando object, not directly on the
4528 # reflector, so we can make sure we don't get confused by named getters.
4529 if descriptor
.proxy
:
4534 JS::Rooted<JSObject*> expando(aCx,
4535 DOMProxyHandler::EnsureExpandoObject(aCx, aReflector));
4540 failureCode
=failureCode
,
4552 JS::Rooted<JSObject*> unforgeableHolder(aCx,
4553 &JS::GetReservedSlot(canonicalProto, DOM_INTERFACE_PROTO_SLOTS_BASE).toObject());
4554 if (!JS_InitializePropertiesFromCompatibleNativeObject(aCx, ${obj}, unforgeableHolder)) {
4559 failureCode
=failureCode
,
4564 return CGWrapper(CGList(copyCode
), pre
="\n").define()
4567 def AssertInheritanceChain(descriptor
):
4568 # We can skip the reinterpret_cast check for the descriptor's nativeType
4569 # if aObject is a pointer of that type.
4572 static_assert(std::is_same_v<decltype(aObject), ${nativeType}*>);
4574 nativeType
=descriptor
.nativeType
,
4576 iface
= descriptor
.interface
4578 iface
= iface
.parent
4579 desc
= descriptor
.getDescriptor(iface
.identifier
.name
)
4581 "MOZ_ASSERT(static_cast<%s*>(aObject) == \n"
4582 " reinterpret_cast<%s*>(aObject),\n"
4583 ' "Multiple inheritance for %s is broken.");\n'
4584 % (desc
.nativeType
, desc
.nativeType
, desc
.nativeType
)
4586 asserts
+= "MOZ_ASSERT(ToSupportsIsCorrect(aObject));\n"
4590 def InitMemberSlots(descriptor
, failureCode
):
4592 Initialize member slots on our JS object if we're supposed to have some.
4594 Note that this is called after the SetWrapper() call in the
4595 wrapperCache case, since that can affect how our getters behave
4596 and we plan to invoke them here. So if we fail, we need to
4599 if not descriptor
.interface
.hasMembersInSlots():
4603 if (!UpdateMemberSlots(aCx, aReflector, aObject)) {
4607 failureCode
=failureCode
,
4611 def DeclareProto(descriptor
, noGivenProto
=False):
4613 Declare the canonicalProto and proto we have for our wrapping operation.
4615 getCanonical
= dedent(
4617 JS::Handle<JSObject*> ${canonicalProto} = GetProtoObjectHandle(aCx);
4618 if (!${canonicalProto}) {
4625 return fill(getCanonical
, canonicalProto
="proto")
4627 getCanonical
= fill(getCanonical
, canonicalProto
="canonicalProto")
4629 preamble
= getCanonical
+ dedent(
4631 JS::Rooted<JSObject*> proto(aCx);
4634 if descriptor
.isMaybeCrossOriginObject():
4635 return preamble
+ dedent(
4637 MOZ_ASSERT(!aGivenProto,
4638 "Shouldn't have constructors on cross-origin objects");
4639 // Set proto to canonicalProto to avoid preserving our wrapper if
4640 // we don't have to.
4641 proto = canonicalProto;
4645 return preamble
+ dedent(
4648 proto = aGivenProto;
4649 // Unfortunately, while aGivenProto was in the compartment of aCx
4650 // coming in, we changed compartments to that of "parent" so may need
4651 // to wrap the proto here.
4652 if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) {
4653 if (!JS_WrapObject(aCx, &proto)) {
4658 proto = canonicalProto;
4664 class CGWrapWithCacheMethod(CGAbstractMethod
):
4666 Create a wrapper JSObject for a given native that implements nsWrapperCache.
4669 def __init__(self
, descriptor
):
4670 assert descriptor
.interface
.hasInterfacePrototypeObject()
4672 Argument("JSContext*", "aCx"),
4673 Argument(descriptor
.nativeType
+ "*", "aObject"),
4674 Argument("nsWrapperCache*", "aCache"),
4675 Argument("JS::Handle<JSObject*>", "aGivenProto"),
4676 Argument("JS::MutableHandle<JSObject*>", "aReflector"),
4678 CGAbstractMethod
.__init
__(self
, descriptor
, "Wrap", "bool", args
)
4680 def definition_body(self
):
4681 failureCode
= dedent(
4683 aCache->ReleaseWrapper(aObject);
4684 aCache->ClearWrapper();
4689 if self
.descriptor
.proxy
:
4690 finalize
= "DOMProxyHandler::getInstance()->finalize"
4692 finalize
= FINALIZE_HOOK_NAME
4696 static_assert(!std::is_base_of_v<NonRefcountedDOMObject, ${nativeType}>,
4697 "Shouldn't have wrappercached things that are not refcounted.");
4698 $*{assertInheritance}
4699 MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx));
4700 MOZ_ASSERT(!aCache->GetWrapper(),
4701 "You should probably not be using Wrap() directly; use "
4702 "GetOrCreateDOMReflector instead");
4704 MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
4705 "nsISupports must be on our primary inheritance chain");
4707 // If the wrapper cache contains a dead reflector then finalize that
4708 // now, ensuring that the finalizer for the old reflector always
4709 // runs before the new reflector is created and attached. This
4710 // avoids the awkward situation where there are multiple reflector
4711 // objects that contain pointers to the same native.
4713 if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) {
4714 ${finalize}(nullptr /* unused */, oldReflector);
4715 MOZ_ASSERT(!aCache->GetWrapperMaybeDead());
4718 JS::Rooted<JSObject*> global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject()));
4722 MOZ_ASSERT(JS_IsGlobalObject(global));
4723 JS::AssertObjectIsNotGray(global);
4725 // That might have ended up wrapping us already, due to the wonders
4726 // of XBL. Check for that, and bail out as needed.
4727 aReflector.set(aCache->GetWrapper());
4730 AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto);
4735 JSAutoRealm ar(aCx, global);
4740 aCache->SetWrapper(aReflector);
4743 creator.InitializationSucceeded();
4745 MOZ_ASSERT(aCache->GetWrapperPreserveColor() &&
4746 aCache->GetWrapperPreserveColor() == aReflector);
4747 // If proto != canonicalProto, we have to preserve our wrapper;
4748 // otherwise we won't be able to properly recreate it later, since
4749 // we won't know what proto to use. Note that we don't check
4750 // aGivenProto here, since it's entirely possible (and even
4751 // somewhat common) to have a non-null aGivenProto which is the
4752 // same as canonicalProto.
4753 if (proto != canonicalProto) {
4754 PreserveWrapper(aObject);
4759 nativeType
=self
.descriptor
.nativeType
,
4760 assertInheritance
=AssertInheritanceChain(self
.descriptor
),
4761 declareProto
=DeclareProto(self
.descriptor
),
4762 createObject
=CreateBindingJSObject(self
.descriptor
),
4763 unforgeable
=CopyUnforgeablePropertiesToInstance(
4764 self
.descriptor
, failureCode
4766 slots
=InitMemberSlots(self
.descriptor
, failureCode
),
4771 class CGWrapMethod(CGAbstractMethod
):
4772 def __init__(self
, descriptor
):
4773 # XXX can we wrap if we don't have an interface prototype object?
4774 assert descriptor
.interface
.hasInterfacePrototypeObject()
4776 Argument("JSContext*", "aCx"),
4777 Argument("T*", "aObject"),
4778 Argument("JS::Handle<JSObject*>", "aGivenProto"),
4780 CGAbstractMethod
.__init
__(
4787 templateArgs
=["class T"],
4790 def definition_body(self
):
4793 JS::Rooted<JSObject*> reflector(aCx);
4794 return Wrap(aCx, aObject, aObject, aGivenProto, &reflector) ? reflector.get() : nullptr;
4799 class CGWrapNonWrapperCacheMethod(CGAbstractMethod
):
4801 Create a wrapper JSObject for a given native that does not implement
4805 def __init__(self
, descriptor
, static
=False, signatureOnly
=False):
4806 # XXX can we wrap if we don't have an interface prototype object?
4807 assert descriptor
.interface
.hasInterfacePrototypeObject()
4808 self
.noGivenProto
= (
4809 descriptor
.interface
.isIteratorInterface()
4810 or descriptor
.interface
.isAsyncIteratorInterface()
4813 Argument("JSContext*", "aCx"),
4814 Argument(descriptor
.nativeType
+ "*", "aObject"),
4816 if not self
.noGivenProto
:
4817 args
.append(Argument("JS::Handle<JSObject*>", "aGivenProto"))
4818 args
.append(Argument("JS::MutableHandle<JSObject*>", "aReflector"))
4819 CGAbstractMethod
.__init
__(
4826 signatureOnly
=signatureOnly
,
4829 def definition_body(self
):
4830 failureCode
= "return false;\n"
4832 declareProto
= DeclareProto(self
.descriptor
, noGivenProto
=self
.noGivenProto
)
4833 if self
.noGivenProto
:
4834 assertGivenProto
= ""
4836 assertGivenProto
= dedent(
4838 MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx));
4844 $*{assertGivenProto}
4846 JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
4855 creator.InitializationSucceeded();
4858 assertions
=AssertInheritanceChain(self
.descriptor
),
4859 assertGivenProto
=assertGivenProto
,
4860 declareProto
=declareProto
,
4861 createObject
=CreateBindingJSObject(self
.descriptor
),
4862 unforgeable
=CopyUnforgeablePropertiesToInstance(
4863 self
.descriptor
, failureCode
4865 slots
=InitMemberSlots(self
.descriptor
, failureCode
),
4869 class CGWrapGlobalMethod(CGAbstractMethod
):
4871 Create a wrapper JSObject for a global. The global must implement
4874 properties should be a PropertyArrays instance.
4877 def __init__(self
, descriptor
, properties
):
4879 descriptor
.interface
.hasInterfacePrototypeObject()
4880 or descriptor
.hasOrdinaryObjectPrototype()
4883 Argument("JSContext*", "aCx"),
4884 Argument(descriptor
.nativeType
+ "*", "aObject"),
4885 Argument("nsWrapperCache*", "aCache"),
4886 Argument("JS::RealmOptions&", "aOptions"),
4887 Argument("JSPrincipals*", "aPrincipal"),
4888 Argument("JS::MutableHandle<JSObject*>", "aReflector"),
4890 CGAbstractMethod
.__init
__(self
, descriptor
, "Wrap", "bool", args
)
4891 self
.descriptor
= descriptor
4892 self
.properties
= properties
4894 def definition_body(self
):
4895 if self
.properties
.hasNonChromeOnly():
4896 properties
= "sNativeProperties.Upcast()"
4898 properties
= "nullptr"
4899 if self
.properties
.hasChromeOnly():
4900 chromeProperties
= "nsContentUtils::ThreadsafeIsSystemCaller(aCx) ? sChromeOnlyNativeProperties.Upcast() : nullptr"
4902 chromeProperties
= "nullptr"
4904 failureCode
= dedent(
4906 aCache->ReleaseWrapper(aObject);
4907 aCache->ClearWrapper();
4912 if self
.descriptor
.hasLegacyUnforgeableMembers
:
4913 unforgeable
= InitUnforgeablePropertiesOnHolder(
4914 self
.descriptor
, self
.properties
, failureCode
, "aReflector"
4919 if self
.descriptor
.hasOrdinaryObjectPrototype():
4920 getProto
= "JS::GetRealmObjectPrototypeHandle"
4922 getProto
= "GetProtoObjectHandle"
4926 MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
4927 "nsISupports must be on our primary inheritance chain");
4929 if (!CreateGlobal<${nativeType}, ${getProto}>(aCx,
4939 // aReflector is a new global, so has a new realm. Enter it
4940 // before doing anything with it.
4941 JSAutoRealm ar(aCx, aReflector);
4943 if (!DefineProperties(aCx, aReflector, ${properties}, ${chromeProperties})) {
4952 assertions
=AssertInheritanceChain(self
.descriptor
),
4953 nativeType
=self
.descriptor
.nativeType
,
4955 properties
=properties
,
4956 chromeProperties
=chromeProperties
,
4957 failureCode
=failureCode
,
4958 unforgeable
=unforgeable
,
4959 slots
=InitMemberSlots(self
.descriptor
, failureCode
),
4963 class CGUpdateMemberSlotsMethod(CGAbstractStaticMethod
):
4964 def __init__(self
, descriptor
):
4966 Argument("JSContext*", "aCx"),
4967 Argument("JS::Handle<JSObject*>", "aWrapper"),
4968 Argument(descriptor
.nativeType
+ "*", "aObject"),
4970 CGAbstractStaticMethod
.__init
__(
4971 self
, descriptor
, "UpdateMemberSlots", "bool", args
4974 def definition_body(self
):
4975 body
= "JS::Rooted<JS::Value> temp(aCx);\n" "JSJitGetterCallArgs args(&temp);\n"
4976 for m
in self
.descriptor
.interface
.members
:
4977 if m
.isAttr() and m
.getExtendedAttribute("StoreInSlot"):
4978 # Skip doing this for the "window" and "self" attributes on the
4979 # Window interface, because those can't be gotten safely until
4980 # we have hooked it up correctly to the outer window. The
4981 # window code handles doing the get itself.
4982 if self
.descriptor
.interface
.identifier
.name
== "Window" and (
4983 m
.identifier
.name
== "window" or m
.identifier
.name
== "self"
4989 static_assert(${slot} < JS::shadow::Object::MAX_FIXED_SLOTS,
4990 "Not enough fixed slots to fit '${interface}.${member}. Ion's visitGetDOMMemberV/visitGetDOMMemberT assume StoreInSlot things are all in fixed slots.");
4991 if (!get_${member}(aCx, aWrapper, aObject, args)) {
4994 // Getter handled setting our reserved slots
4996 slot
=memberReservedSlot(m
, self
.descriptor
),
4997 interface
=self
.descriptor
.interface
.identifier
.name
,
4998 member
=m
.identifier
.name
,
5001 body
+= "\nreturn true;\n"
5005 class CGClearCachedValueMethod(CGAbstractMethod
):
5006 def __init__(self
, descriptor
, member
):
5007 self
.member
= member
5008 # If we're StoreInSlot, we'll need to call the getter
5009 if member
.getExtendedAttribute("StoreInSlot"):
5010 args
= [Argument("JSContext*", "aCx")]
5015 args
.append(Argument(descriptor
.nativeType
+ "*", "aObject"))
5016 name
= MakeClearCachedValueNativeName(member
)
5017 CGAbstractMethod
.__init
__(self
, descriptor
, name
, returnType
, args
)
5019 def definition_body(self
):
5020 slotIndex
= memberReservedSlot(self
.member
, self
.descriptor
)
5021 clearCachedValue
= fill(
5023 JS::SetReservedSlot(obj, ${slotIndex}, JS::UndefinedValue());
5025 slotIndex
=slotIndex
,
5027 if self
.member
.getExtendedAttribute("StoreInSlot"):
5028 # We have to root things and save the old value in case
5029 # regetting fails, so we can restore it.
5030 declObj
= "JS::Rooted<JSObject*> obj(aCx);\n"
5031 noopRetval
= " true"
5033 "JS::Rooted<JS::Value> oldValue(aCx, JS::GetReservedSlot(obj, %s));\n"
5038 JS::Rooted<JS::Value> temp(aCx);
5039 JSJitGetterCallArgs args(&temp);
5040 JSAutoRealm ar(aCx, obj);
5041 if (!get_${name}(aCx, obj, aObject, args)) {
5042 JS::SetReservedSlot(obj, ${slotIndex}, oldValue);
5047 name
=self
.member
.identifier
.name
,
5048 slotIndex
=slotIndex
,
5051 declObj
= "JSObject* obj;\n"
5054 if self
.member
.getExtendedAttribute(
5055 "ReflectedHTMLAttributeReturningFrozenArray"
5057 clearCachedValue
= fill(
5059 ReflectedHTMLAttributeSlots::Clear(obj, ${arrayIndex});
5061 arrayIndex
=reflectedHTMLAttributesArrayIndex(
5062 self
.descriptor
, self
.member
5067 if self
.descriptor
.wantsXrays
:
5068 if self
.member
.getExtendedAttribute("StoreInSlot"):
5069 cx
= "JS::RootingContext::get(aCx)"
5072 if self
.member
.getExtendedAttribute(
5073 "ReflectedHTMLAttributeReturningFrozenArray"
5075 clearXrayExpandoSlots
= fill(
5077 ReflectedHTMLAttributeSlots::ClearInXrays(${cx}, obj, ${arrayIndex});
5080 arrayIndex
=reflectedHTMLAttributesArrayIndex(
5081 self
.descriptor
, self
.member
5085 clearXrayExpandoSlots
= fill(
5087 ClearXrayExpandoSlots(${cx}, obj, ${xraySlotIndex});
5090 xraySlotIndex
=memberXrayExpandoReservedSlot(
5091 self
.member
, self
.descriptor
5095 clearXrayExpandoSlots
= ""
5100 obj = aObject->GetWrapper();
5102 return${noopRetval};
5105 $*{clearCachedValue}
5106 $*{clearXrayExpandoSlots}
5110 noopRetval
=noopRetval
,
5111 saveMember
=saveMember
,
5112 slotIndex
=slotIndex
,
5113 clearCachedValue
=clearCachedValue
,
5114 clearXrayExpandoSlots
=clearXrayExpandoSlots
,
5115 regetMember
=regetMember
,
5119 class CGCrossOriginProperties(CGThing
):
5120 def __init__(self
, descriptor
):
5122 chromeOnlyAttrs
= []
5124 chromeOnlyMethods
= []
5125 for m
in descriptor
.interface
.members
:
5127 m
.getExtendedAttribute("CrossOriginReadable")
5128 or m
.getExtendedAttribute("CrossOriginWritable")
5132 "Don't know how to deal with static method %s"
5135 if PropertyDefiner
.getControllingCondition(
5139 "Don't know how to deal with disabler for %s"
5142 if len(m
.bindingAliases
) > 0:
5144 "Don't know how to deal with aliases for %s" % m
.identifier
.name
5146 if m
.getExtendedAttribute("ChromeOnly") is not None:
5147 chromeOnlyAttrs
.extend(AttrDefiner
.attrData(m
, overrideFlags
="0"))
5149 attrs
.extend(AttrDefiner
.attrData(m
, overrideFlags
="0"))
5150 elif m
.isMethod() and m
.getExtendedAttribute("CrossOriginCallable"):
5153 "Don't know how to deal with static method %s"
5156 if PropertyDefiner
.getControllingCondition(
5160 "Don't know how to deal with disabler for %s"
5163 if len(m
.aliases
) > 0:
5165 "Don't know how to deal with aliases for %s" % m
.identifier
.name
5167 if m
.getExtendedAttribute("ChromeOnly") is not None:
5168 chromeOnlyMethods
.append(
5169 MethodDefiner
.methodData(
5170 m
, descriptor
, overrideFlags
="JSPROP_READONLY"
5175 MethodDefiner
.methodData(
5176 m
, descriptor
, overrideFlags
="JSPROP_READONLY"
5181 self
.attributeSpecs
, _
= PropertyDefiner
.generatePrefableArrayValues(
5184 AttrDefiner
.formatSpec
,
5186 AttrDefiner
.condition
,
5187 functools
.partial(AttrDefiner
.specData
, crossOriginOnly
=True),
5190 self
.attributeSpecs
= [" JS_PS_END\n"]
5191 if len(methods
) > 0:
5192 self
.methodSpecs
, _
= PropertyDefiner
.generatePrefableArrayValues(
5195 MethodDefiner
.formatSpec
,
5197 MethodDefiner
.condition
,
5198 MethodDefiner
.specData
,
5201 self
.methodSpecs
= [" JS_FS_END\n"]
5203 if len(chromeOnlyAttrs
) > 0:
5205 self
.chromeOnlyAttributeSpecs
,
5207 ) = PropertyDefiner
.generatePrefableArrayValues(
5210 AttrDefiner
.formatSpec
,
5212 AttrDefiner
.condition
,
5213 functools
.partial(AttrDefiner
.specData
, crossOriginOnly
=True),
5216 self
.chromeOnlyAttributeSpecs
= []
5217 if len(chromeOnlyMethods
) > 0:
5218 self
.chromeOnlyMethodSpecs
, _
= PropertyDefiner
.generatePrefableArrayValues(
5221 MethodDefiner
.formatSpec
,
5223 MethodDefiner
.condition
,
5224 MethodDefiner
.specData
,
5227 self
.chromeOnlyMethodSpecs
= []
5232 extern const CrossOriginProperties sCrossOriginProperties;
5237 def defineChromeOnly(name
, specs
, specType
):
5239 return ("", "nullptr")
5240 name
= "sChromeOnlyCrossOrigin" + name
5243 static const ${specType} ${name}[] = {
5249 specs
=",\n".join(specs
),
5251 return (define
, name
)
5253 chromeOnlyAttributes
= defineChromeOnly(
5254 "Attributes", self
.chromeOnlyAttributeSpecs
, "JSPropertySpec"
5256 chromeOnlyMethods
= defineChromeOnly(
5257 "Methods", self
.chromeOnlyMethodSpecs
, "JSFunctionSpec"
5261 static const JSPropertySpec sCrossOriginAttributes[] = {
5264 static const JSFunctionSpec sCrossOriginMethods[] = {
5267 $*{chromeOnlyAttributeSpecs}
5268 $*{chromeOnlyMethodSpecs}
5269 const CrossOriginProperties sCrossOriginProperties = {
5270 sCrossOriginAttributes,
5271 sCrossOriginMethods,
5272 ${chromeOnlyAttributes},
5273 ${chromeOnlyMethods}
5276 attributeSpecs
=",\n".join(self
.attributeSpecs
),
5277 methodSpecs
=",\n".join(self
.methodSpecs
),
5278 chromeOnlyAttributeSpecs
=chromeOnlyAttributes
[0],
5279 chromeOnlyMethodSpecs
=chromeOnlyMethods
[0],
5280 chromeOnlyAttributes
=chromeOnlyAttributes
[1],
5281 chromeOnlyMethods
=chromeOnlyMethods
[1],
5285 class CGCycleCollectionTraverseForOwningUnionMethod(CGAbstractMethod
):
5287 ImplCycleCollectionUnlink for owning union type.
5290 def __init__(self
, type):
5293 Argument("nsCycleCollectionTraversalCallback&", "aCallback"),
5294 Argument("%s&" % CGUnionStruct
.unionTypeName(type, True), "aUnion"),
5295 Argument("const char*", "aName"),
5296 Argument("uint32_t", "aFlags", "0"),
5298 CGAbstractMethod
.__init
__(
5299 self
, None, "ImplCycleCollectionTraverse", "void", args
5303 return self
.type.getDeps()
5305 def definition_body(self
):
5307 getUnionMemberName(t
)
5308 for t
in self
.type.flatMemberTypes
5309 if idlTypeNeedsCycleCollection(t
)
5313 conditionTemplate
= "aUnion.Is%s()"
5314 functionCallTemplate
= (
5315 'ImplCycleCollectionTraverse(aCallback, aUnion.GetAs%s(), "m%s", aFlags);\n'
5319 CGIfWrapper(CGGeneric(functionCallTemplate
% (m
, m
)), conditionTemplate
% m
)
5320 for m
in memberNames
5323 return CGElseChain(ifStaments
).define()
5326 class CGCycleCollectionUnlinkForOwningUnionMethod(CGAbstractMethod
):
5328 ImplCycleCollectionUnlink for owning union type.
5331 def __init__(self
, type):
5333 args
= [Argument("%s&" % CGUnionStruct
.unionTypeName(type, True), "aUnion")]
5334 CGAbstractMethod
.__init
__(self
, None, "ImplCycleCollectionUnlink", "void", args
)
5337 return self
.type.getDeps()
5339 def definition_body(self
):
5340 return "aUnion.Uninit();\n"
5344 IDLType
.Tags
.bool: "bool",
5345 IDLType
.Tags
.int8
: "int8_t",
5346 IDLType
.Tags
.int16
: "int16_t",
5347 IDLType
.Tags
.int32
: "int32_t",
5348 IDLType
.Tags
.int64
: "int64_t",
5349 IDLType
.Tags
.uint8
: "uint8_t",
5350 IDLType
.Tags
.uint16
: "uint16_t",
5351 IDLType
.Tags
.uint32
: "uint32_t",
5352 IDLType
.Tags
.uint64
: "uint64_t",
5353 IDLType
.Tags
.unrestricted_float
: "float",
5354 IDLType
.Tags
.float: "float",
5355 IDLType
.Tags
.unrestricted_double
: "double",
5356 IDLType
.Tags
.double
: "double",
5360 IDLType
.Tags
.int8
: "",
5361 IDLType
.Tags
.uint8
: "",
5362 IDLType
.Tags
.int16
: "",
5363 IDLType
.Tags
.uint16
: "",
5364 IDLType
.Tags
.int32
: "",
5365 IDLType
.Tags
.uint32
: "U",
5366 IDLType
.Tags
.int64
: "LL",
5367 IDLType
.Tags
.uint64
: "ULL",
5368 IDLType
.Tags
.unrestricted_float
: "F",
5369 IDLType
.Tags
.float: "F",
5370 IDLType
.Tags
.unrestricted_double
: "",
5371 IDLType
.Tags
.double
: "",
5375 def numericValue(t
, v
):
5376 if t
== IDLType
.Tags
.unrestricted_double
or t
== IDLType
.Tags
.unrestricted_float
:
5377 typeName
= builtinNames
[t
]
5378 if v
== float("inf"):
5379 return "mozilla::PositiveInfinity<%s>()" % typeName
5380 if v
== float("-inf"):
5381 return "mozilla::NegativeInfinity<%s>()" % typeName
5383 return "mozilla::UnspecifiedNaN<%s>()" % typeName
5384 return "%s%s" % (v
, numericSuffixes
[t
])
5387 class CastableObjectUnwrapper
:
5389 A class for unwrapping an object stored in a JS Value (or
5390 MutableHandle<Value> or Handle<Value>) named by the "source" and
5391 "mutableSource" arguments based on the passed-in descriptor and storing it
5392 in a variable called by the name in the "target" argument. The "source"
5393 argument should be able to produce a Value or Handle<Value>; the
5394 "mutableSource" argument should be able to produce a MutableHandle<Value>
5396 codeOnFailure is the code to run if unwrapping fails.
5398 If isCallbackReturnValue is "JSImpl" and our descriptor is also
5399 JS-implemented, fall back to just creating the right object if what we
5400 have isn't one already.
5411 isCallbackReturnValue
=False,
5413 self
.substitution
= {
5414 "type": descriptor
.nativeType
,
5415 "protoID": "prototypes::id::" + descriptor
.name
,
5417 "codeOnFailure": codeOnFailure
,
5419 "mutableSource": mutableSource
,
5422 if isCallbackReturnValue
== "JSImpl" and descriptor
.interface
.isJSImplemented():
5423 exceptionCode
= exceptionCode
or codeOnFailure
5424 self
.substitution
["codeOnFailure"] = fill(
5426 // Be careful to not wrap random DOM objects here, even if
5427 // they're wrapped in opaque security wrappers for some reason.
5428 // XXXbz Wish we could check for a JS-implemented object
5429 // that already has a content reflection...
5430 if (!IsDOMObject(js::UncheckedUnwrap(&${source}.toObject()))) {
5431 nsCOMPtr<nsIGlobalObject> contentGlobal;
5432 JS::Rooted<JSObject*> callback(cx, CallbackOrNull());
5434 !GetContentGlobalForJSImplementedObject(cx, callback, getter_AddRefs(contentGlobal))) {
5437 JS::Rooted<JSObject*> jsImplSourceObj(cx, &${source}.toObject());
5438 MOZ_RELEASE_ASSERT(!js::IsWrapper(jsImplSourceObj),
5439 "Don't return JS implementations from other compartments");
5440 JS::Rooted<JSObject*> jsImplSourceGlobal(cx, JS::GetNonCCWObjectGlobal(jsImplSourceObj));
5441 ${target} = new ${type}(jsImplSourceObj, jsImplSourceGlobal, contentGlobal);
5446 exceptionCode
=exceptionCode
,
5447 **self
.substitution
,
5450 self
.substitution
["codeOnFailure"] = codeOnFailure
5453 substitution
= self
.substitution
.copy()
5454 substitution
["codeOnFailure"] %= {
5455 "securityError": "rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO"
5460 // Our JSContext should be in the right global to do unwrapping in.
5461 nsresult rv = UnwrapObject<${protoID}, ${type}>(${mutableSource}, ${target}, cx);
5462 if (NS_FAILED(rv)) {
5471 class FailureFatalCastableObjectUnwrapper(CastableObjectUnwrapper
):
5473 As CastableObjectUnwrapper, but defaulting to throwing if unwrapping fails
5483 isCallbackReturnValue
,
5486 CastableObjectUnwrapper
.__init
__(
5492 'cx.ThrowErrorMessage<MSG_DOES_NOT_IMPLEMENT_INTERFACE>("%s", "%s");\n'
5494 % (sourceDescription
, descriptor
.interface
.identifier
.name
, exceptionCode
),
5496 isCallbackReturnValue
,
5500 def getCallbackConversionInfo(
5501 type, idlObject
, isMember
, isCallbackReturnValue
, isOptional
5504 Returns a tuple containing the declType, declArgs, and basic
5505 conversion for the given callback type, with the given callback
5506 idl object in the given context (isMember/isCallbackReturnValue/isOptional).
5508 name
= idlObject
.identifier
.name
5510 # We can't use fast callbacks if isOptional because then we get an
5511 # Optional<RootedCallback> thing, which is not transparent to consumers.
5513 (not isMember
or isMember
== "Union")
5514 and not isCallbackReturnValue
5518 name
= "binding_detail::Fast%s" % name
5520 args
= "&${val}.toObject(), JS::CurrentGlobalOrNull(cx)"
5524 JS::Rooted<JSObject*> tempRoot(cx, &${val}.toObject());
5525 JS::Rooted<JSObject*> tempGlobalRoot(cx, JS::CurrentGlobalOrNull(cx));
5528 args
= "cx, tempRoot, tempGlobalRoot, GetIncumbentGlobal()"
5530 if type.nullable() or isCallbackReturnValue
:
5531 declType
= CGGeneric("RefPtr<%s>" % name
)
5533 declType
= CGGeneric("OwningNonNull<%s>" % name
)
5536 declType
= CGTemplatedType("RootedCallback", declType
)
5543 { // scope for tempRoot and tempGlobalRoot if needed
5545 $${declName} = new ${name}(${args});
5552 return (declType
, declArgs
, conversion
)
5555 class JSToNativeConversionInfo
:
5557 An object representing information about a JS-to-native conversion.
5565 dealWithOptional
=False,
5570 template: A string representing the conversion code. This will have
5571 template substitution performed on it as follows:
5573 ${val} is a handle to the JS::Value in question
5574 ${maybeMutableVal} May be a mutable handle to the JS::Value in
5575 question. This is only OK to use if ${val} is
5576 known to not be undefined.
5577 ${holderName} replaced by the holder's name, if any
5578 ${declName} replaced by the declaration's name
5579 ${haveValue} replaced by an expression that evaluates to a boolean
5580 for whether we have a JS::Value. Only used when
5581 defaultValue is not None or when True is passed for
5582 checkForValue to instantiateJSToNativeConversion.
5583 This expression may not be already-parenthesized, so if
5584 you use it with && or || make sure to put parens
5586 ${passedToJSImpl} replaced by an expression that evaluates to a boolean
5587 for whether this value is being passed to a JS-
5588 implemented interface.
5590 declType: A CGThing representing the native C++ type we're converting
5591 to. This is allowed to be None if the conversion code is
5592 supposed to be used as-is.
5594 holderType: A CGThing representing the type of a "holder" which will
5595 hold a possible reference to the C++ thing whose type we
5596 returned in declType, or None if no such holder is needed.
5598 dealWithOptional: A boolean indicating whether the caller has to do
5599 optional-argument handling. This should only be set
5600 to true if the JS-to-native conversion is being done
5601 for an optional argument or dictionary member with no
5602 default value and if the returned template expects
5603 both declType and holderType to be wrapped in
5604 Optional<>, with ${declName} and ${holderName}
5605 adjusted to point to the Value() of the Optional, and
5606 Construct() calls to be made on the Optional<>s as
5609 declArgs: If not None, the arguments to pass to the ${declName}
5610 constructor. These will have template substitution performed
5611 on them so you can use things like ${val}. This is a
5612 single string, not a list of strings.
5614 holderArgs: If not None, the arguments to pass to the ${holderName}
5615 constructor. These will have template substitution
5616 performed on them so you can use things like ${val}.
5617 This is a single string, not a list of strings.
5619 ${declName} must be in scope before the code from 'template' is entered.
5621 If holderType is not None then ${holderName} must be in scope before
5622 the code from 'template' is entered.
5624 assert isinstance(template
, str)
5625 assert declType
is None or isinstance(declType
, CGThing
)
5626 assert holderType
is None or isinstance(holderType
, CGThing
)
5627 self
.template
= template
5628 self
.declType
= declType
5629 self
.holderType
= holderType
5630 self
.dealWithOptional
= dealWithOptional
5631 self
.declArgs
= declArgs
5632 self
.holderArgs
= holderArgs
5635 def getHandleDefault(defaultValue
):
5636 tag
= defaultValue
.type.tag()
5637 if tag
in numericSuffixes
:
5638 # Some numeric literals require a suffix to compile without warnings
5639 return numericValue(tag
, defaultValue
.value
)
5640 assert tag
== IDLType
.Tags
.bool
5641 return toStringBool(defaultValue
.value
)
5644 def handleDefaultStringValue(defaultValue
, method
):
5646 Returns a string which ends up calling 'method' with a (char_t*, length)
5647 pair that sets this string default value. This string is suitable for
5648 passing as the second argument of handleDefault.
5651 defaultValue
.type.isDOMString()
5652 or defaultValue
.type.isUSVString()
5653 or defaultValue
.type.isUTF8String()
5654 or defaultValue
.type.isByteString()
5656 # There shouldn't be any non-ASCII or embedded nulls in here; if
5657 # it ever sneaks in we will need to think about how to properly
5658 # represent that in the C++.
5659 assert all(ord(c
) < 128 and ord(c
) > 0 for c
in defaultValue
.value
)
5660 if defaultValue
.type.isByteString() or defaultValue
.type.isUTF8String():
5666 ${method}(${prefix}"${value}");
5670 value
=defaultValue
.value
,
5674 def recordKeyType(recordType
):
5675 assert recordType
.keyType
.isString()
5676 if recordType
.keyType
.isByteString() or recordType
.keyType
.isUTF8String():
5681 def recordKeyDeclType(recordType
):
5682 return CGGeneric(recordKeyType(recordType
))
5685 def initializerForType(type):
5687 Get the right initializer for the given type for a data location where we
5688 plan to then initialize it from a JS::Value. Some types need to always be
5689 initialized even before we start the JS::Value-to-IDL-value conversion.
5691 Returns a string or None if no initialization is needed.
5695 # We could probably return CGDictionary.getNonInitializingCtorArg() for the
5696 # dictionary case, but code outside DictionaryBase subclasses can't use
5697 # that, so we can't do it across the board.
5701 # If this function is modified, modify CGNativeMember.getArg and
5702 # CGNativeMember.getRetvalInfo accordingly. The latter cares about the decltype
5703 # and holdertype we end up using, because it needs to be able to return the code
5704 # that will convert those to the actual return value of the callback function.
5705 def getJSToNativeConversionInfo(
5709 isDefinitelyObject
=False,
5712 invalidEnumValueFatal
=True,
5714 isNullOrUndefined
=False,
5715 isKnownMissing
=False,
5717 lenientFloatCode
=None,
5718 allowTreatNonCallableAsNull
=False,
5719 isCallbackReturnValue
=False,
5720 sourceDescription
="value",
5724 Get a template for converting a JS value to a native object based on the
5725 given type and descriptor. If failureCode is given, then we're actually
5726 testing whether we can convert the argument to the desired type. That
5727 means that failures to convert due to the JS value being the wrong type of
5728 value need to use failureCode instead of throwing exceptions. Failures to
5729 convert that are due to JS exceptions (from toString or valueOf methods) or
5730 out of memory conditions need to throw exceptions no matter what
5731 failureCode is. However what actually happens when throwing an exception
5732 can be controlled by exceptionCode. The only requirement on that is that
5733 exceptionCode must end up doing a return, and every return from this
5734 function must happen via exceptionCode if exceptionCode is not None.
5736 If isDefinitelyObject is True, that means we have a value and the value
5737 tests true for isObject(), so we have no need to recheck that.
5739 If isNullOrUndefined is True, that means we have a value and the value
5740 tests true for isNullOrUndefined(), so we have no need to recheck that.
5742 If isKnownMissing is True, that means that we are known-missing, and for
5743 cases when we have a default value we only need to output the default value.
5745 if isMember is not False, we're being converted from a property of some JS
5746 object, not from an actual method argument, so we can't rely on our jsval
5747 being rooted or outliving us in any way. Callers can pass "Dictionary",
5748 "Variadic", "Sequence", "Union", or "OwningUnion" to indicate that the conversion
5749 is for something that is a dictionary member, a variadic argument, a sequence,
5750 an union, or an owning union respectively.
5751 XXX Once we swtich *Rooter to Rooted* for Record and Sequence type entirely,
5752 we could remove "Union" from isMember.
5754 If isOptional is true, then we are doing conversion of an optional
5755 argument with no default value.
5757 invalidEnumValueFatal controls whether an invalid enum value conversion
5758 attempt will throw (if true) or simply return without doing anything (if
5761 If defaultValue is not None, it's the IDL default value for this conversion
5763 If isEnforceRange is true, we're converting an integer and throwing if the
5764 value is out of range.
5766 If isClamp is true, we're converting an integer and clamping if the
5767 value is out of range.
5769 If isAllowShared is false, we're converting a buffer source and throwing if
5770 it is a SharedArrayBuffer or backed by a SharedArrayBuffer.
5772 If lenientFloatCode is not None, it should be used in cases when
5773 we're a non-finite float that's not unrestricted.
5775 If allowTreatNonCallableAsNull is true, then [TreatNonCallableAsNull] and
5776 [LegacyTreatNonObjectAsNull] extended attributes on nullable callback functions
5779 If isCallbackReturnValue is "JSImpl" or "Callback", then the declType may be
5780 adjusted to make it easier to return from a callback. Since that type is
5781 never directly observable by any consumers of the callback code, this is OK.
5782 Furthermore, if isCallbackReturnValue is "JSImpl", that affects the behavior
5783 of the FailureFatalCastableObjectUnwrapper conversion; this is used for
5784 implementing auto-wrapping of JS-implemented return values from a
5785 JS-implemented interface.
5787 sourceDescription is a description of what this JS value represents, to be
5788 used in error reporting. Callers should assume that it might get placed in
5789 the middle of a sentence. If it ends up at the beginning of a sentence, its
5790 first character will be automatically uppercased.
5792 The return value from this function is a JSToNativeConversionInfo.
5794 # If we have a defaultValue then we're not actually optional for
5795 # purposes of what we need to be declared as.
5796 assert defaultValue
is None or not isOptional
5798 # Also, we should not have a defaultValue if we know we're an object
5799 assert not isDefinitelyObject
or defaultValue
is None
5801 # And we can't both be an object and be null or undefined
5802 assert not isDefinitelyObject
or not isNullOrUndefined
5804 isClamp
= type.hasClamp()
5805 isEnforceRange
= type.hasEnforceRange()
5806 isAllowShared
= type.hasAllowShared()
5808 # If exceptionCode is not set, we'll just rethrow the exception we got.
5809 # Note that we can't just set failureCode to exceptionCode, because setting
5810 # failureCode will prevent pending exceptions from being set in cases when
5811 # they really should be!
5812 if exceptionCode
is None:
5813 exceptionCode
= "return false;\n"
5815 # Unfortunately, .capitalize() on a string will lowercase things inside the
5816 # string, which we do not want.
5817 def firstCap(string
):
5818 return string
[0].upper() + string
[1:]
5820 # Helper functions for dealing with failures due to the JS value being the
5821 # wrong type of value
5822 def onFailureNotAnObject(failureCode
):
5826 'cx.ThrowErrorMessage<MSG_NOT_OBJECT>("%s");\n'
5827 "%s" % (firstCap(sourceDescription
), exceptionCode
)
5831 def onFailureBadType(failureCode
, typeName
):
5835 'cx.ThrowErrorMessage<MSG_DOES_NOT_IMPLEMENT_INTERFACE>("%s", "%s");\n'
5836 "%s" % (firstCap(sourceDescription
), typeName
, exceptionCode
)
5840 # It's a failure in the committed-to conversion, not a failure to match up
5841 # to a type, so we don't want to use failureCode in here. We want to just
5842 # throw an exception unconditionally.
5843 def onFailureIsShared():
5845 'cx.ThrowErrorMessage<MSG_TYPEDARRAY_IS_SHARED>("%s");\n'
5846 "%s" % (firstCap(sourceDescription
), exceptionCode
)
5849 def onFailureIsLarge():
5851 'cx.ThrowErrorMessage<MSG_TYPEDARRAY_IS_LARGE>("%s");\n'
5852 "%s" % (firstCap(sourceDescription
), exceptionCode
)
5855 def onFailureIsResizable():
5857 'cx.ThrowErrorMessage<MSG_TYPEDARRAY_IS_RESIZABLE>("%s");\n'
5858 "%s" % (firstCap(sourceDescription
), exceptionCode
)
5861 def onFailureNotCallable(failureCode
):
5865 'cx.ThrowErrorMessage<MSG_NOT_CALLABLE>("%s");\n'
5866 "%s" % (firstCap(sourceDescription
), exceptionCode
)
5870 # A helper function for handling default values. Takes a template
5871 # body and the C++ code to set the default value and wraps the
5872 # given template body in handling for the default value.
5873 def handleDefault(template
, setDefault
):
5874 if defaultValue
is None:
5880 // scope for any temporaries our default value setting needs.
5884 setDefault
=setDefault
,
5888 if ($${haveValue}) {
5894 templateBody
=template
,
5895 setDefault
=setDefault
,
5898 # A helper function for wrapping up the template body for
5899 # possibly-nullable objecty stuff
5900 def wrapObjectTemplate(templateBody
, type, codeToSetNull
, failureCode
=None):
5901 if isNullOrUndefined
and type.nullable():
5902 # Just ignore templateBody and set ourselves to null.
5903 # Note that we don't have to worry about default values
5904 # here either, since we already examined this value.
5905 return codeToSetNull
5907 if not isDefinitelyObject
:
5908 # Handle the non-object cases by wrapping up the whole
5909 # thing in an if cascade.
5911 elifLine
= "} else if (${val}.isNullOrUndefined()) {\n"
5912 elifBody
= codeToSetNull
5917 # Note that $${val} below expands to ${val}. This string is
5918 # used as a template later, and val will be filled in then.
5919 templateBody
= fill(
5921 if ($${val}.isObject()) {
5929 templateBody
=templateBody
,
5932 failureBody
=onFailureNotAnObject(failureCode
).define(),
5935 if isinstance(defaultValue
, IDLNullValue
):
5936 assert type.nullable() # Parser should enforce this
5937 templateBody
= handleDefault(templateBody
, codeToSetNull
)
5938 elif isinstance(defaultValue
, IDLEmptySequenceValue
):
5939 # Our caller will handle it
5942 assert defaultValue
is None
5946 # A helper function for converting things that look like a JSObject*.
5947 def handleJSObjectType(
5948 type, isMember
, failureCode
, exceptionCode
, sourceDescription
5950 if not isMember
or isMember
== "Union":
5952 # We have a specialization of Optional that will use a
5953 # Rooted for the storage here.
5954 declType
= CGGeneric("JS::Handle<JSObject*>")
5956 declType
= CGGeneric("JS::Rooted<JSObject*>")
5959 assert isMember
in (
5966 # We'll get traced by the sequence or dictionary or union tracer
5967 declType
= CGGeneric("JSObject*")
5969 templateBody
= "${declName} = &${val}.toObject();\n"
5971 # For JS-implemented APIs, we refuse to allow passing objects that the
5972 # API consumer does not subsume. The extra parens around
5973 # ($${passedToJSImpl}) suppress unreachable code warnings when
5974 # $${passedToJSImpl} is the literal `false`. But Apple is shipping a
5975 # buggy clang (clang 3.9) in Xcode 8.3, so there even the parens are not
5976 # enough. So we manually disable some warnings in clang.
5978 not isinstance(descriptorProvider
, Descriptor
)
5979 or descriptorProvider
.interface
.isJSImplemented()
5985 #pragma clang diagnostic push
5986 #pragma clang diagnostic ignored "-Wunreachable-code"
5987 #pragma clang diagnostic ignored "-Wunreachable-code-return"
5989 if (($${passedToJSImpl}) && !CallerSubsumes($${val})) {
5990 cx.ThrowErrorMessage<MSG_PERMISSION_DENIED_TO_PASS_ARG>("${sourceDescription}");
5994 #pragma clang diagnostic pop
5997 sourceDescription
=sourceDescription
,
5998 exceptionCode
=exceptionCode
,
6003 setToNullCode
= "${declName} = nullptr;\n"
6004 template
= wrapObjectTemplate(templateBody
, type, setToNullCode
, failureCode
)
6005 return JSToNativeConversionInfo(
6006 template
, declType
=declType
, dealWithOptional
=isOptional
, declArgs
=declArgs
6009 def incrementNestingLevel():
6010 if nestingLevel
== "":
6012 return nestingLevel
+ 1
6014 assert not (isEnforceRange
and isClamp
) # These are mutually exclusive
6016 if type.isSequence() or type.isObservableArray():
6017 assert not isEnforceRange
and not isClamp
and not isAllowShared
6019 if failureCode
is None:
6021 'cx.ThrowErrorMessage<MSG_CONVERSION_ERROR>("%s", "%s");\n'
6024 firstCap(sourceDescription
),
6025 "sequence" if type.isSequence() else "observable array",
6030 notSequence
= failureCode
6032 nullable
= type.nullable()
6033 # Be very careful not to change "type": we need it later
6035 elementType
= type.inner
.inner
6037 elementType
= type.inner
6039 # We want to use auto arrays if we can, but we have to be careful with
6040 # reallocation behavior for arrays. In particular, if we use auto
6041 # arrays for sequences and have a sequence of elements which are
6042 # themselves sequences or have sequences as members, we have a problem.
6043 # In that case, resizing the outermost AutoTArray to the right size
6044 # will memmove its elements, but AutoTArrays are not memmovable and
6045 # hence will end up with pointers to bogus memory, which is bad. To
6046 # deal with this, we typically map WebIDL sequences to our Sequence
6047 # type, which is in fact memmovable. The one exception is when we're
6048 # passing in a sequence directly as an argument without any sort of
6049 # optional or nullable complexity going on. In that situation, we can
6050 # use an AutoSequence instead. We have to keep using Sequence in the
6051 # nullable and optional cases because we don't want to leak the
6052 # AutoSequence type to consumers, which would be unavoidable with
6053 # Nullable<AutoSequence> or Optional<AutoSequence>.
6055 (isMember
and isMember
!= "Union")
6058 or isCallbackReturnValue
6060 sequenceClass
= "Sequence"
6062 sequenceClass
= "binding_detail::AutoSequence"
6064 # XXXbz we can't include the index in the sourceDescription, because
6065 # we don't really have a way to pass one in dynamically at runtime...
6066 elementInfo
= getJSToNativeConversionInfo(
6069 isMember
="Sequence",
6070 exceptionCode
=exceptionCode
,
6071 lenientFloatCode
=lenientFloatCode
,
6072 isCallbackReturnValue
=isCallbackReturnValue
,
6073 sourceDescription
="element of %s" % sourceDescription
,
6074 nestingLevel
=incrementNestingLevel(),
6076 if elementInfo
.dealWithOptional
:
6077 raise TypeError("Shouldn't have optional things in sequences")
6078 if elementInfo
.holderType
is not None:
6079 raise TypeError("Shouldn't need holders for sequences")
6081 typeName
= CGTemplatedType(sequenceClass
, elementInfo
.declType
)
6082 sequenceType
= typeName
.define()
6084 if isMember
== "Union" and typeNeedsRooting(type):
6086 typeName
= CGTemplatedType(
6087 "binding_detail::RootedAutoSequence", elementInfo
.declType
6090 typeName
= CGTemplatedType("Nullable", typeName
)
6093 arrayRef
= "${declName}.SetValue()"
6095 arrayRef
= "${declName}"
6097 elementConversion
= string
.Template(elementInfo
.template
).substitute(
6099 "val": "temp" + str(nestingLevel
),
6100 "maybeMutableVal": "&temp" + str(nestingLevel
),
6101 "declName": "slot" + str(nestingLevel
),
6102 # We only need holderName here to handle isExternal()
6103 # interfaces, which use an internal holder for the
6104 # conversion even when forceOwningType ends up true.
6105 "holderName": "tempHolder" + str(nestingLevel
),
6106 "passedToJSImpl": "${passedToJSImpl}",
6110 elementInitializer
= initializerForType(elementType
)
6111 if elementInitializer
is None:
6112 elementInitializer
= ""
6114 elementInitializer
= elementInitializer
+ ", "
6116 # NOTE: Keep this in sync with variadic conversions as needed
6117 templateBody
= fill(
6119 JS::ForOfIterator iter${nestingLevel}(cx);
6120 if (!iter${nestingLevel}.init($${val}, JS::ForOfIterator::AllowNonIterable)) {
6123 if (!iter${nestingLevel}.valueIsIterable()) {
6126 ${sequenceType} &arr${nestingLevel} = ${arrayRef};
6127 JS::Rooted<JS::Value> temp${nestingLevel}(cx);
6129 bool done${nestingLevel};
6130 if (!iter${nestingLevel}.next(&temp${nestingLevel}, &done${nestingLevel})) {
6133 if (done${nestingLevel}) {
6136 ${elementType}* slotPtr${nestingLevel} = arr${nestingLevel}.AppendElement(${elementInitializer}mozilla::fallible);
6137 if (!slotPtr${nestingLevel}) {
6138 JS_ReportOutOfMemory(cx);
6141 ${elementType}& slot${nestingLevel} = *slotPtr${nestingLevel};
6142 $*{elementConversion}
6145 exceptionCode
=exceptionCode
,
6146 notSequence
=notSequence
,
6147 sequenceType
=sequenceType
,
6149 elementType
=elementInfo
.declType
.define(),
6150 elementConversion
=elementConversion
,
6151 elementInitializer
=elementInitializer
,
6152 nestingLevel
=str(nestingLevel
),
6155 templateBody
= wrapObjectTemplate(
6156 templateBody
, type, "${declName}.SetNull();\n", notSequence
6158 if isinstance(defaultValue
, IDLEmptySequenceValue
):
6160 codeToSetEmpty
= "${declName}.SetValue();\n"
6163 "/* ${declName} array is already empty; nothing to do */\n"
6165 templateBody
= handleDefault(templateBody
, codeToSetEmpty
)
6170 # Sequence arguments that might contain traceable things need
6172 if typeNeedsRooting(elementType
):
6174 holderType
= CGTemplatedType("SequenceRooter", elementInfo
.declType
)
6175 # If our sequence is nullable, this will set the Nullable to be
6176 # not-null, but that's ok because we make an explicit SetNull() call
6177 # on it as needed if our JS value is actually null.
6178 holderArgs
= "cx, &%s" % arrayRef
6179 elif isMember
== "Union":
6182 return JSToNativeConversionInfo(
6186 holderType
=holderType
,
6187 dealWithOptional
=isOptional
,
6188 holderArgs
=holderArgs
,
6192 assert not isEnforceRange
and not isClamp
and not isAllowShared
6193 if failureCode
is None:
6194 notRecord
= 'cx.ThrowErrorMessage<MSG_NOT_OBJECT>("%s");\n' "%s" % (
6195 firstCap(sourceDescription
),
6199 notRecord
= failureCode
6201 nullable
= type.nullable()
6202 # Be very careful not to change "type": we need it later
6204 recordType
= type.inner
6207 valueType
= recordType
.inner
6209 valueInfo
= getJSToNativeConversionInfo(
6213 exceptionCode
=exceptionCode
,
6214 lenientFloatCode
=lenientFloatCode
,
6215 isCallbackReturnValue
=isCallbackReturnValue
,
6216 sourceDescription
="value in %s" % sourceDescription
,
6217 nestingLevel
=incrementNestingLevel(),
6219 if valueInfo
.dealWithOptional
:
6220 raise TypeError("Shouldn't have optional things in record")
6221 if valueInfo
.holderType
is not None:
6222 raise TypeError("Shouldn't need holders for record")
6224 declType
= CGTemplatedType(
6225 "Record", [recordKeyDeclType(recordType
), valueInfo
.declType
]
6227 typeName
= declType
.define()
6229 if isMember
== "Union" and typeNeedsRooting(type):
6231 declType
= CGTemplatedType(
6232 "RootedRecord", [recordKeyDeclType(recordType
), valueInfo
.declType
]
6235 declType
= CGTemplatedType("Nullable", declType
)
6238 recordRef
= "${declName}.SetValue()"
6240 recordRef
= "${declName}"
6242 valueConversion
= string
.Template(valueInfo
.template
).substitute(
6245 "maybeMutableVal": "&temp",
6247 # We only need holderName here to handle isExternal()
6248 # interfaces, which use an internal holder for the
6249 # conversion even when forceOwningType ends up true.
6250 "holderName": "tempHolder",
6251 "passedToJSImpl": "${passedToJSImpl}",
6255 keyType
= recordKeyType(recordType
)
6256 if recordType
.keyType
.isJSString():
6258 "Have do deal with JSString record type, but don't know how"
6260 if recordType
.keyType
.isByteString() or recordType
.keyType
.isUTF8String():
6261 hashKeyType
= "nsCStringHashKey"
6262 if recordType
.keyType
.isByteString():
6263 keyConversionFunction
= "ConvertJSValueToByteString"
6265 keyConversionFunction
= "ConvertJSValueToString"
6268 hashKeyType
= "nsStringHashKey"
6269 if recordType
.keyType
.isDOMString():
6270 keyConversionFunction
= "ConvertJSValueToString"
6272 assert recordType
.keyType
.isUSVString()
6273 keyConversionFunction
= "ConvertJSValueToUSVString"
6275 templateBody
= fill(
6277 auto& recordEntries = ${recordRef}.Entries();
6279 JS::Rooted<JSObject*> recordObj(cx, &$${val}.toObject());
6280 JS::RootedVector<jsid> ids(cx);
6281 if (!js::GetPropertyKeys(cx, recordObj,
6282 JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &ids)) {
6285 if (!recordEntries.SetCapacity(ids.length(), mozilla::fallible)) {
6286 JS_ReportOutOfMemory(cx);
6289 JS::Rooted<JS::Value> propNameValue(cx);
6290 JS::Rooted<JS::Value> temp(cx);
6291 JS::Rooted<jsid> curId(cx);
6292 JS::Rooted<JS::Value> idVal(cx);
6293 // Use a hashset to keep track of ids seen, to avoid
6294 // introducing nasty O(N^2) behavior scanning for them all the
6295 // time. Ideally we'd use a data structure with O(1) lookup
6296 // _and_ ordering for the MozMap, but we don't have one lying
6298 nsTHashtable<${hashKeyType}> idsSeen;
6299 for (size_t i = 0; i < ids.length(); ++i) {
6302 JS::Rooted<mozilla::Maybe<JS::PropertyDescriptor>> desc(cx);
6303 if (!JS_GetOwnPropertyDescriptorById(cx, recordObj, curId,
6308 if (desc.isNothing() || !desc->enumerable()) {
6312 idVal = js::IdToValue(curId);
6313 ${keyType} propName;
6314 // This will just throw if idVal is a Symbol, like the spec says
6316 if (!${keyConversionFunction}(cx, idVal, "key of ${sourceDescription}", propName)) {
6320 if (!JS_GetPropertyById(cx, recordObj, curId, &temp)) {
6324 ${typeName}::EntryType* entry;
6325 if (!idsSeen.EnsureInserted(propName)) {
6326 // Find the existing entry.
6327 auto idx = recordEntries.IndexOf(propName);
6328 MOZ_ASSERT(idx != recordEntries.NoIndex,
6329 "Why is it not found?");
6330 // Now blow it away to make it look like it was just added
6331 // to the array, because it's not obvious that it's
6332 // safe to write to its already-initialized mValue via our
6333 // normal codegen conversions. For example, the value
6334 // could be a union and this would change its type, but
6335 // codegen assumes we won't do that.
6336 entry = recordEntries.ReconstructElementAt(idx);
6338 // Safe to do an infallible append here, because we did a
6339 // SetCapacity above to the right capacity.
6340 entry = recordEntries.AppendElement();
6342 entry->mKey = propName;
6343 ${valueType}& slot = entry->mValue;
6347 exceptionCode
=exceptionCode
,
6348 recordRef
=recordRef
,
6349 hashKeyType
=hashKeyType
,
6351 keyConversionFunction
=keyConversionFunction
,
6352 sourceDescription
=sourceDescription
,
6354 valueType
=valueInfo
.declType
.define(),
6355 valueConversion
=valueConversion
,
6358 templateBody
= wrapObjectTemplate(
6359 templateBody
, type, "${declName}.SetNull();\n", notRecord
6365 # record arguments that might contain traceable things need
6367 if not isMember
and isCallbackReturnValue
:
6368 # Go ahead and just convert directly into our actual return value
6369 declType
= CGWrapper(declType
, post
="&")
6370 declArgs
= "aRetVal"
6371 elif typeNeedsRooting(valueType
):
6373 holderType
= CGTemplatedType(
6374 "RecordRooter", [recordKeyDeclType(recordType
), valueInfo
.declType
]
6376 # If our record is nullable, this will set the Nullable to be
6377 # not-null, but that's ok because we make an explicit SetNull() call
6378 # on it as needed if our JS value is actually null.
6379 holderArgs
= "cx, &%s" % recordRef
6380 elif isMember
== "Union":
6383 return JSToNativeConversionInfo(
6387 holderType
=holderType
,
6388 dealWithOptional
=isOptional
,
6389 holderArgs
=holderArgs
,
6393 nullable
= type.nullable()
6397 isOwningUnion
= (isMember
and isMember
!= "Union") or isCallbackReturnValue
6398 unionArgumentObj
= "${declName}"
6400 if isOptional
and not isOwningUnion
:
6401 unionArgumentObj
+= ".Value()"
6402 # If we're owning, we're a Nullable, which hasn't been told it has
6403 # a value. Otherwise we're an already-constructed Maybe.
6404 unionArgumentObj
+= ".SetValue()"
6406 templateBody
= CGIfWrapper(
6407 CGGeneric(exceptionCode
),
6408 '!%s.Init(cx, ${val}, "%s", ${passedToJSImpl})'
6409 % (unionArgumentObj
, firstCap(sourceDescription
)),
6412 if type.hasNullableType
:
6414 # Make sure to handle a null default value here
6415 if defaultValue
and isinstance(defaultValue
, IDLNullValue
):
6416 assert defaultValue
.type == type
6417 templateBody
= CGIfElseWrapper(
6419 CGGeneric("%s.SetNull();\n" % unionArgumentObj
),
6423 typeName
= CGUnionStruct
.unionTypeDecl(type, isOwningUnion
)
6424 argumentTypeName
= typeName
+ "Argument"
6426 typeName
= "Nullable<" + typeName
+ " >"
6428 declType
= CGGeneric(typeName
)
6432 holderType
= CGGeneric(argumentTypeName
)
6434 holderType
= CGTemplatedType("Maybe", holderType
)
6436 # If we're isOptional and not nullable the normal optional handling will
6437 # handle lazy construction of our holder. If we're nullable and not
6438 # owning we do it all by hand because we do not want our holder
6439 # constructed if we're null. But if we're owning we don't have a
6440 # holder anyway, so we can do the normal Optional codepath.
6441 declLoc
= "${declName}"
6442 constructDecl
= None
6444 if isOptional
and not isOwningUnion
:
6445 declType
= CGTemplatedType("Optional", declType
)
6446 constructDecl
= CGGeneric("${declName}.Construct();\n")
6447 declLoc
= "${declName}.Value()"
6449 if not isMember
and isCallbackReturnValue
:
6450 declType
= CGWrapper(declType
, post
="&")
6451 declArgs
= "aRetVal"
6457 and not isinstance(defaultValue
, IDLNullValue
)
6458 and not isinstance(defaultValue
, IDLDefaultDictionaryValue
)
6460 tag
= defaultValue
.type.tag()
6462 if tag
in numericSuffixes
or tag
is IDLType
.Tags
.bool:
6463 defaultStr
= getHandleDefault(defaultValue
)
6464 # Make sure we actually construct the thing inside the nullable.
6465 value
= declLoc
+ (".SetValue()" if nullable
else "")
6466 name
= getUnionMemberName(defaultValue
.type)
6467 default
= CGGeneric(
6468 "%s.RawSetAs%s() = %s;\n" % (value
, name
, defaultStr
)
6470 elif isinstance(defaultValue
, IDLEmptySequenceValue
):
6471 name
= getUnionMemberName(defaultValue
.type)
6472 # Make sure we actually construct the thing inside the nullable.
6473 value
= declLoc
+ (".SetValue()" if nullable
else "")
6474 if not isOwningUnion
and typeNeedsRooting(defaultValue
.type):
6478 # It's enough to set us to the right type; that will
6479 # create an empty array, which is all we need here.
6480 default
= CGGeneric(
6481 "Unused << %s.RawSetAs%s(%s);\n" % (value
, name
, ctorArgs
)
6483 elif defaultValue
.type.isEnum():
6484 name
= getUnionMemberName(defaultValue
.type)
6485 # Make sure we actually construct the thing inside the nullable.
6486 value
= declLoc
+ (".SetValue()" if nullable
else "")
6487 default
= CGGeneric(
6488 "%s.RawSetAs%s() = %s::%s;\n"
6492 defaultValue
.type.inner
.identifier
.name
,
6493 getEnumValueName(defaultValue
.value
),
6497 default
= CGGeneric(
6498 handleDefaultStringValue(
6499 defaultValue
, "%s.SetStringLiteral" % unionArgumentObj
6503 templateBody
= CGIfElseWrapper("!(${haveValue})", default
, templateBody
)
6506 assert not type.hasNullableType
6508 if isinstance(defaultValue
, IDLNullValue
):
6509 extraConditionForNull
= "!(${haveValue}) || "
6511 extraConditionForNull
= "(${haveValue}) && "
6513 extraConditionForNull
= ""
6515 hasUndefinedType
= any(t
.isUndefined() for t
in type.flatMemberTypes
)
6516 assert not hasUndefinedType
or defaultValue
is None
6519 "${val}.isNull()" if hasUndefinedType
else "${val}.isNullOrUndefined()"
6521 templateBody
= CGIfElseWrapper(
6522 extraConditionForNull
+ nullTest
,
6523 CGGeneric("%s.SetNull();\n" % declLoc
),
6527 not type.hasNullableType
6529 and isinstance(defaultValue
, IDLDefaultDictionaryValue
)
6531 assert type.hasDictionaryType()
6532 assert defaultValue
.type.isDictionary()
6533 if not isOwningUnion
and typeNeedsRooting(defaultValue
.type):
6537 initDictionaryWithNull
= CGIfWrapper(
6538 CGGeneric("return false;\n"),
6540 '!%s.RawSetAs%s(%s).Init(cx, JS::NullHandleValue, "Member of %s")'
6543 getUnionMemberName(defaultValue
.type),
6549 templateBody
= CGIfElseWrapper(
6550 "!(${haveValue})", initDictionaryWithNull
, templateBody
6553 templateBody
= CGList([constructDecl
, templateBody
])
6555 return JSToNativeConversionInfo(
6556 templateBody
.define(),
6559 dealWithOptional
=isOptional
and (not nullable
or isOwningUnion
),
6562 if type.isPromise():
6563 assert not type.nullable()
6564 assert defaultValue
is None
6566 # We always have to hold a strong ref to Promise here, because
6567 # Promise::resolve returns an addrefed thing.
6568 argIsPointer
= isCallbackReturnValue
6570 declType
= CGGeneric("RefPtr<Promise>")
6572 declType
= CGGeneric("OwningNonNull<Promise>")
6574 # Per spec, what we're supposed to do is take the original
6575 # Promise.resolve and call it with the original Promise as this
6576 # value to make a Promise out of whatever value we actually have
6577 # here. The question is which global we should use. There are
6578 # several cases to consider:
6580 # 1) Normal call to API with a Promise argument. This is a case the
6581 # spec covers, and we should be using the current Realm's
6582 # Promise. That means the current compartment.
6583 # 2) Call to API with a Promise argument over Xrays. In practice,
6584 # this sort of thing seems to be used for giving an API
6585 # implementation a way to wait for conclusion of an asyc
6586 # operation, _not_ to expose the Promise to content code. So we
6587 # probably want to allow callers to use such an API in a
6588 # "natural" way, by passing chrome-side promises; indeed, that
6589 # may be all that the caller has to represent their async
6590 # operation. That means we really need to do the
6591 # Promise.resolve() in the caller (chrome) compartment: if we do
6592 # it in the content compartment, we will try to call .then() on
6593 # the chrome promise while in the content compartment, which will
6594 # throw and we'll just get a rejected Promise. Note that this is
6595 # also the reason why a caller who has a chrome Promise
6596 # representing an async operation can't itself convert it to a
6597 # content-side Promise (at least not without some serious
6599 # 3) Promise return value from a callback or callback interface.
6600 # Per spec, this should use the Realm of the callback object. In
6601 # our case, that's the compartment of the underlying callback,
6602 # not the current compartment (which may be the compartment of
6603 # some cross-compartment wrapper around said callback).
6604 # 4) Return value from a JS-implemented interface. In this case we
6605 # have a problem. Our current compartment is the compartment of
6606 # the JS implementation. But if the JS implementation returned
6607 # a page-side Promise (which is a totally sane thing to do, and
6608 # in fact the right thing to do given that this return value is
6609 # going right to content script) then we don't want to
6610 # Promise.resolve with our current compartment Promise, because
6611 # that will wrap it up in a chrome-side Promise, which is
6612 # decidedly _not_ what's desired here. So in that case we
6613 # should really unwrap the return value and use the global of
6614 # the result. CheckedUnwrapStatic should be good enough for that;
6615 # if it fails, then we're failing unwrap while in a
6616 # system-privileged compartment, so presumably we have a dead
6617 # object wrapper. Just error out. Do NOT fall back to using
6618 # the current compartment instead: that will return a
6619 # system-privileged rejected (because getting .then inside
6620 # resolve() failed) Promise to the caller, which they won't be
6621 # able to touch. That's not helpful. If we error out, on the
6622 # other hand, they will get a content-side rejected promise.
6623 # Same thing if the value returned is not even an object.
6624 if isCallbackReturnValue
== "JSImpl":
6625 # Case 4 above. Note that globalObj defaults to the current
6626 # compartment global. Note that we don't use $*{exceptionCode}
6627 # here because that will try to aRv.Throw(NS_ERROR_UNEXPECTED)
6628 # which we don't really want here.
6629 assert exceptionCode
== "aRv.Throw(NS_ERROR_UNEXPECTED);\nreturn nullptr;\n"
6630 getPromiseGlobal
= fill(
6632 if (!$${val}.isObject()) {
6633 aRv.ThrowTypeError<MSG_NOT_OBJECT>("${sourceDescription}");
6636 JSObject* unwrappedVal = js::CheckedUnwrapStatic(&$${val}.toObject());
6637 if (!unwrappedVal) {
6638 // A slight lie, but not much of one, for a dead object wrapper.
6639 aRv.ThrowTypeError<MSG_NOT_OBJECT>("${sourceDescription}");
6642 globalObj = JS::GetNonCCWObjectGlobal(unwrappedVal);
6644 sourceDescription
=sourceDescription
,
6646 elif isCallbackReturnValue
== "Callback":
6647 getPromiseGlobal
= dedent(
6649 // We basically want our entry global here. Play it safe
6650 // and use GetEntryGlobal() to get it, with whatever
6651 // principal-clamping it ends up doing.
6652 globalObj = GetEntryGlobal()->GetGlobalJSObject();
6656 getPromiseGlobal
= dedent(
6658 globalObj = JS::CurrentGlobalOrNull(cx);
6662 templateBody
= fill(
6664 { // Scope for our GlobalObject, FastErrorResult, JSAutoRealm,
6667 JS::Rooted<JSObject*> globalObj(cx);
6668 $*{getPromiseGlobal}
6669 JSAutoRealm ar(cx, globalObj);
6670 GlobalObject promiseGlobal(cx, globalObj);
6671 if (promiseGlobal.Failed()) {
6675 JS::Rooted<JS::Value> valueToResolve(cx, $${val});
6676 if (!JS_WrapValue(cx, &valueToResolve)) {
6679 binding_detail::FastErrorResult promiseRv;
6680 nsCOMPtr<nsIGlobalObject> global =
6681 do_QueryInterface(promiseGlobal.GetAsSupports());
6683 promiseRv.Throw(NS_ERROR_UNEXPECTED);
6684 MOZ_ALWAYS_TRUE(promiseRv.MaybeSetPendingException(cx));
6687 $${declName} = Promise::Resolve(global, cx, valueToResolve,
6689 if (promiseRv.MaybeSetPendingException(cx)) {
6694 getPromiseGlobal
=getPromiseGlobal
,
6695 exceptionCode
=exceptionCode
,
6698 return JSToNativeConversionInfo(
6699 templateBody
, declType
=declType
, dealWithOptional
=isOptional
6702 if type.isGeckoInterface():
6703 assert not isEnforceRange
and not isClamp
and not isAllowShared
6705 descriptor
= descriptorProvider
.getDescriptor(
6706 type.unroll().inner
.identifier
.name
6709 assert descriptor
.nativeType
!= "JSObject"
6711 if descriptor
.interface
.isCallback():
6712 (declType
, declArgs
, conversion
) = getCallbackConversionInfo(
6713 type, descriptor
.interface
, isMember
, isCallbackReturnValue
, isOptional
6715 template
= wrapObjectTemplate(
6716 conversion
, type, "${declName} = nullptr;\n", failureCode
6718 return JSToNativeConversionInfo(
6722 dealWithOptional
=isOptional
,
6725 if descriptor
.interface
.identifier
.name
== "WindowProxy":
6726 declType
= CGGeneric("mozilla::dom::WindowProxyHolder")
6728 declType
= CGTemplatedType("Nullable", declType
)
6729 windowProxyHolderRef
= "${declName}.SetValue()"
6731 windowProxyHolderRef
= "${declName}"
6733 failureCode
= onFailureBadType(
6734 failureCode
, descriptor
.interface
.identifier
.name
6736 templateBody
= fill(
6738 JS::Rooted<JSObject*> source(cx, &$${val}.toObject());
6739 if (NS_FAILED(UnwrapWindowProxyArg(cx, source, ${windowProxyHolderRef}))) {
6743 windowProxyHolderRef
=windowProxyHolderRef
,
6744 onFailure
=failureCode
,
6746 templateBody
= wrapObjectTemplate(
6747 templateBody
, type, "${declName}.SetNull();\n", failureCode
6749 return JSToNativeConversionInfo(
6750 templateBody
, declType
=declType
, dealWithOptional
=isOptional
6753 # This is an interface that we implement as a concrete class
6754 # or an XPCOM interface.
6756 # Allow null pointers for nullable types and old-binding classes, and
6757 # use an RefPtr or raw pointer for callback return values to make
6758 # them easier to return.
6760 type.nullable() or type.unroll().inner
.isExternal() or isCallbackReturnValue
6763 # Sequence and dictionary members, as well as owning unions (which can
6764 # appear here as return values in JS-implemented interfaces) have to
6765 # hold a strong ref to the thing being passed down. Those all set
6768 # Also, callback return values always end up addrefing anyway, so there
6769 # is no point trying to avoid it here and it makes other things simpler
6770 # since we can assume the return value is a strong ref.
6771 assert not descriptor
.interface
.isCallback()
6772 forceOwningType
= (isMember
and isMember
!= "Union") or isCallbackReturnValue
6774 typeName
= descriptor
.nativeType
6775 typePtr
= typeName
+ "*"
6777 # Compute a few things:
6778 # - declType is the type we want to return as the first element of our
6780 # - holderType is the type we want to return as the third element
6783 # Set up some sensible defaults for these things insofar as we can.
6787 declType
= "RefPtr<" + typeName
+ ">"
6792 declType
= "OwningNonNull<" + typeName
+ ">"
6794 declType
= "NonNull<" + typeName
+ ">"
6798 templateBody
+= fill(
6800 static_assert(IsRefcounted<${typeName}>::value, "We can only store refcounted classes.");
6805 if not descriptor
.interface
.isExternal():
6806 if failureCode
is not None:
6807 templateBody
+= str(
6808 CastableObjectUnwrapper(
6811 "${maybeMutableVal}",
6817 templateBody
+= str(
6818 FailureFatalCastableObjectUnwrapper(
6821 "${maybeMutableVal}",
6824 isCallbackReturnValue
,
6825 firstCap(sourceDescription
),
6829 # External interface. We always have a holder for these, because we
6830 # don't actually know whether we have to addref when unwrapping or not.
6831 # So we just pass an getter_AddRefs(RefPtr) to XPConnect and if we'll
6832 # need a release it'll put a non-null pointer in there.
6834 # Don't return a holderType in this case; our declName
6835 # will just own stuff.
6836 templateBody
+= "RefPtr<" + typeName
+ "> ${holderName};\n"
6838 holderType
= "RefPtr<" + typeName
+ ">"
6840 "JS::Rooted<JSObject*> source(cx, &${val}.toObject());\n"
6841 + "if (NS_FAILED(UnwrapArg<"
6843 + ">(cx, source, getter_AddRefs(${holderName})))) {\n"
6845 templateBody
+= CGIndenter(
6846 onFailureBadType(failureCode
, descriptor
.interface
.identifier
.name
)
6848 templateBody
+= "}\n" "MOZ_ASSERT(${holderName});\n"
6850 # And store our value in ${declName}
6851 templateBody
+= "${declName} = ${holderName};\n"
6853 # Just pass failureCode, not onFailureBadType, here, so we'll report
6854 # the thing as not an object as opposed to not implementing whatever
6856 templateBody
= wrapObjectTemplate(
6857 templateBody
, type, "${declName} = nullptr;\n", failureCode
6860 declType
= CGGeneric(declType
)
6861 if holderType
is not None:
6862 holderType
= CGGeneric(holderType
)
6863 return JSToNativeConversionInfo(
6866 holderType
=holderType
,
6867 dealWithOptional
=isOptional
,
6870 if type.isSpiderMonkeyInterface():
6871 assert not isEnforceRange
and not isClamp
6872 name
= type.unroll().name
# unroll() because it may be nullable
6873 interfaceType
= CGGeneric(name
)
6874 declType
= interfaceType
6876 declType
= CGTemplatedType("Nullable", declType
)
6877 objRef
= "${declName}.SetValue()"
6879 objRef
= "${declName}"
6881 # Again, this is a bit strange since we are actually building a
6882 # template string here. ${objRef} and $*{badType} below are filled in
6883 # right now; $${val} expands to ${val}, to be filled in later.
6886 if (!${objRef}.Init(&$${val}.toObject())) {
6891 badType
=onFailureBadType(failureCode
, type.name
).define(),
6893 if type.isBufferSource():
6894 if type.isArrayBuffer():
6895 isSharedMethod
= "JS::IsSharedArrayBufferObject"
6896 isLargeMethod
= "JS::IsLargeArrayBufferMaybeShared"
6897 isResizableMethod
= "JS::IsResizableArrayBufferMaybeShared"
6899 assert type.isArrayBufferView() or type.isTypedArray()
6900 isSharedMethod
= "JS::IsArrayBufferViewShared"
6901 isLargeMethod
= "JS::IsLargeArrayBufferView"
6902 isResizableMethod
= "JS::IsResizableArrayBufferView"
6903 if not isAllowShared
:
6906 if (${isSharedMethod}(${objRef}.Obj())) {
6910 isSharedMethod
=isSharedMethod
,
6912 badType
=onFailureIsShared().define(),
6914 # For now reject large (> 2 GB) ArrayBuffers and ArrayBufferViews.
6915 # Supporting this will require changing dom::TypedArray and
6919 if (${isLargeMethod}(${objRef}.Obj())) {
6923 isLargeMethod
=isLargeMethod
,
6925 badType
=onFailureIsLarge().define(),
6927 # For now reject resizable ArrayBuffers and growable
6928 # SharedArrayBuffers. Supporting this will require changing
6929 # dom::TypedArray and consumers.
6932 if (${isResizableMethod}(${objRef}.Obj())) {
6936 isResizableMethod
=isResizableMethod
,
6938 badType
=onFailureIsResizable().define(),
6940 template
= wrapObjectTemplate(
6941 template
, type, "${declName}.SetNull();\n", failureCode
6943 if not isMember
or isMember
== "Union":
6944 # This is a bit annoying. In a union we don't want to have a
6945 # holder, since unions don't support that. But if we're optional we
6946 # want to have a holder, so that the callee doesn't see
6947 # Optional<RootedSpiderMonkeyInterface<InterfaceType>>. So do a
6948 # holder if we're optional and use a RootedSpiderMonkeyInterface
6951 holderType
= CGTemplatedType(
6952 "SpiderMonkeyInterfaceRooter", interfaceType
6954 # If our SpiderMonkey interface is nullable, this will set the
6955 # Nullable to be not-null, but that's ok because we make an
6956 # explicit SetNull() call on it as needed if our JS value is
6957 # actually null. XXXbz Because "Maybe" takes const refs for
6958 # constructor arguments, we can't pass a reference here; have
6959 # to pass a pointer.
6960 holderArgs
= "cx, &%s" % objRef
6965 declType
= CGTemplatedType("RootedSpiderMonkeyInterface", declType
)
6971 return JSToNativeConversionInfo(
6974 holderType
=holderType
,
6975 dealWithOptional
=isOptional
,
6977 holderArgs
=holderArgs
,
6980 if type.isJSString():
6981 assert not isEnforceRange
and not isClamp
and not isAllowShared
6983 raise TypeError("Nullable JSString not supported")
6987 raise TypeError("JSString not supported as member")
6989 declType
= "JS::Rooted<JSString*>"
6992 raise TypeError("JSString not supported as optional")
6993 templateBody
= fill(
6995 if (!($${declName} = ConvertJSValueToJSString(cx, $${val}))) {
6999 exceptionCode
=exceptionCode
,
7002 if defaultValue
is not None:
7003 assert not isinstance(defaultValue
, IDLNullValue
)
7006 static const char data[] = { ${data} };
7007 $${declName} = JS_NewStringCopyN(cx, data, std::size(data) - 1);
7008 if (!$${declName}) {
7013 ["'" + char
+ "'" for char
in defaultValue
.value
] + ["0"]
7015 exceptionCode
=exceptionCode
,
7018 templateBody
= handleDefault(templateBody
, defaultCode
)
7019 return JSToNativeConversionInfo(
7020 templateBody
, declType
=CGGeneric(declType
), declArgs
=declArgs
7023 if type.isDOMString() or type.isUSVString() or type.isUTF8String():
7024 assert not isEnforceRange
and not isClamp
and not isAllowShared
7027 "Default": "eStringify",
7028 "EmptyString": "eEmpty",
7032 # For nullable strings null becomes a null string.
7033 treatNullAs
= "Null"
7034 # For nullable strings undefined also becomes a null string.
7035 undefinedBehavior
= "eNull"
7037 undefinedBehavior
= "eStringify"
7038 if type.legacyNullToEmptyString
:
7039 treatNullAs
= "EmptyString"
7041 treatNullAs
= "Default"
7042 nullBehavior
= treatAs
[treatNullAs
]
7044 def getConversionCode(varName
):
7046 if type.isUSVString():
7047 normalizeCode
= fill(
7049 if (!NormalizeUSVString(${var})) {
7050 JS_ReportOutOfMemory(cx);
7055 exceptionCode
=exceptionCode
,
7058 conversionCode
= fill(
7060 if (!ConvertJSValueToString(cx, $${val}, ${nullBehavior}, ${undefinedBehavior}, ${varName})) {
7065 nullBehavior
=nullBehavior
,
7066 undefinedBehavior
=undefinedBehavior
,
7068 exceptionCode
=exceptionCode
,
7069 normalizeCode
=normalizeCode
,
7072 if defaultValue
is None:
7073 return conversionCode
7075 if isinstance(defaultValue
, IDLNullValue
):
7076 assert type.nullable()
7077 defaultCode
= "%s.SetIsVoid(true);\n" % varName
7079 defaultCode
= handleDefaultStringValue(
7080 defaultValue
, "%s.AssignLiteral" % varName
7082 return handleDefault(conversionCode
, defaultCode
)
7084 if isMember
and isMember
!= "Union":
7085 # Convert directly into the ns[C]String member we have.
7086 if type.isUTF8String():
7087 declType
= "nsCString"
7089 declType
= "nsString"
7090 return JSToNativeConversionInfo(
7091 getConversionCode("${declName}"),
7092 declType
=CGGeneric(declType
),
7093 dealWithOptional
=isOptional
,
7097 if type.isUTF8String():
7098 declType
= "Optional<nsACString>"
7099 holderType
= CGGeneric("binding_detail::FakeString<char>")
7101 declType
= "Optional<nsAString>"
7102 holderType
= CGGeneric("binding_detail::FakeString<char16_t>")
7103 conversionCode
= "%s" "${declName} = &${holderName};\n" % getConversionCode(
7107 if type.isUTF8String():
7108 declType
= "binding_detail::FakeString<char>"
7110 declType
= "binding_detail::FakeString<char16_t>"
7112 conversionCode
= getConversionCode("${declName}")
7114 # No need to deal with optional here; we handled it already
7115 return JSToNativeConversionInfo(
7116 conversionCode
, declType
=CGGeneric(declType
), holderType
=holderType
7119 if type.isByteString():
7120 assert not isEnforceRange
and not isClamp
and not isAllowShared
7122 nullable
= toStringBool(type.nullable())
7124 conversionCode
= fill(
7126 if (!ConvertJSValueToByteString(cx, $${val}, ${nullable}, "${sourceDescription}", $${declName})) {
7131 sourceDescription
=sourceDescription
,
7132 exceptionCode
=exceptionCode
,
7135 if defaultValue
is not None:
7136 if isinstance(defaultValue
, IDLNullValue
):
7137 assert type.nullable()
7138 defaultCode
= "${declName}.SetIsVoid(true);\n"
7140 defaultCode
= handleDefaultStringValue(
7141 defaultValue
, "${declName}.AssignLiteral"
7143 conversionCode
= handleDefault(conversionCode
, defaultCode
)
7145 return JSToNativeConversionInfo(
7146 conversionCode
, declType
=CGGeneric("nsCString"), dealWithOptional
=isOptional
7150 assert not isEnforceRange
and not isClamp
and not isAllowShared
7152 enumName
= type.unroll().inner
.identifier
.name
7153 declType
= CGGeneric(enumName
)
7155 declType
= CGTemplatedType("Nullable", declType
)
7156 declType
= declType
.define()
7157 enumLoc
= "${declName}.SetValue()"
7159 enumLoc
= "${declName}"
7160 declType
= declType
.define()
7162 if invalidEnumValueFatal
:
7163 handleInvalidEnumValueCode
= "MOZ_ASSERT(index >= 0);\n"
7165 # invalidEnumValueFatal is false only for attributes. So we won't
7166 # have a non-default exceptionCode here unless attribute "arg
7167 # conversion" code starts passing in an exceptionCode. At which
7168 # point we'll need to figure out what that even means.
7169 assert exceptionCode
== "return false;\n"
7170 handleInvalidEnumValueCode
= dedent(
7182 if (!binding_detail::FindEnumStringIndex<${invalidEnumValueFatal}>(cx, $${val},
7183 binding_detail::EnumStrings<${enumtype}>::Values,
7184 "${enumtype}", "${sourceDescription}",
7188 $*{handleInvalidEnumValueCode}
7189 ${enumLoc} = static_cast<${enumtype}>(index);
7193 invalidEnumValueFatal
=toStringBool(invalidEnumValueFatal
),
7194 handleInvalidEnumValueCode
=handleInvalidEnumValueCode
,
7195 exceptionCode
=exceptionCode
,
7197 sourceDescription
=sourceDescription
,
7200 setNull
= "${declName}.SetNull();\n"
7203 template
= CGIfElseWrapper(
7204 "${val}.isNullOrUndefined()", CGGeneric(setNull
), CGGeneric(template
)
7207 if defaultValue
is not None:
7208 if isinstance(defaultValue
, IDLNullValue
):
7209 assert type.nullable()
7210 template
= handleDefault(template
, setNull
)
7212 assert defaultValue
.type.tag() == IDLType
.Tags
.domstring
7213 template
= handleDefault(
7217 % (enumLoc
, enumName
, getEnumValueName(defaultValue
.value
))
7220 return JSToNativeConversionInfo(
7221 template
, declType
=CGGeneric(declType
), dealWithOptional
=isOptional
7224 if type.isCallback():
7225 assert not isEnforceRange
and not isClamp
and not isAllowShared
7226 assert not type.treatNonCallableAsNull() or type.nullable()
7227 assert not type.treatNonObjectAsNull() or type.nullable()
7228 assert not type.treatNonObjectAsNull() or not type.treatNonCallableAsNull()
7230 callback
= type.unroll().callback
7231 name
= callback
.identifier
.name
7232 (declType
, declArgs
, conversion
) = getCallbackConversionInfo(
7233 type, callback
, isMember
, isCallbackReturnValue
, isOptional
7236 if allowTreatNonCallableAsNull
and type.treatNonCallableAsNull():
7237 haveCallable
= "JS::IsCallable(&${val}.toObject())"
7238 if not isDefinitelyObject
:
7239 haveCallable
= "${val}.isObject() && " + haveCallable
7240 if defaultValue
is not None:
7241 assert isinstance(defaultValue
, IDLNullValue
)
7242 haveCallable
= "(${haveValue}) && " + haveCallable
7244 ("if (%s) {\n" % haveCallable
) + conversion
+ "} else {\n"
7245 " ${declName} = nullptr;\n"
7248 elif allowTreatNonCallableAsNull
and type.treatNonObjectAsNull():
7249 if not isDefinitelyObject
:
7250 haveObject
= "${val}.isObject()"
7251 if defaultValue
is not None:
7252 assert isinstance(defaultValue
, IDLNullValue
)
7253 haveObject
= "(${haveValue}) && " + haveObject
7254 template
= CGIfElseWrapper(
7256 CGGeneric(conversion
),
7257 CGGeneric("${declName} = nullptr;\n"),
7260 template
= conversion
7262 template
= wrapObjectTemplate(
7263 "if (JS::IsCallable(&${val}.toObject())) {\n"
7266 + indent(onFailureNotCallable(failureCode
).define())
7269 "${declName} = nullptr;\n",
7272 return JSToNativeConversionInfo(
7273 template
, declType
=declType
, declArgs
=declArgs
, dealWithOptional
=isOptional
7277 assert not isEnforceRange
and not isClamp
and not isAllowShared
7280 if isMember
in ("Variadic", "Sequence", "Dictionary", "Record"):
7281 # Rooting is handled by the sequence and dictionary tracers.
7282 declType
= "JS::Value"
7285 declType
= "JS::Rooted<JS::Value>"
7288 assert not isOptional
7289 templateBody
= "${declName} = ${val};\n"
7291 # For JS-implemented APIs, we refuse to allow passing objects that the
7292 # API consumer does not subsume. The extra parens around
7293 # ($${passedToJSImpl}) suppress unreachable code warnings when
7294 # $${passedToJSImpl} is the literal `false`. But Apple is shipping a
7295 # buggy clang (clang 3.9) in Xcode 8.3, so there even the parens are not
7296 # enough. So we manually disable some warnings in clang.
7298 not isinstance(descriptorProvider
, Descriptor
)
7299 or descriptorProvider
.interface
.isJSImplemented()
7305 #pragma clang diagnostic push
7306 #pragma clang diagnostic ignored "-Wunreachable-code"
7307 #pragma clang diagnostic ignored "-Wunreachable-code-return"
7309 if (($${passedToJSImpl}) && !CallerSubsumes($${val})) {
7310 cx.ThrowErrorMessage<MSG_PERMISSION_DENIED_TO_PASS_ARG>("${sourceDescription}");
7314 #pragma clang diagnostic pop
7317 sourceDescription
=sourceDescription
,
7318 exceptionCode
=exceptionCode
,
7323 # We may not have a default value if we're being converted for
7326 if isinstance(defaultValue
, IDLNullValue
):
7327 defaultHandling
= "${declName} = JS::NullValue();\n"
7329 assert isinstance(defaultValue
, IDLUndefinedValue
)
7330 defaultHandling
= "${declName} = JS::UndefinedValue();\n"
7331 templateBody
= handleDefault(templateBody
, defaultHandling
)
7332 return JSToNativeConversionInfo(
7333 templateBody
, declType
=CGGeneric(declType
), declArgs
=declArgs
7337 assert not isEnforceRange
and not isClamp
and not isAllowShared
7338 return handleJSObjectType(
7339 type, isMember
, failureCode
, exceptionCode
, sourceDescription
7342 if type.isDictionary():
7343 # There are no nullable dictionary-typed arguments or dictionary-typed
7344 # dictionary members.
7347 or isCallbackReturnValue
7348 or (isMember
and isMember
!= "Dictionary")
7350 # All optional dictionary-typed arguments always have default values,
7351 # but dictionary-typed dictionary members can be optional.
7352 assert not isOptional
or isMember
== "Dictionary"
7353 # In the callback return value case we never have to worry
7354 # about a default value; we always have a value.
7355 assert not isCallbackReturnValue
or defaultValue
is None
7357 typeName
= CGDictionary
.makeDictionaryName(type.unroll().inner
)
7358 if (not isMember
or isMember
== "Union") and not isCallbackReturnValue
:
7359 # Since we're not a member and not nullable or optional, no one will
7360 # see our real type, so we can do the fast version of the dictionary
7361 # that doesn't pre-initialize members.
7362 typeName
= "binding_detail::Fast" + typeName
7364 declType
= CGGeneric(typeName
)
7366 # We do manual default value handling here, because we actually do want
7367 # a jsval, and we only handle the default-dictionary case (which we map
7368 # into initialization with the JS value `null`) anyway
7369 # NOTE: if isNullOrUndefined or isDefinitelyObject are true,
7370 # we know we have a value, so we don't have to worry about the
7373 not isNullOrUndefined
7374 and not isDefinitelyObject
7375 and defaultValue
is not None
7377 assert isinstance(defaultValue
, IDLDefaultDictionaryValue
)
7378 # Initializing from JS null does the right thing to give
7379 # us a default-initialized dictionary.
7380 val
= "(${haveValue}) ? ${val} : JS::NullHandleValue"
7384 dictLoc
= "${declName}"
7386 dictLoc
+= ".SetValue()"
7388 if type.unroll().inner
.needsConversionFromJS
:
7389 args
= "cx, %s, " % val
7391 # We can end up in this case if a dictionary that does not need
7392 # conversion from JS has a dictionary-typed member with a default
7395 conversionCode
= fill(
7397 if (!${dictLoc}.Init(${args}"${desc}", $${passedToJSImpl})) {
7403 desc
=firstCap(sourceDescription
),
7404 exceptionCode
=exceptionCode
,
7407 if failureCode
is not None:
7408 # This means we're part of an overload or union conversion, and
7409 # should simply skip stuff if our value is not convertible to
7410 # dictionary, instead of trying and throwing. If we're either
7411 # isDefinitelyObject or isNullOrUndefined then we're convertible to
7412 # dictionary and don't need to check here.
7413 if isDefinitelyObject
or isNullOrUndefined
:
7414 template
= conversionCode
7418 if (!IsConvertibleToDictionary(${val})) {
7424 failureCode
=failureCode
,
7425 conversionCode
=conversionCode
,
7428 template
= conversionCode
7431 declType
= CGTemplatedType("Nullable", declType
)
7432 template
= CGIfElseWrapper(
7433 "${val}.isNullOrUndefined()",
7434 CGGeneric("${declName}.SetNull();\n"),
7435 CGGeneric(template
),
7438 # Dictionary arguments that might contain traceable things need to get
7440 if (not isMember
or isMember
== "Union") and isCallbackReturnValue
:
7441 # Go ahead and just convert directly into our actual return value
7442 declType
= CGWrapper(declType
, post
="&")
7443 declArgs
= "aRetVal"
7444 elif (not isMember
or isMember
== "Union") and typeNeedsRooting(type):
7445 declType
= CGTemplatedType("RootedDictionary", declType
)
7450 return JSToNativeConversionInfo(
7451 template
, declType
=declType
, declArgs
=declArgs
, dealWithOptional
=isOptional
7454 if type.isUndefined():
7455 assert not isOptional
7456 # This one only happens for return values, and its easy: Just
7458 return JSToNativeConversionInfo("")
7460 if not type.isPrimitive():
7461 raise TypeError("Need conversion for argument type '%s'" % str(type))
7463 typeName
= builtinNames
[type.tag()]
7465 conversionBehavior
= "eDefault"
7467 assert type.isInteger()
7468 conversionBehavior
= "eEnforceRange"
7470 assert type.isInteger()
7471 conversionBehavior
= "eClamp"
7475 declType
= CGGeneric("Nullable<" + typeName
+ ">")
7476 writeLoc
= "${declName}.SetValue()"
7477 readLoc
= "${declName}.Value()"
7478 nullCondition
= "${val}.isNullOrUndefined()"
7479 if defaultValue
is not None and isinstance(defaultValue
, IDLNullValue
):
7480 nullCondition
= "!(${haveValue}) || " + nullCondition
7485 ${declName}.SetNull();
7491 if (${nullCondition}) {
7492 $${declName}.SetNull();
7493 } else if (!ValueToPrimitive<${typeName}, ${conversionBehavior}>(cx, $${val}, "${sourceDescription}", &${writeLoc})) {
7497 nullCondition
=nullCondition
,
7499 conversionBehavior
=conversionBehavior
,
7500 sourceDescription
=firstCap(sourceDescription
),
7502 exceptionCode
=exceptionCode
,
7505 assert defaultValue
is None or not isinstance(defaultValue
, IDLNullValue
)
7506 writeLoc
= "${declName}"
7510 if (!ValueToPrimitive<${typeName}, ${conversionBehavior}>(cx, $${val}, "${sourceDescription}", &${writeLoc})) {
7515 conversionBehavior
=conversionBehavior
,
7516 sourceDescription
=firstCap(sourceDescription
),
7518 exceptionCode
=exceptionCode
,
7520 declType
= CGGeneric(typeName
)
7522 if type.isFloat() and not type.isUnrestricted() and not alwaysNull
:
7523 if lenientFloatCode
is not None:
7524 nonFiniteCode
= lenientFloatCode
7526 nonFiniteCode
= 'cx.ThrowErrorMessage<MSG_NOT_FINITE>("%s");\n' "%s" % (
7527 firstCap(sourceDescription
),
7531 # We're appending to an if-block brace, so strip trailing whitespace
7532 # and add an extra space before the else.
7533 template
= template
.rstrip()
7536 else if (!std::isfinite(${readLoc})) {
7541 nonFiniteCode
=nonFiniteCode
,
7545 defaultValue
is not None
7547 # We already handled IDLNullValue, so just deal with the other ones
7548 not isinstance(defaultValue
, IDLNullValue
)
7550 tag
= defaultValue
.type.tag()
7551 defaultStr
= getHandleDefault(defaultValue
)
7552 template
= handleDefault(template
, "%s = %s;\n" % (writeLoc
, defaultStr
))
7554 return JSToNativeConversionInfo(
7555 template
, declType
=declType
, dealWithOptional
=isOptional
7559 def instantiateJSToNativeConversion(info
, replacements
, checkForValue
=False):
7561 Take a JSToNativeConversionInfo as returned by getJSToNativeConversionInfo
7562 and a set of replacements as required by the strings in such an object, and
7563 generate code to convert into stack C++ types.
7565 If checkForValue is True, then the conversion will get wrapped in
7566 a check for ${haveValue}.
7568 templateBody
, declType
, holderType
, dealWithOptional
= (
7572 info
.dealWithOptional
,
7575 if dealWithOptional
and not checkForValue
:
7576 raise TypeError("Have to deal with optional things, but don't know how")
7577 if checkForValue
and declType
is None:
7579 "Need to predeclare optional things, so they will be "
7580 "outside the check for big enough arg count!"
7583 # We can't precompute our holder constructor arguments, since
7584 # those might depend on ${declName}, which we change below. Just
7585 # compute arguments at the point when we need them as we go.
7586 def getArgsCGThing(args
):
7587 return CGGeneric(string
.Template(args
).substitute(replacements
))
7590 # Make a copy of "replacements" since we may be about to start modifying it
7591 replacements
= dict(replacements
)
7592 originalDeclName
= replacements
["declName"]
7593 if declType
is not None:
7594 if dealWithOptional
:
7595 replacements
["declName"] = "%s.Value()" % originalDeclName
7596 declType
= CGTemplatedType("Optional", declType
)
7598 elif info
.declArgs
is not None:
7599 declCtorArgs
= CGWrapper(getArgsCGThing(info
.declArgs
), pre
="(", post
=")")
7607 CGGeneric(originalDeclName
),
7614 originalHolderName
= replacements
["holderName"]
7615 if holderType
is not None:
7616 if dealWithOptional
:
7617 replacements
["holderName"] = "%s.ref()" % originalHolderName
7618 holderType
= CGTemplatedType("Maybe", holderType
)
7619 holderCtorArgs
= None
7620 elif info
.holderArgs
is not None:
7621 holderCtorArgs
= CGWrapper(
7622 getArgsCGThing(info
.holderArgs
), pre
="(", post
=")"
7625 holderCtorArgs
= None
7631 CGGeneric(originalHolderName
),
7638 if "maybeMutableVal" not in replacements
:
7639 replacements
["maybeMutableVal"] = replacements
["val"]
7641 conversion
= CGGeneric(string
.Template(templateBody
).substitute(replacements
))
7644 if dealWithOptional
:
7645 declConstruct
= CGIndenter(
7647 "%s.Construct(%s);\n"
7650 getArgsCGThing(info
.declArgs
).define() if info
.declArgs
else "",
7654 if holderType
is not None:
7655 holderConstruct
= CGIndenter(
7661 getArgsCGThing(info
.holderArgs
).define()
7669 holderConstruct
= None
7671 declConstruct
= None
7672 holderConstruct
= None
7674 conversion
= CGList(
7677 string
.Template("if (${haveValue}) {\n").substitute(replacements
)
7681 CGIndenter(conversion
),
7686 result
.append(conversion
)
7690 def convertConstIDLValueToJSVal(value
):
7691 if isinstance(value
, IDLNullValue
):
7692 return "JS::NullValue()"
7693 if isinstance(value
, IDLUndefinedValue
):
7694 return "JS::UndefinedValue()"
7695 tag
= value
.type.tag()
7700 IDLType
.Tags
.uint16
,
7703 return "JS::Int32Value(%s)" % (value
.value
)
7704 if tag
== IDLType
.Tags
.uint32
:
7705 return "JS::NumberValue(%sU)" % (value
.value
)
7706 if tag
in [IDLType
.Tags
.int64
, IDLType
.Tags
.uint64
]:
7707 return "JS::CanonicalizedDoubleValue(%s)" % numericValue(tag
, value
.value
)
7708 if tag
== IDLType
.Tags
.bool:
7709 return "JS::BooleanValue(%s)" % (toStringBool(value
.value
))
7710 if tag
in [IDLType
.Tags
.float, IDLType
.Tags
.double
]:
7711 return "JS::CanonicalizedDoubleValue(%s)" % (value
.value
)
7712 raise TypeError("Const value of unhandled type: %s" % value
.type)
7715 class CGArgumentConverter(CGThing
):
7717 A class that takes an IDL argument object and its index in the
7718 argument list and generates code to unwrap the argument to the
7721 argDescription is a description of the argument for error-reporting
7722 purposes. Callers should assume that it might get placed in the middle of a
7723 sentence. If it ends up at the beginning of a sentence, its first character
7724 will be automatically uppercased.
7734 invalidEnumValueFatal
=True,
7735 lenientFloatCode
=None,
7737 CGThing
.__init
__(self
)
7738 self
.argument
= argument
7739 self
.argDescription
= argDescription
7740 assert not argument
.defaultValue
or argument
.optional
7742 replacer
= {"index": index
, "argc": "args.length()"}
7743 self
.replacementVariables
= {
7744 "declName": "arg%d" % index
,
7745 "holderName": ("arg%d" % index
) + "_holder",
7747 "passedToJSImpl": toStringBool(
7748 isJSImplementedDescriptor(descriptorProvider
)
7751 # If we have a method generated by the maplike/setlike portion of an
7752 # interface, arguments can possibly be undefined, but will need to be
7753 # converted to the key/value type of the backing object. In this case,
7754 # use .get() instead of direct access to the argument. This won't
7755 # matter for iterable since generated functions for those interface
7756 # don't take arguments.
7757 if member
.isMethod() and member
.isMaplikeOrSetlikeOrIterableMethod():
7758 self
.replacementVariables
["val"] = string
.Template(
7759 "args.get(${index})"
7760 ).substitute(replacer
)
7761 self
.replacementVariables
["maybeMutableVal"] = string
.Template(
7763 ).substitute(replacer
)
7765 self
.replacementVariables
["val"] = string
.Template(
7767 ).substitute(replacer
)
7768 haveValueCheck
= string
.Template("args.hasDefined(${index})").substitute(
7771 self
.replacementVariables
["haveValue"] = haveValueCheck
7772 self
.descriptorProvider
= descriptorProvider
7773 if self
.argument
.canHaveMissingValue():
7774 self
.argcAndIndex
= replacer
7776 self
.argcAndIndex
= None
7777 self
.invalidEnumValueFatal
= invalidEnumValueFatal
7778 self
.lenientFloatCode
= lenientFloatCode
7781 typeConversion
= getJSToNativeConversionInfo(
7783 self
.descriptorProvider
,
7784 isOptional
=(self
.argcAndIndex
is not None and not self
.argument
.variadic
),
7785 invalidEnumValueFatal
=self
.invalidEnumValueFatal
,
7786 defaultValue
=self
.argument
.defaultValue
,
7787 lenientFloatCode
=self
.lenientFloatCode
,
7788 isMember
="Variadic" if self
.argument
.variadic
else False,
7789 allowTreatNonCallableAsNull
=self
.argument
.allowTreatNonCallableAsNull(),
7790 sourceDescription
=self
.argDescription
,
7793 if not self
.argument
.variadic
:
7794 return instantiateJSToNativeConversion(
7795 typeConversion
, self
.replacementVariables
, self
.argcAndIndex
is not None
7798 # Variadic arguments get turned into a sequence.
7799 if typeConversion
.dealWithOptional
:
7800 raise TypeError("Shouldn't have optional things in variadics")
7801 if typeConversion
.holderType
is not None:
7802 raise TypeError("Shouldn't need holders for variadics")
7804 replacer
= dict(self
.argcAndIndex
, **self
.replacementVariables
)
7805 replacer
["seqType"] = CGTemplatedType(
7806 "AutoSequence", typeConversion
.declType
7808 if typeNeedsRooting(self
.argument
.type):
7810 "SequenceRooter<%s> ${holderName}(cx, &${declName});\n"
7811 % typeConversion
.declType
.define()
7815 replacer
["elemType"] = typeConversion
.declType
.define()
7817 replacer
["elementInitializer"] = initializerForType(self
.argument
.type) or ""
7819 # NOTE: Keep this in sync with sequence conversions as needed
7820 variadicConversion
= string
.Template(
7821 "${seqType} ${declName};\n"
7825 if (${argc} > ${index}) {
7826 if (!${declName}.SetCapacity(${argc} - ${index}, mozilla::fallible)) {
7827 JS_ReportOutOfMemory(cx);
7830 for (uint32_t variadicArg = ${index}; variadicArg < ${argc}; ++variadicArg) {
7831 // OK to do infallible append here, since we ensured capacity already.
7832 ${elemType}& slot = *${declName}.AppendElement(${elementInitializer});
7835 ).substitute(replacer
)
7837 val
= string
.Template("args[variadicArg]").substitute(replacer
)
7838 variadicConversion
+= indent(
7839 string
.Template(typeConversion
.template
).substitute(
7842 "maybeMutableVal": val
,
7844 # We only need holderName here to handle isExternal()
7845 # interfaces, which use an internal holder for the
7846 # conversion even when forceOwningType ends up true.
7847 "holderName": "tempHolder",
7848 # Use the same ${obj} as for the variadic arg itself
7849 "obj": replacer
["obj"],
7850 "passedToJSImpl": toStringBool(
7851 isJSImplementedDescriptor(self
.descriptorProvider
)
7858 variadicConversion
+= " }\n" "}\n"
7859 return variadicConversion
7862 def getMaybeWrapValueFuncForType(type):
7863 if type.isJSString():
7864 return "MaybeWrapStringValue"
7865 # Callbacks might actually be DOM objects; nothing prevents a page from
7867 if type.isCallback() or type.isCallbackInterface() or type.isObject():
7869 return "MaybeWrapObjectOrNullValue"
7870 return "MaybeWrapObjectValue"
7871 # SpiderMonkey interfaces are never DOM objects. Neither are sequences or
7872 # dictionaries, since those are always plain JS objects.
7873 if type.isSpiderMonkeyInterface() or type.isDictionary() or type.isSequence():
7875 return "MaybeWrapNonDOMObjectOrNullValue"
7876 return "MaybeWrapNonDOMObjectValue"
7878 return "MaybeWrapValue"
7880 # For other types, just go ahead an fall back on MaybeWrapValue for now:
7881 # it's always safe to do, and shouldn't be particularly slow for any of
7883 return "MaybeWrapValue"
7886 sequenceWrapLevel
= 0
7890 def getWrapTemplateForType(
7897 spiderMonkeyInterfacesAreStructs
,
7898 isConstructorRetval
=False,
7901 Reflect a C++ value stored in "result", of IDL type "type" into JS. The
7902 "successCode" is the code to run once we have successfully done the
7903 conversion and must guarantee that execution of the conversion template
7904 stops once the successCode has executed (e.g. by doing a 'return', or by
7905 doing a 'break' if the entire conversion template is inside a block that
7906 the 'break' will exit).
7908 If spiderMonkeyInterfacesAreStructs is true, then if the type is a
7909 SpiderMonkey interface, "result" is one of the
7910 dom::SpiderMonkeyInterfaceObjectStorage subclasses, not a JSObject*.
7912 The resulting string should be used with string.Template. It
7913 needs the following keys when substituting:
7915 jsvalHandle: something that can be passed to methods taking a
7916 JS::MutableHandle<JS::Value>. This can be a
7917 JS::MutableHandle<JS::Value> or a JS::Rooted<JS::Value>*.
7918 jsvalRef: something that can have .address() called on it to get a
7919 JS::Value* and .set() called on it to set it to a JS::Value.
7920 This can be a JS::MutableHandle<JS::Value> or a
7921 JS::Rooted<JS::Value>.
7922 obj: a JS::Handle<JSObject*>.
7924 Returns (templateString, infallibility of conversion template)
7926 if successCode
is None:
7927 successCode
= "return true;\n"
7930 return _setValue("", setter
="setUndefined")
7933 return _setValue("", setter
="setNull")
7935 def setInt32(value
):
7936 return _setValue(value
, setter
="setInt32")
7938 def setString(value
):
7939 return _setValue(value
, wrapAsType
=type, setter
="setString")
7941 def setObject(value
, wrapAsType
=None):
7942 return _setValue(value
, wrapAsType
=wrapAsType
, setter
="setObject")
7944 def setObjectOrNull(value
, wrapAsType
=None):
7945 return _setValue(value
, wrapAsType
=wrapAsType
, setter
="setObjectOrNull")
7947 def setUint32(value
):
7948 return _setValue(value
, setter
="setNumber")
7950 def setDouble(value
):
7951 return _setValue("JS_NumberValue(%s)" % value
)
7953 def setBoolean(value
):
7954 return _setValue(value
, setter
="setBoolean")
7956 def _setValue(value
, wrapAsType
=None, setter
="set"):
7958 Returns the code to set the jsval to value.
7960 If wrapAsType is not None, then will wrap the resulting value using the
7961 function that getMaybeWrapValueFuncForType(wrapAsType) returns.
7962 Otherwise, no wrapping will be done.
7964 if wrapAsType
is None:
7969 if (!${maybeWrap}(cx, $${jsvalHandle})) {
7974 maybeWrap
=getMaybeWrapValueFuncForType(wrapAsType
),
7975 exceptionCode
=exceptionCode
,
7976 successCode
=successCode
,
7978 return ("${jsvalRef}.%s(%s);\n" % (setter
, value
)) + tail
7980 def wrapAndSetPtr(wrapCall
, failureCode
=None):
7982 Returns the code to set the jsval by calling "wrapCall". "failureCode"
7983 is the code to run if calling "wrapCall" fails
7985 if failureCode
is None:
7986 failureCode
= exceptionCode
7995 failureCode
=failureCode
,
7996 successCode
=successCode
,
7999 if type is None or type.isUndefined():
8000 return (setUndefined(), True)
8002 if (type.isSequence() or type.isRecord()) and type.nullable():
8003 # These are both wrapped in Nullable<>
8004 recTemplate
, recInfall
= getWrapTemplateForType(
8007 "%s.Value()" % result
,
8011 spiderMonkeyInterfacesAreStructs
,
8016 if (${result}.IsNull()) {
8023 recTemplate
=recTemplate
,
8025 return code
, recInfall
8027 if type.isSequence():
8028 # Now do non-nullable sequences. Our success code is just to break to
8029 # where we set the element in the array. Note that we bump the
8030 # sequenceWrapLevel around this call so that nested sequence conversions
8031 # will use different iteration variables.
8032 global sequenceWrapLevel
8033 index
= "sequenceIdx%d" % sequenceWrapLevel
8034 sequenceWrapLevel
+= 1
8035 innerTemplate
= wrapForType(
8039 "result": "%s[%s]" % (result
, index
),
8040 "successCode": "break;\n",
8042 "jsvalHandle": "&tmp",
8043 "returnsNewObject": returnsNewObject
,
8044 "exceptionCode": exceptionCode
,
8045 "obj": "returnArray",
8046 "spiderMonkeyInterfacesAreStructs": spiderMonkeyInterfacesAreStructs
,
8049 sequenceWrapLevel
-= 1
8053 uint32_t length = ${result}.Length();
8054 JS::Rooted<JSObject*> returnArray(cx, JS::NewArrayObject(cx, length));
8060 JS::Rooted<JS::Value> tmp(cx);
8061 for (uint32_t ${index} = 0; ${index} < length; ++${index}) {
8062 // Control block to let us common up the JS_DefineElement calls when there
8063 // are different ways to succeed at wrapping the object.
8067 if (!JS_DefineElement(cx, returnArray, ${index}, tmp,
8068 JSPROP_ENUMERATE)) {
8076 exceptionCode
=exceptionCode
,
8078 innerTemplate
=innerTemplate
,
8079 set=setObject("*returnArray"),
8082 return (code
, False)
8085 # Now do non-nullable record. Our success code is just to break to
8086 # where we define the property on the object. Note that we bump the
8087 # recordWrapLevel around this call so that nested record conversions
8088 # will use different temp value names.
8089 global recordWrapLevel
8090 valueName
= "recordValue%d" % recordWrapLevel
8091 recordWrapLevel
+= 1
8092 innerTemplate
= wrapForType(
8096 "result": valueName
,
8097 "successCode": "break;\n",
8099 "jsvalHandle": "&tmp",
8100 "returnsNewObject": returnsNewObject
,
8101 "exceptionCode": exceptionCode
,
8103 "spiderMonkeyInterfacesAreStructs": spiderMonkeyInterfacesAreStructs
,
8106 recordWrapLevel
-= 1
8107 if type.keyType
.isByteString():
8108 # There is no length-taking JS_DefineProperty. So to keep
8109 # things sane with embedded nulls, we want to byte-inflate
8110 # to an nsAString. The only byte-inflation function we
8111 # have around is AppendASCIItoUTF16, which luckily doesn't
8112 # assert anything about the input being ASCII.
8113 expandedKeyDecl
= "NS_ConvertASCIItoUTF16 expandedKey(entry.mKey);\n"
8114 keyName
= "expandedKey"
8115 elif type.keyType
.isUTF8String():
8116 # We do the same as above for utf8 strings. We could do better if
8117 # we had a DefineProperty API that takes utf-8 property names.
8118 expandedKeyDecl
= "NS_ConvertUTF8toUTF16 expandedKey(entry.mKey);\n"
8119 keyName
= "expandedKey"
8121 expandedKeyDecl
= ""
8122 keyName
= "entry.mKey"
8127 JS::Rooted<JSObject*> returnObj(cx, JS_NewPlainObject(cx));
8133 JS::Rooted<JS::Value> tmp(cx);
8134 for (auto& entry : ${result}.Entries()) {
8135 auto& ${valueName} = entry.mValue;
8136 // Control block to let us common up the JS_DefineUCProperty calls when there
8137 // are different ways to succeed at wrapping the value.
8142 if (!JS_DefineUCProperty(cx, returnObj,
8143 ${keyName}.BeginReading(),
8144 ${keyName}.Length(), tmp,
8145 JSPROP_ENUMERATE)) {
8153 exceptionCode
=exceptionCode
,
8154 valueName
=valueName
,
8155 innerTemplate
=innerTemplate
,
8156 expandedKeyDecl
=expandedKeyDecl
,
8158 set=setObject("*returnObj"),
8161 return (code
, False)
8163 if type.isPromise():
8164 assert not type.nullable()
8165 # The use of ToJSValue here is a bit annoying because the Promise
8166 # version is not inlined. But we can't put an inline version in either
8167 # ToJSValue.h or BindingUtils.h, because Promise.h includes ToJSValue.h
8168 # and that includes BindingUtils.h, so we'd get an include loop if
8169 # either of those headers included Promise.h. And trying to write the
8170 # conversion by hand here is pretty annoying because we have to handle
8171 # the various RefPtr, rawptr, NonNull, etc cases, which ToJSValue will
8172 # handle for us. So just eat the cost of the function call.
8173 return (wrapAndSetPtr("ToJSValue(cx, %s, ${jsvalHandle})" % result
), False)
8175 if type.isGeckoInterface() and not type.isCallbackInterface():
8176 descriptor
= descriptorProvider
.getDescriptor(
8177 type.unroll().inner
.identifier
.name
8180 if descriptor
.interface
.identifier
.name
== "WindowProxy":
8181 template
, infal
= getWrapTemplateForType(
8184 "%s.Value()" % result
,
8188 spiderMonkeyInterfacesAreStructs
,
8191 "if (%s.IsNull()) {\n" % result
8198 wrappingCode
= "if (!%s) {\n" % (result
) + indent(setNull()) + "}\n"
8202 if not descriptor
.interface
.isExternal():
8203 if descriptor
.wrapperCache
:
8204 wrapMethod
= "GetOrCreateDOMReflector"
8205 wrapArgs
= "cx, %s, ${jsvalHandle}" % result
8207 wrapMethod
= "WrapNewBindingNonWrapperCachedObject"
8208 wrapArgs
= "cx, ${obj}, %s, ${jsvalHandle}" % result
8209 if isConstructorRetval
:
8210 wrapArgs
+= ", desiredProto"
8211 wrap
= "%s(%s)" % (wrapMethod
, wrapArgs
)
8212 # Can only fail to wrap as a new-binding object if they already
8213 # threw an exception.
8214 failed
= "MOZ_ASSERT(JS_IsExceptionPending(cx));\n" + exceptionCode
8216 if descriptor
.notflattened
:
8217 getIID
= "&NS_GET_IID(%s), " % descriptor
.nativeType
8220 wrap
= "WrapObject(cx, %s, %s${jsvalHandle})" % (result
, getIID
)
8223 wrappingCode
+= wrapAndSetPtr(wrap
, failed
)
8224 return (wrappingCode
, False)
8226 if type.isJSString():
8227 return (setString(result
), False)
8229 if type.isDOMString() or type.isUSVString():
8232 wrapAndSetPtr("xpc::StringToJsval(cx, %s, ${jsvalHandle})" % result
),
8238 "xpc::NonVoidStringToJsval(cx, %s, ${jsvalHandle})" % result
8243 if type.isByteString():
8246 wrapAndSetPtr("ByteStringToJsval(cx, %s, ${jsvalHandle})" % result
),
8252 "NonVoidByteStringToJsval(cx, %s, ${jsvalHandle})" % result
8257 if type.isUTF8String():
8260 wrapAndSetPtr("UTF8StringToJsval(cx, %s, ${jsvalHandle})" % result
),
8266 "NonVoidUTF8StringToJsval(cx, %s, ${jsvalHandle})" % result
8273 resultLoc
= "%s.Value()" % result
8278 if (!ToJSValue(cx, ${result}, $${jsvalHandle})) {
8284 exceptionCode
=exceptionCode
,
8285 successCode
=successCode
,
8289 conversion
= CGIfElseWrapper(
8290 "%s.IsNull()" % result
, CGGeneric(setNull()), CGGeneric(conversion
)
8292 return conversion
, False
8294 if type.isCallback() or type.isCallbackInterface():
8295 # Callbacks can store null if we nuked the compartments their
8297 wrapCode
= setObjectOrNull(
8298 "GetCallbackFromCallbackObject(cx, %(result)s)", wrapAsType
=type
8302 "if (%(result)s) {\n"
8308 wrapCode
= wrapCode
% {"result": result
}
8309 return wrapCode
, False
8312 # See comments in GetOrCreateDOMReflector explaining why we need
8314 # NB: _setValue(..., type-that-is-any) calls JS_WrapValue(), so is fallible
8315 head
= "JS::ExposeValueToActiveJS(%s);\n" % result
8316 return (head
+ _setValue(result
, wrapAsType
=type), False)
8318 if type.isObject() or (
8319 type.isSpiderMonkeyInterface() and not spiderMonkeyInterfacesAreStructs
8321 # See comments in GetOrCreateDOMReflector explaining why we need
8325 setter
= setObjectOrNull
8327 JS::ExposeObjectToActiveJS(%s);
8336 head
= "JS::ExposeObjectToActiveJS(%s);\n" % result
8337 # NB: setObject{,OrNull}(..., some-object-type) calls JS_WrapValue(), so is fallible
8338 return (head
+ setter(toValue
% result
, wrapAsType
=type), False)
8340 if type.isObservableArray():
8341 # This first argument isn't used at all for now, the attribute getter
8342 # for ObservableArray type are generated in getObservableArrayGetterBody
8348 or type.isPrimitive()
8349 or type.isDictionary()
8350 or (type.isSpiderMonkeyInterface() and spiderMonkeyInterfacesAreStructs
)
8352 raise TypeError("Need to learn to wrap %s" % type)
8355 recTemplate
, recInfal
= getWrapTemplateForType(
8358 "%s.Value()" % result
,
8362 spiderMonkeyInterfacesAreStructs
,
8365 "if (%s.IsNull()) {\n" % result
+ indent(setNull()) + "}\n" + recTemplate
,
8369 if type.isSpiderMonkeyInterface():
8370 assert spiderMonkeyInterfacesAreStructs
8371 # See comments in GetOrCreateDOMReflector explaining why we need
8373 # NB: setObject(..., some-object-type) calls JS_WrapValue(), so is fallible
8374 return (setObject("*%s.Obj()" % result
, wrapAsType
=type), False)
8377 return (wrapAndSetPtr("%s.ToJSVal(cx, ${obj}, ${jsvalHandle})" % result
), False)
8379 if type.isDictionary():
8381 wrapAndSetPtr("%s.ToObjectInternal(cx, ${jsvalHandle})" % result
),
8391 IDLType
.Tags
.uint16
,
8394 return (setInt32("int32_t(%s)" % result
), True)
8398 IDLType
.Tags
.uint64
,
8399 IDLType
.Tags
.unrestricted_float
,
8401 IDLType
.Tags
.unrestricted_double
,
8402 IDLType
.Tags
.double
,
8404 # XXXbz will cast to double do the "even significand" thing that webidl
8405 # calls for for 64-bit ints? Do we care?
8406 return (setDouble("double(%s)" % result
), True)
8408 elif tag
== IDLType
.Tags
.uint32
:
8409 return (setUint32(result
), True)
8411 elif tag
== IDLType
.Tags
.bool:
8412 return (setBoolean(result
), True)
8415 raise TypeError("Need to learn to wrap primitive: %s" % type)
8418 def wrapForType(type, descriptorProvider
, templateValues
):
8420 Reflect a C++ value of IDL type "type" into JS. TemplateValues is a dict
8421 that should contain:
8423 * 'jsvalRef': something that can have .address() called on it to get a
8424 JS::Value* and .set() called on it to set it to a JS::Value.
8425 This can be a JS::MutableHandle<JS::Value> or a
8426 JS::Rooted<JS::Value>.
8427 * 'jsvalHandle': something that can be passed to methods taking a
8428 JS::MutableHandle<JS::Value>. This can be a
8429 JS::MutableHandle<JS::Value> or a JS::Rooted<JS::Value>*.
8430 * 'obj' (optional): the name of the variable that contains the JSObject to
8431 use as a scope when wrapping, if not supplied 'obj'
8432 will be used as the name
8433 * 'result' (optional): the name of the variable in which the C++ value is
8434 stored, if not supplied 'result' will be used as
8436 * 'successCode' (optional): the code to run once we have successfully
8437 done the conversion, if not supplied 'return
8438 true;' will be used as the code. The
8439 successCode must ensure that once it runs no
8440 more of the conversion template will be
8441 executed (e.g. by doing a 'return' or 'break'
8443 * 'returnsNewObject' (optional): If true, we're wrapping for the return
8444 value of a [NewObject] method. Assumed
8446 * 'exceptionCode' (optional): Code to run when a JS exception is thrown.
8447 The default is "return false;". The code
8448 passed here must return.
8449 * 'isConstructorRetval' (optional): If true, we're wrapping a constructor
8452 wrap
= getWrapTemplateForType(
8455 templateValues
.get("result", "result"),
8456 templateValues
.get("successCode", None),
8457 templateValues
.get("returnsNewObject", False),
8458 templateValues
.get("exceptionCode", "return false;\n"),
8459 templateValues
.get("spiderMonkeyInterfacesAreStructs", False),
8460 isConstructorRetval
=templateValues
.get("isConstructorRetval", False),
8463 defaultValues
= {"obj": "obj"}
8464 return string
.Template(wrap
).substitute(defaultValues
, **templateValues
)
8467 def infallibleForMember(member
, type, descriptorProvider
):
8469 Determine the fallibility of changing a C++ value of IDL type "type" into
8470 JS for the given attribute. Apart from returnsNewObject, all the defaults
8471 are used, since the fallbility does not change based on the boolean values,
8472 and the template will be discarded.
8474 CURRENT ASSUMPTIONS:
8475 We assume that successCode for wrapping up return values cannot contain
8478 return getWrapTemplateForType(
8483 memberReturnsNewObject(member
),
8489 def leafTypeNeedsCx(type, retVal
):
8493 or type.isJSString()
8494 or (retVal
and type.isSpiderMonkeyInterface())
8498 def leafTypeNeedsScopeObject(type, retVal
):
8499 return retVal
and type.isSpiderMonkeyInterface()
8502 def leafTypeNeedsRooting(type):
8503 return leafTypeNeedsCx(type, False) or type.isSpiderMonkeyInterface()
8506 def typeNeedsRooting(type):
8507 return typeMatchesLambda(type, lambda t
: leafTypeNeedsRooting(t
))
8510 def typeNeedsCx(type, retVal
=False):
8511 return typeMatchesLambda(type, lambda t
: leafTypeNeedsCx(t
, retVal
))
8514 def typeNeedsScopeObject(type, retVal
=False):
8515 return typeMatchesLambda(type, lambda t
: leafTypeNeedsScopeObject(t
, retVal
))
8518 def typeMatchesLambda(type, func
):
8522 return typeMatchesLambda(type.inner
, func
)
8523 if type.isSequence() or type.isRecord():
8524 return typeMatchesLambda(type.inner
, func
)
8526 return any(typeMatchesLambda(t
, func
) for t
in type.unroll().flatMemberTypes
)
8527 if type.isDictionary():
8528 return dictionaryMatchesLambda(type.inner
, func
)
8532 def dictionaryMatchesLambda(dictionary
, func
):
8533 return any(typeMatchesLambda(m
.type, func
) for m
in dictionary
.members
) or (
8534 dictionary
.parent
and dictionaryMatchesLambda(dictionary
.parent
, func
)
8538 # Whenever this is modified, please update CGNativeMember.getRetvalInfo as
8539 # needed to keep the types compatible.
8540 def getRetvalDeclarationForType(returnType
, descriptorProvider
, isMember
=False):
8542 Returns a tuple containing five things:
8544 1) A CGThing for the type of the return value, or None if there is no need
8547 2) A value indicating the kind of ourparam to pass the value as. Valid
8548 options are None to not pass as an out param at all, "ref" (to pass a
8549 reference as an out param), and "ptr" (to pass a pointer as an out
8552 3) A CGThing for a tracer for the return value, or None if no tracing is
8555 4) An argument string to pass to the retval declaration
8556 constructor or None if there are no arguments.
8558 5) The name of a function that needs to be called with the return value
8559 before using it, or None if no function needs to be called.
8561 if returnType
is None or returnType
.isUndefined():
8562 # Nothing to declare
8563 return None, None, None, None, None
8564 if returnType
.isPrimitive() and returnType
.tag() in builtinNames
:
8565 result
= CGGeneric(builtinNames
[returnType
.tag()])
8566 if returnType
.nullable():
8567 result
= CGTemplatedType("Nullable", result
)
8568 return result
, None, None, None, None
8569 if returnType
.isJSString():
8571 raise TypeError("JSString not supported as return type member")
8572 return CGGeneric("JS::Rooted<JSString*>"), "ptr", None, "cx", None
8573 if returnType
.isDOMString() or returnType
.isUSVString():
8575 return CGGeneric("nsString"), "ref", None, None, None
8576 return CGGeneric("DOMString"), "ref", None, None, None
8577 if returnType
.isByteString() or returnType
.isUTF8String():
8579 return CGGeneric("nsCString"), "ref", None, None, None
8580 return CGGeneric("nsAutoCString"), "ref", None, None, None
8581 if returnType
.isEnum():
8582 result
= CGGeneric(returnType
.unroll().inner
.identifier
.name
)
8583 if returnType
.nullable():
8584 result
= CGTemplatedType("Nullable", result
)
8585 return result
, None, None, None, None
8586 if returnType
.isGeckoInterface() or returnType
.isPromise():
8587 if returnType
.isGeckoInterface():
8588 typeName
= returnType
.unroll().inner
.identifier
.name
8589 if typeName
== "WindowProxy":
8590 result
= CGGeneric("WindowProxyHolder")
8591 if returnType
.nullable():
8592 result
= CGTemplatedType("Nullable", result
)
8593 return result
, None, None, None, None
8595 typeName
= descriptorProvider
.getDescriptor(typeName
).nativeType
8597 typeName
= "Promise"
8600 result
= CGGeneric("StrongPtrForMember<%s>" % typeName
)
8602 conversion
= CGGeneric("StrongOrRawPtr<%s>" % typeName
)
8603 result
= CGGeneric("auto")
8604 return result
, None, None, None, conversion
8605 if returnType
.isCallback():
8606 name
= returnType
.unroll().callback
.identifier
.name
8607 return CGGeneric("RefPtr<%s>" % name
), None, None, None, None
8608 if returnType
.isAny():
8610 return CGGeneric("JS::Value"), None, None, None, None
8611 return CGGeneric("JS::Rooted<JS::Value>"), "ptr", None, "cx", None
8612 if returnType
.isObject() or returnType
.isSpiderMonkeyInterface():
8614 return CGGeneric("JSObject*"), None, None, None, None
8615 return CGGeneric("JS::Rooted<JSObject*>"), "ptr", None, "cx", None
8616 if returnType
.isSequence():
8617 nullable
= returnType
.nullable()
8619 returnType
= returnType
.inner
8620 result
, _
, _
, _
, _
= getRetvalDeclarationForType(
8621 returnType
.inner
, descriptorProvider
, isMember
="Sequence"
8623 # While we have our inner type, set up our rooter, if needed
8624 if not isMember
and typeNeedsRooting(returnType
):
8626 "SequenceRooter<%s > resultRooter(cx, &result);\n" % result
.define()
8630 result
= CGTemplatedType("nsTArray", result
)
8632 result
= CGTemplatedType("Nullable", result
)
8633 return result
, "ref", rooter
, None, None
8634 if returnType
.isRecord():
8635 nullable
= returnType
.nullable()
8637 returnType
= returnType
.inner
8638 result
, _
, _
, _
, _
= getRetvalDeclarationForType(
8639 returnType
.inner
, descriptorProvider
, isMember
="Record"
8641 # While we have our inner type, set up our rooter, if needed
8642 if not isMember
and typeNeedsRooting(returnType
):
8644 "RecordRooter<%s> resultRooter(cx, &result);\n"
8645 % ("nsString, " + result
.define())
8649 result
= CGTemplatedType("Record", [recordKeyDeclType(returnType
), result
])
8651 result
= CGTemplatedType("Nullable", result
)
8652 return result
, "ref", rooter
, None, None
8653 if returnType
.isDictionary():
8654 nullable
= returnType
.nullable()
8655 dictName
= CGDictionary
.makeDictionaryName(returnType
.unroll().inner
)
8656 result
= CGGeneric(dictName
)
8657 if not isMember
and typeNeedsRooting(returnType
):
8659 result
= CGTemplatedType("NullableRootedDictionary", result
)
8661 result
= CGTemplatedType("RootedDictionary", result
)
8665 result
= CGTemplatedType("Nullable", result
)
8667 return result
, "ref", None, resultArgs
, None
8668 if returnType
.isUnion():
8669 result
= CGGeneric(CGUnionStruct
.unionTypeName(returnType
.unroll(), True))
8670 if not isMember
and typeNeedsRooting(returnType
):
8671 if returnType
.nullable():
8672 result
= CGTemplatedType("NullableRootedUnion", result
)
8674 result
= CGTemplatedType("RootedUnion", result
)
8677 if returnType
.nullable():
8678 result
= CGTemplatedType("Nullable", result
)
8680 return result
, "ref", None, resultArgs
, None
8681 raise TypeError("Don't know how to declare return value for %s" % returnType
)
8684 def needCx(returnType
, arguments
, extendedAttributes
, considerTypes
, static
=False):
8689 typeNeedsCx(returnType
, True) or any(typeNeedsCx(a
.type) for a
in arguments
)
8691 or "implicitJSContext" in extendedAttributes
8695 def needScopeObject(
8696 returnType
, arguments
, extendedAttributes
, isWrapperCached
, considerTypes
, isMember
8699 isMember should be true if we're dealing with an attribute
8700 annotated as [StoreInSlot].
8704 and not isWrapperCached
8706 (not isMember
and typeNeedsScopeObject(returnType
, True))
8707 or any(typeNeedsScopeObject(a
.type) for a
in arguments
)
8712 def callerTypeGetterForDescriptor(descriptor
):
8713 if descriptor
.interface
.isExposedInAnyWorker():
8714 systemCallerGetter
= "nsContentUtils::ThreadsafeIsSystemCaller"
8716 systemCallerGetter
= "nsContentUtils::IsSystemCaller"
8717 return "%s(cx) ? CallerType::System : CallerType::NonSystem" % systemCallerGetter
8720 class CGCallGenerator(CGThing
):
8722 A class to generate an actual call to a C++ object. Assumes that the C++
8723 object is stored in a variable whose name is given by the |object| argument.
8725 needsCallerType is a boolean indicating whether the call should receive
8726 a PrincipalType for the caller.
8728 needsErrorResult is a boolean indicating whether the call should be
8729 fallible and thus needs ErrorResult parameter.
8731 resultVar: If the returnType is not void, then the result of the call is
8732 stored in a C++ variable named by resultVar. The caller is responsible for
8733 declaring the result variable. If the caller doesn't care about the result
8734 value, resultVar can be omitted.
8736 context: The context string to pass to MaybeSetPendingException.
8756 CGThing
.__init
__(self
)
8764 ) = getRetvalDeclarationForType(returnType
, descriptor
)
8766 args
= CGList([CGGeneric(arg
) for arg
in argsPre
], ", ")
8767 for a
, name
in arguments
:
8768 arg
= CGGeneric(name
)
8770 # Now constify the things that need it
8772 if a
.type.isDictionary():
8774 if a
.type.isSequence():
8776 if a
.type.isRecord():
8778 # isObject() types are always a JS::Rooted, whether
8779 # nullable or not, and it turns out a const JS::Rooted
8780 # is not very helpful at all (in particular, it won't
8781 # even convert to a JS::Handle).
8782 # XXX bz Well, why not???
8783 if a
.type.nullable() and not a
.type.isObject():
8785 if a
.type.isString():
8787 if a
.canHaveMissingValue():
8788 # This will need an Optional or it's a variadic;
8789 # in both cases it should be const.
8791 if a
.type.isUnion():
8793 if a
.type.isSpiderMonkeyInterface():
8798 arg
= CGWrapper(arg
, pre
="Constify(", post
=")")
8799 # And convert NonNull<T> to T&
8801 (a
.type.isGeckoInterface() or a
.type.isCallback() or a
.type.isPromise())
8802 and not a
.type.nullable()
8803 ) or a
.type.isDOMString():
8804 arg
= CGWrapper(arg
, pre
="NonNullHelper(", post
=")")
8806 # If it's a refcounted object, let the static analysis know it's
8807 # alive for the duration of the call.
8808 if a
.type.isGeckoInterface() or a
.type.isCallback():
8809 arg
= CGWrapper(arg
, pre
="MOZ_KnownLive(", post
=")")
8813 needResultDecl
= False
8815 # Build up our actual call
8816 self
.cgRoot
= CGList([])
8818 # Return values that go in outparams go here
8819 if resultOutParam
is not None:
8820 if resultVar
is None:
8821 needResultDecl
= True
8822 resultVar
= "result"
8823 if resultOutParam
== "ref":
8824 args
.append(CGGeneric(resultVar
))
8826 assert resultOutParam
== "ptr"
8827 args
.append(CGGeneric("&" + resultVar
))
8829 needsSubjectPrincipal
= "needsSubjectPrincipal" in extendedAttributes
8830 if needsSubjectPrincipal
:
8831 needsNonSystemPrincipal
= (
8832 "needsNonSystemSubjectPrincipal" in extendedAttributes
8834 if needsNonSystemPrincipal
:
8835 principalType
= "nsIPrincipal*"
8836 subjectPrincipalArg
= "subjectPrincipal"
8837 checkPrincipal
= dedent(
8839 if (principal->IsSystemPrincipal()) {
8840 principal = nullptr;
8845 principalType
= "NonNull<nsIPrincipal>"
8846 subjectPrincipalArg
= "NonNullHelper(subjectPrincipal)"
8853 ${principalType} subjectPrincipal;
8855 JS::Realm* realm = js::GetContextRealm(cx);
8857 JSPrincipals* principals = JS::GetRealmPrincipals(realm);
8858 nsIPrincipal* principal = nsJSPrincipals::get(principals);
8860 subjectPrincipal = principal;
8863 principalType
=principalType
,
8864 checkPrincipal
=checkPrincipal
,
8869 args
.append(CGGeneric("MOZ_KnownLive(%s)" % subjectPrincipalArg
))
8873 args
.append(CGGeneric("SystemCallerGuarantee()"))
8875 args
.append(CGGeneric(callerTypeGetterForDescriptor(descriptor
)))
8877 canOOM
= "canOOM" in extendedAttributes
8878 if needsErrorResult
:
8879 args
.append(CGGeneric("rv"))
8881 args
.append(CGGeneric("OOMReporter::From(rv)"))
8882 args
.extend(CGGeneric(arg
) for arg
in argsPost
)
8884 call
= CGGeneric(nativeMethodName
)
8886 call
= CGWrapper(call
, pre
="%s->" % object)
8887 call
= CGList([call
, CGWrapper(args
, pre
="(", post
=")")])
8888 if returnType
is None or returnType
.isUndefined() or resultOutParam
is not None:
8889 assert resultConversion
is None
8895 "// NOTE: This assert does NOT call the function.\n"
8896 "static_assert(std::is_void_v<decltype("
8898 post
=')>, "Should be returning void here");',
8904 elif resultConversion
is not None:
8905 call
= CGList([resultConversion
, CGWrapper(call
, pre
="(", post
=")")])
8906 if resultVar
is None and result
is not None:
8907 needResultDecl
= True
8908 resultVar
= "result"
8911 if resultArgs
is not None:
8912 resultArgsStr
= "(%s)" % resultArgs
8915 result
= CGWrapper(result
, post
=(" %s%s" % (resultVar
, resultArgsStr
)))
8916 if resultOutParam
is None and resultArgs
is None:
8917 call
= CGList([result
, CGWrapper(call
, pre
="(", post
=")")])
8919 self
.cgRoot
.append(CGWrapper(result
, post
=";\n"))
8920 if resultOutParam
is None:
8921 call
= CGWrapper(call
, pre
=resultVar
+ " = ")
8922 if resultRooter
is not None:
8923 self
.cgRoot
.append(resultRooter
)
8924 elif result
is not None:
8925 assert resultOutParam
is None
8926 call
= CGWrapper(call
, pre
=resultVar
+ " = ")
8928 call
= CGWrapper(call
, post
=";\n")
8929 self
.cgRoot
.append(call
)
8931 if needsErrorResult
or canOOM
:
8932 self
.cgRoot
.prepend(CGGeneric("FastErrorResult rv;\n"))
8937 if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx, ${context}))) {
8946 self
.cgRoot
.append(CGGeneric("MOZ_ASSERT(!JS_IsExceptionPending(cx));\n"))
8949 return self
.cgRoot
.define()
8952 def getUnionMemberName(type):
8953 # Promises can't be in unions, because they're not distinguishable
8954 # from anything else.
8955 assert not type.isPromise()
8956 if type.isGeckoInterface():
8957 return type.inner
.identifier
.name
8959 return type.inner
.identifier
.name
8963 # A counter for making sure that when we're wrapping up things in
8964 # nested sequences we don't use the same variable name to iterate over
8965 # different sequences.
8966 sequenceWrapLevel
= 0
8970 def wrapTypeIntoCurrentCompartment(type, value
, isMember
=True):
8972 Take the thing named by "value" and if it contains "any",
8973 "object", or spidermonkey-interface types inside return a CGThing
8974 that will wrap them into the current compartment.
8977 assert not type.nullable()
8979 value
= "JS::MutableHandle<JS::Value>::fromMarkedLocation(&%s)" % value
8983 "if (!JS_WrapValue(cx, %s)) {\n" " return false;\n" "}\n" % value
8988 value
= "JS::MutableHandle<JSObject*>::fromMarkedLocation(&%s)" % value
8992 "if (!JS_WrapObject(cx, %s)) {\n" " return false;\n" "}\n" % value
8995 if type.isSpiderMonkeyInterface():
8998 value
= "%s.Value()" % value
8999 wrapCode
= CGGeneric(
9000 "if (!%s.WrapIntoNewCompartment(cx)) {\n" " return false;\n" "}\n" % value
9003 wrapCode
= CGIfWrapper(wrapCode
, "!%s.IsNull()" % origValue
)
9006 if type.isSequence():
9011 value
= "%s.Value()" % value
9012 global sequenceWrapLevel
9013 index
= "indexName%d" % sequenceWrapLevel
9014 sequenceWrapLevel
+= 1
9015 wrapElement
= wrapTypeIntoCurrentCompartment(
9016 type.inner
, "%s[%s]" % (value
, index
)
9018 sequenceWrapLevel
-= 1
9021 wrapCode
= CGWrapper(
9022 CGIndenter(wrapElement
),
9024 "for (uint32_t %s = 0; %s < %s.Length(); ++%s) {\n"
9025 % (index
, index
, value
, index
)
9029 if origType
.nullable():
9030 wrapCode
= CGIfWrapper(wrapCode
, "!%s.IsNull()" % origValue
)
9037 recordRef
= "%s.Value()" % value
9040 global recordWrapLevel
9041 entryRef
= "mapEntry%d" % recordWrapLevel
9042 recordWrapLevel
+= 1
9043 wrapElement
= wrapTypeIntoCurrentCompartment(type.inner
, "%s.mValue" % entryRef
)
9044 recordWrapLevel
-= 1
9047 wrapCode
= CGWrapper(
9048 CGIndenter(wrapElement
),
9049 pre
=("for (auto& %s : %s.Entries()) {\n" % (entryRef
, recordRef
)),
9052 if origType
.nullable():
9053 wrapCode
= CGIfWrapper(wrapCode
, "!%s.IsNull()" % value
)
9056 if type.isDictionary():
9057 assert not type.nullable()
9061 for member
in myDict
.members
:
9062 memberWrap
= wrapArgIntoCurrentCompartment(
9065 % (value
, CGDictionary
.makeMemberName(member
.identifier
.name
)),
9068 memberWraps
.append(memberWrap
)
9069 myDict
= myDict
.parent
9070 return CGList(memberWraps
) if len(memberWraps
) != 0 else None
9077 value
= "%s.Value()" % value
9079 for member
in type.flatMemberTypes
:
9080 memberName
= getUnionMemberName(member
)
9081 memberWrap
= wrapTypeIntoCurrentCompartment(
9082 member
, "%s.GetAs%s()" % (value
, memberName
)
9085 memberWrap
= CGIfWrapper(memberWrap
, "%s.Is%s()" % (value
, memberName
))
9086 memberWraps
.append(memberWrap
)
9087 if len(memberWraps
) == 0:
9089 wrapCode
= CGList(memberWraps
, "else ")
9090 if origType
.nullable():
9091 wrapCode
= CGIfWrapper(wrapCode
, "!%s.IsNull()" % origValue
)
9097 or type.isPrimitive()
9099 or type.isGeckoInterface()
9100 or type.isCallback()
9103 # All of these don't need wrapping.
9107 "Unknown type; we don't know how to wrap it in constructor "
9108 "arguments: %s" % type
9112 def wrapArgIntoCurrentCompartment(arg
, value
, isMember
=True):
9114 As wrapTypeIntoCurrentCompartment but handles things being optional
9117 isOptional
= arg
.canHaveMissingValue()
9119 value
= value
+ ".Value()"
9120 wrap
= wrapTypeIntoCurrentCompartment(arg
.type, value
, isMember
)
9121 if wrap
and isOptional
:
9122 wrap
= CGIfWrapper(wrap
, "%s.WasPassed()" % origValue
)
9126 def needsCallerType(m
):
9127 return m
.getExtendedAttribute("NeedsCallerType")
9130 class CGPerSignatureCall(CGThing
):
9132 This class handles the guts of generating code for a particular
9133 call signature. A call signature consists of four things:
9135 1) A return type, which can be None to indicate that there is no
9136 actual return value (e.g. this is an attribute setter) or an
9137 IDLType if there's an IDL type involved (including |void|).
9138 2) An argument list, which is allowed to be empty.
9139 3) A name of a native method to call. It is ignored for methods
9140 annotated with the "[WebExtensionStub=...]" extended attribute.
9141 4) Whether or not this method is static. Note that this only controls how
9142 the method is called (|self->nativeMethodName(...)| vs
9143 |nativeMethodName(...)|).
9145 We also need to know whether this is a method or a getter/setter
9146 to do error reporting correctly.
9148 The idlNode parameter can be either a method or an attr. We can query
9149 |idlNode.identifier| in both cases, so we can be agnostic between the two.
9151 dontSetSlot should be set to True if the value should not be cached in a
9152 slot (even if the attribute is marked as StoreInSlot or Cached in the
9155 errorReportingLabel can contain a custom label to use for error reporting.
9156 It will be inserted as is in the code, so if it needs to be a literal
9157 string in C++ it should be quoted.
9159 additionalArgsPre contains additional arguments that are added after the
9160 arguments that CGPerSignatureCall itself adds (JSContext, global, …), and
9161 before the actual arguments.
9164 # XXXbz For now each entry in the argument list is either an
9165 # IDLArgument or a FakeArgument, but longer-term we may want to
9166 # have ways of flagging things like JSContext* or optional_argc in
9177 argConversionStartsAt
=0,
9180 isConstructor
=False,
9181 useCounterName
=None,
9185 extendedAttributes
=None,
9186 errorReportingLabel
=None,
9187 additionalArgsPre
=[],
9189 assert idlNode
.isMethod() == (not getter
and not setter
)
9190 assert idlNode
.isAttr() == (getter
or setter
)
9191 # Constructors are always static
9192 assert not isConstructor
or static
9194 CGThing
.__init
__(self
)
9195 self
.returnType
= returnType
9196 self
.descriptor
= descriptor
9197 self
.idlNode
= idlNode
9198 if extendedAttributes
is None:
9199 extendedAttributes
= descriptor
.getExtendedAttributes(
9200 idlNode
, getter
=getter
, setter
=setter
9202 self
.extendedAttributes
= extendedAttributes
9203 self
.arguments
= arguments
9204 self
.argCount
= len(arguments
)
9205 self
.isConstructor
= isConstructor
9207 not dontSetSlot
and idlNode
.isAttr() and idlNode
.slotIndices
is not None
9211 deprecated
= idlNode
.getExtendedAttribute("Deprecated") or (
9213 and descriptor
.interface
.getExtendedAttribute("Deprecated")
9220 DeprecationWarning(cx, obj, DeprecatedOperations::e%s);
9227 lenientFloatCode
= None
9228 if idlNode
.getExtendedAttribute("LenientFloat") is not None and (
9229 setter
or idlNode
.isMethod()
9235 bool foundNonFiniteFloat = false;
9240 lenientFloatCode
= "foundNonFiniteFloat = true;\n"
9243 if idlNode
.isStatic():
9244 # If we're a constructor, "obj" may not be a function, so calling
9245 # XrayAwareCalleeGlobal() on it is not safe. Of course in the
9246 # constructor case either "obj" is an Xray or we're already in the
9247 # content compartment, not the Xray compartment, so just
9248 # constructing the GlobalObject from "obj" is fine.
9250 objForGlobalObject
= "obj"
9252 objForGlobalObject
= "xpc::XrayAwareCalleeGlobal(obj)"
9257 GlobalObject global(cx, ${obj});
9258 if (global.Failed()) {
9263 obj
=objForGlobalObject
,
9267 argsPre
.append("global")
9269 # For JS-implemented interfaces we do not want to base the
9270 # needsCx decision on the types involved, just on our extended
9271 # attributes. Also, JSContext is not needed for the static case
9272 # since GlobalObject already contains the context.
9276 self
.extendedAttributes
,
9277 not descriptor
.interface
.isJSImplemented(),
9281 argsPre
.append("cx")
9285 runConstructorInCallerCompartment
= descriptor
.interface
.getExtendedAttribute(
9286 "RunConstructorInCallerCompartment"
9288 if isConstructor
and not runConstructorInCallerCompartment
:
9290 needsUnwrappedVar
= False
9291 unwrappedVar
= "obj"
9292 if descriptor
.interface
.isJSImplemented():
9293 # We need the desired proto in our constructor, because the
9294 # constructor will actually construct our reflector.
9295 argsPost
.append("desiredProto")
9296 elif descriptor
.interface
.isJSImplemented():
9297 if not idlNode
.isStatic():
9299 needsUnwrappedVar
= True
9301 "(unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx))"
9303 elif needScopeObject(
9306 self
.extendedAttributes
,
9307 descriptor
.wrapperCache
,
9309 idlNode
.getExtendedAttribute("StoreInSlot"),
9311 # If we ever end up with APIs like this on cross-origin objects,
9312 # figure out how the CheckedUnwrapDynamic bits should work. Chances
9313 # are, just calling it with "cx" is fine... For now, though, just
9314 # assert that it does not matter.
9315 assert not descriptor
.isMaybeCrossOriginObject()
9316 # The scope object should always be from the relevant
9317 # global. Make sure to unwrap it as needed.
9322 JS::Rooted<JSObject*> unwrappedObj(cx, js::CheckedUnwrapStatic(obj));
9323 // Caller should have ensured that "obj" can be unwrapped already.
9324 MOZ_DIAGNOSTIC_ASSERT(unwrappedObj);
9329 argsPre
.append("unwrappedObj")
9331 if needsUnwrap
and needsUnwrappedVar
:
9332 # We cannot assign into obj because it's a Handle, not a
9333 # MutableHandle, so we need a separate Rooted.
9334 cgThings
.append(CGGeneric("Maybe<JS::Rooted<JSObject*> > unwrappedObj;\n"))
9335 unwrappedVar
= "unwrappedObj.ref()"
9337 if idlNode
.isMethod() and idlNode
.isLegacycaller():
9338 # If we can have legacycaller with identifier, we can't
9339 # just use the idlNode to determine whether we're
9340 # generating code for the legacycaller or not.
9341 assert idlNode
.isIdentifierLess()
9342 # Pass in our thisVal
9343 argsPre
.append("args.thisv()")
9345 if idlNode
.isMethod():
9346 argDescription
= "argument %(index)d"
9348 argDescription
= "value being assigned"
9350 assert self
.argCount
== 0
9353 # It's very important that we construct our unwrappedObj, if we need
9354 # to do it, before we might start setting up Rooted things for our
9355 # arguments, so that we don't violate the stack discipline Rooted
9358 CGGeneric("bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);\n")
9360 if needsUnwrappedVar
:
9363 CGGeneric("unwrappedObj.emplace(cx, obj);\n"), "objIsXray"
9367 for i
in range(argConversionStartsAt
, self
.argCount
):
9369 CGArgumentConverter(
9373 argDescription
% {"index": i
+ 1},
9375 invalidEnumValueFatal
=not setter
,
9376 lenientFloatCode
=lenientFloatCode
,
9380 # Now that argument processing is done, enforce the LenientFloat stuff
9381 if lenientFloatCode
:
9383 foundNonFiniteFloatBehavior
= "return true;\n"
9385 assert idlNode
.isMethod()
9386 foundNonFiniteFloatBehavior
= dedent(
9388 args.rval().setUndefined();
9396 if (foundNonFiniteFloat) {
9400 returnSteps
=foundNonFiniteFloatBehavior
,
9406 # Something depends on having the unwrapped object, so unwrap it now.
9408 # XXXkhuey we should be able to MOZ_ASSERT that ${obj} is
9414 // Since our object is an Xray, we can just CheckedUnwrapStatic:
9415 // we know Xrays have no dynamic unwrap behavior.
9416 ${obj} = js::CheckedUnwrapStatic(${obj});
9426 # If we're called via an xray, we need to enter the underlying
9427 # object's compartment and then wrap up all of our arguments into
9428 # that compartment as needed. This is all happening after we've
9429 # already done the conversions from JS values to WebIDL (C++)
9430 # values, so we only need to worry about cases where there are 'any'
9431 # or 'object' types, or other things that we represent as actual
9432 # JSAPI types, present. Effectively, we're emulating a
9433 # CrossCompartmentWrapper, but working with the C++ types, not the
9434 # original list of JS::Values.
9435 cgThings
.append(CGGeneric("Maybe<JSAutoRealm> ar;\n"))
9436 xraySteps
.append(CGGeneric("ar.emplace(cx, obj);\n"))
9441 if (!JS_WrapObject(cx, &desiredProto)) {
9449 wrapArgIntoCurrentCompartment(arg
, argname
, isMember
=False)
9450 for arg
, argname
in self
.getArguments()
9453 cgThings
.append(CGIfWrapper(CGList(xraySteps
), "objIsXray"))
9455 if idlNode
.getExtendedAttribute("CEReactions") is not None and not getter
:
9460 Maybe<AutoCEReaction> ceReaction;
9461 DocGroup* docGroup = self->GetDocGroup();
9463 ceReaction.emplace(docGroup->CustomElementReactionsStack(), cx);
9470 # If this is a method that was generated by a maplike/setlike
9471 # interface, use the maplike/setlike generator to fill in the body.
9472 # Otherwise, use CGCallGenerator to call the native method.
9473 if idlNode
.isMethod() and idlNode
.isMaplikeOrSetlikeOrIterableMethod():
9475 idlNode
.maplikeOrSetlikeOrIterable
.isMaplike()
9476 or idlNode
.maplikeOrSetlikeOrIterable
.isSetlike()
9479 CGMaplikeOrSetlikeMethodGenerator(
9481 idlNode
.maplikeOrSetlikeOrIterable
,
9482 idlNode
.identifier
.name
,
9487 CGIterableMethodGenerator(
9489 idlNode
.identifier
.name
,
9490 self
.getArgumentNames(),
9493 elif idlNode
.isAttr() and idlNode
.type.isObservableArray():
9495 cgThings
.append(CGObservableArraySetterGenerator(descriptor
, idlNode
))
9497 if errorReportingLabel
is None:
9498 context
= GetLabelForErrorReporting(descriptor
, idlNode
, isConstructor
)
9500 context
= context
+ " getter"
9502 context
= context
+ " setter"
9503 # Callee expects a quoted string for the context if
9504 # there's a context.
9505 context
= '"%s"' % context
9507 context
= errorReportingLabel
9509 if idlNode
.isMethod() and idlNode
.getExtendedAttribute("WebExtensionStub"):
9514 ] = self
.processWebExtensionStubAttribute(cgThings
)
9516 args
= self
.getArguments()
9520 self
.needsErrorResult(),
9521 needsCallerType(idlNode
),
9522 isChromeOnly(idlNode
),
9524 argsPre
+ additionalArgsPre
,
9526 self
.extendedAttributes
,
9530 # We know our "self" must be being kept alive; otherwise we have
9531 # a serious problem. In common cases it's just an argument and
9532 # we're MOZ_CAN_RUN_SCRIPT, but in some cases it's on the stack
9533 # and being kept alive via references from JS.
9534 object="MOZ_KnownLive(self)",
9536 resultVar
=resultVar
,
9542 # Generate a telemetry call for when [UseCounter] is used.
9545 SetUseCounter(obj, eUseCounter_${useCounterName});
9547 useCounterName
=useCounterName
,
9551 SetUseCounter(UseCounterWorker::${useCounterName});
9553 useCounterName
=useCounterName
,
9556 if idlNode
.isExposedInWindow() and idlNode
.isExposedInAnyWorker():
9559 if (NS_IsMainThread()) {
9565 windowCode
=windowCode
,
9566 workerCode
=workerCode
,
9568 elif idlNode
.isExposedInWindow():
9570 elif idlNode
.isExposedInAnyWorker():
9573 cgThings
.append(CGGeneric(code
))
9575 self
.cgRoot
= CGList(cgThings
)
9577 def getArgumentNames(self
):
9578 return ["arg" + str(i
) for i
in range(len(self
.arguments
))]
9580 def getArguments(self
):
9581 return list(zip(self
.arguments
, self
.getArgumentNames()))
9583 def processWebExtensionStubAttribute(self
, cgThings
):
9584 nativeMethodName
= "CallWebExtMethod"
9585 stubNameSuffix
= self
.idlNode
.getExtendedAttribute("WebExtensionStub")
9586 if isinstance(stubNameSuffix
, list):
9587 nativeMethodName
+= stubNameSuffix
[0]
9589 argsLength
= len(self
.getArguments())
9590 singleVariadicArg
= argsLength
== 1 and self
.getArguments()[0][0].variadic
9592 # If the method signature does only include a single variadic arguments,
9593 # then `arg0` is already a Sequence of JS values and we can pass that
9594 # to the WebExtensions Stub method as is.
9595 if singleVariadicArg
:
9598 'u"%s"_ns' % self
.idlNode
.identifier
.name
,
9599 "Constify(%s)" % "arg0",
9602 return [nativeMethodName
, argsPre
, args
]
9606 'u"%s"_ns' % self
.idlNode
.identifier
.name
,
9607 "Constify(%s)" % "args_sequence",
9611 # Determine the maximum number of elements of the js values sequence argument,
9612 # skipping the last optional callback argument if any:
9614 # if this WebExtensions API method does expect a last optional callback argument,
9615 # then it is the callback parameter supported for chrome-compatibility
9616 # reasons, and we want it as a separate argument passed to the WebExtension
9617 # stub method and skip it from the js values sequence including all other
9619 maxArgsSequenceLen
= argsLength
9621 lastArg
= self
.getArguments()[argsLength
- 1]
9622 isCallback
= lastArg
[0].type.tag() == IDLType
.Tags
.callback
9623 if isCallback
and lastArg
[0].optional
:
9625 "MOZ_KnownLive(NonNullHelper(Constify(%s)))" % lastArg
[1]
9627 maxArgsSequenceLen
= argsLength
- 1
9634 // Collecting all args js values into the single sequence argument
9635 // passed to the webextensions stub method.
9637 // NOTE: The stub method will receive the original non-normalized js values,
9638 // but those arguments will still be normalized on the main thread by the
9639 // WebExtensions API request handler using the same JSONSchema defnition
9640 // used by the non-webIDL webextensions API bindings.
9641 AutoSequence<JS::Value> args_sequence;
9642 SequenceRooter<JS::Value> args_sequence_holder(cx, &args_sequence);
9644 // maximum number of arguments expected by the WebExtensions API method
9645 // excluding the last optional chrome-compatible callback argument (which
9646 // is being passed to the stub method as a separate additional argument).
9647 uint32_t maxArgsSequenceLen = ${maxArgsSequenceLen};
9649 uint32_t sequenceArgsLen = args.length() <= maxArgsSequenceLen ?
9650 args.length() : maxArgsSequenceLen;
9652 if (sequenceArgsLen > 0) {
9653 if (!args_sequence.SetCapacity(sequenceArgsLen, mozilla::fallible)) {
9654 JS_ReportOutOfMemory(cx);
9657 for (uint32_t argIdx = 0; argIdx < sequenceArgsLen; ++argIdx) {
9658 // OK to do infallible append here, since we ensured capacity already.
9659 JS::Value& slot = *args_sequence.AppendElement();
9660 slot = args[argIdx];
9664 maxArgsSequenceLen
=maxArgsSequenceLen
,
9670 return [nativeMethodName
, argsPre
, args
]
9672 def needsErrorResult(self
):
9673 return "needsErrorResult" in self
.extendedAttributes
9675 def wrap_return_value(self
):
9678 returnsNewObject
= memberReturnsNewObject(self
.idlNode
)
9679 if returnsNewObject
and (
9680 self
.returnType
.isGeckoInterface() or self
.returnType
.isPromise()
9684 static_assert(!std::is_pointer_v<decltype(result)>,
9685 "NewObject implies that we need to keep the object alive with a strong reference.");
9690 # For attributes in slots, we want to do some
9691 # post-processing once we've wrapped them.
9692 successCode
= "break;\n"
9696 resultTemplateValues
= {
9697 "jsvalRef": "args.rval()",
9698 "jsvalHandle": "args.rval()",
9699 "returnsNewObject": returnsNewObject
,
9700 "isConstructorRetval": self
.isConstructor
,
9701 "successCode": successCode
,
9702 # 'obj' in this dictionary is the thing whose compartment we are
9703 # trying to do the to-JS conversion in. We're going to put that
9704 # thing in a variable named "conversionScope" if setSlot is true.
9705 # Otherwise, just use "obj" for lack of anything better.
9706 "obj": "conversionScope" if self
.setSlot
else "obj",
9709 wrapCode
+= wrapForType(self
.returnType
, self
.descriptor
, resultTemplateValues
)
9712 if self
.idlNode
.isStatic():
9714 "Attribute %s.%s is static, so we don't have a useful slot "
9715 "to cache it in, because we don't have support for that on "
9716 "interface objects. See "
9717 "https://bugzilla.mozilla.org/show_bug.cgi?id=1363870"
9719 self
.descriptor
.interface
.identifier
.name
,
9720 self
.idlNode
.identifier
.name
,
9724 # When using a slot on the Xray expando, we need to make sure that
9725 # our initial conversion to a JS::Value is done in the caller
9726 # compartment. When using a slot on our reflector, we want to do
9727 # the conversion in the compartment of that reflector (that is,
9728 # slotStorage). In both cases we want to make sure that we finally
9729 # set up args.rval() to be in the caller compartment. We also need
9730 # to make sure that the conversion steps happen inside a do/while
9731 # that they can break out of on success.
9733 # Of course we always have to wrap the value into the slotStorage
9734 # compartment before we store it in slotStorage.
9736 # postConversionSteps are the steps that run while we're still in
9737 # the compartment we do our conversion in but after we've finished
9738 # the initial conversion into args.rval().
9739 postConversionSteps
= ""
9740 if self
.idlNode
.getExtendedAttribute("Frozen"):
9742 self
.idlNode
.type.isSequence() or self
.idlNode
.type.isDictionary()
9744 freezeValue
= CGGeneric(
9745 "JS::Rooted<JSObject*> rvalObj(cx, &args.rval().toObject());\n"
9746 "if (!JS_FreezeObject(cx, rvalObj)) {\n"
9750 if self
.idlNode
.type.nullable():
9751 freezeValue
= CGIfWrapper(freezeValue
, "args.rval().isObject()")
9752 postConversionSteps
+= freezeValue
.define()
9754 # slotStorageSteps are steps that run once we have entered the
9755 # slotStorage compartment.
9756 if self
.idlNode
.getExtendedAttribute(
9757 "ReflectedHTMLAttributeReturningFrozenArray"
9761 array[${arrayIndex}] = storedVal;
9763 arrayIndex
=reflectedHTMLAttributesArrayIndex(
9764 self
.descriptor
, self
.idlNode
9768 storeInSlot
= dedent(
9770 JS::SetReservedSlot(slotStorage, slotIndex, storedVal);
9774 slotStorageSteps
= fill(
9776 // Make a copy so that we don't do unnecessary wrapping on args.rval().
9777 JS::Rooted<JS::Value> storedVal(cx, args.rval());
9778 if (!${maybeWrap}(cx, &storedVal)) {
9783 maybeWrap
=getMaybeWrapValueFuncForType(self
.idlNode
.type),
9784 storeInSlot
=storeInSlot
,
9787 checkForXray
= mayUseXrayExpandoSlots(self
.descriptor
, self
.idlNode
)
9789 # For the case of Cached attributes, go ahead and preserve our
9790 # wrapper if needed. We need to do this because otherwise the
9791 # wrapper could get garbage-collected and the cached value would
9792 # suddenly disappear, but the whole premise of cached values is that
9793 # they never change without explicit action on someone's part. We
9794 # don't do this for StoreInSlot, since those get dealt with during
9795 # wrapper setup, and failure would involve us trying to clear an
9796 # already-preserved wrapper.
9798 self
.idlNode
.getExtendedAttribute("Cached")
9799 or self
.idlNode
.getExtendedAttribute(
9800 "ReflectedHTMLAttributeReturningFrozenArray"
9802 ) and self
.descriptor
.wrapperCache
:
9803 preserveWrapper
= dedent(
9805 PreserveWrapper(self);
9809 preserveWrapper
= fill(
9812 // In the Xray case we don't need to do this, because getting the
9813 // expando object already preserved our wrapper.
9817 preserveWrapper
=preserveWrapper
,
9819 slotStorageSteps
+= preserveWrapper
9822 # In the Xray case we use the current global as conversion
9823 # scope, as explained in the big compartment/conversion comment
9825 conversionScope
= "isXray ? JS::CurrentGlobalOrNull(cx) : slotStorage"
9827 conversionScope
= "slotStorage"
9832 JS::Rooted<JSObject*> conversionScope(cx, ${conversionScope});
9833 JSAutoRealm ar(cx, conversionScope);
9834 do { // block we break out of when done wrapping
9837 $*{postConversionSteps}
9839 { // And now store things in the realm of our slotStorage.
9840 JSAutoRealm ar(cx, slotStorage);
9841 $*{slotStorageSteps}
9843 // And now make sure args.rval() is in the caller realm.
9844 return ${maybeWrap}(cx, args.rval());
9846 conversionScope
=conversionScope
,
9848 postConversionSteps
=postConversionSteps
,
9849 slotStorageSteps
=slotStorageSteps
,
9850 maybeWrap
=getMaybeWrapValueFuncForType(self
.idlNode
.type),
9855 return self
.cgRoot
.define() + self
.wrap_return_value()
9858 class CGSwitch(CGList
):
9860 A class to generate code for a switch statement.
9862 Takes three constructor arguments: an expression, a list of cases,
9863 and an optional default.
9865 Each case is a CGCase. The default is a CGThing for the body of
9866 the default case, if any.
9869 def __init__(self
, expression
, cases
, default
=None):
9870 CGList
.__init
__(self
, [CGIndenter(c
) for c
in cases
])
9871 self
.prepend(CGGeneric("switch (" + expression
+ ") {\n"))
9872 if default
is not None:
9875 CGWrapper(CGIndenter(default
), pre
="default: {\n", post
="}\n")
9879 self
.append(CGGeneric("}\n"))
9882 class CGCase(CGList
):
9884 A class to generate code for a case statement.
9886 Takes three constructor arguments: an expression, a CGThing for
9887 the body (allowed to be None if there is no body), and an optional
9888 argument for whether add a break, add fallthrough annotation or add nothing
9889 (defaulting to add a break).
9896 def __init__(self
, expression
, body
, breakOrFallthrough
=ADD_BREAK
):
9897 CGList
.__init
__(self
, [])
9900 breakOrFallthrough
== CGCase
.ADD_BREAK
9901 or breakOrFallthrough
== CGCase
.ADD_FALLTHROUGH
9902 or breakOrFallthrough
== CGCase
.DONT_ADD_BREAK
9905 self
.append(CGGeneric("case " + expression
+ ": {\n"))
9906 bodyList
= CGList([body
])
9907 if breakOrFallthrough
== CGCase
.ADD_FALLTHROUGH
:
9908 bodyList
.append(CGGeneric("[[fallthrough]];\n"))
9909 elif breakOrFallthrough
== CGCase
.ADD_BREAK
:
9910 bodyList
.append(CGGeneric("break;\n"))
9911 self
.append(CGIndenter(bodyList
))
9912 self
.append(CGGeneric("}\n"))
9915 class CGMethodCall(CGThing
):
9917 A class to generate selection of a method signature from a set of
9918 signatures and generation of a call to that signature.
9922 self
, nativeMethodName
, static
, descriptor
, method
, isConstructor
=False
9924 CGThing
.__init
__(self
)
9926 methodName
= GetLabelForErrorReporting(descriptor
, method
, isConstructor
)
9927 argDesc
= "argument %d"
9929 if method
.getExtendedAttribute("UseCounter"):
9930 useCounterName
= methodName
.replace(".", "_").replace(" ", "_")
9932 useCounterName
= None
9934 if method
.isStatic():
9935 nativeType
= descriptor
.nativeType
9936 staticTypeOverride
= PropertyDefiner
.getStringAttr(
9937 method
, "StaticClassOverride"
9939 if staticTypeOverride
:
9940 nativeType
= staticTypeOverride
9941 nativeMethodName
= "%s::%s" % (nativeType
, nativeMethodName
)
9943 def requiredArgCount(signature
):
9944 arguments
= signature
[1]
9945 if len(arguments
) == 0:
9947 requiredArgs
= len(arguments
)
9948 while requiredArgs
and arguments
[requiredArgs
- 1].optional
:
9952 def getPerSignatureCall(signature
, argConversionStartsAt
=0):
9953 return CGPerSignatureCall(
9960 argConversionStartsAt
=argConversionStartsAt
,
9961 isConstructor
=isConstructor
,
9962 useCounterName
=useCounterName
,
9965 signatures
= method
.signatures()
9966 if len(signatures
) == 1:
9967 # Special case: we can just do a per-signature method call
9968 # here for our one signature and not worry about switching
9970 signature
= signatures
[0]
9971 self
.cgRoot
= CGList([getPerSignatureCall(signature
)])
9972 requiredArgs
= requiredArgCount(signature
)
9974 # Skip required arguments check for maplike/setlike interfaces, as
9975 # they can have arguments which are not passed, and are treated as
9976 # if undefined had been explicitly passed.
9977 if requiredArgs
> 0 and not method
.isMaplikeOrSetlikeOrIterableMethod():
9980 if (!args.requireAtLeast(cx, "${methodName}", ${requiredArgs})) {
9984 requiredArgs
=requiredArgs
,
9985 methodName
=methodName
,
9987 self
.cgRoot
.prepend(CGGeneric(code
))
9990 # Need to find the right overload
9991 maxArgCount
= method
.maxArgCount
9992 allowedArgCounts
= method
.allowedArgCounts
9995 for argCountIdx
, argCount
in enumerate(allowedArgCounts
):
9996 possibleSignatures
= method
.signaturesForArgCount(argCount
)
9998 # Try to optimize away cases when the next argCount in the list
9999 # will have the same code as us; if it does, we can fall through to
10001 if argCountIdx
+ 1 < len(allowedArgCounts
):
10002 nextPossibleSignatures
= method
.signaturesForArgCount(
10003 allowedArgCounts
[argCountIdx
+ 1]
10006 nextPossibleSignatures
= None
10007 if possibleSignatures
== nextPossibleSignatures
:
10008 # Same set of signatures means we better have the same
10009 # distinguishing index. So we can in fact just fall through to
10010 # the next case here.
10011 assert len(possibleSignatures
) == 1 or (
10012 method
.distinguishingIndexForArgCount(argCount
)
10013 == method
.distinguishingIndexForArgCount(
10014 allowedArgCounts
[argCountIdx
+ 1]
10017 argCountCases
.append(
10018 CGCase(str(argCount
), None, CGCase
.ADD_FALLTHROUGH
)
10022 if len(possibleSignatures
) == 1:
10024 signature
= possibleSignatures
[0]
10025 argCountCases
.append(
10026 CGCase(str(argCount
), getPerSignatureCall(signature
))
10030 distinguishingIndex
= method
.distinguishingIndexForArgCount(argCount
)
10032 def distinguishingArgument(signature
):
10033 args
= signature
[1]
10034 if distinguishingIndex
< len(args
):
10035 return args
[distinguishingIndex
]
10036 assert args
[-1].variadic
10039 def distinguishingType(signature
):
10040 return distinguishingArgument(signature
).type
10042 for sig
in possibleSignatures
:
10043 # We should not have "any" args at distinguishingIndex,
10044 # since we have multiple possible signatures remaining,
10045 # but "any" is never distinguishable from anything else.
10046 assert not distinguishingType(sig
).isAny()
10047 # We can't handle unions at the distinguishing index.
10048 if distinguishingType(sig
).isUnion():
10050 "No support for unions as distinguishing "
10051 "arguments yet: %s" % distinguishingArgument(sig
).location
10053 # We don't support variadics as the distinguishingArgument yet.
10054 # If you want to add support, consider this case:
10056 # undefined(long... foo);
10057 # undefined(long bar, Int32Array baz);
10059 # in which we have to convert argument 0 to long before picking
10060 # an overload... but all the variadic stuff needs to go into a
10061 # single array in case we pick that overload, so we have to have
10062 # machinery for converting argument 0 to long and then either
10063 # placing it in the variadic bit or not. Or something. We may
10064 # be able to loosen this restriction if the variadic arg is in
10065 # fact at distinguishingIndex, perhaps. Would need to
10067 if distinguishingArgument(sig
).variadic
:
10069 "No support for variadics as distinguishing "
10070 "arguments yet: %s" % distinguishingArgument(sig
).location
10073 # Convert all our arguments up to the distinguishing index.
10074 # Doesn't matter which of the possible signatures we use, since
10075 # they all have the same types up to that point; just use
10076 # possibleSignatures[0]
10078 CGArgumentConverter(
10079 possibleSignatures
[0][1][i
],
10085 for i
in range(0, distinguishingIndex
)
10088 # Select the right overload from our set.
10089 distinguishingArg
= "args[%d]" % distinguishingIndex
10092 signature
, indent
, isDefinitelyObject
=False, isNullOrUndefined
=False
10094 assert not isDefinitelyObject
or not isNullOrUndefined
10095 assert isDefinitelyObject
or isNullOrUndefined
10096 if isDefinitelyObject
:
10097 failureCode
= "break;\n"
10100 type = distinguishingType(signature
)
10101 # The argument at index distinguishingIndex can't possibly be
10102 # unset here, because we've already checked that argc is large
10103 # enough that we can examine this argument. But note that we
10104 # still want to claim that optional arguments are optional, in
10105 # case undefined was passed in.
10106 argIsOptional
= distinguishingArgument(signature
).canHaveMissingValue()
10107 testCode
= instantiateJSToNativeConversion(
10108 getJSToNativeConversionInfo(
10111 failureCode
=failureCode
,
10112 isDefinitelyObject
=isDefinitelyObject
,
10113 isNullOrUndefined
=isNullOrUndefined
,
10114 isOptional
=argIsOptional
,
10115 sourceDescription
=(argDesc
% (distinguishingIndex
+ 1)),
10118 "declName": "arg%d" % distinguishingIndex
,
10119 "holderName": ("arg%d" % distinguishingIndex
) + "_holder",
10120 "val": distinguishingArg
,
10122 "haveValue": "args.hasDefined(%d)" % distinguishingIndex
,
10123 "passedToJSImpl": toStringBool(
10124 isJSImplementedDescriptor(descriptor
)
10127 checkForValue
=argIsOptional
,
10129 caseBody
.append(CGIndenter(testCode
, indent
))
10131 # If we got this far, we know we unwrapped to the right
10132 # C++ type, so just do the call. Start conversion with
10133 # distinguishingIndex + 1, since we already converted
10134 # distinguishingIndex.
10137 getPerSignatureCall(signature
, distinguishingIndex
+ 1), indent
10141 def hasConditionalConversion(type):
10143 Return whether the argument conversion for this type will be
10144 conditional on the type of incoming JS value. For example, for
10145 interface types the conversion is conditional on the incoming
10146 value being isObject().
10148 For the types for which this returns false, we do not have to
10149 output extra isUndefined() or isNullOrUndefined() cases, because
10150 null/undefined values will just fall through into our
10151 unconditional conversion.
10153 if type.isString() or type.isEnum():
10155 if type.isBoolean():
10156 distinguishingTypes
= (
10157 distinguishingType(s
) for s
in possibleSignatures
10160 t
.isString() or t
.isEnum() or t
.isNumeric()
10161 for t
in distinguishingTypes
10163 if type.isNumeric():
10164 distinguishingTypes
= (
10165 distinguishingType(s
) for s
in possibleSignatures
10167 return any(t
.isString() or t
.isEnum() for t
in distinguishingTypes
)
10170 def needsNullOrUndefinedCase(type):
10172 Return true if the type needs a special isNullOrUndefined() case
10175 type.nullable() and hasConditionalConversion(type)
10176 ) or type.isDictionary()
10178 # First check for undefined and optional distinguishing arguments
10179 # and output a special branch for that case. Note that we don't
10180 # use distinguishingArgument here because we actualy want to
10181 # exclude variadic arguments. Also note that we skip this check if
10182 # we plan to output a isNullOrUndefined() special case for this
10183 # argument anyway, since that will subsume our isUndefined() check.
10184 # This is safe, because there can be at most one nullable
10185 # distinguishing argument, so if we're it we'll definitely get
10186 # picked up by the nullable handling. Also, we can skip this check
10187 # if the argument has an unconditional conversion later on.
10190 for s
in possibleSignatures
10191 if distinguishingIndex
< len(s
[1])
10192 and s
[1][distinguishingIndex
].optional
10193 and hasConditionalConversion(s
[1][distinguishingIndex
].type)
10194 and not needsNullOrUndefinedCase(s
[1][distinguishingIndex
].type)
10196 # Can't have multiple signatures with an optional argument at the
10198 assert len(undefSigs
) < 2
10199 if len(undefSigs
) > 0:
10201 CGGeneric("if (%s.isUndefined()) {\n" % distinguishingArg
)
10203 tryCall(undefSigs
[0], 2, isNullOrUndefined
=True)
10204 caseBody
.append(CGGeneric("}\n"))
10206 # Next, check for null or undefined. That means looking for
10207 # nullable arguments at the distinguishing index and outputting a
10208 # separate branch for them. But if the nullable argument has an
10209 # unconditional conversion, we don't need to do that. The reason
10210 # for that is that at most one argument at the distinguishing index
10211 # is nullable (since two nullable arguments are not
10212 # distinguishable), and null/undefined values will always fall
10213 # through to the unconditional conversion we have, if any, since
10214 # they will fail whatever the conditions on the input value are for
10215 # our other conversions.
10216 nullOrUndefSigs
= [
10218 for s
in possibleSignatures
10219 if needsNullOrUndefinedCase(distinguishingType(s
))
10221 # Can't have multiple nullable types here
10222 assert len(nullOrUndefSigs
) < 2
10223 if len(nullOrUndefSigs
) > 0:
10225 CGGeneric("if (%s.isNullOrUndefined()) {\n" % distinguishingArg
)
10227 tryCall(nullOrUndefSigs
[0], 2, isNullOrUndefined
=True)
10228 caseBody
.append(CGGeneric("}\n"))
10230 # Now check for distinguishingArg being various kinds of objects.
10231 # The spec says to check for the following things in order:
10232 # 1) A platform object that's not a platform array object, being
10233 # passed to an interface or "object" arg.
10234 # 2) A callable object being passed to a callback or "object" arg.
10235 # 3) An iterable object being passed to a sequence arg.
10236 # 4) Any object being passed to a array or callback interface or
10237 # dictionary or "object" arg.
10239 # First grab all the overloads that have a non-callback interface
10240 # (which includes SpiderMonkey interfaces) at the distinguishing
10241 # index. We can also include the ones that have an "object" here,
10242 # since if those are present no other object-typed argument will
10246 for s
in possibleSignatures
10248 distinguishingType(s
).isObject()
10249 or distinguishingType(s
).isNonCallbackInterface()
10253 # And all the overloads that take callbacks
10255 s
for s
in possibleSignatures
if distinguishingType(s
).isCallback()
10258 # And all the overloads that take sequences
10260 s
for s
in possibleSignatures
if distinguishingType(s
).isSequence()
10263 # Now append all the overloads that take a dictionary or callback
10264 # interface or record. There should be only one of these!
10265 genericObjectSigs
= [
10267 for s
in possibleSignatures
10269 distinguishingType(s
).isDictionary()
10270 or distinguishingType(s
).isRecord()
10271 or distinguishingType(s
).isCallbackInterface()
10274 assert len(genericObjectSigs
) <= 1
10275 objectSigs
.extend(genericObjectSigs
)
10277 # There might be more than one thing in objectSigs; we need to check
10278 # which ones we unwrap to.
10279 if len(objectSigs
) > 0:
10280 # Here it's enough to guard on our argument being an object.
10281 # The code for unwrapping non-callback interfaces, spiderMonkey
10282 # interfaces, and sequences will just bail out and move
10283 # on to the next overload if the object fails to unwrap
10284 # correctly, while "object" accepts any object anyway. We
10285 # could even not do the isObject() check up front here, but in
10286 # cases where we have multiple object overloads it makes sense
10287 # to do it only once instead of for each overload. That will
10288 # also allow the unwrapping test to skip having to do codegen
10289 # for the null-or-undefined case, which we already handled
10291 caseBody
.append(CGGeneric("if (%s.isObject()) {\n" % distinguishingArg
))
10292 for sig
in objectSigs
:
10293 caseBody
.append(CGIndenter(CGGeneric("do {\n")))
10294 # Indent by 4, since we need to indent further
10295 # than our "do" statement
10296 tryCall(sig
, 4, isDefinitelyObject
=True)
10297 caseBody
.append(CGIndenter(CGGeneric("} while (false);\n")))
10299 caseBody
.append(CGGeneric("}\n"))
10301 # Now we only have to consider booleans, numerics, and strings. If
10302 # we only have one of them, then we can just output it. But if not,
10303 # then we need to output some of the cases conditionally: if we have
10304 # a string overload, then boolean and numeric are conditional, and
10305 # if not then boolean is conditional if we have a numeric overload.
10306 def findUniqueSignature(filterLambda
):
10307 sigs
= [s
for s
in possibleSignatures
if filterLambda(s
)]
10308 assert len(sigs
) < 2
10313 stringSignature
= findUniqueSignature(
10315 distinguishingType(s
).isString() or distinguishingType(s
).isEnum()
10318 numericSignature
= findUniqueSignature(
10319 lambda s
: distinguishingType(s
).isNumeric()
10321 booleanSignature
= findUniqueSignature(
10322 lambda s
: distinguishingType(s
).isBoolean()
10325 if stringSignature
or numericSignature
:
10326 booleanCondition
= "%s.isBoolean()"
10328 booleanCondition
= None
10330 if stringSignature
:
10331 numericCondition
= "%s.isNumber()"
10333 numericCondition
= None
10335 def addCase(sig
, condition
):
10336 sigCode
= getPerSignatureCall(sig
, distinguishingIndex
)
10338 sigCode
= CGIfWrapper(sigCode
, condition
% distinguishingArg
)
10339 caseBody
.append(sigCode
)
10341 if booleanSignature
:
10342 addCase(booleanSignature
, booleanCondition
)
10343 if numericSignature
:
10344 addCase(numericSignature
, numericCondition
)
10345 if stringSignature
:
10346 addCase(stringSignature
, None)
10348 if not booleanSignature
and not numericSignature
and not stringSignature
:
10349 # Just throw; we have no idea what we're supposed to
10353 'return cx.ThrowErrorMessage<MSG_OVERLOAD_RESOLUTION_FAILED>("%d", "%d");\n'
10354 % (distinguishingIndex
+ 1, argCount
)
10358 argCountCases
.append(CGCase(str(argCount
), CGList(caseBody
)))
10360 overloadCGThings
= []
10361 overloadCGThings
.append(
10363 "unsigned argcount = std::min(args.length(), %du);\n" % maxArgCount
10366 overloadCGThings
.append(
10373 // Using nsPrintfCString here would require including that
10374 // header. Let's not worry about it.
10375 nsAutoCString argCountStr;
10376 argCountStr.AppendPrintf("%u", args.length());
10377 return cx.ThrowErrorMessage<MSG_INVALID_OVERLOAD_ARGCOUNT>(argCountStr.get());
10383 overloadCGThings
.append(
10385 'MOZ_CRASH("We have an always-returning default case");\n'
10389 self
.cgRoot
= CGList(overloadCGThings
)
10392 return self
.cgRoot
.define()
10395 class CGGetterCall(CGPerSignatureCall
):
10397 A class to generate a native object getter call for a particular IDL
10407 errorReportingLabel
=None,
10410 extendedAttributes
=None,
10411 preConversionCode
=None,
10413 self
.preConversionCode
= preConversionCode
10414 if attr
.getExtendedAttribute("UseCounter"):
10415 useCounterName
= "%s_%s_getter" % (
10416 descriptor
.interface
.identifier
.name
,
10417 attr
.identifier
.name
,
10420 useCounterName
= None
10421 if attr
.isStatic():
10422 nativeMethodName
= "%s::%s" % (descriptor
.nativeType
, nativeMethodName
)
10423 CGPerSignatureCall
.__init
__(
10432 useCounterName
=useCounterName
,
10433 dontSetSlot
=dontSetSlot
,
10434 extendedAttributes
=extendedAttributes
,
10435 errorReportingLabel
=errorReportingLabel
,
10436 additionalArgsPre
=argsPre
,
10439 def wrap_return_value(self
):
10440 wrap
= CGPerSignatureCall
.wrap_return_value(self
)
10441 if self
.preConversionCode
is not None:
10442 wrap
= self
.preConversionCode
+ wrap
10446 class FakeIdentifier
:
10447 def __init__(self
, name
):
10451 class FakeArgument
:
10453 A class that quacks like an IDLArgument. This is used to make
10454 setters look like method calls or for special operations.
10457 def __init__(self
, type, name
="arg", allowTreatNonCallableAsNull
=False):
10459 self
.optional
= False
10460 self
.variadic
= False
10461 self
.defaultValue
= None
10462 self
._allowTreatNonCallableAsNull
= allowTreatNonCallableAsNull
10464 self
.identifier
= FakeIdentifier(name
)
10466 def allowTreatNonCallableAsNull(self
):
10467 return self
._allowTreatNonCallableAsNull
10469 def canHaveMissingValue(self
):
10473 class CGSetterCall(CGPerSignatureCall
):
10475 A class to generate a native object setter call for a particular IDL
10485 errorReportingLabel
=None,
10488 if attr
.getExtendedAttribute("UseCounter"):
10489 useCounterName
= "%s_%s_setter" % (
10490 descriptor
.interface
.identifier
.name
,
10491 attr
.identifier
.name
,
10494 useCounterName
= None
10495 if attr
.isStatic():
10496 nativeMethodName
= "%s::%s" % (descriptor
.nativeType
, nativeMethodName
)
10497 CGPerSignatureCall
.__init
__(
10500 [FakeArgument(argType
, allowTreatNonCallableAsNull
=True)],
10506 useCounterName
=useCounterName
,
10507 errorReportingLabel
=errorReportingLabel
,
10508 additionalArgsPre
=argsPre
,
10511 def wrap_return_value(self
):
10512 attr
= self
.idlNode
10514 if self
.descriptor
.wrapperCache
and attr
.slotIndices
is not None:
10515 if attr
.getExtendedAttribute("StoreInSlot"):
10516 clearSlot
= "%s(cx, self);\n" % MakeClearCachedValueNativeName(
10519 elif attr
.getExtendedAttribute("Cached"):
10520 clearSlot
= "%s(self);\n" % MakeClearCachedValueNativeName(self
.idlNode
)
10522 # We have no return value
10523 return "\n" "%s" "return true;\n" % clearSlot
10526 class CGAbstractBindingMethod(CGAbstractStaticMethod
):
10528 Common class to generate some of our class hooks. This will generate the
10529 function declaration, get a reference to the JS object for our binding
10530 object (which might be an argument of the class hook or something we get
10531 from a JS::CallArgs), and unwrap into the right C++ type. Subclasses are
10532 expected to override the generate_code function to do the rest of the work.
10533 This function should return a CGThing which is already properly indented.
10535 getThisObj should be code for getting a JSObject* for the binding
10536 object. "" can be passed in if the binding object is already stored in
10539 callArgs should be code for getting a JS::CallArgs into a variable
10540 called 'args'. This can be "" if there is already such a variable
10541 around or if the body does not need a JS::CallArgs.
10551 callArgs
="JS::CallArgs args = JS::CallArgsFromVp(argc, vp);\n",
10553 CGAbstractStaticMethod
.__init
__(
10554 self
, descriptor
, name
, "bool", args
, canRunScript
=True
10557 # This can't ever happen, because we only use this for class hooks.
10558 self
.unwrapFailureCode
= fill(
10560 MOZ_CRASH("Unexpected object in '${name}' hook");
10566 if getThisObj
== "":
10567 self
.getThisObj
= None
10569 self
.getThisObj
= CGGeneric(
10570 "JS::Rooted<JSObject*> obj(cx, %s);\n" % getThisObj
10572 self
.callArgs
= callArgs
10574 def definition_body(self
):
10575 body
= self
.callArgs
10576 if self
.getThisObj
is not None:
10577 body
+= self
.getThisObj
.define() + "\n"
10578 body
+= "%s* self;\n" % self
.descriptor
.nativeType
10581 JS::Rooted<JS::Value> rootSelf(cx, JS::ObjectValue(*obj));
10586 CastableObjectUnwrapper(
10587 self
.descriptor
, "rootSelf", "&rootSelf", "self", self
.unwrapFailureCode
10591 return body
+ self
.generate_code().define()
10593 def generate_code(self
):
10594 assert False # Override me
10597 class CGAbstractStaticBindingMethod(CGAbstractStaticMethod
):
10599 Common class to generate the JSNatives for all our static methods, getters
10600 and setters. This will generate the function declaration and unwrap the
10601 global object. Subclasses are expected to override the generate_code
10602 function to do the rest of the work. This function should return a
10603 CGThing which is already properly indented.
10606 def __init__(self
, descriptor
, name
):
10607 CGAbstractStaticMethod
.__init
__(
10608 self
, descriptor
, name
, "bool", JSNativeArguments(), canRunScript
=True
10611 def definition_body(self
):
10612 # Make sure that "obj" is in the same compartment as "cx", since we'll
10613 # later use it to wrap return values.
10616 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
10617 JS::Rooted<JSObject*> obj(cx, &args.callee());
10621 return unwrap
+ self
.generate_code().define()
10623 def generate_code(self
):
10624 assert False # Override me
10627 def MakeNativeName(name
):
10628 return name
[0].upper() + IDLToCIdentifier(name
[1:])
10631 def GetWebExposedName(idlObject
, descriptor
):
10632 if idlObject
== descriptor
.operations
["Stringifier"]:
10634 name
= idlObject
.identifier
.name
10635 if name
== "__namedsetter":
10636 return "named setter"
10637 if name
== "__namedgetter":
10638 return "named getter"
10639 if name
== "__indexedsetter":
10640 return "indexed setter"
10641 if name
== "__indexedgetter":
10642 return "indexed getter"
10643 if name
== "__legacycaller":
10644 return "legacy caller"
10648 def GetConstructorNameForReporting(descriptor
, ctor
):
10649 # Figure out the name of our constructor for reporting purposes.
10650 # For unnamed webidl constructors, identifier.name is "constructor" but
10651 # the name JS sees is the interface name; for legacy factory functions
10652 # identifier.name is the actual name.
10653 ctorName
= ctor
.identifier
.name
10654 if ctorName
== "constructor":
10655 return descriptor
.interface
.identifier
.name
10659 def GetLabelForErrorReporting(descriptor
, idlObject
, isConstructor
):
10661 descriptor is the descriptor for the interface involved
10663 idlObject is the method (regular or static), attribute (regular or
10664 static), or constructor (named or not) involved.
10666 isConstructor is true if idlObject is a constructor and false otherwise.
10669 return "%s constructor" % GetConstructorNameForReporting(descriptor
, idlObject
)
10671 namePrefix
= descriptor
.interface
.identifier
.name
10672 name
= GetWebExposedName(idlObject
, descriptor
)
10674 # It's got a space already, so just space-separate.
10675 return "%s %s" % (namePrefix
, name
)
10677 return "%s.%s" % (namePrefix
, name
)
10680 class CGSpecializedMethod(CGAbstractStaticMethod
):
10682 A class for generating the C++ code for a specialized method that the JIT
10683 can call with lower overhead.
10686 def __init__(self
, descriptor
, method
):
10687 self
.method
= method
10688 name
= CppKeywords
.checkMethodName(IDLToCIdentifier(method
.identifier
.name
))
10690 Argument("JSContext*", "cx"),
10691 Argument("JS::Handle<JSObject*>", "obj"),
10692 Argument("void*", "void_self"),
10693 Argument("const JSJitMethodCallArgs&", "args"),
10695 CGAbstractStaticMethod
.__init
__(
10696 self
, descriptor
, name
, "bool", args
, canRunScript
=True
10699 def definition_body(self
):
10700 nativeName
= CGSpecializedMethod
.makeNativeName(self
.descriptor
, self
.method
)
10701 call
= CGMethodCall(
10702 nativeName
, self
.method
.isStatic(), self
.descriptor
, self
.method
10705 if self
.method
.getExtendedAttribute("CrossOriginCallable"):
10706 for signature
in self
.method
.signatures():
10707 # non-undefined signatures would require us to deal with remote proxies for the
10708 # return value here.
10709 if not signature
[0].isUndefined():
10711 "We don't support a method marked as CrossOriginCallable "
10712 "with non-undefined return type"
10714 prototypeID
, _
= PrototypeIDAndDepth(self
.descriptor
)
10717 // CrossOriginThisPolicy::UnwrapThisObject stores a ${nativeType}::RemoteProxy in void_self
10718 // if obj is a proxy with a RemoteObjectProxy handler for the right type, or else it stores
10719 // a ${nativeType}. If we get here from the JIT (without going through UnwrapThisObject) we
10720 // know void_self contains a ${nativeType}; we don't have special cases in the JIT to deal
10721 // with remote object proxies.
10722 if (IsRemoteObjectProxy(obj, ${prototypeID})) {
10723 auto* self = static_cast<${nativeType}::RemoteProxy*>(void_self);
10727 prototypeID
=prototypeID
,
10728 nativeType
=self
.descriptor
.nativeType
,
10731 return prefix
+ fill(
10733 auto* self = static_cast<${nativeType}*>(void_self);
10736 nativeType
=self
.descriptor
.nativeType
,
10740 def auto_profiler_label(self
):
10741 interface_name
= self
.descriptor
.interface
.identifier
.name
10742 method_name
= self
.method
.identifier
.name
10745 AUTO_PROFILER_LABEL_DYNAMIC_FAST(
10746 "${interface_name}", "${method_name}", DOM, cx,
10747 uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) |
10748 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
10750 interface_name
=interface_name
,
10751 method_name
=method_name
,
10755 def should_have_method_description(descriptor
, idlMethod
):
10757 Returns whether the given IDL method (static, non-static, constructor)
10758 should have a method description declaration, for use in error
10761 # If a method has overloads, it needs a method description, because it
10762 # can throw MSG_INVALID_OVERLOAD_ARGCOUNT at the very least.
10763 if len(idlMethod
.signatures()) != 1:
10766 # Methods with only one signature need a method description if one of
10767 # their args needs it.
10768 sig
= idlMethod
.signatures()[0]
10771 idlTypeNeedsCallContext(
10774 allowTreatNonCallableAsNull
=arg
.allowTreatNonCallableAsNull(),
10780 def error_reporting_label_helper(descriptor
, idlMethod
, isConstructor
):
10782 Returns the method description to use for error reporting for the given
10783 IDL method. Used to implement common error_reporting_label() functions
10784 across different classes.
10786 if not CGSpecializedMethod
.should_have_method_description(
10787 descriptor
, idlMethod
10790 return '"%s"' % GetLabelForErrorReporting(descriptor
, idlMethod
, isConstructor
)
10792 def error_reporting_label(self
):
10793 return CGSpecializedMethod
.error_reporting_label_helper(
10794 self
.descriptor
, self
.method
, isConstructor
=False
10798 def makeNativeName(descriptor
, method
):
10799 if method
.underlyingAttr
:
10800 return CGSpecializedGetterCommon
.makeNativeName(
10801 descriptor
, method
.underlyingAttr
10803 name
= method
.identifier
.name
10804 return MakeNativeName(descriptor
.binaryNameFor(name
, method
.isStatic()))
10807 class CGMethodPromiseWrapper(CGAbstractStaticMethod
):
10809 A class for generating a wrapper around another method that will
10810 convert exceptions to promises.
10813 def __init__(self
, descriptor
, methodToWrap
):
10814 self
.method
= methodToWrap
10815 name
= self
.makeName(methodToWrap
.name
)
10816 args
= list(methodToWrap
.args
)
10817 CGAbstractStaticMethod
.__init
__(
10818 self
, descriptor
, name
, "bool", args
, canRunScript
=True
10821 def definition_body(self
):
10824 bool ok = ${methodName}(${args});
10828 return ConvertExceptionToPromise(cx, args.rval());
10830 methodName
=self
.method
.name
,
10831 args
=", ".join(arg
.name
for arg
in self
.args
),
10835 def makeName(methodName
):
10836 return methodName
+ "_promiseWrapper"
10839 class CGDefaultToJSONMethod(CGSpecializedMethod
):
10840 def __init__(self
, descriptor
, method
):
10841 assert method
.isDefaultToJSON()
10842 CGSpecializedMethod
.__init
__(self
, descriptor
, method
)
10844 def definition_body(self
):
10847 auto* self = static_cast<${nativeType}*>(void_self);
10848 JS::Rooted<JSObject*> result(cx, JS_NewPlainObject(cx));
10853 nativeType
=self
.descriptor
.nativeType
,
10856 jsonDescriptors
= [self
.descriptor
]
10857 interface
= self
.descriptor
.interface
.parent
10859 descriptor
= self
.descriptor
.getDescriptor(interface
.identifier
.name
)
10860 if descriptor
.hasDefaultToJSON
:
10861 jsonDescriptors
.append(descriptor
)
10862 interface
= interface
.parent
10864 # Iterate the array in reverse: oldest ancestor first
10865 for descriptor
in jsonDescriptors
[::-1]:
10868 if (!${parentclass}::CollectJSONAttributes(cx, obj, MOZ_KnownLive(self), result)) {
10872 parentclass
=toBindingNamespace(descriptor
.name
),
10874 ret
+= "args.rval().setObject(*result);\n" "return true;\n"
10878 class CGLegacyCallHook(CGAbstractBindingMethod
):
10880 Call hook for our object
10883 def __init__(self
, descriptor
):
10884 self
._legacycaller
= descriptor
.operations
["LegacyCaller"]
10885 # Our "self" is actually the callee in this case, not the thisval.
10886 CGAbstractBindingMethod
.__init
__(
10889 LEGACYCALLER_HOOK_NAME
,
10890 JSNativeArguments(),
10891 getThisObj
="&args.callee()",
10895 if not self
._legacycaller
:
10897 return CGAbstractBindingMethod
.define(self
)
10899 def generate_code(self
):
10900 name
= self
._legacycaller
.identifier
.name
10901 nativeName
= MakeNativeName(self
.descriptor
.binaryNameFor(name
, False))
10902 return CGMethodCall(nativeName
, False, self
.descriptor
, self
._legacycaller
)
10904 def error_reporting_label(self
):
10905 # Should act like methods.
10906 return CGSpecializedMethod
.error_reporting_label_helper(
10907 self
.descriptor
, self
._legacycaller
, isConstructor
=False
10911 class CGResolveHook(CGAbstractClassHook
):
10913 Resolve hook for objects that have the NeedResolve extended attribute.
10916 def __init__(self
, descriptor
):
10917 assert descriptor
.interface
.getExtendedAttribute("NeedResolve")
10920 Argument("JSContext*", "cx"),
10921 Argument("JS::Handle<JSObject*>", "obj"),
10922 Argument("JS::Handle<jsid>", "id"),
10923 Argument("bool*", "resolvedp"),
10925 CGAbstractClassHook
.__init
__(self
, descriptor
, RESOLVE_HOOK_NAME
, "bool", args
)
10927 def generate_code(self
):
10930 JS::Rooted<mozilla::Maybe<JS::PropertyDescriptor>> desc(cx);
10931 if (!self->DoResolve(cx, obj, id, &desc)) {
10934 if (desc.isNothing()) {
10937 // If desc.value() is undefined, then the DoResolve call
10938 // has already defined it on the object. Don't try to also
10940 MOZ_ASSERT(desc->isDataDescriptor());
10941 if (!desc->value().isUndefined()) {
10942 JS::Rooted<JS::PropertyDescriptor> defineDesc(cx, *desc);
10943 defineDesc.setResolving(true);
10944 if (!JS_DefinePropertyById(cx, obj, id, defineDesc)) {
10953 def definition_body(self
):
10954 if self
.descriptor
.isGlobal():
10955 # Resolve standard classes
10958 if (!ResolveGlobal(cx, obj, id, resolvedp)) {
10969 return prefix
+ CGAbstractClassHook
.definition_body(self
)
10972 class CGMayResolveHook(CGAbstractStaticMethod
):
10974 Resolve hook for objects that have the NeedResolve extended attribute.
10977 def __init__(self
, descriptor
):
10978 assert descriptor
.interface
.getExtendedAttribute("NeedResolve")
10981 Argument("const JSAtomState&", "names"),
10982 Argument("jsid", "id"),
10983 Argument("JSObject*", "maybeObj"),
10985 CGAbstractStaticMethod
.__init
__(
10986 self
, descriptor
, MAY_RESOLVE_HOOK_NAME
, "bool", args
10989 def definition_body(self
):
10990 if self
.descriptor
.isGlobal():
10991 # Check whether this would resolve as a standard class.
10994 if (MayResolveGlobal(names, id, maybeObj)) {
11002 return prefix
+ "return %s::MayResolve(id);\n" % self
.descriptor
.nativeType
11005 class CGEnumerateHook(CGAbstractBindingMethod
):
11007 Enumerate hook for objects with custom hooks.
11010 def __init__(self
, descriptor
):
11011 assert descriptor
.interface
.getExtendedAttribute("NeedResolve")
11014 Argument("JSContext*", "cx"),
11015 Argument("JS::Handle<JSObject*>", "obj"),
11016 Argument("JS::MutableHandleVector<jsid>", "properties"),
11017 Argument("bool", "enumerableOnly"),
11019 # Our "self" is actually the "obj" argument in this case, not the thisval.
11020 CGAbstractBindingMethod
.__init
__(
11021 self
, descriptor
, NEW_ENUMERATE_HOOK_NAME
, args
, getThisObj
="", callArgs
=""
11024 def generate_code(self
):
11028 FastErrorResult rv;
11029 self->GetOwnPropertyNames(cx, properties, enumerableOnly, rv);
11030 if (rv.MaybeSetPendingException(cx)) {
11038 def definition_body(self
):
11039 if self
.descriptor
.isGlobal():
11040 # Enumerate standard classes
11043 if (!EnumerateGlobal(cx, obj, properties, enumerableOnly)) {
11051 return prefix
+ CGAbstractBindingMethod
.definition_body(self
)
11056 A class for checking if method names declared in webidl
11057 are not in conflict with C++ keywords.
11060 keywords
= frozenset(
11120 "reinterpret_cast",
11153 def checkMethodName(name
):
11154 # Double '_' because 'assert' and '_assert' cannot be used in MS2013 compiler.
11155 # Bug 964892 and bug 963560.
11156 if name
in CppKeywords
.keywords
:
11157 name
= "_" + name
+ "_"
11161 class CGStaticMethod(CGAbstractStaticBindingMethod
):
11163 A class for generating the C++ code for an IDL static method.
11166 def __init__(self
, descriptor
, method
):
11167 self
.method
= method
11168 name
= CppKeywords
.checkMethodName(IDLToCIdentifier(method
.identifier
.name
))
11169 CGAbstractStaticBindingMethod
.__init
__(self
, descriptor
, name
)
11171 def generate_code(self
):
11172 nativeName
= CGSpecializedMethod
.makeNativeName(self
.descriptor
, self
.method
)
11173 return CGMethodCall(nativeName
, True, self
.descriptor
, self
.method
)
11175 def auto_profiler_label(self
):
11176 interface_name
= self
.descriptor
.interface
.identifier
.name
11177 method_name
= self
.method
.identifier
.name
11180 AUTO_PROFILER_LABEL_DYNAMIC_FAST(
11181 "${interface_name}", "${method_name}", DOM, cx,
11182 uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) |
11183 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
11185 interface_name
=interface_name
,
11186 method_name
=method_name
,
11189 def error_reporting_label(self
):
11190 return CGSpecializedMethod
.error_reporting_label_helper(
11191 self
.descriptor
, self
.method
, isConstructor
=False
11195 class CGSpecializedGetterCommon(CGAbstractStaticMethod
):
11197 A class for generating the code for a specialized attribute getter
11198 that the JIT can call with lower overhead.
11208 errorReportingLabel
=None,
11209 additionalArg
=None,
11211 self
.nativeName
= nativeName
11212 self
.errorReportingLabel
= errorReportingLabel
11213 self
.additionalArgs
= [] if additionalArg
is None else [additionalArg
]
11214 # StoreInSlot attributes have their getters called from Wrap(). We
11215 # really hope they can't run script, and don't want to annotate Wrap()
11216 # methods as doing that anyway, so let's not annotate them as
11217 # MOZ_CAN_RUN_SCRIPT.
11218 CGAbstractStaticMethod
.__init
__(
11223 args
+ self
.additionalArgs
,
11224 canRunScript
=not attr
.getExtendedAttribute("StoreInSlot"),
11227 def definition_body(self
):
11230 auto* self = static_cast<${nativeType}*>(void_self);
11232 nativeType
=self
.descriptor
.nativeType
,
11235 if self
.attr
.isMaplikeOrSetlikeAttr():
11236 assert not self
.attr
.getExtendedAttribute("CrossOriginReadable")
11237 # If the interface is maplike/setlike, there will be one getter
11238 # method for the size property of the backing object. Due to having
11239 # to unpack the backing object from the slot, this requires its own
11241 return prefix
+ getMaplikeOrSetlikeSizeGetterBody(
11242 self
.descriptor
, self
.attr
11245 if self
.attr
.type.isObservableArray():
11246 assert not self
.attr
.getExtendedAttribute("CrossOriginReadable")
11247 # If the attribute is observableArray, due to having to unpack the
11248 # backing object from the slot, this requires its own generator.
11249 return prefix
+ getObservableArrayGetterBody(self
.descriptor
, self
.attr
)
11251 if self
.nativeName
is None:
11252 nativeName
= CGSpecializedGetterCommon
.makeNativeName(
11253 self
.descriptor
, self
.attr
11256 nativeName
= self
.nativeName
11258 type = self
.attr
.type
11259 if self
.attr
.getExtendedAttribute("CrossOriginReadable"):
11261 extendedAttributes
= self
.descriptor
.getExtendedAttributes(
11262 self
.attr
, getter
=True
11265 remoteType
.isGeckoInterface()
11266 and not remoteType
.unroll().inner
.isExternal()
11267 and remoteType
.unroll().inner
.getExtendedAttribute("ChromeOnly") is None
11269 # We'll use a JSObject. It might make more sense to use remoteType's
11270 # RemoteProxy, but it's not easy to construct a type for that from here.
11271 remoteType
= BuiltinTypes
[IDLBuiltinType
.Types
.object]
11272 if "needsErrorResult" not in extendedAttributes
:
11273 extendedAttributes
.append("needsErrorResult")
11274 prototypeID
, _
= PrototypeIDAndDepth(self
.descriptor
)
11278 if (IsRemoteObjectProxy(obj, ${prototypeID})) {
11279 ${nativeType}::RemoteProxy* self = static_cast<${nativeType}::RemoteProxy*>(void_self);
11283 prototypeID
=prototypeID
,
11284 nativeType
=self
.descriptor
.nativeType
,
11290 self
.errorReportingLabel
,
11291 argsPre
=[a
.name
for a
in self
.additionalArgs
],
11293 extendedAttributes
=extendedAttributes
,
11299 argsPre
= [a
.name
for a
in self
.additionalArgs
]
11300 maybeReturnCachedVal
= None
11301 if self
.attr
.slotIndices
is not None:
11302 # We're going to store this return value in a slot on some object,
11303 # to cache it. The question is, which object? For dictionary and
11304 # sequence return values, we want to use a slot on the Xray expando
11305 # if we're called via Xrays, and a slot on our reflector otherwise.
11306 # On the other hand, when dealing with some interface types
11307 # (e.g. window.document) we want to avoid calling the getter more
11308 # than once. In the case of window.document, it's because the
11309 # getter can start returning null, which would get hidden in the
11310 # non-Xray case by the fact that it's [StoreOnSlot], so the cached
11311 # version is always around.
11313 # The upshot is that we use the reflector slot for any getter whose
11314 # type is a gecko interface, whether we're called via Xrays or not.
11315 # Since [Cached] and [StoreInSlot] cannot be used with "NewObject",
11316 # we know that in the interface type case the returned object is
11317 # wrappercached. So creating Xrays to it is reasonable.
11318 if mayUseXrayExpandoSlots(self
.descriptor
, self
.attr
):
11321 // Have to either root across the getter call or reget after.
11323 JS::Rooted<JSObject*> slotStorage(cx, GetCachedSlotStorageObject(cx, obj, &isXray));
11324 if (!slotStorage) {
11332 // Have to either root across the getter call or reget after.
11333 JS::Rooted<JSObject*> slotStorage(cx, js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false));
11334 MOZ_ASSERT(IsDOMObject(slotStorage));
11338 if self
.attr
.getExtendedAttribute(
11339 "ReflectedHTMLAttributeReturningFrozenArray"
11341 argsPre
.append("hasCachedValue ? &useCachedValue : nullptr")
11344 if mayUseXrayExpandoSlots(self
.descriptor
, self
.attr
)
11349 auto& array = ReflectedHTMLAttributeSlots::GetOrCreate(slotStorage, ${isXray});
11350 JS::Rooted<JS::Value> cachedVal(cx, array[${arrayIndex}]);
11351 bool hasCachedValue = !cachedVal.isUndefined();
11352 bool useCachedValue = false;
11355 arrayIndex
=reflectedHTMLAttributesArrayIndex(
11356 self
.descriptor
, self
.attr
11359 maybeReturnCachedVal
= fill(
11361 MOZ_ASSERT_IF(useCachedValue, hasCachedValue);
11362 if (hasCachedValue && useCachedValue) {
11363 args.rval().set(cachedVal);
11364 // The cached value is in the compartment of slotStorage,
11365 // so wrap into the caller compartment as needed.
11366 return ${maybeWrap}(cx, args.rval());
11369 ${clearCachedValue}(self);
11372 maybeWrap
=getMaybeWrapValueFuncForType(self
.attr
.type),
11373 clearCachedValue
=MakeClearCachedValueNativeName(self
.attr
),
11376 if mayUseXrayExpandoSlots(self
.descriptor
, self
.attr
):
11379 const size_t slotIndex = isXray ? ${xraySlotIndex} : ${slotIndex};
11381 xraySlotIndex
=memberXrayExpandoReservedSlot(
11382 self
.attr
, self
.descriptor
11384 slotIndex
=memberReservedSlot(self
.attr
, self
.descriptor
),
11389 const size_t slotIndex = ${slotIndex};
11391 slotIndex
=memberReservedSlot(self
.attr
, self
.descriptor
),
11395 MOZ_ASSERT(slotIndex < JSCLASS_RESERVED_SLOTS(JS::GetClass(slotStorage)));
11397 // Scope for cachedVal
11398 JS::Value cachedVal = JS::GetReservedSlot(slotStorage, slotIndex);
11399 if (!cachedVal.isUndefined()) {
11400 args.rval().set(cachedVal);
11401 // The cached value is in the compartment of slotStorage,
11402 // so wrap into the caller compartment as needed.
11403 return ${maybeWrap}(cx, args.rval());
11408 maybeWrap
=getMaybeWrapValueFuncForType(self
.attr
.type),
11418 self
.errorReportingLabel
,
11420 preConversionCode
=maybeReturnCachedVal
,
11424 def auto_profiler_label(self
, profilerLabel
=None):
11425 if profilerLabel
is None:
11426 profilerLabel
= '"' + self
.attr
.identifier
.name
+ '"'
11427 interface_name
= self
.descriptor
.interface
.identifier
.name
11430 AUTO_PROFILER_LABEL_DYNAMIC_FAST(
11431 "${interface_name}", ${attr_name}, DOM, cx,
11432 uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) |
11433 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
11435 interface_name
=interface_name
,
11436 attr_name
=profilerLabel
,
11439 def error_reporting_label(self
):
11440 # Getters never need a BindingCallContext.
11444 def makeNativeName(descriptor
, attr
):
11445 name
= attr
.identifier
.name
11446 nativeName
= MakeNativeName(descriptor
.binaryNameFor(name
, attr
.isStatic()))
11447 _
, resultOutParam
, _
, _
, _
= getRetvalDeclarationForType(attr
.type, descriptor
)
11448 extendedAttrs
= descriptor
.getExtendedAttributes(attr
, getter
=True)
11449 canFail
= "needsErrorResult" in extendedAttrs
or "canOOM" in extendedAttrs
11450 if resultOutParam
or attr
.type.nullable() or canFail
:
11451 nativeName
= "Get" + nativeName
11455 class CGSpecializedGetter(CGSpecializedGetterCommon
):
11457 A class for generating the code for a specialized attribute getter
11458 that the JIT can call with lower overhead.
11461 def __init__(self
, descriptor
, attr
):
11463 name
= "get_" + IDLToCIdentifier(attr
.identifier
.name
)
11465 Argument("JSContext*", "cx"),
11466 Argument("JS::Handle<JSObject*>", "obj"),
11467 Argument("void*", "void_self"),
11468 Argument("JSJitGetterCallArgs", "args"),
11470 CGSpecializedGetterCommon
.__init
__(self
, descriptor
, name
, None, attr
, args
)
11473 class CGTemplateForSpecializedGetter(CGSpecializedGetterCommon
):
11475 A class for generating the code for a specialized attribute getter
11476 that can be used as the common getter that templated attribute
11477 getters can forward to.
11480 def __init__(self
, descriptor
, template
):
11481 self
.attr
= template
.attr
11482 self
.attrNameString
= template
.attrNameString
11484 Argument("JSContext*", "cx"),
11485 Argument("JS::Handle<JSObject*>", "obj"),
11486 Argument("void*", "void_self"),
11487 Argument("JSJitGetterCallArgs", "args"),
11489 errorDescription
= (
11490 'ErrorDescriptionFor<ErrorFor::getter>{ "%s", attrName }'
11491 % descriptor
.interface
.identifier
.name
11493 CGSpecializedGetterCommon
.__init
__(
11500 errorReportingLabel
=errorDescription
,
11501 additionalArg
=Argument(template
.argument
.type, template
.argument
.name
),
11504 def auto_profiler_label(self
):
11508 const char* attrName = ${attrNameString};
11510 attrNameString
=self
.attrNameString
,
11512 + CGSpecializedGetterCommon
.auto_profiler_label(self
, "attrName")
11516 class CGSpecializedTemplatedGetter(CGAbstractStaticMethod
):
11518 A class for generating the code for a specialized templated attribute
11519 getter that forwards to a common template getter.
11522 def __init__(self
, descriptor
, attr
, template
, additionalArg
):
11524 self
.template
= template
11525 self
.additionalArg
= additionalArg
11526 name
= "get_" + IDLToCIdentifier(attr
.identifier
.name
)
11528 Argument("JSContext*", "cx"),
11529 Argument("JS::Handle<JSObject*>", "obj"),
11530 Argument("void*", "void_self"),
11531 Argument("JSJitGetterCallArgs", "args"),
11533 assert not attr
.getExtendedAttribute("StoreInSlot")
11534 CGAbstractStaticMethod
.__init
__(
11543 def definition_body(self
):
11544 if self
.additionalArg
is None:
11545 additionalArg
= self
.attr
.identifier
.name
11547 additionalArg
= self
.additionalArg
11551 return ${namespace}::${getter}(cx, obj, void_self, args, ${additionalArg});
11553 namespace
=toBindingNamespace(
11554 self
.template
.descriptor
.interface
.identifier
.name
11556 getter
=self
.template
.getter
,
11557 additionalArg
=additionalArg
,
11561 class CGGetterPromiseWrapper(CGAbstractStaticMethod
):
11563 A class for generating a wrapper around another getter that will
11564 convert exceptions to promises.
11567 def __init__(self
, descriptor
, getterToWrap
):
11568 self
.getter
= getterToWrap
11569 name
= self
.makeName(getterToWrap
.name
)
11570 args
= list(getterToWrap
.args
)
11571 CGAbstractStaticMethod
.__init
__(
11572 self
, descriptor
, name
, "bool", args
, canRunScript
=True
11575 def definition_body(self
):
11578 bool ok = ${getterName}(${args});
11582 return ConvertExceptionToPromise(cx, args.rval());
11584 getterName
=self
.getter
.name
,
11585 args
=", ".join(arg
.name
for arg
in self
.args
),
11589 def makeName(getterName
):
11590 return getterName
+ "_promiseWrapper"
11593 class CGStaticGetter(CGAbstractStaticBindingMethod
):
11595 A class for generating the C++ code for an IDL static attribute getter.
11598 def __init__(self
, descriptor
, attr
):
11600 name
= "get_" + IDLToCIdentifier(attr
.identifier
.name
)
11601 CGAbstractStaticBindingMethod
.__init
__(self
, descriptor
, name
)
11603 def generate_code(self
):
11604 nativeName
= CGSpecializedGetterCommon
.makeNativeName(
11605 self
.descriptor
, self
.attr
11607 return CGGetterCall(self
.attr
.type, nativeName
, self
.descriptor
, self
.attr
)
11609 def auto_profiler_label(self
):
11610 interface_name
= self
.descriptor
.interface
.identifier
.name
11611 attr_name
= self
.attr
.identifier
.name
11614 AUTO_PROFILER_LABEL_DYNAMIC_FAST(
11615 "${interface_name}", "${attr_name}", DOM, cx,
11616 uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) |
11617 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
11619 interface_name
=interface_name
,
11620 attr_name
=attr_name
,
11623 def error_reporting_label(self
):
11624 # Getters never need a BindingCallContext.
11628 class CGSpecializedSetterCommon(CGAbstractStaticMethod
):
11630 A class for generating the code for a specialized attribute setter
11631 that the JIT can call with lower overhead.
11641 errorReportingLabel
=None,
11642 additionalArg
=None,
11644 self
.nativeName
= nativeName
11645 self
.errorReportingLabel
= errorReportingLabel
11646 self
.additionalArgs
= [] if additionalArg
is None else [additionalArg
]
11647 CGAbstractStaticMethod
.__init
__(
11652 args
+ self
.additionalArgs
,
11656 def definition_body(self
):
11657 type = self
.attr
.type
11658 call
= CGSetterCall(
11663 self
.errorReportingLabel
,
11664 [a
.name
for a
in self
.additionalArgs
],
11667 if self
.attr
.getExtendedAttribute("CrossOriginWritable"):
11668 if type.isGeckoInterface() and not type.unroll().inner
.isExternal():
11669 # a setter taking a Gecko interface would require us to deal with remote
11670 # proxies for the value here.
11672 "We don't support the setter of %s marked as "
11673 "CrossOriginWritable because it takes a Gecko interface "
11675 self
.attr
.identifier
.name
,
11677 prototypeID
, _
= PrototypeIDAndDepth(self
.descriptor
)
11680 if (IsRemoteObjectProxy(obj, ${prototypeID})) {
11681 auto* self = static_cast<${nativeType}::RemoteProxy*>(void_self);
11685 prototypeID
=prototypeID
,
11686 nativeType
=self
.descriptor
.nativeType
,
11690 return prefix
+ fill(
11692 auto* self = static_cast<${nativeType}*>(void_self);
11695 nativeType
=self
.descriptor
.nativeType
,
11699 def auto_profiler_label(self
, profilerLabel
=None):
11700 interface_name
= self
.descriptor
.interface
.identifier
.name
11701 if profilerLabel
is None:
11702 profilerLabel
= '"' + self
.attr
.identifier
.name
+ '"'
11705 AUTO_PROFILER_LABEL_DYNAMIC_FAST(
11706 "${interface_name}", ${attr_name}, DOM, cx,
11707 uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) |
11708 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
11710 interface_name
=interface_name
,
11711 attr_name
=profilerLabel
,
11715 def error_reporting_label_helper(descriptor
, attr
):
11716 # Setters need a BindingCallContext if the type of the attribute needs
11718 if not idlTypeNeedsCallContext(
11719 attr
.type, descriptor
, allowTreatNonCallableAsNull
=True
11723 GetLabelForErrorReporting(descriptor
, attr
, isConstructor
=False) + " setter"
11726 def error_reporting_label(self
):
11727 errorReportingLabel
= CGSpecializedSetterCommon
.error_reporting_label_helper(
11728 self
.descriptor
, self
.attr
11730 if errorReportingLabel
is None:
11732 if self
.errorReportingLabel
:
11733 return self
.errorReportingLabel
11734 return errorReportingLabel
11737 def makeNativeName(descriptor
, attr
):
11738 name
= attr
.identifier
.name
11739 return "Set" + MakeNativeName(descriptor
.binaryNameFor(name
, attr
.isStatic()))
11742 class CGSpecializedSetter(CGSpecializedSetterCommon
):
11744 A class for generating the code for a specialized attribute setter
11745 that the JIT can call with lower overhead.
11748 def __init__(self
, descriptor
, attr
):
11750 name
= "set_" + IDLToCIdentifier(attr
.identifier
.name
)
11752 Argument("JSContext*", "cx"),
11753 Argument("JS::Handle<JSObject*>", "obj"),
11754 Argument("void*", "void_self"),
11755 Argument("JSJitSetterCallArgs", "args"),
11757 CGSpecializedSetterCommon
.__init
__(
11761 CGSpecializedSetterCommon
.makeNativeName(descriptor
, attr
),
11767 class CGTemplateForSpecializedSetter(CGSpecializedSetterCommon
):
11769 A class for generating the code for a specialized attribute setter
11770 that can be used as the common setter that templated attribute
11771 setters can forward to.
11774 def __init__(self
, descriptor
, template
):
11775 self
.attr
= template
.attr
11776 self
.attrNameString
= template
.attrNameString
11778 Argument("JSContext*", "cx"),
11779 Argument("JS::Handle<JSObject*>", "obj"),
11780 Argument("void*", "void_self"),
11781 Argument("JSJitSetterCallArgs", "args"),
11783 errorDescription
= (
11784 'ErrorDescriptionFor<ErrorFor::setter>{ "%s", attrName }'
11785 % descriptor
.interface
.identifier
.name
11787 CGSpecializedSetterCommon
.__init
__(
11794 errorReportingLabel
=errorDescription
,
11795 additionalArg
=Argument(template
.argument
.type, template
.argument
.name
),
11798 def auto_profiler_label(self
):
11802 const char* attrName = ${attrNameString};
11804 attrNameString
=self
.attrNameString
,
11806 + CGSpecializedSetterCommon
.auto_profiler_label(self
, "attrName")
11810 class CGSpecializedTemplatedSetter(CGAbstractStaticMethod
):
11812 A class for generating the code for a specialized templated attribute
11813 setter that forwards to a common template setter.
11816 def __init__(self
, descriptor
, attr
, template
, additionalArg
):
11818 self
.template
= template
11819 self
.additionalArg
= additionalArg
11820 name
= "set_" + IDLToCIdentifier(attr
.identifier
.name
)
11822 Argument("JSContext*", "cx"),
11823 Argument("JS::Handle<JSObject*>", "obj"),
11824 Argument("void*", "void_self"),
11825 Argument("JSJitSetterCallArgs", "args"),
11827 CGAbstractStaticMethod
.__init
__(
11828 self
, descriptor
, name
, "bool", args
, canRunScript
=True
11831 def definition_body(self
):
11832 additionalArgs
= []
11833 if self
.additionalArg
is None:
11834 additionalArgs
.append(self
.attr
.identifier
.name
)
11836 additionalArgs
.append(self
.additionalArg
)
11840 return ${namespace}::${setter}(cx, obj, void_self, args, ${additionalArgs});
11842 namespace
=toBindingNamespace(
11843 self
.template
.descriptor
.interface
.identifier
.name
11845 setter
=self
.template
.setter
,
11846 additionalArgs
=", ".join(additionalArgs
),
11850 class CGStaticSetter(CGAbstractStaticBindingMethod
):
11852 A class for generating the C++ code for an IDL static attribute setter.
11855 def __init__(self
, descriptor
, attr
):
11857 name
= "set_" + IDLToCIdentifier(attr
.identifier
.name
)
11858 CGAbstractStaticBindingMethod
.__init
__(self
, descriptor
, name
)
11860 def generate_code(self
):
11861 nativeName
= CGSpecializedSetterCommon
.makeNativeName(
11862 self
.descriptor
, self
.attr
11864 checkForArg
= CGGeneric(
11867 if (!args.requireAtLeast(cx, "${name} setter", 1)) {
11871 name
=self
.attr
.identifier
.name
,
11874 call
= CGSetterCall(self
.attr
.type, nativeName
, self
.descriptor
, self
.attr
)
11875 return CGList([checkForArg
, call
])
11877 def auto_profiler_label(self
):
11878 interface_name
= self
.descriptor
.interface
.identifier
.name
11879 attr_name
= self
.attr
.identifier
.name
11882 AUTO_PROFILER_LABEL_DYNAMIC_FAST(
11883 "${interface_name}", "${attr_name}", DOM, cx,
11884 uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) |
11885 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
11887 interface_name
=interface_name
,
11888 attr_name
=attr_name
,
11891 def error_reporting_label(self
):
11892 return CGSpecializedSetterCommon
.error_reporting_label_helper(
11893 self
.descriptor
, self
.attr
11897 class CGSpecializedForwardingSetter(CGSpecializedSetter
):
11899 A class for generating the code for a specialized attribute setter with
11900 PutForwards that the JIT can call with lower overhead.
11903 def __init__(self
, descriptor
, attr
):
11904 CGSpecializedSetter
.__init
__(self
, descriptor
, attr
)
11906 def definition_body(self
):
11907 attrName
= self
.attr
.identifier
.name
11908 forwardToAttrName
= self
.attr
.getExtendedAttribute("PutForwards")[0]
11909 # JS_GetProperty and JS_SetProperty can only deal with ASCII
11910 assert all(ord(c
) < 128 for c
in attrName
)
11911 assert all(ord(c
) < 128 for c
in forwardToAttrName
)
11914 JS::Rooted<JS::Value> v(cx);
11915 if (!JS_GetProperty(cx, obj, "${attr}", &v)) {
11919 if (!v.isObject()) {
11920 return cx.ThrowErrorMessage<MSG_NOT_OBJECT>("${interface}.${attr}");
11923 JS::Rooted<JSObject*> targetObj(cx, &v.toObject());
11924 return JS_SetProperty(cx, targetObj, "${forwardToAttrName}", args[0]);
11927 interface
=self
.descriptor
.interface
.identifier
.name
,
11928 forwardToAttrName
=forwardToAttrName
,
11931 def error_reporting_label(self
):
11932 # We always need to be able to throw.
11934 GetLabelForErrorReporting(self
.descriptor
, self
.attr
, isConstructor
=False)
11939 class CGSpecializedReplaceableSetter(CGSpecializedSetter
):
11941 A class for generating the code for a specialized attribute setter with
11942 Replaceable that the JIT can call with lower overhead.
11945 def __init__(self
, descriptor
, attr
):
11946 CGSpecializedSetter
.__init
__(self
, descriptor
, attr
)
11948 def definition_body(self
):
11949 attrName
= self
.attr
.identifier
.name
11950 # JS_DefineProperty can only deal with ASCII
11951 assert all(ord(c
) < 128 for c
in attrName
)
11953 'return JS_DefineProperty(cx, obj, "%s", args[0], JSPROP_ENUMERATE);\n'
11957 def error_reporting_label(self
):
11958 # We never throw directly.
11962 class CGSpecializedLenientSetter(CGSpecializedSetter
):
11964 A class for generating the code for a specialized attribute setter with
11965 LenientSetter that the JIT can call with lower overhead.
11968 def __init__(self
, descriptor
, attr
):
11969 CGSpecializedSetter
.__init
__(self
, descriptor
, attr
)
11971 def definition_body(self
):
11972 attrName
= self
.attr
.identifier
.name
11973 # JS_DefineProperty can only deal with ASCII
11974 assert all(ord(c
) < 128 for c
in attrName
)
11977 DeprecationWarning(cx, obj, DeprecatedOperations::eLenientSetter);
11982 def error_reporting_label(self
):
11983 # We never throw; that's the whole point.
11987 def memberReturnsNewObject(member
):
11988 return member
.getExtendedAttribute("NewObject") is not None
11991 class CGMemberJITInfo(CGThing
):
11993 A class for generating the JITInfo for a property that points to
11994 our specialized getter and setter.
11997 def __init__(self
, descriptor
, member
):
11998 self
.member
= member
11999 self
.descriptor
= descriptor
12020 aliasSet is a JSJitInfo::AliasSet value, without the "JSJitInfo::" bit.
12022 args is None if we don't want to output argTypes for some
12023 reason (e.g. we have overloads or we're not a method) and
12024 otherwise an iterable of the arguments for this method.
12027 not movable
or aliasSet
!= "AliasEverything"
12028 ) # Can't move write-aliasing things
12030 not alwaysInSlot
or movable
12031 ) # Things always in slots had better be movable
12033 not eliminatable
or aliasSet
!= "AliasEverything"
12034 ) # Can't eliminate write-aliasing things
12036 not alwaysInSlot
or eliminatable
12037 ) # Things always in slots had better be eliminatable
12039 def jitInfoInitializer(isTypedMethod
):
12040 initializer
= fill(
12044 { prototypes::id::${name} },
12045 { PrototypeTraits<prototypes::id::${name}>::Depth },
12046 JSJitInfo::${opType},
12047 JSJitInfo::${aliasSet}, /* aliasSet. Not relevant for setters. */
12048 ${returnType}, /* returnType. Not relevant for setters. */
12049 ${isInfallible}, /* isInfallible. False in setters. */
12050 ${isMovable}, /* isMovable. Not relevant for setters. */
12051 ${isEliminatable}, /* isEliminatable. Not relevant for setters. */
12052 ${isAlwaysInSlot}, /* isAlwaysInSlot. Only relevant for getters. */
12053 ${isLazilyCachedInSlot}, /* isLazilyCachedInSlot. Only relevant for getters. */
12054 ${isTypedMethod}, /* isTypedMethod. Only relevant for methods. */
12055 ${slotIndex} /* Reserved slot index, if we're stored in a slot, else 0. */
12059 name
=self
.descriptor
.name
,
12062 returnType
=functools
.reduce(
12063 CGMemberJITInfo
.getSingleReturnType
, returnTypes
, ""
12065 isInfallible
=toStringBool(infallible
),
12066 isMovable
=toStringBool(movable
),
12067 isEliminatable
=toStringBool(eliminatable
),
12068 isAlwaysInSlot
=toStringBool(alwaysInSlot
),
12069 isLazilyCachedInSlot
=toStringBool(lazilyInSlot
),
12070 isTypedMethod
=toStringBool(isTypedMethod
),
12071 slotIndex
="0" if slotIndex
is None else slotIndex
,
12073 return initializer
.rstrip()
12075 if slotIndex
is not None:
12078 static_assert(${slotIndex} <= JSJitInfo::maxSlotIndex, "We won't fit");
12079 static_assert(${slotIndex} < ${classReservedSlots}, "There is no slot for us");
12081 slotIndex
=slotIndex
,
12082 classReservedSlots
=INSTANCE_RESERVED_SLOTS
12083 + self
.descriptor
.interface
.totalMembersInSlots
,
12087 if args
is not None:
12088 argTypes
= "%s_argTypes" % infoName
12089 args
= [CGMemberJITInfo
.getJSArgType(arg
.type) for arg
in args
]
12090 args
.append("JSJitInfo::ArgTypeListEnd")
12091 argTypesDecl
= "static const JSJitInfo::ArgType %s[] = { %s };\n" % (
12098 static const JSTypedMethodJitInfo ${infoName} = {
12104 argTypesDecl
=argTypesDecl
,
12106 jitInfo
=indent(jitInfoInitializer(True)),
12108 slotAssert
=slotAssert
,
12111 # Unexposed things are meant to be used from C++ directly, so we make
12112 # their jitinfo non-static. That way C++ can get at it.
12113 if self
.member
.getExtendedAttribute("Unexposed"):
12114 storageClass
= "extern"
12116 storageClass
= "static"
12120 ${storageClass} const JSJitInfo ${infoName} = ${jitInfo};
12123 storageClass
=storageClass
,
12125 jitInfo
=jitInfoInitializer(False),
12126 slotAssert
=slotAssert
,
12130 if self
.member
.isAttr():
12131 getterinfo
= "%s_getterinfo" % IDLToCIdentifier(self
.member
.identifier
.name
)
12132 name
= IDLToCIdentifier(self
.member
.identifier
.name
)
12133 if self
.member
.type.isPromise():
12134 name
= CGGetterPromiseWrapper
.makeName(name
)
12135 getter
= "get_%s" % name
12136 extendedAttrs
= self
.descriptor
.getExtendedAttributes(
12137 self
.member
, getter
=True
12139 getterinfal
= "needsErrorResult" not in extendedAttrs
12141 # At this point getterinfal is true if our getter either can't throw
12142 # at all, or can only throw OOM. In both cases, it's safe to move,
12143 # or dead-code-eliminate, the getter, because throwing OOM is not
12144 # semantically meaningful, so code can't rely on it happening. Note
12145 # that this makes the behavior consistent for OOM thrown from the
12146 # getter itself and OOM thrown from the to-JS conversion of the
12147 # return value (see the "canOOM" and "infallibleForMember" checks
12149 movable
= self
.mayBeMovable() and getterinfal
12150 eliminatable
= self
.mayBeEliminatable() and getterinfal
12151 aliasSet
= self
.aliasSet()
12153 # Now we have to set getterinfal to whether we can _really_ ever
12154 # throw, from the point of view of the JS engine.
12157 and "canOOM" not in extendedAttrs
12158 and infallibleForMember(self
.member
, self
.member
.type, self
.descriptor
)
12160 isAlwaysInSlot
= self
.member
.getExtendedAttribute("StoreInSlot")
12162 if self
.member
.slotIndices
is not None:
12165 or self
.member
.getExtendedAttribute("Cached")
12166 or self
.member
.getExtendedAttribute(
12167 "ReflectedHTMLAttributeReturningFrozenArray"
12169 or self
.member
.type.isObservableArray()
12171 isLazilyCachedInSlot
= (
12173 and not self
.member
.getExtendedAttribute(
12174 "ReflectedHTMLAttributeReturningFrozenArray"
12177 slotIndex
= memberReservedSlot(self
.member
, self
.descriptor
)
12178 # We'll statically assert that this is not too big in
12179 # CGUpdateMemberSlotsMethod, in the case when
12180 # isAlwaysInSlot is true.
12182 isLazilyCachedInSlot
= False
12185 result
= self
.defineJitInfo(
12194 isLazilyCachedInSlot
,
12196 [self
.member
.type],
12200 not self
.member
.readonly
12201 or self
.member
.getExtendedAttribute("PutForwards") is not None
12202 or self
.member
.getExtendedAttribute("Replaceable") is not None
12203 or self
.member
.getExtendedAttribute("LegacyLenientSetter") is not None
12205 setterinfo
= "%s_setterinfo" % IDLToCIdentifier(
12206 self
.member
.identifier
.name
12208 # Actually a JSJitSetterOp, but JSJitGetterOp is first in the
12210 setter
= "(JSJitGetterOp)set_%s" % IDLToCIdentifier(
12211 self
.member
.identifier
.name
12213 # Setters are always fallible, since they have to do a typed unwrap.
12214 result
+= self
.defineJitInfo(
12225 [BuiltinTypes
[IDLBuiltinType
.Types
.undefined
]],
12229 if self
.member
.isMethod():
12230 methodinfo
= "%s_methodinfo" % IDLToCIdentifier(self
.member
.identifier
.name
)
12231 name
= CppKeywords
.checkMethodName(
12232 IDLToCIdentifier(self
.member
.identifier
.name
)
12234 if self
.member
.returnsPromise():
12235 name
= CGMethodPromiseWrapper
.makeName(name
)
12236 # Actually a JSJitMethodOp, but JSJitGetterOp is first in the union.
12237 method
= "(JSJitGetterOp)%s" % name
12239 # Methods are infallible if they are infallible, have no arguments
12240 # to unwrap, and have a return type that's infallible to wrap up for
12242 sigs
= self
.member
.signatures()
12244 # Don't handle overloading. If there's more than one signature,
12245 # one of them must take arguments.
12246 methodInfal
= False
12249 eliminatable
= False
12252 # For methods that affect nothing, it's OK to set movable to our
12253 # notion of infallible on the C++ side, without considering
12254 # argument conversions, since argument conversions that can
12255 # reliably throw would be effectful anyway and the jit doesn't
12256 # move effectful things.
12257 extendedAttrs
= self
.descriptor
.getExtendedAttributes(self
.member
)
12258 hasInfallibleImpl
= "needsErrorResult" not in extendedAttrs
12259 # At this point hasInfallibleImpl is true if our method either
12260 # can't throw at all, or can only throw OOM. In both cases, it
12261 # may be safe to move, or dead-code-eliminate, the method,
12262 # because throwing OOM is not semantically meaningful, so code
12263 # can't rely on it happening. Note that this makes the behavior
12264 # consistent for OOM thrown from the method itself and OOM
12265 # thrown from the to-JS conversion of the return value (see the
12266 # "canOOM" and "infallibleForMember" checks below).
12267 movable
= self
.mayBeMovable() and hasInfallibleImpl
12268 eliminatable
= self
.mayBeEliminatable() and hasInfallibleImpl
12269 # XXXbz can we move the smarts about fallibility due to arg
12270 # conversions into the JIT, using our new args stuff?
12271 if len(sig
[1]) != 0 or not infallibleForMember(
12272 self
.member
, sig
[0], self
.descriptor
12274 # We have arguments or our return-value boxing can fail
12275 methodInfal
= False
12277 methodInfal
= hasInfallibleImpl
and "canOOM" not in extendedAttrs
12278 # For now, only bother to output args if we're side-effect-free.
12279 if self
.member
.affects
== "Nothing":
12284 aliasSet
= self
.aliasSet()
12285 result
= self
.defineJitInfo(
12296 [s
[0] for s
in sigs
],
12300 raise TypeError("Illegal member type to CGPropertyJITInfo")
12302 def mayBeMovable(self
):
12304 Returns whether this attribute or method may be movable, just
12305 based on Affects/DependsOn annotations.
12307 affects
= self
.member
.affects
12308 dependsOn
= self
.member
.dependsOn
12309 assert affects
in IDLInterfaceMember
.AffectsValues
12310 assert dependsOn
in IDLInterfaceMember
.DependsOnValues
12311 # Things that are DependsOn=DeviceState are not movable, because we
12312 # don't want them coalesced with each other or loop-hoisted, since
12313 # their return value can change even if nothing is going on from our
12315 return affects
== "Nothing" and (
12316 dependsOn
!= "Everything" and dependsOn
!= "DeviceState"
12319 def mayBeEliminatable(self
):
12321 Returns whether this attribute or method may be eliminatable, just
12322 based on Affects/DependsOn annotations.
12324 # dependsOn shouldn't affect this decision at all, except in jitinfo we
12325 # have no way to express "Depends on everything, affects nothing",
12326 # because we only have three alias set values: AliasNone ("depends on
12327 # nothing, affects nothing"), AliasDOMSets ("depends on DOM sets,
12328 # affects nothing"), AliasEverything ("depends on everything, affects
12329 # everything"). So the [Affects=Nothing, DependsOn=Everything] case
12330 # gets encoded as AliasEverything and defineJitInfo asserts that if our
12331 # alias state is AliasEverything then we're not eliminatable (because it
12332 # thinks we might have side-effects at that point). Bug 1155796 is
12333 # tracking possible solutions for this.
12334 affects
= self
.member
.affects
12335 dependsOn
= self
.member
.dependsOn
12336 assert affects
in IDLInterfaceMember
.AffectsValues
12337 assert dependsOn
in IDLInterfaceMember
.DependsOnValues
12338 return affects
== "Nothing" and dependsOn
!= "Everything"
12340 def aliasSet(self
):
12342 Returns the alias set to store in the jitinfo. This may not be the
12343 effective alias set the JIT uses, depending on whether we have enough
12344 information about our args to allow the JIT to prove that effectful
12345 argument conversions won't happen.
12347 dependsOn
= self
.member
.dependsOn
12348 assert dependsOn
in IDLInterfaceMember
.DependsOnValues
12350 if dependsOn
== "Nothing" or dependsOn
== "DeviceState":
12351 assert self
.member
.affects
== "Nothing"
12354 if dependsOn
== "DOMState":
12355 assert self
.member
.affects
== "Nothing"
12356 return "AliasDOMSets"
12358 return "AliasEverything"
12361 def getJSReturnTypeTag(t
):
12363 # Sometimes it might return null, sometimes not
12364 return "JSVAL_TYPE_UNKNOWN"
12365 if t
.isUndefined():
12366 # No return, every time
12367 return "JSVAL_TYPE_UNDEFINED"
12369 return "JSVAL_TYPE_OBJECT"
12371 return "JSVAL_TYPE_OBJECT"
12373 return "JSVAL_TYPE_OBJECT"
12374 if t
.isGeckoInterface():
12375 return "JSVAL_TYPE_OBJECT"
12377 return "JSVAL_TYPE_STRING"
12379 return "JSVAL_TYPE_STRING"
12381 return "JSVAL_TYPE_OBJECT"
12383 # The whole point is to return various stuff
12384 return "JSVAL_TYPE_UNKNOWN"
12386 return "JSVAL_TYPE_OBJECT"
12387 if t
.isSpiderMonkeyInterface():
12388 return "JSVAL_TYPE_OBJECT"
12391 if u
.hasNullableType
:
12392 # Might be null or not
12393 return "JSVAL_TYPE_UNKNOWN"
12394 return functools
.reduce(
12395 CGMemberJITInfo
.getSingleReturnType
, u
.flatMemberTypes
, ""
12397 if t
.isDictionary():
12398 return "JSVAL_TYPE_OBJECT"
12399 if t
.isObservableArray():
12400 return "JSVAL_TYPE_OBJECT"
12401 if not t
.isPrimitive():
12402 raise TypeError("No idea what type " + str(t
) + " is.")
12404 if tag
== IDLType
.Tags
.bool:
12405 return "JSVAL_TYPE_BOOLEAN"
12408 IDLType
.Tags
.uint8
,
12409 IDLType
.Tags
.int16
,
12410 IDLType
.Tags
.uint16
,
12411 IDLType
.Tags
.int32
,
12413 return "JSVAL_TYPE_INT32"
12415 IDLType
.Tags
.int64
,
12416 IDLType
.Tags
.uint64
,
12417 IDLType
.Tags
.unrestricted_float
,
12418 IDLType
.Tags
.float,
12419 IDLType
.Tags
.unrestricted_double
,
12420 IDLType
.Tags
.double
,
12422 # These all use JS_NumberValue, which can return int or double.
12423 # But TI treats "double" as meaning "int or double", so we're
12424 # good to return JSVAL_TYPE_DOUBLE here.
12425 return "JSVAL_TYPE_DOUBLE"
12426 if tag
!= IDLType
.Tags
.uint32
:
12427 raise TypeError("No idea what type " + str(t
) + " is.")
12428 # uint32 is sometimes int and sometimes double.
12429 return "JSVAL_TYPE_DOUBLE"
12432 def getSingleReturnType(existingType
, t
):
12433 type = CGMemberJITInfo
.getJSReturnTypeTag(t
)
12434 if existingType
== "":
12435 # First element of the list; just return its type
12438 if type == existingType
:
12439 return existingType
12440 if (type == "JSVAL_TYPE_DOUBLE" and existingType
== "JSVAL_TYPE_INT32") or (
12441 existingType
== "JSVAL_TYPE_DOUBLE" and type == "JSVAL_TYPE_INT32"
12443 # Promote INT32 to DOUBLE as needed
12444 return "JSVAL_TYPE_DOUBLE"
12446 return "JSVAL_TYPE_UNKNOWN"
12449 def getJSArgType(t
):
12450 assert not t
.isUndefined()
12452 # Sometimes it might return null, sometimes not
12454 "JSJitInfo::ArgType(JSJitInfo::Null | %s)"
12455 % CGMemberJITInfo
.getJSArgType(t
.inner
)
12458 return "JSJitInfo::Object"
12460 return "JSJitInfo::Object"
12461 if t
.isGeckoInterface():
12462 return "JSJitInfo::Object"
12464 return "JSJitInfo::String"
12466 return "JSJitInfo::String"
12468 return "JSJitInfo::Object"
12470 # The whole point is to return various stuff
12471 return "JSJitInfo::Any"
12473 return "JSJitInfo::Object"
12474 if t
.isSpiderMonkeyInterface():
12475 return "JSJitInfo::Object"
12478 type = "JSJitInfo::Null" if u
.hasNullableType
else ""
12479 return "JSJitInfo::ArgType(%s)" % functools
.reduce(
12480 CGMemberJITInfo
.getSingleArgType
, u
.flatMemberTypes
, type
12482 if t
.isDictionary():
12483 return "JSJitInfo::Object"
12484 if not t
.isPrimitive():
12485 raise TypeError("No idea what type " + str(t
) + " is.")
12487 if tag
== IDLType
.Tags
.bool:
12488 return "JSJitInfo::Boolean"
12491 IDLType
.Tags
.uint8
,
12492 IDLType
.Tags
.int16
,
12493 IDLType
.Tags
.uint16
,
12494 IDLType
.Tags
.int32
,
12496 return "JSJitInfo::Integer"
12498 IDLType
.Tags
.int64
,
12499 IDLType
.Tags
.uint64
,
12500 IDLType
.Tags
.unrestricted_float
,
12501 IDLType
.Tags
.float,
12502 IDLType
.Tags
.unrestricted_double
,
12503 IDLType
.Tags
.double
,
12505 # These all use JS_NumberValue, which can return int or double.
12506 # But TI treats "double" as meaning "int or double", so we're
12507 # good to return JSVAL_TYPE_DOUBLE here.
12508 return "JSJitInfo::Double"
12509 if tag
!= IDLType
.Tags
.uint32
:
12510 raise TypeError("No idea what type " + str(t
) + " is.")
12511 # uint32 is sometimes int and sometimes double.
12512 return "JSJitInfo::Double"
12515 def getSingleArgType(existingType
, t
):
12516 type = CGMemberJITInfo
.getJSArgType(t
)
12517 if existingType
== "":
12518 # First element of the list; just return its type
12521 if type == existingType
:
12522 return existingType
12523 return "%s | %s" % (existingType
, type)
12526 class CGStaticMethodJitinfo(CGGeneric
):
12528 A class for generating the JITInfo for a promise-returning static method.
12531 def __init__(self
, method
):
12532 CGGeneric
.__init
__(
12535 "static const JSJitInfo %s_methodinfo = {\n"
12536 " { (JSJitGetterOp)%s },\n"
12537 " { prototypes::id::_ID_Count }, { 0 }, JSJitInfo::StaticMethod,\n"
12538 " JSJitInfo::AliasEverything, JSVAL_TYPE_OBJECT, false, false,\n"
12539 " false, false, 0\n"
12542 IDLToCIdentifier(method
.identifier
.name
),
12543 CppKeywords
.checkMethodName(IDLToCIdentifier(method
.identifier
.name
)),
12548 def getEnumValueName(value
):
12549 # Some enum values can be empty strings. Others might have weird
12550 # characters in them. Deal with the former by returning "_empty",
12551 # deal with possible name collisions from that by throwing if the
12552 # enum value is actually "_empty", and throw on any value
12553 # containing non-ASCII chars for now. Replace all chars other than
12554 # [0-9A-Za-z_] with '_'.
12555 if re
.match("[^\x20-\x7E]", value
):
12556 raise SyntaxError('Enum value "' + value
+ '" contains non-ASCII characters')
12557 if re
.match("^[0-9]", value
):
12558 value
= "_" + value
12559 value
= re
.sub(r
"[^0-9A-Za-z_]", "_", value
)
12560 if re
.match("^_[A-Z]|__", value
):
12561 raise SyntaxError('Enum value "' + value
+ '" is reserved by the C++ spec')
12562 if value
== "_empty":
12563 raise SyntaxError('"_empty" is not an IDL enum value we support yet')
12566 return MakeNativeName(value
)
12569 class CGEnumToJSValue(CGAbstractMethod
):
12570 def __init__(self
, enum
):
12571 enumType
= enum
.identifier
.name
12572 self
.stringsArray
= "binding_detail::EnumStrings<" + enumType
+ ">::Values"
12573 CGAbstractMethod
.__init
__(
12579 Argument("JSContext*", "aCx"),
12580 Argument(enumType
, "aArgument"),
12581 Argument("JS::MutableHandle<JS::Value>", "aValue"),
12585 def definition_body(self
):
12588 MOZ_ASSERT(uint32_t(aArgument) < std::size(${strings}));
12589 JSString* resultStr =
12590 JS_NewStringCopyN(aCx, ${strings}[uint32_t(aArgument)].BeginReading(),
12591 ${strings}[uint32_t(aArgument)].Length());
12595 aValue.setString(resultStr);
12598 strings
=self
.stringsArray
,
12602 class CGEnum(CGThing
):
12603 def __init__(self
, enum
):
12604 CGThing
.__init
__(self
)
12606 strings
= CGNamespace(
12611 template <> struct EnumStrings<${name}> {
12612 static constexpr nsLiteralCString Values[${count}] {
12617 name
=self
.enum
.identifier
.name
,
12618 count
=self
.nEnumStrings(),
12619 entries
="".join('"%s"_ns,\n' % val
for val
in self
.enum
.values()),
12623 constexpr nsLiteralCString EnumStrings<${name}>::Values[${count}];
12625 name
=self
.enum
.identifier
.name
,
12626 count
=self
.nEnumStrings(),
12630 toJSValue
= CGEnumToJSValue(enum
)
12631 self
.cgThings
= CGList([strings
, toJSValue
], "\n")
12633 def nEnumStrings(self
):
12634 return len(self
.enum
.values())
12637 def underlyingType(enum
):
12638 count
= len(enum
.values())
12643 raise ValueError("Enum " + enum
.identifier
.name
+ " has more than 65536 values")
12648 enum class ${name} : ${ty} {
12652 name
=self
.enum
.identifier
.name
,
12653 ty
=CGEnum
.underlyingType(self
.enum
),
12654 enums
=",\n".join(map(getEnumValueName
, self
.enum
.values())) + ",\n",
12657 return decl
+ "\n" + self
.cgThings
.declare()
12660 return self
.cgThings
.define()
12663 return self
.enum
.getDeps()
12666 class CGMaxContiguousEnumValue(CGThing
):
12667 def __init__(self
, enum
):
12668 CGThing
.__init
__(self
)
12672 enumValues
= self
.enum
.values()
12676 struct MaxContiguousEnumValue<dom::${name}>
12678 static constexpr dom::${name} value = dom::${name}::${maxValue};
12680 static_assert(static_cast<${ty}>(dom::${name}::${minValue}) == 0,
12681 "We rely on this in ContiguousEnumValues");
12682 static_assert(std::size(dom::binding_detail::EnumStrings<dom::${name}>::Values) - 1 == UnderlyingValue(value),
12683 "Mismatch between enum strings and enum count");
12686 name
=self
.enum
.identifier
.name
,
12687 ty
=CGEnum
.underlyingType(self
.enum
),
12688 maxValue
=getEnumValueName(enumValues
[-1]),
12689 minValue
=getEnumValueName(enumValues
[0]),
12696 return self
.enum
.getDeps()
12699 def getUnionAccessorSignatureType(type, descriptorProvider
):
12701 Returns the types that are used in the getter and setter signatures for
12704 # Flat member types have already unwrapped nullables.
12705 assert not type.nullable()
12707 # Promise types can never appear in unions, because Promise is not
12708 # distinguishable from anything.
12709 assert not type.isPromise()
12711 if type.isSequence() or type.isRecord():
12712 if type.isSequence():
12713 wrapperType
= "Sequence"
12715 wrapperType
= "Record"
12716 # We don't use the returned template here, so it's OK to just pass no
12717 # sourceDescription.
12718 elementInfo
= getJSToNativeConversionInfo(
12719 type.inner
, descriptorProvider
, isMember
=wrapperType
12721 if wrapperType
== "Sequence":
12722 innerType
= elementInfo
.declType
12724 innerType
= [recordKeyDeclType(type), elementInfo
.declType
]
12726 return CGTemplatedType(wrapperType
, innerType
, isConst
=True, isReference
=True)
12728 # Nested unions are unwrapped automatically into our flatMemberTypes.
12729 assert not type.isUnion()
12731 if type.isGeckoInterface():
12732 descriptor
= descriptorProvider
.getDescriptor(
12733 type.unroll().inner
.identifier
.name
12735 typeName
= CGGeneric(descriptor
.nativeType
)
12736 if not type.unroll().inner
.isExternal():
12737 typeName
= CGWrapper(typeName
, post
="&")
12738 elif descriptor
.interface
.identifier
.name
== "WindowProxy":
12739 typeName
= CGGeneric("WindowProxyHolder const&")
12741 # Allow null pointers for old-binding classes.
12742 typeName
= CGWrapper(typeName
, post
="*")
12745 if type.isSpiderMonkeyInterface():
12746 typeName
= CGGeneric(type.name
)
12747 return CGWrapper(typeName
, post
=" const &")
12749 if type.isJSString():
12750 raise TypeError("JSString not supported in unions")
12752 if type.isDOMString() or type.isUSVString():
12753 return CGGeneric("const nsAString&")
12755 if type.isUTF8String():
12756 return CGGeneric("const nsACString&")
12758 if type.isByteString():
12759 return CGGeneric("const nsCString&")
12762 return CGGeneric(type.inner
.identifier
.name
)
12764 if type.isCallback():
12765 return CGGeneric("%s&" % type.unroll().callback
.identifier
.name
)
12768 return CGGeneric("JS::Value")
12770 if type.isObject():
12771 return CGGeneric("JSObject*")
12773 if type.isDictionary():
12774 return CGGeneric("const %s&" % type.inner
.identifier
.name
)
12776 if not type.isPrimitive():
12777 raise TypeError("Need native type for argument type '%s'" % str(type))
12779 return CGGeneric(builtinNames
[type.tag()])
12782 def getUnionTypeTemplateVars(unionType
, type, descriptorProvider
, isMember
=False):
12783 assert not type.isUndefined()
12784 assert not isMember
or isMember
in ("Union", "OwningUnion")
12786 ownsMembers
= isMember
== "OwningUnion"
12787 name
= getUnionMemberName(type)
12788 holderName
= "m" + name
+ "Holder"
12790 # By the time tryNextCode is invoked, we're guaranteed the union has been
12791 # constructed as some type, since we've been trying to convert into the
12792 # corresponding member.
12793 tryNextCode
= fill(
12802 sourceDescription
= "%s branch of %s" % (type.prettyName(), unionType
.prettyName())
12804 conversionInfo
= getJSToNativeConversionInfo(
12806 descriptorProvider
,
12807 failureCode
=tryNextCode
,
12808 isDefinitelyObject
=not type.isDictionary(),
12810 sourceDescription
=sourceDescription
,
12813 ctorNeedsCx
= conversionInfo
.declArgs
== "cx"
12814 ctorArgs
= "cx" if ctorNeedsCx
else ""
12816 structType
= conversionInfo
.declType
.define()
12817 externalType
= getUnionAccessorSignatureType(type, descriptorProvider
).define()
12819 if type.isObject():
12821 setValue
= "mValue.mObject.SetValue(obj);"
12823 setValue
= "mValue.mObject.SetValue(cx, obj);"
12827 MOZ_ASSERT(mType == eUninitialized);
12834 # It's a bit sketchy to do the security check after setting the value,
12835 # but it keeps the code cleaner and lets us avoid rooting |obj| over the
12836 # call to CallerSubsumes().
12837 body
= body
+ fill(
12839 if (passedToJSImpl && !CallerSubsumes(obj)) {
12840 cx.ThrowErrorMessage<MSG_PERMISSION_DENIED_TO_PASS_ARG>("${sourceDescription}");
12845 sourceDescription
=sourceDescription
,
12853 Argument("BindingCallContext&", "cx"),
12854 Argument("JSObject*", "obj"),
12855 Argument("bool", "passedToJSImpl", default
="false"),
12862 elif type.isDictionary() and not type.inner
.needsConversionFromJS
:
12863 # In this case we are never initialized from JS to start with
12866 # Important: we need to not have our declName involve
12867 # maybe-GCing operations.
12868 jsConversion
= fill(
12869 conversionInfo
.template
,
12871 maybeMutableVal
="value",
12872 declName
="memberSlot",
12873 holderName
=(holderName
if ownsMembers
else "%s.ref()" % holderName
),
12874 passedToJSImpl
="passedToJSImpl",
12877 jsConversion
= fill(
12880 { // scope for memberSlot
12881 ${structType}& memberSlot = RawSetAs${name}(${ctorArgs});
12886 structType
=structType
,
12889 jsConversion
=jsConversion
,
12892 needCallContext
= idlTypeNeedsCallContext(type)
12893 if needCallContext
:
12894 cxType
= "BindingCallContext&"
12896 cxType
= "JSContext*"
12902 Argument(cxType
, "cx"),
12903 Argument("JS::Handle<JS::Value>", "value"),
12904 Argument("bool&", "tryNext"),
12905 Argument("bool", "passedToJSImpl", default
="false"),
12907 visibility
="private",
12911 if needCallContext
:
12912 # Add a method for non-binding uses of unions to allow them to set
12913 # things in the union without providing a call context (though if
12914 # they want good error reporting they'll provide one anyway).
12917 BindingCallContext cx(cx_, nullptr);
12918 return TrySetTo${name}(cx, value, tryNext, passedToJSImpl);
12927 Argument("JSContext*", "cx_"),
12928 Argument("JS::Handle<JS::Value>", "value"),
12929 Argument("bool&", "tryNext"),
12930 Argument("bool", "passedToJSImpl", default
="false"),
12932 visibility
="private",
12939 "structType": structType
,
12940 "externalType": externalType
,
12941 "setters": setters
,
12942 "ctorArgs": ctorArgs
,
12943 "ctorArgList": [Argument("JSContext*", "cx")] if ctorNeedsCx
else [],
12947 def getUnionConversionTemplate(type):
12948 assert type.isUnion()
12949 assert not type.nullable()
12951 memberTypes
= type.flatMemberTypes
12954 interfaceMemberTypes
= [t
for t
in memberTypes
if t
.isNonCallbackInterface()]
12955 if len(interfaceMemberTypes
) > 0:
12956 interfaceObject
= []
12957 for memberType
in interfaceMemberTypes
:
12958 name
= getUnionMemberName(memberType
)
12959 interfaceObject
.append(
12961 "(failed = !TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext"
12965 prettyNames
.append(memberType
.prettyName())
12966 interfaceObject
= CGWrapper(
12967 CGList(interfaceObject
, " ||\n"),
12973 interfaceObject
= None
12975 sequenceObjectMemberTypes
= [t
for t
in memberTypes
if t
.isSequence()]
12976 if len(sequenceObjectMemberTypes
) > 0:
12977 assert len(sequenceObjectMemberTypes
) == 1
12978 memberType
= sequenceObjectMemberTypes
[0]
12979 name
= getUnionMemberName(memberType
)
12980 sequenceObject
= CGGeneric(
12981 "done = (failed = !TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n"
12984 prettyNames
.append(memberType
.prettyName())
12986 sequenceObject
= None
12988 callbackMemberTypes
= [
12989 t
for t
in memberTypes
if t
.isCallback() or t
.isCallbackInterface()
12991 if len(callbackMemberTypes
) > 0:
12992 assert len(callbackMemberTypes
) == 1
12993 memberType
= callbackMemberTypes
[0]
12994 name
= getUnionMemberName(memberType
)
12995 callbackObject
= CGGeneric(
12996 "done = (failed = !TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n"
12999 prettyNames
.append(memberType
.prettyName())
13001 callbackObject
= None
13003 dictionaryMemberTypes
= [t
for t
in memberTypes
if t
.isDictionary()]
13004 if len(dictionaryMemberTypes
) > 0:
13005 assert len(dictionaryMemberTypes
) == 1
13006 memberType
= dictionaryMemberTypes
[0]
13007 name
= getUnionMemberName(memberType
)
13008 setDictionary
= CGGeneric(
13009 "done = (failed = !TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n"
13012 prettyNames
.append(memberType
.prettyName())
13014 setDictionary
= None
13016 recordMemberTypes
= [t
for t
in memberTypes
if t
.isRecord()]
13017 if len(recordMemberTypes
) > 0:
13018 assert len(recordMemberTypes
) == 1
13019 memberType
= recordMemberTypes
[0]
13020 name
= getUnionMemberName(memberType
)
13021 recordObject
= CGGeneric(
13022 "done = (failed = !TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n"
13025 prettyNames
.append(memberType
.prettyName())
13027 recordObject
= None
13029 objectMemberTypes
= [t
for t
in memberTypes
if t
.isObject()]
13030 if len(objectMemberTypes
) > 0:
13031 assert len(objectMemberTypes
) == 1
13032 # Very important to NOT construct a temporary Rooted here, since the
13033 # SetToObject call can call a Rooted constructor and we need to keep
13034 # stack discipline for Rooted.
13035 object = CGGeneric(
13036 "if (!SetToObject(cx, &${val}.toObject(), ${passedToJSImpl})) {\n"
13041 prettyNames
.append(objectMemberTypes
[0].prettyName())
13046 interfaceObject
or sequenceObject
or callbackObject
or object or recordObject
13049 # "object" is not distinguishable from other types
13050 assert not object or not (
13051 interfaceObject
or sequenceObject
or callbackObject
or recordObject
13053 if sequenceObject
or callbackObject
:
13054 # An object can be both an sequence object and a callback or
13055 # dictionary, but we shouldn't have both in the union's members
13056 # because they are not distinguishable.
13057 assert not (sequenceObject
and callbackObject
)
13058 templateBody
= CGElseChain([sequenceObject
, callbackObject
])
13060 templateBody
= None
13061 if interfaceObject
:
13064 templateBody
= CGIfWrapper(templateBody
, "!done")
13065 templateBody
= CGList([interfaceObject
, templateBody
])
13067 templateBody
= CGList([templateBody
, object])
13070 templateBody
= CGList([templateBody
, CGIfWrapper(recordObject
, "!done")])
13072 templateBody
= CGIfWrapper(templateBody
, "${val}.isObject()")
13074 templateBody
= CGGeneric()
13078 templateBody
= CGList([templateBody
, CGIfWrapper(setDictionary
, "!done")])
13080 stringTypes
= [t
for t
in memberTypes
if t
.isString() or t
.isEnum()]
13081 numericTypes
= [t
for t
in memberTypes
if t
.isNumeric()]
13082 booleanTypes
= [t
for t
in memberTypes
if t
.isBoolean()]
13083 if stringTypes
or numericTypes
or booleanTypes
:
13084 assert len(stringTypes
) <= 1
13085 assert len(numericTypes
) <= 1
13086 assert len(booleanTypes
) <= 1
13088 # We will wrap all this stuff in a do { } while (0); so we
13089 # can use "break" for flow control.
13090 def getStringOrPrimitiveConversion(memberType
):
13091 name
= getUnionMemberName(memberType
)
13093 "done = (failed = !TrySetTo%s(cx, ${val}, tryNext)) || !tryNext;\n"
13098 stringConversion
= [getStringOrPrimitiveConversion(t
) for t
in stringTypes
]
13099 numericConversion
= [getStringOrPrimitiveConversion(t
) for t
in numericTypes
]
13100 booleanConversion
= [getStringOrPrimitiveConversion(t
) for t
in booleanTypes
]
13101 if stringConversion
:
13102 if booleanConversion
:
13103 other
.append(CGIfWrapper(booleanConversion
[0], "${val}.isBoolean()"))
13104 if numericConversion
:
13105 other
.append(CGIfWrapper(numericConversion
[0], "${val}.isNumber()"))
13106 other
.append(stringConversion
[0])
13107 elif numericConversion
:
13108 if booleanConversion
:
13109 other
.append(CGIfWrapper(booleanConversion
[0], "${val}.isBoolean()"))
13110 other
.append(numericConversion
[0])
13112 assert booleanConversion
13113 other
.append(booleanConversion
[0])
13115 other
= CGWrapper(CGIndenter(other
), pre
="do {\n", post
="} while (false);\n")
13116 if hasObjectTypes
or setDictionary
:
13117 other
= CGWrapper(CGIndenter(other
), "{\n", post
="}\n")
13119 templateBody
= CGElseChain([templateBody
, other
])
13121 other
= CGWrapper(other
, pre
="if (!done) ")
13122 templateBody
= CGList([templateBody
, other
])
13124 assert templateBody
.define() == ""
13125 templateBody
= other
13129 templateBody
= CGWrapper(
13130 templateBody
, pre
="bool done = false, failed = false, tryNext;\n"
13139 cx.ThrowErrorMessage<MSG_NOT_IN_UNION>(sourceDescription, "${names}");
13143 names
=", ".join(prettyNames
),
13147 templateBody
= CGList([templateBody
, throw
])
13149 hasUndefinedType
= any(t
.isUndefined() for t
in memberTypes
)
13152 # The spec does this before anything else, but we do it after checking
13153 # for null in the case of a nullable union. In practice this shouldn't
13154 # make a difference, but it makes things easier because we first need to
13155 # call Construct on our Maybe<...>, before we can set the union type to
13156 # undefined, and we do that below after checking for null (see the
13157 # 'if nullable:' block below).
13158 if hasUndefinedType
:
13161 CGGeneric("SetUndefined();\n"),
13162 "${val}.isUndefined()",
13166 if type.hasNullableType
:
13168 "${val}.isNull()" if hasUndefinedType
else "${val}.isNullOrUndefined()"
13172 CGGeneric("SetNull();\n"),
13177 if len(elseChain
) > 0:
13178 elseChain
.append(CGWrapper(CGIndenter(templateBody
), pre
="{\n", post
="}\n"))
13179 templateBody
= CGElseChain(elseChain
)
13181 return templateBody
13184 def getUnionInitMethods(type, isOwningUnion
=False):
13185 assert type.isUnion()
13187 template
= getUnionConversionTemplate(type).define()
13191 "passedToJSImpl": "passedToJSImpl",
13196 MOZ_ASSERT(mType == eUninitialized);
13201 conversion
=string
.Template(template
).substitute(replacements
),
13209 Argument("BindingCallContext&", "cx"),
13210 Argument("JS::Handle<JS::Value>", "value"),
13211 Argument("const char*", "sourceDescription", default
='"Value"'),
13212 Argument("bool", "passedToJSImpl", default
="false"),
13214 visibility
="public",
13221 Argument("JSContext*", "cx_"),
13222 Argument("JS::Handle<JS::Value>", "value"),
13223 Argument("const char*", "sourceDescription", default
='"Value"'),
13224 Argument("bool", "passedToJSImpl", default
="false"),
13226 visibility
="public",
13229 BindingCallContext cx(cx_, nullptr);
13230 return Init(cx, value, sourceDescription, passedToJSImpl);
13237 class CGUnionStruct(CGThing
):
13238 def __init__(self
, type, descriptorProvider
, ownsMembers
=False):
13239 CGThing
.__init
__(self
)
13240 self
.type = type.unroll()
13241 self
.descriptorProvider
= descriptorProvider
13242 self
.ownsMembers
= ownsMembers
13243 self
.struct
= self
.getStruct()
13246 return self
.struct
.declare()
13249 return self
.struct
.define()
13252 return self
.type.getDeps()
13254 def getStruct(self
):
13256 ClassMember("mType", "TypeOrUninit", body
="eUninitialized"),
13257 ClassMember("mValue", "Value"),
13259 ctor
= ClassConstructor(
13260 [], bodyInHeader
=True, visibility
="public", explicit
=True
13264 enumValues
= ["eUninitialized"]
13267 "eUninitialized", CGGeneric("return false;\n"), CGCase
.DONT_ADD_BREAK
13270 destructorCases
= [CGCase("eUninitialized", None)]
13271 assignmentCase
= CGCase(
13274 "MOZ_ASSERT(mType == eUninitialized,\n"
13275 ' "We need to destroy ourselves?");\n'
13278 assignmentCases
= [assignmentCase
]
13279 moveCases
= [assignmentCase
]
13283 def addSpecialType(typename
):
13284 enumValue
= "e" + typename
13285 enumValues
.append(enumValue
)
13293 body
="return mType == %s;\n" % enumValue
,
13306 mType = ${enumValue};
13308 enumValue
=enumValue
,
13313 destructorCases
.append(CGCase(enumValue
, None))
13314 assignmentCase
= CGCase(
13319 MOZ_ASSERT(mType == eUninitialized);
13320 mType = ${enumValue};
13322 enumValue
=enumValue
,
13326 assignmentCases
.append(assignmentCase
)
13327 moveCases
.append(assignmentCase
)
13328 toJSValCases
.append(
13334 rval.set${typename}();
13340 CGCase
.DONT_ADD_BREAK
,
13344 if self
.type.hasNullableType
:
13345 addSpecialType("Null")
13347 hasObjectType
= any(t
.isObject() for t
in self
.type.flatMemberTypes
)
13348 skipToJSVal
= False
13349 for t
in self
.type.flatMemberTypes
:
13350 if t
.isUndefined():
13351 addSpecialType("Undefined")
13354 vars = getUnionTypeTemplateVars(
13357 self
.descriptorProvider
,
13358 isMember
="OwningUnion" if self
.ownsMembers
else "Union",
13360 if vars["setters"]:
13361 methods
.extend(vars["setters"])
13362 uninit
= "Uninit();"
13363 if hasObjectType
and not self
.ownsMembers
:
13365 'MOZ_ASSERT(mType != eObject, "This will not play well with Rooted");\n'
13368 if not t
.isObject() or self
.ownsMembers
:
13371 if (mType == e${name}) {
13372 return mValue.m${name}.Value();
13376 return mValue.m${name}.SetValue(${ctorArgs});
13381 # bodyInHeader must be false for return values because they own
13382 # their union members and we don't want include headers in
13383 # UnionTypes.h just to call Addref/Release
13386 "RawSetAs" + vars["name"],
13387 vars["structType"] + "&",
13388 vars["ctorArgList"],
13389 bodyInHeader
=not self
.ownsMembers
,
13390 body
=body
% "MOZ_ASSERT(mType == eUninitialized);",
13396 "SetAs" + vars["name"],
13397 vars["structType"] + "&",
13398 vars["ctorArgList"],
13399 bodyInHeader
=not self
.ownsMembers
,
13400 body
=body
% uninit
,
13405 # Provide a SetStringLiteral() method to support string defaults.
13406 if t
.isByteString() or t
.isUTF8String():
13407 charType
= "const nsCString::char_type"
13409 charType
= "const nsString::char_type"
13416 "SetStringLiteral",
13418 # Hack, but it works...
13419 [Argument(charType
, "(&aData)[N]")],
13422 templateArgs
=["int N"],
13423 body
="RawSetAs%s().AssignLiteral(aData);\n" % t
.name
,
13427 body
= fill("return mType == e${name};\n", **vars)
13430 "Is" + vars["name"],
13441 MOZ_RELEASE_ASSERT(Is${name}(), "Wrong type!");
13442 mValue.m${name}.Destroy();
13443 mType = eUninitialized;
13449 "Destroy" + vars["name"],
13452 visibility
="private",
13453 bodyInHeader
=not self
.ownsMembers
,
13460 MOZ_RELEASE_ASSERT(Is${name}(), "Wrong type!");
13461 return mValue.m${name}.Value();
13465 # The non-const version of GetAs* returns our internal type
13466 getterReturnType
= "%s&" % vars["structType"]
13469 "GetAs" + vars["name"],
13476 # The const version of GetAs* returns our internal type
13477 # for owning unions, but our external type for non-owning
13479 if self
.ownsMembers
:
13480 getterReturnType
= "%s const &" % vars["structType"]
13482 getterReturnType
= vars["externalType"]
13485 "GetAs" + vars["name"],
13494 unionValues
.append(fill("UnionMember<${structType} > m${name}", **vars))
13495 destructorCases
.append(
13496 CGCase("e" + vars["name"], CGGeneric("Destroy%s();\n" % vars["name"]))
13499 enumValues
.append("e" + vars["name"])
13501 conversionToJS
= self
.getConversionToJS(vars, t
)
13503 toJSValCases
.append(
13504 CGCase("e" + vars["name"], conversionToJS
, CGCase
.DONT_ADD_BREAK
)
13509 assignmentCases
.append(
13511 "e" + vars["name"],
13513 "SetAs%s() = aOther.GetAs%s();\n" % (vars["name"], vars["name"])
13519 "e" + vars["name"],
13521 "mType = e%s;\n" % vars["name"]
13522 + "mValue.m%s.SetValue(std::move(aOther.mValue.m%s.Value()));\n"
13523 % (vars["name"], vars["name"])
13527 if self
.ownsMembers
and typeNeedsRooting(t
):
13531 "e" + vars["name"],
13533 'JS::TraceRoot(trc, %s, "%s");\n'
13535 "&mValue.m" + vars["name"] + ".Value()",
13536 "mValue.m" + vars["name"],
13541 elif t
.isDictionary():
13544 "e" + vars["name"],
13546 "mValue.m%s.Value().TraceDictionary(trc);\n"
13551 elif t
.isSequence():
13554 "e" + vars["name"],
13556 "DoTraceSequence(trc, mValue.m%s.Value());\n"
13564 "e" + vars["name"],
13566 "TraceRecord(trc, mValue.m%s.Value());\n" % vars["name"]
13571 assert t
.isSpiderMonkeyInterface()
13574 "e" + vars["name"],
13576 "mValue.m%s.Value().TraceSelf(trc);\n" % vars["name"]
13581 dtor
= CGSwitch("mType", destructorCases
).define()
13583 methods
.extend(getUnionInitMethods(self
.type, isOwningUnion
=self
.ownsMembers
))
13589 visibility
="public",
13591 bodyInHeader
=not self
.ownsMembers
,
13592 inline
=not self
.ownsMembers
,
13596 if not skipToJSVal
:
13602 Argument("JSContext*", "cx"),
13603 Argument("JS::Handle<JSObject*>", "scopeObj"),
13604 Argument("JS::MutableHandle<JS::Value>", "rval"),
13607 "mType", toJSValCases
, default
=CGGeneric("return false;\n")
13613 constructors
= [ctor
]
13614 selfName
= CGUnionStruct
.unionTypeName(self
.type, self
.ownsMembers
)
13615 if self
.ownsMembers
:
13617 traceBody
= CGSwitch(
13618 "mType", traceCases
, default
=CGGeneric("")
13624 [Argument("JSTracer*", "trc")],
13629 op_body
= CGList([])
13630 op_body
.append(CGSwitch("aOther.mType", moveCases
))
13631 constructors
.append(
13633 [Argument("%s&&" % selfName
, "aOther")],
13634 visibility
="public",
13635 body
=op_body
.define(),
13643 [Argument("%s&&" % selfName
, "aOther")],
13644 body
="this->~%s();\nnew (this) %s (std::move(aOther));\nreturn *this;\n"
13645 % (selfName
, selfName
),
13651 MOZ_RELEASE_ASSERT(mType != eUninitialized);
13652 return static_cast<Type>(mType);
13666 if CGUnionStruct
.isUnionCopyConstructible(self
.type):
13667 constructors
.append(
13669 [Argument("const %s&" % selfName
, "aOther")],
13671 visibility
="public",
13673 body
="*this = aOther;\n",
13676 op_body
= CGList([])
13677 op_body
.append(CGSwitch("aOther.mType", assignmentCases
))
13678 op_body
.append(CGGeneric("return *this;\n"))
13683 [Argument("const %s&" % selfName
, "aOther")],
13684 body
=op_body
.define(),
13687 disallowCopyConstruction
= False
13689 disallowCopyConstruction
= True
13691 disallowCopyConstruction
= True
13693 if self
.ownsMembers
and idlTypeNeedsCycleCollection(self
.type):
13695 " friend void ImplCycleCollectionUnlink(%s& aUnion);\n"
13696 % CGUnionStruct
.unionTypeName(self
.type, True)
13701 enumValuesNoUninit
= [x
for x
in enumValues
if x
!= "eUninitialized"]
13706 ClassEnum("TypeOrUninit", enumValues
, visibility
="private"),
13709 enumValuesNoUninit
,
13710 visibility
="public",
13712 values
=["TypeOrUninit::" + x
for x
in enumValuesNoUninit
],
13719 ClassBase("AllOwningUnionBase" if self
.ownsMembers
else "AllUnionBase")
13723 bufferSourceTypes
= [
13724 t
.name
for t
in self
.type.flatMemberTypes
if t
.isBufferSource()
13726 if len(bufferSourceTypes
) > 0:
13727 bases
.append(ClassBase("UnionWithTypedArraysBase"))
13728 memberTypesCount
= len(self
.type.flatMemberTypes
)
13729 if self
.type.hasNullableType
:
13730 memberTypesCount
+= 1
13733 ClassUsingDeclaration(
13734 "ApplyToTypedArrays",
13735 "binding_detail::ApplyToTypedArraysHelper<%s, %s, %s>"
13738 toStringBool(memberTypesCount
> len(bufferSourceTypes
)),
13739 ", ".join(bufferSourceTypes
),
13747 typeAliases
=typeAliases
,
13749 constructors
=constructors
,
13751 disallowCopyConstruction
=disallowCopyConstruction
,
13752 extradeclarations
=friend
,
13753 destructor
=ClassDestructor(
13754 visibility
="public", body
="Uninit();\n", bodyInHeader
=True
13757 unions
=[ClassUnion("Value", unionValues
, visibility
="private")],
13760 def getConversionToJS(self
, templateVars
, type):
13761 if type.isDictionary() and not type.inner
.needsConversionToJS
:
13762 # We won't be able to convert this dictionary to a JS value, nor
13763 # will we need to, since we don't need a ToJSVal method at all.
13766 assert not type.nullable() # flatMemberTypes never has nullable types
13767 val
= "mValue.m%(name)s.Value()" % templateVars
13768 wrapCode
= wrapForType(
13770 self
.descriptorProvider
,
13772 "jsvalRef": "rval",
13773 "jsvalHandle": "rval",
13776 "spiderMonkeyInterfacesAreStructs": True,
13779 return CGGeneric(wrapCode
)
13782 def isUnionCopyConstructible(type):
13783 return all(isTypeCopyConstructible(t
) for t
in type.flatMemberTypes
)
13786 def unionTypeName(type, ownsMembers
):
13788 Returns a string name for this known union type.
13790 assert type.isUnion() and not type.nullable()
13791 return ("Owning" if ownsMembers
else "") + type.name
13794 def unionTypeDecl(type, ownsMembers
):
13796 Returns a string for declaring this possibly-nullable union type.
13798 assert type.isUnion()
13799 nullable
= type.nullable()
13802 decl
= CGGeneric(CGUnionStruct
.unionTypeName(type, ownsMembers
))
13804 decl
= CGTemplatedType("Nullable", decl
)
13805 return decl
.define()
13809 """Use with CGClass"""
13811 def __init__(self
, name
, visibility
):
13813 self
.visibility
= visibility
13815 def declare(self
, cgClass
):
13818 def define(self
, cgClass
):
13822 class ClassBase(ClassItem
):
13823 def __init__(self
, name
, visibility
="public"):
13824 ClassItem
.__init
__(self
, name
, visibility
)
13826 def declare(self
, cgClass
):
13827 return "%s %s" % (self
.visibility
, self
.name
)
13829 def define(self
, cgClass
):
13830 # Only in the header
13834 class ClassMethod(ClassItem
):
13844 bodyInHeader
=False,
13846 visibility
="public",
13848 breakAfterReturnDecl
="\n",
13849 breakAfterSelf
="\n",
13851 canRunScript
=False,
13856 override indicates whether to flag the method as override
13858 assert not override
or virtual
13859 assert not (override
and static
)
13860 assert not (delete
and body
)
13861 self
.returnType
= returnType
13863 self
.inline
= inline
or bodyInHeader
13864 self
.static
= static
13865 self
.virtual
= virtual
13867 self
.bodyInHeader
= bodyInHeader
13868 self
.templateArgs
= templateArgs
13870 self
.breakAfterReturnDecl
= breakAfterReturnDecl
13871 self
.breakAfterSelf
= breakAfterSelf
13872 self
.override
= override
13873 self
.canRunScript
= canRunScript
13874 self
.noDiscard
= noDiscard
13875 self
.delete
= delete
13876 ClassItem
.__init
__(self
, name
, visibility
)
13878 def getDecorators(self
, declaring
):
13881 decorators
.append("[[nodiscard]]")
13882 if self
.canRunScript
:
13883 decorators
.append("MOZ_CAN_RUN_SCRIPT")
13885 decorators
.append("inline")
13888 decorators
.append("static")
13889 if self
.virtual
and not self
.override
:
13890 decorators
.append("virtual")
13892 return " ".join(decorators
) + " "
13896 # Override me or pass a string to constructor
13897 assert self
.body
is not None
13900 def declare(self
, cgClass
):
13902 "template <%s>\n" % ", ".join(self
.templateArgs
)
13903 if self
.bodyInHeader
and self
.templateArgs
13906 args
= ", ".join([a
.declare() for a
in self
.args
])
13908 body
= " = delete;\n"
13909 elif self
.bodyInHeader
:
13910 body
= indent(self
.getBody())
13911 body
= "\n{\n" + body
+ "}\n"
13916 "${templateClause}${decorators}${returnType}${breakAfterReturnDecl}"
13917 "${name}(${args})${const}${override}${body}"
13918 "${breakAfterSelf}",
13919 templateClause
=templateClause
,
13920 decorators
=self
.getDecorators(True),
13921 returnType
=self
.returnType
,
13922 breakAfterReturnDecl
=self
.breakAfterReturnDecl
,
13925 const
=" const" if self
.const
else "",
13926 override
=" override" if self
.override
else "",
13928 breakAfterSelf
=self
.breakAfterSelf
,
13931 def define(self
, cgClass
):
13932 if self
.delete
or self
.bodyInHeader
:
13935 templateArgs
= cgClass
.templateArgs
13937 if cgClass
.templateSpecialization
:
13938 templateArgs
= templateArgs
[len(cgClass
.templateSpecialization
) :]
13941 templateClause
= "template <%s>\n" % ", ".join(
13942 [str(a
) for a
in templateArgs
]
13945 templateClause
= ""
13949 ${templateClause}${decorators}${returnType}
13950 ${className}::${name}(${args})${const}
13955 templateClause
=templateClause
,
13956 decorators
=self
.getDecorators(False),
13957 returnType
=self
.returnType
,
13958 className
=cgClass
.getNameString(),
13960 args
=", ".join([a
.define() for a
in self
.args
]),
13961 const
=" const" if self
.const
else "",
13962 body
=self
.getBody(),
13966 class ClassUsingDeclaration(ClassItem
):
13968 Used for declaring an alias for a type in a CGClass
13970 name is the name of the alias
13972 type is the type to declare an alias of
13974 visibility determines the visibility of the alias (public,
13975 protected, private), defaults to public.
13978 def __init__(self
, name
, type, visibility
="public"):
13980 ClassItem
.__init
__(self
, name
, visibility
)
13982 def declare(self
, cgClass
):
13983 return "using %s = %s;\n\n" % (self
.name
, self
.type)
13985 def define(self
, cgClass
):
13989 class ClassUsingFromBaseDeclaration(ClassItem
):
13991 Used for importing a name from a base class into a CGClass
13993 baseClass is the name of the base class to import the name from
13995 name is the name to import
13997 visibility determines the visibility of the name (public,
13998 protected, private), defaults to public.
14001 def __init__(self
, baseClass
, name
, visibility
="public"):
14002 self
.baseClass
= baseClass
14003 ClassItem
.__init
__(self
, name
, visibility
)
14005 def declare(self
, cgClass
):
14006 return "using %s::%s;\n\n" % (self
.baseClass
, self
.name
)
14008 def define(self
, cgClass
):
14012 class ClassConstructor(ClassItem
):
14014 Used for adding a constructor to a CGClass.
14016 args is a list of Argument objects that are the arguments taken by the
14019 inline should be True if the constructor should be marked inline.
14021 bodyInHeader should be True if the body should be placed in the class
14022 declaration in the header.
14024 default should be True if the definition of the constructor should be
14027 visibility determines the visibility of the constructor (public,
14028 protected, private), defaults to private.
14030 explicit should be True if the constructor should be marked explicit.
14032 baseConstructors is a list of strings containing calls to base constructors,
14035 body contains a string with the code for the constructor, defaults to empty.
14042 bodyInHeader
=False,
14044 visibility
="private",
14047 baseConstructors
=None,
14050 assert not (inline
and constexpr
)
14051 assert not (bodyInHeader
and constexpr
)
14052 assert not (default
and body
)
14054 self
.inline
= inline
or bodyInHeader
14055 self
.bodyInHeader
= bodyInHeader
or constexpr
or default
14056 self
.default
= default
14057 self
.explicit
= explicit
14058 self
.constexpr
= constexpr
14059 self
.baseConstructors
= baseConstructors
or []
14061 ClassItem
.__init
__(self
, None, visibility
)
14063 def getDecorators(self
, declaring
):
14067 decorators
.append("explicit")
14069 decorators
.append("inline")
14071 decorators
.append("constexpr")
14073 return " ".join(decorators
) + " "
14076 def getInitializationList(self
, cgClass
):
14077 items
= [str(c
) for c
in self
.baseConstructors
]
14078 for m
in cgClass
.members
:
14080 initialize
= m
.body
14082 items
.append(m
.name
+ "(" + initialize
+ ")")
14085 return "\n : " + ",\n ".join(items
)
14091 def declare(self
, cgClass
):
14092 args
= ", ".join([a
.declare() for a
in self
.args
])
14093 if self
.bodyInHeader
:
14095 body
= " = default;\n"
14098 self
.getInitializationList(cgClass
)
14100 + indent(self
.getBody())
14107 "${decorators}${className}(${args})${body}\n",
14108 decorators
=self
.getDecorators(True),
14109 className
=cgClass
.getNameString(),
14114 def define(self
, cgClass
):
14115 if self
.bodyInHeader
:
14121 ${className}::${className}(${args})${initializationList}
14126 decorators
=self
.getDecorators(False),
14127 className
=cgClass
.getNameString(),
14128 args
=", ".join([a
.define() for a
in self
.args
]),
14129 initializationList
=self
.getInitializationList(cgClass
),
14130 body
=self
.getBody(),
14134 class ClassDestructor(ClassItem
):
14136 Used for adding a destructor to a CGClass.
14138 inline should be True if the destructor should be marked inline.
14140 bodyInHeader should be True if the body should be placed in the class
14141 declaration in the header.
14143 visibility determines the visibility of the destructor (public,
14144 protected, private), defaults to private.
14146 body contains a string with the code for the destructor, defaults to empty.
14148 virtual determines whether the destructor is virtual, defaults to False.
14154 bodyInHeader
=False,
14155 visibility
="private",
14159 self
.inline
= inline
or bodyInHeader
14160 self
.bodyInHeader
= bodyInHeader
14162 self
.virtual
= virtual
14163 ClassItem
.__init
__(self
, None, visibility
)
14165 def getDecorators(self
, declaring
):
14167 if self
.virtual
and declaring
:
14168 decorators
.append("virtual")
14169 if self
.inline
and declaring
:
14170 decorators
.append("inline")
14172 return " ".join(decorators
) + " "
14178 def declare(self
, cgClass
):
14179 if self
.bodyInHeader
:
14180 body
= "\n{\n" + indent(self
.getBody()) + "}\n"
14185 "${decorators}~${className}()${body}\n",
14186 decorators
=self
.getDecorators(True),
14187 className
=cgClass
.getNameString(),
14191 def define(self
, cgClass
):
14192 if self
.bodyInHeader
:
14197 ${className}::~${className}()
14202 decorators
=self
.getDecorators(False),
14203 className
=cgClass
.getNameString(),
14204 body
=self
.getBody(),
14208 class ClassMember(ClassItem
):
14213 visibility
="private",
14216 hasIgnoreInitCheckFlag
=False,
14219 self
.static
= static
14221 self
.hasIgnoreInitCheckFlag
= hasIgnoreInitCheckFlag
14222 ClassItem
.__init
__(self
, name
, visibility
)
14224 def declare(self
, cgClass
):
14225 return "%s%s%s %s;\n" % (
14226 "static " if self
.static
else "",
14227 "MOZ_INIT_OUTSIDE_CTOR " if self
.hasIgnoreInitCheckFlag
else "",
14232 def define(self
, cgClass
):
14233 if not self
.static
:
14236 body
= " = " + self
.body
14239 return "%s %s::%s%s;\n" % (self
.type, cgClass
.getNameString(), self
.name
, body
)
14242 class ClassEnum(ClassItem
):
14244 self
, name
, entries
, values
=None, visibility
="public", enumClass
=False
14246 self
.entries
= entries
14247 self
.values
= values
14248 self
.enumClass
= enumClass
14249 ClassItem
.__init
__(self
, name
, visibility
)
14251 def declare(self
, cgClass
):
14253 for i
in range(0, len(self
.entries
)):
14254 if not self
.values
or i
>= len(self
.values
):
14255 entry
= "%s" % self
.entries
[i
]
14257 entry
= "%s = %s" % (self
.entries
[i
], self
.values
[i
])
14258 entries
.append(entry
)
14261 self
.enumClass
and decl
.append("class")
14262 self
.name
and decl
.append(self
.name
)
14263 decl
= " ".join(decl
)
14265 return "%s\n{\n%s\n};\n" % (decl
, indent(",\n".join(entries
)))
14267 def define(self
, cgClass
):
14268 # Only goes in the header
14272 class ClassUnion(ClassItem
):
14273 def __init__(self
, name
, entries
, visibility
="public"):
14274 self
.entries
= [entry
+ ";\n" for entry
in entries
]
14275 ClassItem
.__init
__(self
, name
, visibility
)
14277 def declare(self
, cgClass
):
14278 return "union %s\n{\n%s\n};\n" % (self
.name
, indent("".join(self
.entries
)))
14280 def define(self
, cgClass
):
14281 # Only goes in the header
14285 class ClassGroup(ClassItem
):
14286 def __init__(self
, items
):
14288 ClassItem
.__init
__(self
, "", items
[0].visibility
)
14290 def declare(self
, cgClass
):
14293 def define(self
, cgClass
):
14297 class CGClass(CGThing
):
14310 templateSpecialization
=[],
14312 disallowCopyConstruction
=False,
14315 extradeclarations
="",
14316 extradefinitions
="",
14318 CGThing
.__init
__(self
)
14321 self
.typeAliases
= typeAliases
14322 self
.members
= members
14323 self
.constructors
= constructors
14324 # We store our single destructor in a list, since all of our
14325 # code wants lists of members.
14326 self
.destructors
= [destructor
] if destructor
else []
14327 self
.methods
= methods
14329 self
.unions
= unions
14330 self
.templateArgs
= templateArgs
14331 self
.templateSpecialization
= templateSpecialization
14332 self
.isStruct
= isStruct
14333 self
.disallowCopyConstruction
= disallowCopyConstruction
14334 self
.indent
= indent
14335 self
.defaultVisibility
= "public" if isStruct
else "private"
14336 self
.decorators
= decorators
14337 self
.extradeclarations
= extradeclarations
14338 self
.extradefinitions
= extradefinitions
14340 def getNameString(self
):
14341 className
= self
.name
14342 if self
.templateSpecialization
:
14343 className
+= "<%s>" % ", ".join(
14344 [str(a
) for a
in self
.templateSpecialization
]
14349 def flattenClassItemLists(l
):
14351 if isinstance(item
, ClassGroup
):
14352 for inner
in CGClass
.flattenClassItemLists(item
.items
):
14359 if self
.templateArgs
:
14360 templateArgs
= [a
.declare() for a
in self
.templateArgs
]
14361 templateArgs
= templateArgs
[len(self
.templateSpecialization
) :]
14362 result
+= "template <%s>\n" % ",".join([str(a
) for a
in templateArgs
])
14364 type = "struct" if self
.isStruct
else "class"
14366 if self
.templateSpecialization
:
14367 specialization
= "<%s>" % ", ".join(
14368 [str(a
) for a
in self
.templateSpecialization
]
14371 specialization
= ""
14373 myself
= "%s %s%s" % (type, self
.name
, specialization
)
14374 if self
.decorators
!= "":
14375 myself
+= " " + self
.decorators
14381 # Grab our first base
14382 baseItems
= [CGGeneric(b
.declare(self
)) for b
in self
.bases
]
14383 bases
= baseItems
[:1]
14386 CGIndenter(b
, len(myself
) + len(inherit
)) for b
in baseItems
[1:]
14388 result
+= ",\n".join(b
.define() for b
in bases
)
14392 result
+= self
.extradeclarations
14394 def declareMembers(cgClass
, memberList
, defaultVisibility
):
14395 members
= {"private": [], "protected": [], "public": []}
14397 for member
in memberList
:
14398 members
[member
.visibility
].append(member
)
14400 if defaultVisibility
== "public":
14401 order
= ["public", "protected", "private"]
14403 order
= ["private", "protected", "public"]
14407 lastVisibility
= defaultVisibility
14408 for visibility
in order
:
14409 list = members
[visibility
]
14411 for member
in self
.flattenClassItemLists(list):
14412 if member
.visibility
!= lastVisibility
:
14413 result
+= member
.visibility
+ ":\n"
14414 result
+= indent(member
.declare(cgClass
))
14415 lastVisibility
= member
.visibility
14416 return (result
, lastVisibility
)
14418 if self
.disallowCopyConstruction
:
14420 class DisallowedCopyConstructor(object):
14421 def __init__(self
):
14422 self
.visibility
= "private"
14424 def declare(self
, cgClass
):
14425 name
= cgClass
.getNameString()
14427 "%s(const %s&) = delete;\n"
14428 "%s& operator=(const %s&) = delete;\n"
14429 % (name
, name
, name
, name
)
14432 disallowedCopyConstructors
= [DisallowedCopyConstructor()]
14434 disallowedCopyConstructors
= []
14441 self
.constructors
+ disallowedCopyConstructors
,
14446 lastVisibility
= self
.defaultVisibility
14448 for memberList
in order
:
14449 code
, lastVisibility
= declareMembers(self
, memberList
, lastVisibility
)
14452 code
= code
.rstrip() + "\n" # remove extra blank lines at the end
14453 pieces
.append(code
)
14455 result
+= "\n".join(pieces
)
14457 result
= indent(result
, len(self
.indent
))
14461 def defineMembers(cgClass
, memberList
, itemCount
, separator
=""):
14463 for member
in self
.flattenClassItemLists(memberList
):
14465 result
= result
+ separator
14466 definition
= member
.define(cgClass
)
14468 # Member variables would only produce empty lines here.
14469 result
+= definition
14471 return (result
, itemCount
)
14474 (self
.members
, ""),
14475 (self
.constructors
, "\n"),
14476 (self
.destructors
, "\n"),
14477 (self
.methods
, "\n"),
14480 result
= self
.extradefinitions
14482 for memberList
, separator
in order
:
14483 memberString
, itemCount
= defineMembers(
14484 self
, memberList
, itemCount
, separator
14486 result
= result
+ memberString
14490 class CGResolveOwnPropertyViaResolve(CGAbstractBindingMethod
):
14492 An implementation of Xray ResolveOwnProperty stuff for things that have a
14496 def __init__(self
, descriptor
):
14498 Argument("JSContext*", "cx"),
14499 Argument("JS::Handle<JSObject*>", "wrapper"),
14500 Argument("JS::Handle<JSObject*>", "obj"),
14501 Argument("JS::Handle<jsid>", "id"),
14502 Argument("JS::MutableHandle<Maybe<JS::PropertyDescriptor>>", "desc"),
14504 CGAbstractBindingMethod
.__init
__(
14507 "ResolveOwnPropertyViaResolve",
14513 def generate_code(self
):
14518 // Since we're dealing with an Xray, do the resolve on the
14519 // underlying object first. That gives it a chance to
14520 // define properties on the actual object as needed, and
14521 // then use the fact that it created the objects as a flag
14522 // to avoid re-resolving the properties if someone deletes
14524 JSAutoRealm ar(cx, obj);
14525 JS_MarkCrossZoneId(cx, id);
14526 JS::Rooted<mozilla::Maybe<JS::PropertyDescriptor>> objDesc(cx);
14527 if (!self->DoResolve(cx, obj, id, &objDesc)) {
14530 // If desc->value() is undefined, then the DoResolve call
14531 // has already defined the property on the object. Don't
14532 // try to also define it.
14533 if (objDesc.isSome() &&
14534 !objDesc->value().isUndefined()) {
14535 JS::Rooted<JS::PropertyDescriptor> defineDesc(cx, *objDesc);
14536 if (!JS_DefinePropertyById(cx, obj, id, defineDesc)) {
14541 return self->DoResolve(cx, wrapper, id, desc);
14547 class CGEnumerateOwnPropertiesViaGetOwnPropertyNames(CGAbstractBindingMethod
):
14549 An implementation of Xray EnumerateOwnProperties stuff for things
14550 that have a resolve hook.
14553 def __init__(self
, descriptor
):
14555 Argument("JSContext*", "cx"),
14556 Argument("JS::Handle<JSObject*>", "wrapper"),
14557 Argument("JS::Handle<JSObject*>", "obj"),
14558 Argument("JS::MutableHandleVector<jsid>", "props"),
14560 CGAbstractBindingMethod
.__init
__(
14563 "EnumerateOwnPropertiesViaGetOwnPropertyNames",
14569 def generate_code(self
):
14573 FastErrorResult rv;
14574 // This wants all own props, not just enumerable ones.
14575 self->GetOwnPropertyNames(cx, props, false, rv);
14576 if (rv.MaybeSetPendingException(cx)) {
14585 class CGPrototypeTraitsClass(CGClass
):
14586 def __init__(self
, descriptor
, indent
=""):
14587 templateArgs
= [Argument("prototypes::ID", "PrototypeID")]
14588 templateSpecialization
= ["prototypes::id::" + descriptor
.name
]
14589 enums
= [ClassEnum("", ["Depth"], [descriptor
.interface
.inheritanceDepth()])]
14594 templateArgs
=templateArgs
,
14595 templateSpecialization
=templateSpecialization
,
14604 class CGClassForwardDeclare(CGThing
):
14605 def __init__(self
, name
, isStruct
=False):
14606 CGThing
.__init
__(self
)
14608 self
.isStruct
= isStruct
14611 type = "struct" if self
.isStruct
else "class"
14612 return "%s %s;\n" % (type, self
.name
)
14622 class CGProxySpecialOperation(CGPerSignatureCall
):
14624 Base class for classes for calling an indexed or named special operation
14625 (don't use this directly, use the derived classes below).
14627 If checkFound is False, will just assert that the prop is found instead of
14628 checking that it is before wrapping the value.
14630 resultVar: See the docstring for CGCallGenerator.
14632 foundVar: For getters and deleters, the generated code can also set a bool
14633 variable, declared by the caller, if the given indexed or named property
14634 already existed. If the caller wants this, it should pass the name of the
14635 bool variable as the foundVar keyword argument to the constructor. The
14636 caller is responsible for declaring the variable and initializing it to
14645 argumentHandleValue
=None,
14649 self
.checkFound
= checkFound
14650 self
.foundVar
= foundVar
or "found"
14652 nativeName
= MakeNativeName(descriptor
.binaryNameFor(operation
, False))
14653 operation
= descriptor
.operations
[operation
]
14654 assert len(operation
.signatures()) == 1
14655 signature
= operation
.signatures()[0]
14657 returnType
, arguments
= signature
14659 # We pass len(arguments) as the final argument so that the
14660 # CGPerSignatureCall won't do any argument conversion of its own.
14661 CGPerSignatureCall
.__init
__(
14670 resultVar
=resultVar
,
14671 objectName
="proxy",
14674 if operation
.isSetter():
14675 # arguments[0] is the index or name of the item that we're setting.
14676 argument
= arguments
[1]
14677 info
= getJSToNativeConversionInfo(
14680 sourceDescription
=(
14681 "value being assigned to %s setter"
14682 % descriptor
.interface
.identifier
.name
14685 if argumentHandleValue
is None:
14686 argumentHandleValue
= "desc.value()"
14687 rootedValue
= fill(
14689 JS::Rooted<JS::Value> rootedValue(cx, ${argumentHandleValue});
14691 argumentHandleValue
=argumentHandleValue
,
14694 "declName": argument
.identifier
.name
,
14695 "holderName": argument
.identifier
.name
+ "_holder",
14696 "val": argumentHandleValue
,
14697 "maybeMutableVal": "&rootedValue",
14699 "passedToJSImpl": "false",
14701 self
.cgRoot
.prepend(instantiateJSToNativeConversion(info
, templateValues
))
14702 # rootedValue needs to come before the conversion, so we
14703 # need to prepend it last.
14704 self
.cgRoot
.prepend(CGGeneric(rootedValue
))
14705 elif operation
.isGetter() or operation
.isDeleter():
14706 if foundVar
is None:
14707 self
.cgRoot
.prepend(CGGeneric("bool found = false;\n"))
14709 def getArguments(self
):
14710 args
= [(a
, a
.identifier
.name
) for a
in self
.arguments
]
14711 if self
.idlNode
.isGetter() or self
.idlNode
.isDeleter():
14714 FakeArgument(BuiltinTypes
[IDLBuiltinType
.Types
.boolean
]),
14720 def wrap_return_value(self
):
14721 if not self
.idlNode
.isGetter() or self
.templateValues
is None:
14725 wrapForType(self
.returnType
, self
.descriptor
, self
.templateValues
)
14727 if self
.checkFound
:
14728 wrap
= CGIfWrapper(wrap
, self
.foundVar
)
14730 wrap
= CGList([CGGeneric("MOZ_ASSERT(" + self
.foundVar
+ ");\n"), wrap
])
14731 return "\n" + wrap
.define()
14734 class CGProxyIndexedOperation(CGProxySpecialOperation
):
14736 Class to generate a call to an indexed operation.
14738 If doUnwrap is False, the caller is responsible for making sure a variable
14739 named 'self' holds the C++ object somewhere where the code we generate
14742 If checkFound is False, will just assert that the prop is found instead of
14743 checking that it is before wrapping the value.
14745 resultVar: See the docstring for CGCallGenerator.
14747 foundVar: See the docstring for CGProxySpecialOperation.
14756 argumentHandleValue
=None,
14760 self
.doUnwrap
= doUnwrap
14761 CGProxySpecialOperation
.__init
__(
14766 argumentHandleValue
=argumentHandleValue
,
14767 resultVar
=resultVar
,
14772 # Our first argument is the id we're getting.
14773 argName
= self
.arguments
[0].identifier
.name
14774 if argName
== "index":
14775 # We already have our index in a variable with that name
14778 setIndex
= "uint32_t %s = index;\n" % argName
14780 unwrap
= "%s* self = UnwrapProxy(proxy);\n" % self
.descriptor
.nativeType
14783 return setIndex
+ unwrap
+ CGProxySpecialOperation
.define(self
)
14786 class CGProxyIndexedGetter(CGProxyIndexedOperation
):
14788 Class to generate a call to an indexed getter. If templateValues is not None
14789 the returned value will be wrapped with wrapForType using templateValues.
14791 If doUnwrap is False, the caller is responsible for making sure a variable
14792 named 'self' holds the C++ object somewhere where the code we generate
14795 If checkFound is False, will just assert that the prop is found instead of
14796 checking that it is before wrapping the value.
14798 foundVar: See the docstring for CGProxySpecialOperation.
14804 templateValues
=None,
14809 self
.templateValues
= templateValues
14810 CGProxyIndexedOperation
.__init
__(
14811 self
, descriptor
, "IndexedGetter", doUnwrap
, checkFound
, foundVar
=foundVar
14815 class CGProxyIndexedPresenceChecker(CGProxyIndexedGetter
):
14817 Class to generate a call that checks whether an indexed property exists.
14819 For now, we just delegate to CGProxyIndexedGetter
14821 foundVar: See the docstring for CGProxySpecialOperation.
14824 def __init__(self
, descriptor
, foundVar
):
14825 CGProxyIndexedGetter
.__init
__(self
, descriptor
, foundVar
=foundVar
)
14826 self
.cgRoot
.append(CGGeneric("(void)result;\n"))
14829 class CGProxyIndexedSetter(CGProxyIndexedOperation
):
14831 Class to generate a call to an indexed setter.
14834 def __init__(self
, descriptor
, argumentHandleValue
=None):
14835 CGProxyIndexedOperation
.__init
__(
14836 self
, descriptor
, "IndexedSetter", argumentHandleValue
=argumentHandleValue
14840 class CGProxyNamedOperation(CGProxySpecialOperation
):
14842 Class to generate a call to a named operation.
14844 'value' is the jsval to use for the name; None indicates that it should be
14845 gotten from the property id.
14847 resultVar: See the docstring for CGCallGenerator.
14849 foundVar: See the docstring for CGProxySpecialOperation.
14851 tailCode: if we end up with a non-symbol string id, run this code after
14852 we do all our other work.
14860 argumentHandleValue
=None,
14865 CGProxySpecialOperation
.__init
__(
14869 argumentHandleValue
=argumentHandleValue
,
14870 resultVar
=resultVar
,
14874 self
.tailCode
= tailCode
14877 # Our first argument is the id we're getting.
14878 argName
= self
.arguments
[0].identifier
.name
14879 if argName
== "id":
14880 # deal with the name collision
14881 decls
= "JS::Rooted<jsid> id_(cx, id);\n"
14887 decls
+= "FakeString<char16_t> %s;\n" % argName
14891 ${nativeType}* self = UnwrapProxy(proxy);
14895 nativeType
=self
.descriptor
.nativeType
,
14896 op
=CGProxySpecialOperation
.define(self
),
14897 tailCode
=self
.tailCode
,
14900 if self
.value
is None:
14905 if (!ConvertIdToString(cx, ${idName}, ${argName}, isSymbol)) {
14918 # Sadly, we have to set up nameVal even if we have an atom id,
14919 # because we don't know for sure, and we can end up needing it
14920 # so it needs to be higher up the stack. Using a Maybe here
14921 # seems like probable overkill.
14925 JS::Rooted<JS::Value> nameVal(cx, ${value});
14926 if (!nameVal.isSymbol()) {
14927 if (!ConvertJSValueToString(cx, nameVal, eStringify, eStringify,
14941 class CGProxyNamedGetter(CGProxyNamedOperation
):
14943 Class to generate a call to an named getter. If templateValues is not None
14944 the returned value will be wrapped with wrapForType using templateValues.
14945 'value' is the jsval to use for the name; None indicates that it should be
14946 gotten from the property id.
14948 foundVar: See the docstring for CGProxySpecialOperation.
14951 def __init__(self
, descriptor
, templateValues
=None, value
=None, foundVar
=None):
14952 self
.templateValues
= templateValues
14953 CGProxyNamedOperation
.__init
__(
14954 self
, descriptor
, "NamedGetter", value
, foundVar
=foundVar
14958 class CGProxyNamedPresenceChecker(CGProxyNamedGetter
):
14960 Class to generate a call that checks whether a named property exists.
14962 For now, we just delegate to CGProxyNamedGetter
14964 foundVar: See the docstring for CGProxySpecialOperation.
14967 def __init__(self
, descriptor
, foundVar
=None):
14968 CGProxyNamedGetter
.__init
__(self
, descriptor
, foundVar
=foundVar
)
14969 self
.cgRoot
.append(CGGeneric("(void)result;\n"))
14972 class CGProxyNamedSetter(CGProxyNamedOperation
):
14974 Class to generate a call to a named setter.
14977 def __init__(self
, descriptor
, tailCode
, argumentHandleValue
=None):
14978 CGProxyNamedOperation
.__init
__(
14982 argumentHandleValue
=argumentHandleValue
,
14987 class CGProxyNamedDeleter(CGProxyNamedOperation
):
14989 Class to generate a call to a named deleter.
14991 resultVar: See the docstring for CGCallGenerator.
14993 foundVar: See the docstring for CGProxySpecialOperation.
14996 def __init__(self
, descriptor
, resultVar
=None, foundVar
=None):
14997 CGProxyNamedOperation
.__init
__(
14998 self
, descriptor
, "NamedDeleter", resultVar
=resultVar
, foundVar
=foundVar
15002 class CGProxyIsProxy(CGAbstractMethod
):
15003 def __init__(self
, descriptor
):
15004 args
= [Argument("JSObject*", "obj")]
15005 CGAbstractMethod
.__init
__(
15006 self
, descriptor
, "IsProxy", "bool", args
, alwaysInline
=True
15012 def definition_body(self
):
15013 return "return js::IsProxy(obj) && js::GetProxyHandler(obj) == DOMProxyHandler::getInstance();\n"
15016 class CGProxyUnwrap(CGAbstractMethod
):
15017 def __init__(self
, descriptor
):
15018 args
= [Argument("JSObject*", "obj")]
15019 CGAbstractMethod
.__init
__(
15023 descriptor
.nativeType
+ "*",
15031 def definition_body(self
):
15034 MOZ_ASSERT(js::IsProxy(obj));
15035 if (js::GetProxyHandler(obj) != DOMProxyHandler::getInstance()) {
15036 MOZ_ASSERT(xpc::WrapperFactory::IsXrayWrapper(obj));
15037 obj = js::UncheckedUnwrap(obj);
15039 MOZ_ASSERT(IsProxy(obj));
15040 return static_cast<${type}*>(js::GetProxyReservedSlot(obj, DOM_OBJECT_SLOT).toPrivate());
15042 type=self
.descriptor
.nativeType
,
15046 MISSING_PROP_PREF
= "dom.missing_prop_counters.enabled"
15049 def missingPropUseCountersForDescriptor(desc
):
15050 if not desc
.needsMissingPropUseCounters
:
15055 if (StaticPrefs::${pref}() && id.isAtom()) {
15056 CountMaybeMissingProperty(proxy, id);
15060 pref
=prefIdentifier(MISSING_PROP_PREF
),
15064 def findAncestorWithInstrumentedProps(desc
):
15066 Find an ancestor of desc.interface (not including desc.interface
15067 itself) that has instrumented properties on it. May return None
15068 if there is no such ancestor.
15070 ancestor
= desc
.interface
.parent
15072 if ancestor
.getExtendedAttribute("InstrumentedProps"):
15074 ancestor
= ancestor
.parent
15078 class CGCountMaybeMissingProperty(CGAbstractMethod
):
15079 def __init__(self
, descriptor
):
15081 Returns whether we counted the property involved.
15083 CGAbstractMethod
.__init
__(
15086 "CountMaybeMissingProperty",
15089 Argument("JS::Handle<JSObject*>", "proxy"),
15090 Argument("JS::Handle<jsid>", "id"),
15094 def gen_switch(self
, switchDecriptor
):
15096 Generate a switch from the switch descriptor. The descriptor
15097 dictionary must have the following properties:
15099 1) A "precondition" property that contains code to run before the
15100 switch statement. Its value ie a string.
15101 2) A "condition" property for the condition. Its value is a string.
15102 3) A "cases" property. Its value is an object that has property names
15103 corresponding to the case labels. The values of those properties
15104 are either new switch descriptor dictionaries (which will then
15105 generate nested switches) or strings to use for case bodies.
15108 for label
, body
in sorted(switchDecriptor
["cases"].items()):
15109 if isinstance(body
, dict):
15110 body
= self
.gen_switch(body
)
15126 switch (${condition}) {
15130 precondition
=switchDecriptor
["precondition"],
15131 condition
=switchDecriptor
["condition"],
15132 cases
="".join(cases
),
15135 def charSwitch(self
, props
, charIndex
):
15137 Create a switch for the given props, based on the first char where
15138 they start to differ at index charIndex or more. Each prop is a tuple
15139 containing interface name and prop name.
15141 Incoming props should be a sorted list.
15143 if len(props
) == 1:
15144 # We're down to one string: just check whether we match it.
15147 if (JS_LinearStringEqualsLiteral(str, "${name}")) {
15148 counter.emplace(eUseCounter_${iface}_${name});
15151 iface
=self
.descriptor
.name
,
15157 switch
["precondition"] = "StringIdChars chars(nogc, str);\n"
15159 switch
["precondition"] = ""
15161 # Find the first place where we might actually have a difference.
15162 while all(prop
[charIndex
] == props
[0][charIndex
] for prop
in props
):
15165 switch
["condition"] = "chars[%d]" % charIndex
15166 switch
["cases"] = dict()
15167 current_props
= None
15170 while idx
< len(props
):
15171 nextChar
= "'%s'" % props
[idx
][charIndex
]
15172 if nextChar
!= curChar
:
15174 switch
["cases"][curChar
] = self
.charSwitch(
15175 current_props
, charIndex
+ 1
15179 current_props
.append(props
[idx
])
15181 switch
["cases"][curChar
] = self
.charSwitch(current_props
, charIndex
+ 1)
15184 def definition_body(self
):
15185 ancestor
= findAncestorWithInstrumentedProps(self
.descriptor
)
15190 if (${ancestor}_Binding::CountMaybeMissingProperty(proxy, id)) {
15195 ancestor
=ancestor
.identifier
.name
,
15200 instrumentedProps
= self
.descriptor
.instrumentedProps
15201 if not instrumentedProps
:
15202 return body
+ dedent(
15208 lengths
= set(len(prop
) for prop
in instrumentedProps
)
15209 switchDesc
= {"condition": "JS::GetLinearStringLength(str)", "precondition": ""}
15210 switchDesc
["cases"] = dict()
15211 for length
in sorted(lengths
):
15212 switchDesc
["cases"][str(length
)] = self
.charSwitch(
15213 list(sorted(prop
for prop
in instrumentedProps
if len(prop
) == length
)),
15217 return body
+ fill(
15219 MOZ_ASSERT(StaticPrefs::${pref}() && id.isAtom());
15220 Maybe<UseCounter> counter;
15222 // Scope for our no-GC section, so we don't need to rely on SetUseCounter not GCing.
15223 JS::AutoCheckCannotGC nogc;
15224 JSLinearString* str = JS::AtomToLinearString(id.toAtom());
15225 // Don't waste time fetching the chars until we've done the length switch.
15229 SetUseCounter(proxy, *counter);
15235 pref
=prefIdentifier(MISSING_PROP_PREF
),
15236 switch
=self
.gen_switch(switchDesc
),
15240 class CGDOMJSProxyHandler_getOwnPropDescriptor(ClassMethod
):
15241 def __init__(self
, descriptor
):
15243 Argument("JSContext*", "cx"),
15244 Argument("JS::Handle<JSObject*>", "proxy"),
15245 Argument("JS::Handle<jsid>", "id"),
15246 Argument("bool", "ignoreNamedProps"),
15247 Argument("JS::MutableHandle<Maybe<JS::PropertyDescriptor>>", "desc"),
15249 ClassMethod
.__init
__(
15251 "getOwnPropDescriptor",
15258 self
.descriptor
= descriptor
15261 indexedSetter
= self
.descriptor
.operations
["IndexedSetter"]
15263 if self
.descriptor
.isMaybeCrossOriginObject():
15266 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy));
15267 MOZ_ASSERT(IsPlatformObjectSameOrigin(cx, proxy),
15268 "getOwnPropertyDescriptor() and set() should have dealt");
15269 MOZ_ASSERT(js::IsObjectInContextCompartment(proxy, cx),
15270 "getOwnPropertyDescriptor() and set() should have dealt");
15276 xrayDecl
= "bool isXray = xpc::WrapperFactory::IsXrayWrapper(proxy);\n"
15277 xrayCheck
= "!isXray &&"
15279 if self
.descriptor
.supportsIndexedProperties():
15281 "JS::PropertyAttribute::Configurable",
15282 "JS::PropertyAttribute::Enumerable",
15284 if indexedSetter
is not None:
15285 attributes
.append("JS::PropertyAttribute::Writable")
15287 "desc.set(mozilla::Some(JS::PropertyDescriptor::Data(value, { %s })));\nreturn true;\n"
15288 % ", ".join(attributes
)
15291 "jsvalRef": "value",
15292 "jsvalHandle": "&value",
15294 "successCode": setDescriptor
,
15298 uint32_t index = GetArrayIndexFromId(id);
15299 if (IsArrayIndex(index)) {
15300 JS::Rooted<JS::Value> value(cx);
15305 callGetter
=CGProxyIndexedGetter(
15306 self
.descriptor
, templateValues
15312 missingPropUseCounters
= missingPropUseCountersForDescriptor(self
.descriptor
)
15314 if self
.descriptor
.supportsNamedProperties():
15315 operations
= self
.descriptor
.operations
15316 attributes
= ["JS::PropertyAttribute::Configurable"]
15317 if self
.descriptor
.namedPropertiesEnumerable
:
15318 attributes
.append("JS::PropertyAttribute::Enumerable")
15319 if operations
["NamedSetter"] is not None:
15320 attributes
.append("JS::PropertyAttribute::Writable")
15322 "desc.set(mozilla::Some(JS::PropertyDescriptor::Data(value, { %s })));\nreturn true;\n"
15323 % ", ".join(attributes
)
15326 "jsvalRef": "value",
15327 "jsvalHandle": "&value",
15329 "successCode": setDescriptor
,
15332 computeCondition
= dedent(
15335 if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
15338 callNamedGetter = !hasOnProto;
15341 if self
.descriptor
.interface
.getExtendedAttribute("LegacyOverrideBuiltIns"):
15342 computeCondition
= fill(
15345 callNamedGetter = true;
15350 hasOnProto
=computeCondition
,
15353 outerCondition
= "!ignoreNamedProps"
15354 if self
.descriptor
.supportsIndexedProperties():
15355 outerCondition
= "!IsArrayIndex(index) && " + outerCondition
15357 namedGetCode
= CGProxyNamedGetter(self
.descriptor
, templateValues
).define()
15360 bool callNamedGetter = false;
15361 if (${outerCondition}) {
15362 $*{computeCondition}
15364 if (callNamedGetter) {
15365 JS::Rooted<JS::Value> value(cx);
15369 outerCondition
=outerCondition
,
15370 computeCondition
=computeCondition
,
15371 namedGetCode
=namedGetCode
,
15381 $*{missingPropUseCounters}
15382 JS::Rooted<JSObject*> expando(cx);
15383 if (${xrayCheck}(expando = GetExpandoObject(proxy))) {
15384 if (!JS_GetOwnPropertyDescriptorById(cx, expando, id, desc)) {
15387 if (desc.isSome()) {
15397 xrayCheck
=xrayCheck
,
15398 getIndexed
=getIndexed
,
15399 missingPropUseCounters
=missingPropUseCounters
,
15404 class CGDOMJSProxyHandler_defineProperty(ClassMethod
):
15405 def __init__(self
, descriptor
):
15406 # The usual convention is to name the ObjectOpResult out-parameter
15407 # `result`, but that name is a bit overloaded around here.
15409 Argument("JSContext*", "cx_"),
15410 Argument("JS::Handle<JSObject*>", "proxy"),
15411 Argument("JS::Handle<jsid>", "id"),
15412 Argument("JS::Handle<JS::PropertyDescriptor>", "desc"),
15413 Argument("JS::ObjectOpResult&", "opresult"),
15414 Argument("bool*", "done"),
15416 ClassMethod
.__init
__(
15425 self
.descriptor
= descriptor
15430 indexedSetter
= self
.descriptor
.operations
["IndexedSetter"]
15432 error_label
= CGSpecializedMethod
.error_reporting_label_helper(
15433 self
.descriptor
, indexedSetter
, isConstructor
=False
15438 BindingCallContext cx(cx_, ${error_label});
15440 error_label
=error_label
,
15445 JSContext* cx = cx_;
15450 uint32_t index = GetArrayIndexFromId(id);
15451 if (IsArrayIndex(index)) {
15454 // https://webidl.spec.whatwg.org/#legacy-platform-object-defineownproperty
15455 // Step 1.1. The no-indexed-setter case is handled by step 1.2.
15456 if (!desc.isDataDescriptor()) {
15457 return opresult.failNotDataDescriptor();
15461 return opresult.succeed();
15465 callSetter
=CGProxyIndexedSetter(self
.descriptor
).define(),
15467 elif self
.descriptor
.supportsIndexedProperties():
15468 # We allow untrusted content to prevent Xrays from setting a
15469 # property if that property is an indexed property and we have no
15470 # indexed setter. That's how the object would normally behave if
15471 # you tried to set the property on it. That means we don't need to
15472 # do anything special for Xrays here.
15475 if (IsArrayIndex(GetArrayIndexFromId(id))) {
15477 return opresult.failNoIndexedSetter();
15482 namedSetter
= self
.descriptor
.operations
["NamedSetter"]
15484 error_label
= CGSpecializedMethod
.error_reporting_label_helper(
15485 self
.descriptor
, namedSetter
, isConstructor
=False
15490 BindingCallContext cx(cx_, ${error_label});
15492 error_label
=error_label
,
15497 JSContext* cx = cx_;
15500 if self
.descriptor
.hasLegacyUnforgeableMembers
:
15502 "Can't handle a named setter on an interface "
15503 "that has unforgeables. Figure out how that "
15508 // https://webidl.spec.whatwg.org/#legacy-platform-object-defineownproperty
15510 if (!desc.isDataDescriptor()) {
15512 return opresult.failNotDataDescriptor();
15519 return opresult.succeed();
15522 set += CGProxyNamedSetter(self
.descriptor
, tailCode
).define()
15524 # We allow untrusted content to prevent Xrays from setting a
15525 # property if that property is already a named property on the
15526 # object and we have no named setter. That's how the object would
15527 # normally behave if you tried to set the property on it. That
15528 # means we don't need to do anything special for Xrays here.
15529 if self
.descriptor
.supportsNamedProperties():
15532 JSContext* cx = cx_;
15533 bool found = false;
15534 $*{presenceChecker}
15538 return opresult.failNoNamedSetter();
15541 presenceChecker
=CGProxyNamedPresenceChecker(
15542 self
.descriptor
, foundVar
="found"
15545 if self
.descriptor
.isMaybeCrossOriginObject():
15548 MOZ_ASSERT(IsPlatformObjectSameOrigin(cx_, proxy),
15549 "Why did the MaybeCrossOriginObject defineProperty override fail?");
15550 MOZ_ASSERT(js::IsObjectInContextCompartment(proxy, cx_),
15551 "Why did the MaybeCrossOriginObject defineProperty override fail?");
15555 # In all cases we want to tail-call to our base class; we can
15556 # always land here for symbols.
15558 "return mozilla::dom::DOMProxyHandler::defineProperty(%s);\n"
15559 % ", ".join(a
.name
for a
in self
.args
)
15564 def getDeleterBody(descriptor
, type, foundVar
=None):
15566 type should be "Named" or "Indexed"
15568 The possible outcomes:
15569 - an error happened (the emitted code returns false)
15570 - own property not found (foundVar=false, deleteSucceeded=true)
15571 - own property found and deleted (foundVar=true, deleteSucceeded=true)
15572 - own property found but can't be deleted (foundVar=true, deleteSucceeded=false)
15574 assert type in ("Named", "Indexed")
15575 deleter
= descriptor
.operations
[type + "Deleter"]
15577 assert type == "Named"
15578 assert foundVar
is not None
15579 if descriptor
.hasLegacyUnforgeableMembers
:
15581 "Can't handle a deleter on an interface "
15582 "that has unforgeables. Figure out how "
15583 "that should work!"
15585 # See if the deleter method is fallible.
15586 t
= deleter
.signatures()[0][0]
15587 if t
.isPrimitive() and not t
.nullable() and t
.tag() == IDLType
.Tags
.bool:
15588 # The deleter method has a boolean return value. When a
15589 # property is found, the return value indicates whether it
15590 # was successfully deleted.
15593 if (!${foundVar}) {
15594 deleteSucceeded = true;
15600 # No boolean return value: if a property is found,
15601 # deleting it always succeeds.
15602 setDS
= "deleteSucceeded = true;\n"
15605 CGProxyNamedDeleter(
15606 descriptor
, resultVar
="deleteSucceeded", foundVar
=foundVar
15610 elif getattr(descriptor
, "supports%sProperties" % type)():
15611 presenceCheckerClass
= globals()["CGProxy%sPresenceChecker" % type]
15613 if foundVar
is None:
15615 foundDecl
= "bool found = false;\n"
15619 $*{presenceChecker}
15620 deleteSucceeded = !${foundVar};
15622 foundDecl
=foundDecl
,
15623 presenceChecker
=presenceCheckerClass(
15624 descriptor
, foundVar
=foundVar
15633 class CGDeleteNamedProperty(CGAbstractStaticMethod
):
15634 def __init__(self
, descriptor
):
15636 Argument("JSContext*", "cx"),
15637 Argument("JS::Handle<JSObject*>", "xray"),
15638 Argument("JS::Handle<JSObject*>", "proxy"),
15639 Argument("JS::Handle<jsid>", "id"),
15640 Argument("JS::ObjectOpResult&", "opresult"),
15642 CGAbstractStaticMethod
.__init
__(
15643 self
, descriptor
, "DeleteNamedProperty", "bool", args
15646 def definition_body(self
):
15649 MOZ_ASSERT(xpc::WrapperFactory::IsXrayWrapper(xray));
15650 MOZ_ASSERT(js::IsProxy(proxy));
15651 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy));
15652 JSAutoRealm ar(cx, proxy);
15653 bool deleteSucceeded = false;
15654 bool found = false;
15656 if (!found || deleteSucceeded) {
15657 return opresult.succeed();
15659 return opresult.failCantDelete();
15661 namedBody
=getDeleterBody(self
.descriptor
, "Named", foundVar
="found"),
15665 class CGDOMJSProxyHandler_delete(ClassMethod
):
15666 def __init__(self
, descriptor
):
15668 Argument("JSContext*", "cx"),
15669 Argument("JS::Handle<JSObject*>", "proxy"),
15670 Argument("JS::Handle<jsid>", "id"),
15671 Argument("JS::ObjectOpResult&", "opresult"),
15673 ClassMethod
.__init
__(
15674 self
, "delete_", "bool", args
, virtual
=True, override
=True, const
=True
15676 self
.descriptor
= descriptor
15681 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
15682 "Should not have a XrayWrapper here");
15687 if self
.descriptor
.isMaybeCrossOriginObject():
15690 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
15691 return ReportCrossOriginDenial(cx, id, "delete"_ns);
15694 // Safe to enter the Realm of proxy now.
15695 JSAutoRealm ar(cx, proxy);
15696 JS_MarkCrossZoneId(cx, id);
15700 indexedBody
= getDeleterBody(self
.descriptor
, "Indexed")
15701 if indexedBody
is not None:
15702 # Can't handle cross-origin objects here.
15703 assert not self
.descriptor
.isMaybeCrossOriginObject()
15706 uint32_t index = GetArrayIndexFromId(id);
15707 if (IsArrayIndex(index)) {
15708 bool deleteSucceeded;
15710 return deleteSucceeded ? opresult.succeed() : opresult.failCantDelete();
15713 indexedBody
=indexedBody
,
15716 namedBody
= getDeleterBody(self
.descriptor
, "Named", foundVar
="found")
15717 if namedBody
is not None:
15720 // Try named delete only if the named property visibility
15721 // algorithm says the property is visible.
15722 bool tryNamedDelete = true;
15723 { // Scope for expando
15724 JS::Rooted<JSObject*> expando(cx, DOMProxyHandler::GetExpandoObject(proxy));
15727 if (!JS_HasPropertyById(cx, expando, id, &hasProp)) {
15730 tryNamedDelete = !hasProp;
15736 if not self
.descriptor
.interface
.getExtendedAttribute(
15737 "LegacyOverrideBuiltIns"
15741 if (tryNamedDelete) {
15743 if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
15746 tryNamedDelete = !hasOnProto;
15751 # We always return above for an index id in the case when we support
15752 # indexed properties, so we can just treat the id as a name
15753 # unconditionally here.
15756 if (tryNamedDelete) {
15757 bool found = false;
15758 bool deleteSucceeded;
15761 return deleteSucceeded ? opresult.succeed() : opresult.failCantDelete();
15765 namedBody
=namedBody
,
15771 return dom::DOMProxyHandler::delete_(cx, proxy, id, opresult);
15778 class CGDOMJSProxyHandler_ownPropNames(ClassMethod
):
15784 Argument("JSContext*", "cx"),
15785 Argument("JS::Handle<JSObject*>", "proxy"),
15786 Argument("unsigned", "flags"),
15787 Argument("JS::MutableHandleVector<jsid>", "props"),
15789 ClassMethod
.__init
__(
15790 self
, "ownPropNames", "bool", args
, virtual
=True, override
=True, const
=True
15792 self
.descriptor
= descriptor
15795 if self
.descriptor
.isMaybeCrossOriginObject():
15798 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy));
15799 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
15800 if (!(flags & JSITER_HIDDEN)) {
15801 // There are no enumerable cross-origin props, so we're done.
15805 JS::Rooted<JSObject*> holder(cx);
15806 if (!EnsureHolder(cx, proxy, &holder)) {
15810 if (!js::GetPropertyKeys(cx, holder, flags, props)) {
15814 return xpc::AppendCrossOriginWhitelistedPropNames(cx, props);
15821 xrayDecl
= "bool isXray = xpc::WrapperFactory::IsXrayWrapper(proxy);\n"
15822 xrayCheck
= "!isXray &&"
15824 # Per spec, we do indices, then named props, then everything else.
15825 if self
.descriptor
.supportsIndexedProperties():
15826 if self
.descriptor
.lengthNeedsCallerType():
15827 callerType
= callerTypeGetterForDescriptor(self
.descriptor
)
15833 uint32_t length = UnwrapProxy(proxy)->Length(${callerType});
15834 MOZ_ASSERT(int32_t(length) >= 0);
15835 for (int32_t i = 0; i < int32_t(length); ++i) {
15836 if (!props.append(JS::PropertyKey::Int(i))) {
15841 callerType
=callerType
,
15846 if self
.descriptor
.supportsNamedProperties():
15847 if self
.descriptor
.interface
.getExtendedAttribute("LegacyOverrideBuiltIns"):
15852 if self
.descriptor
.supportedNamesNeedCallerType():
15853 callerType
= ", " + callerTypeGetterForDescriptor(self
.descriptor
)
15859 nsTArray<nsString> names;
15860 UnwrapProxy(proxy)->GetSupportedNames(names${callerType});
15861 if (!AppendNamedPropertyIds(cx, proxy, names, ${shadow}, props)) {
15865 callerType
=callerType
,
15868 if not self
.descriptor
.namedPropertiesEnumerable
:
15869 addNames
= CGIfWrapper(
15870 CGGeneric(addNames
), "flags & JSITER_HIDDEN"
15872 addNames
= "\n" + addNames
15876 addExpandoProps
= fill(
15878 JS::Rooted<JSObject*> expando(cx);
15879 if (${xrayCheck}(expando = DOMProxyHandler::GetExpandoObject(proxy)) &&
15880 !js::GetPropertyKeys(cx, expando, flags, props)) {
15884 xrayCheck
=xrayCheck
,
15887 if self
.descriptor
.isMaybeCrossOriginObject():
15888 # We need to enter our compartment (which we might not be
15889 # in right now) to get the expando props.
15890 addExpandoProps
= fill(
15892 { // Scope for accessing the expando.
15893 // Safe to enter our compartment, because IsPlatformObjectSameOrigin tested true.
15894 JSAutoRealm ar(cx, proxy);
15895 $*{addExpandoProps}
15897 for (auto& id : props) {
15898 JS_MarkCrossZoneId(cx, id);
15901 addExpandoProps
=addExpandoProps
,
15910 $*{addExpandoProps}
15915 addIndices
=addIndices
,
15917 addExpandoProps
=addExpandoProps
,
15921 class CGDOMJSProxyHandler_hasOwn(ClassMethod
):
15922 def __init__(self
, descriptor
):
15924 Argument("JSContext*", "cx"),
15925 Argument("JS::Handle<JSObject*>", "proxy"),
15926 Argument("JS::Handle<jsid>", "id"),
15927 Argument("bool*", "bp"),
15929 ClassMethod
.__init
__(
15930 self
, "hasOwn", "bool", args
, virtual
=True, override
=True, const
=True
15932 self
.descriptor
= descriptor
15935 if self
.descriptor
.isMaybeCrossOriginObject():
15936 maybeCrossOrigin
= dedent(
15938 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
15939 // Just hand this off to BaseProxyHandler to do the slow-path thing.
15940 // The BaseProxyHandler code is OK with this happening without entering the
15941 // compartment of "proxy", which is important to get the right answers.
15942 return js::BaseProxyHandler::hasOwn(cx, proxy, id, bp);
15945 // Now safe to enter the Realm of proxy and do the rest of the work there.
15946 JSAutoRealm ar(cx, proxy);
15947 JS_MarkCrossZoneId(cx, id);
15951 maybeCrossOrigin
= ""
15953 if self
.descriptor
.supportsIndexedProperties():
15956 uint32_t index = GetArrayIndexFromId(id);
15957 if (IsArrayIndex(index)) {
15958 bool found = false;
15959 $*{presenceChecker}
15966 presenceChecker
=CGProxyIndexedPresenceChecker(
15967 self
.descriptor
, foundVar
="found"
15973 if self
.descriptor
.supportsNamedProperties():
15974 # If we support indexed properties we always return above for index
15975 # property names, so no need to check for those here.
15978 bool found = false;
15979 $*{presenceChecker}
15983 presenceChecker
=CGProxyNamedPresenceChecker(
15984 self
.descriptor
, foundVar
="found"
15987 if not self
.descriptor
.interface
.getExtendedAttribute(
15988 "LegacyOverrideBuiltIns"
15993 if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
15997 $*{protoLacksProperty}
16001 protoLacksProperty
=named
,
16003 named
+= "*bp = false;\n"
16007 named
= "*bp = false;\n"
16009 missingPropUseCounters
= missingPropUseCountersForDescriptor(self
.descriptor
)
16013 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
16014 "Should not have a XrayWrapper here");
16015 $*{maybeCrossOrigin}
16018 $*{missingPropUseCounters}
16019 JS::Rooted<JSObject*> expando(cx, GetExpandoObject(proxy));
16022 bool ok = JS_HasPropertyById(cx, expando, id, &b);
16032 maybeCrossOrigin
=maybeCrossOrigin
,
16034 missingPropUseCounters
=missingPropUseCounters
,
16039 class CGDOMJSProxyHandler_get(ClassMethod
):
16040 def __init__(self
, descriptor
):
16042 Argument("JSContext*", "cx"),
16043 Argument("JS::Handle<JSObject*>", "proxy"),
16044 Argument("JS::Handle<JS::Value>", "receiver"),
16045 Argument("JS::Handle<jsid>", "id"),
16046 Argument("JS::MutableHandle<JS::Value>", "vp"),
16048 ClassMethod
.__init
__(
16049 self
, "get", "bool", args
, virtual
=True, override
=True, const
=True
16051 self
.descriptor
= descriptor
16054 missingPropUseCounters
= missingPropUseCountersForDescriptor(self
.descriptor
)
16056 getUnforgeableOrExpando
= dedent(
16058 bool expandoHasProp = false;
16059 { // Scope for expando
16060 JS::Rooted<JSObject*> expando(cx, DOMProxyHandler::GetExpandoObject(proxy));
16062 if (!JS_HasPropertyById(cx, expando, id, &expandoHasProp)) {
16066 if (expandoHasProp) {
16067 // Forward the get to the expando object, but our receiver is whatever our
16069 if (!JS_ForwardGetPropertyTo(cx, expando, id, ${receiver}, vp)) {
16078 getOnPrototype
= dedent(
16080 bool foundOnPrototype;
16081 if (!GetPropertyOnPrototype(cx, proxy, ${receiver}, id, &foundOnPrototype, vp)) {
16087 if self
.descriptor
.isMaybeCrossOriginObject():
16088 # We can't handle these for cross-origin objects
16089 assert not self
.descriptor
.supportsIndexedProperties()
16090 assert not self
.descriptor
.supportsNamedProperties()
16094 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
16095 "Should not have a XrayWrapper here");
16097 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
16098 return CrossOriginGet(cx, proxy, receiver, id, vp);
16101 $*{missingPropUseCounters}
16102 { // Scope for the JSAutoRealm accessing expando and prototype.
16103 JSAutoRealm ar(cx, proxy);
16104 JS::Rooted<JS::Value> wrappedReceiver(cx, receiver);
16105 if (!MaybeWrapValue(cx, &wrappedReceiver)) {
16108 JS_MarkCrossZoneId(cx, id);
16110 $*{getUnforgeableOrExpando}
16111 if (!expandoHasProp) {
16113 if (!foundOnPrototype) {
16114 MOZ_ASSERT(vp.isUndefined());
16120 return MaybeWrapValue(cx, vp);
16122 missingPropUseCounters
=missingPropUseCountersForDescriptor(
16125 getUnforgeableOrExpando
=fill(
16126 getUnforgeableOrExpando
, receiver
="wrappedReceiver"
16128 getOnPrototype
=fill(getOnPrototype
, receiver
="wrappedReceiver"),
16131 templateValues
= {"jsvalRef": "vp", "jsvalHandle": "vp", "obj": "proxy"}
16133 getUnforgeableOrExpando
= fill(
16134 getUnforgeableOrExpando
, receiver
="receiver"
16138 if (expandoHasProp) {
16143 if self
.descriptor
.supportsIndexedProperties():
16144 getIndexedOrExpando
= fill(
16146 uint32_t index = GetArrayIndexFromId(id);
16147 if (IsArrayIndex(index)) {
16149 // Even if we don't have this index, we don't forward the
16150 // get on to our expando object.
16152 $*{getUnforgeableOrExpando}
16155 callGetter
=CGProxyIndexedGetter(
16156 self
.descriptor
, templateValues
16158 getUnforgeableOrExpando
=getUnforgeableOrExpando
,
16161 getIndexedOrExpando
= getUnforgeableOrExpando
16163 if self
.descriptor
.supportsNamedProperties():
16164 getNamed
= CGProxyNamedGetter(self
.descriptor
, templateValues
)
16165 if self
.descriptor
.supportsIndexedProperties():
16166 getNamed
= CGIfWrapper(getNamed
, "!IsArrayIndex(index)")
16167 getNamed
= getNamed
.define() + "\n"
16171 getOnPrototype
= fill(getOnPrototype
, receiver
="receiver") + dedent(
16174 if (foundOnPrototype) {
16178 MOZ_ASSERT(vp.isUndefined());
16182 if self
.descriptor
.interface
.getExtendedAttribute("LegacyOverrideBuiltIns"):
16183 getNamedOrOnPrototype
= getNamed
+ getOnPrototype
16185 getNamedOrOnPrototype
= getOnPrototype
+ getNamed
16189 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
16190 "Should not have a XrayWrapper here");
16192 $*{missingPropUseCounters}
16193 $*{indexedOrExpando}
16195 $*{namedOrOnPropotype}
16198 missingPropUseCounters
=missingPropUseCounters
,
16199 indexedOrExpando
=getIndexedOrExpando
,
16200 namedOrOnPropotype
=getNamedOrOnPrototype
,
16204 class CGDOMJSProxyHandler_setCustom(ClassMethod
):
16205 def __init__(self
, descriptor
):
16207 Argument("JSContext*", "cx_"),
16208 Argument("JS::Handle<JSObject*>", "proxy"),
16209 Argument("JS::Handle<jsid>", "id"),
16210 Argument("JS::Handle<JS::Value>", "v"),
16211 Argument("bool*", "done"),
16213 ClassMethod
.__init
__(
16214 self
, "setCustom", "bool", args
, virtual
=True, override
=True, const
=True
16216 self
.descriptor
= descriptor
16220 "MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),\n"
16221 ' "Should not have a XrayWrapper here");\n'
16224 # Correctness first. If we have a NamedSetter and [LegacyOverrideBuiltIns],
16225 # always call the NamedSetter and never do anything else.
16226 namedSetter
= self
.descriptor
.operations
["NamedSetter"]
16227 if namedSetter
is not None and self
.descriptor
.interface
.getExtendedAttribute(
16228 "LegacyOverrideBuiltIns"
16230 # Check assumptions.
16231 if self
.descriptor
.supportsIndexedProperties():
16234 + self
.descriptor
.name
16236 + "Can't cope with [LegacyOverrideBuiltIns] and an indexed getter"
16238 if self
.descriptor
.hasLegacyUnforgeableMembers
:
16241 + self
.descriptor
.name
16243 + "Can't cope with [LegacyOverrideBuiltIns] and unforgeable members"
16252 callSetter
= CGProxyNamedSetter(
16253 self
.descriptor
, tailCode
, argumentHandleValue
="v"
16255 error_label
= CGSpecializedMethod
.error_reporting_label_helper(
16256 self
.descriptor
, namedSetter
, isConstructor
=False
16261 BindingCallContext cx(cx_, ${error_label});
16263 error_label
=error_label
,
16268 JSContext* cx = cx_;
16279 assertion
=assertion
,
16281 callSetter
=callSetter
.define(),
16284 # As an optimization, if we are going to call an IndexedSetter, go
16285 # ahead and call it and have done.
16286 indexedSetter
= self
.descriptor
.operations
["IndexedSetter"]
16287 if indexedSetter
is not None:
16288 error_label
= CGSpecializedMethod
.error_reporting_label_helper(
16289 self
.descriptor
, indexedSetter
, isConstructor
=False
16294 BindingCallContext cx(cx_, ${error_label});
16296 error_label
=error_label
,
16301 JSContext* cx = cx_;
16306 uint32_t index = GetArrayIndexFromId(id);
16307 if (IsArrayIndex(index)) {
16316 callSetter
=CGProxyIndexedSetter(
16317 self
.descriptor
, argumentHandleValue
="v"
16323 return assertion
+ setIndexed
+ "*done = false;\n" "return true;\n"
16326 class CGDOMJSProxyHandler_className(ClassMethod
):
16327 def __init__(self
, descriptor
):
16329 Argument("JSContext*", "cx"),
16330 Argument("JS::Handle<JSObject*>", "proxy"),
16332 ClassMethod
.__init
__(
16341 self
.descriptor
= descriptor
16344 if self
.descriptor
.isMaybeCrossOriginObject():
16345 crossOrigin
= dedent(
16347 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
16360 crossOrigin
=crossOrigin
,
16361 name
=self
.descriptor
.name
,
16365 class CGDOMJSProxyHandler_trace(ClassMethod
):
16366 def __init__(self
, descriptor
):
16367 args
= [Argument("JSTracer*", "trc"), Argument("JSObject*", "proxy")]
16368 ClassMethod
.__init
__(
16377 self
.descriptor
= descriptor
16380 iface
= getReflectedHTMLAttributesIface(self
.descriptor
)
16383 ${reflectedAttributesBase}::ReflectedHTMLAttributeSlots::Trace(${trc}, ${proxy});
16384 return Base::trace(${trc}, ${proxy});
16386 reflectedAttributesBase
=toBindingNamespace(iface
.identifier
.name
),
16387 trc
=self
.args
[0].name
,
16388 proxy
=self
.args
[1].name
,
16392 class CGDOMJSProxyHandler_finalizeInBackground(ClassMethod
):
16393 def __init__(self
, descriptor
):
16394 args
= [Argument("const JS::Value&", "priv")]
16395 ClassMethod
.__init
__(
16397 "finalizeInBackground",
16404 self
.descriptor
= descriptor
16407 return "return false;\n"
16410 class CGDOMJSProxyHandler_finalize(ClassMethod
):
16411 def __init__(self
, descriptor
):
16412 args
= [Argument("JS::GCContext*", "gcx"), Argument("JSObject*", "proxy")]
16413 ClassMethod
.__init
__(
16414 self
, "finalize", "void", args
, virtual
=True, override
=True, const
=True
16416 self
.descriptor
= descriptor
16420 "%s* self = UnwrapPossiblyNotInitializedDOMObject<%s>(proxy);\n"
16421 % (self
.descriptor
.nativeType
, self
.descriptor
.nativeType
)
16424 FINALIZE_HOOK_NAME
,
16430 class CGDOMJSProxyHandler_objectMoved(ClassMethod
):
16431 def __init__(self
, descriptor
):
16432 args
= [Argument("JSObject*", "obj"), Argument("JSObject*", "old")]
16433 ClassMethod
.__init
__(
16434 self
, "objectMoved", "size_t", args
, virtual
=True, override
=True, const
=True
16436 self
.descriptor
= descriptor
16440 "%s* self = UnwrapPossiblyNotInitializedDOMObject<%s>(obj);\n"
16441 % (self
.descriptor
.nativeType
, self
.descriptor
.nativeType
)
16442 ) + objectMovedHook(
16444 OBJECT_MOVED_HOOK_NAME
,
16450 class CGDOMJSProxyHandler_getElements(ClassMethod
):
16451 def __init__(self
, descriptor
):
16452 assert descriptor
.supportsIndexedProperties()
16455 Argument("JSContext*", "cx"),
16456 Argument("JS::Handle<JSObject*>", "proxy"),
16457 Argument("uint32_t", "begin"),
16458 Argument("uint32_t", "end"),
16459 Argument("js::ElementAdder*", "adder"),
16461 ClassMethod
.__init
__(
16462 self
, "getElements", "bool", args
, virtual
=True, override
=True, const
=True
16464 self
.descriptor
= descriptor
16467 # Just like ownPropertyKeys we'll assume that we have no holes, so
16468 # we have all properties from 0 to length. If that ever changes
16469 # (unlikely), we'll need to do something a bit more clever with how we
16470 # forward on to our ancestor.
16473 "jsvalRef": "temp",
16474 "jsvalHandle": "&temp",
16477 "if (!adder->append(cx, temp)) return false;\n" "continue;\n"
16480 get
= CGProxyIndexedGetter(
16481 self
.descriptor
, templateValues
, False, False
16484 if self
.descriptor
.lengthNeedsCallerType():
16485 callerType
= callerTypeGetterForDescriptor(self
.descriptor
)
16491 JS::Rooted<JS::Value> temp(cx);
16492 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
16493 "Should not have a XrayWrapper here");
16495 ${nativeType}* self = UnwrapProxy(proxy);
16496 uint32_t length = self->Length(${callerType});
16497 // Compute the end of the indices we'll get ourselves
16498 uint32_t ourEnd = std::clamp(length, begin, end);
16500 for (uint32_t index = begin; index < ourEnd; ++index) {
16504 if (end > ourEnd) {
16505 JS::Rooted<JSObject*> proto(cx);
16506 if (!js::GetObjectProto(cx, proxy, &proto)) {
16509 return js::GetElementsWithAdder(cx, proto, proxy, ourEnd, end, adder);
16514 nativeType
=self
.descriptor
.nativeType
,
16515 callerType
=callerType
,
16520 class CGJSProxyHandler_getInstance(ClassMethod
):
16521 def __init__(self
, type):
16523 ClassMethod
.__init
__(
16524 self
, "getInstance", "const %s*" % self
.type, [], static
=True
16530 static const ${type} instance;
16537 class CGDOMJSProxyHandler_call(ClassMethod
):
16538 def __init__(self
):
16540 Argument("JSContext*", "cx"),
16541 Argument("JS::Handle<JSObject*>", "proxy"),
16542 Argument("const JS::CallArgs&", "args"),
16545 ClassMethod
.__init
__(
16546 self
, "call", "bool", args
, virtual
=True, override
=True, const
=True
16552 return js::ForwardToNative(cx, ${legacyCaller}, args);
16554 legacyCaller
=LEGACYCALLER_HOOK_NAME
,
16558 class CGDOMJSProxyHandler_isCallable(ClassMethod
):
16559 def __init__(self
):
16560 ClassMethod
.__init
__(
16564 [Argument("JSObject*", "obj")],
16578 class CGDOMJSProxyHandler_canNurseryAllocate(ClassMethod
):
16580 Override the default canNurseryAllocate in BaseProxyHandler, for cases when
16581 we should be nursery-allocated.
16584 def __init__(self
):
16585 ClassMethod
.__init
__(
16587 "canNurseryAllocate",
16603 class CGDOMJSProxyHandler_getOwnPropertyDescriptor(ClassMethod
):
16605 Implementation of getOwnPropertyDescriptor. We only use this for
16606 cross-origin objects.
16609 def __init__(self
, descriptor
):
16610 assert descriptor
.isMaybeCrossOriginObject()
16613 Argument("JSContext*", "cx"),
16614 Argument("JS::Handle<JSObject*>", "proxy"),
16615 Argument("JS::Handle<jsid>", "id"),
16616 Argument("JS::MutableHandle<Maybe<JS::PropertyDescriptor>>", "desc"),
16618 ClassMethod
.__init
__(
16620 "getOwnPropertyDescriptor",
16627 self
.descriptor
= descriptor
16632 // Implementation of <https://html.spec.whatwg.org/multipage/history.html#location-getownproperty>.
16633 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy));
16636 if (IsPlatformObjectSameOrigin(cx, proxy)) {
16637 { // Scope so we can wrap our PropertyDescriptor back into
16638 // the caller compartment.
16639 // Enter the Realm of "proxy" so we can work with it.
16640 JSAutoRealm ar(cx, proxy);
16642 JS_MarkCrossZoneId(cx, id);
16644 // The spec messes around with configurability of the returned
16645 // descriptor here, but it's not clear what should actually happen
16646 // here. See <https://github.com/whatwg/html/issues/4157>. For
16647 // now, keep our old behavior and don't do any magic.
16648 if (!dom::DOMProxyHandler::getOwnPropertyDescriptor(cx, proxy, id, desc)) {
16652 return JS_WrapPropertyDescriptor(cx, desc);
16656 if (!CrossOriginGetOwnPropertyHelper(cx, proxy, id, desc)) {
16661 if (desc.isSome()) {
16666 return CrossOriginPropertyFallback(cx, proxy, id, desc);
16671 class CGDOMJSProxyHandler_getSameOriginPrototype(ClassMethod
):
16673 Implementation of getSameOriginPrototype. We only use this for
16674 cross-origin objects.
16677 def __init__(self
, descriptor
):
16678 assert descriptor
.isMaybeCrossOriginObject()
16680 args
= [Argument("JSContext*", "cx")]
16681 ClassMethod
.__init
__(
16683 "getSameOriginPrototype",
16690 self
.descriptor
= descriptor
16695 return GetProtoObjectHandle(cx);
16700 class CGDOMJSProxyHandler_definePropertySameOrigin(ClassMethod
):
16702 Implementation of definePropertySameOrigin. We only use this for
16703 cross-origin objects.
16706 def __init__(self
, descriptor
):
16707 assert descriptor
.isMaybeCrossOriginObject()
16710 Argument("JSContext*", "cx"),
16711 Argument("JS::Handle<JSObject*>", "proxy"),
16712 Argument("JS::Handle<jsid>", "id"),
16713 Argument("JS::Handle<JS::PropertyDescriptor>", "desc"),
16714 Argument("JS::ObjectOpResult&", "result"),
16716 ClassMethod
.__init
__(
16718 "definePropertySameOrigin",
16725 self
.descriptor
= descriptor
16730 return dom::DOMProxyHandler::defineProperty(cx, proxy, id, desc, result);
16735 class CGDOMJSProxyHandler_set(ClassMethod
):
16737 Implementation of set(). We only use this for cross-origin objects.
16740 def __init__(self
, descriptor
):
16741 assert descriptor
.isMaybeCrossOriginObject()
16744 Argument("JSContext*", "cx"),
16745 Argument("JS::Handle<JSObject*>", "proxy"),
16746 Argument("JS::Handle<jsid>", "id"),
16747 Argument("JS::Handle<JS::Value>", "v"),
16748 Argument("JS::Handle<JS::Value>", "receiver"),
16749 Argument("JS::ObjectOpResult&", "result"),
16751 ClassMethod
.__init
__(
16752 self
, "set", "bool", args
, virtual
=True, override
=True, const
=True
16754 self
.descriptor
= descriptor
16759 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
16760 return CrossOriginSet(cx, proxy, id, v, receiver, result);
16763 // Safe to enter the Realm of proxy now, since it's same-origin with us.
16764 JSAutoRealm ar(cx, proxy);
16765 JS::Rooted<JS::Value> wrappedReceiver(cx, receiver);
16766 if (!MaybeWrapValue(cx, &wrappedReceiver)) {
16770 JS::Rooted<JS::Value> wrappedValue(cx, v);
16771 if (!MaybeWrapValue(cx, &wrappedValue)) {
16775 JS_MarkCrossZoneId(cx, id);
16777 return dom::DOMProxyHandler::set(cx, proxy, id, wrappedValue, wrappedReceiver, result);
16782 class CGDOMJSProxyHandler_EnsureHolder(ClassMethod
):
16784 Implementation of EnsureHolder(). We only use this for cross-origin objects.
16787 def __init__(self
, descriptor
):
16789 Argument("JSContext*", "cx"),
16790 Argument("JS::Handle<JSObject*>", "proxy"),
16791 Argument("JS::MutableHandle<JSObject*>", "holder"),
16793 ClassMethod
.__init
__(
16794 self
, "EnsureHolder", "bool", args
, virtual
=True, override
=True, const
=True
16796 self
.descriptor
= descriptor
16801 return EnsureHolder(cx, proxy,
16802 JSCLASS_RESERVED_SLOTS(JS::GetClass(proxy)) - 1,
16803 sCrossOriginProperties, holder);
16808 class CGDOMJSProxyHandler(CGClass
):
16809 def __init__(self
, descriptor
):
16811 descriptor
.supportsIndexedProperties()
16812 or descriptor
.supportsNamedProperties()
16813 or descriptor
.isMaybeCrossOriginObject()
16816 if descriptor
.interface
.getExtendedAttribute("LegacyOverrideBuiltIns"):
16817 assert not descriptor
.isMaybeCrossOriginObject()
16818 parentClass
= "ShadowingDOMProxyHandler"
16819 elif descriptor
.isMaybeCrossOriginObject():
16820 parentClass
= "MaybeCrossOriginObject<mozilla::dom::DOMProxyHandler>"
16822 parentClass
= "mozilla::dom::DOMProxyHandler"
16825 ClassUsingDeclaration("Base", parentClass
),
16828 CGDOMJSProxyHandler_getOwnPropDescriptor(descriptor
),
16829 CGDOMJSProxyHandler_defineProperty(descriptor
),
16830 ClassUsingFromBaseDeclaration(
16831 "mozilla::dom::DOMProxyHandler", "defineProperty"
16833 CGDOMJSProxyHandler_ownPropNames(descriptor
),
16834 CGDOMJSProxyHandler_hasOwn(descriptor
),
16835 CGDOMJSProxyHandler_get(descriptor
),
16836 CGDOMJSProxyHandler_className(descriptor
),
16837 CGDOMJSProxyHandler_finalizeInBackground(descriptor
),
16838 CGDOMJSProxyHandler_finalize(descriptor
),
16839 CGJSProxyHandler_getInstance("DOMProxyHandler"),
16840 CGDOMJSProxyHandler_delete(descriptor
),
16842 if getReflectedHTMLAttributesIface(descriptor
):
16843 methods
.append(CGDOMJSProxyHandler_trace(descriptor
))
16845 ClassConstructor([], constexpr
=True, visibility
="public", explicit
=True)
16848 if descriptor
.supportsIndexedProperties():
16849 methods
.append(CGDOMJSProxyHandler_getElements(descriptor
))
16850 if descriptor
.operations
["IndexedSetter"] is not None or (
16851 descriptor
.operations
["NamedSetter"] is not None
16852 and descriptor
.interface
.getExtendedAttribute("LegacyOverrideBuiltIns")
16854 methods
.append(CGDOMJSProxyHandler_setCustom(descriptor
))
16855 if descriptor
.operations
["LegacyCaller"]:
16856 methods
.append(CGDOMJSProxyHandler_call())
16857 methods
.append(CGDOMJSProxyHandler_isCallable())
16858 if descriptor
.interface
.hasProbablyShortLivingWrapper():
16859 if not descriptor
.wrapperCache
:
16861 "Need a wrapper cache to support nursery "
16862 "allocation of DOM objects"
16864 methods
.append(CGDOMJSProxyHandler_canNurseryAllocate())
16865 if descriptor
.wrapperCache
:
16866 methods
.append(CGDOMJSProxyHandler_objectMoved(descriptor
))
16868 if descriptor
.isMaybeCrossOriginObject():
16871 CGDOMJSProxyHandler_getOwnPropertyDescriptor(descriptor
),
16872 CGDOMJSProxyHandler_getSameOriginPrototype(descriptor
),
16873 CGDOMJSProxyHandler_definePropertySameOrigin(descriptor
),
16874 CGDOMJSProxyHandler_set(descriptor
),
16875 CGDOMJSProxyHandler_EnsureHolder(descriptor
),
16876 ClassUsingFromBaseDeclaration(
16877 "MaybeCrossOriginObjectMixins", "EnsureHolder"
16885 bases
=[ClassBase(parentClass
)],
16886 typeAliases
=typeAliases
,
16887 constructors
=constructors
,
16892 class CGDOMJSProxyHandlerDeclarer(CGThing
):
16894 A class for declaring a DOMProxyHandler.
16897 def __init__(self
, handlerThing
):
16898 self
.handlerThing
= handlerThing
16901 # Our class declaration should happen when we're defining
16905 return self
.handlerThing
.declare()
16908 class CGDOMJSProxyHandlerDefiner(CGThing
):
16910 A class for defining a DOMProxyHandler.
16913 def __init__(self
, handlerThing
):
16914 self
.handlerThing
= handlerThing
16920 return self
.handlerThing
.define()
16923 def stripTrailingWhitespace(text
):
16924 tail
= "\n" if text
.endswith("\n") else ""
16925 lines
= text
.splitlines()
16926 return "\n".join(line
.rstrip() for line
in lines
) + tail
16929 class MemberProperties
:
16930 def __init__(self
):
16931 self
.isCrossOriginMethod
= False
16932 self
.isCrossOriginGetter
= False
16933 self
.isCrossOriginSetter
= False
16936 def memberProperties(m
, descriptor
):
16937 props
= MemberProperties()
16939 if not m
.isIdentifierLess() or m
== descriptor
.operations
["Stringifier"]:
16940 if not m
.isStatic() and descriptor
.interface
.hasInterfacePrototypeObject():
16941 if m
.getExtendedAttribute("CrossOriginCallable"):
16942 props
.isCrossOriginMethod
= True
16944 if not m
.isStatic() and descriptor
.interface
.hasInterfacePrototypeObject():
16945 if m
.getExtendedAttribute("CrossOriginReadable"):
16946 props
.isCrossOriginGetter
= True
16948 if not m
.isStatic() and descriptor
.interface
.hasInterfacePrototypeObject():
16949 if m
.getExtendedAttribute("CrossOriginWritable"):
16950 props
.isCrossOriginSetter
= True
16951 elif m
.getExtendedAttribute("PutForwards"):
16952 if m
.getExtendedAttribute("CrossOriginWritable"):
16953 props
.isCrossOriginSetter
= True
16954 elif m
.getExtendedAttribute("Replaceable") or m
.getExtendedAttribute(
16955 "LegacyLenientSetter"
16957 if m
.getExtendedAttribute("CrossOriginWritable"):
16958 props
.isCrossOriginSetter
= True
16963 class CGDescriptor(CGThing
):
16964 def __init__(self
, descriptor
, attributeTemplates
):
16965 CGThing
.__init
__(self
)
16968 not descriptor
.concrete
16969 or descriptor
.interface
.hasInterfacePrototypeObject()
16970 or descriptor
.hasOrdinaryObjectPrototype()
16973 self
._deps
= descriptor
.interface
.getDeps()
16975 iteratorCGThings
= None
16977 descriptor
.interface
.isIterable()
16978 and descriptor
.interface
.maplikeOrSetlikeOrIterable
.isPairIterator()
16979 ) or descriptor
.interface
.isAsyncIterable():
16980 # 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.
16981 iteratorCGThings
= []
16983 descriptor
.interface
.maplikeOrSetlikeOrIterable
.iteratorType
.inner
16985 iteratorDescriptor
= descriptor
.getDescriptor(itr_iface
.identifier
.name
)
16986 iteratorCGThings
.append(
16987 CGWrapNonWrapperCacheMethod(
16988 iteratorDescriptor
, static
=True, signatureOnly
=True
16991 iteratorCGThings
= CGList(
16992 (CGIndenter(t
, declareOnly
=True) for t
in iteratorCGThings
), "\n"
16994 iteratorCGThings
= CGWrapper(iteratorCGThings
, pre
="\n", post
="\n")
16995 iteratorCGThings
= CGWrapper(
16997 toBindingNamespace(iteratorDescriptor
.name
), iteratorCGThings
17004 isIteratorInterface
= (
17005 descriptor
.interface
.isIteratorInterface()
17006 or descriptor
.interface
.isAsyncIteratorInterface()
17008 if not isIteratorInterface
:
17010 CGGeneric(declare
="typedef %s NativeType;\n" % descriptor
.nativeType
)
17012 parent
= descriptor
.interface
.parent
17016 "static_assert(IsRefcounted<NativeType>::value == IsRefcounted<%s::NativeType>::value,\n"
17017 ' "Can\'t inherit from an interface with a different ownership model.");\n'
17018 % toBindingNamespace(descriptor
.parentPrototypeName
)
17022 defaultToJSONMethod
= None
17023 needCrossOriginPropertyArrays
= False
17024 unscopableNames
= list()
17026 for n
in descriptor
.interface
.legacyFactoryFunctions
:
17028 CGClassConstructor(descriptor
, n
, LegacyFactoryFunctionName(n
))
17031 if descriptor
.attributeTemplates
is not None:
17032 for template
in descriptor
.attributeTemplates
:
17033 if template
.getter
is not None:
17035 CGTemplateForSpecializedGetter(descriptor
, template
)
17037 if template
.setter
is not None:
17039 CGTemplateForSpecializedSetter(descriptor
, template
)
17042 if descriptor
.interface
.reflectedHTMLAttributesReturningFrozenArray
:
17043 cgThings
.append(CGDefineHTMLAttributeSlots(descriptor
))
17045 for m
in descriptor
.interface
.members
:
17046 if m
.isMethod() and m
.identifier
.name
== "QueryInterface":
17049 props
= memberProperties(m
, descriptor
)
17052 if m
.getExtendedAttribute("Unscopable"):
17053 assert not m
.isStatic()
17054 unscopableNames
.append(m
.identifier
.name
)
17055 if m
.isDefaultToJSON():
17056 defaultToJSONMethod
= m
17058 not m
.isIdentifierLess()
17059 or m
== descriptor
.operations
["Stringifier"]
17062 assert descriptor
.interface
.hasInterfaceObject()
17063 cgThings
.append(CGStaticMethod(descriptor
, m
))
17064 if m
.returnsPromise():
17065 cgThings
.append(CGStaticMethodJitinfo(m
))
17066 elif descriptor
.interface
.hasInterfacePrototypeObject():
17067 specializedMethod
= CGSpecializedMethod(descriptor
, m
)
17068 cgThings
.append(specializedMethod
)
17069 if m
.returnsPromise():
17071 CGMethodPromiseWrapper(descriptor
, specializedMethod
)
17073 cgThings
.append(CGMemberJITInfo(descriptor
, m
))
17074 if props
.isCrossOriginMethod
:
17075 needCrossOriginPropertyArrays
= True
17076 # If we've hit the maplike/setlike member itself, go ahead and
17077 # generate its convenience functions.
17078 elif m
.isMaplikeOrSetlike():
17079 cgThings
.append(CGMaplikeOrSetlikeHelperGenerator(descriptor
, m
))
17081 if m
.type.isObservableArray():
17083 CGObservableArrayProxyHandlerGenerator(descriptor
, m
)
17085 cgThings
.append(CGObservableArrayHelperGenerator(descriptor
, m
))
17086 if m
.getExtendedAttribute("Unscopable"):
17087 assert not m
.isStatic()
17088 unscopableNames
.append(m
.identifier
.name
)
17090 assert descriptor
.interface
.hasInterfaceObject()
17091 cgThings
.append(CGStaticGetter(descriptor
, m
))
17092 elif descriptor
.interface
.hasInterfacePrototypeObject():
17093 template
= m
.getExtendedAttribute("BindingTemplate")
17094 if template
is not None:
17095 templateName
= template
[0][0]
17096 additionalArg
= template
[0][1]
17097 if not (m
.type.isPrimitive() or m
.type.isString()):
17099 "We only support primitives or strings on templated attributes. "
17100 "Attribute '%s' on interface '%s' has type '%s' but tries to "
17101 "use template '%s'"
17104 descriptor
.interface
.identifier
.name
,
17109 template
= attributeTemplates
.get(templateName
)
17110 specializedGetter
= CGSpecializedTemplatedGetter(
17111 descriptor
, m
, template
, additionalArg
17114 specializedGetter
= CGSpecializedGetter(descriptor
, m
)
17115 cgThings
.append(specializedGetter
)
17116 if m
.type.isPromise():
17118 CGGetterPromiseWrapper(descriptor
, specializedGetter
)
17120 if props
.isCrossOriginGetter
:
17121 needCrossOriginPropertyArrays
= True
17124 assert descriptor
.interface
.hasInterfaceObject()
17125 cgThings
.append(CGStaticSetter(descriptor
, m
))
17126 elif descriptor
.interface
.hasInterfacePrototypeObject():
17127 template
= m
.getExtendedAttribute("BindingTemplate")
17128 if template
is not None:
17129 if isinstance(template
[0], list):
17130 templateName
= template
[0][0]
17131 additionalArg
= template
[0][1]
17133 templateName
= template
[0]
17134 additionalArg
= None
17135 template
= attributeTemplates
.get(templateName
)
17136 specializedSetter
= CGSpecializedTemplatedSetter(
17137 descriptor
, m
, template
, additionalArg
17140 specializedSetter
= CGSpecializedSetter(descriptor
, m
)
17141 cgThings
.append(specializedSetter
)
17142 if props
.isCrossOriginSetter
:
17143 needCrossOriginPropertyArrays
= True
17144 elif m
.getExtendedAttribute("PutForwards"):
17145 cgThings
.append(CGSpecializedForwardingSetter(descriptor
, m
))
17146 if props
.isCrossOriginSetter
:
17147 needCrossOriginPropertyArrays
= True
17148 elif m
.getExtendedAttribute("Replaceable"):
17149 cgThings
.append(CGSpecializedReplaceableSetter(descriptor
, m
))
17150 elif m
.getExtendedAttribute("LegacyLenientSetter"):
17151 # XXX In this case, we need to add an include for mozilla/dom/Document.h to the generated cpp file.
17152 cgThings
.append(CGSpecializedLenientSetter(descriptor
, m
))
17155 and descriptor
.interface
.hasInterfacePrototypeObject()
17157 cgThings
.append(CGMemberJITInfo(descriptor
, m
))
17158 if m
.isConst() and m
.type.isPrimitive():
17159 cgThings
.append(CGConstDefinition(m
))
17161 if defaultToJSONMethod
:
17162 cgThings
.append(CGDefaultToJSONMethod(descriptor
, defaultToJSONMethod
))
17163 cgThings
.append(CGMemberJITInfo(descriptor
, defaultToJSONMethod
))
17165 if descriptor
.concrete
and not descriptor
.proxy
:
17166 if wantsAddProperty(descriptor
):
17167 cgThings
.append(CGAddPropertyHook(descriptor
))
17169 # Always have a finalize hook, regardless of whether the class
17170 # wants a custom hook.
17171 cgThings
.append(CGClassFinalizeHook(descriptor
))
17173 if wantsGetWrapperCache(descriptor
):
17174 cgThings
.append(CGGetWrapperCacheHook(descriptor
))
17176 if descriptor
.concrete
and descriptor
.wrapperCache
and not descriptor
.proxy
:
17177 cgThings
.append(CGClassObjectMovedHook(descriptor
))
17179 properties
= PropertyArrays(descriptor
)
17180 cgThings
.append(CGGeneric(define
=str(properties
)))
17181 cgThings
.append(CGNativeProperties(descriptor
, properties
))
17183 if defaultToJSONMethod
:
17184 # Now that we know about our property arrays, we can
17185 # output our "collect attribute values" method, which uses those.
17187 CGCollectJSONAttributesMethod(descriptor
, defaultToJSONMethod
)
17190 # Declare our DOMProxyHandler.
17191 if descriptor
.concrete
and descriptor
.proxy
:
17196 static_assert(std::is_base_of_v<nsISupports, ${nativeType}>,
17197 "We don't support non-nsISupports native classes for "
17198 "proxy-based bindings yet");
17201 nativeType
=descriptor
.nativeType
,
17205 if not descriptor
.wrapperCache
:
17207 "We need a wrappercache to support expandos for proxy-based "
17208 "bindings (" + descriptor
.name
+ ")"
17210 handlerThing
= CGDOMJSProxyHandler(descriptor
)
17211 cgThings
.append(CGDOMJSProxyHandlerDeclarer(handlerThing
))
17212 cgThings
.append(CGProxyIsProxy(descriptor
))
17213 cgThings
.append(CGProxyUnwrap(descriptor
))
17215 # Set up our Xray callbacks as needed. This needs to come
17216 # after we have our DOMProxyHandler defined.
17217 if descriptor
.wantsXrays
:
17218 if descriptor
.concrete
and descriptor
.proxy
:
17219 if descriptor
.needsXrayNamedDeleterHook():
17220 cgThings
.append(CGDeleteNamedProperty(descriptor
))
17221 elif descriptor
.needsXrayResolveHooks():
17222 cgThings
.append(CGResolveOwnPropertyViaResolve(descriptor
))
17224 CGEnumerateOwnPropertiesViaGetOwnPropertyNames(descriptor
)
17226 if descriptor
.wantsXrayExpandoClass
:
17227 cgThings
.append(CGXrayExpandoJSClass(descriptor
))
17229 # Now that we have our ResolveOwnProperty/EnumerateOwnProperties stuff
17230 # done, set up our NativePropertyHooks.
17231 cgThings
.append(CGNativePropertyHooks(descriptor
, properties
))
17233 if descriptor
.interface
.isNamespace():
17234 cgThings
.append(CGNamespaceObjectJSClass(descriptor
))
17235 elif descriptor
.interface
.hasInterfaceObject():
17236 cgThings
.append(CGClassConstructor(descriptor
, descriptor
.interface
.ctor()))
17237 cgThings
.append(CGInterfaceObjectInfo(descriptor
))
17238 cgThings
.append(CGLegacyFactoryFunctions(descriptor
))
17240 cgThings
.append(CGLegacyCallHook(descriptor
))
17241 if descriptor
.interface
.getExtendedAttribute("NeedResolve"):
17242 cgThings
.append(CGResolveHook(descriptor
))
17243 cgThings
.append(CGMayResolveHook(descriptor
))
17244 cgThings
.append(CGEnumerateHook(descriptor
))
17246 if descriptor
.hasNamedPropertiesObject
:
17247 cgThings
.append(CGGetNamedPropertiesObjectMethod(descriptor
))
17249 if descriptor
.interface
.hasInterfacePrototypeObject():
17250 cgThings
.append(CGPrototypeJSClass(descriptor
, properties
))
17253 descriptor
.interface
.hasInterfaceObject()
17254 and not descriptor
.interface
.isExternal()
17255 and descriptor
.isExposedConditionally()
17257 cgThings
.append(CGConstructorEnabled(descriptor
))
17260 descriptor
.interface
.hasMembersInSlots()
17261 and descriptor
.interface
.hasChildInterfaces()
17264 "We don't support members in slots on "
17265 "non-leaf interfaces like %s" % descriptor
.interface
.identifier
.name
17268 if descriptor
.needsMissingPropUseCounters
:
17269 cgThings
.append(CGCountMaybeMissingProperty(descriptor
))
17271 # CGDOMProxyJSClass/CGDOMJSClass need GetProtoObjectHandle, but we don't
17272 # want to export it for the iterator interfaces, or if we don't need it
17273 # for child interfaces or for the named properties object.
17274 protoObjectHandleGetterIsStatic
= descriptor
.concrete
and (
17275 isIteratorInterface
17277 descriptor
.interface
.hasInterfacePrototypeObject()
17278 and not descriptor
.interface
.hasChildInterfaces()
17279 and not descriptor
.hasNamedPropertiesObject
17282 if descriptor
.concrete
:
17283 if descriptor
.interface
.isSerializable():
17284 cgThings
.append(CGSerializer(descriptor
))
17285 cgThings
.append(CGDeserializer(descriptor
))
17287 if protoObjectHandleGetterIsStatic
:
17289 CGGetProtoObjectHandleMethod(
17290 descriptor
, static
=True, signatureOnly
=True
17294 if descriptor
.proxy
:
17295 cgThings
.append(CGDOMJSProxyHandlerDefiner(handlerThing
))
17296 cgThings
.append(CGDOMProxyJSClass(descriptor
))
17298 cgThings
.append(CGDOMJSClass(descriptor
))
17300 if descriptor
.interface
.hasMembersInSlots():
17301 cgThings
.append(CGUpdateMemberSlotsMethod(descriptor
))
17303 if descriptor
.isGlobal():
17304 assert descriptor
.wrapperCache
17305 cgThings
.append(CGWrapGlobalMethod(descriptor
, properties
))
17306 elif descriptor
.wrapperCache
:
17307 cgThings
.append(CGWrapWithCacheMethod(descriptor
))
17308 cgThings
.append(CGWrapMethod(descriptor
))
17311 CGWrapNonWrapperCacheMethod(descriptor
, static
=isIteratorInterface
)
17314 # If we're not wrappercached, we don't know how to clear our
17315 # cached values, since we can't get at the JSObject.
17316 if descriptor
.wrapperCache
:
17318 CGClearCachedValueMethod(descriptor
, m
)
17319 for m
in clearableCachedAttrs(descriptor
)
17322 haveUnscopables
= (
17323 len(unscopableNames
) != 0
17324 and descriptor
.interface
.hasInterfacePrototypeObject()
17326 if haveUnscopables
:
17330 CGGeneric("static const char* const unscopableNames[] = {"),
17333 [CGGeneric('"%s"' % name
) for name
in unscopableNames
]
17334 + [CGGeneric("nullptr")],
17344 legacyWindowAliases
= descriptor
.interface
.legacyWindowAliases
17345 haveLegacyWindowAliases
= len(legacyWindowAliases
) != 0
17346 if haveLegacyWindowAliases
:
17350 CGGeneric("static const char* const legacyWindowAliases[] = {"),
17354 CGGeneric('"%s"' % name
)
17355 for name
in legacyWindowAliases
17357 + [CGGeneric("nullptr")],
17367 if not descriptor
.hasOrdinaryObjectPrototype():
17368 # CGCreateInterfaceObjectsMethod needs to come after our
17369 # CGDOMJSClass and unscopables, if any.
17371 CGCreateInterfaceObjectsMethod(
17375 haveLegacyWindowAliases
,
17376 static
=isIteratorInterface
,
17380 # CGGetProtoObjectMethod and CGGetConstructorObjectMethod need
17381 # to come after CGCreateInterfaceObjectsMethod.
17382 if descriptor
.interface
.hasInterfacePrototypeObject():
17384 CGGetProtoObjectHandleMethod(
17385 descriptor
, static
=protoObjectHandleGetterIsStatic
17388 if descriptor
.interface
.hasChildInterfaces():
17389 assert not isIteratorInterface
17390 cgThings
.append(CGGetProtoObjectMethod(descriptor
))
17391 if descriptor
.interface
.hasInterfaceObject():
17392 cgThings
.append(CGGetConstructorObjectHandleMethod(descriptor
))
17394 CGCreateAndDefineOnGlobalMethod(
17399 # See whether we need to generate cross-origin property arrays.
17400 if needCrossOriginPropertyArrays
:
17401 cgThings
.append(CGCrossOriginProperties(descriptor
))
17403 cgThings
= CGList((CGIndenter(t
, declareOnly
=True) for t
in cgThings
), "\n")
17404 cgThings
= CGWrapper(cgThings
, pre
="\n", post
="\n")
17405 cgThings
= CGWrapper(
17406 CGNamespace(toBindingNamespace(descriptor
.name
), cgThings
), post
="\n"
17408 self
.cgRoot
= CGList([iteratorCGThings
, cgThings
], "\n")
17411 return self
.cgRoot
.declare()
17414 return self
.cgRoot
.define()
17420 class CGNamespacedEnum(CGThing
):
17421 def __init__(self
, namespace
, enumName
, names
, values
, comment
=""):
17425 # Account for explicit enum values.
17427 for i
in range(0, len(names
)):
17428 if len(values
) > i
and values
[i
] is not None:
17429 entry
= "%s = %s" % (names
[i
], values
[i
])
17432 entries
.append(entry
)
17435 entries
.append("_" + enumName
+ "_Count")
17438 entries
= [" " + e
for e
in entries
]
17440 # Build the enum body.
17441 enumstr
= comment
+ "enum %s : uint16_t\n{\n%s\n};\n" % (
17443 ",\n".join(entries
),
17445 curr
= CGGeneric(declare
=enumstr
)
17447 # Add some whitespace padding.
17448 curr
= CGWrapper(curr
, pre
="\n", post
="\n")
17450 # Add the namespace.
17451 curr
= CGNamespace(namespace
, curr
)
17454 typedef
= "\ntypedef %s::%s %s;\n\n" % (namespace
, enumName
, enumName
)
17455 curr
= CGList([curr
, CGGeneric(declare
=typedef
)])
17461 return self
.node
.declare()
17467 def initIdsClassMethod(identifiers
, atomCacheName
):
17469 '!atomsCache->%s.init(cx, "%s")' % (CGDictionary
.makeIdName(id), id)
17470 for id in identifiers
17475 MOZ_ASSERT(reinterpret_cast<jsid*>(atomsCache)->isVoid());
17477 // Initialize these in reverse order so that any failure leaves the first one
17484 idinit
=" ||\n ".join(idinit
),
17486 return ClassMethod(
17489 [Argument("JSContext*", "cx"), Argument("%s*" % atomCacheName
, "atomsCache")],
17492 visibility
="private",
17496 class CGDictionary(CGThing
):
17497 def __init__(self
, dictionary
, descriptorProvider
):
17498 self
.dictionary
= dictionary
17499 self
.descriptorProvider
= descriptorProvider
17500 self
.needToInitIds
= len(dictionary
.members
) > 0
17501 self
.memberInfo
= [
17504 getJSToNativeConversionInfo(
17506 descriptorProvider
,
17507 isMember
="Dictionary",
17508 isOptional
=member
.canHaveMissingValue(),
17509 isKnownMissing
=not dictionary
.needsConversionFromJS
,
17510 defaultValue
=member
.defaultValue
,
17511 sourceDescription
=self
.getMemberSourceDescription(member
),
17514 for member
in dictionary
.members
17517 # If we have a union member which is going to be declared in a different
17518 # header but contains something that will be declared in the same header
17519 # as us, bail: the C++ includes won't work out.
17520 for member
in dictionary
.members
:
17521 type = member
.type.unroll()
17522 if type.isUnion() and CGHeaders
.getUnionDeclarationFilename(
17523 descriptorProvider
.getConfig(), type
17524 ) != CGHeaders
.getDeclarationFilename(dictionary
):
17525 for t
in type.flatMemberTypes
:
17526 if t
.isDictionary() and CGHeaders
.getDeclarationFilename(
17528 ) == CGHeaders
.getDeclarationFilename(dictionary
):
17530 "Dictionary contains a union that will live in a different "
17531 "header that contains a dictionary from the same header as "
17532 "the original dictionary. This won't compile. Move the "
17533 "inner dictionary to a different Web IDL file to move it "
17534 "to a different header.\n%s\n%s"
17535 % (t
.location
, t
.inner
.location
)
17537 self
.structs
= self
.getStructs()
17540 return self
.structs
.declare()
17543 return self
.structs
.define()
17546 if self
.dictionary
.parent
:
17547 return self
.makeClassName(self
.dictionary
.parent
)
17548 return "DictionaryBase"
17550 def initMethod(self
):
17552 This function outputs the body of the Init() method for the dictionary.
17554 For the most part, this is some bookkeeping for our atoms so
17555 we can avoid atomizing strings all the time, then we just spit
17556 out the getMemberConversion() output for each member,
17557 separated by newlines.
17562 // Passing a null JSContext is OK only if we're initing from null,
17563 // Since in that case we will not have to do any property gets
17564 // Also evaluate isNullOrUndefined in order to avoid false-positive
17565 // checkers by static analysis tools
17566 MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined());
17570 if self
.needToInitIds
:
17573 ${dictName}Atoms* atomsCache = nullptr;
17575 atomsCache = GetAtomCache<${dictName}Atoms>(cx);
17576 if (reinterpret_cast<jsid*>(atomsCache)->isVoid() &&
17577 !InitIds(cx, atomsCache)) {
17583 dictName
=self
.makeClassName(self
.dictionary
),
17586 if self
.dictionary
.parent
:
17589 // Per spec, we init the parent's members first
17590 if (!${dictName}::Init(cx, val)) {
17595 dictName
=self
.makeClassName(self
.dictionary
.parent
),
17600 if (!IsConvertibleToDictionary(val)) {
17601 return cx.ThrowErrorMessage<MSG_CONVERSION_ERROR>(sourceDescription, "dictionary");
17607 memberInits
= [self
.getMemberConversion(m
).define() for m
in self
.memberInfo
]
17611 bool isNull = val.isNullOrUndefined();
17612 // We only need these if !isNull, in which case we have |cx|.
17613 Maybe<JS::Rooted<JSObject *> > object;
17614 Maybe<JS::Rooted<JS::Value> > temp;
17617 object.emplace(cx, &val.toObject());
17622 memberInits
="\n".join(memberInits
),
17625 body
+= "return true;\n"
17627 return ClassMethod(
17631 Argument("BindingCallContext&", "cx"),
17632 Argument("JS::Handle<JS::Value>", "val"),
17633 Argument("const char*", "sourceDescription", default
='"Value"'),
17634 Argument("bool", "passedToJSImpl", default
="false"),
17639 def initWithoutCallContextMethod(self
):
17641 This function outputs the body of an Init() method for the dictionary
17642 that takes just a JSContext*. This is needed for non-binding consumers.
17646 // We don't want to use sourceDescription for our context here;
17647 // that's not really what it's formatted for.
17648 BindingCallContext cx(cx_, nullptr);
17649 return Init(cx, val, sourceDescription, passedToJSImpl);
17652 return ClassMethod(
17656 Argument("JSContext*", "cx_"),
17657 Argument("JS::Handle<JS::Value>", "val"),
17658 Argument("const char*", "sourceDescription", default
='"Value"'),
17659 Argument("bool", "passedToJSImpl", default
="false"),
17664 def simpleInitMethod(self
):
17666 This function outputs the body of the Init() method for the dictionary,
17667 for cases when we are just default-initializing it.
17670 relevantMembers
= [
17672 for m
in self
.memberInfo
17673 # We only need to init the things that can have
17675 if m
[0].optional
and m
[0].defaultValue
17678 # We mostly avoid outputting code that uses cx in our native-to-JS
17679 # conversions, but there is one exception: we may have a
17680 # dictionary-typed member that _does_ generally support conversion from
17681 # JS. If we have such a thing, we can pass it a null JSContext and
17682 # JS::NullHandleValue to default-initialize it, but since the
17683 # native-to-JS templates hardcode `cx` as the JSContext value, we're
17684 # going to need to provide that.
17685 haveMemberThatNeedsCx
= any(
17686 m
[0].type.isDictionary() and m
[0].type.unroll().inner
.needsConversionFromJS
17687 for m
in relevantMembers
17689 if haveMemberThatNeedsCx
:
17692 JSContext* cx = nullptr;
17698 if self
.dictionary
.parent
:
17699 if self
.dictionary
.parent
.needsConversionFromJS
:
17700 args
= "nullptr, JS::NullHandleValue"
17705 // We init the parent's members first
17706 if (!${dictName}::Init(${args})) {
17711 dictName
=self
.makeClassName(self
.dictionary
.parent
),
17716 self
.getMemberConversion(m
, isKnownMissing
=True).define()
17717 for m
in relevantMembers
17724 memberInits
="\n".join(memberInits
),
17727 body
+= "return true;\n"
17729 return ClassMethod(
17733 Argument("const char*", "sourceDescription", default
='"Value"'),
17734 Argument("bool", "passedToJSImpl", default
="false"),
17739 def initFromJSONMethod(self
):
17740 return ClassMethod(
17743 [Argument("const nsAString&", "aJSON")],
17747 JSObject* cleanGlobal = SimpleGlobalObject::Create(SimpleGlobalObject::GlobalType::BindingDetail);
17748 if (!cleanGlobal) {
17751 if (!jsapi.Init(cleanGlobal)) {
17754 JSContext* cx = jsapi.cx();
17755 JS::Rooted<JS::Value> json(cx);
17756 bool ok = ParseJSON(cx, aJSON, &json);
17757 NS_ENSURE_TRUE(ok, false);
17758 return Init(cx, json);
17763 def toJSONMethod(self
):
17764 return ClassMethod(
17767 [Argument("nsAString&", "aJSON")],
17772 JSContext *cx = jsapi.cx();
17773 // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here
17774 // because we'll only be creating objects, in ways that have no
17775 // side-effects, followed by a call to JS::ToJSONMaybeSafely,
17776 // which likewise guarantees no side-effects for the sorts of
17777 // things we will pass it.
17778 JSObject* scope = UnprivilegedJunkScopeOrWorkerGlobal(fallible);
17780 JS_ReportOutOfMemory(cx);
17783 JSAutoRealm ar(cx, scope);
17784 JS::Rooted<JS::Value> val(cx);
17785 if (!ToObjectInternal(cx, &val)) {
17788 JS::Rooted<JSObject*> obj(cx, &val.toObject());
17789 return StringifyToJSON(cx, obj, aJSON);
17795 def toObjectInternalMethod(self
):
17797 if self
.needToInitIds
:
17800 ${dictName}Atoms* atomsCache = GetAtomCache<${dictName}Atoms>(cx);
17801 if (reinterpret_cast<jsid*>(atomsCache)->isVoid() &&
17802 !InitIds(cx, atomsCache)) {
17807 dictName
=self
.makeClassName(self
.dictionary
),
17810 if self
.dictionary
.parent
:
17813 // Per spec, we define the parent's members first
17814 if (!${dictName}::ToObjectInternal(cx, rval)) {
17817 JS::Rooted<JSObject*> obj(cx, &rval.toObject());
17820 dictName
=self
.makeClassName(self
.dictionary
.parent
),
17825 JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx));
17829 rval.set(JS::ObjectValue(*obj));
17834 if self
.memberInfo
:
17836 self
.getMemberDefinition(m
).define() for m
in self
.memberInfo
17838 body
+= "\nreturn true;\n"
17840 return ClassMethod(
17841 "ToObjectInternal",
17844 Argument("JSContext*", "cx"),
17845 Argument("JS::MutableHandle<JS::Value>", "rval"),
17851 def initIdsMethod(self
):
17852 assert self
.needToInitIds
17853 return initIdsClassMethod(
17854 [m
.identifier
.name
for m
in self
.dictionary
.members
],
17855 "%sAtoms" % self
.makeClassName(self
.dictionary
),
17858 def traceDictionaryMethod(self
):
17860 if self
.dictionary
.parent
:
17861 cls
= self
.makeClassName(self
.dictionary
.parent
)
17862 body
+= "%s::TraceDictionary(trc);\n" % cls
17865 self
.getMemberTrace(m
)
17866 for m
in self
.dictionary
.members
17867 if typeNeedsRooting(m
.type)
17871 body
+= "\n".join(memberTraces
)
17873 return ClassMethod(
17877 Argument("JSTracer*", "trc"),
17883 def dictionaryNeedsCycleCollection(dictionary
):
17884 return any(idlTypeNeedsCycleCollection(m
.type) for m
in dictionary
.members
) or (
17886 and CGDictionary
.dictionaryNeedsCycleCollection(dictionary
.parent
)
17889 def traverseForCCMethod(self
):
17891 if self
.dictionary
.parent
and self
.dictionaryNeedsCycleCollection(
17892 self
.dictionary
.parent
17894 cls
= self
.makeClassName(self
.dictionary
.parent
)
17895 body
+= "%s::TraverseForCC(aCallback, aFlags);\n" % cls
17897 for m
, _
in self
.memberInfo
:
17898 if idlTypeNeedsCycleCollection(m
.type):
17899 memberName
= self
.makeMemberName(m
.identifier
.name
)
17901 'ImplCycleCollectionTraverse(aCallback, %s, "%s", aFlags);\n'
17902 % (memberName
, memberName
)
17905 return ClassMethod(
17909 Argument("nsCycleCollectionTraversalCallback&", "aCallback"),
17910 Argument("uint32_t", "aFlags"),
17913 # Inline so we don't pay a codesize hit unless someone actually uses
17914 # this traverse method.
17919 def unlinkForCCMethod(self
):
17921 if self
.dictionary
.parent
and self
.dictionaryNeedsCycleCollection(
17922 self
.dictionary
.parent
17924 cls
= self
.makeClassName(self
.dictionary
.parent
)
17925 body
+= "%s::UnlinkForCC();\n" % cls
17927 for m
, _
in self
.memberInfo
:
17928 if idlTypeNeedsCycleCollection(m
.type):
17929 memberName
= self
.makeMemberName(m
.identifier
.name
)
17930 body
+= "ImplCycleCollectionUnlink(%s);\n" % memberName
17932 return ClassMethod(
17937 # Inline so we don't pay a codesize hit unless someone actually uses
17938 # this unlink method.
17943 def assignmentOperator(self
):
17945 body
.append(CGGeneric("%s::operator=(aOther);\n" % self
.base()))
17947 for m
, _
in self
.memberInfo
:
17948 memberName
= self
.makeMemberName(m
.identifier
.name
)
17949 if m
.canHaveMissingValue():
17950 memberAssign
= CGGeneric(
17954 if (aOther.${name}.WasPassed()) {
17955 ${name}.Construct(aOther.${name}.Value());
17962 memberAssign
= CGGeneric("%s = aOther.%s;\n" % (memberName
, memberName
))
17963 body
.append(memberAssign
)
17964 body
.append(CGGeneric("return *this;\n"))
17965 return ClassMethod(
17967 "%s&" % self
.makeClassName(self
.dictionary
),
17968 [Argument("const %s&" % self
.makeClassName(self
.dictionary
), "aOther")],
17969 body
=body
.define(),
17972 def equalityOperator(self
):
17973 # For now we only allow equality operators if our members have a string
17974 # type, a primitive type or an enum type.
17976 m
.type.isString() or m
.type.isPrimitive() or m
.type.isEnum()
17977 for m
in self
.dictionary
.members
17980 "[GenerateEqualityOperator] set on %s, but it"
17981 % self
.dictionary
.needsEqualityOperator
.identifier
.name
17983 if self
.dictionary
.needsEqualityOperator
!= self
.dictionary
:
17984 err
+= "s ancestor %s" % self
.dictionary
.identifier
.name
17985 err
+= " contains types other than string, primitive or enum types."
17986 raise TypeError(err
)
17990 if self
.dictionary
.parent
:
17991 # If we have a parent dictionary we have to call its equals
17993 parentTest
= CGGeneric(
17996 if (!${base}::operator==(aOther)) {
18000 base
=self
.makeClassName(self
.dictionary
.parent
),
18003 body
.append(parentTest
)
18005 for m
, _
in self
.memberInfo
:
18006 memberName
= self
.makeMemberName(m
.identifier
.name
)
18007 memberTest
= CGGeneric(
18010 if (${memberName} != aOther.${memberName}) {
18014 memberName
=memberName
,
18017 body
.append(memberTest
)
18018 body
.append(CGGeneric("return true;\n"))
18019 return ClassMethod(
18022 [Argument("const %s&" % self
.makeClassName(self
.dictionary
), "aOther")],
18024 body
=body
.define(),
18027 def getStructs(self
):
18028 d
= self
.dictionary
18029 selfName
= self
.makeClassName(d
)
18032 self
.makeMemberName(m
[0].identifier
.name
),
18033 self
.getMemberType(m
),
18034 visibility
="public",
18035 body
=self
.getMemberInitializer(m
),
18036 hasIgnoreInitCheckFlag
=True,
18038 for m
in self
.memberInfo
18041 # We always want to init our parent with our non-initializing
18042 # constructor arg, because either we're about to init ourselves (and
18043 # hence our parent) or we don't want any init happening.
18044 baseConstructors
= [
18046 % (self
.makeClassName(d
.parent
), self
.getNonInitializingCtorArg())
18049 baseConstructors
= None
18051 if d
.needsConversionFromJS
:
18052 initArgs
= "nullptr, JS::NullHandleValue"
18058 visibility
="public",
18059 baseConstructors
=baseConstructors
,
18061 "// Safe to pass a null context if we pass a null value\n"
18062 "Init(%s);\n" % initArgs
18066 [Argument("const FastDictionaryInitializer&", "")],
18067 visibility
="public",
18068 baseConstructors
=baseConstructors
,
18071 body
='// Do nothing here; this is used by our "Fast" subclass\n',
18076 if self
.needToInitIds
:
18077 methods
.append(self
.initIdsMethod())
18079 if d
.needsConversionFromJS
:
18080 methods
.append(self
.initMethod())
18081 methods
.append(self
.initWithoutCallContextMethod())
18083 methods
.append(self
.simpleInitMethod())
18085 canBeRepresentedAsJSON
= self
.dictionarySafeToJSONify(d
)
18086 if canBeRepresentedAsJSON
and d
.getExtendedAttribute("GenerateInitFromJSON"):
18087 methods
.append(self
.initFromJSONMethod())
18089 if d
.needsConversionToJS
:
18090 methods
.append(self
.toObjectInternalMethod())
18092 if canBeRepresentedAsJSON
and d
.getExtendedAttribute("GenerateToJSON"):
18093 methods
.append(self
.toJSONMethod())
18095 methods
.append(self
.traceDictionaryMethod())
18098 if self
.dictionaryNeedsCycleCollection(d
):
18099 methods
.append(self
.traverseForCCMethod())
18100 methods
.append(self
.unlinkForCCMethod())
18101 except CycleCollectionUnsupported
:
18102 # We have some member that we don't know how to CC. Don't output
18103 # our cycle collection overloads, so attempts to CC us will fail to
18104 # compile instead of misbehaving.
18109 [Argument("%s&&" % selfName
, "aOther")],
18111 visibility
="public",
18112 baseConstructors
=baseConstructors
,
18116 if CGDictionary
.isDictionaryCopyConstructible(d
):
18117 disallowCopyConstruction
= False
18118 # Note: gcc's -Wextra has a warning against not initializng our
18119 # base explicitly. If we have one. Use our non-initializing base
18120 # constructor to get around that.
18123 [Argument("const %s&" % selfName
, "aOther")],
18125 visibility
="public",
18126 baseConstructors
=baseConstructors
,
18128 body
="*this = aOther;\n",
18131 methods
.append(self
.assignmentOperator())
18133 disallowCopyConstruction
= True
18135 if d
.needsEqualityOperator
:
18136 methods
.append(self
.equalityOperator())
18137 elif d
.parent
and d
.parent
.needsEqualityOperator
:
18144 "const %s&" % self
.makeClassName(self
.dictionary
), "aOther"
18147 visibility
="public",
18154 bases
=[ClassBase(self
.base())],
18156 constructors
=ctors
,
18159 disallowCopyConstruction
=disallowCopyConstruction
,
18162 fastDictionaryCtor
= ClassConstructor(
18164 visibility
="public",
18166 baseConstructors
=["%s(%s)" % (selfName
, self
.getNonInitializingCtorArg())],
18167 body
="// Doesn't matter what int we pass to the parent constructor\n",
18170 fastStruct
= CGClass(
18172 bases
=[ClassBase(selfName
)],
18173 constructors
=[fastDictionaryCtor
],
18177 return CGList([struct
, CGNamespace("binding_detail", fastStruct
)], "\n")
18180 return self
.dictionary
.getDeps()
18183 def makeDictionaryName(dictionary
):
18184 return dictionary
.identifier
.name
18186 def makeClassName(self
, dictionary
):
18187 return self
.makeDictionaryName(dictionary
)
18190 def makeMemberName(name
):
18191 return "m" + name
[0].upper() + IDLToCIdentifier(name
[1:])
18193 def getMemberType(self
, memberInfo
):
18194 member
, conversionInfo
= memberInfo
18195 # We can't handle having a holderType here
18196 assert conversionInfo
.holderType
is None
18198 if member
.getExtendedAttribute("BinaryType"):
18199 return member
.getExtendedAttribute("BinaryType")[0]
18201 declType
= conversionInfo
.declType
18202 if conversionInfo
.dealWithOptional
:
18203 declType
= CGTemplatedType("Optional", declType
)
18204 return declType
.define()
18206 def getMemberConversion(self
, memberInfo
, isKnownMissing
=False):
18208 A function that outputs the initialization of a single dictionary
18209 member from the given dictionary value.
18211 We start with our conversionInfo, which tells us how to
18212 convert a JS::Value to whatever type this member is. We
18213 substiture the template from the conversionInfo with values
18214 that point to our "temp" JS::Value and our member (which is
18215 the C++ value we want to produce). The output is a string of
18216 code to do the conversion. We store this string in
18217 conversionReplacements["convert"].
18219 Now we have three different ways we might use (or skip) this
18220 string of code, depending on whether the value is required,
18221 optional with default value, or optional without default
18222 value. We set up a template in the 'conversion' variable for
18223 exactly how to do this, then substitute into it from the
18224 conversionReplacements dictionary.
18226 member
, conversionInfo
= memberInfo
18228 # We should only be initializing things with default values if
18229 # we're always-missing.
18230 assert not isKnownMissing
or (member
.optional
and member
.defaultValue
)
18233 "declName": self
.makeMemberName(member
.identifier
.name
),
18234 # We need a holder name for external interfaces, but
18235 # it's scoped down to the conversion so we can just use
18236 # anything we want.
18237 "holderName": "holder",
18238 "passedToJSImpl": "passedToJSImpl",
18242 replacements
["val"] = "(JS::NullHandleValue)"
18244 replacements
["val"] = "temp.ref()"
18245 replacements
["maybeMutableVal"] = "temp.ptr()"
18247 # We can't handle having a holderType here
18248 assert conversionInfo
.holderType
is None
18249 if conversionInfo
.dealWithOptional
:
18250 replacements
["declName"] = "(" + replacements
["declName"] + ".Value())"
18251 if member
.defaultValue
:
18253 replacements
["haveValue"] = "false"
18255 replacements
["haveValue"] = "!isNull && !temp->isUndefined()"
18257 propId
= self
.makeIdName(member
.identifier
.name
)
18258 propGet
= "JS_GetPropertyById(cx, *object, atomsCache->%s, temp.ptr())" % propId
18260 conversionReplacements
= {
18261 "prop": self
.makeMemberName(member
.identifier
.name
),
18262 "convert": string
.Template(conversionInfo
.template
).substitute(
18265 "propGet": propGet
,
18267 # The conversion code will only run where a default value or a value passed
18268 # by the author needs to get converted, so we can remember if we have any
18269 # members present here.
18270 conversionReplacements
["convert"] += "mIsAnyMemberPresent = true;\n"
18274 setTempValue
= CGGeneric(
18283 conditions
= getConditionList(member
, "cx", "*object")
18284 if len(conditions
) != 0:
18285 setTempValue
= CGIfElseWrapper(
18286 conditions
.define(),
18288 CGGeneric("temp->setUndefined();\n"),
18290 setTempValue
= CGIfWrapper(setTempValue
, "!isNull")
18291 conversion
= setTempValue
.define()
18293 if member
.defaultValue
:
18294 if member
.type.isUnion() and (
18295 not member
.type.nullable()
18296 or not isinstance(member
.defaultValue
, IDLNullValue
)
18298 # Since this has a default value, it might have been initialized
18299 # already. Go ahead and uninit it before we try to init it
18301 memberName
= self
.makeMemberName(member
.identifier
.name
)
18302 if member
.type.nullable():
18303 conversion
+= fill(
18305 if (!${memberName}.IsNull()) {
18306 ${memberName}.Value().Uninit();
18309 memberName
=memberName
,
18312 conversion
+= "%s.Uninit();\n" % memberName
18313 conversion
+= "${convert}"
18314 elif not conversionInfo
.dealWithOptional
:
18315 # We're required, but have no default value. Make sure
18316 # that we throw if we have no value provided.
18317 conversion
+= dedent(
18319 if (!isNull && !temp->isUndefined()) {
18322 // Don't error out if we have no cx. In that
18323 // situation the caller is default-constructing us and we'll
18324 // just assume they know what they're doing.
18325 return cx.ThrowErrorMessage<MSG_MISSING_REQUIRED_DICTIONARY_MEMBER>("%s");
18328 % self
.getMemberSourceDescription(member
)
18330 conversionReplacements
["convert"] = indent(
18331 conversionReplacements
["convert"]
18335 "if (!isNull && !temp->isUndefined()) {\n"
18336 " ${prop}.Construct();\n"
18340 conversionReplacements
["convert"] = indent(
18341 conversionReplacements
["convert"]
18344 return CGGeneric(string
.Template(conversion
).substitute(conversionReplacements
))
18346 def getMemberDefinition(self
, memberInfo
):
18347 member
= memberInfo
[0]
18348 declType
= memberInfo
[1].declType
18349 memberLoc
= self
.makeMemberName(member
.identifier
.name
)
18350 if not member
.canHaveMissingValue():
18351 memberData
= memberLoc
18353 # The data is inside the Optional<>
18354 memberData
= "%s.InternalValue()" % memberLoc
18356 # If you have to change this list (which you shouldn't!), make sure it
18357 # continues to match the list in test_Object.prototype_props.html
18358 if member
.identifier
.name
in [
18365 "propertyIsEnumerable",
18366 "__defineGetter__",
18367 "__defineSetter__",
18368 "__lookupGetter__",
18369 "__lookupSetter__",
18373 "'%s' member of %s dictionary shadows "
18374 "a property of Object.prototype, and Xrays to "
18375 "Object can't handle that.\n"
18378 member
.identifier
.name
,
18379 self
.dictionary
.identifier
.name
,
18385 "JS_DefinePropertyById(cx, obj, atomsCache->%s, temp, JSPROP_ENUMERATE)"
18386 % self
.makeIdName(member
.identifier
.name
)
18389 innerTemplate
= wrapForType(
18391 self
.descriptorProvider
,
18393 "result": "currentValue",
18395 "if (!%s) {\n" " return false;\n" "}\n" "break;\n" % propDef
18397 "jsvalRef": "temp",
18398 "jsvalHandle": "&temp",
18399 "returnsNewObject": False,
18400 # 'obj' can just be allowed to be the string "obj", since that
18401 # will be our dictionary object, which is presumably itself in
18403 "spiderMonkeyInterfacesAreStructs": True,
18406 conversion
= CGGeneric(innerTemplate
)
18407 conversion
= CGWrapper(
18410 "JS::Rooted<JS::Value> temp(cx);\n"
18411 "%s const & currentValue = %s;\n" % (declType
.define(), memberData
)
18415 # Now make sure that our successCode can actually break out of the
18416 # conversion. This incidentally gives us a scope for 'temp' and
18418 conversion
= CGWrapper(
18419 CGIndenter(conversion
),
18422 " // block for our 'break' successCode and scope for 'temp' and 'currentValue'\n"
18424 post
="} while(false);\n",
18426 if member
.canHaveMissingValue():
18427 # Only do the conversion if we have a value
18428 conversion
= CGIfWrapper(conversion
, "%s.WasPassed()" % memberLoc
)
18429 conditions
= getConditionList(member
, "cx", "obj")
18430 if len(conditions
) != 0:
18431 conversion
= CGIfWrapper(conversion
, conditions
.define())
18434 def getMemberTrace(self
, member
):
18436 assert typeNeedsRooting(type)
18437 memberLoc
= self
.makeMemberName(member
.identifier
.name
)
18438 if not member
.canHaveMissingValue():
18439 memberData
= memberLoc
18441 # The data is inside the Optional<>
18442 memberData
= "%s.Value()" % memberLoc
18444 memberName
= "%s.%s" % (self
.makeClassName(self
.dictionary
), memberLoc
)
18446 if type.isObject():
18448 'JS::TraceRoot(trc, %s, "%s");\n' % ("&" + memberData
, memberName
)
18450 if type.nullable():
18451 trace
= CGIfWrapper(trace
, memberData
)
18454 'JS::TraceRoot(trc, %s, "%s");\n' % ("&" + memberData
, memberName
)
18458 or type.isDictionary()
18459 or type.isSpiderMonkeyInterface()
18463 if type.nullable():
18464 memberNullable
= memberData
18465 memberData
= "%s.Value()" % memberData
18466 if type.isSequence():
18467 trace
= CGGeneric("DoTraceSequence(trc, %s);\n" % memberData
)
18468 elif type.isDictionary():
18469 trace
= CGGeneric("%s.TraceDictionary(trc);\n" % memberData
)
18470 elif type.isUnion():
18471 trace
= CGGeneric("%s.TraceUnion(trc);\n" % memberData
)
18472 elif type.isRecord():
18473 trace
= CGGeneric("TraceRecord(trc, %s);\n" % memberData
)
18475 assert type.isSpiderMonkeyInterface()
18476 trace
= CGGeneric("%s.TraceSelf(trc);\n" % memberData
)
18477 if type.nullable():
18478 trace
= CGIfWrapper(trace
, "!%s.IsNull()" % memberNullable
)
18480 assert False # unknown type
18482 if member
.canHaveMissingValue():
18483 trace
= CGIfWrapper(trace
, "%s.WasPassed()" % memberLoc
)
18485 return trace
.define()
18487 def getMemberInitializer(self
, memberInfo
):
18489 Get the right initializer for the member. Most members don't need one,
18490 but we need to pre-initialize 'object' that have a default value or are
18491 required (and hence are not inside Optional), so they're safe to trace
18492 at all times. And we can optimize a bit for dictionary-typed members.
18494 member
, _
= memberInfo
18495 if member
.canHaveMissingValue():
18496 # Allowed missing value means no need to set it up front, since it's
18497 # inside an Optional and won't get traced until it's actually set
18501 if type.isDictionary():
18502 # When we construct ourselves, we don't want to init our member
18503 # dictionaries. Either we're being constructed-but-not-initialized
18504 # ourselves (and then we don't want to init them) or we're about to
18505 # init ourselves and then we'll init them anyway.
18506 return CGDictionary
.getNonInitializingCtorArg()
18507 return initializerForType(type)
18509 def getMemberSourceDescription(self
, member
):
18510 return "'%s' member of %s" % (
18511 member
.identifier
.name
,
18512 self
.dictionary
.identifier
.name
,
18516 def makeIdName(name
):
18517 return IDLToCIdentifier(name
) + "_id"
18520 def getNonInitializingCtorArg():
18521 return "FastDictionaryInitializer()"
18524 def isDictionaryCopyConstructible(dictionary
):
18525 if dictionary
.parent
and not CGDictionary
.isDictionaryCopyConstructible(
18529 return all(isTypeCopyConstructible(m
.type) for m
in dictionary
.members
)
18532 def typeSafeToJSONify(type):
18534 Determine whether the given type is safe to convert to JSON. The
18535 restriction is that this needs to be safe while in a global controlled
18536 by an adversary, and "safe" means no side-effects when the JS
18537 representation of this type is converted to JSON. That means that we
18538 have to be pretty restrictive about what things we can allow. For
18539 example, "object" is out, because it may have accessor properties on it.
18541 if type.nullable():
18542 # Converting null to JSON is always OK.
18543 return CGDictionary
.typeSafeToJSONify(type.inner
)
18545 if type.isSequence():
18546 # Sequences are arrays we create ourselves, with no holes. They
18547 # should be safe if their contents are safe, as long as we suppress
18548 # invocation of .toJSON on objects.
18549 return CGDictionary
.typeSafeToJSONify(type.inner
)
18552 # OK if everything in it is ok.
18553 return all(CGDictionary
.typeSafeToJSONify(t
) for t
in type.flatMemberTypes
)
18555 if type.isDictionary():
18556 # OK if the dictionary is OK
18557 return CGDictionary
.dictionarySafeToJSONify(type.inner
)
18559 if type.isUndefined() or type.isString() or type.isEnum():
18560 # Strings are always OK.
18563 if type.isPrimitive():
18564 # Primitives (numbers and booleans) are ok, as long as
18565 # they're not unrestricted float/double.
18566 return not type.isFloat() or not type.isUnrestricted()
18568 if type.isRecord():
18569 # Records are okay, as long as the value type is.
18570 # Per spec, only strings are allowed as keys.
18571 return CGDictionary
.typeSafeToJSONify(type.inner
)
18576 def dictionarySafeToJSONify(dictionary
):
18577 # The dictionary itself is OK, so we're good if all our types are.
18578 return all(CGDictionary
.typeSafeToJSONify(m
.type) for m
in dictionary
.members
)
18581 def RegisterNonWindowBindings(descriptors
):
18583 for desc
in descriptors
:
18584 bindingNS
= toBindingNamespace(desc
.name
)
18585 condition
= "!%s::CreateAndDefineOnGlobal(aCx)" % bindingNS
18586 if desc
.isExposedConditionally():
18587 condition
= "%s::ConstructorEnabled(aCx, aObj) && " % bindingNS
+ condition
18588 conditions
.append(condition
)
18590 CGIfWrapper(CGGeneric("return false;\n"), condition
) for condition
in conditions
18592 lines
.append(CGGeneric("return true;\n"))
18593 return CGList(lines
, "\n").define()
18596 class CGRegisterWorkerBindings(CGAbstractMethod
):
18597 def __init__(self
, config
):
18598 CGAbstractMethod
.__init
__(
18601 "RegisterWorkerBindings",
18603 [Argument("JSContext*", "aCx"), Argument("JS::Handle<JSObject*>", "aObj")],
18605 self
.config
= config
18607 def definition_body(self
):
18608 return RegisterNonWindowBindings(
18609 self
.config
.getDescriptors(
18610 hasInterfaceObject
=True, isExposedInAnyWorker
=True, register
=True
18615 class CGRegisterWorkerDebuggerBindings(CGAbstractMethod
):
18616 def __init__(self
, config
):
18617 CGAbstractMethod
.__init
__(
18620 "RegisterWorkerDebuggerBindings",
18622 [Argument("JSContext*", "aCx"), Argument("JS::Handle<JSObject*>", "aObj")],
18624 self
.config
= config
18626 def definition_body(self
):
18627 return RegisterNonWindowBindings(
18628 self
.config
.getDescriptors(
18629 hasInterfaceObject
=True, isExposedInWorkerDebugger
=True, register
=True
18634 class CGRegisterWorkletBindings(CGAbstractMethod
):
18635 def __init__(self
, config
):
18636 CGAbstractMethod
.__init
__(
18639 "RegisterWorkletBindings",
18641 [Argument("JSContext*", "aCx"), Argument("JS::Handle<JSObject*>", "aObj")],
18643 self
.config
= config
18645 def definition_body(self
):
18646 return RegisterNonWindowBindings(
18647 self
.config
.getDescriptors(
18648 hasInterfaceObject
=True, isExposedInAnyWorklet
=True, register
=True
18653 class CGRegisterShadowRealmBindings(CGAbstractMethod
):
18654 def __init__(self
, config
):
18655 CGAbstractMethod
.__init
__(
18658 "RegisterShadowRealmBindings",
18660 [Argument("JSContext*", "aCx"), Argument("JS::Handle<JSObject*>", "aObj")],
18662 self
.config
= config
18664 def definition_body(self
):
18665 return RegisterNonWindowBindings(
18666 self
.config
.getDescriptors(
18667 hasInterfaceObject
=True, isExposedInShadowRealms
=True, register
=True
18672 def BindingNamesOffsetEnum(name
):
18673 return CppKeywords
.checkMethodName(name
.replace(" ", "_"))
18676 class CGGlobalNames(CGGeneric
):
18677 def __init__(self
, names
):
18679 names is expected to be a list of tuples of the name and the descriptor it refers to.
18684 for name
, desc
in names
:
18685 # Generate the entry declaration
18686 # XXX(nika): mCreate & mEnabled require relocations. If we want to
18687 # reduce those, we could move them into separate tables.
18688 nativeEntry
= fill(
18691 /* mNameOffset */ BindingNamesOffset::${nameOffset},
18692 /* mNameLength */ ${nameLength},
18693 /* mConstructorId */ constructors::id::${realname},
18694 /* mCreate */ ${realname}_Binding::CreateInterfaceObjects,
18695 /* mEnabled */ ${enabled}
18698 nameOffset
=BindingNamesOffsetEnum(name
),
18699 nameLength
=len(name
),
18701 realname
=desc
.name
,
18703 "%s_Binding::ConstructorEnabled" % desc
.name
18704 if desc
.isExposedConditionally()
18709 entries
.append((name
.encode(), nativeEntry
))
18711 # Unfortunately, when running tests, we may have no entries.
18712 # PerfectHash will assert if we give it an empty set of entries, so we
18713 # just generate a dummy value.
18714 if len(entries
) == 0:
18715 CGGeneric
.__init
__(
18719 static_assert(false, "No WebIDL global name entries!");
18725 # Build the perfect hash function.
18726 phf
= PerfectHash(entries
, GLOBAL_NAMES_PHF_SIZE
)
18728 # Generate code for the PHF
18729 phfCodegen
= phf
.codegen(
18730 "WebIDLGlobalNameHash::sEntries", "WebIDLNameTableEntry"
18732 entries
= phfCodegen
.gen_entries(lambda e
: e
[1])
18733 getter
= phfCodegen
.gen_jslinearstr_getter(
18734 name
="WebIDLGlobalNameHash::GetEntry",
18735 return_type
="const WebIDLNameTableEntry*",
18736 return_entry
=dedent(
18738 if (JS_LinearStringEqualsAscii(aKey, BindingName(entry.mNameOffset), entry.mNameLength)) {
18748 const uint32_t WebIDLGlobalNameHash::sCount = ${count};
18754 count
=len(phf
.entries
),
18755 strings
="\n".join(strings
) + ";\n",
18759 CGGeneric
.__init
__(self
, define
=define
)
18762 def dependencySortObjects(objects
, dependencyGetter
, nameGetter
):
18764 Sort IDL objects with dependencies on each other such that if A
18765 depends on B then B will come before A. This is needed for
18766 declaring C++ classes in the right order, for example. Objects
18767 that have no dependencies are just sorted by name.
18769 objects should be something that can produce a set of objects
18770 (e.g. a set, iterator, list, etc).
18772 dependencyGetter is something that, given an object, should return
18773 the set of objects it depends on.
18775 # XXXbz this will fail if we have two webidl files F1 and F2 such that F1
18776 # declares an object which depends on an object in F2, and F2 declares an
18777 # object (possibly a different one!) that depends on an object in F1. The
18778 # good news is that I expect this to never happen.
18780 objects
= set(objects
)
18781 while len(objects
) != 0:
18782 # Find the dictionaries that don't depend on anything else
18783 # anymore and move them over.
18784 toMove
= [o
for o
in objects
if len(dependencyGetter(o
) & objects
) == 0]
18785 if len(toMove
) == 0:
18787 "Loop in dependency graph\n" + "\n".join(o
.location
for o
in objects
)
18789 objects
= objects
- set(toMove
)
18790 sortedObjects
.extend(sorted(toMove
, key
=nameGetter
))
18791 return sortedObjects
18794 class ForwardDeclarationBuilder
:
18796 Create a canonical representation of a set of namespaced forward
18800 def __init__(self
):
18802 The set of declarations is represented as a tree of nested namespaces.
18803 Each tree node has a set of declarations |decls| and a dict |children|.
18804 Each declaration is a pair consisting of the class name and a boolean
18805 that is true iff the class is really a struct. |children| maps the
18806 names of inner namespaces to the declarations in that namespace.
18811 def _ensureNonTemplateType(self
, type):
18813 # This is a templated type. We don't really know how to
18814 # forward-declare those, and trying to do it naively is not going to
18815 # go well (e.g. we may have :: characters inside the type we're
18816 # templated on!). Just bail out.
18818 "Attempt to use ForwardDeclarationBuilder on "
18819 "templated type %s. We don't know how to do that "
18823 def _listAdd(self
, namespaces
, name
, isStruct
=False):
18825 Add a forward declaration, where |namespaces| is a list of namespaces.
18826 |name| should not contain any other namespaces.
18829 child
= self
.children
.setdefault(namespaces
[0], ForwardDeclarationBuilder())
18830 child
._listAdd
(namespaces
[1:], name
, isStruct
)
18832 assert "::" not in name
18833 self
.decls
.add((name
, isStruct
))
18835 def addInMozillaDom(self
, name
, isStruct
=False):
18837 Add a forward declaration to the mozilla::dom:: namespace. |name| should not
18838 contain any other namespaces.
18840 self
._ensureNonTemplateType
(name
)
18841 self
._listAdd
(["mozilla", "dom"], name
, isStruct
)
18843 def add(self
, nativeType
, isStruct
=False):
18845 Add a forward declaration, where |nativeType| is a string containing
18846 the type and its namespaces, in the usual C++ way.
18848 self
._ensureNonTemplateType
(nativeType
)
18849 components
= nativeType
.split("::")
18850 self
._listAdd
(components
[:-1], components
[-1], isStruct
)
18852 def _build(self
, atTopLevel
):
18854 Return a codegenerator for the forward declarations.
18861 CGClassForwardDeclare(cname
, isStruct
)
18862 for cname
, isStruct
in sorted(self
.decls
)
18866 for namespace
, child
in sorted(self
.children
.items()):
18867 decls
.append(CGNamespace(namespace
, child
._build
(atTopLevel
=False)))
18869 cg
= CGList(decls
, "\n")
18870 if not atTopLevel
and len(decls
) + len(self
.decls
) > 1:
18871 cg
= CGWrapper(cg
, pre
="\n", post
="\n")
18875 return self
._build
(atTopLevel
=True)
18877 def forwardDeclareForType(self
, t
, config
):
18879 if t
.isGeckoInterface():
18880 name
= t
.inner
.identifier
.name
18882 desc
= config
.getDescriptor(name
)
18883 self
.add(desc
.nativeType
)
18884 except NoSuchDescriptorError
:
18887 # Note: SpiderMonkey interfaces are typedefs, so can't be
18889 elif t
.isPromise():
18890 self
.addInMozillaDom("Promise")
18891 elif t
.isCallback():
18892 self
.addInMozillaDom(t
.callback
.identifier
.name
)
18893 elif t
.isDictionary():
18894 self
.addInMozillaDom(t
.inner
.identifier
.name
, isStruct
=True)
18895 elif t
.isCallbackInterface():
18896 self
.addInMozillaDom(t
.inner
.identifier
.name
)
18898 # Forward declare both the owning and non-owning version,
18899 # since we don't know which one we might want
18900 self
.addInMozillaDom(CGUnionStruct
.unionTypeName(t
, False))
18901 self
.addInMozillaDom(CGUnionStruct
.unionTypeName(t
, True))
18903 self
.forwardDeclareForType(t
.inner
, config
)
18904 # Don't need to do anything for void, primitive, string, any or object.
18905 # There may be some other cases we are missing.
18908 class CGForwardDeclarations(CGWrapper
):
18910 Code generate the forward declarations for a header file.
18911 additionalDeclarations is a list of tuples containing a classname and a
18912 boolean. If the boolean is true we will declare a struct, otherwise we'll
18922 callbackInterfaces
,
18923 additionalDeclarations
=[],
18925 builder
= ForwardDeclarationBuilder()
18927 # Needed for at least Wrap.
18928 for d
in descriptors
:
18929 # If this is a generated iterator interface, we only create these
18930 # in the generated bindings, and don't need to forward declare.
18932 d
.interface
.isIteratorInterface()
18933 or d
.interface
.isAsyncIteratorInterface()
18936 builder
.add(d
.nativeType
)
18937 if d
.interface
.isSerializable():
18938 builder
.add("nsIGlobalObject")
18939 # If we're an interface and we have a maplike/setlike declaration,
18940 # we'll have helper functions exposed to the native side of our
18941 # bindings, which will need to show up in the header. If either of
18942 # our key/value types are interfaces, they'll be passed as
18943 # arguments to helper functions, and they'll need to be forward
18944 # declared in the header.
18945 if d
.interface
.maplikeOrSetlikeOrIterable
:
18946 if d
.interface
.maplikeOrSetlikeOrIterable
.hasKeyType():
18947 builder
.forwardDeclareForType(
18948 d
.interface
.maplikeOrSetlikeOrIterable
.keyType
, config
18950 if d
.interface
.maplikeOrSetlikeOrIterable
.hasValueType():
18951 builder
.forwardDeclareForType(
18952 d
.interface
.maplikeOrSetlikeOrIterable
.valueType
, config
18955 for m
in d
.interface
.members
:
18956 if m
.isAttr() and m
.type.isObservableArray():
18957 builder
.forwardDeclareForType(m
.type, config
)
18959 # We just about always need NativePropertyHooks
18960 builder
.addInMozillaDom("NativePropertyHooks", isStruct
=True)
18961 builder
.addInMozillaDom("ProtoAndIfaceCache")
18963 for callback
in callbacks
:
18964 builder
.addInMozillaDom(callback
.identifier
.name
)
18965 for t
in getTypesFromCallback(callback
):
18966 builder
.forwardDeclareForType(t
, config
)
18968 for d
in callbackInterfaces
:
18969 builder
.add(d
.nativeType
)
18970 builder
.add(d
.nativeType
+ "Atoms", isStruct
=True)
18971 for t
in getTypesFromDescriptor(d
):
18972 builder
.forwardDeclareForType(t
, config
)
18973 if d
.hasCEReactions():
18974 builder
.addInMozillaDom("DocGroup")
18976 for d
in dictionaries
:
18977 if len(d
.members
) > 0:
18978 builder
.addInMozillaDom(d
.identifier
.name
+ "Atoms", isStruct
=True)
18979 for t
in getTypesFromDictionary(d
):
18980 builder
.forwardDeclareForType(t
, config
)
18982 for className
, isStruct
in additionalDeclarations
:
18983 builder
.add(className
, isStruct
=isStruct
)
18985 CGWrapper
.__init
__(self
, builder
.build())
18988 def dependencySortDictionariesAndUnionsAndCallbacks(types
):
18989 def getDependenciesFromType(type):
18990 if type.isDictionary():
18991 return set([type.unroll().inner
])
18992 if type.isSequence():
18993 return getDependenciesFromType(type.unroll())
18995 return set([type.unroll()])
18996 if type.isRecord():
18997 return set([type.unroll().inner
])
18998 if type.isCallback():
18999 return set([type.unroll()])
19002 def getDependencies(unionTypeOrDictionaryOrCallback
):
19003 if isinstance(unionTypeOrDictionaryOrCallback
, IDLDictionary
):
19005 if unionTypeOrDictionaryOrCallback
.parent
:
19006 deps
.add(unionTypeOrDictionaryOrCallback
.parent
)
19007 for member
in unionTypeOrDictionaryOrCallback
.members
:
19008 deps |
= getDependenciesFromType(member
.type)
19012 unionTypeOrDictionaryOrCallback
.isType()
19013 and unionTypeOrDictionaryOrCallback
.isUnion()
19016 for member
in unionTypeOrDictionaryOrCallback
.flatMemberTypes
:
19017 deps |
= getDependenciesFromType(member
)
19020 assert unionTypeOrDictionaryOrCallback
.isCallback()
19023 def getName(unionTypeOrDictionaryOrCallback
):
19024 if isinstance(unionTypeOrDictionaryOrCallback
, IDLDictionary
):
19025 return unionTypeOrDictionaryOrCallback
.identifier
.name
19028 unionTypeOrDictionaryOrCallback
.isType()
19029 and unionTypeOrDictionaryOrCallback
.isUnion()
19031 return unionTypeOrDictionaryOrCallback
.name
19033 assert unionTypeOrDictionaryOrCallback
.isCallback()
19034 return unionTypeOrDictionaryOrCallback
.identifier
.name
19036 return dependencySortObjects(types
, getDependencies
, getName
)
19039 class CGBindingRoot(CGThing
):
19041 Root codegen class for binding generation. Instantiate the class, and call
19042 declare or define to generate header or cpp code (respectively).
19045 def __init__(self
, config
, prefix
, webIDLFile
):
19046 bindingHeaders
= dict.fromkeys(
19047 ("mozilla/dom/NonRefcountedDOMObject.h", "MainThreadUtils.h"), True
19049 bindingDeclareHeaders
= dict.fromkeys(
19051 "mozilla/dom/BindingDeclarations.h",
19052 "mozilla/dom/Nullable.h",
19057 descriptors
= config
.getDescriptors(
19058 webIDLFile
=webIDLFile
, hasInterfaceOrInterfacePrototypeObject
=True
19060 descriptors
.extend(
19061 config
.getDescriptors(
19062 webIDLFile
=webIDLFile
, hasOrdinaryObjectPrototype
=True
19066 unionTypes
= UnionsForFile(config
, webIDLFile
)
19075 ) = UnionTypes(unionTypes
, config
)
19077 bindingDeclareHeaders
.update(dict.fromkeys(unionHeaders
, True))
19078 bindingHeaders
.update(dict.fromkeys(unionImplheaders
, True))
19079 bindingDeclareHeaders
["mozilla/dom/UnionMember.h"] = len(unionStructs
) > 0
19080 bindingDeclareHeaders
["mozilla/dom/FakeString.h"] = len(unionStructs
) > 0
19081 # BindingUtils.h is only needed for SetToObject.
19082 # If it stops being inlined or stops calling CallerSubsumes
19083 # both this bit and the bit in UnionTypes can be removed.
19084 bindingDeclareHeaders
["mozilla/dom/BindingUtils.h"] = any(
19085 d
.isObject() for t
in unionTypes
for d
in t
.flatMemberTypes
19087 bindingDeclareHeaders
["mozilla/dom/JSSlots.h"] = any(
19088 d
.interface
.reflectedHTMLAttributesReturningFrozenArray
for d
in descriptors
19090 bindingHeaders
["mozilla/dom/IterableIterator.h"] = any(
19092 d
.interface
.isIteratorInterface()
19093 and d
.interface
.maplikeOrSetlikeOrIterable
.isPairIterator()
19095 or d
.interface
.isAsyncIteratorInterface()
19096 or d
.interface
.isIterable()
19097 or d
.interface
.isAsyncIterable()
19098 for d
in descriptors
19101 def memberNeedsSubjectPrincipal(d
, m
):
19104 "needsSubjectPrincipal" in d
.getExtendedAttributes(m
, getter
=True)
19107 and "needsSubjectPrincipal"
19108 in d
.getExtendedAttributes(m
, setter
=True)
19110 return m
.isMethod() and "needsSubjectPrincipal" in d
.getExtendedAttributes(
19115 memberNeedsSubjectPrincipal(d
, m
)
19116 for d
in descriptors
19117 for m
in d
.interface
.members
19119 bindingHeaders
["mozilla/BasePrincipal.h"] = True
19120 bindingHeaders
["nsJSPrincipals.h"] = True
19122 # The conditions for which we generate profiler labels are fairly
19123 # complicated. The check below is a little imprecise to make it simple.
19124 # It includes the profiler header in all cases where it is necessary and
19125 # generates only a few false positives.
19126 bindingHeaders
["mozilla/ProfilerLabels.h"] = any(
19127 # constructor profiler label
19128 d
.interface
.legacyFactoryFunctions
19129 or (d
.interface
.hasInterfaceObject() and d
.interface
.ctor())
19131 # getter/setter profiler labels
19133 # method profiler label
19135 for m
in d
.interface
.members
19137 for d
in descriptors
19140 def descriptorHasCrossOriginProperties(desc
):
19141 def hasCrossOriginProperty(m
):
19142 props
= memberProperties(m
, desc
)
19144 props
.isCrossOriginMethod
19145 or props
.isCrossOriginGetter
19146 or props
.isCrossOriginSetter
19149 return any(hasCrossOriginProperty(m
) for m
in desc
.interface
.members
)
19151 def descriptorHasObservableArrayTypes(desc
):
19152 def hasObservableArrayTypes(m
):
19153 return m
.isAttr() and m
.type.isObservableArray()
19155 return any(hasObservableArrayTypes(m
) for m
in desc
.interface
.members
)
19157 bindingDeclareHeaders
["mozilla/dom/RemoteObjectProxy.h"] = any(
19158 descriptorHasCrossOriginProperties(d
) for d
in descriptors
19160 bindingDeclareHeaders
["jsapi.h"] = any(
19161 descriptorHasCrossOriginProperties(d
)
19162 or descriptorHasObservableArrayTypes(d
)
19163 for d
in descriptors
19165 bindingDeclareHeaders
["js/TypeDecls.h"] = not bindingDeclareHeaders
["jsapi.h"]
19166 bindingDeclareHeaders
["js/RootingAPI.h"] = not bindingDeclareHeaders
["jsapi.h"]
19169 bindingDeclareHeaders
["js/CallAndConstruct.h"] = True
19171 def descriptorHasIteratorAlias(desc
):
19172 def hasIteratorAlias(m
):
19173 return m
.isMethod() and (
19174 ("@@iterator" in m
.aliases
) or ("@@asyncIterator" in m
.aliases
)
19177 return any(hasIteratorAlias(m
) for m
in desc
.interface
.members
)
19179 bindingHeaders
["js/Symbol.h"] = any(
19180 descriptorHasIteratorAlias(d
) for d
in descriptors
19183 bindingHeaders
["js/shadow/Object.h"] = any(
19184 d
.interface
.hasMembersInSlots() for d
in descriptors
19187 # The symbols supplied by this header are used so ubiquitously it's not
19188 # worth the effort delineating the exact dependency, if it can't be done
19189 # *at* the places where their definitions are required.
19190 bindingHeaders
["js/experimental/JitInfo.h"] = True
19192 # JS::GetClass, JS::GetCompartment, JS::GetReservedSlot, and
19193 # JS::SetReservedSlot are also used too many places to restate
19194 # dependency logic.
19195 bindingHeaders
["js/Object.h"] = True
19197 # JS::IsCallable, JS::Call, JS::Construct
19198 bindingHeaders
["js/CallAndConstruct.h"] = True
19200 # JS_IsExceptionPending
19201 bindingHeaders
["js/Exception.h"] = True
19203 # JS::Map{Clear, Delete, Has, Get, Set}
19204 bindingHeaders
["js/MapAndSet.h"] = True
19206 # JS_DefineElement, JS_DefineProperty, JS_DefinePropertyById,
19207 # JS_DefineUCProperty, JS_ForwardGetPropertyTo, JS_GetProperty,
19208 # JS_GetPropertyById, JS_HasPropertyById, JS_SetProperty,
19209 # JS_SetPropertyById
19210 bindingHeaders
["js/PropertyAndElement.h"] = True
19212 # JS_GetOwnPropertyDescriptorById
19213 bindingHeaders
["js/PropertyDescriptor.h"] = True
19215 def descriptorDeprecated(desc
):
19216 iface
= desc
.interface
19218 m
.getExtendedAttribute("Deprecated") for m
in iface
.members
+ [iface
]
19221 bindingHeaders
["mozilla/dom/Document.h"] = any(
19222 descriptorDeprecated(d
) for d
in descriptors
19225 bindingHeaders
["mozilla/dom/DOMJSProxyHandler.h"] = any(
19226 d
.concrete
and d
.proxy
for d
in descriptors
19229 bindingHeaders
["mozilla/dom/ProxyHandlerUtils.h"] = any(
19230 d
.concrete
and d
.proxy
for d
in descriptors
19233 bindingHeaders
["js/String.h"] = any(
19234 d
.needsMissingPropUseCounters
for d
in descriptors
19237 hasCrossOriginObjects
= any(
19238 d
.concrete
and d
.isMaybeCrossOriginObject() for d
in descriptors
19240 bindingHeaders
["mozilla/dom/MaybeCrossOriginObject.h"] = hasCrossOriginObjects
19241 bindingHeaders
["AccessCheck.h"] = hasCrossOriginObjects
19242 hasCEReactions
= any(d
.hasCEReactions() for d
in descriptors
)
19243 bindingHeaders
["mozilla/dom/CustomElementRegistry.h"] = hasCEReactions
19244 bindingHeaders
["mozilla/dom/DocGroup.h"] = hasCEReactions
19246 def descriptorHasChromeOnly(desc
):
19247 ctor
= desc
.interface
.ctor()
19251 isChromeOnly(a
) or needsCallerType(a
)
19252 for a
in desc
.interface
.members
19254 or desc
.interface
.getExtendedAttribute("ChromeOnly") is not None
19256 # JS-implemented interfaces with an interface object get a
19257 # chromeonly _create method. And interfaces with an
19258 # interface object might have a ChromeOnly constructor.
19260 desc
.interface
.hasInterfaceObject()
19262 desc
.interface
.isJSImplemented()
19263 or (ctor
and isChromeOnly(ctor
))
19268 # XXXkhuey ugly hack but this is going away soon.
19269 bindingHeaders
["xpcprivate.h"] = webIDLFile
.endswith("EventTarget.webidl")
19271 hasThreadChecks
= any(d
.hasThreadChecks() for d
in descriptors
)
19272 bindingHeaders
["nsThreadUtils.h"] = hasThreadChecks
19274 dictionaries
= config
.getDictionaries(webIDLFile
)
19276 def dictionaryHasChromeOnly(dictionary
):
19278 if any(isChromeOnly(m
) for m
in dictionary
.members
):
19280 dictionary
= dictionary
.parent
19283 def needsNonSystemPrincipal(member
):
19285 member
.getExtendedAttribute("NeedsSubjectPrincipal") == ["NonSystem"]
19286 or member
.getExtendedAttribute("SetterNeedsSubjectPrincipal")
19288 or member
.getExtendedAttribute("GetterNeedsSubjectPrincipal")
19292 def descriptorNeedsNonSystemPrincipal(d
):
19293 return any(needsNonSystemPrincipal(m
) for m
in d
.interface
.members
)
19295 def descriptorHasPrefDisabler(desc
):
19296 iface
= desc
.interface
19298 PropertyDefiner
.getControllingCondition(m
, desc
).hasDisablers()
19299 for m
in iface
.members
19300 if (m
.isMethod() or m
.isAttr() or m
.isConst())
19303 def addPrefHeaderForObject(bindingHeaders
, obj
):
19305 obj might be a dictionary member or an interface.
19307 if obj
is not None:
19308 pref
= PropertyDefiner
.getStringAttr(obj
, "Pref")
19310 bindingHeaders
[prefHeader(pref
)] = True
19312 def addPrefHeadersForDictionary(bindingHeaders
, dictionary
):
19314 for m
in dictionary
.members
:
19315 addPrefHeaderForObject(bindingHeaders
, m
)
19316 dictionary
= dictionary
.parent
19318 for d
in dictionaries
:
19319 addPrefHeadersForDictionary(bindingHeaders
, d
)
19320 for d
in descriptors
:
19321 interface
= d
.interface
19322 addPrefHeaderForObject(bindingHeaders
, interface
)
19323 addPrefHeaderForObject(bindingHeaders
, interface
.ctor())
19325 bindingHeaders
["mozilla/dom/WebIDLPrefs.h"] = any(
19326 descriptorHasPrefDisabler(d
) for d
in descriptors
19328 bindingHeaders
["nsContentUtils.h"] = (
19329 any(descriptorHasChromeOnly(d
) for d
in descriptors
)
19330 or any(descriptorNeedsNonSystemPrincipal(d
) for d
in descriptors
)
19331 or any(dictionaryHasChromeOnly(d
) for d
in dictionaries
)
19333 hasNonEmptyDictionaries
= any(len(dict.members
) > 0 for dict in dictionaries
)
19334 callbacks
= config
.getCallbacks(webIDLFile
)
19335 callbackDescriptors
= config
.getDescriptors(
19336 webIDLFile
=webIDLFile
, isCallback
=True
19338 jsImplemented
= config
.getDescriptors(
19339 webIDLFile
=webIDLFile
, isJSImplemented
=True
19341 bindingDeclareHeaders
["nsWeakReference.h"] = jsImplemented
19342 bindingDeclareHeaders
["mozilla/dom/PrototypeList.h"] = descriptors
19343 bindingHeaders
["nsIGlobalObject.h"] = jsImplemented
19344 bindingHeaders
["AtomList.h"] = (
19345 hasNonEmptyDictionaries
or jsImplemented
or callbackDescriptors
19348 if callbackDescriptors
:
19349 bindingDeclareHeaders
["mozilla/ErrorResult.h"] = True
19351 def descriptorClearsPropsInSlots(descriptor
):
19352 if not descriptor
.wrapperCache
:
19355 m
.isAttr() and m
.getExtendedAttribute("StoreInSlot")
19356 for m
in descriptor
.interface
.members
19359 bindingHeaders
["nsJSUtils.h"] = any(
19360 descriptorClearsPropsInSlots(d
) for d
in descriptors
19363 # Make sure we can sanely use binding_detail in generated code.
19368 namespace binding_detail {}; // Just to make sure it's known as a namespace
19369 using namespace mozilla::dom::binding_detail;
19375 # Do codegen for all the enums
19376 enums
= config
.getEnums(webIDLFile
)
19377 cgthings
.extend(CGEnum(e
) for e
in enums
)
19378 maxEnumValues
= CGList([CGMaxContiguousEnumValue(e
) for e
in enums
], "\n")
19380 bindingDeclareHeaders
["mozilla/Span.h"] = enums
19381 bindingDeclareHeaders
["mozilla/ArrayUtils.h"] = enums
19382 bindingDeclareHeaders
["mozilla/EnumTypeTraits.h"] = enums
19384 hasCode
= descriptors
or callbackDescriptors
or dictionaries
or callbacks
19385 bindingHeaders
["mozilla/dom/BindingUtils.h"] = hasCode
19386 bindingHeaders
["mozilla/OwningNonNull.h"] = hasCode
19387 bindingHeaders
["<type_traits>"] = hasCode
19388 bindingHeaders
["mozilla/dom/BindingDeclarations.h"] = not hasCode
and enums
19390 bindingHeaders
["WrapperFactory.h"] = descriptors
19391 bindingHeaders
["mozilla/dom/DOMJSClass.h"] = descriptors
19392 bindingHeaders
["mozilla/dom/ScriptSettings.h"] = dictionaries
# AutoJSAPI
19393 # Ensure we see our enums in the generated .cpp file, for the ToJSValue
19394 # method body. Also ensure that we see jsapi.h.
19396 bindingHeaders
[CGHeaders
.getDeclarationFilename(enums
[0])] = True
19397 bindingHeaders
["jsapi.h"] = True
19399 # For things that have [UseCounter] or [InstrumentedProps] or [Trial]
19400 for d
in descriptors
:
19402 if d
.instrumentedProps
:
19403 bindingHeaders
["mozilla/UseCounter.h"] = True
19404 if d
.needsMissingPropUseCounters
:
19405 bindingHeaders
[prefHeader(MISSING_PROP_PREF
)] = True
19406 if d
.interface
.isSerializable():
19407 bindingHeaders
["mozilla/dom/StructuredCloneTags.h"] = True
19409 bindingHeaders
["mozilla/Atomics.h"] = True
19410 bindingHeaders
["mozilla/dom/XrayExpandoClass.h"] = True
19411 if d
.wantsXrayExpandoClass
:
19412 bindingHeaders
["XrayWrapper.h"] = True
19413 for m
in d
.interface
.members
:
19414 if m
.getExtendedAttribute("UseCounter"):
19415 bindingHeaders
["mozilla/UseCounter.h"] = True
19416 if m
.getExtendedAttribute("Trial"):
19417 bindingHeaders
["mozilla/OriginTrials.h"] = True
19419 bindingHeaders
["mozilla/dom/SimpleGlobalObject.h"] = any(
19420 CGDictionary
.dictionarySafeToJSONify(d
) for d
in dictionaries
19423 for ancestor
in (findAncestorWithInstrumentedProps(d
) for d
in descriptors
):
19426 bindingHeaders
[CGHeaders
.getDeclarationFilename(ancestor
)] = True
19428 for d
in descriptors
:
19429 ancestor
= d
.interface
.parent
19431 if ancestor
.reflectedHTMLAttributesReturningFrozenArray
:
19432 bindingHeaders
[CGHeaders
.getDeclarationFilename(ancestor
)] = True
19434 ancestor
= ancestor
.parent
19436 cgthings
.extend(traverseMethods
)
19437 cgthings
.extend(unlinkMethods
)
19439 # Do codegen for all the dictionaries. We have to be a bit careful
19440 # here, because we have to generate these in order from least derived
19441 # to most derived so that class inheritance works out. We also have to
19442 # generate members before the dictionary that contains them.
19444 for t
in dependencySortDictionariesAndUnionsAndCallbacks(
19445 dictionaries
+ unionStructs
+ callbacks
19447 if t
.isDictionary():
19448 cgthings
.append(CGDictionary(t
, config
))
19450 cgthings
.append(CGUnionStruct(t
, config
))
19451 cgthings
.append(CGUnionStruct(t
, config
, True))
19453 assert t
.isCallback()
19454 cgthings
.append(CGCallbackFunction(t
, config
))
19455 cgthings
.append(CGNamespace("binding_detail", CGFastCallback(t
)))
19457 # Do codegen for all the descriptors
19459 [CGDescriptor(x
, config
.attributeTemplates
) for x
in descriptors
]
19462 # Do codegen for all the callback interfaces.
19463 cgthings
.extend([CGCallbackInterface(x
) for x
in callbackDescriptors
])
19467 CGNamespace("binding_detail", CGFastCallback(x
.interface
))
19468 for x
in callbackDescriptors
19472 # Do codegen for JS implemented classes
19473 def getParentDescriptor(desc
):
19474 if not desc
.interface
.parent
:
19476 return {desc
.getDescriptor(desc
.interface
.parent
.identifier
.name
)}
19478 for x
in dependencySortObjects(
19479 jsImplemented
, getParentDescriptor
, lambda d
: d
.interface
.identifier
.name
19482 CGCallbackInterface(x
, spiderMonkeyInterfacesAreStructs
=True)
19484 cgthings
.append(CGJSImplClass(x
))
19486 # And make sure we have the right number of newlines at the end
19487 curr
= CGWrapper(CGList(cgthings
, "\n\n"), post
="\n\n")
19489 # Wrap all of that in our namespaces.
19491 if len(maxEnumValues
) > 0:
19492 curr
= CGNamespace("dom", CGWrapper(curr
, pre
="\n"))
19493 curr
= CGWrapper(CGList([curr
, maxEnumValues
], "\n\n"), post
="\n\n")
19494 curr
= CGNamespace("mozilla", CGWrapper(curr
, pre
="\n"))
19496 curr
= CGNamespace
.build(["mozilla", "dom"], CGWrapper(curr
, pre
="\n"))
19500 CGForwardDeclarations(
19505 callbackDescriptors
+ jsImplemented
,
19506 additionalDeclarations
=unionDeclarations
,
19513 # Add header includes.
19515 header
for header
, include
in bindingHeaders
.items() if include
19517 bindingDeclareHeaders
= [
19518 header
for header
, include
in bindingDeclareHeaders
.items() if include
19525 callbackDescriptors
,
19526 bindingDeclareHeaders
,
19534 # Add include guards.
19535 curr
= CGIncludeGuard(prefix
, curr
)
19537 # Add the auto-generated comment.
19541 AUTOGENERATED_WITH_SOURCE_WARNING_COMMENT
% os
.path
.basename(webIDLFile
)
19545 # Store the final result.
19549 return stripTrailingWhitespace(self
.root
.declare())
19552 return stripTrailingWhitespace(self
.root
.define())
19555 return self
.root
.deps()
19558 class CGNativeMember(ClassMethod
):
19561 descriptorProvider
,
19567 passJSBitsAsNeeded
=True,
19568 visibility
="public",
19569 spiderMonkeyInterfacesAreStructs
=True,
19570 variadicIsSequence
=False,
19571 resultNotAddRefed
=False,
19574 canRunScript
=False,
19577 If spiderMonkeyInterfacesAreStructs is false, SpiderMonkey interfaces
19578 will be passed as JS::Handle<JSObject*>. If it's true they will be
19579 passed as one of the dom::SpiderMonkeyInterfaceObjectStorage subclasses.
19581 If passJSBitsAsNeeded is false, we don't automatically pass in a
19582 JSContext* or a JSObject* based on the return and argument types. We
19583 can still pass it based on 'implicitJSContext' annotations.
19585 self
.descriptorProvider
= descriptorProvider
19586 self
.member
= member
19587 self
.extendedAttrs
= extendedAttrs
19588 self
.resultAlreadyAddRefed
= not resultNotAddRefed
19589 self
.passJSBitsAsNeeded
= passJSBitsAsNeeded
19590 self
.spiderMonkeyInterfacesAreStructs
= spiderMonkeyInterfacesAreStructs
19591 self
.variadicIsSequence
= variadicIsSequence
19592 breakAfterSelf
= "\n" if breakAfter
else ""
19593 ClassMethod
.__init
__(
19596 self
.getReturnType(signature
[0], False),
19597 self
.getArgs(signature
[0], signature
[1]),
19598 static
=member
.isStatic(),
19599 # Mark our getters, which are attrs that
19600 # have a non-void return type, as const.
19602 not member
.isStatic()
19603 and member
.isAttr()
19604 and not signature
[0].isUndefined()
19606 breakAfterReturnDecl
=" ",
19607 breakAfterSelf
=breakAfterSelf
,
19608 visibility
=visibility
,
19611 canRunScript
=canRunScript
,
19614 def getReturnType(self
, type, isMember
):
19615 return self
.getRetvalInfo(type, isMember
)[0]
19617 def getRetvalInfo(self
, type, isMember
):
19621 The first element is the type declaration for the retval
19623 The second element is a default value that can be used on error returns.
19624 For cases whose behavior depends on isMember, the second element will be
19625 None if isMember is true.
19627 The third element is a template for actually returning a value stored in
19628 "${declName}" and "${holderName}". This means actually returning it if
19629 we're not outparam, else assigning to the "retval" outparam. If
19630 isMember is true, this can be None, since in that case the caller will
19631 never examine this value.
19633 if type.isUndefined():
19634 return "void", "", ""
19635 if type.isPrimitive() and type.tag() in builtinNames
:
19636 result
= CGGeneric(builtinNames
[type.tag()])
19637 defaultReturnArg
= "0"
19638 if type.nullable():
19639 result
= CGTemplatedType("Nullable", result
)
19640 defaultReturnArg
= ""
19643 "%s(%s)" % (result
.define(), defaultReturnArg
),
19644 "return ${declName};\n",
19646 if type.isJSString():
19648 raise TypeError("JSString not supported as return type member")
19650 return "void", "", "aRetVal.set(${declName});\n"
19651 if type.isDOMString() or type.isUSVString():
19653 # No need for a third element in the isMember case
19654 return "nsString", None, None
19656 return "void", "", "aRetVal = ${declName};\n"
19657 if type.isByteString() or type.isUTF8String():
19659 # No need for a third element in the isMember case
19660 return "nsCString", None, None
19662 return "void", "", "aRetVal = ${declName};\n"
19664 enumName
= type.unroll().inner
.identifier
.name
19665 if type.nullable():
19666 enumName
= CGTemplatedType("Nullable", CGGeneric(enumName
)).define()
19667 defaultValue
= "%s()" % enumName
19669 defaultValue
= "%s(0)" % enumName
19670 return enumName
, defaultValue
, "return ${declName};\n"
19671 if type.isGeckoInterface() or type.isPromise():
19672 if type.isGeckoInterface():
19673 iface
= type.unroll().inner
19674 result
= CGGeneric(
19675 self
.descriptorProvider
.getDescriptor(
19676 iface
.identifier
.name
19680 result
= CGGeneric("Promise")
19681 if self
.resultAlreadyAddRefed
:
19685 holder
= "already_AddRefed"
19686 if memberReturnsNewObject(self
.member
) or isMember
:
19689 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"
19690 result
= CGWrapper(result
, pre
=("%s%s<" % (warning
, holder
)), post
=">")
19692 result
= CGWrapper(result
, post
="*")
19693 # Since we always force an owning type for callback return values,
19694 # our ${declName} is an OwningNonNull or RefPtr. So we can just
19695 # .forget() to get our already_AddRefed.
19696 return result
.define(), "nullptr", "return ${declName}.forget();\n"
19697 if type.isCallback():
19699 "already_AddRefed<%s>" % type.unroll().callback
.identifier
.name
,
19701 "return ${declName}.forget();\n",
19705 # No need for a third element in the isMember case
19706 return "JS::Value", None, None
19708 return "void", "", "aRetVal.set(${declName});\n"
19710 if type.isObject():
19712 # No need for a third element in the isMember case
19713 return "JSObject*", None, None
19714 return "void", "", "aRetVal.set(${declName});\n"
19715 if type.isSpiderMonkeyInterface():
19717 # No need for a third element in the isMember case
19718 return "JSObject*", None, None
19719 if type.nullable():
19721 "${declName}.IsNull() ? nullptr : ${declName}.Value().Obj()"
19724 returnCode
= "${declName}.Obj()"
19725 return "void", "", "aRetVal.set(%s);\n" % returnCode
19726 if type.isSequence():
19727 # If we want to handle sequence-of-sequences return values, we're
19728 # going to need to fix example codegen to not produce nsTArray<void>
19729 # for the relevant argument...
19730 assert not isMember
19732 if type.nullable():
19733 returnCode
= dedent(
19735 if (${declName}.IsNull()) {
19738 aRetVal.SetValue() = std::move(${declName}.Value());
19743 returnCode
= "aRetVal = std::move(${declName});\n"
19744 return "void", "", returnCode
19745 if type.isRecord():
19746 # If we want to handle record-of-record return values, we're
19747 # going to need to fix example codegen to not produce record<void>
19748 # for the relevant argument...
19749 assert not isMember
19750 # In this case we convert directly into our outparam to start with
19751 return "void", "", ""
19752 if type.isDictionary():
19754 # Only the first member of the tuple matters here, but return
19755 # bogus values for the others in case someone decides to use
19757 return CGDictionary
.makeDictionaryName(type.inner
), None, None
19758 # In this case we convert directly into our outparam to start with
19759 return "void", "", ""
19762 # Only the first member of the tuple matters here, but return
19763 # bogus values for the others in case someone decides to use
19765 return CGUnionStruct
.unionTypeDecl(type, True), None, None
19766 # In this case we convert directly into our outparam to start with
19767 return "void", "", ""
19769 raise TypeError("Don't know how to declare return value for %s" % type)
19771 def getArgs(self
, returnType
, argList
):
19772 args
= [self
.getArg(arg
) for arg
in argList
]
19773 # Now the outparams
19774 if returnType
.isJSString():
19775 args
.append(Argument("JS::MutableHandle<JSString*>", "aRetVal"))
19776 elif returnType
.isDOMString() or returnType
.isUSVString():
19777 args
.append(Argument("nsString&", "aRetVal"))
19778 elif returnType
.isByteString() or returnType
.isUTF8String():
19779 args
.append(Argument("nsCString&", "aRetVal"))
19780 elif returnType
.isSequence():
19781 nullable
= returnType
.nullable()
19783 returnType
= returnType
.inner
19784 # And now the actual underlying type
19785 elementDecl
= self
.getReturnType(returnType
.inner
, True)
19786 type = CGTemplatedType("nsTArray", CGGeneric(elementDecl
))
19788 type = CGTemplatedType("Nullable", type)
19789 args
.append(Argument("%s&" % type.define(), "aRetVal"))
19790 elif returnType
.isRecord():
19791 nullable
= returnType
.nullable()
19793 returnType
= returnType
.inner
19794 # And now the actual underlying type
19795 elementDecl
= self
.getReturnType(returnType
.inner
, True)
19796 type = CGTemplatedType(
19797 "Record", [recordKeyDeclType(returnType
), CGGeneric(elementDecl
)]
19800 type = CGTemplatedType("Nullable", type)
19801 args
.append(Argument("%s&" % type.define(), "aRetVal"))
19802 elif returnType
.isDictionary():
19803 nullable
= returnType
.nullable()
19805 returnType
= returnType
.inner
19806 dictType
= CGGeneric(CGDictionary
.makeDictionaryName(returnType
.inner
))
19808 dictType
= CGTemplatedType("Nullable", dictType
)
19809 args
.append(Argument("%s&" % dictType
.define(), "aRetVal"))
19810 elif returnType
.isUnion():
19813 "%s&" % CGUnionStruct
.unionTypeDecl(returnType
, True), "aRetVal"
19816 elif returnType
.isAny():
19817 args
.append(Argument("JS::MutableHandle<JS::Value>", "aRetVal"))
19818 elif returnType
.isObject() or returnType
.isSpiderMonkeyInterface():
19819 args
.append(Argument("JS::MutableHandle<JSObject*>", "aRetVal"))
19821 # And the nsIPrincipal
19822 if "needsSubjectPrincipal" in self
.extendedAttrs
:
19823 if "needsNonSystemSubjectPrincipal" in self
.extendedAttrs
:
19824 args
.append(Argument("nsIPrincipal*", "aPrincipal"))
19826 args
.append(Argument("nsIPrincipal&", "aPrincipal"))
19827 # And the caller type, if desired.
19828 if needsCallerType(self
.member
):
19829 args
.append(Argument("CallerType", "aCallerType"))
19830 # And the ErrorResult or OOMReporter
19831 if "needsErrorResult" in self
.extendedAttrs
:
19832 # Use aRv so it won't conflict with local vars named "rv"
19833 args
.append(Argument("ErrorResult&", "aRv"))
19834 elif "canOOM" in self
.extendedAttrs
:
19835 args
.append(Argument("OOMReporter&", "aRv"))
19837 # The legacycaller thisval
19838 if self
.member
.isMethod() and self
.member
.isLegacycaller():
19839 # If it has an identifier, we can't deal with it yet
19840 assert self
.member
.isIdentifierLess()
19841 args
.insert(0, Argument("const JS::Value&", "aThisVal"))
19842 # And jscontext bits.
19846 self
.extendedAttrs
,
19847 self
.passJSBitsAsNeeded
,
19848 self
.member
.isStatic(),
19850 args
.insert(0, Argument("JSContext*", "cx"))
19851 if needScopeObject(
19854 self
.extendedAttrs
,
19855 self
.descriptorProvider
.wrapperCache
,
19856 self
.passJSBitsAsNeeded
,
19857 self
.member
.getExtendedAttribute("StoreInSlot"),
19859 args
.insert(1, Argument("JS::Handle<JSObject*>", "obj"))
19860 # And if we're static, a global
19861 if self
.member
.isStatic():
19862 args
.insert(0, Argument("const GlobalObject&", "global"))
19865 def doGetArgType(self
, type, optional
, isMember
):
19867 The main work of getArgType. Returns a string type decl, whether this
19868 is a const ref, as well as whether the type should be wrapped in
19869 Nullable as needed.
19871 isMember can be false or one of the strings "Sequence", "Variadic",
19874 if type.isSequence():
19875 nullable
= type.nullable()
19878 elementType
= type.inner
19879 argType
= self
.getArgType(elementType
, False, "Sequence")[0]
19880 decl
= CGTemplatedType("Sequence", argType
)
19881 return decl
.define(), True, True
19883 if type.isRecord():
19884 nullable
= type.nullable()
19887 elementType
= type.inner
19888 argType
= self
.getArgType(elementType
, False, "Record")[0]
19889 decl
= CGTemplatedType("Record", [recordKeyDeclType(type), argType
])
19890 return decl
.define(), True, True
19893 # unionTypeDecl will handle nullable types, so return False for
19894 # auto-wrapping in Nullable
19895 return CGUnionStruct
.unionTypeDecl(type, isMember
), True, False
19897 if type.isPromise():
19898 assert not type.nullable()
19899 if optional
or isMember
:
19900 typeDecl
= "OwningNonNull<Promise>"
19902 typeDecl
= "Promise&"
19903 return (typeDecl
, False, False)
19905 if type.isGeckoInterface() and not type.isCallbackInterface():
19906 iface
= type.unroll().inner
19907 if iface
.identifier
.name
== "WindowProxy":
19908 return "WindowProxyHolder", True, False
19910 argIsPointer
= type.nullable() or iface
.isExternal()
19911 forceOwningType
= iface
.isCallback() or isMember
19913 if (optional
or isMember
) and forceOwningType
:
19914 typeDecl
= "RefPtr<%s>"
19918 if optional
or isMember
:
19919 if forceOwningType
:
19920 typeDecl
= "OwningNonNull<%s>"
19922 typeDecl
= "NonNull<%s>"
19928 % self
.descriptorProvider
.getDescriptor(
19929 iface
.identifier
.name
19936 if type.isSpiderMonkeyInterface():
19937 if not self
.spiderMonkeyInterfacesAreStructs
:
19938 return "JS::Handle<JSObject*>", False, False
19940 # Unroll for the name, in case we're nullable.
19941 return type.unroll().name
, True, True
19943 if type.isJSString():
19945 raise TypeError("JSString not supported as member")
19946 return "JS::Handle<JSString*>", False, False
19948 if type.isDOMString() or type.isUSVString():
19950 declType
= "nsString"
19952 declType
= "nsAString"
19953 return declType
, True, False
19955 if type.isByteString() or type.isUTF8String():
19956 # TODO(emilio): Maybe bytestrings could benefit from nsAutoCString
19958 if type.isUTF8String() and not isMember
:
19959 declType
= "nsACString"
19961 declType
= "nsCString"
19962 return declType
, True, False
19965 return type.unroll().inner
.identifier
.name
, False, True
19967 if type.isCallback() or type.isCallbackInterface():
19968 forceOwningType
= optional
or isMember
19969 if type.nullable():
19970 if forceOwningType
:
19971 declType
= "RefPtr<%s>"
19975 if forceOwningType
:
19976 declType
= "OwningNonNull<%s>"
19979 if type.isCallback():
19980 name
= type.unroll().callback
.identifier
.name
19982 name
= type.unroll().inner
.identifier
.name
19983 return declType
% name
, False, False
19986 # Don't do the rooting stuff for variadics for now
19988 declType
= "JS::Value"
19990 declType
= "JS::Handle<JS::Value>"
19991 return declType
, False, False
19993 if type.isObject():
19995 declType
= "JSObject*"
19997 declType
= "JS::Handle<JSObject*>"
19998 return declType
, False, False
20000 if type.isDictionary():
20001 typeName
= CGDictionary
.makeDictionaryName(type.inner
)
20002 return typeName
, True, True
20004 assert type.isPrimitive()
20006 return builtinNames
[type.tag()], False, True
20008 def getArgType(self
, type, optional
, isMember
):
20010 Get the type of an argument declaration. Returns the type CGThing, and
20011 whether this should be a const ref.
20013 isMember can be False, "Sequence", or "Variadic"
20015 decl
, ref
, handleNullable
= self
.doGetArgType(type, optional
, isMember
)
20016 decl
= CGGeneric(decl
)
20017 if handleNullable
and type.nullable():
20018 decl
= CGTemplatedType("Nullable", decl
)
20020 if isMember
== "Variadic":
20021 arrayType
= "Sequence" if self
.variadicIsSequence
else "nsTArray"
20022 decl
= CGTemplatedType(arrayType
, decl
)
20025 # Note: All variadic args claim to be optional, but we can just use
20026 # empty arrays to represent them not being present.
20027 decl
= CGTemplatedType("Optional", decl
)
20031 def getArg(self
, arg
):
20033 Get the full argument declaration for an argument
20035 decl
, ref
= self
.getArgType(
20036 arg
.type, arg
.canHaveMissingValue(), "Variadic" if arg
.variadic
else False
20039 decl
= CGWrapper(decl
, pre
="const ", post
="&")
20041 return Argument(decl
.define(), arg
.identifier
.name
)
20043 def arguments(self
):
20044 return self
.member
.signatures()[0][1]
20047 class CGExampleMethod(CGNativeMember
):
20048 def __init__(self
, descriptor
, method
, signature
, isConstructor
, breakAfter
=True):
20049 CGNativeMember
.__init
__(
20053 CGSpecializedMethod
.makeNativeName(descriptor
, method
),
20055 descriptor
.getExtendedAttributes(method
),
20056 breakAfter
=breakAfter
,
20057 variadicIsSequence
=True,
20060 def declare(self
, cgClass
):
20061 assert self
.member
.isMethod()
20062 # We skip declaring ourselves if this is a maplike/setlike/iterable
20063 # method, because those get implemented automatically by the binding
20064 # machinery, so the implementor of the interface doesn't have to worry
20066 if self
.member
.isMaplikeOrSetlikeOrIterableMethod():
20068 return CGNativeMember
.declare(self
, cgClass
)
20070 def define(self
, cgClass
):
20074 class CGExampleGetter(CGNativeMember
):
20075 def __init__(self
, descriptor
, attr
):
20076 CGNativeMember
.__init
__(
20080 CGSpecializedGetterCommon
.makeNativeName(descriptor
, attr
),
20082 descriptor
.getExtendedAttributes(attr
, getter
=True),
20085 def getArgs(self
, returnType
, argList
):
20086 args
= CGNativeMember
.getArgs(self
, returnType
, argList
)
20087 if self
.member
.getExtendedAttribute(
20088 "ReflectedHTMLAttributeReturningFrozenArray"
20090 args
.insert(0, Argument("bool*", "aUseCachedValue"))
20093 def declare(self
, cgClass
):
20094 assert self
.member
.isAttr()
20095 # We skip declaring ourselves if this is a maplike/setlike attr (in
20096 # practice, "size"), because those get implemented automatically by the
20097 # binding machinery, so the implementor of the interface doesn't have to
20099 if self
.member
.isMaplikeOrSetlikeAttr():
20101 return CGNativeMember
.declare(self
, cgClass
)
20103 def define(self
, cgClass
):
20107 class CGExampleSetter(CGNativeMember
):
20108 def __init__(self
, descriptor
, attr
):
20109 CGNativeMember
.__init
__(
20113 CGSpecializedSetterCommon
.makeNativeName(descriptor
, attr
),
20115 BuiltinTypes
[IDLBuiltinType
.Types
.undefined
],
20116 [FakeArgument(attr
.type)],
20118 descriptor
.getExtendedAttributes(attr
, setter
=True),
20121 def define(self
, cgClass
):
20125 class CGBindingImplClass(CGClass
):
20127 Common codegen for generating a C++ implementation of a WebIDL interface
20136 wantGetParent
=True,
20137 wrapMethodName
="WrapObject",
20138 skipStaticMethods
=False,
20141 cgMethod, cgGetter and cgSetter are classes used to codegen methods,
20142 getters and setters.
20144 self
.descriptor
= descriptor
20145 self
._deps
= descriptor
.interface
.getDeps()
20147 iface
= descriptor
.interface
20149 self
.methodDecls
= []
20151 def appendMethod(m
, isConstructor
=False):
20152 sigs
= m
.signatures()
20153 for s
in sigs
[:-1]:
20154 # Don't put a blank line after overloads, until we
20155 # get to the last one.
20156 self
.methodDecls
.append(
20157 cgMethod(descriptor
, m
, s
, isConstructor
, breakAfter
=False)
20159 self
.methodDecls
.append(cgMethod(descriptor
, m
, sigs
[-1], isConstructor
))
20162 appendMethod(iface
.ctor(), isConstructor
=True)
20163 for n
in iface
.legacyFactoryFunctions
:
20164 appendMethod(n
, isConstructor
=True)
20165 for m
in iface
.members
:
20167 if m
.isIdentifierLess():
20169 if m
.isMaplikeOrSetlikeOrIterableMethod():
20170 # Handled by generated code already
20172 if not m
.isStatic() or not skipStaticMethods
:
20175 if m
.isMaplikeOrSetlikeAttr() or m
.type.isObservableArray():
20176 # Handled by generated code already
20178 self
.methodDecls
.append(cgGetter(descriptor
, m
))
20180 self
.methodDecls
.append(cgSetter(descriptor
, m
))
20182 # Now do the special operations
20183 def appendSpecialOperation(name
, op
):
20186 assert len(op
.signatures()) == 1
20187 returnType
, args
= op
.signatures()[0]
20188 # Make a copy of the args, since we plan to modify them.
20190 if op
.isGetter() or op
.isDeleter():
20191 # This is a total hack. The '&' belongs with the
20192 # type, not the name! But it works, and is simpler
20193 # than trying to somehow make this pretty.
20196 BuiltinTypes
[IDLBuiltinType
.Types
.boolean
], name
="&found"
20199 if name
== "Stringifier":
20200 if op
.isIdentifierLess():
20201 # XXXbz I wish we were consistent about our renaming here.
20204 # We already added this method
20206 if name
== "LegacyCaller":
20207 if op
.isIdentifierLess():
20208 # XXXbz I wish we were consistent about our renaming here.
20209 name
= "LegacyCall"
20211 # We already added this method
20213 self
.methodDecls
.append(
20218 (returnType
, args
),
20219 descriptor
.getExtendedAttributes(op
),
20223 # Sort things by name so we get stable ordering in the output.
20224 ops
= sorted(descriptor
.operations
.items(), key
=lambda x
: x
[0])
20225 for name
, op
in ops
:
20226 appendSpecialOperation(name
, op
)
20227 # If we support indexed properties, then we need a Length()
20228 # method so we know which indices are supported.
20229 if descriptor
.supportsIndexedProperties():
20230 # But we don't need it if we already have an infallible
20231 # "length" attribute, which we often do.
20232 haveLengthAttr
= any(
20234 for m
in iface
.members
20236 and CGSpecializedGetterCommon
.makeNativeName(descriptor
, m
) == "Length"
20238 if not haveLengthAttr
:
20239 self
.methodDecls
.append(
20244 (BuiltinTypes
[IDLBuiltinType
.Types
.unsigned_long
], []),
20248 # And if we support named properties we need to be able to
20249 # enumerate the supported names.
20250 if descriptor
.supportsNamedProperties():
20251 self
.methodDecls
.append(
20255 "GetSupportedNames",
20258 None, BuiltinTypes
[IDLBuiltinType
.Types
.domstring
]
20266 if descriptor
.concrete
:
20268 Argument("JSContext*", "aCx"),
20269 Argument("JS::Handle<JSObject*>", "aGivenProto"),
20271 if not descriptor
.wrapperCache
:
20272 wrapReturnType
= "bool"
20273 wrapArgs
.append(Argument("JS::MutableHandle<JSObject*>", "aReflector"))
20275 wrapReturnType
= "JSObject*"
20276 self
.methodDecls
.insert(
20282 virtual
=descriptor
.wrapperCache
,
20283 breakAfterReturnDecl
=" ",
20284 override
=descriptor
.wrapperCache
,
20285 body
=self
.getWrapObjectBody(),
20288 if descriptor
.hasCEReactions():
20289 self
.methodDecls
.insert(
20296 breakAfterReturnDecl
=" ",
20297 body
=self
.getGetDocGroupBody(),
20301 self
.methodDecls
.insert(
20305 self
.getGetParentObjectReturnType(),
20308 breakAfterReturnDecl
=" ",
20309 body
=self
.getGetParentObjectBody(),
20313 # Invoke CGClass.__init__ in any subclasses afterwards to do the actual codegen.
20315 def getWrapObjectBody(self
):
20318 def getGetParentObjectReturnType(self
):
20319 # The lack of newline before the end of the string is on purpose.
20322 // This should return something that eventually allows finding a
20323 // path to the global this object is associated with. Most simply,
20324 // returning an actual global works.
20325 nsIGlobalObject*"""
20328 def getGetParentObjectBody(self
):
20331 def getGetDocGroupBody(self
):
20338 class CGExampleObservableArrayCallback(CGNativeMember
):
20339 def __init__(self
, descriptor
, attr
, callbackName
):
20340 assert attr
.isAttr()
20341 assert attr
.type.isObservableArray()
20342 CGNativeMember
.__init
__(
20346 self
.makeNativeName(attr
, callbackName
),
20348 BuiltinTypes
[IDLBuiltinType
.Types
.undefined
],
20350 FakeArgument(attr
.type.inner
, "aValue"),
20352 BuiltinTypes
[IDLBuiltinType
.Types
.unsigned_long
], "aIndex"
20356 ["needsErrorResult"],
20359 def declare(self
, cgClass
):
20360 assert self
.member
.isAttr()
20361 assert self
.member
.type.isObservableArray()
20362 return CGNativeMember
.declare(self
, cgClass
)
20364 def define(self
, cgClass
):
20368 def makeNativeName(attr
, callbackName
):
20369 assert attr
.isAttr()
20370 nativeName
= MakeNativeName(attr
.identifier
.name
)
20371 return "On" + callbackName
+ nativeName
20374 class CGExampleClass(CGBindingImplClass
):
20376 Codegen for the actual example class implementation for this descriptor
20379 def __init__(self
, descriptor
):
20380 CGBindingImplClass
.__init
__(
20386 wantGetParent
=descriptor
.wrapperCache
,
20389 self
.parentIface
= descriptor
.interface
.parent
20390 if self
.parentIface
:
20391 self
.parentDesc
= descriptor
.getDescriptor(self
.parentIface
.identifier
.name
)
20392 bases
= [ClassBase(self
.nativeLeafName(self
.parentDesc
))]
20396 "nsISupports /* or NonRefcountedDOMObject if this is a non-refcounted object */"
20399 if descriptor
.wrapperCache
:
20402 "nsWrapperCache /* Change wrapperCache in the binding configuration if you don't want this */"
20406 destructorVisibility
= "protected"
20407 if self
.parentIface
:
20408 extradeclarations
= (
20410 " NS_DECL_ISUPPORTS_INHERITED\n"
20411 " NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(%s, %s)\n"
20414 self
.nativeLeafName(descriptor
),
20415 self
.nativeLeafName(self
.parentDesc
),
20419 extradeclarations
= (
20421 " NS_DECL_CYCLE_COLLECTING_ISUPPORTS\n"
20422 " NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(%s)\n"
20423 "\n" % self
.nativeLeafName(descriptor
)
20426 if descriptor
.interface
.hasChildInterfaces():
20429 decorators
= "final"
20431 for m
in descriptor
.interface
.members
:
20432 if m
.isAttr() and m
.type.isObservableArray():
20433 self
.methodDecls
.append(
20434 CGExampleObservableArrayCallback(descriptor
, m
, "Set")
20436 self
.methodDecls
.append(
20437 CGExampleObservableArrayCallback(descriptor
, m
, "Delete")
20442 self
.nativeLeafName(descriptor
),
20444 constructors
=[ClassConstructor([], visibility
="public")],
20445 destructor
=ClassDestructor(visibility
=destructorVisibility
),
20446 methods
=self
.methodDecls
,
20447 decorators
=decorators
,
20448 extradeclarations
=extradeclarations
,
20452 # Just override CGClass and do our own thing
20453 nativeType
= self
.nativeLeafName(self
.descriptor
)
20457 ${nativeType}::${nativeType}()
20459 // Add |MOZ_COUNT_CTOR(${nativeType});| for a non-refcounted object.
20462 ${nativeType}::~${nativeType}()
20464 // Add |MOZ_COUNT_DTOR(${nativeType});| for a non-refcounted object.
20467 nativeType
=nativeType
,
20470 if self
.parentIface
:
20474 // Only needed for refcounted objects.
20475 # error "If you don't have members that need cycle collection,
20476 # then remove all the cycle collection bits from this
20477 # implementation and the corresponding header. If you do, you
20478 # want NS_IMPL_CYCLE_COLLECTION_INHERITED(${nativeType},
20479 # ${parentType}, your, members, here)"
20480 NS_IMPL_ADDREF_INHERITED(${nativeType}, ${parentType})
20481 NS_IMPL_RELEASE_INHERITED(${nativeType}, ${parentType})
20482 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
20483 NS_INTERFACE_MAP_END_INHERITING(${parentType})
20486 nativeType
=nativeType
,
20487 parentType
=self
.nativeLeafName(self
.parentDesc
),
20493 // Only needed for refcounted objects.
20494 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(${nativeType})
20495 NS_IMPL_CYCLE_COLLECTING_ADDREF(${nativeType})
20496 NS_IMPL_CYCLE_COLLECTING_RELEASE(${nativeType})
20497 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
20498 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
20499 NS_INTERFACE_MAP_ENTRY(nsISupports)
20500 NS_INTERFACE_MAP_END
20503 nativeType
=nativeType
,
20506 classImpl
= ccImpl
+ ctordtor
+ "\n"
20507 if self
.descriptor
.concrete
:
20508 if self
.descriptor
.wrapperCache
:
20510 reflectorPassArg
= ""
20511 returnType
= "JSObject*"
20513 reflectorArg
= ", JS::MutableHandle<JSObject*> aReflector"
20514 reflectorPassArg
= ", aReflector"
20515 returnType
= "bool"
20519 ${nativeType}::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto${reflectorArg})
20521 return ${ifaceName}_Binding::Wrap(aCx, this, aGivenProto${reflectorPassArg});
20525 returnType
=returnType
,
20526 nativeType
=nativeType
,
20527 reflectorArg
=reflectorArg
,
20528 ifaceName
=self
.descriptor
.name
,
20529 reflectorPassArg
=reflectorPassArg
,
20535 def nativeLeafName(descriptor
):
20536 return descriptor
.nativeType
.split("::")[-1]
20539 class CGExampleRoot(CGThing
):
20541 Root codegen class for example implementation generation. Instantiate the
20542 class and call declare or define to generate header or cpp code,
20546 def __init__(self
, config
, interfaceName
):
20547 descriptor
= config
.getDescriptor(interfaceName
)
20549 self
.root
= CGWrapper(CGExampleClass(descriptor
), pre
="\n", post
="\n")
20551 self
.root
= CGNamespace
.build(["mozilla", "dom"], self
.root
)
20553 builder
= ForwardDeclarationBuilder()
20554 if descriptor
.hasCEReactions():
20555 builder
.addInMozillaDom("DocGroup")
20556 for member
in descriptor
.interface
.members
:
20557 if not member
.isAttr() and not member
.isMethod():
20559 if member
.isStatic():
20560 builder
.addInMozillaDom("GlobalObject")
20561 if member
.isAttr():
20562 if not member
.isMaplikeOrSetlikeAttr():
20563 builder
.forwardDeclareForType(member
.type, config
)
20565 assert member
.isMethod()
20566 if not member
.isMaplikeOrSetlikeOrIterableMethod():
20567 for sig
in member
.signatures():
20568 builder
.forwardDeclareForType(sig
[0], config
)
20570 builder
.forwardDeclareForType(arg
.type, config
)
20572 self
.root
= CGList([builder
.build(), self
.root
], "\n")
20574 # Throw in our #includes
20575 self
.root
= CGHeaders(
20581 "nsWrapperCache.h",
20582 "nsCycleCollectionParticipant.h",
20583 "mozilla/Attributes.h",
20584 "mozilla/ErrorResult.h",
20585 "mozilla/dom/BindingDeclarations.h",
20589 "mozilla/dom/%s.h" % interfaceName
,
20592 % CGHeaders
.getDeclarationFilename(descriptor
.interface
)
20599 # And now some include guards
20600 self
.root
= CGIncludeGuard(interfaceName
, self
.root
)
20602 # And our license block comes before everything else
20603 self
.root
= CGWrapper(
20607 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
20608 /* vim:set ts=2 sw=2 sts=2 et cindent: */
20609 /* This Source Code Form is subject to the terms of the Mozilla Public
20610 * License, v. 2.0. If a copy of the MPL was not distributed with this
20611 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
20618 return self
.root
.declare()
20621 return self
.root
.define()
20624 def jsImplName(name
):
20625 return name
+ "JSImpl"
20628 class CGJSImplMember(CGNativeMember
):
20630 Base class for generating code for the members of the implementation class
20631 for a JS-implemented WebIDL interface.
20636 descriptorProvider
,
20642 passJSBitsAsNeeded
=True,
20643 visibility
="public",
20644 variadicIsSequence
=False,
20648 CGNativeMember
.__init
__(
20650 descriptorProvider
,
20655 breakAfter
=breakAfter
,
20656 passJSBitsAsNeeded
=passJSBitsAsNeeded
,
20657 visibility
=visibility
,
20658 variadicIsSequence
=variadicIsSequence
,
20662 self
.body
= self
.getImpl()
20664 def getArgs(self
, returnType
, argList
):
20665 args
= CGNativeMember
.getArgs(self
, returnType
, argList
)
20666 args
.append(Argument("JS::Realm*", "aRealm", "nullptr"))
20670 class CGJSImplMethod(CGJSImplMember
):
20672 Class for generating code for the methods for a JS-implemented WebIDL
20676 def __init__(self
, descriptor
, method
, signature
, isConstructor
, breakAfter
=True):
20677 self
.signature
= signature
20678 self
.descriptor
= descriptor
20679 self
.isConstructor
= isConstructor
20680 CGJSImplMember
.__init
__(
20684 CGSpecializedMethod
.makeNativeName(descriptor
, method
),
20686 descriptor
.getExtendedAttributes(method
),
20687 breakAfter
=breakAfter
,
20688 variadicIsSequence
=True,
20689 passJSBitsAsNeeded
=False,
20692 def getArgs(self
, returnType
, argList
):
20693 if self
.isConstructor
:
20694 # Skip the JS::Compartment bits for constructors; it's handled
20695 # manually in getImpl. But we do need our aGivenProto argument. We
20696 # allow it to be omitted if the default proto is desired.
20697 return CGNativeMember
.getArgs(self
, returnType
, argList
) + [
20698 Argument("JS::Handle<JSObject*>", "aGivenProto", "nullptr")
20700 return CGJSImplMember
.getArgs(self
, returnType
, argList
)
20703 args
= self
.getArgs(self
.signature
[0], self
.signature
[1])
20704 if not self
.isConstructor
:
20705 return "return mImpl->%s(%s);\n" % (
20707 ", ".join(arg
.name
for arg
in args
),
20710 assert self
.descriptor
.interface
.isJSImplemented()
20711 if self
.name
!= "Constructor":
20713 "Legacy factory functions are not supported for JS implemented WebIDL."
20715 if len(self
.signature
[1]) != 0:
20716 # The first two arguments to the constructor implementation are not
20717 # arguments to the WebIDL constructor, so don't pass them to
20718 # __Init(). The last argument is the prototype we're supposed to
20719 # use, and shouldn't get passed to __Init() either.
20720 assert args
[0].argType
== "const GlobalObject&"
20721 assert args
[1].argType
== "JSContext*"
20722 assert args
[-1].argType
== "JS::Handle<JSObject*>"
20723 assert args
[-1].name
== "aGivenProto"
20724 constructorArgs
= [arg
.name
for arg
in args
[2:-1]]
20725 constructorArgs
.append("js::GetNonCCWObjectRealm(scopeObj)")
20728 // Wrap the object before calling __Init so that __DOM_IMPL__ is available.
20729 JS::Rooted<JSObject*> scopeObj(cx, global.Get());
20730 MOZ_ASSERT(js::IsObjectInContextCompartment(scopeObj, cx));
20731 JS::Rooted<JS::Value> wrappedVal(cx);
20732 if (!GetOrCreateDOMReflector(cx, impl, &wrappedVal, aGivenProto)) {
20733 MOZ_ASSERT(JS_IsExceptionPending(cx));
20734 aRv.Throw(NS_ERROR_UNEXPECTED);
20737 // Initialize the object with the constructor arguments.
20738 impl->mImpl->__Init(${args});
20739 if (aRv.Failed()) {
20743 args
=", ".join(constructorArgs
),
20749 RefPtr<${implClass}> impl =
20750 ConstructJSImplementation<${implClass}>("${contractId}", global, aRv);
20751 if (aRv.Failed()) {
20755 return impl.forget();
20757 contractId
=self
.descriptor
.interface
.getJSImplementation(),
20758 implClass
=self
.descriptor
.name
,
20763 # We're always fallible
20764 def callbackGetterName(attr
, descriptor
):
20765 return "Get" + MakeNativeName(
20766 descriptor
.binaryNameFor(attr
.identifier
.name
, attr
.isStatic())
20770 def callbackSetterName(attr
, descriptor
):
20771 return "Set" + MakeNativeName(
20772 descriptor
.binaryNameFor(attr
.identifier
.name
, attr
.isStatic())
20776 class CGJSImplGetter(CGJSImplMember
):
20778 Class for generating code for the getters of attributes for a JS-implemented
20782 def __init__(self
, descriptor
, attr
):
20783 CGJSImplMember
.__init
__(
20787 CGSpecializedGetterCommon
.makeNativeName(descriptor
, attr
),
20789 descriptor
.getExtendedAttributes(attr
, getter
=True),
20790 passJSBitsAsNeeded
=False,
20794 callbackArgs
= [arg
.name
for arg
in self
.getArgs(self
.member
.type, [])]
20795 return "return mImpl->%s(%s);\n" % (
20796 callbackGetterName(self
.member
, self
.descriptorProvider
),
20797 ", ".join(callbackArgs
),
20801 class CGJSImplSetter(CGJSImplMember
):
20803 Class for generating code for the setters of attributes for a JS-implemented
20807 def __init__(self
, descriptor
, attr
):
20808 CGJSImplMember
.__init
__(
20812 CGSpecializedSetterCommon
.makeNativeName(descriptor
, attr
),
20814 BuiltinTypes
[IDLBuiltinType
.Types
.undefined
],
20815 [FakeArgument(attr
.type)],
20817 descriptor
.getExtendedAttributes(attr
, setter
=True),
20818 passJSBitsAsNeeded
=False,
20824 for arg
in self
.getArgs(
20825 BuiltinTypes
[IDLBuiltinType
.Types
.undefined
],
20826 [FakeArgument(self
.member
.type)],
20829 return "mImpl->%s(%s);\n" % (
20830 callbackSetterName(self
.member
, self
.descriptorProvider
),
20831 ", ".join(callbackArgs
),
20835 class CGJSImplClass(CGBindingImplClass
):
20836 def __init__(self
, descriptor
):
20837 CGBindingImplClass
.__init
__(
20843 skipStaticMethods
=True,
20846 if descriptor
.interface
.parent
:
20847 parentClass
= descriptor
.getDescriptor(
20848 descriptor
.interface
.parent
.identifier
.name
20850 baseClasses
= [ClassBase(parentClass
)]
20851 isupportsDecl
= "NS_DECL_ISUPPORTS_INHERITED\n"
20852 ccDecl
= "NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(%s, %s)\n" % (
20856 extradefinitions
= fill(
20858 NS_IMPL_CYCLE_COLLECTION_INHERITED(${ifaceName}, ${parentClass}, mImpl, mParent)
20859 NS_IMPL_ADDREF_INHERITED(${ifaceName}, ${parentClass})
20860 NS_IMPL_RELEASE_INHERITED(${ifaceName}, ${parentClass})
20861 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${ifaceName})
20862 NS_INTERFACE_MAP_END_INHERITING(${parentClass})
20864 ifaceName
=self
.descriptor
.name
,
20865 parentClass
=parentClass
,
20869 ClassBase("nsSupportsWeakReference"),
20870 ClassBase("nsWrapperCache"),
20872 isupportsDecl
= "NS_DECL_CYCLE_COLLECTING_ISUPPORTS\n"
20874 "NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(%s)\n" % descriptor
.name
20876 extradefinitions
= fill(
20878 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(${ifaceName})
20879 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(${ifaceName})
20880 NS_IMPL_CYCLE_COLLECTION_UNLINK(mImpl)
20881 NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
20882 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
20883 tmp->ClearWeakReferences();
20884 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
20885 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(${ifaceName})
20886 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImpl)
20887 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
20888 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
20889 NS_IMPL_CYCLE_COLLECTING_ADDREF(${ifaceName})
20890 NS_IMPL_CYCLE_COLLECTING_RELEASE(${ifaceName})
20891 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${ifaceName})
20892 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
20893 NS_INTERFACE_MAP_ENTRY(nsISupports)
20894 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
20895 NS_INTERFACE_MAP_END
20897 ifaceName
=self
.descriptor
.name
,
20900 extradeclarations
= fill(
20907 RefPtr<${jsImplName}> mImpl;
20908 nsCOMPtr<nsIGlobalObject> mParent;
20911 isupportsDecl
=isupportsDecl
,
20913 jsImplName
=jsImplName(descriptor
.name
),
20916 if descriptor
.interface
.getExtendedAttribute("WantsEventListenerHooks"):
20917 # No need to do too much sanity checking here; the
20918 # generated code will fail to compile if the methods we
20919 # try to overrid aren't on a superclass.
20920 self
.methodDecls
.extend(
20921 self
.getEventHookMethod(parentClass
, "EventListenerAdded")
20923 self
.methodDecls
.extend(
20924 self
.getEventHookMethod(parentClass
, "EventListenerRemoved")
20927 if descriptor
.interface
.hasChildInterfaces():
20929 # We need a protected virtual destructor our subclasses can use
20930 destructor
= ClassDestructor(virtual
=True, visibility
="protected")
20932 decorators
= "final"
20933 destructor
= ClassDestructor(virtual
=False, visibility
="private")
20935 baseConstructors
= [
20937 "mImpl(new %s(nullptr, aJSImplObject, aJSImplGlobal, /* aIncumbentGlobal = */ nullptr))"
20938 % jsImplName(descriptor
.name
)
20940 "mParent(aParent)",
20942 parentInterface
= descriptor
.interface
.parent
20943 while parentInterface
:
20944 if parentInterface
.isJSImplemented():
20945 baseConstructors
.insert(
20946 0, "%s(aJSImplObject, aJSImplGlobal, aParent)" % parentClass
20949 parentInterface
= parentInterface
.parent
20950 if not parentInterface
and descriptor
.interface
.parent
:
20951 # We only have C++ ancestors, so only pass along the window
20952 baseConstructors
.insert(0, "%s(aParent)" % parentClass
)
20954 constructor
= ClassConstructor(
20956 Argument("JS::Handle<JSObject*>", "aJSImplObject"),
20957 Argument("JS::Handle<JSObject*>", "aJSImplGlobal"),
20958 Argument("nsIGlobalObject*", "aParent"),
20960 visibility
="public",
20961 baseConstructors
=baseConstructors
,
20964 self
.methodDecls
.append(
20968 JSNativeArguments(),
20970 body
=self
.getCreateFromExistingBody(),
20978 constructors
=[constructor
],
20979 destructor
=destructor
,
20980 methods
=self
.methodDecls
,
20981 decorators
=decorators
,
20982 extradeclarations
=extradeclarations
,
20983 extradefinitions
=extradefinitions
,
20986 def getWrapObjectBody(self
):
20989 JS::Rooted<JSObject*> obj(aCx, ${name}_Binding::Wrap(aCx, this, aGivenProto));
20994 // Now define it on our chrome object
20995 JSAutoRealm ar(aCx, mImpl->CallbackGlobalOrNull());
20996 if (!JS_WrapObject(aCx, &obj)) {
20999 JS::Rooted<JSObject*> callback(aCx, mImpl->CallbackOrNull());
21000 if (!JS_DefineProperty(aCx, callback, "__DOM_IMPL__", obj, 0)) {
21005 name
=self
.descriptor
.name
,
21008 def getGetParentObjectReturnType(self
):
21009 return "nsISupports*"
21011 def getGetParentObjectBody(self
):
21012 return "return mParent;\n"
21014 def getGetDocGroupBody(self
):
21017 nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mParent);
21021 return window->GetDocGroup();
21025 def getCreateFromExistingBody(self
):
21026 # XXXbz we could try to get parts of this (e.g. the argument
21027 # conversions) auto-generated by somehow creating an IDLMethod and
21028 # adding it to our interface, but we'd still need to special-case the
21029 # implementation slightly to have it not try to forward to the JS
21033 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
21034 if (!args.requireAtLeast(cx, "${ifaceName}._create", 2)) {
21037 BindingCallContext callCx(cx, "${ifaceName}._create");
21038 if (!args[0].isObject()) {
21039 return callCx.ThrowErrorMessage<MSG_NOT_OBJECT>("Argument 1");
21041 if (!args[1].isObject()) {
21042 return callCx.ThrowErrorMessage<MSG_NOT_OBJECT>("Argument 2");
21045 // GlobalObject will go through wrappers as needed for us, and
21046 // is simpler than the right UnwrapArg incantation.
21047 GlobalObject global(cx, &args[0].toObject());
21048 if (global.Failed()) {
21051 nsCOMPtr<nsIGlobalObject> globalHolder = do_QueryInterface(global.GetAsSupports());
21052 MOZ_ASSERT(globalHolder);
21053 JS::Rooted<JSObject*> arg(cx, &args[1].toObject());
21054 JS::Rooted<JSObject*> argGlobal(cx, JS::CurrentGlobalOrNull(cx));
21055 RefPtr<${implName}> impl = new ${implName}(arg, argGlobal, globalHolder);
21056 MOZ_ASSERT(js::IsObjectInContextCompartment(arg, cx));
21057 return GetOrCreateDOMReflector(cx, impl, args.rval());
21059 ifaceName
=self
.descriptor
.interface
.identifier
.name
,
21060 implName
=self
.descriptor
.name
,
21063 def getEventHookMethod(self
, parentClass
, methodName
):
21066 ${parentClass}::${methodName}(aType);
21067 mImpl->${methodName}(Substring(nsDependentAtomString(aType), 2), IgnoreErrors());
21069 parentClass
=parentClass
,
21070 methodName
=methodName
,
21076 [Argument("nsAtom*", "aType")],
21081 ClassUsingFromBaseDeclaration(parentClass
, methodName
),
21085 def isJSImplementedDescriptor(descriptorProvider
):
21087 isinstance(descriptorProvider
, Descriptor
)
21088 and descriptorProvider
.interface
.isJSImplemented()
21092 class CGCallback(CGClass
):
21094 self
, idlObject
, descriptorProvider
, baseName
, methods
, getters
=[], setters
=[]
21096 self
.baseName
= baseName
21097 self
._deps
= idlObject
.getDeps()
21098 self
.idlObject
= idlObject
21099 self
.name
= idlObject
.identifier
.name
21100 if isJSImplementedDescriptor(descriptorProvider
):
21101 self
.name
= jsImplName(self
.name
)
21102 # For our public methods that needThisHandling we want most of the
21103 # same args and the same return type as what CallbackMember
21104 # generates. So we want to take advantage of all its
21105 # CGNativeMember infrastructure, but that infrastructure can't deal
21106 # with templates and most especially template arguments. So just
21107 # cheat and have CallbackMember compute all those things for us.
21109 for method
in methods
:
21110 if not isinstance(method
, CallbackMember
) or not method
.needThisHandling
:
21111 realMethods
.append(method
)
21113 realMethods
.extend(self
.getMethodImpls(method
))
21114 realMethods
.append(
21118 [Argument("const %s&" % self
.name
, "aOther")],
21122 body
=("return %s::operator==(aOther);\n" % baseName
),
21128 bases
=[ClassBase(baseName
)],
21129 constructors
=self
.getConstructors(),
21130 methods
=realMethods
+ getters
+ setters
,
21133 def getConstructors(self
):
21135 not self
.idlObject
.isInterface()
21136 and not self
.idlObject
._treatNonObjectAsNull
21138 body
= "MOZ_ASSERT(JS::IsCallable(mCallback));\n"
21140 # Not much we can assert about it, other than not being null, and
21141 # CallbackObject does that already.
21146 Argument("JSContext*", "aCx"),
21147 Argument("JS::Handle<JSObject*>", "aCallback"),
21148 Argument("JS::Handle<JSObject*>", "aCallbackGlobal"),
21149 Argument("nsIGlobalObject*", "aIncumbentGlobal"),
21152 visibility
="public",
21155 "%s(aCx, aCallback, aCallbackGlobal, aIncumbentGlobal)"
21162 Argument("JSObject*", "aCallback"),
21163 Argument("JSObject*", "aCallbackGlobal"),
21164 Argument("const FastCallbackConstructor&", ""),
21167 visibility
="public",
21170 "%s(aCallback, aCallbackGlobal, FastCallbackConstructor())"
21177 Argument("JSObject*", "aCallback"),
21178 Argument("JSObject*", "aCallbackGlobal"),
21179 Argument("JSObject*", "aAsyncStack"),
21180 Argument("nsIGlobalObject*", "aIncumbentGlobal"),
21183 visibility
="public",
21186 "%s(aCallback, aCallbackGlobal, aAsyncStack, aIncumbentGlobal)"
21193 def getMethodImpls(self
, method
):
21194 assert method
.needThisHandling
21195 args
= list(method
.args
)
21196 # Strip out the BindingCallContext&/JSObject* args
21198 assert args
[0].name
== "cx" and args
[0].argType
== "BindingCallContext&"
21199 assert args
[1].name
== "aThisVal" and args
[1].argType
== "JS::Handle<JS::Value>"
21202 # Now remember which index the ErrorResult argument is at;
21203 # we'll need this below.
21204 assert args
[-1].name
== "aRv" and args
[-1].argType
== "ErrorResult&"
21205 rvIndex
= len(args
) - 1
21206 assert rvIndex
>= 0
21208 # Record the names of all the arguments, so we can use them when we call
21209 # the private method.
21210 argnames
= [arg
.name
for arg
in args
]
21211 argnamesWithThis
= ["s.GetCallContext()", "thisValJS"] + argnames
21212 argnamesWithoutThis
= [
21213 "s.GetCallContext()",
21214 "JS::UndefinedHandleValue",
21216 # Now that we've recorded the argnames for our call to our private
21217 # method, insert our optional argument for the execution reason.
21218 args
.append(Argument("const char*", "aExecutionReason", "nullptr"))
21220 # Make copies of the arg list for the two "without rv" overloads. Note
21221 # that those don't need aExceptionHandling or aRealm arguments because
21222 # those would make not sense anyway: the only sane thing to do with
21223 # exceptions in the "without rv" cases is to report them.
21224 argsWithoutRv
= list(args
)
21225 argsWithoutRv
.pop(rvIndex
)
21226 argsWithoutThisAndRv
= list(argsWithoutRv
)
21228 # Add the potional argument for deciding whether the CallSetup should
21229 # re-throw exceptions on aRv.
21231 Argument("ExceptionHandling", "aExceptionHandling", "eReportExceptions")
21233 # And the argument for communicating when exceptions should really be
21234 # rethrown. In particular, even when aExceptionHandling is
21235 # eRethrowExceptions they won't get rethrown if aRealm is provided
21236 # and its principal doesn't subsume either the callback or the
21238 args
.append(Argument("JS::Realm*", "aRealm", "nullptr"))
21239 # And now insert our template argument.
21240 argsWithoutThis
= list(args
)
21241 args
.insert(0, Argument("const T&", "thisVal"))
21242 argsWithoutRv
.insert(0, Argument("const T&", "thisVal"))
21244 argnamesWithoutThisAndRv
= [arg
.name
for arg
in argsWithoutThisAndRv
]
21245 argnamesWithoutThisAndRv
.insert(rvIndex
, "IgnoreErrors()")
21246 # If we just leave things like that, and have no actual arguments in the
21247 # IDL, we will end up trying to call the templated "without rv" overload
21248 # with "rv" as the thisVal. That's no good. So explicitly append the
21249 # aExceptionHandling and aRealm values we need to end up matching the
21250 # signature of our non-templated "with rv" overload.
21251 argnamesWithoutThisAndRv
.extend(["eReportExceptions", "nullptr"])
21253 argnamesWithoutRv
= [arg
.name
for arg
in argsWithoutRv
]
21254 # Note that we need to insert at rvIndex + 1, since we inserted a
21255 # thisVal arg at the start.
21256 argnamesWithoutRv
.insert(rvIndex
+ 1, "IgnoreErrors()")
21258 errorReturn
= method
.getDefaultRetval()
21262 MOZ_ASSERT(!aRv.Failed(), "Don't pass an already-failed ErrorResult to a callback!");
21263 if (!aExecutionReason) {
21264 aExecutionReason = "${executionReason}";
21266 CallSetup s(this, aRv, aExecutionReason, aExceptionHandling, aRealm);
21267 if (!s.GetContext()) {
21268 MOZ_ASSERT(aRv.Failed());
21269 return${errorReturn};
21272 errorReturn
=errorReturn
,
21273 executionReason
=method
.getPrettyName(),
21276 bodyWithThis
= fill(
21279 JS::Rooted<JS::Value> thisValJS(s.GetContext());
21280 if (!ToJSValue(s.GetContext(), thisVal, &thisValJS)) {
21281 aRv.Throw(NS_ERROR_FAILURE);
21282 return${errorReturn};
21284 return ${methodName}(${callArgs});
21286 setupCall
=setupCall
,
21287 errorReturn
=errorReturn
,
21288 methodName
=method
.name
,
21289 callArgs
=", ".join(argnamesWithThis
),
21291 bodyWithoutThis
= fill(
21294 return ${methodName}(${callArgs});
21296 setupCall
=setupCall
,
21297 errorReturn
=errorReturn
,
21298 methodName
=method
.name
,
21299 callArgs
=", ".join(argnamesWithoutThis
),
21301 bodyWithThisWithoutRv
= fill(
21303 return ${methodName}(${callArgs});
21305 methodName
=method
.name
,
21306 callArgs
=", ".join(argnamesWithoutRv
),
21308 bodyWithoutThisAndRv
= fill(
21310 return ${methodName}(${callArgs});
21312 methodName
=method
.name
,
21313 callArgs
=", ".join(argnamesWithoutThisAndRv
),
21322 templateArgs
=["typename T"],
21324 canRunScript
=method
.canRunScript
,
21331 body
=bodyWithoutThis
,
21332 canRunScript
=method
.canRunScript
,
21339 templateArgs
=["typename T"],
21340 body
=bodyWithThisWithoutRv
,
21341 canRunScript
=method
.canRunScript
,
21346 argsWithoutThisAndRv
,
21348 body
=bodyWithoutThisAndRv
,
21349 canRunScript
=method
.canRunScript
,
21358 class CGCallbackFunction(CGCallback
):
21359 def __init__(self
, callback
, descriptorProvider
):
21360 self
.callback
= callback
21361 if callback
.isConstructor():
21362 methods
= [ConstructCallback(callback
, descriptorProvider
)]
21364 methods
= [CallCallback(callback
, descriptorProvider
)]
21365 CGCallback
.__init
__(
21366 self
, callback
, descriptorProvider
, "CallbackFunction", methods
21369 def getConstructors(self
):
21370 return CGCallback
.getConstructors(self
) + [
21372 [Argument("CallbackFunction*", "aOther")],
21374 visibility
="public",
21376 baseConstructors
=["CallbackFunction(aOther)"],
21381 class CGFastCallback(CGClass
):
21382 def __init__(self
, idlObject
):
21383 self
._deps
= idlObject
.getDeps()
21384 baseName
= idlObject
.identifier
.name
21385 constructor
= ClassConstructor(
21387 Argument("JSObject*", "aCallback"),
21388 Argument("JSObject*", "aCallbackGlobal"),
21391 visibility
="public",
21394 "%s(aCallback, aCallbackGlobal, FastCallbackConstructor())" % baseName
,
21399 traceMethod
= ClassMethod(
21402 [Argument("JSTracer*", "aTracer")],
21405 visibility
="public",
21406 body
="%s::Trace(aTracer);\n" % baseName
,
21408 holdMethod
= ClassMethod(
21409 "FinishSlowJSInitIfMoreThanOneOwner",
21411 [Argument("JSContext*", "aCx")],
21414 visibility
="public",
21415 body
=("%s::FinishSlowJSInitIfMoreThanOneOwner(aCx);\n" % baseName
),
21420 "Fast%s" % baseName
,
21421 bases
=[ClassBase(baseName
)],
21422 constructors
=[constructor
],
21423 methods
=[traceMethod
, holdMethod
],
21430 class CGCallbackInterface(CGCallback
):
21431 def __init__(self
, descriptor
, spiderMonkeyInterfacesAreStructs
=False):
21432 iface
= descriptor
.interface
21435 for m
in iface
.members
21438 and not m
.isStatic()
21439 and (not m
.isMaplikeOrSetlikeAttr() or not iface
.isJSImplemented())
21443 CallbackGetter(a
, descriptor
, spiderMonkeyInterfacesAreStructs
)
21447 CallbackSetter(a
, descriptor
, spiderMonkeyInterfacesAreStructs
)
21453 for m
in iface
.members
21456 and not m
.isStatic()
21457 and not m
.isIdentifierLess()
21459 not m
.isMaplikeOrSetlikeOrIterableMethod()
21460 or not iface
.isJSImplemented()
21465 CallbackOperation(m
, sig
, descriptor
, spiderMonkeyInterfacesAreStructs
)
21467 for sig
in m
.signatures()
21471 if iface
.isJSImplemented() and iface
.ctor():
21472 sigs
= descriptor
.interface
.ctor().signatures()
21474 raise TypeError("We only handle one constructor. See bug 869268.")
21475 methods
.append(CGJSImplInitOperation(sigs
[0], descriptor
))
21479 descriptor
.binaryNameFor(m
.identifier
.name
, m
.isStatic())
21480 for m
in iface
.members
21481 if m
.isAttr() or m
.isMethod()
21484 idlist
.append("__init")
21486 if iface
.isJSImplemented() and iface
.getExtendedAttribute(
21487 "WantsEventListenerHooks"
21489 methods
.append(CGJSImplEventHookOperation(descriptor
, "eventListenerAdded"))
21491 CGJSImplEventHookOperation(descriptor
, "eventListenerRemoved")
21493 idlist
.append("eventListenerAdded")
21494 idlist
.append("eventListenerRemoved")
21496 if len(idlist
) != 0:
21497 methods
.append(initIdsClassMethod(idlist
, iface
.identifier
.name
+ "Atoms"))
21498 CGCallback
.__init
__(
21502 "CallbackInterface",
21510 def __init__(self
, name
=None):
21511 if name
is not None:
21512 self
.identifier
= FakeIdentifier(name
)
21514 def isStatic(self
):
21520 def isMethod(self
):
21523 def getExtendedAttribute(self
, name
):
21524 # Claim to be a [NewObject] so we can avoid the "return a raw pointer"
21525 # comments CGNativeMember codegen would otherwise stick in.
21526 if name
== "NewObject":
21531 class CallbackMember(CGNativeMember
):
21532 # XXXbz It's OK to use CallbackKnownNotGray for wrapScope because
21533 # CallSetup already handled the unmark-gray bits for us. we don't have
21534 # anything better to use for 'obj', really...
21539 descriptorProvider
,
21541 rethrowContentException
=False,
21542 spiderMonkeyInterfacesAreStructs
=False,
21544 canRunScript
=False,
21545 passJSBitsAsNeeded
=False,
21548 needThisHandling is True if we need to be able to accept a specified
21549 thisObj, False otherwise.
21551 assert not rethrowContentException
or not needThisHandling
21553 self
.retvalType
= sig
[0]
21554 self
.originalSig
= sig
21556 self
.argCount
= len(args
)
21557 if self
.argCount
> 0:
21558 # Check for variadic arguments
21559 lastArg
= args
[self
.argCount
- 1]
21560 if lastArg
.variadic
:
21561 self
.argCountStr
= "(%d - 1) + %s.Length()" % (
21563 lastArg
.identifier
.name
,
21566 self
.argCountStr
= "%d" % self
.argCount
21567 self
.needThisHandling
= needThisHandling
21568 # If needThisHandling, we generate ourselves as private and the caller
21569 # will handle generating public versions that handle the "this" stuff.
21570 visibility
= "private" if needThisHandling
else "public"
21571 self
.rethrowContentException
= rethrowContentException
21573 self
.wrapScope
= wrapScope
21574 # We don't care, for callback codegen, whether our original member was
21575 # a method or attribute or whatnot. Just always pass FakeMember()
21577 CGNativeMember
.__init
__(
21579 descriptorProvider
,
21582 (self
.retvalType
, args
),
21583 extendedAttrs
=["needsErrorResult"],
21584 passJSBitsAsNeeded
=passJSBitsAsNeeded
,
21585 visibility
=visibility
,
21586 spiderMonkeyInterfacesAreStructs
=spiderMonkeyInterfacesAreStructs
,
21587 canRunScript
=canRunScript
,
21589 # We have to do all the generation of our body now, because
21590 # the caller relies on us throwing if we can't manage it.
21591 self
.body
= self
.getImpl()
21594 setupCall
= self
.getCallSetup()
21595 declRval
= self
.getRvalDecl()
21596 if self
.argCount
> 0:
21599 JS::RootedVector<JS::Value> argv(cx);
21600 if (!argv.resize(${argCount})) {
21602 return${errorReturn};
21605 argCount
=self
.argCountStr
,
21606 failureCode
=self
.getArgvDeclFailureCode(),
21607 errorReturn
=self
.getDefaultRetval(),
21610 # Avoid weird 0-sized arrays
21612 convertArgs
= self
.getArgConversions()
21613 doCall
= self
.getCall()
21614 returnResult
= self
.getResultConversion()
21616 body
= declRval
+ argvDecl
+ convertArgs
+ doCall
21617 if self
.needsScopeBody():
21618 body
= "{\n" + indent(body
) + "}\n"
21619 return setupCall
+ body
+ returnResult
21621 def needsScopeBody(self
):
21624 def getArgvDeclFailureCode(self
):
21627 // That threw an exception on the JSContext, and our CallSetup will do
21628 // the right thing with that.
21632 def getExceptionCode(self
, forResult
):
21635 aRv.Throw(NS_ERROR_UNEXPECTED);
21636 return${defaultRetval};
21638 defaultRetval
=self
.getDefaultRetval(),
21641 def getResultConversion(
21642 self
, val
="rval", failureCode
=None, isDefinitelyObject
=False, exceptionCode
=None
21646 "holderName": "rvalHolder",
21647 "declName": "rvalDecl",
21648 # We actually want to pass in a null scope object here, because
21649 # wrapping things into our current compartment (that of mCallback)
21652 "passedToJSImpl": "false",
21655 if isJSImplementedDescriptor(self
.descriptorProvider
):
21656 isCallbackReturnValue
= "JSImpl"
21658 isCallbackReturnValue
= "Callback"
21659 sourceDescription
= "return value of %s" % self
.getPrettyName()
21660 convertType
= instantiateJSToNativeConversion(
21661 getJSToNativeConversionInfo(
21663 self
.descriptorProvider
,
21664 failureCode
=failureCode
,
21665 isDefinitelyObject
=isDefinitelyObject
,
21666 exceptionCode
=exceptionCode
or self
.getExceptionCode(forResult
=True),
21667 isCallbackReturnValue
=isCallbackReturnValue
,
21668 # Allow returning a callback type that
21669 # allows non-callable objects.
21670 allowTreatNonCallableAsNull
=True,
21671 sourceDescription
=sourceDescription
,
21675 assignRetval
= string
.Template(
21676 self
.getRetvalInfo(self
.retvalType
, False)[2]
21677 ).substitute(replacements
)
21678 type = convertType
.define()
21679 return type + assignRetval
21681 def getArgConversions(self
):
21682 # Just reget the arglist from self.originalSig, because our superclasses
21683 # just have way to many members they like to clobber, so I can't find a
21684 # safe member name to store it in.
21686 self
.getArgConversion(i
, arg
) for i
, arg
in enumerate(self
.originalSig
[1])
21688 if not argConversions
:
21691 # Do them back to front, so our argc modifications will work
21692 # correctly, because we examine trailing arguments first.
21693 argConversions
.reverse()
21694 # Wrap each one in a scope so that any locals it has don't leak out, and
21695 # also so that we can just "break;" for our successCode.
21697 CGWrapper(CGIndenter(CGGeneric(c
)), pre
="do {\n", post
="} while (false);\n")
21698 for c
in argConversions
21700 if self
.argCount
> 0:
21701 argConversions
.insert(0, self
.getArgcDecl())
21702 # And slap them together.
21703 return CGList(argConversions
, "\n").define() + "\n"
21705 def getArgConversion(self
, i
, arg
):
21706 argval
= arg
.identifier
.name
21709 argval
= argval
+ "[idx]"
21710 jsvalIndex
= "%d + idx" % i
21712 jsvalIndex
= "%d" % i
21713 if arg
.canHaveMissingValue():
21714 argval
+= ".Value()"
21718 wrapScope
= self
.wrapScope
21719 if arg
.type.isUnion() and wrapScope
is None:
21721 "JS::Rooted<JSObject*> callbackObj(cx, CallbackKnownNotGray());\n"
21723 wrapScope
= "callbackObj"
21725 conversion
= prepend
+ wrapForType(
21727 self
.descriptorProvider
,
21730 "successCode": "continue;\n" if arg
.variadic
else "break;\n",
21731 "jsvalRef": "argv[%s]" % jsvalIndex
,
21732 "jsvalHandle": "argv[%s]" % jsvalIndex
,
21734 "returnsNewObject": False,
21735 "exceptionCode": self
.getExceptionCode(forResult
=False),
21736 "spiderMonkeyInterfacesAreStructs": self
.spiderMonkeyInterfacesAreStructs
,
21743 for (uint32_t idx = 0; idx < ${arg}.Length(); ++idx) {
21748 arg
=arg
.identifier
.name
,
21749 conversion
=conversion
,
21751 elif arg
.canHaveMissingValue():
21754 if (${argName}.WasPassed()) {
21756 } else if (argc == ${iPlus1}) {
21757 // This is our current trailing argument; reduce argc
21760 argv[${i}].setUndefined();
21763 argName
=arg
.identifier
.name
,
21764 conversion
=conversion
,
21770 def getDefaultRetval(self
):
21771 default
= self
.getRetvalInfo(self
.retvalType
, False)[1]
21772 if len(default
) != 0:
21773 default
= " " + default
21776 def getArgs(self
, returnType
, argList
):
21777 args
= CGNativeMember
.getArgs(self
, returnType
, argList
)
21778 if not self
.needThisHandling
:
21779 # Since we don't need this handling, we're the actual method that
21780 # will be called, so we need an aRethrowExceptions argument.
21781 if not self
.rethrowContentException
:
21782 args
.append(Argument("const char*", "aExecutionReason", "nullptr"))
21785 "ExceptionHandling", "aExceptionHandling", "eReportExceptions"
21788 args
.append(Argument("JS::Realm*", "aRealm", "nullptr"))
21790 # We want to allow the caller to pass in a "this" value, as
21791 # well as a BindingCallContext.
21793 Argument("BindingCallContext&", "cx"),
21794 Argument("JS::Handle<JS::Value>", "aThisVal"),
21797 def getCallSetup(self
):
21798 if self
.needThisHandling
:
21799 # It's been done for us already
21801 callSetup
= "CallSetup s(this, aRv"
21802 if self
.rethrowContentException
:
21803 # getArgs doesn't add the aExceptionHandling argument but does add
21806 ', "%s", eRethrowContentExceptions, aRealm, /* aIsJSImplementedWebIDL = */ '
21807 % self
.getPrettyName()
21809 callSetup
+= toStringBool(
21810 isJSImplementedDescriptor(self
.descriptorProvider
)
21813 callSetup
+= ', "%s", aExceptionHandling, aRealm' % self
.getPrettyName()
21814 callSetup
+= ");\n"
21818 if (aRv.Failed()) {
21819 return${errorReturn};
21821 MOZ_ASSERT(s.GetContext());
21822 BindingCallContext& cx = s.GetCallContext();
21825 callSetup
=callSetup
,
21826 errorReturn
=self
.getDefaultRetval(),
21829 def getArgcDecl(self
):
21830 return CGGeneric("unsigned argc = %s;\n" % self
.argCountStr
)
21833 def ensureASCIIName(idlObject
):
21834 type = "attribute" if idlObject
.isAttr() else "operation"
21835 if re
.match("[^\x20-\x7E]", idlObject
.identifier
.name
):
21837 'Callback %s name "%s" contains non-ASCII '
21838 "characters. We can't handle that. %s"
21839 % (type, idlObject
.identifier
.name
, idlObject
.location
)
21841 if re
.match('"', idlObject
.identifier
.name
):
21843 "Callback %s name '%s' contains "
21844 "double-quote character. We can't handle "
21845 "that. %s" % (type, idlObject
.identifier
.name
, idlObject
.location
)
21849 class ConstructCallback(CallbackMember
):
21850 def __init__(self
, callback
, descriptorProvider
):
21851 self
.callback
= callback
21852 CallbackMember
.__init
__(
21854 callback
.signatures()[0],
21856 descriptorProvider
,
21857 needThisHandling
=False,
21861 def getRvalDecl(self
):
21862 # Box constructedObj for getJSToNativeConversionInfo().
21863 return "JS::Rooted<JS::Value> rval(cx);\n"
21866 if self
.argCount
> 0:
21867 args
= "JS::HandleValueArray::subarray(argv, 0, argc)"
21869 args
= "JS::HandleValueArray::empty()"
21873 JS::Rooted<JS::Value> constructor(cx, JS::ObjectValue(*mCallback));
21874 JS::Rooted<JSObject*> constructedObj(cx);
21875 if (!JS::Construct(cx, constructor,
21876 ${args}, &constructedObj)) {
21877 aRv.NoteJSContextException(cx);
21878 return${errorReturn};
21880 rval.setObject(*constructedObj);
21883 errorReturn
=self
.getDefaultRetval(),
21886 def getResultConversion(self
):
21887 return CallbackMember
.getResultConversion(self
, isDefinitelyObject
=True)
21889 def getPrettyName(self
):
21890 return self
.callback
.identifier
.name
21893 class CallbackMethod(CallbackMember
):
21898 descriptorProvider
,
21900 rethrowContentException
=False,
21901 spiderMonkeyInterfacesAreStructs
=False,
21902 canRunScript
=False,
21904 CallbackMember
.__init
__(
21908 descriptorProvider
,
21910 rethrowContentException
,
21911 spiderMonkeyInterfacesAreStructs
=spiderMonkeyInterfacesAreStructs
,
21912 canRunScript
=canRunScript
,
21915 def getRvalDecl(self
):
21916 return "JS::Rooted<JS::Value> rval(cx);\n"
21918 def getNoteCallFailed(self
):
21921 aRv.NoteJSContextException(cx);
21922 return${errorReturn};
21924 errorReturn
=self
.getDefaultRetval(),
21928 if self
.argCount
> 0:
21929 args
= "JS::HandleValueArray::subarray(argv, 0, argc)"
21931 args
= "JS::HandleValueArray::empty()"
21937 if (${callGuard}!JS::Call(cx, ${thisVal}, callable,
21942 declCallable
=self
.getCallableDecl(),
21943 declThis
=self
.getThisDecl(),
21944 callGuard
=self
.getCallGuard(),
21945 thisVal
=self
.getThisVal(),
21947 noteError
=self
.getNoteCallFailed(),
21951 class CallCallback(CallbackMethod
):
21952 def __init__(self
, callback
, descriptorProvider
):
21953 self
.callback
= callback
21954 CallbackMethod
.__init
__(
21956 callback
.signatures()[0],
21958 descriptorProvider
,
21959 needThisHandling
=True,
21960 canRunScript
=not callback
.isRunScriptBoundary(),
21963 def getNoteCallFailed(self
):
21964 if self
.retvalType
.isPromise():
21967 // Convert exception to a rejected promise.
21968 // See https://heycam.github.io/webidl/#call-a-user-objects-operation
21969 // step 12 and step 15.5.
21970 return CreateRejectedPromiseFromThrownException(cx, aRv);
21973 return CallbackMethod
.getNoteCallFailed(self
)
21975 def getExceptionCode(self
, forResult
):
21976 # If the result value is a promise, and conversion
21977 # to the promise throws an exception we shouldn't
21978 # try to convert that exception to a promise again.
21979 if self
.retvalType
.isPromise() and not forResult
:
21982 // Convert exception to a rejected promise.
21983 // See https://heycam.github.io/webidl/#call-a-user-objects-operation
21984 // step 10 and step 15.5.
21985 return CreateRejectedPromiseFromThrownException(cx, aRv);
21988 return CallbackMethod
.getExceptionCode(self
, forResult
)
21990 def getThisDecl(self
):
21993 def getThisVal(self
):
21996 def getCallableDecl(self
):
21997 return "JS::Rooted<JS::Value> callable(cx, JS::ObjectValue(*mCallback));\n"
21999 def getPrettyName(self
):
22000 return self
.callback
.identifier
.name
22002 def getCallGuard(self
):
22003 if self
.callback
._treatNonObjectAsNull
:
22004 return "JS::IsCallable(mCallback) && "
22008 class CallbackOperationBase(CallbackMethod
):
22010 Common class for implementing various callback operations.
22020 rethrowContentException
=False,
22021 spiderMonkeyInterfacesAreStructs
=False,
22023 self
.singleOperation
= singleOperation
22024 self
.methodName
= descriptor
.binaryNameFor(jsName
, False)
22025 CallbackMethod
.__init
__(
22031 rethrowContentException
,
22032 spiderMonkeyInterfacesAreStructs
=spiderMonkeyInterfacesAreStructs
,
22035 def getThisDecl(self
):
22036 if not self
.singleOperation
:
22037 return "JS::Rooted<JS::Value> thisValue(cx, JS::ObjectValue(*mCallback));\n"
22038 # This relies on getCallableDecl declaring a boolean
22039 # isCallable in the case when we're a single-operation
22043 JS::Rooted<JS::Value> thisValue(cx, isCallable ? aThisVal.get()
22044 : JS::ObjectValue(*mCallback));
22048 def getThisVal(self
):
22051 def getCallableDecl(self
):
22052 getCallableFromProp
= fill(
22054 ${atomCacheName}* atomsCache = GetAtomCache<${atomCacheName}>(cx);
22055 if ((reinterpret_cast<jsid*>(atomsCache)->isVoid() &&
22056 !InitIds(cx, atomsCache)) ||
22057 !GetCallableProperty(cx, atomsCache->${methodAtomName}, &callable)) {
22058 aRv.Throw(NS_ERROR_UNEXPECTED);
22059 return${errorReturn};
22062 methodAtomName
=CGDictionary
.makeIdName(self
.methodName
),
22063 atomCacheName
=self
.descriptorProvider
.interface
.identifier
.name
+ "Atoms",
22064 errorReturn
=self
.getDefaultRetval(),
22066 if not self
.singleOperation
:
22067 return "JS::Rooted<JS::Value> callable(cx);\n" + getCallableFromProp
22070 bool isCallable = JS::IsCallable(mCallback);
22071 JS::Rooted<JS::Value> callable(cx);
22073 callable = JS::ObjectValue(*mCallback);
22075 $*{getCallableFromProp}
22078 getCallableFromProp
=getCallableFromProp
,
22081 def getCallGuard(self
):
22085 class CallbackOperation(CallbackOperationBase
):
22087 Codegen actual WebIDL operations on callback interfaces.
22090 def __init__(self
, method
, signature
, descriptor
, spiderMonkeyInterfacesAreStructs
):
22091 self
.ensureASCIIName(method
)
22092 self
.method
= method
22093 jsName
= method
.identifier
.name
22094 CallbackOperationBase
.__init
__(
22098 MakeNativeName(descriptor
.binaryNameFor(jsName
, False)),
22100 descriptor
.interface
.isSingleOperationInterface(),
22101 rethrowContentException
=descriptor
.interface
.isJSImplemented(),
22102 spiderMonkeyInterfacesAreStructs
=spiderMonkeyInterfacesAreStructs
,
22105 def getPrettyName(self
):
22107 self
.descriptorProvider
.interface
.identifier
.name
,
22108 self
.method
.identifier
.name
,
22112 class CallbackAccessor(CallbackMember
):
22114 Shared superclass for CallbackGetter and CallbackSetter.
22117 def __init__(self
, attr
, sig
, name
, descriptor
, spiderMonkeyInterfacesAreStructs
):
22118 self
.ensureASCIIName(attr
)
22119 self
.attrName
= attr
.identifier
.name
22120 CallbackMember
.__init
__(
22125 needThisHandling
=False,
22126 rethrowContentException
=descriptor
.interface
.isJSImplemented(),
22127 spiderMonkeyInterfacesAreStructs
=spiderMonkeyInterfacesAreStructs
,
22130 def getPrettyName(self
):
22132 self
.descriptorProvider
.interface
.identifier
.name
,
22137 class CallbackGetter(CallbackAccessor
):
22138 def __init__(self
, attr
, descriptor
, spiderMonkeyInterfacesAreStructs
):
22139 CallbackAccessor
.__init
__(
22143 callbackGetterName(attr
, descriptor
),
22145 spiderMonkeyInterfacesAreStructs
,
22148 def getRvalDecl(self
):
22149 return "JS::Rooted<JS::Value> rval(cx);\n"
22154 JS::Rooted<JSObject *> callback(cx, mCallback);
22155 ${atomCacheName}* atomsCache = GetAtomCache<${atomCacheName}>(cx);
22156 if ((reinterpret_cast<jsid*>(atomsCache)->isVoid()
22157 && !InitIds(cx, atomsCache)) ||
22158 !JS_GetPropertyById(cx, callback, atomsCache->${attrAtomName}, &rval)) {
22159 aRv.Throw(NS_ERROR_UNEXPECTED);
22160 return${errorReturn};
22163 atomCacheName
=self
.descriptorProvider
.interface
.identifier
.name
+ "Atoms",
22164 attrAtomName
=CGDictionary
.makeIdName(
22165 self
.descriptorProvider
.binaryNameFor(self
.attrName
, False)
22167 errorReturn
=self
.getDefaultRetval(),
22171 class CallbackSetter(CallbackAccessor
):
22172 def __init__(self
, attr
, descriptor
, spiderMonkeyInterfacesAreStructs
):
22173 CallbackAccessor
.__init
__(
22177 BuiltinTypes
[IDLBuiltinType
.Types
.undefined
],
22178 [FakeArgument(attr
.type)],
22180 callbackSetterName(attr
, descriptor
),
22182 spiderMonkeyInterfacesAreStructs
,
22185 def getRvalDecl(self
):
22186 # We don't need an rval
22192 MOZ_ASSERT(argv.length() == 1);
22193 JS::Rooted<JSObject*> callback(cx, CallbackKnownNotGray());
22194 ${atomCacheName}* atomsCache = GetAtomCache<${atomCacheName}>(cx);
22195 if ((reinterpret_cast<jsid*>(atomsCache)->isVoid() &&
22196 !InitIds(cx, atomsCache)) ||
22197 !JS_SetPropertyById(cx, callback, atomsCache->${attrAtomName}, argv[0])) {
22198 aRv.Throw(NS_ERROR_UNEXPECTED);
22199 return${errorReturn};
22202 atomCacheName
=self
.descriptorProvider
.interface
.identifier
.name
+ "Atoms",
22203 attrAtomName
=CGDictionary
.makeIdName(
22204 self
.descriptorProvider
.binaryNameFor(self
.attrName
, False)
22206 errorReturn
=self
.getDefaultRetval(),
22209 def getArgcDecl(self
):
22213 class CGJSImplInitOperation(CallbackOperationBase
):
22215 Codegen the __Init() method used to pass along constructor arguments for JS-implemented WebIDL.
22218 def __init__(self
, sig
, descriptor
):
22219 assert sig
in descriptor
.interface
.ctor().signatures()
22220 CallbackOperationBase
.__init
__(
22222 (BuiltinTypes
[IDLBuiltinType
.Types
.undefined
], sig
[1]),
22226 singleOperation
=False,
22227 rethrowContentException
=True,
22228 spiderMonkeyInterfacesAreStructs
=True,
22231 def getPrettyName(self
):
22235 class CGJSImplEventHookOperation(CallbackOperationBase
):
22237 Codegen the hooks on a JS impl for adding/removing event listeners.
22240 def __init__(self
, descriptor
, name
):
22243 CallbackOperationBase
.__init
__(
22246 BuiltinTypes
[IDLBuiltinType
.Types
.undefined
],
22247 [FakeArgument(BuiltinTypes
[IDLBuiltinType
.Types
.domstring
], "aType")],
22250 MakeNativeName(name
),
22252 singleOperation
=False,
22253 rethrowContentException
=False,
22254 spiderMonkeyInterfacesAreStructs
=True,
22257 def getPrettyName(self
):
22261 def getMaplikeOrSetlikeErrorReturn(helperImpl
):
22263 Generate return values based on whether a maplike or setlike generated
22264 method is an interface method (which returns bool) or a helper function
22265 (which uses ErrorResult).
22270 aRv.Throw(NS_ERROR_UNEXPECTED);
22273 % helperImpl
.getDefaultRetval()
22275 return "return false;\n"
22278 def getMaplikeOrSetlikeBackingObject(descriptor
, maplikeOrSetlike
, helperImpl
=None):
22280 Generate code to get/create a JS backing object for a maplike/setlike
22281 declaration from the declaration slot.
22283 func_prefix
= maplikeOrSetlike
.maplikeOrSetlikeOrIterableType
.title()
22286 JS::Rooted<JSObject*> backingObj(cx);
22287 bool created = false;
22288 if (!Get${func_prefix}BackingObject(cx, obj, ${slot}, &backingObj, &created)) {
22292 PreserveWrapper<${selfType}>(self);
22295 slot
=memberReservedSlot(maplikeOrSetlike
, descriptor
),
22296 func_prefix
=func_prefix
,
22297 errorReturn
=getMaplikeOrSetlikeErrorReturn(helperImpl
),
22298 selfType
=descriptor
.nativeType
,
22303 def getMaplikeOrSetlikeSizeGetterBody(descriptor
, attr
):
22305 Creates the body for the size getter method of maplike/setlike interfaces.
22307 # We should only have one declaration attribute currently
22308 assert attr
.identifier
.name
== "size"
22309 assert attr
.isMaplikeOrSetlikeAttr()
22313 uint32_t result = JS::${funcPrefix}Size(cx, backingObj);
22314 MOZ_ASSERT(!JS_IsExceptionPending(cx));
22315 args.rval().setNumber(result);
22318 getBackingObj
=getMaplikeOrSetlikeBackingObject(
22319 descriptor
, attr
.maplikeOrSetlike
22321 funcPrefix
=attr
.maplikeOrSetlike
.prefix
,
22325 class CGMaplikeOrSetlikeMethodGenerator(CGThing
):
22327 Creates methods for maplike/setlike interfaces. It is expected that all
22328 methods will be have a maplike/setlike object attached. Unwrapping/wrapping
22329 will be taken care of by the usual method generation machinery in
22330 CGMethodCall/CGPerSignatureCall. Functionality is filled in here instead of
22331 using CGCallGenerator.
22339 needsValueTypeReturn
=False,
22342 CGThing
.__init
__(self
)
22343 # True if this will be the body of a C++ helper function.
22344 self
.helperImpl
= helperImpl
22345 self
.descriptor
= descriptor
22346 self
.maplikeOrSetlike
= maplikeOrSetlike
22347 self
.cgRoot
= CGList([])
22348 impl_method_name
= methodName
22349 if impl_method_name
[0] == "_":
22350 # double underscore means this is a js-implemented chrome only rw
22351 # function. Truncate the double underscore so calling the right
22352 # underlying JSAPI function still works.
22353 impl_method_name
= impl_method_name
[2:]
22354 self
.cgRoot
.append(
22356 getMaplikeOrSetlikeBackingObject(
22357 self
.descriptor
, self
.maplikeOrSetlike
, self
.helperImpl
22361 self
.returnStmt
= getMaplikeOrSetlikeErrorReturn(self
.helperImpl
)
22363 # Generates required code for the method. Method descriptions included
22364 # in definitions below. Throw if we don't have a method to fill in what
22365 # we're looking for.
22367 methodGenerator
= getattr(self
, impl_method_name
)
22368 except AttributeError:
22370 "Missing %s method definition '%s'"
22371 % (self
.maplikeOrSetlike
.maplikeOrSetlikeType
, methodName
)
22373 # Method generator returns tuple, containing:
22375 # - a list of CGThings representing setup code for preparing to call
22376 # the JS API function
22377 # - a list of arguments needed for the JS API function we're calling
22378 # - list of code CGThings needed for return value conversion.
22379 (setupCode
, arguments
, setResult
) = methodGenerator()
22381 # Create the actual method call, and then wrap it with the code to
22382 # return the value if needed.
22383 funcName
= self
.maplikeOrSetlike
.prefix
+ MakeNativeName(impl_method_name
)
22384 # Append the list of setup code CGThings
22385 self
.cgRoot
.append(CGList(setupCode
))
22386 # Create the JS API call
22389 if (!JS::${funcName}(${args})) {
22395 if needsValueTypeReturn
:
22396 assert self
.helperImpl
and impl_method_name
== "get"
22399 if (result.isUndefined()) {
22400 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
22404 retval
=self
.helperImpl
.getDefaultRetval(),
22407 self
.cgRoot
.append(
22413 args
=", ".join(["cx", "backingObj"] + arguments
),
22414 errorReturn
=self
.returnStmt
,
22419 # Append result conversion
22420 self
.cgRoot
.append(CGList(setResult
))
22422 def mergeTuples(self
, a
, b
):
22424 Expecting to take 2 tuples were all elements are lists, append the lists in
22425 the second tuple to the lists in the first.
22427 return tuple([x
+ y
for x
, y
in zip(a
, b
)])
22429 def appendArgConversion(self
, name
):
22431 Generate code to convert arguments to JS::Values, so they can be
22432 passed into JSAPI functions.
22437 JS::Rooted<JS::Value> ${name}Val(cx);
22438 if (!ToJSValue(cx, ${name}, &${name}Val)) {
22443 errorReturn
=self
.returnStmt
,
22447 def appendKeyArgConversion(self
):
22449 Generates the key argument for methods. Helper functions will use
22450 a RootedVector<JS::Value>, while interface methods have separate JS::Values.
22452 if self
.helperImpl
:
22453 return ([], ["argv[0]"], [])
22454 return ([self
.appendArgConversion("arg0")], ["arg0Val"], [])
22456 def appendKeyAndValueArgConversion(self
):
22458 Generates arguments for methods that require a key and value. Helper
22459 functions will use a RootedVector<JS::Value>, while interface methods have
22460 separate JS::Values.
22462 r
= self
.appendKeyArgConversion()
22463 if self
.helperImpl
:
22464 return self
.mergeTuples(r
, ([], ["argv[1]"], []))
22465 return self
.mergeTuples(
22466 r
, ([self
.appendArgConversion("arg1")], ["arg1Val"], [])
22469 def appendIteratorResult(self
):
22471 Generate code to output JSObject* return values, needed for functions that
22472 return iterators. Iterators cannot currently be wrapped via Xrays. If
22473 something that would return an iterator is called via Xray, fail early.
22475 # TODO: Bug 1173651 - Remove check once bug 1023984 is fixed.
22479 // TODO (Bug 1173651): Xrays currently cannot wrap iterators. Change
22480 // after bug 1023984 is fixed.
22481 if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
22482 JS_ReportErrorASCII(cx, "Xray wrapping of iterators not supported.");
22485 JS::Rooted<JSObject*> result(cx);
22486 JS::Rooted<JS::Value> v(cx);
22491 setResult
= CGGeneric(
22494 result = &v.toObject();
22498 return ([code
], [arguments
], [setResult
])
22500 def appendSelfResult(self
):
22502 Generate code to return the interface object itself.
22507 JS::Rooted<JSObject*> result(cx);
22511 setResult
= CGGeneric(
22518 return ([code
], [], [setResult
])
22520 def appendBoolResult(self
):
22521 if self
.helperImpl
:
22522 return ([CGGeneric("bool retVal;\n")], ["&retVal"], [])
22523 return ([CGGeneric("bool result;\n")], ["&result"], [])
22527 void forEach(callback c, any thisval);
22529 ForEach takes a callback, and a possible value to use as 'this'. The
22530 callback needs to take value, key, and the interface object
22531 implementing maplike/setlike. In order to make sure that the third arg
22532 is our interface object instead of the map/set backing object, we
22533 create a js function with the callback and original object in its
22534 storage slots, then use a helper function in BindingUtils to make sure
22535 the callback is called correctly.
22537 assert not self
.helperImpl
22542 // Create a wrapper function.
22543 JSFunction* func = js::NewFunctionWithReserved(cx, ForEachHandler, 3, 0, nullptr);
22547 JS::Rooted<JSObject*> funcObj(cx, JS_GetFunctionObject(func));
22548 JS::Rooted<JS::Value> funcVal(cx, JS::ObjectValue(*funcObj));
22549 js::SetFunctionNativeReserved(funcObj, FOREACH_CALLBACK_SLOT,
22550 JS::ObjectValue(*arg0));
22551 js::SetFunctionNativeReserved(funcObj, FOREACH_MAPLIKEORSETLIKEOBJ_SLOT,
22552 JS::ObjectValue(*obj));
22557 arguments
= ["funcVal", "arg1"]
22558 return (code
, arguments
, [])
22562 object set(key, value);
22564 Maplike only function, takes key and sets value to it, returns
22565 interface object unless being called from a C++ helper.
22567 assert self
.maplikeOrSetlike
.isMaplike()
22568 r
= self
.appendKeyAndValueArgConversion()
22569 if self
.helperImpl
:
22571 return self
.mergeTuples(r
, self
.appendSelfResult())
22577 Setlike only function, adds value to set, returns interface object
22578 unless being called from a C++ helper
22580 assert self
.maplikeOrSetlike
.isSetlike()
22581 r
= self
.appendKeyArgConversion()
22582 if self
.helperImpl
:
22584 return self
.mergeTuples(r
, self
.appendSelfResult())
22590 Retrieves a value from a backing object based on the key. Returns value
22591 if key is in backing object, undefined otherwise.
22593 assert self
.maplikeOrSetlike
.isMaplike()
22594 r
= self
.appendKeyArgConversion()
22597 # We don't need to create the result variable because it'll be created elsewhere
22598 # for JSObject Get method
22599 if not self
.helperImpl
or not self
.helperImpl
.needsScopeBody():
22604 JS::Rooted<JS::Value> result(cx);
22610 arguments
= ["&result"]
22611 return self
.mergeTuples(r
, (code
, arguments
, []))
22617 Check if an entry exists in the backing object. Returns true if value
22618 exists in backing object, false otherwise.
22620 return self
.mergeTuples(self
.appendKeyArgConversion(), self
.appendBoolResult())
22626 Returns new object iterator with all keys from backing object.
22628 return self
.appendIteratorResult()
22634 Returns new object iterator with all values from backing object.
22636 return self
.appendIteratorResult()
22642 Returns new object iterator with all keys and values from backing
22643 object. Keys will be null for set.
22645 return self
.appendIteratorResult()
22651 Removes all entries from map/set.
22653 return ([], [], [])
22659 Deletes an entry from the backing object. Returns true if value existed
22660 in backing object, false otherwise.
22662 return self
.mergeTuples(self
.appendKeyArgConversion(), self
.appendBoolResult())
22665 return self
.cgRoot
.define()
22668 class CGHelperFunctionGenerator(CallbackMember
):
22670 Generates code to allow C++ to perform operations. Gets a context from the
22671 binding wrapper, turns arguments into JS::Values (via
22672 CallbackMember/CGNativeMember argument conversion), then uses
22673 getCall to generate the body for getting result, and maybe convert the
22674 result into return type (via CallbackMember/CGNativeMember result
22678 class HelperFunction(CGAbstractMethod
):
22680 Generates context retrieval code and rooted JSObject for interface for
22681 method generator to use
22684 def __init__(self
, descriptor
, name
, args
, code
, returnType
):
22686 CGAbstractMethod
.__init
__(self
, descriptor
, name
, returnType
, args
)
22688 def definition_body(self
):
22696 returnType
=BuiltinTypes
[IDLBuiltinType
.Types
.undefined
],
22697 needsResultConversion
=True,
22699 assert returnType
.isType()
22700 self
.needsResultConversion
= needsResultConversion
22702 # Run CallbackMember init function to generate argument conversion code.
22703 # wrapScope is set to 'obj' when generating maplike or setlike helper
22704 # functions, as we don't have access to the CallbackPreserveColor
22706 CallbackMember
.__init
__(
22708 [returnType
, args
],
22713 passJSBitsAsNeeded
=typeNeedsCx(returnType
),
22716 # Wrap CallbackMember body code into a CGAbstractMethod to make
22717 # generation easier.
22718 self
.implMethod
= CGHelperFunctionGenerator
.HelperFunction(
22719 descriptor
, name
, self
.args
, self
.body
, self
.returnType
22722 def getCallSetup(self
):
22723 # If passJSBitsAsNeeded is true, it means the caller will provide a
22724 # JSContext, so we don't need to create JSContext and enter
22725 # UnprivilegedJunkScopeOrWorkerGlobal here.
22726 code
= "MOZ_ASSERT(self);\n"
22727 if not self
.passJSBitsAsNeeded
:
22732 JSContext* cx = jsapi.cx();
22733 // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here because
22734 // all we want is to wrap into _some_ scope and then unwrap to find
22735 // the reflector, and wrapping has no side-effects.
22736 JSObject* scope = UnprivilegedJunkScopeOrWorkerGlobal(fallible);
22738 aRv.Throw(NS_ERROR_UNEXPECTED);
22741 JSAutoRealm tempRealm(cx, scope);
22743 % self
.getDefaultRetval()
22748 JS::Rooted<JS::Value> v(cx);
22749 if(!ToJSValue(cx, self, &v)) {
22750 aRv.Throw(NS_ERROR_UNEXPECTED);
22753 // This is a reflector, but due to trying to name things
22754 // similarly across method generators, it's called obj here.
22755 JS::Rooted<JSObject*> obj(cx);
22756 obj = js::UncheckedUnwrap(&v.toObject(), /* stopAtWindowProxy = */ false);
22758 % self
.getDefaultRetval()
22761 # We'd like wrap the inner code in a scope such that the code can use the
22762 # same realm. So here we are creating the result variable outside of the
22764 if self
.needsScopeBody():
22765 code
+= "JS::Rooted<JS::Value> result(cx);\n"
22769 def getArgs(self
, returnType
, argList
):
22770 # We don't need the context or the value. We'll generate those instead.
22771 args
= CGNativeMember
.getArgs(self
, returnType
, argList
)
22772 # Prepend a pointer to the binding object onto the arguments
22773 return [Argument(self
.descriptorProvider
.nativeType
+ "*", "self")] + args
22775 def needsScopeBody(self
):
22776 return self
.passJSBitsAsNeeded
22778 def getArgvDeclFailureCode(self
):
22779 return "aRv.Throw(NS_ERROR_UNEXPECTED);\n"
22781 def getResultConversion(self
):
22782 if self
.needsResultConversion
:
22784 if self
.needsScopeBody():
22787 if (!JS_WrapValue(cx, &result)) {
22788 aRv.NoteJSContextException(cx);
22794 failureCode
= dedent("aRv.Throw(NS_ERROR_UNEXPECTED);\nreturn nullptr;\n")
22796 exceptionCode
= None
22797 if self
.retvalType
.isPrimitive():
22798 exceptionCode
= dedent(
22799 "aRv.NoteJSContextException(cx);\nreturn%s;\n"
22800 % self
.getDefaultRetval()
22803 return code
+ CallbackMember
.getResultConversion(
22806 failureCode
=failureCode
,
22807 isDefinitelyObject
=True,
22808 exceptionCode
=exceptionCode
,
22811 assignRetval
= string
.Template(
22812 self
.getRetvalInfo(self
.retvalType
, False)[2]
22815 "declName": "retVal",
22818 return assignRetval
22820 def getRvalDecl(self
):
22821 # hack to make sure we put JSAutoRealm inside the body scope
22822 return "JSAutoRealm reflectorRealm(cx, obj);\n"
22824 def getArgcDecl(self
):
22825 # Don't need argc for anything.
22829 assert False # Override me!
22831 def getPrettyName(self
):
22835 return self
.implMethod
.declare()
22838 return self
.implMethod
.define()
22841 class CGMaplikeOrSetlikeHelperFunctionGenerator(CGHelperFunctionGenerator
):
22843 Generates code to allow C++ to perform operations on backing objects. Gets
22844 a context from the binding wrapper, turns arguments into JS::Values (via
22845 CallbackMember/CGNativeMember argument conversion), then uses
22846 CGMaplikeOrSetlikeMethodGenerator to generate the body.
22855 needsValueArg
=False,
22856 needsValueTypeReturn
=False,
22857 needsBoolReturn
=False,
22858 needsResultConversion
=True,
22860 self
.maplikeOrSetlike
= maplikeOrSetlike
22861 self
.needsValueTypeReturn
= needsValueTypeReturn
22865 args
.append(FakeArgument(maplikeOrSetlike
.keyType
, "aKey"))
22868 assert not needsValueTypeReturn
22869 args
.append(FakeArgument(maplikeOrSetlike
.valueType
, "aValue"))
22871 returnType
= BuiltinTypes
[IDLBuiltinType
.Types
.undefined
]
22872 if needsBoolReturn
:
22873 returnType
= BuiltinTypes
[IDLBuiltinType
.Types
.boolean
]
22874 elif needsValueTypeReturn
:
22875 returnType
= maplikeOrSetlike
.valueType
22877 CGHelperFunctionGenerator
.__init
__(
22883 needsResultConversion
,
22887 return CGMaplikeOrSetlikeMethodGenerator(
22888 self
.descriptorProvider
,
22889 self
.maplikeOrSetlike
,
22891 self
.needsValueTypeReturn
,
22896 class CGMaplikeOrSetlikeHelperGenerator(CGNamespace
):
22898 Declares and defines convenience methods for accessing backing objects on
22899 setlike/maplike interface. Generates function signatures, un/packs
22900 backing objects from slot, etc.
22903 def __init__(self
, descriptor
, maplikeOrSetlike
):
22904 self
.descriptor
= descriptor
22905 # Since iterables are folded in with maplike/setlike, make sure we've
22906 # got the right type here.
22907 assert maplikeOrSetlike
.isMaplike() or maplikeOrSetlike
.isSetlike()
22908 self
.maplikeOrSetlike
= maplikeOrSetlike
22909 self
.namespace
= "%sHelpers" % (
22910 self
.maplikeOrSetlike
.maplikeOrSetlikeOrIterableType
.title()
22913 CGMaplikeOrSetlikeHelperFunctionGenerator(
22914 descriptor
, maplikeOrSetlike
, "Clear"
22916 CGMaplikeOrSetlikeHelperFunctionGenerator(
22921 needsBoolReturn
=True,
22922 needsResultConversion
=False,
22924 CGMaplikeOrSetlikeHelperFunctionGenerator(
22929 needsBoolReturn
=True,
22930 needsResultConversion
=False,
22933 if self
.maplikeOrSetlike
.isMaplike():
22934 self
.helpers
.append(
22935 CGMaplikeOrSetlikeHelperFunctionGenerator(
22940 needsValueArg
=True,
22943 self
.helpers
.append(
22944 CGMaplikeOrSetlikeHelperFunctionGenerator(
22949 needsValueTypeReturn
=True,
22953 assert self
.maplikeOrSetlike
.isSetlike()
22954 self
.helpers
.append(
22955 CGMaplikeOrSetlikeHelperFunctionGenerator(
22956 descriptor
, maplikeOrSetlike
, "Add", needsKeyArg
=True
22959 CGNamespace
.__init
__(self
, self
.namespace
, CGList(self
.helpers
))
22962 class CGIterableMethodGenerator(CGGeneric
):
22964 Creates methods for iterable interfaces. Unwrapping/wrapping
22965 will be taken care of by the usual method generation machinery in
22966 CGMethodCall/CGPerSignatureCall. Functionality is filled in here instead of
22967 using CGCallGenerator.
22970 def __init__(self
, descriptor
, methodName
, args
):
22971 if methodName
== "forEach":
22972 assert len(args
) == 2
22974 CGGeneric
.__init
__(
22978 if (!JS::IsCallable(arg0)) {
22979 cx.ThrowErrorMessage<MSG_NOT_CALLABLE>("Argument 1");
22982 JS::RootedValueArray<3> callArgs(cx);
22983 callArgs[2].setObject(*obj);
22984 JS::Rooted<JS::Value> ignoredReturnVal(cx);
22985 auto GetKeyAtIndex = &${selfType}::GetKeyAtIndex;
22986 auto GetValueAtIndex = &${selfType}::GetValueAtIndex;
22987 for (size_t i = 0; i < self->GetIterableLength(); ++i) {
22988 if (!CallIterableGetter(cx, GetValueAtIndex, self, i,
22992 if (!CallIterableGetter(cx, GetKeyAtIndex, self, i,
22996 if (!JS::Call(cx, arg1, arg0, JS::HandleValueArray(callArgs),
22997 &ignoredReturnVal)) {
23002 ifaceName
=descriptor
.interface
.identifier
.name
,
23003 selfType
=descriptor
.nativeType
,
23008 if descriptor
.interface
.isIterable():
23009 assert descriptor
.interface
.maplikeOrSetlikeOrIterable
.isPairIterator()
23010 assert len(args
) == 0
23012 wrap
= f
"{descriptor.interface.identifier.name}Iterator_Binding::Wrap"
23013 iterClass
= f
"mozilla::dom::binding_detail::WrappableIterableIterator<{descriptor.nativeType}, &{wrap}>"
23015 needReturnMethod
= toStringBool(
23016 descriptor
.interface
.maplikeOrSetlikeOrIterable
.getExtendedAttribute(
23017 "GenerateReturnMethod"
23021 wrap
= f
"{descriptor.interface.identifier.name}AsyncIterator_Binding::Wrap"
23022 iterClass
= f
"mozilla::dom::binding_detail::WrappableAsyncIterableIterator<{descriptor.nativeType}, {needReturnMethod}, &{wrap}>"
23024 createIterator
= fill(
23026 typedef ${iterClass} itrType;
23027 RefPtr<itrType> result(new itrType(self,
23028 itrType::IteratorType::${itrMethod}));
23030 iterClass
=iterClass
,
23031 itrMethod
=methodName
.title(),
23034 if descriptor
.interface
.isAsyncIterable():
23035 args
.append("initError")
23036 createIterator
= fill(
23040 ErrorResult initError;
23041 self->InitAsyncIteratorData(result->Data(), itrType::IteratorType::${itrMethod}, ${args});
23042 if (initError.MaybeSetPendingException(cx, "Asynchronous iterator initialization steps for ${ifaceName} failed")) {
23047 createIterator
=createIterator
,
23048 itrMethod
=methodName
.title(),
23049 args
=", ".join(args
),
23050 ifaceName
=descriptor
.interface
.identifier
.name
,
23053 CGGeneric
.__init
__(self
, createIterator
)
23056 def getObservableArrayBackingObject(descriptor
, attr
, errorReturn
="return false;\n"):
23058 Generate code to get/create a JS backing list for an observableArray attribute
23059 from the declaration slot.
23061 assert attr
.isAttr()
23062 assert attr
.type.isObservableArray()
23064 # GetObservableArrayBackingObject may return a wrapped object for Xrays, so
23065 # when we create it we need to unwrap it to store the interface in the
23069 JS::Rooted<JSObject*> backingObj(cx);
23070 bool created = false;
23071 if (!GetObservableArrayBackingObject(cx, obj, ${slot},
23072 &backingObj, &created, ${namespace}::ObservableArrayProxyHandler::getInstance(),
23077 PreserveWrapper(self);
23080 namespace
=toBindingNamespace(MakeNativeName(attr
.identifier
.name
)),
23081 slot
=memberReservedSlot(attr
, descriptor
),
23082 errorReturn
=errorReturn
,
23083 selfType
=descriptor
.nativeType
,
23087 def getObservableArrayGetterBody(descriptor
, attr
):
23089 Creates the body for the getter method of an observableArray attribute.
23091 assert attr
.type.isObservableArray()
23095 MOZ_ASSERT(!JS_IsExceptionPending(cx));
23096 args.rval().setObject(*backingObj);
23099 getBackingObj
=getObservableArrayBackingObject(descriptor
, attr
),
23103 class CGObservableArrayProxyHandler_callback(ClassMethod
):
23105 Base class for declaring and defining the hook methods for ObservableArrayProxyHandler
23106 subclasses to get the interface native object from backing object and calls
23107 its On{Set|Delete}* callback.
23109 * 'callbackType': "Set" or "Delete".
23110 * 'invalidTypeFatal' (optional): If True, we don't expect the type
23111 conversion would fail, so generate the
23112 assertion code if type conversion fails.
23116 self
, descriptor
, attr
, name
, args
, callbackType
, invalidTypeFatal
=False
23118 assert attr
.isAttr()
23119 assert attr
.type.isObservableArray()
23120 assert callbackType
in ["Set", "Delete"]
23121 self
.descriptor
= descriptor
23123 self
.innertype
= attr
.type.inner
23124 self
.callbackType
= callbackType
23125 self
.invalidTypeFatal
= invalidTypeFatal
23126 ClassMethod
.__init
__(
23131 visibility
="protected",
23137 def preConversion(self
):
23139 The code to run before the conversion steps.
23143 def preCallback(self
):
23145 The code to run before calling the callback.
23149 def postCallback(self
):
23151 The code to run after calling the callback, all subclasses should override
23152 this to generate the return values.
23154 assert False # Override me!
23160 MOZ_ASSERT_UNREACHABLE("The item in ObservableArray backing list is not ${innertype}?");
23163 innertype
=self
.innertype
,
23165 if self
.invalidTypeFatal
23168 convertType
= instantiateJSToNativeConversion(
23169 getJSToNativeConversionInfo(
23172 sourceDescription
="Element in ObservableArray backing list",
23173 exceptionCode
=exceptionCode
,
23176 "declName": "decl",
23177 "holderName": "holder",
23181 callbackArgs
= ["decl", "aIndex", "rv"]
23182 if typeNeedsCx(self
.innertype
):
23183 callbackArgs
.insert(0, "cx")
23186 MOZ_ASSERT(IsObservableArrayProxy(aProxy));
23189 BindingCallContext cx(aCx, "ObservableArray ${name}");
23193 JS::Value val = js::GetProxyReservedSlot(aProxy, OBSERVABLE_ARRAY_DOM_INTERFACE_SLOT);
23194 auto* interface = static_cast<${ifaceType}*>(val.toPrivate());
23195 MOZ_ASSERT(interface);
23198 MOZ_KnownLive(interface)->${methodName}(${callbackArgs});
23201 preConversion
=self
.preConversion(),
23203 convertType
=convertType
.define(),
23204 preCallback
=self
.preCallback(),
23205 ifaceType
=self
.descriptor
.nativeType
,
23206 methodName
="On%s%s"
23207 % (self
.callbackType
, MakeNativeName(self
.attr
.identifier
.name
)),
23208 callbackArgs
=", ".join(callbackArgs
),
23209 postCallback
=self
.postCallback(),
23213 class CGObservableArrayProxyHandler_OnDeleteItem(
23214 CGObservableArrayProxyHandler_callback
23217 Declares and defines the hook methods for ObservableArrayProxyHandler
23218 subclasses to get the interface native object from backing object and calls
23219 its OnDelete* callback.
23222 def __init__(self
, descriptor
, attr
):
23224 Argument("JSContext*", "aCx"),
23225 Argument("JS::Handle<JSObject*>", "aProxy"),
23226 Argument("JS::Handle<JS::Value>", "aValue"),
23227 Argument("uint32_t", "aIndex"),
23229 CGObservableArrayProxyHandler_callback
.__init
__(
23239 def postCallback(self
):
23242 return !rv.MaybeSetPendingException(cx);
23247 class CGObservableArrayProxyHandler_SetIndexedValue(
23248 CGObservableArrayProxyHandler_callback
23251 Declares and defines the hook methods for ObservableArrayProxyHandler
23252 subclasses to run the setting the indexed value steps.
23255 def __init__(self
, descriptor
, attr
):
23257 Argument("JSContext*", "aCx"),
23258 Argument("JS::Handle<JSObject*>", "aProxy"),
23259 Argument("JS::Handle<JSObject*>", "aBackingList"),
23260 Argument("uint32_t", "aIndex"),
23261 Argument("JS::Handle<JS::Value>", "aValue"),
23262 Argument("JS::ObjectOpResult&", "aResult"),
23264 CGObservableArrayProxyHandler_callback
.__init
__(
23273 def preConversion(self
):
23277 if (!JS::GetArrayLength(aCx, aBackingList, &oldLen)) {
23281 if (aIndex > oldLen) {
23282 return aResult.failBadIndex();
23287 def preCallback(self
):
23290 if (aIndex < oldLen) {
23291 JS::Rooted<JS::Value> value(aCx);
23292 if (!JS_GetElement(aCx, aBackingList, aIndex, &value)) {
23296 if (!OnDeleteItem(aCx, aProxy, value, aIndex)) {
23304 def postCallback(self
):
23307 if (rv.MaybeSetPendingException(cx)) {
23311 if (!JS_SetElement(aCx, aBackingList, aIndex, aValue)) {
23315 return aResult.succeed();
23320 class CGObservableArrayProxyHandler(CGThing
):
23322 A class for declaring a ObservableArrayProxyHandler.
23325 def __init__(self
, descriptor
, attr
):
23326 assert attr
.isAttr()
23327 assert attr
.type.isObservableArray()
23329 # The item stored in backing object should always be converted successfully.
23330 CGObservableArrayProxyHandler_OnDeleteItem(descriptor
, attr
),
23331 CGObservableArrayProxyHandler_SetIndexedValue(descriptor
, attr
),
23332 CGJSProxyHandler_getInstance("ObservableArrayProxyHandler"),
23334 parentClass
= "mozilla::dom::ObservableArrayProxyHandler"
23335 self
.proxyHandler
= CGClass(
23336 "ObservableArrayProxyHandler",
23337 bases
=[ClassBase(parentClass
)],
23343 # Our class declaration should happen when we're defining
23347 return self
.proxyHandler
.declare() + "\n" + self
.proxyHandler
.define()
23350 class CGObservableArrayProxyHandlerGenerator(CGNamespace
):
23352 Declares and defines convenience methods for accessing backing list objects
23353 for observable array attribute. Generates function signatures, un/packs
23354 backing list objects from slot, etc.
23357 def __init__(self
, descriptor
, attr
):
23358 assert attr
.isAttr()
23359 assert attr
.type.isObservableArray()
23360 namespace
= toBindingNamespace(MakeNativeName(attr
.identifier
.name
))
23361 proxyHandler
= CGObservableArrayProxyHandler(descriptor
, attr
)
23362 CGNamespace
.__init
__(self
, namespace
, proxyHandler
)
23365 class CGObservableArraySetterGenerator(CGGeneric
):
23367 Creates setter for an observableArray attributes.
23370 def __init__(self
, descriptor
, attr
):
23371 assert attr
.isAttr()
23372 assert attr
.type.isObservableArray()
23373 getBackingObject
= getObservableArrayBackingObject(descriptor
, attr
)
23374 setElement
= dedent(
23376 if (!JS_SetElement(cx, backingObj, i, val)) {
23381 conversion
= wrapForType(
23385 "result": "arg0.ElementAt(i)",
23386 "successCode": setElement
,
23388 "jsvalHandle": "&val",
23391 CGGeneric
.__init
__(
23395 if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
23396 JS_ReportErrorASCII(cx, "Accessing from Xray wrapper is not supported.");
23400 ${getBackingObject}
23401 const ObservableArrayProxyHandler* handler = GetObservableArrayProxyHandler(backingObj);
23402 if (!handler->SetLength(cx, backingObj, 0)) {
23406 JS::Rooted<JS::Value> val(cx);
23407 for (size_t i = 0; i < arg0.Length(); i++) {
23411 conversion
=conversion
,
23412 getBackingObject
=getBackingObject
,
23417 class CGObservableArrayHelperFunctionGenerator(CGHelperFunctionGenerator
):
23419 Generates code to allow C++ to perform operations on backing objects. Gets
23420 a context from the binding wrapper, turns arguments into JS::Values (via
23421 CallbackMember/CGNativeMember argument conversion), then uses
23422 MethodBodyGenerator to generate the body.
23425 class MethodBodyGenerator(CGThing
):
23427 Creates methods body for observable array attribute. It is expected that all
23428 methods will be have a maplike/setlike object attached. Unwrapping/wrapping
23429 will be taken care of by the usual method generation machinery in
23430 CGMethodCall/CGPerSignatureCall. Functionality is filled in here instead of
23431 using CGCallGenerator.
23442 assert attr
.isAttr()
23443 assert attr
.type.isObservableArray()
23445 CGThing
.__init
__(self
)
23446 self
.helperGenerator
= helperGenerator
23447 self
.cgRoot
= CGList([])
23449 self
.cgRoot
.append(
23451 getObservableArrayBackingObject(
23456 aRv.Throw(NS_ERROR_UNEXPECTED);
23459 % helperGenerator
.getDefaultRetval()
23465 # Generates required code for the method. Method descriptions included
23466 # in definitions below. Throw if we don't have a method to fill in what
23467 # we're looking for.
23469 methodGenerator
= getattr(self
, methodName
)
23470 except AttributeError:
23472 "Missing observable array method definition '%s'" % methodName
23474 # Method generator returns tuple, containing:
23476 # - a list of CGThings representing setup code for preparing to call
23477 # the JS API function
23478 # - JS API function name
23479 # - a list of arguments needed for the JS API function we're calling
23480 # - a list of CGThings representing code needed before return.
23481 (setupCode
, funcName
, arguments
, returnCode
) = methodGenerator()
23483 # Append the list of setup code CGThings
23484 self
.cgRoot
.append(CGList(setupCode
))
23485 # Create the JS API call
23487 arguments
.insert(0, "aIndex")
23488 self
.cgRoot
.append(
23493 aRv.MightThrowJSException();
23494 if (!${funcName}(${args})) {
23495 aRv.StealExceptionFromJSContext(cx);
23500 args
=", ".join(["cx", "backingObj"] + arguments
),
23501 retval
=helperGenerator
.getDefaultRetval(),
23506 # Append code before return
23507 self
.cgRoot
.append(CGList(returnCode
))
23509 def elementat(self
):
23511 if not self
.helperGenerator
.needsScopeBody():
23512 setupCode
.append(CGGeneric("JS::Rooted<JS::Value> result(cx);\n"))
23517 if (result.isUndefined()) {
23518 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
23522 retval
=self
.helperGenerator
.getDefaultRetval(),
23526 return (setupCode
, "JS_GetElement", ["&result"], returnCode
)
23528 def replaceelementat(self
):
23534 aRv.MightThrowJSException();
23535 if (!JS::GetArrayLength(cx, backingObj, &length)) {
23536 aRv.StealExceptionFromJSContext(cx);
23539 if (aIndex > length) {
23540 aRv.ThrowRangeError("Invalid index");
23544 retval
=self
.helperGenerator
.getDefaultRetval(),
23548 return (setupCode
, "JS_SetElement", ["argv[0]"], [])
23550 def appendelement(self
):
23556 aRv.MightThrowJSException();
23557 if (!JS::GetArrayLength(cx, backingObj, &length)) {
23558 aRv.StealExceptionFromJSContext(cx);
23562 retval
=self
.helperGenerator
.getDefaultRetval(),
23566 return (setupCode
, "JS_SetElement", ["length", "argv[0]"], [])
23568 def removelastelement(self
):
23574 aRv.MightThrowJSException();
23575 if (!JS::GetArrayLength(cx, backingObj, &length)) {
23576 aRv.StealExceptionFromJSContext(cx);
23580 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
23584 retval
=self
.helperGenerator
.getDefaultRetval(),
23588 return (setupCode
, "JS::SetArrayLength", ["length - 1"], [])
23592 [CGGeneric("uint32_t retVal;\n")],
23593 "JS::GetArrayLength",
23599 return self
.cgRoot
.define()
23606 returnType
=BuiltinTypes
[IDLBuiltinType
.Types
.undefined
],
23607 needsResultConversion
=True,
23608 needsIndexArg
=False,
23609 needsValueArg
=False,
23611 assert attr
.isAttr()
23612 assert attr
.type.isObservableArray()
23614 self
.needsIndexArg
= needsIndexArg
23618 args
.append(FakeArgument(attr
.type.inner
, "aValue"))
23620 CGHelperFunctionGenerator
.__init
__(
23626 needsResultConversion
,
23629 def getArgs(self
, returnType
, argList
):
23630 if self
.needsIndexArg
:
23632 FakeArgument(BuiltinTypes
[IDLBuiltinType
.Types
.unsigned_long
], "aIndex")
23634 return CGHelperFunctionGenerator
.getArgs(self
, returnType
, argList
)
23637 return CGObservableArrayHelperFunctionGenerator
.MethodBodyGenerator(
23638 self
.descriptorProvider
,
23642 self
.needsIndexArg
,
23646 class CGObservableArrayHelperGenerator(CGNamespace
):
23648 Declares and defines convenience methods for accessing backing object for
23649 observable array type. Generates function signatures, un/packs
23650 backing objects from slot, etc.
23653 def __init__(self
, descriptor
, attr
):
23654 assert attr
.isAttr()
23655 assert attr
.type.isObservableArray()
23657 namespace
= "%sHelpers" % MakeNativeName(attr
.identifier
.name
)
23659 CGObservableArrayHelperFunctionGenerator(
23663 returnType
=attr
.type.inner
,
23664 needsIndexArg
=True,
23666 CGObservableArrayHelperFunctionGenerator(
23669 "ReplaceElementAt",
23670 needsIndexArg
=True,
23671 needsValueArg
=True,
23673 CGObservableArrayHelperFunctionGenerator(
23677 needsValueArg
=True,
23679 CGObservableArrayHelperFunctionGenerator(
23682 "RemoveLastElement",
23684 CGObservableArrayHelperFunctionGenerator(
23688 returnType
=BuiltinTypes
[IDLBuiltinType
.Types
.unsigned_long
],
23689 needsResultConversion
=False,
23692 CGNamespace
.__init
__(self
, namespace
, CGList(helpers
, "\n"))
23695 class GlobalGenRoots
:
23697 Roots for global codegen.
23699 To generate code, call the method associated with the target, and then
23700 call the appropriate define/declare method.
23704 def GeneratedAtomList(config
):
23706 dictionaries
= config
.dictionaries
23710 def memberToAtomCacheMember(binaryNameFor
, m
):
23711 binaryMemberName
= binaryNameFor(m
)
23712 return ClassMember(
23713 CGDictionary
.makeIdName(binaryMemberName
),
23715 visibility
="public",
23718 def buildAtomCacheStructure(idlobj
, binaryNameFor
, members
):
23719 classMembers
= [memberToAtomCacheMember(binaryNameFor
, m
) for m
in members
]
23720 structName
= idlobj
.identifier
.name
+ "Atoms"
23725 structName
, bases
=None, isStruct
=True, members
=classMembers
23731 for dict in dictionaries
:
23732 if len(dict.members
) == 0:
23736 buildAtomCacheStructure(dict, lambda m
: m
.identifier
.name
, dict.members
)
23739 for d
in config
.getDescriptors(isJSImplemented
=True) + config
.getDescriptors(
23742 members
= [m
for m
in d
.interface
.members
if m
.isAttr() or m
.isMethod()]
23743 if d
.interface
.isJSImplemented() and d
.interface
.ctor():
23744 # We'll have an __init() method.
23745 members
.append(FakeMember("__init"))
23746 if d
.interface
.isJSImplemented() and d
.interface
.getExtendedAttribute(
23747 "WantsEventListenerHooks"
23749 members
.append(FakeMember("eventListenerAdded"))
23750 members
.append(FakeMember("eventListenerRemoved"))
23751 if len(members
) == 0:
23755 buildAtomCacheStructure(
23757 lambda m
: d
.binaryNameFor(m
.identifier
.name
, m
.isStatic()),
23763 generatedStructs
= [struct
for structName
, struct
in structs
]
23764 structNames
= [structName
for structName
, struct
in structs
]
23766 mainStruct
= CGWrapper(
23768 "PerThreadAtomCache",
23769 bases
=[ClassBase(structName
) for structName
in structNames
],
23775 structs
= CGList(generatedStructs
+ [mainStruct
])
23777 # Wrap all of that in our namespaces.
23778 curr
= CGNamespace
.build(["mozilla", "dom"], CGWrapper(structs
, pre
="\n"))
23779 curr
= CGWrapper(curr
, post
="\n")
23781 # Add include statement for PinnedStringId.
23782 declareIncludes
= ["mozilla/dom/PinnedStringId.h"]
23783 curr
= CGHeaders([], [], [], [], declareIncludes
, [], "GeneratedAtomList", curr
)
23785 # Add include guards.
23786 curr
= CGIncludeGuard("GeneratedAtomList", curr
)
23788 # Add the auto-generated comment.
23789 curr
= CGWrapper(curr
, pre
=AUTOGENERATED_WARNING_COMMENT
)
23795 def GeneratedEventList(config
):
23796 eventList
= CGList([])
23797 for generatedEvent
in config
.generatedEvents
:
23799 CGGeneric(declare
=("GENERATED_EVENT(%s)\n" % generatedEvent
))
23804 def PrototypeList(config
):
23805 # Prototype ID enum.
23806 descriptorsWithPrototype
= config
.getDescriptors(
23807 hasInterfacePrototypeObject
=True
23809 descriptorsWithPrototype
.extend(
23810 config
.getDescriptors(hasOrdinaryObjectPrototype
=True)
23812 descriptorsWithPrototype
.sort(key
=attrgetter("name"))
23813 protos
= [d
.name
for d
in descriptorsWithPrototype
]
23814 idEnum
= CGNamespacedEnum("id", "ID", ["_ID_Start"] + protos
, [0, "_ID_Start"])
23815 idEnum
= CGList([idEnum
])
23817 def fieldSizeAssert(amount
, jitInfoField
, message
):
23819 "(uint64_t(1) << (sizeof(std::declval<JSJitInfo>().%s) * 8))"
23823 define
='static_assert(%s < %s, "%s");\n\n'
23824 % (amount
, maxFieldValue
, message
)
23828 fieldSizeAssert("id::_ID_Count", "protoID", "Too many prototypes!")
23831 # Wrap all of that in our namespaces.
23832 idEnum
= CGNamespace
.build(
23833 ["mozilla", "dom", "prototypes"], CGWrapper(idEnum
, pre
="\n")
23835 idEnum
= CGWrapper(idEnum
, post
="\n")
23839 CGGeneric(define
="#include <stdint.h>\n"),
23840 CGGeneric(define
="#include <type_traits>\n\n"),
23841 CGGeneric(define
='#include "js/experimental/JitInfo.h"\n\n'),
23842 CGGeneric(define
='#include "mozilla/dom/BindingNames.h"\n\n'),
23843 CGGeneric(define
='#include "mozilla/dom/PrototypeList.h"\n\n'),
23848 # Let things know the maximum length of the prototype chain.
23849 maxMacroName
= "MAX_PROTOTYPE_CHAIN_LENGTH"
23850 maxMacro
= CGGeneric(
23851 declare
="#define " + maxMacroName
+ " " + str(config
.maxProtoChainLength
)
23853 curr
.append(CGWrapper(maxMacro
, post
="\n\n"))
23856 maxMacroName
, "depth", "Some inheritance chain is too long!"
23860 # Constructor ID enum.
23861 constructors
= [d
.name
for d
in config
.getDescriptors(hasInterfaceObject
=True)]
23862 idEnum
= CGNamespacedEnum(
23865 ["_ID_Start"] + constructors
,
23866 ["prototypes::id::_ID_Count", "_ID_Start"],
23869 # Wrap all of that in our namespaces.
23870 idEnum
= CGNamespace
.build(
23871 ["mozilla", "dom", "constructors"], CGWrapper(idEnum
, pre
="\n")
23873 idEnum
= CGWrapper(idEnum
, post
="\n")
23875 curr
.append(idEnum
)
23877 # Named properties object enum.
23878 namedPropertiesObjects
= [
23879 d
.name
for d
in config
.getDescriptors(hasNamedPropertiesObject
=True)
23881 idEnum
= CGNamespacedEnum(
23884 ["_ID_Start"] + namedPropertiesObjects
,
23885 ["constructors::id::_ID_Count", "_ID_Start"],
23888 # Wrap all of that in our namespaces.
23889 idEnum
= CGNamespace
.build(
23890 ["mozilla", "dom", "namedpropertiesobjects"], CGWrapper(idEnum
, pre
="\n")
23892 idEnum
= CGWrapper(idEnum
, post
="\n")
23894 curr
.append(idEnum
)
23900 template <prototypes::ID PrototypeID>
23901 struct PrototypeTraits;
23906 traitsDecls
.extend(CGPrototypeTraitsClass(d
) for d
in descriptorsWithPrototype
)
23908 ifaceNamesWithProto
= [
23909 d
.interface
.getClassName() for d
in descriptorsWithPrototype
23911 traitsDecls
.append(
23912 CGStringTable("NamesOfInterfacesWithProtos", ifaceNamesWithProto
)
23915 traitsDecl
= CGNamespace
.build(["mozilla", "dom"], CGList(traitsDecls
))
23917 curr
.append(traitsDecl
)
23919 # Add include guards.
23920 curr
= CGIncludeGuard("PrototypeList", curr
)
23922 # Add the auto-generated comment.
23923 curr
= CGWrapper(curr
, pre
=AUTOGENERATED_WARNING_COMMENT
)
23929 def BindingNames(config
):
23932 enum class BindingNamesOffset : uint16_t {
23936 namespace binding_detail {
23937 extern const char sBindingNames[];
23938 } // namespace binding_detail
23940 MOZ_ALWAYS_INLINE const char* BindingName(BindingNamesOffset aOffset) {
23941 return binding_detail::sBindingNames + static_cast<size_t>(aOffset);
23944 enumValues
="".join(
23945 "%s = %i,\n" % (BindingNamesOffsetEnum(n
), o
)
23946 for (n
, o
) in config
.namesStringOffsets
23951 namespace binding_detail {
23953 const char sBindingNames[] = {
23957 } // namespace binding_detail
23959 // Making this enum bigger than a uint16_t has consequences on the size
23960 // of some structs (eg. WebIDLNameTableEntry) and tables. We should try
23962 static_assert(EnumTypeFitsWithin<BindingNamesOffset, uint16_t>::value,
23965 namesString
=' "\\0"\n'.join(
23966 '/* %5i */ "%s"' % (o
, n
) for (n
, o
) in config
.namesStringOffsets
23971 curr
= CGGeneric(declare
=declare
, define
=define
)
23972 curr
= CGWrapper(curr
, pre
="\n", post
="\n")
23974 curr
= CGNamespace
.build(["mozilla", "dom"], curr
)
23975 curr
= CGWrapper(curr
, post
="\n")
23982 ["<stddef.h>", "<stdint.h>", "mozilla/Attributes.h"],
23983 ["mozilla/dom/BindingNames.h", "mozilla/EnumTypeTraits.h"],
23988 # Add include guards.
23989 curr
= CGIncludeGuard("BindingNames", curr
)
23995 def RegisterBindings(config
):
23996 curr
= CGNamespace
.build(
23997 ["mozilla", "dom"], CGGlobalNames(config
.windowGlobalNames
)
23999 curr
= CGWrapper(curr
, post
="\n")
24003 CGHeaders
.getDeclarationFilename(desc
.interface
)
24004 for desc
in config
.getDescriptors(
24005 hasInterfaceObject
=True, isExposedInWindow
=True, register
=True
24008 defineIncludes
.append("mozilla/dom/BindingNames.h")
24009 defineIncludes
.append("mozilla/dom/WebIDLGlobalNameHash.h")
24010 defineIncludes
.append("mozilla/dom/PrototypeList.h")
24011 defineIncludes
.append("mozilla/PerfectHash.h")
24012 defineIncludes
.append("js/String.h")
24013 curr
= CGHeaders([], [], [], [], [], defineIncludes
, "RegisterBindings", curr
)
24015 # Add include guards.
24016 curr
= CGIncludeGuard("RegisterBindings", curr
)
24022 def RegisterWorkerBindings(config
):
24023 curr
= CGRegisterWorkerBindings(config
)
24025 # Wrap all of that in our namespaces.
24026 curr
= CGNamespace
.build(["mozilla", "dom"], CGWrapper(curr
, post
="\n"))
24027 curr
= CGWrapper(curr
, post
="\n")
24031 CGHeaders
.getDeclarationFilename(desc
.interface
)
24032 for desc
in config
.getDescriptors(
24033 hasInterfaceObject
=True, register
=True, isExposedInAnyWorker
=True
24038 [], [], [], [], [], defineIncludes
, "RegisterWorkerBindings", curr
24041 # Add include guards.
24042 curr
= CGIncludeGuard("RegisterWorkerBindings", curr
)
24048 def RegisterWorkerDebuggerBindings(config
):
24049 curr
= CGRegisterWorkerDebuggerBindings(config
)
24051 # Wrap all of that in our namespaces.
24052 curr
= CGNamespace
.build(["mozilla", "dom"], CGWrapper(curr
, post
="\n"))
24053 curr
= CGWrapper(curr
, post
="\n")
24057 CGHeaders
.getDeclarationFilename(desc
.interface
)
24058 for desc
in config
.getDescriptors(
24059 hasInterfaceObject
=True, register
=True, isExposedInWorkerDebugger
=True
24064 [], [], [], [], [], defineIncludes
, "RegisterWorkerDebuggerBindings", curr
24067 # Add include guards.
24068 curr
= CGIncludeGuard("RegisterWorkerDebuggerBindings", curr
)
24074 def RegisterWorkletBindings(config
):
24075 curr
= CGRegisterWorkletBindings(config
)
24077 # Wrap all of that in our namespaces.
24078 curr
= CGNamespace
.build(["mozilla", "dom"], CGWrapper(curr
, post
="\n"))
24079 curr
= CGWrapper(curr
, post
="\n")
24083 CGHeaders
.getDeclarationFilename(desc
.interface
)
24084 for desc
in config
.getDescriptors(
24085 hasInterfaceObject
=True, register
=True, isExposedInAnyWorklet
=True
24090 [], [], [], [], [], defineIncludes
, "RegisterWorkletBindings", curr
24093 # Add include guards.
24094 curr
= CGIncludeGuard("RegisterWorkletBindings", curr
)
24100 def RegisterShadowRealmBindings(config
):
24101 curr
= CGRegisterShadowRealmBindings(config
)
24103 # Wrap all of that in our namespaces.
24104 curr
= CGNamespace
.build(["mozilla", "dom"], CGWrapper(curr
, post
="\n"))
24105 curr
= CGWrapper(curr
, post
="\n")
24109 CGHeaders
.getDeclarationFilename(desc
.interface
)
24110 for desc
in config
.getDescriptors(
24111 hasInterfaceObject
=True, register
=True, isExposedInShadowRealms
=True
24116 [], [], [], [], [], defineIncludes
, "RegisterShadowRealmBindings", curr
24119 # Add include guards.
24120 curr
= CGIncludeGuard("RegisterShadowRealmBindings", curr
)
24126 def UnionTypes(config
):
24127 unionTypes
= UnionsForFile(config
, None)
24135 ) = UnionTypes(unionTypes
, config
)
24137 unionStructs
= dependencySortDictionariesAndUnionsAndCallbacks(unionStructs
)
24142 + [CGUnionStruct(t
, config
) for t
in unionStructs
]
24143 + [CGUnionStruct(t
, config
, True) for t
in unionStructs
],
24147 includes
.add("mozilla/OwningNonNull.h")
24148 includes
.add("mozilla/dom/UnionMember.h")
24149 includes
.add("mozilla/dom/BindingDeclarations.h")
24150 # BindingUtils.h is only needed for SetToObject.
24151 # If it stops being inlined or stops calling CallerSubsumes
24152 # both this bit and the bit in CGBindingRoot can be removed.
24153 includes
.add("mozilla/dom/BindingUtils.h")
24155 # Wrap all of that in our namespaces.
24156 curr
= CGNamespace
.build(["mozilla", "dom"], unions
)
24158 curr
= CGWrapper(curr
, post
="\n")
24160 builder
= ForwardDeclarationBuilder()
24161 for className
, isStruct
in declarations
:
24162 builder
.add(className
, isStruct
=isStruct
)
24164 curr
= CGList([builder
.build(), curr
], "\n")
24166 curr
= CGHeaders([], [], [], [], includes
, implincludes
, "UnionTypes", curr
)
24168 # Add include guards.
24169 curr
= CGIncludeGuard("UnionTypes", curr
)
24175 def WebIDLPrefs(config
):
24177 headers
= set(["mozilla/dom/WebIDLPrefs.h"])
24178 for d
in config
.getDescriptors(hasInterfaceOrInterfacePrototypeObject
=True):
24179 for m
in d
.interface
.members
:
24180 pref
= PropertyDefiner
.getStringAttr(m
, "Pref")
24182 headers
.add(prefHeader(pref
))
24183 prefs
.add((pref
, prefIdentifier(pref
)))
24184 prefs
= sorted(prefs
)
24187 enum class WebIDLPrefIndex : uint8_t {
24191 typedef bool (*WebIDLPrefFunc)();
24192 extern const WebIDLPrefFunc sWebIDLPrefs[${len}];
24194 prefs
=",\n".join(map(lambda p
: "// " + p
[0] + "\n" + p
[1], prefs
)) + "\n",
24195 len=len(prefs
) + 1,
24199 const WebIDLPrefFunc sWebIDLPrefs[] = {
24205 map(lambda p
: "// " + p
[0] + "\nStaticPrefs::" + p
[1], prefs
)
24209 prefFunctions
= CGGeneric(declare
=declare
, define
=define
)
24211 # Wrap all of that in our namespaces.
24212 curr
= CGNamespace
.build(["mozilla", "dom"], prefFunctions
)
24214 curr
= CGWrapper(curr
, post
="\n")
24216 curr
= CGHeaders([], [], [], [], [], headers
, "WebIDLPrefs", curr
)
24218 # Add include guards.
24219 curr
= CGIncludeGuard("WebIDLPrefs", curr
)
24225 def WebIDLSerializable(config
):
24226 # We need a declaration of StructuredCloneTags in the header.
24227 declareIncludes
= set(
24229 "mozilla/dom/DOMJSClass.h",
24230 "mozilla/dom/StructuredCloneTags.h",
24234 defineIncludes
= set(
24235 ["mozilla/dom/WebIDLSerializable.h", "mozilla/PerfectHash.h"]
24238 for d
in config
.getDescriptors(isSerializable
=True):
24239 names
.append(d
.name
)
24240 defineIncludes
.add(CGHeaders
.getDeclarationFilename(d
.interface
))
24242 if len(names
) == 0:
24243 # We can't really create a PerfectHash out of this, but also there's
24244 # not much point to this file if we have no [Serializable] objects.
24245 # Just spit out an empty file.
24246 return CGIncludeGuard("WebIDLSerializable", CGGeneric(""))
24248 # If we had a lot of serializable things, it might be worth it to use a
24249 # PerfectHash here, or an array ordered by sctag value and binary
24250 # search. But setting those up would require knowing in this python
24251 # code the values of the various SCTAG_DOM_*. We could hardcode them
24252 # here and add static asserts that the values are right, or switch to
24253 # code-generating StructuredCloneTags.h or something. But in practice,
24254 # there's a pretty small number of serializable interfaces, and just
24255 # doing a linear walk is fine. It's not obviously worse than the
24256 # if-cascade we used to have. Let's just make sure we notice if we do
24257 # end up with a lot of serializable things here.
24259 # Also, in practice it looks like compilers compile this linear walk to
24260 # an out-of-bounds check followed by a direct index into an array, by
24261 # basically making a second copy of this array ordered by tag, with the
24262 # holes filled in. Again, worth checking whether this still happens if
24263 # we have too many serializable things.
24264 if len(names
) > 20:
24266 "We now have %s serializable interfaces. "
24267 "Double-check that the compiler is still "
24268 "generating a jump table." % len(names
)
24272 # Make sure we have stable ordering.
24273 for name
in sorted(names
):
24274 exposedGlobals
= computeGlobalNamesFromExposureSet(d
.interface
.exposureSet
)
24275 # Strip off trailing newline to make our formatting look right.
24281 /* mDeserialize */ ${name}_Binding::Deserialize,
24282 /* mExposedGlobals */ ${exposedGlobals},
24285 tag
=StructuredCloneTag(name
),
24287 exposedGlobals
=exposedGlobals
,
24293 Maybe<std::pair<uint16_t, WebIDLDeserializer>> LookupDeserializer(StructuredCloneTags aTag);
24298 struct WebIDLSerializableEntry {
24299 StructuredCloneTags mTag;
24300 WebIDLDeserializer mDeserialize;
24301 uint16_t mExposedGlobals;
24304 static const WebIDLSerializableEntry sEntries[] = {
24308 Maybe<std::pair<uint16_t, WebIDLDeserializer>> LookupDeserializer(StructuredCloneTags aTag) {
24309 for (auto& entry : sEntries) {
24310 if (entry.mTag == aTag) {
24311 return Some(std::pair(entry.mExposedGlobals, entry.mDeserialize));
24317 entries
=",\n".join(entries
) + "\n",
24320 code
= CGGeneric(declare
=declare
, define
=define
)
24322 # Wrap all of that in our namespaces.
24323 curr
= CGNamespace
.build(["mozilla", "dom"], code
)
24325 curr
= CGWrapper(curr
, post
="\n")
24328 [], [], [], [], declareIncludes
, defineIncludes
, "WebIDLSerializable", curr
24331 # Add include guards.
24332 curr
= CGIncludeGuard("WebIDLSerializable", curr
)
24338 # Code generator for simple events
24339 class CGEventGetter(CGNativeMember
):
24340 def __init__(self
, descriptor
, attr
):
24341 ea
= descriptor
.getExtendedAttributes(attr
, getter
=True)
24342 CGNativeMember
.__init
__(
24346 CGSpecializedGetterCommon
.makeNativeName(descriptor
, attr
),
24349 resultNotAddRefed
=not attr
.type.isSequence(),
24351 self
.body
= self
.getMethodBody()
24353 def getArgs(self
, returnType
, argList
):
24354 if "needsErrorResult" in self
.extendedAttrs
:
24355 raise TypeError("Event code generator does not support [Throws]!")
24356 if "canOOM" in self
.extendedAttrs
:
24357 raise TypeError("Event code generator does not support [CanOOM]!")
24358 if not self
.member
.isAttr():
24359 raise TypeError("Event code generator does not support methods")
24360 if self
.member
.isStatic():
24361 raise TypeError("Event code generators does not support static attributes")
24362 return CGNativeMember
.getArgs(self
, returnType
, argList
)
24364 def getMethodBody(self
):
24365 type = self
.member
.type
24366 memberName
= CGDictionary
.makeMemberName(self
.member
.identifier
.name
)
24368 (type.isPrimitive() and type.tag() in builtinNames
)
24370 or type.isPromise()
24371 or type.isGeckoInterface()
24373 return "return " + memberName
+ ";\n"
24374 if type.isJSString():
24375 # https://bugzilla.mozilla.org/show_bug.cgi?id=1580167
24376 raise TypeError("JSString not supported as member of a generated event")
24379 or type.isByteString()
24380 or type.isUSVString()
24381 or type.isUTF8String()
24383 return "aRetVal = " + memberName
+ ";\n"
24384 if type.isSpiderMonkeyInterface() or type.isObject():
24387 if (${memberName}) {
24388 JS::ExposeObjectToActiveJS(${memberName});
24390 aRetVal.set(${memberName});
24393 memberName
=memberName
,
24398 ${selfName}(aRetVal);
24400 selfName
=self
.name
,
24403 return "aRetVal = " + memberName
+ ";\n"
24404 if type.isSequence():
24405 if type.nullable():
24409 + ".IsNull()) { aRetVal.SetNull(); } else { aRetVal.SetValue("
24411 + ".Value().Clone()); }\n"
24414 return "aRetVal = " + memberName
+ ".Clone();\n"
24415 if type.isDictionary():
24416 return "aRetVal = " + memberName
+ ";\n"
24417 raise TypeError("Event code generator does not support this type!")
24419 def declare(self
, cgClass
):
24421 getattr(self
.member
, "originatingInterface", cgClass
.descriptor
.interface
)
24422 != cgClass
.descriptor
.interface
24425 return CGNativeMember
.declare(self
, cgClass
)
24427 def define(self
, cgClass
):
24429 getattr(self
.member
, "originatingInterface", cgClass
.descriptor
.interface
)
24430 != cgClass
.descriptor
.interface
24433 return CGNativeMember
.define(self
, cgClass
)
24436 class CGEventSetter(CGNativeMember
):
24437 def __init__(self
):
24438 raise TypeError("Event code generator does not support setters!")
24441 class CGEventMethod(CGNativeMember
):
24442 def __init__(self
, descriptor
, method
, signature
, isConstructor
, breakAfter
=True):
24443 self
.isInit
= False
24445 CGNativeMember
.__init
__(
24449 CGSpecializedMethod
.makeNativeName(descriptor
, method
),
24451 descriptor
.getExtendedAttributes(method
),
24452 breakAfter
=breakAfter
,
24453 variadicIsSequence
=True,
24455 self
.originalArgs
= list(self
.args
)
24457 iface
= descriptor
.interface
24458 allowed
= isConstructor
24459 if not allowed
and iface
.getExtendedAttribute("LegacyEventInit"):
24460 # Allow it, only if it fits the initFooEvent profile exactly
24461 # We could check the arg types but it's not worth the effort.
24463 method
.identifier
.name
== "init" + iface
.identifier
.name
24464 and signature
[1][0].type.isDOMString()
24465 and signature
[1][1].type.isBoolean()
24466 and signature
[1][2].type.isBoolean()
24468 # -3 on the left to ignore the type, bubbles, and cancelable parameters
24469 # -1 on the right to ignore the .trusted property which bleeds through
24470 # here because it is [Unforgeable].
24471 len(signature
[1]) - 3
24472 == len([x
for x
in iface
.members
if x
.isAttr()]) - 1
24478 raise TypeError("Event code generator does not support methods!")
24480 def getArgs(self
, returnType
, argList
):
24481 args
= [self
.getArg(arg
) for arg
in argList
]
24484 def getArg(self
, arg
):
24485 decl
, ref
= self
.getArgType(
24486 arg
.type, arg
.canHaveMissingValue(), "Variadic" if arg
.variadic
else False
24489 decl
= CGWrapper(decl
, pre
="const ", post
="&")
24491 name
= arg
.identifier
.name
24492 name
= "a" + name
[0].upper() + name
[1:]
24493 return Argument(decl
.define(), name
)
24495 def declare(self
, cgClass
):
24497 constructorForNativeCaller
= ""
24499 self
.args
= list(self
.originalArgs
)
24500 self
.args
.insert(0, Argument("mozilla::dom::EventTarget*", "aOwner"))
24501 constructorForNativeCaller
= CGNativeMember
.declare(self
, cgClass
)
24503 self
.args
= list(self
.originalArgs
)
24504 if needCx(None, self
.arguments(), [], considerTypes
=True, static
=True):
24505 self
.args
.insert(0, Argument("JSContext*", "aCx"))
24506 if not self
.isInit
:
24507 self
.args
.insert(0, Argument("const GlobalObject&", "aGlobal"))
24509 return constructorForNativeCaller
+ CGNativeMember
.declare(self
, cgClass
)
24511 def defineInit(self
, cgClass
):
24512 iface
= self
.descriptorProvider
.interface
24514 while iface
.identifier
.name
!= "Event":
24515 i
= 3 # Skip the boilerplate args: type, bubble,s cancelable.
24516 for m
in iface
.members
:
24518 # We need to initialize all the member variables that do
24519 # not come from Event.
24521 getattr(m
, "originatingInterface", iface
).identifier
.name
24525 name
= CGDictionary
.makeMemberName(m
.identifier
.name
)
24526 members
+= "%s = %s;\n" % (name
, self
.args
[i
].name
)
24528 iface
= iface
.parent
24532 InitEvent(${typeArg}, ${bubblesArg}, ${cancelableArg});
24535 typeArg
=self
.args
[0].name
,
24536 bubblesArg
=self
.args
[1].name
,
24537 cancelableArg
=self
.args
[2].name
,
24541 return CGNativeMember
.define(self
, cgClass
)
24543 def define(self
, cgClass
):
24544 self
.args
= list(self
.originalArgs
)
24546 return self
.defineInit(cgClass
)
24549 iface
= self
.descriptorProvider
.interface
24550 while iface
.identifier
.name
!= "Event":
24551 for m
in self
.descriptorProvider
.getDescriptor(
24552 iface
.identifier
.name
24553 ).interface
.members
:
24555 # We initialize all the other member variables in the
24556 # Constructor except those ones coming from the Event.
24559 m
, "originatingInterface", cgClass
.descriptor
.interface
24564 name
= CGDictionary
.makeMemberName(m
.identifier
.name
)
24565 if m
.type.isSequence():
24566 # For sequences we may not be able to do a simple
24567 # assignment because the underlying types may not match.
24568 # For example, the argument can be a
24569 # Sequence<OwningNonNull<SomeInterface>> while our
24570 # member is an nsTArray<RefPtr<SomeInterface>>. So
24571 # use AppendElements, which is actually a template on
24572 # the incoming type on nsTArray and does the right thing
24575 source
= "%s.%s" % (self
.args
[1].name
, name
)
24576 sequenceCopy
= "e->%s.AppendElements(%s);\n"
24577 if m
.type.nullable():
24578 sequenceCopy
= CGIfWrapper(
24579 CGGeneric(sequenceCopy
), "!%s.IsNull()" % source
24581 target
+= ".SetValue()"
24582 source
+= ".Value()"
24583 members
+= sequenceCopy
% (target
, source
)
24584 elif m
.type.isSpiderMonkeyInterface():
24585 srcname
= "%s.%s" % (self
.args
[1].name
, name
)
24586 if m
.type.nullable():
24589 if (${srcname}.IsNull()) {
24590 e->${varname} = nullptr;
24592 e->${varname} = ${srcname}.Value().Obj();
24601 e->${varname}.set(${srcname}.Obj());
24607 members
+= "e->%s = %s.%s;\n" % (name
, self
.args
[1].name
, name
)
24610 or m
.type.isObject()
24611 or m
.type.isSpiderMonkeyInterface()
24613 holdJS
= "mozilla::HoldJSObjects(e.get());\n"
24614 iface
= iface
.parent
24618 RefPtr<${nativeType}> e = new ${nativeType}(aOwner);
24619 bool trusted = e->Init(aOwner);
24620 e->InitEvent(${eventType}, ${eventInit}.mBubbles, ${eventInit}.mCancelable);
24622 e->SetTrusted(trusted);
24623 e->SetComposed(${eventInit}.mComposed);
24627 nativeType
=self
.descriptorProvider
.nativeType
.split("::")[-1],
24628 eventType
=self
.args
[0].name
,
24629 eventInit
=self
.args
[1].name
,
24634 self
.args
.insert(0, Argument("mozilla::dom::EventTarget*", "aOwner"))
24635 constructorForNativeCaller
= CGNativeMember
.define(self
, cgClass
) + "\n"
24636 self
.args
= list(self
.originalArgs
)
24639 nsCOMPtr<mozilla::dom::EventTarget> owner = do_QueryInterface(aGlobal.GetAsSupports());
24640 return Constructor(owner, ${arg0}, ${arg1});
24642 arg0
=self
.args
[0].name
,
24643 arg1
=self
.args
[1].name
,
24645 if needCx(None, self
.arguments(), [], considerTypes
=True, static
=True):
24646 self
.args
.insert(0, Argument("JSContext*", "aCx"))
24647 self
.args
.insert(0, Argument("const GlobalObject&", "aGlobal"))
24648 return constructorForNativeCaller
+ CGNativeMember
.define(self
, cgClass
)
24651 class CGEventClass(CGBindingImplClass
):
24653 Codegen for the actual Event class implementation for this descriptor
24656 def __init__(self
, descriptor
):
24657 CGBindingImplClass
.__init
__(
24664 "WrapObjectInternal",
24668 self
.membersNeedingCC
= []
24669 self
.membersNeedingTrace
= []
24671 for m
in descriptor
.interface
.members
:
24673 getattr(m
, "originatingInterface", descriptor
.interface
)
24674 != descriptor
.interface
24680 self
.membersNeedingTrace
.append(m
)
24681 # Add a getter that doesn't need a JSContext. Note that we
24682 # don't need to do this if our originating interface is not
24683 # the descriptor's interface, because in that case we
24684 # wouldn't generate the getter that _does_ need a JSContext
24686 extraMethods
.append(
24688 CGSpecializedGetterCommon
.makeNativeName(descriptor
, m
),
24690 [Argument("JS::MutableHandle<JS::Value>", "aRetVal")],
24694 JS::ExposeValueToActiveJS(${memberName});
24695 aRetVal.set(${memberName});
24697 memberName
=CGDictionary
.makeMemberName(
24703 elif m
.type.isObject() or m
.type.isSpiderMonkeyInterface():
24704 self
.membersNeedingTrace
.append(m
)
24705 elif typeNeedsRooting(m
.type):
24707 "Need to implement tracing for event member of type %s" % m
.type
24709 elif idlTypeNeedsCycleCollection(m
.type):
24710 self
.membersNeedingCC
.append(m
)
24712 nativeType
= self
.getNativeTypeForIDLType(m
.type).define()
24715 CGDictionary
.makeMemberName(m
.identifier
.name
),
24717 visibility
="private",
24722 parent
= self
.descriptor
.interface
.parent
24723 self
.parentType
= self
.descriptor
.getDescriptor(
24724 parent
.identifier
.name
24725 ).nativeType
.split("::")[-1]
24726 self
.nativeType
= self
.descriptor
.nativeType
.split("::")[-1]
24729 isupportsDecl
= fill(
24731 NS_DECL_ISUPPORTS_INHERITED
24732 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(${nativeType}, ${parentType})
24734 nativeType
=self
.nativeType
,
24735 parentType
=self
.parentType
,
24738 isupportsDecl
= fill(
24740 NS_INLINE_DECL_REFCOUNTING_INHERITED(${nativeType}, ${parentType})
24742 nativeType
=self
.nativeType
,
24743 parentType
=self
.parentType
,
24746 baseDeclarations
= fill(
24752 virtual ~${nativeType}();
24753 explicit ${nativeType}(mozilla::dom::EventTarget* aOwner);
24756 isupportsDecl
=isupportsDecl
,
24757 nativeType
=self
.nativeType
,
24758 parentType
=self
.parentType
,
24761 className
= self
.nativeType
24762 asConcreteTypeMethod
= ClassMethod(
24763 "As%s" % className
,
24767 body
="return this;\n",
24768 breakAfterReturnDecl
=" ",
24771 extraMethods
.append(asConcreteTypeMethod
)
24776 bases
=[ClassBase(self
.parentType
)],
24777 methods
=extraMethods
+ self
.methodDecls
,
24779 extradeclarations
=baseDeclarations
,
24782 def getWrapObjectBody(self
):
24784 "return %s_Binding::Wrap(aCx, this, aGivenProto);\n" % self
.descriptor
.name
24788 return len(self
.membersNeedingCC
) != 0 or len(self
.membersNeedingTrace
) != 0
24790 def implTraverse(self
):
24792 for m
in self
.membersNeedingCC
:
24794 " NS_IMPL_CYCLE_COLLECTION_TRAVERSE(%s)\n"
24795 % CGDictionary
.makeMemberName(m
.identifier
.name
)
24799 def implUnlink(self
):
24801 for m
in self
.membersNeedingCC
:
24803 " NS_IMPL_CYCLE_COLLECTION_UNLINK(%s)\n"
24804 % CGDictionary
.makeMemberName(m
.identifier
.name
)
24806 for m
in self
.membersNeedingTrace
:
24807 name
= CGDictionary
.makeMemberName(m
.identifier
.name
)
24809 retVal
+= " tmp->" + name
+ ".setUndefined();\n"
24810 elif m
.type.isObject() or m
.type.isSpiderMonkeyInterface():
24811 retVal
+= " tmp->" + name
+ " = nullptr;\n"
24813 raise TypeError("Unknown traceable member type %s" % m
.type)
24816 def implTrace(self
):
24818 for m
in self
.membersNeedingTrace
:
24820 " NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(%s)\n"
24821 % CGDictionary
.makeMemberName(m
.identifier
.name
)
24826 for m
in self
.membersNeedingTrace
:
24828 m
.type.isAny() or m
.type.isObject() or m
.type.isSpiderMonkeyInterface()
24830 raise TypeError("Unknown traceable member type %s" % m
.type)
24832 if len(self
.membersNeedingTrace
) > 0:
24833 dropJS
= "mozilla::DropJSObjects(this);\n"
24836 # Just override CGClass and do our own thing
24838 "aOwner, nullptr, nullptr" if self
.parentType
== "Event" else "aOwner"
24845 NS_IMPL_CYCLE_COLLECTION_CLASS(${nativeType})
24847 NS_IMPL_ADDREF_INHERITED(${nativeType}, ${parentType})
24848 NS_IMPL_RELEASE_INHERITED(${nativeType}, ${parentType})
24850 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(${nativeType}, ${parentType})
24852 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
24854 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(${nativeType}, ${parentType})
24856 NS_IMPL_CYCLE_COLLECTION_TRACE_END
24858 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(${nativeType}, ${parentType})
24860 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
24862 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
24863 NS_INTERFACE_MAP_END_INHERITING(${parentType})
24865 nativeType
=self
.nativeType
,
24866 parentType
=self
.parentType
,
24867 traverse
=self
.implTraverse(),
24868 unlink
=self
.implUnlink(),
24869 trace
=self
.implTrace(),
24877 ${nativeType}::${nativeType}(mozilla::dom::EventTarget* aOwner)
24878 : ${parentType}(${ctorParams})
24882 ${nativeType}::~${nativeType}()
24888 nativeType
=self
.nativeType
,
24889 ctorParams
=ctorParams
,
24890 parentType
=self
.parentType
,
24894 return classImpl
+ CGBindingImplClass
.define(self
)
24896 def getNativeTypeForIDLType(self
, type):
24897 if type.isPrimitive() and type.tag() in builtinNames
:
24898 nativeType
= CGGeneric(builtinNames
[type.tag()])
24899 if type.nullable():
24900 nativeType
= CGTemplatedType("Nullable", nativeType
)
24901 elif type.isEnum():
24902 nativeType
= CGGeneric(type.unroll().inner
.identifier
.name
)
24903 if type.nullable():
24904 nativeType
= CGTemplatedType("Nullable", nativeType
)
24905 elif type.isJSString():
24906 nativeType
= CGGeneric("JS::Heap<JSString*>")
24907 elif type.isDOMString() or type.isUSVString():
24908 nativeType
= CGGeneric("nsString")
24909 elif type.isByteString() or type.isUTF8String():
24910 nativeType
= CGGeneric("nsCString")
24911 elif type.isPromise():
24912 nativeType
= CGGeneric("RefPtr<Promise>")
24913 elif type.isDictionary():
24914 if typeNeedsRooting(type):
24916 "We don't support event members that are dictionary types "
24917 "that need rooting (%s)" % type
24919 nativeType
= CGGeneric(CGDictionary
.makeDictionaryName(type.unroll().inner
))
24920 if type.nullable():
24921 nativeType
= CGTemplatedType("Nullable", nativeType
)
24922 elif type.isGeckoInterface():
24923 iface
= type.unroll().inner
24924 nativeType
= self
.descriptor
.getDescriptor(iface
.identifier
.name
).nativeType
24925 # Now trim off unnecessary namespaces
24926 nativeType
= nativeType
.split("::")
24927 if nativeType
[0] == "mozilla":
24929 if nativeType
[0] == "dom":
24931 nativeType
= CGWrapper(
24932 CGGeneric("::".join(nativeType
)), pre
="RefPtr<", post
=">"
24935 nativeType
= CGGeneric("JS::Heap<JS::Value>")
24936 elif type.isObject() or type.isSpiderMonkeyInterface():
24937 nativeType
= CGGeneric("JS::Heap<JSObject*>")
24938 elif type.isUnion():
24939 nativeType
= CGGeneric(CGUnionStruct
.unionTypeDecl(type, True))
24940 elif type.isSequence():
24941 if type.nullable():
24942 innerType
= type.inner
.inner
24944 innerType
= type.inner
24946 not innerType
.isPrimitive()
24947 and not innerType
.isEnum()
24948 and not innerType
.isDOMString()
24949 and not innerType
.isByteString()
24950 and not innerType
.isUTF8String()
24951 and not innerType
.isPromise()
24952 and not innerType
.isGeckoInterface()
24955 "Don't know how to properly manage GC/CC for "
24956 "event member of type %s" % type
24958 nativeType
= CGTemplatedType(
24959 "nsTArray", self
.getNativeTypeForIDLType(innerType
)
24961 if type.nullable():
24962 nativeType
= CGTemplatedType("Nullable", nativeType
)
24964 raise TypeError("Don't know how to declare event member of type %s" % type)
24968 class CGEventRoot(CGThing
):
24969 def __init__(self
, config
, interfaceName
):
24970 descriptor
= config
.getDescriptor(interfaceName
)
24972 self
.root
= CGWrapper(CGEventClass(descriptor
), pre
="\n", post
="\n")
24974 self
.root
= CGNamespace
.build(["mozilla", "dom"], self
.root
)
24976 self
.root
= CGList(
24977 [CGClassForwardDeclare("JSContext", isStruct
=True), self
.root
]
24980 parent
= descriptor
.interface
.parent
.identifier
.name
24982 # Throw in our #includes
24983 self
.root
= CGHeaders(
24989 config
.getDescriptor(parent
).headerFile
,
24990 "mozilla/Attributes.h",
24991 "mozilla/dom/%sBinding.h" % interfaceName
,
24992 "mozilla/dom/BindingUtils.h",
24995 "%s.h" % interfaceName
,
24997 "mozilla/HoldDropJSObjects.h",
24998 "mozilla/dom/Nullable.h",
25005 # And now some include guards
25006 self
.root
= CGIncludeGuard(interfaceName
, self
.root
)
25008 self
.root
= CGWrapper(
25011 AUTOGENERATED_WITH_SOURCE_WARNING_COMMENT
25012 % os
.path
.basename(descriptor
.interface
.filename
)
25016 self
.root
= CGWrapper(
25020 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
25021 /* vim:set ts=2 sw=2 sts=2 et cindent: */
25022 /* This Source Code Form is subject to the terms of the Mozilla Public
25023 * License, v. 2.0. If a copy of the MPL was not distributed with this
25024 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
25031 return self
.root
.declare()
25034 return self
.root
.define()