211 lines
5.7 KiB
C++
211 lines
5.7 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
|
* 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/. */
|
|
|
|
#ifndef jit_JitAllocPolicy_h
|
|
#define jit_JitAllocPolicy_h
|
|
|
|
#include "mozilla/Attributes.h"
|
|
#include "mozilla/GuardObjects.h"
|
|
#include "mozilla/OperatorNewExtensions.h"
|
|
#include "mozilla/TypeTraits.h"
|
|
|
|
#include "jscntxt.h"
|
|
|
|
#include "ds/LifoAlloc.h"
|
|
#include "jit/InlineList.h"
|
|
#include "jit/Ion.h"
|
|
|
|
namespace js {
|
|
namespace jit {
|
|
|
|
class TempAllocator
|
|
{
|
|
LifoAllocScope lifoScope_;
|
|
|
|
public:
|
|
// Most infallible JIT allocations are small, so we use a ballast of 16
|
|
// KiB. And with a ballast of 16 KiB, a chunk size of 32 KiB works well,
|
|
// because TempAllocators with a peak allocation size of less than 16 KiB
|
|
// (which is most of them) only have to allocate a single chunk.
|
|
static const size_t BallastSize; // 16 KiB
|
|
static const size_t PreferredLifoChunkSize; // 32 KiB
|
|
|
|
explicit TempAllocator(LifoAlloc* lifoAlloc)
|
|
: lifoScope_(lifoAlloc)
|
|
{
|
|
lifoAlloc->setAsInfallibleByDefault();
|
|
}
|
|
|
|
void* allocateInfallible(size_t bytes)
|
|
{
|
|
return lifoScope_.alloc().allocInfallible(bytes);
|
|
}
|
|
|
|
MOZ_MUST_USE void* allocate(size_t bytes)
|
|
{
|
|
LifoAlloc::AutoFallibleScope fallibleAllocator(lifoAlloc());
|
|
void* p = lifoScope_.alloc().alloc(bytes);
|
|
if (!ensureBallast())
|
|
return nullptr;
|
|
return p;
|
|
}
|
|
|
|
template <typename T>
|
|
MOZ_MUST_USE T* allocateArray(size_t n)
|
|
{
|
|
LifoAlloc::AutoFallibleScope fallibleAllocator(lifoAlloc());
|
|
size_t bytes;
|
|
if (MOZ_UNLIKELY(!CalculateAllocSize<T>(n, &bytes)))
|
|
return nullptr;
|
|
T* p = static_cast<T*>(lifoScope_.alloc().alloc(bytes));
|
|
if (MOZ_UNLIKELY(!ensureBallast()))
|
|
return nullptr;
|
|
return p;
|
|
}
|
|
|
|
// View this allocator as a fallible allocator.
|
|
struct Fallible { TempAllocator& alloc; };
|
|
Fallible fallible() { return { *this }; }
|
|
|
|
LifoAlloc* lifoAlloc() {
|
|
return &lifoScope_.alloc();
|
|
}
|
|
|
|
MOZ_MUST_USE bool ensureBallast() {
|
|
JS_OOM_POSSIBLY_FAIL_BOOL();
|
|
return lifoScope_.alloc().ensureUnusedApproximate(BallastSize);
|
|
}
|
|
};
|
|
|
|
class JitAllocPolicy
|
|
{
|
|
TempAllocator& alloc_;
|
|
|
|
public:
|
|
MOZ_IMPLICIT JitAllocPolicy(TempAllocator& alloc)
|
|
: alloc_(alloc)
|
|
{}
|
|
template <typename T>
|
|
T* maybe_pod_malloc(size_t numElems) {
|
|
size_t bytes;
|
|
if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes)))
|
|
return nullptr;
|
|
return static_cast<T*>(alloc_.allocate(bytes));
|
|
}
|
|
template <typename T>
|
|
T* maybe_pod_calloc(size_t numElems) {
|
|
T* p = maybe_pod_malloc<T>(numElems);
|
|
if (MOZ_LIKELY(p))
|
|
memset(p, 0, numElems * sizeof(T));
|
|
return p;
|
|
}
|
|
template <typename T>
|
|
T* maybe_pod_realloc(T* p, size_t oldSize, size_t newSize) {
|
|
T* n = pod_malloc<T>(newSize);
|
|
if (MOZ_UNLIKELY(!n))
|
|
return n;
|
|
MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value));
|
|
memcpy(n, p, Min(oldSize * sizeof(T), newSize * sizeof(T)));
|
|
return n;
|
|
}
|
|
template <typename T>
|
|
T* pod_malloc(size_t numElems) {
|
|
return maybe_pod_malloc<T>(numElems);
|
|
}
|
|
template <typename T>
|
|
T* pod_calloc(size_t numElems) {
|
|
return maybe_pod_calloc<T>(numElems);
|
|
}
|
|
template <typename T>
|
|
T* pod_realloc(T* ptr, size_t oldSize, size_t newSize) {
|
|
return maybe_pod_realloc<T>(ptr, oldSize, newSize);
|
|
}
|
|
void free_(void* p) {
|
|
}
|
|
void reportAllocOverflow() const {
|
|
}
|
|
MOZ_MUST_USE bool checkSimulatedOOM() const {
|
|
return !js::oom::ShouldFailWithOOM();
|
|
}
|
|
};
|
|
|
|
class AutoJitContextAlloc
|
|
{
|
|
TempAllocator tempAlloc_;
|
|
JitContext* jcx_;
|
|
TempAllocator* prevAlloc_;
|
|
|
|
public:
|
|
explicit AutoJitContextAlloc(JSContext* cx)
|
|
: tempAlloc_(&cx->tempLifoAlloc()),
|
|
jcx_(GetJitContext()),
|
|
prevAlloc_(jcx_->temp)
|
|
{
|
|
jcx_->temp = &tempAlloc_;
|
|
}
|
|
|
|
~AutoJitContextAlloc() {
|
|
MOZ_ASSERT(jcx_->temp == &tempAlloc_);
|
|
jcx_->temp = prevAlloc_;
|
|
}
|
|
};
|
|
|
|
struct TempObject
|
|
{
|
|
inline void* operator new(size_t nbytes, TempAllocator::Fallible view) throw() {
|
|
return view.alloc.allocate(nbytes);
|
|
}
|
|
inline void* operator new(size_t nbytes, TempAllocator& alloc) {
|
|
return alloc.allocateInfallible(nbytes);
|
|
}
|
|
template <class T>
|
|
inline void* operator new(size_t nbytes, T* pos) {
|
|
static_assert(mozilla::IsConvertible<T*, TempObject*>::value,
|
|
"Placement new argument type must inherit from TempObject");
|
|
return pos;
|
|
}
|
|
template <class T>
|
|
inline void* operator new(size_t nbytes, mozilla::NotNullTag, T* pos) {
|
|
static_assert(mozilla::IsConvertible<T*, TempObject*>::value,
|
|
"Placement new argument type must inherit from TempObject");
|
|
MOZ_ASSERT(pos);
|
|
return pos;
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
class TempObjectPool
|
|
{
|
|
TempAllocator* alloc_;
|
|
InlineForwardList<T> freed_;
|
|
|
|
public:
|
|
TempObjectPool()
|
|
: alloc_(nullptr)
|
|
{}
|
|
void setAllocator(TempAllocator& alloc) {
|
|
MOZ_ASSERT(freed_.empty());
|
|
alloc_ = &alloc;
|
|
}
|
|
T* allocate() {
|
|
MOZ_ASSERT(alloc_);
|
|
if (freed_.empty())
|
|
return new(alloc_->fallible()) T();
|
|
return freed_.popFront();
|
|
}
|
|
void free(T* obj) {
|
|
freed_.pushFront(obj);
|
|
}
|
|
void clear() {
|
|
freed_.clear();
|
|
}
|
|
};
|
|
|
|
} // namespace jit
|
|
} // namespace js
|
|
|
|
#endif /* jit_JitAllocPolicy_h */
|