Browse Source

Add `free` for maps (a previous oversight)

Ginger Bill 8 years ago
parent
commit
eed873c6ec
8 changed files with 218 additions and 192 deletions
  1. 69 112
      core/_preload.odin
  2. 4 2
      core/hash.odin
  3. 6 3
      core/mem.odin
  4. 3 7
      core/os_windows.odin
  5. 3 1
      core/strings.odin
  6. 10 5
      src/checker.cpp
  7. 113 53
      src/common.cpp
  8. 10 9
      src/ir.cpp

+ 69 - 112
core/_preload.odin

@@ -117,6 +117,39 @@ __type_table: []TypeInfo;
 __argv__: ^^u8;
 __argc__: i32;
 
+// IMPORTANT NOTE(bill): Must be in this order (as the compiler relies upon it)
+AllocatorMode :: enum u8 {
+	Alloc,
+	Free,
+	FreeAll,
+	Resize,
+}
+AllocatorProc :: proc(allocator_data: rawptr, mode: AllocatorMode,
+                      size, alignment: int,
+                      old_memory: rawptr, old_size: int, flags: u64 = 0) -> rawptr;
+Allocator :: struct #ordered {
+	procedure: AllocatorProc,
+	data:      rawptr,
+}
+
+
+Context :: struct #ordered {
+	thread_id:  int,
+
+	allocator:  Allocator,
+
+	user_data:  rawptr,
+	user_index: int,
+}
+
+DEFAULT_ALIGNMENT :: align_of([vector 4]f32);
+
+SourceCodeLocation :: struct {
+	fully_pathed_filename: string,
+	line, column:          i64,
+	procedure:             string,
+}
+
 
 __INITIAL_MAP_CAP :: 16;
 
@@ -181,40 +214,7 @@ foreign __llvm_core {
 	read_cycle_counter :: proc() -> u64    #link_name "llvm.readcyclecounter" ---;
 }
 
-// IMPORTANT NOTE(bill): Must be in this order (as the compiler relies upon it)
-AllocatorMode :: enum u8 {
-	Alloc,
-	Free,
-	FreeAll,
-	Resize,
-}
-AllocatorProc :: proc(allocator_data: rawptr, mode: AllocatorMode,
-                      size, alignment: int,
-                      old_memory: rawptr, old_size: int, flags: u64 = 0) -> rawptr;
-Allocator :: struct #ordered {
-	procedure: AllocatorProc,
-	data:      rawptr,
-}
-
-
-Context :: struct #ordered {
-	thread_id:  int,
-
-	allocator:  Allocator,
-
-	user_data:  rawptr,
-	user_index: int,
-}
-
-// #thread_local var __context: Context;
-
-
 
-SourceCodeLocation :: struct {
-	fully_pathed_filename: string,
-	line, column:          i64,
-	procedure:             string,
-}
 
 make_source_code_location :: proc(file: string, line, column: i64, procedure: string) -> SourceCodeLocation #cc_contextless #inline {
 	return SourceCodeLocation{file, line, column, procedure};
@@ -222,7 +222,6 @@ make_source_code_location :: proc(file: string, line, column: i64, procedure: st
 
 
 
-DEFAULT_ALIGNMENT :: align_of([vector 4]f32);
 
 __init_context_from_ptr :: proc(c: ^Context, other: ^Context) #cc_contextless {
 	if c == nil do return;
@@ -255,35 +254,25 @@ __check_context :: proc() {
 */
 
 alloc :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT) -> rawptr #inline {
-	// __check_context();
 	a := context.allocator;
 	return a.procedure(a.data, AllocatorMode.Alloc, size, alignment, nil, 0, 0);
 }
 
 free_ptr_with_allocator :: proc(a: Allocator, ptr: rawptr) #inline {
-	if ptr == nil {
-		return;
-	}
-	if a.procedure == nil {
-		return;
-	}
+	if ptr == nil do return;
+	if a.procedure == nil do return;
 	a.procedure(a.data, AllocatorMode.Free, 0, 0, ptr, 0, 0);
 }
 
-free_ptr :: proc(ptr: rawptr) #inline {
-	// __check_context();
-	free_ptr_with_allocator(context.allocator, ptr);
-}
+free_ptr :: proc(ptr: rawptr) #inline do free_ptr_with_allocator(context.allocator, ptr);
 
 free_all :: proc() #inline {
-	// __check_context();
 	a := context.allocator;
 	a.procedure(a.data, AllocatorMode.FreeAll, 0, 0, nil, 0, 0);
 }
 
 
 resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT) -> rawptr #inline {
-	// __check_context();
 	a := context.allocator;
 	return a.procedure(a.data, AllocatorMode.Resize, new_size, alignment, ptr, old_size, 0);
 }
@@ -298,14 +287,12 @@ copy :: proc(dst, src: []$T) -> int #cc_contextless {
 
 
 append :: proc(array: ^[]$T, args: ..T) -> int {
-	if array == nil {
-		return 0;
-	}
+	if array == nil do return 0;
+
 	slice := ^raw.Slice(array);
+
 	arg_len := len(args);
-	if arg_len <= 0 {
-		return slice.len;
-	}
+	if arg_len <= 0 do return slice.len;
 
 	arg_len = min(slice.cap-slice.len, arg_len);
 	if arg_len > 0 {
@@ -319,15 +306,12 @@ append :: proc(array: ^[]$T, args: ..T) -> int {
 }
 
 append :: proc(array: ^[dynamic]$T, args: ..T) -> int {
-	if array == nil {
-		return 0;
-	}
+	if array == nil do return 0;
+
 	a := ^raw.DynamicArray(array);
 
 	arg_len := len(args);
-	if arg_len <= 0 {
-		return a.len;
-	}
+	if arg_len <= 0 do return a.len;
 
 
 	ok := true;
@@ -345,7 +329,7 @@ append :: proc(array: ^[dynamic]$T, args: ..T) -> int {
 	return a.len;
 }
 
-pop :: proc(array: ^[]$T) -> T {
+pop :: proc(array: ^[]$T) -> T #cc_contextless {
 	res: T;
 	if array do return res;
 	assert(len(array) > 0);
@@ -354,7 +338,7 @@ pop :: proc(array: ^[]$T) -> T {
 	return res;
 }
 
-pop :: proc(array: ^[dynamic]$T) -> T {
+pop :: proc(array: ^[dynamic]$T) -> T #cc_contextless {
 	res: T;
 	if array do return res;
 	assert(len(array) > 0);
@@ -384,7 +368,6 @@ reserve :: proc(array: ^[dynamic]$T, capacity: int) -> bool {
 
 	if capacity <= a.cap do return true;
 
-	// __check_context();
 	if a.allocator.procedure == nil {
 		a.allocator = context.allocator;
 	}
@@ -403,7 +386,7 @@ reserve :: proc(array: ^[dynamic]$T, capacity: int) -> bool {
 }
 
 
-__get_map_header :: proc(m: ^map[$K]$V) -> __MapHeader {
+__get_map_header :: proc(m: ^map[$K]$V) -> __MapHeader #cc_contextless {
 	header := __MapHeader{m = ^raw.DynamicMap(m)};
 	Entry :: struct {
 		key:   __MapKey,
@@ -419,9 +402,9 @@ __get_map_header :: proc(m: ^map[$K]$V) -> __MapHeader {
 	return header;
 }
 
-__get_map_key :: proc(key: $K) -> __MapKey {
+__get_map_key :: proc(key: $K) -> __MapKey #cc_contextless {
 	map_key: __MapKey;
-	ti := type_info(K);
+	ti := type_info_base_without_enum(type_info(K));
 	match {
 	case types.is_integer(ti):
 		match 8*size_of(key) {
@@ -463,29 +446,15 @@ delete :: proc(m: ^map[$K]$V, key: K) {
 
 new  :: proc(T: type) -> ^T #inline do return ^T(alloc(size_of(T), align_of(T)));
 
+free :: proc(ptr:   rawptr)      do free_ptr(ptr);
+free :: proc(str:   string)      do free_ptr(^raw.String(&str).data);
 free :: proc(array: [dynamic]$T) do free_ptr(^raw.DynamicArray(&array).data);
 free :: proc(slice: []$T)        do free_ptr(^raw.Slice(&slice).data);
-free :: proc(str:   string)      do free_ptr(^raw.String(&str).data);
-free :: proc(ptr:   rawptr)      do free_ptr(ptr);
-
-slice_to_bytes :: proc(slice: []$T) -> []u8 {
-	s := ^raw.Slice(&slice);
-	s.len *= size_of(T);
-	s.cap *= size_of(T);
-	return ^[]u8(s)^;
-}
-
-slice_ptr :: proc(ptr: ^$T, len: int) -> []T {
-	assert(0 <= len);
-	s := raw.Slice{ptr, len, len};
-	return ^[]T(&s)^;
+free :: proc(m:     map[$K]$V) {
+	raw := ^raw.DynamicMap(&m);
+	free(raw.hashes);
+	free(raw.entries.data);
 }
-slice_ptr :: proc(ptr: ^$T, len, cap: int) -> []T {
-	assert(0 <= len && len <= cap);
-	s := raw.Slice{ptr, len, cap};
-	return ^[]T(&s)^;
-}
-
 
 
 default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int) -> rawptr {
@@ -625,14 +594,12 @@ __string_decode_rune :: proc(s: string) -> (rune, int) #cc_contextless #inline {
 
 __mem_set :: proc(data: rawptr, value: i32, len: int) -> rawptr #cc_contextless {
 	when size_of(rawptr) == 8 {
-		foreign __llvm_core llvm_memset_64bit :: proc(dst: rawptr, val: u8, len: int, align: i32, is_volatile: bool) #link_name "llvm.memset.p0i8.i64" ---;
-		llvm_memset_64bit(data, u8(value), len, 1, false);
-		return data;
+		foreign __llvm_core llvm_memset :: proc(dst: rawptr, val: u8, len: int, align: i32, is_volatile: bool) #link_name "llvm.memset.p0i8.i64" ---;
 	} else {
-		foreign __llvm_core llvm_memset_32bit :: proc(dst: rawptr, val: u8, len: int, align: i32, is_volatile: bool) #link_name "llvm.memset.p0i8.i32" ---;
-		llvm_memset_32bit(data, u8(value), len, 1, false);
-		return data;
+		foreign __llvm_core llvm_memset :: proc(dst: rawptr, val: u8, len: int, align: i32, is_volatile: bool) #link_name "llvm.memset.p0i8.i32" ---;
 	}
+	llvm_memset(data, u8(value), len, 1, false);
+	return data;
 }
 __mem_zero :: proc(data: rawptr, len: int) -> rawptr #cc_contextless {
 	return __mem_set(data, 0, len);
@@ -640,26 +607,22 @@ __mem_zero :: proc(data: rawptr, len: int) -> rawptr #cc_contextless {
 __mem_copy :: proc(dst, src: rawptr, len: int) -> rawptr #cc_contextless {
 	// NOTE(bill): This _must_ be implemented like C's memmove
 	when size_of(rawptr) == 8 {
-		foreign __llvm_core llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #link_name "llvm.memmove.p0i8.p0i8.i64" ---;
-		llvm_memmove_64bit(dst, src, len, 1, false);
-		return dst;
+		foreign __llvm_core llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #link_name "llvm.memmove.p0i8.p0i8.i64" ---;
 	} else {
-		foreign __llvm_core llvm_memmove_32bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #link_name "llvm.memmove.p0i8.p0i8.i32" ---;
-		llvm_memmove_32bit(dst, src, len, 1, false);
-		return dst;
+		foreign __llvm_core llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #link_name "llvm.memmove.p0i8.p0i8.i32" ---;
 	}
+	llvm_memmove(dst, src, len, 1, false);
+	return dst;
 }
 __mem_copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #cc_contextless {
 	// NOTE(bill): This _must_ be implemented like C's memcpy
 	when size_of(rawptr) == 8 {
-		foreign __llvm_core llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #link_name "llvm.memcpy.p0i8.p0i8.i64" ---;
-		llvm_memcpy_64bit(dst, src, len, 1, false);
-		return dst;
+		foreign __llvm_core llvm_memcpy_ :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #link_name "llvm.memcpy.p0i8.p0i8.i64" ---;
 	} else {
-		foreign __llvm_core llvm_memcpy_32bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #link_name "llvm.memcpy.p0i8.p0i8.i32";
-		llvm_memcpy_32bit(dst, src, len, 1, false);
-		return dst;
+		foreign __llvm_core llvm_memcpy_ :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #link_name "llvm.memcpy.p0i8.p0i8.i32";
 	}
+	llvm_memcpy_(dst, src, len, 1, false);
+	return dst;
 }
 
 __mem_compare :: proc(a, b: ^u8, n: int) -> int #cc_contextless {
@@ -702,7 +665,6 @@ __abs_complex128 :: proc(x: complex128) -> f64 #inline #cc_contextless {
 
 __dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, cap: int) {
 	array := ^raw.DynamicArray(array_);
-	// __check_context();
 	array.allocator = context.allocator;
 	assert(array.allocator.procedure != nil);
 
@@ -717,7 +679,6 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap:
 
 	if cap <= array.cap do return true;
 
-	// __check_context();
 	if array.allocator.procedure == nil {
 		array.allocator = context.allocator;
 	}
@@ -866,8 +827,7 @@ __dynamic_map_get :: proc(h: __MapHeader, key: __MapKey) -> rawptr {
 	index := __dynamic_map_find(h, key).entry_index;
 	if index >= 0 {
 		data := ^u8(__dynamic_map_get_entry(h, index));
-		val := data + h.value_offset;
-		return val;
+		return data + h.value_offset;
 	}
 	return nil;
 }
@@ -932,9 +892,7 @@ __dynamic_map_find :: proc(using h: __MapHeader, key: __MapKey) -> __MapFindResu
 		fr.entry_index = m.hashes[fr.hash_index];
 		for fr.entry_index >= 0 {
 			entry := __dynamic_map_get_entry(h, fr.entry_index);
-			if __dynamic_map_hash_equal(h, entry.key, key) {
-				return fr;
-			}
+			if __dynamic_map_hash_equal(h, entry.key, key) do return fr;
 			fr.entry_prev = fr.entry_index;
 			fr.entry_index = entry.next;
 		}
@@ -961,8 +919,7 @@ __dynamic_map_delete :: proc(using h: __MapHeader, key: __MapKey) {
 }
 
 __dynamic_map_get_entry :: proc(using h: __MapHeader, index: int) -> ^__MapEntryHeader {
-	data := ^u8(m.entries.data) + index*entry_size;
-	return ^__MapEntryHeader(data);
+	return ^__MapEntryHeader(^u8(m.entries.data) + index*entry_size);
 }
 
 __dynamic_map_erase :: proc(using h: __MapHeader, fr: __MapFindResult) {

+ 4 - 2
core/hash.odin

@@ -1,3 +1,5 @@
+import "mem.odin";
+
 crc32 :: proc(data: []u8) -> u32 {
 	result := ~u32(0);
 	for b in data {
@@ -102,7 +104,7 @@ murmur64 :: proc(data: []u8) -> u64 {
 		r :: 47;
 
 		h: u64 = SEED ~ (u64(len(data)) * m);
-		data64 := slice_ptr(^u64(&data[0]), len(data)/size_of(u64));
+		data64 := mem.slice_ptr(^u64(&data[0]), len(data)/size_of(u64));
 
 		for _, i in data64 {
 			k := data64[i];
@@ -138,7 +140,7 @@ murmur64 :: proc(data: []u8) -> u64 {
 
 		h1 := u32(SEED) ~ u32(len(data));
 		h2 := u32(SEED) >> 32;
-		data32 := slice_ptr(^u32(&data[0]), len(data)/size_of(u32));
+		data32 := mem.slice_ptr(^u32(&data[0]), len(data)/size_of(u32));
 		len := len(data);
 		i := 0;
 

+ 6 - 3
core/mem.odin

@@ -25,7 +25,7 @@ compare :: proc(a, b: []u8) -> int #cc_contextless {
 	return __mem_compare(&a[0], &b[0], min(len(a), len(b)));
 }
 
-/*
+
 slice_ptr :: proc(ptr: ^$T, len: int) -> []T #cc_contextless {
 	assert(len >= 0);
 	slice := raw.Slice{data = ptr, len = len, cap = len};
@@ -43,7 +43,6 @@ slice_to_bytes :: proc(slice: []$T) -> []u8 #cc_contextless {
 	s.cap *= size_of(T);
 	return ^[]u8(s)^;
 }
-*/
 
 
 kilobytes :: proc(x: int) -> int #inline #cc_contextless { return          (x) * 1024; }
@@ -121,7 +120,7 @@ init_arena_from_context :: proc(using a: ^Arena, size: int) {
 	temp_count = 0;
 }
 
-free_arena :: proc(using a: ^Arena) {
+destroy_arena :: proc(using a: ^Arena) {
 	if backing.procedure != nil {
 		push_allocator backing {
 			free(memory);
@@ -214,6 +213,8 @@ align_of_type_info :: proc(type_info: ^TypeInfo) -> int {
 		return align_of_type_info(info.base);
 	case Integer:
 		return info.size;
+	case Rune:
+		return info.size;
 	case Float:
 		return info.size;
 	case String:
@@ -267,6 +268,8 @@ size_of_type_info :: proc(type_info: ^TypeInfo) -> int {
 		return size_of_type_info(info.base);
 	case Integer:
 		return info.size;
+	case Rune:
+		return info.size;
 	case Float:
 		return info.size;
 	case String:

+ 3 - 7
core/os_windows.odin

@@ -57,9 +57,7 @@ args := _alloc_command_line_arguments();
 
 
 open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
-	if len(path) == 0 {
-		return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
-	}
+	if len(path) == 0 do return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
 
 	access: u32;
 	match mode & (O_RDONLY|O_WRONLY|O_RDWR) {
@@ -245,9 +243,7 @@ heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
 	return win32.heap_realloc(win32.get_process_heap(), win32.HEAP_ZERO_MEMORY, ptr, new_size);
 }
 heap_free :: proc(ptr: rawptr) {
-	if ptr == nil {
-		return;
-	}
+	if ptr == nil do return;
 	win32.heap_free(win32.get_process_heap(), 0, ptr);
 }
 
@@ -272,7 +268,7 @@ _alloc_command_line_arguments :: proc() -> []string {
 
 		len := 2*wstr_len-1;
 		buf := make([]u8, len+1);
-		str := slice_ptr(wstr, wstr_len+1);
+		str := mem.slice_ptr(wstr, wstr_len+1);
 
 		i, j := 0, 0;
 		for str[j] != 0 {

+ 3 - 1
core/strings.odin

@@ -1,3 +1,5 @@
+import "mem.odin";
+
 new_string :: proc(s: string) -> string {
 	c := make([]u8, len(s)+1);
 	copy(c, []u8(s));
@@ -15,5 +17,5 @@ new_c_string :: proc(s: string) -> ^u8 {
 to_odin_string :: proc(c: ^u8) -> string {
 	len := 0;
 	for (c+len)^ != 0 do len++;
-	return string(slice_ptr(c, len));
+	return string(mem.slice_ptr(c, len));
 }

+ 10 - 5
src/checker.cpp

@@ -305,9 +305,10 @@ struct Checker {
 	Array<DelayedDecl>         delayed_foreign_libraries;
 	Array<CheckerFileNode>     file_nodes;
 
+	Pool                       pool;
+	gbAllocator                allocator;
 	gbArena                    arena;
 	gbArena                    tmp_arena;
-	gbAllocator                allocator;
 	gbAllocator                tmp_allocator;
 
 	CheckerContext             context;
@@ -773,11 +774,13 @@ void init_checker(Checker *c, Parser *parser) {
 		total_token_count += f->tokens.count;
 	}
 	isize arena_size = 2 * item_size * total_token_count;
-	gb_arena_init_from_allocator(&c->arena, a, arena_size);
 	gb_arena_init_from_allocator(&c->tmp_arena, a, arena_size);
+	gb_arena_init_from_allocator(&c->arena, a, arena_size);
 
-
-	c->allocator     = gb_arena_allocator(&c->arena);
+	pool_init(&c->pool, gb_megabytes(4), gb_kilobytes(384));
+	// c->allocator = pool_allocator(&c->pool);
+	c->allocator = heap_allocator();
+	// c->allocator     = gb_arena_allocator(&c->arena);
 	c->tmp_allocator = gb_arena_allocator(&c->tmp_arena);
 
 	c->global_scope = make_scope(universal_scope, c->allocator);
@@ -793,7 +796,9 @@ void destroy_checker(Checker *c) {
 	array_free(&c->delayed_foreign_libraries);
 	array_free(&c->file_nodes);
 
-	gb_arena_free(&c->arena);
+	pool_destroy(&c->pool);
+	gb_arena_free(&c->tmp_arena);
+	// gb_arena_free(&c->arena);
 }
 
 

+ 113 - 53
src/common.cpp

@@ -23,6 +23,9 @@ gbAllocator heap_allocator(void) {
 #include "integer128.cpp"
 #include "murmurhash3.cpp"
 
+#define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
+
+
 u128 fnv128a(void const *data, isize len) {
 	u128 o = u128_lo_hi(0x13bull, 0x1000000ull);
 	u128 h = u128_lo_hi(0x62b821756295c58dull, 0x6c62272e07bb0142ull);
@@ -52,87 +55,145 @@ gbAllocator scratch_allocator(void) {
 	return gb_scratch_allocator(&scratch_memory);
 }
 
+struct Pool {
+	isize       memblock_size;
+	isize       out_of_band_size;
+	isize       alignment;
 
-struct DynamicArenaBlock {
-	DynamicArenaBlock *prev;
-	DynamicArenaBlock *next;
-	u8 *               start;
-	isize              count;
-	isize              capacity;
+	Array<u8 *> unused_memblock;
+	Array<u8 *> used_memblock;
+	Array<u8 *> out_of_band_allocations;
 
-	gbVirtualMemory    vm;
-};
+	u8 *        current_memblock;
+	u8 *        current_pos;
+	isize       bytes_left;
 
-struct DynamicArena {
-	DynamicArenaBlock *start_block;
-	DynamicArenaBlock *current_block;
-	isize              block_size;
+	gbAllocator block_allocator;
 };
 
-DynamicArenaBlock *add_dynamic_arena_block(DynamicArena *a) {
-	GB_ASSERT(a != NULL);
-	GB_ASSERT(a->block_size > 0);
+enum {
+	POOL_BUCKET_SIZE_DEFAULT      = 65536,
+	POOL_OUT_OF_BAND_SIZE_DEFAULT = 6554,
+};
 
-	gbVirtualMemory vm = gb_vm_alloc(NULL, a->block_size);
-	DynamicArenaBlock *block = cast(DynamicArenaBlock *)vm.data;
+void pool_init(Pool *pool,
+               isize memblock_size = POOL_BUCKET_SIZE_DEFAULT,
+               isize out_of_band_size = POOL_OUT_OF_BAND_SIZE_DEFAULT,
+               isize alignment = 8,
+               gbAllocator block_allocator = heap_allocator(),
+               gbAllocator array_allocator = heap_allocator()) {
+	pool->memblock_size = memblock_size;
+	pool->out_of_band_size = out_of_band_size;
+	pool->alignment = alignment;
+	pool->block_allocator = block_allocator;
+
+	array_init(&pool->unused_memblock,         array_allocator);
+	array_init(&pool->used_memblock,           array_allocator);
+	array_init(&pool->out_of_band_allocations, array_allocator);
+}
 
-	u8 *start = cast(u8 *)gb_align_forward(cast(u8 *)(block + 1), GB_DEFAULT_MEMORY_ALIGNMENT);
-	u8 *end = cast(u8 *)vm.data + vm.size;
+void pool_free_all(Pool *p) {
+	if (p->current_memblock != NULL) {
+		array_add(&p->unused_memblock, p->current_memblock);
+		p->current_memblock = NULL;
+	}
 
-	block->vm       = vm;
-	block->start    = start;
-	block->count    = 0;
-	block->capacity = end-start;
+	for_array(i, p->used_memblock) {
+		array_add(&p->unused_memblock, p->used_memblock[i]);
+	}
+	array_clear(&p->unused_memblock);
 
-	if (a->current_block != NULL) {
-		a->current_block->next = block;
-		block->prev = a->current_block;
+	for_array(i, p->out_of_band_allocations) {
+		gb_free(p->block_allocator, p->out_of_band_allocations[i]);
 	}
-	a->current_block = block;
-	return block;
+	array_clear(&p->out_of_band_allocations);
 }
 
-void init_dynamic_arena(DynamicArena *a, isize block_size) {
-	isize size = gb_size_of(DynamicArenaBlock) + block_size;
-	size = cast(isize)gb_align_forward(cast(void *)cast(uintptr)size, GB_DEFAULT_MEMORY_ALIGNMENT);
-	a->block_size = size;
-	a->start_block = add_dynamic_arena_block(a);
+void pool_destroy(Pool *p) {
+	pool_free_all(p);
+
+	for_array(i, p->unused_memblock) {
+		gb_free(p->block_allocator, p->unused_memblock[i]);
+	}
 }
 
-void destroy_dynamic_arena(DynamicArena *a) {
-	DynamicArenaBlock *b = a->current_block;
-	while (b != NULL) {
-		gbVirtualMemory vm = b->vm;
-		b = b->prev;
-		gb_vm_free(b->vm);
+void pool_cycle_new_block(Pool *p) {
+	GB_ASSERT_MSG(p->block_allocator.proc != NULL,
+	              "You must call pool_init on a Pool before using it!");
+
+	if (p->current_memblock != NULL) {
+		array_add(&p->used_memblock, p->current_memblock);
+	}
+
+	u8 *new_block = NULL;
+
+	if (p->unused_memblock.count > 0) {
+		new_block = array_pop(&p->unused_memblock);
+	} else {
+		GB_ASSERT(p->block_allocator.proc != NULL);
+		new_block = cast(u8 *)gb_alloc_align(p->block_allocator, p->memblock_size, p->alignment);
 	}
+
+	p->bytes_left       = p->memblock_size;
+	p->current_memblock = new_block;
+	p->current_memblock = new_block;
 }
 
-GB_ALLOCATOR_PROC(dynamic_arena_allocator_proc) {
-	DynamicArena *a = cast(DynamicArena *)allocator_data;
-	void *ptr = NULL;
+void *pool_get(Pool *p,
+               isize size, isize alignment = 0) {
+	if (alignment <= 0) alignment = p->alignment;
+
+	isize extra = alignment - (size & alignment);
+	size += extra;
+	if (size >= p->out_of_band_size) {
+		GB_ASSERT(p->block_allocator.proc != NULL);
+		u8 *memory = cast(u8 *)gb_alloc_align(p->block_allocator, p->memblock_size, alignment);
+		if (memory != NULL) {
+			array_add(&p->out_of_band_allocations, memory);
+		}
+		return memory;
+	}
 
-	switch (type) {
-	case gbAllocation_Alloc: {
+	if (p->bytes_left < size) {
+		pool_cycle_new_block(p);
+		if (p->current_memblock != NULL) {
+			return NULL;
+		}
+	}
+
+	u8 *res = p->current_pos;
+	p->current_pos += size;
+	p->bytes_left  -= size;
+	return res;
+}
 
-	} break;
 
-	case gbAllocation_Free: {
-	} break;
+gbAllocator pool_allocator(Pool *pool);
 
-	case gbAllocation_Resize: {
-	} break;
+GB_ALLOCATOR_PROC(pool_allocator_procedure) {
+	Pool *p = cast(Pool *)allocator_data;
+	void *ptr = NULL;
 
+	switch (type) {
+	case gbAllocation_Alloc:
+		return pool_get(p, size, alignment);
+	case gbAllocation_Free:
+		// Does nothing
+		break;
 	case gbAllocation_FreeAll:
-		GB_PANIC("free_all is not supported by this allocator");
+		pool_free_all(p);
 		break;
+	case gbAllocation_Resize:
+		return gb_default_resize_align(pool_allocator(p), old_memory, old_size, size, alignment);
 	}
 
 	return ptr;
 }
 
-gbAllocator dynamic_arena_allocator(DynamicArena *a) {
-	gbAllocator allocator = {dynamic_arena_allocator_proc, a};
+gbAllocator pool_allocator(Pool *pool) {
+	gbAllocator allocator;
+	allocator.proc = pool_allocator_procedure;
+	allocator.data = pool;
 	return allocator;
 }
 
@@ -224,7 +285,6 @@ f64 gb_sqrt(f64 x) {
 
 
 
-#define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
 
 
 // Doubly Linked Lists

+ 10 - 9
src/ir.cpp

@@ -7123,20 +7123,21 @@ void ir_init_module(irModule *m, Checker *c) {
 	// TODO(bill): Determine a decent size for the arena
 	isize token_count = c->parser->total_token_count;
 	isize arena_size = 4 * token_count * gb_size_of(irValue);
-	gb_arena_init_from_allocator(&m->arena, heap_allocator(), arena_size);
+	gb_arena_init_from_allocator(&m->arena,     heap_allocator(), arena_size);
 	gb_arena_init_from_allocator(&m->tmp_arena, heap_allocator(), arena_size);
-	m->allocator     = gb_arena_allocator(&m->arena);
+	// m->allocator     = gb_arena_allocator(&m->arena);
+	m->allocator     = heap_allocator();
 	m->tmp_allocator = gb_arena_allocator(&m->tmp_arena);
 	m->info = &c->info;
 
-	map_init(&m->values,  heap_allocator());
-	map_init(&m->members, heap_allocator());
-	map_init(&m->debug_info, heap_allocator());
-	map_init(&m->entity_names, heap_allocator());
-	array_init(&m->procs,    heap_allocator());
-	array_init(&m->procs_to_generate, heap_allocator());
+	map_init(&m->values,                  heap_allocator());
+	map_init(&m->members,                 heap_allocator());
+	map_init(&m->debug_info,              heap_allocator());
+	map_init(&m->entity_names,            heap_allocator());
+	array_init(&m->procs,                 heap_allocator());
+	array_init(&m->procs_to_generate,     heap_allocator());
 	array_init(&m->foreign_library_paths, heap_allocator());
-	map_init(&m->const_strings, heap_allocator());
+	map_init(&m->const_strings,           heap_allocator());
 
 	// Default states
 	m->stmt_state_flags = 0;