z3-z3-4.13.0.src.util.stack.cpp Maven / Gradle / Ivy
The newest version!
/*++
Copyright (c) 2007 Microsoft Corporation
Module Name:
stack.cpp
Abstract:
Low level stack (aka stack-based allocator).
Author:
Leonardo (leonardo) 2011-02-27
Notes:
--*/
#include "util/stack.h"
#include "util/page.h"
#include "util/tptr.h"
inline void stack::store_mark(size_t m) {
reinterpret_cast(m_curr_ptr)[0] = m;
m_curr_ptr += sizeof(size_t);
}
inline size_t stack::top_mark() const {
return reinterpret_cast(m_curr_ptr)[-1];
}
inline size_t ptr2mark(void * ptr, bool external) {
return reinterpret_cast(ptr) | static_cast(external);
}
#define MASK (static_cast(-1) - 1)
inline char * mark2ptr(size_t m) {
return reinterpret_cast(m & MASK);
}
inline bool external_ptr(size_t m) {
return static_cast(m & 1);
}
inline void stack::allocate_page(size_t m) {
m_curr_page = allocate_default_page(m_curr_page, m_free_pages);
m_curr_ptr = m_curr_page;
m_curr_end_ptr = end_of_default_page(m_curr_page);
store_mark(m);
}
inline void stack::store_mark(void * ptr, bool external) {
SASSERT(m_curr_ptr < m_curr_end_ptr || m_curr_ptr == m_curr_end_ptr); // mem is aligned
if (m_curr_ptr + sizeof(size_t) > m_curr_end_ptr) {
SASSERT(m_curr_ptr == m_curr_end_ptr);
// doesn't fit in the current page
allocate_page(ptr2mark(ptr, external));
}
else {
store_mark(ptr2mark(ptr, external));
}
}
stack::stack() {
m_curr_page = nullptr;
m_curr_ptr = nullptr;
m_curr_end_ptr = nullptr;
m_free_pages = nullptr;
allocate_page(0);
SASSERT(empty());
}
stack::~stack() {
reset();
del_pages(m_curr_page);
del_pages(m_free_pages);
}
void stack::reset() {
while(!empty())
deallocate();
}
void * stack::top() const {
SASSERT(!empty());
size_t m = top_mark();
void * r = mark2ptr(m);
if (external_ptr(m))
r = reinterpret_cast(r)[0];
return r;
}
void * stack::allocate_small(size_t size, bool external) {
SASSERT(size < DEFAULT_PAGE_SIZE);
char * new_curr_ptr = m_curr_ptr + size;
char * result;
if (new_curr_ptr < m_curr_end_ptr) {
result = m_curr_ptr;
m_curr_ptr = ALIGN(char *, new_curr_ptr);
}
else {
allocate_page(top_mark());
result = m_curr_ptr;
m_curr_ptr += size;
m_curr_ptr = ALIGN(char *, m_curr_ptr);
}
store_mark(result, external);
SASSERT(m_curr_ptr > m_curr_page);
SASSERT(m_curr_ptr <= m_curr_end_ptr);
return result;
}
void * stack::allocate_big(size_t size) {
char * r = alloc_svect(char, size);
void * mem = allocate_small(sizeof(char*), true);
reinterpret_cast(mem)[0] = r;
SASSERT(m_curr_ptr > m_curr_page);
SASSERT(m_curr_ptr <= m_curr_end_ptr);
return r;
}
void stack::deallocate() {
SASSERT(m_curr_ptr > m_curr_page);
SASSERT(m_curr_ptr <= m_curr_end_ptr);
size_t m = top_mark();
SASSERT(m != 0);
if (m_curr_ptr == m_curr_page + sizeof(size_t)) {
// mark is in the beginning of the page
char * prev = prev_page(m_curr_page);
recycle_page(m_curr_page, m_free_pages);
m_curr_page = prev;
m_curr_ptr = mark2ptr(m);
m_curr_end_ptr = end_of_default_page(m_curr_page);
SASSERT(m_curr_ptr > m_curr_page);
SASSERT(m_curr_ptr <= m_curr_end_ptr);
}
else {
// mark is in the middle of the page
m_curr_ptr = mark2ptr(m);
SASSERT(m_curr_ptr < m_curr_end_ptr);
}
if (external_ptr(m)) {
dealloc_svect(reinterpret_cast(m_curr_ptr)[0]);
}
SASSERT(m_curr_ptr > m_curr_page);
}