/src/mozilla-central/modules/libpref/SharedPrefMap.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* vim: set ts=8 sts=4 et sw=4 tw=99: */ |
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 "SharedPrefMap.h" |
8 | | |
9 | | #include "mozilla/dom/ipc/MemMapSnapshot.h" |
10 | | |
11 | | #include "mozilla/BinarySearch.h" |
12 | | #include "mozilla/ResultExtensions.h" |
13 | | #include "mozilla/ipc/FileDescriptor.h" |
14 | | |
15 | | using namespace mozilla::loader; |
16 | | |
17 | | namespace mozilla { |
18 | | |
19 | | using namespace ipc; |
20 | | |
21 | | static inline size_t |
22 | | GetAlignmentOffset(size_t aOffset, size_t aAlign) |
23 | 0 | { |
24 | 0 | auto mod = aOffset % aAlign; |
25 | 0 | return mod ? aAlign - mod : 0; |
26 | 0 | } |
27 | | |
28 | | SharedPrefMap::SharedPrefMap(const FileDescriptor& aMapFile, size_t aMapSize) |
29 | 0 | { |
30 | 0 | auto result = mMap.initWithHandle(aMapFile, aMapSize); |
31 | 0 | MOZ_RELEASE_ASSERT(result.isOk()); |
32 | 0 | // We return literal nsCStrings pointing to the mapped data for preference |
33 | 0 | // names and string values, which means that we may still have references to |
34 | 0 | // the mapped data even after this instance is destroyed. That means that we |
35 | 0 | // need to keep the mapping alive until process shutdown, in order to be safe. |
36 | 0 | mMap.setPersistent(); |
37 | 0 | } |
38 | | |
39 | | SharedPrefMap::SharedPrefMap(SharedPrefMapBuilder&& aBuilder) |
40 | 0 | { |
41 | 0 | auto result = aBuilder.Finalize(mMap); |
42 | 0 | MOZ_RELEASE_ASSERT(result.isOk()); |
43 | 0 | mMap.setPersistent(); |
44 | 0 | } |
45 | | |
46 | | mozilla::ipc::FileDescriptor |
47 | | SharedPrefMap::CloneFileDescriptor() const |
48 | 0 | { |
49 | 0 | return mMap.cloneHandle(); |
50 | 0 | } |
51 | | |
52 | | bool |
53 | | SharedPrefMap::Has(const char* aKey) const |
54 | 0 | { |
55 | 0 | size_t index; |
56 | 0 | return Find(aKey, &index); |
57 | 0 | } |
58 | | |
59 | | Maybe<const SharedPrefMap::Pref> |
60 | | SharedPrefMap::Get(const char* aKey) const |
61 | 0 | { |
62 | 0 | Maybe<const Pref> result; |
63 | 0 |
|
64 | 0 | size_t index; |
65 | 0 | if (Find(aKey, &index)) { |
66 | 0 | result.emplace(Pref{ this, &Entries()[index] }); |
67 | 0 | } |
68 | 0 |
|
69 | 0 | return result; |
70 | 0 | } |
71 | | |
72 | | bool |
73 | | SharedPrefMap::Find(const char* aKey, size_t* aIndex) const |
74 | 0 | { |
75 | 0 | const auto& keys = KeyTable(); |
76 | 0 |
|
77 | 0 | return BinarySearchIf(Entries(), |
78 | 0 | 0, |
79 | 0 | EntryCount(), |
80 | 0 | [&](const Entry& aEntry) { |
81 | 0 | return strcmp(aKey, keys.GetBare(aEntry.mKey)); |
82 | 0 | }, |
83 | 0 | aIndex); |
84 | 0 | } |
85 | | |
86 | | void |
87 | | SharedPrefMapBuilder::Add(const char* aKey, |
88 | | const Flags& aFlags, |
89 | | bool aDefaultValue, |
90 | | bool aUserValue) |
91 | 0 | { |
92 | 0 | mEntries.AppendElement(Entry{ |
93 | 0 | aKey, |
94 | 0 | mKeyTable.Add(aKey), |
95 | 0 | { aDefaultValue, aUserValue }, |
96 | 0 | uint8_t(PrefType::Bool), |
97 | 0 | aFlags.mHasDefaultValue, |
98 | 0 | aFlags.mHasUserValue, |
99 | 0 | aFlags.mIsSticky, |
100 | 0 | aFlags.mIsLocked, |
101 | 0 | aFlags.mDefaultChanged, |
102 | 0 | }); |
103 | 0 | } |
104 | | |
105 | | void |
106 | | SharedPrefMapBuilder::Add(const char* aKey, |
107 | | const Flags& aFlags, |
108 | | int32_t aDefaultValue, |
109 | | int32_t aUserValue) |
110 | 0 | { |
111 | 0 | ValueIdx index; |
112 | 0 | if (aFlags.mHasUserValue) { |
113 | 0 | index = mIntValueTable.Add(aDefaultValue, aUserValue); |
114 | 0 | } else { |
115 | 0 | index = mIntValueTable.Add(aDefaultValue); |
116 | 0 | } |
117 | 0 |
|
118 | 0 | mEntries.AppendElement(Entry{ |
119 | 0 | aKey, |
120 | 0 | mKeyTable.Add(aKey), |
121 | 0 | { index }, |
122 | 0 | uint8_t(PrefType::Int), |
123 | 0 | aFlags.mHasDefaultValue, |
124 | 0 | aFlags.mHasUserValue, |
125 | 0 | aFlags.mIsSticky, |
126 | 0 | aFlags.mIsLocked, |
127 | 0 | aFlags.mDefaultChanged, |
128 | 0 | }); |
129 | 0 | } |
130 | | |
131 | | void |
132 | | SharedPrefMapBuilder::Add(const char* aKey, |
133 | | const Flags& aFlags, |
134 | | const nsCString& aDefaultValue, |
135 | | const nsCString& aUserValue) |
136 | 0 | { |
137 | 0 | ValueIdx index; |
138 | 0 | StringTableEntry defaultVal = mValueStringTable.Add(aDefaultValue); |
139 | 0 | if (aFlags.mHasUserValue) { |
140 | 0 | StringTableEntry userVal = mValueStringTable.Add(aUserValue); |
141 | 0 | index = mStringValueTable.Add(defaultVal, userVal); |
142 | 0 | } else { |
143 | 0 | index = mStringValueTable.Add(defaultVal); |
144 | 0 | } |
145 | 0 |
|
146 | 0 | mEntries.AppendElement(Entry{ |
147 | 0 | aKey, |
148 | 0 | mKeyTable.Add(aKey), |
149 | 0 | { index }, |
150 | 0 | uint8_t(PrefType::String), |
151 | 0 | aFlags.mHasDefaultValue, |
152 | 0 | aFlags.mHasUserValue, |
153 | 0 | aFlags.mIsSticky, |
154 | 0 | aFlags.mIsLocked, |
155 | 0 | aFlags.mDefaultChanged, |
156 | 0 | }); |
157 | 0 | } |
158 | | |
159 | | Result<Ok, nsresult> |
160 | | SharedPrefMapBuilder::Finalize(loader::AutoMemMap& aMap) |
161 | 0 | { |
162 | 0 | using Header = SharedPrefMap::Header; |
163 | 0 |
|
164 | 0 | // Create an array of entry pointers for the entry array, and sort it by |
165 | 0 | // preference name prior to serialization, so that entries can be looked up |
166 | 0 | // using binary search. |
167 | 0 | nsTArray<Entry*> entries(mEntries.Length()); |
168 | 0 | for (auto& entry : mEntries) { |
169 | 0 | entries.AppendElement(&entry); |
170 | 0 | } |
171 | 0 | entries.Sort([](const Entry* aA, const Entry* aB) { |
172 | 0 | return strcmp(aA->mKeyString, aB->mKeyString); |
173 | 0 | }); |
174 | 0 |
|
175 | 0 | Header header = { uint32_t(entries.Length()) }; |
176 | 0 |
|
177 | 0 | size_t offset = sizeof(header); |
178 | 0 | offset += GetAlignmentOffset(offset, alignof(Header)); |
179 | 0 |
|
180 | 0 | offset += entries.Length() * sizeof(SharedPrefMap::Entry); |
181 | 0 |
|
182 | 0 | header.mKeyStrings.mOffset = offset; |
183 | 0 | header.mKeyStrings.mSize = mKeyTable.Size(); |
184 | 0 | offset += header.mKeyStrings.mSize; |
185 | 0 |
|
186 | 0 | offset += GetAlignmentOffset(offset, mIntValueTable.Alignment()); |
187 | 0 | header.mUserIntValues.mOffset = offset; |
188 | 0 | header.mUserIntValues.mSize = mIntValueTable.UserSize(); |
189 | 0 | offset += header.mUserIntValues.mSize; |
190 | 0 |
|
191 | 0 | offset += GetAlignmentOffset(offset, mIntValueTable.Alignment()); |
192 | 0 | header.mDefaultIntValues.mOffset = offset; |
193 | 0 | header.mDefaultIntValues.mSize = mIntValueTable.DefaultSize(); |
194 | 0 | offset += header.mDefaultIntValues.mSize; |
195 | 0 |
|
196 | 0 | offset += GetAlignmentOffset(offset, mStringValueTable.Alignment()); |
197 | 0 | header.mUserStringValues.mOffset = offset; |
198 | 0 | header.mUserStringValues.mSize = mStringValueTable.UserSize(); |
199 | 0 | offset += header.mUserStringValues.mSize; |
200 | 0 |
|
201 | 0 | offset += GetAlignmentOffset(offset, mStringValueTable.Alignment()); |
202 | 0 | header.mDefaultStringValues.mOffset = offset; |
203 | 0 | header.mDefaultStringValues.mSize = mStringValueTable.DefaultSize(); |
204 | 0 | offset += header.mDefaultStringValues.mSize; |
205 | 0 |
|
206 | 0 | header.mValueStrings.mOffset = offset; |
207 | 0 | header.mValueStrings.mSize = mValueStringTable.Size(); |
208 | 0 | offset += header.mValueStrings.mSize; |
209 | 0 |
|
210 | 0 | MemMapSnapshot mem; |
211 | 0 | MOZ_TRY(mem.Init(offset)); |
212 | 0 |
|
213 | 0 | auto headerPtr = mem.Get<Header>(); |
214 | 0 | headerPtr[0] = header; |
215 | 0 |
|
216 | 0 | auto* entryPtr = reinterpret_cast<SharedPrefMap::Entry*>(&headerPtr[1]); |
217 | 0 | for (auto* entry : entries) { |
218 | 0 | *entryPtr = { |
219 | 0 | entry->mKey, GetValue(*entry), |
220 | 0 | entry->mType, entry->mHasDefaultValue, |
221 | 0 | entry->mHasUserValue, entry->mIsSticky, |
222 | 0 | entry->mIsLocked, entry->mDefaultChanged, |
223 | 0 | }; |
224 | 0 | entryPtr++; |
225 | 0 | } |
226 | 0 |
|
227 | 0 | auto ptr = mem.Get<uint8_t>(); |
228 | 0 |
|
229 | 0 | mKeyTable.Write( |
230 | 0 | { &ptr[header.mKeyStrings.mOffset], header.mKeyStrings.mSize }); |
231 | 0 |
|
232 | 0 | mValueStringTable.Write( |
233 | 0 | { &ptr[header.mValueStrings.mOffset], header.mValueStrings.mSize }); |
234 | 0 |
|
235 | 0 | mIntValueTable.WriteDefaultValues( |
236 | 0 | { &ptr[header.mDefaultIntValues.mOffset], header.mDefaultIntValues.mSize }); |
237 | 0 | mIntValueTable.WriteUserValues( |
238 | 0 | { &ptr[header.mUserIntValues.mOffset], header.mUserIntValues.mSize }); |
239 | 0 |
|
240 | 0 | mStringValueTable.WriteDefaultValues( |
241 | 0 | { &ptr[header.mDefaultStringValues.mOffset], |
242 | 0 | header.mDefaultStringValues.mSize }); |
243 | 0 | mStringValueTable.WriteUserValues( |
244 | 0 | { &ptr[header.mUserStringValues.mOffset], header.mUserStringValues.mSize }); |
245 | 0 |
|
246 | 0 | mKeyTable.Clear(); |
247 | 0 | mValueStringTable.Clear(); |
248 | 0 | mIntValueTable.Clear(); |
249 | 0 | mStringValueTable.Clear(); |
250 | 0 | mEntries.Clear(); |
251 | 0 |
|
252 | 0 | return mem.Finalize(aMap); |
253 | 0 | } |
254 | | |
255 | | } // mozilla |