1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 # You can obtain one at http://mozilla.org/MPL/2.0/.
5 # Common codegen classes.
14 from perfecthash
import PerfectHash
20 IDLDefaultDictionaryValue
,
27 IDLEmptySequenceValue
,
30 from Configuration
import (
31 NoSuchDescriptorError
,
32 getTypesFromDescriptor
,
33 getTypesFromDictionary
,
37 MemberIsLegacyUnforgeable
,
41 AUTOGENERATED_WARNING_COMMENT
= (
42 "/* THIS FILE IS AUTOGENERATED BY Codegen.py - DO NOT EDIT */\n\n"
44 AUTOGENERATED_WITH_SOURCE_WARNING_COMMENT
= (
45 "/* THIS FILE IS AUTOGENERATED FROM %s BY Codegen.py - DO NOT EDIT */\n\n"
47 ADDPROPERTY_HOOK_NAME
= "_addProperty"
48 GETWRAPPERCACHE_HOOK_NAME
= "_getWrapperCache"
49 FINALIZE_HOOK_NAME
= "_finalize"
50 OBJECT_MOVED_HOOK_NAME
= "_objectMoved"
51 CONSTRUCT_HOOK_NAME
= "_constructor"
52 LEGACYCALLER_HOOK_NAME
= "_legacycaller"
53 RESOLVE_HOOK_NAME
= "_resolve"
54 MAY_RESOLVE_HOOK_NAME
= "_mayResolve"
55 NEW_ENUMERATE_HOOK_NAME
= "_newEnumerate"
56 ENUM_ENTRY_VARIABLE_NAME
= "strings"
57 INSTANCE_RESERVED_SLOTS
= 1
59 # This size is arbitrary. It is a power of 2 to make using it as a modulo
60 # operand cheap, and is usually around 1/3-1/5th of the set size (sometimes
61 # smaller for very large sets).
62 GLOBAL_NAMES_PHF_SIZE
= 256
65 def memberReservedSlot(member
, descriptor
):
67 "(DOM_INSTANCE_RESERVED_SLOTS + %d)"
68 % member
.slotIndices
[descriptor
.interface
.identifier
.name
]
72 def memberXrayExpandoReservedSlot(member
, descriptor
):
74 "(xpc::JSSLOT_EXPANDO_COUNT + %d)"
75 % member
.slotIndices
[descriptor
.interface
.identifier
.name
]
79 def mayUseXrayExpandoSlots(descriptor
, attr
):
80 assert not attr
.getExtendedAttribute("NewObject")
81 # For attributes whose type is a Gecko interface we always use
82 # slots on the reflector for caching. Also, for interfaces that
83 # don't want Xrays we obviously never use the Xray expando slot.
84 return descriptor
.wantsXrays
and not attr
.type.isGeckoInterface()
87 def toStringBool(arg
):
89 Converts IDL/Python Boolean (True/False) to C++ Boolean (true/false)
91 return str(not not arg
).lower()
94 def toBindingNamespace(arg
):
95 return arg
+ "_Binding"
98 def isTypeCopyConstructible(type):
99 # Nullable and sequence stuff doesn't affect copy-constructibility
105 or (type.isUnion() and CGUnionStruct
.isUnionCopyConstructible(type))
108 and CGDictionary
.isDictionaryCopyConstructible(type.inner
)
111 # Interface types are only copy-constructible if they're Gecko
112 # interfaces. SpiderMonkey interfaces are not copy-constructible
113 # because of rooting issues.
114 (type.isInterface() and type.isGeckoInterface())
118 class CycleCollectionUnsupported(TypeError):
119 def __init__(self
, message
):
120 TypeError.__init
__(self
, message
)
123 def idlTypeNeedsCycleCollection(type):
124 type = type.unroll() # Takes care of sequences and nullables
126 (type.isPrimitive() and type.tag() in builtinNames
)
131 or type.isSpiderMonkeyInterface()
134 elif type.isCallback() or type.isPromise() or type.isGeckoInterface():
137 return any(idlTypeNeedsCycleCollection(t
) for t
in type.flatMemberTypes
)
138 elif type.isRecord():
139 if idlTypeNeedsCycleCollection(type.inner
):
140 raise CycleCollectionUnsupported(
141 "Cycle collection for type %s is not supported" % type
144 elif type.isDictionary():
145 return CGDictionary
.dictionaryNeedsCycleCollection(type.inner
)
147 raise CycleCollectionUnsupported(
148 "Don't know whether to cycle-collect type %s" % type
152 def idlTypeNeedsCallContext(type, descriptor
=None, allowTreatNonCallableAsNull
=False):
154 Returns whether the given type needs error reporting via a
155 BindingCallContext for JS-to-C++ conversions. This will happen when the
156 conversion can throw an exception due to logic in the IDL spec or
157 Gecko-specific security checks. In particular, a type needs a
158 BindingCallContext if and only if the JS-to-C++ conversion for that type can
159 end up calling ThrowErrorMessage.
161 For some types this depends on the descriptor (e.g. because we do certain
162 checks only for some kinds of interfaces).
164 The allowTreatNonCallableAsNull optimization is there so we can avoid
165 generating an unnecessary BindingCallContext for all the event handler
170 if type.isSequence():
171 # Sequences can always throw "not an object"
174 # treatNonObjectAsNull() and treatNonCallableAsNull() are
175 # only sane things to test on nullable types, so do that now.
177 allowTreatNonCallableAsNull
178 and type.isCallback()
179 and (type.treatNonObjectAsNull() or type.treatNonCallableAsNull())
181 # This can't throw. so never needs a method description.
187 # The float check needs to come before the isPrimitive() check,
188 # because floats are primitives too.
190 # Floats can throw if restricted.
191 return not type.isUnrestricted()
192 if type.isPrimitive() and type.tag() in builtinNames
:
193 # Numbers can throw if enforcing range.
194 return type.hasEnforceRange()
196 # Can throw on invalid value.
199 # Can throw if it's a ByteString
200 return type.isByteString()
202 # JS-implemented interfaces do extra security checks so need a
203 # method description here. If we have no descriptor, this
204 # might be JS-implemented thing, so it will do the security
205 # check and we need the method description.
206 return not descriptor
or descriptor
.interface
.isJSImplemented()
208 # JS-to-Promise conversion won't cause us to throw any
209 # specific exceptions, so does not need a method description.
213 or type.isInterface()
215 or type.isDictionary()
218 # These can all throw if a primitive is passed in, at the very least.
219 # There are some rare cases when we know we have an object, but those
220 # are not worth the complexity of optimizing for.
222 # Note that we checked the [LegacyTreatNonObjectAsNull] case already when
223 # unwrapping nullables.
226 # Can throw if a type not in the union is passed in.
229 # Clearly doesn't need a method description; we can only get here from
230 # CGHeaders trying to decide whether to include the method description
233 raise TypeError("Don't know whether type '%s' needs a method description" % type)
236 # TryPreserveWrapper uses the addProperty hook to preserve the wrapper of
237 # non-nsISupports cycle collected objects, so if wantsAddProperty is changed
238 # to not cover that case then TryPreserveWrapper will need to be changed.
239 def wantsAddProperty(desc
):
240 return desc
.concrete
and desc
.wrapperCache
and not desc
.isGlobal()
243 def wantsGetWrapperCache(desc
):
245 desc
.concrete
and desc
.wrapperCache
and not desc
.isGlobal() and not desc
.proxy
249 # We'll want to insert the indent at the beginnings of lines, but we
250 # don't want to indent empty lines. So only indent lines that have a
251 # non-newline character on them.
252 lineStartDetector
= re
.compile("^(?=[^\n#])", re
.MULTILINE
)
255 def indent(s
, indentLevel
=2):
259 Weird secret feature: this doesn't indent lines that start with # (such as
260 #include lines or #ifdef/#endif).
264 return re
.sub(lineStartDetector
, indentLevel
* " ", s
)
267 # dedent() and fill() are often called on the same string multiple
268 # times. We want to memoize their return values so we don't keep
269 # recomputing them all the time.
272 Decorator to memoize a function of one argument. The cache just
279 retval
= cache
.get(arg
)
281 retval
= cache
[arg
] = fn(arg
)
290 Remove all leading whitespace from s, and remove a blank line
293 if s
.startswith("\n"):
295 return textwrap
.dedent(s
)
298 # This works by transforming the fill()-template to an equivalent
300 fill_multiline_substitution_re
= re
.compile(r
"( *)\$\*{(\w+)}(\n)?")
303 find_substitutions
= re
.compile(r
"\${")
307 def compile_fill_template(template
):
309 Helper function for fill(). Given the template string passed to fill(),
310 do the reusable part of template processing and return a pair (t,
311 argModList) that can be used every time fill() is called with that
314 argsModList is list of tuples that represent modifications to be
315 made to args. Each modification has, in order: i) the arg name,
316 ii) the modified name, iii) the indent depth.
319 assert t
.endswith("\n") or "\n" not in t
324 Replaces a line like ' $*{xyz}\n' with '${xyz_n}',
325 where n is the indent depth, and add a corresponding entry to
328 Note that this needs to close over argModList, so it has to be
329 defined inside compile_fill_template().
331 indentation
, name
, nl
= match
.groups()
332 depth
= len(indentation
)
334 # Check that $*{xyz} appears by itself on a line.
335 prev
= match
.string
[: match
.start()]
336 if (prev
and not prev
.endswith("\n")) or nl
is None:
338 "Invalid fill() template: $*{%s} must appear by itself on a line" % name
341 # Now replace this whole line of template with the indented equivalent.
342 modified_name
= name
+ "_" + str(depth
)
343 argModList
.append((name
, modified_name
, depth
))
344 return "${" + modified_name
+ "}"
346 t
= re
.sub(fill_multiline_substitution_re
, replace
, t
)
347 if not re
.search(find_substitutions
, t
):
348 raise TypeError("Using fill() when dedent() would do.")
349 return (string
.Template(t
), argModList
)
352 def fill(template
, **args
):
354 Convenience function for filling in a multiline template.
356 `fill(template, name1=v1, name2=v2)` is a lot like
357 `string.Template(template).substitute({"name1": v1, "name2": v2})`.
359 However, it's shorter, and has a few nice features:
361 * If `template` is indented, fill() automatically dedents it!
362 This makes code using fill() with Python's multiline strings
363 much nicer to look at.
365 * If `template` starts with a blank line, fill() strips it off.
366 (Again, convenient with multiline strings.)
368 * fill() recognizes a special kind of substitution
369 of the form `$*{name}`.
371 Use this to paste in, and automatically indent, multiple lines.
372 (Mnemonic: The `*` is for "multiple lines").
374 A `$*` substitution must appear by itself on a line, with optional
375 preceding indentation (spaces only). The whole line is replaced by the
376 corresponding keyword argument, indented appropriately. If the
377 argument is an empty string, no output is generated, not even a blank
381 t
, argModList
= compile_fill_template(template
)
382 # Now apply argModList to args
383 for (name
, modified_name
, depth
) in argModList
:
384 if not (args
[name
] == "" or args
[name
].endswith("\n")):
386 "Argument %s with value %r is missing a newline" % (name
, args
[name
])
388 args
[modified_name
] = indent(args
[name
], depth
)
390 return t
.substitute(args
)
395 Abstract base class for things that spit out code.
399 pass # Nothing for now
402 """Produce code for a header file."""
403 assert False # Override me!
406 """Produce code for a cpp file."""
407 assert False # Override me!
410 """Produce the deps for a pp file"""
411 assert False # Override me!
414 class CGStringTable(CGThing
):
416 Generate a string table for the given strings with a function accessor:
418 const char *accessorName(unsigned int index) {
419 static const char table[] = "...";
420 static const uint16_t indices = { ... };
421 return &table[indices[index]];
424 This is more efficient than the more natural:
426 const char *table[] = {
430 The uint16_t indices are smaller than the pointer equivalents, and the
431 string table requires no runtime relocations.
434 def __init__(self
, accessorName
, strings
, static
=False):
435 CGThing
.__init
__(self
)
436 self
.accessorName
= accessorName
437 self
.strings
= strings
443 return "extern const char *%s(unsigned int aIndex);\n" % self
.accessorName
446 table
= ' "\\0" '.join('"%s"' % s
for s
in self
.strings
)
449 for s
in self
.strings
:
450 indices
.append(currentIndex
)
451 currentIndex
+= len(s
) + 1 # for the null terminator
454 ${static}const char *${name}(unsigned int aIndex)
456 static const char table[] = ${table};
457 static const uint16_t indices[] = { ${indices} };
458 static_assert(${currentIndex} <= UINT16_MAX, "string table overflow!");
459 return &table[indices[aIndex]];
462 static
="static " if self
.static
else "",
463 name
=self
.accessorName
,
465 indices
=", ".join("%d" % index
for index
in indices
),
466 currentIndex
=currentIndex
,
470 class CGNativePropertyHooks(CGThing
):
472 Generate a NativePropertyHooks for a given descriptor
475 def __init__(self
, descriptor
, properties
):
476 CGThing
.__init
__(self
)
477 self
.descriptor
= descriptor
478 self
.properties
= properties
481 if not self
.descriptor
.wantsXrays
:
485 // We declare this as an array so that retrieving a pointer to this
486 // binding's property hooks only requires compile/link-time resolvable
487 // address arithmetic. Declaring it as a pointer instead would require
488 // doing a run-time load to fetch a pointer to this binding's property
489 // hooks. And then structures which embedded a pointer to this structure
490 // would require a run-time load for proper initialization, which would
491 // then induce static constructors. Lots of static constructors.
492 extern const NativePropertyHooks sNativePropertyHooks[];
497 if not self
.descriptor
.wantsXrays
:
499 deleteNamedProperty
= "nullptr"
501 self
.descriptor
.concrete
502 and self
.descriptor
.proxy
503 and not self
.descriptor
.isMaybeCrossOriginObject()
505 resolveOwnProperty
= "ResolveOwnProperty"
506 enumerateOwnProperties
= "EnumerateOwnProperties"
507 if self
.descriptor
.needsXrayNamedDeleterHook():
508 deleteNamedProperty
= "DeleteNamedProperty"
509 elif self
.descriptor
.needsXrayResolveHooks():
510 resolveOwnProperty
= "ResolveOwnPropertyViaResolve"
511 enumerateOwnProperties
= "EnumerateOwnPropertiesViaGetOwnPropertyNames"
513 resolveOwnProperty
= "nullptr"
514 enumerateOwnProperties
= "nullptr"
515 if self
.properties
.hasNonChromeOnly():
516 regular
= "sNativeProperties.Upcast()"
519 if self
.properties
.hasChromeOnly():
520 chrome
= "sChromeOnlyNativeProperties.Upcast()"
523 constructorID
= "constructors::id::"
524 if self
.descriptor
.interface
.hasInterfaceObject():
525 constructorID
+= self
.descriptor
.name
527 constructorID
+= "_ID_Count"
528 prototypeID
= "prototypes::id::"
529 if self
.descriptor
.interface
.hasInterfacePrototypeObject():
530 prototypeID
+= self
.descriptor
.name
532 prototypeID
+= "_ID_Count"
533 parentProtoName
= self
.descriptor
.parentPrototypeName
535 toBindingNamespace(parentProtoName
) + "::sNativePropertyHooks"
540 if self
.descriptor
.wantsXrayExpandoClass
:
541 expandoClass
= "&sXrayExpandoObjectClass"
543 expandoClass
= "&DefaultXrayExpandoObjectClass"
547 const NativePropertyHooks sNativePropertyHooks[] = { {
548 ${resolveOwnProperty},
549 ${enumerateOwnProperties},
550 ${deleteNamedProperty},
551 { ${regular}, ${chrome} },
558 resolveOwnProperty
=resolveOwnProperty
,
559 enumerateOwnProperties
=enumerateOwnProperties
,
560 deleteNamedProperty
=deleteNamedProperty
,
563 prototypeID
=prototypeID
,
564 constructorID
=constructorID
,
565 parentHooks
=parentHooks
,
566 expandoClass
=expandoClass
,
570 def NativePropertyHooks(descriptor
):
572 "&sEmptyNativePropertyHooks"
573 if not descriptor
.wantsXrays
574 else "sNativePropertyHooks"
578 def DOMClass(descriptor
):
579 protoList
= ["prototypes::id::" + proto
for proto
in descriptor
.prototypeNameChain
]
580 # Pad out the list to the right length with _ID_Count so we
581 # guarantee that all the lists are the same length. _ID_Count
582 # is never the ID of any prototype, so it's safe to use as
585 ["prototypes::id::_ID_Count"]
586 * (descriptor
.config
.maxProtoChainLength
- len(protoList
))
589 if descriptor
.interface
.isSerializable():
590 serializer
= "Serialize"
592 serializer
= "nullptr"
594 if wantsGetWrapperCache(descriptor
):
595 wrapperCacheGetter
= GETWRAPPERCACHE_HOOK_NAME
597 wrapperCacheGetter
= "nullptr"
602 std::is_base_of_v<nsISupports, ${nativeType}>,
604 FindAssociatedGlobalForNative<${nativeType}>::Get,
605 GetProtoObjectHandle,
606 GetCCParticipant<${nativeType}>::Get(),
608 ${wrapperCacheGetter}
610 protoChain
=", ".join(protoList
),
611 nativeType
=descriptor
.nativeType
,
612 hooks
=NativePropertyHooks(descriptor
),
613 serializer
=serializer
,
614 wrapperCacheGetter
=wrapperCacheGetter
,
618 def InstanceReservedSlots(descriptor
):
619 slots
= INSTANCE_RESERVED_SLOTS
+ descriptor
.interface
.totalMembersInSlots
620 if descriptor
.isMaybeCrossOriginObject():
621 # We need a slot for the cross-origin holder too.
622 if descriptor
.interface
.hasChildInterfaces():
624 "We don't support non-leaf cross-origin interfaces "
625 "like %s" % descriptor
.interface
.identifier
.name
631 class CGDOMJSClass(CGThing
):
633 Generate a DOMJSClass for a given descriptor
636 def __init__(self
, descriptor
):
637 CGThing
.__init
__(self
)
638 self
.descriptor
= descriptor
645 LEGACYCALLER_HOOK_NAME
646 if self
.descriptor
.operations
["LegacyCaller"]
650 OBJECT_MOVED_HOOK_NAME
if self
.descriptor
.wrapperCache
else "nullptr"
652 slotCount
= InstanceReservedSlots(self
.descriptor
)
653 classFlags
= "JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | "
654 if self
.descriptor
.isGlobal():
656 "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS)"
658 traceHook
= "JS_GlobalObjectTraceHook"
659 reservedSlots
= "JSCLASS_GLOBAL_APPLICATION_SLOTS"
661 classFlags
+= "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount
662 traceHook
= "nullptr"
663 reservedSlots
= slotCount
664 if self
.descriptor
.interface
.hasProbablyShortLivingWrapper():
665 if not self
.descriptor
.wrapperCache
:
667 "Need a wrapper cache to support nursery "
668 "allocation of DOM objects"
670 classFlags
+= " | JSCLASS_SKIP_NURSERY_FINALIZE"
672 if self
.descriptor
.interface
.getExtendedAttribute("NeedResolve"):
673 resolveHook
= RESOLVE_HOOK_NAME
674 mayResolveHook
= MAY_RESOLVE_HOOK_NAME
675 newEnumerateHook
= NEW_ENUMERATE_HOOK_NAME
676 elif self
.descriptor
.isGlobal():
677 resolveHook
= "mozilla::dom::ResolveGlobal"
678 mayResolveHook
= "mozilla::dom::MayResolveGlobal"
679 newEnumerateHook
= "mozilla::dom::EnumerateGlobal"
681 resolveHook
= "nullptr"
682 mayResolveHook
= "nullptr"
683 newEnumerateHook
= "nullptr"
687 static const JSClassOps sClassOps = {
688 ${addProperty}, /* addProperty */
689 nullptr, /* delProperty */
690 nullptr, /* enumerate */
691 ${newEnumerate}, /* newEnumerate */
692 ${resolve}, /* resolve */
693 ${mayResolve}, /* mayResolve */
694 ${finalize}, /* finalize */
696 nullptr, /* hasInstance */
697 nullptr, /* construct */
698 ${trace}, /* trace */
701 static const js::ClassExtension sClassExtension = {
702 ${objectMoved} /* objectMovedOp */
705 static const DOMJSClass sClass = {
715 static_assert(${instanceReservedSlots} == DOM_INSTANCE_RESERVED_SLOTS,
716 "Must have the right minimal number of reserved slots.");
717 static_assert(${reservedSlots} >= ${slotCount},
718 "Must have enough reserved slots.");
720 name
=self
.descriptor
.interface
.getClassName(),
722 addProperty
=ADDPROPERTY_HOOK_NAME
723 if wantsAddProperty(self
.descriptor
)
725 newEnumerate
=newEnumerateHook
,
727 mayResolve
=mayResolveHook
,
728 finalize
=FINALIZE_HOOK_NAME
,
731 objectMoved
=objectMovedHook
,
732 descriptor
=DOMClass(self
.descriptor
),
733 instanceReservedSlots
=INSTANCE_RESERVED_SLOTS
,
734 reservedSlots
=reservedSlots
,
739 class CGDOMProxyJSClass(CGThing
):
741 Generate a DOMJSClass for a given proxy descriptor
744 def __init__(self
, descriptor
):
745 CGThing
.__init
__(self
)
746 self
.descriptor
= descriptor
752 slotCount
= InstanceReservedSlots(self
.descriptor
)
753 # We need one reserved slot (DOM_OBJECT_SLOT).
754 flags
= ["JSCLASS_IS_DOMJSCLASS", "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount
]
755 # We don't use an IDL annotation for JSCLASS_EMULATES_UNDEFINED because
756 # we don't want people ever adding that to any interface other than
757 # HTMLAllCollection. So just hardcode it here.
758 if self
.descriptor
.interface
.identifier
.name
== "HTMLAllCollection":
759 flags
.append("JSCLASS_EMULATES_UNDEFINED")
762 static const DOMJSClass sClass = {
763 PROXY_CLASS_DEF("${name}",
768 name
=self
.descriptor
.interface
.identifier
.name
,
769 flags
=" | ".join(flags
),
770 descriptor
=DOMClass(self
.descriptor
),
774 class CGXrayExpandoJSClass(CGThing
):
776 Generate a JSClass for an Xray expando object. This is only
777 needed if we have members in slots (for [Cached] or [StoreInSlot]
781 def __init__(self
, descriptor
):
782 assert descriptor
.interface
.totalMembersInSlots
!= 0
783 assert descriptor
.wantsXrays
784 assert descriptor
.wantsXrayExpandoClass
785 CGThing
.__init
__(self
)
786 self
.descriptor
= descriptor
794 // This may allocate too many slots, because we only really need
795 // slots for our non-interface-typed members that we cache. But
796 // allocating slots only for those would make the slot index
797 // computations much more complicated, so let's do this the simple
799 DEFINE_XRAY_EXPANDO_CLASS(static, sXrayExpandoObjectClass, ${memberSlots});
801 memberSlots
=self
.descriptor
.interface
.totalMembersInSlots
,
805 def PrototypeIDAndDepth(descriptor
):
806 prototypeID
= "prototypes::id::"
807 if descriptor
.interface
.hasInterfacePrototypeObject():
808 prototypeID
+= descriptor
.interface
.identifier
.name
809 depth
= "PrototypeTraits<%s>::Depth" % prototypeID
811 prototypeID
+= "_ID_Count"
813 return (prototypeID
, depth
)
816 def InterfacePrototypeObjectProtoGetter(descriptor
):
818 Returns a tuple with two elements:
820 1) The name of the function to call to get the prototype to use for the
821 interface prototype object as a JSObject*.
823 2) The name of the function to call to get the prototype to use for the
824 interface prototype object as a JS::Handle<JSObject*> or None if no
825 such function exists.
827 parentProtoName
= descriptor
.parentPrototypeName
828 if descriptor
.hasNamedPropertiesObject
:
829 protoGetter
= "GetNamedPropertiesObject"
830 protoHandleGetter
= None
831 elif parentProtoName
is None:
832 if descriptor
.interface
.getExtendedAttribute("ExceptionClass"):
833 protoGetter
= "JS::GetRealmErrorPrototype"
834 elif descriptor
.interface
.isIteratorInterface():
835 protoGetter
= "JS::GetRealmIteratorPrototype"
837 protoGetter
= "JS::GetRealmObjectPrototype"
838 protoHandleGetter
= None
840 prefix
= toBindingNamespace(parentProtoName
)
841 protoGetter
= prefix
+ "::GetProtoObject"
842 protoHandleGetter
= prefix
+ "::GetProtoObjectHandle"
844 return (protoGetter
, protoHandleGetter
)
847 class CGPrototypeJSClass(CGThing
):
848 def __init__(self
, descriptor
, properties
):
849 CGThing
.__init
__(self
)
850 self
.descriptor
= descriptor
851 self
.properties
= properties
854 # We're purely for internal consumption
858 prototypeID
, depth
= PrototypeIDAndDepth(self
.descriptor
)
859 slotCount
= "DOM_INTERFACE_PROTO_SLOTS_BASE"
860 # Globals handle unforgeables directly in Wrap() instead of
863 self
.descriptor
.hasLegacyUnforgeableMembers
864 and not self
.descriptor
.isGlobal()
867 " + 1 /* slot for the JSObject holding the unforgeable properties */"
869 (protoGetter
, _
) = InterfacePrototypeObjectProtoGetter(self
.descriptor
)
871 "eGlobalInterfacePrototype"
872 if self
.descriptor
.isGlobal()
873 else "eInterfacePrototype"
877 static const DOMIfaceAndProtoJSClass sPrototypeClass = {
880 JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(${slotCount}),
895 name
=self
.descriptor
.interface
.getClassName(),
898 hooks
=NativePropertyHooks(self
.descriptor
),
899 prototypeID
=prototypeID
,
901 protoGetter
=protoGetter
,
905 def InterfaceObjectProtoGetter(descriptor
, forXrays
=False):
907 Returns a tuple with two elements:
909 1) The name of the function to call to get the prototype to use for the
910 interface object as a JSObject*.
912 2) The name of the function to call to get the prototype to use for the
913 interface prototype as a JS::Handle<JSObject*> or None if no such
916 parentInterface
= descriptor
.interface
.parent
918 assert not descriptor
.interface
.isNamespace()
919 parentIfaceName
= parentInterface
.identifier
.name
920 parentDesc
= descriptor
.getDescriptor(parentIfaceName
)
921 prefix
= toBindingNamespace(parentDesc
.name
)
922 protoGetter
= prefix
+ "::GetConstructorObject"
923 protoHandleGetter
= prefix
+ "::GetConstructorObjectHandle"
924 elif descriptor
.interface
.isNamespace():
925 if forXrays
or not descriptor
.interface
.getExtendedAttribute("ProtoObjectHack"):
926 protoGetter
= "JS::GetRealmObjectPrototype"
928 protoGetter
= "GetHackedNamespaceProtoObject"
929 protoHandleGetter
= None
931 protoGetter
= "JS::GetRealmFunctionPrototype"
932 protoHandleGetter
= None
933 return (protoGetter
, protoHandleGetter
)
936 class CGInterfaceObjectJSClass(CGThing
):
937 def __init__(self
, descriptor
, properties
):
938 CGThing
.__init
__(self
)
939 self
.descriptor
= descriptor
940 self
.properties
= properties
943 # We're purely for internal consumption
947 if self
.descriptor
.interface
.ctor():
948 assert not self
.descriptor
.interface
.isNamespace()
949 ctorname
= CONSTRUCT_HOOK_NAME
950 elif self
.descriptor
.interface
.isNamespace():
953 ctorname
= "ThrowingConstructor"
954 needsHasInstance
= self
.descriptor
.interface
.hasInterfacePrototypeObject()
956 prototypeID
, depth
= PrototypeIDAndDepth(self
.descriptor
)
957 slotCount
= "DOM_INTERFACE_SLOTS_BASE"
958 if len(self
.descriptor
.interface
.legacyFactoryFunctions
) > 0:
959 slotCount
+= " + %i /* slots for the legacy factory functions */" % len(
960 self
.descriptor
.interface
.legacyFactoryFunctions
962 (protoGetter
, _
) = InterfaceObjectProtoGetter(self
.descriptor
, forXrays
=True)
964 if ctorname
== "ThrowingConstructor":
966 classOpsPtr
= "&sBoringInterfaceObjectClassClassOps"
967 elif ctorname
== "nullptr":
969 classOpsPtr
= "JS_NULL_CLASS_OPS"
973 static const JSClassOps sInterfaceObjectClassOps = {
974 nullptr, /* addProperty */
975 nullptr, /* delProperty */
976 nullptr, /* enumerate */
977 nullptr, /* newEnumerate */
978 nullptr, /* resolve */
979 nullptr, /* mayResolve */
980 nullptr, /* finalize */
981 ${ctorname}, /* call */
982 nullptr, /* hasInstance */
983 ${ctorname}, /* construct */
990 classOpsPtr
= "&sInterfaceObjectClassOps"
992 if self
.descriptor
.interface
.isNamespace():
993 classString
= self
.descriptor
.interface
.getExtendedAttribute("ClassString")
994 if classString
is None:
995 classString
= "Object"
997 classString
= classString
[0]
998 funToString
= "nullptr"
999 objectOps
= "JS_NULL_OBJECT_OPS"
1001 classString
= "Function"
1003 '"function %s() {\\n [native code]\\n}"'
1004 % self
.descriptor
.interface
.identifier
.name
1006 # We need non-default ObjectOps so we can actually make
1007 # use of our funToString.
1008 objectOps
= "&sInterfaceObjectClassObjectOps"
1012 static const DOMIfaceAndProtoJSClass sInterfaceObjectClass = {
1015 JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(${slotCount}),
1022 ${needsHasInstance},
1030 classString
=classString
,
1031 slotCount
=slotCount
,
1032 classOpsPtr
=classOpsPtr
,
1033 hooks
=NativePropertyHooks(self
.descriptor
),
1034 objectOps
=objectOps
,
1035 needsHasInstance
=toStringBool(needsHasInstance
),
1036 prototypeID
=prototypeID
,
1038 funToString
=funToString
,
1039 protoGetter
=protoGetter
,
1044 class CGList(CGThing
):
1046 Generate code for a list of GCThings. Just concatenates them together, with
1047 an optional joiner string. "\n" is a common joiner.
1050 def __init__(self
, children
, joiner
=""):
1051 CGThing
.__init
__(self
)
1052 # Make a copy of the kids into a list, because if someone passes in a
1053 # generator we won't be able to both declare and define ourselves, or
1054 # define ourselves more than once!
1055 self
.children
= list(children
)
1056 self
.joiner
= joiner
1058 def append(self
, child
):
1059 self
.children
.append(child
)
1061 def prepend(self
, child
):
1062 self
.children
.insert(0, child
)
1064 def extend(self
, kids
):
1065 self
.children
.extend(kids
)
1067 def join(self
, iterable
):
1068 return self
.joiner
.join(s
for s
in iterable
if len(s
) > 0)
1072 child
.declare() for child
in self
.children
if child
is not None
1076 return self
.join(child
.define() for child
in self
.children
if child
is not None)
1080 for child
in self
.children
:
1083 deps
= deps
.union(child
.deps())
1087 return len(self
.children
)
1090 class CGGeneric(CGThing
):
1092 A class that spits out a fixed string into the codegen. Can spit out a
1093 separate string for the declaration too.
1096 def __init__(self
, define
="", declare
=""):
1097 self
.declareText
= declare
1098 self
.defineText
= define
1101 return self
.declareText
1104 return self
.defineText
1110 class CGIndenter(CGThing
):
1112 A class that takes another CGThing and generates code that indents that
1113 CGThing by some number of spaces. The default indent is two spaces.
1116 def __init__(self
, child
, indentLevel
=2, declareOnly
=False):
1117 assert isinstance(child
, CGThing
)
1118 CGThing
.__init
__(self
)
1120 self
.indentLevel
= indentLevel
1121 self
.declareOnly
= declareOnly
1124 return indent(self
.child
.declare(), self
.indentLevel
)
1127 defn
= self
.child
.define()
1128 if self
.declareOnly
:
1131 return indent(defn
, self
.indentLevel
)
1134 class CGWrapper(CGThing
):
1136 Generic CGThing that wraps other CGThings with pre and post text.
1152 CGThing
.__init
__(self
)
1154 self
.declarePre
= declarePre
or pre
1155 self
.declarePost
= declarePost
or post
1156 self
.definePre
= definePre
or pre
1157 self
.definePost
= definePost
or post
1158 self
.declareOnly
= declareOnly
1159 self
.defineOnly
= defineOnly
1160 self
.reindent
= reindent
1165 decl
= self
.child
.declare()
1167 decl
= self
.reindentString(decl
, self
.declarePre
)
1168 return self
.declarePre
+ decl
+ self
.declarePost
1171 if self
.declareOnly
:
1173 defn
= self
.child
.define()
1175 defn
= self
.reindentString(defn
, self
.definePre
)
1176 return self
.definePre
+ defn
+ self
.definePost
1179 def reindentString(stringToIndent
, widthString
):
1180 # We don't use lineStartDetector because we don't want to
1181 # insert whitespace at the beginning of our _first_ line.
1182 # Use the length of the last line of width string, in case
1183 # it is a multiline string.
1184 lastLineWidth
= len(widthString
.splitlines()[-1])
1185 return stripTrailingWhitespace(
1186 stringToIndent
.replace("\n", "\n" + (" " * lastLineWidth
))
1190 return self
.child
.deps()
1193 class CGIfWrapper(CGList
):
1194 def __init__(self
, child
, condition
):
1199 CGGeneric(condition
), pre
="if (", post
=") {\n", reindent
=True
1207 class CGIfElseWrapper(CGList
):
1208 def __init__(self
, condition
, ifTrue
, ifFalse
):
1213 CGGeneric(condition
), pre
="if (", post
=") {\n", reindent
=True
1216 CGGeneric("} else {\n"),
1217 CGIndenter(ifFalse
),
1223 class CGElseChain(CGThing
):
1225 Concatenate if statements in an if-else-if-else chain.
1228 def __init__(self
, children
):
1229 self
.children
= [c
for c
in children
if c
is not None]
1235 if not self
.children
:
1237 s
= self
.children
[0].define()
1238 assert s
.endswith("\n")
1239 for child
in self
.children
[1:]:
1240 code
= child
.define()
1241 assert code
.startswith("if") or code
.startswith("{")
1242 assert code
.endswith("\n")
1243 s
= s
.rstrip() + " else " + code
1247 class CGTemplatedType(CGWrapper
):
1248 def __init__(self
, templateName
, child
, isConst
=False, isReference
=False):
1249 if isinstance(child
, list):
1250 child
= CGList(child
, ", ")
1251 const
= "const " if isConst
else ""
1252 pre
= "%s%s<" % (const
, templateName
)
1253 ref
= "&" if isReference
else ""
1255 CGWrapper
.__init
__(self
, child
, pre
=pre
, post
=post
)
1258 class CGNamespace(CGWrapper
):
1259 def __init__(self
, namespace
, child
, declareOnly
=False):
1260 pre
= "namespace %s {\n" % namespace
1261 post
= "} // namespace %s\n" % namespace
1262 CGWrapper
.__init
__(self
, child
, pre
=pre
, post
=post
, declareOnly
=declareOnly
)
1265 def build(namespaces
, child
, declareOnly
=False):
1267 Static helper method to build multiple wrapped namespaces.
1270 return CGWrapper(child
, declareOnly
=declareOnly
)
1271 inner
= CGNamespace
.build(namespaces
[1:], child
, declareOnly
=declareOnly
)
1272 return CGNamespace(namespaces
[0], inner
, declareOnly
=declareOnly
)
1275 class CGIncludeGuard(CGWrapper
):
1277 Generates include guards for a header.
1280 def __init__(self
, prefix
, child
):
1281 """|prefix| is the filename without the extension."""
1282 define
= "mozilla_dom_%s_h" % prefix
1286 declarePre
="#ifndef %s\n#define %s\n\n" % (define
, define
),
1287 declarePost
="\n#endif // %s\n" % define
,
1291 class CGHeaders(CGWrapper
):
1293 Generates the appropriate include statements.
1301 callbackDescriptors
,
1307 jsImplementedDescriptors
=[],
1310 Builds a set of includes to cover |descriptors|.
1312 Also includes the files in |declareIncludes| in the header
1313 file and the files in |defineIncludes| in the .cpp.
1315 |prefix| contains the basename of the file that we generate include
1319 # Determine the filenames for which we need headers.
1320 interfaceDeps
= [d
.interface
for d
in descriptors
]
1322 for iface
in interfaceDeps
:
1324 # We're going to need our parent's prototype, to use as the
1325 # prototype of our prototype object.
1326 ancestors
.append(iface
.parent
)
1327 # And if we have an interface object, we'll need the nearest
1328 # ancestor with an interface object too, so we can use its
1329 # interface object as the proto of our interface object.
1330 if iface
.hasInterfaceObject():
1331 parent
= iface
.parent
1332 while parent
and not parent
.hasInterfaceObject():
1333 parent
= parent
.parent
1335 ancestors
.append(parent
)
1336 interfaceDeps
.extend(ancestors
)
1338 # Include parent interface headers needed for default toJSON code.
1339 jsonInterfaceParents
= []
1340 for desc
in descriptors
:
1341 if not desc
.hasDefaultToJSON
:
1343 parent
= desc
.interface
.parent
1345 parentDesc
= desc
.getDescriptor(parent
.identifier
.name
)
1346 if parentDesc
.hasDefaultToJSON
:
1347 jsonInterfaceParents
.append(parentDesc
.interface
)
1348 parent
= parent
.parent
1349 interfaceDeps
.extend(jsonInterfaceParents
)
1351 bindingIncludes
= set(self
.getDeclarationFilename(d
) for d
in interfaceDeps
)
1353 # Grab all the implementation declaration files we need.
1354 implementationIncludes
= set(
1355 d
.headerFile
for d
in descriptors
if d
.needsHeaderInclude()
1358 # Now find all the things we'll need as arguments because we
1359 # need to wrap or unwrap them.
1360 bindingHeaders
= set()
1361 declareIncludes
= set(declareIncludes
)
1363 def addHeadersForType(typeAndPossibleDictionary
):
1365 Add the relevant headers for this type. We use dictionary, if
1366 passed, to decide what to do with interface types.
1368 t
, dictionary
= typeAndPossibleDictionary
1369 # Dictionaries have members that need to be actually
1370 # declared, not just forward-declared.
1372 headerSet
= declareIncludes
1374 headerSet
= bindingHeaders
1375 # Strip off outer layers and add headers they might require. (This
1376 # is conservative: only nullable non-pointer types need Nullable.h;
1377 # only sequences outside unions need ForOfIterator.h; only functions
1378 # that return, and attributes that are, sequences in interfaces need
1382 if idlTypeNeedsCallContext(unrolled
):
1383 bindingHeaders
.add("mozilla/dom/BindingCallContext.h")
1384 if unrolled
.nullable():
1385 headerSet
.add("mozilla/dom/Nullable.h")
1386 elif unrolled
.isSequence():
1387 bindingHeaders
.add("js/Array.h")
1388 bindingHeaders
.add("js/ForOfIterator.h")
1391 unrolled
= unrolled
.inner
1392 if unrolled
.isUnion():
1393 headerSet
.add(self
.getUnionDeclarationFilename(config
, unrolled
))
1394 bindingHeaders
.add("mozilla/dom/UnionConversions.h")
1395 for t
in unrolled
.flatMemberTypes
:
1396 addHeadersForType((t
, None))
1397 elif unrolled
.isPromise():
1398 # See comment in the isInterface() case for why we add
1399 # Promise.h to headerSet, not bindingHeaders.
1400 headerSet
.add("mozilla/dom/Promise.h")
1401 # We need ToJSValue to do the Promise to JS conversion.
1402 bindingHeaders
.add("mozilla/dom/ToJSValue.h")
1403 elif unrolled
.isInterface():
1404 if unrolled
.isSpiderMonkeyInterface():
1405 bindingHeaders
.add("jsfriendapi.h")
1406 if jsImplementedDescriptors
:
1407 # Since we can't forward-declare typed array types
1408 # (because they're typedefs), we have to go ahead and
1409 # just include their header if we need to have functions
1410 # taking references to them declared in that header.
1411 headerSet
= declareIncludes
1412 if unrolled
.isReadableStream():
1413 headerSet
.add("mozilla/dom/ReadableStream.h")
1415 headerSet
.add("mozilla/dom/TypedArray.h")
1418 typeDesc
= config
.getDescriptor(unrolled
.inner
.identifier
.name
)
1419 except NoSuchDescriptorError
:
1421 # Dictionaries with interface members rely on the
1422 # actual class definition of that interface member
1423 # being visible in the binding header, because they
1424 # store them in RefPtr and have inline
1425 # constructors/destructors.
1427 # XXXbz maybe dictionaries with interface members
1428 # should just have out-of-line constructors and
1430 headerSet
.add(typeDesc
.headerFile
)
1431 elif unrolled
.isDictionary():
1432 headerSet
.add(self
.getDeclarationFilename(unrolled
.inner
))
1433 # And if it needs rooting, we need RootedDictionary too
1434 if typeNeedsRooting(unrolled
):
1435 headerSet
.add("mozilla/dom/RootedDictionary.h")
1436 elif unrolled
.isCallback():
1437 headerSet
.add(self
.getDeclarationFilename(unrolled
.callback
))
1438 elif unrolled
.isFloat() and not unrolled
.isUnrestricted():
1439 # Restricted floats are tested for finiteness
1440 bindingHeaders
.add("mozilla/FloatingPoint.h")
1441 bindingHeaders
.add("mozilla/dom/PrimitiveConversions.h")
1442 elif unrolled
.isEnum():
1443 filename
= self
.getDeclarationFilename(unrolled
.inner
)
1444 declareIncludes
.add(filename
)
1445 elif unrolled
.isPrimitive():
1446 bindingHeaders
.add("mozilla/dom/PrimitiveConversions.h")
1447 elif unrolled
.isRecord():
1448 if dictionary
or jsImplementedDescriptors
:
1449 declareIncludes
.add("mozilla/dom/Record.h")
1451 bindingHeaders
.add("mozilla/dom/Record.h")
1452 # Also add headers for the type the record is
1453 # parametrized over, if needed.
1454 addHeadersForType((t
.inner
, dictionary
))
1456 for t
in getAllTypes(
1457 descriptors
+ callbackDescriptors
, dictionaries
, callbacks
1459 addHeadersForType(t
)
1461 def addHeaderForFunc(func
, desc
):
1464 # Include the right class header, which we can only do
1465 # if this is a class member function.
1466 if desc
is not None and not desc
.headerIsDefault
:
1467 # An explicit header file was provided, assume that we know
1472 # Strip out the function name and convert "::" to "/"
1473 bindingHeaders
.add("/".join(func
.split("::")[:-1]) + ".h")
1475 # Now for non-callback descriptors make sure we include any
1476 # headers needed by Func declarations and other things like that.
1477 for desc
in descriptors
:
1478 # If this is an iterator interface generated for a separate
1479 # iterable interface, skip generating type includes, as we have
1480 # what we need in IterableIterator.h
1481 if desc
.interface
.isIteratorInterface():
1484 for m
in desc
.interface
.members
:
1485 addHeaderForFunc(PropertyDefiner
.getStringAttr(m
, "Func"), desc
)
1486 staticTypeOverride
= PropertyDefiner
.getStringAttr(
1487 m
, "StaticClassOverride"
1489 if staticTypeOverride
:
1490 bindingHeaders
.add("/".join(staticTypeOverride
.split("::")) + ".h")
1491 # getExtendedAttribute() returns a list, extract the entry.
1492 funcList
= desc
.interface
.getExtendedAttribute("Func")
1493 if funcList
is not None:
1494 addHeaderForFunc(funcList
[0], desc
)
1496 if desc
.interface
.maplikeOrSetlikeOrIterable
:
1497 # We need ToJSValue.h for maplike/setlike type conversions
1498 bindingHeaders
.add("mozilla/dom/ToJSValue.h")
1499 # Add headers for the key and value types of the
1500 # maplike/setlike/iterable, since they'll be needed for
1501 # convenience functions
1502 if desc
.interface
.maplikeOrSetlikeOrIterable
.hasKeyType():
1504 (desc
.interface
.maplikeOrSetlikeOrIterable
.keyType
, None)
1506 if desc
.interface
.maplikeOrSetlikeOrIterable
.hasValueType():
1508 (desc
.interface
.maplikeOrSetlikeOrIterable
.valueType
, None)
1511 for d
in dictionaries
:
1513 declareIncludes
.add(self
.getDeclarationFilename(d
.parent
))
1514 bindingHeaders
.add(self
.getDeclarationFilename(d
))
1516 addHeaderForFunc(PropertyDefiner
.getStringAttr(m
, "Func"), None)
1517 # No need to worry about Func on members of ancestors, because that
1518 # will happen automatically in whatever files those ancestors live
1522 bindingHeaders
.add(self
.getDeclarationFilename(c
))
1524 for c
in callbackDescriptors
:
1525 bindingHeaders
.add(self
.getDeclarationFilename(c
.interface
))
1527 if len(callbacks
) != 0:
1528 # We need CallbackFunction to serve as our parent class
1529 declareIncludes
.add("mozilla/dom/CallbackFunction.h")
1530 # And we need ToJSValue.h so we can wrap "this" objects
1531 declareIncludes
.add("mozilla/dom/ToJSValue.h")
1533 if len(callbackDescriptors
) != 0 or len(jsImplementedDescriptors
) != 0:
1534 # We need CallbackInterface to serve as our parent class
1535 declareIncludes
.add("mozilla/dom/CallbackInterface.h")
1536 # And we need ToJSValue.h so we can wrap "this" objects
1537 declareIncludes
.add("mozilla/dom/ToJSValue.h")
1539 # Also need to include the headers for ancestors of
1540 # JS-implemented interfaces.
1541 for jsImplemented
in jsImplementedDescriptors
:
1542 jsParent
= jsImplemented
.interface
.parent
1544 parentDesc
= jsImplemented
.getDescriptor(jsParent
.identifier
.name
)
1545 declareIncludes
.add(parentDesc
.jsImplParentHeader
)
1547 # Now make sure we're not trying to include the header from inside itself
1548 declareIncludes
.discard(prefix
+ ".h")
1550 # Let the machinery do its thing.
1551 def _includeString(includes
):
1552 def headerName(include
):
1553 # System headers are specified inside angle brackets.
1554 if include
.startswith("<"):
1556 # Non-system headers need to be placed in quotes.
1557 return '"%s"' % include
1559 return "".join(["#include %s\n" % headerName(i
) for i
in includes
]) + "\n"
1564 declarePre
=_includeString(sorted(declareIncludes
)),
1565 definePre
=_includeString(
1570 | implementationIncludes
1576 def getDeclarationFilename(decl
):
1577 # Use our local version of the header, not the exported one, so that
1578 # test bindings, which don't export, will work correctly.
1579 basename
= os
.path
.basename(decl
.filename())
1580 return basename
.replace(".webidl", "Binding.h")
1583 def getUnionDeclarationFilename(config
, unionType
):
1584 assert unionType
.isUnion()
1585 assert unionType
.unroll() == unionType
1586 # If a union is "defined" in multiple files, it goes in UnionTypes.h.
1587 if len(config
.filenamesPerUnion
[unionType
.name
]) > 1:
1588 return "mozilla/dom/UnionTypes.h"
1589 # If a union is defined by a built-in typedef, it also goes in
1591 assert len(config
.filenamesPerUnion
[unionType
.name
]) == 1
1592 if "<unknown>" in config
.filenamesPerUnion
[unionType
.name
]:
1593 return "mozilla/dom/UnionTypes.h"
1594 return CGHeaders
.getDeclarationFilename(unionType
)
1597 def SortedDictValues(d
):
1599 Returns a list of values from the dict sorted by key.
1601 return [v
for k
, v
in sorted(d
.items())]
1604 def UnionsForFile(config
, webIDLFile
):
1606 Returns a list of union types for all union types that are only used in
1607 webIDLFile. If webIDLFile is None this will return the list of tuples for
1608 union types that are used in more than one WebIDL file.
1610 return config
.unionsPerFilename
.get(webIDLFile
, [])
1613 def UnionTypes(unionTypes
, config
):
1615 The unionTypes argument should be a list of union types. This is typically
1616 the list generated by UnionsForFile.
1618 Returns a tuple containing a set of header filenames to include in
1619 the header for the types in unionTypes, a set of header filenames to
1620 include in the implementation file for the types in unionTypes, a set
1621 of tuples containing a type declaration and a boolean if the type is a
1622 struct for member types of the union, a list of traverse methods,
1623 unlink methods and a list of union types. These last three lists only
1624 contain unique union types.
1629 declarations
= set()
1630 unionStructs
= dict()
1631 traverseMethods
= dict()
1632 unlinkMethods
= dict()
1634 for t
in unionTypes
:
1636 if name
not in unionStructs
:
1637 unionStructs
[name
] = t
1639 def addHeadersForType(f
):
1641 headers
.add("mozilla/dom/Nullable.h")
1642 isSequence
= f
.isSequence()
1644 # Dealing with sequences requires for-of-compatible
1646 implheaders
.add("js/ForOfIterator.h")
1647 # Sequences can always throw "not an object" exceptions.
1648 implheaders
.add("mozilla/dom/BindingCallContext.h")
1650 if idlTypeNeedsCallContext(f
):
1651 implheaders
.add("mozilla/dom/BindingCallContext.h")
1653 headers
.add("mozilla/dom/Promise.h")
1654 # We need ToJSValue to do the Promise to JS conversion.
1655 headers
.add("mozilla/dom/ToJSValue.h")
1656 elif f
.isInterface():
1657 if f
.isSpiderMonkeyInterface():
1658 headers
.add("js/RootingAPI.h")
1659 headers
.add("js/Value.h")
1660 if f
.isReadableStream():
1661 headers
.add("mozilla/dom/ReadableStream.h")
1663 headers
.add("mozilla/dom/TypedArray.h")
1666 typeDesc
= config
.getDescriptor(f
.inner
.identifier
.name
)
1667 except NoSuchDescriptorError
:
1669 if typeDesc
.interface
.isCallback() or isSequence
:
1670 # Callback interfaces always use strong refs, so
1671 # we need to include the right header to be able
1672 # to Release() in our inlined code.
1674 # Similarly, sequences always contain strong
1675 # refs, so we'll need the header to handler
1677 headers
.add(typeDesc
.headerFile
)
1678 elif typeDesc
.interface
.identifier
.name
== "WindowProxy":
1679 # In UnionTypes.h we need to see the declaration of the
1680 # WindowProxyHolder that we use to store the WindowProxy, so
1681 # we have its sizeof and know how big to make our union.
1682 headers
.add(typeDesc
.headerFile
)
1684 declarations
.add((typeDesc
.nativeType
, False))
1685 implheaders
.add(typeDesc
.headerFile
)
1686 elif f
.isDictionary():
1687 # For a dictionary, we need to see its declaration in
1688 # UnionTypes.h so we have its sizeof and know how big to
1690 headers
.add(CGHeaders
.getDeclarationFilename(f
.inner
))
1691 # And if it needs rooting, we need RootedDictionary too
1692 if typeNeedsRooting(f
):
1693 headers
.add("mozilla/dom/RootedDictionary.h")
1694 elif f
.isFloat() and not f
.isUnrestricted():
1695 # Restricted floats are tested for finiteness
1696 implheaders
.add("mozilla/FloatingPoint.h")
1697 implheaders
.add("mozilla/dom/PrimitiveConversions.h")
1699 # Need to see the actual definition of the enum,
1701 headers
.add(CGHeaders
.getDeclarationFilename(f
.inner
))
1702 elif f
.isPrimitive():
1703 implheaders
.add("mozilla/dom/PrimitiveConversions.h")
1704 elif f
.isCallback():
1705 # Callbacks always use strong refs, so we need to include
1706 # the right header to be able to Release() in our inlined
1708 headers
.add(CGHeaders
.getDeclarationFilename(f
.callback
))
1710 headers
.add("mozilla/dom/Record.h")
1711 # And add headers for the type we're parametrized over
1712 addHeadersForType(f
.inner
)
1714 implheaders
.add(CGHeaders
.getUnionDeclarationFilename(config
, t
))
1715 for f
in t
.flatMemberTypes
:
1716 assert not f
.nullable()
1717 addHeadersForType(f
)
1719 if idlTypeNeedsCycleCollection(t
):
1721 ("mozilla::dom::%s" % CGUnionStruct
.unionTypeName(t
, True), False)
1723 traverseMethods
[name
] = CGCycleCollectionTraverseForOwningUnionMethod(t
)
1724 unlinkMethods
[name
] = CGCycleCollectionUnlinkForOwningUnionMethod(t
)
1726 # The order of items in CGList is important.
1727 # Since the union structs friend the unlinkMethods, the forward-declaration
1728 # for these methods should come before the class declaration. Otherwise
1729 # some compilers treat the friend declaration as a forward-declaration in
1735 SortedDictValues(traverseMethods
),
1736 SortedDictValues(unlinkMethods
),
1737 SortedDictValues(unionStructs
),
1741 def UnionConversions(unionTypes
, config
):
1743 The unionTypes argument should be a list of tuples, each containing two
1744 elements: a union type and a descriptor. This is typically the list
1745 generated by UnionsForFile.
1747 Returns a tuple containing a list of headers and a CGThing to declare all
1748 union argument conversion helper structs.
1751 unionConversions
= dict()
1753 for t
in unionTypes
:
1755 if name
not in unionConversions
:
1756 unionConversions
[name
] = CGUnionConversionStruct(t
, config
)
1758 def addHeadersForType(f
):
1760 # Sequences require JSAPI C++ for-of iteration code to fill
1762 headers
.add("js/ForOfIterator.h")
1763 # Sequences can always throw "not an object" exceptions.
1764 headers
.add("mozilla/dom/BindingCallContext.h")
1766 if idlTypeNeedsCallContext(f
):
1767 headers
.add("mozilla/dom/BindingCallContext.h")
1769 headers
.add("mozilla/dom/Promise.h")
1770 # We need ToJSValue to do the Promise to JS conversion.
1771 headers
.add("mozilla/dom/ToJSValue.h")
1772 elif f
.isInterface():
1773 if f
.isSpiderMonkeyInterface():
1774 headers
.add("js/RootingAPI.h")
1775 if f
.isReadableStream():
1776 headers
.add("mozilla/dom/ReadableStream.h")
1778 headers
.add("mozilla/dom/TypedArray.h")
1779 elif f
.inner
.isExternal():
1781 typeDesc
= config
.getDescriptor(f
.inner
.identifier
.name
)
1782 except NoSuchDescriptorError
:
1784 headers
.add(typeDesc
.headerFile
)
1786 headers
.add(CGHeaders
.getDeclarationFilename(f
.inner
))
1787 elif f
.isDictionary():
1788 headers
.add(CGHeaders
.getDeclarationFilename(f
.inner
))
1789 elif f
.isFloat() and not f
.isUnrestricted():
1790 # Restricted floats are tested for finiteness
1791 headers
.add("mozilla/FloatingPoint.h")
1792 headers
.add("mozilla/dom/PrimitiveConversions.h")
1793 elif f
.isPrimitive():
1794 headers
.add("mozilla/dom/PrimitiveConversions.h")
1796 headers
.add("mozilla/dom/Record.h")
1797 # And the internal type of the record
1798 addHeadersForType(f
.inner
)
1800 # We plan to include UnionTypes.h no matter what, so it's
1801 # OK if we throw it into the set here.
1802 headers
.add(CGHeaders
.getUnionDeclarationFilename(config
, t
))
1804 for f
in t
.flatMemberTypes
:
1805 addHeadersForType(f
)
1809 CGWrapper(CGList(SortedDictValues(unionConversions
), "\n"), post
="\n\n"),
1815 A class for outputting the type and name of an argument
1818 def __init__(self
, argType
, name
, default
=None):
1819 self
.argType
= argType
1821 self
.default
= default
1824 string
= self
.argType
+ " " + self
.name
1825 if self
.default
is not None:
1826 string
+= " = " + self
.default
1830 return self
.argType
+ " " + self
.name
1833 class CGAbstractMethod(CGThing
):
1835 An abstract class for generating code for a method. Subclasses
1836 should override definition_body to create the actual code.
1838 descriptor is the descriptor for the interface the method is associated with
1840 name is the name of the method as a string
1842 returnType is the IDLType of the return value
1844 args is a list of Argument objects
1846 inline should be True to generate an inline method, whose body is
1847 part of the declaration.
1849 alwaysInline should be True to generate an inline method annotated with
1852 static should be True to generate a static method, which only has
1855 If templateArgs is not None it should be a list of strings containing
1856 template arguments, and the function will be templatized using those
1859 canRunScript should be True to generate a MOZ_CAN_RUN_SCRIPT annotation.
1874 CGThing
.__init
__(self
)
1875 self
.descriptor
= descriptor
1877 self
.returnType
= returnType
1879 self
.inline
= inline
1880 self
.alwaysInline
= alwaysInline
1881 self
.static
= static
1882 self
.templateArgs
= templateArgs
1883 self
.canRunScript
= canRunScript
1885 def _argstring(self
, declare
):
1886 return ", ".join([a
.declare() if declare
else a
.define() for a
in self
.args
])
1888 def _template(self
):
1889 if self
.templateArgs
is None:
1891 return "template <%s>\n" % ", ".join(self
.templateArgs
)
1893 def _decorators(self
):
1895 if self
.canRunScript
:
1896 decorators
.append("MOZ_CAN_RUN_SCRIPT")
1897 if self
.alwaysInline
:
1898 decorators
.append("MOZ_ALWAYS_INLINE")
1900 decorators
.append("inline")
1902 decorators
.append("static")
1903 decorators
.append(self
.returnType
)
1904 maybeNewline
= " " if self
.inline
else "\n"
1905 return " ".join(decorators
) + maybeNewline
1909 return self
._define
(True)
1910 return "%s%s%s(%s);\n" % (
1914 self
._argstring
(True),
1917 def indent_body(self
, body
):
1919 Indent the code returned by self.definition_body(). Most classes
1920 simply indent everything two spaces. This is here for
1921 CGRegisterProtos, which needs custom indentation.
1925 def _define(self
, fromDeclare
=False):
1927 self
.definition_prologue(fromDeclare
)
1928 + self
.indent_body(self
.definition_body())
1929 + self
.definition_epilogue()
1933 return "" if self
.inline
else self
._define
()
1935 def definition_prologue(self
, fromDeclare
):
1936 error_reporting_label
= self
.error_reporting_label()
1937 if error_reporting_label
:
1938 # We're going to want a BindingCallContext. Rename our JSContext*
1941 while i
< len(self
.args
):
1943 if arg
.argType
== "JSContext*":
1945 self
.args
[i
] = Argument(arg
.argType
, "cx_", arg
.default
)
1948 if i
== len(self
.args
):
1949 raise TypeError("Must have a JSContext* to create a BindingCallContext")
1951 prologue
= "%s%s%s(%s)\n{\n" % (
1955 self
._argstring
(fromDeclare
),
1957 if error_reporting_label
:
1961 BindingCallContext ${cxname}(cx_, "${label}");
1964 label
=error_reporting_label
,
1968 profiler_label
= self
.auto_profiler_label()
1970 prologue
+= indent(profiler_label
) + "\n"
1974 def definition_epilogue(self
):
1977 def definition_body(self
):
1978 assert False # Override me!
1981 Override this method to return a pair of (descriptive string, name of a
1982 JSContext* variable) in order to generate a profiler label for this method.
1985 def auto_profiler_label(self
):
1986 return None # Override me!
1989 Override this method to return a string to be used as the label for a
1990 BindingCallContext. If this does not return None, one of the arguments of
1991 this method must be of type 'JSContext*'. Its name will be replaced with
1992 'cx_' and a BindingCallContext named 'cx' will be instantiated with the
1996 def error_reporting_label(self
):
1997 return None # Override me!
2000 class CGAbstractStaticMethod(CGAbstractMethod
):
2002 Abstract base class for codegen of implementation-only (no
2003 declaration) static methods.
2006 def __init__(self
, descriptor
, name
, returnType
, args
, canRunScript
=False):
2007 CGAbstractMethod
.__init
__(
2015 canRunScript
=canRunScript
,
2019 # We only have implementation
2023 class CGAbstractClassHook(CGAbstractStaticMethod
):
2025 Meant for implementing JSClass hooks, like Finalize or Trace. Does very raw
2026 'this' unwrapping as it assumes that the unwrapped type is always known.
2029 def __init__(self
, descriptor
, name
, returnType
, args
):
2030 CGAbstractStaticMethod
.__init
__(self
, descriptor
, name
, returnType
, args
)
2032 def definition_body_prologue(self
):
2033 return "%s* self = UnwrapPossiblyNotInitializedDOMObject<%s>(obj);\n" % (
2034 self
.descriptor
.nativeType
,
2035 self
.descriptor
.nativeType
,
2038 def definition_body(self
):
2039 return self
.definition_body_prologue() + self
.generate_code()
2041 def generate_code(self
):
2042 assert False # Override me!
2045 class CGGetJSClassMethod(CGAbstractMethod
):
2046 def __init__(self
, descriptor
):
2047 CGAbstractMethod
.__init
__(self
, descriptor
, "GetJSClass", "const JSClass*", [])
2049 def definition_body(self
):
2050 return "return sClass.ToJSClass();\n"
2053 class CGAddPropertyHook(CGAbstractClassHook
):
2055 A hook for addProperty, used to preserve our wrapper from GC.
2058 def __init__(self
, descriptor
):
2060 Argument("JSContext*", "cx"),
2061 Argument("JS::Handle<JSObject*>", "obj"),
2062 Argument("JS::Handle<jsid>", "id"),
2063 Argument("JS::Handle<JS::Value>", "val"),
2065 CGAbstractClassHook
.__init
__(
2066 self
, descriptor
, ADDPROPERTY_HOOK_NAME
, "bool", args
2069 def generate_code(self
):
2070 assert self
.descriptor
.wrapperCache
2071 # This hook is also called by TryPreserveWrapper on non-nsISupports
2072 # cycle collected objects, so if addProperty is ever changed to do
2073 # anything more or less than preserve the wrapper, TryPreserveWrapper
2074 # will need to be changed.
2077 // We don't want to preserve if we don't have a wrapper, and we
2078 // obviously can't preserve if we're not initialized.
2079 if (self && self->GetWrapperPreserveColor()) {
2080 PreserveWrapper(self);
2087 class CGGetWrapperCacheHook(CGAbstractClassHook
):
2089 A hook for GetWrapperCache, used by HasReleasedWrapper to get the
2090 nsWrapperCache pointer for a non-nsISupports object.
2093 def __init__(self
, descriptor
):
2094 args
= [Argument("JS::Handle<JSObject*>", "obj")]
2095 CGAbstractClassHook
.__init
__(
2096 self
, descriptor
, GETWRAPPERCACHE_HOOK_NAME
, "nsWrapperCache*", args
2099 def generate_code(self
):
2100 assert self
.descriptor
.wrapperCache
2108 def finalizeHook(descriptor
, hookName
, freeOp
, obj
):
2109 finalize
= "JS::SetReservedSlot(%s, DOM_OBJECT_SLOT, JS::UndefinedValue());\n" % obj
2110 if descriptor
.interface
.getExtendedAttribute("LegacyOverrideBuiltIns"):
2113 // Either our proxy created an expando object or not. If it did,
2114 // then we would have preserved ourselves, and hence if we're going
2115 // away so is our C++ object and we should reset its expando value.
2116 // It's possible that in this situation the C++ object's reflector
2117 // pointer has been nulled out, but if not it's pointing to us. If
2118 // our proxy did _not_ create an expando object then it's possible
2119 // that we're no longer the reflector for our C++ object (and
2120 // incremental finalization is finally getting to us), and that in
2121 // the meantime the new reflector has created an expando object.
2122 // In that case we do NOT want to clear the expando pointer in the
2125 // It's important to do this before we ClearWrapper, of course.
2126 JSObject* reflector = self->GetWrapperMaybeDead();
2127 if (!reflector || reflector == ${obj}) {
2128 self->mExpandoAndGeneration.expando = JS::UndefinedValue();
2133 if descriptor
.wrapperCache
:
2134 finalize
+= "ClearWrapper(self, self, %s);\n" % obj
2135 if descriptor
.isGlobal():
2136 finalize
+= "mozilla::dom::FinalizeGlobal(%s, %s);\n" % (freeOp
, 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("JSFreeOp*", "fop"), 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
))
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 namedConstructors
= ""
2337 for n
in self
.descriptor
.interface
.legacyFactoryFunctions
:
2338 namedConstructors
+= (
2339 '{ "%s", { %s, &sLegacyFactoryFunctionNativePropertyHooks }, %i },\n'
2340 % (n
.identifier
.name
, LegacyFactoryFunctionName(n
), methodLength(n
))
2345 const NativePropertyHooks sLegacyFactoryFunctionNativePropertyHooks = {
2349 { nullptr, nullptr },
2350 prototypes::id::${name},
2355 static const LegacyFactoryFunction namedConstructors[] = {
2356 $*{namedConstructors}
2357 { nullptr, { nullptr, nullptr }, 0 }
2360 name
=self
.descriptor
.name
,
2361 constructorID
=constructorID
,
2362 namedConstructors
=namedConstructors
,
2366 def isChromeOnly(m
):
2367 return m
.getExtendedAttribute("ChromeOnly")
2370 def prefIdentifier(pref
):
2371 return pref
.replace(".", "_").replace("-", "_")
2374 def prefHeader(pref
):
2375 return "mozilla/StaticPrefs_%s.h" % pref
.partition(".")[0]
2378 class MemberCondition
:
2380 An object representing the condition for a member to actually be
2381 exposed. Any of the arguments can be None. If not
2382 None, they should have the following types:
2384 pref: The name of the preference.
2385 func: The name of the function.
2386 secureContext: A bool indicating whether a secure context is required.
2387 nonExposedGlobals: A set of names of globals. Can be empty, in which case
2388 it's treated the same way as None.
2392 self
, pref
=None, func
=None, secureContext
=False, nonExposedGlobals
=None
2394 assert pref
is None or isinstance(pref
, str)
2395 assert func
is None or isinstance(func
, str)
2396 assert isinstance(secureContext
, bool)
2397 assert nonExposedGlobals
is None or isinstance(nonExposedGlobals
, set)
2400 identifier
= prefIdentifier(self
.pref
)
2401 self
.prefFuncIndex
= "WebIDLPrefIndex::" + identifier
2403 self
.prefFuncIndex
= "WebIDLPrefIndex::NoPref"
2405 self
.secureContext
= secureContext
2412 self
.func
= toFuncPtr(func
)
2414 if nonExposedGlobals
:
2416 self
.nonExposedGlobals
= " | ".join(
2417 map(lambda g
: "GlobalNames::%s" % g
, sorted(nonExposedGlobals
))
2420 self
.nonExposedGlobals
= "0"
2422 def __eq__(self
, other
):
2424 self
.pref
== other
.pref
2425 and self
.func
== other
.func
2426 and self
.secureContext
== other
.secureContext
2427 and self
.nonExposedGlobals
== other
.nonExposedGlobals
2430 def __ne__(self
, other
):
2431 return not self
.__eq
__(other
)
2433 def hasDisablers(self
):
2435 self
.pref
is not None
2436 or self
.secureContext
2437 or self
.func
!= "nullptr"
2438 or self
.nonExposedGlobals
!= "0"
2442 class PropertyDefiner
:
2444 A common superclass for defining things on prototype objects.
2446 Subclasses should implement generateArray to generate the actual arrays of
2447 things we're defining. They should also set self.chrome to the list of
2448 things only exposed to chrome and self.regular to the list of things exposed
2449 to both chrome and web pages.
2452 def __init__(self
, descriptor
, name
):
2453 self
.descriptor
= descriptor
2456 def hasChromeOnly(self
):
2457 return len(self
.chrome
) > 0
2459 def hasNonChromeOnly(self
):
2460 return len(self
.regular
) > 0
2462 def variableName(self
, chrome
):
2464 if self
.hasChromeOnly():
2465 return "sChrome" + self
.name
2467 if self
.hasNonChromeOnly():
2468 return "s" + self
.name
2471 def usedForXrays(self
):
2472 return self
.descriptor
.wantsXrays
2474 def length(self
, chrome
):
2475 return len(self
.chrome
) if chrome
else len(self
.regular
)
2478 # We only need to generate id arrays for things that will end
2479 # up used via ResolveProperty or EnumerateProperties.
2480 str = self
.generateArray(self
.regular
, self
.variableName(False))
2481 if self
.hasChromeOnly():
2482 str += self
.generateArray(self
.chrome
, self
.variableName(True))
2486 def getStringAttr(member
, name
):
2487 attr
= member
.getExtendedAttribute(name
)
2490 # It's a list of strings
2491 assert len(attr
) == 1
2492 assert attr
[0] is not None
2496 def getControllingCondition(interfaceMember
, descriptor
):
2497 interface
= descriptor
.interface
2498 nonExposureSet
= interface
.exposureSet
- interfaceMember
.exposureSet
2500 return MemberCondition(
2501 PropertyDefiner
.getStringAttr(interfaceMember
, "Pref"),
2502 PropertyDefiner
.getStringAttr(interfaceMember
, "Func"),
2503 interfaceMember
.getExtendedAttribute("SecureContext") is not None,
2508 def generatePrefableArrayValues(
2515 switchToCondition
=None,
2518 This method generates an array of spec entries for interface members. It returns
2519 a tuple containing the array of spec entries and the maximum of the number of
2520 spec entries per condition.
2522 array is an array of interface members.
2524 descriptor is the descriptor for the interface that array contains members of.
2526 specFormatter is a function that takes a single argument, a tuple,
2527 and returns a string, a spec array entry.
2529 specTerminator is a terminator for the spec array (inserted every time
2530 our controlling pref changes and at the end of the array).
2532 getCondition is a callback function that takes an array entry and
2533 returns the corresponding MemberCondition.
2535 getDataTuple is a callback function that takes an array entry and
2536 returns a tuple suitable to be passed to specFormatter.
2538 switchToCondition is a function that takes a MemberCondition and an array of
2539 previously generated spec entries. If None is passed for this function then all
2540 the interface members should return the same value from getCondition.
2543 def unsupportedSwitchToCondition(condition
, specs
):
2544 # If no specs have been added yet then this is just the first call to
2545 # switchToCondition that we call to avoid putting a specTerminator at the
2546 # front of the list.
2549 raise "Not supported"
2551 if switchToCondition
is None:
2552 switchToCondition
= unsupportedSwitchToCondition
2555 numSpecsInCurPrefable
= 0
2556 maxNumSpecsInPrefable
= 0
2558 # So we won't put a specTerminator at the very front of the list:
2559 lastCondition
= getCondition(array
[0], descriptor
)
2561 switchToCondition(lastCondition
, specs
)
2563 for member
in array
:
2564 curCondition
= getCondition(member
, descriptor
)
2565 if lastCondition
!= curCondition
:
2566 # Terminate previous list
2567 specs
.append(specTerminator
)
2568 if numSpecsInCurPrefable
> maxNumSpecsInPrefable
:
2569 maxNumSpecsInPrefable
= numSpecsInCurPrefable
2570 numSpecsInCurPrefable
= 0
2571 # And switch to our new condition
2572 switchToCondition(curCondition
, specs
)
2573 lastCondition
= curCondition
2574 # And the actual spec
2575 specs
.append(specFormatter(getDataTuple(member
, descriptor
)))
2576 numSpecsInCurPrefable
+= 1
2577 if numSpecsInCurPrefable
> maxNumSpecsInPrefable
:
2578 maxNumSpecsInPrefable
= numSpecsInCurPrefable
2579 specs
.append(specTerminator
)
2581 return (specs
, maxNumSpecsInPrefable
)
2583 def generatePrefableArray(
2594 This method generates our various arrays.
2596 array is an array of interface members as passed to generateArray
2598 name is the name as passed to generateArray
2600 specFormatter is a function that takes a single argument, a tuple,
2601 and returns a string, a spec array entry
2603 specTerminator is a terminator for the spec array (inserted every time
2604 our controlling pref changes and at the end of the array)
2606 specType is the actual typename of our spec
2608 getCondition is a callback function that takes an array entry and
2609 returns the corresponding MemberCondition.
2611 getDataTuple is a callback function that takes an array entry and
2612 returns a tuple suitable to be passed to specFormatter.
2615 # We want to generate a single list of specs, but with specTerminator
2616 # inserted at every point where the pref name controlling the member
2617 # changes. That will make sure the order of the properties as exposed
2618 # on the interface and interface prototype objects does not change when
2619 # pref control is added to members while still allowing us to define all
2620 # the members in the smallest number of JSAPI calls.
2621 assert len(array
) != 0
2626 disablersTemplate
= dedent(
2628 static const PrefableDisablers %s_disablers%d = {
2633 prefableWithDisablersTemplate
= " { &%s_disablers%d, &%s_specs[%d] }"
2634 prefableWithoutDisablersTemplate
= " { nullptr, &%s_specs[%d] }"
2635 prefCacheTemplate
= "&%s[%d].disablers->enabled"
2637 def switchToCondition(condition
, specs
):
2638 # Set up pointers to the new sets of specs inside prefableSpecs
2639 if condition
.hasDisablers():
2640 prefableSpecs
.append(
2641 prefableWithDisablersTemplate
% (name
, len(specs
), name
, len(specs
))
2648 condition
.prefFuncIndex
,
2649 toStringBool(condition
.secureContext
),
2650 condition
.nonExposedGlobals
,
2655 prefableSpecs
.append(
2656 prefableWithoutDisablersTemplate
% (name
, len(specs
))
2659 specs
, maxNumSpecsInPrefable
= self
.generatePrefableArrayValues(
2668 prefableSpecs
.append(" { nullptr, nullptr }")
2670 specType
= "const " + specType
2673 // We deliberately use brace-elision to make Visual Studio produce better initalization code.
2674 static ${specType} ${name}_specs[] = {
2679 static const Prefable<${specType}> ${name}[] = {
2686 disablers
="\n".join(disablers
),
2687 specs
=",\n".join(specs
),
2688 prefableSpecs
=",\n".join(prefableSpecs
),
2691 if self
.usedForXrays():
2695 static_assert(${numPrefableSpecs} <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX,
2696 "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)");
2697 static_assert(${maxNumSpecsInPrefable} <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX,
2698 "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)");
2702 # Minus 1 because there's a list terminator in prefableSpecs.
2703 numPrefableSpecs
=len(prefableSpecs
) - 1,
2704 maxNumSpecsInPrefable
=maxNumSpecsInPrefable
,
2710 # The length of a method is the minimum of the lengths of the
2711 # argument lists of all its overloads.
2712 def overloadLength(arguments
):
2714 while i
> 0 and arguments
[i
- 1].optional
:
2719 def methodLength(method
):
2720 signatures
= method
.signatures()
2721 return min(overloadLength(arguments
) for retType
, arguments
in signatures
)
2724 def clearableCachedAttrs(descriptor
):
2727 for m
in descriptor
.interface
.members
2729 # Constants should never need clearing!
2730 m
.dependsOn
!= "Nothing" and m
.slotIndices
is not None
2734 def MakeClearCachedValueNativeName(member
):
2735 return "ClearCached%sValue" % MakeNativeName(member
.identifier
.name
)
2738 def IDLToCIdentifier(name
):
2739 return name
.replace("-", "_")
2742 def EnumerabilityFlags(member
):
2743 if member
.getExtendedAttribute("NonEnumerable"):
2745 return "JSPROP_ENUMERATE"
2748 class MethodDefiner(PropertyDefiner
):
2750 A class for defining methods on a prototype object.
2753 def __init__(self
, descriptor
, name
, crossOriginOnly
, static
, unforgeable
=False):
2754 assert not (static
and unforgeable
)
2755 PropertyDefiner
.__init
__(self
, descriptor
, name
)
2757 # FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=772822
2758 # We should be able to check for special operations without an
2759 # identifier. For now we check if the name starts with __
2761 # Ignore non-static methods for interfaces without a proto object
2762 if descriptor
.interface
.hasInterfacePrototypeObject() or static
:
2765 for m
in descriptor
.interface
.members
2767 and m
.isStatic() == static
2768 and MemberIsLegacyUnforgeable(m
, descriptor
) == unforgeable
2770 not crossOriginOnly
or m
.getExtendedAttribute("CrossOriginCallable")
2772 and not m
.isIdentifierLess()
2773 and not m
.getExtendedAttribute("Unexposed")
2780 method
= self
.methodData(m
, descriptor
)
2783 method
["nativeName"] = CppKeywords
.checkMethodName(
2784 IDLToCIdentifier(m
.identifier
.name
)
2788 self
.chrome
.append(method
)
2790 self
.regular
.append(method
)
2792 # TODO: Once iterable is implemented, use tiebreak rules instead of
2793 # failing. Also, may be more tiebreak rules to implement once spec bug
2795 # https://www.w3.org/Bugs/Public/show_bug.cgi?id=28592
2796 def hasIterator(methods
, regular
):
2797 return any("@@iterator" in m
.aliases
for m
in methods
) or any(
2798 "@@iterator" == r
["name"] for r
in regular
2801 # Check whether we need to output an @@iterator due to having an indexed
2802 # getter. We only do this while outputting non-static and
2803 # non-unforgeable methods, since the @@iterator function will be
2805 if not static
and not unforgeable
and descriptor
.supportsIndexedProperties():
2806 if hasIterator(methods
, self
.regular
):
2808 "Cannot have indexed getter/attr on "
2809 "interface %s with other members "
2810 "that generate @@iterator, such as "
2811 "maplike/setlike or aliased functions."
2812 % self
.descriptor
.interface
.identifier
.name
2814 self
.regular
.append(
2816 "name": "@@iterator",
2817 "methodInfo": False,
2818 "selfHostedName": "$ArrayValues",
2820 "flags": "0", # Not enumerable, per spec.
2821 "condition": MemberCondition(),
2825 # Generate the keys/values/entries aliases for value iterables.
2826 maplikeOrSetlikeOrIterable
= descriptor
.interface
.maplikeOrSetlikeOrIterable
2830 and maplikeOrSetlikeOrIterable
2831 and maplikeOrSetlikeOrIterable
.isIterable()
2832 and maplikeOrSetlikeOrIterable
.isValueIterator()
2834 # Add our keys/values/entries/forEach
2835 self
.regular
.append(
2838 "methodInfo": False,
2839 "selfHostedName": "ArrayKeys",
2841 "flags": "JSPROP_ENUMERATE",
2842 "condition": PropertyDefiner
.getControllingCondition(
2843 maplikeOrSetlikeOrIterable
, descriptor
2847 self
.regular
.append(
2850 "methodInfo": False,
2851 "selfHostedName": "$ArrayValues",
2853 "flags": "JSPROP_ENUMERATE",
2854 "condition": PropertyDefiner
.getControllingCondition(
2855 maplikeOrSetlikeOrIterable
, descriptor
2859 self
.regular
.append(
2862 "methodInfo": False,
2863 "selfHostedName": "ArrayEntries",
2865 "flags": "JSPROP_ENUMERATE",
2866 "condition": PropertyDefiner
.getControllingCondition(
2867 maplikeOrSetlikeOrIterable
, descriptor
2871 self
.regular
.append(
2874 "methodInfo": False,
2875 "selfHostedName": "ArrayForEach",
2877 "flags": "JSPROP_ENUMERATE",
2878 "condition": PropertyDefiner
.getControllingCondition(
2879 maplikeOrSetlikeOrIterable
, descriptor
2885 stringifier
= descriptor
.operations
["Stringifier"]
2886 if stringifier
and unforgeable
== MemberIsLegacyUnforgeable(
2887 stringifier
, descriptor
2890 "name": GetWebExposedName(stringifier
, descriptor
),
2891 "nativeName": stringifier
.identifier
.name
,
2893 "flags": "JSPROP_ENUMERATE",
2894 "condition": PropertyDefiner
.getControllingCondition(
2895 stringifier
, descriptor
2898 if isChromeOnly(stringifier
):
2899 self
.chrome
.append(toStringDesc
)
2901 self
.regular
.append(toStringDesc
)
2902 if unforgeable
and descriptor
.interface
.getExtendedAttribute(
2905 # Synthesize our valueOf method
2906 self
.regular
.append(
2909 "selfHostedName": "Object_valueOf",
2910 "methodInfo": False,
2912 "flags": "0", # readonly/permanent added automatically.
2913 "condition": MemberCondition(),
2917 if descriptor
.interface
.isJSImplemented():
2919 if descriptor
.interface
.hasInterfaceObject():
2923 "nativeName": ("%s::_Create" % descriptor
.name
),
2924 "methodInfo": False,
2927 "condition": MemberCondition(),
2931 self
.unforgeable
= unforgeable
2934 if not descriptor
.interface
.hasInterfaceObject():
2935 # static methods go on the interface object
2936 assert not self
.hasChromeOnly() and not self
.hasNonChromeOnly()
2938 if not descriptor
.interface
.hasInterfacePrototypeObject():
2939 # non-static methods go on the interface prototype object
2940 assert not self
.hasChromeOnly() and not self
.hasNonChromeOnly()
2943 def methodData(m
, descriptor
, overrideFlags
=None):
2945 "name": m
.identifier
.name
,
2946 "methodInfo": not m
.isStatic(),
2947 "length": methodLength(m
),
2948 "flags": EnumerabilityFlags(m
)
2949 if (overrideFlags
is None)
2951 "condition": PropertyDefiner
.getControllingCondition(m
, descriptor
),
2952 "allowCrossOriginThis": m
.getExtendedAttribute("CrossOriginCallable"),
2953 "returnsPromise": m
.returnsPromise(),
2954 "hasIteratorAlias": "@@iterator" in m
.aliases
,
2958 def formatSpec(fields
):
2959 if fields
[0].startswith("@@"):
2960 fields
= (fields
[0][2:],) + fields
[1:]
2961 return " JS_SYM_FNSPEC(%s, %s, %s, %s, %s, %s)" % fields
2962 return ' JS_FNSPEC("%s", %s, %s, %s, %s, %s)' % fields
2965 def specData(m
, descriptor
, unforgeable
=False):
2966 def flags(m
, unforgeable
):
2967 unforgeable
= " | JSPROP_PERMANENT | JSPROP_READONLY" if unforgeable
else ""
2968 return m
["flags"] + unforgeable
2970 if "selfHostedName" in m
:
2971 selfHostedName
= '"%s"' % m
["selfHostedName"]
2972 assert not m
.get("methodInfo", True)
2973 accessor
= "nullptr"
2976 selfHostedName
= "nullptr"
2977 # When defining symbols, function name may not match symbol name
2978 methodName
= m
.get("methodName", m
["name"])
2979 accessor
= m
.get("nativeName", IDLToCIdentifier(methodName
))
2980 if m
.get("methodInfo", True):
2981 if m
.get("returnsPromise", False):
2982 exceptionPolicy
= "ConvertExceptionsToPromises"
2984 exceptionPolicy
= "ThrowExceptions"
2986 # Cast this in case the methodInfo is a
2987 # JSTypedMethodJitInfo.
2989 "reinterpret_cast<const JSJitInfo*>(&%s_methodinfo)" % accessor
2991 if m
.get("allowCrossOriginThis", False):
2993 "(GenericMethod<CrossOriginThisPolicy, %s>)" % exceptionPolicy
2995 elif descriptor
.interface
.hasDescendantWithCrossOriginMembers
:
2997 "(GenericMethod<MaybeCrossOriginObjectThisPolicy, %s>)"
3000 elif descriptor
.interface
.isOnGlobalProtoChain():
3002 "(GenericMethod<MaybeGlobalThisPolicy, %s>)" % exceptionPolicy
3005 accessor
= "(GenericMethod<NormalThisPolicy, %s>)" % exceptionPolicy
3007 if m
.get("returnsPromise", False):
3008 jitinfo
= "&%s_methodinfo" % accessor
3009 accessor
= "StaticMethodPromiseWrapper"
3018 flags(m
, unforgeable
),
3023 def condition(m
, d
):
3024 return m
["condition"]
3026 def generateArray(self
, array
, name
):
3030 return self
.generatePrefableArray(
3037 functools
.partial(self
.specData
, unforgeable
=self
.unforgeable
),
3041 class AttrDefiner(PropertyDefiner
):
3042 def __init__(self
, descriptor
, name
, crossOriginOnly
, static
, unforgeable
=False):
3043 assert not (static
and unforgeable
)
3044 PropertyDefiner
.__init
__(self
, descriptor
, name
)
3046 # Ignore non-static attributes for interfaces without a proto object
3047 if descriptor
.interface
.hasInterfacePrototypeObject() or static
:
3050 for m
in descriptor
.interface
.members
3052 and m
.isStatic() == static
3053 and MemberIsLegacyUnforgeable(m
, descriptor
) == unforgeable
3056 or m
.getExtendedAttribute("CrossOriginReadable")
3057 or m
.getExtendedAttribute("CrossOriginWritable")
3064 for attr
in idlAttrs
:
3065 attributes
.extend(self
.attrData(attr
, unforgeable
))
3066 self
.chrome
= [m
for m
in attributes
if isChromeOnly(m
["attr"])]
3067 self
.regular
= [m
for m
in attributes
if not isChromeOnly(m
["attr"])]
3068 self
.static
= static
3073 and descriptor
.interface
.hasInterfacePrototypeObject()
3075 self
.regular
.append(
3076 {"name": "@@toStringTag", "attr": None, "flags": "JSPROP_READONLY"}
3080 if not descriptor
.interface
.hasInterfaceObject():
3081 # static attributes go on the interface object
3082 assert not self
.hasChromeOnly() and not self
.hasNonChromeOnly()
3084 if not descriptor
.interface
.hasInterfacePrototypeObject():
3085 # non-static attributes go on the interface prototype object
3086 assert not self
.hasChromeOnly() and not self
.hasNonChromeOnly()
3089 def attrData(attr
, unforgeable
=False, overrideFlags
=None):
3090 if overrideFlags
is None:
3091 permanent
= " | JSPROP_PERMANENT" if unforgeable
else ""
3092 flags
= EnumerabilityFlags(attr
) + permanent
3094 flags
= overrideFlags
3096 {"name": name
, "attr": attr
, "flags": flags
}
3097 for name
in [attr
.identifier
.name
] + attr
.bindingAliases
3101 def condition(m
, d
):
3102 if m
["name"] == "@@toStringTag":
3103 return MemberCondition()
3104 return PropertyDefiner
.getControllingCondition(m
["attr"], d
)
3107 def specData(entry
, descriptor
, static
=False, crossOriginOnly
=False):
3108 if entry
["name"] == "@@toStringTag":
3109 return (entry
["name"], entry
["flags"], descriptor
.interface
.getClassName())
3112 if crossOriginOnly
and not attr
.getExtendedAttribute("CrossOriginReadable"):
3113 return "nullptr, nullptr"
3115 if attr
.type.isPromise():
3117 "Don't know how to handle "
3118 "static Promise-returning "
3119 "attribute %s.%s" % (descriptor
.name
, attr
.identifier
.name
)
3121 accessor
= "get_" + IDLToCIdentifier(attr
.identifier
.name
)
3124 if attr
.type.isPromise():
3125 exceptionPolicy
= "ConvertExceptionsToPromises"
3127 exceptionPolicy
= "ThrowExceptions"
3129 if attr
.hasLegacyLenientThis():
3130 if attr
.getExtendedAttribute("CrossOriginReadable"):
3132 "Can't handle lenient cross-origin "
3133 "readable attribute %s.%s"
3134 % (self
.descriptor
.name
, attr
.identifier
.name
)
3136 if descriptor
.interface
.hasDescendantWithCrossOriginMembers
:
3138 "GenericGetter<MaybeCrossOriginObjectLenientThisPolicy, %s>"
3143 "GenericGetter<LenientThisPolicy, %s>" % exceptionPolicy
3145 elif attr
.getExtendedAttribute("CrossOriginReadable"):
3147 "GenericGetter<CrossOriginThisPolicy, %s>" % exceptionPolicy
3149 elif descriptor
.interface
.hasDescendantWithCrossOriginMembers
:
3151 "GenericGetter<MaybeCrossOriginObjectThisPolicy, %s>"
3154 elif descriptor
.interface
.isOnGlobalProtoChain():
3156 "GenericGetter<MaybeGlobalThisPolicy, %s>" % exceptionPolicy
3159 accessor
= "GenericGetter<NormalThisPolicy, %s>" % exceptionPolicy
3160 jitinfo
= "&%s_getterinfo" % IDLToCIdentifier(attr
.identifier
.name
)
3161 return "%s, %s" % (accessor
, jitinfo
)
3166 and attr
.getExtendedAttribute("PutForwards") is None
3167 and attr
.getExtendedAttribute("Replaceable") is None
3168 and attr
.getExtendedAttribute("LegacyLenientSetter") is None
3170 return "nullptr, nullptr"
3171 if crossOriginOnly
and not attr
.getExtendedAttribute("CrossOriginWritable"):
3172 return "nullptr, nullptr"
3174 accessor
= "set_" + IDLToCIdentifier(attr
.identifier
.name
)
3177 if attr
.hasLegacyLenientThis():
3178 if attr
.getExtendedAttribute("CrossOriginWritable"):
3180 "Can't handle lenient cross-origin "
3181 "writable attribute %s.%s"
3182 % (descriptor
.name
, attr
.identifier
.name
)
3184 if descriptor
.interface
.hasDescendantWithCrossOriginMembers
:
3186 "GenericSetter<MaybeCrossOriginObjectLenientThisPolicy>"
3189 accessor
= "GenericSetter<LenientThisPolicy>"
3190 elif attr
.getExtendedAttribute("CrossOriginWritable"):
3191 accessor
= "GenericSetter<CrossOriginThisPolicy>"
3192 elif descriptor
.interface
.hasDescendantWithCrossOriginMembers
:
3193 accessor
= "GenericSetter<MaybeCrossOriginObjectThisPolicy>"
3194 elif descriptor
.interface
.isOnGlobalProtoChain():
3195 accessor
= "GenericSetter<MaybeGlobalThisPolicy>"
3197 accessor
= "GenericSetter<NormalThisPolicy>"
3198 jitinfo
= "&%s_setterinfo" % IDLToCIdentifier(attr
.identifier
.name
)
3199 return "%s, %s" % (accessor
, jitinfo
)
3201 name
, attr
, flags
= entry
["name"], entry
["attr"], entry
["flags"]
3202 return (name
, flags
, getter(attr
), setter(attr
))
3205 def formatSpec(fields
):
3206 if fields
[0] == "@@toStringTag":
3207 return ' JS_STRING_SYM_PS(%s, "%s", %s)' % (
3213 return ' JSPropertySpec::nativeAccessors("%s", %s, %s, %s)' % fields
3215 def generateArray(self
, array
, name
):
3219 return self
.generatePrefableArray(
3226 functools
.partial(self
.specData
, static
=self
.static
),
3230 class ConstDefiner(PropertyDefiner
):
3232 A class for definining constants on the interface object
3235 def __init__(self
, descriptor
, name
):
3236 PropertyDefiner
.__init
__(self
, descriptor
, name
)
3238 constants
= [m
for m
in descriptor
.interface
.members
if m
.isConst()]
3239 self
.chrome
= [m
for m
in constants
if isChromeOnly(m
)]
3240 self
.regular
= [m
for m
in constants
if not isChromeOnly(m
)]
3242 def generateArray(self
, array
, name
):
3246 def specData(const
, descriptor
):
3247 return (const
.identifier
.name
, convertConstIDLValueToJSVal(const
.value
))
3249 return self
.generatePrefableArray(
3252 lambda fields
: ' { "%s", %s }' % fields
,
3253 " { 0, JS::UndefinedValue() }",
3255 PropertyDefiner
.getControllingCondition
,
3260 class PropertyArrays
:
3261 def __init__(self
, descriptor
, crossOriginOnly
=False):
3262 self
.staticMethods
= MethodDefiner(
3263 descriptor
, "StaticMethods", crossOriginOnly
, static
=True
3265 self
.staticAttrs
= AttrDefiner(
3266 descriptor
, "StaticAttributes", crossOriginOnly
, static
=True
3268 self
.methods
= MethodDefiner(
3269 descriptor
, "Methods", crossOriginOnly
, static
=False
3271 self
.attrs
= AttrDefiner(
3272 descriptor
, "Attributes", crossOriginOnly
, static
=False
3274 self
.unforgeableMethods
= MethodDefiner(
3276 "UnforgeableMethods",
3281 self
.unforgeableAttrs
= AttrDefiner(
3283 "UnforgeableAttributes",
3288 self
.consts
= ConstDefiner(descriptor
, "Constants")
3297 "unforgeableMethods",
3302 def hasChromeOnly(self
):
3303 return any(getattr(self
, a
).hasChromeOnly() for a
in self
.arrayNames())
3305 def hasNonChromeOnly(self
):
3306 return any(getattr(self
, a
).hasNonChromeOnly() for a
in self
.arrayNames())
3310 for array
in self
.arrayNames():
3311 define
+= str(getattr(self
, array
))
3315 class CGConstDefinition(CGThing
):
3317 Given a const member of an interface, return the C++ static const definition
3318 for the member. Should be part of the interface namespace in the header
3322 def __init__(self
, member
):
3325 and member
.value
.type.isPrimitive()
3326 and not member
.value
.type.nullable()
3329 name
= CppKeywords
.checkMethodName(IDLToCIdentifier(member
.identifier
.name
))
3330 tag
= member
.value
.type.tag()
3331 value
= member
.value
.value
3332 if tag
== IDLType
.Tags
.bool:
3333 value
= toStringBool(member
.value
.value
)
3334 self
.const
= "static const %s %s = %s;" % (builtinNames
[tag
], name
, value
)
3346 class CGNativeProperties(CGList
):
3347 def __init__(self
, descriptor
, properties
):
3348 def generateNativeProperties(name
, chrome
):
3350 return p
.hasChromeOnly() if chrome
else p
.hasNonChromeOnly()
3352 nativePropsInts
= []
3353 nativePropsPtrs
= []
3354 nativePropsDuos
= []
3358 for array
in properties
.arrayNames():
3359 propertyArray
= getattr(properties
, array
)
3360 if check(propertyArray
):
3361 varName
= propertyArray
.variableName(chrome
)
3362 bitfields
= "true, %d /* %s */" % (duosOffset
, varName
)
3364 nativePropsInts
.append(CGGeneric(bitfields
))
3366 if propertyArray
.usedForXrays():
3367 ids
= "&%s_propertyInfos[%d]" % (name
, idsOffset
)
3368 idsOffset
+= propertyArray
.length(chrome
)
3371 duo
= "{ %s, %s }" % (varName
, ids
)
3372 nativePropsDuos
.append(CGGeneric(duo
))
3374 bitfields
= "false, 0"
3375 nativePropsInts
.append(CGGeneric(bitfields
))
3377 iteratorAliasIndex
= -1
3378 for index
, item
in enumerate(properties
.methods
.regular
):
3379 if item
.get("hasIteratorAlias"):
3380 iteratorAliasIndex
= index
3382 nativePropsInts
.append(CGGeneric(str(iteratorAliasIndex
)))
3386 CGIndenter(CGList(nativePropsDuos
, ",\n")), pre
="{\n", post
="\n}"
3390 pre
= "static const NativePropertiesN<%d> %s = {\n" % (duosOffset
, name
)
3392 if descriptor
.wantsXrays
:
3395 static uint16_t ${name}_sortedPropertyIndices[${size}];
3396 static PropertyInfo ${name}_propertyInfos[${size}];
3404 if iteratorAliasIndex
> 0:
3405 # The iteratorAliasMethodIndex is a signed integer, so the
3406 # max value it can store is 2^(nbits-1)-1.
3410 static_assert(${iteratorAliasIndex} < 1ull << (CHAR_BIT * sizeof(${name}.iteratorAliasMethodIndex) - 1),
3411 "We have an iterator alias index that is oversized");
3414 iteratorAliasIndex
=iteratorAliasIndex
,
3420 static_assert(${propertyInfoCount} < 1ull << (CHAR_BIT * sizeof(${name}.propertyInfoCount)),
3421 "We have a property info count that is oversized");
3424 propertyInfoCount
=idsOffset
,
3427 nativePropsInts
.append(CGGeneric("%d" % idsOffset
))
3428 nativePropsPtrs
.append(CGGeneric("%s_sortedPropertyIndices" % name
))
3430 nativePropsInts
.append(CGGeneric("0"))
3431 nativePropsPtrs
.append(CGGeneric("nullptr"))
3432 nativeProps
= nativePropsInts
+ nativePropsPtrs
+ nativePropsDuos
3433 return CGWrapper(CGIndenter(CGList(nativeProps
, ",\n")), pre
=pre
, post
=post
)
3435 nativeProperties
= []
3436 if properties
.hasNonChromeOnly():
3437 nativeProperties
.append(
3438 generateNativeProperties("sNativeProperties", False)
3440 if properties
.hasChromeOnly():
3441 nativeProperties
.append(
3442 generateNativeProperties("sChromeOnlyNativeProperties", True)
3445 CGList
.__init
__(self
, nativeProperties
, "\n")
3451 return CGList
.define(self
)
3454 class CGCollectJSONAttributesMethod(CGAbstractMethod
):
3456 Generate the CollectJSONAttributes method for an interface descriptor
3459 def __init__(self
, descriptor
, toJSONMethod
):
3461 Argument("JSContext*", "cx"),
3462 Argument("JS::Handle<JSObject*>", "obj"),
3463 Argument("%s*" % descriptor
.nativeType
, "self"),
3464 Argument("JS::Rooted<JSObject*>&", "result"),
3466 CGAbstractMethod
.__init
__(
3467 self
, descriptor
, "CollectJSONAttributes", "bool", args
, canRunScript
=True
3469 self
.toJSONMethod
= toJSONMethod
3471 def definition_body(self
):
3473 interface
= self
.descriptor
.interface
3474 toJSONCondition
= PropertyDefiner
.getControllingCondition(
3475 self
.toJSONMethod
, self
.descriptor
3477 needUnwrappedObj
= False
3478 for m
in interface
.members
:
3479 if m
.isAttr() and not m
.isStatic() and m
.type.isJSONType():
3480 getAndDefine
= fill(
3482 JS::Rooted<JS::Value> temp(cx);
3483 if (!get_${name}(cx, obj, self, JSJitGetterCallArgs(&temp))) {
3486 if (!JS_DefineProperty(cx, result, "${name}", temp, JSPROP_ENUMERATE)) {
3490 name
=IDLToCIdentifier(m
.identifier
.name
),
3492 # Make sure we don't include things which are supposed to be
3493 # disabled. Things that either don't have disablers or whose
3494 # disablers match the disablers for our toJSON method can't
3495 # possibly be disabled, but other things might be.
3496 condition
= PropertyDefiner
.getControllingCondition(m
, self
.descriptor
)
3497 if condition
.hasDisablers() and condition
!= toJSONCondition
:
3498 needUnwrappedObj
= True
3501 // This is unfortunately a linear scan through sAttributes, but we
3502 // only do it for things which _might_ be disabled, which should
3503 // help keep the performance problems down.
3504 if (IsGetterEnabled(cx, unwrappedObj, (JSJitGetterOp)get_${name}, sAttributes)) {
3508 name
=IDLToCIdentifier(m
.identifier
.name
),
3509 getAndDefine
=getAndDefine
,
3514 { // scope for "temp"
3518 getAndDefine
=getAndDefine
,
3520 ret
+= "return true;\n"
3522 if needUnwrappedObj
:
3523 # If we started allowing cross-origin objects here, we'd need to
3524 # use CheckedUnwrapDynamic and figure out whether it makes sense.
3525 # But in practice no one is trying to add toJSON methods to those,
3526 # so let's just guard against it.
3527 assert not self
.descriptor
.isMaybeCrossOriginObject()
3530 JS::Rooted<JSObject*> unwrappedObj(cx, js::CheckedUnwrapStatic(obj));
3531 if (!unwrappedObj) {
3532 // How did that happen? We managed to get called with that
3533 // object as "this"! Just give up on sanity.
3545 class CGCreateInterfaceObjectsMethod(CGAbstractMethod
):
3547 Generate the CreateInterfaceObjects method for an interface descriptor.
3549 properties should be a PropertyArrays instance.
3553 self
, descriptor
, properties
, haveUnscopables
, haveLegacyWindowAliases
3556 Argument("JSContext*", "aCx"),
3557 Argument("JS::Handle<JSObject*>", "aGlobal"),
3558 Argument("ProtoAndIfaceCache&", "aProtoAndIfaceCache"),
3559 Argument("bool", "aDefineOnGlobal"),
3561 CGAbstractMethod
.__init
__(
3562 self
, descriptor
, "CreateInterfaceObjects", "void", args
3564 self
.properties
= properties
3565 self
.haveUnscopables
= haveUnscopables
3566 self
.haveLegacyWindowAliases
= haveLegacyWindowAliases
3568 def definition_body(self
):
3569 (protoGetter
, protoHandleGetter
) = InterfacePrototypeObjectProtoGetter(
3572 if protoHandleGetter
is None:
3573 parentProtoType
= "Rooted"
3574 getParentProto
= "aCx, " + protoGetter
3576 parentProtoType
= "Handle"
3577 getParentProto
= protoHandleGetter
3578 getParentProto
= getParentProto
+ "(aCx)"
3580 (protoGetter
, protoHandleGetter
) = InterfaceObjectProtoGetter(self
.descriptor
)
3581 if protoHandleGetter
is None:
3582 getConstructorProto
= "aCx, " + protoGetter
3583 constructorProtoType
= "Rooted"
3585 getConstructorProto
= protoHandleGetter
3586 constructorProtoType
= "Handle"
3587 getConstructorProto
+= "(aCx)"
3589 needInterfaceObject
= self
.descriptor
.interface
.hasInterfaceObject()
3590 needInterfacePrototypeObject
= (
3591 self
.descriptor
.interface
.hasInterfacePrototypeObject()
3594 # if we don't need to create anything, why are we generating this?
3595 assert needInterfaceObject
or needInterfacePrototypeObject
3597 getParentProto
= fill(
3599 JS::${type}<JSObject*> parentProto(${getParentProto});
3604 type=parentProtoType
,
3605 getParentProto
=getParentProto
,
3608 getConstructorProto
= fill(
3610 JS::${type}<JSObject*> constructorProto(${getConstructorProto});
3611 if (!constructorProto) {
3615 type=constructorProtoType
,
3616 getConstructorProto
=getConstructorProto
,
3620 # There is no need to init any IDs in bindings that don't want Xrays.
3621 if self
.descriptor
.wantsXrays
:
3622 if self
.properties
.hasNonChromeOnly():
3623 idsToInit
.append("sNativeProperties")
3624 if self
.properties
.hasChromeOnly():
3625 idsToInit
.append("sChromeOnlyNativeProperties")
3626 if len(idsToInit
) > 0:
3628 "!InitIds(aCx, %s.Upcast())" % (properties
) for properties
in idsToInit
3630 idsInitedFlag
= CGGeneric(
3631 "static Atomic<bool, Relaxed> sIdsInited(false);\n"
3633 setFlag
= CGGeneric("sIdsInited = true;\n")
3634 initIdConditionals
= [
3635 CGIfWrapper(CGGeneric("return;\n"), call
) for call
in initIdCalls
3641 CGList(initIdConditionals
+ [setFlag
]),
3642 "!sIdsInited && NS_IsMainThread()",
3649 if self
.descriptor
.interface
.ctor():
3650 constructArgs
= methodLength(self
.descriptor
.interface
.ctor())
3653 if len(self
.descriptor
.interface
.legacyFactoryFunctions
) > 0:
3654 namedConstructors
= "namedConstructors"
3656 namedConstructors
= "nullptr"
3658 if needInterfacePrototypeObject
:
3659 protoClass
= "&sPrototypeClass.mBase"
3661 "&aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::%s)"
3662 % self
.descriptor
.name
3664 parentProto
= "parentProto"
3665 getParentProto
= CGGeneric(getParentProto
)
3667 protoClass
= "nullptr"
3668 protoCache
= "nullptr"
3669 parentProto
= "nullptr"
3670 getParentProto
= None
3672 if needInterfaceObject
:
3673 interfaceClass
= "&sInterfaceObjectClass.mBase"
3675 "&aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::%s)"
3676 % self
.descriptor
.name
3678 getConstructorProto
= CGGeneric(getConstructorProto
)
3679 constructorProto
= "constructorProto"
3681 # We don't have slots to store the legacy factory functions.
3682 assert len(self
.descriptor
.interface
.legacyFactoryFunctions
) == 0
3683 interfaceClass
= "nullptr"
3684 interfaceCache
= "nullptr"
3685 getConstructorProto
= None
3686 constructorProto
= "nullptr"
3688 isGlobal
= self
.descriptor
.isGlobal() is not None
3689 if self
.properties
.hasNonChromeOnly():
3690 properties
= "sNativeProperties.Upcast()"
3692 properties
= "nullptr"
3693 if self
.properties
.hasChromeOnly():
3694 chromeProperties
= "sChromeOnlyNativeProperties.Upcast()"
3696 chromeProperties
= "nullptr"
3700 JS::Heap<JSObject*>* protoCache = ${protoCache};
3701 JS::Heap<JSObject*>* interfaceCache = ${interfaceCache};
3702 dom::CreateInterfaceObjects(aCx, aGlobal, ${parentProto},
3703 ${protoClass}, protoCache,
3704 ${constructorProto}, ${interfaceClass}, ${constructArgs}, ${namedConstructors},
3707 ${chromeProperties},
3708 ${name}, aDefineOnGlobal,
3711 ${legacyWindowAliases},
3714 protoClass
=protoClass
,
3715 parentProto
=parentProto
,
3716 protoCache
=protoCache
,
3717 constructorProto
=constructorProto
,
3718 interfaceClass
=interfaceClass
,
3719 constructArgs
=constructArgs
,
3720 namedConstructors
=namedConstructors
,
3721 interfaceCache
=interfaceCache
,
3722 properties
=properties
,
3723 chromeProperties
=chromeProperties
,
3724 name
='"' + self
.descriptor
.interface
.identifier
.name
+ '"'
3725 if needInterfaceObject
3727 unscopableNames
="unscopableNames" if self
.haveUnscopables
else "nullptr",
3728 isGlobal
=toStringBool(isGlobal
),
3729 legacyWindowAliases
="legacyWindowAliases"
3730 if self
.haveLegacyWindowAliases
3732 isNamespace
=toStringBool(self
.descriptor
.interface
.isNamespace()),
3735 # If we fail after here, we must clear interface and prototype caches
3736 # using this code: intermediate failure must not expose the interface in
3737 # partially-constructed state. Note that every case after here needs an
3738 # interface prototype object.
3739 failureCode
= dedent(
3741 *protoCache = nullptr;
3742 if (interfaceCache) {
3743 *interfaceCache = nullptr;
3750 m
for m
in self
.descriptor
.interface
.members
if m
.isMethod() and m
.aliases
3753 assert needInterfacePrototypeObject
3755 def defineAlias(alias
):
3756 if alias
== "@@iterator":
3757 symbolJSID
= "SYMBOL_TO_JSID(JS::GetWellKnownSymbol(aCx, JS::SymbolCode::iterator))"
3758 getSymbolJSID
= CGGeneric(
3760 "JS::Rooted<jsid> iteratorId(aCx, ${symbolJSID});",
3761 symbolJSID
=symbolJSID
,
3764 defineFn
= "JS_DefinePropertyById"
3766 enumFlags
= "0" # Not enumerable, per spec.
3767 elif alias
.startswith("@@"):
3769 "Can't handle any well-known Symbol other than @@iterator"
3772 getSymbolJSID
= None
3773 defineFn
= "JS_DefineProperty"
3774 prop
= '"%s"' % alias
3775 # XXX If we ever create non-enumerable properties that can
3776 # be aliased, we should consider making the aliases
3777 # match the enumerability of the property being aliased.
3778 enumFlags
= "JSPROP_ENUMERATE"
3785 if (!${defineFn}(aCx, proto, ${prop}, aliasedVal, ${enumFlags})) {
3791 enumFlags
=enumFlags
,
3792 failureCode
=failureCode
,
3799 def defineAliasesFor(m
):
3805 if (!JS_GetProperty(aCx, proto, \"${prop}\", &aliasedVal)) {
3809 failureCode
=failureCode
,
3810 prop
=m
.identifier
.name
,
3814 + [defineAlias(alias
) for alias
in sorted(m
.aliases
)]
3817 defineAliases
= CGList(
3822 // Set up aliases on the interface prototype object we just created.
3823 JS::Handle<JSObject*> proto = GetProtoObjectHandle(aCx);
3829 failureCode
=failureCode
,
3832 CGGeneric("JS::Rooted<JS::Value> aliasedVal(aCx);\n\n"),
3836 for m
in sorted(aliasedMembers
, key
=lambda m
: m
.identifier
.name
)
3840 defineAliases
= None
3842 # Globals handle unforgeables directly in Wrap() instead of
3845 self
.descriptor
.hasLegacyUnforgeableMembers
3846 and not self
.descriptor
.isGlobal()
3848 assert needInterfacePrototypeObject
3850 # We want to use the same JSClass and prototype as the object we'll
3851 # end up defining the unforgeable properties on in the end, so that
3852 # we can use JS_InitializePropertiesFromCompatibleNativeObject to do
3853 # a fast copy. In the case of proxies that's null, because the
3854 # expando object is a vanilla object, but in the case of other DOM
3855 # objects it's whatever our class is.
3856 if self
.descriptor
.proxy
:
3857 holderClass
= "nullptr"
3858 holderProto
= "nullptr"
3860 holderClass
= "sClass.ToJSClass()"
3861 holderProto
= "*protoCache"
3862 createUnforgeableHolder
= CGGeneric(
3865 JS::Rooted<JSObject*> unforgeableHolder(aCx);
3867 JS::Rooted<JSObject*> holderProto(aCx, ${holderProto});
3868 unforgeableHolder = JS_NewObjectWithoutMetadata(aCx, ${holderClass}, holderProto);
3869 if (!unforgeableHolder) {
3874 holderProto
=holderProto
,
3875 holderClass
=holderClass
,
3876 failureCode
=failureCode
,
3879 defineUnforgeables
= InitUnforgeablePropertiesOnHolder(
3880 self
.descriptor
, self
.properties
, failureCode
3882 createUnforgeableHolder
= CGList(
3883 [createUnforgeableHolder
, defineUnforgeables
]
3886 installUnforgeableHolder
= CGGeneric(
3890 JS::SetReservedSlot(*protoCache, DOM_INTERFACE_PROTO_SLOTS_BASE,
3891 JS::ObjectValue(*unforgeableHolder));
3897 unforgeableHolderSetup
= CGList(
3898 [createUnforgeableHolder
, installUnforgeableHolder
], "\n"
3901 unforgeableHolderSetup
= None
3904 self
.descriptor
.interface
.isOnGlobalProtoChain()
3905 and needInterfacePrototypeObject
3907 makeProtoPrototypeImmutable
= CGGeneric(
3910 if (*${protoCache}) {
3912 JS::Handle<JSObject*> prot = GetProtoObjectHandle(aCx);
3913 if (!JS_SetImmutablePrototype(aCx, prot, &succeeded)) {
3917 MOZ_ASSERT(succeeded,
3918 "making a fresh prototype object's [[Prototype]] "
3919 "immutable can internally fail, but it should "
3920 "never be unsuccessful");
3923 protoCache
=protoCache
,
3924 failureCode
=failureCode
,
3928 makeProtoPrototypeImmutable
= None
3933 getConstructorProto
,
3937 unforgeableHolderSetup
,
3938 makeProtoPrototypeImmutable
,
3944 class CGGetProtoObjectHandleMethod(CGAbstractMethod
):
3946 A method for getting the interface prototype object.
3949 def __init__(self
, descriptor
):
3950 CGAbstractMethod
.__init
__(
3953 "GetProtoObjectHandle",
3954 "JS::Handle<JSObject*>",
3955 [Argument("JSContext*", "aCx")],
3959 def definition_body(self
):
3962 /* Get the interface prototype object for this class. This will create the
3963 object as needed. */
3964 return GetPerInterfaceObjectHandle(aCx, prototypes::id::${name},
3965 &CreateInterfaceObjects,
3966 /* aDefineOnGlobal = */ true);
3969 name
=self
.descriptor
.name
,
3973 class CGGetProtoObjectMethod(CGAbstractMethod
):
3975 A method for getting the interface prototype object.
3978 def __init__(self
, descriptor
):
3979 CGAbstractMethod
.__init
__(
3984 [Argument("JSContext*", "aCx")],
3987 def definition_body(self
):
3988 return "return GetProtoObjectHandle(aCx);\n"
3991 class CGGetConstructorObjectHandleMethod(CGAbstractMethod
):
3993 A method for getting the interface constructor object.
3996 def __init__(self
, descriptor
):
3997 CGAbstractMethod
.__init
__(
4000 "GetConstructorObjectHandle",
4001 "JS::Handle<JSObject*>",
4003 Argument("JSContext*", "aCx"),
4004 Argument("bool", "aDefineOnGlobal", "true"),
4009 def definition_body(self
):
4012 /* Get the interface object for this class. This will create the object as
4015 return GetPerInterfaceObjectHandle(aCx, constructors::id::${name},
4016 &CreateInterfaceObjects,
4019 name
=self
.descriptor
.name
,
4023 class CGGetConstructorObjectMethod(CGAbstractMethod
):
4025 A method for getting the interface constructor object.
4028 def __init__(self
, descriptor
):
4029 CGAbstractMethod
.__init
__(
4032 "GetConstructorObject",
4034 [Argument("JSContext*", "aCx")],
4037 def definition_body(self
):
4038 return "return GetConstructorObjectHandle(aCx);\n"
4041 class CGGetNamedPropertiesObjectMethod(CGAbstractStaticMethod
):
4042 def __init__(self
, descriptor
):
4043 args
= [Argument("JSContext*", "aCx")]
4044 CGAbstractStaticMethod
.__init
__(
4045 self
, descriptor
, "GetNamedPropertiesObject", "JSObject*", args
4048 def definition_body(self
):
4049 parentProtoName
= self
.descriptor
.parentPrototypeName
4050 if parentProtoName
is None:
4052 parentProto
= "nullptr"
4054 getParentProto
= fill(
4056 JS::Rooted<JSObject*> parentProto(aCx, ${parent}::GetProtoObjectHandle(aCx));
4061 parent
=toBindingNamespace(parentProtoName
),
4063 parentProto
= "parentProto"
4066 /* Make sure our global is sane. Hopefully we can remove this sometime */
4067 JSObject* global = JS::CurrentGlobalOrNull(aCx);
4068 if (!(JS::GetClass(global)->flags & JSCLASS_DOM_GLOBAL)) {
4072 /* Check to see whether the named properties object has already been created */
4073 ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
4075 JS::Heap<JSObject*>& namedPropertiesObject = protoAndIfaceCache.EntrySlotOrCreate(namedpropertiesobjects::id::${ifaceName});
4076 if (!namedPropertiesObject) {
4078 namedPropertiesObject = ${nativeType}::CreateNamedPropertiesObject(aCx, ${parentProto});
4079 DebugOnly<const DOMIfaceAndProtoJSClass*> clasp =
4080 DOMIfaceAndProtoJSClass::FromJSClass(JS::GetClass(namedPropertiesObject));
4081 MOZ_ASSERT(clasp->mType == eNamedPropertiesObject,
4082 "Expected ${nativeType}::CreateNamedPropertiesObject to return a named properties object");
4083 MOZ_ASSERT(clasp->mNativeHooks,
4084 "The named properties object for ${nativeType} should have NativePropertyHooks.");
4085 MOZ_ASSERT(!clasp->mNativeHooks->mResolveOwnProperty,
4086 "Shouldn't resolve the properties of the named properties object for ${nativeType} for Xrays.");
4087 MOZ_ASSERT(!clasp->mNativeHooks->mEnumerateOwnProperties,
4088 "Shouldn't enumerate the properties of the named properties object for ${nativeType} for Xrays.");
4090 return namedPropertiesObject.get();
4092 getParentProto
=getParentProto
,
4093 ifaceName
=self
.descriptor
.name
,
4094 parentProto
=parentProto
,
4095 nativeType
=self
.descriptor
.nativeType
,
4099 def getRawConditionList(idlobj
, cxName
, objName
, ignoreSecureContext
=False):
4101 Get the list of conditions for idlobj (to be used in "is this enabled"
4102 checks). This will be returned as a CGList with " &&\n" as the separator,
4105 objName is the name of the object that we're working with, because some of
4106 our test functions want that.
4108 ignoreSecureContext is used only for constructors in which the WebIDL interface
4109 itself is already marked as [SecureContext]. There is no need to do the work twice.
4112 pref
= idlobj
.getExtendedAttribute("Pref")
4114 assert isinstance(pref
, list) and len(pref
) == 1
4115 conditions
.append("StaticPrefs::%s()" % prefIdentifier(pref
[0]))
4116 if isChromeOnly(idlobj
):
4117 conditions
.append("nsContentUtils::ThreadsafeIsSystemCaller(%s)" % cxName
)
4118 func
= idlobj
.getExtendedAttribute("Func")
4120 assert isinstance(func
, list) and len(func
) == 1
4121 conditions
.append("%s(%s, %s)" % (func
[0], cxName
, objName
))
4122 if not ignoreSecureContext
and idlobj
.getExtendedAttribute("SecureContext"):
4124 "mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(%s, %s)"
4130 def getConditionList(idlobj
, cxName
, objName
, ignoreSecureContext
=False):
4132 Get the list of conditions from getRawConditionList
4133 See comment on getRawConditionList above for more info about arguments.
4135 The return value is a possibly-empty conjunctive CGList of conditions.
4137 conditions
= getRawConditionList(idlobj
, cxName
, objName
, ignoreSecureContext
)
4138 return CGList((CGGeneric(cond
) for cond
in conditions
), " &&\n")
4141 class CGConstructorEnabled(CGAbstractMethod
):
4143 A method for testing whether we should be exposing this interface object.
4144 This can perform various tests depending on what conditions are specified
4148 def __init__(self
, descriptor
):
4149 CGAbstractMethod
.__init
__(
4152 "ConstructorEnabled",
4154 [Argument("JSContext*", "aCx"), Argument("JS::Handle<JSObject*>", "aObj")],
4157 def definition_body(self
):
4158 body
= CGList([], "\n")
4160 iface
= self
.descriptor
.interface
4162 if not iface
.isExposedInWindow():
4163 exposedInWindowCheck
= dedent(
4165 MOZ_ASSERT(!NS_IsMainThread(), "Why did we even get called?");
4168 body
.append(CGGeneric(exposedInWindowCheck
))
4170 if iface
.isExposedInSomeButNotAllWorkers():
4171 workerGlobals
= sorted(iface
.getWorkerExposureSet())
4172 workerCondition
= CGList(
4174 CGGeneric('strcmp(name, "%s")' % workerGlobal
)
4175 for workerGlobal
in workerGlobals
4179 exposedInWorkerCheck
= fill(
4181 const char* name = JS::GetClass(aObj)->name;
4182 if (${workerCondition}) {
4186 workerCondition
=workerCondition
.define(),
4188 exposedInWorkerCheck
= CGGeneric(exposedInWorkerCheck
)
4189 if iface
.isExposedInWindow():
4190 exposedInWorkerCheck
= CGIfWrapper(
4191 exposedInWorkerCheck
, "!NS_IsMainThread()"
4193 body
.append(exposedInWorkerCheck
)
4195 conditions
= getConditionList(iface
, "aCx", "aObj")
4197 # We should really have some conditions
4198 assert len(body
) or len(conditions
)
4200 conditionsWrapper
= ""
4202 conditionsWrapper
= CGWrapper(
4203 conditions
, pre
="return ", post
=";\n", reindent
=True
4206 conditionsWrapper
= CGGeneric("return true;\n")
4208 body
.append(conditionsWrapper
)
4209 return body
.define()
4212 def StructuredCloneTag(name
):
4213 return "SCTAG_DOM_%s" % name
.upper()
4216 class CGSerializer(CGAbstractStaticMethod
):
4218 Implementation of serialization for things marked [Serializable].
4219 This gets stored in our DOMJSClass, so it can be static.
4221 The caller is expected to pass in the object whose DOMJSClass it
4222 used to get the serializer.
4225 def __init__(self
, descriptor
):
4227 Argument("JSContext*", "aCx"),
4228 Argument("JSStructuredCloneWriter*", "aWriter"),
4229 Argument("JS::Handle<JSObject*>", "aObj"),
4231 CGAbstractStaticMethod
.__init
__(self
, descriptor
, "Serialize", "bool", args
)
4233 def definition_body(self
):
4236 MOZ_ASSERT(IsDOMObject(aObj), "Non-DOM object passed");
4237 MOZ_ASSERT(GetDOMClass(aObj)->mSerializer == &Serialize,
4238 "Wrong object passed");
4239 return JS_WriteUint32Pair(aWriter, ${tag}, 0) &&
4240 UnwrapDOMObject<${type}>(aObj)->WriteStructuredClone(aCx, aWriter);
4242 tag
=StructuredCloneTag(self
.descriptor
.name
),
4243 type=self
.descriptor
.nativeType
,
4247 class CGDeserializer(CGAbstractMethod
):
4249 Implementation of deserialization for things marked [Serializable].
4250 This will need to be accessed from WebIDLSerializable, so can't be static.
4253 def __init__(self
, descriptor
):
4255 Argument("JSContext*", "aCx"),
4256 Argument("nsIGlobalObject*", "aGlobal"),
4257 Argument("JSStructuredCloneReader*", "aReader"),
4259 CGAbstractMethod
.__init
__(self
, descriptor
, "Deserialize", "JSObject*", args
)
4261 def definition_body(self
):
4262 # WrapObject has different signatures depending on whether
4263 # the object is wrappercached.
4264 if self
.descriptor
.wrapperCache
:
4267 result = obj->WrapObject(aCx, nullptr);
4276 if (!obj->WrapObject(aCx, nullptr, &result)) {
4284 // Protect the result from a moving GC in ~RefPtr
4285 JS::Rooted<JSObject*> result(aCx);
4286 { // Scope for the RefPtr
4287 RefPtr<${type}> obj = ${type}::ReadStructuredClone(aCx, aGlobal, aReader);
4295 type=self
.descriptor
.nativeType
,
4300 def CreateBindingJSObject(descriptor
, properties
):
4301 objDecl
= "BindingJSObjectCreator<%s> creator(aCx);\n" % descriptor
.nativeType
4303 # We don't always need to root obj, but there are a variety
4304 # of cases where we do, so for simplicity, just always root it.
4305 if descriptor
.proxy
:
4306 if descriptor
.interface
.getExtendedAttribute("LegacyOverrideBuiltIns"):
4307 assert not descriptor
.isMaybeCrossOriginObject()
4310 aObject->mExpandoAndGeneration.expando.setUndefined();
4311 JS::Rooted<JS::Value> expandoValue(aCx, JS::PrivateValue(&aObject->mExpandoAndGeneration));
4312 creator.CreateProxyObject(aCx, &sClass.mBase, DOMProxyHandler::getInstance(),
4313 proto, /* aLazyProto = */ false, aObject,
4314 expandoValue, aReflector);
4318 if descriptor
.isMaybeCrossOriginObject():
4326 creator.CreateProxyObject(aCx, &sClass.mBase, DOMProxyHandler::getInstance(),
4327 ${proto}, /* aLazyProto = */ ${lazyProto},
4328 aObject, JS::UndefinedHandleValue, aReflector);
4331 lazyProto
=lazyProto
,
4336 creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector);
4352 def InitUnforgeablePropertiesOnHolder(
4353 descriptor
, properties
, failureCode
, holderName
="unforgeableHolder"
4356 Define the unforgeable properties on the unforgeable holder for
4357 the interface represented by descriptor.
4359 properties is a PropertyArrays instance.
4363 properties
.unforgeableAttrs
.hasNonChromeOnly()
4364 or properties
.unforgeableAttrs
.hasChromeOnly()
4365 or properties
.unforgeableMethods
.hasNonChromeOnly()
4366 or properties
.unforgeableMethods
.hasChromeOnly()
4371 defineUnforgeableAttrs
= fill(
4373 if (!DefineLegacyUnforgeableAttributes(aCx, ${holderName}, %s)) {
4377 failureCode
=failureCode
,
4378 holderName
=holderName
,
4380 defineUnforgeableMethods
= fill(
4382 if (!DefineLegacyUnforgeableMethods(aCx, ${holderName}, %s)) {
4386 failureCode
=failureCode
,
4387 holderName
=holderName
,
4390 unforgeableMembers
= [
4391 (defineUnforgeableAttrs
, properties
.unforgeableAttrs
),
4392 (defineUnforgeableMethods
, properties
.unforgeableMethods
),
4394 for (template
, array
) in unforgeableMembers
:
4395 if array
.hasNonChromeOnly():
4396 unforgeables
.append(CGGeneric(template
% array
.variableName(False)))
4397 if array
.hasChromeOnly():
4398 unforgeables
.append(
4400 CGGeneric(template
% array
.variableName(True)),
4401 "nsContentUtils::ThreadsafeIsSystemCaller(aCx)",
4405 if descriptor
.interface
.getExtendedAttribute("LegacyUnforgeable"):
4406 # We do our undefined toPrimitive here, not as a regular property
4407 # because we don't have a concept of value props anywhere in IDL.
4408 unforgeables
.append(
4412 JS::RootedId toPrimitive(aCx,
4413 SYMBOL_TO_JSID(JS::GetWellKnownSymbol(aCx, JS::SymbolCode::toPrimitive)));
4414 if (!JS_DefinePropertyById(aCx, ${holderName}, toPrimitive,
4415 JS::UndefinedHandleValue,
4416 JSPROP_READONLY | JSPROP_PERMANENT)) {
4420 failureCode
=failureCode
,
4421 holderName
=holderName
,
4426 return CGWrapper(CGList(unforgeables
), pre
="\n")
4429 def CopyUnforgeablePropertiesToInstance(descriptor
, failureCode
):
4431 Copy the unforgeable properties from the unforgeable holder for
4432 this interface to the instance object we have.
4434 assert not descriptor
.isGlobal()
4436 if not descriptor
.hasLegacyUnforgeableMembers
:
4443 // Important: do unforgeable property setup after we have handed
4444 // over ownership of the C++ object to obj as needed, so that if
4445 // we fail and it ends up GCed it won't have problems in the
4446 // finalizer trying to drop its ownership of the C++ object.
4452 # For proxies, we want to define on the expando object, not directly on the
4453 # reflector, so we can make sure we don't get confused by named getters.
4454 if descriptor
.proxy
:
4459 JS::Rooted<JSObject*> expando(aCx,
4460 DOMProxyHandler::EnsureExpandoObject(aCx, aReflector));
4465 failureCode
=failureCode
,
4477 JS::Rooted<JSObject*> unforgeableHolder(aCx,
4478 &JS::GetReservedSlot(canonicalProto, DOM_INTERFACE_PROTO_SLOTS_BASE).toObject());
4479 if (!JS_InitializePropertiesFromCompatibleNativeObject(aCx, ${obj}, unforgeableHolder)) {
4484 failureCode
=failureCode
,
4489 return CGWrapper(CGList(copyCode
), pre
="\n").define()
4492 def AssertInheritanceChain(descriptor
):
4494 iface
= descriptor
.interface
4496 desc
= descriptor
.getDescriptor(iface
.identifier
.name
)
4498 "MOZ_ASSERT(static_cast<%s*>(aObject) == \n"
4499 " reinterpret_cast<%s*>(aObject),\n"
4500 ' "Multiple inheritance for %s is broken.");\n'
4501 % (desc
.nativeType
, desc
.nativeType
, desc
.nativeType
)
4503 iface
= iface
.parent
4504 asserts
+= "MOZ_ASSERT(ToSupportsIsCorrect(aObject));\n"
4508 def InitMemberSlots(descriptor
, failureCode
):
4510 Initialize member slots on our JS object if we're supposed to have some.
4512 Note that this is called after the SetWrapper() call in the
4513 wrapperCache case, since that can affect how our getters behave
4514 and we plan to invoke them here. So if we fail, we need to
4517 if not descriptor
.interface
.hasMembersInSlots():
4521 if (!UpdateMemberSlots(aCx, aReflector, aObject)) {
4525 failureCode
=failureCode
,
4529 def DeclareProto(descriptor
):
4531 Declare the canonicalProto and proto we have for our wrapping operation.
4535 JS::Handle<JSObject*> canonicalProto = GetProtoObjectHandle(aCx);
4536 if (!canonicalProto) {
4539 JS::Rooted<JSObject*> proto(aCx);
4542 if descriptor
.isMaybeCrossOriginObject():
4543 return preamble
+ dedent(
4545 MOZ_ASSERT(!aGivenProto,
4546 "Shouldn't have constructors on cross-origin objects");
4547 // Set proto to canonicalProto to avoid preserving our wrapper if
4548 // we don't have to.
4549 proto = canonicalProto;
4553 return preamble
+ dedent(
4556 proto = aGivenProto;
4557 // Unfortunately, while aGivenProto was in the compartment of aCx
4558 // coming in, we changed compartments to that of "parent" so may need
4559 // to wrap the proto here.
4560 if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) {
4561 if (!JS_WrapObject(aCx, &proto)) {
4566 proto = canonicalProto;
4572 class CGWrapWithCacheMethod(CGAbstractMethod
):
4574 Create a wrapper JSObject for a given native that implements nsWrapperCache.
4576 properties should be a PropertyArrays instance.
4579 def __init__(self
, descriptor
, properties
):
4580 assert descriptor
.interface
.hasInterfacePrototypeObject()
4582 Argument("JSContext*", "aCx"),
4583 Argument(descriptor
.nativeType
+ "*", "aObject"),
4584 Argument("nsWrapperCache*", "aCache"),
4585 Argument("JS::Handle<JSObject*>", "aGivenProto"),
4586 Argument("JS::MutableHandle<JSObject*>", "aReflector"),
4588 CGAbstractMethod
.__init
__(self
, descriptor
, "Wrap", "bool", args
)
4589 self
.properties
= properties
4591 def definition_body(self
):
4592 failureCode
= dedent(
4594 aCache->ReleaseWrapper(aObject);
4595 aCache->ClearWrapper();
4600 if self
.descriptor
.proxy
:
4601 finalize
= "DOMProxyHandler::getInstance()->finalize"
4603 finalize
= FINALIZE_HOOK_NAME
4607 static_assert(!std::is_base_of_v<NonRefcountedDOMObject, ${nativeType}>,
4608 "Shouldn't have wrappercached things that are not refcounted.");
4609 $*{assertInheritance}
4610 MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx));
4611 MOZ_ASSERT(!aCache->GetWrapper(),
4612 "You should probably not be using Wrap() directly; use "
4613 "GetOrCreateDOMReflector instead");
4615 MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
4616 "nsISupports must be on our primary inheritance chain");
4618 // If the wrapper cache contains a dead reflector then finalize that
4619 // now, ensuring that the finalizer for the old reflector always
4620 // runs before the new reflector is created and attached. This
4621 // avoids the awkward situation where there are multiple reflector
4622 // objects that contain pointers to the same native.
4624 if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) {
4625 ${finalize}(nullptr /* unused */, oldReflector);
4626 MOZ_ASSERT(!aCache->GetWrapperMaybeDead());
4629 JS::Rooted<JSObject*> global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject()));
4633 MOZ_ASSERT(JS_IsGlobalObject(global));
4634 JS::AssertObjectIsNotGray(global);
4636 // That might have ended up wrapping us already, due to the wonders
4637 // of XBL. Check for that, and bail out as needed.
4638 aReflector.set(aCache->GetWrapper());
4641 AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto);
4646 JSAutoRealm ar(aCx, global);
4651 aCache->SetWrapper(aReflector);
4654 creator.InitializationSucceeded();
4656 MOZ_ASSERT(aCache->GetWrapperPreserveColor() &&
4657 aCache->GetWrapperPreserveColor() == aReflector);
4658 // If proto != canonicalProto, we have to preserve our wrapper;
4659 // otherwise we won't be able to properly recreate it later, since
4660 // we won't know what proto to use. Note that we don't check
4661 // aGivenProto here, since it's entirely possible (and even
4662 // somewhat common) to have a non-null aGivenProto which is the
4663 // same as canonicalProto.
4664 if (proto != canonicalProto) {
4665 PreserveWrapper(aObject);
4670 nativeType
=self
.descriptor
.nativeType
,
4671 assertInheritance
=AssertInheritanceChain(self
.descriptor
),
4672 declareProto
=DeclareProto(self
.descriptor
),
4673 createObject
=CreateBindingJSObject(self
.descriptor
, self
.properties
),
4674 unforgeable
=CopyUnforgeablePropertiesToInstance(
4675 self
.descriptor
, failureCode
4677 slots
=InitMemberSlots(self
.descriptor
, failureCode
),
4682 class CGWrapMethod(CGAbstractMethod
):
4683 def __init__(self
, descriptor
):
4684 # XXX can we wrap if we don't have an interface prototype object?
4685 assert descriptor
.interface
.hasInterfacePrototypeObject()
4687 Argument("JSContext*", "aCx"),
4688 Argument("T*", "aObject"),
4689 Argument("JS::Handle<JSObject*>", "aGivenProto"),
4691 CGAbstractMethod
.__init
__(
4698 templateArgs
=["class T"],
4701 def definition_body(self
):
4704 JS::Rooted<JSObject*> reflector(aCx);
4705 return Wrap(aCx, aObject, aObject, aGivenProto, &reflector) ? reflector.get() : nullptr;
4710 class CGWrapNonWrapperCacheMethod(CGAbstractMethod
):
4712 Create a wrapper JSObject for a given native that does not implement
4715 properties should be a PropertyArrays instance.
4718 def __init__(self
, descriptor
, properties
):
4719 # XXX can we wrap if we don't have an interface prototype object?
4720 assert descriptor
.interface
.hasInterfacePrototypeObject()
4722 Argument("JSContext*", "aCx"),
4723 Argument(descriptor
.nativeType
+ "*", "aObject"),
4724 Argument("JS::Handle<JSObject*>", "aGivenProto"),
4725 Argument("JS::MutableHandle<JSObject*>", "aReflector"),
4727 CGAbstractMethod
.__init
__(self
, descriptor
, "Wrap", "bool", args
)
4728 self
.properties
= properties
4730 def definition_body(self
):
4731 failureCode
= "return false;\n"
4736 MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx));
4738 JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
4747 creator.InitializationSucceeded();
4750 assertions
=AssertInheritanceChain(self
.descriptor
),
4751 declareProto
=DeclareProto(self
.descriptor
),
4752 createObject
=CreateBindingJSObject(self
.descriptor
, self
.properties
),
4753 unforgeable
=CopyUnforgeablePropertiesToInstance(
4754 self
.descriptor
, failureCode
4756 slots
=InitMemberSlots(self
.descriptor
, failureCode
),
4760 class CGWrapGlobalMethod(CGAbstractMethod
):
4762 Create a wrapper JSObject for a global. The global must implement
4765 properties should be a PropertyArrays instance.
4768 def __init__(self
, descriptor
, properties
):
4769 assert descriptor
.interface
.hasInterfacePrototypeObject()
4771 Argument("JSContext*", "aCx"),
4772 Argument(descriptor
.nativeType
+ "*", "aObject"),
4773 Argument("nsWrapperCache*", "aCache"),
4774 Argument("JS::RealmOptions&", "aOptions"),
4775 Argument("JSPrincipals*", "aPrincipal"),
4776 Argument("bool", "aInitStandardClasses"),
4777 Argument("JS::MutableHandle<JSObject*>", "aReflector"),
4779 CGAbstractMethod
.__init
__(self
, descriptor
, "Wrap", "bool", args
)
4780 self
.descriptor
= descriptor
4781 self
.properties
= properties
4783 def definition_body(self
):
4784 if self
.properties
.hasNonChromeOnly():
4785 properties
= "sNativeProperties.Upcast()"
4787 properties
= "nullptr"
4788 if self
.properties
.hasChromeOnly():
4789 chromeProperties
= "nsContentUtils::ThreadsafeIsSystemCaller(aCx) ? sChromeOnlyNativeProperties.Upcast() : nullptr"
4791 chromeProperties
= "nullptr"
4793 failureCode
= dedent(
4795 aCache->ReleaseWrapper(aObject);
4796 aCache->ClearWrapper();
4801 if self
.descriptor
.hasLegacyUnforgeableMembers
:
4802 unforgeable
= InitUnforgeablePropertiesOnHolder(
4803 self
.descriptor
, self
.properties
, failureCode
, "aReflector"
4811 MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
4812 "nsISupports must be on our primary inheritance chain");
4814 if (!CreateGlobal<${nativeType}, GetProtoObjectHandle>(aCx,
4820 aInitStandardClasses,
4825 // aReflector is a new global, so has a new realm. Enter it
4826 // before doing anything with it.
4827 JSAutoRealm ar(aCx, aReflector);
4829 if (!DefineProperties(aCx, aReflector, ${properties}, ${chromeProperties})) {
4838 assertions
=AssertInheritanceChain(self
.descriptor
),
4839 nativeType
=self
.descriptor
.nativeType
,
4840 properties
=properties
,
4841 chromeProperties
=chromeProperties
,
4842 failureCode
=failureCode
,
4843 unforgeable
=unforgeable
,
4844 slots
=InitMemberSlots(self
.descriptor
, failureCode
),
4848 class CGUpdateMemberSlotsMethod(CGAbstractStaticMethod
):
4849 def __init__(self
, descriptor
):
4851 Argument("JSContext*", "aCx"),
4852 Argument("JS::Handle<JSObject*>", "aWrapper"),
4853 Argument(descriptor
.nativeType
+ "*", "aObject"),
4855 CGAbstractStaticMethod
.__init
__(
4856 self
, descriptor
, "UpdateMemberSlots", "bool", args
4859 def definition_body(self
):
4860 body
= "JS::Rooted<JS::Value> temp(aCx);\n" "JSJitGetterCallArgs args(&temp);\n"
4861 for m
in self
.descriptor
.interface
.members
:
4862 if m
.isAttr() and m
.getExtendedAttribute("StoreInSlot"):
4863 # Skip doing this for the "window" and "self" attributes on the
4864 # Window interface, because those can't be gotten safely until
4865 # we have hooked it up correctly to the outer window. The
4866 # window code handles doing the get itself.
4867 if self
.descriptor
.interface
.identifier
.name
== "Window" and (
4868 m
.identifier
.name
== "window" or m
.identifier
.name
== "self"
4874 static_assert(${slot} < JS::shadow::Object::MAX_FIXED_SLOTS,
4875 "Not enough fixed slots to fit '${interface}.${member}. Ion's visitGetDOMMemberV/visitGetDOMMemberT assume StoreInSlot things are all in fixed slots.");
4876 if (!get_${member}(aCx, aWrapper, aObject, args)) {
4879 // Getter handled setting our reserved slots
4881 slot
=memberReservedSlot(m
, self
.descriptor
),
4882 interface
=self
.descriptor
.interface
.identifier
.name
,
4883 member
=m
.identifier
.name
,
4886 body
+= "\nreturn true;\n"
4890 class CGClearCachedValueMethod(CGAbstractMethod
):
4891 def __init__(self
, descriptor
, member
):
4892 self
.member
= member
4893 # If we're StoreInSlot, we'll need to call the getter
4894 if member
.getExtendedAttribute("StoreInSlot"):
4895 args
= [Argument("JSContext*", "aCx")]
4900 args
.append(Argument(descriptor
.nativeType
+ "*", "aObject"))
4901 name
= MakeClearCachedValueNativeName(member
)
4902 CGAbstractMethod
.__init
__(self
, descriptor
, name
, returnType
, args
)
4904 def definition_body(self
):
4905 slotIndex
= memberReservedSlot(self
.member
, self
.descriptor
)
4906 if self
.member
.getExtendedAttribute("StoreInSlot"):
4907 # We have to root things and save the old value in case
4908 # regetting fails, so we can restore it.
4909 declObj
= "JS::Rooted<JSObject*> obj(aCx);\n"
4910 noopRetval
= " true"
4912 "JS::Rooted<JS::Value> oldValue(aCx, JS::GetReservedSlot(obj, %s));\n"
4917 JS::Rooted<JS::Value> temp(aCx);
4918 JSJitGetterCallArgs args(&temp);
4919 JSAutoRealm ar(aCx, obj);
4920 if (!get_${name}(aCx, obj, aObject, args)) {
4921 JS::SetReservedSlot(obj, ${slotIndex}, oldValue);
4926 name
=self
.member
.identifier
.name
,
4927 slotIndex
=slotIndex
,
4930 declObj
= "JSObject* obj;\n"
4935 if self
.descriptor
.wantsXrays
:
4936 clearXrayExpandoSlots
= fill(
4938 xpc::ClearXrayExpandoSlots(obj, ${xraySlotIndex});
4940 xraySlotIndex
=memberXrayExpandoReservedSlot(
4941 self
.member
, self
.descriptor
4945 clearXrayExpandoSlots
= ""
4950 obj = aObject->GetWrapper();
4952 return${noopRetval};
4955 JS::SetReservedSlot(obj, ${slotIndex}, JS::UndefinedValue());
4956 $*{clearXrayExpandoSlots}
4960 noopRetval
=noopRetval
,
4961 saveMember
=saveMember
,
4962 slotIndex
=slotIndex
,
4963 clearXrayExpandoSlots
=clearXrayExpandoSlots
,
4964 regetMember
=regetMember
,
4968 class CGCrossOriginProperties(CGThing
):
4969 def __init__(self
, descriptor
):
4971 chromeOnlyAttrs
= []
4973 chromeOnlyMethods
= []
4974 for m
in descriptor
.interface
.members
:
4976 m
.getExtendedAttribute("CrossOriginReadable")
4977 or m
.getExtendedAttribute("CrossOriginWritable")
4981 "Don't know how to deal with static method %s"
4984 if PropertyDefiner
.getControllingCondition(
4988 "Don't know how to deal with disabler for %s"
4991 if len(m
.bindingAliases
) > 0:
4993 "Don't know how to deal with aliases for %s" % m
.identifier
.name
4995 if m
.getExtendedAttribute("ChromeOnly") is not None:
4996 chromeOnlyAttrs
.extend(AttrDefiner
.attrData(m
, overrideFlags
="0"))
4998 attrs
.extend(AttrDefiner
.attrData(m
, overrideFlags
="0"))
4999 elif m
.isMethod() and m
.getExtendedAttribute("CrossOriginCallable"):
5002 "Don't know how to deal with static method %s"
5005 if PropertyDefiner
.getControllingCondition(
5009 "Don't know how to deal with disabler for %s"
5012 if len(m
.aliases
) > 0:
5014 "Don't know how to deal with aliases for %s" % m
.identifier
.name
5016 if m
.getExtendedAttribute("ChromeOnly") is not None:
5017 chromeOnlyMethods
.append(
5018 MethodDefiner
.methodData(
5019 m
, descriptor
, overrideFlags
="JSPROP_READONLY"
5024 MethodDefiner
.methodData(
5025 m
, descriptor
, overrideFlags
="JSPROP_READONLY"
5030 self
.attributeSpecs
, _
= PropertyDefiner
.generatePrefableArrayValues(
5033 AttrDefiner
.formatSpec
,
5035 AttrDefiner
.condition
,
5036 functools
.partial(AttrDefiner
.specData
, crossOriginOnly
=True),
5039 self
.attributeSpecs
= [" JS_PS_END\n"]
5040 if len(methods
) > 0:
5041 self
.methodSpecs
, _
= PropertyDefiner
.generatePrefableArrayValues(
5044 MethodDefiner
.formatSpec
,
5046 MethodDefiner
.condition
,
5047 MethodDefiner
.specData
,
5050 self
.methodSpecs
= [" JS_FS_END\n"]
5052 if len(chromeOnlyAttrs
) > 0:
5054 self
.chromeOnlyAttributeSpecs
,
5056 ) = PropertyDefiner
.generatePrefableArrayValues(
5059 AttrDefiner
.formatSpec
,
5061 AttrDefiner
.condition
,
5062 functools
.partial(AttrDefiner
.specData
, crossOriginOnly
=True),
5065 self
.chromeOnlyAttributeSpecs
= []
5066 if len(chromeOnlyMethods
) > 0:
5067 self
.chromeOnlyMethodSpecs
, _
= PropertyDefiner
.generatePrefableArrayValues(
5070 MethodDefiner
.formatSpec
,
5072 MethodDefiner
.condition
,
5073 MethodDefiner
.specData
,
5076 self
.chromeOnlyMethodSpecs
= []
5081 extern const CrossOriginProperties sCrossOriginProperties;
5086 def defineChromeOnly(name
, specs
, specType
):
5088 return ("", "nullptr")
5089 name
= "sChromeOnlyCrossOrigin" + name
5092 static const ${specType} ${name}[] = {
5098 specs
=",\n".join(specs
),
5100 return (define
, name
)
5102 chromeOnlyAttributes
= defineChromeOnly(
5103 "Attributes", self
.chromeOnlyAttributeSpecs
, "JSPropertySpec"
5105 chromeOnlyMethods
= defineChromeOnly(
5106 "Methods", self
.chromeOnlyMethodSpecs
, "JSFunctionSpec"
5110 // We deliberately use brace-elision to make Visual Studio produce better initalization code.
5111 static const JSPropertySpec sCrossOriginAttributes[] = {
5114 static const JSFunctionSpec sCrossOriginMethods[] = {
5117 $*{chromeOnlyAttributeSpecs}
5118 $*{chromeOnlyMethodSpecs}
5119 const CrossOriginProperties sCrossOriginProperties = {
5120 sCrossOriginAttributes,
5121 sCrossOriginMethods,
5122 ${chromeOnlyAttributes},
5123 ${chromeOnlyMethods}
5126 attributeSpecs
=",\n".join(self
.attributeSpecs
),
5127 methodSpecs
=",\n".join(self
.methodSpecs
),
5128 chromeOnlyAttributeSpecs
=chromeOnlyAttributes
[0],
5129 chromeOnlyMethodSpecs
=chromeOnlyMethods
[0],
5130 chromeOnlyAttributes
=chromeOnlyAttributes
[1],
5131 chromeOnlyMethods
=chromeOnlyMethods
[1],
5135 class CGCycleCollectionTraverseForOwningUnionMethod(CGAbstractMethod
):
5137 ImplCycleCollectionUnlink for owning union type.
5140 def __init__(self
, type):
5143 Argument("nsCycleCollectionTraversalCallback&", "aCallback"),
5144 Argument("%s&" % CGUnionStruct
.unionTypeName(type, True), "aUnion"),
5145 Argument("const char*", "aName"),
5146 Argument("uint32_t", "aFlags", "0"),
5148 CGAbstractMethod
.__init
__(
5149 self
, None, "ImplCycleCollectionTraverse", "void", args
5153 return self
.type.getDeps()
5155 def definition_body(self
):
5157 getUnionMemberName(t
)
5158 for t
in self
.type.flatMemberTypes
5159 if idlTypeNeedsCycleCollection(t
)
5163 conditionTemplate
= "aUnion.Is%s()"
5164 functionCallTemplate
= (
5165 'ImplCycleCollectionTraverse(aCallback, aUnion.GetAs%s(), "m%s", aFlags);\n'
5169 CGIfWrapper(CGGeneric(functionCallTemplate
% (m
, m
)), conditionTemplate
% m
)
5170 for m
in memberNames
5173 return CGElseChain(ifStaments
).define()
5176 class CGCycleCollectionUnlinkForOwningUnionMethod(CGAbstractMethod
):
5178 ImplCycleCollectionUnlink for owning union type.
5181 def __init__(self
, type):
5183 args
= [Argument("%s&" % CGUnionStruct
.unionTypeName(type, True), "aUnion")]
5184 CGAbstractMethod
.__init
__(self
, None, "ImplCycleCollectionUnlink", "void", args
)
5187 return self
.type.getDeps()
5189 def definition_body(self
):
5190 return "aUnion.Uninit();\n"
5194 IDLType
.Tags
.bool: "bool",
5195 IDLType
.Tags
.int8
: "int8_t",
5196 IDLType
.Tags
.int16
: "int16_t",
5197 IDLType
.Tags
.int32
: "int32_t",
5198 IDLType
.Tags
.int64
: "int64_t",
5199 IDLType
.Tags
.uint8
: "uint8_t",
5200 IDLType
.Tags
.uint16
: "uint16_t",
5201 IDLType
.Tags
.uint32
: "uint32_t",
5202 IDLType
.Tags
.uint64
: "uint64_t",
5203 IDLType
.Tags
.unrestricted_float
: "float",
5204 IDLType
.Tags
.float: "float",
5205 IDLType
.Tags
.unrestricted_double
: "double",
5206 IDLType
.Tags
.double
: "double",
5210 IDLType
.Tags
.int8
: "",
5211 IDLType
.Tags
.uint8
: "",
5212 IDLType
.Tags
.int16
: "",
5213 IDLType
.Tags
.uint16
: "",
5214 IDLType
.Tags
.int32
: "",
5215 IDLType
.Tags
.uint32
: "U",
5216 IDLType
.Tags
.int64
: "LL",
5217 IDLType
.Tags
.uint64
: "ULL",
5218 IDLType
.Tags
.unrestricted_float
: "F",
5219 IDLType
.Tags
.float: "F",
5220 IDLType
.Tags
.unrestricted_double
: "",
5221 IDLType
.Tags
.double
: "",
5225 def numericValue(t
, v
):
5226 if t
== IDLType
.Tags
.unrestricted_double
or t
== IDLType
.Tags
.unrestricted_float
:
5227 typeName
= builtinNames
[t
]
5228 if v
== float("inf"):
5229 return "mozilla::PositiveInfinity<%s>()" % typeName
5230 if v
== float("-inf"):
5231 return "mozilla::NegativeInfinity<%s>()" % typeName
5233 return "mozilla::UnspecifiedNaN<%s>()" % typeName
5234 return "%s%s" % (v
, numericSuffixes
[t
])
5237 class CastableObjectUnwrapper
:
5239 A class for unwrapping an object stored in a JS Value (or
5240 MutableHandle<Value> or Handle<Value>) named by the "source" and
5241 "mutableSource" arguments based on the passed-in descriptor and storing it
5242 in a variable called by the name in the "target" argument. The "source"
5243 argument should be able to produce a Value or Handle<Value>; the
5244 "mutableSource" argument should be able to produce a MutableHandle<Value>
5246 codeOnFailure is the code to run if unwrapping fails.
5248 If isCallbackReturnValue is "JSImpl" and our descriptor is also
5249 JS-implemented, fall back to just creating the right object if what we
5250 have isn't one already.
5261 isCallbackReturnValue
=False,
5263 self
.substitution
= {
5264 "type": descriptor
.nativeType
,
5265 "protoID": "prototypes::id::" + descriptor
.name
,
5267 "codeOnFailure": codeOnFailure
,
5269 "mutableSource": mutableSource
,
5272 if isCallbackReturnValue
== "JSImpl" and descriptor
.interface
.isJSImplemented():
5273 exceptionCode
= exceptionCode
or codeOnFailure
5274 self
.substitution
["codeOnFailure"] = fill(
5276 // Be careful to not wrap random DOM objects here, even if
5277 // they're wrapped in opaque security wrappers for some reason.
5278 // XXXbz Wish we could check for a JS-implemented object
5279 // that already has a content reflection...
5280 if (!IsDOMObject(js::UncheckedUnwrap(&${source}.toObject()))) {
5281 nsCOMPtr<nsIGlobalObject> contentGlobal;
5282 JS::Rooted<JSObject*> callback(cx, CallbackOrNull());
5284 !GetContentGlobalForJSImplementedObject(cx, callback, getter_AddRefs(contentGlobal))) {
5287 JS::Rooted<JSObject*> jsImplSourceObj(cx, &${source}.toObject());
5288 MOZ_RELEASE_ASSERT(!js::IsWrapper(jsImplSourceObj),
5289 "Don't return JS implementations from other compartments");
5290 JS::Rooted<JSObject*> jsImplSourceGlobal(cx, JS::GetNonCCWObjectGlobal(jsImplSourceObj));
5291 ${target} = new ${type}(jsImplSourceObj, jsImplSourceGlobal, contentGlobal);
5296 exceptionCode
=exceptionCode
,
5300 self
.substitution
["codeOnFailure"] = codeOnFailure
5303 substitution
= self
.substitution
.copy()
5304 substitution
["codeOnFailure"] %= {
5305 "securityError": "rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO"
5310 // Our JSContext should be in the right global to do unwrapping in.
5311 nsresult rv = UnwrapObject<${protoID}, ${type}>(${mutableSource}, ${target}, cx);
5312 if (NS_FAILED(rv)) {
5321 class FailureFatalCastableObjectUnwrapper(CastableObjectUnwrapper
):
5323 As CastableObjectUnwrapper, but defaulting to throwing if unwrapping fails
5333 isCallbackReturnValue
,
5336 CastableObjectUnwrapper
.__init
__(
5342 'cx.ThrowErrorMessage<MSG_DOES_NOT_IMPLEMENT_INTERFACE>("%s", "%s");\n'
5344 % (sourceDescription
, descriptor
.interface
.identifier
.name
, exceptionCode
),
5346 isCallbackReturnValue
,
5350 def getCallbackConversionInfo(
5351 type, idlObject
, isMember
, isCallbackReturnValue
, isOptional
5354 Returns a tuple containing the declType, declArgs, and basic
5355 conversion for the given callback type, with the given callback
5356 idl object in the given context (isMember/isCallbackReturnValue/isOptional).
5358 name
= idlObject
.identifier
.name
5360 # We can't use fast callbacks if isOptional because then we get an
5361 # Optional<RootedCallback> thing, which is not transparent to consumers.
5362 useFastCallback
= not isMember
and not isCallbackReturnValue
and not isOptional
5364 name
= "binding_detail::Fast%s" % name
5366 args
= "&${val}.toObject(), JS::CurrentGlobalOrNull(cx)"
5370 JS::Rooted<JSObject*> tempRoot(cx, &${val}.toObject());
5371 JS::Rooted<JSObject*> tempGlobalRoot(cx, JS::CurrentGlobalOrNull(cx));
5374 args
= "cx, tempRoot, tempGlobalRoot, GetIncumbentGlobal()"
5376 if type.nullable() or isCallbackReturnValue
:
5377 declType
= CGGeneric("RefPtr<%s>" % name
)
5379 declType
= CGGeneric("OwningNonNull<%s>" % name
)
5382 declType
= CGTemplatedType("RootedCallback", declType
)
5389 { // scope for tempRoot and tempGlobalRoot if needed
5391 $${declName} = new ${name}(${args});
5398 return (declType
, declArgs
, conversion
)
5401 class JSToNativeConversionInfo
:
5403 An object representing information about a JS-to-native conversion.
5411 dealWithOptional
=False,
5416 template: A string representing the conversion code. This will have
5417 template substitution performed on it as follows:
5419 ${val} is a handle to the JS::Value in question
5420 ${maybeMutableVal} May be a mutable handle to the JS::Value in
5421 question. This is only OK to use if ${val} is
5422 known to not be undefined.
5423 ${holderName} replaced by the holder's name, if any
5424 ${declName} replaced by the declaration's name
5425 ${haveValue} replaced by an expression that evaluates to a boolean
5426 for whether we have a JS::Value. Only used when
5427 defaultValue is not None or when True is passed for
5428 checkForValue to instantiateJSToNativeConversion.
5429 This expression may not be already-parenthesized, so if
5430 you use it with && or || make sure to put parens
5432 ${passedToJSImpl} replaced by an expression that evaluates to a boolean
5433 for whether this value is being passed to a JS-
5434 implemented interface.
5436 declType: A CGThing representing the native C++ type we're converting
5437 to. This is allowed to be None if the conversion code is
5438 supposed to be used as-is.
5440 holderType: A CGThing representing the type of a "holder" which will
5441 hold a possible reference to the C++ thing whose type we
5442 returned in declType, or None if no such holder is needed.
5444 dealWithOptional: A boolean indicating whether the caller has to do
5445 optional-argument handling. This should only be set
5446 to true if the JS-to-native conversion is being done
5447 for an optional argument or dictionary member with no
5448 default value and if the returned template expects
5449 both declType and holderType to be wrapped in
5450 Optional<>, with ${declName} and ${holderName}
5451 adjusted to point to the Value() of the Optional, and
5452 Construct() calls to be made on the Optional<>s as
5455 declArgs: If not None, the arguments to pass to the ${declName}
5456 constructor. These will have template substitution performed
5457 on them so you can use things like ${val}. This is a
5458 single string, not a list of strings.
5460 holderArgs: If not None, the arguments to pass to the ${holderName}
5461 constructor. These will have template substitution
5462 performed on them so you can use things like ${val}.
5463 This is a single string, not a list of strings.
5465 ${declName} must be in scope before the code from 'template' is entered.
5467 If holderType is not None then ${holderName} must be in scope before
5468 the code from 'template' is entered.
5470 assert isinstance(template
, str)
5471 assert declType
is None or isinstance(declType
, CGThing
)
5472 assert holderType
is None or isinstance(holderType
, CGThing
)
5473 self
.template
= template
5474 self
.declType
= declType
5475 self
.holderType
= holderType
5476 self
.dealWithOptional
= dealWithOptional
5477 self
.declArgs
= declArgs
5478 self
.holderArgs
= holderArgs
5481 def getHandleDefault(defaultValue
):
5482 tag
= defaultValue
.type.tag()
5483 if tag
in numericSuffixes
:
5484 # Some numeric literals require a suffix to compile without warnings
5485 return numericValue(tag
, defaultValue
.value
)
5486 assert tag
== IDLType
.Tags
.bool
5487 return toStringBool(defaultValue
.value
)
5490 def handleDefaultStringValue(defaultValue
, method
):
5492 Returns a string which ends up calling 'method' with a (char_t*, length)
5493 pair that sets this string default value. This string is suitable for
5494 passing as the second argument of handleDefault.
5497 defaultValue
.type.isDOMString()
5498 or defaultValue
.type.isUSVString()
5499 or defaultValue
.type.isUTF8String()
5500 or defaultValue
.type.isByteString()
5502 # There shouldn't be any non-ASCII or embedded nulls in here; if
5503 # it ever sneaks in we will need to think about how to properly
5504 # represent that in the C++.
5505 assert all(ord(c
) < 128 and ord(c
) > 0 for c
in defaultValue
.value
)
5506 if defaultValue
.type.isByteString() or defaultValue
.type.isUTF8String():
5512 ${method}(${prefix}"${value}");
5516 value
=defaultValue
.value
,
5520 def recordKeyType(recordType
):
5521 assert recordType
.keyType
.isString()
5522 if recordType
.keyType
.isByteString() or recordType
.keyType
.isUTF8String():
5527 def recordKeyDeclType(recordType
):
5528 return CGGeneric(recordKeyType(recordType
))
5531 def initializerForType(type):
5533 Get the right initializer for the given type for a data location where we
5534 plan to then initialize it from a JS::Value. Some types need to always be
5535 initialized even before we start the JS::Value-to-IDL-value conversion.
5537 Returns a string or None if no initialization is needed.
5541 # We could probably return CGDictionary.getNonInitializingCtorArg() for the
5542 # dictionary case, but code outside DictionaryBase subclasses can't use
5543 # that, so we can't do it across the board.
5547 # If this function is modified, modify CGNativeMember.getArg and
5548 # CGNativeMember.getRetvalInfo accordingly. The latter cares about the decltype
5549 # and holdertype we end up using, because it needs to be able to return the code
5550 # that will convert those to the actual return value of the callback function.
5551 def getJSToNativeConversionInfo(
5555 isDefinitelyObject
=False,
5558 invalidEnumValueFatal
=True,
5560 isNullOrUndefined
=False,
5561 isKnownMissing
=False,
5563 lenientFloatCode
=None,
5564 allowTreatNonCallableAsNull
=False,
5565 isCallbackReturnValue
=False,
5566 sourceDescription
="value",
5570 Get a template for converting a JS value to a native object based on the
5571 given type and descriptor. If failureCode is given, then we're actually
5572 testing whether we can convert the argument to the desired type. That
5573 means that failures to convert due to the JS value being the wrong type of
5574 value need to use failureCode instead of throwing exceptions. Failures to
5575 convert that are due to JS exceptions (from toString or valueOf methods) or
5576 out of memory conditions need to throw exceptions no matter what
5577 failureCode is. However what actually happens when throwing an exception
5578 can be controlled by exceptionCode. The only requirement on that is that
5579 exceptionCode must end up doing a return, and every return from this
5580 function must happen via exceptionCode if exceptionCode is not None.
5582 If isDefinitelyObject is True, that means we have a value and the value
5583 tests true for isObject(), so we have no need to recheck that.
5585 If isNullOrUndefined is True, that means we have a value and the value
5586 tests true for isNullOrUndefined(), so we have no need to recheck that.
5588 If isKnownMissing is True, that means that we are known-missing, and for
5589 cases when we have a default value we only need to output the default value.
5591 if isMember is not False, we're being converted from a property of some JS
5592 object, not from an actual method argument, so we can't rely on our jsval
5593 being rooted or outliving us in any way. Callers can pass "Dictionary",
5594 "Variadic", "Sequence", or "OwningUnion" to indicate that the conversion is
5595 for something that is a dictionary member, a variadic argument, a sequence,
5596 or an owning union respectively.
5598 If isOptional is true, then we are doing conversion of an optional
5599 argument with no default value.
5601 invalidEnumValueFatal controls whether an invalid enum value conversion
5602 attempt will throw (if true) or simply return without doing anything (if
5605 If defaultValue is not None, it's the IDL default value for this conversion
5607 If isEnforceRange is true, we're converting an integer and throwing if the
5608 value is out of range.
5610 If isClamp is true, we're converting an integer and clamping if the
5611 value is out of range.
5613 If isAllowShared is false, we're converting a buffer source and throwing if
5614 it is a SharedArrayBuffer or backed by a SharedArrayBuffer.
5616 If lenientFloatCode is not None, it should be used in cases when
5617 we're a non-finite float that's not unrestricted.
5619 If allowTreatNonCallableAsNull is true, then [TreatNonCallableAsNull] and
5620 [LegacyTreatNonObjectAsNull] extended attributes on nullable callback functions
5623 If isCallbackReturnValue is "JSImpl" or "Callback", then the declType may be
5624 adjusted to make it easier to return from a callback. Since that type is
5625 never directly observable by any consumers of the callback code, this is OK.
5626 Furthermore, if isCallbackReturnValue is "JSImpl", that affects the behavior
5627 of the FailureFatalCastableObjectUnwrapper conversion; this is used for
5628 implementing auto-wrapping of JS-implemented return values from a
5629 JS-implemented interface.
5631 sourceDescription is a description of what this JS value represents, to be
5632 used in error reporting. Callers should assume that it might get placed in
5633 the middle of a sentence. If it ends up at the beginning of a sentence, its
5634 first character will be automatically uppercased.
5636 The return value from this function is a JSToNativeConversionInfo.
5638 # If we have a defaultValue then we're not actually optional for
5639 # purposes of what we need to be declared as.
5640 assert defaultValue
is None or not isOptional
5642 # Also, we should not have a defaultValue if we know we're an object
5643 assert not isDefinitelyObject
or defaultValue
is None
5645 # And we can't both be an object and be null or undefined
5646 assert not isDefinitelyObject
or not isNullOrUndefined
5648 isClamp
= type.hasClamp()
5649 isEnforceRange
= type.hasEnforceRange()
5650 isAllowShared
= type.hasAllowShared()
5652 # If exceptionCode is not set, we'll just rethrow the exception we got.
5653 # Note that we can't just set failureCode to exceptionCode, because setting
5654 # failureCode will prevent pending exceptions from being set in cases when
5655 # they really should be!
5656 if exceptionCode
is None:
5657 exceptionCode
= "return false;\n"
5659 # Unfortunately, .capitalize() on a string will lowercase things inside the
5660 # string, which we do not want.
5661 def firstCap(string
):
5662 return string
[0].upper() + string
[1:]
5664 # Helper functions for dealing with failures due to the JS value being the
5665 # wrong type of value
5666 def onFailureNotAnObject(failureCode
):
5670 'cx.ThrowErrorMessage<MSG_NOT_OBJECT>("%s");\n'
5671 "%s" % (firstCap(sourceDescription
), exceptionCode
)
5675 def onFailureBadType(failureCode
, typeName
):
5679 'cx.ThrowErrorMessage<MSG_DOES_NOT_IMPLEMENT_INTERFACE>("%s", "%s");\n'
5680 "%s" % (firstCap(sourceDescription
), typeName
, exceptionCode
)
5684 # It's a failure in the committed-to conversion, not a failure to match up
5685 # to a type, so we don't want to use failureCode in here. We want to just
5686 # throw an exception unconditionally.
5687 def onFailureIsShared():
5689 'cx.ThrowErrorMessage<MSG_TYPEDARRAY_IS_SHARED>("%s");\n'
5690 "%s" % (firstCap(sourceDescription
), exceptionCode
)
5693 def onFailureIsLarge():
5695 'cx.ThrowErrorMessage<MSG_TYPEDARRAY_IS_LARGE>("%s");\n'
5696 "%s" % (firstCap(sourceDescription
), exceptionCode
)
5699 def onFailureNotCallable(failureCode
):
5703 'cx.ThrowErrorMessage<MSG_NOT_CALLABLE>("%s");\n'
5704 "%s" % (firstCap(sourceDescription
), exceptionCode
)
5708 # A helper function for handling default values. Takes a template
5709 # body and the C++ code to set the default value and wraps the
5710 # given template body in handling for the default value.
5711 def handleDefault(template
, setDefault
):
5712 if defaultValue
is None:
5718 // scope for any temporaries our default value setting needs.
5722 setDefault
=setDefault
,
5726 if ($${haveValue}) {
5732 templateBody
=template
,
5733 setDefault
=setDefault
,
5736 # A helper function for wrapping up the template body for
5737 # possibly-nullable objecty stuff
5738 def wrapObjectTemplate(templateBody
, type, codeToSetNull
, failureCode
=None):
5739 if isNullOrUndefined
and type.nullable():
5740 # Just ignore templateBody and set ourselves to null.
5741 # Note that we don't have to worry about default values
5742 # here either, since we already examined this value.
5743 return codeToSetNull
5745 if not isDefinitelyObject
:
5746 # Handle the non-object cases by wrapping up the whole
5747 # thing in an if cascade.
5749 elifLine
= "} else if (${val}.isNullOrUndefined()) {\n"
5750 elifBody
= codeToSetNull
5755 # Note that $${val} below expands to ${val}. This string is
5756 # used as a template later, and val will be filled in then.
5757 templateBody
= fill(
5759 if ($${val}.isObject()) {
5767 templateBody
=templateBody
,
5770 failureBody
=onFailureNotAnObject(failureCode
).define(),
5773 if isinstance(defaultValue
, IDLNullValue
):
5774 assert type.nullable() # Parser should enforce this
5775 templateBody
= handleDefault(templateBody
, codeToSetNull
)
5776 elif isinstance(defaultValue
, IDLEmptySequenceValue
):
5777 # Our caller will handle it
5780 assert defaultValue
is None
5784 # A helper function for converting things that look like a JSObject*.
5785 def handleJSObjectType(
5786 type, isMember
, failureCode
, exceptionCode
, sourceDescription
5790 # We have a specialization of Optional that will use a
5791 # Rooted for the storage here.
5792 declType
= CGGeneric("JS::Handle<JSObject*>")
5794 declType
= CGGeneric("JS::Rooted<JSObject*>")
5797 assert isMember
in (
5804 # We'll get traced by the sequence or dictionary or union tracer
5805 declType
= CGGeneric("JSObject*")
5807 templateBody
= "${declName} = &${val}.toObject();\n"
5809 # For JS-implemented APIs, we refuse to allow passing objects that the
5810 # API consumer does not subsume. The extra parens around
5811 # ($${passedToJSImpl}) suppress unreachable code warnings when
5812 # $${passedToJSImpl} is the literal `false`. But Apple is shipping a
5813 # buggy clang (clang 3.9) in Xcode 8.3, so there even the parens are not
5814 # enough. So we manually disable some warnings in clang.
5816 not isinstance(descriptorProvider
, Descriptor
)
5817 or descriptorProvider
.interface
.isJSImplemented()
5823 #pragma clang diagnostic push
5824 #pragma clang diagnostic ignored "-Wunreachable-code"
5825 #pragma clang diagnostic ignored "-Wunreachable-code-return"
5827 if (($${passedToJSImpl}) && !CallerSubsumes($${val})) {
5828 cx.ThrowErrorMessage<MSG_PERMISSION_DENIED_TO_PASS_ARG>("${sourceDescription}");
5832 #pragma clang diagnostic pop
5835 sourceDescription
=sourceDescription
,
5836 exceptionCode
=exceptionCode
,
5841 setToNullCode
= "${declName} = nullptr;\n"
5842 template
= wrapObjectTemplate(templateBody
, type, setToNullCode
, failureCode
)
5843 return JSToNativeConversionInfo(
5844 template
, declType
=declType
, dealWithOptional
=isOptional
, declArgs
=declArgs
5847 def incrementNestingLevel():
5848 if nestingLevel
== "":
5850 return nestingLevel
+ 1
5852 assert not (isEnforceRange
and isClamp
) # These are mutually exclusive
5854 if type.isSequence():
5855 assert not isEnforceRange
and not isClamp
and not isAllowShared
5857 if failureCode
is None:
5858 notSequence
= 'cx.ThrowErrorMessage<MSG_NOT_SEQUENCE>("%s");\n' "%s" % (
5859 firstCap(sourceDescription
),
5863 notSequence
= failureCode
5865 nullable
= type.nullable()
5866 # Be very careful not to change "type": we need it later
5868 elementType
= type.inner
.inner
5870 elementType
= type.inner
5872 # We want to use auto arrays if we can, but we have to be careful with
5873 # reallocation behavior for arrays. In particular, if we use auto
5874 # arrays for sequences and have a sequence of elements which are
5875 # themselves sequences or have sequences as members, we have a problem.
5876 # In that case, resizing the outermost AutoTArray to the right size
5877 # will memmove its elements, but AutoTArrays are not memmovable and
5878 # hence will end up with pointers to bogus memory, which is bad. To
5879 # deal with this, we typically map WebIDL sequences to our Sequence
5880 # type, which is in fact memmovable. The one exception is when we're
5881 # passing in a sequence directly as an argument without any sort of
5882 # optional or nullable complexity going on. In that situation, we can
5883 # use an AutoSequence instead. We have to keep using Sequence in the
5884 # nullable and optional cases because we don't want to leak the
5885 # AutoSequence type to consumers, which would be unavoidable with
5886 # Nullable<AutoSequence> or Optional<AutoSequence>.
5887 if isMember
or isOptional
or nullable
or isCallbackReturnValue
:
5888 sequenceClass
= "Sequence"
5890 sequenceClass
= "binding_detail::AutoSequence"
5892 # XXXbz we can't include the index in the sourceDescription, because
5893 # we don't really have a way to pass one in dynamically at runtime...
5894 elementInfo
= getJSToNativeConversionInfo(
5897 isMember
="Sequence",
5898 exceptionCode
=exceptionCode
,
5899 lenientFloatCode
=lenientFloatCode
,
5900 isCallbackReturnValue
=isCallbackReturnValue
,
5901 sourceDescription
="element of %s" % sourceDescription
,
5902 nestingLevel
=incrementNestingLevel(),
5904 if elementInfo
.dealWithOptional
:
5905 raise TypeError("Shouldn't have optional things in sequences")
5906 if elementInfo
.holderType
is not None:
5907 raise TypeError("Shouldn't need holders for sequences")
5909 typeName
= CGTemplatedType(sequenceClass
, elementInfo
.declType
)
5910 sequenceType
= typeName
.define()
5912 typeName
= CGTemplatedType("Nullable", typeName
)
5913 arrayRef
= "${declName}.SetValue()"
5915 arrayRef
= "${declName}"
5917 elementConversion
= string
.Template(elementInfo
.template
).substitute(
5919 "val": "temp" + str(nestingLevel
),
5920 "maybeMutableVal": "&temp" + str(nestingLevel
),
5921 "declName": "slot" + str(nestingLevel
),
5922 # We only need holderName here to handle isExternal()
5923 # interfaces, which use an internal holder for the
5924 # conversion even when forceOwningType ends up true.
5925 "holderName": "tempHolder" + str(nestingLevel
),
5926 "passedToJSImpl": "${passedToJSImpl}",
5930 elementInitializer
= initializerForType(elementType
)
5931 if elementInitializer
is None:
5932 elementInitializer
= ""
5934 elementInitializer
= elementInitializer
+ ", "
5936 # NOTE: Keep this in sync with variadic conversions as needed
5937 templateBody
= fill(
5939 JS::ForOfIterator iter${nestingLevel}(cx);
5940 if (!iter${nestingLevel}.init($${val}, JS::ForOfIterator::AllowNonIterable)) {
5943 if (!iter${nestingLevel}.valueIsIterable()) {
5946 ${sequenceType} &arr${nestingLevel} = ${arrayRef};
5947 JS::Rooted<JS::Value> temp${nestingLevel}(cx);
5949 bool done${nestingLevel};
5950 if (!iter${nestingLevel}.next(&temp${nestingLevel}, &done${nestingLevel})) {
5953 if (done${nestingLevel}) {
5956 ${elementType}* slotPtr${nestingLevel} = arr${nestingLevel}.AppendElement(${elementInitializer}mozilla::fallible);
5957 if (!slotPtr${nestingLevel}) {
5958 JS_ReportOutOfMemory(cx);
5961 ${elementType}& slot${nestingLevel} = *slotPtr${nestingLevel};
5962 $*{elementConversion}
5965 exceptionCode
=exceptionCode
,
5966 notSequence
=notSequence
,
5967 sequenceType
=sequenceType
,
5969 elementType
=elementInfo
.declType
.define(),
5970 elementConversion
=elementConversion
,
5971 elementInitializer
=elementInitializer
,
5972 nestingLevel
=str(nestingLevel
),
5975 templateBody
= wrapObjectTemplate(
5976 templateBody
, type, "${declName}.SetNull();\n", notSequence
5978 if isinstance(defaultValue
, IDLEmptySequenceValue
):
5980 codeToSetEmpty
= "${declName}.SetValue();\n"
5983 "/* ${declName} array is already empty; nothing to do */\n"
5985 templateBody
= handleDefault(templateBody
, codeToSetEmpty
)
5987 # Sequence arguments that might contain traceable things need
5989 if not isMember
and typeNeedsRooting(elementType
):
5990 holderType
= CGTemplatedType("SequenceRooter", elementInfo
.declType
)
5991 # If our sequence is nullable, this will set the Nullable to be
5992 # not-null, but that's ok because we make an explicit SetNull() call
5993 # on it as needed if our JS value is actually null.
5994 holderArgs
= "cx, &%s" % arrayRef
5999 return JSToNativeConversionInfo(
6002 holderType
=holderType
,
6003 dealWithOptional
=isOptional
,
6004 holderArgs
=holderArgs
,
6008 assert not isEnforceRange
and not isClamp
and not isAllowShared
6009 if failureCode
is None:
6010 notRecord
= 'cx.ThrowErrorMessage<MSG_NOT_OBJECT>("%s");\n' "%s" % (
6011 firstCap(sourceDescription
),
6015 notRecord
= failureCode
6017 nullable
= type.nullable()
6018 # Be very careful not to change "type": we need it later
6020 recordType
= type.inner
6023 valueType
= recordType
.inner
6025 valueInfo
= getJSToNativeConversionInfo(
6029 exceptionCode
=exceptionCode
,
6030 lenientFloatCode
=lenientFloatCode
,
6031 isCallbackReturnValue
=isCallbackReturnValue
,
6032 sourceDescription
="value in %s" % sourceDescription
,
6033 nestingLevel
=incrementNestingLevel(),
6035 if valueInfo
.dealWithOptional
:
6036 raise TypeError("Shouldn't have optional things in record")
6037 if valueInfo
.holderType
is not None:
6038 raise TypeError("Shouldn't need holders for record")
6040 declType
= CGTemplatedType(
6041 "Record", [recordKeyDeclType(recordType
), valueInfo
.declType
]
6043 typeName
= declType
.define()
6045 declType
= CGTemplatedType("Nullable", declType
)
6046 recordRef
= "${declName}.SetValue()"
6048 recordRef
= "${declName}"
6050 valueConversion
= string
.Template(valueInfo
.template
).substitute(
6053 "maybeMutableVal": "&temp",
6055 # We only need holderName here to handle isExternal()
6056 # interfaces, which use an internal holder for the
6057 # conversion even when forceOwningType ends up true.
6058 "holderName": "tempHolder",
6059 "passedToJSImpl": "${passedToJSImpl}",
6063 keyType
= recordKeyType(recordType
)
6064 if recordType
.keyType
.isJSString():
6066 "Have do deal with JSString record type, but don't know how"
6068 if recordType
.keyType
.isByteString() or recordType
.keyType
.isUTF8String():
6069 hashKeyType
= "nsCStringHashKey"
6070 if recordType
.keyType
.isByteString():
6071 keyConversionFunction
= "ConvertJSValueToByteString"
6073 keyConversionFunction
= "ConvertJSValueToString"
6076 hashKeyType
= "nsStringHashKey"
6077 if recordType
.keyType
.isDOMString():
6078 keyConversionFunction
= "ConvertJSValueToString"
6080 assert recordType
.keyType
.isUSVString()
6081 keyConversionFunction
= "ConvertJSValueToUSVString"
6083 templateBody
= fill(
6085 auto& recordEntries = ${recordRef}.Entries();
6087 JS::Rooted<JSObject*> recordObj(cx, &$${val}.toObject());
6088 JS::RootedVector<jsid> ids(cx);
6089 if (!js::GetPropertyKeys(cx, recordObj,
6090 JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &ids)) {
6093 if (!recordEntries.SetCapacity(ids.length(), mozilla::fallible)) {
6094 JS_ReportOutOfMemory(cx);
6097 JS::Rooted<JS::Value> propNameValue(cx);
6098 JS::Rooted<JS::Value> temp(cx);
6099 JS::Rooted<jsid> curId(cx);
6100 JS::Rooted<JS::Value> idVal(cx);
6101 // Use a hashset to keep track of ids seen, to avoid
6102 // introducing nasty O(N^2) behavior scanning for them all the
6103 // time. Ideally we'd use a data structure with O(1) lookup
6104 // _and_ ordering for the MozMap, but we don't have one lying
6106 nsTHashtable<${hashKeyType}> idsSeen;
6107 for (size_t i = 0; i < ids.length(); ++i) {
6110 JS::Rooted<JS::PropertyDescriptor> desc(cx);
6111 if (!JS_GetOwnPropertyDescriptorById(cx, recordObj, curId,
6116 if (!desc.object() /* == undefined in spec terms */ ||
6117 !desc.enumerable()) {
6121 idVal = js::IdToValue(curId);
6122 ${keyType} propName;
6123 // This will just throw if idVal is a Symbol, like the spec says
6125 if (!${keyConversionFunction}(cx, idVal, "key of ${sourceDescription}", propName)) {
6129 if (!JS_GetPropertyById(cx, recordObj, curId, &temp)) {
6133 ${typeName}::EntryType* entry;
6134 if (!idsSeen.EnsureInserted(propName)) {
6135 // Find the existing entry.
6136 auto idx = recordEntries.IndexOf(propName);
6137 MOZ_ASSERT(idx != recordEntries.NoIndex,
6138 "Why is it not found?");
6139 // Now blow it away to make it look like it was just added
6140 // to the array, because it's not obvious that it's
6141 // safe to write to its already-initialized mValue via our
6142 // normal codegen conversions. For example, the value
6143 // could be a union and this would change its type, but
6144 // codegen assumes we won't do that.
6145 entry = recordEntries.ReconstructElementAt(idx);
6147 // Safe to do an infallible append here, because we did a
6148 // SetCapacity above to the right capacity.
6149 entry = recordEntries.AppendElement();
6151 entry->mKey = propName;
6152 ${valueType}& slot = entry->mValue;
6156 exceptionCode
=exceptionCode
,
6157 recordRef
=recordRef
,
6158 hashKeyType
=hashKeyType
,
6160 keyConversionFunction
=keyConversionFunction
,
6161 sourceDescription
=sourceDescription
,
6163 valueType
=valueInfo
.declType
.define(),
6164 valueConversion
=valueConversion
,
6167 templateBody
= wrapObjectTemplate(
6168 templateBody
, type, "${declName}.SetNull();\n", notRecord
6174 # record arguments that might contain traceable things need
6176 if not isMember
and isCallbackReturnValue
:
6177 # Go ahead and just convert directly into our actual return value
6178 declType
= CGWrapper(declType
, post
="&")
6179 declArgs
= "aRetVal"
6180 elif not isMember
and typeNeedsRooting(valueType
):
6181 holderType
= CGTemplatedType(
6182 "RecordRooter", [recordKeyDeclType(recordType
), valueInfo
.declType
]
6184 # If our record is nullable, this will set the Nullable to be
6185 # not-null, but that's ok because we make an explicit SetNull() call
6186 # on it as needed if our JS value is actually null.
6187 holderArgs
= "cx, &%s" % recordRef
6189 return JSToNativeConversionInfo(
6193 holderType
=holderType
,
6194 dealWithOptional
=isOptional
,
6195 holderArgs
=holderArgs
,
6199 nullable
= type.nullable()
6203 isOwningUnion
= isMember
or isCallbackReturnValue
6204 unionArgumentObj
= "${declName}" if isOwningUnion
else "${holderName}"
6206 # If we're owning, we're a Nullable, which hasn't been told it has
6207 # a value. Otherwise we're an already-constructed Maybe.
6208 unionArgumentObj
+= ".SetValue()" if isOwningUnion
else ".ref()"
6210 memberTypes
= type.flatMemberTypes
6213 interfaceMemberTypes
= [t
for t
in memberTypes
if t
.isNonCallbackInterface()]
6214 if len(interfaceMemberTypes
) > 0:
6215 interfaceObject
= []
6216 for memberType
in interfaceMemberTypes
:
6217 name
= getUnionMemberName(memberType
)
6218 interfaceObject
.append(
6220 "(failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext"
6221 % (unionArgumentObj
, name
)
6224 prettyNames
.append(memberType
.prettyName())
6225 interfaceObject
= CGWrapper(
6226 CGList(interfaceObject
, " ||\n"),
6232 interfaceObject
= None
6234 sequenceObjectMemberTypes
= [t
for t
in memberTypes
if t
.isSequence()]
6235 if len(sequenceObjectMemberTypes
) > 0:
6236 assert len(sequenceObjectMemberTypes
) == 1
6237 memberType
= sequenceObjectMemberTypes
[0]
6238 name
= getUnionMemberName(memberType
)
6239 sequenceObject
= CGGeneric(
6240 "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n"
6241 % (unionArgumentObj
, name
)
6243 prettyNames
.append(memberType
.prettyName())
6245 sequenceObject
= None
6247 callbackMemberTypes
= [
6248 t
for t
in memberTypes
if t
.isCallback() or t
.isCallbackInterface()
6250 if len(callbackMemberTypes
) > 0:
6251 assert len(callbackMemberTypes
) == 1
6252 memberType
= callbackMemberTypes
[0]
6253 name
= getUnionMemberName(memberType
)
6254 callbackObject
= CGGeneric(
6255 "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n"
6256 % (unionArgumentObj
, name
)
6258 prettyNames
.append(memberType
.prettyName())
6260 callbackObject
= None
6262 dictionaryMemberTypes
= [t
for t
in memberTypes
if t
.isDictionary()]
6263 if len(dictionaryMemberTypes
) > 0:
6264 assert len(dictionaryMemberTypes
) == 1
6265 memberType
= dictionaryMemberTypes
[0]
6266 name
= getUnionMemberName(memberType
)
6267 setDictionary
= CGGeneric(
6268 "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n"
6269 % (unionArgumentObj
, name
)
6271 prettyNames
.append(memberType
.prettyName())
6273 setDictionary
= None
6275 recordMemberTypes
= [t
for t
in memberTypes
if t
.isRecord()]
6276 if len(recordMemberTypes
) > 0:
6277 assert len(recordMemberTypes
) == 1
6278 memberType
= recordMemberTypes
[0]
6279 name
= getUnionMemberName(memberType
)
6280 recordObject
= CGGeneric(
6281 "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n"
6282 % (unionArgumentObj
, name
)
6284 prettyNames
.append(memberType
.prettyName())
6288 objectMemberTypes
= [t
for t
in memberTypes
if t
.isObject()]
6289 if len(objectMemberTypes
) > 0:
6290 assert len(objectMemberTypes
) == 1
6291 # Very important to NOT construct a temporary Rooted here, since the
6292 # SetToObject call can call a Rooted constructor and we need to keep
6293 # stack discipline for Rooted.
6295 "if (!%s.SetToObject(cx, &${val}.toObject(), ${passedToJSImpl})) {\n"
6298 "done = true;\n" % (unionArgumentObj
, indent(exceptionCode
))
6300 prettyNames
.append(objectMemberTypes
[0].prettyName())
6312 # "object" is not distinguishable from other types
6313 assert not object or not (
6314 interfaceObject
or sequenceObject
or callbackObject
or recordObject
6316 if sequenceObject
or callbackObject
:
6317 # An object can be both an sequence object and a callback or
6318 # dictionary, but we shouldn't have both in the union's members
6319 # because they are not distinguishable.
6320 assert not (sequenceObject
and callbackObject
)
6321 templateBody
= CGElseChain([sequenceObject
, callbackObject
])
6327 templateBody
= CGIfWrapper(templateBody
, "!done")
6328 templateBody
= CGList([interfaceObject
, templateBody
])
6330 templateBody
= CGList([templateBody
, object])
6333 templateBody
= CGList(
6334 [templateBody
, CGIfWrapper(recordObject
, "!done")]
6337 templateBody
= CGIfWrapper(templateBody
, "${val}.isObject()")
6339 templateBody
= CGGeneric()
6343 templateBody
= CGList([templateBody
, CGIfWrapper(setDictionary
, "!done")])
6345 stringTypes
= [t
for t
in memberTypes
if t
.isString() or t
.isEnum()]
6346 numericTypes
= [t
for t
in memberTypes
if t
.isNumeric()]
6347 booleanTypes
= [t
for t
in memberTypes
if t
.isBoolean()]
6348 if stringTypes
or numericTypes
or booleanTypes
:
6349 assert len(stringTypes
) <= 1
6350 assert len(numericTypes
) <= 1
6351 assert len(booleanTypes
) <= 1
6353 # We will wrap all this stuff in a do { } while (0); so we
6354 # can use "break" for flow control.
6355 def getStringOrPrimitiveConversion(memberType
):
6356 name
= getUnionMemberName(memberType
)
6358 "done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext;\n"
6359 "break;\n" % (unionArgumentObj
, name
)
6363 stringConversion
= [getStringOrPrimitiveConversion(t
) for t
in stringTypes
]
6364 numericConversion
= [
6365 getStringOrPrimitiveConversion(t
) for t
in numericTypes
6367 booleanConversion
= [
6368 getStringOrPrimitiveConversion(t
) for t
in booleanTypes
6370 if stringConversion
:
6371 if booleanConversion
:
6373 CGIfWrapper(booleanConversion
[0], "${val}.isBoolean()")
6375 if numericConversion
:
6376 other
.append(CGIfWrapper(numericConversion
[0], "${val}.isNumber()"))
6377 other
.append(stringConversion
[0])
6378 elif numericConversion
:
6379 if booleanConversion
:
6381 CGIfWrapper(booleanConversion
[0], "${val}.isBoolean()")
6383 other
.append(numericConversion
[0])
6385 assert booleanConversion
6386 other
.append(booleanConversion
[0])
6389 CGIndenter(other
), pre
="do {\n", post
="} while (false);\n"
6391 if hasObjectTypes
or setDictionary
:
6392 other
= CGWrapper(CGIndenter(other
), "{\n", post
="}\n")
6394 templateBody
= CGElseChain([templateBody
, other
])
6396 other
= CGWrapper(other
, pre
="if (!done) ")
6397 templateBody
= CGList([templateBody
, other
])
6399 assert templateBody
.define() == ""
6400 templateBody
= other
6404 templateBody
= CGWrapper(
6405 templateBody
, pre
="bool done = false, failed = false, tryNext;\n"
6414 cx.ThrowErrorMessage<MSG_NOT_IN_UNION>("${desc}", "${names}");
6418 exceptionCode
=exceptionCode
,
6419 desc
=firstCap(sourceDescription
),
6420 names
=", ".join(prettyNames
),
6424 templateBody
= CGWrapper(
6425 CGIndenter(CGList([templateBody
, throw
])), pre
="{\n", post
="}\n"
6428 typeName
= CGUnionStruct
.unionTypeDecl(type, isOwningUnion
)
6429 argumentTypeName
= typeName
+ "Argument"
6431 typeName
= "Nullable<" + typeName
+ " >"
6433 def handleNull(templateBody
, setToNullVar
, extraConditionForNull
=""):
6434 nullTest
= "%s${val}.isNullOrUndefined()" % extraConditionForNull
6435 return CGIfElseWrapper(
6436 nullTest
, CGGeneric("%s.SetNull();\n" % setToNullVar
), templateBody
6439 if type.hasNullableType
:
6441 # Make sure to handle a null default value here
6442 if defaultValue
and isinstance(defaultValue
, IDLNullValue
):
6443 assert defaultValue
.type == type
6444 extraConditionForNull
= "!(${haveValue}) || "
6446 extraConditionForNull
= ""
6447 templateBody
= handleNull(
6450 extraConditionForNull
=extraConditionForNull
,
6453 declType
= CGGeneric(typeName
)
6457 holderType
= CGGeneric(argumentTypeName
)
6459 holderType
= CGTemplatedType("Maybe", holderType
)
6461 # If we're isOptional and not nullable the normal optional handling will
6462 # handle lazy construction of our holder. If we're nullable and not
6463 # owning we do it all by hand because we do not want our holder
6464 # constructed if we're null. But if we're owning we don't have a
6465 # holder anyway, so we can do the normal Optional codepath.
6466 declLoc
= "${declName}"
6467 constructDecl
= None
6469 if isOptional
and not isOwningUnion
:
6470 holderArgs
= "${declName}.Value().SetValue()"
6471 declType
= CGTemplatedType("Optional", declType
)
6472 constructDecl
= CGGeneric("${declName}.Construct();\n")
6473 declLoc
= "${declName}.Value()"
6475 holderArgs
= "${declName}.SetValue()"
6476 if holderType
is not None:
6477 constructHolder
= CGGeneric("${holderName}.emplace(%s);\n" % holderArgs
)
6479 constructHolder
= None
6480 # Don't need to pass those args when the holder is being constructed
6483 holderArgs
= "${declName}"
6484 constructHolder
= None
6486 if not isMember
and isCallbackReturnValue
:
6487 declType
= CGWrapper(declType
, post
="&")
6488 declArgs
= "aRetVal"
6494 and not isinstance(defaultValue
, IDLNullValue
)
6495 and not isinstance(defaultValue
, IDLDefaultDictionaryValue
)
6497 tag
= defaultValue
.type.tag()
6499 if tag
in numericSuffixes
or tag
is IDLType
.Tags
.bool:
6500 defaultStr
= getHandleDefault(defaultValue
)
6501 # Make sure we actually construct the thing inside the nullable.
6502 value
= declLoc
+ (".SetValue()" if nullable
else "")
6503 name
= getUnionMemberName(defaultValue
.type)
6504 default
= CGGeneric(
6505 "%s.RawSetAs%s() = %s;\n" % (value
, name
, defaultStr
)
6507 elif isinstance(defaultValue
, IDLEmptySequenceValue
):
6508 name
= getUnionMemberName(defaultValue
.type)
6509 # Make sure we actually construct the thing inside the nullable.
6510 value
= declLoc
+ (".SetValue()" if nullable
else "")
6511 # It's enough to set us to the right type; that will
6512 # create an empty array, which is all we need here.
6513 default
= CGGeneric("%s.RawSetAs%s();\n" % (value
, name
))
6514 elif defaultValue
.type.isEnum():
6515 name
= getUnionMemberName(defaultValue
.type)
6516 # Make sure we actually construct the thing inside the nullable.
6517 value
= declLoc
+ (".SetValue()" if nullable
else "")
6518 default
= CGGeneric(
6519 "%s.RawSetAs%s() = %s::%s;\n"
6523 defaultValue
.type.inner
.identifier
.name
,
6524 getEnumValueName(defaultValue
.value
),
6528 default
= CGGeneric(
6529 handleDefaultStringValue(
6530 defaultValue
, "%s.SetStringLiteral" % unionArgumentObj
6534 templateBody
= CGIfElseWrapper("!(${haveValue})", default
, templateBody
)
6536 templateBody
= CGList([constructHolder
, templateBody
])
6540 if isinstance(defaultValue
, IDLNullValue
):
6541 extraConditionForNull
= "!(${haveValue}) || "
6543 extraConditionForNull
= "(${haveValue}) && "
6545 extraConditionForNull
= ""
6546 templateBody
= handleNull(
6547 templateBody
, declLoc
, extraConditionForNull
=extraConditionForNull
6550 not type.hasNullableType
6552 and isinstance(defaultValue
, IDLDefaultDictionaryValue
)
6554 assert type.hasDictionaryType()
6555 assert defaultValue
.type.isDictionary()
6556 if not isOwningUnion
and typeNeedsRooting(defaultValue
.type):
6560 initDictionaryWithNull
= CGIfWrapper(
6561 CGGeneric("return false;\n"),
6563 '!%s.RawSetAs%s(%s).Init(cx, JS::NullHandleValue, "Member of %s")'
6566 getUnionMemberName(defaultValue
.type),
6572 templateBody
= CGIfElseWrapper(
6573 "!(${haveValue})", initDictionaryWithNull
, templateBody
6576 templateBody
= CGList([constructDecl
, templateBody
])
6578 return JSToNativeConversionInfo(
6579 templateBody
.define(),
6582 holderType
=holderType
,
6583 holderArgs
=holderArgs
,
6584 dealWithOptional
=isOptional
and (not nullable
or isOwningUnion
),
6587 if type.isPromise():
6588 assert not type.nullable()
6589 assert defaultValue
is None
6591 # We always have to hold a strong ref to Promise here, because
6592 # Promise::resolve returns an addrefed thing.
6593 argIsPointer
= isCallbackReturnValue
6595 declType
= CGGeneric("RefPtr<Promise>")
6597 declType
= CGGeneric("OwningNonNull<Promise>")
6599 # Per spec, what we're supposed to do is take the original
6600 # Promise.resolve and call it with the original Promise as this
6601 # value to make a Promise out of whatever value we actually have
6602 # here. The question is which global we should use. There are
6603 # several cases to consider:
6605 # 1) Normal call to API with a Promise argument. This is a case the
6606 # spec covers, and we should be using the current Realm's
6607 # Promise. That means the current compartment.
6608 # 2) Call to API with a Promise argument over Xrays. In practice,
6609 # this sort of thing seems to be used for giving an API
6610 # implementation a way to wait for conclusion of an asyc
6611 # operation, _not_ to expose the Promise to content code. So we
6612 # probably want to allow callers to use such an API in a
6613 # "natural" way, by passing chrome-side promises; indeed, that
6614 # may be all that the caller has to represent their async
6615 # operation. That means we really need to do the
6616 # Promise.resolve() in the caller (chrome) compartment: if we do
6617 # it in the content compartment, we will try to call .then() on
6618 # the chrome promise while in the content compartment, which will
6619 # throw and we'll just get a rejected Promise. Note that this is
6620 # also the reason why a caller who has a chrome Promise
6621 # representing an async operation can't itself convert it to a
6622 # content-side Promise (at least not without some serious
6624 # 3) Promise return value from a callback or callback interface.
6625 # Per spec, this should use the Realm of the callback object. In
6626 # our case, that's the compartment of the underlying callback,
6627 # not the current compartment (which may be the compartment of
6628 # some cross-compartment wrapper around said callback).
6629 # 4) Return value from a JS-implemented interface. In this case we
6630 # have a problem. Our current compartment is the compartment of
6631 # the JS implementation. But if the JS implementation returned
6632 # a page-side Promise (which is a totally sane thing to do, and
6633 # in fact the right thing to do given that this return value is
6634 # going right to content script) then we don't want to
6635 # Promise.resolve with our current compartment Promise, because
6636 # that will wrap it up in a chrome-side Promise, which is
6637 # decidedly _not_ what's desired here. So in that case we
6638 # should really unwrap the return value and use the global of
6639 # the result. CheckedUnwrapStatic should be good enough for that;
6640 # if it fails, then we're failing unwrap while in a
6641 # system-privileged compartment, so presumably we have a dead
6642 # object wrapper. Just error out. Do NOT fall back to using
6643 # the current compartment instead: that will return a
6644 # system-privileged rejected (because getting .then inside
6645 # resolve() failed) Promise to the caller, which they won't be
6646 # able to touch. That's not helpful. If we error out, on the
6647 # other hand, they will get a content-side rejected promise.
6648 # Same thing if the value returned is not even an object.
6649 if isCallbackReturnValue
== "JSImpl":
6650 # Case 4 above. Note that globalObj defaults to the current
6651 # compartment global. Note that we don't use $*{exceptionCode}
6652 # here because that will try to aRv.Throw(NS_ERROR_UNEXPECTED)
6653 # which we don't really want here.
6654 assert exceptionCode
== "aRv.Throw(NS_ERROR_UNEXPECTED);\nreturn nullptr;\n"
6655 getPromiseGlobal
= fill(
6657 if (!$${val}.isObject()) {
6658 aRv.ThrowTypeError<MSG_NOT_OBJECT>("${sourceDescription}");
6661 JSObject* unwrappedVal = js::CheckedUnwrapStatic(&$${val}.toObject());
6662 if (!unwrappedVal) {
6663 // A slight lie, but not much of one, for a dead object wrapper.
6664 aRv.ThrowTypeError<MSG_NOT_OBJECT>("${sourceDescription}");
6667 globalObj = JS::GetNonCCWObjectGlobal(unwrappedVal);
6669 sourceDescription
=sourceDescription
,
6671 elif isCallbackReturnValue
== "Callback":
6672 getPromiseGlobal
= dedent(
6674 // We basically want our entry global here. Play it safe
6675 // and use GetEntryGlobal() to get it, with whatever
6676 // principal-clamping it ends up doing.
6677 globalObj = GetEntryGlobal()->GetGlobalJSObject();
6681 getPromiseGlobal
= dedent(
6683 globalObj = JS::CurrentGlobalOrNull(cx);
6687 templateBody
= fill(
6689 { // Scope for our GlobalObject, FastErrorResult, JSAutoRealm,
6692 JS::Rooted<JSObject*> globalObj(cx);
6693 $*{getPromiseGlobal}
6694 JSAutoRealm ar(cx, globalObj);
6695 GlobalObject promiseGlobal(cx, globalObj);
6696 if (promiseGlobal.Failed()) {
6700 JS::Rooted<JS::Value> valueToResolve(cx, $${val});
6701 if (!JS_WrapValue(cx, &valueToResolve)) {
6704 binding_detail::FastErrorResult promiseRv;
6705 nsCOMPtr<nsIGlobalObject> global =
6706 do_QueryInterface(promiseGlobal.GetAsSupports());
6708 promiseRv.Throw(NS_ERROR_UNEXPECTED);
6709 MOZ_ALWAYS_TRUE(promiseRv.MaybeSetPendingException(cx));
6712 $${declName} = Promise::Resolve(global, cx, valueToResolve,
6714 if (promiseRv.MaybeSetPendingException(cx)) {
6719 getPromiseGlobal
=getPromiseGlobal
,
6720 exceptionCode
=exceptionCode
,
6723 return JSToNativeConversionInfo(
6724 templateBody
, declType
=declType
, dealWithOptional
=isOptional
6727 if type.isGeckoInterface():
6728 assert not isEnforceRange
and not isClamp
and not isAllowShared
6730 descriptor
= descriptorProvider
.getDescriptor(
6731 type.unroll().inner
.identifier
.name
6734 assert descriptor
.nativeType
!= "JSObject"
6736 if descriptor
.interface
.isCallback():
6737 (declType
, declArgs
, conversion
) = getCallbackConversionInfo(
6738 type, descriptor
.interface
, isMember
, isCallbackReturnValue
, isOptional
6740 template
= wrapObjectTemplate(
6741 conversion
, type, "${declName} = nullptr;\n", failureCode
6743 return JSToNativeConversionInfo(
6747 dealWithOptional
=isOptional
,
6750 if descriptor
.interface
.identifier
.name
== "WindowProxy":
6751 declType
= CGGeneric("mozilla::dom::WindowProxyHolder")
6753 declType
= CGTemplatedType("Nullable", declType
)
6754 windowProxyHolderRef
= "${declName}.SetValue()"
6756 windowProxyHolderRef
= "${declName}"
6758 failureCode
= onFailureBadType(
6759 failureCode
, descriptor
.interface
.identifier
.name
6761 templateBody
= fill(
6763 JS::Rooted<JSObject*> source(cx, &$${val}.toObject());
6764 if (NS_FAILED(UnwrapWindowProxyArg(cx, source, ${windowProxyHolderRef}))) {
6768 windowProxyHolderRef
=windowProxyHolderRef
,
6769 onFailure
=failureCode
,
6771 templateBody
= wrapObjectTemplate(
6772 templateBody
, type, "${declName}.SetNull();\n", failureCode
6774 return JSToNativeConversionInfo(
6775 templateBody
, declType
=declType
, dealWithOptional
=isOptional
6778 # This is an interface that we implement as a concrete class
6779 # or an XPCOM interface.
6781 # Allow null pointers for nullable types and old-binding classes, and
6782 # use an RefPtr or raw pointer for callback return values to make
6783 # them easier to return.
6785 type.nullable() or type.unroll().inner
.isExternal() or isCallbackReturnValue
6788 # Sequence and dictionary members, as well as owning unions (which can
6789 # appear here as return values in JS-implemented interfaces) have to
6790 # hold a strong ref to the thing being passed down. Those all set
6793 # Also, callback return values always end up addrefing anyway, so there
6794 # is no point trying to avoid it here and it makes other things simpler
6795 # since we can assume the return value is a strong ref.
6796 assert not descriptor
.interface
.isCallback()
6797 forceOwningType
= isMember
or isCallbackReturnValue
6799 typeName
= descriptor
.nativeType
6800 typePtr
= typeName
+ "*"
6802 # Compute a few things:
6803 # - declType is the type we want to return as the first element of our
6805 # - holderType is the type we want to return as the third element
6808 # Set up some sensible defaults for these things insofar as we can.
6812 declType
= "RefPtr<" + typeName
+ ">"
6817 declType
= "OwningNonNull<" + typeName
+ ">"
6819 declType
= "NonNull<" + typeName
+ ">"
6823 templateBody
+= fill(
6825 static_assert(IsRefcounted<${typeName}>::value, "We can only store refcounted classes.");
6830 if not descriptor
.interface
.isExternal():
6831 if failureCode
is not None:
6832 templateBody
+= str(
6833 CastableObjectUnwrapper(
6836 "${maybeMutableVal}",
6842 templateBody
+= str(
6843 FailureFatalCastableObjectUnwrapper(
6846 "${maybeMutableVal}",
6849 isCallbackReturnValue
,
6850 firstCap(sourceDescription
),
6854 # External interface. We always have a holder for these, because we
6855 # don't actually know whether we have to addref when unwrapping or not.
6856 # So we just pass an getter_AddRefs(RefPtr) to XPConnect and if we'll
6857 # need a release it'll put a non-null pointer in there.
6859 # Don't return a holderType in this case; our declName
6860 # will just own stuff.
6861 templateBody
+= "RefPtr<" + typeName
+ "> ${holderName};\n"
6863 holderType
= "RefPtr<" + typeName
+ ">"
6865 "JS::Rooted<JSObject*> source(cx, &${val}.toObject());\n"
6866 + "if (NS_FAILED(UnwrapArg<"
6868 + ">(cx, source, getter_AddRefs(${holderName})))) {\n"
6870 templateBody
+= CGIndenter(
6871 onFailureBadType(failureCode
, descriptor
.interface
.identifier
.name
)
6873 templateBody
+= "}\n" "MOZ_ASSERT(${holderName});\n"
6875 # And store our value in ${declName}
6876 templateBody
+= "${declName} = ${holderName};\n"
6878 # Just pass failureCode, not onFailureBadType, here, so we'll report
6879 # the thing as not an object as opposed to not implementing whatever
6881 templateBody
= wrapObjectTemplate(
6882 templateBody
, type, "${declName} = nullptr;\n", failureCode
6885 declType
= CGGeneric(declType
)
6886 if holderType
is not None:
6887 holderType
= CGGeneric(holderType
)
6888 return JSToNativeConversionInfo(
6891 holderType
=holderType
,
6892 dealWithOptional
=isOptional
,
6895 if type.isSpiderMonkeyInterface():
6896 assert not isEnforceRange
and not isClamp
6897 name
= type.unroll().name
# unroll() because it may be nullable
6898 interfaceType
= CGGeneric(name
)
6899 declType
= interfaceType
6901 declType
= CGTemplatedType("Nullable", declType
)
6902 objRef
= "${declName}.SetValue()"
6904 objRef
= "${declName}"
6906 # Again, this is a bit strange since we are actually building a
6907 # template string here. ${objRef} and $*{badType} below are filled in
6908 # right now; $${val} expands to ${val}, to be filled in later.
6911 if (!${objRef}.Init(&$${val}.toObject())) {
6916 badType
=onFailureBadType(failureCode
, type.name
).define(),
6918 if type.isBufferSource():
6919 if type.isArrayBuffer():
6920 isSharedMethod
= "JS::IsSharedArrayBufferObject"
6921 isLargeMethod
= "JS::IsLargeArrayBufferMaybeShared"
6923 assert type.isArrayBufferView() or type.isTypedArray()
6924 isSharedMethod
= "JS::IsArrayBufferViewShared"
6925 isLargeMethod
= "JS::IsLargeArrayBufferView"
6926 if not isAllowShared
:
6929 if (${isSharedMethod}(${objRef}.Obj())) {
6933 isSharedMethod
=isSharedMethod
,
6935 badType
=onFailureIsShared().define(),
6937 # For now reject large (> 2 GB) ArrayBuffers and ArrayBufferViews.
6938 # Supporting this will require changing dom::TypedArray and
6942 if (${isLargeMethod}(${objRef}.Obj())) {
6946 isLargeMethod
=isLargeMethod
,
6948 badType
=onFailureIsLarge().define(),
6950 template
= wrapObjectTemplate(
6951 template
, type, "${declName}.SetNull();\n", failureCode
6954 # This is a bit annoying. In a union we don't want to have a
6955 # holder, since unions don't support that. But if we're optional we
6956 # want to have a holder, so that the callee doesn't see
6957 # Optional<RootedSpiderMonkeyInterface<InterfaceType>>. So do a
6958 # holder if we're optional and use a RootedSpiderMonkeyInterface
6961 holderType
= CGTemplatedType(
6962 "SpiderMonkeyInterfaceRooter", interfaceType
6964 # If our SpiderMonkey interface is nullable, this will set the
6965 # Nullable to be not-null, but that's ok because we make an
6966 # explicit SetNull() call on it as needed if our JS value is
6967 # actually null. XXXbz Because "Maybe" takes const refs for
6968 # constructor arguments, we can't pass a reference here; have
6969 # to pass a pointer.
6970 holderArgs
= "cx, &%s" % objRef
6975 declType
= CGTemplatedType("RootedSpiderMonkeyInterface", declType
)
6981 return JSToNativeConversionInfo(
6984 holderType
=holderType
,
6985 dealWithOptional
=isOptional
,
6987 holderArgs
=holderArgs
,
6990 if type.isJSString():
6991 assert not isEnforceRange
and not isClamp
and not isAllowShared
6993 raise TypeError("Nullable JSString not supported")
6997 raise TypeError("JSString not supported as member")
6999 declType
= "JS::Rooted<JSString*>"
7002 raise TypeError("JSString not supported as optional")
7003 templateBody
= fill(
7005 if (!($${declName} = ConvertJSValueToJSString(cx, $${val}))) {
7009 exceptionCode
=exceptionCode
,
7012 if defaultValue
is not None:
7013 assert not isinstance(defaultValue
, IDLNullValue
)
7016 static const char data[] = { ${data} };
7017 $${declName} = JS_NewStringCopyN(cx, data, ArrayLength(data) - 1);
7018 if (!$${declName}) {
7023 ["'" + char
+ "'" for char
in defaultValue
.value
] + ["0"]
7025 exceptionCode
=exceptionCode
,
7028 templateBody
= handleDefault(templateBody
, defaultCode
)
7029 return JSToNativeConversionInfo(
7030 templateBody
, declType
=CGGeneric(declType
), declArgs
=declArgs
7033 if type.isDOMString() or type.isUSVString() or type.isUTF8String():
7034 assert not isEnforceRange
and not isClamp
and not isAllowShared
7037 "Default": "eStringify",
7038 "EmptyString": "eEmpty",
7042 # For nullable strings null becomes a null string.
7043 treatNullAs
= "Null"
7044 # For nullable strings undefined also becomes a null string.
7045 undefinedBehavior
= "eNull"
7047 undefinedBehavior
= "eStringify"
7048 if type.legacyNullToEmptyString
:
7049 treatNullAs
= "EmptyString"
7051 treatNullAs
= "Default"
7052 nullBehavior
= treatAs
[treatNullAs
]
7054 def getConversionCode(varName
):
7056 if type.isUSVString():
7057 normalizeCode
= fill(
7059 if (!NormalizeUSVString(${var})) {
7060 JS_ReportOutOfMemory(cx);
7065 exceptionCode
=exceptionCode
,
7068 conversionCode
= fill(
7070 if (!ConvertJSValueToString(cx, $${val}, ${nullBehavior}, ${undefinedBehavior}, ${varName})) {
7075 nullBehavior
=nullBehavior
,
7076 undefinedBehavior
=undefinedBehavior
,
7078 exceptionCode
=exceptionCode
,
7079 normalizeCode
=normalizeCode
,
7082 if defaultValue
is None:
7083 return conversionCode
7085 if isinstance(defaultValue
, IDLNullValue
):
7086 assert type.nullable()
7087 defaultCode
= "%s.SetIsVoid(true);\n" % varName
7089 defaultCode
= handleDefaultStringValue(
7090 defaultValue
, "%s.AssignLiteral" % varName
7092 return handleDefault(conversionCode
, defaultCode
)
7095 # Convert directly into the ns[C]String member we have.
7096 if type.isUTF8String():
7097 declType
= "nsCString"
7099 declType
= "nsString"
7100 return JSToNativeConversionInfo(
7101 getConversionCode("${declName}"),
7102 declType
=CGGeneric(declType
),
7103 dealWithOptional
=isOptional
,
7107 if type.isUTF8String():
7108 declType
= "Optional<nsACString>"
7109 holderType
= CGGeneric("binding_detail::FakeString<char>")
7111 declType
= "Optional<nsAString>"
7112 holderType
= CGGeneric("binding_detail::FakeString<char16_t>")
7113 conversionCode
= "%s" "${declName} = &${holderName};\n" % getConversionCode(
7117 if type.isUTF8String():
7118 declType
= "binding_detail::FakeString<char>"
7120 declType
= "binding_detail::FakeString<char16_t>"
7122 conversionCode
= getConversionCode("${declName}")
7124 # No need to deal with optional here; we handled it already
7125 return JSToNativeConversionInfo(
7126 conversionCode
, declType
=CGGeneric(declType
), holderType
=holderType
7129 if type.isByteString():
7130 assert not isEnforceRange
and not isClamp
and not isAllowShared
7132 nullable
= toStringBool(type.nullable())
7134 conversionCode
= fill(
7136 if (!ConvertJSValueToByteString(cx, $${val}, ${nullable}, "${sourceDescription}", $${declName})) {
7141 sourceDescription
=sourceDescription
,
7142 exceptionCode
=exceptionCode
,
7145 if defaultValue
is not None:
7146 if isinstance(defaultValue
, IDLNullValue
):
7147 assert type.nullable()
7148 defaultCode
= "${declName}.SetIsVoid(true);\n"
7150 defaultCode
= handleDefaultStringValue(
7151 defaultValue
, "${declName}.AssignLiteral"
7153 conversionCode
= handleDefault(conversionCode
, defaultCode
)
7155 return JSToNativeConversionInfo(
7156 conversionCode
, declType
=CGGeneric("nsCString"), dealWithOptional
=isOptional
7160 assert not isEnforceRange
and not isClamp
and not isAllowShared
7162 enumName
= type.unroll().inner
.identifier
.name
7163 declType
= CGGeneric(enumName
)
7165 declType
= CGTemplatedType("Nullable", declType
)
7166 declType
= declType
.define()
7167 enumLoc
= "${declName}.SetValue()"
7169 enumLoc
= "${declName}"
7170 declType
= declType
.define()
7172 if invalidEnumValueFatal
:
7173 handleInvalidEnumValueCode
= "MOZ_ASSERT(index >= 0);\n"
7175 # invalidEnumValueFatal is false only for attributes. So we won't
7176 # have a non-default exceptionCode here unless attribute "arg
7177 # conversion" code starts passing in an exceptionCode. At which
7178 # point we'll need to figure out what that even means.
7179 assert exceptionCode
== "return false;\n"
7180 handleInvalidEnumValueCode
= dedent(
7192 if (!FindEnumStringIndex<${invalidEnumValueFatal}>(cx, $${val}, ${values}, "${enumtype}", "${sourceDescription}", &index)) {
7195 $*{handleInvalidEnumValueCode}
7196 ${enumLoc} = static_cast<${enumtype}>(index);
7200 values
=enumName
+ "Values::" + ENUM_ENTRY_VARIABLE_NAME
,
7201 invalidEnumValueFatal
=toStringBool(invalidEnumValueFatal
),
7202 handleInvalidEnumValueCode
=handleInvalidEnumValueCode
,
7203 exceptionCode
=exceptionCode
,
7205 sourceDescription
=sourceDescription
,
7208 setNull
= "${declName}.SetNull();\n"
7211 template
= CGIfElseWrapper(
7212 "${val}.isNullOrUndefined()", CGGeneric(setNull
), CGGeneric(template
)
7215 if defaultValue
is not None:
7216 if isinstance(defaultValue
, IDLNullValue
):
7217 assert type.nullable()
7218 template
= handleDefault(template
, setNull
)
7220 assert defaultValue
.type.tag() == IDLType
.Tags
.domstring
7221 template
= handleDefault(
7225 % (enumLoc
, enumName
, getEnumValueName(defaultValue
.value
))
7228 return JSToNativeConversionInfo(
7229 template
, declType
=CGGeneric(declType
), dealWithOptional
=isOptional
7232 if type.isCallback():
7233 assert not isEnforceRange
and not isClamp
and not isAllowShared
7234 assert not type.treatNonCallableAsNull() or type.nullable()
7235 assert not type.treatNonObjectAsNull() or type.nullable()
7236 assert not type.treatNonObjectAsNull() or not type.treatNonCallableAsNull()
7238 callback
= type.unroll().callback
7239 name
= callback
.identifier
.name
7240 (declType
, declArgs
, conversion
) = getCallbackConversionInfo(
7241 type, callback
, isMember
, isCallbackReturnValue
, isOptional
7244 if allowTreatNonCallableAsNull
and type.treatNonCallableAsNull():
7245 haveCallable
= "JS::IsCallable(&${val}.toObject())"
7246 if not isDefinitelyObject
:
7247 haveCallable
= "${val}.isObject() && " + haveCallable
7248 if defaultValue
is not None:
7249 assert isinstance(defaultValue
, IDLNullValue
)
7250 haveCallable
= "(${haveValue}) && " + haveCallable
7252 ("if (%s) {\n" % haveCallable
) + conversion
+ "} else {\n"
7253 " ${declName} = nullptr;\n"
7256 elif allowTreatNonCallableAsNull
and type.treatNonObjectAsNull():
7257 if not isDefinitelyObject
:
7258 haveObject
= "${val}.isObject()"
7259 if defaultValue
is not None:
7260 assert isinstance(defaultValue
, IDLNullValue
)
7261 haveObject
= "(${haveValue}) && " + haveObject
7262 template
= CGIfElseWrapper(
7264 CGGeneric(conversion
),
7265 CGGeneric("${declName} = nullptr;\n"),
7268 template
= conversion
7270 template
= wrapObjectTemplate(
7271 "if (JS::IsCallable(&${val}.toObject())) {\n"
7274 + indent(onFailureNotCallable(failureCode
).define())
7277 "${declName} = nullptr;\n",
7280 return JSToNativeConversionInfo(
7281 template
, declType
=declType
, declArgs
=declArgs
, dealWithOptional
=isOptional
7285 assert not isEnforceRange
and not isClamp
and not isAllowShared
7288 if isMember
in ("Variadic", "Sequence", "Dictionary", "Record"):
7289 # Rooting is handled by the sequence and dictionary tracers.
7290 declType
= "JS::Value"
7293 declType
= "JS::Rooted<JS::Value>"
7296 assert not isOptional
7297 templateBody
= "${declName} = ${val};\n"
7299 # For JS-implemented APIs, we refuse to allow passing objects that the
7300 # API consumer does not subsume. The extra parens around
7301 # ($${passedToJSImpl}) suppress unreachable code warnings when
7302 # $${passedToJSImpl} is the literal `false`. But Apple is shipping a
7303 # buggy clang (clang 3.9) in Xcode 8.3, so there even the parens are not
7304 # enough. So we manually disable some warnings in clang.
7306 not isinstance(descriptorProvider
, Descriptor
)
7307 or descriptorProvider
.interface
.isJSImplemented()
7313 #pragma clang diagnostic push
7314 #pragma clang diagnostic ignored "-Wunreachable-code"
7315 #pragma clang diagnostic ignored "-Wunreachable-code-return"
7317 if (($${passedToJSImpl}) && !CallerSubsumes($${val})) {
7318 cx.ThrowErrorMessage<MSG_PERMISSION_DENIED_TO_PASS_ARG>("${sourceDescription}");
7322 #pragma clang diagnostic pop
7325 sourceDescription
=sourceDescription
,
7326 exceptionCode
=exceptionCode
,
7331 # We may not have a default value if we're being converted for
7334 if isinstance(defaultValue
, IDLNullValue
):
7335 defaultHandling
= "${declName} = JS::NullValue();\n"
7337 assert isinstance(defaultValue
, IDLUndefinedValue
)
7338 defaultHandling
= "${declName} = JS::UndefinedValue();\n"
7339 templateBody
= handleDefault(templateBody
, defaultHandling
)
7340 return JSToNativeConversionInfo(
7341 templateBody
, declType
=CGGeneric(declType
), declArgs
=declArgs
7345 assert not isEnforceRange
and not isClamp
and not isAllowShared
7346 return handleJSObjectType(
7347 type, isMember
, failureCode
, exceptionCode
, sourceDescription
7350 if type.isDictionary():
7351 # There are no nullable dictionary-typed arguments or dictionary-typed
7352 # dictionary members.
7355 or isCallbackReturnValue
7356 or (isMember
and isMember
!= "Dictionary")
7358 # All optional dictionary-typed arguments always have default values,
7359 # but dictionary-typed dictionary members can be optional.
7360 assert not isOptional
or isMember
== "Dictionary"
7361 # In the callback return value case we never have to worry
7362 # about a default value; we always have a value.
7363 assert not isCallbackReturnValue
or defaultValue
is None
7365 typeName
= CGDictionary
.makeDictionaryName(type.unroll().inner
)
7366 if not isMember
and not isCallbackReturnValue
:
7367 # Since we're not a member and not nullable or optional, no one will
7368 # see our real type, so we can do the fast version of the dictionary
7369 # that doesn't pre-initialize members.
7370 typeName
= "binding_detail::Fast" + typeName
7372 declType
= CGGeneric(typeName
)
7374 # We do manual default value handling here, because we actually do want
7375 # a jsval, and we only handle the default-dictionary case (which we map
7376 # into initialization with the JS value `null`) anyway
7377 # NOTE: if isNullOrUndefined or isDefinitelyObject are true,
7378 # we know we have a value, so we don't have to worry about the
7381 not isNullOrUndefined
7382 and not isDefinitelyObject
7383 and defaultValue
is not None
7385 assert isinstance(defaultValue
, IDLDefaultDictionaryValue
)
7386 # Initializing from JS null does the right thing to give
7387 # us a default-initialized dictionary.
7388 val
= "(${haveValue}) ? ${val} : JS::NullHandleValue"
7392 dictLoc
= "${declName}"
7394 dictLoc
+= ".SetValue()"
7396 if type.unroll().inner
.needsConversionFromJS
:
7397 args
= "cx, %s, " % val
7399 # We can end up in this case if a dictionary that does not need
7400 # conversion from JS has a dictionary-typed member with a default
7403 conversionCode
= fill(
7405 if (!${dictLoc}.Init(${args}"${desc}", $${passedToJSImpl})) {
7411 desc
=firstCap(sourceDescription
),
7412 exceptionCode
=exceptionCode
,
7415 if failureCode
is not None:
7416 # This means we're part of an overload or union conversion, and
7417 # should simply skip stuff if our value is not convertible to
7418 # dictionary, instead of trying and throwing. If we're either
7419 # isDefinitelyObject or isNullOrUndefined then we're convertible to
7420 # dictionary and don't need to check here.
7421 if isDefinitelyObject
or isNullOrUndefined
:
7422 template
= conversionCode
7426 if (!IsConvertibleToDictionary(${val})) {
7432 failureCode
=failureCode
,
7433 conversionCode
=conversionCode
,
7436 template
= conversionCode
7439 declType
= CGTemplatedType("Nullable", declType
)
7440 template
= CGIfElseWrapper(
7441 "${val}.isNullOrUndefined()",
7442 CGGeneric("${declName}.SetNull();\n"),
7443 CGGeneric(template
),
7446 # Dictionary arguments that might contain traceable things need to get
7448 if not isMember
and isCallbackReturnValue
:
7449 # Go ahead and just convert directly into our actual return value
7450 declType
= CGWrapper(declType
, post
="&")
7451 declArgs
= "aRetVal"
7452 elif not isMember
and typeNeedsRooting(type):
7453 declType
= CGTemplatedType("RootedDictionary", declType
)
7458 return JSToNativeConversionInfo(
7459 template
, declType
=declType
, declArgs
=declArgs
, dealWithOptional
=isOptional
7463 assert not isOptional
7464 # This one only happens for return values, and its easy: Just
7466 return JSToNativeConversionInfo("")
7468 if not type.isPrimitive():
7469 raise TypeError("Need conversion for argument type '%s'" % str(type))
7471 typeName
= builtinNames
[type.tag()]
7473 conversionBehavior
= "eDefault"
7475 assert type.isInteger()
7476 conversionBehavior
= "eEnforceRange"
7478 assert type.isInteger()
7479 conversionBehavior
= "eClamp"
7483 declType
= CGGeneric("Nullable<" + typeName
+ ">")
7484 writeLoc
= "${declName}.SetValue()"
7485 readLoc
= "${declName}.Value()"
7486 nullCondition
= "${val}.isNullOrUndefined()"
7487 if defaultValue
is not None and isinstance(defaultValue
, IDLNullValue
):
7488 nullCondition
= "!(${haveValue}) || " + nullCondition
7493 ${declName}.SetNull();
7499 if (${nullCondition}) {
7500 $${declName}.SetNull();
7501 } else if (!ValueToPrimitive<${typeName}, ${conversionBehavior}>(cx, $${val}, "${sourceDescription}", &${writeLoc})) {
7505 nullCondition
=nullCondition
,
7507 conversionBehavior
=conversionBehavior
,
7508 sourceDescription
=firstCap(sourceDescription
),
7510 exceptionCode
=exceptionCode
,
7513 assert defaultValue
is None or not isinstance(defaultValue
, IDLNullValue
)
7514 writeLoc
= "${declName}"
7518 if (!ValueToPrimitive<${typeName}, ${conversionBehavior}>(cx, $${val}, "${sourceDescription}", &${writeLoc})) {
7523 conversionBehavior
=conversionBehavior
,
7524 sourceDescription
=firstCap(sourceDescription
),
7526 exceptionCode
=exceptionCode
,
7528 declType
= CGGeneric(typeName
)
7530 if type.isFloat() and not type.isUnrestricted() and not alwaysNull
:
7531 if lenientFloatCode
is not None:
7532 nonFiniteCode
= lenientFloatCode
7534 nonFiniteCode
= 'cx.ThrowErrorMessage<MSG_NOT_FINITE>("%s");\n' "%s" % (
7535 firstCap(sourceDescription
),
7539 # We're appending to an if-block brace, so strip trailing whitespace
7540 # and add an extra space before the else.
7541 template
= template
.rstrip()
7544 else if (!mozilla::IsFinite(${readLoc})) {
7549 nonFiniteCode
=nonFiniteCode
,
7553 defaultValue
is not None
7555 # We already handled IDLNullValue, so just deal with the other ones
7556 not isinstance(defaultValue
, IDLNullValue
)
7558 tag
= defaultValue
.type.tag()
7559 defaultStr
= getHandleDefault(defaultValue
)
7560 template
= handleDefault(template
, "%s = %s;\n" % (writeLoc
, defaultStr
))
7562 return JSToNativeConversionInfo(
7563 template
, declType
=declType
, dealWithOptional
=isOptional
7567 def instantiateJSToNativeConversion(info
, replacements
, checkForValue
=False):
7569 Take a JSToNativeConversionInfo as returned by getJSToNativeConversionInfo
7570 and a set of replacements as required by the strings in such an object, and
7571 generate code to convert into stack C++ types.
7573 If checkForValue is True, then the conversion will get wrapped in
7574 a check for ${haveValue}.
7576 templateBody
, declType
, holderType
, dealWithOptional
= (
7580 info
.dealWithOptional
,
7583 if dealWithOptional
and not checkForValue
:
7584 raise TypeError("Have to deal with optional things, but don't know how")
7585 if checkForValue
and declType
is None:
7587 "Need to predeclare optional things, so they will be "
7588 "outside the check for big enough arg count!"
7591 # We can't precompute our holder constructor arguments, since
7592 # those might depend on ${declName}, which we change below. Just
7593 # compute arguments at the point when we need them as we go.
7594 def getArgsCGThing(args
):
7595 return CGGeneric(string
.Template(args
).substitute(replacements
))
7598 # Make a copy of "replacements" since we may be about to start modifying it
7599 replacements
= dict(replacements
)
7600 originalDeclName
= replacements
["declName"]
7601 if declType
is not None:
7602 if dealWithOptional
:
7603 replacements
["declName"] = "%s.Value()" % originalDeclName
7604 declType
= CGTemplatedType("Optional", declType
)
7606 elif info
.declArgs
is not None:
7607 declCtorArgs
= CGWrapper(getArgsCGThing(info
.declArgs
), pre
="(", post
=")")
7615 CGGeneric(originalDeclName
),
7622 originalHolderName
= replacements
["holderName"]
7623 if holderType
is not None:
7624 if dealWithOptional
:
7625 replacements
["holderName"] = "%s.ref()" % originalHolderName
7626 holderType
= CGTemplatedType("Maybe", holderType
)
7627 holderCtorArgs
= None
7628 elif info
.holderArgs
is not None:
7629 holderCtorArgs
= CGWrapper(
7630 getArgsCGThing(info
.holderArgs
), pre
="(", post
=")"
7633 holderCtorArgs
= None
7639 CGGeneric(originalHolderName
),
7646 if "maybeMutableVal" not in replacements
:
7647 replacements
["maybeMutableVal"] = replacements
["val"]
7649 conversion
= CGGeneric(string
.Template(templateBody
).substitute(replacements
))
7652 if dealWithOptional
:
7653 declConstruct
= CGIndenter(
7655 "%s.Construct(%s);\n"
7658 getArgsCGThing(info
.declArgs
).define() if info
.declArgs
else "",
7662 if holderType
is not None:
7663 holderConstruct
= CGIndenter(
7668 getArgsCGThing(info
.holderArgs
).define()
7675 holderConstruct
= None
7677 declConstruct
= None
7678 holderConstruct
= None
7680 conversion
= CGList(
7683 string
.Template("if (${haveValue}) {\n").substitute(replacements
)
7687 CGIndenter(conversion
),
7692 result
.append(conversion
)
7696 def convertConstIDLValueToJSVal(value
):
7697 if isinstance(value
, IDLNullValue
):
7698 return "JS::NullValue()"
7699 if isinstance(value
, IDLUndefinedValue
):
7700 return "JS::UndefinedValue()"
7701 tag
= value
.type.tag()
7706 IDLType
.Tags
.uint16
,
7709 return "JS::Int32Value(%s)" % (value
.value
)
7710 if tag
== IDLType
.Tags
.uint32
:
7711 return "JS::NumberValue(%sU)" % (value
.value
)
7712 if tag
in [IDLType
.Tags
.int64
, IDLType
.Tags
.uint64
]:
7713 return "JS::CanonicalizedDoubleValue(%s)" % numericValue(tag
, value
.value
)
7714 if tag
== IDLType
.Tags
.bool:
7715 return "JS::BooleanValue(%s)" % (toStringBool(value
.value
))
7716 if tag
in [IDLType
.Tags
.float, IDLType
.Tags
.double
]:
7717 return "JS::CanonicalizedDoubleValue(%s)" % (value
.value
)
7718 raise TypeError("Const value of unhandled type: %s" % value
.type)
7721 class CGArgumentConverter(CGThing
):
7723 A class that takes an IDL argument object and its index in the
7724 argument list and generates code to unwrap the argument to the
7727 argDescription is a description of the argument for error-reporting
7728 purposes. Callers should assume that it might get placed in the middle of a
7729 sentence. If it ends up at the beginning of a sentence, its first character
7730 will be automatically uppercased.
7740 invalidEnumValueFatal
=True,
7741 lenientFloatCode
=None,
7743 CGThing
.__init
__(self
)
7744 self
.argument
= argument
7745 self
.argDescription
= argDescription
7746 assert not argument
.defaultValue
or argument
.optional
7748 replacer
= {"index": index
, "argc": "args.length()"}
7749 self
.replacementVariables
= {
7750 "declName": "arg%d" % index
,
7751 "holderName": ("arg%d" % index
) + "_holder",
7753 "passedToJSImpl": toStringBool(
7754 isJSImplementedDescriptor(descriptorProvider
)
7757 # If we have a method generated by the maplike/setlike portion of an
7758 # interface, arguments can possibly be undefined, but will need to be
7759 # converted to the key/value type of the backing object. In this case,
7760 # use .get() instead of direct access to the argument. This won't
7761 # matter for iterable since generated functions for those interface
7762 # don't take arguments.
7763 if member
.isMethod() and member
.isMaplikeOrSetlikeOrIterableMethod():
7764 self
.replacementVariables
["val"] = string
.Template(
7765 "args.get(${index})"
7766 ).substitute(replacer
)
7767 self
.replacementVariables
["maybeMutableVal"] = string
.Template(
7769 ).substitute(replacer
)
7771 self
.replacementVariables
["val"] = string
.Template(
7773 ).substitute(replacer
)
7774 haveValueCheck
= string
.Template("args.hasDefined(${index})").substitute(
7777 self
.replacementVariables
["haveValue"] = haveValueCheck
7778 self
.descriptorProvider
= descriptorProvider
7779 if self
.argument
.canHaveMissingValue():
7780 self
.argcAndIndex
= replacer
7782 self
.argcAndIndex
= None
7783 self
.invalidEnumValueFatal
= invalidEnumValueFatal
7784 self
.lenientFloatCode
= lenientFloatCode
7787 typeConversion
= getJSToNativeConversionInfo(
7789 self
.descriptorProvider
,
7790 isOptional
=(self
.argcAndIndex
is not None and not self
.argument
.variadic
),
7791 invalidEnumValueFatal
=self
.invalidEnumValueFatal
,
7792 defaultValue
=self
.argument
.defaultValue
,
7793 lenientFloatCode
=self
.lenientFloatCode
,
7794 isMember
="Variadic" if self
.argument
.variadic
else False,
7795 allowTreatNonCallableAsNull
=self
.argument
.allowTreatNonCallableAsNull(),
7796 sourceDescription
=self
.argDescription
,
7799 if not self
.argument
.variadic
:
7800 return instantiateJSToNativeConversion(
7801 typeConversion
, self
.replacementVariables
, self
.argcAndIndex
is not None
7804 # Variadic arguments get turned into a sequence.
7805 if typeConversion
.dealWithOptional
:
7806 raise TypeError("Shouldn't have optional things in variadics")
7807 if typeConversion
.holderType
is not None:
7808 raise TypeError("Shouldn't need holders for variadics")
7810 replacer
= dict(self
.argcAndIndex
, **self
.replacementVariables
)
7811 replacer
["seqType"] = CGTemplatedType(
7812 "AutoSequence", typeConversion
.declType
7814 if typeNeedsRooting(self
.argument
.type):
7816 "SequenceRooter<%s> ${holderName}(cx, &${declName});\n"
7817 % typeConversion
.declType
.define()
7821 replacer
["elemType"] = typeConversion
.declType
.define()
7823 replacer
["elementInitializer"] = initializerForType(self
.argument
.type) or ""
7825 # NOTE: Keep this in sync with sequence conversions as needed
7826 variadicConversion
= string
.Template(
7827 "${seqType} ${declName};\n"
7831 if (${argc} > ${index}) {
7832 if (!${declName}.SetCapacity(${argc} - ${index}, mozilla::fallible)) {
7833 JS_ReportOutOfMemory(cx);
7836 for (uint32_t variadicArg = ${index}; variadicArg < ${argc}; ++variadicArg) {
7837 // OK to do infallible append here, since we ensured capacity already.
7838 ${elemType}& slot = *${declName}.AppendElement(${elementInitializer});
7841 ).substitute(replacer
)
7843 val
= string
.Template("args[variadicArg]").substitute(replacer
)
7844 variadicConversion
+= indent(
7845 string
.Template(typeConversion
.template
).substitute(
7848 "maybeMutableVal": val
,
7850 # We only need holderName here to handle isExternal()
7851 # interfaces, which use an internal holder for the
7852 # conversion even when forceOwningType ends up true.
7853 "holderName": "tempHolder",
7854 # Use the same ${obj} as for the variadic arg itself
7855 "obj": replacer
["obj"],
7856 "passedToJSImpl": toStringBool(
7857 isJSImplementedDescriptor(self
.descriptorProvider
)
7864 variadicConversion
+= " }\n" "}\n"
7865 return variadicConversion
7868 def getMaybeWrapValueFuncForType(type):
7869 if type.isJSString():
7870 return "MaybeWrapStringValue"
7871 # Callbacks might actually be DOM objects; nothing prevents a page from
7873 if type.isCallback() or type.isCallbackInterface() or type.isObject():
7875 return "MaybeWrapObjectOrNullValue"
7876 return "MaybeWrapObjectValue"
7877 # SpiderMonkey interfaces are never DOM objects. Neither are sequences or
7878 # dictionaries, since those are always plain JS objects.
7879 if type.isSpiderMonkeyInterface() or type.isDictionary() or type.isSequence():
7881 return "MaybeWrapNonDOMObjectOrNullValue"
7882 return "MaybeWrapNonDOMObjectValue"
7884 return "MaybeWrapValue"
7886 # For other types, just go ahead an fall back on MaybeWrapValue for now:
7887 # it's always safe to do, and shouldn't be particularly slow for any of
7889 return "MaybeWrapValue"
7892 sequenceWrapLevel
= 0
7896 def getWrapTemplateForType(
7903 spiderMonkeyInterfacesAreStructs
,
7904 isConstructorRetval
=False,
7907 Reflect a C++ value stored in "result", of IDL type "type" into JS. The
7908 "successCode" is the code to run once we have successfully done the
7909 conversion and must guarantee that execution of the conversion template
7910 stops once the successCode has executed (e.g. by doing a 'return', or by
7911 doing a 'break' if the entire conversion template is inside a block that
7912 the 'break' will exit).
7914 If spiderMonkeyInterfacesAreStructs is true, then if the type is a
7915 SpiderMonkey interface, "result" is one of the
7916 dom::SpiderMonkeyInterfaceObjectStorage subclasses, not a JSObject*.
7918 The resulting string should be used with string.Template. It
7919 needs the following keys when substituting:
7921 jsvalHandle: something that can be passed to methods taking a
7922 JS::MutableHandle<JS::Value>. This can be a
7923 JS::MutableHandle<JS::Value> or a JS::Rooted<JS::Value>*.
7924 jsvalRef: something that can have .address() called on it to get a
7925 JS::Value* and .set() called on it to set it to a JS::Value.
7926 This can be a JS::MutableHandle<JS::Value> or a
7927 JS::Rooted<JS::Value>.
7928 obj: a JS::Handle<JSObject*>.
7930 Returns (templateString, infallibility of conversion template)
7932 if successCode
is None:
7933 successCode
= "return true;\n"
7936 return _setValue("", setter
="setUndefined")
7939 return _setValue("", setter
="setNull")
7941 def setInt32(value
):
7942 return _setValue(value
, setter
="setInt32")
7944 def setString(value
):
7945 return _setValue(value
, wrapAsType
=type, setter
="setString")
7947 def setObject(value
, wrapAsType
=None):
7948 return _setValue(value
, wrapAsType
=wrapAsType
, setter
="setObject")
7950 def setObjectOrNull(value
, wrapAsType
=None):
7951 return _setValue(value
, wrapAsType
=wrapAsType
, setter
="setObjectOrNull")
7953 def setUint32(value
):
7954 return _setValue(value
, setter
="setNumber")
7956 def setDouble(value
):
7957 return _setValue("JS_NumberValue(%s)" % value
)
7959 def setBoolean(value
):
7960 return _setValue(value
, setter
="setBoolean")
7962 def _setValue(value
, wrapAsType
=None, setter
="set"):
7964 Returns the code to set the jsval to value.
7966 If wrapAsType is not None, then will wrap the resulting value using the
7967 function that getMaybeWrapValueFuncForType(wrapAsType) returns.
7968 Otherwise, no wrapping will be done.
7970 if wrapAsType
is None:
7975 if (!${maybeWrap}(cx, $${jsvalHandle})) {
7980 maybeWrap
=getMaybeWrapValueFuncForType(wrapAsType
),
7981 exceptionCode
=exceptionCode
,
7982 successCode
=successCode
,
7984 return ("${jsvalRef}.%s(%s);\n" % (setter
, value
)) + tail
7986 def wrapAndSetPtr(wrapCall
, failureCode
=None):
7988 Returns the code to set the jsval by calling "wrapCall". "failureCode"
7989 is the code to run if calling "wrapCall" fails
7991 if failureCode
is None:
7992 failureCode
= exceptionCode
8001 failureCode
=failureCode
,
8002 successCode
=successCode
,
8005 if type is None or type.isVoid():
8006 return (setUndefined(), True)
8008 if (type.isSequence() or type.isRecord()) and type.nullable():
8009 # These are both wrapped in Nullable<>
8010 recTemplate
, recInfall
= getWrapTemplateForType(
8013 "%s.Value()" % result
,
8017 spiderMonkeyInterfacesAreStructs
,
8022 if (${result}.IsNull()) {
8029 recTemplate
=recTemplate
,
8031 return code
, recInfall
8033 if type.isSequence():
8034 # Now do non-nullable sequences. Our success code is just to break to
8035 # where we set the element in the array. Note that we bump the
8036 # sequenceWrapLevel around this call so that nested sequence conversions
8037 # will use different iteration variables.
8038 global sequenceWrapLevel
8039 index
= "sequenceIdx%d" % sequenceWrapLevel
8040 sequenceWrapLevel
+= 1
8041 innerTemplate
= wrapForType(
8045 "result": "%s[%s]" % (result
, index
),
8046 "successCode": "break;\n",
8048 "jsvalHandle": "&tmp",
8049 "returnsNewObject": returnsNewObject
,
8050 "exceptionCode": exceptionCode
,
8051 "obj": "returnArray",
8052 "spiderMonkeyInterfacesAreStructs": spiderMonkeyInterfacesAreStructs
,
8055 sequenceWrapLevel
-= 1
8059 uint32_t length = ${result}.Length();
8060 JS::Rooted<JSObject*> returnArray(cx, JS::NewArrayObject(cx, length));
8066 JS::Rooted<JS::Value> tmp(cx);
8067 for (uint32_t ${index} = 0; ${index} < length; ++${index}) {
8068 // Control block to let us common up the JS_DefineElement calls when there
8069 // are different ways to succeed at wrapping the object.
8073 if (!JS_DefineElement(cx, returnArray, ${index}, tmp,
8074 JSPROP_ENUMERATE)) {
8082 exceptionCode
=exceptionCode
,
8084 innerTemplate
=innerTemplate
,
8085 set=setObject("*returnArray"),
8088 return (code
, False)
8091 # Now do non-nullable record. Our success code is just to break to
8092 # where we define the property on the object. Note that we bump the
8093 # recordWrapLevel around this call so that nested record conversions
8094 # will use different temp value names.
8095 global recordWrapLevel
8096 valueName
= "recordValue%d" % recordWrapLevel
8097 recordWrapLevel
+= 1
8098 innerTemplate
= wrapForType(
8102 "result": valueName
,
8103 "successCode": "break;\n",
8105 "jsvalHandle": "&tmp",
8106 "returnsNewObject": returnsNewObject
,
8107 "exceptionCode": exceptionCode
,
8109 "spiderMonkeyInterfacesAreStructs": spiderMonkeyInterfacesAreStructs
,
8112 recordWrapLevel
-= 1
8113 if type.keyType
.isByteString():
8114 # There is no length-taking JS_DefineProperty. So to keep
8115 # things sane with embedded nulls, we want to byte-inflate
8116 # to an nsAString. The only byte-inflation function we
8117 # have around is AppendASCIItoUTF16, which luckily doesn't
8118 # assert anything about the input being ASCII.
8119 expandedKeyDecl
= "NS_ConvertASCIItoUTF16 expandedKey(entry.mKey);\n"
8120 keyName
= "expandedKey"
8121 elif type.keyType
.isUTF8String():
8122 # We do the same as above for utf8 strings. We could do better if
8123 # we had a DefineProperty API that takes utf-8 property names.
8124 expandedKeyDecl
= "NS_ConvertUTF8toUTF16 expandedKey(entry.mKey);\n"
8125 keyName
= "expandedKey"
8127 expandedKeyDecl
= ""
8128 keyName
= "entry.mKey"
8133 JS::Rooted<JSObject*> returnObj(cx, JS_NewPlainObject(cx));
8139 JS::Rooted<JS::Value> tmp(cx);
8140 for (auto& entry : ${result}.Entries()) {
8141 auto& ${valueName} = entry.mValue;
8142 // Control block to let us common up the JS_DefineUCProperty calls when there
8143 // are different ways to succeed at wrapping the value.
8148 if (!JS_DefineUCProperty(cx, returnObj,
8149 ${keyName}.BeginReading(),
8150 ${keyName}.Length(), tmp,
8151 JSPROP_ENUMERATE)) {
8159 exceptionCode
=exceptionCode
,
8160 valueName
=valueName
,
8161 innerTemplate
=innerTemplate
,
8162 expandedKeyDecl
=expandedKeyDecl
,
8164 set=setObject("*returnObj"),
8167 return (code
, False)
8169 if type.isPromise():
8170 assert not type.nullable()
8171 # The use of ToJSValue here is a bit annoying because the Promise
8172 # version is not inlined. But we can't put an inline version in either
8173 # ToJSValue.h or BindingUtils.h, because Promise.h includes ToJSValue.h
8174 # and that includes BindingUtils.h, so we'd get an include loop if
8175 # either of those headers included Promise.h. And trying to write the
8176 # conversion by hand here is pretty annoying because we have to handle
8177 # the various RefPtr, rawptr, NonNull, etc cases, which ToJSValue will
8178 # handle for us. So just eat the cost of the function call.
8179 return (wrapAndSetPtr("ToJSValue(cx, %s, ${jsvalHandle})" % result
), False)
8181 if type.isGeckoInterface() and not type.isCallbackInterface():
8182 descriptor
= descriptorProvider
.getDescriptor(
8183 type.unroll().inner
.identifier
.name
8186 if descriptor
.interface
.identifier
.name
== "WindowProxy":
8187 template
, infal
= getWrapTemplateForType(
8190 "%s.Value()" % result
,
8194 spiderMonkeyInterfacesAreStructs
,
8197 "if (%s.IsNull()) {\n" % result
8204 wrappingCode
= "if (!%s) {\n" % (result
) + indent(setNull()) + "}\n"
8208 if not descriptor
.interface
.isExternal():
8209 if descriptor
.wrapperCache
:
8210 wrapMethod
= "GetOrCreateDOMReflector"
8211 wrapArgs
= "cx, %s, ${jsvalHandle}" % result
8213 wrapMethod
= "WrapNewBindingNonWrapperCachedObject"
8214 wrapArgs
= "cx, ${obj}, %s, ${jsvalHandle}" % result
8215 if isConstructorRetval
:
8216 wrapArgs
+= ", desiredProto"
8217 wrap
= "%s(%s)" % (wrapMethod
, wrapArgs
)
8218 # Can only fail to wrap as a new-binding object if they already
8219 # threw an exception.
8220 failed
= "MOZ_ASSERT(JS_IsExceptionPending(cx));\n" + exceptionCode
8222 if descriptor
.notflattened
:
8223 getIID
= "&NS_GET_IID(%s), " % descriptor
.nativeType
8226 wrap
= "WrapObject(cx, %s, %s${jsvalHandle})" % (result
, getIID
)
8229 wrappingCode
+= wrapAndSetPtr(wrap
, failed
)
8230 return (wrappingCode
, False)
8232 if type.isJSString():
8233 return (setString(result
), False)
8235 if type.isDOMString() or type.isUSVString():
8238 wrapAndSetPtr("xpc::StringToJsval(cx, %s, ${jsvalHandle})" % result
),
8244 "xpc::NonVoidStringToJsval(cx, %s, ${jsvalHandle})" % result
8249 if type.isByteString():
8252 wrapAndSetPtr("ByteStringToJsval(cx, %s, ${jsvalHandle})" % result
),
8258 "NonVoidByteStringToJsval(cx, %s, ${jsvalHandle})" % result
8263 if type.isUTF8String():
8266 wrapAndSetPtr("UTF8StringToJsval(cx, %s, ${jsvalHandle})" % result
),
8272 "NonVoidUTF8StringToJsval(cx, %s, ${jsvalHandle})" % result
8279 resultLoc
= "%s.Value()" % result
8284 if (!ToJSValue(cx, ${result}, $${jsvalHandle})) {
8290 exceptionCode
=exceptionCode
,
8291 successCode
=successCode
,
8295 conversion
= CGIfElseWrapper(
8296 "%s.IsNull()" % result
, CGGeneric(setNull()), CGGeneric(conversion
)
8298 return conversion
, False
8300 if type.isCallback() or type.isCallbackInterface():
8301 # Callbacks can store null if we nuked the compartments their
8303 wrapCode
= setObjectOrNull(
8304 "GetCallbackFromCallbackObject(cx, %(result)s)", wrapAsType
=type
8308 "if (%(result)s) {\n"
8314 wrapCode
= wrapCode
% {"result": result
}
8315 return wrapCode
, False
8318 # See comments in GetOrCreateDOMReflector explaining why we need
8320 # NB: _setValue(..., type-that-is-any) calls JS_WrapValue(), so is fallible
8321 head
= "JS::ExposeValueToActiveJS(%s);\n" % result
8322 return (head
+ _setValue(result
, wrapAsType
=type), False)
8324 if type.isObject() or (
8325 type.isSpiderMonkeyInterface() and not spiderMonkeyInterfacesAreStructs
8327 # See comments in GetOrCreateDOMReflector explaining why we need
8331 setter
= setObjectOrNull
8333 JS::ExposeObjectToActiveJS(%s);
8342 head
= "JS::ExposeObjectToActiveJS(%s);\n" % result
8343 # NB: setObject{,OrNull}(..., some-object-type) calls JS_WrapValue(), so is fallible
8344 return (head
+ setter(toValue
% result
, wrapAsType
=type), False)
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
.isVoid():
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 checkPrincipal
= dedent(
8837 if (principal->IsSystemPrincipal()) {
8838 principal = nullptr;
8845 getPrincipal
= fill(
8847 JS::Realm* realm = js::GetContextRealm(cx);
8849 JSPrincipals* principals = JS::GetRealmPrincipals(realm);
8850 nsIPrincipal* principal = nsJSPrincipals::get(principals);
8853 checkPrincipal
=checkPrincipal
,
8856 if descriptor
.interface
.isExposedInAnyWorker():
8861 Maybe<nsIPrincipal*> subjectPrincipal;
8862 if (NS_IsMainThread()) {
8864 subjectPrincipal.emplace(principal);
8867 getPrincipal
=getPrincipal
,
8871 subjectPrincipalArg
= "subjectPrincipal"
8873 if needsNonSystemPrincipal
:
8874 principalType
= "nsIPrincipal*"
8875 subjectPrincipalArg
= "subjectPrincipal"
8877 principalType
= "NonNull<nsIPrincipal>"
8878 subjectPrincipalArg
= "NonNullHelper(subjectPrincipal)"
8884 ${principalType} subjectPrincipal;
8887 subjectPrincipal = principal;
8890 principalType
=principalType
,
8891 getPrincipal
=getPrincipal
,
8896 args
.append(CGGeneric("MOZ_KnownLive(%s)" % subjectPrincipalArg
))
8900 args
.append(CGGeneric("SystemCallerGuarantee()"))
8902 args
.append(CGGeneric(callerTypeGetterForDescriptor(descriptor
)))
8904 canOOM
= "canOOM" in extendedAttributes
8905 if needsErrorResult
:
8906 args
.append(CGGeneric("rv"))
8908 args
.append(CGGeneric("OOMReporter::From(rv)"))
8909 args
.extend(CGGeneric(arg
) for arg
in argsPost
)
8911 call
= CGGeneric(nativeMethodName
)
8913 call
= CGWrapper(call
, pre
="%s->" % object)
8914 call
= CGList([call
, CGWrapper(args
, pre
="(", post
=")")])
8915 if returnType
is None or returnType
.isVoid() or resultOutParam
is not None:
8916 assert resultConversion
is None
8922 "// NOTE: This assert does NOT call the function.\n"
8923 "static_assert(std::is_void_v<decltype("
8925 post
=')>, "Should be returning void here");',
8931 elif resultConversion
is not None:
8932 call
= CGList([resultConversion
, CGWrapper(call
, pre
="(", post
=")")])
8933 if resultVar
is None and result
is not None:
8934 needResultDecl
= True
8935 resultVar
= "result"
8938 if resultArgs
is not None:
8939 resultArgsStr
= "(%s)" % resultArgs
8942 result
= CGWrapper(result
, post
=(" %s%s" % (resultVar
, resultArgsStr
)))
8943 if resultOutParam
is None and resultArgs
is None:
8944 call
= CGList([result
, CGWrapper(call
, pre
="(", post
=")")])
8946 self
.cgRoot
.append(CGWrapper(result
, post
=";\n"))
8947 if resultOutParam
is None:
8948 call
= CGWrapper(call
, pre
=resultVar
+ " = ")
8949 if resultRooter
is not None:
8950 self
.cgRoot
.append(resultRooter
)
8951 elif result
is not None:
8952 assert resultOutParam
is None
8953 call
= CGWrapper(call
, pre
=resultVar
+ " = ")
8955 call
= CGWrapper(call
, post
=";\n")
8956 self
.cgRoot
.append(call
)
8958 if needsErrorResult
or canOOM
:
8959 self
.cgRoot
.prepend(CGGeneric("FastErrorResult rv;\n"))
8964 if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx, ${context}))) {
8973 self
.cgRoot
.append(CGGeneric("MOZ_ASSERT(!JS_IsExceptionPending(cx));\n"))
8976 return self
.cgRoot
.define()
8979 def getUnionMemberName(type):
8980 # Promises can't be in unions, because they're not distinguishable
8981 # from anything else.
8982 assert not type.isPromise()
8983 if type.isGeckoInterface():
8984 return type.inner
.identifier
.name
8986 return type.inner
.identifier
.name
8990 # A counter for making sure that when we're wrapping up things in
8991 # nested sequences we don't use the same variable name to iterate over
8992 # different sequences.
8993 sequenceWrapLevel
= 0
8997 def wrapTypeIntoCurrentCompartment(type, value
, isMember
=True):
8999 Take the thing named by "value" and if it contains "any",
9000 "object", or spidermonkey-interface types inside return a CGThing
9001 that will wrap them into the current compartment.
9004 assert not type.nullable()
9006 value
= "JS::MutableHandle<JS::Value>::fromMarkedLocation(&%s)" % value
9010 "if (!JS_WrapValue(cx, %s)) {\n" " return false;\n" "}\n" % value
9015 value
= "JS::MutableHandle<JSObject*>::fromMarkedLocation(&%s)" % value
9019 "if (!JS_WrapObject(cx, %s)) {\n" " return false;\n" "}\n" % value
9022 if type.isSpiderMonkeyInterface():
9025 value
= "%s.Value()" % value
9026 wrapCode
= CGGeneric(
9027 "if (!%s.WrapIntoNewCompartment(cx)) {\n" " return false;\n" "}\n" % value
9030 wrapCode
= CGIfWrapper(wrapCode
, "!%s.IsNull()" % origValue
)
9033 if type.isSequence():
9038 value
= "%s.Value()" % value
9039 global sequenceWrapLevel
9040 index
= "indexName%d" % sequenceWrapLevel
9041 sequenceWrapLevel
+= 1
9042 wrapElement
= wrapTypeIntoCurrentCompartment(
9043 type.inner
, "%s[%s]" % (value
, index
)
9045 sequenceWrapLevel
-= 1
9048 wrapCode
= CGWrapper(
9049 CGIndenter(wrapElement
),
9051 "for (uint32_t %s = 0; %s < %s.Length(); ++%s) {\n"
9052 % (index
, index
, value
, index
)
9056 if origType
.nullable():
9057 wrapCode
= CGIfWrapper(wrapCode
, "!%s.IsNull()" % origValue
)
9064 recordRef
= "%s.Value()" % value
9067 global recordWrapLevel
9068 entryRef
= "mapEntry%d" % recordWrapLevel
9069 recordWrapLevel
+= 1
9070 wrapElement
= wrapTypeIntoCurrentCompartment(type.inner
, "%s.mValue" % entryRef
)
9071 recordWrapLevel
-= 1
9074 wrapCode
= CGWrapper(
9075 CGIndenter(wrapElement
),
9076 pre
=("for (auto& %s : %s.Entries()) {\n" % (entryRef
, recordRef
)),
9079 if origType
.nullable():
9080 wrapCode
= CGIfWrapper(wrapCode
, "!%s.IsNull()" % value
)
9083 if type.isDictionary():
9084 assert not type.nullable()
9088 for member
in myDict
.members
:
9089 memberWrap
= wrapArgIntoCurrentCompartment(
9092 % (value
, CGDictionary
.makeMemberName(member
.identifier
.name
)),
9095 memberWraps
.append(memberWrap
)
9096 myDict
= myDict
.parent
9097 return CGList(memberWraps
) if len(memberWraps
) != 0 else None
9103 value
= "%s.Value()" % value
9104 for member
in type.flatMemberTypes
:
9105 memberName
= getUnionMemberName(member
)
9106 memberWrap
= wrapTypeIntoCurrentCompartment(
9107 member
, "%s.GetAs%s()" % (value
, memberName
)
9110 memberWrap
= CGIfWrapper(memberWrap
, "%s.Is%s()" % (value
, memberName
))
9111 memberWraps
.append(memberWrap
)
9112 return CGList(memberWraps
, "else ") if len(memberWraps
) != 0 else None
9116 or type.isPrimitive()
9118 or type.isGeckoInterface()
9119 or type.isCallback()
9122 # All of these don't need wrapping.
9126 "Unknown type; we don't know how to wrap it in constructor "
9127 "arguments: %s" % type
9131 def wrapArgIntoCurrentCompartment(arg
, value
, isMember
=True):
9133 As wrapTypeIntoCurrentCompartment but handles things being optional
9136 isOptional
= arg
.canHaveMissingValue()
9138 value
= value
+ ".Value()"
9139 wrap
= wrapTypeIntoCurrentCompartment(arg
.type, value
, isMember
)
9140 if wrap
and isOptional
:
9141 wrap
= CGIfWrapper(wrap
, "%s.WasPassed()" % origValue
)
9145 def needsContainsHack(m
):
9146 return m
.getExtendedAttribute("ReturnValueNeedsContainsHack")
9149 def needsCallerType(m
):
9150 return m
.getExtendedAttribute("NeedsCallerType")
9153 class CGPerSignatureCall(CGThing
):
9155 This class handles the guts of generating code for a particular
9156 call signature. A call signature consists of four things:
9158 1) A return type, which can be None to indicate that there is no
9159 actual return value (e.g. this is an attribute setter) or an
9160 IDLType if there's an IDL type involved (including |void|).
9161 2) An argument list, which is allowed to be empty.
9162 3) A name of a native method to call.
9163 4) Whether or not this method is static. Note that this only controls how
9164 the method is called (|self->nativeMethodName(...)| vs
9165 |nativeMethodName(...)|).
9167 We also need to know whether this is a method or a getter/setter
9168 to do error reporting correctly.
9170 The idlNode parameter can be either a method or an attr. We can query
9171 |idlNode.identifier| in both cases, so we can be agnostic between the two.
9173 dontSetSlot should be set to True if the value should not be cached in a
9174 slot (even if the attribute is marked as StoreInSlot or Cached in the
9178 # XXXbz For now each entry in the argument list is either an
9179 # IDLArgument or a FakeArgument, but longer-term we may want to
9180 # have ways of flagging things like JSContext* or optional_argc in
9191 argConversionStartsAt
=0,
9194 isConstructor
=False,
9195 useCounterName
=None,
9199 extendedAttributes
=None,
9201 assert idlNode
.isMethod() == (not getter
and not setter
)
9202 assert idlNode
.isAttr() == (getter
or setter
)
9203 # Constructors are always static
9204 assert not isConstructor
or static
9206 CGThing
.__init
__(self
)
9207 self
.returnType
= returnType
9208 self
.descriptor
= descriptor
9209 self
.idlNode
= idlNode
9210 if extendedAttributes
is None:
9211 extendedAttributes
= descriptor
.getExtendedAttributes(
9212 idlNode
, getter
=getter
, setter
=setter
9214 self
.extendedAttributes
= extendedAttributes
9215 self
.arguments
= arguments
9216 self
.argCount
= len(arguments
)
9217 self
.isConstructor
= isConstructor
9219 not dontSetSlot
and idlNode
.isAttr() and idlNode
.slotIndices
is not None
9223 deprecated
= idlNode
.getExtendedAttribute("Deprecated") or (
9225 and descriptor
.interface
.getExtendedAttribute("Deprecated")
9232 DeprecationWarning(cx, obj, DeprecatedOperations::e%s);
9239 lenientFloatCode
= None
9240 if idlNode
.getExtendedAttribute("LenientFloat") is not None and (
9241 setter
or idlNode
.isMethod()
9247 bool foundNonFiniteFloat = false;
9252 lenientFloatCode
= "foundNonFiniteFloat = true;\n"
9255 if idlNode
.isStatic():
9256 # If we're a constructor, "obj" may not be a function, so calling
9257 # XrayAwareCalleeGlobal() on it is not safe. Of course in the
9258 # constructor case either "obj" is an Xray or we're already in the
9259 # content compartment, not the Xray compartment, so just
9260 # constructing the GlobalObject from "obj" is fine.
9262 objForGlobalObject
= "obj"
9264 objForGlobalObject
= "xpc::XrayAwareCalleeGlobal(obj)"
9269 GlobalObject global(cx, ${obj});
9270 if (global.Failed()) {
9275 obj
=objForGlobalObject
,
9279 argsPre
.append("global")
9281 # For JS-implemented interfaces we do not want to base the
9282 # needsCx decision on the types involved, just on our extended
9283 # attributes. Also, JSContext is not needed for the static case
9284 # since GlobalObject already contains the context.
9288 self
.extendedAttributes
,
9289 not descriptor
.interface
.isJSImplemented(),
9293 argsPre
.append("cx")
9297 runConstructorInCallerCompartment
= descriptor
.interface
.getExtendedAttribute(
9298 "RunConstructorInCallerCompartment"
9300 if isConstructor
and not runConstructorInCallerCompartment
:
9302 needsUnwrappedVar
= False
9303 unwrappedVar
= "obj"
9304 if descriptor
.interface
.isJSImplemented():
9305 # We need the desired proto in our constructor, because the
9306 # constructor will actually construct our reflector.
9307 argsPost
.append("desiredProto")
9308 elif descriptor
.interface
.isJSImplemented():
9309 if not idlNode
.isStatic():
9311 needsUnwrappedVar
= True
9313 "(unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx))"
9315 elif needScopeObject(
9318 self
.extendedAttributes
,
9319 descriptor
.wrapperCache
,
9321 idlNode
.getExtendedAttribute("StoreInSlot"),
9323 # If we ever end up with APIs like this on cross-origin objects,
9324 # figure out how the CheckedUnwrapDynamic bits should work. Chances
9325 # are, just calling it with "cx" is fine... For now, though, just
9326 # assert that it does not matter.
9327 assert not descriptor
.isMaybeCrossOriginObject()
9328 # The scope object should always be from the relevant
9329 # global. Make sure to unwrap it as needed.
9334 JS::Rooted<JSObject*> unwrappedObj(cx, js::CheckedUnwrapStatic(obj));
9335 // Caller should have ensured that "obj" can be unwrapped already.
9336 MOZ_DIAGNOSTIC_ASSERT(unwrappedObj);
9341 argsPre
.append("unwrappedObj")
9343 if needsUnwrap
and needsUnwrappedVar
:
9344 # We cannot assign into obj because it's a Handle, not a
9345 # MutableHandle, so we need a separate Rooted.
9346 cgThings
.append(CGGeneric("Maybe<JS::Rooted<JSObject*> > unwrappedObj;\n"))
9347 unwrappedVar
= "unwrappedObj.ref()"
9349 if idlNode
.isMethod() and idlNode
.isLegacycaller():
9350 # If we can have legacycaller with identifier, we can't
9351 # just use the idlNode to determine whether we're
9352 # generating code for the legacycaller or not.
9353 assert idlNode
.isIdentifierLess()
9354 # Pass in our thisVal
9355 argsPre
.append("args.thisv()")
9357 if idlNode
.isMethod():
9358 argDescription
= "argument %(index)d"
9360 argDescription
= "value being assigned"
9362 assert self
.argCount
== 0
9365 # It's very important that we construct our unwrappedObj, if we need
9366 # to do it, before we might start setting up Rooted things for our
9367 # arguments, so that we don't violate the stack discipline Rooted
9370 CGGeneric("bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);\n")
9372 if needsUnwrappedVar
:
9375 CGGeneric("unwrappedObj.emplace(cx, obj);\n"), "objIsXray"
9379 for i
in range(argConversionStartsAt
, self
.argCount
):
9381 CGArgumentConverter(
9385 argDescription
% {"index": i
+ 1},
9387 invalidEnumValueFatal
=not setter
,
9388 lenientFloatCode
=lenientFloatCode
,
9392 # Now that argument processing is done, enforce the LenientFloat stuff
9393 if lenientFloatCode
:
9395 foundNonFiniteFloatBehavior
= "return true;\n"
9397 assert idlNode
.isMethod()
9398 foundNonFiniteFloatBehavior
= dedent(
9400 args.rval().setUndefined();
9408 if (foundNonFiniteFloat) {
9412 returnSteps
=foundNonFiniteFloatBehavior
,
9418 # Something depends on having the unwrapped object, so unwrap it now.
9420 # XXXkhuey we should be able to MOZ_ASSERT that ${obj} is
9426 // Since our object is an Xray, we can just CheckedUnwrapStatic:
9427 // we know Xrays have no dynamic unwrap behavior.
9428 ${obj} = js::CheckedUnwrapStatic(${obj});
9438 # If we're called via an xray, we need to enter the underlying
9439 # object's compartment and then wrap up all of our arguments into
9440 # that compartment as needed. This is all happening after we've
9441 # already done the conversions from JS values to WebIDL (C++)
9442 # values, so we only need to worry about cases where there are 'any'
9443 # or 'object' types, or other things that we represent as actual
9444 # JSAPI types, present. Effectively, we're emulating a
9445 # CrossCompartmentWrapper, but working with the C++ types, not the
9446 # original list of JS::Values.
9447 cgThings
.append(CGGeneric("Maybe<JSAutoRealm> ar;\n"))
9448 xraySteps
.append(CGGeneric("ar.emplace(cx, obj);\n"))
9453 if (!JS_WrapObject(cx, &desiredProto)) {
9461 wrapArgIntoCurrentCompartment(arg
, argname
, isMember
=False)
9462 for arg
, argname
in self
.getArguments()
9465 cgThings
.append(CGIfWrapper(CGList(xraySteps
), "objIsXray"))
9467 if idlNode
.getExtendedAttribute("CEReactions") is not None and not getter
:
9472 Maybe<AutoCEReaction> ceReaction;
9473 DocGroup* docGroup = self->GetDocGroup();
9475 ceReaction.emplace(docGroup->CustomElementReactionsStack(), cx);
9482 # If this is a method that was generated by a maplike/setlike
9483 # interface, use the maplike/setlike generator to fill in the body.
9484 # Otherwise, use CGCallGenerator to call the native method.
9485 if idlNode
.isMethod() and idlNode
.isMaplikeOrSetlikeOrIterableMethod():
9487 idlNode
.maplikeOrSetlikeOrIterable
.isMaplike()
9488 or idlNode
.maplikeOrSetlikeOrIterable
.isSetlike()
9491 CGMaplikeOrSetlikeMethodGenerator(
9493 idlNode
.maplikeOrSetlikeOrIterable
,
9494 idlNode
.identifier
.name
,
9499 CGIterableMethodGenerator(
9501 idlNode
.maplikeOrSetlikeOrIterable
,
9502 idlNode
.identifier
.name
,
9506 context
= GetLabelForErrorReporting(descriptor
, idlNode
, isConstructor
)
9508 context
= context
+ " getter"
9510 context
= context
+ " setter"
9511 # Callee expects a quoted string for the context if
9512 # there's a context.
9513 context
= '"%s"' % context
9516 self
.needsErrorResult(),
9517 needsCallerType(idlNode
),
9518 isChromeOnly(idlNode
),
9519 self
.getArguments(),
9522 self
.extendedAttributes
,
9526 # We know our "self" must be being kept alive; otherwise we have
9527 # a serious problem. In common cases it's just an argument and
9528 # we're MOZ_CAN_RUN_SCRIPT, but in some cases it's on the stack
9529 # and being kept alive via references from JS.
9530 object="MOZ_KnownLive(self)",
9532 resultVar
=resultVar
,
9538 # Generate a telemetry call for when [UseCounter] is used.
9541 SetUseCounter(obj, eUseCounter_${useCounterName});
9543 useCounterName
=useCounterName
,
9547 SetUseCounter(UseCounterWorker::${useCounterName});
9549 useCounterName
=useCounterName
,
9552 if idlNode
.isExposedInWindow() and idlNode
.isExposedInAnyWorker():
9555 if (NS_IsMainThread()) {
9561 windowCode
=windowCode
,
9562 workerCode
=workerCode
,
9564 elif idlNode
.isExposedInWindow():
9566 elif idlNode
.isExposedInAnyWorker():
9569 cgThings
.append(CGGeneric(code
))
9571 self
.cgRoot
= CGList(cgThings
)
9573 def getArguments(self
):
9574 return [(a
, "arg" + str(i
)) for i
, a
in enumerate(self
.arguments
)]
9576 def needsErrorResult(self
):
9577 return "needsErrorResult" in self
.extendedAttributes
9579 def wrap_return_value(self
):
9582 returnsNewObject
= memberReturnsNewObject(self
.idlNode
)
9583 if returnsNewObject
and (
9584 self
.returnType
.isGeckoInterface() or self
.returnType
.isPromise()
9588 static_assert(!std::is_pointer_v<decltype(result)>,
9589 "NewObject implies that we need to keep the object alive with a strong reference.");
9594 # For attributes in slots, we want to do some
9595 # post-processing once we've wrapped them.
9596 successCode
= "break;\n"
9600 resultTemplateValues
= {
9601 "jsvalRef": "args.rval()",
9602 "jsvalHandle": "args.rval()",
9603 "returnsNewObject": returnsNewObject
,
9604 "isConstructorRetval": self
.isConstructor
,
9605 "successCode": successCode
,
9606 # 'obj' in this dictionary is the thing whose compartment we are
9607 # trying to do the to-JS conversion in. We're going to put that
9608 # thing in a variable named "conversionScope" if setSlot is true.
9609 # Otherwise, just use "obj" for lack of anything better.
9610 "obj": "conversionScope" if self
.setSlot
else "obj",
9613 wrapCode
+= wrapForType(self
.returnType
, self
.descriptor
, resultTemplateValues
)
9616 if self
.idlNode
.isStatic():
9618 "Attribute %s.%s is static, so we don't have a useful slot "
9619 "to cache it in, because we don't have support for that on "
9620 "interface objects. See "
9621 "https://bugzilla.mozilla.org/show_bug.cgi?id=1363870"
9623 self
.descriptor
.interface
.identifier
.name
,
9624 self
.idlNode
.identifier
.name
,
9628 # When using a slot on the Xray expando, we need to make sure that
9629 # our initial conversion to a JS::Value is done in the caller
9630 # compartment. When using a slot on our reflector, we want to do
9631 # the conversion in the compartment of that reflector (that is,
9632 # slotStorage). In both cases we want to make sure that we finally
9633 # set up args.rval() to be in the caller compartment. We also need
9634 # to make sure that the conversion steps happen inside a do/while
9635 # that they can break out of on success.
9637 # Of course we always have to wrap the value into the slotStorage
9638 # compartment before we store it in slotStorage.
9640 # postConversionSteps are the steps that run while we're still in
9641 # the compartment we do our conversion in but after we've finished
9642 # the initial conversion into args.rval().
9643 postConversionSteps
= ""
9644 if needsContainsHack(self
.idlNode
):
9645 # Define a .contains on the object that has the same value as
9646 # .includes; needed for backwards compat in extensions as we
9647 # migrate some DOMStringLists to FrozenArray.
9648 postConversionSteps
+= dedent(
9650 if (args.rval().isObject() && nsContentUtils::ThreadsafeIsSystemCaller(cx)) {
9651 JS::Rooted<JSObject*> rvalObj(cx, &args.rval().toObject());
9652 JS::Rooted<JS::Value> includesVal(cx);
9653 if (!JS_GetProperty(cx, rvalObj, "includes", &includesVal) ||
9654 !JS_DefineProperty(cx, rvalObj, "contains", includesVal, JSPROP_ENUMERATE)) {
9661 if self
.idlNode
.getExtendedAttribute("Frozen"):
9663 self
.idlNode
.type.isSequence() or self
.idlNode
.type.isDictionary()
9665 freezeValue
= CGGeneric(
9666 "JS::Rooted<JSObject*> rvalObj(cx, &args.rval().toObject());\n"
9667 "if (!JS_FreezeObject(cx, rvalObj)) {\n"
9671 if self
.idlNode
.type.nullable():
9672 freezeValue
= CGIfWrapper(freezeValue
, "args.rval().isObject()")
9673 postConversionSteps
+= freezeValue
.define()
9675 # slotStorageSteps are steps that run once we have entered the
9676 # slotStorage compartment.
9677 slotStorageSteps
= fill(
9679 // Make a copy so that we don't do unnecessary wrapping on args.rval().
9680 JS::Rooted<JS::Value> storedVal(cx, args.rval());
9681 if (!${maybeWrap}(cx, &storedVal)) {
9684 JS::SetReservedSlot(slotStorage, slotIndex, storedVal);
9686 maybeWrap
=getMaybeWrapValueFuncForType(self
.idlNode
.type),
9689 checkForXray
= mayUseXrayExpandoSlots(self
.descriptor
, self
.idlNode
)
9691 # For the case of Cached attributes, go ahead and preserve our
9692 # wrapper if needed. We need to do this because otherwise the
9693 # wrapper could get garbage-collected and the cached value would
9694 # suddenly disappear, but the whole premise of cached values is that
9695 # they never change without explicit action on someone's part. We
9696 # don't do this for StoreInSlot, since those get dealt with during
9697 # wrapper setup, and failure would involve us trying to clear an
9698 # already-preserved wrapper.
9700 self
.idlNode
.getExtendedAttribute("Cached")
9701 and self
.descriptor
.wrapperCache
9703 preserveWrapper
= dedent(
9705 PreserveWrapper(self);
9709 preserveWrapper
= fill(
9712 // In the Xray case we don't need to do this, because getting the
9713 // expando object already preserved our wrapper.
9717 preserveWrapper
=preserveWrapper
,
9719 slotStorageSteps
+= preserveWrapper
9722 # In the Xray case we use the current global as conversion
9723 # scope, as explained in the big compartment/conversion comment
9725 conversionScope
= "isXray ? JS::CurrentGlobalOrNull(cx) : slotStorage"
9727 conversionScope
= "slotStorage"
9732 JS::Rooted<JSObject*> conversionScope(cx, ${conversionScope});
9733 JSAutoRealm ar(cx, conversionScope);
9734 do { // block we break out of when done wrapping
9737 $*{postConversionSteps}
9739 { // And now store things in the realm of our slotStorage.
9740 JSAutoRealm ar(cx, slotStorage);
9741 $*{slotStorageSteps}
9743 // And now make sure args.rval() is in the caller realm.
9744 return ${maybeWrap}(cx, args.rval());
9746 conversionScope
=conversionScope
,
9748 postConversionSteps
=postConversionSteps
,
9749 slotStorageSteps
=slotStorageSteps
,
9750 maybeWrap
=getMaybeWrapValueFuncForType(self
.idlNode
.type),
9755 return self
.cgRoot
.define() + self
.wrap_return_value()
9758 class CGSwitch(CGList
):
9760 A class to generate code for a switch statement.
9762 Takes three constructor arguments: an expression, a list of cases,
9763 and an optional default.
9765 Each case is a CGCase. The default is a CGThing for the body of
9766 the default case, if any.
9769 def __init__(self
, expression
, cases
, default
=None):
9770 CGList
.__init
__(self
, [CGIndenter(c
) for c
in cases
])
9771 self
.prepend(CGGeneric("switch (" + expression
+ ") {\n"))
9772 if default
is not None:
9776 CGIndenter(default
), pre
="default: {\n", post
=" break;\n}\n"
9781 self
.append(CGGeneric("}\n"))
9784 class CGCase(CGList
):
9786 A class to generate code for a case statement.
9788 Takes three constructor arguments: an expression, a CGThing for
9789 the body (allowed to be None if there is no body), and an optional
9790 argument (defaulting to False) for whether to fall through.
9793 def __init__(self
, expression
, body
, fallThrough
=False):
9794 CGList
.__init
__(self
, [])
9795 self
.append(CGGeneric("case " + expression
+ ": {\n"))
9796 bodyList
= CGList([body
])
9798 bodyList
.append(CGGeneric("[[fallthrough]];\n"))
9800 bodyList
.append(CGGeneric("break;\n"))
9801 self
.append(CGIndenter(bodyList
))
9802 self
.append(CGGeneric("}\n"))
9805 class CGMethodCall(CGThing
):
9807 A class to generate selection of a method signature from a set of
9808 signatures and generation of a call to that signature.
9812 self
, nativeMethodName
, static
, descriptor
, method
, isConstructor
=False
9814 CGThing
.__init
__(self
)
9816 methodName
= GetLabelForErrorReporting(descriptor
, method
, isConstructor
)
9817 argDesc
= "argument %d"
9819 if method
.getExtendedAttribute("UseCounter"):
9820 useCounterName
= methodName
.replace(".", "_")
9822 useCounterName
= None
9824 if method
.isStatic():
9825 nativeType
= descriptor
.nativeType
9826 staticTypeOverride
= PropertyDefiner
.getStringAttr(
9827 method
, "StaticClassOverride"
9829 if staticTypeOverride
:
9830 nativeType
= staticTypeOverride
9831 nativeMethodName
= "%s::%s" % (nativeType
, nativeMethodName
)
9833 def requiredArgCount(signature
):
9834 arguments
= signature
[1]
9835 if len(arguments
) == 0:
9837 requiredArgs
= len(arguments
)
9838 while requiredArgs
and arguments
[requiredArgs
- 1].optional
:
9842 def getPerSignatureCall(signature
, argConversionStartsAt
=0):
9843 return CGPerSignatureCall(
9850 argConversionStartsAt
=argConversionStartsAt
,
9851 isConstructor
=isConstructor
,
9852 useCounterName
=useCounterName
,
9855 signatures
= method
.signatures()
9856 if len(signatures
) == 1:
9857 # Special case: we can just do a per-signature method call
9858 # here for our one signature and not worry about switching
9860 signature
= signatures
[0]
9861 self
.cgRoot
= CGList([getPerSignatureCall(signature
)])
9862 requiredArgs
= requiredArgCount(signature
)
9864 # Skip required arguments check for maplike/setlike interfaces, as
9865 # they can have arguments which are not passed, and are treated as
9866 # if undefined had been explicitly passed.
9867 if requiredArgs
> 0 and not method
.isMaplikeOrSetlikeOrIterableMethod():
9870 if (!args.requireAtLeast(cx, "${methodName}", ${requiredArgs})) {
9874 requiredArgs
=requiredArgs
,
9875 methodName
=methodName
,
9877 self
.cgRoot
.prepend(CGGeneric(code
))
9880 # Need to find the right overload
9881 maxArgCount
= method
.maxArgCount
9882 allowedArgCounts
= method
.allowedArgCounts
9885 for argCountIdx
, argCount
in enumerate(allowedArgCounts
):
9886 possibleSignatures
= method
.signaturesForArgCount(argCount
)
9888 # Try to optimize away cases when the next argCount in the list
9889 # will have the same code as us; if it does, we can fall through to
9891 if argCountIdx
+ 1 < len(allowedArgCounts
):
9892 nextPossibleSignatures
= method
.signaturesForArgCount(
9893 allowedArgCounts
[argCountIdx
+ 1]
9896 nextPossibleSignatures
= None
9897 if possibleSignatures
== nextPossibleSignatures
:
9898 # Same set of signatures means we better have the same
9899 # distinguishing index. So we can in fact just fall through to
9900 # the next case here.
9901 assert len(possibleSignatures
) == 1 or (
9902 method
.distinguishingIndexForArgCount(argCount
)
9903 == method
.distinguishingIndexForArgCount(
9904 allowedArgCounts
[argCountIdx
+ 1]
9907 argCountCases
.append(CGCase(str(argCount
), None, True))
9910 if len(possibleSignatures
) == 1:
9912 signature
= possibleSignatures
[0]
9913 argCountCases
.append(
9914 CGCase(str(argCount
), getPerSignatureCall(signature
))
9918 distinguishingIndex
= method
.distinguishingIndexForArgCount(argCount
)
9920 def distinguishingArgument(signature
):
9922 if distinguishingIndex
< len(args
):
9923 return args
[distinguishingIndex
]
9924 assert args
[-1].variadic
9927 def distinguishingType(signature
):
9928 return distinguishingArgument(signature
).type
9930 for sig
in possibleSignatures
:
9931 # We should not have "any" args at distinguishingIndex,
9932 # since we have multiple possible signatures remaining,
9933 # but "any" is never distinguishable from anything else.
9934 assert not distinguishingType(sig
).isAny()
9935 # We can't handle unions at the distinguishing index.
9936 if distinguishingType(sig
).isUnion():
9938 "No support for unions as distinguishing "
9939 "arguments yet: %s" % distinguishingArgument(sig
).location
9941 # We don't support variadics as the distinguishingArgument yet.
9942 # If you want to add support, consider this case:
9944 # void(long... foo);
9945 # void(long bar, Int32Array baz);
9947 # in which we have to convert argument 0 to long before picking
9948 # an overload... but all the variadic stuff needs to go into a
9949 # single array in case we pick that overload, so we have to have
9950 # machinery for converting argument 0 to long and then either
9951 # placing it in the variadic bit or not. Or something. We may
9952 # be able to loosen this restriction if the variadic arg is in
9953 # fact at distinguishingIndex, perhaps. Would need to
9955 if distinguishingArgument(sig
).variadic
:
9957 "No support for variadics as distinguishing "
9958 "arguments yet: %s" % distinguishingArgument(sig
).location
9961 # Convert all our arguments up to the distinguishing index.
9962 # Doesn't matter which of the possible signatures we use, since
9963 # they all have the same types up to that point; just use
9964 # possibleSignatures[0]
9966 CGArgumentConverter(
9967 possibleSignatures
[0][1][i
],
9973 for i
in range(0, distinguishingIndex
)
9976 # Select the right overload from our set.
9977 distinguishingArg
= "args[%d]" % distinguishingIndex
9980 signature
, indent
, isDefinitelyObject
=False, isNullOrUndefined
=False
9982 assert not isDefinitelyObject
or not isNullOrUndefined
9983 assert isDefinitelyObject
or isNullOrUndefined
9984 if isDefinitelyObject
:
9985 failureCode
= "break;\n"
9988 type = distinguishingType(signature
)
9989 # The argument at index distinguishingIndex can't possibly be
9990 # unset here, because we've already checked that argc is large
9991 # enough that we can examine this argument. But note that we
9992 # still want to claim that optional arguments are optional, in
9993 # case undefined was passed in.
9994 argIsOptional
= distinguishingArgument(signature
).canHaveMissingValue()
9995 testCode
= instantiateJSToNativeConversion(
9996 getJSToNativeConversionInfo(
9999 failureCode
=failureCode
,
10000 isDefinitelyObject
=isDefinitelyObject
,
10001 isNullOrUndefined
=isNullOrUndefined
,
10002 isOptional
=argIsOptional
,
10003 sourceDescription
=(argDesc
% (distinguishingIndex
+ 1)),
10006 "declName": "arg%d" % distinguishingIndex
,
10007 "holderName": ("arg%d" % distinguishingIndex
) + "_holder",
10008 "val": distinguishingArg
,
10010 "haveValue": "args.hasDefined(%d)" % distinguishingIndex
,
10011 "passedToJSImpl": toStringBool(
10012 isJSImplementedDescriptor(descriptor
)
10015 checkForValue
=argIsOptional
,
10017 caseBody
.append(CGIndenter(testCode
, indent
))
10019 # If we got this far, we know we unwrapped to the right
10020 # C++ type, so just do the call. Start conversion with
10021 # distinguishingIndex + 1, since we already converted
10022 # distinguishingIndex.
10025 getPerSignatureCall(signature
, distinguishingIndex
+ 1), indent
10029 def hasConditionalConversion(type):
10031 Return whether the argument conversion for this type will be
10032 conditional on the type of incoming JS value. For example, for
10033 interface types the conversion is conditional on the incoming
10034 value being isObject().
10036 For the types for which this returns false, we do not have to
10037 output extra isUndefined() or isNullOrUndefined() cases, because
10038 null/undefined values will just fall through into our
10039 unconditional conversion.
10041 if type.isString() or type.isEnum():
10043 if type.isBoolean():
10044 distinguishingTypes
= (
10045 distinguishingType(s
) for s
in possibleSignatures
10048 t
.isString() or t
.isEnum() or t
.isNumeric()
10049 for t
in distinguishingTypes
10051 if type.isNumeric():
10052 distinguishingTypes
= (
10053 distinguishingType(s
) for s
in possibleSignatures
10055 return any(t
.isString() or t
.isEnum() for t
in distinguishingTypes
)
10058 def needsNullOrUndefinedCase(type):
10060 Return true if the type needs a special isNullOrUndefined() case
10063 type.nullable() and hasConditionalConversion(type)
10064 ) or type.isDictionary()
10066 # First check for undefined and optional distinguishing arguments
10067 # and output a special branch for that case. Note that we don't
10068 # use distinguishingArgument here because we actualy want to
10069 # exclude variadic arguments. Also note that we skip this check if
10070 # we plan to output a isNullOrUndefined() special case for this
10071 # argument anyway, since that will subsume our isUndefined() check.
10072 # This is safe, because there can be at most one nullable
10073 # distinguishing argument, so if we're it we'll definitely get
10074 # picked up by the nullable handling. Also, we can skip this check
10075 # if the argument has an unconditional conversion later on.
10078 for s
in possibleSignatures
10079 if distinguishingIndex
< len(s
[1])
10080 and s
[1][distinguishingIndex
].optional
10081 and hasConditionalConversion(s
[1][distinguishingIndex
].type)
10082 and not needsNullOrUndefinedCase(s
[1][distinguishingIndex
].type)
10084 # Can't have multiple signatures with an optional argument at the
10086 assert len(undefSigs
) < 2
10087 if len(undefSigs
) > 0:
10089 CGGeneric("if (%s.isUndefined()) {\n" % distinguishingArg
)
10091 tryCall(undefSigs
[0], 2, isNullOrUndefined
=True)
10092 caseBody
.append(CGGeneric("}\n"))
10094 # Next, check for null or undefined. That means looking for
10095 # nullable arguments at the distinguishing index and outputting a
10096 # separate branch for them. But if the nullable argument has an
10097 # unconditional conversion, we don't need to do that. The reason
10098 # for that is that at most one argument at the distinguishing index
10099 # is nullable (since two nullable arguments are not
10100 # distinguishable), and null/undefined values will always fall
10101 # through to the unconditional conversion we have, if any, since
10102 # they will fail whatever the conditions on the input value are for
10103 # our other conversions.
10104 nullOrUndefSigs
= [
10106 for s
in possibleSignatures
10107 if needsNullOrUndefinedCase(distinguishingType(s
))
10109 # Can't have multiple nullable types here
10110 assert len(nullOrUndefSigs
) < 2
10111 if len(nullOrUndefSigs
) > 0:
10113 CGGeneric("if (%s.isNullOrUndefined()) {\n" % distinguishingArg
)
10115 tryCall(nullOrUndefSigs
[0], 2, isNullOrUndefined
=True)
10116 caseBody
.append(CGGeneric("}\n"))
10118 # Now check for distinguishingArg being various kinds of objects.
10119 # The spec says to check for the following things in order:
10120 # 1) A platform object that's not a platform array object, being
10121 # passed to an interface or "object" arg.
10122 # 2) A callable object being passed to a callback or "object" arg.
10123 # 3) An iterable object being passed to a sequence arg.
10124 # 4) Any object being passed to a array or callback interface or
10125 # dictionary or "object" arg.
10127 # First grab all the overloads that have a non-callback interface
10128 # (which includes SpiderMonkey interfaces) at the distinguishing
10129 # index. We can also include the ones that have an "object" here,
10130 # since if those are present no other object-typed argument will
10134 for s
in possibleSignatures
10136 distinguishingType(s
).isObject()
10137 or distinguishingType(s
).isNonCallbackInterface()
10141 # And all the overloads that take callbacks
10143 s
for s
in possibleSignatures
if distinguishingType(s
).isCallback()
10146 # And all the overloads that take sequences
10148 s
for s
in possibleSignatures
if distinguishingType(s
).isSequence()
10151 # Now append all the overloads that take a dictionary or callback
10152 # interface or record. There should be only one of these!
10153 genericObjectSigs
= [
10155 for s
in possibleSignatures
10157 distinguishingType(s
).isDictionary()
10158 or distinguishingType(s
).isRecord()
10159 or distinguishingType(s
).isCallbackInterface()
10162 assert len(genericObjectSigs
) <= 1
10163 objectSigs
.extend(genericObjectSigs
)
10165 # There might be more than one thing in objectSigs; we need to check
10166 # which ones we unwrap to.
10167 if len(objectSigs
) > 0:
10168 # Here it's enough to guard on our argument being an object.
10169 # The code for unwrapping non-callback interfaces, spiderMonkey
10170 # interfaces, and sequences will just bail out and move
10171 # on to the next overload if the object fails to unwrap
10172 # correctly, while "object" accepts any object anyway. We
10173 # could even not do the isObject() check up front here, but in
10174 # cases where we have multiple object overloads it makes sense
10175 # to do it only once instead of for each overload. That will
10176 # also allow the unwrapping test to skip having to do codegen
10177 # for the null-or-undefined case, which we already handled
10179 caseBody
.append(CGGeneric("if (%s.isObject()) {\n" % distinguishingArg
))
10180 for sig
in objectSigs
:
10181 caseBody
.append(CGIndenter(CGGeneric("do {\n")))
10182 # Indent by 4, since we need to indent further
10183 # than our "do" statement
10184 tryCall(sig
, 4, isDefinitelyObject
=True)
10185 caseBody
.append(CGIndenter(CGGeneric("} while (false);\n")))
10187 caseBody
.append(CGGeneric("}\n"))
10189 # Now we only have to consider booleans, numerics, and strings. If
10190 # we only have one of them, then we can just output it. But if not,
10191 # then we need to output some of the cases conditionally: if we have
10192 # a string overload, then boolean and numeric are conditional, and
10193 # if not then boolean is conditional if we have a numeric overload.
10194 def findUniqueSignature(filterLambda
):
10195 sigs
= [s
for s
in possibleSignatures
if filterLambda(s
)]
10196 assert len(sigs
) < 2
10201 stringSignature
= findUniqueSignature(
10203 distinguishingType(s
).isString() or distinguishingType(s
).isEnum()
10206 numericSignature
= findUniqueSignature(
10207 lambda s
: distinguishingType(s
).isNumeric()
10209 booleanSignature
= findUniqueSignature(
10210 lambda s
: distinguishingType(s
).isBoolean()
10213 if stringSignature
or numericSignature
:
10214 booleanCondition
= "%s.isBoolean()"
10216 booleanCondition
= None
10218 if stringSignature
:
10219 numericCondition
= "%s.isNumber()"
10221 numericCondition
= None
10223 def addCase(sig
, condition
):
10224 sigCode
= getPerSignatureCall(sig
, distinguishingIndex
)
10226 sigCode
= CGIfWrapper(sigCode
, condition
% distinguishingArg
)
10227 caseBody
.append(sigCode
)
10229 if booleanSignature
:
10230 addCase(booleanSignature
, booleanCondition
)
10231 if numericSignature
:
10232 addCase(numericSignature
, numericCondition
)
10233 if stringSignature
:
10234 addCase(stringSignature
, None)
10236 if not booleanSignature
and not numericSignature
and not stringSignature
:
10237 # Just throw; we have no idea what we're supposed to
10241 'return cx.ThrowErrorMessage<MSG_OVERLOAD_RESOLUTION_FAILED>("%d", "%d");\n'
10242 % (distinguishingIndex
+ 1, argCount
)
10246 argCountCases
.append(CGCase(str(argCount
), CGList(caseBody
)))
10248 overloadCGThings
= []
10249 overloadCGThings
.append(
10251 "unsigned argcount = std::min(args.length(), %du);\n" % maxArgCount
10254 overloadCGThings
.append(
10261 // Using nsPrintfCString here would require including that
10262 // header. Let's not worry about it.
10263 nsAutoCString argCountStr;
10264 argCountStr.AppendPrintf("%u", args.length());
10265 return cx.ThrowErrorMessage<MSG_INVALID_OVERLOAD_ARGCOUNT>(argCountStr.get());
10271 overloadCGThings
.append(
10273 'MOZ_CRASH("We have an always-returning default case");\n'
10277 self
.cgRoot
= CGList(overloadCGThings
)
10280 return self
.cgRoot
.define()
10283 class CGGetterCall(CGPerSignatureCall
):
10285 A class to generate a native object getter call for a particular IDL
10296 extendedAttributes
=None,
10298 if attr
.getExtendedAttribute("UseCounter"):
10299 useCounterName
= "%s_%s_getter" % (
10300 descriptor
.interface
.identifier
.name
,
10301 attr
.identifier
.name
,
10304 useCounterName
= None
10305 if attr
.isStatic():
10306 nativeMethodName
= "%s::%s" % (descriptor
.nativeType
, nativeMethodName
)
10307 CGPerSignatureCall
.__init
__(
10316 useCounterName
=useCounterName
,
10317 dontSetSlot
=dontSetSlot
,
10318 extendedAttributes
=extendedAttributes
,
10322 class FakeIdentifier
:
10323 def __init__(self
, name
):
10327 class FakeArgument
:
10329 A class that quacks like an IDLArgument. This is used to make
10330 setters look like method calls or for special operations.
10334 self
, type, interfaceMember
, name
="arg", allowTreatNonCallableAsNull
=False
10337 self
.optional
= False
10338 self
.variadic
= False
10339 self
.defaultValue
= None
10340 self
._allowTreatNonCallableAsNull
= allowTreatNonCallableAsNull
10342 self
.identifier
= FakeIdentifier(name
)
10344 def allowTreatNonCallableAsNull(self
):
10345 return self
._allowTreatNonCallableAsNull
10347 def canHaveMissingValue(self
):
10351 class CGSetterCall(CGPerSignatureCall
):
10353 A class to generate a native object setter call for a particular IDL
10357 def __init__(self
, argType
, nativeMethodName
, descriptor
, attr
):
10358 if attr
.getExtendedAttribute("UseCounter"):
10359 useCounterName
= "%s_%s_setter" % (
10360 descriptor
.interface
.identifier
.name
,
10361 attr
.identifier
.name
,
10364 useCounterName
= None
10365 if attr
.isStatic():
10366 nativeMethodName
= "%s::%s" % (descriptor
.nativeType
, nativeMethodName
)
10367 CGPerSignatureCall
.__init
__(
10370 [FakeArgument(argType
, attr
, allowTreatNonCallableAsNull
=True)],
10376 useCounterName
=useCounterName
,
10379 def wrap_return_value(self
):
10380 attr
= self
.idlNode
10381 if self
.descriptor
.wrapperCache
and attr
.slotIndices
is not None:
10382 if attr
.getExtendedAttribute("StoreInSlot"):
10386 clearSlot
= "%s(%s);\n" % (
10387 MakeClearCachedValueNativeName(self
.idlNode
),
10393 # We have no return value
10394 return "\n" "%s" "return true;\n" % clearSlot
10397 class CGAbstractBindingMethod(CGAbstractStaticMethod
):
10399 Common class to generate some of our class hooks. This will generate the
10400 function declaration, get a reference to the JS object for our binding
10401 object (which might be an argument of the class hook or something we get
10402 from a JS::CallArgs), and unwrap into the right C++ type. Subclasses are
10403 expected to override the generate_code function to do the rest of the work.
10404 This function should return a CGThing which is already properly indented.
10406 getThisObj should be code for getting a JSObject* for the binding
10407 object. "" can be passed in if the binding object is already stored in
10410 callArgs should be code for getting a JS::CallArgs into a variable
10411 called 'args'. This can be "" if there is already such a variable
10412 around or if the body does not need a JS::CallArgs.
10422 callArgs
="JS::CallArgs args = JS::CallArgsFromVp(argc, vp);\n",
10424 CGAbstractStaticMethod
.__init
__(
10425 self
, descriptor
, name
, "bool", args
, canRunScript
=True
10428 # This can't ever happen, because we only use this for class hooks.
10429 self
.unwrapFailureCode
= fill(
10431 MOZ_CRASH("Unexpected object in '${name}' hook");
10437 if getThisObj
== "":
10438 self
.getThisObj
= None
10440 self
.getThisObj
= CGGeneric(
10441 "JS::Rooted<JSObject*> obj(cx, %s);\n" % getThisObj
10443 self
.callArgs
= callArgs
10445 def definition_body(self
):
10446 body
= self
.callArgs
10447 if self
.getThisObj
is not None:
10448 body
+= self
.getThisObj
.define() + "\n"
10449 body
+= "%s* self;\n" % self
.descriptor
.nativeType
10452 JS::Rooted<JS::Value> rootSelf(cx, JS::ObjectValue(*obj));
10457 CastableObjectUnwrapper(
10458 self
.descriptor
, "rootSelf", "&rootSelf", "self", self
.unwrapFailureCode
10462 return body
+ self
.generate_code().define()
10464 def generate_code(self
):
10465 assert False # Override me
10468 class CGAbstractStaticBindingMethod(CGAbstractStaticMethod
):
10470 Common class to generate the JSNatives for all our static methods, getters
10471 and setters. This will generate the function declaration and unwrap the
10472 global object. Subclasses are expected to override the generate_code
10473 function to do the rest of the work. This function should return a
10474 CGThing which is already properly indented.
10477 def __init__(self
, descriptor
, name
):
10478 CGAbstractStaticMethod
.__init
__(
10479 self
, descriptor
, name
, "bool", JSNativeArguments(), canRunScript
=True
10482 def definition_body(self
):
10483 # Make sure that "obj" is in the same compartment as "cx", since we'll
10484 # later use it to wrap return values.
10487 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
10488 JS::Rooted<JSObject*> obj(cx, &args.callee());
10492 return unwrap
+ self
.generate_code().define()
10494 def generate_code(self
):
10495 assert False # Override me
10498 def MakeNativeName(name
):
10499 return name
[0].upper() + IDLToCIdentifier(name
[1:])
10502 def GetWebExposedName(idlObject
, descriptor
):
10503 if idlObject
== descriptor
.operations
["Stringifier"]:
10505 name
= idlObject
.identifier
.name
10506 if name
== "__namedsetter":
10507 return "named setter"
10508 if name
== "__namedgetter":
10509 return "named getter"
10510 if name
== "__indexedsetter":
10511 return "indexed setter"
10512 if name
== "__indexedgetter":
10513 return "indexed getter"
10514 if name
== "__legacycaller":
10515 return "legacy caller"
10519 def GetConstructorNameForReporting(descriptor
, ctor
):
10520 # Figure out the name of our constructor for reporting purposes.
10521 # For unnamed webidl constructors, identifier.name is "constructor" but
10522 # the name JS sees is the interface name; for legacy factory functions
10523 # identifier.name is the actual name.
10524 ctorName
= ctor
.identifier
.name
10525 if ctorName
== "constructor":
10526 return descriptor
.interface
.identifier
.name
10530 def GetLabelForErrorReporting(descriptor
, idlObject
, isConstructor
):
10532 descriptor is the descriptor for the interface involved
10534 idlObject is the method (regular or static), attribute (regular or
10535 static), or constructor (named or not) involved.
10537 isConstructor is true if idlObject is a constructor and false otherwise.
10540 return "%s constructor" % GetConstructorNameForReporting(descriptor
, idlObject
)
10542 namePrefix
= descriptor
.interface
.identifier
.name
10543 name
= GetWebExposedName(idlObject
, descriptor
)
10545 # It's got a space already, so just space-separate.
10546 return "%s %s" % (namePrefix
, name
)
10548 return "%s.%s" % (namePrefix
, name
)
10551 class CGSpecializedMethod(CGAbstractStaticMethod
):
10553 A class for generating the C++ code for a specialized method that the JIT
10554 can call with lower overhead.
10557 def __init__(self
, descriptor
, method
):
10558 self
.method
= method
10559 name
= CppKeywords
.checkMethodName(IDLToCIdentifier(method
.identifier
.name
))
10561 Argument("JSContext*", "cx"),
10562 Argument("JS::Handle<JSObject*>", "obj"),
10563 Argument("void*", "void_self"),
10564 Argument("const JSJitMethodCallArgs&", "args"),
10566 CGAbstractStaticMethod
.__init
__(
10567 self
, descriptor
, name
, "bool", args
, canRunScript
=True
10570 def definition_body(self
):
10571 nativeName
= CGSpecializedMethod
.makeNativeName(self
.descriptor
, self
.method
)
10572 call
= CGMethodCall(
10573 nativeName
, self
.method
.isStatic(), self
.descriptor
, self
.method
10576 if self
.method
.getExtendedAttribute("CrossOriginCallable"):
10577 for signature
in self
.method
.signatures():
10578 # non-void signatures would require us to deal with remote proxies for the
10579 # return value here.
10580 if not signature
[0].isVoid():
10582 "We don't support a method marked as CrossOriginCallable "
10583 "with non-void return type"
10585 prototypeID
, _
= PrototypeIDAndDepth(self
.descriptor
)
10588 // CrossOriginThisPolicy::UnwrapThisObject stores a ${nativeType}::RemoteProxy in void_self
10589 // if obj is a proxy with a RemoteObjectProxy handler for the right type, or else it stores
10590 // a ${nativeType}. If we get here from the JIT (without going through UnwrapThisObject) we
10591 // know void_self contains a ${nativeType}; we don't have special cases in the JIT to deal
10592 // with remote object proxies.
10593 if (IsRemoteObjectProxy(obj, ${prototypeID})) {
10594 auto* self = static_cast<${nativeType}::RemoteProxy*>(void_self);
10598 prototypeID
=prototypeID
,
10599 nativeType
=self
.descriptor
.nativeType
,
10602 return prefix
+ fill(
10604 auto* self = static_cast<${nativeType}*>(void_self);
10607 nativeType
=self
.descriptor
.nativeType
,
10611 def auto_profiler_label(self
):
10612 interface_name
= self
.descriptor
.interface
.identifier
.name
10613 method_name
= self
.method
.identifier
.name
10616 AUTO_PROFILER_LABEL_DYNAMIC_FAST(
10617 "${interface_name}", "${method_name}", DOM, cx,
10618 uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) |
10619 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
10621 interface_name
=interface_name
,
10622 method_name
=method_name
,
10626 def should_have_method_description(descriptor
, idlMethod
):
10628 Returns whether the given IDL method (static, non-static, constructor)
10629 should have a method description declaration, for use in error
10632 # If a method has overloads, it needs a method description, because it
10633 # can throw MSG_INVALID_OVERLOAD_ARGCOUNT at the very least.
10634 if len(idlMethod
.signatures()) != 1:
10637 # Methods with only one signature need a method description if one of
10638 # their args needs it.
10639 sig
= idlMethod
.signatures()[0]
10642 idlTypeNeedsCallContext(
10645 allowTreatNonCallableAsNull
=arg
.allowTreatNonCallableAsNull(),
10651 def error_reporting_label_helper(descriptor
, idlMethod
, isConstructor
):
10653 Returns the method description to use for error reporting for the given
10654 IDL method. Used to implement common error_reporting_label() functions
10655 across different classes.
10657 if not CGSpecializedMethod
.should_have_method_description(
10658 descriptor
, idlMethod
10661 return GetLabelForErrorReporting(descriptor
, idlMethod
, isConstructor
)
10663 def error_reporting_label(self
):
10664 return CGSpecializedMethod
.error_reporting_label_helper(
10665 self
.descriptor
, self
.method
, isConstructor
=False
10669 def makeNativeName(descriptor
, method
):
10670 if method
.underlyingAttr
:
10671 return CGSpecializedGetter
.makeNativeName(descriptor
, method
.underlyingAttr
)
10672 name
= method
.identifier
.name
10673 return MakeNativeName(descriptor
.binaryNameFor(name
))
10676 class CGMethodPromiseWrapper(CGAbstractStaticMethod
):
10678 A class for generating a wrapper around another method that will
10679 convert exceptions to promises.
10682 def __init__(self
, descriptor
, methodToWrap
):
10683 self
.method
= methodToWrap
10684 name
= self
.makeName(methodToWrap
.name
)
10685 args
= list(methodToWrap
.args
)
10686 CGAbstractStaticMethod
.__init
__(
10687 self
, descriptor
, name
, "bool", args
, canRunScript
=True
10690 def definition_body(self
):
10693 bool ok = ${methodName}(${args});
10697 return ConvertExceptionToPromise(cx, args.rval());
10699 methodName
=self
.method
.name
,
10700 args
=", ".join(arg
.name
for arg
in self
.args
),
10704 def makeName(methodName
):
10705 return methodName
+ "_promiseWrapper"
10708 class CGDefaultToJSONMethod(CGSpecializedMethod
):
10709 def __init__(self
, descriptor
, method
):
10710 assert method
.isDefaultToJSON()
10711 CGSpecializedMethod
.__init
__(self
, descriptor
, method
)
10713 def definition_body(self
):
10716 auto* self = static_cast<${nativeType}*>(void_self);
10717 JS::Rooted<JSObject*> result(cx, JS_NewPlainObject(cx));
10722 nativeType
=self
.descriptor
.nativeType
,
10725 jsonDescriptors
= [self
.descriptor
]
10726 interface
= self
.descriptor
.interface
.parent
10728 descriptor
= self
.descriptor
.getDescriptor(interface
.identifier
.name
)
10729 if descriptor
.hasDefaultToJSON
:
10730 jsonDescriptors
.append(descriptor
)
10731 interface
= interface
.parent
10733 # Iterate the array in reverse: oldest ancestor first
10734 for descriptor
in jsonDescriptors
[::-1]:
10737 if (!${parentclass}::CollectJSONAttributes(cx, obj, MOZ_KnownLive(self), result)) {
10741 parentclass
=toBindingNamespace(descriptor
.name
),
10743 ret
+= "args.rval().setObject(*result);\n" "return true;\n"
10747 class CGLegacyCallHook(CGAbstractBindingMethod
):
10749 Call hook for our object
10752 def __init__(self
, descriptor
):
10753 self
._legacycaller
= descriptor
.operations
["LegacyCaller"]
10754 # Our "self" is actually the callee in this case, not the thisval.
10755 CGAbstractBindingMethod
.__init
__(
10758 LEGACYCALLER_HOOK_NAME
,
10759 JSNativeArguments(),
10760 getThisObj
="&args.callee()",
10764 if not self
._legacycaller
:
10766 return CGAbstractBindingMethod
.define(self
)
10768 def generate_code(self
):
10769 name
= self
._legacycaller
.identifier
.name
10770 nativeName
= MakeNativeName(self
.descriptor
.binaryNameFor(name
))
10771 return CGMethodCall(nativeName
, False, self
.descriptor
, self
._legacycaller
)
10773 def error_reporting_label(self
):
10774 # Should act like methods.
10775 return CGSpecializedMethod
.error_reporting_label_helper(
10776 self
.descriptor
, self
._legacycaller
, isConstructor
=False
10780 class CGResolveHook(CGAbstractClassHook
):
10782 Resolve hook for objects that have the NeedResolve extended attribute.
10785 def __init__(self
, descriptor
):
10786 assert descriptor
.interface
.getExtendedAttribute("NeedResolve")
10789 Argument("JSContext*", "cx"),
10790 Argument("JS::Handle<JSObject*>", "obj"),
10791 Argument("JS::Handle<jsid>", "id"),
10792 Argument("bool*", "resolvedp"),
10794 CGAbstractClassHook
.__init
__(self
, descriptor
, RESOLVE_HOOK_NAME
, "bool", args
)
10796 def generate_code(self
):
10799 JS::Rooted<JS::PropertyDescriptor> desc(cx);
10800 if (!self->DoResolve(cx, obj, id, &desc)) {
10803 if (!desc.object()) {
10806 // If desc.value() is undefined, then the DoResolve call
10807 // has already defined it on the object. Don't try to also
10809 if (!desc.value().isUndefined()) {
10810 desc.attributesRef() |= JSPROP_RESOLVING;
10811 if (!JS_DefinePropertyById(cx, obj, id, desc)) {
10820 def definition_body(self
):
10821 if self
.descriptor
.isGlobal():
10822 # Resolve standard classes
10825 if (!ResolveGlobal(cx, obj, id, resolvedp)) {
10836 return prefix
+ CGAbstractClassHook
.definition_body(self
)
10839 class CGMayResolveHook(CGAbstractStaticMethod
):
10841 Resolve hook for objects that have the NeedResolve extended attribute.
10844 def __init__(self
, descriptor
):
10845 assert descriptor
.interface
.getExtendedAttribute("NeedResolve")
10848 Argument("const JSAtomState&", "names"),
10849 Argument("jsid", "id"),
10850 Argument("JSObject*", "maybeObj"),
10852 CGAbstractStaticMethod
.__init
__(
10853 self
, descriptor
, MAY_RESOLVE_HOOK_NAME
, "bool", args
10856 def definition_body(self
):
10857 if self
.descriptor
.isGlobal():
10858 # Check whether this would resolve as a standard class.
10861 if (MayResolveGlobal(names, id, maybeObj)) {
10869 return prefix
+ "return %s::MayResolve(id);\n" % self
.descriptor
.nativeType
10872 class CGEnumerateHook(CGAbstractBindingMethod
):
10874 Enumerate hook for objects with custom hooks.
10877 def __init__(self
, descriptor
):
10878 assert descriptor
.interface
.getExtendedAttribute("NeedResolve")
10881 Argument("JSContext*", "cx"),
10882 Argument("JS::Handle<JSObject*>", "obj"),
10883 Argument("JS::MutableHandleVector<jsid>", "properties"),
10884 Argument("bool", "enumerableOnly"),
10886 # Our "self" is actually the "obj" argument in this case, not the thisval.
10887 CGAbstractBindingMethod
.__init
__(
10888 self
, descriptor
, NEW_ENUMERATE_HOOK_NAME
, args
, getThisObj
="", callArgs
=""
10891 def generate_code(self
):
10895 FastErrorResult rv;
10896 self->GetOwnPropertyNames(cx, properties, enumerableOnly, rv);
10897 if (rv.MaybeSetPendingException(cx)) {
10905 def definition_body(self
):
10906 if self
.descriptor
.isGlobal():
10907 # Enumerate standard classes
10910 if (!EnumerateGlobal(cx, obj, properties, enumerableOnly)) {
10918 return prefix
+ CGAbstractBindingMethod
.definition_body(self
)
10923 A class for checking if method names declared in webidl
10924 are not in conflict with C++ keywords.
10927 keywords
= frozenset(
10987 "reinterpret_cast",
11020 def checkMethodName(name
):
11021 # Double '_' because 'assert' and '_assert' cannot be used in MS2013 compiler.
11022 # Bug 964892 and bug 963560.
11023 if name
in CppKeywords
.keywords
:
11024 name
= "_" + name
+ "_"
11028 class CGStaticMethod(CGAbstractStaticBindingMethod
):
11030 A class for generating the C++ code for an IDL static method.
11033 def __init__(self
, descriptor
, method
):
11034 self
.method
= method
11035 name
= CppKeywords
.checkMethodName(IDLToCIdentifier(method
.identifier
.name
))
11036 CGAbstractStaticBindingMethod
.__init
__(self
, descriptor
, name
)
11038 def generate_code(self
):
11039 nativeName
= CGSpecializedMethod
.makeNativeName(self
.descriptor
, self
.method
)
11040 return CGMethodCall(nativeName
, True, self
.descriptor
, self
.method
)
11042 def auto_profiler_label(self
):
11043 interface_name
= self
.descriptor
.interface
.identifier
.name
11044 method_name
= self
.method
.identifier
.name
11047 AUTO_PROFILER_LABEL_DYNAMIC_FAST(
11048 "${interface_name}", "${method_name}", DOM, cx,
11049 uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) |
11050 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
11052 interface_name
=interface_name
,
11053 method_name
=method_name
,
11056 def error_reporting_label(self
):
11057 return CGSpecializedMethod
.error_reporting_label_helper(
11058 self
.descriptor
, self
.method
, isConstructor
=False
11062 class CGSpecializedGetter(CGAbstractStaticMethod
):
11064 A class for generating the code for a specialized attribute getter
11065 that the JIT can call with lower overhead.
11068 def __init__(self
, descriptor
, attr
):
11070 name
= "get_" + IDLToCIdentifier(attr
.identifier
.name
)
11072 Argument("JSContext*", "cx"),
11073 Argument("JS::Handle<JSObject*>", "obj"),
11074 Argument("void*", "void_self"),
11075 Argument("JSJitGetterCallArgs", "args"),
11077 # StoreInSlot attributes have their getters called from Wrap(). We
11078 # really hope they can't run script, and don't want to annotate Wrap()
11079 # methods as doing that anyway, so let's not annotate them as
11080 # MOZ_CAN_RUN_SCRIPT.
11081 CGAbstractStaticMethod
.__init
__(
11087 canRunScript
=not attr
.getExtendedAttribute("StoreInSlot"),
11090 def definition_body(self
):
11093 auto* self = static_cast<${nativeType}*>(void_self);
11095 nativeType
=self
.descriptor
.nativeType
,
11098 if self
.attr
.isMaplikeOrSetlikeAttr():
11099 assert not self
.attr
.getExtendedAttribute("CrossOriginReadable")
11100 # If the interface is maplike/setlike, there will be one getter
11101 # method for the size property of the backing object. Due to having
11102 # to unpack the backing object from the slot, this requires its own
11104 return prefix
+ getMaplikeOrSetlikeSizeGetterBody(
11105 self
.descriptor
, self
.attr
11107 nativeName
= CGSpecializedGetter
.makeNativeName(self
.descriptor
, self
.attr
)
11108 type = self
.attr
.type
11109 if self
.attr
.getExtendedAttribute("CrossOriginReadable"):
11111 extendedAttributes
= self
.descriptor
.getExtendedAttributes(
11112 self
.attr
, getter
=True
11115 remoteType
.isGeckoInterface()
11116 and not remoteType
.unroll().inner
.isExternal()
11117 and remoteType
.unroll().inner
.getExtendedAttribute("ChromeOnly") is None
11119 # We'll use a JSObject. It might make more sense to use remoteType's
11120 # RemoteProxy, but it's not easy to construct a type for that from here.
11121 remoteType
= BuiltinTypes
[IDLBuiltinType
.Types
.object]
11122 if "needsErrorResult" not in extendedAttributes
:
11123 extendedAttributes
.append("needsErrorResult")
11124 prototypeID
, _
= PrototypeIDAndDepth(self
.descriptor
)
11128 if (IsRemoteObjectProxy(obj, ${prototypeID})) {
11129 ${nativeType}::RemoteProxy* self = static_cast<${nativeType}::RemoteProxy*>(void_self);
11133 prototypeID
=prototypeID
,
11134 nativeType
=self
.descriptor
.nativeType
,
11141 extendedAttributes
=extendedAttributes
,
11147 if self
.attr
.slotIndices
is not None:
11148 # We're going to store this return value in a slot on some object,
11149 # to cache it. The question is, which object? For dictionary and
11150 # sequence return values, we want to use a slot on the Xray expando
11151 # if we're called via Xrays, and a slot on our reflector otherwise.
11152 # On the other hand, when dealing with some interfacce types
11153 # (e.g. window.document) we want to avoid calling the getter more
11154 # than once. In the case of window.document, it's because the
11155 # getter can start returning null, which would get hidden in the
11156 # non-Xray case by the fact that it's [StoreOnSlot], so the cached
11157 # version is always around.
11159 # The upshot is that we use the reflector slot for any getter whose
11160 # type is a gecko interface, whether we're called via Xrays or not.
11161 # Since [Cached] and [StoreInSlot] cannot be used with "NewObject",
11162 # we know that in the interface type case the returned object is
11163 # wrappercached. So creating Xrays to it is reasonable.
11164 if mayUseXrayExpandoSlots(self
.descriptor
, self
.attr
):
11167 // Have to either root across the getter call or reget after.
11169 JS::Rooted<JSObject*> slotStorage(cx, GetCachedSlotStorageObject(cx, obj, &isXray));
11170 if (!slotStorage) {
11173 const size_t slotIndex = isXray ? ${xraySlotIndex} : ${slotIndex};
11175 xraySlotIndex
=memberXrayExpandoReservedSlot(
11176 self
.attr
, self
.descriptor
11178 slotIndex
=memberReservedSlot(self
.attr
, self
.descriptor
),
11183 // Have to either root across the getter call or reget after.
11184 JS::Rooted<JSObject*> slotStorage(cx, js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false));
11185 MOZ_ASSERT(IsDOMObject(slotStorage));
11186 const size_t slotIndex = ${slotIndex};
11188 slotIndex
=memberReservedSlot(self
.attr
, self
.descriptor
),
11193 MOZ_ASSERT(JSCLASS_RESERVED_SLOTS(JS::GetClass(slotStorage)) > slotIndex);
11195 // Scope for cachedVal
11196 JS::Value cachedVal = JS::GetReservedSlot(slotStorage, slotIndex);
11197 if (!cachedVal.isUndefined()) {
11198 args.rval().set(cachedVal);
11199 // The cached value is in the compartment of slotStorage,
11200 // so wrap into the caller compartment as needed.
11201 return ${maybeWrap}(cx, args.rval());
11206 maybeWrap
=getMaybeWrapValueFuncForType(self
.attr
.type),
11210 prefix
+ CGGetterCall(type, nativeName
, self
.descriptor
, self
.attr
).define()
11213 def auto_profiler_label(self
):
11214 interface_name
= self
.descriptor
.interface
.identifier
.name
11215 attr_name
= self
.attr
.identifier
.name
11218 AUTO_PROFILER_LABEL_DYNAMIC_FAST(
11219 "${interface_name}", "${attr_name}", DOM, cx,
11220 uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) |
11221 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
11223 interface_name
=interface_name
,
11224 attr_name
=attr_name
,
11227 def error_reporting_label(self
):
11228 # Getters never need a BindingCallContext.
11232 def makeNativeName(descriptor
, attr
):
11233 name
= attr
.identifier
.name
11234 nativeName
= MakeNativeName(descriptor
.binaryNameFor(name
))
11235 _
, resultOutParam
, _
, _
, _
= getRetvalDeclarationForType(attr
.type, descriptor
)
11236 extendedAttrs
= descriptor
.getExtendedAttributes(attr
, getter
=True)
11237 canFail
= "needsErrorResult" in extendedAttrs
or "canOOM" in extendedAttrs
11238 if resultOutParam
or attr
.type.nullable() or canFail
:
11239 nativeName
= "Get" + nativeName
11243 class CGGetterPromiseWrapper(CGAbstractStaticMethod
):
11245 A class for generating a wrapper around another getter that will
11246 convert exceptions to promises.
11249 def __init__(self
, descriptor
, getterToWrap
):
11250 self
.getter
= getterToWrap
11251 name
= self
.makeName(getterToWrap
.name
)
11252 args
= list(getterToWrap
.args
)
11253 CGAbstractStaticMethod
.__init
__(
11254 self
, descriptor
, name
, "bool", args
, canRunScript
=True
11257 def definition_body(self
):
11260 bool ok = ${getterName}(${args});
11264 return ConvertExceptionToPromise(cx, args.rval());
11266 getterName
=self
.getter
.name
,
11267 args
=", ".join(arg
.name
for arg
in self
.args
),
11271 def makeName(getterName
):
11272 return getterName
+ "_promiseWrapper"
11275 class CGStaticGetter(CGAbstractStaticBindingMethod
):
11277 A class for generating the C++ code for an IDL static attribute getter.
11280 def __init__(self
, descriptor
, attr
):
11282 name
= "get_" + IDLToCIdentifier(attr
.identifier
.name
)
11283 CGAbstractStaticBindingMethod
.__init
__(self
, descriptor
, name
)
11285 def generate_code(self
):
11286 nativeName
= CGSpecializedGetter
.makeNativeName(self
.descriptor
, self
.attr
)
11287 return CGGetterCall(self
.attr
.type, nativeName
, self
.descriptor
, self
.attr
)
11289 def auto_profiler_label(self
):
11290 interface_name
= self
.descriptor
.interface
.identifier
.name
11291 attr_name
= self
.attr
.identifier
.name
11294 AUTO_PROFILER_LABEL_DYNAMIC_FAST(
11295 "${interface_name}", "${attr_name}", DOM, cx,
11296 uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) |
11297 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
11299 interface_name
=interface_name
,
11300 attr_name
=attr_name
,
11303 def error_reporting_label(self
):
11304 # Getters never need a BindingCallContext.
11308 class CGSpecializedSetter(CGAbstractStaticMethod
):
11310 A class for generating the code for a specialized attribute setter
11311 that the JIT can call with lower overhead.
11314 def __init__(self
, descriptor
, attr
):
11316 name
= "set_" + IDLToCIdentifier(attr
.identifier
.name
)
11318 Argument("JSContext*", "cx"),
11319 Argument("JS::Handle<JSObject*>", "obj"),
11320 Argument("void*", "void_self"),
11321 Argument("JSJitSetterCallArgs", "args"),
11323 CGAbstractStaticMethod
.__init
__(
11324 self
, descriptor
, name
, "bool", args
, canRunScript
=True
11327 def definition_body(self
):
11328 nativeName
= CGSpecializedSetter
.makeNativeName(self
.descriptor
, self
.attr
)
11329 type = self
.attr
.type
11330 call
= CGSetterCall(type, nativeName
, self
.descriptor
, self
.attr
).define()
11332 if self
.attr
.getExtendedAttribute("CrossOriginWritable"):
11333 if type.isGeckoInterface() and not type.unroll().inner
.isExternal():
11334 # a setter taking a Gecko interface would require us to deal with remote
11335 # proxies for the value here.
11337 "We don't support the setter of %s marked as "
11338 "CrossOriginWritable because it takes a Gecko interface "
11340 attr
.identifier
.name
,
11342 prototypeID
, _
= PrototypeIDAndDepth(self
.descriptor
)
11345 if (IsRemoteObjectProxy(obj, ${prototypeID})) {
11346 auto* self = static_cast<${nativeType}::RemoteProxy*>(void_self);
11350 prototypeID
=prototypeID
,
11351 nativeType
=self
.descriptor
.nativeType
,
11354 return prefix
+ fill(
11356 auto* self = static_cast<${nativeType}*>(void_self);
11359 nativeType
=self
.descriptor
.nativeType
,
11363 def auto_profiler_label(self
):
11364 interface_name
= self
.descriptor
.interface
.identifier
.name
11365 attr_name
= self
.attr
.identifier
.name
11368 AUTO_PROFILER_LABEL_DYNAMIC_FAST(
11369 "${interface_name}", "${attr_name}", DOM, cx,
11370 uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) |
11371 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
11373 interface_name
=interface_name
,
11374 attr_name
=attr_name
,
11378 def error_reporting_label_helper(descriptor
, attr
):
11379 # Setters need a BindingCallContext if the type of the attribute needs
11381 if not idlTypeNeedsCallContext(
11382 attr
.type, descriptor
, allowTreatNonCallableAsNull
=True
11386 GetLabelForErrorReporting(descriptor
, attr
, isConstructor
=False) + " setter"
11389 def error_reporting_label(self
):
11390 return CGSpecializedSetter
.error_reporting_label_helper(
11391 self
.descriptor
, self
.attr
11395 def makeNativeName(descriptor
, attr
):
11396 name
= attr
.identifier
.name
11397 return "Set" + MakeNativeName(descriptor
.binaryNameFor(name
))
11400 class CGStaticSetter(CGAbstractStaticBindingMethod
):
11402 A class for generating the C++ code for an IDL static attribute setter.
11405 def __init__(self
, descriptor
, attr
):
11407 name
= "set_" + IDLToCIdentifier(attr
.identifier
.name
)
11408 CGAbstractStaticBindingMethod
.__init
__(self
, descriptor
, name
)
11410 def generate_code(self
):
11411 nativeName
= CGSpecializedSetter
.makeNativeName(self
.descriptor
, self
.attr
)
11412 checkForArg
= CGGeneric(
11415 if (!args.requireAtLeast(cx, "${name} setter", 1)) {
11419 name
=self
.attr
.identifier
.name
,
11422 call
= CGSetterCall(self
.attr
.type, nativeName
, self
.descriptor
, self
.attr
)
11423 return CGList([checkForArg
, call
])
11425 def auto_profiler_label(self
):
11426 interface_name
= self
.descriptor
.interface
.identifier
.name
11427 attr_name
= self
.attr
.identifier
.name
11430 AUTO_PROFILER_LABEL_DYNAMIC_FAST(
11431 "${interface_name}", "${attr_name}", DOM, cx,
11432 uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) |
11433 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS));
11435 interface_name
=interface_name
,
11436 attr_name
=attr_name
,
11439 def error_reporting_label(self
):
11440 return CGSpecializedSetter
.error_reporting_label_helper(
11441 self
.descriptor
, self
.attr
11445 class CGSpecializedForwardingSetter(CGSpecializedSetter
):
11447 A class for generating the code for a specialized attribute setter with
11448 PutForwards that the JIT can call with lower overhead.
11451 def __init__(self
, descriptor
, attr
):
11452 CGSpecializedSetter
.__init
__(self
, descriptor
, attr
)
11454 def definition_body(self
):
11455 attrName
= self
.attr
.identifier
.name
11456 forwardToAttrName
= self
.attr
.getExtendedAttribute("PutForwards")[0]
11457 # JS_GetProperty and JS_SetProperty can only deal with ASCII
11458 assert all(ord(c
) < 128 for c
in attrName
)
11459 assert all(ord(c
) < 128 for c
in forwardToAttrName
)
11462 JS::Rooted<JS::Value> v(cx);
11463 if (!JS_GetProperty(cx, obj, "${attr}", &v)) {
11467 if (!v.isObject()) {
11468 return cx.ThrowErrorMessage<MSG_NOT_OBJECT>("${interface}.${attr}");
11471 JS::Rooted<JSObject*> targetObj(cx, &v.toObject());
11472 return JS_SetProperty(cx, targetObj, "${forwardToAttrName}", args[0]);
11475 interface
=self
.descriptor
.interface
.identifier
.name
,
11476 forwardToAttrName
=forwardToAttrName
,
11479 def error_reporting_label(self
):
11480 # We always need to be able to throw.
11482 GetLabelForErrorReporting(self
.descriptor
, self
.attr
, isConstructor
=False)
11487 class CGSpecializedReplaceableSetter(CGSpecializedSetter
):
11489 A class for generating the code for a specialized attribute setter with
11490 Replaceable that the JIT can call with lower overhead.
11493 def __init__(self
, descriptor
, attr
):
11494 CGSpecializedSetter
.__init
__(self
, descriptor
, attr
)
11496 def definition_body(self
):
11497 attrName
= self
.attr
.identifier
.name
11498 # JS_DefineProperty can only deal with ASCII
11499 assert all(ord(c
) < 128 for c
in attrName
)
11501 'return JS_DefineProperty(cx, obj, "%s", args[0], JSPROP_ENUMERATE);\n'
11505 def error_reporting_label(self
):
11506 # We never throw directly.
11510 class CGSpecializedLenientSetter(CGSpecializedSetter
):
11512 A class for generating the code for a specialized attribute setter with
11513 LenientSetter that the JIT can call with lower overhead.
11516 def __init__(self
, descriptor
, attr
):
11517 CGSpecializedSetter
.__init
__(self
, descriptor
, attr
)
11519 def definition_body(self
):
11520 attrName
= self
.attr
.identifier
.name
11521 # JS_DefineProperty can only deal with ASCII
11522 assert all(ord(c
) < 128 for c
in attrName
)
11525 DeprecationWarning(cx, obj, DeprecatedOperations::eLenientSetter);
11530 def error_reporting_label(self
):
11531 # We never throw; that's the whole point.
11535 def memberReturnsNewObject(member
):
11536 return member
.getExtendedAttribute("NewObject") is not None
11539 class CGMemberJITInfo(CGThing
):
11541 A class for generating the JITInfo for a property that points to
11542 our specialized getter and setter.
11545 def __init__(self
, descriptor
, member
):
11546 self
.member
= member
11547 self
.descriptor
= descriptor
11568 aliasSet is a JSJitInfo::AliasSet value, without the "JSJitInfo::" bit.
11570 args is None if we don't want to output argTypes for some
11571 reason (e.g. we have overloads or we're not a method) and
11572 otherwise an iterable of the arguments for this method.
11575 not movable
or aliasSet
!= "AliasEverything"
11576 ) # Can't move write-aliasing things
11578 not alwaysInSlot
or movable
11579 ) # Things always in slots had better be movable
11581 not eliminatable
or aliasSet
!= "AliasEverything"
11582 ) # Can't eliminate write-aliasing things
11584 not alwaysInSlot
or eliminatable
11585 ) # Things always in slots had better be eliminatable
11587 def jitInfoInitializer(isTypedMethod
):
11588 initializer
= fill(
11592 { prototypes::id::${name} },
11593 { PrototypeTraits<prototypes::id::${name}>::Depth },
11594 JSJitInfo::${opType},
11595 JSJitInfo::${aliasSet}, /* aliasSet. Not relevant for setters. */
11596 ${returnType}, /* returnType. Not relevant for setters. */
11597 ${isInfallible}, /* isInfallible. False in setters. */
11598 ${isMovable}, /* isMovable. Not relevant for setters. */
11599 ${isEliminatable}, /* isEliminatable. Not relevant for setters. */
11600 ${isAlwaysInSlot}, /* isAlwaysInSlot. Only relevant for getters. */
11601 ${isLazilyCachedInSlot}, /* isLazilyCachedInSlot. Only relevant for getters. */
11602 ${isTypedMethod}, /* isTypedMethod. Only relevant for methods. */
11603 ${slotIndex} /* Reserved slot index, if we're stored in a slot, else 0. */
11607 name
=self
.descriptor
.name
,
11610 returnType
=functools
.reduce(
11611 CGMemberJITInfo
.getSingleReturnType
, returnTypes
, ""
11613 isInfallible
=toStringBool(infallible
),
11614 isMovable
=toStringBool(movable
),
11615 isEliminatable
=toStringBool(eliminatable
),
11616 isAlwaysInSlot
=toStringBool(alwaysInSlot
),
11617 isLazilyCachedInSlot
=toStringBool(lazilyInSlot
),
11618 isTypedMethod
=toStringBool(isTypedMethod
),
11619 slotIndex
=slotIndex
,
11621 return initializer
.rstrip()
11625 static_assert(${slotIndex} <= JSJitInfo::maxSlotIndex, "We won't fit");
11626 static_assert(${slotIndex} < ${classReservedSlots}, "There is no slot for us");
11628 slotIndex
=slotIndex
,
11629 classReservedSlots
=INSTANCE_RESERVED_SLOTS
11630 + self
.descriptor
.interface
.totalMembersInSlots
,
11632 if args
is not None:
11633 argTypes
= "%s_argTypes" % infoName
11634 args
= [CGMemberJITInfo
.getJSArgType(arg
.type) for arg
in args
]
11635 args
.append("JSJitInfo::ArgTypeListEnd")
11636 argTypesDecl
= "static const JSJitInfo::ArgType %s[] = { %s };\n" % (
11643 static const JSTypedMethodJitInfo ${infoName} = {
11649 argTypesDecl
=argTypesDecl
,
11651 jitInfo
=indent(jitInfoInitializer(True)),
11653 slotAssert
=slotAssert
,
11656 # Unexposed things are meant to be used from C++ directly, so we make
11657 # their jitinfo non-static. That way C++ can get at it.
11658 if self
.member
.getExtendedAttribute("Unexposed"):
11659 storageClass
= "extern"
11661 storageClass
= "static"
11665 ${storageClass} const JSJitInfo ${infoName} = ${jitInfo};
11668 storageClass
=storageClass
,
11670 jitInfo
=jitInfoInitializer(False),
11671 slotAssert
=slotAssert
,
11675 if self
.member
.isAttr():
11676 getterinfo
= "%s_getterinfo" % IDLToCIdentifier(self
.member
.identifier
.name
)
11677 name
= IDLToCIdentifier(self
.member
.identifier
.name
)
11678 if self
.member
.type.isPromise():
11679 name
= CGGetterPromiseWrapper
.makeName(name
)
11680 getter
= "get_%s" % name
11681 extendedAttrs
= self
.descriptor
.getExtendedAttributes(
11682 self
.member
, getter
=True
11684 getterinfal
= "needsErrorResult" not in extendedAttrs
11686 # At this point getterinfal is true if our getter either can't throw
11687 # at all, or can only throw OOM. In both cases, it's safe to move,
11688 # or dead-code-eliminate, the getter, because throwing OOM is not
11689 # semantically meaningful, so code can't rely on it happening. Note
11690 # that this makes the behavior consistent for OOM thrown from the
11691 # getter itself and OOM thrown from the to-JS conversion of the
11692 # return value (see the "canOOM" and "infallibleForMember" checks
11694 movable
= self
.mayBeMovable() and getterinfal
11695 eliminatable
= self
.mayBeEliminatable() and getterinfal
11696 aliasSet
= self
.aliasSet()
11698 # Now we have to set getterinfal to whether we can _really_ ever
11699 # throw, from the point of view of the JS engine.
11702 and "canOOM" not in extendedAttrs
11703 and infallibleForMember(self
.member
, self
.member
.type, self
.descriptor
)
11705 isAlwaysInSlot
= self
.member
.getExtendedAttribute("StoreInSlot")
11706 if self
.member
.slotIndices
is not None:
11707 assert isAlwaysInSlot
or self
.member
.getExtendedAttribute("Cached")
11708 isLazilyCachedInSlot
= not isAlwaysInSlot
11709 slotIndex
= memberReservedSlot(self
.member
, self
.descriptor
)
11710 # We'll statically assert that this is not too big in
11711 # CGUpdateMemberSlotsMethod, in the case when
11712 # isAlwaysInSlot is true.
11714 isLazilyCachedInSlot
= False
11717 result
= self
.defineJitInfo(
11726 isLazilyCachedInSlot
,
11728 [self
.member
.type],
11732 not self
.member
.readonly
11733 or self
.member
.getExtendedAttribute("PutForwards") is not None
11734 or self
.member
.getExtendedAttribute("Replaceable") is not None
11735 or self
.member
.getExtendedAttribute("LegacyLenientSetter") is not None
11737 setterinfo
= "%s_setterinfo" % IDLToCIdentifier(
11738 self
.member
.identifier
.name
11740 # Actually a JSJitSetterOp, but JSJitGetterOp is first in the
11742 setter
= "(JSJitGetterOp)set_%s" % IDLToCIdentifier(
11743 self
.member
.identifier
.name
11745 # Setters are always fallible, since they have to do a typed unwrap.
11746 result
+= self
.defineJitInfo(
11757 [BuiltinTypes
[IDLBuiltinType
.Types
.void
]],
11761 if self
.member
.isMethod():
11762 methodinfo
= "%s_methodinfo" % IDLToCIdentifier(self
.member
.identifier
.name
)
11763 name
= CppKeywords
.checkMethodName(
11764 IDLToCIdentifier(self
.member
.identifier
.name
)
11766 if self
.member
.returnsPromise():
11767 name
= CGMethodPromiseWrapper
.makeName(name
)
11768 # Actually a JSJitMethodOp, but JSJitGetterOp is first in the union.
11769 method
= "(JSJitGetterOp)%s" % name
11771 # Methods are infallible if they are infallible, have no arguments
11772 # to unwrap, and have a return type that's infallible to wrap up for
11774 sigs
= self
.member
.signatures()
11776 # Don't handle overloading. If there's more than one signature,
11777 # one of them must take arguments.
11778 methodInfal
= False
11781 eliminatable
= False
11784 # For methods that affect nothing, it's OK to set movable to our
11785 # notion of infallible on the C++ side, without considering
11786 # argument conversions, since argument conversions that can
11787 # reliably throw would be effectful anyway and the jit doesn't
11788 # move effectful things.
11789 extendedAttrs
= self
.descriptor
.getExtendedAttributes(self
.member
)
11790 hasInfallibleImpl
= "needsErrorResult" not in extendedAttrs
11791 # At this point hasInfallibleImpl is true if our method either
11792 # can't throw at all, or can only throw OOM. In both cases, it
11793 # may be safe to move, or dead-code-eliminate, the method,
11794 # because throwing OOM is not semantically meaningful, so code
11795 # can't rely on it happening. Note that this makes the behavior
11796 # consistent for OOM thrown from the method itself and OOM
11797 # thrown from the to-JS conversion of the return value (see the
11798 # "canOOM" and "infallibleForMember" checks below).
11799 movable
= self
.mayBeMovable() and hasInfallibleImpl
11800 eliminatable
= self
.mayBeEliminatable() and hasInfallibleImpl
11801 # XXXbz can we move the smarts about fallibility due to arg
11802 # conversions into the JIT, using our new args stuff?
11803 if len(sig
[1]) != 0 or not infallibleForMember(
11804 self
.member
, sig
[0], self
.descriptor
11806 # We have arguments or our return-value boxing can fail
11807 methodInfal
= False
11809 methodInfal
= hasInfallibleImpl
and "canOOM" not in extendedAttrs
11810 # For now, only bother to output args if we're side-effect-free.
11811 if self
.member
.affects
== "Nothing":
11816 aliasSet
= self
.aliasSet()
11817 result
= self
.defineJitInfo(
11828 [s
[0] for s
in sigs
],
11832 raise TypeError("Illegal member type to CGPropertyJITInfo")
11834 def mayBeMovable(self
):
11836 Returns whether this attribute or method may be movable, just
11837 based on Affects/DependsOn annotations.
11839 affects
= self
.member
.affects
11840 dependsOn
= self
.member
.dependsOn
11841 assert affects
in IDLInterfaceMember
.AffectsValues
11842 assert dependsOn
in IDLInterfaceMember
.DependsOnValues
11843 # Things that are DependsOn=DeviceState are not movable, because we
11844 # don't want them coalesced with each other or loop-hoisted, since
11845 # their return value can change even if nothing is going on from our
11847 return affects
== "Nothing" and (
11848 dependsOn
!= "Everything" and dependsOn
!= "DeviceState"
11851 def mayBeEliminatable(self
):
11853 Returns whether this attribute or method may be eliminatable, just
11854 based on Affects/DependsOn annotations.
11856 # dependsOn shouldn't affect this decision at all, except in jitinfo we
11857 # have no way to express "Depends on everything, affects nothing",
11858 # because we only have three alias set values: AliasNone ("depends on
11859 # nothing, affects nothing"), AliasDOMSets ("depends on DOM sets,
11860 # affects nothing"), AliasEverything ("depends on everything, affects
11861 # everything"). So the [Affects=Nothing, DependsOn=Everything] case
11862 # gets encoded as AliasEverything and defineJitInfo asserts that if our
11863 # alias state is AliasEverything then we're not eliminatable (because it
11864 # thinks we might have side-effects at that point). Bug 1155796 is
11865 # tracking possible solutions for this.
11866 affects
= self
.member
.affects
11867 dependsOn
= self
.member
.dependsOn
11868 assert affects
in IDLInterfaceMember
.AffectsValues
11869 assert dependsOn
in IDLInterfaceMember
.DependsOnValues
11870 return affects
== "Nothing" and dependsOn
!= "Everything"
11872 def aliasSet(self
):
11874 Returns the alias set to store in the jitinfo. This may not be the
11875 effective alias set the JIT uses, depending on whether we have enough
11876 information about our args to allow the JIT to prove that effectful
11877 argument conversions won't happen.
11879 dependsOn
= self
.member
.dependsOn
11880 assert dependsOn
in IDLInterfaceMember
.DependsOnValues
11882 if dependsOn
== "Nothing" or dependsOn
== "DeviceState":
11883 assert self
.member
.affects
== "Nothing"
11886 if dependsOn
== "DOMState":
11887 assert self
.member
.affects
== "Nothing"
11888 return "AliasDOMSets"
11890 return "AliasEverything"
11893 def getJSReturnTypeTag(t
):
11895 # Sometimes it might return null, sometimes not
11896 return "JSVAL_TYPE_UNKNOWN"
11898 # No return, every time
11899 return "JSVAL_TYPE_UNDEFINED"
11901 return "JSVAL_TYPE_OBJECT"
11903 return "JSVAL_TYPE_OBJECT"
11905 return "JSVAL_TYPE_OBJECT"
11906 if t
.isGeckoInterface():
11907 return "JSVAL_TYPE_OBJECT"
11909 return "JSVAL_TYPE_STRING"
11911 return "JSVAL_TYPE_STRING"
11913 return "JSVAL_TYPE_OBJECT"
11915 # The whole point is to return various stuff
11916 return "JSVAL_TYPE_UNKNOWN"
11918 return "JSVAL_TYPE_OBJECT"
11919 if t
.isSpiderMonkeyInterface():
11920 return "JSVAL_TYPE_OBJECT"
11923 if u
.hasNullableType
:
11924 # Might be null or not
11925 return "JSVAL_TYPE_UNKNOWN"
11926 return functools
.reduce(
11927 CGMemberJITInfo
.getSingleReturnType
, u
.flatMemberTypes
, ""
11929 if t
.isDictionary():
11930 return "JSVAL_TYPE_OBJECT"
11931 if not t
.isPrimitive():
11932 raise TypeError("No idea what type " + str(t
) + " is.")
11934 if tag
== IDLType
.Tags
.bool:
11935 return "JSVAL_TYPE_BOOLEAN"
11938 IDLType
.Tags
.uint8
,
11939 IDLType
.Tags
.int16
,
11940 IDLType
.Tags
.uint16
,
11941 IDLType
.Tags
.int32
,
11943 return "JSVAL_TYPE_INT32"
11945 IDLType
.Tags
.int64
,
11946 IDLType
.Tags
.uint64
,
11947 IDLType
.Tags
.unrestricted_float
,
11948 IDLType
.Tags
.float,
11949 IDLType
.Tags
.unrestricted_double
,
11950 IDLType
.Tags
.double
,
11952 # These all use JS_NumberValue, which can return int or double.
11953 # But TI treats "double" as meaning "int or double", so we're
11954 # good to return JSVAL_TYPE_DOUBLE here.
11955 return "JSVAL_TYPE_DOUBLE"
11956 if tag
!= IDLType
.Tags
.uint32
:
11957 raise TypeError("No idea what type " + str(t
) + " is.")
11958 # uint32 is sometimes int and sometimes double.
11959 return "JSVAL_TYPE_DOUBLE"
11962 def getSingleReturnType(existingType
, t
):
11963 type = CGMemberJITInfo
.getJSReturnTypeTag(t
)
11964 if existingType
== "":
11965 # First element of the list; just return its type
11968 if type == existingType
:
11969 return existingType
11970 if (type == "JSVAL_TYPE_DOUBLE" and existingType
== "JSVAL_TYPE_INT32") or (
11971 existingType
== "JSVAL_TYPE_DOUBLE" and type == "JSVAL_TYPE_INT32"
11973 # Promote INT32 to DOUBLE as needed
11974 return "JSVAL_TYPE_DOUBLE"
11976 return "JSVAL_TYPE_UNKNOWN"
11979 def getJSArgType(t
):
11980 assert not t
.isVoid()
11982 # Sometimes it might return null, sometimes not
11984 "JSJitInfo::ArgType(JSJitInfo::Null | %s)"
11985 % CGMemberJITInfo
.getJSArgType(t
.inner
)
11988 return "JSJitInfo::Object"
11990 return "JSJitInfo::Object"
11991 if t
.isGeckoInterface():
11992 return "JSJitInfo::Object"
11994 return "JSJitInfo::String"
11996 return "JSJitInfo::String"
11998 return "JSJitInfo::Object"
12000 # The whole point is to return various stuff
12001 return "JSJitInfo::Any"
12003 return "JSJitInfo::Object"
12004 if t
.isSpiderMonkeyInterface():
12005 return "JSJitInfo::Object"
12008 type = "JSJitInfo::Null" if u
.hasNullableType
else ""
12009 return "JSJitInfo::ArgType(%s)" % functools
.reduce(
12010 CGMemberJITInfo
.getSingleArgType
, u
.flatMemberTypes
, type
12012 if t
.isDictionary():
12013 return "JSJitInfo::Object"
12014 if not t
.isPrimitive():
12015 raise TypeError("No idea what type " + str(t
) + " is.")
12017 if tag
== IDLType
.Tags
.bool:
12018 return "JSJitInfo::Boolean"
12021 IDLType
.Tags
.uint8
,
12022 IDLType
.Tags
.int16
,
12023 IDLType
.Tags
.uint16
,
12024 IDLType
.Tags
.int32
,
12026 return "JSJitInfo::Integer"
12028 IDLType
.Tags
.int64
,
12029 IDLType
.Tags
.uint64
,
12030 IDLType
.Tags
.unrestricted_float
,
12031 IDLType
.Tags
.float,
12032 IDLType
.Tags
.unrestricted_double
,
12033 IDLType
.Tags
.double
,
12035 # These all use JS_NumberValue, which can return int or double.
12036 # But TI treats "double" as meaning "int or double", so we're
12037 # good to return JSVAL_TYPE_DOUBLE here.
12038 return "JSJitInfo::Double"
12039 if tag
!= IDLType
.Tags
.uint32
:
12040 raise TypeError("No idea what type " + str(t
) + " is.")
12041 # uint32 is sometimes int and sometimes double.
12042 return "JSJitInfo::Double"
12045 def getSingleArgType(existingType
, t
):
12046 type = CGMemberJITInfo
.getJSArgType(t
)
12047 if existingType
== "":
12048 # First element of the list; just return its type
12051 if type == existingType
:
12052 return existingType
12053 return "%s | %s" % (existingType
, type)
12056 class CGStaticMethodJitinfo(CGGeneric
):
12058 A class for generating the JITInfo for a promise-returning static method.
12061 def __init__(self
, method
):
12062 CGGeneric
.__init
__(
12065 "static const JSJitInfo %s_methodinfo = {\n"
12066 " { (JSJitGetterOp)%s },\n"
12067 " { prototypes::id::_ID_Count }, { 0 }, JSJitInfo::StaticMethod,\n"
12068 " JSJitInfo::AliasEverything, JSVAL_TYPE_OBJECT, false, false,\n"
12069 " false, false, 0\n"
12072 IDLToCIdentifier(method
.identifier
.name
),
12073 CppKeywords
.checkMethodName(IDLToCIdentifier(method
.identifier
.name
)),
12078 def getEnumValueName(value
):
12079 # Some enum values can be empty strings. Others might have weird
12080 # characters in them. Deal with the former by returning "_empty",
12081 # deal with possible name collisions from that by throwing if the
12082 # enum value is actually "_empty", and throw on any value
12083 # containing non-ASCII chars for now. Replace all chars other than
12084 # [0-9A-Za-z_] with '_'.
12085 if re
.match("[^\x20-\x7E]", value
):
12086 raise SyntaxError('Enum value "' + value
+ '" contains non-ASCII characters')
12087 if re
.match("^[0-9]", value
):
12088 value
= "_" + value
12089 value
= re
.sub(r
"[^0-9A-Za-z_]", "_", value
)
12090 if re
.match("^_[A-Z]|__", value
):
12091 raise SyntaxError('Enum value "' + value
+ '" is reserved by the C++ spec')
12092 if value
== "_empty":
12093 raise SyntaxError('"_empty" is not an IDL enum value we support yet')
12096 nativeName
= MakeNativeName(value
)
12097 if nativeName
== "EndGuard_":
12099 'Enum value "' + value
+ '" cannot be used because it'
12100 " collides with our internal EndGuard_ value. Please"
12101 " rename our internal EndGuard_ to something else"
12106 class CGEnumToJSValue(CGAbstractMethod
):
12107 def __init__(self
, enum
):
12108 enumType
= enum
.identifier
.name
12109 self
.stringsArray
= enumType
+ "Values::" + ENUM_ENTRY_VARIABLE_NAME
12110 CGAbstractMethod
.__init
__(
12116 Argument("JSContext*", "aCx"),
12117 Argument(enumType
, "aArgument"),
12118 Argument("JS::MutableHandle<JS::Value>", "aValue"),
12122 def definition_body(self
):
12125 MOZ_ASSERT(uint32_t(aArgument) < ArrayLength(${strings}));
12126 JSString* resultStr =
12127 JS_NewStringCopyN(aCx, ${strings}[uint32_t(aArgument)].value,
12128 ${strings}[uint32_t(aArgument)].length);
12132 aValue.setString(resultStr);
12135 strings
=self
.stringsArray
,
12139 class CGEnum(CGThing
):
12140 def __init__(self
, enum
):
12141 CGThing
.__init
__(self
)
12145 extern const EnumEntry ${entry_array}[${entry_count}];
12147 static constexpr size_t Count = ${real_entry_count};
12149 // Our "${entry_array}" contains an extra entry with a null string.
12150 static_assert(mozilla::ArrayLength(${entry_array}) - 1 == Count,
12151 "Mismatch between enum strings and enum count");
12153 static_assert(static_cast<size_t>(${name}::EndGuard_) == Count,
12154 "Mismatch between enum value and enum count");
12156 inline auto GetString(${name} stringId) {
12157 MOZ_ASSERT(static_cast<${type}>(stringId) < Count);
12158 const EnumEntry& entry = ${entry_array}[static_cast<${type}>(stringId)];
12159 return Span<const char>{entry.value, entry.length};
12162 entry_array
=ENUM_ENTRY_VARIABLE_NAME
,
12163 entry_count
=self
.nEnumStrings(),
12164 # -1 because nEnumStrings() includes a string for EndGuard_
12165 real_entry_count
=self
.nEnumStrings() - 1,
12166 name
=self
.enum
.identifier
.name
,
12167 type=self
.underlyingType(),
12169 strings
= CGNamespace(
12170 self
.stringsNamespace(),
12175 extern const EnumEntry ${name}[${count}] = {
12180 name
=ENUM_ENTRY_VARIABLE_NAME
,
12181 count
=self
.nEnumStrings(),
12183 '{"%s", %d},\n' % (val
, len(val
)) for val
in self
.enum
.values()
12188 toJSValue
= CGEnumToJSValue(enum
)
12189 self
.cgThings
= CGList([strings
, toJSValue
], "\n")
12191 def stringsNamespace(self
):
12192 return self
.enum
.identifier
.name
+ "Values"
12194 def nEnumStrings(self
):
12195 return len(self
.enum
.values()) + 1
12197 def underlyingType(self
):
12198 count
= self
.nEnumStrings()
12204 "Enum " + self
.enum
.identifier
.name
+ " has more than 65536 values"
12210 enum class ${name} : ${ty} {
12215 name
=self
.enum
.identifier
.name
,
12216 ty
=self
.underlyingType(),
12217 enums
=",\n".join(map(getEnumValueName
, self
.enum
.values())) + ",\n",
12220 return decl
+ "\n" + self
.cgThings
.declare()
12223 return self
.cgThings
.define()
12226 return self
.enum
.getDeps()
12229 def getUnionAccessorSignatureType(type, descriptorProvider
):
12231 Returns the types that are used in the getter and setter signatures for
12234 # Flat member types have already unwrapped nullables.
12235 assert not type.nullable()
12237 # Promise types can never appear in unions, because Promise is not
12238 # distinguishable from anything.
12239 assert not type.isPromise()
12241 if type.isSequence() or type.isRecord():
12242 if type.isSequence():
12243 wrapperType
= "Sequence"
12245 wrapperType
= "Record"
12246 # We don't use the returned template here, so it's OK to just pass no
12247 # sourceDescription.
12248 elementInfo
= getJSToNativeConversionInfo(
12249 type.inner
, descriptorProvider
, isMember
=wrapperType
12251 if wrapperType
== "Sequence":
12252 innerType
= elementInfo
.declType
12254 innerType
= [recordKeyDeclType(type), elementInfo
.declType
]
12256 return CGTemplatedType(wrapperType
, innerType
, isConst
=True, isReference
=True)
12258 # Nested unions are unwrapped automatically into our flatMemberTypes.
12259 assert not type.isUnion()
12261 if type.isGeckoInterface():
12262 descriptor
= descriptorProvider
.getDescriptor(
12263 type.unroll().inner
.identifier
.name
12265 typeName
= CGGeneric(descriptor
.nativeType
)
12266 if not type.unroll().inner
.isExternal():
12267 typeName
= CGWrapper(typeName
, post
="&")
12268 elif descriptor
.interface
.identifier
.name
== "WindowProxy":
12269 typeName
= CGGeneric("WindowProxyHolder const&")
12271 # Allow null pointers for old-binding classes.
12272 typeName
= CGWrapper(typeName
, post
="*")
12275 if type.isSpiderMonkeyInterface():
12276 typeName
= CGGeneric(type.name
)
12277 return CGWrapper(typeName
, post
=" const &")
12279 if type.isJSString():
12280 raise TypeError("JSString not supported in unions")
12282 if type.isDOMString() or type.isUSVString():
12283 return CGGeneric("const nsAString&")
12285 if type.isUTF8String():
12286 return CGGeneric("const nsACString&")
12288 if type.isByteString():
12289 return CGGeneric("const nsCString&")
12292 return CGGeneric(type.inner
.identifier
.name
)
12294 if type.isCallback():
12295 return CGGeneric("%s&" % type.unroll().callback
.identifier
.name
)
12298 return CGGeneric("JS::Value")
12300 if type.isObject():
12301 return CGGeneric("JSObject*")
12303 if type.isDictionary():
12304 return CGGeneric("const %s&" % type.inner
.identifier
.name
)
12306 if not type.isPrimitive():
12307 raise TypeError("Need native type for argument type '%s'" % str(type))
12309 return CGGeneric(builtinNames
[type.tag()])
12312 def getUnionTypeTemplateVars(unionType
, type, descriptorProvider
, ownsMembers
=False):
12313 name
= getUnionMemberName(type)
12314 holderName
= "m" + name
+ "Holder"
12316 # By the time tryNextCode is invoked, we're guaranteed the union has been
12317 # constructed as some type, since we've been trying to convert into the
12318 # corresponding member.
12319 prefix
= "" if ownsMembers
else "mUnion."
12321 "$*{destroyHolder}\n"
12323 "tryNext = true;\n"
12324 "return true;\n" % (prefix
, name
)
12327 sourceDescription
= "%s branch of %s" % (type.prettyName(), unionType
.prettyName())
12329 conversionInfo
= getJSToNativeConversionInfo(
12331 descriptorProvider
,
12332 failureCode
=tryNextCode
,
12333 isDefinitelyObject
=not type.isDictionary(),
12334 isMember
=("OwningUnion" if ownsMembers
else None),
12335 sourceDescription
=sourceDescription
,
12338 if conversionInfo
.holderType
is not None:
12339 assert not ownsMembers
12340 destroyHolder
= "%s.reset();\n" % holderName
12344 ctorNeedsCx
= conversionInfo
.declArgs
== "cx"
12345 ctorArgs
= "cx" if ctorNeedsCx
else ""
12347 structType
= conversionInfo
.declType
.define()
12348 externalType
= getUnionAccessorSignatureType(type, descriptorProvider
).define()
12350 if type.isObject():
12354 MOZ_ASSERT(mType == eUninitialized);
12355 mValue.mObject.SetValue(obj);
12362 MOZ_ASSERT(mUnion.mType == mUnion.eUninitialized);
12363 mUnion.mValue.mObject.SetValue(cx, obj);
12364 mUnion.mType = mUnion.eObject;
12368 # It's a bit sketchy to do the security check after setting the value,
12369 # but it keeps the code cleaner and lets us avoid rooting |obj| over the
12370 # call to CallerSubsumes().
12371 body
= body
+ fill(
12373 if (passedToJSImpl && !CallerSubsumes(obj)) {
12374 cx.ThrowErrorMessage<MSG_PERMISSION_DENIED_TO_PASS_ARG>("${sourceDescription}");
12379 sourceDescription
=sourceDescription
,
12387 Argument("BindingCallContext&", "cx"),
12388 Argument("JSObject*", "obj"),
12389 Argument("bool", "passedToJSImpl", default
="false"),
12396 elif type.isDictionary() and not type.inner
.needsConversionFromJS
:
12397 # In this case we are never initialized from JS to start with
12400 # Important: we need to not have our declName involve
12401 # maybe-GCing operations.
12402 if conversionInfo
.holderType
is not None:
12403 holderArgs
= conversionInfo
.holderArgs
12404 if holderArgs
is None:
12406 initHolder
= "%s.emplace(%s);\n" % (holderName
, holderArgs
)
12410 jsConversion
= fill(
12411 initHolder
+ conversionInfo
.template
,
12413 maybeMutableVal
="value",
12414 declName
="memberSlot",
12415 holderName
=(holderName
if ownsMembers
else "%s.ref()" % holderName
),
12416 destroyHolder
=destroyHolder
,
12417 passedToJSImpl
="passedToJSImpl",
12420 jsConversion
= fill(
12423 { // scope for memberSlot
12424 ${structType}& memberSlot = RawSetAs${name}(${ctorArgs});
12429 structType
=structType
,
12432 jsConversion
=jsConversion
,
12436 handleType
= "JS::Handle<JS::Value>"
12438 handleType
= "JS::MutableHandle<JS::Value>"
12440 needCallContext
= idlTypeNeedsCallContext(type)
12441 if needCallContext
:
12442 cxType
= "BindingCallContext&"
12444 cxType
= "JSContext*"
12450 Argument(cxType
, "cx"),
12451 Argument(handleType
, "value"),
12452 Argument("bool&", "tryNext"),
12453 Argument("bool", "passedToJSImpl", default
="false"),
12455 inline
=not ownsMembers
,
12456 bodyInHeader
=not ownsMembers
,
12460 if needCallContext
:
12461 # Add a method for non-binding uses of unions to allow them to set
12462 # things in the union without providing a call context (though if
12463 # they want good error reporting they'll provide one anyway).
12466 BindingCallContext cx(cx_, nullptr);
12467 return TrySetTo${name}(cx, value, tryNext, passedToJSImpl);
12476 Argument("JSContext*", "cx_"),
12477 Argument(handleType
, "value"),
12478 Argument("bool&", "tryNext"),
12479 Argument("bool", "passedToJSImpl", default
="false"),
12481 inline
=not ownsMembers
,
12482 bodyInHeader
=not ownsMembers
,
12489 "structType": structType
,
12490 "externalType": externalType
,
12491 "setters": setters
,
12492 "holderType": conversionInfo
.holderType
.define()
12493 if conversionInfo
.holderType
12495 "ctorArgs": ctorArgs
,
12496 "ctorArgList": [Argument("JSContext*", "cx")] if ctorNeedsCx
else [],
12500 class CGUnionStruct(CGThing
):
12501 def __init__(self
, type, descriptorProvider
, ownsMembers
=False):
12502 CGThing
.__init
__(self
)
12503 self
.type = type.unroll()
12504 self
.descriptorProvider
= descriptorProvider
12505 self
.ownsMembers
= ownsMembers
12506 self
.struct
= self
.getStruct()
12509 return self
.struct
.declare()
12512 return self
.struct
.define()
12515 return self
.type.getDeps()
12517 def getStruct(self
):
12520 ClassMember("mType", "Type", body
="eUninitialized"),
12521 ClassMember("mValue", "Value"),
12523 ctor
= ClassConstructor(
12524 [], bodyInHeader
=True, visibility
="public", explicit
=True
12528 enumValues
= ["eUninitialized"]
12529 toJSValCases
= [CGCase("eUninitialized", CGGeneric("return false;\n"))]
12530 destructorCases
= [CGCase("eUninitialized", None)]
12531 assignmentCases
= [
12535 "MOZ_ASSERT(mType == eUninitialized,\n"
12536 ' "We need to destroy ourselves?");\n'
12542 if self
.type.hasNullableType
:
12543 enumValues
.append("eNull")
12551 body
="return mType == eNull;\n",
12561 body
=("Uninit();\n" "mType = eNull;\n"),
12565 destructorCases
.append(CGCase("eNull", None))
12566 assignmentCases
.append(
12570 "MOZ_ASSERT(mType == eUninitialized);\n" "mType = eNull;\n"
12574 toJSValCases
.append(
12575 CGCase("eNull", CGGeneric("rval.setNull();\n" "return true;\n"))
12578 hasObjectType
= any(t
.isObject() for t
in self
.type.flatMemberTypes
)
12579 skipToJSVal
= False
12580 for t
in self
.type.flatMemberTypes
:
12581 vars = getUnionTypeTemplateVars(
12582 self
.type, t
, self
.descriptorProvider
, ownsMembers
=self
.ownsMembers
12584 if vars["name"] != "Object" or self
.ownsMembers
:
12587 if (mType == e${name}) {
12588 return mValue.m${name}.Value();
12592 return mValue.m${name}.SetValue(${ctorArgs});
12597 # bodyInHeader must be false for return values because they own
12598 # their union members and we don't want include headers in
12599 # UnionTypes.h just to call Addref/Release
12602 "RawSetAs" + vars["name"],
12603 vars["structType"] + "&",
12604 vars["ctorArgList"],
12605 bodyInHeader
=not self
.ownsMembers
,
12606 body
=body
% "MOZ_ASSERT(mType == eUninitialized);",
12609 uninit
= "Uninit();"
12610 if hasObjectType
and not self
.ownsMembers
:
12612 'MOZ_ASSERT(mType != eObject, "This will not play well with Rooted");\n'
12617 "SetAs" + vars["name"],
12618 vars["structType"] + "&",
12619 vars["ctorArgList"],
12620 bodyInHeader
=not self
.ownsMembers
,
12621 body
=body
% uninit
,
12624 if self
.ownsMembers
:
12625 if vars["setters"]:
12626 methods
.extend(vars["setters"])
12627 # Provide a SetStringLiteral() method to support string defaults.
12628 if t
.isByteString() or t
.isUTF8String():
12629 charType
= "const nsCString::char_type"
12631 charType
= "const nsString::char_type"
12638 "SetStringLiteral",
12640 # Hack, but it works...
12641 [Argument(charType
, "(&aData)[N]")],
12644 templateArgs
=["int N"],
12645 body
="RawSetAs%s().AssignLiteral(aData);\n" % t
.name
,
12651 MOZ_ASSERT(Is${name}(), "Wrong type!");
12652 mValue.m${name}.Destroy();
12653 mType = eUninitialized;
12659 "Destroy" + vars["name"],
12662 visibility
="private",
12663 bodyInHeader
=not self
.ownsMembers
,
12668 body
= fill("return mType == e${name};\n", **vars)
12671 "Is" + vars["name"],
12682 MOZ_ASSERT(Is${name}(), "Wrong type!");
12683 return mValue.m${name}.Value();
12687 # The non-const version of GetAs* returns our internal type
12688 getterReturnType
= "%s&" % vars["structType"]
12691 "GetAs" + vars["name"],
12698 # The const version of GetAs* returns our internal type
12699 # for owning unions, but our external type for non-owning
12701 if self
.ownsMembers
:
12702 getterReturnType
= "%s const &" % vars["structType"]
12704 getterReturnType
= vars["externalType"]
12707 "GetAs" + vars["name"],
12716 unionValues
.append(fill("UnionMember<${structType} > m${name}", **vars))
12717 enumValues
.append("e" + vars["name"])
12719 conversionToJS
= self
.getConversionToJS(vars, t
)
12721 toJSValCases
.append(CGCase("e" + vars["name"], conversionToJS
))
12725 destructorCases
.append(
12726 CGCase("e" + vars["name"], CGGeneric("Destroy%s();\n" % vars["name"]))
12728 assignmentCases
.append(
12730 "e" + vars["name"],
12732 "SetAs%s() = aOther.GetAs%s();\n" % (vars["name"], vars["name"])
12736 if self
.ownsMembers
and typeNeedsRooting(t
):
12740 "e" + vars["name"],
12742 'JS::UnsafeTraceRoot(trc, %s, "%s");\n'
12744 "&mValue.m" + vars["name"] + ".Value()",
12745 "mValue.m" + vars["name"],
12750 elif t
.isDictionary():
12753 "e" + vars["name"],
12755 "mValue.m%s.Value().TraceDictionary(trc);\n"
12760 elif t
.isSequence():
12763 "e" + vars["name"],
12765 "DoTraceSequence(trc, mValue.m%s.Value());\n"
12773 "e" + vars["name"],
12775 "TraceRecord(trc, mValue.m%s.Value());\n" % vars["name"]
12780 assert t
.isSpiderMonkeyInterface()
12783 "e" + vars["name"],
12785 "mValue.m%s.Value().TraceSelf(trc);\n" % vars["name"]
12790 dtor
= CGSwitch("mType", destructorCases
).define()
12797 visibility
="public",
12799 bodyInHeader
=not self
.ownsMembers
,
12800 inline
=not self
.ownsMembers
,
12804 if not skipToJSVal
:
12810 Argument("JSContext*", "cx"),
12811 Argument("JS::Handle<JSObject*>", "scopeObj"),
12812 Argument("JS::MutableHandle<JS::Value>", "rval"),
12815 "mType", toJSValCases
, default
=CGGeneric("return false;\n")
12817 + "\nreturn false;\n",
12822 constructors
= [ctor
]
12823 selfName
= CGUnionStruct
.unionTypeName(self
.type, self
.ownsMembers
)
12824 if self
.ownsMembers
:
12826 traceBody
= CGSwitch(
12827 "mType", traceCases
, default
=CGGeneric("")
12833 "TraceUnion", "void", [Argument("JSTracer*", "trc")], body
=traceBody
12836 if CGUnionStruct
.isUnionCopyConstructible(self
.type):
12837 constructors
.append(
12839 [Argument("const %s&" % selfName
, "aOther")],
12841 visibility
="public",
12843 body
="*this = aOther;\n",
12846 op_body
= CGList([])
12847 op_body
.append(CGSwitch("aOther.mType", assignmentCases
))
12848 op_body
.append(CGGeneric("return *this;\n"))
12853 [Argument("const %s&" % selfName
, "aOther")],
12854 body
=op_body
.define(),
12857 disallowCopyConstruction
= False
12859 disallowCopyConstruction
= True
12861 disallowCopyConstruction
= True
12863 if self
.ownsMembers
:
12865 " friend void ImplCycleCollectionUnlink(%s& aUnion);\n"
12866 % CGUnionStruct
.unionTypeName(self
.type, True)
12869 friend
= " friend class %sArgument;\n" % str(self
.type)
12871 bases
= [ClassBase("AllOwningUnionBase")] if self
.ownsMembers
else []
12876 constructors
=constructors
,
12878 disallowCopyConstruction
=disallowCopyConstruction
,
12879 extradeclarations
=friend
,
12880 destructor
=ClassDestructor(
12881 visibility
="public", body
="Uninit();\n", bodyInHeader
=True
12883 enums
=[ClassEnum("Type", enumValues
, visibility
="private")],
12884 unions
=[ClassUnion("Value", unionValues
, visibility
="private")],
12887 def getConversionToJS(self
, templateVars
, type):
12888 if type.isDictionary() and not type.inner
.needsConversionToJS
:
12889 # We won't be able to convert this dictionary to a JS value, nor
12890 # will we need to, since we don't need a ToJSVal method at all.
12893 assert not type.nullable() # flatMemberTypes never has nullable types
12894 val
= "mValue.m%(name)s.Value()" % templateVars
12895 wrapCode
= wrapForType(
12897 self
.descriptorProvider
,
12899 "jsvalRef": "rval",
12900 "jsvalHandle": "rval",
12903 "spiderMonkeyInterfacesAreStructs": True,
12906 return CGGeneric(wrapCode
)
12909 def isUnionCopyConstructible(type):
12910 return all(isTypeCopyConstructible(t
) for t
in type.flatMemberTypes
)
12913 def unionTypeName(type, ownsMembers
):
12915 Returns a string name for this known union type.
12917 assert type.isUnion() and not type.nullable()
12918 return ("Owning" if ownsMembers
else "") + type.name
12921 def unionTypeDecl(type, ownsMembers
):
12923 Returns a string for declaring this possibly-nullable union type.
12925 assert type.isUnion()
12926 nullable
= type.nullable()
12929 decl
= CGGeneric(CGUnionStruct
.unionTypeName(type, ownsMembers
))
12931 decl
= CGTemplatedType("Nullable", decl
)
12932 return decl
.define()
12935 class CGUnionConversionStruct(CGThing
):
12936 def __init__(self
, type, descriptorProvider
):
12937 CGThing
.__init
__(self
)
12938 self
.type = type.unroll()
12939 self
.descriptorProvider
= descriptorProvider
12943 structName
= str(self
.type)
12946 "mUnion", structName
+ "&", body
="const_cast<%s&>(aUnion)" % structName
12949 # Argument needs to be a const ref because that's all Maybe<> allows
12950 ctor
= ClassConstructor(
12951 [Argument("const %s&" % structName
, "aUnion")],
12953 visibility
="public",
12958 if self
.type.hasNullableType
:
12965 "MOZ_ASSERT(mUnion.mType == mUnion.eUninitialized);\n"
12966 "mUnion.mType = mUnion.eNull;\n"
12974 for t
in self
.type.flatMemberTypes
:
12975 vars = getUnionTypeTemplateVars(self
.type, t
, self
.descriptorProvider
)
12976 if vars["setters"]:
12977 methods
.extend(vars["setters"])
12978 if vars["name"] != "Object":
12981 MOZ_ASSERT(mUnion.mType == mUnion.eUninitialized);
12982 mUnion.mType = mUnion.e${name};
12983 return mUnion.mValue.m${name}.SetValue(${ctorArgs});
12989 "RawSetAs" + vars["name"],
12990 vars["structType"] + "&",
12991 vars["ctorArgList"],
12994 visibility
="private",
12997 # Provide a SetStringLiteral() method to support string defaults.
12998 if t
.isByteString() or t
.isUTF8String():
12999 charType
= "const nsCString::char_type"
13001 charType
= "const nsString::char_type"
13008 "SetStringLiteral",
13010 # Hack, but it works...
13011 [Argument(charType
, "(&aData)[N]")],
13014 templateArgs
=["int N"],
13015 body
="RawSetAs%s().AssignLiteral(aData);\n" % t
.name
,
13019 if vars["holderType"] is not None:
13020 holderType
= CGTemplatedType(
13021 "Maybe", CGGeneric(vars["holderType"])
13023 members
.append(ClassMember("m%sHolder" % vars["name"], holderType
))
13026 structName
+ "Argument",
13028 constructors
=[ctor
],
13030 disallowCopyConstruction
=True,
13041 """ Use with CGClass """
13043 def __init__(self
, name
, visibility
):
13045 self
.visibility
= visibility
13047 def declare(self
, cgClass
):
13050 def define(self
, cgClass
):
13054 class ClassBase(ClassItem
):
13055 def __init__(self
, name
, visibility
="public"):
13056 ClassItem
.__init
__(self
, name
, visibility
)
13058 def declare(self
, cgClass
):
13059 return "%s %s" % (self
.visibility
, self
.name
)
13061 def define(self
, cgClass
):
13062 # Only in the header
13066 class ClassMethod(ClassItem
):
13076 bodyInHeader
=False,
13078 visibility
="public",
13080 breakAfterReturnDecl
="\n",
13081 breakAfterSelf
="\n",
13083 canRunScript
=False,
13086 override indicates whether to flag the method as override
13088 assert not override
or virtual
13089 assert not (override
and static
)
13090 self
.returnType
= returnType
13092 self
.inline
= inline
or bodyInHeader
13093 self
.static
= static
13094 self
.virtual
= virtual
13096 self
.bodyInHeader
= bodyInHeader
13097 self
.templateArgs
= templateArgs
13099 self
.breakAfterReturnDecl
= breakAfterReturnDecl
13100 self
.breakAfterSelf
= breakAfterSelf
13101 self
.override
= override
13102 self
.canRunScript
= canRunScript
13103 ClassItem
.__init
__(self
, name
, visibility
)
13105 def getDecorators(self
, declaring
):
13107 if self
.canRunScript
:
13108 decorators
.append("MOZ_CAN_RUN_SCRIPT")
13110 decorators
.append("inline")
13113 decorators
.append("static")
13114 if self
.virtual
and not self
.override
:
13115 decorators
.append("virtual")
13117 return " ".join(decorators
) + " "
13121 # Override me or pass a string to constructor
13122 assert self
.body
is not None
13125 def declare(self
, cgClass
):
13127 "template <%s>\n" % ", ".join(self
.templateArgs
)
13128 if self
.bodyInHeader
and self
.templateArgs
13131 args
= ", ".join([a
.declare() for a
in self
.args
])
13132 if self
.bodyInHeader
:
13133 body
= indent(self
.getBody())
13134 body
= "\n{\n" + body
+ "}\n"
13139 "${templateClause}${decorators}${returnType}${breakAfterReturnDecl}"
13140 "${name}(${args})${const}${override}${body}"
13141 "${breakAfterSelf}",
13142 templateClause
=templateClause
,
13143 decorators
=self
.getDecorators(True),
13144 returnType
=self
.returnType
,
13145 breakAfterReturnDecl
=self
.breakAfterReturnDecl
,
13148 const
=" const" if self
.const
else "",
13149 override
=" override" if self
.override
else "",
13151 breakAfterSelf
=self
.breakAfterSelf
,
13154 def define(self
, cgClass
):
13155 if self
.bodyInHeader
:
13158 templateArgs
= cgClass
.templateArgs
13160 if cgClass
.templateSpecialization
:
13161 templateArgs
= templateArgs
[len(cgClass
.templateSpecialization
) :]
13164 templateClause
= "template <%s>\n" % ", ".join(
13165 [str(a
) for a
in templateArgs
]
13168 templateClause
= ""
13172 ${templateClause}${decorators}${returnType}
13173 ${className}::${name}(${args})${const}
13178 templateClause
=templateClause
,
13179 decorators
=self
.getDecorators(False),
13180 returnType
=self
.returnType
,
13181 className
=cgClass
.getNameString(),
13183 args
=", ".join([a
.define() for a
in self
.args
]),
13184 const
=" const" if self
.const
else "",
13185 body
=self
.getBody(),
13189 class ClassUsingDeclaration(ClassItem
):
13191 Used for importing a name from a base class into a CGClass
13193 baseClass is the name of the base class to import the name from
13195 name is the name to import
13197 visibility determines the visibility of the name (public,
13198 protected, private), defaults to public.
13201 def __init__(self
, baseClass
, name
, visibility
="public"):
13202 self
.baseClass
= baseClass
13203 ClassItem
.__init
__(self
, name
, visibility
)
13205 def declare(self
, cgClass
):
13206 return "using %s::%s;\n\n" % (self
.baseClass
, self
.name
)
13208 def define(self
, cgClass
):
13212 class ClassConstructor(ClassItem
):
13214 Used for adding a constructor to a CGClass.
13216 args is a list of Argument objects that are the arguments taken by the
13219 inline should be True if the constructor should be marked inline.
13221 bodyInHeader should be True if the body should be placed in the class
13222 declaration in the header.
13224 visibility determines the visibility of the constructor (public,
13225 protected, private), defaults to private.
13227 explicit should be True if the constructor should be marked explicit.
13229 baseConstructors is a list of strings containing calls to base constructors,
13232 body contains a string with the code for the constructor, defaults to empty.
13239 bodyInHeader
=False,
13240 visibility
="private",
13243 baseConstructors
=None,
13246 assert not (inline
and constexpr
)
13247 assert not (bodyInHeader
and constexpr
)
13249 self
.inline
= inline
or bodyInHeader
13250 self
.bodyInHeader
= bodyInHeader
or constexpr
13251 self
.explicit
= explicit
13252 self
.constexpr
= constexpr
13253 self
.baseConstructors
= baseConstructors
or []
13255 ClassItem
.__init
__(self
, None, visibility
)
13257 def getDecorators(self
, declaring
):
13260 decorators
.append("explicit")
13261 if self
.inline
and declaring
:
13262 decorators
.append("inline")
13263 if self
.constexpr
and declaring
:
13264 decorators
.append("constexpr")
13266 return " ".join(decorators
) + " "
13269 def getInitializationList(self
, cgClass
):
13270 items
= [str(c
) for c
in self
.baseConstructors
]
13271 for m
in cgClass
.members
:
13273 initialize
= m
.body
13275 items
.append(m
.name
+ "(" + initialize
+ ")")
13278 return "\n : " + ",\n ".join(items
)
13284 def declare(self
, cgClass
):
13285 args
= ", ".join([a
.declare() for a
in self
.args
])
13286 if self
.bodyInHeader
:
13288 self
.getInitializationList(cgClass
)
13290 + indent(self
.getBody())
13297 "${decorators}${className}(${args})${body}\n",
13298 decorators
=self
.getDecorators(True),
13299 className
=cgClass
.getNameString(),
13304 def define(self
, cgClass
):
13305 if self
.bodyInHeader
:
13311 ${className}::${className}(${args})${initializationList}
13316 decorators
=self
.getDecorators(False),
13317 className
=cgClass
.getNameString(),
13318 args
=", ".join([a
.define() for a
in self
.args
]),
13319 initializationList
=self
.getInitializationList(cgClass
),
13320 body
=self
.getBody(),
13324 class ClassDestructor(ClassItem
):
13326 Used for adding a destructor to a CGClass.
13328 inline should be True if the destructor should be marked inline.
13330 bodyInHeader should be True if the body should be placed in the class
13331 declaration in the header.
13333 visibility determines the visibility of the destructor (public,
13334 protected, private), defaults to private.
13336 body contains a string with the code for the destructor, defaults to empty.
13338 virtual determines whether the destructor is virtual, defaults to False.
13344 bodyInHeader
=False,
13345 visibility
="private",
13349 self
.inline
= inline
or bodyInHeader
13350 self
.bodyInHeader
= bodyInHeader
13352 self
.virtual
= virtual
13353 ClassItem
.__init
__(self
, None, visibility
)
13355 def getDecorators(self
, declaring
):
13357 if self
.virtual
and declaring
:
13358 decorators
.append("virtual")
13359 if self
.inline
and declaring
:
13360 decorators
.append("inline")
13362 return " ".join(decorators
) + " "
13368 def declare(self
, cgClass
):
13369 if self
.bodyInHeader
:
13370 body
= "\n{\n" + indent(self
.getBody()) + "}\n"
13375 "${decorators}~${className}()${body}\n",
13376 decorators
=self
.getDecorators(True),
13377 className
=cgClass
.getNameString(),
13381 def define(self
, cgClass
):
13382 if self
.bodyInHeader
:
13387 ${className}::~${className}()
13392 decorators
=self
.getDecorators(False),
13393 className
=cgClass
.getNameString(),
13394 body
=self
.getBody(),
13398 class ClassMember(ClassItem
):
13403 visibility
="private",
13406 hasIgnoreInitCheckFlag
=False,
13409 self
.static
= static
13411 self
.hasIgnoreInitCheckFlag
= hasIgnoreInitCheckFlag
13412 ClassItem
.__init
__(self
, name
, visibility
)
13414 def declare(self
, cgClass
):
13415 return "%s%s%s %s;\n" % (
13416 "static " if self
.static
else "",
13417 "MOZ_INIT_OUTSIDE_CTOR " if self
.hasIgnoreInitCheckFlag
else "",
13422 def define(self
, cgClass
):
13423 if not self
.static
:
13426 body
= " = " + self
.body
13429 return "%s %s::%s%s;\n" % (self
.type, cgClass
.getNameString(), self
.name
, body
)
13432 class ClassEnum(ClassItem
):
13433 def __init__(self
, name
, entries
, values
=None, visibility
="public"):
13434 self
.entries
= entries
13435 self
.values
= values
13436 ClassItem
.__init
__(self
, name
, visibility
)
13438 def declare(self
, cgClass
):
13440 for i
in range(0, len(self
.entries
)):
13441 if not self
.values
or i
>= len(self
.values
):
13442 entry
= "%s" % self
.entries
[i
]
13444 entry
= "%s = %s" % (self
.entries
[i
], self
.values
[i
])
13445 entries
.append(entry
)
13446 name
= "" if not self
.name
else " " + self
.name
13447 return "enum%s\n{\n%s\n};\n" % (name
, indent(",\n".join(entries
)))
13449 def define(self
, cgClass
):
13450 # Only goes in the header
13454 class ClassUnion(ClassItem
):
13455 def __init__(self
, name
, entries
, visibility
="public"):
13456 self
.entries
= [entry
+ ";\n" for entry
in entries
]
13457 ClassItem
.__init
__(self
, name
, visibility
)
13459 def declare(self
, cgClass
):
13460 return "union %s\n{\n%s\n};\n" % (self
.name
, indent("".join(self
.entries
)))
13462 def define(self
, cgClass
):
13463 # Only goes in the header
13467 class CGClass(CGThing
):
13479 templateSpecialization
=[],
13481 disallowCopyConstruction
=False,
13484 extradeclarations
="",
13485 extradefinitions
="",
13487 CGThing
.__init
__(self
)
13490 self
.members
= members
13491 self
.constructors
= constructors
13492 # We store our single destructor in a list, since all of our
13493 # code wants lists of members.
13494 self
.destructors
= [destructor
] if destructor
else []
13495 self
.methods
= methods
13497 self
.unions
= unions
13498 self
.templateArgs
= templateArgs
13499 self
.templateSpecialization
= templateSpecialization
13500 self
.isStruct
= isStruct
13501 self
.disallowCopyConstruction
= disallowCopyConstruction
13502 self
.indent
= indent
13503 self
.defaultVisibility
= "public" if isStruct
else "private"
13504 self
.decorators
= decorators
13505 self
.extradeclarations
= extradeclarations
13506 self
.extradefinitions
= extradefinitions
13508 def getNameString(self
):
13509 className
= self
.name
13510 if self
.templateSpecialization
:
13511 className
+= "<%s>" % ", ".join(
13512 [str(a
) for a
in self
.templateSpecialization
]
13518 if self
.templateArgs
:
13519 templateArgs
= [a
.declare() for a
in self
.templateArgs
]
13520 templateArgs
= templateArgs
[len(self
.templateSpecialization
) :]
13521 result
+= "template <%s>\n" % ",".join([str(a
) for a
in templateArgs
])
13523 type = "struct" if self
.isStruct
else "class"
13525 if self
.templateSpecialization
:
13526 specialization
= "<%s>" % ", ".join(
13527 [str(a
) for a
in self
.templateSpecialization
]
13530 specialization
= ""
13532 myself
= "%s %s%s" % (type, self
.name
, specialization
)
13533 if self
.decorators
!= "":
13534 myself
+= " " + self
.decorators
13540 # Grab our first base
13541 baseItems
= [CGGeneric(b
.declare(self
)) for b
in self
.bases
]
13542 bases
= baseItems
[:1]
13545 CGIndenter(b
, len(myself
) + len(inherit
)) for b
in baseItems
[1:]
13547 result
+= ",\n".join(b
.define() for b
in bases
)
13551 result
+= self
.extradeclarations
13553 def declareMembers(cgClass
, memberList
, defaultVisibility
):
13554 members
= {"private": [], "protected": [], "public": []}
13556 for member
in memberList
:
13557 members
[member
.visibility
].append(member
)
13559 if defaultVisibility
== "public":
13560 order
= ["public", "protected", "private"]
13562 order
= ["private", "protected", "public"]
13566 lastVisibility
= defaultVisibility
13567 for visibility
in order
:
13568 list = members
[visibility
]
13570 if visibility
!= lastVisibility
:
13571 result
+= visibility
+ ":\n"
13572 for member
in list:
13573 result
+= indent(member
.declare(cgClass
))
13574 lastVisibility
= visibility
13575 return (result
, lastVisibility
)
13577 if self
.disallowCopyConstruction
:
13579 class DisallowedCopyConstructor(object):
13580 def __init__(self
):
13581 self
.visibility
= "private"
13583 def declare(self
, cgClass
):
13584 name
= cgClass
.getNameString()
13586 "%s(const %s&) = delete;\n"
13587 "%s& operator=(const %s&) = delete;\n"
13588 % (name
, name
, name
, name
)
13591 disallowedCopyConstructors
= [DisallowedCopyConstructor()]
13593 disallowedCopyConstructors
= []
13599 self
.constructors
+ disallowedCopyConstructors
,
13604 lastVisibility
= self
.defaultVisibility
13606 for memberList
in order
:
13607 code
, lastVisibility
= declareMembers(self
, memberList
, lastVisibility
)
13610 code
= code
.rstrip() + "\n" # remove extra blank lines at the end
13611 pieces
.append(code
)
13613 result
+= "\n".join(pieces
)
13615 result
= indent(result
, len(self
.indent
))
13619 def defineMembers(cgClass
, memberList
, itemCount
, separator
=""):
13621 for member
in memberList
:
13623 result
= result
+ separator
13624 definition
= member
.define(cgClass
)
13626 # Member variables would only produce empty lines here.
13627 result
+= definition
13629 return (result
, itemCount
)
13632 (self
.members
, ""),
13633 (self
.constructors
, "\n"),
13634 (self
.destructors
, "\n"),
13635 (self
.methods
, "\n"),
13638 result
= self
.extradefinitions
13640 for memberList
, separator
in order
:
13641 memberString
, itemCount
= defineMembers(
13642 self
, memberList
, itemCount
, separator
13644 result
= result
+ memberString
13648 class CGResolveOwnProperty(CGAbstractStaticMethod
):
13649 def __init__(self
, descriptor
):
13651 Argument("JSContext*", "cx"),
13652 Argument("JS::Handle<JSObject*>", "wrapper"),
13653 Argument("JS::Handle<JSObject*>", "obj"),
13654 Argument("JS::Handle<jsid>", "id"),
13655 Argument("JS::MutableHandle<JS::PropertyDescriptor>", "desc"),
13657 CGAbstractStaticMethod
.__init
__(
13658 self
, descriptor
, "ResolveOwnProperty", "bool", args
13661 def definition_body(self
):
13664 JS::Rooted<mozilla::Maybe<JS::PropertyDescriptor>> ownDesc(cx);
13665 if (!js::GetProxyHandler(obj)->getOwnPropertyDescriptor(cx, wrapper, id, &ownDesc)) {
13669 if (ownDesc.isNothing()) {
13670 desc.object().set(nullptr);
13672 desc.set(*ownDesc);
13680 class CGResolveOwnPropertyViaResolve(CGAbstractBindingMethod
):
13682 An implementation of Xray ResolveOwnProperty stuff for things that have a
13686 def __init__(self
, descriptor
):
13688 Argument("JSContext*", "cx"),
13689 Argument("JS::Handle<JSObject*>", "wrapper"),
13690 Argument("JS::Handle<JSObject*>", "obj"),
13691 Argument("JS::Handle<jsid>", "id"),
13692 Argument("JS::MutableHandle<JS::PropertyDescriptor>", "desc"),
13694 CGAbstractBindingMethod
.__init
__(
13697 "ResolveOwnPropertyViaResolve",
13703 def generate_code(self
):
13708 // Since we're dealing with an Xray, do the resolve on the
13709 // underlying object first. That gives it a chance to
13710 // define properties on the actual object as needed, and
13711 // then use the fact that it created the objects as a flag
13712 // to avoid re-resolving the properties if someone deletes
13714 JSAutoRealm ar(cx, obj);
13715 JS_MarkCrossZoneId(cx, id);
13716 JS::Rooted<JS::PropertyDescriptor> objDesc(cx);
13717 if (!self->DoResolve(cx, obj, id, &objDesc)) {
13720 // If desc.value() is undefined, then the DoResolve call
13721 // has already defined the property on the object. Don't
13722 // try to also define it.
13723 if (objDesc.object() &&
13724 !objDesc.value().isUndefined() &&
13725 !JS_DefinePropertyById(cx, obj, id, objDesc)) {
13729 return self->DoResolve(cx, wrapper, id, desc);
13735 class CGEnumerateOwnProperties(CGAbstractStaticMethod
):
13736 def __init__(self
, descriptor
):
13738 Argument("JSContext*", "cx"),
13739 Argument("JS::Handle<JSObject*>", "wrapper"),
13740 Argument("JS::Handle<JSObject*>", "obj"),
13741 Argument("JS::MutableHandleVector<jsid>", "props"),
13743 CGAbstractStaticMethod
.__init
__(
13744 self
, descriptor
, "EnumerateOwnProperties", "bool", args
13747 def definition_body(self
):
13748 return "return js::GetProxyHandler(obj)->ownPropertyKeys(cx, wrapper, props);\n"
13751 class CGEnumerateOwnPropertiesViaGetOwnPropertyNames(CGAbstractBindingMethod
):
13753 An implementation of Xray EnumerateOwnProperties stuff for things
13754 that have a resolve hook.
13757 def __init__(self
, descriptor
):
13759 Argument("JSContext*", "cx"),
13760 Argument("JS::Handle<JSObject*>", "wrapper"),
13761 Argument("JS::Handle<JSObject*>", "obj"),
13762 Argument("JS::MutableHandleVector<jsid>", "props"),
13764 CGAbstractBindingMethod
.__init
__(
13767 "EnumerateOwnPropertiesViaGetOwnPropertyNames",
13773 def generate_code(self
):
13777 FastErrorResult rv;
13778 // This wants all own props, not just enumerable ones.
13779 self->GetOwnPropertyNames(cx, props, false, rv);
13780 if (rv.MaybeSetPendingException(cx)) {
13789 class CGPrototypeTraitsClass(CGClass
):
13790 def __init__(self
, descriptor
, indent
=""):
13791 templateArgs
= [Argument("prototypes::ID", "PrototypeID")]
13792 templateSpecialization
= ["prototypes::id::" + descriptor
.name
]
13793 enums
= [ClassEnum("", ["Depth"], [descriptor
.interface
.inheritanceDepth()])]
13798 templateArgs
=templateArgs
,
13799 templateSpecialization
=templateSpecialization
,
13808 class CGClassForwardDeclare(CGThing
):
13809 def __init__(self
, name
, isStruct
=False):
13810 CGThing
.__init
__(self
)
13812 self
.isStruct
= isStruct
13815 type = "struct" if self
.isStruct
else "class"
13816 return "%s %s;\n" % (type, self
.name
)
13826 class CGProxySpecialOperation(CGPerSignatureCall
):
13828 Base class for classes for calling an indexed or named special operation
13829 (don't use this directly, use the derived classes below).
13831 If checkFound is False, will just assert that the prop is found instead of
13832 checking that it is before wrapping the value.
13834 resultVar: See the docstring for CGCallGenerator.
13836 foundVar: For getters and deleters, the generated code can also set a bool
13837 variable, declared by the caller, if the given indexed or named property
13838 already existed. If the caller wants this, it should pass the name of the
13839 bool variable as the foundVar keyword argument to the constructor. The
13840 caller is responsible for declaring the variable and initializing it to
13849 argumentHandleValue
=None,
13853 self
.checkFound
= checkFound
13854 self
.foundVar
= foundVar
or "found"
13856 nativeName
= MakeNativeName(descriptor
.binaryNameFor(operation
))
13857 operation
= descriptor
.operations
[operation
]
13858 assert len(operation
.signatures()) == 1
13859 signature
= operation
.signatures()[0]
13861 returnType
, arguments
= signature
13863 # We pass len(arguments) as the final argument so that the
13864 # CGPerSignatureCall won't do any argument conversion of its own.
13865 CGPerSignatureCall
.__init
__(
13874 resultVar
=resultVar
,
13875 objectName
="proxy",
13878 if operation
.isSetter():
13879 # arguments[0] is the index or name of the item that we're setting.
13880 argument
= arguments
[1]
13881 info
= getJSToNativeConversionInfo(
13884 sourceDescription
=(
13885 "value being assigned to %s setter"
13886 % descriptor
.interface
.identifier
.name
13889 if argumentHandleValue
is None:
13890 argumentHandleValue
= "desc.value()"
13891 rootedValue
= fill(
13893 JS::Rooted<JS::Value> rootedValue(cx, ${argumentHandleValue});
13895 argumentHandleValue
=argumentHandleValue
,
13898 "declName": argument
.identifier
.name
,
13899 "holderName": argument
.identifier
.name
+ "_holder",
13900 "val": argumentHandleValue
,
13901 "maybeMutableVal": "&rootedValue",
13903 "passedToJSImpl": "false",
13905 self
.cgRoot
.prepend(instantiateJSToNativeConversion(info
, templateValues
))
13906 # rootedValue needs to come before the conversion, so we
13907 # need to prepend it last.
13908 self
.cgRoot
.prepend(CGGeneric(rootedValue
))
13909 elif operation
.isGetter() or operation
.isDeleter():
13910 if foundVar
is None:
13911 self
.cgRoot
.prepend(CGGeneric("bool found = false;\n"))
13913 def getArguments(self
):
13914 args
= [(a
, a
.identifier
.name
) for a
in self
.arguments
]
13915 if self
.idlNode
.isGetter() or self
.idlNode
.isDeleter():
13919 BuiltinTypes
[IDLBuiltinType
.Types
.boolean
], self
.idlNode
13926 def wrap_return_value(self
):
13927 if not self
.idlNode
.isGetter() or self
.templateValues
is None:
13931 wrapForType(self
.returnType
, self
.descriptor
, self
.templateValues
)
13933 if self
.checkFound
:
13934 wrap
= CGIfWrapper(wrap
, self
.foundVar
)
13936 wrap
= CGList([CGGeneric("MOZ_ASSERT(" + self
.foundVar
+ ");\n"), wrap
])
13937 return "\n" + wrap
.define()
13940 class CGProxyIndexedOperation(CGProxySpecialOperation
):
13942 Class to generate a call to an indexed operation.
13944 If doUnwrap is False, the caller is responsible for making sure a variable
13945 named 'self' holds the C++ object somewhere where the code we generate
13948 If checkFound is False, will just assert that the prop is found instead of
13949 checking that it is before wrapping the value.
13951 resultVar: See the docstring for CGCallGenerator.
13953 foundVar: See the docstring for CGProxySpecialOperation.
13962 argumentHandleValue
=None,
13966 self
.doUnwrap
= doUnwrap
13967 CGProxySpecialOperation
.__init
__(
13972 argumentHandleValue
=argumentHandleValue
,
13973 resultVar
=resultVar
,
13978 # Our first argument is the id we're getting.
13979 argName
= self
.arguments
[0].identifier
.name
13980 if argName
== "index":
13981 # We already have our index in a variable with that name
13984 setIndex
= "uint32_t %s = index;\n" % argName
13986 unwrap
= "%s* self = UnwrapProxy(proxy);\n" % self
.descriptor
.nativeType
13989 return setIndex
+ unwrap
+ CGProxySpecialOperation
.define(self
)
13992 class CGProxyIndexedGetter(CGProxyIndexedOperation
):
13994 Class to generate a call to an indexed getter. If templateValues is not None
13995 the returned value will be wrapped with wrapForType using templateValues.
13997 If doUnwrap is False, the caller is responsible for making sure a variable
13998 named 'self' holds the C++ object somewhere where the code we generate
14001 If checkFound is False, will just assert that the prop is found instead of
14002 checking that it is before wrapping the value.
14004 foundVar: See the docstring for CGProxySpecialOperation.
14010 templateValues
=None,
14015 self
.templateValues
= templateValues
14016 CGProxyIndexedOperation
.__init
__(
14017 self
, descriptor
, "IndexedGetter", doUnwrap
, checkFound
, foundVar
=foundVar
14021 class CGProxyIndexedPresenceChecker(CGProxyIndexedGetter
):
14023 Class to generate a call that checks whether an indexed property exists.
14025 For now, we just delegate to CGProxyIndexedGetter
14027 foundVar: See the docstring for CGProxySpecialOperation.
14030 def __init__(self
, descriptor
, foundVar
):
14031 CGProxyIndexedGetter
.__init
__(self
, descriptor
, foundVar
=foundVar
)
14032 self
.cgRoot
.append(CGGeneric("(void)result;\n"))
14035 class CGProxyIndexedSetter(CGProxyIndexedOperation
):
14037 Class to generate a call to an indexed setter.
14040 def __init__(self
, descriptor
, argumentHandleValue
=None):
14041 CGProxyIndexedOperation
.__init
__(
14042 self
, descriptor
, "IndexedSetter", argumentHandleValue
=argumentHandleValue
14046 class CGProxyNamedOperation(CGProxySpecialOperation
):
14048 Class to generate a call to a named operation.
14050 'value' is the jsval to use for the name; None indicates that it should be
14051 gotten from the property id.
14053 resultVar: See the docstring for CGCallGenerator.
14055 foundVar: See the docstring for CGProxySpecialOperation.
14057 tailCode: if we end up with a non-symbol string id, run this code after
14058 we do all our other work.
14066 argumentHandleValue
=None,
14071 CGProxySpecialOperation
.__init
__(
14075 argumentHandleValue
=argumentHandleValue
,
14076 resultVar
=resultVar
,
14080 self
.tailCode
= tailCode
14083 # Our first argument is the id we're getting.
14084 argName
= self
.arguments
[0].identifier
.name
14085 if argName
== "id":
14086 # deal with the name collision
14087 decls
= "JS::Rooted<jsid> id_(cx, id);\n"
14093 decls
+= "FakeString<char16_t> %s;\n" % argName
14097 ${nativeType}* self = UnwrapProxy(proxy);
14101 nativeType
=self
.descriptor
.nativeType
,
14102 op
=CGProxySpecialOperation
.define(self
),
14103 tailCode
=self
.tailCode
,
14106 if self
.value
is None:
14111 if (!ConvertIdToString(cx, ${idName}, ${argName}, isSymbol)) {
14124 # Sadly, we have to set up nameVal even if we have an atom id,
14125 # because we don't know for sure, and we can end up needing it
14126 # so it needs to be higher up the stack. Using a Maybe here
14127 # seems like probable overkill.
14131 JS::Rooted<JS::Value> nameVal(cx, ${value});
14132 if (!nameVal.isSymbol()) {
14133 if (!ConvertJSValueToString(cx, nameVal, eStringify, eStringify,
14147 class CGProxyNamedGetter(CGProxyNamedOperation
):
14149 Class to generate a call to an named getter. If templateValues is not None
14150 the returned value will be wrapped with wrapForType using templateValues.
14151 'value' is the jsval to use for the name; None indicates that it should be
14152 gotten from the property id.
14154 foundVar: See the docstring for CGProxySpecialOperation.
14157 def __init__(self
, descriptor
, templateValues
=None, value
=None, foundVar
=None):
14158 self
.templateValues
= templateValues
14159 CGProxyNamedOperation
.__init
__(
14160 self
, descriptor
, "NamedGetter", value
, foundVar
=foundVar
14164 class CGProxyNamedPresenceChecker(CGProxyNamedGetter
):
14166 Class to generate a call that checks whether a named property exists.
14168 For now, we just delegate to CGProxyNamedGetter
14170 foundVar: See the docstring for CGProxySpecialOperation.
14173 def __init__(self
, descriptor
, foundVar
=None):
14174 CGProxyNamedGetter
.__init
__(self
, descriptor
, foundVar
=foundVar
)
14175 self
.cgRoot
.append(CGGeneric("(void)result;\n"))
14178 class CGProxyNamedSetter(CGProxyNamedOperation
):
14180 Class to generate a call to a named setter.
14183 def __init__(self
, descriptor
, tailCode
, argumentHandleValue
=None):
14184 CGProxyNamedOperation
.__init
__(
14188 argumentHandleValue
=argumentHandleValue
,
14193 class CGProxyNamedDeleter(CGProxyNamedOperation
):
14195 Class to generate a call to a named deleter.
14197 resultVar: See the docstring for CGCallGenerator.
14199 foundVar: See the docstring for CGProxySpecialOperation.
14202 def __init__(self
, descriptor
, resultVar
=None, foundVar
=None):
14203 CGProxyNamedOperation
.__init
__(
14204 self
, descriptor
, "NamedDeleter", resultVar
=resultVar
, foundVar
=foundVar
14208 class CGProxyIsProxy(CGAbstractMethod
):
14209 def __init__(self
, descriptor
):
14210 args
= [Argument("JSObject*", "obj")]
14211 CGAbstractMethod
.__init
__(
14212 self
, descriptor
, "IsProxy", "bool", args
, alwaysInline
=True
14218 def definition_body(self
):
14219 return "return js::IsProxy(obj) && js::GetProxyHandler(obj) == DOMProxyHandler::getInstance();\n"
14222 class CGProxyUnwrap(CGAbstractMethod
):
14223 def __init__(self
, descriptor
):
14224 args
= [Argument("JSObject*", "obj")]
14225 CGAbstractMethod
.__init
__(
14229 descriptor
.nativeType
+ "*",
14237 def definition_body(self
):
14240 MOZ_ASSERT(js::IsProxy(obj));
14241 if (js::GetProxyHandler(obj) != DOMProxyHandler::getInstance()) {
14242 MOZ_ASSERT(xpc::WrapperFactory::IsXrayWrapper(obj));
14243 obj = js::UncheckedUnwrap(obj);
14245 MOZ_ASSERT(IsProxy(obj));
14246 return static_cast<${type}*>(js::GetProxyReservedSlot(obj, DOM_OBJECT_SLOT).toPrivate());
14248 type=self
.descriptor
.nativeType
,
14252 MISSING_PROP_PREF
= "dom.missing_prop_counters.enabled"
14255 def missingPropUseCountersForDescriptor(desc
):
14256 if not desc
.needsMissingPropUseCounters
:
14261 if (StaticPrefs::${pref}() && JSID_IS_ATOM(id)) {
14262 CountMaybeMissingProperty(proxy, id);
14266 pref
=prefIdentifier(MISSING_PROP_PREF
),
14270 def findAncestorWithInstrumentedProps(desc
):
14272 Find an ancestor of desc.interface (not including desc.interface
14273 itself) that has instrumented properties on it. May return None
14274 if there is no such ancestor.
14276 ancestor
= desc
.interface
.parent
14278 if ancestor
.getExtendedAttribute("InstrumentedProps"):
14280 ancestor
= ancestor
.parent
14284 class CGCountMaybeMissingProperty(CGAbstractMethod
):
14285 def __init__(self
, descriptor
):
14287 Returns whether we counted the property involved.
14289 CGAbstractMethod
.__init
__(
14292 "CountMaybeMissingProperty",
14295 Argument("JS::Handle<JSObject*>", "proxy"),
14296 Argument("JS::Handle<jsid>", "id"),
14300 def gen_switch(self
, switchDecriptor
):
14302 Generate a switch from the switch descriptor. The descriptor
14303 dictionary must have the following properties:
14305 1) A "precondition" property that contains code to run before the
14306 switch statement. Its value ie a string.
14307 2) A "condition" property for the condition. Its value is a string.
14308 3) A "cases" property. Its value is an object that has property names
14309 corresponding to the case labels. The values of those properties
14310 are either new switch descriptor dictionaries (which will then
14311 generate nested switches) or strings to use for case bodies.
14314 for label
, body
in sorted(six
.iteritems(switchDecriptor
["cases"])):
14315 if isinstance(body
, dict):
14316 body
= self
.gen_switch(body
)
14332 switch (${condition}) {
14336 precondition
=switchDecriptor
["precondition"],
14337 condition
=switchDecriptor
["condition"],
14338 cases
="".join(cases
),
14341 def charSwitch(self
, props
, charIndex
):
14343 Create a switch for the given props, based on the first char where
14344 they start to differ at index charIndex or more. Each prop is a tuple
14345 containing interface name and prop name.
14347 Incoming props should be a sorted list.
14349 if len(props
) == 1:
14350 # We're down to one string: just check whether we match it.
14353 if (JS_LinearStringEqualsLiteral(str, "${name}")) {
14354 counter.emplace(eUseCounter_${iface}_${name});
14357 iface
=self
.descriptor
.name
,
14363 switch
["precondition"] = "StringIdChars chars(nogc, str);\n"
14365 switch
["precondition"] = ""
14367 # Find the first place where we might actually have a difference.
14368 while all(prop
[charIndex
] == props
[0][charIndex
] for prop
in props
):
14371 switch
["condition"] = "chars[%d]" % charIndex
14372 switch
["cases"] = dict()
14373 current_props
= None
14376 while idx
< len(props
):
14377 nextChar
= "'%s'" % props
[idx
][charIndex
]
14378 if nextChar
!= curChar
:
14380 switch
["cases"][curChar
] = self
.charSwitch(
14381 current_props
, charIndex
+ 1
14385 current_props
.append(props
[idx
])
14387 switch
["cases"][curChar
] = self
.charSwitch(current_props
, charIndex
+ 1)
14390 def definition_body(self
):
14391 ancestor
= findAncestorWithInstrumentedProps(self
.descriptor
)
14396 if (${ancestor}_Binding::CountMaybeMissingProperty(proxy, id)) {
14401 ancestor
=ancestor
.identifier
.name
,
14406 instrumentedProps
= self
.descriptor
.instrumentedProps
14407 if not instrumentedProps
:
14408 return body
+ dedent(
14414 lengths
= set(len(prop
) for prop
in instrumentedProps
)
14415 switchDesc
= {"condition": "JS::GetLinearStringLength(str)", "precondition": ""}
14416 switchDesc
["cases"] = dict()
14417 for length
in sorted(lengths
):
14418 switchDesc
["cases"][str(length
)] = self
.charSwitch(
14419 list(sorted(prop
for prop
in instrumentedProps
if len(prop
) == length
)),
14423 return body
+ fill(
14425 MOZ_ASSERT(StaticPrefs::${pref}() && JSID_IS_ATOM(id));
14426 Maybe<UseCounter> counter;
14428 // Scope for our no-GC section, so we don't need to rely on SetUseCounter not GCing.
14429 JS::AutoCheckCannotGC nogc;
14430 JSLinearString* str = JS::AtomToLinearString(JSID_TO_ATOM(id));
14431 // Don't waste time fetching the chars until we've done the length switch.
14435 SetUseCounter(proxy, *counter);
14441 pref
=prefIdentifier(MISSING_PROP_PREF
),
14442 switch
=self
.gen_switch(switchDesc
),
14446 class CGDOMJSProxyHandler_getOwnPropDescriptor(ClassMethod
):
14447 def __init__(self
, descriptor
):
14449 Argument("JSContext*", "cx"),
14450 Argument("JS::Handle<JSObject*>", "proxy"),
14451 Argument("JS::Handle<jsid>", "id"),
14452 Argument("bool", "ignoreNamedProps"),
14453 Argument("JS::MutableHandle<JS::PropertyDescriptor>", "desc"),
14455 ClassMethod
.__init
__(
14457 "getOwnPropDescriptor",
14464 self
.descriptor
= descriptor
14467 indexedGetter
= self
.descriptor
.operations
["IndexedGetter"]
14468 indexedSetter
= self
.descriptor
.operations
["IndexedSetter"]
14470 if self
.descriptor
.isMaybeCrossOriginObject():
14473 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy));
14474 MOZ_ASSERT(IsPlatformObjectSameOrigin(cx, proxy),
14475 "getOwnPropertyDescriptor() and set() should have dealt");
14476 MOZ_ASSERT(js::IsObjectInContextCompartment(proxy, cx),
14477 "getOwnPropertyDescriptor() and set() should have dealt");
14483 xrayDecl
= "bool isXray = xpc::WrapperFactory::IsXrayWrapper(proxy);\n"
14484 xrayCheck
= "!isXray &&"
14486 if self
.descriptor
.supportsIndexedProperties():
14487 readonly
= toStringBool(indexedSetter
is None)
14489 "FillPropertyDescriptor(desc, proxy, %s);\nreturn true;\n" % readonly
14492 "jsvalRef": "desc.value()",
14493 "jsvalHandle": "desc.value()",
14495 "successCode": fillDescriptor
,
14499 uint32_t index = GetArrayIndexFromId(id);
14500 if (IsArrayIndex(index)) {
14505 callGetter
=CGProxyIndexedGetter(
14506 self
.descriptor
, templateValues
14512 missingPropUseCounters
= missingPropUseCountersForDescriptor(self
.descriptor
)
14514 if self
.descriptor
.supportsNamedProperties():
14515 operations
= self
.descriptor
.operations
14516 readonly
= toStringBool(operations
["NamedSetter"] is None)
14518 "FillPropertyDescriptor(desc, proxy, %s, %s);\n"
14520 % (readonly
, toStringBool(self
.descriptor
.namedPropertiesEnumerable
))
14523 "jsvalRef": "desc.value()",
14524 "jsvalHandle": "desc.value()",
14526 "successCode": fillDescriptor
,
14529 computeCondition
= dedent(
14532 if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
14535 callNamedGetter = !hasOnProto;
14538 if self
.descriptor
.interface
.getExtendedAttribute("LegacyOverrideBuiltIns"):
14539 computeCondition
= fill(
14542 callNamedGetter = true;
14547 hasOnProto
=computeCondition
,
14550 outerCondition
= "!ignoreNamedProps"
14551 if self
.descriptor
.supportsIndexedProperties():
14552 outerCondition
= "!IsArrayIndex(index) && " + outerCondition
14554 namedGetCode
= CGProxyNamedGetter(self
.descriptor
, templateValues
).define()
14557 bool callNamedGetter = false;
14558 if (${outerCondition}) {
14559 $*{computeCondition}
14561 if (callNamedGetter) {
14565 outerCondition
=outerCondition
,
14566 computeCondition
=computeCondition
,
14567 namedGetCode
=namedGetCode
,
14577 $*{missingPropUseCounters}
14578 JS::Rooted<JSObject*> expando(cx);
14579 if (${xrayCheck}(expando = GetExpandoObject(proxy))) {
14580 if (!JS_GetOwnPropertyDescriptorById(cx, expando, id, desc)) {
14583 if (desc.object()) {
14584 // Pretend the property lives on the wrapper.
14585 desc.object().set(proxy);
14591 desc.object().set(nullptr);
14595 xrayCheck
=xrayCheck
,
14596 getIndexed
=getIndexed
,
14597 missingPropUseCounters
=missingPropUseCounters
,
14602 class CGDOMJSProxyHandler_defineProperty(ClassMethod
):
14603 def __init__(self
, descriptor
):
14604 # The usual convention is to name the ObjectOpResult out-parameter
14605 # `result`, but that name is a bit overloaded around here.
14607 Argument("JSContext*", "cx_"),
14608 Argument("JS::Handle<JSObject*>", "proxy"),
14609 Argument("JS::Handle<jsid>", "id"),
14610 Argument("JS::Handle<JS::PropertyDescriptor>", "desc"),
14611 Argument("JS::ObjectOpResult&", "opresult"),
14612 Argument("bool*", "done"),
14614 ClassMethod
.__init
__(
14623 self
.descriptor
= descriptor
14628 indexedSetter
= self
.descriptor
.operations
["IndexedSetter"]
14630 error_label
= CGSpecializedMethod
.error_reporting_label_helper(
14631 self
.descriptor
, indexedSetter
, isConstructor
=False
14636 BindingCallContext cx(cx_, "${error_label}");
14638 error_label
=error_label
,
14643 JSContext* cx = cx_;
14648 uint32_t index = GetArrayIndexFromId(id);
14649 if (IsArrayIndex(index)) {
14652 // https://heycam.github.io/webidl/#legacy-platform-object-defineownproperty
14653 // Step 1.1. The no-indexed-setter case is handled by step 1.2.
14654 if (!desc.isDataDescriptor()) {
14655 return opresult.failNotDataDescriptor();
14659 return opresult.succeed();
14663 callSetter
=CGProxyIndexedSetter(self
.descriptor
).define(),
14665 elif self
.descriptor
.supportsIndexedProperties():
14666 # We allow untrusted content to prevent Xrays from setting a
14667 # property if that property is an indexed property and we have no
14668 # indexed setter. That's how the object would normally behave if
14669 # you tried to set the property on it. That means we don't need to
14670 # do anything special for Xrays here.
14673 if (IsArrayIndex(GetArrayIndexFromId(id))) {
14675 return opresult.failNoIndexedSetter();
14680 namedSetter
= self
.descriptor
.operations
["NamedSetter"]
14682 error_label
= CGSpecializedMethod
.error_reporting_label_helper(
14683 self
.descriptor
, namedSetter
, isConstructor
=False
14688 BindingCallContext cx(cx_, "${error_label}");
14690 error_label
=error_label
,
14695 JSContext* cx = cx_;
14698 if self
.descriptor
.hasLegacyUnforgeableMembers
:
14700 "Can't handle a named setter on an interface "
14701 "that has unforgeables. Figure out how that "
14707 return opresult.succeed();
14710 set += CGProxyNamedSetter(self
.descriptor
, tailCode
).define()
14712 # We allow untrusted content to prevent Xrays from setting a
14713 # property if that property is already a named property on the
14714 # object and we have no named setter. That's how the object would
14715 # normally behave if you tried to set the property on it. That
14716 # means we don't need to do anything special for Xrays here.
14717 if self
.descriptor
.supportsNamedProperties():
14720 JSContext* cx = cx_;
14721 bool found = false;
14722 $*{presenceChecker}
14726 return opresult.failNoNamedSetter();
14729 presenceChecker
=CGProxyNamedPresenceChecker(
14730 self
.descriptor
, foundVar
="found"
14733 if self
.descriptor
.isMaybeCrossOriginObject():
14736 MOZ_ASSERT(IsPlatformObjectSameOrigin(cx_, proxy),
14737 "Why did the MaybeCrossOriginObject defineProperty override fail?");
14738 MOZ_ASSERT(js::IsObjectInContextCompartment(proxy, cx_),
14739 "Why did the MaybeCrossOriginObject defineProperty override fail?");
14743 # In all cases we want to tail-call to our base class; we can
14744 # always land here for symbols.
14746 "return mozilla::dom::DOMProxyHandler::defineProperty(%s);\n"
14747 % ", ".join(a
.name
for a
in self
.args
)
14752 def getDeleterBody(descriptor
, type, foundVar
=None):
14754 type should be "Named" or "Indexed"
14756 The possible outcomes:
14757 - an error happened (the emitted code returns false)
14758 - own property not found (foundVar=false, deleteSucceeded=true)
14759 - own property found and deleted (foundVar=true, deleteSucceeded=true)
14760 - own property found but can't be deleted (foundVar=true, deleteSucceeded=false)
14762 assert type in ("Named", "Indexed")
14763 deleter
= descriptor
.operations
[type + "Deleter"]
14765 assert type == "Named"
14766 assert foundVar
is not None
14767 if descriptor
.hasLegacyUnforgeableMembers
:
14769 "Can't handle a deleter on an interface "
14770 "that has unforgeables. Figure out how "
14771 "that should work!"
14773 # See if the deleter method is fallible.
14774 t
= deleter
.signatures()[0][0]
14775 if t
.isPrimitive() and not t
.nullable() and t
.tag() == IDLType
.Tags
.bool:
14776 # The deleter method has a boolean return value. When a
14777 # property is found, the return value indicates whether it
14778 # was successfully deleted.
14781 if (!${foundVar}) {
14782 deleteSucceeded = true;
14788 # No boolean return value: if a property is found,
14789 # deleting it always succeeds.
14790 setDS
= "deleteSucceeded = true;\n"
14793 CGProxyNamedDeleter(
14794 descriptor
, resultVar
="deleteSucceeded", foundVar
=foundVar
14798 elif getattr(descriptor
, "supports%sProperties" % type)():
14799 presenceCheckerClass
= globals()["CGProxy%sPresenceChecker" % type]
14801 if foundVar
is None:
14803 foundDecl
= "bool found = false;\n"
14807 $*{presenceChecker}
14808 deleteSucceeded = !${foundVar};
14810 foundDecl
=foundDecl
,
14811 presenceChecker
=presenceCheckerClass(
14812 descriptor
, foundVar
=foundVar
14821 class CGDeleteNamedProperty(CGAbstractStaticMethod
):
14822 def __init__(self
, descriptor
):
14824 Argument("JSContext*", "cx"),
14825 Argument("JS::Handle<JSObject*>", "xray"),
14826 Argument("JS::Handle<JSObject*>", "proxy"),
14827 Argument("JS::Handle<jsid>", "id"),
14828 Argument("JS::ObjectOpResult&", "opresult"),
14830 CGAbstractStaticMethod
.__init
__(
14831 self
, descriptor
, "DeleteNamedProperty", "bool", args
14834 def definition_body(self
):
14837 MOZ_ASSERT(xpc::WrapperFactory::IsXrayWrapper(xray));
14838 MOZ_ASSERT(js::IsProxy(proxy));
14839 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy));
14840 JSAutoRealm ar(cx, proxy);
14841 bool deleteSucceeded = false;
14842 bool found = false;
14844 if (!found || deleteSucceeded) {
14845 return opresult.succeed();
14847 return opresult.failCantDelete();
14849 namedBody
=getDeleterBody(self
.descriptor
, "Named", foundVar
="found"),
14853 class CGDOMJSProxyHandler_delete(ClassMethod
):
14854 def __init__(self
, descriptor
):
14856 Argument("JSContext*", "cx"),
14857 Argument("JS::Handle<JSObject*>", "proxy"),
14858 Argument("JS::Handle<jsid>", "id"),
14859 Argument("JS::ObjectOpResult&", "opresult"),
14861 ClassMethod
.__init
__(
14862 self
, "delete_", "bool", args
, virtual
=True, override
=True, const
=True
14864 self
.descriptor
= descriptor
14869 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
14870 "Should not have a XrayWrapper here");
14875 if self
.descriptor
.isMaybeCrossOriginObject():
14878 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
14879 return ReportCrossOriginDenial(cx, id, "delete"_ns);
14882 // Safe to enter the Realm of proxy now.
14883 JSAutoRealm ar(cx, proxy);
14884 JS_MarkCrossZoneId(cx, id);
14888 indexedBody
= getDeleterBody(self
.descriptor
, "Indexed")
14889 if indexedBody
is not None:
14890 # Can't handle cross-origin objects here.
14891 assert not self
.descriptor
.isMaybeCrossOriginObject()
14894 uint32_t index = GetArrayIndexFromId(id);
14895 if (IsArrayIndex(index)) {
14896 bool deleteSucceeded;
14898 return deleteSucceeded ? opresult.succeed() : opresult.failCantDelete();
14901 indexedBody
=indexedBody
,
14904 namedBody
= getDeleterBody(self
.descriptor
, "Named", foundVar
="found")
14905 if namedBody
is not None:
14908 // Try named delete only if the named property visibility
14909 // algorithm says the property is visible.
14910 bool tryNamedDelete = true;
14911 { // Scope for expando
14912 JS::Rooted<JSObject*> expando(cx, DOMProxyHandler::GetExpandoObject(proxy));
14915 if (!JS_HasPropertyById(cx, expando, id, &hasProp)) {
14918 tryNamedDelete = !hasProp;
14924 if not self
.descriptor
.interface
.getExtendedAttribute(
14925 "LegacyOverrideBuiltIns"
14929 if (tryNamedDelete) {
14931 if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
14934 tryNamedDelete = !hasOnProto;
14939 # We always return above for an index id in the case when we support
14940 # indexed properties, so we can just treat the id as a name
14941 # unconditionally here.
14944 if (tryNamedDelete) {
14945 bool found = false;
14946 bool deleteSucceeded;
14949 return deleteSucceeded ? opresult.succeed() : opresult.failCantDelete();
14953 namedBody
=namedBody
,
14959 return dom::DOMProxyHandler::delete_(cx, proxy, id, opresult);
14966 class CGDOMJSProxyHandler_ownPropNames(ClassMethod
):
14972 Argument("JSContext*", "cx"),
14973 Argument("JS::Handle<JSObject*>", "proxy"),
14974 Argument("unsigned", "flags"),
14975 Argument("JS::MutableHandleVector<jsid>", "props"),
14977 ClassMethod
.__init
__(
14978 self
, "ownPropNames", "bool", args
, virtual
=True, override
=True, const
=True
14980 self
.descriptor
= descriptor
14983 if self
.descriptor
.isMaybeCrossOriginObject():
14986 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy));
14987 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
14988 if (!(flags & JSITER_HIDDEN)) {
14989 // There are no enumerable cross-origin props, so we're done.
14993 JS::Rooted<JSObject*> holder(cx);
14994 if (!EnsureHolder(cx, proxy, &holder)) {
14998 if (!js::GetPropertyKeys(cx, holder, flags, props)) {
15002 return xpc::AppendCrossOriginWhitelistedPropNames(cx, props);
15009 xrayDecl
= "bool isXray = xpc::WrapperFactory::IsXrayWrapper(proxy);\n"
15010 xrayCheck
= "!isXray &&"
15012 # Per spec, we do indices, then named props, then everything else.
15013 if self
.descriptor
.supportsIndexedProperties():
15014 if self
.descriptor
.lengthNeedsCallerType():
15015 callerType
= callerTypeGetterForDescriptor(self
.descriptor
)
15021 uint32_t length = UnwrapProxy(proxy)->Length(${callerType});
15022 MOZ_ASSERT(int32_t(length) >= 0);
15023 for (int32_t i = 0; i < int32_t(length); ++i) {
15024 if (!props.append(INT_TO_JSID(i))) {
15029 callerType
=callerType
,
15034 if self
.descriptor
.supportsNamedProperties():
15035 if self
.descriptor
.interface
.getExtendedAttribute("LegacyOverrideBuiltIns"):
15040 if self
.descriptor
.supportedNamesNeedCallerType():
15041 callerType
= ", " + callerTypeGetterForDescriptor(self
.descriptor
)
15047 nsTArray<nsString> names;
15048 UnwrapProxy(proxy)->GetSupportedNames(names${callerType});
15049 if (!AppendNamedPropertyIds(cx, proxy, names, ${shadow}, props)) {
15053 callerType
=callerType
,
15056 if not self
.descriptor
.namedPropertiesEnumerable
:
15057 addNames
= CGIfWrapper(
15058 CGGeneric(addNames
), "flags & JSITER_HIDDEN"
15060 addNames
= "\n" + addNames
15064 addExpandoProps
= fill(
15066 JS::Rooted<JSObject*> expando(cx);
15067 if (${xrayCheck}(expando = DOMProxyHandler::GetExpandoObject(proxy)) &&
15068 !js::GetPropertyKeys(cx, expando, flags, props)) {
15072 xrayCheck
=xrayCheck
,
15075 if self
.descriptor
.isMaybeCrossOriginObject():
15076 # We need to enter our compartment (which we might not be
15077 # in right now) to get the expando props.
15078 addExpandoProps
= fill(
15080 { // Scope for accessing the expando.
15081 // Safe to enter our compartment, because IsPlatformObjectSameOrigin tested true.
15082 JSAutoRealm ar(cx, proxy);
15083 $*{addExpandoProps}
15085 for (auto& id : props) {
15086 JS_MarkCrossZoneId(cx, id);
15089 addExpandoProps
=addExpandoProps
,
15098 $*{addExpandoProps}
15103 addIndices
=addIndices
,
15105 addExpandoProps
=addExpandoProps
,
15109 class CGDOMJSProxyHandler_hasOwn(ClassMethod
):
15110 def __init__(self
, descriptor
):
15112 Argument("JSContext*", "cx"),
15113 Argument("JS::Handle<JSObject*>", "proxy"),
15114 Argument("JS::Handle<jsid>", "id"),
15115 Argument("bool*", "bp"),
15117 ClassMethod
.__init
__(
15118 self
, "hasOwn", "bool", args
, virtual
=True, override
=True, const
=True
15120 self
.descriptor
= descriptor
15123 if self
.descriptor
.isMaybeCrossOriginObject():
15124 maybeCrossOrigin
= dedent(
15126 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
15127 // Just hand this off to BaseProxyHandler to do the slow-path thing.
15128 // The BaseProxyHandler code is OK with this happening without entering the
15129 // compartment of "proxy", which is important to get the right answers.
15130 return js::BaseProxyHandler::hasOwn(cx, proxy, id, bp);
15133 // Now safe to enter the Realm of proxy and do the rest of the work there.
15134 JSAutoRealm ar(cx, proxy);
15135 JS_MarkCrossZoneId(cx, id);
15139 maybeCrossOrigin
= ""
15141 if self
.descriptor
.supportsIndexedProperties():
15144 uint32_t index = GetArrayIndexFromId(id);
15145 if (IsArrayIndex(index)) {
15146 bool found = false;
15147 $*{presenceChecker}
15154 presenceChecker
=CGProxyIndexedPresenceChecker(
15155 self
.descriptor
, foundVar
="found"
15161 if self
.descriptor
.supportsNamedProperties():
15162 # If we support indexed properties we always return above for index
15163 # property names, so no need to check for those here.
15166 bool found = false;
15167 $*{presenceChecker}
15171 presenceChecker
=CGProxyNamedPresenceChecker(
15172 self
.descriptor
, foundVar
="found"
15175 if not self
.descriptor
.interface
.getExtendedAttribute(
15176 "LegacyOverrideBuiltIns"
15181 if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
15185 $*{protoLacksProperty}
15189 protoLacksProperty
=named
,
15191 named
+= "*bp = false;\n"
15195 named
= "*bp = false;\n"
15197 missingPropUseCounters
= missingPropUseCountersForDescriptor(self
.descriptor
)
15201 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
15202 "Should not have a XrayWrapper here");
15203 $*{maybeCrossOrigin}
15206 $*{missingPropUseCounters}
15207 JS::Rooted<JSObject*> expando(cx, GetExpandoObject(proxy));
15210 bool ok = JS_HasPropertyById(cx, expando, id, &b);
15220 maybeCrossOrigin
=maybeCrossOrigin
,
15222 missingPropUseCounters
=missingPropUseCounters
,
15227 class CGDOMJSProxyHandler_get(ClassMethod
):
15228 def __init__(self
, descriptor
):
15230 Argument("JSContext*", "cx"),
15231 Argument("JS::Handle<JSObject*>", "proxy"),
15232 Argument("JS::Handle<JS::Value>", "receiver"),
15233 Argument("JS::Handle<jsid>", "id"),
15234 Argument("JS::MutableHandle<JS::Value>", "vp"),
15236 ClassMethod
.__init
__(
15237 self
, "get", "bool", args
, virtual
=True, override
=True, const
=True
15239 self
.descriptor
= descriptor
15242 if self
.descriptor
.isMaybeCrossOriginObject():
15243 maybeCrossOriginGet
= dedent(
15245 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
15246 return CrossOriginGet(cx, proxy, receiver, id, vp);
15252 maybeCrossOriginGet
= ""
15254 missingPropUseCounters
= missingPropUseCountersForDescriptor(self
.descriptor
)
15256 getUnforgeableOrExpando
= dedent(
15258 { // Scope for expando
15259 JS::Rooted<JSObject*> expando(cx, DOMProxyHandler::GetExpandoObject(proxy));
15261 if (!JS_HasPropertyById(cx, expando, id, &expandoHasProp)) {
15265 if (expandoHasProp) {
15266 // Forward the get to the expando object, but our receiver is whatever our
15268 if (!JS_ForwardGetPropertyTo(cx, expando, id, rootedReceiver, vp)) {
15277 if self
.descriptor
.isMaybeCrossOriginObject():
15278 getUnforgeableOrExpando
= fill(
15280 { // Scope for the JSAutoRealm accessing expando
15281 JSAutoRealm ar(cx, proxy);
15282 if (!MaybeWrapValue(cx, &rootedReceiver)) {
15285 JS_MarkCrossZoneId(cx, id);
15287 $*{getUnforgeableOrExpando}
15289 if (expandoHasProp) {
15290 return MaybeWrapValue(cx, vp);
15293 getUnforgeableOrExpando
=getUnforgeableOrExpando
,
15296 getUnforgeableOrExpando
= fill(
15298 $*{getUnforgeableOrExpando}
15300 if (expandoHasProp) {
15304 getUnforgeableOrExpando
=getUnforgeableOrExpando
,
15307 getUnforgeableOrExpando
= fill(
15309 bool expandoHasProp = false;
15310 $*{getUnforgeableOrExpando}
15312 getUnforgeableOrExpando
=getUnforgeableOrExpando
,
15315 templateValues
= {"jsvalRef": "vp", "jsvalHandle": "vp", "obj": "proxy"}
15317 if self
.descriptor
.supportsIndexedProperties():
15318 # We can't handle this for cross-origin objects
15319 assert not self
.descriptor
.isMaybeCrossOriginObject()
15321 getIndexedOrExpando
= fill(
15323 uint32_t index = GetArrayIndexFromId(id);
15324 if (IsArrayIndex(index)) {
15326 // Even if we don't have this index, we don't forward the
15327 // get on to our expando object.
15329 $*{getUnforgeableOrExpando}
15332 callGetter
=CGProxyIndexedGetter(
15333 self
.descriptor
, templateValues
15335 getUnforgeableOrExpando
=getUnforgeableOrExpando
,
15338 getIndexedOrExpando
= getUnforgeableOrExpando
15340 if self
.descriptor
.supportsNamedProperties():
15341 # We can't handle this for cross-origin objects
15342 assert not self
.descriptor
.isMaybeCrossOriginObject()
15344 getNamed
= CGProxyNamedGetter(self
.descriptor
, templateValues
)
15345 if self
.descriptor
.supportsIndexedProperties():
15346 getNamed
= CGIfWrapper(getNamed
, "!IsArrayIndex(index)")
15347 getNamed
= getNamed
.define() + "\n"
15351 getOnPrototype
= dedent(
15353 if (!GetPropertyOnPrototype(cx, proxy, rootedReceiver, id, &foundOnPrototype, vp)) {
15360 if self
.descriptor
.isMaybeCrossOriginObject():
15361 getOnPrototype
= fill(
15363 bool foundOnPrototype;
15364 { // Scope for JSAutoRealm
15365 JSAutoRealm ar(cx, proxy);
15366 // We already wrapped rootedReceiver
15367 MOZ_ASSERT_IF(rootedReceiver.isObject(),
15368 js::IsObjectInContextCompartment(&rootedReceiver.toObject(), cx));
15369 JS_MarkCrossZoneId(cx, id);
15373 if (foundOnPrototype) {
15374 return MaybeWrapValue(cx, vp);
15378 getOnPrototype
=getOnPrototype
,
15381 getOnPrototype
= fill(
15383 bool foundOnPrototype;
15385 if (foundOnPrototype) {
15390 getOnPrototype
=getOnPrototype
,
15393 if self
.descriptor
.interface
.getExtendedAttribute("LegacyOverrideBuiltIns"):
15394 getNamed
= getNamed
+ getOnPrototype
15396 getNamed
= getOnPrototype
+ getNamed
15400 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
15401 "Should not have a XrayWrapper here");
15403 $*{maybeCrossOriginGet}
15404 JS::Rooted<JS::Value> rootedReceiver(cx, receiver);
15406 $*{missingPropUseCounters}
15407 $*{indexedOrExpando}
15413 maybeCrossOriginGet
=maybeCrossOriginGet
,
15414 missingPropUseCounters
=missingPropUseCounters
,
15415 indexedOrExpando
=getIndexedOrExpando
,
15420 class CGDOMJSProxyHandler_setCustom(ClassMethod
):
15421 def __init__(self
, descriptor
):
15423 Argument("JSContext*", "cx_"),
15424 Argument("JS::Handle<JSObject*>", "proxy"),
15425 Argument("JS::Handle<jsid>", "id"),
15426 Argument("JS::Handle<JS::Value>", "v"),
15427 Argument("bool*", "done"),
15429 ClassMethod
.__init
__(
15430 self
, "setCustom", "bool", args
, virtual
=True, override
=True, const
=True
15432 self
.descriptor
= descriptor
15436 "MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),\n"
15437 ' "Should not have a XrayWrapper here");\n'
15440 # Correctness first. If we have a NamedSetter and [LegacyOverrideBuiltIns],
15441 # always call the NamedSetter and never do anything else.
15442 namedSetter
= self
.descriptor
.operations
["NamedSetter"]
15443 if namedSetter
is not None and self
.descriptor
.interface
.getExtendedAttribute(
15444 "LegacyOverrideBuiltIns"
15446 # Check assumptions.
15447 if self
.descriptor
.supportsIndexedProperties():
15450 + self
.descriptor
.name
15452 + "Can't cope with [LegacyOverrideBuiltIns] and an indexed getter"
15454 if self
.descriptor
.hasLegacyUnforgeableMembers
:
15457 + self
.descriptor
.name
15459 + "Can't cope with [LegacyOverrideBuiltIns] and unforgeable members"
15468 callSetter
= CGProxyNamedSetter(
15469 self
.descriptor
, tailCode
, argumentHandleValue
="v"
15471 error_label
= CGSpecializedMethod
.error_reporting_label_helper(
15472 self
.descriptor
, namedSetter
, isConstructor
=False
15477 BindingCallContext cx(cx_, "${error_label}");
15479 error_label
=error_label
,
15484 JSContext* cx = cx_;
15495 assertion
=assertion
,
15497 callSetter
=callSetter
.define(),
15500 # As an optimization, if we are going to call an IndexedSetter, go
15501 # ahead and call it and have done.
15502 indexedSetter
= self
.descriptor
.operations
["IndexedSetter"]
15503 if indexedSetter
is not None:
15504 error_label
= CGSpecializedMethod
.error_reporting_label_helper(
15505 self
.descriptor
, indexedSetter
, isConstructor
=False
15510 BindingCallContext cx(cx_, "${error_label}");
15512 error_label
=error_label
,
15517 JSContext* cx = cx_;
15522 uint32_t index = GetArrayIndexFromId(id);
15523 if (IsArrayIndex(index)) {
15532 callSetter
=CGProxyIndexedSetter(
15533 self
.descriptor
, argumentHandleValue
="v"
15539 return assertion
+ setIndexed
+ "*done = false;\n" "return true;\n"
15542 class CGDOMJSProxyHandler_className(ClassMethod
):
15543 def __init__(self
, descriptor
):
15545 Argument("JSContext*", "cx"),
15546 Argument("JS::Handle<JSObject*>", "proxy"),
15548 ClassMethod
.__init
__(
15557 self
.descriptor
= descriptor
15560 if self
.descriptor
.isMaybeCrossOriginObject():
15561 crossOrigin
= dedent(
15563 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
15576 crossOrigin
=crossOrigin
,
15577 name
=self
.descriptor
.name
,
15581 class CGDOMJSProxyHandler_finalizeInBackground(ClassMethod
):
15582 def __init__(self
, descriptor
):
15583 args
= [Argument("const JS::Value&", "priv")]
15584 ClassMethod
.__init
__(
15586 "finalizeInBackground",
15593 self
.descriptor
= descriptor
15596 return "return false;\n"
15599 class CGDOMJSProxyHandler_finalize(ClassMethod
):
15600 def __init__(self
, descriptor
):
15601 args
= [Argument("JSFreeOp*", "fop"), Argument("JSObject*", "proxy")]
15602 ClassMethod
.__init
__(
15603 self
, "finalize", "void", args
, virtual
=True, override
=True, const
=True
15605 self
.descriptor
= descriptor
15609 "%s* self = UnwrapPossiblyNotInitializedDOMObject<%s>(proxy);\n"
15610 % (self
.descriptor
.nativeType
, self
.descriptor
.nativeType
)
15613 FINALIZE_HOOK_NAME
,
15619 class CGDOMJSProxyHandler_objectMoved(ClassMethod
):
15620 def __init__(self
, descriptor
):
15621 args
= [Argument("JSObject*", "obj"), Argument("JSObject*", "old")]
15622 ClassMethod
.__init
__(
15623 self
, "objectMoved", "size_t", args
, virtual
=True, override
=True, const
=True
15625 self
.descriptor
= descriptor
15629 "%s* self = UnwrapPossiblyNotInitializedDOMObject<%s>(obj);\n"
15630 % (self
.descriptor
.nativeType
, self
.descriptor
.nativeType
)
15631 ) + objectMovedHook(
15633 OBJECT_MOVED_HOOK_NAME
,
15639 class CGDOMJSProxyHandler_getElements(ClassMethod
):
15640 def __init__(self
, descriptor
):
15641 assert descriptor
.supportsIndexedProperties()
15644 Argument("JSContext*", "cx"),
15645 Argument("JS::Handle<JSObject*>", "proxy"),
15646 Argument("uint32_t", "begin"),
15647 Argument("uint32_t", "end"),
15648 Argument("js::ElementAdder*", "adder"),
15650 ClassMethod
.__init
__(
15651 self
, "getElements", "bool", args
, virtual
=True, override
=True, const
=True
15653 self
.descriptor
= descriptor
15656 # Just like ownPropertyKeys we'll assume that we have no holes, so
15657 # we have all properties from 0 to length. If that ever changes
15658 # (unlikely), we'll need to do something a bit more clever with how we
15659 # forward on to our ancestor.
15662 "jsvalRef": "temp",
15663 "jsvalHandle": "&temp",
15666 "if (!adder->append(cx, temp)) return false;\n" "continue;\n"
15669 get
= CGProxyIndexedGetter(
15670 self
.descriptor
, templateValues
, False, False
15673 if self
.descriptor
.lengthNeedsCallerType():
15674 callerType
= callerTypeGetterForDescriptor(self
.descriptor
)
15680 JS::Rooted<JS::Value> temp(cx);
15681 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
15682 "Should not have a XrayWrapper here");
15684 ${nativeType}* self = UnwrapProxy(proxy);
15685 uint32_t length = self->Length(${callerType});
15686 // Compute the end of the indices we'll get ourselves
15687 uint32_t ourEnd = std::max(begin, std::min(end, length));
15689 for (uint32_t index = begin; index < ourEnd; ++index) {
15693 if (end > ourEnd) {
15694 JS::Rooted<JSObject*> proto(cx);
15695 if (!js::GetObjectProto(cx, proxy, &proto)) {
15698 return js::GetElementsWithAdder(cx, proto, proxy, ourEnd, end, adder);
15703 nativeType
=self
.descriptor
.nativeType
,
15704 callerType
=callerType
,
15709 class CGDOMJSProxyHandler_getInstance(ClassMethod
):
15710 def __init__(self
):
15711 ClassMethod
.__init
__(
15712 self
, "getInstance", "const DOMProxyHandler*", [], static
=True
15718 static const DOMProxyHandler instance;
15724 class CGDOMJSProxyHandler_call(ClassMethod
):
15725 def __init__(self
):
15727 Argument("JSContext*", "cx"),
15728 Argument("JS::Handle<JSObject*>", "proxy"),
15729 Argument("const JS::CallArgs&", "args"),
15732 ClassMethod
.__init
__(
15733 self
, "call", "bool", args
, virtual
=True, override
=True, const
=True
15739 return js::ForwardToNative(cx, ${legacyCaller}, args);
15741 legacyCaller
=LEGACYCALLER_HOOK_NAME
,
15745 class CGDOMJSProxyHandler_isCallable(ClassMethod
):
15746 def __init__(self
):
15747 ClassMethod
.__init
__(
15751 [Argument("JSObject*", "obj")],
15765 class CGDOMJSProxyHandler_canNurseryAllocate(ClassMethod
):
15767 Override the default canNurseryAllocate in BaseProxyHandler, for cases when
15768 we should be nursery-allocated.
15771 def __init__(self
):
15772 ClassMethod
.__init
__(
15774 "canNurseryAllocate",
15790 class CGDOMJSProxyHandler_getOwnPropertyDescriptor(ClassMethod
):
15792 Implementation of getOwnPropertyDescriptor. We only use this for
15793 cross-origin objects.
15796 def __init__(self
, descriptor
):
15797 assert descriptor
.isMaybeCrossOriginObject()
15800 Argument("JSContext*", "cx"),
15801 Argument("JS::Handle<JSObject*>", "proxy"),
15802 Argument("JS::Handle<jsid>", "id"),
15803 Argument("JS::MutableHandle<Maybe<JS::PropertyDescriptor>>", "desc"),
15805 ClassMethod
.__init
__(
15807 "getOwnPropertyDescriptor",
15814 self
.descriptor
= descriptor
15819 // Implementation of <https://html.spec.whatwg.org/multipage/history.html#location-getownproperty>.
15820 MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy));
15823 if (IsPlatformObjectSameOrigin(cx, proxy)) {
15824 { // Scope so we can wrap our PropertyDescriptor back into
15825 // the caller compartment.
15826 // Enter the Realm of "proxy" so we can work with it.
15827 JSAutoRealm ar(cx, proxy);
15829 JS_MarkCrossZoneId(cx, id);
15831 // The spec messes around with configurability of the returned
15832 // descriptor here, but it's not clear what should actually happen
15833 // here. See <https://github.com/whatwg/html/issues/4157>. For
15834 // now, keep our old behavior and don't do any magic.
15835 if (!dom::DOMProxyHandler::getOwnPropertyDescriptor(cx, proxy, id, desc)) {
15839 return JS_WrapPropertyDescriptor(cx, desc);
15843 if (!CrossOriginGetOwnPropertyHelper(cx, proxy, id, desc)) {
15848 if (desc.isSome()) {
15853 return CrossOriginPropertyFallback(cx, proxy, id, desc);
15858 class CGDOMJSProxyHandler_getSameOriginPrototype(ClassMethod
):
15860 Implementation of getSameOriginPrototype. We only use this for
15861 cross-origin objects.
15864 def __init__(self
, descriptor
):
15865 assert descriptor
.isMaybeCrossOriginObject()
15867 args
= [Argument("JSContext*", "cx")]
15868 ClassMethod
.__init
__(
15870 "getSameOriginPrototype",
15877 self
.descriptor
= descriptor
15882 return GetProtoObjectHandle(cx);
15887 class CGDOMJSProxyHandler_definePropertySameOrigin(ClassMethod
):
15889 Implementation of definePropertySameOrigin. We only use this for
15890 cross-origin objects.
15893 def __init__(self
, descriptor
):
15894 assert descriptor
.isMaybeCrossOriginObject()
15897 Argument("JSContext*", "cx"),
15898 Argument("JS::Handle<JSObject*>", "proxy"),
15899 Argument("JS::Handle<jsid>", "id"),
15900 Argument("JS::Handle<JS::PropertyDescriptor>", "desc"),
15901 Argument("JS::ObjectOpResult&", "result"),
15903 ClassMethod
.__init
__(
15905 "definePropertySameOrigin",
15912 self
.descriptor
= descriptor
15917 return dom::DOMProxyHandler::defineProperty(cx, proxy, id, desc, result);
15922 class CGDOMJSProxyHandler_set(ClassMethod
):
15924 Implementation of set(). We only use this for cross-origin objects.
15927 def __init__(self
, descriptor
):
15928 assert descriptor
.isMaybeCrossOriginObject()
15931 Argument("JSContext*", "cx"),
15932 Argument("JS::Handle<JSObject*>", "proxy"),
15933 Argument("JS::Handle<jsid>", "id"),
15934 Argument("JS::Handle<JS::Value>", "v"),
15935 Argument("JS::Handle<JS::Value>", "receiver"),
15936 Argument("JS::ObjectOpResult&", "result"),
15938 ClassMethod
.__init
__(
15939 self
, "set", "bool", args
, virtual
=True, override
=True, const
=True
15941 self
.descriptor
= descriptor
15946 if (!IsPlatformObjectSameOrigin(cx, proxy)) {
15947 return CrossOriginSet(cx, proxy, id, v, receiver, result);
15950 // Safe to enter the Realm of proxy now, since it's same-origin with us.
15951 JSAutoRealm ar(cx, proxy);
15952 JS::Rooted<JS::Value> wrappedReceiver(cx, receiver);
15953 if (!MaybeWrapValue(cx, &wrappedReceiver)) {
15957 JS::Rooted<JS::Value> wrappedValue(cx, v);
15958 if (!MaybeWrapValue(cx, &wrappedValue)) {
15962 JS_MarkCrossZoneId(cx, id);
15964 return dom::DOMProxyHandler::set(cx, proxy, id, wrappedValue, wrappedReceiver, result);
15969 class CGDOMJSProxyHandler_EnsureHolder(ClassMethod
):
15971 Implementation of EnsureHolder(). We only use this for cross-origin objects.
15974 def __init__(self
, descriptor
):
15976 Argument("JSContext*", "cx"),
15977 Argument("JS::Handle<JSObject*>", "proxy"),
15978 Argument("JS::MutableHandle<JSObject*>", "holder"),
15980 ClassMethod
.__init
__(
15981 self
, "EnsureHolder", "bool", args
, virtual
=True, override
=True, const
=True
15983 self
.descriptor
= descriptor
15988 return EnsureHolder(cx, proxy,
15989 JSCLASS_RESERVED_SLOTS(JS::GetClass(proxy)) - 1,
15990 sCrossOriginProperties, holder);
15995 class CGDOMJSProxyHandler(CGClass
):
15996 def __init__(self
, descriptor
):
15998 descriptor
.supportsIndexedProperties()
15999 or descriptor
.supportsNamedProperties()
16000 or descriptor
.isMaybeCrossOriginObject()
16003 CGDOMJSProxyHandler_getOwnPropDescriptor(descriptor
),
16004 CGDOMJSProxyHandler_defineProperty(descriptor
),
16005 ClassUsingDeclaration("mozilla::dom::DOMProxyHandler", "defineProperty"),
16006 CGDOMJSProxyHandler_ownPropNames(descriptor
),
16007 CGDOMJSProxyHandler_hasOwn(descriptor
),
16008 CGDOMJSProxyHandler_get(descriptor
),
16009 CGDOMJSProxyHandler_className(descriptor
),
16010 CGDOMJSProxyHandler_finalizeInBackground(descriptor
),
16011 CGDOMJSProxyHandler_finalize(descriptor
),
16012 CGDOMJSProxyHandler_getInstance(),
16013 CGDOMJSProxyHandler_delete(descriptor
),
16016 ClassConstructor([], constexpr
=True, visibility
="public", explicit
=True)
16019 if descriptor
.supportsIndexedProperties():
16020 methods
.append(CGDOMJSProxyHandler_getElements(descriptor
))
16021 if descriptor
.operations
["IndexedSetter"] is not None or (
16022 descriptor
.operations
["NamedSetter"] is not None
16023 and descriptor
.interface
.getExtendedAttribute("LegacyOverrideBuiltIns")
16025 methods
.append(CGDOMJSProxyHandler_setCustom(descriptor
))
16026 if descriptor
.operations
["LegacyCaller"]:
16027 methods
.append(CGDOMJSProxyHandler_call())
16028 methods
.append(CGDOMJSProxyHandler_isCallable())
16029 if descriptor
.interface
.hasProbablyShortLivingWrapper():
16030 if not descriptor
.wrapperCache
:
16032 "Need a wrapper cache to support nursery "
16033 "allocation of DOM objects"
16035 methods
.append(CGDOMJSProxyHandler_canNurseryAllocate())
16036 if descriptor
.wrapperCache
:
16037 methods
.append(CGDOMJSProxyHandler_objectMoved(descriptor
))
16039 if descriptor
.isMaybeCrossOriginObject():
16042 CGDOMJSProxyHandler_getOwnPropertyDescriptor(descriptor
),
16043 CGDOMJSProxyHandler_getSameOriginPrototype(descriptor
),
16044 CGDOMJSProxyHandler_definePropertySameOrigin(descriptor
),
16045 CGDOMJSProxyHandler_set(descriptor
),
16046 CGDOMJSProxyHandler_EnsureHolder(descriptor
),
16047 ClassUsingDeclaration(
16048 "MaybeCrossOriginObjectMixins", "EnsureHolder"
16053 if descriptor
.interface
.getExtendedAttribute("LegacyOverrideBuiltIns"):
16054 assert not descriptor
.isMaybeCrossOriginObject()
16055 parentClass
= "ShadowingDOMProxyHandler"
16056 elif descriptor
.isMaybeCrossOriginObject():
16057 parentClass
= "MaybeCrossOriginObject<mozilla::dom::DOMProxyHandler>"
16059 parentClass
= "mozilla::dom::DOMProxyHandler"
16064 bases
=[ClassBase(parentClass
)],
16065 constructors
=constructors
,
16070 class CGDOMJSProxyHandlerDeclarer(CGThing
):
16072 A class for declaring a DOMProxyHandler.
16075 def __init__(self
, handlerThing
):
16076 self
.handlerThing
= handlerThing
16079 # Our class declaration should happen when we're defining
16083 return self
.handlerThing
.declare()
16086 class CGDOMJSProxyHandlerDefiner(CGThing
):
16088 A class for defining a DOMProxyHandler.
16091 def __init__(self
, handlerThing
):
16092 self
.handlerThing
= handlerThing
16098 return self
.handlerThing
.define()
16101 def stripTrailingWhitespace(text
):
16102 tail
= "\n" if text
.endswith("\n") else ""
16103 lines
= text
.splitlines()
16104 return "\n".join(line
.rstrip() for line
in lines
) + tail
16107 class MemberProperties
:
16108 def __init__(self
):
16109 self
.isCrossOriginMethod
= False
16110 self
.isCrossOriginGetter
= False
16111 self
.isCrossOriginSetter
= False
16114 def memberProperties(m
, descriptor
):
16115 props
= MemberProperties()
16117 if not m
.isIdentifierLess() or m
== descriptor
.operations
["Stringifier"]:
16118 if not m
.isStatic() and descriptor
.interface
.hasInterfacePrototypeObject():
16119 if m
.getExtendedAttribute("CrossOriginCallable"):
16120 props
.isCrossOriginMethod
= True
16122 if not m
.isStatic() and descriptor
.interface
.hasInterfacePrototypeObject():
16123 if m
.getExtendedAttribute("CrossOriginReadable"):
16124 props
.isCrossOriginGetter
= True
16126 if not m
.isStatic() and descriptor
.interface
.hasInterfacePrototypeObject():
16127 if m
.getExtendedAttribute("CrossOriginWritable"):
16128 props
.isCrossOriginSetter
= True
16129 elif m
.getExtendedAttribute("PutForwards"):
16130 if m
.getExtendedAttribute("CrossOriginWritable"):
16131 props
.isCrossOriginSetter
= True
16132 elif m
.getExtendedAttribute("Replaceable") or m
.getExtendedAttribute(
16133 "LegacyLenientSetter"
16135 if m
.getExtendedAttribute("CrossOriginWritable"):
16136 props
.isCrossOriginSetter
= True
16141 class CGDescriptor(CGThing
):
16142 def __init__(self
, descriptor
):
16143 CGThing
.__init
__(self
)
16146 not descriptor
.concrete
16147 or descriptor
.interface
.hasInterfacePrototypeObject()
16150 self
._deps
= descriptor
.interface
.getDeps()
16154 CGGeneric(declare
="typedef %s NativeType;\n" % descriptor
.nativeType
)
16156 parent
= descriptor
.interface
.parent
16160 "static_assert(IsRefcounted<NativeType>::value == IsRefcounted<%s::NativeType>::value,\n"
16161 ' "Can\'t inherit from an interface with a different ownership model.");\n'
16162 % toBindingNamespace(descriptor
.parentPrototypeName
)
16166 defaultToJSONMethod
= None
16167 needCrossOriginPropertyArrays
= False
16168 unscopableNames
= list()
16169 for n
in descriptor
.interface
.legacyFactoryFunctions
:
16171 CGClassConstructor(descriptor
, n
, LegacyFactoryFunctionName(n
))
16173 for m
in descriptor
.interface
.members
:
16174 if m
.isMethod() and m
.identifier
.name
== "QueryInterface":
16177 props
= memberProperties(m
, descriptor
)
16180 if m
.getExtendedAttribute("Unscopable"):
16181 assert not m
.isStatic()
16182 unscopableNames
.append(m
.identifier
.name
)
16183 if m
.isDefaultToJSON():
16184 defaultToJSONMethod
= m
16186 not m
.isIdentifierLess()
16187 or m
== descriptor
.operations
["Stringifier"]
16190 assert descriptor
.interface
.hasInterfaceObject()
16191 cgThings
.append(CGStaticMethod(descriptor
, m
))
16192 if m
.returnsPromise():
16193 cgThings
.append(CGStaticMethodJitinfo(m
))
16194 elif descriptor
.interface
.hasInterfacePrototypeObject():
16195 specializedMethod
= CGSpecializedMethod(descriptor
, m
)
16196 cgThings
.append(specializedMethod
)
16197 if m
.returnsPromise():
16199 CGMethodPromiseWrapper(descriptor
, specializedMethod
)
16201 cgThings
.append(CGMemberJITInfo(descriptor
, m
))
16202 if props
.isCrossOriginMethod
:
16203 needCrossOriginPropertyArrays
= True
16204 # If we've hit the maplike/setlike member itself, go ahead and
16205 # generate its convenience functions.
16206 elif m
.isMaplikeOrSetlike():
16207 cgThings
.append(CGMaplikeOrSetlikeHelperGenerator(descriptor
, m
))
16209 if m
.getExtendedAttribute("Unscopable"):
16210 assert not m
.isStatic()
16211 unscopableNames
.append(m
.identifier
.name
)
16213 assert descriptor
.interface
.hasInterfaceObject()
16214 cgThings
.append(CGStaticGetter(descriptor
, m
))
16215 elif descriptor
.interface
.hasInterfacePrototypeObject():
16216 specializedGetter
= CGSpecializedGetter(descriptor
, m
)
16217 cgThings
.append(specializedGetter
)
16218 if m
.type.isPromise():
16220 CGGetterPromiseWrapper(descriptor
, specializedGetter
)
16222 if props
.isCrossOriginGetter
:
16223 needCrossOriginPropertyArrays
= True
16226 assert descriptor
.interface
.hasInterfaceObject()
16227 cgThings
.append(CGStaticSetter(descriptor
, m
))
16228 elif descriptor
.interface
.hasInterfacePrototypeObject():
16229 cgThings
.append(CGSpecializedSetter(descriptor
, m
))
16230 if props
.isCrossOriginSetter
:
16231 needCrossOriginPropertyArrays
= True
16232 elif m
.getExtendedAttribute("PutForwards"):
16233 cgThings
.append(CGSpecializedForwardingSetter(descriptor
, m
))
16234 if props
.isCrossOriginSetter
:
16235 needCrossOriginPropertyArrays
= True
16236 elif m
.getExtendedAttribute("Replaceable"):
16237 cgThings
.append(CGSpecializedReplaceableSetter(descriptor
, m
))
16238 elif m
.getExtendedAttribute("LegacyLenientSetter"):
16239 # XXX In this case, we need to add an include for mozilla/dom/Document.h to the generated cpp file.
16240 cgThings
.append(CGSpecializedLenientSetter(descriptor
, m
))
16243 and descriptor
.interface
.hasInterfacePrototypeObject()
16245 cgThings
.append(CGMemberJITInfo(descriptor
, m
))
16246 if m
.isConst() and m
.type.isPrimitive():
16247 cgThings
.append(CGConstDefinition(m
))
16249 if defaultToJSONMethod
:
16250 cgThings
.append(CGDefaultToJSONMethod(descriptor
, defaultToJSONMethod
))
16251 cgThings
.append(CGMemberJITInfo(descriptor
, defaultToJSONMethod
))
16253 if descriptor
.concrete
and not descriptor
.proxy
:
16254 if wantsAddProperty(descriptor
):
16255 cgThings
.append(CGAddPropertyHook(descriptor
))
16257 # Always have a finalize hook, regardless of whether the class
16258 # wants a custom hook.
16259 cgThings
.append(CGClassFinalizeHook(descriptor
))
16261 if wantsGetWrapperCache(descriptor
):
16262 cgThings
.append(CGGetWrapperCacheHook(descriptor
))
16264 if descriptor
.concrete
and descriptor
.wrapperCache
and not descriptor
.proxy
:
16265 cgThings
.append(CGClassObjectMovedHook(descriptor
))
16267 properties
= PropertyArrays(descriptor
)
16268 cgThings
.append(CGGeneric(define
=str(properties
)))
16269 cgThings
.append(CGNativeProperties(descriptor
, properties
))
16271 if defaultToJSONMethod
:
16272 # Now that we know about our property arrays, we can
16273 # output our "collect attribute values" method, which uses those.
16275 CGCollectJSONAttributesMethod(descriptor
, defaultToJSONMethod
)
16278 if descriptor
.interface
.hasInterfaceObject():
16279 cgThings
.append(CGClassConstructor(descriptor
, descriptor
.interface
.ctor()))
16280 cgThings
.append(CGInterfaceObjectJSClass(descriptor
, properties
))
16281 cgThings
.append(CGLegacyFactoryFunctions(descriptor
))
16283 cgThings
.append(CGLegacyCallHook(descriptor
))
16284 if descriptor
.interface
.getExtendedAttribute("NeedResolve"):
16285 cgThings
.append(CGResolveHook(descriptor
))
16286 cgThings
.append(CGMayResolveHook(descriptor
))
16287 cgThings
.append(CGEnumerateHook(descriptor
))
16289 if descriptor
.hasNamedPropertiesObject
:
16290 cgThings
.append(CGGetNamedPropertiesObjectMethod(descriptor
))
16292 if descriptor
.interface
.hasInterfacePrototypeObject():
16293 cgThings
.append(CGPrototypeJSClass(descriptor
, properties
))
16296 descriptor
.interface
.hasInterfaceObject()
16297 and not descriptor
.interface
.isExternal()
16298 and descriptor
.isExposedConditionally()
16300 cgThings
.append(CGConstructorEnabled(descriptor
))
16303 descriptor
.interface
.hasMembersInSlots()
16304 and descriptor
.interface
.hasChildInterfaces()
16307 "We don't support members in slots on "
16308 "non-leaf interfaces like %s" % descriptor
.interface
.identifier
.name
16311 if descriptor
.needsMissingPropUseCounters
:
16312 cgThings
.append(CGCountMaybeMissingProperty(descriptor
))
16314 if descriptor
.concrete
:
16315 if descriptor
.interface
.isSerializable():
16316 cgThings
.append(CGSerializer(descriptor
))
16317 cgThings
.append(CGDeserializer(descriptor
))
16319 if descriptor
.proxy
:
16324 static_assert(std::is_base_of_v<nsISupports, ${nativeType}>,
16325 "We don't support non-nsISupports native classes for "
16326 "proxy-based bindings yet");
16329 nativeType
=descriptor
.nativeType
,
16333 if not descriptor
.wrapperCache
:
16335 "We need a wrappercache to support expandos for proxy-based "
16336 "bindings (" + descriptor
.name
+ ")"
16338 handlerThing
= CGDOMJSProxyHandler(descriptor
)
16339 cgThings
.append(CGDOMJSProxyHandlerDeclarer(handlerThing
))
16340 cgThings
.append(CGProxyIsProxy(descriptor
))
16341 cgThings
.append(CGProxyUnwrap(descriptor
))
16342 cgThings
.append(CGDOMJSProxyHandlerDefiner(handlerThing
))
16343 cgThings
.append(CGDOMProxyJSClass(descriptor
))
16345 cgThings
.append(CGDOMJSClass(descriptor
))
16346 cgThings
.append(CGGetJSClassMethod(descriptor
))
16348 if descriptor
.interface
.hasMembersInSlots():
16349 cgThings
.append(CGUpdateMemberSlotsMethod(descriptor
))
16351 if descriptor
.isGlobal():
16352 assert descriptor
.wrapperCache
16353 cgThings
.append(CGWrapGlobalMethod(descriptor
, properties
))
16354 elif descriptor
.wrapperCache
:
16355 cgThings
.append(CGWrapWithCacheMethod(descriptor
, properties
))
16356 cgThings
.append(CGWrapMethod(descriptor
))
16358 cgThings
.append(CGWrapNonWrapperCacheMethod(descriptor
, properties
))
16360 # Set up our Xray callbacks as needed. This needs to come
16361 # after we have our DOMProxyHandler defined.
16362 if descriptor
.wantsXrays
:
16363 if descriptor
.concrete
and descriptor
.proxy
:
16364 if not descriptor
.isMaybeCrossOriginObject():
16365 cgThings
.append(CGResolveOwnProperty(descriptor
))
16366 cgThings
.append(CGEnumerateOwnProperties(descriptor
))
16367 if descriptor
.needsXrayNamedDeleterHook():
16368 cgThings
.append(CGDeleteNamedProperty(descriptor
))
16369 elif descriptor
.needsXrayResolveHooks():
16370 cgThings
.append(CGResolveOwnPropertyViaResolve(descriptor
))
16372 CGEnumerateOwnPropertiesViaGetOwnPropertyNames(descriptor
)
16374 if descriptor
.wantsXrayExpandoClass
:
16375 cgThings
.append(CGXrayExpandoJSClass(descriptor
))
16377 # Now that we have our ResolveOwnProperty/EnumerateOwnProperties stuff
16378 # done, set up our NativePropertyHooks.
16379 cgThings
.append(CGNativePropertyHooks(descriptor
, properties
))
16381 # If we're not wrappercached, we don't know how to clear our
16382 # cached values, since we can't get at the JSObject.
16383 if descriptor
.wrapperCache
:
16385 CGClearCachedValueMethod(descriptor
, m
)
16386 for m
in clearableCachedAttrs(descriptor
)
16389 haveUnscopables
= (
16390 len(unscopableNames
) != 0
16391 and descriptor
.interface
.hasInterfacePrototypeObject()
16393 if haveUnscopables
:
16397 CGGeneric("static const char* const unscopableNames[] = {"),
16400 [CGGeneric('"%s"' % name
) for name
in unscopableNames
]
16401 + [CGGeneric("nullptr")],
16411 legacyWindowAliases
= descriptor
.interface
.legacyWindowAliases
16412 haveLegacyWindowAliases
= len(legacyWindowAliases
) != 0
16413 if haveLegacyWindowAliases
:
16417 CGGeneric("static const char* const legacyWindowAliases[] = {"),
16421 CGGeneric('"%s"' % name
)
16422 for name
in legacyWindowAliases
16424 + [CGGeneric("nullptr")],
16434 # CGCreateInterfaceObjectsMethod needs to come after our
16435 # CGDOMJSClass and unscopables, if any.
16437 CGCreateInterfaceObjectsMethod(
16438 descriptor
, properties
, haveUnscopables
, haveLegacyWindowAliases
16442 # CGGetProtoObjectMethod and CGGetConstructorObjectMethod need
16443 # to come after CGCreateInterfaceObjectsMethod.
16444 if descriptor
.interface
.hasInterfacePrototypeObject():
16445 cgThings
.append(CGGetProtoObjectHandleMethod(descriptor
))
16446 if descriptor
.interface
.hasChildInterfaces():
16447 cgThings
.append(CGGetProtoObjectMethod(descriptor
))
16448 if descriptor
.interface
.hasInterfaceObject():
16449 cgThings
.append(CGGetConstructorObjectHandleMethod(descriptor
))
16450 cgThings
.append(CGGetConstructorObjectMethod(descriptor
))
16452 # See whether we need to generate cross-origin property arrays.
16453 if needCrossOriginPropertyArrays
:
16454 cgThings
.append(CGCrossOriginProperties(descriptor
))
16456 cgThings
= CGList((CGIndenter(t
, declareOnly
=True) for t
in cgThings
), "\n")
16457 cgThings
= CGWrapper(cgThings
, pre
="\n", post
="\n")
16458 self
.cgRoot
= CGWrapper(
16459 CGNamespace(toBindingNamespace(descriptor
.name
), cgThings
), post
="\n"
16463 return self
.cgRoot
.declare()
16466 return self
.cgRoot
.define()
16472 class CGNamespacedEnum(CGThing
):
16473 def __init__(self
, namespace
, enumName
, names
, values
, comment
=""):
16478 # Account for explicit enum values.
16480 for i
in range(0, len(names
)):
16481 if len(values
) > i
and values
[i
] is not None:
16482 entry
= "%s = %s" % (names
[i
], values
[i
])
16485 entries
.append(entry
)
16488 entries
.append("_" + enumName
+ "_Count")
16491 entries
= [" " + e
for e
in entries
]
16493 # Build the enum body.
16494 enumstr
= comment
+ "enum %s : uint16_t\n{\n%s\n};\n" % (
16496 ",\n".join(entries
),
16498 curr
= CGGeneric(declare
=enumstr
)
16500 # Add some whitespace padding.
16501 curr
= CGWrapper(curr
, pre
="\n", post
="\n")
16503 # Add the namespace.
16504 curr
= CGNamespace(namespace
, curr
)
16507 typedef
= "\ntypedef %s::%s %s;\n\n" % (namespace
, enumName
, enumName
)
16508 curr
= CGList([curr
, CGGeneric(declare
=typedef
)])
16514 return self
.node
.declare()
16520 def initIdsClassMethod(identifiers
, atomCacheName
):
16522 '!atomsCache->%s.init(cx, "%s")' % (CGDictionary
.makeIdName(id), id)
16523 for id in identifiers
16528 MOZ_ASSERT(JSID_IS_VOID(*reinterpret_cast<jsid*>(atomsCache)));
16530 // Initialize these in reverse order so that any failure leaves the first one
16537 idinit
=" ||\n ".join(idinit
),
16539 return ClassMethod(
16542 [Argument("JSContext*", "cx"), Argument("%s*" % atomCacheName
, "atomsCache")],
16545 visibility
="private",
16549 class CGDictionary(CGThing
):
16550 def __init__(self
, dictionary
, descriptorProvider
):
16551 self
.dictionary
= dictionary
16552 self
.descriptorProvider
= descriptorProvider
16553 self
.needToInitIds
= len(dictionary
.members
) > 0
16554 self
.memberInfo
= [
16557 getJSToNativeConversionInfo(
16559 descriptorProvider
,
16560 isMember
="Dictionary",
16561 isOptional
=member
.canHaveMissingValue(),
16562 isKnownMissing
=not dictionary
.needsConversionFromJS
,
16563 defaultValue
=member
.defaultValue
,
16564 sourceDescription
=self
.getMemberSourceDescription(member
),
16567 for member
in dictionary
.members
16570 # If we have a union member which is going to be declared in a different
16571 # header but contains something that will be declared in the same header
16572 # as us, bail: the C++ includes won't work out.
16573 for member
in dictionary
.members
:
16574 type = member
.type.unroll()
16575 if type.isUnion() and CGHeaders
.getUnionDeclarationFilename(
16576 descriptorProvider
.getConfig(), type
16577 ) != CGHeaders
.getDeclarationFilename(dictionary
):
16578 for t
in type.flatMemberTypes
:
16579 if t
.isDictionary() and CGHeaders
.getDeclarationFilename(
16581 ) == CGHeaders
.getDeclarationFilename(dictionary
):
16583 "Dictionary contains a union that will live in a different "
16584 "header that contains a dictionary from the same header as "
16585 "the original dictionary. This won't compile. Move the "
16586 "inner dictionary to a different Web IDL file to move it "
16587 "to a different header.\n%s\n%s"
16588 % (t
.location
, t
.inner
.location
)
16590 self
.structs
= self
.getStructs()
16593 return self
.structs
.declare()
16596 return self
.structs
.define()
16599 if self
.dictionary
.parent
:
16600 return self
.makeClassName(self
.dictionary
.parent
)
16601 return "DictionaryBase"
16603 def initMethod(self
):
16605 This function outputs the body of the Init() method for the dictionary.
16607 For the most part, this is some bookkeeping for our atoms so
16608 we can avoid atomizing strings all the time, then we just spit
16609 out the getMemberConversion() output for each member,
16610 separated by newlines.
16615 // Passing a null JSContext is OK only if we're initing from null,
16616 // Since in that case we will not have to do any property gets
16617 // Also evaluate isNullOrUndefined in order to avoid false-positive
16618 // checkers by static analysis tools
16619 MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined());
16623 if self
.needToInitIds
:
16626 ${dictName}Atoms* atomsCache = nullptr;
16628 atomsCache = GetAtomCache<${dictName}Atoms>(cx);
16629 if (JSID_IS_VOID(*reinterpret_cast<jsid*>(atomsCache)) &&
16630 !InitIds(cx, atomsCache)) {
16636 dictName
=self
.makeClassName(self
.dictionary
),
16639 if self
.dictionary
.parent
:
16642 // Per spec, we init the parent's members first
16643 if (!${dictName}::Init(cx, val)) {
16648 dictName
=self
.makeClassName(self
.dictionary
.parent
),
16653 if (!IsConvertibleToDictionary(val)) {
16654 return cx.ThrowErrorMessage<MSG_NOT_DICTIONARY>(sourceDescription);
16660 memberInits
= [self
.getMemberConversion(m
).define() for m
in self
.memberInfo
]
16664 bool isNull = val.isNullOrUndefined();
16665 // We only need these if !isNull, in which case we have |cx|.
16666 Maybe<JS::Rooted<JSObject *> > object;
16667 Maybe<JS::Rooted<JS::Value> > temp;
16670 object.emplace(cx, &val.toObject());
16675 memberInits
="\n".join(memberInits
),
16678 body
+= "return true;\n"
16680 return ClassMethod(
16684 Argument("BindingCallContext&", "cx"),
16685 Argument("JS::Handle<JS::Value>", "val"),
16686 Argument("const char*", "sourceDescription", default
='"Value"'),
16687 Argument("bool", "passedToJSImpl", default
="false"),
16692 def initWithoutCallContextMethod(self
):
16694 This function outputs the body of an Init() method for the dictionary
16695 that takes just a JSContext*. This is needed for non-binding consumers.
16699 // We don't want to use sourceDescription for our context here;
16700 // that's not really what it's formatted for.
16701 BindingCallContext cx(cx_, nullptr);
16702 return Init(cx, val, sourceDescription, passedToJSImpl);
16705 return ClassMethod(
16709 Argument("JSContext*", "cx_"),
16710 Argument("JS::Handle<JS::Value>", "val"),
16711 Argument("const char*", "sourceDescription", default
='"Value"'),
16712 Argument("bool", "passedToJSImpl", default
="false"),
16717 def simpleInitMethod(self
):
16719 This function outputs the body of the Init() method for the dictionary,
16720 for cases when we are just default-initializing it.
16723 relevantMembers
= [
16725 for m
in self
.memberInfo
16726 # We only need to init the things that can have
16728 if m
[0].optional
and m
[0].defaultValue
16731 # We mostly avoid outputting code that uses cx in our native-to-JS
16732 # conversions, but there is one exception: we may have a
16733 # dictionary-typed member that _does_ generally support conversion from
16734 # JS. If we have such a thing, we can pass it a null JSContext and
16735 # JS::NullHandleValue to default-initialize it, but since the
16736 # native-to-JS templates hardcode `cx` as the JSContext value, we're
16737 # going to need to provide that.
16738 haveMemberThatNeedsCx
= any(
16739 m
[0].type.isDictionary() and m
[0].type.unroll().inner
.needsConversionFromJS
16740 for m
in relevantMembers
16742 if haveMemberThatNeedsCx
:
16745 JSContext* cx = nullptr;
16751 if self
.dictionary
.parent
:
16752 if self
.dictionary
.parent
.needsConversionFromJS
:
16753 args
= "nullptr, JS::NullHandleValue"
16758 // We init the parent's members first
16759 if (!${dictName}::Init(${args})) {
16764 dictName
=self
.makeClassName(self
.dictionary
.parent
),
16769 self
.getMemberConversion(m
, isKnownMissing
=True).define()
16770 for m
in relevantMembers
16777 memberInits
="\n".join(memberInits
),
16780 body
+= "return true;\n"
16782 return ClassMethod(
16786 Argument("const char*", "sourceDescription", default
='"Value"'),
16787 Argument("bool", "passedToJSImpl", default
="false"),
16792 def initFromJSONMethod(self
):
16793 return ClassMethod(
16796 [Argument("const nsAString&", "aJSON")],
16800 JSObject* cleanGlobal = SimpleGlobalObject::Create(SimpleGlobalObject::GlobalType::BindingDetail);
16801 if (!cleanGlobal) {
16804 if (!jsapi.Init(cleanGlobal)) {
16807 JSContext* cx = jsapi.cx();
16808 JS::Rooted<JS::Value> json(cx);
16809 bool ok = ParseJSON(cx, aJSON, &json);
16810 NS_ENSURE_TRUE(ok, false);
16811 return Init(cx, json);
16816 def toJSONMethod(self
):
16817 return ClassMethod(
16820 [Argument("nsAString&", "aJSON")],
16825 JSContext *cx = jsapi.cx();
16826 // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here
16827 // because we'll only be creating objects, in ways that have no
16828 // side-effects, followed by a call to JS::ToJSONMaybeSafely,
16829 // which likewise guarantees no side-effects for the sorts of
16830 // things we will pass it.
16831 JSObject* scope = UnprivilegedJunkScopeOrWorkerGlobal(fallible);
16833 JS_ReportOutOfMemory(cx);
16836 JSAutoRealm ar(cx, scope);
16837 JS::Rooted<JS::Value> val(cx);
16838 if (!ToObjectInternal(cx, &val)) {
16841 JS::Rooted<JSObject*> obj(cx, &val.toObject());
16842 return StringifyToJSON(cx, obj, aJSON);
16848 def toObjectInternalMethod(self
):
16850 if self
.needToInitIds
:
16853 ${dictName}Atoms* atomsCache = GetAtomCache<${dictName}Atoms>(cx);
16854 if (JSID_IS_VOID(*reinterpret_cast<jsid*>(atomsCache)) &&
16855 !InitIds(cx, atomsCache)) {
16860 dictName
=self
.makeClassName(self
.dictionary
),
16863 if self
.dictionary
.parent
:
16866 // Per spec, we define the parent's members first
16867 if (!${dictName}::ToObjectInternal(cx, rval)) {
16870 JS::Rooted<JSObject*> obj(cx, &rval.toObject());
16873 dictName
=self
.makeClassName(self
.dictionary
.parent
),
16878 JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx));
16882 rval.set(JS::ObjectValue(*obj));
16887 if self
.memberInfo
:
16889 self
.getMemberDefinition(m
).define() for m
in self
.memberInfo
16891 body
+= "\nreturn true;\n"
16893 return ClassMethod(
16894 "ToObjectInternal",
16897 Argument("JSContext*", "cx"),
16898 Argument("JS::MutableHandle<JS::Value>", "rval"),
16904 def initIdsMethod(self
):
16905 assert self
.needToInitIds
16906 return initIdsClassMethod(
16907 [m
.identifier
.name
for m
in self
.dictionary
.members
],
16908 "%sAtoms" % self
.makeClassName(self
.dictionary
),
16911 def traceDictionaryMethod(self
):
16913 if self
.dictionary
.parent
:
16914 cls
= self
.makeClassName(self
.dictionary
.parent
)
16915 body
+= "%s::TraceDictionary(trc);\n" % cls
16918 self
.getMemberTrace(m
)
16919 for m
in self
.dictionary
.members
16920 if typeNeedsRooting(m
.type)
16924 body
+= "\n".join(memberTraces
)
16926 return ClassMethod(
16930 Argument("JSTracer*", "trc"),
16936 def dictionaryNeedsCycleCollection(dictionary
):
16937 return any(idlTypeNeedsCycleCollection(m
.type) for m
in dictionary
.members
) or (
16939 and CGDictionary
.dictionaryNeedsCycleCollection(dictionary
.parent
)
16942 def traverseForCCMethod(self
):
16944 if self
.dictionary
.parent
and self
.dictionaryNeedsCycleCollection(
16945 self
.dictionary
.parent
16947 cls
= self
.makeClassName(self
.dictionary
.parent
)
16948 body
+= "%s::TraverseForCC(aCallback, aFlags);\n" % cls
16950 for m
, _
in self
.memberInfo
:
16951 if idlTypeNeedsCycleCollection(m
.type):
16952 memberName
= self
.makeMemberName(m
.identifier
.name
)
16954 'ImplCycleCollectionTraverse(aCallback, %s, "%s", aFlags);\n'
16955 % (memberName
, memberName
)
16958 return ClassMethod(
16962 Argument("nsCycleCollectionTraversalCallback&", "aCallback"),
16963 Argument("uint32_t", "aFlags"),
16966 # Inline so we don't pay a codesize hit unless someone actually uses
16967 # this traverse method.
16972 def unlinkForCCMethod(self
):
16974 if self
.dictionary
.parent
and self
.dictionaryNeedsCycleCollection(
16975 self
.dictionary
.parent
16977 cls
= self
.makeClassName(self
.dictionary
.parent
)
16978 body
+= "%s::UnlinkForCC();\n" % cls
16980 for m
, _
in self
.memberInfo
:
16981 if idlTypeNeedsCycleCollection(m
.type):
16982 memberName
= self
.makeMemberName(m
.identifier
.name
)
16983 body
+= "ImplCycleCollectionUnlink(%s);\n" % memberName
16985 return ClassMethod(
16990 # Inline so we don't pay a codesize hit unless someone actually uses
16991 # this unlink method.
16996 def assignmentOperator(self
):
16998 body
.append(CGGeneric("%s::operator=(aOther);\n" % self
.base()))
17000 for m
, _
in self
.memberInfo
:
17001 memberName
= self
.makeMemberName(m
.identifier
.name
)
17002 if m
.canHaveMissingValue():
17003 memberAssign
= CGGeneric(
17007 if (aOther.${name}.WasPassed()) {
17008 ${name}.Construct(aOther.${name}.Value());
17015 memberAssign
= CGGeneric("%s = aOther.%s;\n" % (memberName
, memberName
))
17016 body
.append(memberAssign
)
17017 body
.append(CGGeneric("return *this;\n"))
17018 return ClassMethod(
17020 "%s&" % self
.makeClassName(self
.dictionary
),
17021 [Argument("const %s&" % self
.makeClassName(self
.dictionary
), "aOther")],
17022 body
=body
.define(),
17025 def canHaveEqualsOperator(self
):
17027 m
.type.isString() or m
.type.isPrimitive() for (m
, _
) in self
.memberInfo
17030 def equalsOperator(self
):
17033 for m
, _
in self
.memberInfo
:
17034 memberName
= self
.makeMemberName(m
.identifier
.name
)
17035 memberTest
= CGGeneric(
17038 if (${memberName} != aOther.${memberName}) {
17042 memberName
=memberName
,
17045 body
.append(memberTest
)
17046 body
.append(CGGeneric("return true;\n"))
17047 return ClassMethod(
17050 [Argument("const %s&" % self
.makeClassName(self
.dictionary
), "aOther")],
17052 body
=body
.define(),
17055 def getStructs(self
):
17056 d
= self
.dictionary
17057 selfName
= self
.makeClassName(d
)
17060 self
.makeMemberName(m
[0].identifier
.name
),
17061 self
.getMemberType(m
),
17062 visibility
="public",
17063 body
=self
.getMemberInitializer(m
),
17064 hasIgnoreInitCheckFlag
=True,
17066 for m
in self
.memberInfo
17069 # We always want to init our parent with our non-initializing
17070 # constructor arg, because either we're about to init ourselves (and
17071 # hence our parent) or we don't want any init happening.
17072 baseConstructors
= [
17074 % (self
.makeClassName(d
.parent
), self
.getNonInitializingCtorArg())
17077 baseConstructors
= None
17079 if d
.needsConversionFromJS
:
17080 initArgs
= "nullptr, JS::NullHandleValue"
17086 visibility
="public",
17087 baseConstructors
=baseConstructors
,
17089 "// Safe to pass a null context if we pass a null value\n"
17090 "Init(%s);\n" % initArgs
17094 [Argument("const FastDictionaryInitializer&", "")],
17095 visibility
="public",
17096 baseConstructors
=baseConstructors
,
17099 body
='// Do nothing here; this is used by our "Fast" subclass\n',
17104 if self
.needToInitIds
:
17105 methods
.append(self
.initIdsMethod())
17107 if d
.needsConversionFromJS
:
17108 methods
.append(self
.initMethod())
17109 methods
.append(self
.initWithoutCallContextMethod())
17111 methods
.append(self
.simpleInitMethod())
17113 canBeRepresentedAsJSON
= self
.dictionarySafeToJSONify(d
)
17114 if canBeRepresentedAsJSON
and d
.getExtendedAttribute("GenerateInitFromJSON"):
17115 methods
.append(self
.initFromJSONMethod())
17117 if d
.needsConversionToJS
:
17118 methods
.append(self
.toObjectInternalMethod())
17120 if canBeRepresentedAsJSON
and d
.getExtendedAttribute("GenerateToJSON"):
17121 methods
.append(self
.toJSONMethod())
17123 methods
.append(self
.traceDictionaryMethod())
17126 if self
.dictionaryNeedsCycleCollection(d
):
17127 methods
.append(self
.traverseForCCMethod())
17128 methods
.append(self
.unlinkForCCMethod())
17129 except CycleCollectionUnsupported
:
17130 # We have some member that we don't know how to CC. Don't output
17131 # our cycle collection overloads, so attempts to CC us will fail to
17132 # compile instead of misbehaving.
17135 if CGDictionary
.isDictionaryCopyConstructible(d
):
17136 disallowCopyConstruction
= False
17137 # Note: gcc's -Wextra has a warning against not initializng our
17138 # base explicitly. If we have one. Use our non-initializing base
17139 # constructor to get around that.
17142 [Argument("const %s&" % selfName
, "aOther")],
17144 visibility
="public",
17145 baseConstructors
=baseConstructors
,
17147 body
="*this = aOther;\n",
17150 methods
.append(self
.assignmentOperator())
17152 disallowCopyConstruction
= True
17154 if self
.canHaveEqualsOperator():
17155 methods
.append(self
.equalsOperator())
17159 bases
=[ClassBase(self
.base())],
17161 constructors
=ctors
,
17164 disallowCopyConstruction
=disallowCopyConstruction
,
17167 fastDictionaryCtor
= ClassConstructor(
17169 visibility
="public",
17171 baseConstructors
=["%s(%s)" % (selfName
, self
.getNonInitializingCtorArg())],
17172 body
="// Doesn't matter what int we pass to the parent constructor\n",
17175 fastStruct
= CGClass(
17177 bases
=[ClassBase(selfName
)],
17178 constructors
=[fastDictionaryCtor
],
17182 return CGList([struct
, CGNamespace("binding_detail", fastStruct
)], "\n")
17185 return self
.dictionary
.getDeps()
17188 def makeDictionaryName(dictionary
):
17189 return dictionary
.identifier
.name
17191 def makeClassName(self
, dictionary
):
17192 return self
.makeDictionaryName(dictionary
)
17195 def makeMemberName(name
):
17196 return "m" + name
[0].upper() + IDLToCIdentifier(name
[1:])
17198 def getMemberType(self
, memberInfo
):
17199 _
, conversionInfo
= memberInfo
17200 # We can't handle having a holderType here
17201 assert conversionInfo
.holderType
is None
17202 declType
= conversionInfo
.declType
17203 if conversionInfo
.dealWithOptional
:
17204 declType
= CGTemplatedType("Optional", declType
)
17205 return declType
.define()
17207 def getMemberConversion(self
, memberInfo
, isKnownMissing
=False):
17209 A function that outputs the initialization of a single dictionary
17210 member from the given dictionary value.
17212 We start with our conversionInfo, which tells us how to
17213 convert a JS::Value to whatever type this member is. We
17214 substiture the template from the conversionInfo with values
17215 that point to our "temp" JS::Value and our member (which is
17216 the C++ value we want to produce). The output is a string of
17217 code to do the conversion. We store this string in
17218 conversionReplacements["convert"].
17220 Now we have three different ways we might use (or skip) this
17221 string of code, depending on whether the value is required,
17222 optional with default value, or optional without default
17223 value. We set up a template in the 'conversion' variable for
17224 exactly how to do this, then substitute into it from the
17225 conversionReplacements dictionary.
17227 member
, conversionInfo
= memberInfo
17229 # We should only be initializing things with default values if
17230 # we're always-missing.
17231 assert not isKnownMissing
or (member
.optional
and member
.defaultValue
)
17234 "declName": self
.makeMemberName(member
.identifier
.name
),
17235 # We need a holder name for external interfaces, but
17236 # it's scoped down to the conversion so we can just use
17237 # anything we want.
17238 "holderName": "holder",
17239 "passedToJSImpl": "passedToJSImpl",
17243 replacements
["val"] = "(JS::NullHandleValue)"
17245 replacements
["val"] = "temp.ref()"
17246 replacements
["maybeMutableVal"] = "temp.ptr()"
17248 # We can't handle having a holderType here
17249 assert conversionInfo
.holderType
is None
17250 if conversionInfo
.dealWithOptional
:
17251 replacements
["declName"] = "(" + replacements
["declName"] + ".Value())"
17252 if member
.defaultValue
:
17254 replacements
["haveValue"] = "false"
17256 replacements
["haveValue"] = "!isNull && !temp->isUndefined()"
17258 propId
= self
.makeIdName(member
.identifier
.name
)
17259 propGet
= "JS_GetPropertyById(cx, *object, atomsCache->%s, temp.ptr())" % propId
17261 conversionReplacements
= {
17262 "prop": self
.makeMemberName(member
.identifier
.name
),
17263 "convert": string
.Template(conversionInfo
.template
).substitute(
17266 "propGet": propGet
,
17268 # The conversion code will only run where a default value or a value passed
17269 # by the author needs to get converted, so we can remember if we have any
17270 # members present here.
17271 conversionReplacements
["convert"] += "mIsAnyMemberPresent = true;\n"
17275 setTempValue
= CGGeneric(
17284 conditions
= getConditionList(member
, "cx", "*object")
17285 if len(conditions
) != 0:
17286 setTempValue
= CGIfElseWrapper(
17287 conditions
.define(),
17289 CGGeneric("temp->setUndefined();\n"),
17291 setTempValue
= CGIfWrapper(setTempValue
, "!isNull")
17292 conversion
= setTempValue
.define()
17294 if member
.defaultValue
:
17295 if member
.type.isUnion() and (
17296 not member
.type.nullable()
17297 or not isinstance(member
.defaultValue
, IDLNullValue
)
17299 # Since this has a default value, it might have been initialized
17300 # already. Go ahead and uninit it before we try to init it
17302 memberName
= self
.makeMemberName(member
.identifier
.name
)
17303 if member
.type.nullable():
17304 conversion
+= fill(
17306 if (!${memberName}.IsNull()) {
17307 ${memberName}.Value().Uninit();
17310 memberName
=memberName
,
17313 conversion
+= "%s.Uninit();\n" % memberName
17314 conversion
+= "${convert}"
17315 elif not conversionInfo
.dealWithOptional
:
17316 # We're required, but have no default value. Make sure
17317 # that we throw if we have no value provided.
17318 conversion
+= dedent(
17320 if (!isNull && !temp->isUndefined()) {
17323 // Don't error out if we have no cx. In that
17324 // situation the caller is default-constructing us and we'll
17325 // just assume they know what they're doing.
17326 return cx.ThrowErrorMessage<MSG_MISSING_REQUIRED_DICTIONARY_MEMBER>("%s");
17329 % self
.getMemberSourceDescription(member
)
17331 conversionReplacements
["convert"] = indent(
17332 conversionReplacements
["convert"]
17336 "if (!isNull && !temp->isUndefined()) {\n"
17337 " ${prop}.Construct();\n"
17341 conversionReplacements
["convert"] = indent(
17342 conversionReplacements
["convert"]
17345 return CGGeneric(string
.Template(conversion
).substitute(conversionReplacements
))
17347 def getMemberDefinition(self
, memberInfo
):
17348 member
= memberInfo
[0]
17349 declType
= memberInfo
[1].declType
17350 memberLoc
= self
.makeMemberName(member
.identifier
.name
)
17351 if not member
.canHaveMissingValue():
17352 memberData
= memberLoc
17354 # The data is inside the Optional<>
17355 memberData
= "%s.InternalValue()" % memberLoc
17357 # If you have to change this list (which you shouldn't!), make sure it
17358 # continues to match the list in test_Object.prototype_props.html
17359 if member
.identifier
.name
in [
17366 "propertyIsEnumerable",
17367 "__defineGetter__",
17368 "__defineSetter__",
17369 "__lookupGetter__",
17370 "__lookupSetter__",
17374 "'%s' member of %s dictionary shadows "
17375 "a property of Object.prototype, and Xrays to "
17376 "Object can't handle that.\n"
17379 member
.identifier
.name
,
17380 self
.dictionary
.identifier
.name
,
17386 "JS_DefinePropertyById(cx, obj, atomsCache->%s, temp, JSPROP_ENUMERATE)"
17387 % self
.makeIdName(member
.identifier
.name
)
17390 innerTemplate
= wrapForType(
17392 self
.descriptorProvider
,
17394 "result": "currentValue",
17396 "if (!%s) {\n" " return false;\n" "}\n" "break;\n" % propDef
17398 "jsvalRef": "temp",
17399 "jsvalHandle": "&temp",
17400 "returnsNewObject": False,
17401 # 'obj' can just be allowed to be the string "obj", since that
17402 # will be our dictionary object, which is presumably itself in
17404 "spiderMonkeyInterfacesAreStructs": True,
17407 conversion
= CGGeneric(innerTemplate
)
17408 conversion
= CGWrapper(
17411 "JS::Rooted<JS::Value> temp(cx);\n"
17412 "%s const & currentValue = %s;\n" % (declType
.define(), memberData
)
17416 # Now make sure that our successCode can actually break out of the
17417 # conversion. This incidentally gives us a scope for 'temp' and
17419 conversion
= CGWrapper(
17420 CGIndenter(conversion
),
17423 " // block for our 'break' successCode and scope for 'temp' and 'currentValue'\n"
17425 post
="} while(false);\n",
17427 if member
.canHaveMissingValue():
17428 # Only do the conversion if we have a value
17429 conversion
= CGIfWrapper(conversion
, "%s.WasPassed()" % memberLoc
)
17430 conditions
= getConditionList(member
, "cx", "obj")
17431 if len(conditions
) != 0:
17432 conversion
= CGIfWrapper(conversion
, conditions
.define())
17435 def getMemberTrace(self
, member
):
17437 assert typeNeedsRooting(type)
17438 memberLoc
= self
.makeMemberName(member
.identifier
.name
)
17439 if not member
.canHaveMissingValue():
17440 memberData
= memberLoc
17442 # The data is inside the Optional<>
17443 memberData
= "%s.Value()" % memberLoc
17445 memberName
= "%s.%s" % (self
.makeClassName(self
.dictionary
), memberLoc
)
17447 if type.isObject():
17449 'JS::UnsafeTraceRoot(trc, %s, "%s");\n' % ("&" + memberData
, memberName
)
17451 if type.nullable():
17452 trace
= CGIfWrapper(trace
, memberData
)
17455 'JS::UnsafeTraceRoot(trc, %s, "%s");\n' % ("&" + memberData
, memberName
)
17459 or type.isDictionary()
17460 or type.isSpiderMonkeyInterface()
17464 if type.nullable():
17465 memberNullable
= memberData
17466 memberData
= "%s.Value()" % memberData
17467 if type.isSequence():
17468 trace
= CGGeneric("DoTraceSequence(trc, %s);\n" % memberData
)
17469 elif type.isDictionary():
17470 trace
= CGGeneric("%s.TraceDictionary(trc);\n" % memberData
)
17471 elif type.isUnion():
17472 trace
= CGGeneric("%s.TraceUnion(trc);\n" % memberData
)
17473 elif type.isRecord():
17474 trace
= CGGeneric("TraceRecord(trc, %s);\n" % memberData
)
17476 assert type.isSpiderMonkeyInterface()
17477 trace
= CGGeneric("%s.TraceSelf(trc);\n" % memberData
)
17478 if type.nullable():
17479 trace
= CGIfWrapper(trace
, "!%s.IsNull()" % memberNullable
)
17481 assert False # unknown type
17483 if member
.canHaveMissingValue():
17484 trace
= CGIfWrapper(trace
, "%s.WasPassed()" % memberLoc
)
17486 return trace
.define()
17488 def getMemberInitializer(self
, memberInfo
):
17490 Get the right initializer for the member. Most members don't need one,
17491 but we need to pre-initialize 'object' that have a default value or are
17492 required (and hence are not inside Optional), so they're safe to trace
17493 at all times. And we can optimize a bit for dictionary-typed members.
17495 member
, _
= memberInfo
17496 if member
.canHaveMissingValue():
17497 # Allowed missing value means no need to set it up front, since it's
17498 # inside an Optional and won't get traced until it's actually set
17502 if type.isDictionary():
17503 # When we construct ourselves, we don't want to init our member
17504 # dictionaries. Either we're being constructed-but-not-initialized
17505 # ourselves (and then we don't want to init them) or we're about to
17506 # init ourselves and then we'll init them anyway.
17507 return CGDictionary
.getNonInitializingCtorArg()
17508 return initializerForType(type)
17510 def getMemberSourceDescription(self
, member
):
17511 return "'%s' member of %s" % (
17512 member
.identifier
.name
,
17513 self
.dictionary
.identifier
.name
,
17517 def makeIdName(name
):
17518 return IDLToCIdentifier(name
) + "_id"
17521 def getNonInitializingCtorArg():
17522 return "FastDictionaryInitializer()"
17525 def isDictionaryCopyConstructible(dictionary
):
17526 if dictionary
.parent
and not CGDictionary
.isDictionaryCopyConstructible(
17530 return all(isTypeCopyConstructible(m
.type) for m
in dictionary
.members
)
17533 def typeSafeToJSONify(type):
17535 Determine whether the given type is safe to convert to JSON. The
17536 restriction is that this needs to be safe while in a global controlled
17537 by an adversary, and "safe" means no side-effects when the JS
17538 representation of this type is converted to JSON. That means that we
17539 have to be pretty restrictive about what things we can allow. For
17540 example, "object" is out, because it may have accessor properties on it.
17542 if type.nullable():
17543 # Converting null to JSON is always OK.
17544 return CGDictionary
.typeSafeToJSONify(type.inner
)
17546 if type.isSequence():
17547 # Sequences are arrays we create ourselves, with no holes. They
17548 # should be safe if their contents are safe, as long as we suppress
17549 # invocation of .toJSON on objects.
17550 return CGDictionary
.typeSafeToJSONify(type.inner
)
17553 # OK if everything in it is ok.
17554 return all(CGDictionary
.typeSafeToJSONify(t
) for t
in type.flatMemberTypes
)
17556 if type.isDictionary():
17557 # OK if the dictionary is OK
17558 return CGDictionary
.dictionarySafeToJSONify(type.inner
)
17560 if type.isString() or type.isEnum():
17561 # Strings are always OK.
17564 if type.isPrimitive():
17565 # Primitives (numbers and booleans) are ok, as long as
17566 # they're not unrestricted float/double.
17567 return not type.isFloat() or not type.isUnrestricted()
17569 if type.isRecord():
17570 # Records are okay, as long as the value type is.
17571 # Per spec, only strings are allowed as keys.
17572 return CGDictionary
.typeSafeToJSONify(type.inner
)
17577 def dictionarySafeToJSONify(dictionary
):
17578 # The dictionary itself is OK, so we're good if all our types are.
17579 return all(CGDictionary
.typeSafeToJSONify(m
.type) for m
in dictionary
.members
)
17582 class CGRegisterWorkerBindings(CGAbstractMethod
):
17583 def __init__(self
, config
):
17584 CGAbstractMethod
.__init
__(
17587 "RegisterWorkerBindings",
17589 [Argument("JSContext*", "aCx"), Argument("JS::Handle<JSObject*>", "aObj")],
17591 self
.config
= config
17593 def definition_body(self
):
17594 descriptors
= self
.config
.getDescriptors(
17595 hasInterfaceObject
=True, isExposedInAnyWorker
=True, register
=True
17598 for desc
in descriptors
:
17599 bindingNS
= toBindingNamespace(desc
.name
)
17600 condition
= "!%s::GetConstructorObject(aCx)" % bindingNS
17601 if desc
.isExposedConditionally():
17603 "%s::ConstructorEnabled(aCx, aObj) && " % bindingNS
+ condition
17605 conditions
.append(condition
)
17607 CGIfWrapper(CGGeneric("return false;\n"), condition
)
17608 for condition
in conditions
17610 lines
.append(CGGeneric("return true;\n"))
17611 return CGList(lines
, "\n").define()
17614 class CGRegisterWorkerDebuggerBindings(CGAbstractMethod
):
17615 def __init__(self
, config
):
17616 CGAbstractMethod
.__init
__(
17619 "RegisterWorkerDebuggerBindings",
17621 [Argument("JSContext*", "aCx"), Argument("JS::Handle<JSObject*>", "aObj")],
17623 self
.config
= config
17625 def definition_body(self
):
17626 descriptors
= self
.config
.getDescriptors(
17627 hasInterfaceObject
=True, isExposedInWorkerDebugger
=True, register
=True
17630 for desc
in descriptors
:
17631 bindingNS
= toBindingNamespace(desc
.name
)
17632 condition
= "!%s::GetConstructorObject(aCx)" % bindingNS
17633 if desc
.isExposedConditionally():
17635 "%s::ConstructorEnabled(aCx, aObj) && " % bindingNS
+ condition
17637 conditions
.append(condition
)
17639 CGIfWrapper(CGGeneric("return false;\n"), condition
)
17640 for condition
in conditions
17642 lines
.append(CGGeneric("return true;\n"))
17643 return CGList(lines
, "\n").define()
17646 class CGRegisterWorkletBindings(CGAbstractMethod
):
17647 def __init__(self
, config
):
17648 CGAbstractMethod
.__init
__(
17651 "RegisterWorkletBindings",
17653 [Argument("JSContext*", "aCx"), Argument("JS::Handle<JSObject*>", "aObj")],
17655 self
.config
= config
17657 def definition_body(self
):
17658 descriptors
= self
.config
.getDescriptors(
17659 hasInterfaceObject
=True, isExposedInAnyWorklet
=True, register
=True
17662 for desc
in descriptors
:
17663 bindingNS
= toBindingNamespace(desc
.name
)
17664 condition
= "!%s::GetConstructorObject(aCx)" % bindingNS
17665 if desc
.isExposedConditionally():
17667 "%s::ConstructorEnabled(aCx, aObj) && " % bindingNS
+ condition
17669 conditions
.append(condition
)
17671 CGIfWrapper(CGGeneric("return false;\n"), condition
)
17672 for condition
in conditions
17674 lines
.append(CGGeneric("return true;\n"))
17675 return CGList(lines
, "\n").define()
17678 def getGlobalNames(config
):
17680 for desc
in config
.getDescriptors(registersGlobalNamesOnWindow
=True):
17681 names
.append((desc
.name
, desc
))
17683 (n
.identifier
.name
, desc
) for n
in desc
.interface
.legacyFactoryFunctions
17685 names
.extend((n
, desc
) for n
in desc
.interface
.legacyWindowAliases
)
17689 class CGGlobalNames(CGGeneric
):
17690 def __init__(self
, config
):
17694 for name
, desc
in getGlobalNames(config
):
17695 # Add a string to the list.
17696 offset
= currentOffset
17697 strings
.append('/* %i */ "%s\\0"' % (offset
, name
))
17698 currentOffset
+= len(name
) + 1 # Add trailing null.
17700 # Generate the entry declaration
17701 # XXX(nika): mCreate & mEnabled require relocations. If we want to
17702 # reduce those, we could move them into separate tables.
17703 nativeEntry
= fill(
17706 /* mNameOffset */ ${nameOffset}, // "${name}"
17707 /* mNameLength */ ${nameLength},
17708 /* mConstructorId */ constructors::id::${realname},
17709 /* mCreate */ ${realname}_Binding::CreateInterfaceObjects,
17710 /* mEnabled */ ${enabled}
17714 nameLength
=len(name
),
17716 realname
=desc
.name
,
17718 "%s_Binding::ConstructorEnabled" % desc
.name
17719 if desc
.isExposedConditionally()
17724 entries
.append((name
, nativeEntry
))
17726 # Unfortunately, when running tests, we may have no entries.
17727 # PerfectHash will assert if we give it an empty set of entries, so we
17728 # just generate a dummy value.
17729 if len(entries
) == 0:
17730 CGGeneric
.__init
__(
17734 static_assert(false, "No WebIDL global name entries!");
17740 # Build the perfect hash function.
17741 phf
= PerfectHash(entries
, GLOBAL_NAMES_PHF_SIZE
)
17743 # Generate code for the PHF
17744 phfCodegen
= phf
.codegen(
17745 "WebIDLGlobalNameHash::sEntries", "WebIDLNameTableEntry"
17747 entries
= phfCodegen
.gen_entries(lambda e
: e
[1])
17748 getter
= phfCodegen
.gen_jslinearstr_getter(
17749 name
="WebIDLGlobalNameHash::GetEntry",
17750 return_type
="const WebIDLNameTableEntry*",
17751 return_entry
=dedent(
17753 if (JS_LinearStringEqualsAscii(aKey, sNames + entry.mNameOffset, entry.mNameLength)) {
17763 const uint32_t WebIDLGlobalNameHash::sCount = ${count};
17765 const char WebIDLGlobalNameHash::sNames[] =
17773 count
=len(phf
.entries
),
17774 strings
="\n".join(strings
) + ";\n",
17778 CGGeneric
.__init
__(self
, define
=define
)
17781 def dependencySortObjects(objects
, dependencyGetter
, nameGetter
):
17783 Sort IDL objects with dependencies on each other such that if A
17784 depends on B then B will come before A. This is needed for
17785 declaring C++ classes in the right order, for example. Objects
17786 that have no dependencies are just sorted by name.
17788 objects should be something that can produce a set of objects
17789 (e.g. a set, iterator, list, etc).
17791 dependencyGetter is something that, given an object, should return
17792 the set of objects it depends on.
17794 # XXXbz this will fail if we have two webidl files F1 and F2 such that F1
17795 # declares an object which depends on an object in F2, and F2 declares an
17796 # object (possibly a different one!) that depends on an object in F1. The
17797 # good news is that I expect this to never happen.
17799 objects
= set(objects
)
17800 while len(objects
) != 0:
17801 # Find the dictionaries that don't depend on anything else
17802 # anymore and move them over.
17803 toMove
= [o
for o
in objects
if len(dependencyGetter(o
) & objects
) == 0]
17804 if len(toMove
) == 0:
17806 "Loop in dependency graph\n" + "\n".join(o
.location
for o
in objects
)
17808 objects
= objects
- set(toMove
)
17809 sortedObjects
.extend(sorted(toMove
, key
=nameGetter
))
17810 return sortedObjects
17813 class ForwardDeclarationBuilder
:
17815 Create a canonical representation of a set of namespaced forward
17819 def __init__(self
):
17821 The set of declarations is represented as a tree of nested namespaces.
17822 Each tree node has a set of declarations |decls| and a dict |children|.
17823 Each declaration is a pair consisting of the class name and a boolean
17824 that is true iff the class is really a struct. |children| maps the
17825 names of inner namespaces to the declarations in that namespace.
17830 def _ensureNonTemplateType(self
, type):
17832 # This is a templated type. We don't really know how to
17833 # forward-declare those, and trying to do it naively is not going to
17834 # go well (e.g. we may have :: characters inside the type we're
17835 # templated on!). Just bail out.
17837 "Attempt to use ForwardDeclarationBuilder on "
17838 "templated type %s. We don't know how to do that "
17842 def _listAdd(self
, namespaces
, name
, isStruct
=False):
17844 Add a forward declaration, where |namespaces| is a list of namespaces.
17845 |name| should not contain any other namespaces.
17848 child
= self
.children
.setdefault(namespaces
[0], ForwardDeclarationBuilder())
17849 child
._listAdd
(namespaces
[1:], name
, isStruct
)
17851 assert "::" not in name
17852 self
.decls
.add((name
, isStruct
))
17854 def addInMozillaDom(self
, name
, isStruct
=False):
17856 Add a forward declaration to the mozilla::dom:: namespace. |name| should not
17857 contain any other namespaces.
17859 self
._ensureNonTemplateType
(name
)
17860 self
._listAdd
(["mozilla", "dom"], name
, isStruct
)
17862 def add(self
, nativeType
, isStruct
=False):
17864 Add a forward declaration, where |nativeType| is a string containing
17865 the type and its namespaces, in the usual C++ way.
17867 self
._ensureNonTemplateType
(nativeType
)
17868 components
= nativeType
.split("::")
17869 self
._listAdd
(components
[:-1], components
[-1], isStruct
)
17871 def _build(self
, atTopLevel
):
17873 Return a codegenerator for the forward declarations.
17880 CGClassForwardDeclare(cname
, isStruct
)
17881 for cname
, isStruct
in sorted(self
.decls
)
17885 for namespace
, child
in sorted(six
.iteritems(self
.children
)):
17887 CGNamespace(namespace
, child
._build
(atTopLevel
=False), declareOnly
=True)
17890 cg
= CGList(decls
, "\n")
17891 if not atTopLevel
and len(decls
) + len(self
.decls
) > 1:
17892 cg
= CGWrapper(cg
, pre
="\n", post
="\n")
17896 return self
._build
(atTopLevel
=True)
17898 def forwardDeclareForType(self
, t
, config
):
17900 if t
.isGeckoInterface():
17901 name
= t
.inner
.identifier
.name
17903 desc
= config
.getDescriptor(name
)
17904 self
.add(desc
.nativeType
)
17905 except NoSuchDescriptorError
:
17908 # Note: SpiderMonkey interfaces are typedefs, so can't be
17910 elif t
.isPromise():
17911 self
.addInMozillaDom("Promise")
17912 elif t
.isCallback():
17913 self
.addInMozillaDom(t
.callback
.identifier
.name
)
17914 elif t
.isDictionary():
17915 self
.addInMozillaDom(t
.inner
.identifier
.name
, isStruct
=True)
17916 elif t
.isCallbackInterface():
17917 self
.addInMozillaDom(t
.inner
.identifier
.name
)
17919 # Forward declare both the owning and non-owning version,
17920 # since we don't know which one we might want
17921 self
.addInMozillaDom(CGUnionStruct
.unionTypeName(t
, False))
17922 self
.addInMozillaDom(CGUnionStruct
.unionTypeName(t
, True))
17924 self
.forwardDeclareForType(t
.inner
, config
)
17925 # Don't need to do anything for void, primitive, string, any or object.
17926 # There may be some other cases we are missing.
17929 class CGForwardDeclarations(CGWrapper
):
17931 Code generate the forward declarations for a header file.
17932 additionalDeclarations is a list of tuples containing a classname and a
17933 boolean. If the boolean is true we will declare a struct, otherwise we'll
17943 callbackInterfaces
,
17944 additionalDeclarations
=[],
17946 builder
= ForwardDeclarationBuilder()
17948 # Needed for at least Wrap.
17949 for d
in descriptors
:
17950 # If this is a generated iterator interface, we only create these
17951 # in the generated bindings, and don't need to forward declare.
17952 if d
.interface
.isIteratorInterface():
17954 builder
.add(d
.nativeType
)
17955 if d
.interface
.isSerializable():
17956 builder
.add("nsIGlobalObject")
17957 # If we're an interface and we have a maplike/setlike declaration,
17958 # we'll have helper functions exposed to the native side of our
17959 # bindings, which will need to show up in the header. If either of
17960 # our key/value types are interfaces, they'll be passed as
17961 # arguments to helper functions, and they'll need to be forward
17962 # declared in the header.
17963 if d
.interface
.maplikeOrSetlikeOrIterable
:
17964 if d
.interface
.maplikeOrSetlikeOrIterable
.hasKeyType():
17965 builder
.forwardDeclareForType(
17966 d
.interface
.maplikeOrSetlikeOrIterable
.keyType
, config
17968 if d
.interface
.maplikeOrSetlikeOrIterable
.hasValueType():
17969 builder
.forwardDeclareForType(
17970 d
.interface
.maplikeOrSetlikeOrIterable
.valueType
, config
17973 # We just about always need NativePropertyHooks
17974 builder
.addInMozillaDom("NativePropertyHooks", isStruct
=True)
17975 builder
.addInMozillaDom("ProtoAndIfaceCache")
17976 # Add the atoms cache type, even if we don't need it.
17977 for d
in descriptors
:
17978 # Iterators have native types that are template classes, so
17979 # creating an 'Atoms' cache type doesn't work for them, and is one
17980 # of the cases where we don't need it anyways.
17981 if d
.interface
.isIteratorInterface():
17983 builder
.add(d
.nativeType
+ "Atoms", isStruct
=True)
17985 for callback
in callbacks
:
17986 builder
.addInMozillaDom(callback
.identifier
.name
)
17987 for t
in getTypesFromCallback(callback
):
17988 builder
.forwardDeclareForType(t
, config
)
17990 for d
in callbackInterfaces
:
17991 builder
.add(d
.nativeType
)
17992 builder
.add(d
.nativeType
+ "Atoms", isStruct
=True)
17993 for t
in getTypesFromDescriptor(d
):
17994 builder
.forwardDeclareForType(t
, config
)
17995 if d
.hasCEReactions():
17996 builder
.addInMozillaDom("DocGroup")
17998 for d
in dictionaries
:
17999 if len(d
.members
) > 0:
18000 builder
.addInMozillaDom(d
.identifier
.name
+ "Atoms", isStruct
=True)
18001 for t
in getTypesFromDictionary(d
):
18002 builder
.forwardDeclareForType(t
, config
)
18004 for className
, isStruct
in additionalDeclarations
:
18005 builder
.add(className
, isStruct
=isStruct
)
18007 CGWrapper
.__init
__(self
, builder
.build())
18010 class CGBindingRoot(CGThing
):
18012 Root codegen class for binding generation. Instantiate the class, and call
18013 declare or define to generate header or cpp code (respectively).
18016 def __init__(self
, config
, prefix
, webIDLFile
):
18017 bindingHeaders
= dict.fromkeys(
18018 ("mozilla/dom/NonRefcountedDOMObject.h", "MainThreadUtils.h"), True
18020 bindingDeclareHeaders
= dict.fromkeys(
18022 "mozilla/dom/BindingDeclarations.h",
18023 "mozilla/dom/Nullable.h",
18028 descriptors
= config
.getDescriptors(
18029 webIDLFile
=webIDLFile
, hasInterfaceOrInterfacePrototypeObject
=True
18032 unionTypes
= UnionsForFile(config
, webIDLFile
)
18041 ) = UnionTypes(unionTypes
, config
)
18043 bindingDeclareHeaders
.update(dict.fromkeys(unionHeaders
, True))
18044 bindingHeaders
.update(dict.fromkeys(unionImplheaders
, True))
18045 bindingDeclareHeaders
["mozilla/dom/UnionMember.h"] = len(unionStructs
) > 0
18046 bindingDeclareHeaders
["mozilla/dom/FakeString.h"] = len(unionStructs
) > 0
18047 # BindingUtils.h is only needed for SetToObject.
18048 # If it stops being inlined or stops calling CallerSubsumes
18049 # both this bit and the bit in UnionTypes can be removed.
18050 bindingDeclareHeaders
["mozilla/dom/BindingUtils.h"] = any(
18051 d
.isObject() for t
in unionTypes
for d
in t
.flatMemberTypes
18053 bindingDeclareHeaders
["mozilla/dom/IterableIterator.h"] = any(
18054 d
.interface
.isIteratorInterface() or d
.interface
.isIterable()
18055 for d
in descriptors
18058 def memberNeedsSubjectPrincipal(d
, m
):
18061 "needsSubjectPrincipal" in d
.getExtendedAttributes(m
, getter
=True)
18064 and "needsSubjectPrincipal"
18065 in d
.getExtendedAttributes(m
, setter
=True)
18067 return m
.isMethod() and "needsSubjectPrincipal" in d
.getExtendedAttributes(
18072 memberNeedsSubjectPrincipal(d
, m
)
18073 for d
in descriptors
18074 for m
in d
.interface
.members
18076 bindingHeaders
["mozilla/BasePrincipal.h"] = True
18077 bindingHeaders
["nsJSPrincipals.h"] = True
18079 # The conditions for which we generate profiler labels are fairly
18080 # complicated. The check below is a little imprecise to make it simple.
18081 # It includes the profiler header in all cases where it is necessary and
18082 # generates only a few false positives.
18083 bindingHeaders
["mozilla/ProfilerLabels.h"] = any(
18084 # constructor profiler label
18085 d
.interface
.legacyFactoryFunctions
18086 or (d
.interface
.hasInterfaceObject() and d
.interface
.ctor())
18088 # getter/setter profiler labels
18090 # method profiler label
18092 for m
in d
.interface
.members
18094 for d
in descriptors
18097 def descriptorHasCrossOriginProperties(desc
):
18098 def hasCrossOriginProperty(m
):
18099 props
= memberProperties(m
, desc
)
18101 props
.isCrossOriginMethod
18102 or props
.isCrossOriginGetter
18103 or props
.isCrossOriginSetter
18106 return any(hasCrossOriginProperty(m
) for m
in desc
.interface
.members
)
18108 bindingDeclareHeaders
["mozilla/dom/RemoteObjectProxy.h"] = any(
18109 descriptorHasCrossOriginProperties(d
) for d
in descriptors
18111 bindingDeclareHeaders
["jsapi.h"] = any(
18112 descriptorHasCrossOriginProperties(d
) for d
in descriptors
18114 bindingDeclareHeaders
["js/TypeDecls.h"] = not bindingDeclareHeaders
["jsapi.h"]
18115 bindingDeclareHeaders
["js/RootingAPI.h"] = not bindingDeclareHeaders
["jsapi.h"]
18117 def descriptorHasIteratorAlias(desc
):
18118 def hasIteratorAlias(m
):
18119 return m
.isMethod() and "@@iterator" in m
.aliases
18121 return any(hasIteratorAlias(m
) for m
in desc
.interface
.members
)
18123 bindingHeaders
["js/Symbol.h"] = any(
18124 descriptorHasIteratorAlias(d
) for d
in descriptors
18127 bindingHeaders
["js/shadow/Object.h"] = any(
18128 d
.interface
.hasMembersInSlots() for d
in descriptors
18131 # The symbols supplied by this header are used so ubiquitously it's not
18132 # worth the effort delineating the exact dependency, if it can't be done
18133 # *at* the places where their definitions are required.
18134 bindingHeaders
["js/experimental/JitInfo.h"] = True
18136 # JS::GetClass, JS::GetCompartment, JS::GetReservedSlot, and
18137 # JS::SetReservedSlot are also used too many places to restate
18138 # dependency logic.
18139 bindingHeaders
["js/Object.h"] = True
18141 def descriptorDeprecated(desc
):
18142 iface
= desc
.interface
18144 m
.getExtendedAttribute("Deprecated") for m
in iface
.members
+ [iface
]
18147 bindingHeaders
["mozilla/dom/Document.h"] = any(
18148 descriptorDeprecated(d
) for d
in descriptors
18151 bindingHeaders
["mozilla/dom/DOMJSProxyHandler.h"] = any(
18152 d
.concrete
and d
.proxy
for d
in descriptors
18155 bindingHeaders
["js/String.h"] = any(
18156 d
.needsMissingPropUseCounters
for d
in descriptors
18159 hasCrossOriginObjects
= any(
18160 d
.concrete
and d
.isMaybeCrossOriginObject() for d
in descriptors
18162 bindingHeaders
["mozilla/dom/MaybeCrossOriginObject.h"] = hasCrossOriginObjects
18163 bindingHeaders
["AccessCheck.h"] = hasCrossOriginObjects
18164 hasCEReactions
= any(d
.hasCEReactions() for d
in descriptors
)
18165 bindingHeaders
["mozilla/dom/CustomElementRegistry.h"] = hasCEReactions
18166 bindingHeaders
["mozilla/dom/DocGroup.h"] = hasCEReactions
18168 def descriptorHasChromeOnly(desc
):
18169 ctor
= desc
.interface
.ctor()
18173 isChromeOnly(a
) or needsContainsHack(a
) or needsCallerType(a
)
18174 for a
in desc
.interface
.members
18176 or desc
.interface
.getExtendedAttribute("ChromeOnly") is not None
18178 # JS-implemented interfaces with an interface object get a
18179 # chromeonly _create method. And interfaces with an
18180 # interface object might have a ChromeOnly constructor.
18182 desc
.interface
.hasInterfaceObject()
18184 desc
.interface
.isJSImplemented()
18185 or (ctor
and isChromeOnly(ctor
))
18190 # XXXkhuey ugly hack but this is going away soon.
18191 bindingHeaders
["xpcprivate.h"] = webIDLFile
.endswith("EventTarget.webidl")
18193 hasThreadChecks
= any(d
.hasThreadChecks() for d
in descriptors
)
18194 bindingHeaders
["nsThreadUtils.h"] = hasThreadChecks
18196 dictionaries
= config
.getDictionaries(webIDLFile
)
18198 def dictionaryHasChromeOnly(dictionary
):
18200 if any(isChromeOnly(m
) for m
in dictionary
.members
):
18202 dictionary
= dictionary
.parent
18205 def needsNonSystemPrincipal(member
):
18207 member
.getExtendedAttribute("NeedsSubjectPrincipal") == ["NonSystem"]
18208 or member
.getExtendedAttribute("SetterNeedsSubjectPrincipal")
18210 or member
.getExtendedAttribute("GetterNeedsSubjectPrincipal")
18214 def descriptorNeedsNonSystemPrincipal(d
):
18215 return any(needsNonSystemPrincipal(m
) for m
in d
.interface
.members
)
18217 def descriptorHasPrefDisabler(desc
):
18218 iface
= desc
.interface
18220 PropertyDefiner
.getControllingCondition(m
, desc
).hasDisablers()
18221 for m
in iface
.members
18222 if (m
.isMethod() or m
.isAttr() or m
.isConst())
18225 def addPrefHeaderForObject(bindingHeaders
, obj
):
18227 obj might be a dictionary member or an interface.
18229 if obj
is not None:
18230 pref
= PropertyDefiner
.getStringAttr(obj
, "Pref")
18232 bindingHeaders
[prefHeader(pref
)] = True
18234 def addPrefHeadersForDictionary(bindingHeaders
, dictionary
):
18236 for m
in dictionary
.members
:
18237 addPrefHeaderForObject(bindingHeaders
, m
)
18238 dictionary
= dictionary
.parent
18240 for d
in dictionaries
:
18241 addPrefHeadersForDictionary(bindingHeaders
, d
)
18242 for d
in descriptors
:
18243 interface
= d
.interface
18244 addPrefHeaderForObject(bindingHeaders
, interface
)
18245 addPrefHeaderForObject(bindingHeaders
, interface
.ctor())
18247 bindingHeaders
["mozilla/dom/WebIDLPrefs.h"] = any(
18248 descriptorHasPrefDisabler(d
) for d
in descriptors
18250 bindingHeaders
["nsContentUtils.h"] = (
18251 any(descriptorHasChromeOnly(d
) for d
in descriptors
)
18252 or any(descriptorNeedsNonSystemPrincipal(d
) for d
in descriptors
)
18253 or any(dictionaryHasChromeOnly(d
) for d
in dictionaries
)
18255 hasNonEmptyDictionaries
= any(len(dict.members
) > 0 for dict in dictionaries
)
18256 callbacks
= config
.getCallbacks(webIDLFile
)
18257 callbackDescriptors
= config
.getDescriptors(
18258 webIDLFile
=webIDLFile
, isCallback
=True
18260 jsImplemented
= config
.getDescriptors(
18261 webIDLFile
=webIDLFile
, isJSImplemented
=True
18263 bindingDeclareHeaders
["nsWeakReference.h"] = jsImplemented
18264 bindingDeclareHeaders
["mozilla/dom/PrototypeList.h"] = descriptors
18265 bindingHeaders
["nsIGlobalObject.h"] = jsImplemented
18266 bindingHeaders
["AtomList.h"] = (
18267 hasNonEmptyDictionaries
or jsImplemented
or callbackDescriptors
18270 if callbackDescriptors
:
18271 bindingDeclareHeaders
["mozilla/ErrorResult.h"] = True
18273 def descriptorClearsPropsInSlots(descriptor
):
18274 if not descriptor
.wrapperCache
:
18277 m
.isAttr() and m
.getExtendedAttribute("StoreInSlot")
18278 for m
in descriptor
.interface
.members
18281 bindingHeaders
["nsJSUtils.h"] = any(
18282 descriptorClearsPropsInSlots(d
) for d
in descriptors
18285 # Make sure we can sanely use binding_detail in generated code.
18290 namespace binding_detail {}; // Just to make sure it's known as a namespace
18291 using namespace mozilla::dom::binding_detail;
18297 # Do codegen for all the enums
18298 enums
= config
.getEnums(webIDLFile
)
18299 cgthings
.extend(CGEnum(e
) for e
in enums
)
18301 bindingDeclareHeaders
["mozilla/Span.h"] = enums
18302 bindingDeclareHeaders
["mozilla/ArrayUtils.h"] = enums
18304 hasCode
= descriptors
or callbackDescriptors
or dictionaries
or callbacks
18305 bindingHeaders
["mozilla/dom/BindingUtils.h"] = hasCode
18306 bindingHeaders
["mozilla/OwningNonNull.h"] = hasCode
18307 bindingHeaders
["<type_traits>"] = hasCode
18308 bindingHeaders
["mozilla/dom/BindingDeclarations.h"] = not hasCode
and enums
18310 bindingHeaders
["WrapperFactory.h"] = descriptors
18311 bindingHeaders
["mozilla/dom/DOMJSClass.h"] = descriptors
18312 bindingHeaders
["mozilla/dom/ScriptSettings.h"] = dictionaries
# AutoJSAPI
18313 # Ensure we see our enums in the generated .cpp file, for the ToJSValue
18314 # method body. Also ensure that we see jsapi.h.
18316 bindingHeaders
[CGHeaders
.getDeclarationFilename(enums
[0])] = True
18317 bindingHeaders
["jsapi.h"] = True
18319 # For things that have [UseCounter] or [InstrumentedProps]
18320 descriptorsHaveUseCounters
= any(
18321 m
.getExtendedAttribute("UseCounter")
18322 for d
in descriptors
18323 for m
in d
.interface
.members
18325 descriptorsHaveInstrumentedProps
= any(
18326 d
.instrumentedProps
for d
in descriptors
if d
.concrete
18328 descriptorsHaveNeedsMissingPropUseCounters
= any(
18329 d
.needsMissingPropUseCounters
for d
in descriptors
if d
.concrete
18332 bindingHeaders
["mozilla/UseCounter.h"] = (
18333 descriptorsHaveUseCounters
or descriptorsHaveInstrumentedProps
18335 # Make sure to not overwrite existing pref header bits!
18336 bindingHeaders
[prefHeader(MISSING_PROP_PREF
)] = (
18337 bindingHeaders
.get(prefHeader(MISSING_PROP_PREF
))
18338 or descriptorsHaveNeedsMissingPropUseCounters
18340 bindingHeaders
["mozilla/dom/SimpleGlobalObject.h"] = any(
18341 CGDictionary
.dictionarySafeToJSONify(d
) for d
in dictionaries
18343 bindingHeaders
["XrayWrapper.h"] = any(
18344 d
.wantsXrays
and d
.wantsXrayExpandoClass
for d
in descriptors
18346 bindingHeaders
["mozilla/dom/XrayExpandoClass.h"] = any(
18347 d
.wantsXrays
for d
in descriptors
18349 bindingHeaders
["mozilla/dom/StructuredCloneTags.h"] = any(
18350 d
.interface
.isSerializable() for d
in descriptors
18352 bindingHeaders
["mozilla/Atomics.h"] = any(d
.wantsXrays
for d
in descriptors
)
18354 for ancestor
in (findAncestorWithInstrumentedProps(d
) for d
in descriptors
):
18357 bindingHeaders
[CGHeaders
.getDeclarationFilename(ancestor
)] = True
18359 cgthings
.extend(traverseMethods
)
18360 cgthings
.extend(unlinkMethods
)
18362 # Do codegen for all the dictionaries. We have to be a bit careful
18363 # here, because we have to generate these in order from least derived
18364 # to most derived so that class inheritance works out. We also have to
18365 # generate members before the dictionary that contains them.
18367 def getDependenciesFromType(type):
18368 if type.isDictionary():
18369 return set([type.unroll().inner
])
18370 if type.isSequence():
18371 return getDependenciesFromType(type.unroll())
18373 return set([type.unroll()])
18376 def getDependencies(unionTypeOrDictionary
):
18377 if isinstance(unionTypeOrDictionary
, IDLDictionary
):
18379 if unionTypeOrDictionary
.parent
:
18380 deps
.add(unionTypeOrDictionary
.parent
)
18381 for member
in unionTypeOrDictionary
.members
:
18382 deps |
= getDependenciesFromType(member
.type)
18385 assert unionTypeOrDictionary
.isType() and unionTypeOrDictionary
.isUnion()
18387 for member
in unionTypeOrDictionary
.flatMemberTypes
:
18388 deps |
= getDependenciesFromType(member
)
18391 def getName(unionTypeOrDictionary
):
18392 if isinstance(unionTypeOrDictionary
, IDLDictionary
):
18393 return unionTypeOrDictionary
.identifier
.name
18395 assert unionTypeOrDictionary
.isType() and unionTypeOrDictionary
.isUnion()
18396 return unionTypeOrDictionary
.name
18398 for t
in dependencySortObjects(
18399 dictionaries
+ unionStructs
, getDependencies
, getName
18401 if t
.isDictionary():
18402 cgthings
.append(CGDictionary(t
, config
))
18405 cgthings
.append(CGUnionStruct(t
, config
))
18406 cgthings
.append(CGUnionStruct(t
, config
, True))
18408 # Do codegen for all the callbacks.
18409 cgthings
.extend(CGCallbackFunction(c
, config
) for c
in callbacks
)
18412 [CGNamespace("binding_detail", CGFastCallback(c
)) for c
in callbacks
]
18415 # Do codegen for all the descriptors
18416 cgthings
.extend([CGDescriptor(x
) for x
in descriptors
])
18418 # Do codegen for all the callback interfaces.
18419 cgthings
.extend([CGCallbackInterface(x
) for x
in callbackDescriptors
])
18423 CGNamespace("binding_detail", CGFastCallback(x
.interface
))
18424 for x
in callbackDescriptors
18428 # Do codegen for JS implemented classes
18429 def getParentDescriptor(desc
):
18430 if not desc
.interface
.parent
:
18432 return {desc
.getDescriptor(desc
.interface
.parent
.identifier
.name
)}
18434 for x
in dependencySortObjects(
18435 jsImplemented
, getParentDescriptor
, lambda d
: d
.interface
.identifier
.name
18438 CGCallbackInterface(x
, spiderMonkeyInterfacesAreStructs
=True)
18440 cgthings
.append(CGJSImplClass(x
))
18442 # And make sure we have the right number of newlines at the end
18443 curr
= CGWrapper(CGList(cgthings
, "\n\n"), post
="\n\n")
18445 # Wrap all of that in our namespaces.
18446 curr
= CGNamespace
.build(["mozilla", "dom"], CGWrapper(curr
, pre
="\n"))
18450 CGForwardDeclarations(
18455 callbackDescriptors
+ jsImplemented
,
18456 additionalDeclarations
=unionDeclarations
,
18463 # Add header includes.
18465 header
for header
, include
in six
.iteritems(bindingHeaders
) if include
18467 bindingDeclareHeaders
= [
18469 for header
, include
in six
.iteritems(bindingDeclareHeaders
)
18477 callbackDescriptors
,
18478 bindingDeclareHeaders
,
18486 # Add include guards.
18487 curr
= CGIncludeGuard(prefix
, curr
)
18489 # Add the auto-generated comment.
18493 AUTOGENERATED_WITH_SOURCE_WARNING_COMMENT
% os
.path
.basename(webIDLFile
)
18497 # Store the final result.
18501 return stripTrailingWhitespace(self
.root
.declare())
18504 return stripTrailingWhitespace(self
.root
.define())
18507 return self
.root
.deps()
18510 class CGNativeMember(ClassMethod
):
18513 descriptorProvider
,
18519 passJSBitsAsNeeded
=True,
18520 visibility
="public",
18521 spiderMonkeyInterfacesAreStructs
=True,
18522 variadicIsSequence
=False,
18523 resultNotAddRefed
=False,
18526 canRunScript
=False,
18529 If spiderMonkeyInterfacesAreStructs is false, SpiderMonkey interfaces
18530 will be passed as JS::Handle<JSObject*>. If it's true they will be
18531 passed as one of the dom::SpiderMonkeyInterfaceObjectStorage subclasses.
18533 If passJSBitsAsNeeded is false, we don't automatically pass in a
18534 JSContext* or a JSObject* based on the return and argument types. We
18535 can still pass it based on 'implicitJSContext' annotations.
18537 self
.descriptorProvider
= descriptorProvider
18538 self
.member
= member
18539 self
.extendedAttrs
= extendedAttrs
18540 self
.resultAlreadyAddRefed
= not resultNotAddRefed
18541 self
.passJSBitsAsNeeded
= passJSBitsAsNeeded
18542 self
.spiderMonkeyInterfacesAreStructs
= spiderMonkeyInterfacesAreStructs
18543 self
.variadicIsSequence
= variadicIsSequence
18544 breakAfterSelf
= "\n" if breakAfter
else ""
18545 ClassMethod
.__init
__(
18548 self
.getReturnType(signature
[0], False),
18549 self
.getArgs(signature
[0], signature
[1]),
18550 static
=member
.isStatic(),
18551 # Mark our getters, which are attrs that
18552 # have a non-void return type, as const.
18554 not member
.isStatic() and member
.isAttr() and not signature
[0].isVoid()
18556 breakAfterReturnDecl
=" ",
18557 breakAfterSelf
=breakAfterSelf
,
18558 visibility
=visibility
,
18561 canRunScript
=canRunScript
,
18564 def getReturnType(self
, type, isMember
):
18565 return self
.getRetvalInfo(type, isMember
)[0]
18567 def getRetvalInfo(self
, type, isMember
):
18571 The first element is the type declaration for the retval
18573 The second element is a default value that can be used on error returns.
18574 For cases whose behavior depends on isMember, the second element will be
18575 None if isMember is true.
18577 The third element is a template for actually returning a value stored in
18578 "${declName}" and "${holderName}". This means actually returning it if
18579 we're not outparam, else assigning to the "retval" outparam. If
18580 isMember is true, this can be None, since in that case the caller will
18581 never examine this value.
18584 return "void", "", ""
18585 if type.isPrimitive() and type.tag() in builtinNames
:
18586 result
= CGGeneric(builtinNames
[type.tag()])
18587 defaultReturnArg
= "0"
18588 if type.nullable():
18589 result
= CGTemplatedType("Nullable", result
)
18590 defaultReturnArg
= ""
18593 "%s(%s)" % (result
.define(), defaultReturnArg
),
18594 "return ${declName};\n",
18596 if type.isJSString():
18598 raise TypeError("JSString not supported as return type member")
18600 return "void", "", "aRetVal.set(${declName});\n"
18601 if type.isDOMString() or type.isUSVString():
18603 # No need for a third element in the isMember case
18604 return "nsString", None, None
18606 return "void", "", "aRetVal = ${declName};\n"
18607 if type.isByteString() or type.isUTF8String():
18609 # No need for a third element in the isMember case
18610 return "nsCString", None, None
18612 return "void", "", "aRetVal = ${declName};\n"
18614 enumName
= type.unroll().inner
.identifier
.name
18615 if type.nullable():
18616 enumName
= CGTemplatedType("Nullable", CGGeneric(enumName
)).define()
18617 defaultValue
= "%s()" % enumName
18619 defaultValue
= "%s(0)" % enumName
18620 return enumName
, defaultValue
, "return ${declName};\n"
18621 if type.isGeckoInterface() or type.isPromise():
18622 if type.isGeckoInterface():
18623 iface
= type.unroll().inner
18624 result
= CGGeneric(
18625 self
.descriptorProvider
.getDescriptor(
18626 iface
.identifier
.name
18630 result
= CGGeneric("Promise")
18631 if self
.resultAlreadyAddRefed
:
18635 holder
= "already_AddRefed"
18636 if memberReturnsNewObject(self
.member
) or isMember
:
18639 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"
18640 result
= CGWrapper(result
, pre
=("%s%s<" % (warning
, holder
)), post
=">")
18642 result
= CGWrapper(result
, post
="*")
18643 # Since we always force an owning type for callback return values,
18644 # our ${declName} is an OwningNonNull or RefPtr. So we can just
18645 # .forget() to get our already_AddRefed.
18646 return result
.define(), "nullptr", "return ${declName}.forget();\n"
18647 if type.isCallback():
18649 "already_AddRefed<%s>" % type.unroll().callback
.identifier
.name
,
18651 "return ${declName}.forget();\n",
18655 # No need for a third element in the isMember case
18656 return "JS::Value", None, None
18658 return "void", "", "aRetVal.set(${declName});\n"
18660 if type.isObject():
18662 # No need for a third element in the isMember case
18663 return "JSObject*", None, None
18664 return "void", "", "aRetVal.set(${declName});\n"
18665 if type.isSpiderMonkeyInterface():
18667 # No need for a third element in the isMember case
18668 return "JSObject*", None, None
18669 if type.nullable():
18671 "${declName}.IsNull() ? nullptr : ${declName}.Value().Obj()"
18674 returnCode
= "${declName}.Obj()"
18675 return "void", "", "aRetVal.set(%s);\n" % returnCode
18676 if type.isSequence():
18677 # If we want to handle sequence-of-sequences return values, we're
18678 # going to need to fix example codegen to not produce nsTArray<void>
18679 # for the relevant argument...
18680 assert not isMember
18682 if type.nullable():
18683 returnCode
= dedent(
18685 if (${declName}.IsNull()) {
18688 aRetVal.SetValue() = std::move(${declName}.Value());
18693 returnCode
= "aRetVal = std::move(${declName});\n"
18694 return "void", "", returnCode
18695 if type.isRecord():
18696 # If we want to handle record-of-record return values, we're
18697 # going to need to fix example codegen to not produce record<void>
18698 # for the relevant argument...
18699 assert not isMember
18700 # In this case we convert directly into our outparam to start with
18701 return "void", "", ""
18702 if type.isDictionary():
18704 # Only the first member of the tuple matters here, but return
18705 # bogus values for the others in case someone decides to use
18707 return CGDictionary
.makeDictionaryName(type.inner
), None, None
18708 # In this case we convert directly into our outparam to start with
18709 return "void", "", ""
18712 # Only the first member of the tuple matters here, but return
18713 # bogus values for the others in case someone decides to use
18715 return CGUnionStruct
.unionTypeDecl(type, True), None, None
18716 # In this case we convert directly into our outparam to start with
18717 return "void", "", ""
18719 raise TypeError("Don't know how to declare return value for %s" % type)
18721 def getArgs(self
, returnType
, argList
):
18722 args
= [self
.getArg(arg
) for arg
in argList
]
18723 # Now the outparams
18724 if returnType
.isJSString():
18725 args
.append(Argument("JS::MutableHandle<JSString*>", "aRetVal"))
18726 elif returnType
.isDOMString() or returnType
.isUSVString():
18727 args
.append(Argument("nsString&", "aRetVal"))
18728 elif returnType
.isByteString() or returnType
.isUTF8String():
18729 args
.append(Argument("nsCString&", "aRetVal"))
18730 elif returnType
.isSequence():
18731 nullable
= returnType
.nullable()
18733 returnType
= returnType
.inner
18734 # And now the actual underlying type
18735 elementDecl
= self
.getReturnType(returnType
.inner
, True)
18736 type = CGTemplatedType("nsTArray", CGGeneric(elementDecl
))
18738 type = CGTemplatedType("Nullable", type)
18739 args
.append(Argument("%s&" % type.define(), "aRetVal"))
18740 elif returnType
.isRecord():
18741 nullable
= returnType
.nullable()
18743 returnType
= returnType
.inner
18744 # And now the actual underlying type
18745 elementDecl
= self
.getReturnType(returnType
.inner
, True)
18746 type = CGTemplatedType(
18747 "Record", [recordKeyDeclType(returnType
), CGGeneric(elementDecl
)]
18750 type = CGTemplatedType("Nullable", type)
18751 args
.append(Argument("%s&" % type.define(), "aRetVal"))
18752 elif returnType
.isDictionary():
18753 nullable
= returnType
.nullable()
18755 returnType
= returnType
.inner
18756 dictType
= CGGeneric(CGDictionary
.makeDictionaryName(returnType
.inner
))
18758 dictType
= CGTemplatedType("Nullable", dictType
)
18759 args
.append(Argument("%s&" % dictType
.define(), "aRetVal"))
18760 elif returnType
.isUnion():
18763 "%s&" % CGUnionStruct
.unionTypeDecl(returnType
, True), "aRetVal"
18766 elif returnType
.isAny():
18767 args
.append(Argument("JS::MutableHandle<JS::Value>", "aRetVal"))
18768 elif returnType
.isObject() or returnType
.isSpiderMonkeyInterface():
18769 args
.append(Argument("JS::MutableHandle<JSObject*>", "aRetVal"))
18771 # And the nsIPrincipal
18772 if "needsSubjectPrincipal" in self
.extendedAttrs
:
18773 # Cheat and assume self.descriptorProvider is a descriptor
18774 if self
.descriptorProvider
.interface
.isExposedInAnyWorker():
18775 args
.append(Argument("Maybe<nsIPrincipal*>", "aSubjectPrincipal"))
18776 elif "needsNonSystemSubjectPrincipal" in self
.extendedAttrs
:
18777 args
.append(Argument("nsIPrincipal*", "aPrincipal"))
18779 args
.append(Argument("nsIPrincipal&", "aPrincipal"))
18780 # And the caller type, if desired.
18781 if needsCallerType(self
.member
):
18782 args
.append(Argument("CallerType", "aCallerType"))
18783 # And the ErrorResult or OOMReporter
18784 if "needsErrorResult" in self
.extendedAttrs
:
18785 # Use aRv so it won't conflict with local vars named "rv"
18786 args
.append(Argument("ErrorResult&", "aRv"))
18787 elif "canOOM" in self
.extendedAttrs
:
18788 args
.append(Argument("OOMReporter&", "aRv"))
18790 # The legacycaller thisval
18791 if self
.member
.isMethod() and self
.member
.isLegacycaller():
18792 # If it has an identifier, we can't deal with it yet
18793 assert self
.member
.isIdentifierLess()
18794 args
.insert(0, Argument("const JS::Value&", "aThisVal"))
18795 # And jscontext bits.
18799 self
.extendedAttrs
,
18800 self
.passJSBitsAsNeeded
,
18801 self
.member
.isStatic(),
18803 args
.insert(0, Argument("JSContext*", "cx"))
18804 if needScopeObject(
18807 self
.extendedAttrs
,
18808 self
.descriptorProvider
.wrapperCache
,
18809 self
.passJSBitsAsNeeded
,
18810 self
.member
.getExtendedAttribute("StoreInSlot"),
18812 args
.insert(1, Argument("JS::Handle<JSObject*>", "obj"))
18813 # And if we're static, a global
18814 if self
.member
.isStatic():
18815 args
.insert(0, Argument("const GlobalObject&", "global"))
18818 def doGetArgType(self
, type, optional
, isMember
):
18820 The main work of getArgType. Returns a string type decl, whether this
18821 is a const ref, as well as whether the type should be wrapped in
18822 Nullable as needed.
18824 isMember can be false or one of the strings "Sequence", "Variadic",
18827 if type.isSequence():
18828 nullable
= type.nullable()
18831 elementType
= type.inner
18832 argType
= self
.getArgType(elementType
, False, "Sequence")[0]
18833 decl
= CGTemplatedType("Sequence", argType
)
18834 return decl
.define(), True, True
18836 if type.isRecord():
18837 nullable
= type.nullable()
18840 elementType
= type.inner
18841 argType
= self
.getArgType(elementType
, False, "Record")[0]
18842 decl
= CGTemplatedType("Record", [recordKeyDeclType(type), argType
])
18843 return decl
.define(), True, True
18846 # unionTypeDecl will handle nullable types, so return False for
18847 # auto-wrapping in Nullable
18848 return CGUnionStruct
.unionTypeDecl(type, isMember
), True, False
18850 if type.isPromise():
18851 assert not type.nullable()
18852 if optional
or isMember
:
18853 typeDecl
= "OwningNonNull<Promise>"
18855 typeDecl
= "Promise&"
18856 return (typeDecl
, False, False)
18858 if type.isGeckoInterface() and not type.isCallbackInterface():
18859 iface
= type.unroll().inner
18860 if iface
.identifier
.name
== "WindowProxy":
18861 return "WindowProxyHolder", True, False
18863 argIsPointer
= type.nullable() or iface
.isExternal()
18864 forceOwningType
= iface
.isCallback() or isMember
18866 if (optional
or isMember
) and forceOwningType
:
18867 typeDecl
= "RefPtr<%s>"
18871 if optional
or isMember
:
18872 if forceOwningType
:
18873 typeDecl
= "OwningNonNull<%s>"
18875 typeDecl
= "NonNull<%s>"
18881 % self
.descriptorProvider
.getDescriptor(
18882 iface
.identifier
.name
18889 if type.isSpiderMonkeyInterface():
18890 if not self
.spiderMonkeyInterfacesAreStructs
:
18891 return "JS::Handle<JSObject*>", False, False
18893 # Unroll for the name, in case we're nullable.
18894 return type.unroll().name
, True, True
18896 if type.isJSString():
18898 raise TypeError("JSString not supported as member")
18899 return "JS::Handle<JSString*>", False, False
18901 if type.isDOMString() or type.isUSVString():
18903 declType
= "nsString"
18905 declType
= "nsAString"
18906 return declType
, True, False
18908 if type.isByteString() or type.isUTF8String():
18909 # TODO(emilio): Maybe bytestrings could benefit from nsAutoCString
18911 if type.isUTF8String() and not isMember
:
18912 declType
= "nsACString"
18914 declType
= "nsCString"
18915 return declType
, True, False
18918 return type.unroll().inner
.identifier
.name
, False, True
18920 if type.isCallback() or type.isCallbackInterface():
18921 forceOwningType
= optional
or isMember
18922 if type.nullable():
18923 if forceOwningType
:
18924 declType
= "RefPtr<%s>"
18928 if forceOwningType
:
18929 declType
= "OwningNonNull<%s>"
18932 if type.isCallback():
18933 name
= type.unroll().callback
.identifier
.name
18935 name
= type.unroll().inner
.identifier
.name
18936 return declType
% name
, False, False
18939 # Don't do the rooting stuff for variadics for now
18941 declType
= "JS::Value"
18943 declType
= "JS::Handle<JS::Value>"
18944 return declType
, False, False
18946 if type.isObject():
18948 declType
= "JSObject*"
18950 declType
= "JS::Handle<JSObject*>"
18951 return declType
, False, False
18953 if type.isDictionary():
18954 typeName
= CGDictionary
.makeDictionaryName(type.inner
)
18955 return typeName
, True, True
18957 assert type.isPrimitive()
18959 return builtinNames
[type.tag()], False, True
18961 def getArgType(self
, type, optional
, isMember
):
18963 Get the type of an argument declaration. Returns the type CGThing, and
18964 whether this should be a const ref.
18966 isMember can be False, "Sequence", or "Variadic"
18968 decl
, ref
, handleNullable
= self
.doGetArgType(type, optional
, isMember
)
18969 decl
= CGGeneric(decl
)
18970 if handleNullable
and type.nullable():
18971 decl
= CGTemplatedType("Nullable", decl
)
18973 if isMember
== "Variadic":
18974 arrayType
= "Sequence" if self
.variadicIsSequence
else "nsTArray"
18975 decl
= CGTemplatedType(arrayType
, decl
)
18978 # Note: All variadic args claim to be optional, but we can just use
18979 # empty arrays to represent them not being present.
18980 decl
= CGTemplatedType("Optional", decl
)
18984 def getArg(self
, arg
):
18986 Get the full argument declaration for an argument
18988 decl
, ref
= self
.getArgType(
18989 arg
.type, arg
.canHaveMissingValue(), "Variadic" if arg
.variadic
else False
18992 decl
= CGWrapper(decl
, pre
="const ", post
="&")
18994 return Argument(decl
.define(), arg
.identifier
.name
)
18996 def arguments(self
):
18997 return self
.member
.signatures()[0][1]
19000 class CGExampleMethod(CGNativeMember
):
19001 def __init__(self
, descriptor
, method
, signature
, isConstructor
, breakAfter
=True):
19002 CGNativeMember
.__init
__(
19006 CGSpecializedMethod
.makeNativeName(descriptor
, method
),
19008 descriptor
.getExtendedAttributes(method
),
19009 breakAfter
=breakAfter
,
19010 variadicIsSequence
=True,
19013 def declare(self
, cgClass
):
19014 assert self
.member
.isMethod()
19015 # We skip declaring ourselves if this is a maplike/setlike/iterable
19016 # method, because those get implemented automatically by the binding
19017 # machinery, so the implementor of the interface doesn't have to worry
19019 if self
.member
.isMaplikeOrSetlikeOrIterableMethod():
19021 return CGNativeMember
.declare(self
, cgClass
)
19023 def define(self
, cgClass
):
19027 class CGExampleGetter(CGNativeMember
):
19028 def __init__(self
, descriptor
, attr
):
19029 CGNativeMember
.__init
__(
19033 CGSpecializedGetter
.makeNativeName(descriptor
, attr
),
19035 descriptor
.getExtendedAttributes(attr
, getter
=True),
19038 def declare(self
, cgClass
):
19039 assert self
.member
.isAttr()
19040 # We skip declaring ourselves if this is a maplike/setlike attr (in
19041 # practice, "size"), because those get implemented automatically by the
19042 # binding machinery, so the implementor of the interface doesn't have to
19044 if self
.member
.isMaplikeOrSetlikeAttr():
19046 return CGNativeMember
.declare(self
, cgClass
)
19048 def define(self
, cgClass
):
19052 class CGExampleSetter(CGNativeMember
):
19053 def __init__(self
, descriptor
, attr
):
19054 CGNativeMember
.__init
__(
19058 CGSpecializedSetter
.makeNativeName(descriptor
, attr
),
19059 (BuiltinTypes
[IDLBuiltinType
.Types
.void
], [FakeArgument(attr
.type, attr
)]),
19060 descriptor
.getExtendedAttributes(attr
, setter
=True),
19063 def define(self
, cgClass
):
19067 class CGBindingImplClass(CGClass
):
19069 Common codegen for generating a C++ implementation of a WebIDL interface
19078 wantGetParent
=True,
19079 wrapMethodName
="WrapObject",
19080 skipStaticMethods
=False,
19083 cgMethod, cgGetter and cgSetter are classes used to codegen methods,
19084 getters and setters.
19086 self
.descriptor
= descriptor
19087 self
._deps
= descriptor
.interface
.getDeps()
19089 iface
= descriptor
.interface
19091 self
.methodDecls
= []
19093 def appendMethod(m
, isConstructor
=False):
19094 sigs
= m
.signatures()
19095 for s
in sigs
[:-1]:
19096 # Don't put a blank line after overloads, until we
19097 # get to the last one.
19098 self
.methodDecls
.append(
19099 cgMethod(descriptor
, m
, s
, isConstructor
, breakAfter
=False)
19101 self
.methodDecls
.append(cgMethod(descriptor
, m
, sigs
[-1], isConstructor
))
19104 appendMethod(iface
.ctor(), isConstructor
=True)
19105 for n
in iface
.legacyFactoryFunctions
:
19106 appendMethod(n
, isConstructor
=True)
19107 for m
in iface
.members
:
19109 if m
.isIdentifierLess():
19111 if m
.isMaplikeOrSetlikeOrIterableMethod():
19112 # Handled by generated code already
19114 if not m
.isStatic() or not skipStaticMethods
:
19117 if m
.isMaplikeOrSetlikeAttr():
19118 # Handled by generated code already
19120 self
.methodDecls
.append(cgGetter(descriptor
, m
))
19122 self
.methodDecls
.append(cgSetter(descriptor
, m
))
19124 # Now do the special operations
19125 def appendSpecialOperation(name
, op
):
19128 assert len(op
.signatures()) == 1
19129 returnType
, args
= op
.signatures()[0]
19130 # Make a copy of the args, since we plan to modify them.
19132 if op
.isGetter() or op
.isDeleter():
19133 # This is a total hack. The '&' belongs with the
19134 # type, not the name! But it works, and is simpler
19135 # than trying to somehow make this pretty.
19138 BuiltinTypes
[IDLBuiltinType
.Types
.boolean
], op
, name
="&found"
19141 if name
== "Stringifier":
19142 if op
.isIdentifierLess():
19143 # XXXbz I wish we were consistent about our renaming here.
19146 # We already added this method
19148 if name
== "LegacyCaller":
19149 if op
.isIdentifierLess():
19150 # XXXbz I wish we were consistent about our renaming here.
19151 name
= "LegacyCall"
19153 # We already added this method
19155 self
.methodDecls
.append(
19160 (returnType
, args
),
19161 descriptor
.getExtendedAttributes(op
),
19165 # Sort things by name so we get stable ordering in the output.
19166 ops
= sorted(descriptor
.operations
.items(), key
=lambda x
: x
[0])
19167 for name
, op
in ops
:
19168 appendSpecialOperation(name
, op
)
19169 # If we support indexed properties, then we need a Length()
19170 # method so we know which indices are supported.
19171 if descriptor
.supportsIndexedProperties():
19172 # But we don't need it if we already have an infallible
19173 # "length" attribute, which we often do.
19174 haveLengthAttr
= any(
19176 for m
in iface
.members
19178 and CGSpecializedGetter
.makeNativeName(descriptor
, m
) == "Length"
19180 if not haveLengthAttr
:
19181 self
.methodDecls
.append(
19186 (BuiltinTypes
[IDLBuiltinType
.Types
.unsigned_long
], []),
19190 # And if we support named properties we need to be able to
19191 # enumerate the supported names.
19192 if descriptor
.supportsNamedProperties():
19193 self
.methodDecls
.append(
19197 "GetSupportedNames",
19200 None, BuiltinTypes
[IDLBuiltinType
.Types
.domstring
]
19208 if descriptor
.concrete
:
19210 Argument("JSContext*", "aCx"),
19211 Argument("JS::Handle<JSObject*>", "aGivenProto"),
19213 if not descriptor
.wrapperCache
:
19214 wrapReturnType
= "bool"
19215 wrapArgs
.append(Argument("JS::MutableHandle<JSObject*>", "aReflector"))
19217 wrapReturnType
= "JSObject*"
19218 self
.methodDecls
.insert(
19224 virtual
=descriptor
.wrapperCache
,
19225 breakAfterReturnDecl
=" ",
19226 override
=descriptor
.wrapperCache
,
19227 body
=self
.getWrapObjectBody(),
19230 if descriptor
.hasCEReactions():
19231 self
.methodDecls
.insert(
19238 breakAfterReturnDecl
=" ",
19239 body
=self
.getGetDocGroupBody(),
19243 self
.methodDecls
.insert(
19247 self
.getGetParentObjectReturnType(),
19250 breakAfterReturnDecl
=" ",
19251 body
=self
.getGetParentObjectBody(),
19255 # Invoke CGClass.__init__ in any subclasses afterwards to do the actual codegen.
19257 def getWrapObjectBody(self
):
19260 def getGetParentObjectReturnType(self
):
19261 # The lack of newline before the end of the string is on purpose.
19264 // This should return something that eventually allows finding a
19265 // path to the global this object is associated with. Most simply,
19266 // returning an actual global works.
19267 nsIGlobalObject*"""
19270 def getGetParentObjectBody(self
):
19273 def getGetDocGroupBody(self
):
19280 class CGExampleClass(CGBindingImplClass
):
19282 Codegen for the actual example class implementation for this descriptor
19285 def __init__(self
, descriptor
):
19286 CGBindingImplClass
.__init
__(
19292 wantGetParent
=descriptor
.wrapperCache
,
19295 self
.parentIface
= descriptor
.interface
.parent
19296 if self
.parentIface
:
19297 self
.parentDesc
= descriptor
.getDescriptor(self
.parentIface
.identifier
.name
)
19298 bases
= [ClassBase(self
.nativeLeafName(self
.parentDesc
))]
19302 "nsISupports /* or NonRefcountedDOMObject if this is a non-refcounted object */"
19305 if descriptor
.wrapperCache
:
19308 "nsWrapperCache /* Change wrapperCache in the binding configuration if you don't want this */"
19312 destructorVisibility
= "protected"
19313 if self
.parentIface
:
19314 extradeclarations
= (
19316 " NS_DECL_ISUPPORTS_INHERITED\n"
19317 " NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(%s, %s)\n"
19320 self
.nativeLeafName(descriptor
),
19321 self
.nativeLeafName(self
.parentDesc
),
19325 extradeclarations
= (
19327 " NS_DECL_CYCLE_COLLECTING_ISUPPORTS\n"
19328 " NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(%s)\n"
19329 "\n" % self
.nativeLeafName(descriptor
)
19332 if descriptor
.interface
.hasChildInterfaces():
19335 decorators
= "final"
19339 self
.nativeLeafName(descriptor
),
19341 constructors
=[ClassConstructor([], visibility
="public")],
19342 destructor
=ClassDestructor(visibility
=destructorVisibility
),
19343 methods
=self
.methodDecls
,
19344 decorators
=decorators
,
19345 extradeclarations
=extradeclarations
,
19349 # Just override CGClass and do our own thing
19350 nativeType
= self
.nativeLeafName(self
.descriptor
)
19354 ${nativeType}::${nativeType}()
19356 // Add |MOZ_COUNT_CTOR(${nativeType});| for a non-refcounted object.
19359 ${nativeType}::~${nativeType}()
19361 // Add |MOZ_COUNT_DTOR(${nativeType});| for a non-refcounted object.
19364 nativeType
=nativeType
,
19367 if self
.parentIface
:
19371 // Only needed for refcounted objects.
19372 # error "If you don't have members that need cycle collection,
19373 # then remove all the cycle collection bits from this
19374 # implementation and the corresponding header. If you do, you
19375 # want NS_IMPL_CYCLE_COLLECTION_INHERITED(${nativeType},
19376 # ${parentType}, your, members, here)"
19377 NS_IMPL_ADDREF_INHERITED(${nativeType}, ${parentType})
19378 NS_IMPL_RELEASE_INHERITED(${nativeType}, ${parentType})
19379 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
19380 NS_INTERFACE_MAP_END_INHERITING(${parentType})
19383 nativeType
=nativeType
,
19384 parentType
=self
.nativeLeafName(self
.parentDesc
),
19390 // Only needed for refcounted objects.
19391 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(${nativeType})
19392 NS_IMPL_CYCLE_COLLECTING_ADDREF(${nativeType})
19393 NS_IMPL_CYCLE_COLLECTING_RELEASE(${nativeType})
19394 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
19395 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
19396 NS_INTERFACE_MAP_ENTRY(nsISupports)
19397 NS_INTERFACE_MAP_END
19400 nativeType
=nativeType
,
19403 classImpl
= ccImpl
+ ctordtor
+ "\n"
19404 if self
.descriptor
.concrete
:
19405 if self
.descriptor
.wrapperCache
:
19407 reflectorPassArg
= ""
19408 returnType
= "JSObject*"
19410 reflectorArg
= ", JS::MutableHandle<JSObject*> aReflector"
19411 reflectorPassArg
= ", aReflector"
19412 returnType
= "bool"
19416 ${nativeType}::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto${reflectorArg})
19418 return ${ifaceName}_Binding::Wrap(aCx, this, aGivenProto${reflectorPassArg});
19422 returnType
=returnType
,
19423 nativeType
=nativeType
,
19424 reflectorArg
=reflectorArg
,
19425 ifaceName
=self
.descriptor
.name
,
19426 reflectorPassArg
=reflectorPassArg
,
19432 def nativeLeafName(descriptor
):
19433 return descriptor
.nativeType
.split("::")[-1]
19436 class CGExampleRoot(CGThing
):
19438 Root codegen class for example implementation generation. Instantiate the
19439 class and call declare or define to generate header or cpp code,
19443 def __init__(self
, config
, interfaceName
):
19444 descriptor
= config
.getDescriptor(interfaceName
)
19446 self
.root
= CGWrapper(CGExampleClass(descriptor
), pre
="\n", post
="\n")
19448 self
.root
= CGNamespace
.build(["mozilla", "dom"], self
.root
)
19450 builder
= ForwardDeclarationBuilder()
19451 if descriptor
.hasCEReactions():
19452 builder
.addInMozillaDom("DocGroup")
19453 for member
in descriptor
.interface
.members
:
19454 if not member
.isAttr() and not member
.isMethod():
19456 if member
.isStatic():
19457 builder
.addInMozillaDom("GlobalObject")
19458 if member
.isAttr():
19459 if not member
.isMaplikeOrSetlikeAttr():
19460 builder
.forwardDeclareForType(member
.type, config
)
19462 assert member
.isMethod()
19463 if not member
.isMaplikeOrSetlikeOrIterableMethod():
19464 for sig
in member
.signatures():
19465 builder
.forwardDeclareForType(sig
[0], config
)
19467 builder
.forwardDeclareForType(arg
.type, config
)
19469 self
.root
= CGList([builder
.build(), self
.root
], "\n")
19471 # Throw in our #includes
19472 self
.root
= CGHeaders(
19478 "nsWrapperCache.h",
19479 "nsCycleCollectionParticipant.h",
19480 "mozilla/Attributes.h",
19481 "mozilla/ErrorResult.h",
19482 "mozilla/dom/BindingDeclarations.h",
19486 "mozilla/dom/%s.h" % interfaceName
,
19489 % CGHeaders
.getDeclarationFilename(descriptor
.interface
)
19496 # And now some include guards
19497 self
.root
= CGIncludeGuard(interfaceName
, self
.root
)
19499 # And our license block comes before everything else
19500 self
.root
= CGWrapper(
19504 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
19505 /* vim:set ts=2 sw=2 sts=2 et cindent: */
19506 /* This Source Code Form is subject to the terms of the Mozilla Public
19507 * License, v. 2.0. If a copy of the MPL was not distributed with this
19508 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
19515 return self
.root
.declare()
19518 return self
.root
.define()
19521 def jsImplName(name
):
19522 return name
+ "JSImpl"
19525 class CGJSImplMember(CGNativeMember
):
19527 Base class for generating code for the members of the implementation class
19528 for a JS-implemented WebIDL interface.
19533 descriptorProvider
,
19539 passJSBitsAsNeeded
=True,
19540 visibility
="public",
19541 variadicIsSequence
=False,
19545 CGNativeMember
.__init
__(
19547 descriptorProvider
,
19552 breakAfter
=breakAfter
,
19553 passJSBitsAsNeeded
=passJSBitsAsNeeded
,
19554 visibility
=visibility
,
19555 variadicIsSequence
=variadicIsSequence
,
19559 self
.body
= self
.getImpl()
19561 def getArgs(self
, returnType
, argList
):
19562 args
= CGNativeMember
.getArgs(self
, returnType
, argList
)
19563 args
.append(Argument("JS::Realm*", "aRealm", "nullptr"))
19567 class CGJSImplMethod(CGJSImplMember
):
19569 Class for generating code for the methods for a JS-implemented WebIDL
19573 def __init__(self
, descriptor
, method
, signature
, isConstructor
, breakAfter
=True):
19574 self
.signature
= signature
19575 self
.descriptor
= descriptor
19576 self
.isConstructor
= isConstructor
19577 CGJSImplMember
.__init
__(
19581 CGSpecializedMethod
.makeNativeName(descriptor
, method
),
19583 descriptor
.getExtendedAttributes(method
),
19584 breakAfter
=breakAfter
,
19585 variadicIsSequence
=True,
19586 passJSBitsAsNeeded
=False,
19589 def getArgs(self
, returnType
, argList
):
19590 if self
.isConstructor
:
19591 # Skip the JS::Compartment bits for constructors; it's handled
19592 # manually in getImpl. But we do need our aGivenProto argument. We
19593 # allow it to be omitted if the default proto is desired.
19594 return CGNativeMember
.getArgs(self
, returnType
, argList
) + [
19595 Argument("JS::Handle<JSObject*>", "aGivenProto", "nullptr")
19597 return CGJSImplMember
.getArgs(self
, returnType
, argList
)
19600 args
= self
.getArgs(self
.signature
[0], self
.signature
[1])
19601 if not self
.isConstructor
:
19602 return "return mImpl->%s(%s);\n" % (
19604 ", ".join(arg
.name
for arg
in args
),
19607 assert self
.descriptor
.interface
.isJSImplemented()
19608 if self
.name
!= "Constructor":
19610 "Named constructors are not supported for JS implemented WebIDL. See bug 851287."
19612 if len(self
.signature
[1]) != 0:
19613 # The first two arguments to the constructor implementation are not
19614 # arguments to the WebIDL constructor, so don't pass them to
19615 # __Init(). The last argument is the prototype we're supposed to
19616 # use, and shouldn't get passed to __Init() either.
19617 assert args
[0].argType
== "const GlobalObject&"
19618 assert args
[1].argType
== "JSContext*"
19619 assert args
[-1].argType
== "JS::Handle<JSObject*>"
19620 assert args
[-1].name
== "aGivenProto"
19621 constructorArgs
= [arg
.name
for arg
in args
[2:-1]]
19622 constructorArgs
.append("js::GetNonCCWObjectRealm(scopeObj)")
19625 // Wrap the object before calling __Init so that __DOM_IMPL__ is available.
19626 JS::Rooted<JSObject*> scopeObj(cx, global.Get());
19627 MOZ_ASSERT(js::IsObjectInContextCompartment(scopeObj, cx));
19628 JS::Rooted<JS::Value> wrappedVal(cx);
19629 if (!GetOrCreateDOMReflector(cx, impl, &wrappedVal, aGivenProto)) {
19630 MOZ_ASSERT(JS_IsExceptionPending(cx));
19631 aRv.Throw(NS_ERROR_UNEXPECTED);
19634 // Initialize the object with the constructor arguments.
19635 impl->mImpl->__Init(${args});
19636 if (aRv.Failed()) {
19640 args
=", ".join(constructorArgs
),
19646 RefPtr<${implClass}> impl =
19647 ConstructJSImplementation<${implClass}>("${contractId}", global, aRv);
19648 if (aRv.Failed()) {
19652 return impl.forget();
19654 contractId
=self
.descriptor
.interface
.getJSImplementation(),
19655 implClass
=self
.descriptor
.name
,
19660 # We're always fallible
19661 def callbackGetterName(attr
, descriptor
):
19662 return "Get" + MakeNativeName(descriptor
.binaryNameFor(attr
.identifier
.name
))
19665 def callbackSetterName(attr
, descriptor
):
19666 return "Set" + MakeNativeName(descriptor
.binaryNameFor(attr
.identifier
.name
))
19669 class CGJSImplGetter(CGJSImplMember
):
19671 Class for generating code for the getters of attributes for a JS-implemented
19675 def __init__(self
, descriptor
, attr
):
19676 CGJSImplMember
.__init
__(
19680 CGSpecializedGetter
.makeNativeName(descriptor
, attr
),
19682 descriptor
.getExtendedAttributes(attr
, getter
=True),
19683 passJSBitsAsNeeded
=False,
19687 callbackArgs
= [arg
.name
for arg
in self
.getArgs(self
.member
.type, [])]
19688 return "return mImpl->%s(%s);\n" % (
19689 callbackGetterName(self
.member
, self
.descriptorProvider
),
19690 ", ".join(callbackArgs
),
19694 class CGJSImplSetter(CGJSImplMember
):
19696 Class for generating code for the setters of attributes for a JS-implemented
19700 def __init__(self
, descriptor
, attr
):
19701 CGJSImplMember
.__init
__(
19705 CGSpecializedSetter
.makeNativeName(descriptor
, attr
),
19706 (BuiltinTypes
[IDLBuiltinType
.Types
.void
], [FakeArgument(attr
.type, attr
)]),
19707 descriptor
.getExtendedAttributes(attr
, setter
=True),
19708 passJSBitsAsNeeded
=False,
19714 for arg
in self
.getArgs(
19715 BuiltinTypes
[IDLBuiltinType
.Types
.void
],
19716 [FakeArgument(self
.member
.type, self
.member
)],
19719 return "mImpl->%s(%s);\n" % (
19720 callbackSetterName(self
.member
, self
.descriptorProvider
),
19721 ", ".join(callbackArgs
),
19725 class CGJSImplClass(CGBindingImplClass
):
19726 def __init__(self
, descriptor
):
19727 CGBindingImplClass
.__init
__(
19733 skipStaticMethods
=True,
19736 if descriptor
.interface
.parent
:
19737 parentClass
= descriptor
.getDescriptor(
19738 descriptor
.interface
.parent
.identifier
.name
19740 baseClasses
= [ClassBase(parentClass
)]
19741 isupportsDecl
= "NS_DECL_ISUPPORTS_INHERITED\n"
19742 ccDecl
= "NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(%s, %s)\n" % (
19746 constructorBody
= dedent(
19748 // Make sure we're an nsWrapperCache already
19749 MOZ_ASSERT(static_cast<nsWrapperCache*>(this));
19752 extradefinitions
= fill(
19754 NS_IMPL_CYCLE_COLLECTION_INHERITED(${ifaceName}, ${parentClass}, mImpl, mParent)
19755 NS_IMPL_ADDREF_INHERITED(${ifaceName}, ${parentClass})
19756 NS_IMPL_RELEASE_INHERITED(${ifaceName}, ${parentClass})
19757 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${ifaceName})
19758 NS_INTERFACE_MAP_END_INHERITING(${parentClass})
19760 ifaceName
=self
.descriptor
.name
,
19761 parentClass
=parentClass
,
19765 ClassBase("nsSupportsWeakReference"),
19766 ClassBase("nsWrapperCache"),
19768 isupportsDecl
= "NS_DECL_CYCLE_COLLECTING_ISUPPORTS\n"
19770 "NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(%s)\n" % descriptor
.name
19772 extradefinitions
= fill(
19774 NS_IMPL_CYCLE_COLLECTION_CLASS(${ifaceName})
19775 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(${ifaceName})
19776 NS_IMPL_CYCLE_COLLECTION_UNLINK(mImpl)
19777 NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
19778 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
19779 tmp->ClearWeakReferences();
19780 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
19781 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(${ifaceName})
19782 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImpl)
19783 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
19784 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
19785 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(${ifaceName})
19786 NS_IMPL_CYCLE_COLLECTING_ADDREF(${ifaceName})
19787 NS_IMPL_CYCLE_COLLECTING_RELEASE(${ifaceName})
19788 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${ifaceName})
19789 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
19790 NS_INTERFACE_MAP_ENTRY(nsISupports)
19791 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
19792 NS_INTERFACE_MAP_END
19794 ifaceName
=self
.descriptor
.name
,
19797 extradeclarations
= fill(
19804 RefPtr<${jsImplName}> mImpl;
19805 nsCOMPtr<nsIGlobalObject> mParent;
19808 isupportsDecl
=isupportsDecl
,
19810 jsImplName
=jsImplName(descriptor
.name
),
19813 if descriptor
.interface
.getExtendedAttribute("WantsEventListenerHooks"):
19814 # No need to do too much sanity checking here; the
19815 # generated code will fail to compile if the methods we
19816 # try to overrid aren't on a superclass.
19817 self
.methodDecls
.extend(
19818 self
.getEventHookMethod(parentClass
, "EventListenerAdded")
19820 self
.methodDecls
.extend(
19821 self
.getEventHookMethod(parentClass
, "EventListenerRemoved")
19824 if descriptor
.interface
.hasChildInterfaces():
19826 # We need a protected virtual destructor our subclasses can use
19827 destructor
= ClassDestructor(virtual
=True, visibility
="protected")
19829 decorators
= "final"
19830 destructor
= ClassDestructor(virtual
=False, visibility
="private")
19832 baseConstructors
= [
19834 "mImpl(new %s(nullptr, aJSImplObject, aJSImplGlobal, /* aIncumbentGlobal = */ nullptr))"
19835 % jsImplName(descriptor
.name
)
19837 "mParent(aParent)",
19839 parentInterface
= descriptor
.interface
.parent
19840 while parentInterface
:
19841 if parentInterface
.isJSImplemented():
19842 baseConstructors
.insert(
19843 0, "%s(aJSImplObject, aJSImplGlobal, aParent)" % parentClass
19846 parentInterface
= parentInterface
.parent
19847 if not parentInterface
and descriptor
.interface
.parent
:
19848 # We only have C++ ancestors, so only pass along the window
19849 baseConstructors
.insert(0, "%s(aParent)" % parentClass
)
19851 constructor
= ClassConstructor(
19853 Argument("JS::Handle<JSObject*>", "aJSImplObject"),
19854 Argument("JS::Handle<JSObject*>", "aJSImplGlobal"),
19855 Argument("nsIGlobalObject*", "aParent"),
19857 visibility
="public",
19858 baseConstructors
=baseConstructors
,
19861 self
.methodDecls
.append(
19865 JSNativeArguments(),
19867 body
=self
.getCreateFromExistingBody(),
19872 descriptor
.interface
.isJSImplemented()
19873 and descriptor
.interface
.maplikeOrSetlikeOrIterable
19874 and descriptor
.interface
.maplikeOrSetlikeOrIterable
.isMaplike()
19876 self
.methodDecls
.append(
19881 Argument("JS::Handle<JS::Value>", "aKey"),
19882 Argument("JS::Handle<JS::Value>", "aValue"),
19883 Argument("ErrorResult&", "aRv"),
19885 body
="mImpl->__OnGet(aKey, aValue, aRv);\n",
19893 constructors
=[constructor
],
19894 destructor
=destructor
,
19895 methods
=self
.methodDecls
,
19896 decorators
=decorators
,
19897 extradeclarations
=extradeclarations
,
19898 extradefinitions
=extradefinitions
,
19901 def getWrapObjectBody(self
):
19904 JS::Rooted<JSObject*> obj(aCx, ${name}_Binding::Wrap(aCx, this, aGivenProto));
19909 // Now define it on our chrome object
19910 JSAutoRealm ar(aCx, mImpl->CallbackGlobalOrNull());
19911 if (!JS_WrapObject(aCx, &obj)) {
19914 JS::Rooted<JSObject*> callback(aCx, mImpl->CallbackOrNull());
19915 if (!JS_DefineProperty(aCx, callback, "__DOM_IMPL__", obj, 0)) {
19920 name
=self
.descriptor
.name
,
19923 def getGetParentObjectReturnType(self
):
19924 return "nsISupports*"
19926 def getGetParentObjectBody(self
):
19927 return "return mParent;\n"
19929 def getGetDocGroupBody(self
):
19932 nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mParent);
19936 return window->GetDocGroup();
19940 def getCreateFromExistingBody(self
):
19941 # XXXbz we could try to get parts of this (e.g. the argument
19942 # conversions) auto-generated by somehow creating an IDLMethod and
19943 # adding it to our interface, but we'd still need to special-case the
19944 # implementation slightly to have it not try to forward to the JS
19948 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
19949 if (!args.requireAtLeast(cx, "${ifaceName}._create", 2)) {
19952 BindingCallContext callCx(cx, "${ifaceName}._create");
19953 if (!args[0].isObject()) {
19954 return callCx.ThrowErrorMessage<MSG_NOT_OBJECT>("Argument 1");
19956 if (!args[1].isObject()) {
19957 return callCx.ThrowErrorMessage<MSG_NOT_OBJECT>("Argument 2");
19960 // GlobalObject will go through wrappers as needed for us, and
19961 // is simpler than the right UnwrapArg incantation.
19962 GlobalObject global(cx, &args[0].toObject());
19963 if (global.Failed()) {
19966 nsCOMPtr<nsIGlobalObject> globalHolder = do_QueryInterface(global.GetAsSupports());
19967 MOZ_ASSERT(globalHolder);
19968 JS::Rooted<JSObject*> arg(cx, &args[1].toObject());
19969 JS::Rooted<JSObject*> argGlobal(cx, JS::CurrentGlobalOrNull(cx));
19970 RefPtr<${implName}> impl = new ${implName}(arg, argGlobal, globalHolder);
19971 MOZ_ASSERT(js::IsObjectInContextCompartment(arg, cx));
19972 return GetOrCreateDOMReflector(cx, impl, args.rval());
19974 ifaceName
=self
.descriptor
.interface
.identifier
.name
,
19975 implName
=self
.descriptor
.name
,
19978 def getEventHookMethod(self
, parentClass
, methodName
):
19981 ${parentClass}::${methodName}(aType);
19982 mImpl->${methodName}(Substring(nsDependentAtomString(aType), 2), IgnoreErrors());
19984 parentClass
=parentClass
,
19985 methodName
=methodName
,
19991 [Argument("nsAtom*", "aType")],
19996 ClassUsingDeclaration(parentClass
, methodName
),
20000 def isJSImplementedDescriptor(descriptorProvider
):
20002 isinstance(descriptorProvider
, Descriptor
)
20003 and descriptorProvider
.interface
.isJSImplemented()
20007 class CGCallback(CGClass
):
20009 self
, idlObject
, descriptorProvider
, baseName
, methods
, getters
=[], setters
=[]
20011 self
.baseName
= baseName
20012 self
._deps
= idlObject
.getDeps()
20013 self
.idlObject
= idlObject
20014 self
.name
= idlObject
.identifier
.name
20015 if isJSImplementedDescriptor(descriptorProvider
):
20016 self
.name
= jsImplName(self
.name
)
20017 # For our public methods that needThisHandling we want most of the
20018 # same args and the same return type as what CallbackMember
20019 # generates. So we want to take advantage of all its
20020 # CGNativeMember infrastructure, but that infrastructure can't deal
20021 # with templates and most especially template arguments. So just
20022 # cheat and have CallbackMember compute all those things for us.
20024 for method
in methods
:
20025 if not isinstance(method
, CallbackMember
) or not method
.needThisHandling
:
20026 realMethods
.append(method
)
20028 realMethods
.extend(self
.getMethodImpls(method
))
20029 realMethods
.append(
20033 [Argument("const %s&" % self
.name
, "aOther")],
20037 body
=("return %s::operator==(aOther);\n" % baseName
),
20043 bases
=[ClassBase(baseName
)],
20044 constructors
=self
.getConstructors(),
20045 methods
=realMethods
+ getters
+ setters
,
20048 def getConstructors(self
):
20050 not self
.idlObject
.isInterface()
20051 and not self
.idlObject
._treatNonObjectAsNull
20053 body
= "MOZ_ASSERT(JS::IsCallable(mCallback));\n"
20055 # Not much we can assert about it, other than not being null, and
20056 # CallbackObject does that already.
20061 Argument("JSContext*", "aCx"),
20062 Argument("JS::Handle<JSObject*>", "aCallback"),
20063 Argument("JS::Handle<JSObject*>", "aCallbackGlobal"),
20064 Argument("nsIGlobalObject*", "aIncumbentGlobal"),
20067 visibility
="public",
20070 "%s(aCx, aCallback, aCallbackGlobal, aIncumbentGlobal)"
20077 Argument("JSObject*", "aCallback"),
20078 Argument("JSObject*", "aCallbackGlobal"),
20079 Argument("const FastCallbackConstructor&", ""),
20082 visibility
="public",
20085 "%s(aCallback, aCallbackGlobal, FastCallbackConstructor())"
20092 Argument("JSObject*", "aCallback"),
20093 Argument("JSObject*", "aCallbackGlobal"),
20094 Argument("JSObject*", "aAsyncStack"),
20095 Argument("nsIGlobalObject*", "aIncumbentGlobal"),
20098 visibility
="public",
20101 "%s(aCallback, aCallbackGlobal, aAsyncStack, aIncumbentGlobal)"
20108 def getMethodImpls(self
, method
):
20109 assert method
.needThisHandling
20110 args
= list(method
.args
)
20111 # Strip out the BindingCallContext&/JSObject* args
20113 assert args
[0].name
== "cx" and args
[0].argType
== "BindingCallContext&"
20114 assert args
[1].name
== "aThisVal" and args
[1].argType
== "JS::Handle<JS::Value>"
20117 # Now remember which index the ErrorResult argument is at;
20118 # we'll need this below.
20119 assert args
[-1].name
== "aRv" and args
[-1].argType
== "ErrorResult&"
20120 rvIndex
= len(args
) - 1
20121 assert rvIndex
>= 0
20123 # Record the names of all the arguments, so we can use them when we call
20124 # the private method.
20125 argnames
= [arg
.name
for arg
in args
]
20126 argnamesWithThis
= ["s.GetCallContext()", "thisValJS"] + argnames
20127 argnamesWithoutThis
= [
20128 "s.GetCallContext()",
20129 "JS::UndefinedHandleValue",
20131 # Now that we've recorded the argnames for our call to our private
20132 # method, insert our optional argument for the execution reason.
20133 args
.append(Argument("const char*", "aExecutionReason", "nullptr"))
20135 # Make copies of the arg list for the two "without rv" overloads. Note
20136 # that those don't need aExceptionHandling or aRealm arguments because
20137 # those would make not sense anyway: the only sane thing to do with
20138 # exceptions in the "without rv" cases is to report them.
20139 argsWithoutRv
= list(args
)
20140 argsWithoutRv
.pop(rvIndex
)
20141 argsWithoutThisAndRv
= list(argsWithoutRv
)
20143 # Add the potional argument for deciding whether the CallSetup should
20144 # re-throw exceptions on aRv.
20146 Argument("ExceptionHandling", "aExceptionHandling", "eReportExceptions")
20148 # And the argument for communicating when exceptions should really be
20149 # rethrown. In particular, even when aExceptionHandling is
20150 # eRethrowExceptions they won't get rethrown if aRealm is provided
20151 # and its principal doesn't subsume either the callback or the
20153 args
.append(Argument("JS::Realm*", "aRealm", "nullptr"))
20154 # And now insert our template argument.
20155 argsWithoutThis
= list(args
)
20156 args
.insert(0, Argument("const T&", "thisVal"))
20157 argsWithoutRv
.insert(0, Argument("const T&", "thisVal"))
20159 argnamesWithoutThisAndRv
= [arg
.name
for arg
in argsWithoutThisAndRv
]
20160 argnamesWithoutThisAndRv
.insert(rvIndex
, "IgnoreErrors()")
20161 # If we just leave things like that, and have no actual arguments in the
20162 # IDL, we will end up trying to call the templated "without rv" overload
20163 # with "rv" as the thisVal. That's no good. So explicitly append the
20164 # aExceptionHandling and aRealm values we need to end up matching the
20165 # signature of our non-templated "with rv" overload.
20166 argnamesWithoutThisAndRv
.extend(["eReportExceptions", "nullptr"])
20168 argnamesWithoutRv
= [arg
.name
for arg
in argsWithoutRv
]
20169 # Note that we need to insert at rvIndex + 1, since we inserted a
20170 # thisVal arg at the start.
20171 argnamesWithoutRv
.insert(rvIndex
+ 1, "IgnoreErrors()")
20173 errorReturn
= method
.getDefaultRetval()
20177 MOZ_ASSERT(!aRv.Failed(), "Don't pass an already-failed ErrorResult to a callback!");
20178 if (!aExecutionReason) {
20179 aExecutionReason = "${executionReason}";
20181 CallSetup s(this, aRv, aExecutionReason, aExceptionHandling, aRealm);
20182 if (!s.GetContext()) {
20183 MOZ_ASSERT(aRv.Failed());
20184 return${errorReturn};
20187 errorReturn
=errorReturn
,
20188 executionReason
=method
.getPrettyName(),
20191 bodyWithThis
= fill(
20194 JS::Rooted<JS::Value> thisValJS(s.GetContext());
20195 if (!ToJSValue(s.GetContext(), thisVal, &thisValJS)) {
20196 aRv.Throw(NS_ERROR_FAILURE);
20197 return${errorReturn};
20199 return ${methodName}(${callArgs});
20201 setupCall
=setupCall
,
20202 errorReturn
=errorReturn
,
20203 methodName
=method
.name
,
20204 callArgs
=", ".join(argnamesWithThis
),
20206 bodyWithoutThis
= fill(
20209 return ${methodName}(${callArgs});
20211 setupCall
=setupCall
,
20212 errorReturn
=errorReturn
,
20213 methodName
=method
.name
,
20214 callArgs
=", ".join(argnamesWithoutThis
),
20216 bodyWithThisWithoutRv
= fill(
20218 return ${methodName}(${callArgs});
20220 methodName
=method
.name
,
20221 callArgs
=", ".join(argnamesWithoutRv
),
20223 bodyWithoutThisAndRv
= fill(
20225 return ${methodName}(${callArgs});
20227 methodName
=method
.name
,
20228 callArgs
=", ".join(argnamesWithoutThisAndRv
),
20237 templateArgs
=["typename T"],
20239 canRunScript
=method
.canRunScript
,
20246 body
=bodyWithoutThis
,
20247 canRunScript
=method
.canRunScript
,
20254 templateArgs
=["typename T"],
20255 body
=bodyWithThisWithoutRv
,
20256 canRunScript
=method
.canRunScript
,
20261 argsWithoutThisAndRv
,
20263 body
=bodyWithoutThisAndRv
,
20264 canRunScript
=method
.canRunScript
,
20273 class CGCallbackFunction(CGCallback
):
20274 def __init__(self
, callback
, descriptorProvider
):
20275 self
.callback
= callback
20276 if callback
.isConstructor():
20277 methods
= [ConstructCallback(callback
, descriptorProvider
)]
20279 methods
= [CallCallback(callback
, descriptorProvider
)]
20280 CGCallback
.__init
__(
20281 self
, callback
, descriptorProvider
, "CallbackFunction", methods
20284 def getConstructors(self
):
20285 return CGCallback
.getConstructors(self
) + [
20287 [Argument("CallbackFunction*", "aOther")],
20289 visibility
="public",
20291 baseConstructors
=["CallbackFunction(aOther)"],
20296 class CGFastCallback(CGClass
):
20297 def __init__(self
, idlObject
):
20298 self
._deps
= idlObject
.getDeps()
20299 baseName
= idlObject
.identifier
.name
20300 constructor
= ClassConstructor(
20302 Argument("JSObject*", "aCallback"),
20303 Argument("JSObject*", "aCallbackGlobal"),
20306 visibility
="public",
20309 "%s(aCallback, aCallbackGlobal, FastCallbackConstructor())" % baseName
,
20314 traceMethod
= ClassMethod(
20317 [Argument("JSTracer*", "aTracer")],
20320 visibility
="public",
20321 body
="%s::Trace(aTracer);\n" % baseName
,
20323 holdMethod
= ClassMethod(
20324 "FinishSlowJSInitIfMoreThanOneOwner",
20326 [Argument("JSContext*", "aCx")],
20329 visibility
="public",
20330 body
=("%s::FinishSlowJSInitIfMoreThanOneOwner(aCx);\n" % baseName
),
20335 "Fast%s" % baseName
,
20336 bases
=[ClassBase(baseName
)],
20337 constructors
=[constructor
],
20338 methods
=[traceMethod
, holdMethod
],
20345 class CGCallbackInterface(CGCallback
):
20346 def __init__(self
, descriptor
, spiderMonkeyInterfacesAreStructs
=False):
20347 iface
= descriptor
.interface
20350 for m
in iface
.members
20353 and not m
.isStatic()
20354 and (not m
.isMaplikeOrSetlikeAttr() or not iface
.isJSImplemented())
20358 CallbackGetter(a
, descriptor
, spiderMonkeyInterfacesAreStructs
)
20362 CallbackSetter(a
, descriptor
, spiderMonkeyInterfacesAreStructs
)
20368 for m
in iface
.members
20371 and not m
.isStatic()
20372 and not m
.isIdentifierLess()
20374 not m
.isMaplikeOrSetlikeOrIterableMethod()
20375 or not iface
.isJSImplemented()
20380 CallbackOperation(m
, sig
, descriptor
, spiderMonkeyInterfacesAreStructs
)
20382 for sig
in m
.signatures()
20386 if iface
.isJSImplemented() and iface
.ctor():
20387 sigs
= descriptor
.interface
.ctor().signatures()
20389 raise TypeError("We only handle one constructor. See bug 869268.")
20390 methods
.append(CGJSImplInitOperation(sigs
[0], descriptor
))
20393 needOnGetId
= False
20395 iface
.isJSImplemented()
20396 and iface
.maplikeOrSetlikeOrIterable
20397 and iface
.maplikeOrSetlikeOrIterable
.isMaplike()
20399 methods
.append(CGJSImplOnGetOperation(descriptor
))
20403 descriptor
.binaryNameFor(m
.identifier
.name
)
20404 for m
in iface
.members
20405 if m
.isAttr() or m
.isMethod()
20408 idlist
.append("__init")
20410 idlist
.append("__onget")
20412 if iface
.isJSImplemented() and iface
.getExtendedAttribute(
20413 "WantsEventListenerHooks"
20415 methods
.append(CGJSImplEventHookOperation(descriptor
, "eventListenerAdded"))
20417 CGJSImplEventHookOperation(descriptor
, "eventListenerRemoved")
20419 idlist
.append("eventListenerAdded")
20420 idlist
.append("eventListenerRemoved")
20422 if len(idlist
) != 0:
20423 methods
.append(initIdsClassMethod(idlist
, iface
.identifier
.name
+ "Atoms"))
20424 CGCallback
.__init
__(
20428 "CallbackInterface",
20436 def __init__(self
, name
=None):
20437 if name
is not None:
20438 self
.identifier
= FakeIdentifier(name
)
20440 def isStatic(self
):
20446 def isMethod(self
):
20449 def getExtendedAttribute(self
, name
):
20450 # Claim to be a [NewObject] so we can avoid the "return a raw pointer"
20451 # comments CGNativeMember codegen would otherwise stick in.
20452 if name
== "NewObject":
20457 class CallbackMember(CGNativeMember
):
20458 # XXXbz It's OK to use CallbackKnownNotGray for wrapScope because
20459 # CallSetup already handled the unmark-gray bits for us. we don't have
20460 # anything better to use for 'obj', really...
20465 descriptorProvider
,
20467 rethrowContentException
=False,
20468 spiderMonkeyInterfacesAreStructs
=False,
20470 canRunScript
=False,
20471 passJSBitsAsNeeded
=False,
20474 needThisHandling is True if we need to be able to accept a specified
20475 thisObj, False otherwise.
20477 assert not rethrowContentException
or not needThisHandling
20479 self
.retvalType
= sig
[0]
20480 self
.originalSig
= sig
20482 self
.argCount
= len(args
)
20483 if self
.argCount
> 0:
20484 # Check for variadic arguments
20485 lastArg
= args
[self
.argCount
- 1]
20486 if lastArg
.variadic
:
20487 self
.argCountStr
= "(%d - 1) + %s.Length()" % (
20489 lastArg
.identifier
.name
,
20492 self
.argCountStr
= "%d" % self
.argCount
20493 self
.needThisHandling
= needThisHandling
20494 # If needThisHandling, we generate ourselves as private and the caller
20495 # will handle generating public versions that handle the "this" stuff.
20496 visibility
= "private" if needThisHandling
else "public"
20497 self
.rethrowContentException
= rethrowContentException
20499 self
.wrapScope
= wrapScope
20500 # We don't care, for callback codegen, whether our original member was
20501 # a method or attribute or whatnot. Just always pass FakeMember()
20503 CGNativeMember
.__init
__(
20505 descriptorProvider
,
20508 (self
.retvalType
, args
),
20509 extendedAttrs
=["needsErrorResult"],
20510 passJSBitsAsNeeded
=passJSBitsAsNeeded
,
20511 visibility
=visibility
,
20512 spiderMonkeyInterfacesAreStructs
=spiderMonkeyInterfacesAreStructs
,
20513 canRunScript
=canRunScript
,
20515 # We have to do all the generation of our body now, because
20516 # the caller relies on us throwing if we can't manage it.
20517 self
.exceptionCode
= (
20518 "aRv.Throw(NS_ERROR_UNEXPECTED);\n" "return%s;\n" % self
.getDefaultRetval()
20520 self
.body
= self
.getImpl()
20523 setupCall
= self
.getCallSetup()
20524 declRval
= self
.getRvalDecl()
20525 if self
.argCount
> 0:
20528 JS::RootedVector<JS::Value> argv(cx);
20529 if (!argv.resize(${argCount})) {
20531 return${errorReturn};
20534 argCount
=self
.argCountStr
,
20535 failureCode
=self
.getArgvDeclFailureCode(),
20536 errorReturn
=self
.getDefaultRetval(),
20539 # Avoid weird 0-sized arrays
20541 convertArgs
= self
.getArgConversions()
20542 doCall
= self
.getCall()
20543 returnResult
= self
.getResultConversion()
20545 body
= declRval
+ argvDecl
+ convertArgs
+ doCall
20546 if self
.needsScopeBody():
20547 body
= "{\n" + indent(body
) + "}\n"
20548 return setupCall
+ body
+ returnResult
20550 def needsScopeBody(self
):
20553 def getArgvDeclFailureCode(self
):
20556 // That threw an exception on the JSContext, and our CallSetup will do
20557 // the right thing with that.
20561 def getResultConversion(
20562 self
, val
="rval", failureCode
=None, isDefinitelyObject
=False, exceptionCode
=None
20566 "holderName": "rvalHolder",
20567 "declName": "rvalDecl",
20568 # We actually want to pass in a null scope object here, because
20569 # wrapping things into our current compartment (that of mCallback)
20572 "passedToJSImpl": "false",
20575 if isJSImplementedDescriptor(self
.descriptorProvider
):
20576 isCallbackReturnValue
= "JSImpl"
20578 isCallbackReturnValue
= "Callback"
20579 sourceDescription
= "return value of %s" % self
.getPrettyName()
20580 convertType
= instantiateJSToNativeConversion(
20581 getJSToNativeConversionInfo(
20583 self
.descriptorProvider
,
20584 failureCode
=failureCode
,
20585 isDefinitelyObject
=isDefinitelyObject
,
20586 exceptionCode
=exceptionCode
or self
.exceptionCode
,
20587 isCallbackReturnValue
=isCallbackReturnValue
,
20588 # Allow returning a callback type that
20589 # allows non-callable objects.
20590 allowTreatNonCallableAsNull
=True,
20591 sourceDescription
=sourceDescription
,
20595 assignRetval
= string
.Template(
20596 self
.getRetvalInfo(self
.retvalType
, False)[2]
20597 ).substitute(replacements
)
20598 type = convertType
.define()
20599 return type + assignRetval
20601 def getArgConversions(self
):
20602 # Just reget the arglist from self.originalSig, because our superclasses
20603 # just have way to many members they like to clobber, so I can't find a
20604 # safe member name to store it in.
20606 self
.getArgConversion(i
, arg
) for i
, arg
in enumerate(self
.originalSig
[1])
20608 if not argConversions
:
20611 # Do them back to front, so our argc modifications will work
20612 # correctly, because we examine trailing arguments first.
20613 argConversions
.reverse()
20614 # Wrap each one in a scope so that any locals it has don't leak out, and
20615 # also so that we can just "break;" for our successCode.
20617 CGWrapper(CGIndenter(CGGeneric(c
)), pre
="do {\n", post
="} while (false);\n")
20618 for c
in argConversions
20620 if self
.argCount
> 0:
20621 argConversions
.insert(0, self
.getArgcDecl())
20622 # And slap them together.
20623 return CGList(argConversions
, "\n").define() + "\n"
20625 def getArgConversion(self
, i
, arg
):
20626 argval
= arg
.identifier
.name
20629 argval
= argval
+ "[idx]"
20630 jsvalIndex
= "%d + idx" % i
20632 jsvalIndex
= "%d" % i
20633 if arg
.canHaveMissingValue():
20634 argval
+= ".Value()"
20636 if arg
.type.isDOMString():
20637 # XPConnect string-to-JS conversion wants to mutate the string. So
20638 # let's give it a string it can mutate
20639 # XXXbz if we try to do a sequence of strings, this will kinda fail.
20640 result
= "mutableStr"
20641 prepend
= "nsString mutableStr(%s);\n" % argval
20646 if arg
.type.isUnion() and self
.wrapScope
is None:
20648 "JS::Rooted<JSObject*> callbackObj(cx, CallbackKnownNotGray());\n"
20650 self
.wrapScope
= "callbackObj"
20652 conversion
= prepend
+ wrapForType(
20654 self
.descriptorProvider
,
20657 "successCode": "continue;\n" if arg
.variadic
else "break;\n",
20658 "jsvalRef": "argv[%s]" % jsvalIndex
,
20659 "jsvalHandle": "argv[%s]" % jsvalIndex
,
20660 "obj": self
.wrapScope
,
20661 "returnsNewObject": False,
20662 "exceptionCode": self
.exceptionCode
,
20663 "spiderMonkeyInterfacesAreStructs": self
.spiderMonkeyInterfacesAreStructs
,
20670 for (uint32_t idx = 0; idx < ${arg}.Length(); ++idx) {
20675 arg
=arg
.identifier
.name
,
20676 conversion
=conversion
,
20678 elif arg
.canHaveMissingValue():
20681 if (${argName}.WasPassed()) {
20683 } else if (argc == ${iPlus1}) {
20684 // This is our current trailing argument; reduce argc
20687 argv[${i}].setUndefined();
20690 argName
=arg
.identifier
.name
,
20691 conversion
=conversion
,
20697 def getDefaultRetval(self
):
20698 default
= self
.getRetvalInfo(self
.retvalType
, False)[1]
20699 if len(default
) != 0:
20700 default
= " " + default
20703 def getArgs(self
, returnType
, argList
):
20704 args
= CGNativeMember
.getArgs(self
, returnType
, argList
)
20705 if not self
.needThisHandling
:
20706 # Since we don't need this handling, we're the actual method that
20707 # will be called, so we need an aRethrowExceptions argument.
20708 if not self
.rethrowContentException
:
20709 args
.append(Argument("const char*", "aExecutionReason", "nullptr"))
20712 "ExceptionHandling", "aExceptionHandling", "eReportExceptions"
20715 args
.append(Argument("JS::Realm*", "aRealm", "nullptr"))
20717 # We want to allow the caller to pass in a "this" value, as
20718 # well as a BindingCallContext.
20720 Argument("BindingCallContext&", "cx"),
20721 Argument("JS::Handle<JS::Value>", "aThisVal"),
20724 def getCallSetup(self
):
20725 if self
.needThisHandling
:
20726 # It's been done for us already
20728 callSetup
= "CallSetup s(this, aRv"
20729 if self
.rethrowContentException
:
20730 # getArgs doesn't add the aExceptionHandling argument but does add
20733 ', "%s", eRethrowContentExceptions, aRealm, /* aIsJSImplementedWebIDL = */ '
20734 % self
.getPrettyName()
20736 callSetup
+= toStringBool(
20737 isJSImplementedDescriptor(self
.descriptorProvider
)
20740 callSetup
+= ', "%s", aExceptionHandling, aRealm' % self
.getPrettyName()
20741 callSetup
+= ");\n"
20745 if (aRv.Failed()) {
20746 return${errorReturn};
20748 MOZ_ASSERT(s.GetContext());
20749 BindingCallContext& cx = s.GetCallContext();
20752 callSetup
=callSetup
,
20753 errorReturn
=self
.getDefaultRetval(),
20756 def getArgcDecl(self
):
20757 return CGGeneric("unsigned argc = %s;\n" % self
.argCountStr
)
20760 def ensureASCIIName(idlObject
):
20761 type = "attribute" if idlObject
.isAttr() else "operation"
20762 if re
.match("[^\x20-\x7E]", idlObject
.identifier
.name
):
20764 'Callback %s name "%s" contains non-ASCII '
20765 "characters. We can't handle that. %s"
20766 % (type, idlObject
.identifier
.name
, idlObject
.location
)
20768 if re
.match('"', idlObject
.identifier
.name
):
20770 "Callback %s name '%s' contains "
20771 "double-quote character. We can't handle "
20772 "that. %s" % (type, idlObject
.identifier
.name
, idlObject
.location
)
20776 class ConstructCallback(CallbackMember
):
20777 def __init__(self
, callback
, descriptorProvider
):
20778 self
.callback
= callback
20779 CallbackMember
.__init
__(
20781 callback
.signatures()[0],
20783 descriptorProvider
,
20784 needThisHandling
=False,
20788 def getRvalDecl(self
):
20789 # Box constructedObj for getJSToNativeConversionInfo().
20790 return "JS::Rooted<JS::Value> rval(cx);\n"
20793 if self
.argCount
> 0:
20794 args
= "JS::HandleValueArray::subarray(argv, 0, argc)"
20796 args
= "JS::HandleValueArray::empty()"
20800 JS::Rooted<JS::Value> constructor(cx, JS::ObjectValue(*mCallback));
20801 JS::Rooted<JSObject*> constructedObj(cx);
20802 if (!JS::Construct(cx, constructor,
20803 ${args}, &constructedObj)) {
20804 aRv.NoteJSContextException(cx);
20805 return${errorReturn};
20807 rval.setObject(*constructedObj);
20810 errorReturn
=self
.getDefaultRetval(),
20813 def getResultConversion(self
):
20814 return CallbackMember
.getResultConversion(self
, isDefinitelyObject
=True)
20816 def getPrettyName(self
):
20817 return self
.callback
.identifier
.name
20820 class CallbackMethod(CallbackMember
):
20825 descriptorProvider
,
20827 rethrowContentException
=False,
20828 spiderMonkeyInterfacesAreStructs
=False,
20829 canRunScript
=False,
20831 CallbackMember
.__init
__(
20835 descriptorProvider
,
20837 rethrowContentException
,
20838 spiderMonkeyInterfacesAreStructs
=spiderMonkeyInterfacesAreStructs
,
20839 canRunScript
=canRunScript
,
20842 def getRvalDecl(self
):
20843 return "JS::Rooted<JS::Value> rval(cx);\n"
20846 if self
.argCount
> 0:
20847 args
= "JS::HandleValueArray::subarray(argv, 0, argc)"
20849 args
= "JS::HandleValueArray::empty()"
20855 if (${callGuard}!JS::Call(cx, ${thisVal}, callable,
20857 aRv.NoteJSContextException(cx);
20858 return${errorReturn};
20861 declCallable
=self
.getCallableDecl(),
20862 declThis
=self
.getThisDecl(),
20863 callGuard
=self
.getCallGuard(),
20864 thisVal
=self
.getThisVal(),
20866 errorReturn
=self
.getDefaultRetval(),
20870 class CallCallback(CallbackMethod
):
20871 def __init__(self
, callback
, descriptorProvider
):
20872 self
.callback
= callback
20873 CallbackMethod
.__init
__(
20875 callback
.signatures()[0],
20877 descriptorProvider
,
20878 needThisHandling
=True,
20879 canRunScript
=not callback
.isRunScriptBoundary(),
20882 def getThisDecl(self
):
20885 def getThisVal(self
):
20888 def getCallableDecl(self
):
20889 return "JS::Rooted<JS::Value> callable(cx, JS::ObjectValue(*mCallback));\n"
20891 def getPrettyName(self
):
20892 return self
.callback
.identifier
.name
20894 def getCallGuard(self
):
20895 if self
.callback
._treatNonObjectAsNull
:
20896 return "JS::IsCallable(mCallback) && "
20900 class CallbackOperationBase(CallbackMethod
):
20902 Common class for implementing various callback operations.
20912 rethrowContentException
=False,
20913 spiderMonkeyInterfacesAreStructs
=False,
20915 self
.singleOperation
= singleOperation
20916 self
.methodName
= descriptor
.binaryNameFor(jsName
)
20917 CallbackMethod
.__init
__(
20923 rethrowContentException
,
20924 spiderMonkeyInterfacesAreStructs
=spiderMonkeyInterfacesAreStructs
,
20927 def getThisDecl(self
):
20928 if not self
.singleOperation
:
20929 return "JS::Rooted<JS::Value> thisValue(cx, JS::ObjectValue(*mCallback));\n"
20930 # This relies on getCallableDecl declaring a boolean
20931 # isCallable in the case when we're a single-operation
20935 JS::Rooted<JS::Value> thisValue(cx, isCallable ? aThisVal.get()
20936 : JS::ObjectValue(*mCallback));
20940 def getThisVal(self
):
20943 def getCallableDecl(self
):
20944 getCallableFromProp
= fill(
20946 ${atomCacheName}* atomsCache = GetAtomCache<${atomCacheName}>(cx);
20947 if ((JSID_IS_VOID(*reinterpret_cast<jsid*>(atomsCache)) &&
20948 !InitIds(cx, atomsCache)) ||
20949 !GetCallableProperty(cx, atomsCache->${methodAtomName}, &callable)) {
20950 aRv.Throw(NS_ERROR_UNEXPECTED);
20951 return${errorReturn};
20954 methodAtomName
=CGDictionary
.makeIdName(self
.methodName
),
20955 atomCacheName
=self
.descriptorProvider
.interface
.identifier
.name
+ "Atoms",
20956 errorReturn
=self
.getDefaultRetval(),
20958 if not self
.singleOperation
:
20959 return "JS::Rooted<JS::Value> callable(cx);\n" + getCallableFromProp
20962 bool isCallable = JS::IsCallable(mCallback);
20963 JS::Rooted<JS::Value> callable(cx);
20965 callable = JS::ObjectValue(*mCallback);
20967 $*{getCallableFromProp}
20970 getCallableFromProp
=getCallableFromProp
,
20973 def getCallGuard(self
):
20977 class CallbackOperation(CallbackOperationBase
):
20979 Codegen actual WebIDL operations on callback interfaces.
20982 def __init__(self
, method
, signature
, descriptor
, spiderMonkeyInterfacesAreStructs
):
20983 self
.ensureASCIIName(method
)
20984 self
.method
= method
20985 jsName
= method
.identifier
.name
20986 CallbackOperationBase
.__init
__(
20990 MakeNativeName(descriptor
.binaryNameFor(jsName
)),
20992 descriptor
.interface
.isSingleOperationInterface(),
20993 rethrowContentException
=descriptor
.interface
.isJSImplemented(),
20994 spiderMonkeyInterfacesAreStructs
=spiderMonkeyInterfacesAreStructs
,
20997 def getPrettyName(self
):
20999 self
.descriptorProvider
.interface
.identifier
.name
,
21000 self
.method
.identifier
.name
,
21004 class CallbackAccessor(CallbackMember
):
21006 Shared superclass for CallbackGetter and CallbackSetter.
21009 def __init__(self
, attr
, sig
, name
, descriptor
, spiderMonkeyInterfacesAreStructs
):
21010 self
.ensureASCIIName(attr
)
21011 self
.attrName
= attr
.identifier
.name
21012 CallbackMember
.__init
__(
21017 needThisHandling
=False,
21018 rethrowContentException
=descriptor
.interface
.isJSImplemented(),
21019 spiderMonkeyInterfacesAreStructs
=spiderMonkeyInterfacesAreStructs
,
21022 def getPrettyName(self
):
21024 self
.descriptorProvider
.interface
.identifier
.name
,
21029 class CallbackGetter(CallbackAccessor
):
21030 def __init__(self
, attr
, descriptor
, spiderMonkeyInterfacesAreStructs
):
21031 CallbackAccessor
.__init
__(
21035 callbackGetterName(attr
, descriptor
),
21037 spiderMonkeyInterfacesAreStructs
,
21040 def getRvalDecl(self
):
21041 return "JS::Rooted<JS::Value> rval(cx);\n"
21046 JS::Rooted<JSObject *> callback(cx, mCallback);
21047 ${atomCacheName}* atomsCache = GetAtomCache<${atomCacheName}>(cx);
21048 if ((JSID_IS_VOID(*reinterpret_cast<jsid*>(atomsCache))
21049 && !InitIds(cx, atomsCache)) ||
21050 !JS_GetPropertyById(cx, callback, atomsCache->${attrAtomName}, &rval)) {
21051 aRv.Throw(NS_ERROR_UNEXPECTED);
21052 return${errorReturn};
21055 atomCacheName
=self
.descriptorProvider
.interface
.identifier
.name
+ "Atoms",
21056 attrAtomName
=CGDictionary
.makeIdName(
21057 self
.descriptorProvider
.binaryNameFor(self
.attrName
)
21059 errorReturn
=self
.getDefaultRetval(),
21063 class CallbackSetter(CallbackAccessor
):
21064 def __init__(self
, attr
, descriptor
, spiderMonkeyInterfacesAreStructs
):
21065 CallbackAccessor
.__init
__(
21068 (BuiltinTypes
[IDLBuiltinType
.Types
.void
], [FakeArgument(attr
.type, attr
)]),
21069 callbackSetterName(attr
, descriptor
),
21071 spiderMonkeyInterfacesAreStructs
,
21074 def getRvalDecl(self
):
21075 # We don't need an rval
21081 MOZ_ASSERT(argv.length() == 1);
21082 JS::Rooted<JSObject*> callback(cx, CallbackKnownNotGray());
21083 ${atomCacheName}* atomsCache = GetAtomCache<${atomCacheName}>(cx);
21084 if ((JSID_IS_VOID(*reinterpret_cast<jsid*>(atomsCache)) &&
21085 !InitIds(cx, atomsCache)) ||
21086 !JS_SetPropertyById(cx, callback, atomsCache->${attrAtomName}, argv[0])) {
21087 aRv.Throw(NS_ERROR_UNEXPECTED);
21088 return${errorReturn};
21091 atomCacheName
=self
.descriptorProvider
.interface
.identifier
.name
+ "Atoms",
21092 attrAtomName
=CGDictionary
.makeIdName(
21093 self
.descriptorProvider
.binaryNameFor(self
.attrName
)
21095 errorReturn
=self
.getDefaultRetval(),
21098 def getArgcDecl(self
):
21102 class CGJSImplInitOperation(CallbackOperationBase
):
21104 Codegen the __Init() method used to pass along constructor arguments for JS-implemented WebIDL.
21107 def __init__(self
, sig
, descriptor
):
21108 assert sig
in descriptor
.interface
.ctor().signatures()
21109 CallbackOperationBase
.__init
__(
21111 (BuiltinTypes
[IDLBuiltinType
.Types
.void
], sig
[1]),
21115 singleOperation
=False,
21116 rethrowContentException
=True,
21117 spiderMonkeyInterfacesAreStructs
=True,
21120 def getPrettyName(self
):
21124 class CGJSImplOnGetOperation(CallbackOperationBase
):
21126 Codegen the __OnGet() method used to notify the JS impl that a get() is
21127 happening on a JS-implemented maplike. This method takes two arguments
21128 (key and value) and returns nothing.
21131 def __init__(self
, descriptor
):
21132 CallbackOperationBase
.__init
__(
21135 BuiltinTypes
[IDLBuiltinType
.Types
.void
],
21137 FakeArgument(BuiltinTypes
[IDLBuiltinType
.Types
.any
], None, "key"),
21138 FakeArgument(BuiltinTypes
[IDLBuiltinType
.Types
.any
], None, "value"),
21144 singleOperation
=False,
21145 rethrowContentException
=True,
21146 spiderMonkeyInterfacesAreStructs
=True,
21149 def getPrettyName(self
):
21153 class CGJSImplEventHookOperation(CallbackOperationBase
):
21155 Codegen the hooks on a JS impl for adding/removing event listeners.
21158 def __init__(self
, descriptor
, name
):
21161 CallbackOperationBase
.__init
__(
21164 BuiltinTypes
[IDLBuiltinType
.Types
.void
],
21167 BuiltinTypes
[IDLBuiltinType
.Types
.domstring
], None, "aType"
21172 MakeNativeName(name
),
21174 singleOperation
=False,
21175 rethrowContentException
=False,
21176 spiderMonkeyInterfacesAreStructs
=True,
21179 def getPrettyName(self
):
21183 def getMaplikeOrSetlikeErrorReturn(helperImpl
):
21185 Generate return values based on whether a maplike or setlike generated
21186 method is an interface method (which returns bool) or a helper function
21187 (which uses ErrorResult).
21192 aRv.Throw(NS_ERROR_UNEXPECTED);
21195 % helperImpl
.getDefaultRetval()
21197 return "return false;\n"
21200 def getMaplikeOrSetlikeBackingObject(descriptor
, maplikeOrSetlike
, helperImpl
=None):
21202 Generate code to get/create a JS backing object for a maplike/setlike
21203 declaration from the declaration slot.
21205 func_prefix
= maplikeOrSetlike
.maplikeOrSetlikeOrIterableType
.title()
21208 JS::Rooted<JSObject*> backingObj(cx);
21209 bool created = false;
21210 if (!Get${func_prefix}BackingObject(cx, obj, ${slot}, &backingObj, &created)) {
21214 PreserveWrapper<${selfType}>(self);
21217 slot
=memberReservedSlot(maplikeOrSetlike
, descriptor
),
21218 func_prefix
=func_prefix
,
21219 errorReturn
=getMaplikeOrSetlikeErrorReturn(helperImpl
),
21220 selfType
=descriptor
.nativeType
,
21225 def getMaplikeOrSetlikeSizeGetterBody(descriptor
, attr
):
21227 Creates the body for the size getter method of maplike/setlike interfaces.
21229 # We should only have one declaration attribute currently
21230 assert attr
.identifier
.name
== "size"
21231 assert attr
.isMaplikeOrSetlikeAttr()
21235 uint32_t result = JS::${funcPrefix}Size(cx, backingObj);
21236 MOZ_ASSERT(!JS_IsExceptionPending(cx));
21237 args.rval().setNumber(result);
21240 getBackingObj
=getMaplikeOrSetlikeBackingObject(
21241 descriptor
, attr
.maplikeOrSetlike
21243 funcPrefix
=attr
.maplikeOrSetlike
.prefix
,
21247 class CGMaplikeOrSetlikeMethodGenerator(CGThing
):
21249 Creates methods for maplike/setlike interfaces. It is expected that all
21250 methods will be have a maplike/setlike object attached. Unwrapping/wrapping
21251 will be taken care of by the usual method generation machinery in
21252 CGMethodCall/CGPerSignatureCall. Functionality is filled in here instead of
21253 using CGCallGenerator.
21261 needsValueTypeReturn
=False,
21264 CGThing
.__init
__(self
)
21265 # True if this will be the body of a C++ helper function.
21266 self
.helperImpl
= helperImpl
21267 self
.descriptor
= descriptor
21268 self
.maplikeOrSetlike
= maplikeOrSetlike
21269 self
.cgRoot
= CGList([])
21270 impl_method_name
= methodName
21271 if impl_method_name
[0] == "_":
21272 # double underscore means this is a js-implemented chrome only rw
21273 # function. Truncate the double underscore so calling the right
21274 # underlying JSAPI function still works.
21275 impl_method_name
= impl_method_name
[2:]
21276 self
.cgRoot
.append(
21278 getMaplikeOrSetlikeBackingObject(
21279 self
.descriptor
, self
.maplikeOrSetlike
, self
.helperImpl
21283 self
.returnStmt
= getMaplikeOrSetlikeErrorReturn(self
.helperImpl
)
21285 # Generates required code for the method. Method descriptions included
21286 # in definitions below. Throw if we don't have a method to fill in what
21287 # we're looking for.
21289 methodGenerator
= getattr(self
, impl_method_name
)
21290 except AttributeError:
21292 "Missing %s method definition '%s'"
21293 % (self
.maplikeOrSetlike
.maplikeOrSetlikeType
, methodName
)
21295 # Method generator returns tuple, containing:
21297 # - a list of CGThings representing setup code for preparing to call
21298 # the JS API function
21299 # - a list of arguments needed for the JS API function we're calling
21300 # - list of code CGThings needed for return value conversion.
21301 (setupCode
, arguments
, setResult
) = methodGenerator()
21303 # Create the actual method call, and then wrap it with the code to
21304 # return the value if needed.
21305 funcName
= self
.maplikeOrSetlike
.prefix
+ MakeNativeName(impl_method_name
)
21306 # Append the list of setup code CGThings
21307 self
.cgRoot
.append(CGList(setupCode
))
21308 # Create the JS API call
21311 if (!JS::${funcName}(${args})) {
21317 if needsValueTypeReturn
:
21318 assert self
.helperImpl
and impl_method_name
== "get"
21321 if (result.isUndefined()) {
21322 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
21326 retval
=self
.helperImpl
.getDefaultRetval(),
21329 self
.cgRoot
.append(
21335 args
=", ".join(["cx", "backingObj"] + arguments
),
21336 errorReturn
=self
.returnStmt
,
21341 # Append result conversion
21342 self
.cgRoot
.append(CGList(setResult
))
21344 def mergeTuples(self
, a
, b
):
21346 Expecting to take 2 tuples were all elements are lists, append the lists in
21347 the second tuple to the lists in the first.
21349 return tuple([x
+ y
for x
, y
in zip(a
, b
)])
21351 def appendArgConversion(self
, name
):
21353 Generate code to convert arguments to JS::Values, so they can be
21354 passed into JSAPI functions.
21359 JS::Rooted<JS::Value> ${name}Val(cx);
21360 if (!ToJSValue(cx, ${name}, &${name}Val)) {
21365 errorReturn
=self
.returnStmt
,
21369 def appendKeyArgConversion(self
):
21371 Generates the key argument for methods. Helper functions will use
21372 a RootedVector<JS::Value>, while interface methods have separate JS::Values.
21374 if self
.helperImpl
:
21375 return ([], ["argv[0]"], [])
21376 return ([self
.appendArgConversion("arg0")], ["arg0Val"], [])
21378 def appendKeyAndValueArgConversion(self
):
21380 Generates arguments for methods that require a key and value. Helper
21381 functions will use a RootedVector<JS::Value>, while interface methods have
21382 separate JS::Values.
21384 r
= self
.appendKeyArgConversion()
21385 if self
.helperImpl
:
21386 return self
.mergeTuples(r
, ([], ["argv[1]"], []))
21387 return self
.mergeTuples(
21388 r
, ([self
.appendArgConversion("arg1")], ["arg1Val"], [])
21391 def appendIteratorResult(self
):
21393 Generate code to output JSObject* return values, needed for functions that
21394 return iterators. Iterators cannot currently be wrapped via Xrays. If
21395 something that would return an iterator is called via Xray, fail early.
21397 # TODO: Bug 1173651 - Remove check once bug 1023984 is fixed.
21401 // TODO (Bug 1173651): Xrays currently cannot wrap iterators. Change
21402 // after bug 1023984 is fixed.
21403 if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
21404 JS_ReportErrorASCII(cx, "Xray wrapping of iterators not supported.");
21407 JS::Rooted<JSObject*> result(cx);
21408 JS::Rooted<JS::Value> v(cx);
21413 setResult
= CGGeneric(
21416 result = &v.toObject();
21420 return ([code
], [arguments
], [setResult
])
21422 def appendSelfResult(self
):
21424 Generate code to return the interface object itself.
21429 JS::Rooted<JSObject*> result(cx);
21433 setResult
= CGGeneric(
21440 return ([code
], [], [setResult
])
21442 def appendBoolResult(self
):
21443 if self
.helperImpl
:
21444 return ([CGGeneric()], ["&aRetVal"], [])
21445 return ([CGGeneric("bool result;\n")], ["&result"], [])
21449 void forEach(callback c, any thisval);
21451 ForEach takes a callback, and a possible value to use as 'this'. The
21452 callback needs to take value, key, and the interface object
21453 implementing maplike/setlike. In order to make sure that the third arg
21454 is our interface object instead of the map/set backing object, we
21455 create a js function with the callback and original object in its
21456 storage slots, then use a helper function in BindingUtils to make sure
21457 the callback is called correctly.
21459 assert not self
.helperImpl
21464 // Create a wrapper function.
21465 JSFunction* func = js::NewFunctionWithReserved(cx, ForEachHandler, 3, 0, nullptr);
21469 JS::Rooted<JSObject*> funcObj(cx, JS_GetFunctionObject(func));
21470 JS::Rooted<JS::Value> funcVal(cx, JS::ObjectValue(*funcObj));
21471 js::SetFunctionNativeReserved(funcObj, FOREACH_CALLBACK_SLOT,
21472 JS::ObjectValue(*arg0));
21473 js::SetFunctionNativeReserved(funcObj, FOREACH_MAPLIKEORSETLIKEOBJ_SLOT,
21474 JS::ObjectValue(*obj));
21479 arguments
= ["funcVal", "arg1"]
21480 return (code
, arguments
, [])
21484 object set(key, value);
21486 Maplike only function, takes key and sets value to it, returns
21487 interface object unless being called from a C++ helper.
21489 assert self
.maplikeOrSetlike
.isMaplike()
21490 r
= self
.appendKeyAndValueArgConversion()
21491 if self
.helperImpl
:
21493 return self
.mergeTuples(r
, self
.appendSelfResult())
21499 Setlike only function, adds value to set, returns interface object
21500 unless being called from a C++ helper
21502 assert self
.maplikeOrSetlike
.isSetlike()
21503 r
= self
.appendKeyArgConversion()
21504 if self
.helperImpl
:
21506 return self
.mergeTuples(r
, self
.appendSelfResult())
21512 Retrieves a value from a backing object based on the key. Returns value
21513 if key is in backing object, undefined otherwise.
21515 assert self
.maplikeOrSetlike
.isMaplike()
21516 r
= self
.appendKeyArgConversion()
21519 # We don't need to create the result variable because it'll be created elsewhere
21520 # for JSObject Get method
21521 if not self
.helperImpl
or not self
.helperImpl
.handleJSObjectGetHelper():
21526 JS::Rooted<JS::Value> result(cx);
21532 arguments
= ["&result"]
21535 self
.descriptor
.interface
.isJSImplemented()
21536 and not self
.helperImpl
# For C++ MaplikeHelper Get method, we don't notify underlying js implementation
21543 JS::ExposeValueToActiveJS(result);
21544 ErrorResult onGetResult;
21545 self->__OnGet(arg0Val, result, onGetResult);
21546 if (onGetResult.MaybeSetPendingException(cx)) {
21554 return self
.mergeTuples(r
, (code
, arguments
, callOnGet
))
21560 Check if an entry exists in the backing object. Returns true if value
21561 exists in backing object, false otherwise.
21563 return self
.mergeTuples(self
.appendKeyArgConversion(), self
.appendBoolResult())
21569 Returns new object iterator with all keys from backing object.
21571 return self
.appendIteratorResult()
21577 Returns new object iterator with all values from backing object.
21579 return self
.appendIteratorResult()
21585 Returns new object iterator with all keys and values from backing
21586 object. Keys will be null for set.
21588 return self
.appendIteratorResult()
21594 Removes all entries from map/set.
21596 return ([], [], [])
21602 Deletes an entry from the backing object. Returns true if value existed
21603 in backing object, false otherwise.
21605 return self
.mergeTuples(self
.appendKeyArgConversion(), self
.appendBoolResult())
21608 return self
.cgRoot
.define()
21611 class CGMaplikeOrSetlikeHelperFunctionGenerator(CallbackMember
):
21613 Generates code to allow C++ to perform operations on backing objects. Gets
21614 a context from the binding wrapper, turns arguments into JS::Values (via
21615 CallbackMember/CGNativeMember argument conversion), then uses
21616 CGMaplikeOrSetlikeMethodGenerator to generate the body.
21620 class HelperFunction(CGAbstractMethod
):
21622 Generates context retrieval code and rooted JSObject for interface for
21623 CGMaplikeOrSetlikeMethodGenerator to use
21626 def __init__(self
, descriptor
, name
, args
, code
, returnType
):
21628 CGAbstractMethod
.__init
__(self
, descriptor
, name
, returnType
, args
)
21630 def definition_body(self
):
21639 needsValueArg
=False,
21640 needsValueTypeReturn
=False,
21641 needsBoolReturn
=False,
21643 assert not (needsValueTypeReturn
and needsBoolReturn
)
21645 self
.maplikeOrSetlike
= maplikeOrSetlike
21646 self
.needsBoolReturn
= needsBoolReturn
21647 self
.needsValueTypeReturn
= needsValueTypeReturn
21650 BuiltinTypes
[IDLBuiltinType
.Types
.void
]
21651 if not self
.needsValueTypeReturn
21652 else maplikeOrSetlike
.valueType
21656 args
.append(FakeArgument(maplikeOrSetlike
.keyType
, None, "aKey"))
21659 assert not needsValueTypeReturn
21660 args
.append(FakeArgument(maplikeOrSetlike
.valueType
, None, "aValue"))
21661 # Run CallbackMember init function to generate argument conversion code.
21662 # wrapScope is set to 'obj' when generating maplike or setlike helper
21663 # functions, as we don't have access to the CallbackPreserveColor
21665 CallbackMember
.__init
__(
21667 [returnType
, args
],
21672 passJSBitsAsNeeded
=self
.handleJSObjectGetHelper(),
21675 if self
.needsValueTypeReturn
:
21676 finalReturnType
= self
.returnType
21677 elif needsBoolReturn
:
21678 finalReturnType
= "bool"
21680 finalReturnType
= "void"
21681 # Wrap CallbackMember body code into a CGAbstractMethod to make
21682 # generation easier.
21683 self
.implMethod
= CGMaplikeOrSetlikeHelperFunctionGenerator
.HelperFunction(
21684 descriptor
, name
, self
.args
, self
.body
, finalReturnType
21687 def getCallSetup(self
):
21688 # If handleJSObjectGetHelper is true, it means the caller will provide a JSContext,
21689 # so we don't need to create JSContext and enter UnprivilegedJunkScopeOrWorkerGlobal here.
21690 code
= "MOZ_ASSERT(self);\n"
21691 if not self
.handleJSObjectGetHelper():
21696 JSContext* cx = jsapi.cx();
21697 // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here because
21698 // all we want is to wrap into _some_ scope and then unwrap to find
21699 // the reflector, and wrapping has no side-effects.
21700 JSObject* scope = UnprivilegedJunkScopeOrWorkerGlobal(fallible);
21702 aRv.Throw(NS_ERROR_UNEXPECTED);
21705 JSAutoRealm tempRealm(cx, scope);
21707 % self
.getDefaultRetval()
21712 JS::Rooted<JS::Value> v(cx);
21713 if(!ToJSValue(cx, self, &v)) {
21714 aRv.Throw(NS_ERROR_UNEXPECTED);
21717 // This is a reflector, but due to trying to name things
21718 // similarly across method generators, it's called obj here.
21719 JS::Rooted<JSObject*> obj(cx);
21720 obj = js::UncheckedUnwrap(&v.toObject(), /* stopAtWindowProxy = */ false);
21722 % self
.getDefaultRetval()
21725 # For the JSObject Get method, we'd like wrap the inner code in a scope such that
21726 # the code can use the same realm. So here we are creating the result variable
21727 # outside of the scope.
21728 if self
.handleJSObjectGetHelper():
21731 JS::Rooted<JS::Value> result(cx);
21737 JSAutoRealm reflectorRealm(cx, obj);
21742 def getArgs(self
, returnType
, argList
):
21743 # We don't need the context or the value. We'll generate those instead.
21744 args
= CGNativeMember
.getArgs(self
, returnType
, argList
)
21745 # Prepend a pointer to the binding object onto the arguments
21746 return [Argument(self
.descriptorProvider
.nativeType
+ "*", "self")] + args
21748 def needsScopeBody(self
):
21749 return self
.handleJSObjectGetHelper()
21751 def getArgvDeclFailureCode(self
):
21752 return "aRv.Throw(NS_ERROR_UNEXPECTED);\n"
21754 def handleJSObjectGetHelper(self
):
21755 return self
.needsValueTypeReturn
and self
.maplikeOrSetlike
.valueType
.isObject()
21757 def getResultConversion(self
):
21758 if self
.needsBoolReturn
:
21759 return "return aRetVal;\n"
21760 elif self
.needsValueTypeReturn
:
21762 if self
.handleJSObjectGetHelper():
21765 if (!JS_WrapValue(cx, &result)) {
21766 aRv.NoteJSContextException(cx);
21772 failureCode
= dedent("aRv.Throw(NS_ERROR_UNEXPECTED);\nreturn nullptr;\n")
21774 exceptionCode
= None
21775 if self
.maplikeOrSetlike
.valueType
.isPrimitive():
21776 exceptionCode
= dedent(
21777 "aRv.NoteJSContextException(cx);\nreturn%s;\n"
21778 % self
.getDefaultRetval()
21781 return code
+ CallbackMember
.getResultConversion(
21784 failureCode
=failureCode
,
21785 isDefinitelyObject
=True,
21786 exceptionCode
=exceptionCode
,
21790 def getRvalDecl(self
):
21791 if self
.needsBoolReturn
:
21792 return "bool aRetVal;\n"
21793 elif self
.handleJSObjectGetHelper():
21794 return "JSAutoRealm reflectorRealm(cx, obj);\n"
21797 def getArgcDecl(self
):
21798 # Don't need argc for anything.
21801 def getDefaultRetval(self
):
21802 if self
.needsBoolReturn
:
21804 elif self
.needsValueTypeReturn
:
21805 return CallbackMember
.getDefaultRetval(self
)
21809 return CGMaplikeOrSetlikeMethodGenerator(
21810 self
.descriptorProvider
,
21811 self
.maplikeOrSetlike
,
21813 self
.needsValueTypeReturn
,
21817 def getPrettyName(self
):
21821 return self
.implMethod
.declare()
21824 return self
.implMethod
.define()
21827 class CGMaplikeOrSetlikeHelperGenerator(CGNamespace
):
21829 Declares and defines convenience methods for accessing backing objects on
21830 setlike/maplike interface. Generates function signatures, un/packs
21831 backing objects from slot, etc.
21834 def __init__(self
, descriptor
, maplikeOrSetlike
):
21835 self
.descriptor
= descriptor
21836 # Since iterables are folded in with maplike/setlike, make sure we've
21837 # got the right type here.
21838 assert maplikeOrSetlike
.isMaplike() or maplikeOrSetlike
.isSetlike()
21839 self
.maplikeOrSetlike
= maplikeOrSetlike
21840 self
.namespace
= "%sHelpers" % (
21841 self
.maplikeOrSetlike
.maplikeOrSetlikeOrIterableType
.title()
21844 CGMaplikeOrSetlikeHelperFunctionGenerator(
21845 descriptor
, maplikeOrSetlike
, "Clear"
21847 CGMaplikeOrSetlikeHelperFunctionGenerator(
21852 needsBoolReturn
=True,
21854 CGMaplikeOrSetlikeHelperFunctionGenerator(
21859 needsBoolReturn
=True,
21862 if self
.maplikeOrSetlike
.isMaplike():
21863 self
.helpers
.append(
21864 CGMaplikeOrSetlikeHelperFunctionGenerator(
21869 needsValueArg
=True,
21872 self
.helpers
.append(
21873 CGMaplikeOrSetlikeHelperFunctionGenerator(
21878 needsValueTypeReturn
=True,
21882 assert self
.maplikeOrSetlike
.isSetlike()
21883 self
.helpers
.append(
21884 CGMaplikeOrSetlikeHelperFunctionGenerator(
21885 descriptor
, maplikeOrSetlike
, "Add", needsKeyArg
=True
21888 CGNamespace
.__init
__(self
, self
.namespace
, CGList(self
.helpers
))
21891 class CGIterableMethodGenerator(CGGeneric
):
21893 Creates methods for iterable interfaces. Unwrapping/wrapping
21894 will be taken care of by the usual method generation machinery in
21895 CGMethodCall/CGPerSignatureCall. Functionality is filled in here instead of
21896 using CGCallGenerator.
21899 def __init__(self
, descriptor
, iterable
, methodName
):
21900 if methodName
== "forEach":
21901 CGGeneric
.__init
__(
21905 if (!JS::IsCallable(arg0)) {
21906 cx.ThrowErrorMessage<MSG_NOT_CALLABLE>("Argument 1");
21909 JS::RootedValueArray<3> callArgs(cx);
21910 callArgs[2].setObject(*obj);
21911 JS::Rooted<JS::Value> ignoredReturnVal(cx);
21912 auto GetKeyAtIndex = &${selfType}::GetKeyAtIndex;
21913 auto GetValueAtIndex = &${selfType}::GetValueAtIndex;
21914 for (size_t i = 0; i < self->GetIterableLength(); ++i) {
21915 if (!CallIterableGetter(cx, GetValueAtIndex, self, i,
21919 if (!CallIterableGetter(cx, GetKeyAtIndex, self, i,
21923 if (!JS::Call(cx, arg1, arg0, JS::HandleValueArray(callArgs),
21924 &ignoredReturnVal)) {
21929 ifaceName
=descriptor
.interface
.identifier
.name
,
21930 selfType
=descriptor
.nativeType
,
21934 CGGeneric
.__init
__(
21938 typedef ${iterClass} itrType;
21939 RefPtr<itrType> result(new itrType(self,
21940 itrType::IterableIteratorType::${itrMethod},
21941 &${ifaceName}Iterator_Binding::Wrap));
21943 iterClass
=iteratorNativeType(descriptor
),
21944 ifaceName
=descriptor
.interface
.identifier
.name
,
21945 itrMethod
=methodName
.title(),
21950 class GlobalGenRoots
:
21952 Roots for global codegen.
21954 To generate code, call the method associated with the target, and then
21955 call the appropriate define/declare method.
21959 def GeneratedAtomList(config
):
21961 dictionaries
= config
.dictionaries
21965 def memberToAtomCacheMember(binaryNameFor
, m
):
21966 binaryMemberName
= binaryNameFor(m
.identifier
.name
)
21967 return ClassMember(
21968 CGDictionary
.makeIdName(binaryMemberName
),
21970 visibility
="public",
21973 def buildAtomCacheStructure(idlobj
, binaryNameFor
, members
):
21974 classMembers
= [memberToAtomCacheMember(binaryNameFor
, m
) for m
in members
]
21975 structName
= idlobj
.identifier
.name
+ "Atoms"
21980 structName
, bases
=None, isStruct
=True, members
=classMembers
21986 for dict in dictionaries
:
21987 if len(dict.members
) == 0:
21990 structs
.append(buildAtomCacheStructure(dict, lambda x
: x
, dict.members
))
21992 for d
in config
.getDescriptors(isJSImplemented
=True) + config
.getDescriptors(
21995 members
= [m
for m
in d
.interface
.members
if m
.isAttr() or m
.isMethod()]
21996 if d
.interface
.isJSImplemented() and d
.interface
.ctor():
21997 # We'll have an __init() method.
21998 members
.append(FakeMember("__init"))
22000 d
.interface
.isJSImplemented()
22001 and d
.interface
.maplikeOrSetlikeOrIterable
22002 and d
.interface
.maplikeOrSetlikeOrIterable
.isMaplike()
22004 # We'll have an __onget() method.
22005 members
.append(FakeMember("__onget"))
22006 if d
.interface
.isJSImplemented() and d
.interface
.getExtendedAttribute(
22007 "WantsEventListenerHooks"
22009 members
.append(FakeMember("eventListenerAdded"))
22010 members
.append(FakeMember("eventListenerRemoved"))
22011 if len(members
) == 0:
22015 buildAtomCacheStructure(
22016 d
.interface
, lambda x
: d
.binaryNameFor(x
), members
22021 generatedStructs
= [struct
for structName
, struct
in structs
]
22022 structNames
= [structName
for structName
, struct
in structs
]
22024 mainStruct
= CGWrapper(
22026 "PerThreadAtomCache",
22027 bases
=[ClassBase(structName
) for structName
in structNames
],
22033 structs
= CGList(generatedStructs
+ [mainStruct
])
22035 # Wrap all of that in our namespaces.
22036 curr
= CGNamespace
.build(["mozilla", "dom"], CGWrapper(structs
, pre
="\n"))
22037 curr
= CGWrapper(curr
, post
="\n")
22039 # Add include statement for PinnedStringId.
22040 declareIncludes
= ["mozilla/dom/PinnedStringId.h"]
22041 curr
= CGHeaders([], [], [], [], declareIncludes
, [], "GeneratedAtomList", curr
)
22043 # Add include guards.
22044 curr
= CGIncludeGuard("GeneratedAtomList", curr
)
22046 # Add the auto-generated comment.
22047 curr
= CGWrapper(curr
, pre
=AUTOGENERATED_WARNING_COMMENT
)
22053 def GeneratedEventList(config
):
22054 eventList
= CGList([])
22055 for generatedEvent
in config
.generatedEvents
:
22057 CGGeneric(declare
=("GENERATED_EVENT(%s)\n" % generatedEvent
))
22062 def PrototypeList(config
):
22064 # Prototype ID enum.
22065 descriptorsWithPrototype
= config
.getDescriptors(
22066 hasInterfacePrototypeObject
=True
22068 protos
= [d
.name
for d
in descriptorsWithPrototype
]
22069 idEnum
= CGNamespacedEnum("id", "ID", ["_ID_Start"] + protos
, [0, "_ID_Start"])
22070 idEnum
= CGList([idEnum
])
22072 def fieldSizeAssert(amount
, jitInfoField
, message
):
22074 "(uint64_t(1) << (sizeof(std::declval<JSJitInfo>().%s) * 8))"
22078 define
='static_assert(%s < %s, "%s");\n\n'
22079 % (amount
, maxFieldValue
, message
)
22083 fieldSizeAssert("id::_ID_Count", "protoID", "Too many prototypes!")
22086 # Wrap all of that in our namespaces.
22087 idEnum
= CGNamespace
.build(
22088 ["mozilla", "dom", "prototypes"], CGWrapper(idEnum
, pre
="\n")
22090 idEnum
= CGWrapper(idEnum
, post
="\n")
22094 CGGeneric(define
="#include <stdint.h>\n"),
22095 CGGeneric(define
="#include <type_traits>\n\n"),
22096 CGGeneric(define
='#include "js/experimental/JitInfo.h"\n\n'),
22097 CGGeneric(define
='#include "mozilla/dom/PrototypeList.h"\n\n'),
22102 # Let things know the maximum length of the prototype chain.
22103 maxMacroName
= "MAX_PROTOTYPE_CHAIN_LENGTH"
22104 maxMacro
= CGGeneric(
22105 declare
="#define " + maxMacroName
+ " " + str(config
.maxProtoChainLength
)
22107 curr
.append(CGWrapper(maxMacro
, post
="\n\n"))
22110 maxMacroName
, "depth", "Some inheritance chain is too long!"
22114 # Constructor ID enum.
22115 constructors
= [d
.name
for d
in config
.getDescriptors(hasInterfaceObject
=True)]
22116 idEnum
= CGNamespacedEnum(
22119 ["_ID_Start"] + constructors
,
22120 ["prototypes::id::_ID_Count", "_ID_Start"],
22123 # Wrap all of that in our namespaces.
22124 idEnum
= CGNamespace
.build(
22125 ["mozilla", "dom", "constructors"], CGWrapper(idEnum
, pre
="\n")
22127 idEnum
= CGWrapper(idEnum
, post
="\n")
22129 curr
.append(idEnum
)
22131 # Named properties object enum.
22132 namedPropertiesObjects
= [
22133 d
.name
for d
in config
.getDescriptors(hasNamedPropertiesObject
=True)
22135 idEnum
= CGNamespacedEnum(
22138 ["_ID_Start"] + namedPropertiesObjects
,
22139 ["constructors::id::_ID_Count", "_ID_Start"],
22142 # Wrap all of that in our namespaces.
22143 idEnum
= CGNamespace
.build(
22144 ["mozilla", "dom", "namedpropertiesobjects"], CGWrapper(idEnum
, pre
="\n")
22146 idEnum
= CGWrapper(idEnum
, post
="\n")
22148 curr
.append(idEnum
)
22154 template <prototypes::ID PrototypeID>
22155 struct PrototypeTraits;
22160 traitsDecls
.extend(CGPrototypeTraitsClass(d
) for d
in descriptorsWithPrototype
)
22162 ifaceNamesWithProto
= [
22163 d
.interface
.identifier
.name
for d
in descriptorsWithPrototype
22165 traitsDecls
.append(
22166 CGStringTable("NamesOfInterfacesWithProtos", ifaceNamesWithProto
)
22169 traitsDecl
= CGNamespace
.build(["mozilla", "dom"], CGList(traitsDecls
))
22171 curr
.append(traitsDecl
)
22173 # Add include guards.
22174 curr
= CGIncludeGuard("PrototypeList", curr
)
22176 # Add the auto-generated comment.
22177 curr
= CGWrapper(curr
, pre
=AUTOGENERATED_WARNING_COMMENT
)
22183 def RegisterBindings(config
):
22185 curr
= CGNamespace
.build(["mozilla", "dom"], CGGlobalNames(config
))
22186 curr
= CGWrapper(curr
, post
="\n")
22190 CGHeaders
.getDeclarationFilename(desc
.interface
)
22191 for desc
in config
.getDescriptors(
22192 hasInterfaceObject
=True, isExposedInWindow
=True, register
=True
22195 defineIncludes
.append("mozilla/dom/WebIDLGlobalNameHash.h")
22196 defineIncludes
.append("mozilla/dom/PrototypeList.h")
22197 defineIncludes
.append("mozilla/PerfectHash.h")
22198 defineIncludes
.append("js/String.h")
22199 curr
= CGHeaders([], [], [], [], [], defineIncludes
, "RegisterBindings", curr
)
22201 # Add include guards.
22202 curr
= CGIncludeGuard("RegisterBindings", curr
)
22208 def RegisterWorkerBindings(config
):
22210 curr
= CGRegisterWorkerBindings(config
)
22212 # Wrap all of that in our namespaces.
22213 curr
= CGNamespace
.build(["mozilla", "dom"], CGWrapper(curr
, post
="\n"))
22214 curr
= CGWrapper(curr
, post
="\n")
22218 CGHeaders
.getDeclarationFilename(desc
.interface
)
22219 for desc
in config
.getDescriptors(
22220 hasInterfaceObject
=True, register
=True, isExposedInAnyWorker
=True
22225 [], [], [], [], [], defineIncludes
, "RegisterWorkerBindings", curr
22228 # Add include guards.
22229 curr
= CGIncludeGuard("RegisterWorkerBindings", curr
)
22235 def RegisterWorkerDebuggerBindings(config
):
22237 curr
= CGRegisterWorkerDebuggerBindings(config
)
22239 # Wrap all of that in our namespaces.
22240 curr
= CGNamespace
.build(["mozilla", "dom"], CGWrapper(curr
, post
="\n"))
22241 curr
= CGWrapper(curr
, post
="\n")
22245 CGHeaders
.getDeclarationFilename(desc
.interface
)
22246 for desc
in config
.getDescriptors(
22247 hasInterfaceObject
=True, register
=True, isExposedInWorkerDebugger
=True
22252 [], [], [], [], [], defineIncludes
, "RegisterWorkerDebuggerBindings", curr
22255 # Add include guards.
22256 curr
= CGIncludeGuard("RegisterWorkerDebuggerBindings", curr
)
22262 def RegisterWorkletBindings(config
):
22264 curr
= CGRegisterWorkletBindings(config
)
22266 # Wrap all of that in our namespaces.
22267 curr
= CGNamespace
.build(["mozilla", "dom"], CGWrapper(curr
, post
="\n"))
22268 curr
= CGWrapper(curr
, post
="\n")
22272 CGHeaders
.getDeclarationFilename(desc
.interface
)
22273 for desc
in config
.getDescriptors(
22274 hasInterfaceObject
=True, register
=True, isExposedInAnyWorklet
=True
22279 [], [], [], [], [], defineIncludes
, "RegisterWorkletBindings", curr
22282 # Add include guards.
22283 curr
= CGIncludeGuard("RegisterWorkletBindings", curr
)
22289 def UnionTypes(config
):
22290 unionTypes
= UnionsForFile(config
, None)
22298 ) = UnionTypes(unionTypes
, config
)
22303 + [CGUnionStruct(t
, config
) for t
in unionStructs
]
22304 + [CGUnionStruct(t
, config
, True) for t
in unionStructs
],
22308 includes
.add("mozilla/OwningNonNull.h")
22309 includes
.add("mozilla/dom/UnionMember.h")
22310 includes
.add("mozilla/dom/BindingDeclarations.h")
22311 # BindingUtils.h is only needed for SetToObject.
22312 # If it stops being inlined or stops calling CallerSubsumes
22313 # both this bit and the bit in CGBindingRoot can be removed.
22314 includes
.add("mozilla/dom/BindingUtils.h")
22316 # Wrap all of that in our namespaces.
22317 curr
= CGNamespace
.build(["mozilla", "dom"], unions
)
22319 curr
= CGWrapper(curr
, post
="\n")
22321 builder
= ForwardDeclarationBuilder()
22322 for className
, isStruct
in declarations
:
22323 builder
.add(className
, isStruct
=isStruct
)
22325 curr
= CGList([builder
.build(), curr
], "\n")
22327 curr
= CGHeaders([], [], [], [], includes
, implincludes
, "UnionTypes", curr
)
22329 # Add include guards.
22330 curr
= CGIncludeGuard("UnionTypes", curr
)
22336 def UnionConversions(config
):
22338 for l
in six
.itervalues(config
.unionsPerFilename
):
22339 unionTypes
.extend(l
)
22340 unionTypes
.sort(key
=lambda u
: u
.name
)
22341 headers
, unions
= UnionConversions(unionTypes
, config
)
22343 # Wrap all of that in our namespaces.
22344 curr
= CGNamespace
.build(["mozilla", "dom"], unions
)
22346 curr
= CGWrapper(curr
, post
="\n")
22348 headers
.update(["nsDebug.h", "mozilla/dom/UnionTypes.h"])
22349 curr
= CGHeaders([], [], [], [], headers
, [], "UnionConversions", curr
)
22351 # Add include guards.
22352 curr
= CGIncludeGuard("UnionConversions", curr
)
22358 def WebIDLPrefs(config
):
22360 headers
= set(["mozilla/dom/WebIDLPrefs.h"])
22361 for d
in config
.getDescriptors(hasInterfaceOrInterfacePrototypeObject
=True):
22362 for m
in d
.interface
.members
:
22363 pref
= PropertyDefiner
.getStringAttr(m
, "Pref")
22365 headers
.add(prefHeader(pref
))
22366 prefs
.add((pref
, prefIdentifier(pref
)))
22367 prefs
= sorted(prefs
)
22370 enum class WebIDLPrefIndex : uint8_t {
22374 typedef bool (*WebIDLPrefFunc)();
22375 extern const WebIDLPrefFunc sWebIDLPrefs[${len}];
22377 prefs
=",\n".join(map(lambda p
: "// " + p
[0] + "\n" + p
[1], prefs
)) + "\n",
22378 len=len(prefs
) + 1,
22382 const WebIDLPrefFunc sWebIDLPrefs[] = {
22388 map(lambda p
: "// " + p
[0] + "\nStaticPrefs::" + p
[1], prefs
)
22392 prefFunctions
= CGGeneric(declare
=declare
, define
=define
)
22394 # Wrap all of that in our namespaces.
22395 curr
= CGNamespace
.build(["mozilla", "dom"], prefFunctions
)
22397 curr
= CGWrapper(curr
, post
="\n")
22399 curr
= CGHeaders([], [], [], [], [], headers
, "WebIDLPrefs", curr
)
22401 # Add include guards.
22402 curr
= CGIncludeGuard("WebIDLPrefs", curr
)
22408 def WebIDLSerializable(config
):
22409 # We need a declaration of StructuredCloneTags in the header.
22410 declareIncludes
= set(
22412 "mozilla/dom/DOMJSClass.h",
22413 "mozilla/dom/StructuredCloneTags.h",
22417 defineIncludes
= set(
22418 ["mozilla/dom/WebIDLSerializable.h", "mozilla/PerfectHash.h"]
22421 for d
in config
.getDescriptors(isSerializable
=True):
22422 names
.append(d
.name
)
22423 defineIncludes
.add(CGHeaders
.getDeclarationFilename(d
.interface
))
22425 if len(names
) == 0:
22426 # We can't really create a PerfectHash out of this, but also there's
22427 # not much point to this file if we have no [Serializable] objects.
22428 # Just spit out an empty file.
22429 return CGIncludeGuard("WebIDLSerializable", CGGeneric(""))
22431 # If we had a lot of serializable things, it might be worth it to use a
22432 # PerfectHash here, or an array ordered by sctag value and binary
22433 # search. But setting those up would require knowing in this python
22434 # code the values of the various SCTAG_DOM_*. We could hardcode them
22435 # here and add static asserts that the values are right, or switch to
22436 # code-generating StructuredCloneTags.h or something. But in practice,
22437 # there's a pretty small number of serializable interfaces, and just
22438 # doing a linear walk is fine. It's not obviously worse than the
22439 # if-cascade we used to have. Let's just make sure we notice if we do
22440 # end up with a lot of serializable things here.
22442 # Also, in practice it looks like compilers compile this linear walk to
22443 # an out-of-bounds check followed by a direct index into an array, by
22444 # basically making a second copy of this array ordered by tag, with the
22445 # holes filled in. Again, worth checking whether this still happens if
22446 # we have too many serializable things.
22447 if len(names
) > 20:
22449 "We now have %s serializable interfaces. "
22450 "Double-check that the compiler is still "
22451 "generating a jump table." % len(names
)
22455 # Make sure we have stable ordering.
22456 for name
in sorted(names
):
22457 # Strip off trailing newline to make our formatting look right.
22463 /* mDeserialize */ ${name}_Binding::Deserialize
22466 tag
=StructuredCloneTag(name
),
22473 WebIDLDeserializer LookupDeserializer(StructuredCloneTags aTag);
22478 struct WebIDLSerializableEntry {
22479 StructuredCloneTags mTag;
22480 WebIDLDeserializer mDeserialize;
22483 static const WebIDLSerializableEntry sEntries[] = {
22487 WebIDLDeserializer LookupDeserializer(StructuredCloneTags aTag) {
22488 for (auto& entry : sEntries) {
22489 if (entry.mTag == aTag) {
22490 return entry.mDeserialize;
22496 entries
=",\n".join(entries
) + "\n",
22499 code
= CGGeneric(declare
=declare
, define
=define
)
22501 # Wrap all of that in our namespaces.
22502 curr
= CGNamespace
.build(["mozilla", "dom"], code
)
22504 curr
= CGWrapper(curr
, post
="\n")
22507 [], [], [], [], declareIncludes
, defineIncludes
, "WebIDLSerializable", curr
22510 # Add include guards.
22511 curr
= CGIncludeGuard("WebIDLSerializable", curr
)
22517 # Code generator for simple events
22518 class CGEventGetter(CGNativeMember
):
22519 def __init__(self
, descriptor
, attr
):
22520 ea
= descriptor
.getExtendedAttributes(attr
, getter
=True)
22521 CGNativeMember
.__init
__(
22525 CGSpecializedGetter
.makeNativeName(descriptor
, attr
),
22528 resultNotAddRefed
=not attr
.type.isSequence(),
22530 self
.body
= self
.getMethodBody()
22532 def getArgs(self
, returnType
, argList
):
22533 if "needsErrorResult" in self
.extendedAttrs
:
22534 raise TypeError("Event code generator does not support [Throws]!")
22535 if "canOOM" in self
.extendedAttrs
:
22536 raise TypeError("Event code generator does not support [CanOOM]!")
22537 if not self
.member
.isAttr():
22538 raise TypeError("Event code generator does not support methods")
22539 if self
.member
.isStatic():
22540 raise TypeError("Event code generators does not support static attributes")
22541 return CGNativeMember
.getArgs(self
, returnType
, argList
)
22543 def getMethodBody(self
):
22544 type = self
.member
.type
22545 memberName
= CGDictionary
.makeMemberName(self
.member
.identifier
.name
)
22547 (type.isPrimitive() and type.tag() in builtinNames
)
22549 or type.isPromise()
22550 or type.isGeckoInterface()
22552 return "return " + memberName
+ ";\n"
22553 if type.isJSString():
22554 # https://bugzilla.mozilla.org/show_bug.cgi?id=1580167
22555 raise TypeError("JSString not supported as member of a generated event")
22558 or type.isByteString()
22559 or type.isUSVString()
22560 or type.isUTF8String()
22562 return "aRetVal = " + memberName
+ ";\n"
22563 if type.isSpiderMonkeyInterface() or type.isObject():
22566 if (${memberName}) {
22567 JS::ExposeObjectToActiveJS(${memberName});
22569 aRetVal.set(${memberName});
22572 memberName
=memberName
,
22577 ${selfName}(aRetVal);
22579 selfName
=self
.name
,
22582 return "aRetVal = " + memberName
+ ";\n"
22583 if type.isSequence():
22584 if type.nullable():
22588 + ".IsNull()) { aRetVal.SetNull(); } else { aRetVal.SetValue("
22590 + ".Value().Clone()); }\n"
22593 return "aRetVal = " + memberName
+ ".Clone();\n"
22594 raise TypeError("Event code generator does not support this type!")
22596 def declare(self
, cgClass
):
22598 getattr(self
.member
, "originatingInterface", cgClass
.descriptor
.interface
)
22599 != cgClass
.descriptor
.interface
22602 return CGNativeMember
.declare(self
, cgClass
)
22604 def define(self
, cgClass
):
22606 getattr(self
.member
, "originatingInterface", cgClass
.descriptor
.interface
)
22607 != cgClass
.descriptor
.interface
22610 return CGNativeMember
.define(self
, cgClass
)
22613 class CGEventSetter(CGNativeMember
):
22614 def __init__(self
):
22615 raise TypeError("Event code generator does not support setters!")
22618 class CGEventMethod(CGNativeMember
):
22619 def __init__(self
, descriptor
, method
, signature
, isConstructor
, breakAfter
=True):
22620 self
.isInit
= False
22622 CGNativeMember
.__init
__(
22626 CGSpecializedMethod
.makeNativeName(descriptor
, method
),
22628 descriptor
.getExtendedAttributes(method
),
22629 breakAfter
=breakAfter
,
22630 variadicIsSequence
=True,
22632 self
.originalArgs
= list(self
.args
)
22634 iface
= descriptor
.interface
22635 allowed
= isConstructor
22636 if not allowed
and iface
.getExtendedAttribute("LegacyEventInit"):
22637 # Allow it, only if it fits the initFooEvent profile exactly
22638 # We could check the arg types but it's not worth the effort.
22640 method
.identifier
.name
== "init" + iface
.identifier
.name
22641 and signature
[1][0].type.isDOMString()
22642 and signature
[1][1].type.isBoolean()
22643 and signature
[1][2].type.isBoolean()
22645 # -3 on the left to ignore the type, bubbles, and cancelable parameters
22646 # -1 on the right to ignore the .trusted property which bleeds through
22647 # here because it is [Unforgeable].
22648 len(signature
[1]) - 3
22649 == len([x
for x
in iface
.members
if x
.isAttr()]) - 1
22655 raise TypeError("Event code generator does not support methods!")
22657 def getArgs(self
, returnType
, argList
):
22658 args
= [self
.getArg(arg
) for arg
in argList
]
22661 def getArg(self
, arg
):
22662 decl
, ref
= self
.getArgType(
22663 arg
.type, arg
.canHaveMissingValue(), "Variadic" if arg
.variadic
else False
22666 decl
= CGWrapper(decl
, pre
="const ", post
="&")
22668 name
= arg
.identifier
.name
22669 name
= "a" + name
[0].upper() + name
[1:]
22670 return Argument(decl
.define(), name
)
22672 def declare(self
, cgClass
):
22674 constructorForNativeCaller
= ""
22676 self
.args
= list(self
.originalArgs
)
22677 self
.args
.insert(0, Argument("mozilla::dom::EventTarget*", "aOwner"))
22678 constructorForNativeCaller
= CGNativeMember
.declare(self
, cgClass
)
22680 self
.args
= list(self
.originalArgs
)
22681 if needCx(None, self
.arguments(), [], considerTypes
=True, static
=True):
22682 self
.args
.insert(0, Argument("JSContext*", "aCx"))
22683 if not self
.isInit
:
22684 self
.args
.insert(0, Argument("const GlobalObject&", "aGlobal"))
22686 return constructorForNativeCaller
+ CGNativeMember
.declare(self
, cgClass
)
22688 def defineInit(self
, cgClass
):
22689 iface
= self
.descriptorProvider
.interface
22691 while iface
.identifier
.name
!= "Event":
22692 i
= 3 # Skip the boilerplate args: type, bubble,s cancelable.
22693 for m
in iface
.members
:
22695 # We need to initialize all the member variables that do
22696 # not come from Event.
22698 getattr(m
, "originatingInterface", iface
).identifier
.name
22702 name
= CGDictionary
.makeMemberName(m
.identifier
.name
)
22703 members
+= "%s = %s;\n" % (name
, self
.args
[i
].name
)
22705 iface
= iface
.parent
22709 InitEvent(${typeArg}, ${bubblesArg}, ${cancelableArg});
22712 typeArg
=self
.args
[0].name
,
22713 bubblesArg
=self
.args
[1].name
,
22714 cancelableArg
=self
.args
[2].name
,
22718 return CGNativeMember
.define(self
, cgClass
)
22720 def define(self
, cgClass
):
22721 self
.args
= list(self
.originalArgs
)
22723 return self
.defineInit(cgClass
)
22726 iface
= self
.descriptorProvider
.interface
22727 while iface
.identifier
.name
!= "Event":
22728 for m
in self
.descriptorProvider
.getDescriptor(
22729 iface
.identifier
.name
22730 ).interface
.members
:
22732 # We initialize all the other member variables in the
22733 # Constructor except those ones coming from the Event.
22736 m
, "originatingInterface", cgClass
.descriptor
.interface
22741 name
= CGDictionary
.makeMemberName(m
.identifier
.name
)
22742 if m
.type.isSequence():
22743 # For sequences we may not be able to do a simple
22744 # assignment because the underlying types may not match.
22745 # For example, the argument can be a
22746 # Sequence<OwningNonNull<SomeInterface>> while our
22747 # member is an nsTArray<RefPtr<SomeInterface>>. So
22748 # use AppendElements, which is actually a template on
22749 # the incoming type on nsTArray and does the right thing
22752 source
= "%s.%s" % (self
.args
[1].name
, name
)
22753 sequenceCopy
= "e->%s.AppendElements(%s);\n"
22754 if m
.type.nullable():
22755 sequenceCopy
= CGIfWrapper(
22756 CGGeneric(sequenceCopy
), "!%s.IsNull()" % source
22758 target
+= ".SetValue()"
22759 source
+= ".Value()"
22760 members
+= sequenceCopy
% (target
, source
)
22761 elif m
.type.isSpiderMonkeyInterface():
22762 srcname
= "%s.%s" % (self
.args
[1].name
, name
)
22763 if m
.type.nullable():
22766 if (${srcname}.IsNull()) {
22767 e->${varname} = nullptr;
22769 e->${varname} = ${srcname}.Value().Obj();
22778 e->${varname}.set(${srcname}.Obj());
22784 members
+= "e->%s = %s.%s;\n" % (name
, self
.args
[1].name
, name
)
22787 or m
.type.isObject()
22788 or m
.type.isSpiderMonkeyInterface()
22790 holdJS
= "mozilla::HoldJSObjects(e.get());\n"
22791 iface
= iface
.parent
22795 RefPtr<${nativeType}> e = new ${nativeType}(aOwner);
22796 bool trusted = e->Init(aOwner);
22797 e->InitEvent(${eventType}, ${eventInit}.mBubbles, ${eventInit}.mCancelable);
22799 e->SetTrusted(trusted);
22800 e->SetComposed(${eventInit}.mComposed);
22804 nativeType
=self
.descriptorProvider
.nativeType
.split("::")[-1],
22805 eventType
=self
.args
[0].name
,
22806 eventInit
=self
.args
[1].name
,
22811 self
.args
.insert(0, Argument("mozilla::dom::EventTarget*", "aOwner"))
22812 constructorForNativeCaller
= CGNativeMember
.define(self
, cgClass
) + "\n"
22813 self
.args
= list(self
.originalArgs
)
22816 nsCOMPtr<mozilla::dom::EventTarget> owner = do_QueryInterface(aGlobal.GetAsSupports());
22817 return Constructor(owner, ${arg0}, ${arg1});
22819 arg0
=self
.args
[0].name
,
22820 arg1
=self
.args
[1].name
,
22822 if needCx(None, self
.arguments(), [], considerTypes
=True, static
=True):
22823 self
.args
.insert(0, Argument("JSContext*", "aCx"))
22824 self
.args
.insert(0, Argument("const GlobalObject&", "aGlobal"))
22825 return constructorForNativeCaller
+ CGNativeMember
.define(self
, cgClass
)
22828 class CGEventClass(CGBindingImplClass
):
22830 Codegen for the actual Event class implementation for this descriptor
22833 def __init__(self
, descriptor
):
22834 CGBindingImplClass
.__init
__(
22841 "WrapObjectInternal",
22845 self
.membersNeedingCC
= []
22846 self
.membersNeedingTrace
= []
22848 for m
in descriptor
.interface
.members
:
22850 getattr(m
, "originatingInterface", descriptor
.interface
)
22851 != descriptor
.interface
22857 self
.membersNeedingTrace
.append(m
)
22858 # Add a getter that doesn't need a JSContext. Note that we
22859 # don't need to do this if our originating interface is not
22860 # the descriptor's interface, because in that case we
22861 # wouldn't generate the getter that _does_ need a JSContext
22863 extraMethods
.append(
22865 CGSpecializedGetter
.makeNativeName(descriptor
, m
),
22867 [Argument("JS::MutableHandle<JS::Value>", "aRetVal")],
22871 JS::ExposeValueToActiveJS(${memberName});
22872 aRetVal.set(${memberName});
22874 memberName
=CGDictionary
.makeMemberName(
22880 elif m
.type.isObject() or m
.type.isSpiderMonkeyInterface():
22881 self
.membersNeedingTrace
.append(m
)
22882 elif typeNeedsRooting(m
.type):
22884 "Need to implement tracing for event member of type %s" % m
.type
22886 elif idlTypeNeedsCycleCollection(m
.type):
22887 self
.membersNeedingCC
.append(m
)
22889 nativeType
= self
.getNativeTypeForIDLType(m
.type).define()
22892 CGDictionary
.makeMemberName(m
.identifier
.name
),
22894 visibility
="private",
22899 parent
= self
.descriptor
.interface
.parent
22900 self
.parentType
= self
.descriptor
.getDescriptor(
22901 parent
.identifier
.name
22902 ).nativeType
.split("::")[-1]
22903 self
.nativeType
= self
.descriptor
.nativeType
.split("::")[-1]
22906 isupportsDecl
= fill(
22908 NS_DECL_ISUPPORTS_INHERITED
22909 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(${nativeType}, ${parentType})
22911 nativeType
=self
.nativeType
,
22912 parentType
=self
.parentType
,
22915 isupportsDecl
= fill(
22917 NS_INLINE_DECL_REFCOUNTING_INHERITED(${nativeType}, ${parentType})
22919 nativeType
=self
.nativeType
,
22920 parentType
=self
.parentType
,
22923 baseDeclarations
= fill(
22929 virtual ~${nativeType}();
22930 explicit ${nativeType}(mozilla::dom::EventTarget* aOwner);
22933 isupportsDecl
=isupportsDecl
,
22934 nativeType
=self
.nativeType
,
22935 parentType
=self
.parentType
,
22938 className
= self
.nativeType
22939 asConcreteTypeMethod
= ClassMethod(
22940 "As%s" % className
,
22944 body
="return this;\n",
22945 breakAfterReturnDecl
=" ",
22948 extraMethods
.append(asConcreteTypeMethod
)
22953 bases
=[ClassBase(self
.parentType
)],
22954 methods
=extraMethods
+ self
.methodDecls
,
22956 extradeclarations
=baseDeclarations
,
22959 def getWrapObjectBody(self
):
22961 "return %s_Binding::Wrap(aCx, this, aGivenProto);\n" % self
.descriptor
.name
22965 return len(self
.membersNeedingCC
) != 0 or len(self
.membersNeedingTrace
) != 0
22967 def implTraverse(self
):
22969 for m
in self
.membersNeedingCC
:
22971 " NS_IMPL_CYCLE_COLLECTION_TRAVERSE(%s)\n"
22972 % CGDictionary
.makeMemberName(m
.identifier
.name
)
22976 def implUnlink(self
):
22978 for m
in self
.membersNeedingCC
:
22980 " NS_IMPL_CYCLE_COLLECTION_UNLINK(%s)\n"
22981 % CGDictionary
.makeMemberName(m
.identifier
.name
)
22983 for m
in self
.membersNeedingTrace
:
22984 name
= CGDictionary
.makeMemberName(m
.identifier
.name
)
22986 retVal
+= " tmp->" + name
+ ".setUndefined();\n"
22987 elif m
.type.isObject() or m
.type.isSpiderMonkeyInterface():
22988 retVal
+= " tmp->" + name
+ " = nullptr;\n"
22990 raise TypeError("Unknown traceable member type %s" % m
.type)
22993 def implTrace(self
):
22995 for m
in self
.membersNeedingTrace
:
22997 " NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(%s)\n"
22998 % CGDictionary
.makeMemberName(m
.identifier
.name
)
23004 for m
in self
.membersNeedingTrace
:
23005 member
= CGDictionary
.makeMemberName(m
.identifier
.name
)
23007 dropJS
+= member
+ " = JS::UndefinedValue();\n"
23008 elif m
.type.isObject() or m
.type.isSpiderMonkeyInterface():
23009 dropJS
+= member
+ " = nullptr;\n"
23011 raise TypeError("Unknown traceable member type %s" % m
.type)
23014 dropJS
+= "mozilla::DropJSObjects(this);\n"
23015 # Just override CGClass and do our own thing
23017 "aOwner, nullptr, nullptr" if self
.parentType
== "Event" else "aOwner"
23024 NS_IMPL_CYCLE_COLLECTION_CLASS(${nativeType})
23026 NS_IMPL_ADDREF_INHERITED(${nativeType}, ${parentType})
23027 NS_IMPL_RELEASE_INHERITED(${nativeType}, ${parentType})
23029 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(${nativeType}, ${parentType})
23031 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
23033 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(${nativeType}, ${parentType})
23035 NS_IMPL_CYCLE_COLLECTION_TRACE_END
23037 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(${nativeType}, ${parentType})
23039 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
23041 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
23042 NS_INTERFACE_MAP_END_INHERITING(${parentType})
23044 nativeType
=self
.nativeType
,
23045 parentType
=self
.parentType
,
23046 traverse
=self
.implTraverse(),
23047 unlink
=self
.implUnlink(),
23048 trace
=self
.implTrace(),
23056 ${nativeType}::${nativeType}(mozilla::dom::EventTarget* aOwner)
23057 : ${parentType}(${ctorParams})
23061 ${nativeType}::~${nativeType}()
23067 nativeType
=self
.nativeType
,
23068 ctorParams
=ctorParams
,
23069 parentType
=self
.parentType
,
23073 return classImpl
+ CGBindingImplClass
.define(self
)
23075 def getNativeTypeForIDLType(self
, type):
23076 if type.isPrimitive() and type.tag() in builtinNames
:
23077 nativeType
= CGGeneric(builtinNames
[type.tag()])
23078 if type.nullable():
23079 nativeType
= CGTemplatedType("Nullable", nativeType
)
23080 elif type.isEnum():
23081 nativeType
= CGGeneric(type.unroll().inner
.identifier
.name
)
23082 if type.nullable():
23083 nativeType
= CGTemplatedType("Nullable", nativeType
)
23084 elif type.isJSString():
23085 nativeType
= CGGeneric("JS::Heap<JSString*>")
23086 elif type.isDOMString() or type.isUSVString():
23087 nativeType
= CGGeneric("nsString")
23088 elif type.isByteString() or type.isUTF8String():
23089 nativeType
= CGGeneric("nsCString")
23090 elif type.isPromise():
23091 nativeType
= CGGeneric("RefPtr<Promise>")
23092 elif type.isGeckoInterface():
23093 iface
= type.unroll().inner
23094 nativeType
= self
.descriptor
.getDescriptor(iface
.identifier
.name
).nativeType
23095 # Now trim off unnecessary namespaces
23096 nativeType
= nativeType
.split("::")
23097 if nativeType
[0] == "mozilla":
23099 if nativeType
[0] == "dom":
23101 nativeType
= CGWrapper(
23102 CGGeneric("::".join(nativeType
)), pre
="RefPtr<", post
=">"
23105 nativeType
= CGGeneric("JS::Heap<JS::Value>")
23106 elif type.isObject() or type.isSpiderMonkeyInterface():
23107 nativeType
= CGGeneric("JS::Heap<JSObject*>")
23108 elif type.isUnion():
23109 nativeType
= CGGeneric(CGUnionStruct
.unionTypeDecl(type, True))
23110 elif type.isSequence():
23111 if type.nullable():
23112 innerType
= type.inner
.inner
23114 innerType
= type.inner
23116 not innerType
.isPrimitive()
23117 and not innerType
.isEnum()
23118 and not innerType
.isDOMString()
23119 and not innerType
.isByteString()
23120 and not innerType
.isUTF8String()
23121 and not innerType
.isPromise()
23122 and not innerType
.isGeckoInterface()
23125 "Don't know how to properly manage GC/CC for "
23126 "event member of type %s" % type
23128 nativeType
= CGTemplatedType(
23129 "nsTArray", self
.getNativeTypeForIDLType(innerType
)
23131 if type.nullable():
23132 nativeType
= CGTemplatedType("Nullable", nativeType
)
23134 raise TypeError("Don't know how to declare event member of type %s" % type)
23138 class CGEventRoot(CGThing
):
23139 def __init__(self
, config
, interfaceName
):
23140 descriptor
= config
.getDescriptor(interfaceName
)
23142 self
.root
= CGWrapper(CGEventClass(descriptor
), pre
="\n", post
="\n")
23144 self
.root
= CGNamespace
.build(["mozilla", "dom"], self
.root
)
23146 self
.root
= CGList(
23147 [CGClassForwardDeclare("JSContext", isStruct
=True), self
.root
]
23150 parent
= descriptor
.interface
.parent
.identifier
.name
23152 # Throw in our #includes
23153 self
.root
= CGHeaders(
23159 config
.getDescriptor(parent
).headerFile
,
23160 "mozilla/Attributes.h",
23161 "mozilla/dom/%sBinding.h" % interfaceName
,
23162 "mozilla/dom/BindingUtils.h",
23165 "%s.h" % interfaceName
,
23167 "mozilla/HoldDropJSObjects.h",
23168 "mozilla/dom/Nullable.h",
23175 # And now some include guards
23176 self
.root
= CGIncludeGuard(interfaceName
, self
.root
)
23178 self
.root
= CGWrapper(
23181 AUTOGENERATED_WITH_SOURCE_WARNING_COMMENT
23182 % os
.path
.basename(descriptor
.interface
.filename())
23186 self
.root
= CGWrapper(
23190 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
23191 /* vim:set ts=2 sw=2 sts=2 et cindent: */
23192 /* This Source Code Form is subject to the terms of the Mozilla Public
23193 * License, v. 2.0. If a copy of the MPL was not distributed with this
23194 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
23201 return self
.root
.declare()
23204 return self
.root
.define()