diff options
Diffstat (limited to 'src/heap.cpp')
| -rw-r--r-- | src/heap.cpp | 315 |
1 files changed, 0 insertions, 315 deletions
diff --git a/src/heap.cpp b/src/heap.cpp deleted file mode 100644 index 7e7a171bde..0000000000 --- a/src/heap.cpp +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (c) 2020 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include <new> -#include <string.h> - -#include "config.h" -#include "heap.hpp" - -namespace heap { - -extern mem::Allocator &bootstrap_allocator; - -// -// BootstrapAllocator implementation is identical to CAllocator minus -// profile profile functionality. Splitting off to a base interface doesn't -// seem worthwhile. -// - -void BootstrapAllocator::init(const char *name) {} -void BootstrapAllocator::deinit() {} - -void *BootstrapAllocator::internal_allocate(const mem::TypeInfo &info, size_t count) { - return mem::os::calloc(count, info.size); -} - -void *BootstrapAllocator::internal_allocate_nonzero(const mem::TypeInfo &info, size_t count) { - return mem::os::malloc(count * info.size); -} - -void *BootstrapAllocator::internal_reallocate(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) { - auto new_ptr = this->internal_reallocate_nonzero(info, old_ptr, old_count, new_count); - if (new_count > old_count) - memset(reinterpret_cast<uint8_t *>(new_ptr) + (old_count * info.size), 0, (new_count - old_count) * info.size); - return new_ptr; -} - -void *BootstrapAllocator::internal_reallocate_nonzero(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) { - return mem::os::realloc(old_ptr, new_count * info.size); -} - -void BootstrapAllocator::internal_deallocate(const mem::TypeInfo &info, void *ptr, size_t count) { - mem::os::free(ptr); -} - -void CAllocator::init(const char *name) { } - -void CAllocator::deinit() { } - -CAllocator *CAllocator::construct(mem::Allocator *allocator, const char *name) { - auto p = new(allocator->create<CAllocator>()) CAllocator(); - p->init(name); - return p; -} - -void CAllocator::destruct(mem::Allocator *allocator) { - this->deinit(); - allocator->destroy(this); -} - -void *CAllocator::internal_allocate(const mem::TypeInfo &info, size_t count) { - return mem::os::calloc(count, info.size); -} - -void *CAllocator::internal_allocate_nonzero(const mem::TypeInfo &info, size_t count) { - return mem::os::malloc(count * info.size); -} - -void *CAllocator::internal_reallocate(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) { - auto new_ptr = this->internal_reallocate_nonzero(info, old_ptr, old_count, new_count); - if (new_count > old_count) - memset(reinterpret_cast<uint8_t *>(new_ptr) + (old_count * info.size), 0, (new_count - old_count) * info.size); - return new_ptr; -} - -void *CAllocator::internal_reallocate_nonzero(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) { - return mem::os::realloc(old_ptr, new_count * info.size); -} - -void CAllocator::internal_deallocate(const mem::TypeInfo &info, void *ptr, size_t count) { - mem::os::free(ptr); -} - -struct ArenaAllocator::Impl { - Allocator *backing; - - // regular allocations bump through a segment of static size - struct Segment { - static constexpr size_t size = 65536; - static constexpr size_t object_threshold = 4096; - - uint8_t data[size]; - }; - - // active segment - Segment *segment; - size_t segment_offset; - - // keep track of segments - struct SegmentTrack { - static constexpr size_t size = (4096 - sizeof(SegmentTrack *)) / sizeof(Segment *); - - // null if first - SegmentTrack *prev; - Segment *segments[size]; - }; - static_assert(sizeof(SegmentTrack) <= 4096, "unwanted struct padding"); - - // active segment track - SegmentTrack *segment_track; - size_t segment_track_remain; - - // individual allocations punted to backing allocator - struct Object { - uint8_t *ptr; - size_t len; - }; - - // keep track of objects - struct ObjectTrack { - static constexpr size_t size = (4096 - sizeof(ObjectTrack *)) / sizeof(Object); - - // null if first - ObjectTrack *prev; - Object objects[size]; - }; - static_assert(sizeof(ObjectTrack) <= 4096, "unwanted struct padding"); - - // active object track - ObjectTrack *object_track; - size_t object_track_remain; - - ATTRIBUTE_RETURNS_NOALIAS inline void *allocate(const mem::TypeInfo& info, size_t count); - inline void *reallocate(const mem::TypeInfo& info, void *old_ptr, size_t old_count, size_t new_count); - - inline void new_segment(); - inline void track_segment(); - inline void track_object(Object object); -}; - -void *ArenaAllocator::Impl::allocate(const mem::TypeInfo& info, size_t count) { -#ifndef NDEBUG - // make behavior when size == 0 portable - if (info.size == 0 || count == 0) - return nullptr; -#endif - const size_t nbytes = info.size * count; - this->segment_offset = (this->segment_offset + (info.alignment - 1)) & ~(info.alignment - 1); - if (nbytes >= Segment::object_threshold) { - auto ptr = this->backing->allocate<uint8_t>(nbytes); - this->track_object({ptr, nbytes}); - return ptr; - } - if (this->segment_offset + nbytes > Segment::size) - this->new_segment(); - auto ptr = &this->segment->data[this->segment_offset]; - this->segment_offset += nbytes; - return ptr; -} - -void *ArenaAllocator::Impl::reallocate(const mem::TypeInfo& info, void *old_ptr, size_t old_count, size_t new_count) { -#ifndef NDEBUG - // make behavior when size == 0 portable - if (info.size == 0 && old_ptr == nullptr) - return nullptr; -#endif - const size_t new_nbytes = info.size * new_count; - if (new_nbytes <= info.size * old_count) - return old_ptr; - const size_t old_nbytes = info.size * old_count; - this->segment_offset = (this->segment_offset + (info.alignment - 1)) & ~(info.alignment - 1); - if (new_nbytes >= Segment::object_threshold) { - auto new_ptr = this->backing->allocate<uint8_t>(new_nbytes); - this->track_object({new_ptr, new_nbytes}); - memcpy(new_ptr, old_ptr, old_nbytes); - return new_ptr; - } - if (this->segment_offset + new_nbytes > Segment::size) - this->new_segment(); - auto new_ptr = &this->segment->data[this->segment_offset]; - this->segment_offset += new_nbytes; - memcpy(new_ptr, old_ptr, old_nbytes); - return new_ptr; -} - -void ArenaAllocator::Impl::new_segment() { - this->segment = this->backing->create<Segment>(); - this->segment_offset = 0; - this->track_segment(); -} - -void ArenaAllocator::Impl::track_segment() { - assert(this->segment != nullptr); - if (this->segment_track_remain < 1) { - auto prev = this->segment_track; - this->segment_track = this->backing->create<SegmentTrack>(); - this->segment_track->prev = prev; - this->segment_track_remain = SegmentTrack::size; - } - this->segment_track_remain -= 1; - this->segment_track->segments[this->segment_track_remain] = this->segment; -} - -void ArenaAllocator::Impl::track_object(Object object) { - if (this->object_track_remain < 1) { - auto prev = this->object_track; - this->object_track = this->backing->create<ObjectTrack>(); - this->object_track->prev = prev; - this->object_track_remain = ObjectTrack::size; - } - this->object_track_remain -= 1; - this->object_track->objects[this->object_track_remain] = object; -} - -void ArenaAllocator::init(Allocator *backing, const char *name) { - this->impl = bootstrap_allocator.create<Impl>(); - { - auto &r = *this->impl; - r.backing = backing; - r.segment_offset = Impl::Segment::size; - } -} - -void ArenaAllocator::deinit() { - auto &backing = *this->impl->backing; - - // segments - if (this->impl->segment_track) { - // active track is not full and bounded by track_remain - auto prev = this->impl->segment_track->prev; - { - auto t = this->impl->segment_track; - for (size_t i = this->impl->segment_track_remain; i < Impl::SegmentTrack::size; ++i) - backing.destroy(t->segments[i]); - backing.destroy(t); - } - - // previous tracks are full - for (auto t = prev; t != nullptr;) { - for (size_t i = 0; i < Impl::SegmentTrack::size; ++i) - backing.destroy(t->segments[i]); - prev = t->prev; - backing.destroy(t); - t = prev; - } - } - - // objects - if (this->impl->object_track) { - // active track is not full and bounded by track_remain - auto prev = this->impl->object_track->prev; - { - auto t = this->impl->object_track; - for (size_t i = this->impl->object_track_remain; i < Impl::ObjectTrack::size; ++i) { - auto &obj = t->objects[i]; - backing.deallocate(obj.ptr, obj.len); - } - backing.destroy(t); - } - - // previous tracks are full - for (auto t = prev; t != nullptr;) { - for (size_t i = 0; i < Impl::ObjectTrack::size; ++i) { - auto &obj = t->objects[i]; - backing.deallocate(obj.ptr, obj.len); - } - prev = t->prev; - backing.destroy(t); - t = prev; - } - } -} - -ArenaAllocator *ArenaAllocator::construct(mem::Allocator *allocator, mem::Allocator *backing, const char *name) { - auto p = new(allocator->create<ArenaAllocator>()) ArenaAllocator; - p->init(backing, name); - return p; -} - -void ArenaAllocator::destruct(mem::Allocator *allocator) { - this->deinit(); - allocator->destroy(this); -} - -void *ArenaAllocator::internal_allocate(const mem::TypeInfo &info, size_t count) { - return this->impl->allocate(info, count); -} - -void *ArenaAllocator::internal_allocate_nonzero(const mem::TypeInfo &info, size_t count) { - return this->impl->allocate(info, count); -} - -void *ArenaAllocator::internal_reallocate(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) { - return this->internal_reallocate_nonzero(info, old_ptr, old_count, new_count); -} - -void *ArenaAllocator::internal_reallocate_nonzero(const mem::TypeInfo &info, void *old_ptr, size_t old_count, size_t new_count) { - return this->impl->reallocate(info, old_ptr, old_count, new_count); -} - -void ArenaAllocator::internal_deallocate(const mem::TypeInfo &info, void *ptr, size_t count) { - // noop -} - -BootstrapAllocator bootstrap_allocator_state; -mem::Allocator &bootstrap_allocator = bootstrap_allocator_state; - -CAllocator c_allocator_state; -mem::Allocator &c_allocator = c_allocator_state; - -} // namespace heap |
