diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /js/src/jit/JitAllocPolicy.h | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/jit/JitAllocPolicy.h')
-rw-r--r-- | js/src/jit/JitAllocPolicy.h | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/js/src/jit/JitAllocPolicy.h b/js/src/jit/JitAllocPolicy.h new file mode 100644 index 0000000000..3980f3f2fb --- /dev/null +++ b/js/src/jit/JitAllocPolicy.h @@ -0,0 +1,179 @@ +/* -*- 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 http://mozilla.org/MPL/2.0/. */ + +#ifndef jit_JitAllocPolicy_h +#define jit_JitAllocPolicy_h + +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/Likely.h" +#include "mozilla/OperatorNewExtensions.h" +#include "mozilla/TemplateLib.h" + +#include <algorithm> +#include <stddef.h> +#include <string.h> +#include <type_traits> +#include <utility> + +#include "ds/LifoAlloc.h" +#include "jit/InlineList.h" +#include "js/Utility.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); + } + + [[nodiscard]] void* allocate(size_t bytes) { + LifoAlloc::AutoFallibleScope fallibleAllocator(lifoAlloc()); + return lifoScope_.alloc().allocEnsureUnused(bytes, BallastSize); + } + + template <typename T> + [[nodiscard]] T* allocateArray(size_t n) { + LifoAlloc::AutoFallibleScope fallibleAllocator(lifoAlloc()); + size_t bytes; + if (MOZ_UNLIKELY(!CalculateAllocSize<T>(n, &bytes))) { + return nullptr; + } + return static_cast<T*>( + lifoScope_.alloc().allocEnsureUnused(bytes, BallastSize)); + } + + // View this allocator as a fallible allocator. + struct Fallible { + TempAllocator& alloc; + }; + Fallible fallible() { return {*this}; } + + LifoAlloc* lifoAlloc() { return &lifoScope_.alloc(); } + + [[nodiscard]] 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, std::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); + } + template <typename T> + void free_(T* p, size_t numElems = 0) {} + void reportAllocOverflow() const {} + [[nodiscard]] bool checkSimulatedOOM() const { + return !js::oom::ShouldFailWithOOM(); + } +}; + +struct TempObject { + inline void* operator new(size_t nbytes, + TempAllocator::Fallible view) noexcept(true) { + 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(std::is_convertible_v<T*, TempObject*>, + "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(std::is_convertible_v<T*, TempObject*>, + "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; + } + template <typename... Args> + T* allocate(Args&&... args) { + MOZ_ASSERT(alloc_); + if (freed_.empty()) { + return new (alloc_->fallible()) T(std::forward<Args>(args)...); + } + T* res = freed_.popFront(); + return new (res) T(std::forward<Args>(args)...); + } + void free(T* obj) { freed_.pushFront(obj); } + void clear() { freed_.clear(); } +}; + +} // namespace jit +} // namespace js + +#endif /* jit_JitAllocPolicy_h */ |