| /* -*- 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/GuardObjects.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) |
| { } |
| |
| void* allocateInfallible(size_t bytes) |
| { |
| return lifoScope_.alloc().allocInfallibleOrAssert(bytes); |
| } |
| |
| void* allocate(size_t bytes) |
| { |
| void* p = lifoScope_.alloc().alloc(bytes); |
| if (!ensureBallast()) |
| return nullptr; |
| return p; |
| } |
| |
| template <typename T> |
| T* allocateArray(size_t n) |
| { |
| 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; |
| } |
| |
| LifoAlloc* lifoAlloc() |
| { |
| return &lifoScope_.alloc(); |
| } |
| |
| bool ensureBallast() { |
| 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 { |
| } |
| bool checkSimulatedOOM() const { |
| return !js::oom::ShouldFailWithOOM(); |
| } |
| }; |
| |
| class OldJitAllocPolicy |
| { |
| public: |
| OldJitAllocPolicy() |
| {} |
| 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*>(GetJitContext()->temp->allocate(bytes)); |
| } |
| template <typename T> |
| T* pod_malloc(size_t numElems) { |
| return maybe_pod_malloc<T>(numElems); |
| } |
| void free_(void* p) { |
| } |
| void reportAllocOverflow() const { |
| } |
| 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& 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 <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_) T(); |
| return freed_.popFront(); |
| } |
| void free(T* obj) { |
| freed_.pushFront(obj); |
| } |
| void clear() { |
| freed_.clear(); |
| } |
| }; |
| |
| } // namespace jit |
| } // namespace js |
| |
| #endif /* jit_JitAllocPolicy_h */ |