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 "SharedPrefMap.h"
9 #include "mozilla/dom/ipc/MemMapSnapshot.h"
11 #include "mozilla/BinarySearch.h"
12 #include "mozilla/ResultExtensions.h"
13 #include "mozilla/Try.h"
14 #include "mozilla/ipc/FileDescriptor.h"
16 using namespace mozilla::loader
;
22 static inline size_t GetAlignmentOffset(size_t aOffset
, size_t aAlign
) {
23 auto mod
= aOffset
% aAlign
;
24 return mod
? aAlign
- mod
: 0;
27 SharedPrefMap::SharedPrefMap(const FileDescriptor
& aMapFile
, size_t aMapSize
) {
28 auto result
= mMap
.initWithHandle(aMapFile
, aMapSize
);
29 MOZ_RELEASE_ASSERT(result
.isOk());
30 // We return literal nsCStrings pointing to the mapped data for preference
31 // names and string values, which means that we may still have references to
32 // the mapped data even after this instance is destroyed. That means that we
33 // need to keep the mapping alive until process shutdown, in order to be safe.
37 SharedPrefMap::SharedPrefMap(SharedPrefMapBuilder
&& aBuilder
) {
38 auto result
= aBuilder
.Finalize(mMap
);
39 MOZ_RELEASE_ASSERT(result
.isOk());
43 mozilla::ipc::FileDescriptor
SharedPrefMap::CloneFileDescriptor() const {
44 return mMap
.cloneHandle();
47 bool SharedPrefMap::Has(const char* aKey
) const {
49 return Find(aKey
, &index
);
52 Maybe
<const SharedPrefMap::Pref
> SharedPrefMap::Get(const char* aKey
) const {
53 Maybe
<const Pref
> result
;
56 if (Find(aKey
, &index
)) {
57 result
.emplace(Pref
{this, &Entries()[index
]});
63 bool SharedPrefMap::Find(const char* aKey
, size_t* aIndex
) const {
64 const auto& keys
= KeyTable();
66 return BinarySearchIf(
67 Entries(), 0, EntryCount(),
68 [&](const Entry
& aEntry
) {
69 return strcmp(aKey
, keys
.GetBare(aEntry
.mKey
));
74 void SharedPrefMapBuilder::Add(const nsCString
& aKey
, const Flags
& aFlags
,
75 bool aDefaultValue
, bool aUserValue
) {
76 mEntries
.AppendElement(Entry
{
79 {aDefaultValue
, aUserValue
},
80 uint8_t(PrefType::Bool
),
81 aFlags
.mHasDefaultValue
,
86 aFlags
.mIsSkippedByIteration
,
90 void SharedPrefMapBuilder::Add(const nsCString
& aKey
, const Flags
& aFlags
,
91 int32_t aDefaultValue
, int32_t aUserValue
) {
93 if (aFlags
.mHasUserValue
) {
94 index
= mIntValueTable
.Add(aDefaultValue
, aUserValue
);
96 index
= mIntValueTable
.Add(aDefaultValue
);
99 mEntries
.AppendElement(Entry
{
103 uint8_t(PrefType::Int
),
104 aFlags
.mHasDefaultValue
,
105 aFlags
.mHasUserValue
,
109 aFlags
.mIsSkippedByIteration
,
113 void SharedPrefMapBuilder::Add(const nsCString
& aKey
, const Flags
& aFlags
,
114 const nsCString
& aDefaultValue
,
115 const nsCString
& aUserValue
) {
117 StringTableEntry defaultVal
= mValueStringTable
.Add(aDefaultValue
);
118 if (aFlags
.mHasUserValue
) {
119 StringTableEntry userVal
= mValueStringTable
.Add(aUserValue
);
120 index
= mStringValueTable
.Add(defaultVal
, userVal
);
122 index
= mStringValueTable
.Add(defaultVal
);
125 mEntries
.AppendElement(Entry
{
129 uint8_t(PrefType::String
),
130 aFlags
.mHasDefaultValue
,
131 aFlags
.mHasUserValue
,
135 aFlags
.mIsSkippedByIteration
,
139 Result
<Ok
, nsresult
> SharedPrefMapBuilder::Finalize(loader::AutoMemMap
& aMap
) {
140 using Header
= SharedPrefMap::Header
;
142 // Create an array of entry pointers for the entry array, and sort it by
143 // preference name prior to serialization, so that entries can be looked up
144 // using binary search.
145 nsTArray
<Entry
*> entries(mEntries
.Length());
146 for (auto& entry
: mEntries
) {
147 entries
.AppendElement(&entry
);
149 entries
.Sort([](const Entry
* aA
, const Entry
* aB
) {
150 return strcmp(aA
->mKeyString
, aB
->mKeyString
);
153 Header header
= {uint32_t(entries
.Length())};
155 size_t offset
= sizeof(header
);
156 offset
+= GetAlignmentOffset(offset
, alignof(Header
));
158 offset
+= entries
.Length() * sizeof(SharedPrefMap::Entry
);
160 header
.mKeyStrings
.mOffset
= offset
;
161 header
.mKeyStrings
.mSize
= mKeyTable
.Size();
162 offset
+= header
.mKeyStrings
.mSize
;
164 offset
+= GetAlignmentOffset(offset
, mIntValueTable
.Alignment());
165 header
.mUserIntValues
.mOffset
= offset
;
166 header
.mUserIntValues
.mSize
= mIntValueTable
.UserSize();
167 offset
+= header
.mUserIntValues
.mSize
;
169 offset
+= GetAlignmentOffset(offset
, mIntValueTable
.Alignment());
170 header
.mDefaultIntValues
.mOffset
= offset
;
171 header
.mDefaultIntValues
.mSize
= mIntValueTable
.DefaultSize();
172 offset
+= header
.mDefaultIntValues
.mSize
;
174 offset
+= GetAlignmentOffset(offset
, mStringValueTable
.Alignment());
175 header
.mUserStringValues
.mOffset
= offset
;
176 header
.mUserStringValues
.mSize
= mStringValueTable
.UserSize();
177 offset
+= header
.mUserStringValues
.mSize
;
179 offset
+= GetAlignmentOffset(offset
, mStringValueTable
.Alignment());
180 header
.mDefaultStringValues
.mOffset
= offset
;
181 header
.mDefaultStringValues
.mSize
= mStringValueTable
.DefaultSize();
182 offset
+= header
.mDefaultStringValues
.mSize
;
184 header
.mValueStrings
.mOffset
= offset
;
185 header
.mValueStrings
.mSize
= mValueStringTable
.Size();
186 offset
+= header
.mValueStrings
.mSize
;
189 MOZ_TRY(mem
.Init(offset
));
191 auto headerPtr
= mem
.Get
<Header
>();
192 headerPtr
[0] = header
;
194 auto* entryPtr
= reinterpret_cast<SharedPrefMap::Entry
*>(&headerPtr
[1]);
195 for (auto* entry
: entries
) {
200 entry
->mHasDefaultValue
,
201 entry
->mHasUserValue
,
205 entry
->mIsSkippedByIteration
,
210 auto ptr
= mem
.Get
<uint8_t>();
212 mKeyTable
.Write({&ptr
[header
.mKeyStrings
.mOffset
], header
.mKeyStrings
.mSize
});
214 mValueStringTable
.Write(
215 {&ptr
[header
.mValueStrings
.mOffset
], header
.mValueStrings
.mSize
});
217 mIntValueTable
.WriteDefaultValues(
218 {&ptr
[header
.mDefaultIntValues
.mOffset
], header
.mDefaultIntValues
.mSize
});
219 mIntValueTable
.WriteUserValues(
220 {&ptr
[header
.mUserIntValues
.mOffset
], header
.mUserIntValues
.mSize
});
222 mStringValueTable
.WriteDefaultValues(
223 {&ptr
[header
.mDefaultStringValues
.mOffset
],
224 header
.mDefaultStringValues
.mSize
});
225 mStringValueTable
.WriteUserValues(
226 {&ptr
[header
.mUserStringValues
.mOffset
], header
.mUserStringValues
.mSize
});
229 mValueStringTable
.Clear();
230 mIntValueTable
.Clear();
231 mStringValueTable
.Clear();
234 return mem
.Finalize(aMap
);
237 } // namespace mozilla