/*++ Copyright (c) 2018 Microsoft Corporation Module Name: sat_allocator.h Abstract: Small object allocator suitable for clauses Author: Nikolaj bjorner (nbjorner) 2018-04-26. Revision History: --*/ #pragma once #include "util/vector.h" #include "util/machine.h" class sat_allocator { static const unsigned CHUNK_SIZE = (1 << 16) - sizeof(char*); static const unsigned SMALL_OBJ_SIZE = 512; static const unsigned MASK = ((1 << PTR_ALIGNMENT) - 1); static const unsigned NUM_FREE = 1 + (SMALL_OBJ_SIZE >> PTR_ALIGNMENT); struct chunk { char * m_curr; char m_data[CHUNK_SIZE]; chunk():m_curr(m_data) {} }; char const * m_id; size_t m_alloc_size; ptr_vector m_chunks; void * m_chunk_ptr; ptr_vector m_free[NUM_FREE]; unsigned align_size(size_t sz) const { return free_slot_id(sz) << PTR_ALIGNMENT; } unsigned free_slot_id(size_t size) const { return (static_cast(size >> PTR_ALIGNMENT) + ((0 != (size & MASK)) ? 1u : 0u)); } public: sat_allocator(char const * id = "unknown"): m_id(id), m_alloc_size(0), m_chunk_ptr(nullptr) {} ~sat_allocator() { reset(); } void reset() { for (chunk * ch : m_chunks) dealloc(ch); m_chunks.reset(); for (unsigned i = 0; i < NUM_FREE; ++i) m_free[i].reset(); m_alloc_size = 0; m_chunk_ptr = nullptr; } void * allocate(size_t size) { m_alloc_size += size; if (size >= SMALL_OBJ_SIZE) { return memory::allocate(size); } unsigned slot_id = free_slot_id(size); if (!m_free[slot_id].empty()) { void* result = m_free[slot_id].back(); m_free[slot_id].pop_back(); return result; } if (m_chunks.empty()) { m_chunks.push_back(alloc(chunk)); m_chunk_ptr = m_chunks.back(); } unsigned sz = align_size(size); if ((char*)m_chunk_ptr + sz > (char*)m_chunks.back() + CHUNK_SIZE) { m_chunks.push_back(alloc(chunk)); m_chunk_ptr = m_chunks.back(); } void * result = m_chunk_ptr; m_chunk_ptr = (char*)m_chunk_ptr + sz; return result; } void deallocate(size_t size, void * p) { m_alloc_size -= size; if (size >= SMALL_OBJ_SIZE) { memory::deallocate(p); } else { m_free[free_slot_id(size)].push_back(p); } } size_t get_allocation_size() const { return m_alloc_size; } char const* id() const { return m_id; } }; inline void * operator new(size_t s, sat_allocator & r) { return r.allocate(s); } inline void * operator new[](size_t s, sat_allocator & r) { return r.allocate(s); } inline void operator delete(void * p, sat_allocator & r) { UNREACHABLE(); } inline void operator delete[](void * p, sat_allocator & r) { UNREACHABLE(); }