tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SharedPrefMap.h (37666B)


      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/. */
      6 
      7 #ifndef dom_ipc_SharedPrefMap_h
      8 #define dom_ipc_SharedPrefMap_h
      9 
     10 #include "mozilla/Preferences.h"
     11 #include "mozilla/Result.h"
     12 #include "mozilla/dom/ipc/StringTable.h"
     13 #include "mozilla/ipc/SharedMemoryHandle.h"
     14 #include "mozilla/ipc/SharedMemoryMapping.h"
     15 #include "nsTHashMap.h"
     16 
     17 namespace mozilla {
     18 
     19 // The approximate number of preferences expected to be in an ordinary
     20 // preferences database.
     21 //
     22 // This number is used to determine initial allocation sizes for data structures
     23 // when building the shared preference map, and should be slightly higher than
     24 // the expected number of preferences in an ordinary database to avoid
     25 // unnecessary reallocations/rehashes.
     26 constexpr size_t kExpectedPrefCount = 4000;
     27 
     28 class SharedPrefMapBuilder;
     29 
     30 // This class provides access to a compact, read-only copy of a preference
     31 // database, backed by a shared memory buffer which can be shared between
     32 // processes. All state data for the database is stored in the shared memory
     33 // region, so individual instances require no dynamic memory allocation.
     34 //
     35 // Further, all strings returned from this API are nsLiteralCStrings with
     36 // pointers into the shared memory region, which means that they can be copied
     37 // into new nsCString instances without additional allocations. For instance,
     38 // the following (where `pref` is a Pref object) will not cause any string
     39 // copies, memory allocations, or atomic refcount changes:
     40 //
     41 //   nsCString prefName(pref.NameString());
     42 //
     43 // whereas if we returned a nsDependentCString or a dynamically allocated
     44 // nsCString, it would.
     45 //
     46 // The set of entries is stored in sorted order by preference name, so look-ups
     47 // are done by binary search. This means that look-ups have O(log n) complexity,
     48 // rather than the O(1) complexity of a dynamic hashtable. Consumers should keep
     49 // this in mind when planning their accesses.
     50 //
     51 // Important: The mapped memory created by this class is persistent. Once an
     52 // instance has been initialized, the memory that it allocates can never be
     53 // freed before process shutdown. Do not use it for short-lived mappings.
     54 class SharedPrefMap {
     55  friend class SharedPrefMapBuilder;
     56 
     57  // Describes a block of memory within the shared memory region.
     58  struct DataBlock {
     59    // The byte offset from the start of the shared memory region to the start
     60    // of the block.
     61    size_t mOffset;
     62    // The size of the block, in bytes. This is typically used only for bounds
     63    // checking in debug builds.
     64    size_t mSize;
     65  };
     66 
     67  // Describes the contents of the shared memory region, which is laid-out as
     68  // follows:
     69  //
     70  // - The Header struct
     71  //
     72  // - An array of Entry structs with mEntryCount elements, lexicographically
     73  //   sorted by preference name.
     74  //
     75  // - A set of data blocks, with offsets and sizes described by the DataBlock
     76  //   entries in the header, described below.
     77  //
     78  // Each entry stores its name string and values as indices into these blocks,
     79  // as documented in the Entry struct, but with some important optimizations:
     80  //
     81  // - Boolean values are always stored inline. Both the default and user
     82  //   values can be retrieved directly from the entry. Other types have only
     83  //   one value index, and their values appear at the same indices in the
     84  //   default and user value arrays.
     85  //
     86  //   Aside from reducing our memory footprint, this space-efficiency means
     87  //   that we can fit more entries in the CPU cache at once, and reduces the
     88  //   number of likely cache misses during lookups.
     89  //
     90  // - Key strings are stored in a separate string table from value strings. As
     91  //   above, this makes it more likely that the strings we need will be
     92  //   available in the CPU cache during lookups by not interleaving them with
     93  //   extraneous data.
     94  //
     95  // - Default and user values are stored in separate arrays. Entries with user
     96  //   values always appear before entries with default values in the value
     97  //   arrays, and entries without user values do not have entries in the user
     98  //   array at all. Since the same index is used for both arrays, this means
     99  //   that entries with a default value but no user value do not allocate any
    100  //   space to store their user value.
    101  //
    102  // - For preferences with no user value, the entries in the default value are
    103  //   de-duplicated. All preferences with the same default value (and no user
    104  //   value) point to the same index in the default value array.
    105  //
    106  //
    107  // For example, a preference database containing:
    108  //
    109  // +---------+-------------------------------+-------------------------------+
    110  // | Name    | Default Value | User Value    |                               |
    111  // +---------+---------------+---------------+-------------------------------+
    112  // | string1 | "meh"         | "hem"         |                               |
    113  // | string2 |               | "b"           |                               |
    114  // | string3 | "a"           |               |                               |
    115  // | string4 | "foo"         |               |                               |
    116  // | string5 | "foo"         |               |                               |
    117  // | string6 | "meh"         |               |                               |
    118  // +---------+---------------+---------------+-------------------------------+
    119  // | bool1   | false         | true          |                               |
    120  // | bool2   |               | false         |                               |
    121  // | bool3   | true          |               |                               |
    122  // +---------+---------------+---------------+-------------------------------+
    123  // | int1    | 18            | 16            |                               |
    124  // | int2    |               | 24            |                               |
    125  // | int3    | 42            |               |                               |
    126  // | int4    | 12            |               |                               |
    127  // | int5    | 12            |               |                               |
    128  // | int6    | 18            |               |                               |
    129  // +---------+---------------+---------------+-------------------------------+
    130  //
    131  // Results in a database that looks like:
    132  //
    133  // +-------------------------------------------------------------------------+
    134  // | Header:                                                                 |
    135  // +-------------------------------------------------------------------------+
    136  // |  mEntryCount = 15                                                       |
    137  // |  ...                                                                    |
    138  // +-------------------------------------------------------------------------+
    139  //
    140  // +-------------------------------------------------------------------------+
    141  // | Key strings:                                                            |
    142  // +--------+----------------------------------------------------------------+
    143  // | Offset | Value                                                          |
    144  // +--------+----------------------------------------------------------------+
    145  // |      0 | string1\0                                                      |
    146  // |      8 | string2\0                                                      |
    147  // |     16 | string3\0                                                      |
    148  // |     24 | string4\0                                                      |
    149  // |     32 | string5\0                                                      |
    150  // |     40 | string6\0                                                      |
    151  // |     48 | bool1\0                                                        |
    152  // |     54 | bool2\0                                                        |
    153  // |     60 | bool3\0                                                        |
    154  // |     66 | int1\0                                                         |
    155  // |     71 | int2\0                                                         |
    156  // |     76 | int3\0                                                         |
    157  // |     81 | int4\0                                                         |
    158  // |     86 | int6\0                                                         |
    159  // |     91 | int6\0                                                         |
    160  // +--------+----------------------------------------------------------------+
    161  //
    162  // +-------------------------------------------------------------------------+
    163  // | Entries:                                                                |
    164  // +---------------------+------+------------+------------+------------------+
    165  // | Key[1]              | Type | HasDefault | HasUser    | Value            |
    166  // +---------------------+------+------------+------------+------------------+
    167  // | K["bool1", 48, 5]   | 3    | true       | true       | { false, true }  |
    168  // | K["bool2", 54, 5]   | 3    | false      | true       | { 0,     false } |
    169  // | K["bool3", 60, 5]   | 3    | true       | false      | { true,  0    }  |
    170  // | K["int1", 66, 4]    | 2    | true       | true       | 0                |
    171  // | K["int2", 71, 4]    | 2    | false      | true       | 1                |
    172  // | K["int3", 76, 4]    | 2    | true       | false      | 2                |
    173  // | K["int4", 81, 4]    | 2    | true       | false      | 3                |
    174  // | K["int5", 86, 4]    | 2    | true       | false      | 3                |
    175  // | K["int6", 91, 4]    | 2    | true       | false      | 4                |
    176  // | K["string1",  0, 6] | 1    | true       | true       | 0                |
    177  // | K["string2",  8, 6] | 1    | false      | true       | 1                |
    178  // | K["string3", 16, 6] | 1    | true       | false      | 2                |
    179  // | K["string4", 24, 6] | 1    | true       | false      | 3                |
    180  // | K["string5", 32, 6] | 1    | true       | false      | 3                |
    181  // | K["string6", 40, 6] | 1    | true       | false      | 4                |
    182  // +---------------------+------+------------+------------+------------------+
    183  // | [1]: Encoded as an offset into the key table and a length. Specified    |
    184  // |      as K[string, offset, length] for clarity.                          |
    185  // +-------------------------------------------------------------------------+
    186  //
    187  // +------------------------------------+------------------------------------+
    188  // | User integer values                | Default integer values             |
    189  // +-------+----------------------------+-------+----------------------------+
    190  // | Index | Contents                   | Index | Contents                   |
    191  // +-------+----------------------------+-------+----------------------------+
    192  // |     0 | 16                         |     0 | 18                         |
    193  // |     1 | 24                         |     1 |                            |
    194  // |       |                            |     2 | 42                         |
    195  // |       |                            |     3 | 12                         |
    196  // |       |                            |     4 | 18                         |
    197  // +-------+----------------------------+-------+----------------------------+
    198  // | * Note: Tables are laid out sequentially in memory, but displayed       |
    199  // |         here side-by-side for clarity.                                  |
    200  // +-------------------------------------------------------------------------+
    201  //
    202  // +------------------------------------+------------------------------------+
    203  // | User string values                 | Default string values              |
    204  // +-------+----------------------------+-------+----------------------------+
    205  // | Index | Contents[1]                | Index | Contents[1]                |
    206  // +-------+----------------------------+-------+----------------------------+
    207  // |     0 | V["hem", 0, 3]             |     0 | V["meh", 4, 3]             |
    208  // |     1 | V["b", 8, 1]               |     1 |                            |
    209  // |       |                            |     2 | V["a", 10, 1]              |
    210  // |       |                            |     3 | V["foo", 12, 3]            |
    211  // |       |                            |     4 | V["meh", 4, 3]             |
    212  // |-------+----------------------------+-------+----------------------------+
    213  // | [1]: Encoded as an offset into the value table and a length. Specified  |
    214  // |      as V[string, offset, length] for clarity.                          |
    215  // +-------------------------------------------------------------------------+
    216  // | * Note: Tables are laid out sequentially in memory, but displayed       |
    217  // |         here side-by-side for clarity.                                  |
    218  // +-------------------------------------------------------------------------+
    219  //
    220  // +-------------------------------------------------------------------------+
    221  // | Value strings:                                                          |
    222  // +--------+----------------------------------------------------------------+
    223  // | Offset | Value                                                          |
    224  // +--------+----------------------------------------------------------------+
    225  // |      0 | hem\0                                                          |
    226  // |      4 | meh\0                                                          |
    227  // |      8 | b\0                                                            |
    228  // |     10 | a\0                                                            |
    229  // |     12 | foo\0                                                          |
    230  // +--------+----------------------------------------------------------------+
    231  struct Header {
    232    // The number of entries in this map.
    233    uint32_t mEntryCount;
    234 
    235    // The StringTable data block for preference name strings, which act as keys
    236    // in the map.
    237    DataBlock mKeyStrings;
    238 
    239    // The int32_t arrays of user and default int preference values. Entries in
    240    // the map store their values as indices into these arrays.
    241    DataBlock mUserIntValues;
    242    DataBlock mDefaultIntValues;
    243 
    244    // The StringTableEntry arrays of user and default string preference values.
    245    //
    246    // Strings are stored as StringTableEntry structs with character offsets
    247    // into the mValueStrings string table and their corresponding lengths.
    248    //
    249    // Entries in the map, likewise, store their string values as indices into
    250    // these arrays.
    251    DataBlock mUserStringValues;
    252    DataBlock mDefaultStringValues;
    253 
    254    // The StringTable data block for string preference values, referenced by
    255    // the above two data blocks.
    256    DataBlock mValueStrings;
    257  };
    258 
    259  using StringTableEntry = mozilla::dom::ipc::StringTableEntry;
    260 
    261  // Represents a preference value, as either a pair of boolean values, or an
    262  // index into one of the above value arrays.
    263  union Value {
    264    Value(bool aDefaultValue, bool aUserValue)
    265        : mDefaultBool(aDefaultValue), mUserBool(aUserValue) {}
    266 
    267    MOZ_IMPLICIT Value(uint16_t aIndex) : mIndex(aIndex) {}
    268 
    269    // The index of this entry in the value arrays.
    270    //
    271    // User and default preference values have the same indices in their
    272    // respective arrays. However, entries without a user value are not
    273    // guaranteed to have space allocated for them in the user value array, and
    274    // likewise for preferences without default values in the default value
    275    // array. This means that callers must only access value entries for entries
    276    // which claim to have a value of that type.
    277    uint16_t mIndex;
    278    struct {
    279      bool mDefaultBool;
    280      bool mUserBool;
    281    };
    282  };
    283 
    284  // Represents a preference entry in the map, containing its name, type info,
    285  // flags, and a reference to its value.
    286  struct Entry {
    287    // A pointer to the preference name in the KeyTable string table.
    288    StringTableEntry mKey;
    289 
    290    // The preference's value, either as a pair of booleans, or an index into
    291    // the value arrays. Please see the documentation for the Value struct
    292    // above.
    293    Value mValue;
    294 
    295    // The preference's type, as a PrefType enum value. This must *never* be
    296    // PrefType::None for values in a shared array.
    297    uint8_t mType : 2;
    298    // True if the preference has a default value. Callers must not attempt to
    299    // access the entry's default value if this is false.
    300    uint8_t mHasDefaultValue : 1;
    301    // True if the preference has a user value. Callers must not attempt to
    302    // access the entry's user value if this is false.
    303    uint8_t mHasUserValue : 1;
    304    // True if the preference is sticky, as defined by the preference service.
    305    uint8_t mIsSticky : 1;
    306    // True if the preference is locked, as defined by the preference service.
    307    uint8_t mIsLocked : 1;
    308    // True if the preference is sanitized, as defined by the preference
    309    // service.
    310    uint8_t mIsSanitized : 1;
    311    // True if the preference should be skipped while iterating over the
    312    // SharedPrefMap. This is used to internally store Once StaticPrefs.
    313    // This property is not visible to users the way sticky and locked are.
    314    uint8_t mIsSkippedByIteration : 1;
    315  };
    316 
    317 public:
    318  NS_INLINE_DECL_REFCOUNTING(SharedPrefMap)
    319 
    320  // A temporary wrapper class for accessing entries in the array. Instances of
    321  // this class are valid as long as SharedPrefMap instance is alive, but
    322  // generally should not be stored long term, or allocated on the heap.
    323  //
    324  // The class is implemented as two pointers, one to the SharedPrefMap
    325  // instance, and one to the Entry that corresponds to the preference, and is
    326  // meant to be cheaply returned by value from preference lookups and
    327  // iterators. All property accessors lazily fetch the appropriate values from
    328  // the shared memory region.
    329  class MOZ_STACK_CLASS Pref final {
    330   public:
    331    const char* Name() const { return mMap->KeyTable().GetBare(mEntry->mKey); }
    332 
    333    nsCString NameString() const { return mMap->KeyTable().Get(mEntry->mKey); }
    334 
    335    PrefType Type() const {
    336      MOZ_ASSERT(PrefType(mEntry->mType) != PrefType::None);
    337      return PrefType(mEntry->mType);
    338    }
    339 
    340    bool HasDefaultValue() const { return mEntry->mHasDefaultValue; }
    341    bool HasUserValue() const { return mEntry->mHasUserValue; }
    342    bool IsLocked() const { return mEntry->mIsLocked; }
    343    bool IsSanitized() const { return mEntry->mIsSanitized; }
    344    bool IsSticky() const { return mEntry->mIsSticky; }
    345    bool IsSkippedByIteration() const { return mEntry->mIsSkippedByIteration; }
    346 
    347    bool GetBoolValue(PrefValueKind aKind = PrefValueKind::User) const {
    348      MOZ_ASSERT(Type() == PrefType::Bool);
    349      MOZ_ASSERT(aKind == PrefValueKind::Default ? HasDefaultValue()
    350                                                 : HasUserValue());
    351 
    352      return aKind == PrefValueKind::Default ? mEntry->mValue.mDefaultBool
    353                                             : mEntry->mValue.mUserBool;
    354    }
    355 
    356    int32_t GetIntValue(PrefValueKind aKind = PrefValueKind::User) const {
    357      MOZ_ASSERT(Type() == PrefType::Int);
    358      MOZ_ASSERT(aKind == PrefValueKind::Default ? HasDefaultValue()
    359                                                 : HasUserValue());
    360 
    361      return aKind == PrefValueKind::Default
    362                 ? mMap->DefaultIntValues()[mEntry->mValue.mIndex]
    363                 : mMap->UserIntValues()[mEntry->mValue.mIndex];
    364    }
    365 
    366   private:
    367    const StringTableEntry& GetStringEntry(PrefValueKind aKind) const {
    368      MOZ_ASSERT(Type() == PrefType::String);
    369      MOZ_ASSERT(aKind == PrefValueKind::Default ? HasDefaultValue()
    370                                                 : HasUserValue());
    371 
    372      return aKind == PrefValueKind::Default
    373                 ? mMap->DefaultStringValues()[mEntry->mValue.mIndex]
    374                 : mMap->UserStringValues()[mEntry->mValue.mIndex];
    375    }
    376 
    377   public:
    378    nsCString GetStringValue(PrefValueKind aKind = PrefValueKind::User) const {
    379      return mMap->ValueTable().Get(GetStringEntry(aKind));
    380    }
    381 
    382    const char* GetBareStringValue(
    383        PrefValueKind aKind = PrefValueKind::User) const {
    384      return mMap->ValueTable().GetBare(GetStringEntry(aKind));
    385    }
    386 
    387    // Returns the entry's index in the map, as understood by GetKeyAt() and
    388    // GetValueAt().
    389    size_t Index() const { return mEntry - mMap->Entries().get(); }
    390 
    391    bool operator==(const Pref& aPref) const { return mEntry == aPref.mEntry; }
    392    bool operator!=(const Pref& aPref) const { return !(*this == aPref); }
    393 
    394    // This is odd, but necessary in order for the C++ range iterator protocol
    395    // to work here.
    396    Pref& operator*() { return *this; }
    397 
    398    // Updates this wrapper to point to the next visible entry in the map. This
    399    // should not be attempted unless Index() is less than the map's Count().
    400    Pref& operator++() {
    401      do {
    402        mEntry++;
    403      } while (mEntry->mIsSkippedByIteration && Index() < mMap->Count());
    404      return *this;
    405    }
    406 
    407    Pref(const Pref& aPref) = default;
    408 
    409   protected:
    410    friend class SharedPrefMap;
    411 
    412    Pref(const SharedPrefMap* aPrefMap, const Entry* aEntry)
    413        : mMap(aPrefMap), mEntry(aEntry) {}
    414 
    415   private:
    416    const SharedPrefMap* const mMap;
    417    const Entry* mEntry;
    418  };
    419 
    420  // Note: These constructors are infallible, because the preference database is
    421  // critical to platform functionality, and we cannot operate without it.
    422  explicit SharedPrefMap(const mozilla::ipc::ReadOnlySharedMemoryHandle&);
    423  explicit SharedPrefMap(SharedPrefMapBuilder&&);
    424 
    425  // Searches for the given preference in the map, and returns true if it
    426  // exists.
    427  bool Has(const char* aKey) const;
    428 
    429  bool Has(const nsCString& aKey) const { return Has(aKey.get()); }
    430 
    431  // Searches for the given preference in the map, and if it exists, returns
    432  // a Some<Pref> containing its details.
    433  Maybe<const Pref> Get(const char* aKey) const;
    434 
    435  Maybe<const Pref> Get(const nsCString& aKey) const { return Get(aKey.get()); }
    436 
    437 private:
    438  // Searches for an entry for the given key. If found, returns true, and
    439  // places its index in the entry array in aIndex.
    440  bool Find(const char* aKey, size_t* aIndex) const;
    441 
    442 public:
    443  // Returns the number of entries in the map.
    444  uint32_t Count() const { return EntryCount(); }
    445 
    446  // Returns the string entry at the given index. Keys are guaranteed to be
    447  // sorted lexicographically.
    448  //
    449  // The given index *must* be less than the value returned by Count().
    450  //
    451  // The returned value is a literal string which references the mapped memory
    452  // region.
    453  nsCString GetKeyAt(uint32_t aIndex) const {
    454    MOZ_ASSERT(aIndex < Count());
    455    return KeyTable().Get(Entries()[aIndex].mKey);
    456  }
    457 
    458  // Returns the value for the entry at the given index.
    459  //
    460  // The given index *must* be less than the value returned by Count().
    461  //
    462  // The returned value is valid for the lifetime of this map instance.
    463  const Pref GetValueAt(uint32_t aIndex) const {
    464    MOZ_ASSERT(aIndex < Count());
    465    return UncheckedGetValueAt(aIndex);
    466  }
    467 
    468 private:
    469  // Returns a wrapper with a pointer to an entry without checking its bounds.
    470  // This should only be used by range iterators, to check their end positions.
    471  //
    472  // Note: In debug builds, the RangePtr returned by entries will still assert
    473  // that aIndex is no more than 1 past the last element in the array, since it
    474  // also takes into account the ranged iteration use case.
    475  Pref UncheckedGetValueAt(uint32_t aIndex) const {
    476    return {this, (Entries() + aIndex).get()};
    477  }
    478 
    479 public:
    480  // C++ range iterator protocol. begin() and end() return references to the
    481  // first (non-skippable) and last entries in the array. The begin wrapper
    482  // can be incremented until it matches the last element in the array, at which
    483  // point it becomes invalid and the iteration is over.
    484  Pref begin() const {
    485    for (uint32_t aIndex = 0; aIndex < Count(); aIndex++) {
    486      Pref pref = UncheckedGetValueAt(aIndex);
    487      if (!pref.IsSkippedByIteration()) {
    488        return pref;
    489      }
    490    }
    491    return end();
    492  }
    493  Pref end() const { return UncheckedGetValueAt(Count()); }
    494 
    495  // A cosmetic helper for range iteration. Returns a reference value from a
    496  // pointer to this instance so that its .begin() and .end() methods can be
    497  // accessed in a ranged for loop. `map->Iter()` is equivalent to `*map`, but
    498  // makes its purpose slightly clearer.
    499  const SharedPrefMap& Iter() const { return *this; }
    500 
    501  // Returns a copy of the read-only shared memory handle which backs the shared
    502  // memory region for this map. The handle may be passed between processes, and
    503  // used to construct new instances of SharedPrefMap with the same data as this
    504  // instance.
    505  mozilla::ipc::ReadOnlySharedMemoryHandle CloneHandle() const;
    506 
    507  // Returns the size of the mapped memory region. This size must be passed to
    508  // the constructor when mapping the shared region in another process.
    509  size_t MapSize() const { return mMappedMemory.size(); }
    510 
    511 protected:
    512  ~SharedPrefMap() = default;
    513 
    514 private:
    515  template <typename T>
    516  using StringTable = mozilla::dom::ipc::StringTable<T>;
    517 
    518  // Type-safe getters for values in the shared memory region:
    519  const Header& GetHeader() const {
    520    return *reinterpret_cast<const Header*>(mMappedMemory.data());
    521  }
    522 
    523  RangedPtr<const Entry> Entries() const {
    524    return {reinterpret_cast<const Entry*>(&GetHeader() + 1), EntryCount()};
    525  }
    526 
    527  uint32_t EntryCount() const { return GetHeader().mEntryCount; }
    528 
    529  template <typename T>
    530  RangedPtr<const T> GetBlock(const DataBlock& aBlock) const {
    531    return RangedPtr<const uint8_t>(&mMappedMemory.data()[aBlock.mOffset],
    532                                    aBlock.mSize)
    533        .ReinterpretCast<const T>();
    534  }
    535 
    536  RangedPtr<const int32_t> DefaultIntValues() const {
    537    return GetBlock<int32_t>(GetHeader().mDefaultIntValues);
    538  }
    539  RangedPtr<const int32_t> UserIntValues() const {
    540    return GetBlock<int32_t>(GetHeader().mUserIntValues);
    541  }
    542 
    543  RangedPtr<const StringTableEntry> DefaultStringValues() const {
    544    return GetBlock<StringTableEntry>(GetHeader().mDefaultStringValues);
    545  }
    546  RangedPtr<const StringTableEntry> UserStringValues() const {
    547    return GetBlock<StringTableEntry>(GetHeader().mUserStringValues);
    548  }
    549 
    550  StringTable<nsCString> KeyTable() const {
    551    auto& block = GetHeader().mKeyStrings;
    552    return {{(uint8_t*)&mMappedMemory.data()[block.mOffset], block.mSize}};
    553  }
    554 
    555  StringTable<nsCString> ValueTable() const {
    556    auto& block = GetHeader().mValueStrings;
    557    return {{(uint8_t*)&mMappedMemory.data()[block.mOffset], block.mSize}};
    558  }
    559 
    560  mozilla::ipc::ReadOnlySharedMemoryHandle mHandle;
    561  // This is a leaked shared memory mapping (see the constructor definition for
    562  // an explanation). It replaces AutoMemMap::setPersistent behavior as part of
    563  // bug 1454816.
    564  mozilla::ipc::shared_memory::LeakedReadOnlyMapping mMappedMemory;
    565 };
    566 
    567 // A helper class which builds the contiguous look-up table used by
    568 // SharedPrefMap. Each preference in the final map is added to the builder,
    569 // before it is finalized and transformed into a read-only snapshot.
    570 class MOZ_RAII SharedPrefMapBuilder {
    571 public:
    572  SharedPrefMapBuilder() = default;
    573 
    574  // The set of flags for the preference, as documented in SharedPrefMap::Entry.
    575  struct Flags {
    576    uint8_t mHasDefaultValue : 1;
    577    uint8_t mHasUserValue : 1;
    578    uint8_t mIsSticky : 1;
    579    uint8_t mIsLocked : 1;
    580    uint8_t mIsSanitized : 1;
    581    uint8_t mIsSkippedByIteration : 1;
    582  };
    583 
    584  void Add(const nsCString& aKey, const Flags& aFlags, bool aDefaultValue,
    585           bool aUserValue);
    586 
    587  void Add(const nsCString& aKey, const Flags& aFlags, int32_t aDefaultValue,
    588           int32_t aUserValue);
    589 
    590  void Add(const nsCString& aKey, const Flags& aFlags,
    591           const nsCString& aDefaultValue, const nsCString& aUserValue);
    592 
    593  // Finalizes the binary representation of the map, writes it to a shared
    594  // memory region, and then initializes the given ReadOnlySharedMemoryMapping
    595  // with a reference to the read-only copy of it.
    596  //
    597  // This should generally not be used directly by callers. The
    598  // SharedPrefMapBuilder instance should instead be passed to the SharedPrefMap
    599  // constructor as a move reference.
    600  Result<mozilla::ipc::ReadOnlySharedMemoryHandle, nsresult> Finalize();
    601 
    602 private:
    603  using StringTableEntry = mozilla::dom::ipc::StringTableEntry;
    604  template <typename T, typename U>
    605  using StringTableBuilder = mozilla::dom::ipc::StringTableBuilder<T, U>;
    606 
    607  // An opaque descriptor of the index of a preference entry in a value array,
    608  // which can be converted numeric index after the ValueTableBuilder is
    609  // finalized.
    610  struct ValueIdx {
    611    // The relative index of the entry, based on its class. Entries for
    612    // preferences with user values appear at the value arrays. Entries with
    613    // only default values begin after the last entry with a user value.
    614    uint16_t mIndex;
    615    bool mHasUserValue;
    616  };
    617 
    618  // A helper class for building default and user value arrays for preferences.
    619  //
    620  // As described in the SharedPrefMap class, this helper optimizes the way that
    621  // it builds its value arrays, in that:
    622  //
    623  // - It stores value entries for all preferences with user values before
    624  //   entries for preferences with only default values, and allocates no
    625  //   entries for preferences with only default values in the user value array.
    626  //   Since most preferences have only default values, this dramatically
    627  //   reduces the space required for value storage.
    628  //
    629  // - For preferences with only default values, it de-duplicates value entries,
    630  //   and returns the same indices for all preferences with the same value.
    631  //
    632  // One important complication of this approach is that it means we cannot know
    633  // the final index of any entry with only a default value until all entries
    634  // have been added to the builder, since it depends on the final number of
    635  // user entries in the output.
    636  //
    637  // To deal with this, when entries are added, we return an opaque ValueIndex
    638  // struct, from which we can calculate the final index after the map has been
    639  // finalized.
    640  template <typename HashKey, typename ValueType_>
    641  class ValueTableBuilder {
    642   public:
    643    using ValueType = ValueType_;
    644 
    645    // Adds an entry for a preference with only a default value to the array,
    646    // and returns an opaque descriptor for its index.
    647    ValueIdx Add(const ValueType& aDefaultValue) {
    648      auto index = uint16_t(mDefaultEntries.Count());
    649 
    650      return mDefaultEntries.WithEntryHandle(aDefaultValue, [&](auto&& entry) {
    651        entry.OrInsertWith([&] { return Entry{index, false, aDefaultValue}; });
    652 
    653        return ValueIdx{entry->mIndex, false};
    654      });
    655    }
    656 
    657    // Adds an entry for a preference with a user value to the array. Regardless
    658    // of whether the preference has a default value, space must be allocated
    659    // for it. For preferences with no default value, the actual value which
    660    // appears in the array at its value index is ignored.
    661    ValueIdx Add(const ValueType& aDefaultValue, const ValueType& aUserValue) {
    662      auto index = uint16_t(mUserEntries.Length());
    663 
    664      mUserEntries.AppendElement(Entry{index, true, aDefaultValue, aUserValue});
    665 
    666      return {index, true};
    667    }
    668 
    669    // Returns the final index for an entry based on its opaque index
    670    // descriptor. This must only be called after the caller has finished adding
    671    // entries to the builder.
    672    uint16_t GetIndex(const ValueIdx& aIndex) const {
    673      uint16_t base = aIndex.mHasUserValue ? 0 : UserCount();
    674      return base + aIndex.mIndex;
    675    }
    676 
    677    // Writes out the array of default values at the block beginning at the
    678    // given pointer. The block must be at least as large as the value returned
    679    // by DefaultSize().
    680    void WriteDefaultValues(const RangedPtr<uint8_t>& aBuffer) const {
    681      auto buffer = aBuffer.ReinterpretCast<ValueType>();
    682 
    683      for (const auto& entry : mUserEntries) {
    684        buffer[entry.mIndex] = entry.mDefaultValue;
    685      }
    686 
    687      size_t defaultsOffset = UserCount();
    688      for (const auto& data : mDefaultEntries.Values()) {
    689        buffer[defaultsOffset + data.mIndex] = data.mDefaultValue;
    690      }
    691    }
    692 
    693    // Writes out the array of user values at the block beginning at the
    694    // given pointer. The block must be at least as large as the value returned
    695    // by UserSize().
    696    void WriteUserValues(const RangedPtr<uint8_t>& aBuffer) const {
    697      auto buffer = aBuffer.ReinterpretCast<ValueType>();
    698 
    699      for (const auto& entry : mUserEntries) {
    700        buffer[entry.mIndex] = entry.mUserValue;
    701      }
    702    }
    703 
    704    // These return the number of entries in the default and user value arrays,
    705    // respectively.
    706    uint32_t DefaultCount() const {
    707      return UserCount() + mDefaultEntries.Count();
    708    }
    709    uint32_t UserCount() const { return mUserEntries.Length(); }
    710 
    711    // These return the byte sizes of the default and user value arrays,
    712    // respectively.
    713    uint32_t DefaultSize() const { return DefaultCount() * sizeof(ValueType); }
    714    uint32_t UserSize() const { return UserCount() * sizeof(ValueType); }
    715 
    716    void Clear() {
    717      mUserEntries.Clear();
    718      mDefaultEntries.Clear();
    719    }
    720 
    721    static constexpr size_t Alignment() { return alignof(ValueType); }
    722 
    723   private:
    724    struct Entry {
    725      uint16_t mIndex;
    726      bool mHasUserValue;
    727      ValueType mDefaultValue;
    728      ValueType mUserValue{};
    729    };
    730 
    731    AutoTArray<Entry, 256> mUserEntries;
    732 
    733    nsTHashMap<HashKey, Entry> mDefaultEntries;
    734  };
    735 
    736  // A special-purpose string table builder for keys which are already
    737  // guaranteed to be unique. Duplicate values will not be detected or
    738  // de-duplicated.
    739  template <typename CharType>
    740  class UniqueStringTableBuilder {
    741   public:
    742    using ElemType = CharType;
    743 
    744    explicit UniqueStringTableBuilder(size_t aCapacity) : mEntries(aCapacity) {}
    745 
    746    StringTableEntry Add(const nsTString<CharType>& aKey) {
    747      auto entry = mEntries.AppendElement(
    748          Entry{mSize, uint32_t(aKey.Length()), aKey.get()});
    749 
    750      mSize += entry->mLength + 1;
    751 
    752      return {entry->mOffset, entry->mLength};
    753    }
    754 
    755    void Write(const RangedPtr<uint8_t>& aBuffer) {
    756      auto buffer = aBuffer.ReinterpretCast<ElemType>();
    757 
    758      for (auto& entry : mEntries) {
    759        memcpy(&buffer[entry.mOffset], entry.mValue,
    760               sizeof(ElemType) * (entry.mLength + 1));
    761      }
    762    }
    763 
    764    uint32_t Count() const { return mEntries.Length(); }
    765 
    766    uint32_t Size() const { return mSize * sizeof(ElemType); }
    767 
    768    void Clear() { mEntries.Clear(); }
    769 
    770    static constexpr size_t Alignment() { return alignof(ElemType); }
    771 
    772   private:
    773    struct Entry {
    774      uint32_t mOffset;
    775      uint32_t mLength;
    776      const CharType* mValue;
    777    };
    778 
    779    nsTArray<Entry> mEntries;
    780    uint32_t mSize = 0;
    781  };
    782 
    783  // A preference value entry, roughly corresponding to the
    784  // SharedPrefMap::Value struct, but with a temporary place-holder value rather
    785  // than a final value index.
    786  union Value {
    787    Value(bool aDefaultValue, bool aUserValue)
    788        : mDefaultBool(aDefaultValue), mUserBool(aUserValue) {}
    789 
    790    MOZ_IMPLICIT Value(const ValueIdx& aIndex) : mIndex(aIndex) {}
    791 
    792    // For Bool preferences, their default and user bool values.
    793    struct {
    794      bool mDefaultBool;
    795      bool mUserBool;
    796    };
    797    // For Int and String preferences, an opaque descriptor for their entries in
    798    // their value arrays. This must be passed to the appropriate
    799    // ValueTableBuilder to obtain the final index when the entry is serialized.
    800    ValueIdx mIndex;
    801  };
    802 
    803  // A preference entry, to be converted to a SharedPrefMap::Entry struct during
    804  // serialization.
    805  struct Entry {
    806    // The entry's preference name, as passed to Add(). The caller is
    807    // responsible for keeping this pointer alive until the builder is
    808    // finalized.
    809    const char* mKeyString;
    810    // The entry in mKeyTable corresponding to mKeyString.
    811    StringTableEntry mKey;
    812    Value mValue;
    813 
    814    uint8_t mType : 2;
    815    uint8_t mHasDefaultValue : 1;
    816    uint8_t mHasUserValue : 1;
    817    uint8_t mIsSticky : 1;
    818    uint8_t mIsLocked : 1;
    819    uint8_t mIsSanitized : 1;
    820    uint8_t mIsSkippedByIteration : 1;
    821  };
    822 
    823  // Converts a builder Value struct to a SharedPrefMap::Value struct for
    824  // serialization. This must not be called before callers have finished adding
    825  // entries to the value array builders.
    826  SharedPrefMap::Value GetValue(const Entry& aEntry) const {
    827    switch (PrefType(aEntry.mType)) {
    828      case PrefType::Bool:
    829        return {aEntry.mValue.mDefaultBool, aEntry.mValue.mUserBool};
    830      case PrefType::Int:
    831        return {mIntValueTable.GetIndex(aEntry.mValue.mIndex)};
    832      case PrefType::String:
    833        return {mStringValueTable.GetIndex(aEntry.mValue.mIndex)};
    834      default:
    835        MOZ_ASSERT_UNREACHABLE("Invalid pref type");
    836        return {false, false};
    837    }
    838  }
    839 
    840  UniqueStringTableBuilder<char> mKeyTable{kExpectedPrefCount};
    841  StringTableBuilder<nsCStringHashKey, nsCString> mValueStringTable;
    842 
    843  ValueTableBuilder<nsUint32HashKey, uint32_t> mIntValueTable;
    844  ValueTableBuilder<nsGenericHashKey<StringTableEntry>, StringTableEntry>
    845      mStringValueTable;
    846 
    847  nsTArray<Entry> mEntries{kExpectedPrefCount};
    848 };
    849 
    850 }  // namespace mozilla
    851 
    852 #endif  // dom_ipc_SharedPrefMap_h