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"
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"
20 #include "nsComponentManager.h"
21 #include "nsContentUtils.h"
22 #include "nsIFactory.h"
23 #include "nsISupports.h"
24 #include "nsIXPConnect.h"
26 #include "nsStringEnumerator.h"
30 #include "js/PropertyAndElement.h" // JS_GetProperty
32 // Cleanup pollution from zipstruct.h
39 //# @relative_includes@
49 static constexpr uint32_t kNoContractID
= 0xffffffff;
52 // Template helpers for constructor function sanity checks.
54 struct RemoveAlreadyAddRefed
{
59 struct RemoveAlreadyAddRefed
<already_AddRefed
<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
[] =
75 const StaticCategory gStaticCategories
[kStaticCategoryCount
] = {
78 const StaticCategoryEntry gStaticCategoryEntries
[] = {
79 //# @category_entries@
82 const nsXPTInterface gInterfaces
[] = {
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
[] = {
95 const StringOffset gComponentESModules
[] = {
96 //# @component_esmodules@
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
];
107 result
.AssignLiteral(str
, strlen(str
));
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
;
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
));
138 MOZ_TRY(mozJSModuleLoader::Get()->ImportESModule(cx
, aURI
, &exports
));
141 JS::Rooted
<JS::Value
> ctor(cx
);
142 if (!JS_GetProperty(cx
, exports
, aConstructor
, &ctor
) ||
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
),
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
)) {
192 SetBit(gInitCalled
, aIdx
);
194 MOZ_ASSERT(NS_SUCCEEDED(rv
));
198 static void CallUnloadFuncs() {
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.
210 MOZ_ASSERT_UNREACHABLE("Constructor didn't return");
211 return NS_ERROR_FAILURE
;
217 class StaticModuleFactory final
: public nsIFactory
{
221 explicit StaticModuleFactory(ModuleID aID
) : mID(aID
) {}
224 ~StaticModuleFactory() = default;
229 NS_IMPL_ISUPPORTS(StaticModuleFactory
, nsIFactory
)
231 NS_IMETHODIMP
StaticModuleFactory::CreateInstance(const nsIID
& aIID
,
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
)) {
291 #ifdef MOZ_BACKGROUNDTASKS
292 if (MOZ_UNLIKELY(BackgroundTasks::IsBackgroundTaskMode())) {
293 return mBackgroundTasksSelector
!= Module::BackgroundTasksSelector::NO_TASKS
;
295 #endif /* MOZ_BACKGROUNDTASKS */
299 nsCString
StaticCategory::Name() const {
300 return GetString(mName
);
303 nsCString
JSServiceEntry::Name() const {
304 return GetString(mName
);
307 JSServiceEntry::InterfaceList
JSServiceEntry::Interfaces() const {
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());
320 const JSServiceEntry
* JSServiceEntry::Lookup(const nsACString
& aName
) {
321 return LookupJSService(aName
);
324 nsCString
StaticProtocolHandler::Scheme() const {
325 return GetString(mScheme
);
329 const StaticProtocolHandler
* StaticProtocolHandler::Lookup(const nsACString
& aScheme
) {
330 return LookupProtocolHandler(aScheme
);
333 /* static */ const StaticModule
* StaticComponents::LookupByCID(
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();
348 /* static */ bool StaticComponents::InvalidateContractID(
349 const nsACString
& aContractID
, bool aInvalid
) {
350 if (const ContractEntry
* entry
= LookupContractID(aContractID
)) {
351 entry
->SetInvalid(aInvalid
);
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
));
366 auto jsms
= MakeUnique
<nsTArray
<nsCString
>>(0);
369 nsCOMPtr
<nsIUTF8StringEnumerator
> result
;
370 MOZ_ALWAYS_SUCCEEDS(NS_NewAdoptingUTF8StringEnumerator(getter_AddRefs(result
),
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() {
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 {
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
);
419 } // namespace mozilla