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(contracts, PHF_SIZE, key=lambda entry: entry.contract)
925 js_services_phf = PerfectHash(
926 list(js_services.values()), PHF_SIZE, key=lambda entry: entry.js_name
929 protocol_handlers_phf = PerfectHash(
930 list(protocol_handlers.values()), TINY_PHF_SIZE, key=lambda entry: entry.scheme
933 js_services_json = {}
934 for entry in js_services.values():
935 for iface in entry.interfaces:
936 js_services_json[iface] = entry.js_name
940 gen_categories(substs, categories)
942 substs["module_ids
"] = "".join(" %s,\n" % entry.name for entry in cid_phf.entries)
944 substs["module_count
"] = len(modules)
945 substs["contract_count
"] = len(contracts)
946 substs["protocol_handler_count
"] = len(protocol_handlers)
948 substs["default_protocol_handler_idx
"] = protocol_handlers_phf.get_index("default
")
950 gen_module_funcs(substs, module_funcs)
952 gen_includes(substs, headers)
954 substs["component_jsms
"] = (
955 "\n".join(" %s," % strings.entry_to_cxx(jsm) for jsm in sorted(jsms)) + "\n"
957 substs["component_esmodules
"] = (
959 " %s," % strings.entry_to_cxx(esModule) for esModule in sorted(esModules)
964 substs["interfaces
"] = gen_interfaces(interfaces)
966 substs["decls
"] = gen_decls(types)
968 substs["constructors
"] = gen_constructors(cid_phf.entries)
970 substs["component_getters
"] = gen_getters(cid_phf.entries)
972 substs["component_getters_rust
"] = gen_getters_rust(cid_phf.entries)
974 substs["module_cid_table
"] = cid_phf.cxx_codegen(
976 entry_type="StaticModule
",
977 entries_name="gStaticModules
",
978 lower_entry=lambda entry: entry.to_cxx(),
979 return_type="const StaticModule
*",
981 "return entry
.CID().Equals(aKey
) && entry
.Active()" " ?
&entry
: nullptr
;"
983 key_type="const nsID
&",
984 key_bytes="reinterpret_cast
<const char
*>(&aKey
)",
985 key_length="sizeof(nsID
)",
988 substs["module_contract_id_table
"] = contract_phf.cxx_codegen(
989 name="LookupContractID
",
990 entry_type="ContractEntry
",
991 entries_name="gContractEntries
",
992 lower_entry=lambda entry: entry.to_cxx(),
993 return_type="const ContractEntry
*",
994 return_entry="return entry
.Matches(aKey
) ?
&entry
: nullptr
;",
995 key_type="const nsACString
&",
996 key_bytes="aKey
.BeginReading()",
997 key_length="aKey
.Length()",
1000 substs["js_services_table
"] = js_services_phf.cxx_codegen(
1001 name="LookupJSService
",
1002 entry_type="JSServiceEntry
",
1003 entries_name="gJSServices
",
1004 lower_entry=lambda entry: entry.lower_js_service(),
1005 return_type="const JSServiceEntry
*",
1006 return_entry="return entry
.Name() == aKey ?
&entry
: nullptr
;",
1007 key_type="const nsACString
&",
1008 key_bytes="aKey
.BeginReading()",
1009 key_length="aKey
.Length()",
1012 substs["protocol_handlers_table
"] = protocol_handlers_phf.cxx_codegen(
1013 name="LookupProtocolHandler
",
1014 entry_type="StaticProtocolHandler
",
1015 entries_name="gStaticProtocolHandlers
",
1016 lower_entry=lambda entry: entry.to_cxx(),
1017 return_type="const StaticProtocolHandler
*",
1018 return_entry="return entry
.Scheme() == aKey ?
&entry
: nullptr
;",
1019 key_type="const nsACString
&",
1020 key_bytes="aKey
.BeginReading()",
1021 key_length="aKey
.Length()",
1024 substs["js_services_json
"] = json.dumps(js_services_json, sort_keys=True, indent=4)
1026 # Do this only after everything else has been emitted so we're sure the
1027 # string table is complete.
1028 substs["strings
"] = strings.to_cxx()
1032 # Returns true if the given build config substitution is defined and truthy.
1034 return bool(buildconfig.substs.get(subst))
1037 def read_manifest(filename):
1039 "buildconfig
": buildconfig,
1041 "ProcessSelector
": ProcessSelector,
1042 "BackgroundTasksSelector
": BackgroundTasksSelector,
1044 code = compile(open(filename).read(), filename, "exec")
1049 def main(fd, conf_file, template_file):
1050 def open_output(filename):
1051 return FileAvoidWrite(os.path.join(os.path.dirname(fd.name), filename))
1053 conf = json.load(open(conf_file, "r
"))
1058 for filename in conf["manifests
"]:
1060 manifest = read_manifest(filename)
1061 manifests.append(manifest)
1062 manifest.setdefault("Priority
", 50)
1063 manifest["__filename__
"] = filename
1065 manifests.sort(key=lambda man: (man["Priority
"], man["__filename__
"]))
1067 substs = gen_substs(manifests)
1069 def replacer(match):
1070 return substs[match.group(1)]
1072 with open_output("StaticComponents
.cpp
") as fh:
1073 with open(template_file, "r
") as tfh:
1074 template = tfh.read()
1076 fh.write(re.sub(r"//# @([a-zA-Z_]+)@\n", replacer, template))
1078 with
open_output("StaticComponentData.h") as fh
:
1081 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
1082 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
1083 /* This Source Code Form is subject to the terms of the Mozilla Public
1084 * License, v. 2.0. If a copy of the MPL was not distributed with this
1085 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
1087 #ifndef StaticComponentData_h
1088 #define StaticComponentData_h
1095 static constexpr size_t kStaticModuleCount = %(module_count)d;
1097 static constexpr size_t kContractCount = %(contract_count)d;
1099 static constexpr size_t kStaticCategoryCount = %(category_count)d;
1101 static constexpr size_t kModuleInitCount = %(init_count)d;
1103 static constexpr size_t kStaticProtocolHandlerCount = %(protocol_handler_count)d;
1105 static constexpr size_t kDefaultProtocolHandlerIndex = %(default_protocol_handler_idx)d;
1107 } // namespace xpcom
1108 } // namespace mozilla
1115 with
open_output("components.rs") as fh
:
1118 /// Unique IDs for each statically-registered module.
1124 %(component_getters_rust)s
1131 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
1132 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
1133 /* This Source Code Form is subject to the terms of the Mozilla Public
1134 * License, v. 2.0. If a copy of the MPL was not distributed with this
1135 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
1137 #ifndef mozilla_Components_h
1138 #define mozilla_Components_h
1140 #include "nsCOMPtr.h"
1144 #define NS_IMPL_COMPONENT_FACTORY(iface) \\
1146 already_AddRefed<nsISupports> mozCreateComponent<iface>()
1148 template <typename T>
1149 already_AddRefed<nsISupports> mozCreateComponent();
1154 enum class ModuleID : uint16_t {
1158 // May be added as a friend function to allow constructing services via
1159 // private constructors and init methods.
1160 nsresult CreateInstanceImpl(ModuleID aID, const nsIID& aIID, void** aResult);
1162 class MOZ_STACK_CLASS StaticModuleHelper : public nsCOMPtr_helper {
1164 StaticModuleHelper(ModuleID aId, nsresult* aErrorPtr)
1165 : mId(aId), mErrorPtr(aErrorPtr) {}
1168 nsresult SetResult(nsresult aRv) const {
1176 nsresult* mErrorPtr;
1179 class MOZ_STACK_CLASS GetServiceHelper final : public StaticModuleHelper {
1181 using StaticModuleHelper::StaticModuleHelper;
1183 nsresult NS_FASTCALL operator()(const nsIID& aIID,
1184 void** aResult) const override;
1187 class MOZ_STACK_CLASS CreateInstanceHelper final : public StaticModuleHelper {
1189 using StaticModuleHelper::StaticModuleHelper;
1191 nsresult NS_FASTCALL operator()(const nsIID& aIID,
1192 void** aResult) const override;
1195 class Components final {
1197 static const nsID& GetCID(ModuleID aID);
1200 } // namespace xpcom
1202 namespace components {
1203 %(component_getters)s
1204 } // namespace components
1206 } // namespace mozilla
1213 with
open_output("services.json") as fh
:
1214 fh
.write(substs
["js_services_json"])