DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (e5ef045527c6)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
/* -*- 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 "nsID.h"
#include "nsStringFwd.h"
#include "nscore.h"

#include "mozilla/Components.h"
#include "StaticComponentData.h"

class nsIFactory;
class nsIUTF8StringEnumerator;
class nsISupports;

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 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;

  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];
  }
};

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();

  /**
   * Calls any module unload from manifests whose components have been loaded.
   */
  static void Shutdown();
};

}  // namespace xpcom
}  // namespace mozilla

#endif  // defined StaticComponents_h