Source code
Revision control
Copy as Markdown
Other Tools
/* -*- 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
#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;
struct StaticProtocolHandler;
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[];
extern const StaticProtocolHandler
gStaticProtocolHandlers[kStaticProtocolHandlerCount];
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 {
uint16_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(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::BackgroundTasksSelector mBackgroundTasksSelector;
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;
};
struct StaticProtocolHandler final {
static const StaticProtocolHandler* Lookup(const nsACString& aScheme);
static const StaticProtocolHandler& Default() {
return gStaticProtocolHandlers[kDefaultProtocolHandlerIndex];
}
StringOffset mScheme;
uint32_t mProtocolFlags;
int32_t mDefaultPort;
ModuleID mModuleID;
bool mHasDynamicFlags;
nsCString Scheme() const;
const StaticModule& Module() const {
return gStaticModules[size_t(mModuleID)];
}
};
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 already_AddRefed<nsIUTF8StringEnumerator> GetComponentESModules();
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