SharedStringMap.cpp (4193B)
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 #include "SharedStringMap.h" 8 9 #include "MemMapSnapshot.h" 10 #include "ScriptPreloader-inl.h" 11 #include "mozilla/BinarySearch.h" 12 #include "mozilla/Try.h" 13 14 using namespace mozilla::loader; 15 16 namespace mozilla { 17 18 using namespace ipc; 19 20 namespace dom::ipc { 21 22 static constexpr uint32_t kSharedStringMapMagic = 0x9e3779b9; 23 24 static inline size_t GetAlignmentOffset(size_t aOffset, size_t aAlign) { 25 auto mod = aOffset % aAlign; 26 return mod ? aAlign - mod : 0; 27 } 28 29 SharedStringMap::SharedStringMap(const ReadOnlySharedMemoryHandle& aMapHandle) { 30 mHandle = aMapHandle.Clone(); 31 MOZ_RELEASE_ASSERT(mHandle.IsValid()); 32 auto mapping = aMapHandle.Map(); 33 MOZ_RELEASE_ASSERT(mapping.IsValid()); 34 35 // We return literal nsStrings and nsCStrings pointing to the mapped data, 36 // which means that we may still have references to the mapped data even 37 // after this instance is destroyed. That means that we need to keep the 38 // mapping alive until process shutdown, in order to be safe. 39 mMappedMemory = std::move(mapping).Release(); 40 41 MOZ_RELEASE_ASSERT(GetHeader().mMagic == kSharedStringMapMagic); 42 } 43 44 SharedStringMap::SharedStringMap(SharedStringMapBuilder&& aBuilder) { 45 ReadOnlySharedMemoryMappingWithHandle mappingWithHandle; 46 auto result = aBuilder.Finalize(); 47 MOZ_RELEASE_ASSERT(result.isOk()); 48 mHandle = result.unwrap(); 49 auto mapping = mHandle.Map(); 50 MOZ_RELEASE_ASSERT(mapping.IsValid()); 51 52 mMappedMemory = std::move(mapping).Release(); 53 54 MOZ_RELEASE_ASSERT(GetHeader().mMagic == kSharedStringMapMagic); 55 } 56 57 mozilla::ipc::ReadOnlySharedMemoryHandle SharedStringMap::CloneHandle() const { 58 return mHandle.Clone(); 59 } 60 61 bool SharedStringMap::Has(const nsCString& aKey) { 62 size_t index; 63 return Find(aKey, &index); 64 } 65 66 bool SharedStringMap::Get(const nsCString& aKey, nsAString& aValue) { 67 const auto& entries = Entries(); 68 69 size_t index; 70 if (!Find(aKey, &index)) { 71 return false; 72 } 73 74 aValue.Assign(ValueTable().Get(entries[index].mValue)); 75 return true; 76 } 77 78 bool SharedStringMap::Find(const nsCString& aKey, size_t* aIndex) { 79 const auto& keys = KeyTable(); 80 81 return BinarySearchIf( 82 Entries(), 0, EntryCount(), 83 [&](const Entry& aEntry) { return Compare(aKey, keys.Get(aEntry.mKey)); }, 84 aIndex); 85 } 86 87 void SharedStringMapBuilder::Add(const nsCString& aKey, 88 const nsString& aValue) { 89 mEntries.InsertOrUpdate(aKey, 90 Entry{mKeyTable.Add(aKey), mValueTable.Add(aValue)}); 91 } 92 93 Result<ReadOnlySharedMemoryHandle, nsresult> 94 SharedStringMapBuilder::Finalize() { 95 using Header = SharedStringMap::Header; 96 97 MOZ_ASSERT(mEntries.Count() == mKeyTable.Count()); 98 99 auto keys = ToTArray<nsTArray<nsCString>>(mEntries.Keys()); 100 keys.Sort(); 101 102 Header header = {kSharedStringMapMagic, uint32_t(keys.Length())}; 103 104 size_t offset = sizeof(header); 105 offset += GetAlignmentOffset(offset, alignof(Header)); 106 107 offset += keys.Length() * sizeof(SharedStringMap::Entry); 108 109 header.mKeyStringsOffset = offset; 110 header.mKeyStringsSize = mKeyTable.Size(); 111 112 offset += header.mKeyStringsSize; 113 offset += 114 GetAlignmentOffset(offset, alignof(decltype(mValueTable)::ElemType)); 115 116 header.mValueStringsOffset = offset; 117 header.mValueStringsSize = mValueTable.Size(); 118 119 offset += header.mValueStringsSize; 120 121 MemMapSnapshot mem; 122 MOZ_TRY(mem.Init(offset)); 123 124 auto headerPtr = mem.Get<Header>(); 125 headerPtr[0] = header; 126 127 auto* entry = reinterpret_cast<Entry*>(&headerPtr[1]); 128 for (auto& key : keys) { 129 *entry++ = mEntries.Get(key); 130 } 131 132 auto ptr = mem.Get<uint8_t>(); 133 134 mKeyTable.Write({&ptr[header.mKeyStringsOffset], header.mKeyStringsSize}); 135 136 mValueTable.Write( 137 {&ptr[header.mValueStringsOffset], header.mValueStringsSize}); 138 139 mKeyTable.Clear(); 140 mValueTable.Clear(); 141 mEntries.Clear(); 142 143 return mem.Finalize(); 144 } 145 146 } // namespace dom::ipc 147 } // namespace mozilla