5 from collections
import defaultdict
9 from mozbuild
.util
import FileAvoidWrite
10 from perfecthash
import PerfectHash
12 NO_CONTRACT_ID
= 0xFFFFFFFF
18 # In tests, we might not have a (complete) buildconfig.
20 "<" if buildconfig
.substs
.get("TARGET_ENDIANNESS", "little") == "little" else ">"
24 # Represents a UUID in the format used internally by Gecko, and supports
25 # serializing it in that format to both C++ source and raw byte arrays.
26 class UUIDRepr(object):
27 def __init__(self
, uuid
):
38 d
.append(fields
[5] >> (8 * (5 - i
)) & 0xFF)
47 return struct
.pack(ENDIAN
+ "IHHBBBBBBBB", self
.a
, self
.b
, self
.c
, *self
.d
)
50 rest
= ", ".join("0x%02x" % b
for b
in self
.d
)
52 return "{ 0x%x, 0x%x, 0x%x, { %s } }" % (self
.a
, self
.b
, self
.c
, rest
)
55 # Corresponds to the Module::ProcessSelector enum in Module.h. The actual
56 # values don't matter, since the code generator emits symbolic constants for
57 # these values, but we use the same values as the enum constants for clarity.
58 class ProcessSelector
:
60 MAIN_PROCESS_ONLY
= 1 << 0
61 CONTENT_PROCESS_ONLY
= 1 << 1
62 ALLOW_IN_GPU_PROCESS
= 1 << 2
63 ALLOW_IN_VR_PROCESS
= 1 << 3
64 ALLOW_IN_SOCKET_PROCESS
= 1 << 4
65 ALLOW_IN_RDD_PROCESS
= 1 << 5
66 ALLOW_IN_UTILITY_PROCESS
= 1 << 6
67 ALLOW_IN_GMPLUGIN_PROCESS
= 1 << 7
68 ALLOW_IN_GPU_AND_MAIN_PROCESS
= ALLOW_IN_GPU_PROCESS | MAIN_PROCESS_ONLY
69 ALLOW_IN_GPU_AND_SOCKET_PROCESS
= ALLOW_IN_GPU_PROCESS | ALLOW_IN_SOCKET_PROCESS
70 ALLOW_IN_GPU_AND_VR_PROCESS
= ALLOW_IN_GPU_PROCESS | ALLOW_IN_VR_PROCESS
71 ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS
= (
72 ALLOW_IN_GPU_PROCESS | ALLOW_IN_VR_PROCESS | ALLOW_IN_SOCKET_PROCESS
74 ALLOW_IN_RDD_AND_SOCKET_PROCESS
= ALLOW_IN_RDD_PROCESS | ALLOW_IN_SOCKET_PROCESS
75 ALLOW_IN_GPU_RDD_AND_SOCKET_PROCESS
= (
76 ALLOW_IN_GPU_PROCESS | ALLOW_IN_RDD_PROCESS | ALLOW_IN_SOCKET_PROCESS
78 ALLOW_IN_GPU_RDD_SOCKET_AND_UTILITY_PROCESS
= (
80 | ALLOW_IN_RDD_PROCESS
81 | ALLOW_IN_SOCKET_PROCESS
82 | ALLOW_IN_UTILITY_PROCESS
84 ALLOW_IN_GPU_RDD_VR_AND_SOCKET_PROCESS
= (
86 | ALLOW_IN_RDD_PROCESS
88 | ALLOW_IN_SOCKET_PROCESS
90 ALLOW_IN_GPU_RDD_VR_SOCKET_AND_UTILITY_PROCESS
= (
92 | ALLOW_IN_RDD_PROCESS
94 | ALLOW_IN_SOCKET_PROCESS
95 | ALLOW_IN_UTILITY_PROCESS
97 ALLOW_IN_GPU_RDD_VR_SOCKET_UTILITY_AND_GMPLUGIN_PROCESS
= (
99 | ALLOW_IN_RDD_PROCESS
100 | ALLOW_IN_VR_PROCESS
101 | ALLOW_IN_SOCKET_PROCESS
102 | ALLOW_IN_UTILITY_PROCESS
103 | ALLOW_IN_GMPLUGIN_PROCESS
107 # Maps ProcessSelector constants to the name of the corresponding
108 # Module::ProcessSelector enum value.
110 ProcessSelector
.ANY_PROCESS
: "ANY_PROCESS",
111 ProcessSelector
.MAIN_PROCESS_ONLY
: "MAIN_PROCESS_ONLY",
112 ProcessSelector
.CONTENT_PROCESS_ONLY
: "CONTENT_PROCESS_ONLY",
113 ProcessSelector
.ALLOW_IN_GPU_PROCESS
: "ALLOW_IN_GPU_PROCESS",
114 ProcessSelector
.ALLOW_IN_VR_PROCESS
: "ALLOW_IN_VR_PROCESS",
115 ProcessSelector
.ALLOW_IN_SOCKET_PROCESS
: "ALLOW_IN_SOCKET_PROCESS",
116 ProcessSelector
.ALLOW_IN_RDD_PROCESS
: "ALLOW_IN_RDD_PROCESS",
117 ProcessSelector
.ALLOW_IN_GPU_AND_MAIN_PROCESS
: "ALLOW_IN_GPU_AND_MAIN_PROCESS",
118 ProcessSelector
.ALLOW_IN_GPU_AND_SOCKET_PROCESS
: "ALLOW_IN_GPU_AND_SOCKET_PROCESS",
119 ProcessSelector
.ALLOW_IN_GPU_AND_VR_PROCESS
: "ALLOW_IN_GPU_AND_VR_PROCESS",
120 ProcessSelector
.ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS
: "ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS",
121 ProcessSelector
.ALLOW_IN_RDD_AND_SOCKET_PROCESS
: "ALLOW_IN_RDD_AND_SOCKET_PROCESS",
122 ProcessSelector
.ALLOW_IN_GPU_RDD_AND_SOCKET_PROCESS
: "ALLOW_IN_GPU_RDD_AND_SOCKET_PROCESS",
123 ProcessSelector
.ALLOW_IN_GPU_RDD_SOCKET_AND_UTILITY_PROCESS
: "ALLOW_IN_GPU_RDD_SOCKET_AND_UTILITY_PROCESS", # NOQA: E501
124 ProcessSelector
.ALLOW_IN_GPU_RDD_VR_AND_SOCKET_PROCESS
: "ALLOW_IN_GPU_RDD_VR_AND_SOCKET_PROCESS", # NOQA: E501
125 ProcessSelector
.ALLOW_IN_GPU_RDD_VR_SOCKET_AND_UTILITY_PROCESS
: "ALLOW_IN_GPU_RDD_VR_SOCKET_AND_UTILITY_PROCESS", # NOQA: E501
126 ProcessSelector
.ALLOW_IN_GPU_RDD_VR_SOCKET_UTILITY_AND_GMPLUGIN_PROCESS
: "ALLOW_IN_GPU_RDD_VR_SOCKET_UTILITY_AND_GMPLUGIN_PROCESS", # NOQA: E501
130 # Emits the C++ symbolic constant corresponding to a ProcessSelector constant.
131 def lower_processes(processes
):
132 return "Module::ProcessSelector::%s" % PROCESSES
[processes
]
135 # Emits the C++ symbolic constant for a ModuleEntry's ModuleID enum entry.
136 def lower_module_id(module
):
137 return "ModuleID::%s" % module
.name
140 # Corresponds to the Module::BackgroundTasksSelector enum in Module.h. The
141 # actual values don't matter, since the code generator emits symbolic constants
142 # for these values, but we use the same values as the enum constants for
144 class BackgroundTasksSelector
:
149 # Maps BackgroundTasksSelector constants to the name of the corresponding
150 # Module::BackgroundTasksSelector enum value.
152 BackgroundTasksSelector
.ALL_TASKS
: "ALL_TASKS",
153 BackgroundTasksSelector
.NO_TASKS
: "NO_TASKS",
157 # Emits the C++ symbolic constant corresponding to a BackgroundTasks constant.
158 def lower_backgroundtasks(backgroundtasks
):
159 return "Module::BackgroundTasksSelector::%s" % BACKGROUNDTASKS
[backgroundtasks
]
162 # Represents a static string table, indexed by offset. This allows us to
163 # reference strings from static data structures without requiring runtime
165 class StringTable(object):
171 self
._serialized
= False
173 # Returns the index of the given string in the `entry_list` array. If
174 # no entry for the string exists, it first creates one.
175 def get_idx(self
, string
):
176 idx
= self
.entries
.get(string
, None)
180 assert not self
._serialized
182 assert len(string
) == len(string
.encode("utf-8"))
185 self
.size
+= len(string
) + 1
187 self
.entries
[string
] = idx
188 self
.entry_list
.append(string
)
191 # Returns the C++ code representing string data of this string table, as a
192 # single string literal. This must only be called after the last call to
193 # `get_idx()` or `entry_to_cxx()` for this instance.
195 self
._serialized
= True
200 for entry
in self
.entry_list
:
201 str_
= entry
.replace("\\", "\\\\").replace('"', r
"\"").replace("\n", r"\n")
203 lines.append(' /* 0x%x */ "%s\\0"\n' % (idx, str_))
205 idx += len(entry) + 1
207 return "".join(lines)
209 # Returns a `StringEntry` struct initializer for the string table entry
210 # corresponding to the given string. If no matching entry exists, it is
212 def entry_to_cxx(self, string):
213 idx = self.get_idx(string)
214 return "{ 0x
%x } /* %s */" % (idx, pretty_string(string))
217 strings = StringTable()
222 # Represents a C++ namespace, containing a set of classes and potentially
223 # sub-namespaces. This is used to generate pre-declarations for incomplete
224 # types referenced in XPCOM manifests.
225 class Namespace(object):
226 def __init__(self, name=None):
231 # Returns a Namespace object for the sub-namespace with the given name.
233 assert name not in self.classes
235 if name not in self.namespaces:
236 self.namespaces[name] = Namespace(name)
237 return self.namespaces[name]
239 # Generates C++ code to pre-declare all classes in this namespace and all
240 # of its sub-namespaces.
244 res += "namespace
%s {\n" % self.name
246 for clas in sorted(self.classes):
247 res += "class %s;\n" % clas
249 for ns in sorted(self.namespaces.keys()):
250 res += self.namespaces[ns].to_cxx()
253 res += "} // namespace
%s\n" % self.name
258 # Represents a component defined in an XPCOM manifest's `Classes` array.
259 class ModuleEntry(object):
262 def __init__(self, data, init_idx):
263 self.cid = UUIDRepr(UUID(data["cid
"]))
264 self.contract_ids = data.get("contract_ids
", [])
265 self.type = data.get("type", "nsISupports
")
266 self.categories = data.get("categories
", {})
267 self.processes = data.get("processes
", 0)
268 self.headers = data.get("headers
", [])
270 self.js_name = data.get("js_name
", None)
271 self.interfaces = data.get("interfaces
", [])
273 if len(self.interfaces) > 255:
275 "JS service
%s may
not have more than
255 " "interfaces
" % self.js_name
278 self.interfaces_offset = len(interfaces)
279 for iface in self.interfaces:
280 interfaces.append(iface)
282 # If the manifest declares Init or Unload functions, this contains its
283 # index, as understood by the `CallInitFunc()` function.
285 # If it contains any value other than `None`, a corresponding
286 # `CallInitFunc(init_idx)` call will be genrated before calling this
287 # module's constructor.
288 self.init_idx = init_idx
290 self.constructor = data.get("constructor
", None)
291 self.legacy_constructor = data.get("legacy_constructor
", None)
292 self.init_method = data.get("init_method
", [])
294 self.jsm = data.get("jsm
", None)
295 self.esModule = data.get("esModule
", None)
297 self.external = data.get(
298 "external
", not (self.headers or self.legacy_constructor)
300 self.singleton = data.get("singleton
", False)
301 self.overridable = data.get("overridable
", False)
303 self.protocol_config = data.get("protocol_config
", None)
306 self.anonymous = False
307 self.name = data["name
"]
309 self.anonymous = True
310 self.name = "Anonymous
%03d
" % ModuleEntry.next_anon_id
311 ModuleEntry.next_anon_id += 1
315 "Error defining component
%s (%s): %s"
316 % (str(self.cid), ", ".join(map(repr, self.contract_ids)), str_)
320 if not self.constructor:
321 error("JavaScript components must specify a constructor
")
323 for prop in ("init_method
", "legacy_constructor
", "headers
"):
324 if getattr(self, prop):
326 "JavaScript components may
not specify a
'%s' "
330 if not self.constructor:
331 error("JavaScript components must specify a constructor
")
333 for prop in ("init_method
", "legacy_constructor
", "headers
"):
334 if getattr(self, prop):
336 "JavaScript components may
not specify a
'%s' "
340 if self.constructor or self.legacy_constructor:
342 "Externally
-constructed components may
not specify
"
343 "'constructor' or 'legacy_constructor' properties
"
347 "Externally
-constructed components may
not specify
"
348 "'init_method' properties
"
350 if self.type == "nsISupports
":
352 "Externally
-constructed components must specify a
type "
353 "other than nsISupports
"
356 if self.constructor and self.legacy_constructor:
358 "The
'constructor' and 'legacy_constructor' properties
"
359 "are mutually exclusive
"
362 if self.overridable and not self.contract_ids:
363 error("Overridable components must specify at least one contract
" "ID
")
366 def contract_id(self):
367 return self.contract_ids[0]
369 # Generates the C++ code for a StaticModule struct initializer
370 # representing this component.
373 strings.entry_to_cxx(self.contract_id)
375 else "{ 0x
%x }" % NO_CONTRACT_ID
380 /* {{{cid_string}}} */
386 cid=self.cid.to_cxx(),
387 cid_string=str(self.cid),
388 contract_id=contract_id,
389 processes=lower_processes(self.processes),
392 # Generates the C++ code for a JSServiceEntry representing this module.
393 def lower_js_service(self):
398 {{ {iface_offset} }},
401 js_name=strings.entry_to_cxx(self.js_name),
403 iface_offset=self.interfaces_offset,
404 iface_count=len(self.interfaces),
407 # Generates the C++ code necessary to construct an instance of this
410 # This code lives in a function with the following arguments:
412 # - aIID: The `const nsIID&` interface ID that the resulting instance
413 # will be queried to.
415 # - aResult: The `void**` pointer in which to store the result.
417 # And which returns an `nsresult` indicating success or failure.
418 def lower_constructor(self):
421 if self.init_idx is not None:
422 res += " MOZ_TRY(CallInitFunc(%d));\n" % self.init_idx
424 if self.legacy_constructor:
426 " return /* legacy
*/ %s(aIID
, aResult
);\n"
427 % self.legacy_constructor
433 " nsCOMPtr
<nsISupports
> inst
;\n"
434 " MOZ_TRY(ConstructJSMComponent(nsLiteralCString(%s),\n"
436 " getter_AddRefs(inst
)));"
437 "\n" % (json.dumps(self.jsm), json.dumps(self.constructor))
441 " nsCOMPtr
<nsISupports
> inst
;\n"
442 " MOZ_TRY(ConstructESModuleComponent(nsLiteralCString(%s),\n"
444 " getter_AddRefs(inst
)));"
445 "\n" % (json.dumps(self.esModule), json.dumps(self.constructor))
449 " nsCOMPtr
<nsISupports
> inst
= "
450 "mozCreateComponent
<%s>();\n" % self.type
452 # The custom constructor may return null, so check before calling
454 res += " NS_ENSURE_TRUE(inst
, NS_ERROR_FAILURE
);\n"
456 res += " RefPtr
<%s> inst
= " % self.type
458 if not self.constructor:
459 res += "new
%s();\n" % self.type
461 res += "%s();\n" % self.constructor
462 # The `new` operator is infallible, so we don't need to worry
463 # about it returning null, but custom constructors may, so
464 # check before calling any methods.
465 res += " NS_ENSURE_TRUE(inst
, NS_ERROR_OUT_OF_MEMORY
);\n"
467 # Check that the constructor function returns an appropriate
468 # `already_AddRefed` value for our declared type.
471 RemoveAlreadyAddRefed<decltype(%(constructor)s())>::Type;
473 std::is_same_v<already_AddRefed<T>, decltype(%(constructor)s())>,
474 "Singleton constructor must
return already_AddRefed
");
476 std::is_base_of<%(type)s, T>::value,
477 "Singleton constructor must
return correct already_AddRefed
");
481 "constructor
": self.constructor,
485 res += " MOZ_TRY(inst
->%s());\n" % self.init_method
487 res += " return inst
->QueryInterface(aIID
, aResult
);\n"
491 # Generates the C++ code for the `mozilla::components::<name>` entry
492 # corresponding to this component. This may not be called for modules
493 # without an explicit `name` (in which cases, `self.anonymous` will be
495 def lower_getters(self):
496 assert not self.anonymous
500 "id": "::mozilla
::xpcom
::ModuleID
::%s" % self.name,
506 static inline const nsID& CID() {
507 return ::mozilla::xpcom::Components::GetCID(%(id)s);
510 static inline ::mozilla::xpcom::GetServiceHelper Service(nsresult* aRv = nullptr) {
511 return {%(id)s, aRv};
517 if not self.singleton:
520 static inline ::mozilla::xpcom::CreateInstanceHelper Create(nsresult* aRv = nullptr) {
521 return {%(id)s, aRv};
529 } // namespace %(name)s
536 # Generates the rust code for the `xpcom::components::<name>` entry
537 # corresponding to this component. This may not be called for modules
538 # without an explicit `name` (in which cases, `self.anonymous` will be
540 def lower_getters_rust(self):
541 assert not self.anonymous
545 "id": "super::ModuleID
::%s" % self.name,
550 #[allow(non_snake_case)]
552 /// Get the singleton service instance for this component.
553 pub fn service<T: crate::XpCom>() -> Result<crate::RefPtr<T>, nserror::nsresult> {
554 let mut ga = crate::GetterAddrefs::<T>::new();
555 let rv = unsafe { super::Gecko_GetServiceByModuleID(%(id)s, &T::IID, ga.void_ptr()) };
559 ga.refptr().ok_or(nserror::NS_ERROR_NO_INTERFACE)
565 if not self.singleton:
568 /// Create a new instance of this component.
569 pub fn create<T: crate::XpCom>() -> Result<crate::RefPtr<T>, nserror::nsresult> {
570 let mut ga = crate::GetterAddrefs::<T>::new();
571 let rv = unsafe { super::Gecko_CreateInstanceByModuleID(%(id)s, &T::IID, ga.void_ptr()) };
575 ga.refptr().ok_or(nserror::NS_ERROR_NO_INTERFACE)
588 # Returns a quoted string literal representing the given raw string, with
589 # certain special characters replaced so that it can be used in a C++-style
590 # (/* ... */) comment.
591 def pretty_string(string):
592 return json.dumps(string).replace("*/", r"*\
/").replace("/*", r"/\
*")
595 # Represents a static contract ID entry, corresponding to a C++ ContractEntry
596 # struct, mapping a contract ID to a static module entry.
597 class ContractEntry(object):
598 def __init__(self, contract, module):
599 self.contract = contract
608 contract=strings.entry_to_cxx(self.contract),
609 module_id=lower_module_id(self.module),
613 # Represents a static ProtocolHandler entry, corresponding to a C++
614 # ProtocolEntry struct, mapping a scheme to a static module entry and metadata.
615 class ProtocolHandler(object):
616 def __init__(self, config, module):
619 "Error defining protocol handler
%s (%s): %s"
620 % (str(module.cid), ", ".join(map(repr, module.contract_ids)), str_)
624 self.scheme = config.get("scheme
", None)
625 if self.scheme is None:
626 error("No scheme defined
for protocol component
")
627 self.flags = config.get("flags
", None)
628 if self.flags is None:
629 error("No flags defined
for protocol component
")
630 self.default_port = config.get("default_port
", -1)
631 self.has_dynamic_flags = config.get("has_dynamic_flags
", False)
637 .mProtocolFlags = {flags},
638 .mDefaultPort = {default_port},
639 .mModuleID = {module_id},
640 .mHasDynamicFlags = {has_dynamic_flags},
643 scheme=strings.entry_to_cxx(self.scheme),
644 module_id=lower_module_id(self.module),
645 flags=" |
".join("nsIProtocolHandler
::%s" % flag for flag in self.flags),
646 default_port=self.default_port,
647 has_dynamic_flags="true
" if self.has_dynamic_flags else "false
",
651 # Generates the C++ code for the StaticCategoryEntry and StaticCategory
652 # structs for all category entries declared in XPCOM manifests.
653 def gen_categories(substs, categories):
658 for category, entries in sorted(categories.items()):
661 return tuple(entry[0]["name
"]) + entry[1:]
667 " %d, %d },\n" % (strings.entry_to_cxx(category), count, len(entries))
669 count += len(entries)
671 ents.append(" /* %s */\n" % pretty_string(category))
672 for entry, value, processes in entries:
674 backgroundtasks = entry.get(
675 "backgroundtasks
", BackgroundTasksSelector.NO_TASKS
684 strings.entry_to_cxx(name),
685 strings.entry_to_cxx(value),
686 lower_backgroundtasks(backgroundtasks),
687 lower_processes(processes),
693 substs["category_count
"] = len(cats)
694 substs["categories
"] = "".join(cats)
695 substs["category_entries
"] = "".join(ents)
698 # Generates the C++ code for all Init and Unload functions declared in XPCOM
699 # manifests. These form the bodies of the `CallInitFunc()` and `CallUnload`
700 # functions in StaticComponents.cpp.
701 def gen_module_funcs(substs, funcs):
711 for i, (init, unload) in enumerate(funcs):
712 init_code = "%s();" % init if init else "/* empty
*/"
713 inits.append(template % (i, init_code))
718 if (CalledInit(%d)) {
725 substs["init_funcs
"] = "".join(inits)
726 substs["unload_funcs
"] = "".join(unloads)
727 substs["init_count
"] = len(funcs)
730 def gen_interfaces(ifaces):
733 res.append(" nsXPTInterface
::%s,\n" % iface)
737 # Generates class pre-declarations for any types referenced in `Classes` array
738 # entries which do not have corresponding `headers` entries to fully declare
740 def gen_decls(types):
741 root_ns = Namespace()
743 for type_ in sorted(types):
744 parts = type_.split("::")
747 for part in parts[:-1]:
749 ns.classes.add(parts[-1])
751 return root_ns.to_cxx()
754 # Generates the `switch` body for the `CreateInstanceImpl()` function, with a
755 # `case` for each value in ModuleID to construct an instance of the
756 # corresponding component.
757 def gen_constructors(entries):
759 for entry in entries:
766 id=lower_module_id(entry), constructor=entry.lower_constructor()
770 return "".join(constructors)
773 # Generates the getter code for each named component entry in the
774 # `mozilla::components::` namespace.
775 def gen_getters(entries):
776 entries = list(entries)
777 entries.sort(key=lambda e: e.name)
779 return "".join(entry.lower_getters() for entry in entries if not entry.anonymous)
782 # Generates the rust getter code for each named component entry in the
783 # `xpcom::components::` module.
784 def gen_getters_rust(entries):
785 entries = list(entries)
786 entries.sort(key=lambda e: e.name)
789 entry.lower_getters_rust() for entry in entries if not entry.anonymous
793 def gen_includes(substs, all_headers):
795 absolute_headers = set()
797 for header in all_headers:
798 if header.startswith("/"):
799 absolute_headers.add(header)
803 includes = ['#include "%s"' % header for header in sorted(headers)]
804 substs["includes
"] = "\n".join(includes) + "\n"
806 relative_includes = [
807 '#include "../..%s"' % header for header in sorted(absolute_headers)
809 substs["relative_includes
"] = "\n".join(relative_includes) + "\n"
812 def to_category_list(val):
813 # Entries can be bare strings (like `"m
-browser
"`), lists of bare strings,
814 # or dictionaries (like `{"name
": "m
-browser
", "backgroundtasks
":
815 # BackgroundTasksSelector.ALL_TASKS}`), somewhat recursively.
818 # Turn `v` into `{"name
": v}` if it's not already a dict.
819 if isinstance(v, dict):
823 if isinstance(val, (list, tuple)):
824 return tuple(ensure_dict(v) for v in val)
826 if isinstance(val, dict):
827 # Explode `{"name
": ["x
", "y
"], "backgroundtasks
": ...}` into
828 # `[{"name
": "x
", "backgroundtasks
": ...}, {"name
": "y
", "backgroundtasks
": ...}]`.
829 names = val.pop("name
")
832 for entry in to_category_list(names):
834 d["name
"] = entry["name
"]
839 return (ensure_dict(val),)
842 def gen_substs(manifests):
848 categories = defaultdict(list)
850 for manifest in manifests:
851 headers |= set(manifest.get("Headers
", []))
854 init = manifest.get("InitFunc
")
855 unload = manifest.get("UnloadFunc
")
857 init_idx = len(module_funcs)
858 module_funcs.append((init, unload))
860 for clas in manifest["Classes
"]:
861 modules.append(ModuleEntry(clas, init_idx))
863 for category, entries in manifest.get("Categories
", {}).items():
864 for key, entry in entries.items():
865 if isinstance(entry, tuple):
866 value, process = entry
868 value, process = entry, 0
869 categories[category].append(({"name
": key}, value, process))
875 protocol_handlers = {}
883 headers |= set(mod.headers)
885 for contract_id in mod.contract_ids:
886 if contract_id in contract_map:
887 raise Exception("Duplicate contract ID
: %s" % contract_id)
889 entry = ContractEntry(contract_id, mod)
890 contracts.append(entry)
891 contract_map[contract_id] = entry
893 for category, entries in mod.categories.items():
894 for entry in to_category_list(entries):
895 categories[category].append((entry, mod.contract_id, mod.processes))
897 if mod.type and not mod.headers:
904 esModules.add(mod.esModule)
907 if mod.js_name in js_services:
908 raise Exception("Duplicate JS service name
: %s" % mod.js_name)
909 js_services[mod.js_name] = mod
911 if mod.protocol_config:
912 handler = ProtocolHandler(mod.protocol_config, mod)
913 if handler.scheme in protocol_handlers:
914 raise Exception("Duplicate protocol handler
: %s" % handler.scheme)
915 protocol_handlers[handler.scheme] = handler
917 if str(mod.cid) in cids:
918 raise Exception("Duplicate cid
: %s" % str(mod.cid))
919 cids.add(str(mod.cid))
921 cid_phf = PerfectHash(modules, PHF_SIZE, key=lambda module: module.cid.bytes)
923 contract_phf = PerfectHash(
924 contracts, PHF_SIZE, key=lambda entry: entry.contract.encode()
927 js_services_phf = PerfectHash(
928 list(js_services.values()), PHF_SIZE, key=lambda entry: entry.js_name.encode()
931 protocol_handlers_phf = PerfectHash(
932 list(protocol_handlers.values()),
934 key=lambda entry: entry.scheme.encode(),
937 js_services_json = {}
938 for entry in js_services.values():
939 for iface in entry.interfaces:
940 js_services_json[iface] = entry.js_name
944 gen_categories(substs, categories)
946 substs["module_ids
"] = "".join(" %s,\n" % entry.name for entry in cid_phf.entries)
948 substs["module_count
"] = len(modules)
949 substs["contract_count
"] = len(contracts)
950 substs["protocol_handler_count
"] = len(protocol_handlers)
952 substs["default_protocol_handler_idx
"] = protocol_handlers_phf.get_index(b"default
")
954 gen_module_funcs(substs, module_funcs)
956 gen_includes(substs, headers)
958 substs["component_jsms
"] = (
959 "\n".join(" %s," % strings.entry_to_cxx(jsm) for jsm in sorted(jsms)) + "\n"
961 substs["define_has_component_jsms
"] = (
962 "#define HAS_COMPONENT_JSMS" if len(jsms) > 0 else ""
964 substs
["component_esmodules"] = (
966 " %s," % strings
.entry_to_cxx(esModule
) for esModule
in sorted(esModules
)
971 substs
["interfaces"] = gen_interfaces(interfaces
)
973 substs
["decls"] = gen_decls(types
)
975 substs
["constructors"] = gen_constructors(cid_phf
.entries
)
977 substs
["component_getters"] = gen_getters(cid_phf
.entries
)
979 substs
["component_getters_rust"] = gen_getters_rust(cid_phf
.entries
)
981 substs
["module_cid_table"] = cid_phf
.cxx_codegen(
983 entry_type
="StaticModule",
984 entries_name
="gStaticModules",
985 lower_entry
=lambda entry
: entry
.to_cxx(),
986 return_type
="const StaticModule*",
988 "return entry.CID().Equals(aKey) && entry.Active()" " ? &entry : nullptr;"
990 key_type
="const nsID&",
991 key_bytes
="reinterpret_cast<const char*>(&aKey)",
992 key_length
="sizeof(nsID)",
995 substs
["module_contract_id_table"] = contract_phf
.cxx_codegen(
996 name
="LookupContractID",
997 entry_type
="ContractEntry",
998 entries_name
="gContractEntries",
999 lower_entry
=lambda entry
: entry
.to_cxx(),
1000 return_type
="const ContractEntry*",
1001 return_entry
="return entry.Matches(aKey) ? &entry : nullptr;",
1002 key_type
="const nsACString&",
1003 key_bytes
="aKey.BeginReading()",
1004 key_length
="aKey.Length()",
1007 substs
["js_services_table"] = js_services_phf
.cxx_codegen(
1008 name
="LookupJSService",
1009 entry_type
="JSServiceEntry",
1010 entries_name
="gJSServices",
1011 lower_entry
=lambda entry
: entry
.lower_js_service(),
1012 return_type
="const JSServiceEntry*",
1013 return_entry
="return entry.Name() == aKey ? &entry : nullptr;",
1014 key_type
="const nsACString&",
1015 key_bytes
="aKey.BeginReading()",
1016 key_length
="aKey.Length()",
1019 substs
["protocol_handlers_table"] = protocol_handlers_phf
.cxx_codegen(
1020 name
="LookupProtocolHandler",
1021 entry_type
="StaticProtocolHandler",
1022 entries_name
="gStaticProtocolHandlers",
1023 lower_entry
=lambda entry
: entry
.to_cxx(),
1024 return_type
="const StaticProtocolHandler*",
1025 return_entry
="return entry.Scheme() == aKey ? &entry : nullptr;",
1026 key_type
="const nsACString&",
1027 key_bytes
="aKey.BeginReading()",
1028 key_length
="aKey.Length()",
1031 substs
["js_services_json"] = (
1032 json
.dumps(js_services_json
, sort_keys
=True, indent
=2) + "\n"
1035 # Do this only after everything else has been emitted so we're sure the
1036 # string table is complete.
1037 substs
["strings"] = strings
.to_cxx()
1041 # Returns true if the given build config substitution is defined and truthy.
1043 return bool(buildconfig
.substs
.get(subst
))
1046 def read_manifest(filename
):
1048 "buildconfig": buildconfig
,
1050 "ProcessSelector": ProcessSelector
,
1051 "BackgroundTasksSelector": BackgroundTasksSelector
,
1053 code
= compile(open(filename
).read(), filename
, "exec")
1058 def main(fd
, conf_file
, template_file
):
1059 def open_output(filename
):
1060 return FileAvoidWrite(os
.path
.join(os
.path
.dirname(fd
.name
), filename
))
1062 conf
= json
.load(open(conf_file
, "r"))
1067 for filename
in conf
["manifests"]:
1069 manifest
= read_manifest(filename
)
1070 manifests
.append(manifest
)
1071 manifest
.setdefault("Priority", 50)
1072 manifest
["__filename__"] = filename
1074 manifests
.sort(key
=lambda man
: (man
["Priority"], man
["__filename__"]))
1076 substs
= gen_substs(manifests
)
1078 def replacer(match
):
1079 return substs
[match
.group(1)]
1081 with
open_output("StaticComponents.cpp") as fh
:
1082 with
open(template_file
, "r") as tfh
:
1083 template
= tfh
.read()
1085 fh
.write(re
.sub(r
"//# @([a-zA-Z_]+)@\n", replacer
, template
))
1087 with
open_output("StaticComponentData.h") as fh
:
1090 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
1091 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
1092 /* This Source Code Form is subject to the terms of the Mozilla Public
1093 * License, v. 2.0. If a copy of the MPL was not distributed with this
1094 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
1096 #ifndef StaticComponentData_h
1097 #define StaticComponentData_h
1104 static constexpr size_t kStaticModuleCount = %(module_count)d;
1106 static constexpr size_t kContractCount = %(contract_count)d;
1108 static constexpr size_t kStaticCategoryCount = %(category_count)d;
1110 static constexpr size_t kModuleInitCount = %(init_count)d;
1112 static constexpr size_t kStaticProtocolHandlerCount = %(protocol_handler_count)d;
1114 static constexpr size_t kDefaultProtocolHandlerIndex = %(default_protocol_handler_idx)d;
1116 } // namespace xpcom
1117 } // namespace mozilla
1124 with
open_output("components.rs") as fh
:
1127 /// Unique IDs for each statically-registered module.
1133 %(component_getters_rust)s
1140 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
1141 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
1142 /* This Source Code Form is subject to the terms of the Mozilla Public
1143 * License, v. 2.0. If a copy of the MPL was not distributed with this
1144 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
1146 #ifndef mozilla_Components_h
1147 #define mozilla_Components_h
1149 #include "nsCOMPtr.h"
1153 #define NS_IMPL_COMPONENT_FACTORY(iface) \\
1155 already_AddRefed<nsISupports> mozCreateComponent<iface>()
1157 template <typename T>
1158 already_AddRefed<nsISupports> mozCreateComponent();
1163 enum class ModuleID : uint16_t {
1167 // May be added as a friend function to allow constructing services via
1168 // private constructors and init methods.
1169 nsresult CreateInstanceImpl(ModuleID aID, const nsIID& aIID, void** aResult);
1171 class MOZ_STACK_CLASS StaticModuleHelper : public nsCOMPtr_helper {
1173 StaticModuleHelper(ModuleID aId, nsresult* aErrorPtr)
1174 : mId(aId), mErrorPtr(aErrorPtr) {}
1177 nsresult SetResult(nsresult aRv) const {
1185 nsresult* mErrorPtr;
1188 class MOZ_STACK_CLASS GetServiceHelper final : public StaticModuleHelper {
1190 using StaticModuleHelper::StaticModuleHelper;
1192 nsresult NS_FASTCALL operator()(const nsIID& aIID,
1193 void** aResult) const override;
1196 class MOZ_STACK_CLASS CreateInstanceHelper final : public StaticModuleHelper {
1198 using StaticModuleHelper::StaticModuleHelper;
1200 nsresult NS_FASTCALL operator()(const nsIID& aIID,
1201 void** aResult) const override;
1204 class Components final {
1206 static const nsID& GetCID(ModuleID aID);
1209 } // namespace xpcom
1211 namespace components {
1212 %(component_getters)s
1213 } // namespace components
1215 } // namespace mozilla
1222 with
open_output("services.json") as fh
:
1223 fh
.write(substs
["js_services_json"])