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 #include "mozilla/PerfectHash.h"
11 #include "mozilla/ResultExtensions.h"
12 #include "mozilla/StaticPtr.h"
13 #include "mozilla/UniquePtr.h"
14 #include "mozilla/dom/ScriptSettings.h"
15 #include "mozJSComponentLoader.h"
17 #include "nsComponentManager.h"
18 #include "nsContentUtils.h"
19 #include "nsIFactory.h"
20 #include "nsISupports.h"
21 #include "nsIXPConnect.h"
23 #include "nsStringEnumerator.h"
27 // Cleanup pollution from zipstruct.h
34 //# @relative_includes@
44 static constexpr uint32_t kNoContractID
= 0xffffffff;
47 // Template helpers for constructor function sanity checks.
49 struct RemoveAlreadyAddRefed
{
54 struct RemoveAlreadyAddRefed
<already_AddRefed
<T
>> {
57 } // anonymous namespace
60 uint8_t gInvalidContracts
[kContractCount
/ 8 + 1];
62 static StaticRefPtr
<nsISupports
> gServiceInstances
[kStaticModuleCount
];
64 uint8_t gInitCalled
[kModuleInitCount
/ 8 + 1];
66 static const char gStrings
[] =
70 const StaticCategory gStaticCategories
[kStaticCategoryCount
] = {
73 const StaticCategoryEntry gStaticCategoryEntries
[] = {
74 //# @category_entries@
77 const nsXPTInterface gInterfaces
[] = {
81 const StringOffset gComponentJSMs
[] = {
86 * Returns a nsCString corresponding to the given entry in the `gStrings` string
87 * table. The resulting nsCString points directly to static storage, and does
88 * not incur any memory allocation overhead.
90 static inline nsCString
GetString(const StringOffset
& aOffset
) {
91 const char* str
= &gStrings
[aOffset
.mOffset
];
93 result
.AssignLiteral(str
, strlen(str
));
97 nsCString
ContractEntry::ContractID() const {
98 return GetString(mContractID
);
101 bool ContractEntry::Matches(const nsACString
& aContractID
) const {
102 return aContractID
== ContractID() && Module().Active();
106 static nsresult
ConstructJSMComponent(const nsACString
& aURI
,
107 const char* aConstructor
,
108 nsISupports
** aResult
) {
109 if (!nsComponentManagerImpl::JSLoaderReady()) {
110 return NS_ERROR_NOT_AVAILABLE
;
114 MOZ_ALWAYS_TRUE(jsapi
.Init(xpc::PrivilegedJunkScope()));
115 JSContext
* cx
= jsapi
.cx();
117 JS::RootedObject
global(cx
);
118 JS::RootedObject
exports(cx
);
119 MOZ_TRY(mozJSComponentLoader::Get()->Import(cx
, aURI
, &global
, &exports
));
121 JS::RootedValue
ctor(cx
);
122 if (!JS_GetProperty(cx
, exports
, aConstructor
, &ctor
) ||
124 return NS_ERROR_XPC_JSOBJECT_HAS_NO_FUNCTION_NAMED
;
127 JS::RootedObject
inst(cx
);
128 if (!JS::Construct(cx
, ctor
, JS::HandleValueArray::empty(), &inst
)) {
129 return NS_ERROR_FAILURE
;
132 return nsContentUtils::XPConnect()->WrapJS(cx
, inst
, NS_GET_IID(nsISupports
),
137 //# @module_cid_table@
139 //# @module_contract_id_table@
141 //# @js_services_table@
143 static inline bool CalledInit(size_t aIdx
) {
144 return GetBit(gInitCalled
, aIdx
);
147 static nsresult
CallInitFunc(size_t aIdx
) {
148 if (CalledInit(aIdx
)) {
157 SetBit(gInitCalled
, aIdx
);
159 MOZ_ASSERT(NS_SUCCEEDED(rv
));
163 static void CallUnloadFuncs() {
167 static nsresult
CreateInstanceImpl(ModuleID aID
, nsISupports
* aOuter
,
168 const nsIID
& aIID
, void** aResult
) {
170 return NS_ERROR_NO_AGGREGATION
;
173 // The full set of constructors for all static modules.
174 // This switch statement will be compiled to a relative address jump table
175 // with no runtime relocations and a single indirect jump.
180 MOZ_ASSERT_UNREACHABLE("Constructor didn't return");
181 return NS_ERROR_FAILURE
;
187 class StaticModuleFactory final
: public nsIFactory
{
191 explicit StaticModuleFactory(ModuleID aID
) : mID(aID
) {}
194 ~StaticModuleFactory() = default;
199 NS_IMPL_ISUPPORTS(StaticModuleFactory
, nsIFactory
)
201 NS_IMETHODIMP
StaticModuleFactory::CreateInstance(nsISupports
* aOuter
,
204 return CreateInstanceImpl(mID
, aOuter
, aIID
, aResult
);
207 NS_IMETHODIMP
StaticModuleFactory::LockFactory(bool aLock
) {
208 MOZ_CRASH("LockFactory is no longer a thing");
209 return NS_ERROR_NOT_IMPLEMENTED
;
212 } // anonymous namespace
215 already_AddRefed
<nsIFactory
> StaticModule::GetFactory() const {
216 return do_AddRef(new StaticModuleFactory(ID()));
219 bool StaticModule::Active() const {
220 return FastProcessSelectorMatches(mProcessSelector
);
223 bool StaticModule::Overridable() const {
224 return mContractID
.mOffset
!= kNoContractID
;
227 nsCString
StaticModule::ContractID() const {
228 MOZ_ASSERT(Overridable());
229 return GetString(mContractID
);
232 nsresult
StaticModule::CreateInstance(nsISupports
* aOuter
, const nsIID
& aIID
,
233 void** aResult
) const {
234 return CreateInstanceImpl(ID(), aOuter
, aIID
, aResult
);
237 GetServiceHelper
StaticModule::GetService() const {
238 return { ID(), nullptr };
241 GetServiceHelper
StaticModule::GetService(nsresult
* aRv
) const {
242 return { ID(), aRv
};
246 nsISupports
* StaticModule::ServiceInstance() const {
247 return gServiceInstances
[Idx()];
250 void StaticModule::SetServiceInstance(
251 already_AddRefed
<nsISupports
> aInst
) const {
252 gServiceInstances
[Idx()] = aInst
;
256 nsCString
StaticCategoryEntry::Entry() const {
257 return GetString(mEntry
);
259 nsCString
StaticCategoryEntry::Value() const {
260 return GetString(mValue
);
262 bool StaticCategoryEntry::Active() const {
263 return FastProcessSelectorMatches(mProcessSelector
);
266 nsCString
StaticCategory::Name() const {
267 return GetString(mName
);
270 nsCString
JSServiceEntry::Name() const {
271 return GetString(mName
);
274 JSServiceEntry::InterfaceList
JSServiceEntry::Interfaces() const {
276 iids
.SetCapacity(mInterfaceCount
);
278 for (size_t i
= 0; i
< mInterfaceCount
; i
++) {
279 nsXPTInterface ifaceID
= gInterfaces
[mInterfaceOffset
.mOffset
+ i
];
280 iids
.AppendElement(&nsXPTInterfaceInfo::Get(ifaceID
)->IID());
287 const JSServiceEntry
* JSServiceEntry::Lookup(const nsACString
& aName
) {
288 return LookupJSService(aName
);
291 /* static */ const StaticModule
* StaticComponents::LookupByCID(
293 return ModuleByCID(aCID
);
296 /* static */ const StaticModule
* StaticComponents::LookupByContractID(
297 const nsACString
& aContractID
) {
298 if (const ContractEntry
* entry
= LookupContractID(aContractID
)) {
299 if (!entry
->Invalid()) {
300 return &entry
->Module();
306 /* static */ bool StaticComponents::InvalidateContractID(
307 const nsACString
& aContractID
, bool aInvalid
) {
308 if (const ContractEntry
* entry
= LookupContractID(aContractID
)) {
309 entry
->SetInvalid(aInvalid
);
315 /* static */ already_AddRefed
<nsIUTF8StringEnumerator
>
316 StaticComponents::GetComponentJSMs() {
317 auto jsms
= MakeUnique
<nsTArray
<nsCString
>>(MOZ_ARRAY_LENGTH(gComponentJSMs
));
319 for (const auto& entry
: gComponentJSMs
) {
320 jsms
->AppendElement(GetString(entry
));
323 nsCOMPtr
<nsIUTF8StringEnumerator
> result
;
324 MOZ_ALWAYS_SUCCEEDS(NS_NewAdoptingUTF8StringEnumerator(getter_AddRefs(result
),
326 return result
.forget();
329 /* static */ Span
<const JSServiceEntry
> StaticComponents::GetJSServices() {
330 return { gJSServices
, ArrayLength(gJSServices
) };
333 /* static */ void StaticComponents::Shutdown() {
337 /* static */ const nsID
& Components::GetCID(ModuleID aID
) {
338 return gStaticModules
[size_t(aID
)].CID();
341 nsresult
GetServiceHelper::operator()(const nsIID
& aIID
, void** aResult
) const {
343 nsComponentManagerImpl::gComponentManager
->GetService(mId
, aIID
, aResult
);
344 return SetResult(rv
);
347 nsresult
CreateInstanceHelper::operator()(const nsIID
& aIID
,
348 void** aResult
) const {
349 const auto& entry
= gStaticModules
[size_t(mId
)];
350 if (!entry
.Active()) {
351 return SetResult(NS_ERROR_FACTORY_NOT_REGISTERED
);
354 nsresult rv
= entry
.CreateInstance(nullptr, aIID
, aResult
);
355 return SetResult(rv
);
359 } // namespace mozilla