diff options
Diffstat (limited to 'xpcom/components/StaticComponents.h')
-rw-r--r-- | xpcom/components/StaticComponents.h | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/xpcom/components/StaticComponents.h b/xpcom/components/StaticComponents.h new file mode 100644 index 0000000000..cf853f3656 --- /dev/null +++ b/xpcom/components/StaticComponents.h @@ -0,0 +1,258 @@ +/* -*- 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; + +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[]; + +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 { + uint32_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(nsISupports* aOuter, 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::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; +}; + +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 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 |