about summary refs log tree commit diff
path: root/src/rt/rust_obstack.cpp
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2011-08-31 19:19:05 -0700
committerPatrick Walton <pcwalton@mimiga.net>2011-08-31 19:19:05 -0700
commit614a930c51d8e8f66e6893261616a449d9ab0754 (patch)
tree5ec334ad863047aae11989bef8ad5d6ff1327129 /src/rt/rust_obstack.cpp
parent729437d2c07cfaf3d924df59a9341b3ac2efa1d6 (diff)
downloadrust-614a930c51d8e8f66e6893261616a449d9ab0754.tar.gz
rust-614a930c51d8e8f66e6893261616a449d9ab0754.zip
rt: Make the dynamic stack self-describing
Diffstat (limited to 'src/rt/rust_obstack.cpp')
-rw-r--r--src/rt/rust_obstack.cpp53
1 files changed, 39 insertions, 14 deletions
diff --git a/src/rt/rust_obstack.cpp b/src/rt/rust_obstack.cpp
index f76a80aada9..d703cfca63c 100644
--- a/src/rt/rust_obstack.cpp
+++ b/src/rt/rust_obstack.cpp
@@ -3,6 +3,7 @@
 #include <algorithm>
 #include <cassert>
 #include <cstdlib>
+#include <new>
 #include <stdint.h>
 
 #include "rust_internal.h"
@@ -18,9 +19,20 @@
 #define DPRINT(fmt,...)
 
 //const size_t DEFAULT_CHUNK_SIZE = 4096;
-const size_t DEFAULT_CHUNK_SIZE = 300000;
+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;
+    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.
 struct rust_obstack_chunk {
     rust_obstack_chunk *prev;
     size_t size;
@@ -31,22 +43,24 @@ struct rust_obstack_chunk {
     rust_obstack_chunk(rust_obstack_chunk *in_prev, size_t in_size)
     : prev(in_prev), size(in_size), alen(0) {}
 
-    void *alloc(size_t len);
+    void *alloc(size_t len, type_desc *tydesc);
     bool free(void *ptr);
+    void *mark();
 };
 
 void *
-rust_obstack_chunk::alloc(size_t len) {
+rust_obstack_chunk::alloc(size_t len, type_desc *tydesc) {
     alen = align_to(alen, DEFAULT_ALIGNMENT);
 
-    if (len > size - alen) {
+    if (sizeof(rust_obstack_alloc) + len > size - alen) {
         DPRINT("Not enough space, len=%lu!\n", len);
         assert(0);
         return NULL;    // Not enough space.
     }
-    void *result = data + alen;
-    alen += len;
-    return result;
+
+    rust_obstack_alloc *a = new(data + alen) rust_obstack_alloc(len, tydesc);
+    alen += sizeof(*a) + len;
+    return &a->data;
 }
 
 bool
@@ -59,14 +73,20 @@ rust_obstack_chunk::free(void *ptr) {
     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) {
-    size_t chunk_size = std::max(len, DEFAULT_CHUNK_SIZE);
+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);
+    return chunk->alloc(len, tydesc);
 }
 
 rust_obstack::~rust_obstack() {
@@ -78,14 +98,14 @@ rust_obstack::~rust_obstack() {
 }
 
 void *
-rust_obstack::alloc(size_t len) {
+rust_obstack::alloc(size_t len, type_desc *tydesc) {
     if (!chunk)
-        return alloc_new(len);
+        return alloc_new(len, tydesc);
 
     DPRINT("alloc sz %u", (uint32_t)len);
 
-    void *ptr = chunk->alloc(len);
-    ptr = ptr ? ptr : alloc_new(len);
+    void *ptr = chunk->alloc(len, tydesc);
+    ptr = ptr ? ptr : alloc_new(len, tydesc);
 
     return ptr;
 }
@@ -107,3 +127,8 @@ rust_obstack::free(void *ptr) {
     }
 }
 
+void *
+rust_obstack::mark() {
+    return chunk ? chunk->mark() : NULL;
+}
+