mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 11:42:28 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			148 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			148 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*++
 | |
| 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<size_t*>(m_curr_ptr)[0] = m;
 | |
|     m_curr_ptr += sizeof(size_t);
 | |
| }
 | |
| 
 | |
| inline size_t stack::top_mark() const {
 | |
|     return reinterpret_cast<size_t*>(m_curr_ptr)[-1];
 | |
| }
 | |
| 
 | |
| inline size_t ptr2mark(void * ptr, bool external) {
 | |
|     return reinterpret_cast<size_t>(ptr) | static_cast<size_t>(external);
 | |
| }
 | |
| 
 | |
| #define MASK (static_cast<size_t>(-1) - 1)
 | |
| 
 | |
| inline char * mark2ptr(size_t m) {
 | |
|     return reinterpret_cast<char *>(m & MASK);
 | |
| }
 | |
| 
 | |
| inline bool external_ptr(size_t m) {
 | |
|     return static_cast<bool>(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<void**>(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<char**>(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<char**>(m_curr_ptr)[0]);
 | |
|     }
 | |
|     SASSERT(m_curr_ptr > m_curr_page);
 | |
| }
 | |
| 
 | |
| 
 |