2011-08-16 21:48:47 -05:00
|
|
|
// Object stacks, used in lieu of dynamically-sized frames.
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstdlib>
|
2011-09-01 13:44:13 -05:00
|
|
|
#include <iostream>
|
2011-08-31 21:19:05 -05:00
|
|
|
#include <new>
|
2011-08-16 21:48:47 -05:00
|
|
|
#include <stdint.h>
|
|
|
|
|
|
|
|
#include "rust_internal.h"
|
|
|
|
#include "rust_obstack.h"
|
2011-09-01 13:44:13 -05:00
|
|
|
#include "rust_shape.h"
|
2011-08-16 21:48:47 -05:00
|
|
|
#include "rust_task.h"
|
|
|
|
|
|
|
|
// ISAAC, let go of max()!
|
|
|
|
#ifdef max
|
|
|
|
#undef max
|
|
|
|
#endif
|
|
|
|
|
2011-08-17 20:14:47 -05:00
|
|
|
//const size_t DEFAULT_CHUNK_SIZE = 4096;
|
2011-08-31 21:19:05 -05:00
|
|
|
const size_t DEFAULT_CHUNK_SIZE = 500000;
|
2011-08-17 20:14:47 -05:00
|
|
|
const size_t DEFAULT_ALIGNMENT = 16;
|
2011-08-16 21:48:47 -05:00
|
|
|
|
2011-08-31 21:19:05 -05:00
|
|
|
// A single type-tagged allocation in a chunk.
|
|
|
|
struct rust_obstack_alloc {
|
|
|
|
size_t len;
|
|
|
|
const type_desc *tydesc;
|
|
|
|
uint8_t data[];
|
|
|
|
|
|
|
|
rust_obstack_alloc(size_t in_len, const type_desc *in_tydesc)
|
|
|
|
: len(in_len), tydesc(in_tydesc) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
// A contiguous set of allocations.
|
2011-08-16 21:48:47 -05:00
|
|
|
struct rust_obstack_chunk {
|
|
|
|
rust_obstack_chunk *prev;
|
|
|
|
size_t size;
|
|
|
|
size_t alen;
|
|
|
|
size_t pad;
|
|
|
|
uint8_t data[];
|
|
|
|
|
|
|
|
rust_obstack_chunk(rust_obstack_chunk *in_prev, size_t in_size)
|
|
|
|
: prev(in_prev), size(in_size), alen(0) {}
|
|
|
|
|
2011-08-31 21:19:05 -05:00
|
|
|
void *alloc(size_t len, type_desc *tydesc);
|
2011-08-16 21:48:47 -05:00
|
|
|
bool free(void *ptr);
|
2011-08-31 21:19:05 -05:00
|
|
|
void *mark();
|
2011-08-16 21:48:47 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
void *
|
2011-08-31 21:19:05 -05:00
|
|
|
rust_obstack_chunk::alloc(size_t len, type_desc *tydesc) {
|
2011-08-17 20:14:47 -05:00
|
|
|
alen = align_to(alen, DEFAULT_ALIGNMENT);
|
|
|
|
|
2011-08-31 21:19:05 -05:00
|
|
|
if (sizeof(rust_obstack_alloc) + len > size - alen) {
|
2011-08-17 20:14:47 -05:00
|
|
|
DPRINT("Not enough space, len=%lu!\n", len);
|
2011-09-01 13:43:29 -05:00
|
|
|
assert(0); // FIXME
|
2011-08-16 21:48:47 -05:00
|
|
|
return NULL; // Not enough space.
|
2011-08-17 20:14:47 -05:00
|
|
|
}
|
2011-08-31 21:19:05 -05:00
|
|
|
|
|
|
|
rust_obstack_alloc *a = new(data + alen) rust_obstack_alloc(len, tydesc);
|
|
|
|
alen += sizeof(*a) + len;
|
2011-09-01 13:44:59 -05:00
|
|
|
memset(a->data, '\0', len); // FIXME: For GC.
|
2011-08-31 21:19:05 -05:00
|
|
|
return &a->data;
|
2011-08-16 21:48:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
rust_obstack_chunk::free(void *ptr) {
|
|
|
|
uint8_t *p = (uint8_t *)ptr;
|
2011-08-17 20:14:47 -05:00
|
|
|
if (p < data || p > data + size)
|
2011-08-16 21:48:47 -05:00
|
|
|
return false;
|
2011-08-17 15:58:49 -05:00
|
|
|
assert(p <= data + alen);
|
2011-08-16 21:48:47 -05:00
|
|
|
alen = (size_t)(p - data);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-08-31 21:19:05 -05:00
|
|
|
void *
|
|
|
|
rust_obstack_chunk::mark() {
|
|
|
|
return data + alen;
|
|
|
|
}
|
|
|
|
|
2011-08-16 21:48:47 -05:00
|
|
|
// Allocates the given number of bytes in a new chunk.
|
|
|
|
void *
|
2011-08-31 21:19:05 -05:00
|
|
|
rust_obstack::alloc_new(size_t len, type_desc *tydesc) {
|
|
|
|
size_t chunk_size = std::max(sizeof(rust_obstack_alloc) + len,
|
|
|
|
DEFAULT_CHUNK_SIZE);
|
2011-08-16 21:48:47 -05:00
|
|
|
void *ptr = task->malloc(sizeof(chunk) + chunk_size, "obstack");
|
2011-08-17 20:14:47 -05:00
|
|
|
DPRINT("making new chunk at %p, len %lu\n", ptr, chunk_size);
|
2011-08-16 21:48:47 -05:00
|
|
|
chunk = new(ptr) rust_obstack_chunk(chunk, chunk_size);
|
2011-08-31 21:19:05 -05:00
|
|
|
return chunk->alloc(len, tydesc);
|
2011-08-16 21:48:47 -05:00
|
|
|
}
|
|
|
|
|
2011-08-17 15:15:04 -05:00
|
|
|
rust_obstack::~rust_obstack() {
|
|
|
|
while (chunk) {
|
|
|
|
rust_obstack_chunk *prev = chunk->prev;
|
|
|
|
task->free(chunk);
|
|
|
|
chunk = prev;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-16 21:48:47 -05:00
|
|
|
void *
|
2011-08-31 21:19:05 -05:00
|
|
|
rust_obstack::alloc(size_t len, type_desc *tydesc) {
|
2011-08-16 21:48:47 -05:00
|
|
|
if (!chunk)
|
2011-08-31 21:19:05 -05:00
|
|
|
return alloc_new(len, tydesc);
|
2011-08-17 20:14:47 -05:00
|
|
|
|
2011-09-01 13:45:20 -05:00
|
|
|
DPRINT("alloc sz %u\n", (uint32_t)len);
|
2011-08-17 20:14:47 -05:00
|
|
|
|
2011-08-31 21:19:05 -05:00
|
|
|
void *ptr = chunk->alloc(len, tydesc);
|
|
|
|
ptr = ptr ? ptr : alloc_new(len, tydesc);
|
2011-08-17 20:14:47 -05:00
|
|
|
|
2011-08-17 15:58:49 -05:00
|
|
|
return ptr;
|
2011-08-16 21:48:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rust_obstack::free(void *ptr) {
|
|
|
|
if (!ptr)
|
|
|
|
return;
|
|
|
|
|
2011-08-17 20:14:47 -05:00
|
|
|
DPRINT("free ptr %p\n", ptr);
|
|
|
|
|
2011-08-16 21:48:47 -05:00
|
|
|
assert(chunk);
|
|
|
|
while (!chunk->free(ptr)) {
|
2011-08-17 20:14:47 -05:00
|
|
|
DPRINT("deleting chunk at %p\n", chunk);
|
2011-08-16 21:48:47 -05:00
|
|
|
rust_obstack_chunk *prev = chunk->prev;
|
|
|
|
task->free(chunk);
|
|
|
|
chunk = prev;
|
|
|
|
assert(chunk);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-31 21:19:05 -05:00
|
|
|
void *
|
|
|
|
rust_obstack::mark() {
|
|
|
|
return chunk ? chunk->mark() : NULL;
|
|
|
|
}
|
|
|
|
|