diff options
Diffstat (limited to 'xpcom/components/StaticComponents.cpp.in')
-rw-r--r-- | xpcom/components/StaticComponents.cpp.in | 359 |
1 files changed, 359 insertions, 0 deletions
diff --git a/xpcom/components/StaticComponents.cpp.in b/xpcom/components/StaticComponents.cpp.in new file mode 100644 index 0000000000..c4b340b2ff --- /dev/null +++ b/xpcom/components/StaticComponents.cpp.in @@ -0,0 +1,359 @@ +/* -*- 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/. */ + +#include "StaticComponents.h" + +#include "mozilla/ArrayUtils.h" +#include "mozilla/PerfectHash.h" +#include "mozilla/ResultExtensions.h" +#include "mozilla/StaticPtr.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/dom/ScriptSettings.h" +#include "mozJSComponentLoader.h" +#include "nsCOMPtr.h" +#include "nsComponentManager.h" +#include "nsContentUtils.h" +#include "nsIFactory.h" +#include "nsISupports.h" +#include "nsIXPConnect.h" +#include "nsString.h" +#include "nsStringEnumerator.h" +#include "nsTArray.h" +#include "xptinfo.h" + +// Cleanup pollution from zipstruct.h +#undef UNSUPPORTED + +// Public includes +//# @includes@ + +// Relative includes +//# @relative_includes@ + +//# @decls@ + +namespace mozilla { + +using dom::AutoJSAPI; + +namespace xpcom { + +static constexpr uint32_t kNoContractID = 0xffffffff; + +namespace { +// Template helpers for constructor function sanity checks. +template <typename T> +struct RemoveAlreadyAddRefed { + using Type = T; +}; + +template <typename T> +struct RemoveAlreadyAddRefed<already_AddRefed<T>> { + using Type = T; +}; +} // anonymous namespace + + +uint8_t gInvalidContracts[kContractCount / 8 + 1]; + +static StaticRefPtr<nsISupports> gServiceInstances[kStaticModuleCount]; + +uint8_t gInitCalled[kModuleInitCount / 8 + 1]; + +static const char gStrings[] = +//# @strings@ + ""; + +const StaticCategory gStaticCategories[kStaticCategoryCount] = { +//# @categories@ +}; +const StaticCategoryEntry gStaticCategoryEntries[] = { +//# @category_entries@ +}; + +const nsXPTInterface gInterfaces[] = { +//# @interfaces@ +}; + +const StringOffset gComponentJSMs[] = { +//# @component_jsms@ +}; + +/** + * Returns a nsCString corresponding to the given entry in the `gStrings` string + * table. The resulting nsCString points directly to static storage, and does + * not incur any memory allocation overhead. + */ +static inline nsCString GetString(const StringOffset& aOffset) { + const char* str = &gStrings[aOffset.mOffset]; + nsCString result; + result.AssignLiteral(str, strlen(str)); + return result; +} + +nsCString ContractEntry::ContractID() const { + return GetString(mContractID); +} + +bool ContractEntry::Matches(const nsACString& aContractID) const { + return aContractID == ContractID() && Module().Active(); +} + + +static nsresult ConstructJSMComponent(const nsACString& aURI, + const char* aConstructor, + nsISupports** aResult) { + if (!nsComponentManagerImpl::JSLoaderReady()) { + return NS_ERROR_NOT_AVAILABLE; + } + + AutoJSAPI jsapi; + MOZ_ALWAYS_TRUE(jsapi.Init(xpc::PrivilegedJunkScope())); + JSContext* cx = jsapi.cx(); + + JS::RootedObject global(cx); + JS::RootedObject exports(cx); + MOZ_TRY(mozJSComponentLoader::Get()->Import(cx, aURI, &global, &exports)); + + JS::RootedValue ctor(cx); + if (!JS_GetProperty(cx, exports, aConstructor, &ctor) || + !ctor.isObject()) { + return NS_ERROR_XPC_JSOBJECT_HAS_NO_FUNCTION_NAMED; + } + + JS::RootedObject inst(cx); + if (!JS::Construct(cx, ctor, JS::HandleValueArray::empty(), &inst)) { + return NS_ERROR_FAILURE; + } + + return nsContentUtils::XPConnect()->WrapJS(cx, inst, NS_GET_IID(nsISupports), + (void**)aResult); +} + + +//# @module_cid_table@ + +//# @module_contract_id_table@ + +//# @js_services_table@ + +static inline bool CalledInit(size_t aIdx) { + return GetBit(gInitCalled, aIdx); +} + +static nsresult CallInitFunc(size_t aIdx) { + if (CalledInit(aIdx)) { + return NS_OK; + } + + nsresult rv = NS_OK; + switch (aIdx) { +//# @init_funcs@ + } + + SetBit(gInitCalled, aIdx); + + MOZ_ASSERT(NS_SUCCEEDED(rv)); + return rv; +} + +static void CallUnloadFuncs() { +//# @unload_funcs@ +} + +static nsresult CreateInstanceImpl(ModuleID aID, nsISupports* aOuter, + const nsIID& aIID, void** aResult) { + if (aOuter) { + return NS_ERROR_NO_AGGREGATION; + } + + // The full set of constructors for all static modules. + // This switch statement will be compiled to a relative address jump table + // with no runtime relocations and a single indirect jump. + switch (aID) { +//# @constructors@ + } + + MOZ_ASSERT_UNREACHABLE("Constructor didn't return"); + return NS_ERROR_FAILURE; +} + + +namespace { + +class StaticModuleFactory final : public nsIFactory { + NS_DECL_ISUPPORTS + NS_DECL_NSIFACTORY + + explicit StaticModuleFactory(ModuleID aID) : mID(aID) {} + +private: + ~StaticModuleFactory() = default; + + const ModuleID mID; +}; + +NS_IMPL_ISUPPORTS(StaticModuleFactory, nsIFactory) + +NS_IMETHODIMP StaticModuleFactory::CreateInstance(nsISupports* aOuter, + const nsIID& aIID, + void** aResult) { + return CreateInstanceImpl(mID, aOuter, aIID, aResult); +} + +NS_IMETHODIMP StaticModuleFactory::LockFactory(bool aLock) { + MOZ_CRASH("LockFactory is no longer a thing"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +} // anonymous namespace + + +already_AddRefed<nsIFactory> StaticModule::GetFactory() const { + return do_AddRef(new StaticModuleFactory(ID())); +} + +bool StaticModule::Active() const { + return FastProcessSelectorMatches(mProcessSelector); +} + +bool StaticModule::Overridable() const { + return mContractID.mOffset != kNoContractID; +} + +nsCString StaticModule::ContractID() const { + MOZ_ASSERT(Overridable()); + return GetString(mContractID); +} + +nsresult StaticModule::CreateInstance(nsISupports* aOuter, const nsIID& aIID, + void** aResult) const { + return CreateInstanceImpl(ID(), aOuter, aIID, aResult); +} + +GetServiceHelper StaticModule::GetService() const { + return { ID(), nullptr }; +} + +GetServiceHelper StaticModule::GetService(nsresult* aRv) const { + return { ID(), aRv }; +} + + +nsISupports* StaticModule::ServiceInstance() const { + return gServiceInstances[Idx()]; +} + +void StaticModule::SetServiceInstance( + already_AddRefed<nsISupports> aInst) const { + gServiceInstances[Idx()] = aInst; +} + + +nsCString StaticCategoryEntry::Entry() const { + return GetString(mEntry); +} +nsCString StaticCategoryEntry::Value() const { + return GetString(mValue); +} +bool StaticCategoryEntry::Active() const { + return FastProcessSelectorMatches(mProcessSelector); +} + +nsCString StaticCategory::Name() const { + return GetString(mName); +} + +nsCString JSServiceEntry::Name() const { + return GetString(mName); +} + +JSServiceEntry::InterfaceList JSServiceEntry::Interfaces() const { + InterfaceList iids; + iids.SetCapacity(mInterfaceCount); + + for (size_t i = 0; i < mInterfaceCount; i++) { + nsXPTInterface ifaceID = gInterfaces[mInterfaceOffset.mOffset + i]; + iids.AppendElement(&nsXPTInterfaceInfo::Get(ifaceID)->IID()); + } + return iids; +} + + +/* static */ +const JSServiceEntry* JSServiceEntry::Lookup(const nsACString& aName) { + return LookupJSService(aName); +} + +/* static */ const StaticModule* StaticComponents::LookupByCID( + const nsID& aCID) { + return ModuleByCID(aCID); +} + +/* static */ const StaticModule* StaticComponents::LookupByContractID( + const nsACString& aContractID) { + if (const ContractEntry* entry = LookupContractID(aContractID)) { + if (!entry->Invalid()) { + return &entry->Module(); + } + } + return nullptr; +} + +/* static */ bool StaticComponents::InvalidateContractID( + const nsACString& aContractID, bool aInvalid) { + if (const ContractEntry* entry = LookupContractID(aContractID)) { + entry->SetInvalid(aInvalid); + return true; + } + return false; +} + +/* static */ already_AddRefed<nsIUTF8StringEnumerator> +StaticComponents::GetComponentJSMs() { + auto jsms = MakeUnique<nsTArray<nsCString>>(MOZ_ARRAY_LENGTH(gComponentJSMs)); + + for (const auto& entry : gComponentJSMs) { + jsms->AppendElement(GetString(entry)); + } + + nsCOMPtr<nsIUTF8StringEnumerator> result; + MOZ_ALWAYS_SUCCEEDS(NS_NewAdoptingUTF8StringEnumerator(getter_AddRefs(result), + jsms.release())); + return result.forget(); +} + +/* static */ Span<const JSServiceEntry> StaticComponents::GetJSServices() { + return { gJSServices, ArrayLength(gJSServices) }; +} + +/* static */ void StaticComponents::Shutdown() { + CallUnloadFuncs(); +} + +/* static */ const nsID& Components::GetCID(ModuleID aID) { + return gStaticModules[size_t(aID)].CID(); +} + +nsresult GetServiceHelper::operator()(const nsIID& aIID, void** aResult) const { + nsresult rv = + nsComponentManagerImpl::gComponentManager->GetService(mId, aIID, aResult); + return SetResult(rv); +} + +nsresult CreateInstanceHelper::operator()(const nsIID& aIID, + void** aResult) const { + const auto& entry = gStaticModules[size_t(mId)]; + if (!entry.Active()) { + return SetResult(NS_ERROR_FACTORY_NOT_REGISTERED); + } + + nsresult rv = entry.CreateInstance(nullptr, aIID, aResult); + return SetResult(rv); +} + +} // namespace xpcom +} // namespace mozilla |