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/. */
7 #include "SharedStringMap.h"
9 #include "MemMapSnapshot.h"
10 #include "ScriptPreloader-inl.h"
12 #include "mozilla/BinarySearch.h"
13 #include "mozilla/Try.h"
15 using namespace mozilla::loader
;
23 static constexpr uint32_t kSharedStringMapMagic
= 0x9e3779b9;
25 static inline size_t GetAlignmentOffset(size_t aOffset
, size_t aAlign
) {
26 auto mod
= aOffset
% aAlign
;
27 return mod
? aAlign
- mod
: 0;
30 SharedStringMap::SharedStringMap(const SharedMemoryHandle
& aMapHandle
,
32 auto map
= MakeRefPtr
<SharedMemory
>();
34 auto result
= map
->SetHandle(SharedMemory::CloneHandle(aMapHandle
),
35 SharedMemory::OpenRights::RightsReadOnly
);
36 MOZ_RELEASE_ASSERT(result
);
39 auto result
= map
->Map(aMapSize
);
40 MOZ_RELEASE_ASSERT(result
);
43 // We return literal nsStrings and nsCStrings pointing to the mapped data,
44 // which means that we may still have references to the mapped data even
45 // after this instance is destroyed. That means that we need to keep the
46 // mapping alive until process shutdown, in order to be safe.
47 mMappedMemory
= map
->TakeMapping();
48 mHandle
= map
->TakeHandle();
50 MOZ_RELEASE_ASSERT(GetHeader().mMagic
== kSharedStringMapMagic
);
53 SharedStringMap::SharedStringMap(SharedStringMapBuilder
&& aBuilder
) {
54 RefPtr
<SharedMemory
> map
;
55 auto result
= aBuilder
.Finalize(map
);
56 MOZ_RELEASE_ASSERT(result
.isOk() && map
);
58 mMappedMemory
= map
->TakeMapping();
59 mHandle
= map
->TakeHandle();
61 MOZ_RELEASE_ASSERT(GetHeader().mMagic
== kSharedStringMapMagic
);
64 mozilla::ipc::SharedMemoryHandle
SharedStringMap::CloneHandle() const {
65 return SharedMemory::CloneHandle(mHandle
);
68 bool SharedStringMap::Has(const nsCString
& aKey
) {
70 return Find(aKey
, &index
);
73 bool SharedStringMap::Get(const nsCString
& aKey
, nsAString
& aValue
) {
74 const auto& entries
= Entries();
77 if (!Find(aKey
, &index
)) {
81 aValue
.Assign(ValueTable().Get(entries
[index
].mValue
));
85 bool SharedStringMap::Find(const nsCString
& aKey
, size_t* aIndex
) {
86 const auto& keys
= KeyTable();
88 return BinarySearchIf(
89 Entries(), 0, EntryCount(),
90 [&](const Entry
& aEntry
) { return Compare(aKey
, keys
.Get(aEntry
.mKey
)); },
94 void SharedStringMapBuilder::Add(const nsCString
& aKey
,
95 const nsString
& aValue
) {
96 mEntries
.InsertOrUpdate(aKey
,
97 Entry
{mKeyTable
.Add(aKey
), mValueTable
.Add(aValue
)});
100 Result
<Ok
, nsresult
> SharedStringMapBuilder::Finalize(
101 RefPtr
<SharedMemory
>& aMap
) {
102 using Header
= SharedStringMap::Header
;
104 MOZ_ASSERT(mEntries
.Count() == mKeyTable
.Count());
106 auto keys
= ToTArray
<nsTArray
<nsCString
>>(mEntries
.Keys());
109 Header header
= {kSharedStringMapMagic
, uint32_t(keys
.Length())};
111 size_t offset
= sizeof(header
);
112 offset
+= GetAlignmentOffset(offset
, alignof(Header
));
114 offset
+= keys
.Length() * sizeof(SharedStringMap::Entry
);
116 header
.mKeyStringsOffset
= offset
;
117 header
.mKeyStringsSize
= mKeyTable
.Size();
119 offset
+= header
.mKeyStringsSize
;
121 GetAlignmentOffset(offset
, alignof(decltype(mValueTable
)::ElemType
));
123 header
.mValueStringsOffset
= offset
;
124 header
.mValueStringsSize
= mValueTable
.Size();
126 offset
+= header
.mValueStringsSize
;
129 MOZ_TRY(mem
.Init(offset
));
131 auto headerPtr
= mem
.Get
<Header
>();
132 headerPtr
[0] = header
;
134 auto* entry
= reinterpret_cast<Entry
*>(&headerPtr
[1]);
135 for (auto& key
: keys
) {
136 *entry
++ = mEntries
.Get(key
);
139 auto ptr
= mem
.Get
<uint8_t>();
141 mKeyTable
.Write({&ptr
[header
.mKeyStringsOffset
], header
.mKeyStringsSize
});
144 {&ptr
[header
.mValueStringsOffset
], header
.mValueStringsSize
});
150 return mem
.Finalize(aMap
);
153 } // namespace dom::ipc
154 } // namespace mozilla