SharedStringMap.h (7446B)
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_SharedStringMap_h 8 #define dom_ipc_SharedStringMap_h 9 10 #include "mozilla/Result.h" 11 #include "mozilla/dom/ipc/StringTable.h" 12 #include "mozilla/ipc/SharedMemoryHandle.h" 13 #include "mozilla/ipc/SharedMemoryMapping.h" 14 #include "nsTHashMap.h" 15 16 namespace mozilla::dom::ipc { 17 18 class SharedStringMapBuilder; 19 20 /** 21 * This class provides a simple, read-only key-value string store, with all 22 * data packed into a single segment of memory, which can be shared between 23 * processes. 24 * 25 * Look-ups are performed by binary search of a static table in the mapped 26 * memory region, and all returned strings are literals which reference the 27 * mapped data. No copies are performed on instantiation or look-up. 28 * 29 * Important: The mapped memory created by this class is persistent. Once an 30 * instance has been initialized, the memory that it allocates can never be 31 * freed before process shutdown. Do not use it for short-lived mappings. 32 */ 33 class SharedStringMap { 34 public: 35 /** 36 * The header at the beginning of the shared memory region describing its 37 * layout. The layout of the shared memory is as follows: 38 * 39 * - Header: 40 * A Header struct describing the contents of the rest of the memory region. 41 * 42 * - Optional alignment padding for Header[]. 43 * 44 * - Entry[header.mEntryCount]: 45 * An array of Entry structs, one for each entry in the map. Entries are 46 * lexocographically sorted by key. 47 * 48 * - StringTable<nsCString>: 49 * A region of flat, null-terminated C strings. Entry key strings are 50 * encoded as character offsets into this region. 51 * 52 * - Optional alignment padding for char16_t[] 53 * 54 * - StringTable<nsString>: 55 * A region of flat, null-terminated UTF-16 strings. Entry value strings are 56 * encoded as character (*not* byte) offsets into this region. 57 */ 58 struct Header { 59 uint32_t mMagic; 60 // The number of entries in this map. 61 uint32_t mEntryCount; 62 63 // The raw byte offset of the beginning of the key string table, from the 64 // start of the shared memory region, and its size in bytes. 65 size_t mKeyStringsOffset; 66 size_t mKeyStringsSize; 67 68 // The raw byte offset of the beginning of the value string table, from the 69 // start of the shared memory region, and its size in bytes (*not* 70 // characters). 71 size_t mValueStringsOffset; 72 size_t mValueStringsSize; 73 }; 74 75 /** 76 * Describes a value in the string map, as offsets into the key and value 77 * string tables. 78 */ 79 struct Entry { 80 // The offset and size of the entry's UTF-8 key in the key string table. 81 StringTableEntry mKey; 82 // The offset and size of the entry's UTF-16 value in the value string 83 // table. 84 StringTableEntry mValue; 85 }; 86 87 NS_INLINE_DECL_REFCOUNTING(SharedStringMap) 88 89 // Note: These constructors are infallible on the premise that this class 90 // is used primarily in cases where it is critical to platform 91 // functionality. 92 explicit SharedStringMap(const mozilla::ipc::ReadOnlySharedMemoryHandle&); 93 explicit SharedStringMap(SharedStringMapBuilder&&); 94 95 /** 96 * Searches for the given value in the map, and returns true if it exists. 97 */ 98 bool Has(const nsCString& aKey); 99 100 /** 101 * Searches for the given value in the map, and, if it exists, returns true 102 * and places its value in aValue. 103 * 104 * The returned value is a literal string which references the mapped memory 105 * region. 106 */ 107 bool Get(const nsCString& aKey, nsAString& aValue); 108 109 private: 110 /** 111 * Searches for an entry for the given key. If found, returns true, and 112 * places its index in the entry array in aIndex. 113 */ 114 bool Find(const nsCString& aKey, size_t* aIndex); 115 116 public: 117 /** 118 * Returns the number of entries in the map. 119 */ 120 uint32_t Count() const { return EntryCount(); } 121 122 /** 123 * Returns the string entry at the given index. Keys are guaranteed to be 124 * sorted lexographically. 125 * 126 * The given index *must* be less than the value returned by Count(). 127 * 128 * The returned value is a literal string which references the mapped memory 129 * region. 130 */ 131 nsCString GetKeyAt(uint32_t aIndex) const { 132 MOZ_ASSERT(aIndex < Count()); 133 return KeyTable().Get(Entries()[aIndex].mKey); 134 } 135 136 /** 137 * Returns the string value for the entry at the given index. 138 * 139 * The given index *must* be less than the value returned by Count(). 140 * 141 * The returned value is a literal string which references the mapped memory 142 * region. 143 */ 144 nsString GetValueAt(uint32_t aIndex) const { 145 MOZ_ASSERT(aIndex < Count()); 146 return ValueTable().Get(Entries()[aIndex].mValue); 147 } 148 149 /** 150 * Returns a copy of the read-only shared memory handle which backs the shared 151 * memory region for this map. The handle may be passed between processes, and 152 * used to construct new instances of SharedStringMap with the same data as 153 * this instance. 154 */ 155 mozilla::ipc::ReadOnlySharedMemoryHandle CloneHandle() const; 156 157 size_t MapSize() const { return mMappedMemory.size(); } 158 159 protected: 160 ~SharedStringMap() = default; 161 162 private: 163 // Type-safe getters for values in the shared memory region: 164 const Header& GetHeader() const { 165 return *reinterpret_cast<const Header*>(mMappedMemory.data()); 166 } 167 168 RangedPtr<const Entry> Entries() const { 169 return {reinterpret_cast<const Entry*>(&GetHeader() + 1), EntryCount()}; 170 } 171 172 uint32_t EntryCount() const { return GetHeader().mEntryCount; } 173 174 StringTable<nsCString> KeyTable() const { 175 const auto& header = GetHeader(); 176 return { 177 {const_cast<uint8_t*>(&mMappedMemory.data()[header.mKeyStringsOffset]), 178 header.mKeyStringsSize}}; 179 } 180 181 StringTable<nsString> ValueTable() const { 182 const auto& header = GetHeader(); 183 return {{const_cast<uint8_t*>( 184 &mMappedMemory.data()[header.mValueStringsOffset]), 185 header.mValueStringsSize}}; 186 } 187 188 mozilla::ipc::ReadOnlySharedMemoryHandle mHandle; 189 // This is a leaked shared memory mapping (see the constructor definition for 190 // an explanation). It replaces AutoMemMap::setPersistent behavior as part of 191 // bug 1454816. 192 mozilla::ipc::shared_memory::LeakedReadOnlyMapping mMappedMemory; 193 }; 194 195 /** 196 * A helper class which builds the contiguous look-up table used by 197 * SharedStringMap. Each key-value pair in the final map is added to the 198 * builder, before it is finalized and transformed into a snapshot. 199 */ 200 class MOZ_RAII SharedStringMapBuilder { 201 public: 202 SharedStringMapBuilder() = default; 203 204 /** 205 * Adds a key-value pair to the map. 206 */ 207 void Add(const nsCString& aKey, const nsString& aValue); 208 209 /** 210 * Finalizes the binary representation of the map, writes it to a shared 211 * memory region, and then returns a read-only handle to it. 212 */ 213 Result<mozilla::ipc::ReadOnlySharedMemoryHandle, nsresult> Finalize(); 214 215 private: 216 using Entry = SharedStringMap::Entry; 217 218 StringTableBuilder<nsCStringHashKey, nsCString> mKeyTable; 219 StringTableBuilder<nsStringHashKey, nsString> mValueTable; 220 221 nsTHashMap<nsCStringHashKey, Entry> mEntries; 222 }; 223 224 } // namespace mozilla::dom::ipc 225 226 #endif // dom_ipc_SharedStringMap_h