1import json 2import os 3import re 4import struct 5from collections import defaultdict 6 7from uuid import UUID 8 9from mozbuild.util import FileAvoidWrite 10from perfecthash import PerfectHash 11import buildconfig 12 13 14NO_CONTRACT_ID = 0xffffffff 15 16PHF_SIZE = 512 17 18ENDIAN = '<' if buildconfig.substs['TARGET_ENDIANNESS'] == 'little' else '>' 19 20 21# Represents a UUID in the format used internally by Gecko, and supports 22# serializing it in that format to both C++ source and raw byte arrays. 23class UUIDRepr(object): 24 25 def __init__(self, uuid): 26 self.uuid = uuid 27 28 fields = uuid.fields 29 30 self.a = fields[0] 31 self.b = fields[1] 32 self.c = fields[2] 33 34 d = list(fields[3:5]) 35 for i in range(0, 6): 36 d.append(fields[5] >> (8 * (5 - i)) & 0xff) 37 38 self.d = tuple(d) 39 40 def __str__(self): 41 return str(self.uuid) 42 43 @property 44 def bytes(self): 45 return struct.pack(ENDIAN + 'IHHBBBBBBBB', 46 self.a, self.b, self.c, *self.d) 47 48 def to_cxx(self): 49 rest = ', '.join('0x%02x' % b for b in self.d) 50 51 return '{ 0x%x, 0x%x, 0x%x, { %s } }' % (self.a, self.b, self.c, 52 rest) 53 54 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. 58class ProcessSelector: 59 ANY_PROCESS = 0x0 60 MAIN_PROCESS_ONLY = 0x1 61 CONTENT_PROCESS_ONLY = 0x2 62 ALLOW_IN_GPU_PROCESS = 0x4 63 ALLOW_IN_VR_PROCESS = 0x8 64 ALLOW_IN_SOCKET_PROCESS = 0x10 65 ALLOW_IN_RDD_PROCESS = 0x20 66 ALLOW_IN_GPU_AND_SOCKET_PROCESS = (ALLOW_IN_GPU_PROCESS | 67 ALLOW_IN_SOCKET_PROCESS) 68 ALLOW_IN_GPU_AND_VR_PROCESS = ALLOW_IN_GPU_PROCESS | ALLOW_IN_VR_PROCESS 69 ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS = (ALLOW_IN_GPU_PROCESS | 70 ALLOW_IN_VR_PROCESS | 71 ALLOW_IN_SOCKET_PROCESS) 72 ALLOW_IN_RDD_AND_SOCKET_PROCESS = (ALLOW_IN_RDD_PROCESS | 73 ALLOW_IN_SOCKET_PROCESS) 74 ALLOW_IN_GPU_RDD_AND_SOCKET_PROCESS = (ALLOW_IN_GPU_PROCESS | 75 ALLOW_IN_RDD_PROCESS | 76 ALLOW_IN_SOCKET_PROCESS) 77 ALLOW_IN_GPU_RDD_VR_AND_SOCKET_PROCESS = (ALLOW_IN_GPU_PROCESS | 78 ALLOW_IN_RDD_PROCESS | 79 ALLOW_IN_VR_PROCESS | 80 ALLOW_IN_SOCKET_PROCESS) 81 82 83# Maps ProcessSelector constants to the name of the corresponding 84# Module::ProcessSelector enum value. 85PROCESSES = { 86 ProcessSelector.ANY_PROCESS: 'ANY_PROCESS', 87 ProcessSelector.MAIN_PROCESS_ONLY: 'MAIN_PROCESS_ONLY', 88 ProcessSelector.CONTENT_PROCESS_ONLY: 'CONTENT_PROCESS_ONLY', 89 ProcessSelector.ALLOW_IN_GPU_PROCESS: 'ALLOW_IN_GPU_PROCESS', 90 ProcessSelector.ALLOW_IN_VR_PROCESS: 'ALLOW_IN_VR_PROCESS', 91 ProcessSelector.ALLOW_IN_SOCKET_PROCESS: 'ALLOW_IN_SOCKET_PROCESS', 92 ProcessSelector.ALLOW_IN_RDD_PROCESS: 'ALLOW_IN_RDD_PROCESS', 93 ProcessSelector.ALLOW_IN_GPU_AND_SOCKET_PROCESS: 'ALLOW_IN_GPU_AND_SOCKET_PROCESS', 94 ProcessSelector.ALLOW_IN_GPU_AND_VR_PROCESS: 'ALLOW_IN_GPU_AND_VR_PROCESS', 95 ProcessSelector.ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS: 'ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS', 96 ProcessSelector.ALLOW_IN_RDD_AND_SOCKET_PROCESS: 97 'ALLOW_IN_RDD_AND_SOCKET_PROCESS', 98 ProcessSelector.ALLOW_IN_GPU_RDD_AND_SOCKET_PROCESS: 99 'ALLOW_IN_GPU_RDD_AND_SOCKET_PROCESS', 100 ProcessSelector.ALLOW_IN_GPU_RDD_VR_AND_SOCKET_PROCESS: 101 'ALLOW_IN_GPU_RDD_VR_AND_SOCKET_PROCESS', 102} 103 104 105# Emits the C++ symbolic constant corresponding to a ProcessSelector constant. 106def lower_processes(processes): 107 return 'Module::ProcessSelector::%s' % PROCESSES[processes] 108 109 110# Emits the C++ symbolic constant for a ModuleEntry's ModuleID enum entry. 111def lower_module_id(module): 112 return 'ModuleID::%s' % module.name 113 114 115# Represents a static string table, indexed by offset. This allows us to 116# reference strings from static data structures without requiring runtime 117# relocations. 118class StringTable(object): 119 120 def __init__(self): 121 self.entries = {} 122 self.entry_list = [] 123 self.size = 0 124 125 self._serialized = False 126 127 # Returns the index of the given string in the `entry_list` array. If 128 # no entry for the string exists, it first creates one. 129 def get_idx(self, string): 130 idx = self.entries.get(string, None) 131 if idx is not None: 132 return idx 133 134 assert not self._serialized 135 136 assert len(string) == len(string.encode('utf-8')) 137 138 idx = self.size 139 self.size += len(string) + 1 140 141 self.entries[string] = idx 142 self.entry_list.append(string) 143 return idx 144 145 # Returns the C++ code representing string data of this string table, as a 146 # single string literal. This must only be called after the last call to 147 # `get_idx()` or `entry_to_cxx()` for this instance. 148 def to_cxx(self): 149 self._serialized = True 150 151 lines = [] 152 153 idx = 0 154 for entry in self.entry_list: 155 str_ = entry.replace('\\', '\\\\').replace('"', r'\"') \ 156 .replace('\n', r'\n') 157 158 lines.append(' /* 0x%x */ "%s\\0"\n' % (idx, str_)) 159 160 idx += len(entry) + 1 161 162 return ''.join(lines) 163 164 # Returns a `StringEntry` struct initializer for the string table entry 165 # corresponding to the given string. If no matching entry exists, it is 166 # first created. 167 def entry_to_cxx(self, string): 168 idx = self.get_idx(string) 169 return '{ 0x%x } /* %s */' % ( 170 idx, 171 pretty_string(string)) 172 173 174strings = StringTable() 175 176 177# Represents a C++ namespace, containing a set of classes and potentially 178# sub-namespaces. This is used to generate pre-declarations for incomplete 179# types referenced in XPCOM manifests. 180class Namespace(object): 181 182 def __init__(self, name=None): 183 self.name = name 184 self.classes = set() 185 self.namespaces = {} 186 187 # Returns a Namespace object for the sub-namespace with the given name. 188 def sub(self, name): 189 assert name not in self.classes 190 191 if name not in self.namespaces: 192 self.namespaces[name] = Namespace(name) 193 return self.namespaces[name] 194 195 # Generates C++ code to pre-declare all classes in this namespace and all 196 # of its sub-namespaces. 197 def to_cxx(self): 198 res = "" 199 if self.name: 200 res += 'namespace %s {\n' % self.name 201 202 for clas in sorted(self.classes): 203 res += 'class %s;\n' % clas 204 205 for ns in sorted(self.namespaces.keys()): 206 res += self.namespaces[ns].to_cxx() 207 208 if self.name: 209 res += '} // namespace %s\n' % self.name 210 211 return res 212 213 214# Represents a component defined in an XPCOM manifest's `Classes` array. 215class ModuleEntry(object): 216 next_anon_id = 0 217 218 def __init__(self, data, init_idx): 219 self.cid = UUIDRepr(UUID(data['cid'])) 220 self.contract_ids = data.get('contract_ids', []) 221 self.type = data.get('type', 'nsISupports') 222 self.categories = data.get('categories', {}) 223 self.processes = data.get('processes', 0) 224 self.headers = data.get('headers', []) 225 226 # If the manifest declares Init or Unload functions, this contains its 227 # index, as understood by the `CallInitFunc()` function. 228 # 229 # If it contains any value other than `None`, a corresponding 230 # `CallInitFunc(init_idx)` call will be genrated before calling this 231 # module's constructor. 232 self.init_idx = init_idx 233 234 self.constructor = data.get('constructor', None) 235 self.legacy_constructor = data.get('legacy_constructor', None) 236 self.init_method = data.get('init_method', []) 237 238 self.jsm = data.get('jsm', None) 239 240 self.external = data.get('external', not (self.headers or 241 self.legacy_constructor)) 242 self.singleton = data.get('singleton', False) 243 self.overridable = data.get('overridable', False) 244 245 if 'name' in data: 246 self.anonymous = False 247 self.name = data['name'] 248 else: 249 self.anonymous = True 250 self.name = 'Anonymous%03d' % ModuleEntry.next_anon_id 251 ModuleEntry.next_anon_id += 1 252 253 def error(str_): 254 raise Exception("Error defining component %s (%s): %s" % ( 255 str(self.cid), ', '.join(map(repr, self.contract_ids)), 256 str_)) 257 258 if self.jsm: 259 if not self.constructor: 260 error("JavaScript components must specify a constructor") 261 262 for prop in ('init_method', 'legacy_constructor', 'headers'): 263 if getattr(self, prop): 264 error("JavaScript components may not specify a '%s' " 265 "property" % prop) 266 elif self.external: 267 if self.constructor or self.legacy_constructor: 268 error("Externally-constructed components may not specify " 269 "'constructor' or 'legacy_constructor' properties") 270 if self.init_method: 271 error("Externally-constructed components may not specify " 272 "'init_method' properties") 273 if self.type == 'nsISupports': 274 error("Externally-constructed components must specify a type " 275 "other than nsISupports") 276 277 if self.constructor and self.legacy_constructor: 278 error("The 'constructor' and 'legacy_constructor' properties " 279 "are mutually exclusive") 280 281 if self.overridable and not self.contract_ids: 282 error("Overridable components must specify at least one contract " 283 "ID") 284 285 @property 286 def contract_id(self): 287 return self.contract_ids[0] 288 289 # Generates the C++ code for a StaticModule struct initializer 290 # representing this component. 291 def to_cxx(self): 292 contract_id = (strings.entry_to_cxx(self.contract_id) 293 if self.overridable 294 else '{ 0x%x }' % NO_CONTRACT_ID) 295 296 return """ 297 /* {name} */ {{ 298 /* {{{cid_string}}} */ 299 {cid}, 300 {contract_id}, 301 {processes}, 302 }}""".format(name=self.name, cid=self.cid.to_cxx(), 303 cid_string=str(self.cid), 304 contract_id=contract_id, 305 processes=lower_processes(self.processes)) 306 307 # Generates the C++ code necessary to construct an instance of this 308 # component. 309 # 310 # This code lives in a function with the following arguments: 311 # 312 # - aIID: The `const nsIID&` interface ID that the resulting instance 313 # will be queried to. 314 # 315 # - aResult: The `void**` pointer in which to store the result. 316 # 317 # And which returns an `nsresult` indicating success or failure. 318 def lower_constructor(self): 319 res = '' 320 321 if self.init_idx is not None: 322 res += ' MOZ_TRY(CallInitFunc(%d));\n' % self.init_idx 323 324 if self.legacy_constructor: 325 res += (' return /* legacy */ %s(nullptr, aIID, aResult);\n' 326 % self.legacy_constructor) 327 return res 328 329 if self.jsm: 330 res += ( 331 ' nsCOMPtr<nsISupports> inst;\n' 332 ' MOZ_TRY(ConstructJSMComponent(NS_LITERAL_CSTRING(%s),\n' 333 ' %s,\n' 334 ' getter_AddRefs(inst)));' 335 '\n' % (json.dumps(self.jsm), json.dumps(self.constructor))) 336 elif self.external: 337 res += (' nsCOMPtr<nsISupports> inst = ' 338 'mozCreateComponent<%s>();\n' % self.type) 339 # The custom constructor may return null, so check before calling 340 # any methods. 341 res += ' NS_ENSURE_TRUE(inst, NS_ERROR_FAILURE);\n' 342 else: 343 res += ' RefPtr<%s> inst = ' % self.type 344 345 if not self.constructor: 346 res += 'new %s();\n' % self.type 347 else: 348 res += '%s();\n' % self.constructor 349 # The `new` operator is infallible, so we don't need to worry 350 # about it returning null, but custom constructors may, so 351 # check before calling any methods. 352 res += ' NS_ENSURE_TRUE(inst, NS_ERROR_OUT_OF_MEMORY);\n' 353 354 # Check that the constructor function returns an appropriate 355 # `already_AddRefed` value for our declared type. 356 res += """ 357 using T = 358 RemoveAlreadyAddRefed<decltype(%(constructor)s())>::Type; 359 static_assert( 360 std::is_same_v<already_AddRefed<T>, decltype(%(constructor)s())>, 361 "Singleton constructor must return already_AddRefed"); 362 static_assert( 363 std::is_base_of<%(type)s, T>::value, 364 "Singleton constructor must return correct already_AddRefed"); 365 366""" % {'type': self.type, 'constructor': self.constructor} 367 368 if self.init_method: 369 res += ' MOZ_TRY(inst->%s());\n' % self.init_method 370 371 res += ' return inst->QueryInterface(aIID, aResult);\n' 372 373 return res 374 375 # Generates the C++ code for the `mozilla::components::<name>` entry 376 # corresponding to this component. This may not be called for modules 377 # without an explicit `name` (in which cases, `self.anonymous` will be 378 # true). 379 def lower_getters(self): 380 assert not self.anonymous 381 382 substs = { 383 'name': self.name, 384 'id': '::mozilla::xpcom::ModuleID::%s' % self.name, 385 } 386 387 res = """ 388namespace %(name)s { 389static inline const nsID& CID() { 390 return ::mozilla::xpcom::Components::GetCID(%(id)s); 391} 392 393static inline ::mozilla::xpcom::GetServiceHelper Service(nsresult* aRv = nullptr) { 394 return {%(id)s, aRv}; 395} 396""" % substs 397 398 if not self.singleton: 399 res += """ 400static inline ::mozilla::xpcom::CreateInstanceHelper Create(nsresult* aRv = nullptr) { 401 return {%(id)s, aRv}; 402} 403""" % substs 404 405 res += """\ 406} // namespace %(name)s 407""" % substs 408 409 return res 410 411 412# Returns a quoted string literal representing the given raw string, with 413# certain special characters replaced so that it can be used in a C++-style 414# (/* ... */) comment. 415def pretty_string(string): 416 return (json.dumps(string).replace('*/', r'*\/') 417 .replace('/*', r'/\*')) 418 419 420# Represents a static contract ID entry, corresponding to a C++ ContractEntry 421# struct, mapping a contract ID to a static module entry. 422class ContractEntry(object): 423 424 def __init__(self, contract, module): 425 self.contract = contract 426 self.module = module 427 428 def to_cxx(self): 429 return """ 430 {{ 431 {contract}, 432 {module_id}, 433 }}""".format(contract=strings.entry_to_cxx(self.contract), 434 module_id=lower_module_id(self.module)) 435 436 437# Generates the C++ code for the StaticCategoryEntry and StaticCategory 438# structs for all category entries declared in XPCOM manifests. 439def gen_categories(substs, categories): 440 cats = [] 441 ents = [] 442 443 count = 0 444 for category, entries in sorted(categories.items()): 445 entries.sort() 446 447 cats.append(' { %s,\n' 448 ' %d, %d },\n' 449 % (strings.entry_to_cxx(category), 450 count, len(entries))) 451 count += len(entries) 452 453 ents.append(' /* %s */\n' % pretty_string(category)) 454 for entry, value, processes in entries: 455 ents.append(' { %s,\n' 456 ' %s,\n' 457 ' %s },\n' 458 % (strings.entry_to_cxx(entry), 459 strings.entry_to_cxx(value), 460 lower_processes(processes))) 461 ents.append('\n') 462 ents.pop() 463 464 substs['category_count'] = len(cats) 465 substs['categories'] = ''.join(cats) 466 substs['category_entries'] = ''.join(ents) 467 468 469# Generates the C++ code for all Init and Unload functions declared in XPCOM 470# manifests. These form the bodies of the `CallInitFunc()` and `CallUnload` 471# functions in StaticComponents.cpp. 472def gen_module_funcs(substs, funcs): 473 inits = [] 474 unloads = [] 475 476 template = """\ 477 case %d: 478 %s 479 break; 480""" 481 482 for i, (init, unload) in enumerate(funcs): 483 init_code = '%s();' % init if init else '/* empty */' 484 inits.append(template % (i, init_code)) 485 486 if unload: 487 unloads.append("""\ 488 if (CalledInit(%d)) { 489 %s(); 490 } 491""" % (i, unload)) 492 493 substs['init_funcs'] = ''.join(inits) 494 substs['unload_funcs'] = ''.join(unloads) 495 substs['init_count'] = len(funcs) 496 497 498# Generates class pre-declarations for any types referenced in `Classes` array 499# entries which do not have corresponding `headers` entries to fully declare 500# their types. 501def gen_decls(types): 502 root_ns = Namespace() 503 504 for type_ in sorted(types): 505 parts = type_.split('::') 506 507 ns = root_ns 508 for part in parts[:-1]: 509 ns = ns.sub(part) 510 ns.classes.add(parts[-1]) 511 512 return root_ns.to_cxx() 513 514 515# Generates the `switch` body for the `CreateInstanceImpl()` function, with a 516# `case` for each value in ModuleID to construct an instance of the 517# corresponding component. 518def gen_constructors(entries): 519 constructors = [] 520 for entry in entries: 521 constructors.append("""\ 522 case {id}: {{ 523{constructor}\ 524 }} 525""".format(id=lower_module_id(entry), 526 constructor=entry.lower_constructor())) 527 528 return ''.join(constructors) 529 530 531# Generates the getter code for each named component entry in the 532# `mozilla::components::` namespace. 533def gen_getters(entries): 534 entries = list(entries) 535 entries.sort(key=lambda e: e.name) 536 537 return ''.join(entry.lower_getters() 538 for entry in entries 539 if not entry.anonymous) 540 541 542def gen_includes(substs, all_headers): 543 headers = set() 544 absolute_headers = set() 545 546 for header in all_headers: 547 if header.startswith('/'): 548 absolute_headers.add(header) 549 else: 550 headers.add(header) 551 552 includes = ['#include "%s"' % header for header in sorted(headers)] 553 substs['includes'] = '\n'.join(includes) + '\n' 554 555 relative_includes = ['#include "../..%s"' % header 556 for header in sorted(absolute_headers)] 557 substs['relative_includes'] = '\n'.join(relative_includes) + '\n' 558 559 560def to_list(val): 561 if isinstance(val, (list, tuple)): 562 return val 563 return val, 564 565 566def gen_substs(manifests): 567 module_funcs = [] 568 569 headers = set() 570 571 modules = [] 572 573 for manifest in manifests: 574 headers |= set(manifest.get('Headers', [])) 575 576 init_idx = None 577 init = manifest.get('InitFunc') 578 unload = manifest.get('UnloadFunc') 579 if init or unload: 580 init_idx = len(module_funcs) 581 module_funcs.append((init, unload)) 582 583 for clas in manifest['Classes']: 584 modules.append(ModuleEntry(clas, init_idx)) 585 586 contracts = [] 587 contract_map = {} 588 categories = defaultdict(list) 589 590 jsms = set() 591 592 types = set() 593 594 for mod in modules: 595 headers |= set(mod.headers) 596 597 for contract_id in mod.contract_ids: 598 if contract_id in contract_map: 599 raise Exception('Duplicate contract ID: %s' % contract_id) 600 601 entry = ContractEntry(contract_id, mod) 602 contracts.append(entry) 603 contract_map[contract_id] = entry 604 605 for category, entries in mod.categories.items(): 606 for entry in to_list(entries): 607 categories[category].append((entry, mod.contract_id, 608 mod.processes)) 609 610 if mod.type and not mod.headers: 611 types.add(mod.type) 612 613 if mod.jsm: 614 jsms.add(mod.jsm) 615 616 cid_phf = PerfectHash(modules, PHF_SIZE, 617 key=lambda module: module.cid.bytes) 618 619 contract_phf = PerfectHash(contracts, PHF_SIZE, 620 key=lambda entry: entry.contract) 621 622 substs = {} 623 624 gen_categories(substs, categories) 625 626 substs['module_ids'] = ''.join(' %s,\n' % entry.name 627 for entry in cid_phf.entries) 628 629 substs['module_count'] = len(modules) 630 substs['contract_count'] = len(contracts) 631 632 gen_module_funcs(substs, module_funcs) 633 634 gen_includes(substs, headers) 635 636 substs['component_jsms'] = '\n'.join(' %s,' % strings.entry_to_cxx(jsm) 637 for jsm in sorted(jsms)) + '\n' 638 639 substs['decls'] = gen_decls(types) 640 641 substs['constructors'] = gen_constructors(cid_phf.entries) 642 643 substs['component_getters'] = gen_getters(cid_phf.entries) 644 645 substs['module_cid_table'] = cid_phf.cxx_codegen( 646 name='ModuleByCID', 647 entry_type='StaticModule', 648 entries_name='gStaticModules', 649 lower_entry=lambda entry: entry.to_cxx(), 650 651 return_type='const StaticModule*', 652 return_entry=('return entry.CID().Equals(aKey) && entry.Active()' 653 ' ? &entry : nullptr;'), 654 655 key_type='const nsID&', 656 key_bytes='reinterpret_cast<const char*>(&aKey)', 657 key_length='sizeof(nsID)') 658 659 substs['module_contract_id_table'] = contract_phf.cxx_codegen( 660 name='LookupContractID', 661 entry_type='ContractEntry', 662 entries_name='gContractEntries', 663 lower_entry=lambda entry: entry.to_cxx(), 664 665 return_type='const ContractEntry*', 666 return_entry='return entry.Matches(aKey) ? &entry : nullptr;', 667 668 key_type='const nsACString&', 669 key_bytes='aKey.BeginReading()', 670 key_length='aKey.Length()') 671 672 # Do this only after everything else has been emitted so we're sure the 673 # string table is complete. 674 substs['strings'] = strings.to_cxx() 675 return substs 676 677 678# Returns true if the given build config substitution is defined and truthy. 679def defined(subst): 680 return bool(buildconfig.substs.get(subst)) 681 682 683def read_manifest(filename): 684 glbl = {'buildconfig': buildconfig, 685 'defined': defined, 686 'ProcessSelector': ProcessSelector} 687 exec(open(filename).read(), glbl) 688 return glbl 689 690 691def main(fd, conf_file, template_file): 692 def open_output(filename): 693 return FileAvoidWrite(os.path.join(os.path.dirname(fd.name), filename)) 694 695 conf = json.load(open(conf_file, 'r')) 696 697 deps = set() 698 699 manifests = [] 700 for filename in conf['manifests']: 701 deps.add(filename) 702 manifest = read_manifest(filename) 703 manifests.append(manifest) 704 manifest.setdefault('Priority', 50) 705 manifest['__filename__'] = filename 706 707 manifests.sort(key=lambda man: (man['Priority'], man['__filename__'])) 708 709 substs = gen_substs(manifests) 710 711 def replacer(match): 712 return substs[match.group(1)] 713 714 with open_output('StaticComponents.cpp') as fh: 715 with open(template_file, 'r') as tfh: 716 template = tfh.read() 717 718 fh.write(re.sub(r'//# @([a-zA-Z_]+)@\n', replacer, template)) 719 720 with open_output('StaticComponentData.h') as fh: 721 fh.write("""\ 722/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 723/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 724/* This Source Code Form is subject to the terms of the Mozilla Public 725 * License, v. 2.0. If a copy of the MPL was not distributed with this 726 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 727 728#ifndef StaticComponentData_h 729#define StaticComponentData_h 730 731namespace mozilla { 732namespace xpcom { 733 734static constexpr size_t kStaticModuleCount = %(module_count)d; 735 736static constexpr size_t kContractCount = %(contract_count)d; 737 738static constexpr size_t kStaticCategoryCount = %(category_count)d; 739 740static constexpr size_t kModuleInitCount = %(init_count)d; 741 742} // namespace xpcom 743} // namespace mozilla 744 745#endif 746""" % substs) 747 748 fd.write("""\ 749/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 750/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 751/* This Source Code Form is subject to the terms of the Mozilla Public 752 * License, v. 2.0. If a copy of the MPL was not distributed with this 753 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 754 755#ifndef mozilla_Components_h 756#define mozilla_Components_h 757 758#include "nsCOMPtr.h" 759 760struct nsID; 761 762#define NS_IMPL_COMPONENT_FACTORY(iface) \\ 763 template <> \\ 764 already_AddRefed<nsISupports> mozCreateComponent<iface>() 765 766template <typename T> 767already_AddRefed<nsISupports> mozCreateComponent(); 768 769namespace mozilla { 770namespace xpcom { 771 772enum class ModuleID : uint16_t { 773%(module_ids)s 774}; 775 776class MOZ_STACK_CLASS StaticModuleHelper : public nsCOMPtr_helper { 777 public: 778 StaticModuleHelper(ModuleID aId, nsresult* aErrorPtr) 779 : mId(aId), mErrorPtr(aErrorPtr) {} 780 781 protected: 782 nsresult SetResult(nsresult aRv) const { 783 if (mErrorPtr) { 784 *mErrorPtr = aRv; 785 } 786 return aRv; 787 } 788 789 ModuleID mId; 790 nsresult* mErrorPtr; 791}; 792 793class MOZ_STACK_CLASS GetServiceHelper final : public StaticModuleHelper { 794 public: 795 using StaticModuleHelper::StaticModuleHelper; 796 797 nsresult NS_FASTCALL operator()(const nsIID& aIID, 798 void** aResult) const override; 799}; 800 801class MOZ_STACK_CLASS CreateInstanceHelper final : public StaticModuleHelper { 802 public: 803 using StaticModuleHelper::StaticModuleHelper; 804 805 nsresult NS_FASTCALL operator()(const nsIID& aIID, 806 void** aResult) const override; 807}; 808 809class Components final { 810 public: 811 static const nsID& GetCID(ModuleID aID); 812}; 813 814} // namespace xpcom 815 816namespace components { 817%(component_getters)s 818} // namespace components 819 820} // namespace mozilla 821 822#endif 823""" % substs) 824 825 return deps 826