1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef StaticComponents_h
8 #define StaticComponents_h
9 
10 #include "mozilla/AlreadyAddRefed.h"
11 #include "mozilla/Module.h"
12 #include "mozilla/Span.h"
13 #include "nsID.h"
14 #include "nsStringFwd.h"
15 #include "nscore.h"
16 
17 #include "mozilla/Components.h"
18 #include "StaticComponentData.h"
19 
20 class nsIFactory;
21 class nsIUTF8StringEnumerator;
22 class nsISupports;
23 template <typename T, size_t N>
24 class AutoTArray;
25 
26 namespace mozilla {
27 namespace xpcom {
28 
29 struct ContractEntry;
30 struct StaticModule;
31 
32 struct StaticCategoryEntry;
33 struct StaticCategory;
34 
35 extern const StaticModule gStaticModules[kStaticModuleCount];
36 
37 extern const ContractEntry gContractEntries[kContractCount];
38 extern uint8_t gInvalidContracts[kContractCount / 8 + 1];
39 
40 extern const StaticCategory gStaticCategories[kStaticCategoryCount];
41 extern const StaticCategoryEntry gStaticCategoryEntries[];
42 
43 template <size_t N>
GetBit(const uint8_t (& aBits)[N],size_t aBit)44 static inline bool GetBit(const uint8_t (&aBits)[N], size_t aBit) {
45   static constexpr size_t width = sizeof(aBits[0]) * 8;
46 
47   size_t idx = aBit / width;
48   MOZ_ASSERT(idx < N);
49   return aBits[idx] & (1 << (aBit % width));
50 }
51 
52 template <size_t N>
53 static inline void SetBit(uint8_t (&aBits)[N], size_t aBit,
54                           bool aValue = true) {
55   static constexpr size_t width = sizeof(aBits[0]) * 8;
56 
57   size_t idx = aBit / width;
58   MOZ_ASSERT(idx < N);
59   if (aValue) {
60     aBits[idx] |= 1 << (aBit % width);
61   } else {
62     aBits[idx] &= ~(1 << (aBit % width));
63   }
64 }
65 
66 /**
67  * Represents a string entry in the static string table. Can be converted to a
68  * nsCString using GetString() in StaticComponents.cpp.
69  *
70  * This is a struct rather than a pure offset primarily for the purposes of type
71  * safety, but also so that it can easily be extended to include a static length
72  * in the future, if efficiency concerns warrant it.
73  */
74 struct StringOffset final {
75   uint32_t mOffset;
76 };
77 
78 /**
79  * Represents an offset into the interfaces table.
80  */
81 struct InterfaceOffset final {
82   uint32_t mOffset;
83 };
84 
85 /**
86  * Represents a static component entry defined in a `Classes` list in an XPCOM
87  * manifest. Handles creating instances of and caching service instances for
88  * that class.
89  */
90 struct StaticModule {
91   nsID mCID;
92   StringOffset mContractID;
93   Module::ProcessSelector mProcessSelector;
94 
CIDStaticModule95   const nsID& CID() const { return mCID; }
96 
IDStaticModule97   ModuleID ID() const { return ModuleID(this - gStaticModules); }
98 
99   /**
100    * Returns this entry's index in the gStaticModules array.
101    */
IdxStaticModule102   size_t Idx() const { return size_t(ID()); }
103 
104   /**
105    * Returns true if this component's corresponding contract ID is expected to
106    * be overridden at runtime. If so, it should always be looked up by its
107    * ContractID() when retrieving its service instance.
108    */
109   bool Overridable() const;
110 
111   /**
112    * If this entry is overridable, returns its associated contract ID string.
113    * The component should always be looked up by this contract ID when
114    * retrieving its service instance.
115    *
116    * Note: This may *only* be called if Overridable() returns true.
117    */
118   nsCString ContractID() const;
119 
120   /**
121    * Returns true if this entry is active. Typically this will only return false
122    * if the entry's process selector does not match this process.
123    */
124   bool Active() const;
125 
126   already_AddRefed<nsIFactory> GetFactory() const;
127 
128   nsresult CreateInstance(nsISupports* aOuter, const nsIID& aIID,
129                           void** aResult) const;
130 
131   GetServiceHelper GetService() const;
132   GetServiceHelper GetService(nsresult*) const;
133 
134   nsISupports* ServiceInstance() const;
135   void SetServiceInstance(already_AddRefed<nsISupports> aInst) const;
136 };
137 
138 /**
139  * Represents a static mapping between a contract ID string and a StaticModule
140  * entry.
141  */
142 struct ContractEntry final {
143   StringOffset mContractID;
144   ModuleID mModuleID;
145 
Idxfinal146   size_t Idx() const { return this - gContractEntries; }
147 
148   nsCString ContractID() const;
149 
Modulefinal150   const StaticModule& Module() const {
151     return gStaticModules[size_t(mModuleID)];
152   }
153 
154   /**
155    * Returns true if this entry's underlying module is active, and its contract
156    * ID matches the given contract ID string. This is used by the PerfectHash
157    * function to determine whether to return a result for this entry.
158    */
159   bool Matches(const nsACString& aContractID) const;
160 
161   /**
162    * Returns true if this entry has been invalidated, and should be ignored.
163    *
164    * Contract IDs may be overwritten at runtime. When that happens for a static
165    * contract ID, we mark its entry invalid, and ignore it thereafter.
166    */
Invalidfinal167   bool Invalid() const { return GetBit(gInvalidContracts, Idx()); }
168 
169   /**
170    * Marks this entry invalid (or unsets the invalid bit if aInvalid is false),
171    * after which it will be ignored in contract ID lookup attempts. See
172    * `Invalid()` above.
173    */
174   void SetInvalid(bool aInvalid = true) const {
175     return SetBit(gInvalidContracts, Idx(), aInvalid);
176   }
177 };
178 
179 /**
180  * Represents a declared category manager entry declared in an XPCOM manifest.
181  *
182  * The entire set of static category entries is read at startup and loaded into
183  * the category manager's dynamic hash tables, so there is memory and
184  * initialization overhead for each entry in these tables. This may be further
185  * optimized in the future to reduce some of that overhead.
186  */
187 struct StaticCategoryEntry final {
188   StringOffset mEntry;
189   StringOffset mValue;
190   Module::BackgroundTasksSelector mBackgroundTasksSelector;
191   Module::ProcessSelector mProcessSelector;
192 
193   nsCString Entry() const;
194   nsCString Value() const;
195   bool Active() const;
196 };
197 
198 struct StaticCategory final {
199   StringOffset mName;
200   uint16_t mStart;
201   uint16_t mCount;
202 
203   nsCString Name() const;
204 
beginfinal205   const StaticCategoryEntry* begin() const {
206     return &gStaticCategoryEntries[mStart];
207   }
endfinal208   const StaticCategoryEntry* end() const {
209     return &gStaticCategoryEntries[mStart + mCount];
210   }
211 };
212 
213 struct JSServiceEntry final {
214   using InterfaceList = AutoTArray<const nsIID*, 4>;
215 
216   static const JSServiceEntry* Lookup(const nsACString& aName);
217 
218   StringOffset mName;
219   ModuleID mModuleID;
220 
221   InterfaceOffset mInterfaceOffset;
222   uint8_t mInterfaceCount;
223 
224   nsCString Name() const;
225 
Modulefinal226   const StaticModule& Module() const {
227     return gStaticModules[size_t(mModuleID)];
228   }
229 
230   InterfaceList Interfaces() const;
231 };
232 
233 class StaticComponents final {
234  public:
235   static const StaticModule* LookupByCID(const nsID& aCID);
236 
237   static const StaticModule* LookupByContractID(const nsACString& aContractID);
238 
239   /**
240    * Marks a static contract ID entry invalid (or unsets the invalid bit if
241    * aInvalid is false). See `CategoryEntry::Invalid()`.
242    */
243   static bool InvalidateContractID(const nsACString& aContractID,
244                                    bool aInvalid = true);
245 
246   static already_AddRefed<nsIUTF8StringEnumerator> GetComponentJSMs();
247 
248   static Span<const JSServiceEntry> GetJSServices();
249 
250   /**
251    * Calls any module unload from manifests whose components have been loaded.
252    */
253   static void Shutdown();
254 };
255 
256 }  // namespace xpcom
257 }  // namespace mozilla
258 
259 #endif  // defined StaticComponents_h
260