Bug 1910362 - Create new Nimbus helper r=aaronmt,ohorvath
[gecko.git] / xpcom / components / StaticComponents.cpp.in
blob6f3db11e38a4b6e0ca5c66b1c06aff22e6f42597
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/. */
7 #include "StaticComponents.h"
9 #include "mozilla/ArrayUtils.h"
10 #ifdef MOZ_BACKGROUNDTASKS
11 # include "mozilla/BackgroundTasks.h"
12 #endif
13 #include "mozilla/PerfectHash.h"
14 #include "mozilla/ResultExtensions.h"
15 #include "mozilla/StaticPtr.h"
16 #include "mozilla/UniquePtr.h"
17 #include "mozilla/dom/ScriptSettings.h"
18 #include "mozJSModuleLoader.h"
19 #include "nsCOMPtr.h"
20 #include "nsComponentManager.h"
21 #include "nsContentUtils.h"
22 #include "nsIFactory.h"
23 #include "nsISupports.h"
24 #include "nsIXPConnect.h"
25 #include "nsString.h"
26 #include "nsStringEnumerator.h"
27 #include "nsTArray.h"
28 #include "xptdata.h"
29 #include "xptinfo.h"
30 #include "js/PropertyAndElement.h" // JS_GetProperty
32 // Cleanup pollution from zipstruct.h
33 #undef UNSUPPORTED
35 // Public includes
36 //# @includes@
38 // Relative includes
39 //# @relative_includes@
41 //# @decls@
43 namespace mozilla {
45 using dom::AutoJSAPI;
47 namespace xpcom {
49 static constexpr uint32_t kNoContractID = 0xffffffff;
51 namespace {
52 // Template helpers for constructor function sanity checks.
53 template <typename T>
54 struct RemoveAlreadyAddRefed {
55 using Type = T;
58 template <typename T>
59 struct RemoveAlreadyAddRefed<already_AddRefed<T>> {
60 using Type = T;
62 } // anonymous namespace
65 uint8_t gInvalidContracts[kContractCount / 8 + 1];
67 static StaticRefPtr<nsISupports> gServiceInstances[kStaticModuleCount];
69 uint8_t gInitCalled[kModuleInitCount / 8 + 1];
71 static const char gStrings[] =
72 //# @strings@
73 "";
75 const StaticCategory gStaticCategories[kStaticCategoryCount] = {
76 //# @categories@
78 const StaticCategoryEntry gStaticCategoryEntries[] = {
79 //# @category_entries@
82 const nsXPTInterface gInterfaces[] = {
83 //# @interfaces@
86 //# @define_has_component_jsms@
88 #ifdef HAS_COMPONENT_JSMS
89 // TODO: Remove this once m-c and c-c migrations finish (bug 1881887).
90 const StringOffset gComponentJSMs[] = {
91 //# @component_jsms@
93 #endif
95 const StringOffset gComponentESModules[] = {
96 //# @component_esmodules@
99 /**
100 * Returns a nsCString corresponding to the given entry in the `gStrings` string
101 * table. The resulting nsCString points directly to static storage, and does
102 * not incur any memory allocation overhead.
104 static inline nsCString GetString(const StringOffset& aOffset) {
105 const char* str = &gStrings[aOffset.mOffset];
106 nsCString result;
107 result.AssignLiteral(str, strlen(str));
108 return result;
111 nsCString ContractEntry::ContractID() const {
112 return GetString(mContractID);
115 bool ContractEntry::Matches(const nsACString& aContractID) const {
116 return aContractID == ContractID() && Module().Active();
119 enum class ComponentType { JSM, ESM };
121 template <ComponentType type>
122 static nsresult ConstructJSMOrESMComponent(const nsACString& aURI,
123 const char* aConstructor,
124 nsISupports** aResult) {
125 if (!nsComponentManagerImpl::JSLoaderReady()) {
126 return NS_ERROR_NOT_AVAILABLE;
129 AutoJSAPI jsapi;
130 MOZ_ALWAYS_TRUE(jsapi.Init(xpc::PrivilegedJunkScope()));
131 JSContext* cx = jsapi.cx();
133 JS::Rooted<JSObject*> exports(cx);
134 if constexpr (type == ComponentType::JSM) {
135 JS::Rooted<JSObject*> global(cx);
136 MOZ_TRY(mozJSModuleLoader::Get()->Import(cx, aURI, &global, &exports));
137 } else {
138 MOZ_TRY(mozJSModuleLoader::Get()->ImportESModule(cx, aURI, &exports));
141 JS::Rooted<JS::Value> ctor(cx);
142 if (!JS_GetProperty(cx, exports, aConstructor, &ctor) ||
143 !ctor.isObject()) {
144 return NS_ERROR_XPC_JSOBJECT_HAS_NO_FUNCTION_NAMED;
147 JS::Rooted<JSObject*> inst(cx);
148 if (!JS::Construct(cx, ctor, JS::HandleValueArray::empty(), &inst)) {
149 return NS_ERROR_FAILURE;
152 return nsContentUtils::XPConnect()->WrapJS(cx, inst, NS_GET_IID(nsISupports),
153 (void**)aResult);
156 [[maybe_unused]] static nsresult ConstructJSMComponent(const nsACString& aURI,
157 const char* aConstructor,
158 nsISupports** aResult) {
159 return ConstructJSMOrESMComponent<ComponentType::JSM>(
160 aURI, aConstructor, aResult);
163 static nsresult ConstructESModuleComponent(const nsACString& aURI,
164 const char* aConstructor,
165 nsISupports** aResult) {
166 return ConstructJSMOrESMComponent<ComponentType::ESM>(
167 aURI, aConstructor, aResult);
170 //# @module_cid_table@
172 //# @module_contract_id_table@
174 //# @js_services_table@
176 //# @protocol_handlers_table@
178 static inline bool CalledInit(size_t aIdx) {
179 return GetBit(gInitCalled, aIdx);
182 static nsresult CallInitFunc(size_t aIdx) {
183 if (CalledInit(aIdx)) {
184 return NS_OK;
187 nsresult rv = NS_OK;
188 switch (aIdx) {
189 //# @init_funcs@
192 SetBit(gInitCalled, aIdx);
194 MOZ_ASSERT(NS_SUCCEEDED(rv));
195 return rv;
198 static void CallUnloadFuncs() {
199 //# @unload_funcs@
202 nsresult CreateInstanceImpl(ModuleID aID, const nsIID& aIID, void** aResult) {
203 // The full set of constructors for all static modules.
204 // This switch statement will be compiled to a relative address jump table
205 // with no runtime relocations and a single indirect jump.
206 switch (aID) {
207 //# @constructors@
210 MOZ_ASSERT_UNREACHABLE("Constructor didn't return");
211 return NS_ERROR_FAILURE;
215 namespace {
217 class StaticModuleFactory final : public nsIFactory {
218 NS_DECL_ISUPPORTS
219 NS_DECL_NSIFACTORY
221 explicit StaticModuleFactory(ModuleID aID) : mID(aID) {}
223 private:
224 ~StaticModuleFactory() = default;
226 const ModuleID mID;
229 NS_IMPL_ISUPPORTS(StaticModuleFactory, nsIFactory)
231 NS_IMETHODIMP StaticModuleFactory::CreateInstance(const nsIID& aIID,
232 void** aResult) {
233 return CreateInstanceImpl(mID, aIID, aResult);
236 } // anonymous namespace
239 already_AddRefed<nsIFactory> StaticModule::GetFactory() const {
240 return do_AddRef(new StaticModuleFactory(ID()));
243 bool StaticModule::Active() const {
244 return FastProcessSelectorMatches(mProcessSelector);
247 bool StaticModule::Overridable() const {
248 return mContractID.mOffset != kNoContractID;
251 nsCString StaticModule::ContractID() const {
252 MOZ_ASSERT(Overridable());
253 return GetString(mContractID);
256 nsresult StaticModule::CreateInstance(const nsIID& aIID, void** aResult) const {
257 return CreateInstanceImpl(ID(), aIID, aResult);
260 GetServiceHelper StaticModule::GetService() const {
261 return { ID(), nullptr };
264 GetServiceHelper StaticModule::GetService(nsresult* aRv) const {
265 return { ID(), aRv };
269 nsISupports* StaticModule::ServiceInstance() const {
270 return gServiceInstances[Idx()];
273 void StaticModule::SetServiceInstance(
274 already_AddRefed<nsISupports> aInst) const {
275 gServiceInstances[Idx()] = aInst;
279 nsCString StaticCategoryEntry::Entry() const {
280 return GetString(mEntry);
283 nsCString StaticCategoryEntry::Value() const {
284 return GetString(mValue);
287 bool StaticCategoryEntry::Active() const {
288 if (!FastProcessSelectorMatches(mProcessSelector)) {
289 return false;
291 #ifdef MOZ_BACKGROUNDTASKS
292 if (MOZ_UNLIKELY(BackgroundTasks::IsBackgroundTaskMode())) {
293 return mBackgroundTasksSelector != Module::BackgroundTasksSelector::NO_TASKS;
295 #endif /* MOZ_BACKGROUNDTASKS */
296 return true;
299 nsCString StaticCategory::Name() const {
300 return GetString(mName);
303 nsCString JSServiceEntry::Name() const {
304 return GetString(mName);
307 JSServiceEntry::InterfaceList JSServiceEntry::Interfaces() const {
308 InterfaceList iids;
309 iids.SetCapacity(mInterfaceCount);
311 for (size_t i = 0; i < mInterfaceCount; i++) {
312 nsXPTInterface ifaceID = gInterfaces[mInterfaceOffset.mOffset + i];
313 iids.AppendElement(&nsXPTInterfaceInfo::Get(ifaceID)->IID());
315 return iids;
319 /* static */
320 const JSServiceEntry* JSServiceEntry::Lookup(const nsACString& aName) {
321 return LookupJSService(aName);
324 nsCString StaticProtocolHandler::Scheme() const {
325 return GetString(mScheme);
328 /* static */
329 const StaticProtocolHandler* StaticProtocolHandler::Lookup(const nsACString& aScheme) {
330 return LookupProtocolHandler(aScheme);
333 /* static */ const StaticModule* StaticComponents::LookupByCID(
334 const nsID& aCID) {
335 return ModuleByCID(aCID);
338 /* static */ const StaticModule* StaticComponents::LookupByContractID(
339 const nsACString& aContractID) {
340 if (const ContractEntry* entry = LookupContractID(aContractID)) {
341 if (!entry->Invalid()) {
342 return &entry->Module();
345 return nullptr;
348 /* static */ bool StaticComponents::InvalidateContractID(
349 const nsACString& aContractID, bool aInvalid) {
350 if (const ContractEntry* entry = LookupContractID(aContractID)) {
351 entry->SetInvalid(aInvalid);
352 return true;
354 return false;
357 /* static */ already_AddRefed<nsIUTF8StringEnumerator>
358 StaticComponents::GetComponentJSMs() {
359 #ifdef HAS_COMPONENT_JSMS
360 auto jsms = MakeUnique<nsTArray<nsCString>>(std::size(gComponentJSMs));
362 for (const auto& entry : gComponentJSMs) {
363 jsms->AppendElement(GetString(entry));
365 #else
366 auto jsms = MakeUnique<nsTArray<nsCString>>(0);
367 #endif
369 nsCOMPtr<nsIUTF8StringEnumerator> result;
370 MOZ_ALWAYS_SUCCEEDS(NS_NewAdoptingUTF8StringEnumerator(getter_AddRefs(result),
371 jsms.release()));
372 return result.forget();
375 /* static */ already_AddRefed<nsIUTF8StringEnumerator>
376 StaticComponents::GetComponentESModules() {
377 auto esModules = MakeUnique<nsTArray<nsCString>>(std::size(gComponentESModules));
379 for (const auto& entry : gComponentESModules) {
380 esModules->AppendElement(GetString(entry));
383 nsCOMPtr<nsIUTF8StringEnumerator> result;
384 MOZ_ALWAYS_SUCCEEDS(NS_NewAdoptingUTF8StringEnumerator(getter_AddRefs(result),
385 esModules.release()));
386 return result.forget();
389 /* static */ Span<const JSServiceEntry> StaticComponents::GetJSServices() {
390 return { gJSServices, std::size(gJSServices) };
393 /* static */ void StaticComponents::Shutdown() {
394 CallUnloadFuncs();
397 /* static */ const nsID& Components::GetCID(ModuleID aID) {
398 return gStaticModules[size_t(aID)].CID();
401 nsresult GetServiceHelper::operator()(const nsIID& aIID, void** aResult) const {
402 nsresult rv =
403 nsComponentManagerImpl::gComponentManager->GetService(mId, aIID, aResult);
404 return SetResult(rv);
407 nsresult CreateInstanceHelper::operator()(const nsIID& aIID,
408 void** aResult) const {
409 const auto& entry = gStaticModules[size_t(mId)];
410 if (!entry.Active()) {
411 return SetResult(NS_ERROR_FACTORY_NOT_REGISTERED);
414 nsresult rv = entry.CreateInstance(aIID, aResult);
415 return SetResult(rv);
418 } // namespace xpcom
419 } // namespace mozilla