diff options
Diffstat (limited to 'toolkit/xre/dllservices/mozglue/interceptor/RangeMap.h')
-rw-r--r-- | toolkit/xre/dllservices/mozglue/interceptor/RangeMap.h | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/toolkit/xre/dllservices/mozglue/interceptor/RangeMap.h b/toolkit/xre/dllservices/mozglue/interceptor/RangeMap.h new file mode 100644 index 0000000000..d45d031613 --- /dev/null +++ b/toolkit/xre/dllservices/mozglue/interceptor/RangeMap.h @@ -0,0 +1,142 @@ +/* -*- 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 https://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_interceptor_RangeMap_h +#define mozilla_interceptor_RangeMap_h + +#include "mozilla/Attributes.h" +#include "mozilla/Maybe.h" +#include "mozilla/mozalloc.h" +#include "mozilla/Span.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/Vector.h" + +#include <algorithm> + +namespace mozilla { +namespace interceptor { + +/** + * This class maintains a vector of VMSharingPolicyUnique objects, sorted on + * the memory range that is used for reserving each object. + * + * This is used by VMSharingPolicyShared for creating and looking up VM regions + * that are within proximity of the applicable range. + * + * VMSharingPolicyUnique objects managed by this class are reused whenever + * possible. If no range is required, we just return the first available + * policy. + * + * If no range is required and no policies have yet been allocated, we create + * a new one with a null range as a default. + */ +template <typename MMPolicyT> +class RangeMap final { + private: + /** + * This class is used as the comparison key for sorting and insertion. + */ + class Range { + public: + constexpr Range() : mBase(0), mLimit(0) {} + + explicit Range(const Maybe<Span<const uint8_t>>& aBounds) + : mBase(aBounds ? reinterpret_cast<const uintptr_t>( + MMPolicyT::GetLowerBound(aBounds.ref())) + : 0), + mLimit(aBounds ? reinterpret_cast<const uintptr_t>( + MMPolicyT::GetUpperBoundIncl(aBounds.ref())) + : 0) {} + + Range& operator=(const Range&) = default; + Range(const Range&) = default; + Range(Range&&) = default; + Range& operator=(Range&&) = default; + + bool operator<(const Range& aOther) const { + return mBase < aOther.mBase || + (mBase == aOther.mBase && mLimit < aOther.mLimit); + } + + bool Contains(const Range& aOther) const { + return mBase <= aOther.mBase && mLimit >= aOther.mLimit; + } + + private: + uintptr_t mBase; + uintptr_t mLimit; + }; + + class PolicyInfo final : public Range { + public: + explicit PolicyInfo(const Range& aRange) + : Range(aRange), + mPolicy(MakeUnique<VMSharingPolicyUnique<MMPolicyT>>()) {} + + PolicyInfo(const PolicyInfo&) = delete; + PolicyInfo& operator=(const PolicyInfo&) = delete; + + PolicyInfo(PolicyInfo&& aOther) = default; + PolicyInfo& operator=(PolicyInfo&& aOther) = default; + + VMSharingPolicyUnique<MMPolicyT>* GetPolicy() { return mPolicy.get(); } + + private: + UniquePtr<VMSharingPolicyUnique<MMPolicyT>> mPolicy; + }; + + using VectorType = Vector<PolicyInfo, 0, InfallibleAllocPolicy>; + + public: + constexpr RangeMap() : mPolicies(nullptr) {} + + VMSharingPolicyUnique<MMPolicyT>* GetPolicy( + const Maybe<Span<const uint8_t>>& aBounds) { + Range testRange(aBounds); + + if (!mPolicies) { + mPolicies = new VectorType(); + } + + // If no bounds are specified, we just use the first available policy + if (!aBounds) { + if (mPolicies->empty()) { + if (!mPolicies->append(PolicyInfo(testRange))) { + return nullptr; + } + } + + return GetFirstPolicy(); + } + + // mPolicies is sorted, so we search + auto itr = + std::lower_bound(mPolicies->begin(), mPolicies->end(), testRange); + if (itr != mPolicies->end() && itr->Contains(testRange)) { + return itr->GetPolicy(); + } + + itr = mPolicies->insert(itr, PolicyInfo(testRange)); + + MOZ_ASSERT(std::is_sorted(mPolicies->begin(), mPolicies->end())); + + return itr->GetPolicy(); + } + + private: + VMSharingPolicyUnique<MMPolicyT>* GetFirstPolicy() { + MOZ_RELEASE_ASSERT(mPolicies && !mPolicies->empty()); + return mPolicies->begin()->GetPolicy(); + } + + private: + VectorType* mPolicies; +}; + +} // namespace interceptor +} // namespace mozilla + +#endif // mozilla_interceptor_RangeMap_h |