// Object stacks, used in lieu of dynamically-sized frames. #include #include #include #include #include #include #include "rust_internal.h" #include "rust_obstack.h" #include "rust_shape.h" #include "rust_task.h" // ISAAC, let go of max()! #ifdef max #undef max #endif #undef DPRINT #define DPRINT(fmt, ...) //const size_t DEFAULT_CHUNK_SIZE = 4096; const size_t DEFAULT_CHUNK_SIZE = 500000; const size_t DEFAULT_ALIGNMENT = 16; // A single type-tagged allocation in a chunk. struct rust_obstack_alloc { size_t len; const type_desc *tydesc; uint32_t pad0; // FIXME: x86-specific uint32_t pad1; uint8_t data[]; rust_obstack_alloc(size_t in_len, const type_desc *in_tydesc) : len(in_len), tydesc(in_tydesc) {} }; void * rust_obstack_chunk::alloc(size_t len, type_desc *tydesc) { alen = align_to(alen, DEFAULT_ALIGNMENT); if (sizeof(rust_obstack_alloc) + len > size - alen) { DPRINT("Not enough space, len=%lu!\n", len); assert(0); // FIXME return NULL; // Not enough space. } rust_obstack_alloc *a = new(data + alen) rust_obstack_alloc(len, tydesc); alen += sizeof(*a) + len; memset(a->data, '\0', len); // FIXME: For GC. return &a->data; } bool rust_obstack_chunk::free(void *ptr) { uint8_t *p = (uint8_t *)ptr; if (p < data || p > data + size) return false; assert(p <= data + alen); alen = (size_t)(p - data); return true; } void * rust_obstack_chunk::mark() { return data + alen; } // Allocates the given number of bytes in a new chunk. void * rust_obstack::alloc_new(size_t len, type_desc *tydesc) { size_t chunk_size = std::max(sizeof(rust_obstack_alloc) + len, DEFAULT_CHUNK_SIZE); void *ptr = task->malloc(sizeof(chunk) + chunk_size, "obstack"); DPRINT("making new chunk at %p, len %lu\n", ptr, chunk_size); chunk = new(ptr) rust_obstack_chunk(chunk, chunk_size); return chunk->alloc(len, tydesc); } rust_obstack::~rust_obstack() { while (chunk) { rust_obstack_chunk *prev = chunk->prev; task->free(chunk); chunk = prev; } } void * rust_obstack::alloc(size_t len, type_desc *tydesc) { if (!chunk) return alloc_new(len, tydesc); void *ptr = chunk->alloc(len, tydesc); ptr = ptr ? ptr : alloc_new(len, tydesc); return ptr; } void rust_obstack::free(void *ptr) { if (!ptr) return; assert(chunk); while (!chunk->free(ptr)) { DPRINT("deleting chunk at %p\n", chunk); rust_obstack_chunk *prev = chunk->prev; task->free(chunk); chunk = prev; assert(chunk); } } void * rust_obstack::mark() { return chunk ? chunk->mark() : NULL; } // Iteration over self-describing obstacks std::pair rust_obstack::iterator::operator*() const { return std::make_pair(alloc->tydesc, alloc->data); } rust_obstack::iterator & rust_obstack::iterator::operator++() { uint8_t *adata = align_to(alloc->data + alloc->len, DEFAULT_ALIGNMENT); alloc = reinterpret_cast(adata); if (reinterpret_cast(alloc) >= chunk->data + chunk->alen) { // We reached the end of this chunk; go on to the next one. chunk = chunk->prev; if (chunk) alloc = reinterpret_cast(chunk->data); else alloc = NULL; } return *this; } bool rust_obstack::iterator::operator==(const rust_obstack::iterator &other) const { return chunk == other.chunk && alloc == other.alloc; } bool rust_obstack::iterator::operator!=(const rust_obstack::iterator &other) const { return !(*this == other); } // Debugging void rust_obstack::dump() const { iterator b = begin(), e = end(); while (b != e) { std::pair data = *b; uint8_t *dp = reinterpret_cast(data.second); shape::arena arena; shape::type_param *params = shape::type_param::from_tydesc_and_data(data.first, dp, arena); shape::log log(task, true, data.first->shape, params, data.first->shape_tables, dp, std::cerr); log.walk(); std::cerr << "\n"; ++b; } std::cerr << "end of dynastack dump\n"; }