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/ipc/FileDescriptor.h"
15 using namespace mozilla::loader
;
21 static inline size_t GetAlignmentOffset(size_t aOffset
, size_t aAlign
) {
22 auto mod
= aOffset
% aAlign
;
23 return mod
? aAlign
- mod
: 0;
26 SharedPrefMap::SharedPrefMap(const FileDescriptor
& aMapFile
, size_t aMapSize
) {
27 auto result
= mMap
.initWithHandle(aMapFile
, aMapSize
);
28 MOZ_RELEASE_ASSERT(result
.isOk());
29 // We return literal nsCStrings pointing to the mapped data for preference
30 // names and string values, which means that we may still have references to
31 // the mapped data even after this instance is destroyed. That means that we
32 // need to keep the mapping alive until process shutdown, in order to be safe.
36 SharedPrefMap::SharedPrefMap(SharedPrefMapBuilder
&& aBuilder
) {
37 auto result
= aBuilder
.Finalize(mMap
);
38 MOZ_RELEASE_ASSERT(result
.isOk());
42 mozilla::ipc::FileDescriptor
SharedPrefMap::CloneFileDescriptor() const {
43 return mMap
.cloneHandle();
46 bool SharedPrefMap::Has(const char* aKey
) const {
48 return Find(aKey
, &index
);
51 Maybe
<const SharedPrefMap::Pref
> SharedPrefMap::Get(const char* aKey
) const {
52 Maybe
<const Pref
> result
;
55 if (Find(aKey
, &index
)) {
56 result
.emplace(Pref
{this, &Entries()[index
]});
62 bool SharedPrefMap::Find(const char* aKey
, size_t* aIndex
) const {
63 const auto& keys
= KeyTable();
65 return BinarySearchIf(
66 Entries(), 0, EntryCount(),
67 [&](const Entry
& aEntry
) {
68 return strcmp(aKey
, keys
.GetBare(aEntry
.mKey
));
73 void SharedPrefMapBuilder::Add(const nsCString
& aKey
, const Flags
& aFlags
,
74 bool aDefaultValue
, bool aUserValue
) {
75 mEntries
.AppendElement(Entry
{
78 {aDefaultValue
, aUserValue
},
79 uint8_t(PrefType::Bool
),
80 aFlags
.mHasDefaultValue
,
85 aFlags
.mIsSkippedByIteration
,
89 void SharedPrefMapBuilder::Add(const nsCString
& aKey
, const Flags
& aFlags
,
90 int32_t aDefaultValue
, int32_t aUserValue
) {
92 if (aFlags
.mHasUserValue
) {
93 index
= mIntValueTable
.Add(aDefaultValue
, aUserValue
);
95 index
= mIntValueTable
.Add(aDefaultValue
);
98 mEntries
.AppendElement(Entry
{
102 uint8_t(PrefType::Int
),
103 aFlags
.mHasDefaultValue
,
104 aFlags
.mHasUserValue
,
108 aFlags
.mIsSkippedByIteration
,
112 void SharedPrefMapBuilder::Add(const nsCString
& aKey
, const Flags
& aFlags
,
113 const nsCString
& aDefaultValue
,
114 const nsCString
& aUserValue
) {
116 StringTableEntry defaultVal
= mValueStringTable
.Add(aDefaultValue
);
117 if (aFlags
.mHasUserValue
) {
118 StringTableEntry userVal
= mValueStringTable
.Add(aUserValue
);
119 index
= mStringValueTable
.Add(defaultVal
, userVal
);
121 index
= mStringValueTable
.Add(defaultVal
);
124 mEntries
.AppendElement(Entry
{
128 uint8_t(PrefType::String
),
129 aFlags
.mHasDefaultValue
,
130 aFlags
.mHasUserValue
,
134 aFlags
.mIsSkippedByIteration
,
138 Result
<Ok
, nsresult
> SharedPrefMapBuilder::Finalize(loader::AutoMemMap
& aMap
) {
139 using Header
= SharedPrefMap::Header
;
141 // Create an array of entry pointers for the entry array, and sort it by
142 // preference name prior to serialization, so that entries can be looked up
143 // using binary search.
144 nsTArray
<Entry
*> entries(mEntries
.Length());
145 for (auto& entry
: mEntries
) {
146 entries
.AppendElement(&entry
);
148 entries
.Sort([](const Entry
* aA
, const Entry
* aB
) {
149 return strcmp(aA
->mKeyString
, aB
->mKeyString
);
152 Header header
= {uint32_t(entries
.Length())};
154 size_t offset
= sizeof(header
);
155 offset
+= GetAlignmentOffset(offset
, alignof(Header
));
157 offset
+= entries
.Length() * sizeof(SharedPrefMap::Entry
);
159 header
.mKeyStrings
.mOffset
= offset
;
160 header
.mKeyStrings
.mSize
= mKeyTable
.Size();
161 offset
+= header
.mKeyStrings
.mSize
;
163 offset
+= GetAlignmentOffset(offset
, mIntValueTable
.Alignment());
164 header
.mUserIntValues
.mOffset
= offset
;
165 header
.mUserIntValues
.mSize
= mIntValueTable
.UserSize();
166 offset
+= header
.mUserIntValues
.mSize
;
168 offset
+= GetAlignmentOffset(offset
, mIntValueTable
.Alignment());
169 header
.mDefaultIntValues
.mOffset
= offset
;
170 header
.mDefaultIntValues
.mSize
= mIntValueTable
.DefaultSize();
171 offset
+= header
.mDefaultIntValues
.mSize
;
173 offset
+= GetAlignmentOffset(offset
, mStringValueTable
.Alignment());
174 header
.mUserStringValues
.mOffset
= offset
;
175 header
.mUserStringValues
.mSize
= mStringValueTable
.UserSize();
176 offset
+= header
.mUserStringValues
.mSize
;
178 offset
+= GetAlignmentOffset(offset
, mStringValueTable
.Alignment());
179 header
.mDefaultStringValues
.mOffset
= offset
;
180 header
.mDefaultStringValues
.mSize
= mStringValueTable
.DefaultSize();
181 offset
+= header
.mDefaultStringValues
.mSize
;
183 header
.mValueStrings
.mOffset
= offset
;
184 header
.mValueStrings
.mSize
= mValueStringTable
.Size();
185 offset
+= header
.mValueStrings
.mSize
;
188 MOZ_TRY(mem
.Init(offset
));
190 auto headerPtr
= mem
.Get
<Header
>();
191 headerPtr
[0] = header
;
193 auto* entryPtr
= reinterpret_cast<SharedPrefMap::Entry
*>(&headerPtr
[1]);
194 for (auto* entry
: entries
) {
199 entry
->mHasDefaultValue
,
200 entry
->mHasUserValue
,
204 entry
->mIsSkippedByIteration
,
209 auto ptr
= mem
.Get
<uint8_t>();
211 mKeyTable
.Write({&ptr
[header
.mKeyStrings
.mOffset
], header
.mKeyStrings
.mSize
});
213 mValueStringTable
.Write(
214 {&ptr
[header
.mValueStrings
.mOffset
], header
.mValueStrings
.mSize
});
216 mIntValueTable
.WriteDefaultValues(
217 {&ptr
[header
.mDefaultIntValues
.mOffset
], header
.mDefaultIntValues
.mSize
});
218 mIntValueTable
.WriteUserValues(
219 {&ptr
[header
.mUserIntValues
.mOffset
], header
.mUserIntValues
.mSize
});
221 mStringValueTable
.WriteDefaultValues(
222 {&ptr
[header
.mDefaultStringValues
.mOffset
],
223 header
.mDefaultStringValues
.mSize
});
224 mStringValueTable
.WriteUserValues(
225 {&ptr
[header
.mUserStringValues
.mOffset
], header
.mUserStringValues
.mSize
});
228 mValueStringTable
.Clear();
229 mIntValueTable
.Clear();
230 mStringValueTable
.Clear();
233 return mem
.Finalize(aMap
);
236 } // namespace mozilla