diff options
Diffstat (limited to 'js/src/jit/JitAllocPolicy.h')
-rw-r--r-- | js/src/jit/JitAllocPolicy.h | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/js/src/jit/JitAllocPolicy.h b/js/src/jit/JitAllocPolicy.h new file mode 100644 index 000000000..bf1629290 --- /dev/null +++ b/js/src/jit/JitAllocPolicy.h @@ -0,0 +1,210 @@ +/* -*- 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 */ |