michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef jit_IonAllocPolicy_h michael@0: #define jit_IonAllocPolicy_h michael@0: michael@0: #include "mozilla/GuardObjects.h" michael@0: #include "mozilla/TypeTraits.h" michael@0: michael@0: #include "jscntxt.h" michael@0: michael@0: #include "ds/LifoAlloc.h" michael@0: #include "jit/InlineList.h" michael@0: #include "jit/Ion.h" michael@0: michael@0: namespace js { michael@0: namespace jit { michael@0: michael@0: class TempAllocator michael@0: { michael@0: LifoAllocScope lifoScope_; michael@0: michael@0: // Linked list of GCThings rooted by this allocator. michael@0: CompilerRootNode *rootList_; michael@0: michael@0: public: michael@0: TempAllocator(LifoAlloc *lifoAlloc) michael@0: : lifoScope_(lifoAlloc), michael@0: rootList_(nullptr) michael@0: { } michael@0: michael@0: void *allocateOrCrash(size_t bytes) michael@0: { michael@0: void *p = lifoScope_.alloc().alloc(bytes); michael@0: if (!p) michael@0: js::CrashAtUnhandlableOOM("LifoAlloc::allocOrCrash"); michael@0: return p; michael@0: } michael@0: michael@0: void *allocate(size_t bytes) michael@0: { michael@0: void *p = lifoScope_.alloc().alloc(bytes); michael@0: if (!ensureBallast()) michael@0: return nullptr; michael@0: return p; michael@0: } michael@0: michael@0: template michael@0: void *allocateArray(size_t n) michael@0: { michael@0: if (n & mozilla::tl::MulOverflowMask::value) michael@0: return nullptr; michael@0: void *p = lifoScope_.alloc().alloc(n * ElemSize); michael@0: if (!ensureBallast()) michael@0: return nullptr; michael@0: return p; michael@0: } michael@0: michael@0: LifoAlloc *lifoAlloc() michael@0: { michael@0: return &lifoScope_.alloc(); michael@0: } michael@0: michael@0: CompilerRootNode *&rootList() michael@0: { michael@0: return rootList_; michael@0: } michael@0: michael@0: bool ensureBallast() { michael@0: // Most infallible Ion allocations are small, so we use a ballast of michael@0: // ~16K for now. michael@0: return lifoScope_.alloc().ensureUnusedApproximate(16 * 1024); michael@0: } michael@0: }; michael@0: michael@0: // Stack allocated rooter for all roots associated with a TempAllocator michael@0: class AutoTempAllocatorRooter : private AutoGCRooter michael@0: { michael@0: public: michael@0: explicit AutoTempAllocatorRooter(JSContext *cx, TempAllocator *temp michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : AutoGCRooter(cx, IONALLOC), temp(temp) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: } michael@0: michael@0: friend void AutoGCRooter::trace(JSTracer *trc); michael@0: void trace(JSTracer *trc); michael@0: michael@0: private: michael@0: TempAllocator *temp; michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: }; michael@0: michael@0: class IonAllocPolicy michael@0: { michael@0: TempAllocator &alloc_; michael@0: michael@0: public: michael@0: IonAllocPolicy(TempAllocator &alloc) michael@0: : alloc_(alloc) michael@0: {} michael@0: void *malloc_(size_t bytes) { michael@0: return alloc_.allocate(bytes); michael@0: } michael@0: void *calloc_(size_t bytes) { michael@0: void *p = alloc_.allocate(bytes); michael@0: if (p) michael@0: memset(p, 0, bytes); michael@0: return p; michael@0: } michael@0: void *realloc_(void *p, size_t oldBytes, size_t bytes) { michael@0: void *n = malloc_(bytes); michael@0: if (!n) michael@0: return n; michael@0: memcpy(n, p, Min(oldBytes, bytes)); michael@0: return n; michael@0: } michael@0: void free_(void *p) { michael@0: } michael@0: void reportAllocOverflow() const { michael@0: } michael@0: }; michael@0: michael@0: // Deprecated. Don't use this. Will be removed after everything has been michael@0: // converted to IonAllocPolicy. michael@0: class OldIonAllocPolicy michael@0: { michael@0: public: michael@0: OldIonAllocPolicy() michael@0: {} michael@0: void *malloc_(size_t bytes) { michael@0: return GetIonContext()->temp->allocate(bytes); michael@0: } michael@0: void *calloc_(size_t bytes) { michael@0: void *p = GetIonContext()->temp->allocate(bytes); michael@0: if (p) michael@0: memset(p, 0, bytes); michael@0: return p; michael@0: } michael@0: void *realloc_(void *p, size_t oldBytes, size_t bytes) { michael@0: void *n = malloc_(bytes); michael@0: if (!n) michael@0: return n; michael@0: memcpy(n, p, Min(oldBytes, bytes)); michael@0: return n; michael@0: } michael@0: void free_(void *p) { michael@0: } michael@0: void reportAllocOverflow() const { michael@0: } michael@0: }; michael@0: michael@0: class AutoIonContextAlloc michael@0: { michael@0: TempAllocator tempAlloc_; michael@0: IonContext *icx_; michael@0: TempAllocator *prevAlloc_; michael@0: michael@0: public: michael@0: explicit AutoIonContextAlloc(JSContext *cx) michael@0: : tempAlloc_(&cx->tempLifoAlloc()), michael@0: icx_(GetIonContext()), michael@0: prevAlloc_(icx_->temp) michael@0: { michael@0: icx_->temp = &tempAlloc_; michael@0: } michael@0: michael@0: ~AutoIonContextAlloc() { michael@0: JS_ASSERT(icx_->temp == &tempAlloc_); michael@0: icx_->temp = prevAlloc_; michael@0: } michael@0: }; michael@0: michael@0: struct TempObject michael@0: { michael@0: inline void *operator new(size_t nbytes, TempAllocator &alloc) { michael@0: return alloc.allocateOrCrash(nbytes); michael@0: } michael@0: template michael@0: inline void *operator new(size_t nbytes, T *pos) { michael@0: static_assert(mozilla::IsConvertible::value, michael@0: "Placement new argument type must inherit from TempObject"); michael@0: return pos; michael@0: } michael@0: }; michael@0: michael@0: template michael@0: class TempObjectPool michael@0: { michael@0: TempAllocator *alloc_; michael@0: InlineForwardList freed_; michael@0: michael@0: public: michael@0: TempObjectPool() michael@0: : alloc_(nullptr) michael@0: {} michael@0: void setAllocator(TempAllocator &alloc) { michael@0: JS_ASSERT(freed_.empty()); michael@0: alloc_ = &alloc; michael@0: } michael@0: T *allocate() { michael@0: JS_ASSERT(alloc_); michael@0: if (freed_.empty()) michael@0: return new(*alloc_) T(); michael@0: return freed_.popFront(); michael@0: } michael@0: void free(T *obj) { michael@0: freed_.pushFront(obj); michael@0: } michael@0: void clear() { michael@0: freed_.clear(); michael@0: } michael@0: }; michael@0: michael@0: } // namespace jit michael@0: } // namespace js michael@0: michael@0: #endif /* jit_IonAllocPolicy_h */