142 lines
4.1 KiB
C++
142 lines
4.1 KiB
C++
/* -*- 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
|