diff options
Diffstat (limited to '')
-rw-r--r-- | modules/libpref/SharedPrefMap.cpp | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/modules/libpref/SharedPrefMap.cpp b/modules/libpref/SharedPrefMap.cpp new file mode 100644 index 0000000000..7782ffdcbf --- /dev/null +++ b/modules/libpref/SharedPrefMap.cpp @@ -0,0 +1,237 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SharedPrefMap.h" + +#include "mozilla/dom/ipc/MemMapSnapshot.h" + +#include "mozilla/BinarySearch.h" +#include "mozilla/ResultExtensions.h" +#include "mozilla/Try.h" +#include "mozilla/ipc/FileDescriptor.h" + +using namespace mozilla::loader; + +namespace mozilla { + +using namespace ipc; + +static inline size_t GetAlignmentOffset(size_t aOffset, size_t aAlign) { + auto mod = aOffset % aAlign; + return mod ? aAlign - mod : 0; +} + +SharedPrefMap::SharedPrefMap(const FileDescriptor& aMapFile, size_t aMapSize) { + auto result = mMap.initWithHandle(aMapFile, aMapSize); + MOZ_RELEASE_ASSERT(result.isOk()); + // We return literal nsCStrings pointing to the mapped data for preference + // names and string values, which means that we may still have references to + // the mapped data even after this instance is destroyed. That means that we + // need to keep the mapping alive until process shutdown, in order to be safe. + mMap.setPersistent(); +} + +SharedPrefMap::SharedPrefMap(SharedPrefMapBuilder&& aBuilder) { + auto result = aBuilder.Finalize(mMap); + MOZ_RELEASE_ASSERT(result.isOk()); + mMap.setPersistent(); +} + +mozilla::ipc::FileDescriptor SharedPrefMap::CloneFileDescriptor() const { + return mMap.cloneHandle(); +} + +bool SharedPrefMap::Has(const char* aKey) const { + size_t index; + return Find(aKey, &index); +} + +Maybe<const SharedPrefMap::Pref> SharedPrefMap::Get(const char* aKey) const { + Maybe<const Pref> result; + + size_t index; + if (Find(aKey, &index)) { + result.emplace(Pref{this, &Entries()[index]}); + } + + return result; +} + +bool SharedPrefMap::Find(const char* aKey, size_t* aIndex) const { + const auto& keys = KeyTable(); + + return BinarySearchIf( + Entries(), 0, EntryCount(), + [&](const Entry& aEntry) { + return strcmp(aKey, keys.GetBare(aEntry.mKey)); + }, + aIndex); +} + +void SharedPrefMapBuilder::Add(const nsCString& aKey, const Flags& aFlags, + bool aDefaultValue, bool aUserValue) { + mEntries.AppendElement(Entry{ + aKey.get(), + mKeyTable.Add(aKey), + {aDefaultValue, aUserValue}, + uint8_t(PrefType::Bool), + aFlags.mHasDefaultValue, + aFlags.mHasUserValue, + aFlags.mIsSticky, + aFlags.mIsLocked, + aFlags.mIsSanitized, + aFlags.mIsSkippedByIteration, + }); +} + +void SharedPrefMapBuilder::Add(const nsCString& aKey, const Flags& aFlags, + int32_t aDefaultValue, int32_t aUserValue) { + ValueIdx index; + if (aFlags.mHasUserValue) { + index = mIntValueTable.Add(aDefaultValue, aUserValue); + } else { + index = mIntValueTable.Add(aDefaultValue); + } + + mEntries.AppendElement(Entry{ + aKey.get(), + mKeyTable.Add(aKey), + {index}, + uint8_t(PrefType::Int), + aFlags.mHasDefaultValue, + aFlags.mHasUserValue, + aFlags.mIsSticky, + aFlags.mIsLocked, + aFlags.mIsSanitized, + aFlags.mIsSkippedByIteration, + }); +} + +void SharedPrefMapBuilder::Add(const nsCString& aKey, const Flags& aFlags, + const nsCString& aDefaultValue, + const nsCString& aUserValue) { + ValueIdx index; + StringTableEntry defaultVal = mValueStringTable.Add(aDefaultValue); + if (aFlags.mHasUserValue) { + StringTableEntry userVal = mValueStringTable.Add(aUserValue); + index = mStringValueTable.Add(defaultVal, userVal); + } else { + index = mStringValueTable.Add(defaultVal); + } + + mEntries.AppendElement(Entry{ + aKey.get(), + mKeyTable.Add(aKey), + {index}, + uint8_t(PrefType::String), + aFlags.mHasDefaultValue, + aFlags.mHasUserValue, + aFlags.mIsSticky, + aFlags.mIsLocked, + aFlags.mIsSanitized, + aFlags.mIsSkippedByIteration, + }); +} + +Result<Ok, nsresult> SharedPrefMapBuilder::Finalize(loader::AutoMemMap& aMap) { + using Header = SharedPrefMap::Header; + + // Create an array of entry pointers for the entry array, and sort it by + // preference name prior to serialization, so that entries can be looked up + // using binary search. + nsTArray<Entry*> entries(mEntries.Length()); + for (auto& entry : mEntries) { + entries.AppendElement(&entry); + } + entries.Sort([](const Entry* aA, const Entry* aB) { + return strcmp(aA->mKeyString, aB->mKeyString); + }); + + Header header = {uint32_t(entries.Length())}; + + size_t offset = sizeof(header); + offset += GetAlignmentOffset(offset, alignof(Header)); + + offset += entries.Length() * sizeof(SharedPrefMap::Entry); + + header.mKeyStrings.mOffset = offset; + header.mKeyStrings.mSize = mKeyTable.Size(); + offset += header.mKeyStrings.mSize; + + offset += GetAlignmentOffset(offset, mIntValueTable.Alignment()); + header.mUserIntValues.mOffset = offset; + header.mUserIntValues.mSize = mIntValueTable.UserSize(); + offset += header.mUserIntValues.mSize; + + offset += GetAlignmentOffset(offset, mIntValueTable.Alignment()); + header.mDefaultIntValues.mOffset = offset; + header.mDefaultIntValues.mSize = mIntValueTable.DefaultSize(); + offset += header.mDefaultIntValues.mSize; + + offset += GetAlignmentOffset(offset, mStringValueTable.Alignment()); + header.mUserStringValues.mOffset = offset; + header.mUserStringValues.mSize = mStringValueTable.UserSize(); + offset += header.mUserStringValues.mSize; + + offset += GetAlignmentOffset(offset, mStringValueTable.Alignment()); + header.mDefaultStringValues.mOffset = offset; + header.mDefaultStringValues.mSize = mStringValueTable.DefaultSize(); + offset += header.mDefaultStringValues.mSize; + + header.mValueStrings.mOffset = offset; + header.mValueStrings.mSize = mValueStringTable.Size(); + offset += header.mValueStrings.mSize; + + MemMapSnapshot mem; + MOZ_TRY(mem.Init(offset)); + + auto headerPtr = mem.Get<Header>(); + headerPtr[0] = header; + + auto* entryPtr = reinterpret_cast<SharedPrefMap::Entry*>(&headerPtr[1]); + for (auto* entry : entries) { + *entryPtr = { + entry->mKey, + GetValue(*entry), + entry->mType, + entry->mHasDefaultValue, + entry->mHasUserValue, + entry->mIsSticky, + entry->mIsLocked, + entry->mIsSanitized, + entry->mIsSkippedByIteration, + }; + entryPtr++; + } + + auto ptr = mem.Get<uint8_t>(); + + mKeyTable.Write({&ptr[header.mKeyStrings.mOffset], header.mKeyStrings.mSize}); + + mValueStringTable.Write( + {&ptr[header.mValueStrings.mOffset], header.mValueStrings.mSize}); + + mIntValueTable.WriteDefaultValues( + {&ptr[header.mDefaultIntValues.mOffset], header.mDefaultIntValues.mSize}); + mIntValueTable.WriteUserValues( + {&ptr[header.mUserIntValues.mOffset], header.mUserIntValues.mSize}); + + mStringValueTable.WriteDefaultValues( + {&ptr[header.mDefaultStringValues.mOffset], + header.mDefaultStringValues.mSize}); + mStringValueTable.WriteUserValues( + {&ptr[header.mUserStringValues.mOffset], header.mUserStringValues.mSize}); + + mKeyTable.Clear(); + mValueStringTable.Clear(); + mIntValueTable.Clear(); + mStringValueTable.Clear(); + mEntries.Clear(); + + return mem.Finalize(aMap); +} + +} // namespace mozilla |