/* -*- 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 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 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>& aBounds) : mBase(aBounds ? reinterpret_cast( MMPolicyT::GetLowerBound(aBounds.ref())) : 0), mLimit(aBounds ? reinterpret_cast( 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>()) {} PolicyInfo(const PolicyInfo&) = delete; PolicyInfo& operator=(const PolicyInfo&) = delete; PolicyInfo(PolicyInfo&& aOther) = default; PolicyInfo& operator=(PolicyInfo&& aOther) = default; VMSharingPolicyUnique* GetPolicy() { return mPolicy.get(); } private: UniquePtr> mPolicy; }; using VectorType = Vector; public: constexpr RangeMap() : mPolicies(nullptr) {} VMSharingPolicyUnique* GetPolicy( const Maybe>& 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* GetFirstPolicy() { MOZ_RELEASE_ASSERT(mPolicies && !mPolicies->empty()); return mPolicies->begin()->GetPolicy(); } private: VectorType* mPolicies; }; } // namespace interceptor } // namespace mozilla #endif // mozilla_interceptor_RangeMap_h