summaryrefslogtreecommitdiffstats
path: root/xpcom/components/StaticComponents.h
blob: ac4095f2f35e85e367b0a455453e8b84db3ee09a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef StaticComponents_h
#define StaticComponents_h

#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/Module.h"
#include "mozilla/Span.h"
#include "nsID.h"
#include "nsStringFwd.h"
#include "nscore.h"

#include "mozilla/Components.h"
#include "StaticComponentData.h"

class nsIFactory;
class nsIUTF8StringEnumerator;
class nsISupports;
template <typename T, size_t N>
class AutoTArray;

namespace mozilla {
namespace xpcom {

struct ContractEntry;
struct StaticModule;

struct StaticCategoryEntry;
struct StaticCategory;

struct StaticProtocolHandler;

extern const StaticModule gStaticModules[kStaticModuleCount];

extern const ContractEntry gContractEntries[kContractCount];
extern uint8_t gInvalidContracts[kContractCount / 8 + 1];

extern const StaticCategory gStaticCategories[kStaticCategoryCount];
extern const StaticCategoryEntry gStaticCategoryEntries[];

extern const StaticProtocolHandler
    gStaticProtocolHandlers[kStaticProtocolHandlerCount];

template <size_t N>
static inline bool GetBit(const uint8_t (&aBits)[N], size_t aBit) {
  static constexpr size_t width = sizeof(aBits[0]) * 8;

  size_t idx = aBit / width;
  MOZ_ASSERT(idx < N);
  return aBits[idx] & (1 << (aBit % width));
}

template <size_t N>
static inline void SetBit(uint8_t (&aBits)[N], size_t aBit,
                          bool aValue = true) {
  static constexpr size_t width = sizeof(aBits[0]) * 8;

  size_t idx = aBit / width;
  MOZ_ASSERT(idx < N);
  if (aValue) {
    aBits[idx] |= 1 << (aBit % width);
  } else {
    aBits[idx] &= ~(1 << (aBit % width));
  }
}

/**
 * Represents a string entry in the static string table. Can be converted to a
 * nsCString using GetString() in StaticComponents.cpp.
 *
 * This is a struct rather than a pure offset primarily for the purposes of type
 * safety, but also so that it can easily be extended to include a static length
 * in the future, if efficiency concerns warrant it.
 */
struct StringOffset final {
  uint32_t mOffset;
};

/**
 * Represents an offset into the interfaces table.
 */
struct InterfaceOffset final {
  uint16_t mOffset;
};

/**
 * Represents a static component entry defined in a `Classes` list in an XPCOM
 * manifest. Handles creating instances of and caching service instances for
 * that class.
 */
struct StaticModule {
  nsID mCID;
  StringOffset mContractID;
  Module::ProcessSelector mProcessSelector;

  const nsID& CID() const { return mCID; }

  ModuleID ID() const { return ModuleID(this - gStaticModules); }

  /**
   * Returns this entry's index in the gStaticModules array.
   */
  size_t Idx() const { return size_t(ID()); }

  /**
   * Returns true if this component's corresponding contract ID is expected to
   * be overridden at runtime. If so, it should always be looked up by its
   * ContractID() when retrieving its service instance.
   */
  bool Overridable() const;

  /**
   * If this entry is overridable, returns its associated contract ID string.
   * The component should always be looked up by this contract ID when
   * retrieving its service instance.
   *
   * Note: This may *only* be called if Overridable() returns true.
   */
  nsCString ContractID() const;

  /**
   * Returns true if this entry is active. Typically this will only return false
   * if the entry's process selector does not match this process.
   */
  bool Active() const;

  already_AddRefed<nsIFactory> GetFactory() const;

  nsresult CreateInstance(const nsIID& aIID, void** aResult) const;

  GetServiceHelper GetService() const;
  GetServiceHelper GetService(nsresult*) const;

  nsISupports* ServiceInstance() const;
  void SetServiceInstance(already_AddRefed<nsISupports> aInst) const;
};

/**
 * Represents a static mapping between a contract ID string and a StaticModule
 * entry.
 */
struct ContractEntry final {
  StringOffset mContractID;
  ModuleID mModuleID;

  size_t Idx() const { return this - gContractEntries; }

  nsCString ContractID() const;

  const StaticModule& Module() const {
    return gStaticModules[size_t(mModuleID)];
  }

  /**
   * Returns true if this entry's underlying module is active, and its contract
   * ID matches the given contract ID string. This is used by the PerfectHash
   * function to determine whether to return a result for this entry.
   */
  bool Matches(const nsACString& aContractID) const;

  /**
   * Returns true if this entry has been invalidated, and should be ignored.
   *
   * Contract IDs may be overwritten at runtime. When that happens for a static
   * contract ID, we mark its entry invalid, and ignore it thereafter.
   */
  bool Invalid() const { return GetBit(gInvalidContracts, Idx()); }

  /**
   * Marks this entry invalid (or unsets the invalid bit if aInvalid is false),
   * after which it will be ignored in contract ID lookup attempts. See
   * `Invalid()` above.
   */
  void SetInvalid(bool aInvalid = true) const {
    return SetBit(gInvalidContracts, Idx(), aInvalid);
  }
};

/**
 * Represents a declared category manager entry declared in an XPCOM manifest.
 *
 * The entire set of static category entries is read at startup and loaded into
 * the category manager's dynamic hash tables, so there is memory and
 * initialization overhead for each entry in these tables. This may be further
 * optimized in the future to reduce some of that overhead.
 */
struct StaticCategoryEntry final {
  StringOffset mEntry;
  StringOffset mValue;
  Module::BackgroundTasksSelector mBackgroundTasksSelector;
  Module::ProcessSelector mProcessSelector;

  nsCString Entry() const;
  nsCString Value() const;
  bool Active() const;
};

struct StaticCategory final {
  StringOffset mName;
  uint16_t mStart;
  uint16_t mCount;

  nsCString Name() const;

  const StaticCategoryEntry* begin() const {
    return &gStaticCategoryEntries[mStart];
  }
  const StaticCategoryEntry* end() const {
    return &gStaticCategoryEntries[mStart + mCount];
  }
};

struct JSServiceEntry final {
  using InterfaceList = AutoTArray<const nsIID*, 4>;

  static const JSServiceEntry* Lookup(const nsACString& aName);

  StringOffset mName;
  ModuleID mModuleID;

  InterfaceOffset mInterfaceOffset;

  uint8_t mInterfaceCount;

  nsCString Name() const;

  const StaticModule& Module() const {
    return gStaticModules[size_t(mModuleID)];
  }

  InterfaceList Interfaces() const;
};

struct StaticProtocolHandler final {
  static const StaticProtocolHandler* Lookup(const nsACString& aScheme);
  static const StaticProtocolHandler& Default() {
    return gStaticProtocolHandlers[kDefaultProtocolHandlerIndex];
  }

  StringOffset mScheme;
  uint32_t mProtocolFlags;
  int32_t mDefaultPort;
  ModuleID mModuleID;
  bool mHasDynamicFlags;

  nsCString Scheme() const;

  const StaticModule& Module() const {
    return gStaticModules[size_t(mModuleID)];
  }
};

class StaticComponents final {
 public:
  static const StaticModule* LookupByCID(const nsID& aCID);

  static const StaticModule* LookupByContractID(const nsACString& aContractID);

  /**
   * Marks a static contract ID entry invalid (or unsets the invalid bit if
   * aInvalid is false). See `CategoryEntry::Invalid()`.
   */
  static bool InvalidateContractID(const nsACString& aContractID,
                                   bool aInvalid = true);

  static already_AddRefed<nsIUTF8StringEnumerator> GetComponentJSMs();
  static already_AddRefed<nsIUTF8StringEnumerator> GetComponentESModules();

  static Span<const JSServiceEntry> GetJSServices();

  /**
   * Calls any module unload from manifests whose components have been loaded.
   */
  static void Shutdown();
};

}  // namespace xpcom
}  // namespace mozilla

#endif  // defined StaticComponents_h