Use backtrace on windows. Updated backtrace API

This commit is contained in:
Christoffer Lerno
2023-11-16 23:18:43 +01:00
committed by Christoffer Lerno
parent 81c93e3488
commit ffb0021d04
24 changed files with 272 additions and 273 deletions

View File

@@ -86,9 +86,9 @@ struct GrowableBitSet
* @param initial_capacity
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
**/
fn GrowableBitSet* GrowableBitSet.init_new(&self, usz initial_capacity = 1, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn GrowableBitSet* GrowableBitSet.init_new(&self, usz initial_capacity = 1, Allocator* allocator = mem::heap())
{
self.data.init_new(initial_capacity, allocator, env);
self.data.init_new(initial_capacity, allocator);
return self;
}

View File

@@ -22,14 +22,14 @@ struct List (Printable)
* @param initial_capacity "The initial capacity to reserve"
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
**/
fn List* List.init_new(&self, usz initial_capacity = 16, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn List* List.init_new(&self, usz initial_capacity = 16, Allocator* allocator = mem::heap())
{
self.allocator = allocator;
self.size = 0;
if (initial_capacity > 0)
{
initial_capacity = math::next_power_of_2(initial_capacity);
self.entries = allocator.alloc_aligned(Type.sizeof * initial_capacity, .alignment = Type[1].alignof, .env = env)!!;
self.entries = allocator.alloc_aligned(Type.sizeof * initial_capacity, .alignment = Type[1].alignof)!!;
}
else
{

View File

@@ -26,13 +26,13 @@ struct HashMap
* @require !map.allocator "Map was already initialized"
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
**/
fn HashMap* HashMap.init_new(&map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn HashMap* HashMap.init_new(&map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator* allocator = mem::heap())
{
capacity = math::next_power_of_2(capacity);
map.allocator = allocator;
map.load_factor = load_factor;
map.threshold = (uint)(capacity * load_factor);
map.table = allocator.new_zero_array(Entry*, capacity, .env = env);
map.table = allocator.new_zero_array(Entry*, capacity);
return map;
}
@@ -62,9 +62,9 @@ fn bool HashMap.is_initialized(&map)
* @param [&inout] allocator "The allocator to use"
* @param [&in] other_map "The map to copy from."
**/
fn HashMap* HashMap.init_new_from_map(&self, HashMap* other_map, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn HashMap* HashMap.init_new_from_map(&self, HashMap* other_map, Allocator* allocator = mem::heap())
{
self.init_new(other_map.table.len, other_map.load_factor, allocator, env);
self.init_new(other_map.table.len, other_map.load_factor, allocator);
self.put_all_for_create(other_map);
return self;
}

View File

@@ -78,9 +78,9 @@ fn usz! Object.to_format(&self, Formatter* formatter) @dynamic
}
}
fn Object* new_obj(Allocator* allocator, TrackingEnv* env = mem::get_tracking_env())
fn Object* new_obj(Allocator* allocator)
{
Object* o = allocator.new(Object, .env = env);
Object* o = allocator.new(Object);
*o = { .allocator = allocator, .type = void.typeid };
return o;
}

View File

@@ -36,9 +36,9 @@ struct PrivatePriorityQueue (Printable)
Heap heap;
}
fn void PrivatePriorityQueue.init_new(&self, usz initial_capacity = 16, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env()) @inline
fn void PrivatePriorityQueue.init_new(&self, usz initial_capacity = 16, Allocator* allocator = mem::heap()) @inline
{
self.heap.init_new(initial_capacity, allocator, .env = env);
self.heap.init_new(initial_capacity, allocator);
}
fn void PrivatePriorityQueue.init_temp(&self, usz initial_capacity = 16) @inline

View File

@@ -29,7 +29,7 @@ struct ArenaAllocatorHeader @local
char[*] data;
}
fn void ArenaAllocator.release(&self, void* ptr, bool, TrackingEnv* env = null) @dynamic
fn void ArenaAllocator.release(&self, void* ptr, bool) @dynamic
{
if (!ptr) return;
assert((uptr)ptr >= (uptr)self.data.ptr, "Pointer originates from a different allocator.");
@@ -50,7 +50,7 @@ fn void ArenaAllocator.reset(&self, usz mark) @dynamic => self.used = mark;
* @require offset <= size && offset >= 0
* @require mem::aligned_offset(offset, ArenaAllocatorHeader.alignof) == offset
**/
fn void*! ArenaAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset, TrackingEnv* env = null) @dynamic
fn void*! ArenaAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset) @dynamic
{
if (!size) return null;
alignment = alignment_for_allocation(alignment);
@@ -76,7 +76,7 @@ fn void*! ArenaAllocator.acquire(&self, usz size, bool clear, usz alignment, usz
* @require offset <= size && offset >= 0
* @require mem::aligned_offset(offset, ArenaAllocatorHeader.alignof) == offset
**/
fn void*! ArenaAllocator.resize(&self, void *old_pointer, usz size, usz alignment, usz offset, TrackingEnv* env) @dynamic
fn void*! ArenaAllocator.resize(&self, void *old_pointer, usz size, usz alignment, usz offset) @dynamic
{
if (!size)
{
@@ -110,7 +110,7 @@ fn void*! ArenaAllocator.resize(&self, void *old_pointer, usz size, usz alignmen
return old_pointer;
}
// Otherwise just allocate new memory.
void* mem = self.acquire(size, false, alignment, offset, env)!;
void* mem = self.acquire(size, false, alignment, offset)!;
mem::copy(mem, old_pointer, old_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT);
return mem;
}

View File

@@ -60,7 +60,7 @@ struct DynamicArenaChunk @local
/**
* @require self.page `tried to free pointer on invalid allocator`
*/
fn void DynamicArenaAllocator.release(&self, void* ptr, bool, TrackingEnv* env) @dynamic
fn void DynamicArenaAllocator.release(&self, void* ptr, bool) @dynamic
{
if (!ptr) return;
DynamicArenaPage* current_page = self.page;
@@ -74,16 +74,16 @@ fn void DynamicArenaAllocator.release(&self, void* ptr, bool, TrackingEnv* env)
/**
* @require self.page `tried to realloc pointer on invalid allocator`
*/
fn void*! DynamicArenaAllocator.resize(&self, void* old_pointer, usz size, usz alignment, usz offset, TrackingEnv* env) @dynamic
fn void*! DynamicArenaAllocator.resize(&self, void* old_pointer, usz size, usz alignment, usz offset) @dynamic
{
if (!size)
{
self.release(old_pointer, alignment > 0, env);
self.release(old_pointer, alignment > 0);
return null;
}
if (!old_pointer)
{
return self.acquire(size, true, alignment, offset, env);
return self.acquire(size, true, alignment, offset);
}
DynamicArenaPage* current_page = self.page;
alignment = alignment_for_allocation(alignment);
@@ -108,7 +108,7 @@ fn void*! DynamicArenaAllocator.resize(&self, void* old_pointer, usz size, usz a
current_page.used += add_size;
return old_pointer;
}
void* new_mem = self.acquire(size, false, alignment, offset, env)!;
void* new_mem = self.acquire(size, false, alignment, offset)!;
mem::copy(new_mem, old_pointer, old_size, mem::DEFAULT_MEM_ALIGNMENT);
return new_mem;
}
@@ -163,7 +163,7 @@ fn void*! DynamicArenaAllocator._alloc_new(&self, usz size, usz alignment, usz o
/**
* @require !alignment || math::is_power_of_2(alignment)
*/
fn void*! DynamicArenaAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset, TrackingEnv* env) @dynamic
fn void*! DynamicArenaAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset) @dynamic
{
if (!size) return null;
alignment = alignment_for_allocation(alignment);

View File

@@ -21,7 +21,7 @@ fn void SimpleHeapAllocator.init(&self, MemoryAllocFn allocator)
self.free_list = null;
}
fn void*! SimpleHeapAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset, TrackingEnv* env) @dynamic
fn void*! SimpleHeapAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset) @dynamic
{
if (!size) return null;
if (clear)
@@ -31,23 +31,23 @@ fn void*! SimpleHeapAllocator.acquire(&self, usz size, bool clear, usz alignment
return alignment > 0 ? @aligned_alloc(self._alloc, size, alignment, offset) : self._alloc(size);
}
fn void*! SimpleHeapAllocator.resize(&self, void* old_pointer, usz size, usz alignment, usz offset, TrackingEnv* env) @dynamic
fn void*! SimpleHeapAllocator.resize(&self, void* old_pointer, usz size, usz alignment, usz offset) @dynamic
{
if (!size)
{
self.release(old_pointer, alignment > 0, env);
self.release(old_pointer, alignment > 0);
return null;
}
if (!old_pointer)
{
return self.acquire(size, true, alignment, offset, env);
return self.acquire(size, true, alignment, offset);
}
return alignment > 0
? @aligned_realloc(self._calloc, self._free, old_pointer, size, alignment, offset)
: self._realloc(old_pointer, size);
}
fn void SimpleHeapAllocator.release(&self, void* old_pointer, bool aligned, TrackingEnv* env) @dynamic
fn void SimpleHeapAllocator.release(&self, void* old_pointer, bool aligned) @dynamic
{
if (aligned)
{

View File

@@ -10,7 +10,7 @@ const LibcAllocator LIBC_ALLOCATOR = {};
distinct LibcAllocator (Allocator) = uptr;
fn void*! LibcAllocator.acquire(&self, usz bytes, bool clear, usz alignment, usz offset, TrackingEnv* env) @dynamic
fn void*! LibcAllocator.acquire(&self, usz bytes, bool clear, usz alignment, usz offset) @dynamic
{
assert(alignment != 0 || offset == 0);
if (clear)
@@ -29,17 +29,17 @@ fn void*! LibcAllocator.acquire(&self, usz bytes, bool clear, usz alignment, usz
}
}
fn void*! LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment, usz offset, TrackingEnv* env) @dynamic
fn void*! LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment, usz offset) @dynamic
{
assert(alignment != 0 || offset == 0);
if (!new_bytes)
{
self.release(old_ptr, alignment > 0, env);
self.release(old_ptr, alignment > 0);
return null;
}
if (!old_ptr)
{
return self.acquire(new_bytes, true, alignment, offset, env);
return self.acquire(new_bytes, true, alignment, offset);
}
if (alignment)
{
@@ -50,7 +50,7 @@ fn void*! LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignmen
}
fn void LibcAllocator.release(&self, void* old_ptr, bool aligned, TrackingEnv* env) @dynamic
fn void LibcAllocator.release(&self, void* old_ptr, bool aligned) @dynamic
{
if (aligned)
{

View File

@@ -54,7 +54,7 @@ struct OnStackAllocatorHeader
char[*] data;
}
fn void OnStackAllocator.release(&self, void* old_pointer, bool aligned, TrackingEnv* env = null) @dynamic
fn void OnStackAllocator.release(&self, void* old_pointer, bool aligned) @dynamic
{
if (!old_pointer) return;
if (allocation_in_stack_mem(self, old_pointer)) return;
@@ -103,18 +103,18 @@ fn OnStackAllocatorExtraChunk* on_stack_allocator_find_chunk(OnStackAllocator* a
* @require offset <= size && offset >= 0
* @require mem::aligned_offset(offset, OnStackAllocatorExtraChunk.alignof) == offset
**/
fn void*! OnStackAllocator.resize(&self, void* old_pointer, usz size, usz alignment, usz offset, TrackingEnv* env) @dynamic
fn void*! OnStackAllocator.resize(&self, void* old_pointer, usz size, usz alignment, usz offset) @dynamic
{
if (!allocation_in_stack_mem(self, old_pointer))
{
OnStackAllocatorExtraChunk* chunk = on_stack_allocator_find_chunk(self, old_pointer);
assert(chunk, "Tried to realloc pointer not belonging to the allocator");
return chunk.data = self.backing_allocator.resize(old_pointer, size, alignment, offset, env)!;
return chunk.data = self.backing_allocator.resize(old_pointer, size, alignment, offset)!;
}
OnStackAllocatorHeader* header = old_pointer - OnStackAllocatorHeader.sizeof;
usz old_size = header.size;
void* mem = self.acquire(size, true, alignment, offset, env)!;
void* mem = self.acquire(size, true, alignment, offset)!;
mem::copy(mem, old_pointer, old_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT);
return mem;
}
@@ -126,7 +126,7 @@ fn void*! OnStackAllocator.resize(&self, void* old_pointer, usz size, usz alignm
* @require offset == 0 || alignment > 0
* @require mem::aligned_offset(offset, OnStackAllocatorHeader.alignof) == offset
**/
fn void*! OnStackAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset, TrackingEnv* env) @dynamic
fn void*! OnStackAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset) @dynamic
{
if (size == 0) return null;
bool aligned = alignment > 0;
@@ -144,7 +144,7 @@ fn void*! OnStackAllocator.acquire(&self, usz size, bool clear, usz alignment, u
defer catch backing_allocator.free(chunk);
defer try self.chunk = chunk;
*chunk = { .prev = self.chunk, .is_aligned = aligned };
return chunk.data = backing_allocator.acquire(size, clear, aligned ? alignment : 0, offset, env)!;
return chunk.data = backing_allocator.acquire(size, clear, aligned ? alignment : 0, offset)!;
}
self.used = end;
void *mem = aligned_pointer_to_offset - offset;

View File

@@ -47,7 +47,7 @@ fn TempAllocator*! new_temp(usz size, Allocator* allocator)
fn usz TempAllocator.mark(&self) @dynamic => self.used;
fn void TempAllocator.release(&self, void* old_pointer, bool, TrackingEnv* env) @dynamic
fn void TempAllocator.release(&self, void* old_pointer, bool) @dynamic
{
usz old_size = *(usz*)(old_pointer - DEFAULT_SIZE_PREFIX);
if (old_pointer + old_size == &self.data[self.used])
@@ -75,7 +75,7 @@ fn void! TempAllocator._free_page(&self, TempAllocatorPage* page) @inline @local
return self.backing_allocator.free(mem);
}
fn void*! TempAllocator._realloc_page(&self, TempAllocatorPage* page, usz size, usz alignment, usz offset, TrackingEnv* env) @inline @local
fn void*! TempAllocator._realloc_page(&self, TempAllocatorPage* page, usz size, usz alignment, usz offset) @inline @local
{
// Then the actual start pointer:
void* real_pointer = page.start;
@@ -90,7 +90,7 @@ fn void*! TempAllocator._realloc_page(&self, TempAllocatorPage* page, usz size,
*pointer_to_prev = page.prev_page;
usz page_size = page.pagesize();
// Clear on size > original size.
void* data = self.acquire(size, size > page_size, alignment, offset, env)!;
void* data = self.acquire(size, size > page_size, alignment, offset)!;
mem::copy(data, &page.data[0], page_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT);
if (page.is_aligned())
{
@@ -103,16 +103,16 @@ fn void*! TempAllocator._realloc_page(&self, TempAllocatorPage* page, usz size,
return data;
}
fn void*! TempAllocator.resize(&self, void* pointer, usz size, usz alignment, usz offset, TrackingEnv* env) @dynamic
fn void*! TempAllocator.resize(&self, void* pointer, usz size, usz alignment, usz offset) @dynamic
{
if (!size)
{
self.release(pointer, alignment > 0, env);
self.release(pointer, alignment > 0);
return null;
}
if (!pointer)
{
return self.acquire(size, true, alignment, offset, env);
return self.acquire(size, true, alignment, offset);
}
TempAllocatorChunk *chunk = pointer - TempAllocatorChunk.sizeof;
if (chunk.size == (usz)-1)
@@ -120,11 +120,11 @@ fn void*! TempAllocator.resize(&self, void* pointer, usz size, usz alignment, us
assert(self.last_page, "Realloc of non temp pointer");
// First grab the page
TempAllocatorPage *page = pointer - TempAllocatorPage.sizeof;
return self._realloc_page(page, size, alignment, offset, env);
return self._realloc_page(page, size, alignment, offset);
}
// TODO optimize last allocation
TempAllocatorChunk* data = self.acquire(size, size > chunk.size, alignment, offset, env)!;
TempAllocatorChunk* data = self.acquire(size, size > chunk.size, alignment, offset)!;
mem::copy(data, pointer, chunk.size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT);
return data;
@@ -134,7 +134,7 @@ fn void*! TempAllocator.resize(&self, void* pointer, usz size, usz alignment, us
* @require !alignment || math::is_power_of_2(alignment)
* @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big`
**/
fn void*! TempAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset, TrackingEnv* env) @dynamic
fn void*! TempAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset) @dynamic
{
if (!size) return null;
alignment = alignment_for_allocation(alignment);
@@ -182,7 +182,7 @@ fn void*! TempAllocator.acquire(&self, usz size, bool clear, usz alignment, usz
// Here we might need to pad
usz padded_header_size = mem::aligned_offset(TempAllocatorPage.sizeof, mem::DEFAULT_MEM_ALIGNMENT);
usz total_alloc_size = padded_header_size + size;
void* alloc = self.backing_allocator.acquire(total_alloc_size, clear, 0, 0, null)!;
void* alloc = self.backing_allocator.acquire(total_alloc_size, clear, 0, 0)!;
// Find the page.
page = alloc + padded_header_size - TempAllocatorPage.sizeof;

View File

@@ -6,11 +6,12 @@ module std::core::mem::allocator;
import std::collections::map;
import std::collections::list;
const MAX_BACKTRACE = 8;
struct Allocation
{
usz size;
TrackingEnv tracking_env;
void* ptr;
usz size;
void*[MAX_BACKTRACE] backtrace;
}
def AllocMap = HashMap(<uptr, Allocation>);
@@ -79,38 +80,42 @@ fn Allocation[] TrackingAllocator.allocations_tlist(&self, Allocator* allocator)
**/
fn usz TrackingAllocator.allocation_count(&self) => self.map.count;
fn void*! TrackingAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset, TrackingEnv* env) @dynamic
fn void*! TrackingAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset) @dynamic
{
void* data = self.inner_allocator.acquire(size, clear, alignment, offset, env)!;
void* data = self.inner_allocator.acquire(size, clear, alignment, offset)!;
self.allocs_total++;
if (data)
{
self.map.set((uptr)data, { .size = size, .ptr = data, .tracking_env = env ? *env : TrackingEnv{} });
void*[MAX_BACKTRACE] bt;
backtrace::capture_current(&bt);
self.map.set((uptr)data, { data, size, bt });
self.mem_total += size;
self.allocs_total++;
}
return data;
}
fn void*! TrackingAllocator.resize(&self, void* old_pointer, usz size, usz alignment, usz offset, TrackingEnv* env) @dynamic
fn void*! TrackingAllocator.resize(&self, void* old_pointer, usz size, usz alignment, usz offset) @dynamic
{
void* data = self.inner_allocator.resize(old_pointer, size, alignment, offset, env)!;
void* data = self.inner_allocator.resize(old_pointer, size, alignment, offset)!;
if (old_pointer)
{
self.map.remove((uptr)old_pointer);
}
if (data)
{
self.map.set((uptr)data, { .size = size, .ptr = data, .tracking_env = env ? *env : TrackingEnv{} });
void*[8] bt;
backtrace::capture_current(&bt);
self.map.set((uptr)data, { data, size, bt });
self.mem_total += size;
self.allocs_total++;
}
return data;
}
fn void TrackingAllocator.release(&self, void* old_pointer, bool is_aligned, TrackingEnv* env) @dynamic
fn void TrackingAllocator.release(&self, void* old_pointer, bool is_aligned) @dynamic
{
self.inner_allocator.release(old_pointer, is_aligned, env);
self.inner_allocator.release(old_pointer, is_aligned);
if (old_pointer) self.map.remove((uptr)old_pointer);
}
@@ -126,41 +131,84 @@ fn void! TrackingAllocator.fprint_report(&self, OutStream* out)
usz total = 0;
usz entries = 0;
bool leaks = false;
@pool()
{
Allocation[] allocs = self.map.value_tlist();
if (allocs.len)
{
$if (!env::TRACK_MEMORY):
io::fprintn(out, "======== Memory Report ========")!;
io::fprintn(out, "Size in bytes Address")!;
foreach (i, &allocation : allocs)
if (!allocs[0].backtrace[0])
{
entries++;
total += allocation.size;
io::fprintfn(out, "%13s %p", allocation.size, allocation.ptr)!;
io::fprintn(out, "======== Memory Report ========")!;
io::fprintn(out, "Size in bytes Address")!;
foreach (i, &allocation : allocs)
{
entries++;
total += allocation.size;
io::fprintfn(out, "%13s %p", allocation.size, allocation.ptr)!;
}
io::fprintn(out, "===============================")!;
}
io::fprintn(out, "===============================")!;
$else
io::fprintn(out, "================================== Memory Report ==================================")!;
io::fprintn(out, "Size in bytes Address Function File")!;
foreach (i, &allocation : allocs)
else
{
entries++;
total += allocation.size;
TrackingEnv *env = &allocation.tracking_env;
io::fprintfn(out, "%13s %p %-30s %s:%d", allocation.size, allocation.ptr, env.function, env.file, env.line)!;
io::fprintn(out, "================================== Memory Report ==================================")!;
io::fprintn(out, "Size in bytes Address Function ")!;
foreach (i, &allocation : allocs)
{
entries++;
total += allocation.size;
BacktraceList backtraces = {};
Backtrace trace = backtrace::BACKTRACE_UNKNOWN;
if (allocation.backtrace[3])
{
trace = backtrace::symbolize_backtrace(allocation.backtrace[3:1], mem::temp()).get(0) ?? backtrace::BACKTRACE_UNKNOWN;
}
if (trace.function.len) leaks = true;
io::fprintfn(out, "%13s %p %s:%d", allocation.size,
allocation.ptr, trace.function.len ? trace.function : "???",
trace.line ? trace.line : 0)!;
}
io::fprintn(out, "===================================================================================")!;
}
io::fprintn(out, "===================================================================================")!;
$endif
}
else
{
io::fprintn(out, "* NO ALLOCATIONS FOUND *")!;
}
io::fprintfn(out, "- Total currently allocated memory: %d", total)!;
io::fprintfn(out, "- Total current allocations: %d", entries)!;
io::fprintfn(out, "- Total allocations (freed and retained): %d", self.allocs_total)!;
io::fprintfn(out, "- Total allocated memory (freed and retained): %d", self.mem_total)!;
if (leaks)
{
io::fprintn(out)!;
io::fprintn(out, "Full leak report:")!;
foreach (i, &allocation : allocs)
{
if (!allocation.backtrace[3])
{
io::fprintfn(out, "Allocation %d (%d bytes) - no backtrace available.", i + 1, allocation.size)!;
continue;
}
BacktraceList backtraces = {};
usz end = MAX_BACKTRACE;
foreach (j, val : allocation.backtrace)
{
if (!val)
{
end = j;
break;
}
}
BacktraceList list = backtrace::symbolize_backtrace(allocation.backtrace[3..(end - 1)], mem::temp())!;
io::fprintfn(out, "Allocation %d (%d bytes): ", i + 1, allocation.size)!;
foreach (trace : list)
{
io::fprintfn(out, " %s", trace);
}
}
}
};
io::fprintfn(out, "- Total currently allocated memory: %d", total)!;
io::fprintfn(out, "- Total current allocations: %d", entries)!;
io::fprintfn(out, "- Total allocations (freed and retained): %d", self.allocs_total)!;
io::fprintfn(out, "- Total allocated memory (freed and retained): %d", self.mem_total)!;
}

View File

@@ -8,10 +8,10 @@ const usz MIN_CAPACITY @private = 16;
/**
* @require !self.data() "String already initialized"
**/
fn DString DString.init_new(&self, usz capacity = MIN_CAPACITY, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn DString DString.init_new(&self, usz capacity = MIN_CAPACITY, Allocator* allocator = mem::heap())
{
if (capacity < MIN_CAPACITY) capacity = MIN_CAPACITY;
StringData* data = allocator.new(StringData, .end_padding = capacity, .env = env);
StringData* data = allocator.new(StringData, .end_padding = capacity);
data.allocator = allocator;
data.len = 0;
data.capacity = capacity;
@@ -27,17 +27,17 @@ fn DString DString.init_temp(&self, usz capacity = MIN_CAPACITY)
return *self;
}
fn DString new_with_capacity(usz capacity, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn DString new_with_capacity(usz capacity, Allocator* allocator = mem::heap())
{
return DString{}.init_new(capacity, allocator, .env = env);
return DString{}.init_new(capacity, allocator);
}
fn DString temp_with_capacity(usz capacity) => new_with_capacity(capacity, mem::temp()) @inline;
fn DString new(String c = "", Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn DString new(String c = "", Allocator* allocator = mem::heap())
{
usz len = c.len;
StringData* data = (StringData*)new_with_capacity(len, allocator, env);
StringData* data = (StringData*)new_with_capacity(len, allocator);
if (len)
{
data.len = len;
@@ -48,10 +48,10 @@ fn DString new(String c = "", Allocator* allocator = mem::heap(), TrackingEnv* e
fn DString temp_new(String s = "") => new(s, mem::temp()) @inline;
fn DString DString.new_concat(self, DString b, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn DString DString.new_concat(self, DString b, Allocator* allocator = mem::heap())
{
DString string;
string.init_new(self.len() + b.len(), allocator, env);
string.init_new(self.len() + b.len(), allocator);
string.append(self);
string.append(b);
return string;
@@ -148,37 +148,37 @@ fn void DString.append_char32(&self, Char32 c)
fn DString DString.tcopy(&self) => self.copy(mem::temp());
fn DString DString.copy(self, Allocator* allocator = null, TrackingEnv* env = mem::get_tracking_env())
fn DString DString.copy(self, Allocator* allocator = null)
{
if (!self)
{
if (allocator) return new_with_capacity(0, allocator, env);
if (allocator) return new_with_capacity(0, allocator);
return (DString)null;
}
StringData* data = self.data();
if (!allocator) allocator = mem::heap();
DString new_string = new_with_capacity(data.capacity, allocator, env);
DString new_string = new_with_capacity(data.capacity, allocator);
mem::copy((char*)new_string.data(), (char*)data, StringData.sizeof + data.len);
return new_string;
}
fn ZString DString.copy_zstr(self, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn ZString DString.copy_zstr(self, Allocator* allocator = mem::heap())
{
usz str_len = self.len();
if (!str_len)
{
return (ZString)allocator.calloc(1, env);
return (ZString)allocator.calloc(1);
}
char* zstr = allocator.alloc(str_len + 1, env);
char* zstr = allocator.alloc(str_len + 1);
StringData* data = self.data();
mem::copy(zstr, &data.chars, str_len);
zstr[str_len] = 0;
return (ZString)zstr;
}
fn String DString.copy_str(self, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn String DString.copy_str(self, Allocator* allocator = mem::heap())
{
return (String)self.copy_zstr(allocator, env)[:self.len()];
return (String)self.copy_zstr(allocator)[:self.len()];
}
fn String DString.tcopy_str(self) => self.copy_str(mem::temp()) @inline;
@@ -240,9 +240,9 @@ fn void DString.append_chars(&self, String str)
data.len += other_len;
}
fn Char32[] DString.copy_utf32(&self, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn Char32[] DString.copy_utf32(&self, Allocator* allocator = mem::heap())
{
return self.str_view().to_new_utf32(allocator, env) @inline!!;
return self.str_view().to_new_utf32(allocator) @inline!!;
}
fn void DString.append_string(&self, DString str)
@@ -354,7 +354,7 @@ fn usz! DString.appendfn(&self, String format, args...) @maydiscard
return len + 1;
}
fn DString new_join(String[] s, String joiner, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn DString new_join(String[] s, String joiner, Allocator* allocator = mem::heap())
{
if (!s.len) return (DString)null;
usz total_size = joiner.len * s.len;
@@ -362,7 +362,7 @@ fn DString new_join(String[] s, String joiner, Allocator* allocator = mem::heap(
{
total_size += str.len;
}
DString res = new_with_capacity(total_size, allocator, env);
DString res = new_with_capacity(total_size, allocator);
res.append(s[0]);
foreach (String* &str : s[1..])
{
@@ -384,12 +384,12 @@ fn StringData* DString.data(self) @inline @private
return (StringData*)self;
}
fn void DString.reserve(&self, usz addition, TrackingEnv* env = mem::get_tracking_env())
fn void DString.reserve(&self, usz addition)
{
StringData* data = self.data();
if (!data)
{
*self = dstring::new_with_capacity(addition, .env = env);
*self = dstring::new_with_capacity(addition);
return;
}
usz len = data.len + addition;
@@ -398,7 +398,7 @@ fn void DString.reserve(&self, usz addition, TrackingEnv* env = mem::get_trackin
if (new_capacity < MIN_CAPACITY) new_capacity = MIN_CAPACITY;
while (new_capacity < len) new_capacity *= 2;
data.capacity = new_capacity;
*self = (DString)data.allocator.realloc(data, StringData.sizeof + new_capacity, env);
*self = (DString)data.allocator.realloc(data, StringData.sizeof + new_capacity);
}
fn usz! DString.read_from_stream(&self, InStream* reader)

View File

@@ -520,9 +520,9 @@ macro TrackingEnv* get_tracking_env()
$endif
}
macro @clone(value, TrackingEnv* env = mem::get_tracking_env()) @builtin
macro @clone(value) @builtin
{
return mem::heap().clone(value, env);
return mem::heap().clone(value);
}
macro @tclone(value) @builtin
@@ -530,24 +530,24 @@ macro @tclone(value) @builtin
return mem::temp().clone(value);
}
fn void* malloc(usz size, TrackingEnv* env = mem::get_tracking_env()) @builtin @inline
fn void* malloc(usz size) @builtin @inline
{
return mem::heap().alloc(size, env);
return mem::heap().alloc(size);
}
fn void* tmalloc(usz size, usz alignment = 0, usz offset = 0, TrackingEnv* env = mem::get_tracking_env()) @builtin @inline
fn void* tmalloc(usz size, usz alignment = 0, usz offset = 0) @builtin @inline
{
return temp().acquire(size, false, alignment, offset, env)!!;
return temp().acquire(size, false, alignment, offset)!!;
}
macro new($Type, TrackingEnv* env = mem::get_tracking_env())
macro new($Type)
{
return heap().new($Type, .env = env);
return heap().new($Type);
}
macro new_clear($Type, TrackingEnv* env = mem::get_tracking_env())
macro new_clear($Type)
{
return heap().new_clear($Type, env);
return heap().new_clear($Type);
}
macro new_temp($Type)
@@ -560,9 +560,9 @@ macro new_temp_clear($Type)
return tcalloc($Type.sizeof);
}
macro new_array($Type, usz elements, TrackingEnv* env = mem::get_tracking_env())
macro new_array($Type, usz elements)
{
return heap().new_array($Type, elements, .env = env);
return heap().new_array($Type, elements);
}
macro temp_array($Type, usz elements)
@@ -570,9 +570,9 @@ macro temp_array($Type, usz elements)
return (($Type*)tmalloc($Type.sizeof * elements, $Type.alignof))[:elements];
}
macro new_zero_array($Type, usz elements, TrackingEnv* env = mem::get_tracking_env())
macro new_zero_array($Type, usz elements)
{
return heap().new_zero_array($Type, elements, env);
return heap().new_zero_array($Type, elements);
}
macro temp_zero_array($Type, usz elements)
@@ -580,28 +580,28 @@ macro temp_zero_array($Type, usz elements)
return (($Type*)tcalloc($Type.sizeof * elements, $Type.alignof))[:elements];
}
fn void* calloc(usz size, TrackingEnv* env = mem::get_tracking_env()) @builtin @inline
fn void* calloc(usz size) @builtin @inline
{
return heap().calloc(size, env);
return heap().calloc(size);
}
fn void* tcalloc(usz size, usz alignment = 0, usz offset = 0) @builtin @inline
{
return temp().acquire(size, false, alignment, offset, null)!!;
return temp().acquire(size, false, alignment, offset)!!;
}
fn void* realloc(void *ptr, usz new_size, TrackingEnv* env = mem::get_tracking_env()) @builtin @inline
fn void* realloc(void *ptr, usz new_size) @builtin @inline
{
return heap().realloc(ptr, new_size, env);
return heap().realloc(ptr, new_size);
}
fn void free(void* ptr, TrackingEnv* env = mem::get_tracking_env()) @builtin @inline
fn void free(void* ptr) @builtin @inline
{
heap().free(ptr, env);
heap().free(ptr);
}
fn void* trealloc(void* ptr, usz size, usz alignment = mem::DEFAULT_MEM_ALIGNMENT) @builtin @inline
{
return temp().resize(ptr, size, alignment, 0, null)!!;
return temp().resize(ptr, size, alignment, 0)!!;
}

View File

@@ -15,9 +15,9 @@ interface Allocator
{
fn void reset(usz mark) @optional;
fn usz mark() @optional;
fn void*! acquire(usz size, bool clear, usz alignment, usz offset, TrackingEnv* env);
fn void*! resize(void* ptr, usz new_size, usz alignment, usz offset, TrackingEnv* env);
fn void release(void* ptr, bool aligned, TrackingEnv* env);
fn void*! acquire(usz size, bool clear, usz alignment, usz offset);
fn void*! resize(void* ptr, usz new_size, usz alignment, usz offset);
fn void release(void* ptr, bool aligned);
}
struct AlignedBlock
@@ -107,118 +107,118 @@ fn usz alignment_for_allocation(usz alignment) @inline @private
// Allocator "functions"
macro void*! Allocator.alloc_checked(&self, usz size, TrackingEnv* env = mem::get_tracking_env())
macro void*! Allocator.alloc_checked(&self, usz size)
{
$if env::TESTING:
char* data = self.acquire(size, false, 0, 0, env)!;
char* data = self.acquire(size, false, 0, 0)!;
mem::set(data, 0xAA, size, mem::DEFAULT_MEM_ALIGNMENT);
return data;
$else
return self.acquire(size, false, 0, 0, env);
return self.acquire(size, false, 0, 0);
$endif
}
macro void*! Allocator.calloc_checked(&self, usz size, TrackingEnv* env = mem::get_tracking_env())
macro void*! Allocator.calloc_checked(&self, usz size)
{
return self.acquire(size, true, 0, 0, env);
return self.acquire(size, true, 0, 0);
}
macro void*! Allocator.realloc_checked(&self, void* ptr, usz new_size, TrackingEnv* env = mem::get_tracking_env())
macro void*! Allocator.realloc_checked(&self, void* ptr, usz new_size)
{
return self.resize(ptr, new_size, 0, 0, env);
return self.resize(ptr, new_size, 0, 0);
}
macro Allocator.new_array(&self, $Type, usz size, usz end_padding = 0, TrackingEnv* env = mem::get_tracking_env())
macro Allocator.new_array(&self, $Type, usz size, usz end_padding = 0)
{
return (($Type*)self.alloc_checked($Type.sizeof * size + end_padding, env))[:size]!!;
return (($Type*)self.alloc_checked($Type.sizeof * size + end_padding))[:size]!!;
}
macro Allocator.new_array_checked(&self, $Type, usz size, usz end_padding = 0, TrackingEnv* env = mem::get_tracking_env())
macro Allocator.new_array_checked(&self, $Type, usz size, usz end_padding = 0)
{
return (($Type*)self.alloc_checked($Type.sizeof * size + end_padding, env))[:size];
return (($Type*)self.alloc_checked($Type.sizeof * size + end_padding))[:size];
}
macro Allocator.new_zero_array(&self, $Type, usz size, usz end_padding = 0, TrackingEnv* env = mem::get_tracking_env())
macro Allocator.new_zero_array(&self, $Type, usz size, usz end_padding = 0)
{
return (($Type*)self.calloc_checked($Type.sizeof * size + end_padding, env))[:size]!!;
return (($Type*)self.calloc_checked($Type.sizeof * size + end_padding))[:size]!!;
}
macro Allocator.new_zero_array_checked(&self, $Type, usz size, usz end_padding = 0, TrackingEnv* env = mem::get_tracking_env())
macro Allocator.new_zero_array_checked(&self, $Type, usz size, usz end_padding = 0)
{
return (($Type*)self.calloc_checked($Type.sizeof * size + end_padding, env))[:size];
return (($Type*)self.calloc_checked($Type.sizeof * size + end_padding))[:size];
}
macro Allocator.new(&self, $Type, usz end_padding = 0, TrackingEnv* env = mem::get_tracking_env()) @nodiscard
macro Allocator.new(&self, $Type, usz end_padding = 0) @nodiscard
{
return ($Type*)self.alloc_checked($Type.sizeof + end_padding, env)!!;
return ($Type*)self.alloc_checked($Type.sizeof + end_padding)!!;
}
macro Allocator.new_checked(&self, $Type, usz end_padding = 0, TrackingEnv* env = mem::get_tracking_env()) @nodiscard
macro Allocator.new_checked(&self, $Type, usz end_padding = 0) @nodiscard
{
return ($Type*)self.alloc_checked($Type.sizeof + end_padding, env);
return ($Type*)self.alloc_checked($Type.sizeof + end_padding);
}
macro Allocator.new_clear(&self, $Type, usz end_padding = 0, TrackingEnv* env = mem::get_tracking_env()) @nodiscard
macro Allocator.new_clear(&self, $Type, usz end_padding = 0) @nodiscard
{
return ($Type*)self.calloc_checked($Type.sizeof + end_padding, env)!!;
return ($Type*)self.calloc_checked($Type.sizeof + end_padding)!!;
}
macro Allocator.new_clear_checked(&self, $Type, usz end_padding = 0, TrackingEnv* env = mem::get_tracking_env()) @nodiscard
macro Allocator.new_clear_checked(&self, $Type, usz end_padding = 0) @nodiscard
{
return ($Type*)self.calloc_checked($Type.sizeof + end_padding, env);
return ($Type*)self.calloc_checked($Type.sizeof + end_padding);
}
macro Allocator.clone(&self, value, TrackingEnv* env = mem::get_tracking_env())
macro Allocator.clone(&self, value)
{
var x = self.alloc($typeof(value), env);
var x = self.alloc($typeof(value));
*x = value;
return x;
}
macro void* Allocator.alloc(&self, usz size, TrackingEnv* env = mem::get_tracking_env()) @nodiscard
macro void* Allocator.alloc(&self, usz size) @nodiscard
{
return self.alloc_checked(size, env)!!;
return self.alloc_checked(size)!!;
}
macro void* Allocator.calloc(&self, usz size, TrackingEnv* env = mem::get_tracking_env()) @nodiscard
macro void* Allocator.calloc(&self, usz size) @nodiscard
{
return self.acquire(size, true, 0, 0, env)!!;
return self.acquire(size, true, 0, 0)!!;
}
macro void* Allocator.realloc(&self, void* ptr, usz new_size, TrackingEnv* env = mem::get_tracking_env()) @nodiscard
macro void* Allocator.realloc(&self, void* ptr, usz new_size) @nodiscard
{
return self.resize(ptr, new_size, 0, 0, env)!!;
return self.resize(ptr, new_size, 0, 0)!!;
}
macro void*! Allocator.alloc_aligned(&self, usz size, usz alignment, usz offset = 0, TrackingEnv* env = mem::get_tracking_env())
macro void*! Allocator.alloc_aligned(&self, usz size, usz alignment, usz offset = 0)
{
$if env::TESTING:
char* data = self.acquire(size, false, alignment, offset, env)!;
char* data = self.acquire(size, false, alignment, offset)!;
mem::set(data, 0xAA, size, mem::DEFAULT_MEM_ALIGNMENT);
return data;
$else
return self.acquire(size, false, alignment, offset, env);
return self.acquire(size, false, alignment, offset);
$endif
}
macro void*! Allocator.calloc_aligned(&self, usz size, usz alignment, usz offset = 0, TrackingEnv* env = mem::get_tracking_env())
macro void*! Allocator.calloc_aligned(&self, usz size, usz alignment, usz offset = 0)
{
return self.acquire(size, true, alignment, offset, env);
return self.acquire(size, true, alignment, offset);
}
macro void*! Allocator.realloc_aligned(&self, void* ptr, usz new_size, usz alignment = 0, usz offset = 0, TrackingEnv* env = mem::get_tracking_env())
macro void*! Allocator.realloc_aligned(&self, void* ptr, usz new_size, usz alignment = 0, usz offset = 0)
{
return self.resize(ptr, new_size, alignment, offset, env);
return self.resize(ptr, new_size, alignment, offset);
}
macro void Allocator.free(&self, void* ptr, TrackingEnv* env = mem::get_tracking_env())
macro void Allocator.free(&self, void* ptr)
{
$if env::TESTING:
if (ptr) ((char*)ptr)[0] = 0xBA;
$endif
self.release(ptr, false, env);
self.release(ptr, false);
}
macro void Allocator.free_aligned(&self, void* ptr, TrackingEnv* env = mem::get_tracking_env())
macro void Allocator.free_aligned(&self, void* ptr)
{
$if env::TESTING:
if (ptr) ((char*)ptr)[0] = 0xBA;
$endif
self.release(ptr, true, env);
self.release(ptr, true);
}

View File

@@ -38,13 +38,13 @@ macro String tformat(String fmt, ...)
return str.str_view();
}
macro String new_format(String fmt, ..., Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
macro String new_format(String fmt, ..., Allocator* allocator = mem::heap())
{
@pool(allocator)
{
DString str = dstring::temp_with_capacity(fmt.len + $vacount * 8);
str.appendf(fmt, $vasplat());
return str.copy_str(allocator, env);
return str.copy_str(allocator);
};
}
@@ -55,11 +55,11 @@ macro bool char_in_set(char c, String set)
return false;
}
fn String join_new(String[] s, String joiner, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn String join_new(String[] s, String joiner, Allocator* allocator = mem::heap())
{
if (!s)
{
return (String)allocator.new_zero_array(char, 2, .env = env)[:0];
return (String)allocator.new_zero_array(char, 2)[:0];
}
usz total_size = joiner.len * s.len;
@@ -76,7 +76,7 @@ fn String join_new(String[] s, String joiner, Allocator* allocator = mem::heap()
res.append(joiner);
res.append(*str);
}
return res.copy_str(allocator, env);
return res.copy_str(allocator);
};
}
@@ -153,11 +153,11 @@ fn String String.strip_end(string, String needle)
* @require needle.len > 0 "The needle must be at least 1 character long"
* @ensure return.len > 0
**/
fn String[] String.split(s, String needle, usz max = 0, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn String[] String.split(s, String needle, usz max = 0, Allocator* allocator = mem::heap())
{
usz capacity = 16;
usz i = 0;
String* holder = allocator.new_array(String, capacity, .env = env);
String* holder = allocator.new_array(String, capacity);
bool no_more = false;
while (!no_more)
{
@@ -176,7 +176,7 @@ fn String[] String.split(s, String needle, usz max = 0, Allocator* allocator = m
if (i == capacity)
{
capacity *= 2;
holder = allocator.realloc(holder, String.sizeof * capacity, env);
holder = allocator.realloc(holder, String.sizeof * capacity);
}
holder[i++] = res;
}
@@ -312,19 +312,19 @@ fn usz ZString.len(str)
}
fn ZString String.zstr_copy(s, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn ZString String.zstr_copy(s, Allocator* allocator = mem::heap())
{
usz len = s.len;
char* str = allocator.alloc(len + 1, env);
char* str = allocator.alloc(len + 1);
mem::copy(str, s.ptr, len);
str[len] = 0;
return (ZString)str;
}
fn String String.concat(s1, String s2, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn String String.concat(s1, String s2, Allocator* allocator = mem::heap())
{
usz full_len = s1.len + s2.len;
char* str = allocator.alloc(full_len + 1, env);
char* str = allocator.alloc(full_len + 1);
usz s1_len = s1.len;
mem::copy(str, s1.ptr, s1_len);
mem::copy(str + s1_len, s2.ptr, s2.len);
@@ -337,27 +337,27 @@ fn String String.tconcat(s1, String s2) => s1.concat(s2, mem::temp());
fn ZString String.zstr_tcopy(s) => s.zstr_copy(mem::temp()) @inline;
fn String String.copy(s, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn String String.copy(s, Allocator* allocator = mem::heap())
{
usz len = s.len;
char* str = allocator.alloc(len + 1, env);
char* str = allocator.alloc(len + 1);
mem::copy(str, s.ptr, len);
str[len] = 0;
return (String)str[:len];
}
fn void String.free(&s, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn void String.free(&s, Allocator* allocator = mem::heap())
{
if (!s.len) return;
allocator.free(s.ptr, env);
allocator.free(s.ptr);
*s = "";
}
fn String String.tcopy(s) => s.copy(mem::temp()) @inline;
fn String ZString.copy(z, Allocator* allocator = mem::temp(), TrackingEnv* env = mem::get_tracking_env())
fn String ZString.copy(z, Allocator* allocator = mem::temp())
{
return z.str_view().copy(allocator, env) @inline;
return z.str_view().copy(allocator) @inline;
}
fn String ZString.tcopy(z)
@@ -371,10 +371,10 @@ fn String ZString.tcopy(z)
* @return! UnicodeResult.INVALID_UTF8 "If the string contained an invalid UTF-8 sequence"
* @return! AllocationFailure "If allocation of the string fails"
**/
fn Char16[]! String.to_new_utf16(s, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn Char16[]! String.to_new_utf16(s, Allocator* allocator = mem::heap())
{
usz len16 = conv::utf16len_for_utf8(s);
Char16* data = allocator.new_array_checked(Char16, len16 + 1, .env = env)!;
Char16* data = allocator.new_array_checked(Char16, len16 + 1)!;
conv::utf8to16_unsafe(s, data)!;
data[len16] = 0;
return data[:len16];
@@ -391,9 +391,9 @@ fn Char16[]! String.to_temp_utf16(s)
return s.to_new_utf16(mem::temp());
}
fn WString! String.to_new_wstring(s, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn WString! String.to_new_wstring(s, Allocator* allocator = mem::heap())
{
return (WString)s.to_new_utf16(allocator, env).ptr;
return (WString)s.to_new_utf16(allocator).ptr;
}
fn WString! String.to_temp_wstring(s)
@@ -401,10 +401,10 @@ fn WString! String.to_temp_wstring(s)
return (WString)s.to_temp_utf16().ptr;
}
fn Char32[]! String.to_new_utf32(s, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn Char32[]! String.to_new_utf32(s, Allocator* allocator = mem::heap())
{
usz codepoints = conv::utf8_codepoints(s);
Char32* data = allocator.new_array(Char32, codepoints + 1, .env = env);
Char32* data = allocator.new_array(Char32, codepoints + 1);
conv::utf8to32_unsafe(s, data)!;
data[codepoints] = 0;
return data[:codepoints];
@@ -449,32 +449,32 @@ fn String String.temp_ascii_to_upper(s)
return s.new_ascii_to_upper(mem::temp());
}
fn String! new_from_utf32(Char32[] utf32, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn String! new_from_utf32(Char32[] utf32, Allocator* allocator = mem::heap())
{
usz len = conv::utf8len_for_utf32(utf32);
char* data = allocator.alloc_checked(len + 1, env)!;
char* data = allocator.alloc_checked(len + 1)!;
defer catch allocator.free(data);
conv::utf32to8_unsafe(utf32, data);
data[len] = 0;
return (String)data[:len];
}
fn String! new_from_utf16(Char16[] utf16, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn String! new_from_utf16(Char16[] utf16, Allocator* allocator = mem::heap())
{
usz len = conv::utf8len_for_utf16(utf16);
char* data = allocator.alloc_checked(len + 1, env)!;
char* data = allocator.alloc_checked(len + 1)!;
defer catch allocator.free(data);
conv::utf16to8_unsafe(utf16, data)!;
data[len] = 0;
return (String)data[:len];
}
fn String! new_from_wstring(WString wstring, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn String! new_from_wstring(WString wstring, Allocator* allocator = mem::heap())
{
usz utf16_len;
while (wstring[utf16_len] != 0) utf16_len++;
Char16[] utf16 = wstring[:utf16_len];
return new_from_utf16(utf16, allocator, env);
return new_from_utf16(utf16, allocator);
}
fn String! temp_from_wstring(WString wstring) => new_from_wstring(wstring, mem::temp()) @inline;

View File

@@ -16,11 +16,11 @@ struct ByteBuffer (InStream, OutStream)
* max_read defines how many bytes might be kept before its internal buffer is shrinked.
* @require self.bytes.len == 0 "Buffer already initialized."
**/
fn ByteBuffer*! ByteBuffer.init_new(&self, usz max_read, usz initial_capacity = 16, Allocator* allocator = mem::heap(), TrackingEnv* env = mem::get_tracking_env())
fn ByteBuffer*! ByteBuffer.init_new(&self, usz max_read, usz initial_capacity = 16, Allocator* allocator = mem::heap())
{
*self = { .allocator = allocator, .max_read = max_read };
initial_capacity = max(initial_capacity, 16);
self.grow(initial_capacity, env)!;
self.grow(initial_capacity)!;
return self;
}
@@ -128,10 +128,10 @@ fn usz! ByteBuffer.available(&self) @inline @dynamic
return self.write_idx - self.read_idx;
}
fn void! ByteBuffer.grow(&self, usz n, TrackingEnv* env = mem::get_tracking_env())
fn void! ByteBuffer.grow(&self, usz n)
{
n = math::next_power_of_2(n);
char* p = self.allocator.realloc_aligned(self.bytes, n, .alignment = char.alignof, .env = env)!;
char* p = self.allocator.realloc_aligned(self.bytes, n, .alignment = char.alignof)!;
self.bytes = p[:n];
}

View File

@@ -74,7 +74,7 @@ fn Backtrace* Backtrace.init(&self, uptr offset, String function, String object_
return self;
}
fn void*[] capture_current(void*[] buffer) @if(env::POSIX || env::WIN32)
fn void*[] capture_current(void*[] buffer)
{
if (!buffer.len) return buffer[:0];
$switch
@@ -94,3 +94,8 @@ def BacktraceList = List(<Backtrace>);
def symbolize_backtrace = linux::symbolize_backtrace @if(env::LINUX);
def symbolize_backtrace = win32::symbolize_backtrace @if(env::WIN32);
def symbolize_backtrace = darwin::symbolize_backtrace @if(env::DARWIN);
fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator* allocator) @if(!env::NATIVE_STACKTRACE)
{
return {};
}

View File

@@ -3,6 +3,7 @@
## 0.5.0 Change List
### Changes / improvements
- Trackable allocator with leak allocation backtraces.
- `$defined` can take a list of expressions.
- `$and` compile time "and" which does not check expressions after the first is an error.
- `$is_const` returns true if an expression is compile time const.

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.704"
#define COMPILER_VERSION "0.4.705"

View File

@@ -81,7 +81,6 @@ entry:
%type = load ptr, ptr %.cachedtype, align 8
%4 = icmp eq ptr %3, %type
br i1 %4, label %cache_hit, label %cache_miss
cache_miss: ; preds = %entry
%5 = getelementptr inbounds %.introspect, ptr %3, i32 0, i32 2
%6 = load ptr, ptr %5, align 8
@@ -89,36 +88,29 @@ cache_miss: ; preds = %entry
store ptr %7, ptr %.inlinecache, align 8
store ptr %3, ptr %.cachedtype, align 8
br label %8
cache_hit: ; preds = %entry
%cache_hit_fn = load ptr, ptr %.inlinecache, align 8
br label %8
8: ; preds = %cache_hit, %cache_miss
%fn_phi = phi ptr [ %cache_hit_fn, %cache_hit ], [ %7, %cache_miss ]
%9 = icmp eq ptr %fn_phi, null
br i1 %9, label %missing_function, label %match
missing_function: ; preds = %8
%10 = load ptr, ptr @std.core.builtin.panic, align 8
call void %10(ptr @.panic_msg, i64 44, ptr @.file, i64 16
unreachable
match: ; preds = %8
%11 = load ptr, ptr %2, align 8
%12 = call i64 %fn_phi(ptr %retparam, ptr %11, i64 8, i8 zeroext 0, i64 0, i64 0, ptr null)
%12 = call i64 %fn_phi(ptr %retparam, ptr %11, i64 8, i8 zeroext 0, i64 0, i64 0)
%not_err = icmp eq i64 %12, 0
%13 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
br i1 %13, label %after_check, label %assign_optional
assign_optional: ; preds = %match
store i64 %12, ptr %error_var, align 8
br label %panic_block
after_check: ; preds = %match
%14 = load ptr, ptr %retparam, align 8
br label %noerr_block
panic_block: ; preds = %assign_optional
%15 = insertvalue %"any*" undef, ptr %error_var, 0
%16 = insertvalue %"any*" %15, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1
@@ -129,7 +121,6 @@ panic_block: ; preds = %assign_optional
store %"any*[]" %"$$temp", ptr %indirectarg, align 8
call void @std.core.builtin.panicf(ptr @.panic_msg.1, i64 36, ptr @.file
unreachable
noerr_block: ; preds = %after_check
%19 = insertvalue %"any*" undef, ptr %14, 0
%20 = insertvalue %"any*" %19, i64 ptrtoint (ptr @"$ct.inherit.Test" to i64), 1
@@ -141,7 +132,6 @@ noerr_block: ; preds = %after_check
%type4 = load ptr, ptr %.cachedtype3, align 8
%25 = icmp eq ptr %24, %type4
br i1 %25, label %cache_hit6, label %cache_miss5
cache_miss5: ; preds = %noerr_block
%26 = getelementptr inbounds %.introspect, ptr %24, i32 0, i32 2
%27 = load ptr, ptr %26, align 8
@@ -149,21 +139,17 @@ cache_miss5: ; preds = %noerr_block
store ptr %28, ptr %.inlinecache2, align 8
store ptr %24, ptr %.cachedtype3, align 8
br label %29
cache_hit6: ; preds = %noerr_block
%cache_hit_fn7 = load ptr, ptr %.inlinecache2, align 8
br label %29
29: ; preds = %cache_hit6, %cache_miss5
%fn_phi8 = phi ptr [ %cache_hit_fn7, %cache_hit6 ], [ %28, %cache_miss5 ]
%30 = icmp eq ptr %fn_phi8, null
br i1 %30, label %missing_function9, label %match10
missing_function9: ; preds = %29
%31 = load ptr, ptr @std.core.builtin.panic, align 8
call void %31(ptr @.panic_msg.2, i64 41
unreachable
match10: ; preds = %29
%32 = load ptr, ptr %23, align 8
call void %fn_phi8(ptr %32)
@@ -176,7 +162,6 @@ match10: ; preds = %29
%type13 = load ptr, ptr %.cachedtype12, align 8
%38 = icmp eq ptr %37, %type13
br i1 %38, label %cache_hit15, label %cache_miss14
cache_miss14: ; preds = %match10
%39 = getelementptr inbounds %.introspect, ptr %37, i32 0, i32 2
%40 = load ptr, ptr %39, align 8
@@ -184,21 +169,17 @@ cache_miss14: ; preds = %match10
store ptr %41, ptr %.inlinecache11, align 8
store ptr %37, ptr %.cachedtype12, align 8
br label %42
cache_hit15: ; preds = %match10
%cache_hit_fn16 = load ptr, ptr %.inlinecache11, align 8
br label %42
42: ; preds = %cache_hit15, %cache_miss14
%fn_phi17 = phi ptr [ %cache_hit_fn16, %cache_hit15 ], [ %41, %cache_miss14 ]
%43 = icmp eq ptr %fn_phi17, null
br i1 %43, label %missing_function18, label %match19
missing_function18: ; preds = %42
%44 = load ptr, ptr @std.core.builtin.panic, align 8
call void %44(ptr @.panic_msg.2, i64 41, ptr @.file.3, i64 10, ptr @.func, i64 4, i32 36)
unreachable
match19: ; preds = %42
%45 = load ptr, ptr %36, align 8
call void %fn_phi17(ptr %45)
@@ -209,25 +190,20 @@ match19: ; preds = %42
define weak_odr ptr @.dyn_search(ptr %0, ptr %1) unnamed_addr {
entry:
br label %check
check: ; preds = %no_match, %entry
%2 = phi ptr [ %0, %entry ], [ %9, %no_match ]
%3 = icmp eq ptr %2, null
br i1 %3, label %missing_function, label %compare
missing_function: ; preds = %check
ret ptr null
compare: ; preds = %check
%4 = getelementptr inbounds { ptr, ptr, ptr }, ptr %2, i32 0, i32 1
%5 = load ptr, ptr %4, align 8
%6 = icmp eq ptr %5, %1
br i1 %6, label %match, label %no_match
match: ; preds = %compare
%7 = load ptr, ptr %2, align 8
ret ptr %7
no_match: ; preds = %compare
%8 = getelementptr inbounds { ptr, ptr, ptr }, ptr %2, i32 0, i32 2
%9 = load ptr, ptr %8, align 8
@@ -237,31 +213,25 @@ no_match: ; preds = %compare
define internal void @.static_initialize.0() {
entry:
br label %dtable_check
dtable_check: ; preds = %dtable_next, %entry
%dtable_ref = phi ptr [ getelementptr inbounds (%.introspect, ptr @"$ct.inherit.Test", i32 0, i32 2), %entry ], [ %next_dtable_ref, %dtable_next ]
%dtable_ptr = load ptr, ptr %dtable_ref, align 8
%0 = icmp eq ptr %dtable_ptr, null
br i1 %0, label %dtable_found, label %dtable_next
dtable_next: ; preds = %dtable_check
%next_dtable_ref = getelementptr inbounds { ptr, ptr, ptr }, ptr %dtable_ptr, i32 0, i32 2
br label %dtable_check
dtable_found: ; preds = %dtable_check
store ptr @"$ct.dyn.inherit.Test.tesT", ptr %dtable_ref, align 8
br label %dtable_check1
dtable_check1: ; preds = %dtable_next4, %dtable_found
%dtable_ref2 = phi ptr [ getelementptr inbounds (%.introspect, ptr @"$ct.inherit.Test", i32 0, i32 2), %dtable_found ], [ %next_dtable_ref5, %dtable_next4 ]
%dtable_ptr3 = load ptr, ptr %dtable_ref2, align 8
%1 = icmp eq ptr %dtable_ptr3, null
br i1 %1, label %dtable_found6, label %dtable_next4
dtable_next4: ; preds = %dtable_check1
%next_dtable_ref5 = getelementptr inbounds { ptr, ptr, ptr }, ptr %dtable_ptr3, i32 0, i32 2
br label %dtable_check1
dtable_found6: ; preds = %dtable_check1
store ptr @"$ct.dyn.inherit.Test.hello", ptr %dtable_ref2, align 8
ret void

View File

@@ -68,7 +68,6 @@ entry:
%type = load ptr, ptr %.cachedtype, align 8
%4 = icmp eq ptr %3, %type
br i1 %4, label %cache_hit, label %cache_miss
cache_miss: ; preds = %entry
%5 = getelementptr inbounds %.introspect, ptr %3, i32 0, i32 2
%6 = load ptr, ptr %5, align 8
@@ -76,36 +75,29 @@ cache_miss: ; preds = %entry
store ptr %7, ptr %.inlinecache, align 8
store ptr %3, ptr %.cachedtype, align 8
br label %8
cache_hit: ; preds = %entry
%cache_hit_fn = load ptr, ptr %.inlinecache, align 8
br label %8
8: ; preds = %cache_hit, %cache_miss
%fn_phi = phi ptr [ %cache_hit_fn, %cache_hit ], [ %7, %cache_miss ]
%9 = icmp eq ptr %fn_phi, null
br i1 %9, label %missing_function, label %match
missing_function: ; preds = %8
%10 = load ptr, ptr @std.core.builtin.panic, align 8
call void %10(ptr @.panic_msg, i64 44, ptr @.file, i64 16, ptr @.func, i64 4
unreachable
match: ; preds = %8
%11 = load ptr, ptr %2, align 8
%12 = call i64 %fn_phi(ptr %retparam, ptr %11, i64 8, i8 zeroext 0, i64 0, i64 0, ptr null)
%12 = call i64 %fn_phi(ptr %retparam, ptr %11, i64 8, i8 zeroext 0, i64 0, i64 0)
%not_err = icmp eq i64 %12, 0
%13 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
br i1 %13, label %after_check, label %assign_optional
assign_optional: ; preds = %match
store i64 %12, ptr %error_var, align 8
br label %panic_block
after_check: ; preds = %match
%14 = load ptr, ptr %retparam, align 8
br label %noerr_block
panic_block: ; preds = %assign_optional
%15 = insertvalue %"any*" undef, ptr %error_var, 0
%16 = insertvalue %"any*" %15, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1
@@ -116,7 +108,6 @@ panic_block: ; preds = %assign_optional
store %"any*[]" %"$$temp", ptr %indirectarg, align 8
call void @std.core.builtin.panicf(ptr @.panic_msg.1
unreachable
noerr_block: ; preds = %after_check
%19 = insertvalue %"any*" undef, ptr %14, 0
%20 = insertvalue %"any*" %19, i64 ptrtoint (ptr @"$ct.overlap.Test" to i64), 1
@@ -128,7 +119,6 @@ noerr_block: ; preds = %after_check
%type4 = load ptr, ptr %.cachedtype3, align 8
%25 = icmp eq ptr %24, %type4
br i1 %25, label %cache_hit6, label %cache_miss5
cache_miss5: ; preds = %noerr_block
%26 = getelementptr inbounds %.introspect, ptr %24, i32 0, i32 2
%27 = load ptr, ptr %26, align 8
@@ -136,21 +126,17 @@ cache_miss5: ; preds = %noerr_block
store ptr %28, ptr %.inlinecache2, align 8
store ptr %24, ptr %.cachedtype3, align 8
br label %29
cache_hit6: ; preds = %noerr_block
%cache_hit_fn7 = load ptr, ptr %.inlinecache2, align 8
br label %29
29: ; preds = %cache_hit6, %cache_miss5
%fn_phi8 = phi ptr [ %cache_hit_fn7, %cache_hit6 ], [ %28, %cache_miss5 ]
%30 = icmp eq ptr %fn_phi8, null
br i1 %30, label %missing_function9, label %match10
missing_function9: ; preds = %29
%31 = load ptr, ptr @std.core.builtin.panic, align 8
call void %31(ptr @.panic_msg.2, i64 41, ptr @.file
unreachable
match10: ; preds = %29
%32 = load ptr, ptr %23, align 8
call void %fn_phi8(ptr %32)
@@ -163,7 +149,6 @@ match10: ; preds = %29
%type13 = load ptr, ptr %.cachedtype12, align 8
%38 = icmp eq ptr %37, %type13
br i1 %38, label %cache_hit15, label %cache_miss14
cache_miss14: ; preds = %match10
%39 = getelementptr inbounds %.introspect, ptr %37, i32 0, i32 2
%40 = load ptr, ptr %39, align 8
@@ -171,21 +156,17 @@ cache_miss14: ; preds = %match10
store ptr %41, ptr %.inlinecache11, align 8
store ptr %37, ptr %.cachedtype12, align 8
br label %42
cache_hit15: ; preds = %match10
%cache_hit_fn16 = load ptr, ptr %.inlinecache11, align 8
br label %42
42: ; preds = %cache_hit15, %cache_miss14
%fn_phi17 = phi ptr [ %cache_hit_fn16, %cache_hit15 ], [ %41, %cache_miss14 ]
%43 = icmp eq ptr %fn_phi17, null
br i1 %43, label %missing_function18, label %match19
missing_function18: ; preds = %42
%44 = load ptr, ptr @std.core.builtin.panic, align 8
call void %44(ptr @.panic_msg.2, i64 41, ptr @.file.3, i64 23, ptr @.func, i64 4, i32 30)
unreachable
match19: ; preds = %42
%45 = load ptr, ptr %36, align 8
call void %fn_phi17(ptr %45)
@@ -194,31 +175,25 @@ match19: ; preds = %42
define internal void @.static_initialize.0() {
entry:
br label %dtable_check
dtable_check: ; preds = %dtable_next, %entry
%dtable_ref = phi ptr [ getelementptr inbounds (%.introspect, ptr @"$ct.overlap.Test", i32 0, i32 2), %entry ], [ %next_dtable_ref, %dtable_next ]
%dtable_ptr = load ptr, ptr %dtable_ref, align 8
%0 = icmp eq ptr %dtable_ptr, null
br i1 %0, label %dtable_found, label %dtable_next
dtable_next: ; preds = %dtable_check
%next_dtable_ref = getelementptr inbounds { ptr, ptr, ptr }, ptr %dtable_ptr, i32 0, i32 2
br label %dtable_check
dtable_found: ; preds = %dtable_check
store ptr @"$ct.dyn.overlap.Test.tesT", ptr %dtable_ref, align 8
br label %dtable_check1
dtable_check1: ; preds = %dtable_next4, %dtable_found
%dtable_ref2 = phi ptr [ getelementptr inbounds (%.introspect, ptr @"$ct.overlap.Test", i32 0, i32 2), %dtable_found ], [ %next_dtable_ref5, %dtable_next4 ]
%dtable_ptr3 = load ptr, ptr %dtable_ref2, align 8
%1 = icmp eq ptr %dtable_ptr3, null
br i1 %1, label %dtable_found6, label %dtable_next4
dtable_next4: ; preds = %dtable_check1
%next_dtable_ref5 = getelementptr inbounds { ptr, ptr, ptr }, ptr %dtable_ptr3, i32 0, i32 2
br label %dtable_check1
dtable_found6: ; preds = %dtable_check1
store ptr @"$ct.dyn.overlap.Test.foo", ptr %dtable_ref2, align 8
ret void

View File

@@ -332,7 +332,7 @@ if.then7: ; preds = %if.exit4
%15 = getelementptr inbounds %Doc, ptr %literal9, i32 0, i32 0
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %literal10, ptr align 8 @.__const.5, i32 8, i1 false)
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %value, ptr align 8 %literal10, i32 8, i1 false)
%16 = call ptr @std.core.mem.malloc(i64 8, ptr null) #3
%16 = call ptr @std.core.mem.malloc(i64 8) #3
store ptr %16, ptr %temp, align 8
%17 = load ptr, ptr %temp, align 8
%not = icmp eq ptr %17, null
@@ -371,7 +371,7 @@ if.then16: ; preds = %if.exit13
store ptr null, ptr %literal20, align 8
%26 = getelementptr inbounds %Head, ptr %literal20, i32 0, i32 0
store %"char[]" zeroinitializer, ptr %value22, align 8
%27 = call ptr @std.core.mem.malloc(i64 16, ptr null) #3
%27 = call ptr @std.core.mem.malloc(i64 16) #3
store ptr %27, ptr %temp23, align 8
%28 = load ptr, ptr %temp23, align 8
%not24 = icmp eq ptr %28, null
@@ -394,7 +394,7 @@ noerr_block28: ; preds = %if.exit26
%31 = load ptr, ptr %temp23, align 8
store ptr %31, ptr %26, align 8
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %value29, ptr align 8 %literal20, i32 8, i1 false)
%32 = call ptr @std.core.mem.malloc(i64 8, ptr null) #3
%32 = call ptr @std.core.mem.malloc(i64 8) #3
store ptr %32, ptr %temp30, align 8
%33 = load ptr, ptr %temp30, align 8
%not31 = icmp eq ptr %33, null
@@ -430,7 +430,7 @@ if.exit36: ; preds = %if.exit13
store i64 %sext, ptr %len, align 8
%42 = load i64, ptr %len, align 8
%add = add i64 %42, 1
%43 = call ptr @std.core.mem.malloc(i64 %add, ptr null) #3
%43 = call ptr @std.core.mem.malloc(i64 %add) #3
store ptr %43, ptr %str, align 8
%44 = load ptr, ptr %str, align 8
%not37 = icmp eq ptr %44, null
@@ -461,7 +461,7 @@ if.exit39: ; preds = %if.exit36
%57 = insertvalue %"char[]" undef, ptr %ptroffset47, 0
%58 = insertvalue %"char[]" %57, i64 %size, 1
store %"char[]" %58, ptr %value48, align 8
%59 = call ptr @std.core.mem.malloc(i64 16, ptr null) #3
%59 = call ptr @std.core.mem.malloc(i64 16) #3
store ptr %59, ptr %temp49, align 8
%60 = load ptr, ptr %temp49, align 8
%not50 = icmp eq ptr %60, null
@@ -484,7 +484,7 @@ noerr_block54: ; preds = %if.exit52
%63 = load ptr, ptr %temp49, align 8
store ptr %63, ptr %53, align 8
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %value55, ptr align 8 %literal45, i32 8, i1 false)
%64 = call ptr @std.core.mem.malloc(i64 8, ptr null) #3
%64 = call ptr @std.core.mem.malloc(i64 8) #3
store ptr %64, ptr %temp56, align 8
%65 = load ptr, ptr %temp56, align 8
%not57 = icmp eq ptr %65, null

View File

@@ -66,7 +66,7 @@ entry:
%lo = load i64, ptr %3, align 8
%4 = getelementptr inbounds { i64, ptr }, ptr %allocator, i32 0, i32 1
%hi = load ptr, ptr %4, align 8
%5 = call ptr @std.core.dstring.new_with_capacity(i64 128, i64 %lo, ptr %hi, ptr null)
%5 = call ptr @std.core.dstring.new_with_capacity(i64 128, i64 %lo, ptr %hi)
store ptr %5, ptr %s, align 8
%6 = getelementptr inbounds %Foo, ptr %0, i32 0, i32 0
%7 = insertvalue %"any*" undef, ptr %6, 0
@@ -133,7 +133,7 @@ entry:
call void @llvm.memset.p0.i64(ptr align 8 %map, i8 0, i64 48, i1 false)
%lo = load i64, ptr @std.core.mem.thread_allocator, align 8
%hi = load ptr, ptr getelementptr inbounds ({ i64, ptr }, ptr @std.core.mem.thread_allocator, i32 0, i32 1), align 8
%0 = call ptr @"std.collections.map$int$test.Foo$.HashMap.init_new"(ptr %map, i32 16, float 7.500000e-01, i64 %lo, ptr %hi, ptr null)
%0 = call ptr @"std.collections.map$int$test.Foo$.HashMap.init_new"(ptr %map, i32 16, float 7.500000e-01, i64 %lo, ptr %hi)
%1 = getelementptr inbounds %HashMap, ptr %map, i32 0, i32 2
%2 = insertvalue %"any*" undef, ptr %1, 0
%3 = insertvalue %"any*" %2, i64 ptrtoint (ptr @"$ct.uint" to i64), 1
@@ -213,7 +213,7 @@ after_check14: ; preds = %entry, %after_check
call void @llvm.memset.p0.i64(ptr align 8 %map2, i8 0, i64 48, i1 false)
%lo33 = load i64, ptr @std.core.mem.thread_allocator, align 8
%hi34 = load ptr, ptr getelementptr inbounds ({ i64, ptr }, ptr @std.core.mem.thread_allocator, i32 0, i32 1), align 8
%48 = call ptr @"std.collections.map$int$double$.HashMap.init_new"(ptr %map2, i32 16, float 7.500000e-01, i64 %lo33, ptr %hi34, ptr null)
%48 = call ptr @"std.collections.map$int$double$.HashMap.init_new"(ptr %map2, i32 16, float 7.500000e-01, i64 %lo33, ptr %hi34)
%49 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map2, i32 4, double 1.300000e+00)
%50 = call i8 @"std.collections.map$int$double$.HashMap.has_value"(ptr %map2, double 1.300000e+00)
store i8 %50, ptr %taddr36, align 1
@@ -266,7 +266,7 @@ if.exit: ; preds = %if.then, %after_che
call void @llvm.memset.p0.i64(ptr align 8 %map3, i8 0, i64 48, i1 false)
%lo59 = load i64, ptr @std.core.mem.thread_allocator, align 8
%hi60 = load ptr, ptr getelementptr inbounds ({ i64, ptr }, ptr @std.core.mem.thread_allocator, i32 0, i32 1), align 8
%76 = call ptr @"std.collections.map$int$double$.HashMap.init_new"(ptr %map3, i32 16, float 7.500000e-01, i64 %lo59, ptr %hi60, ptr null)
%76 = call ptr @"std.collections.map$int$double$.HashMap.init_new"(ptr %map3, i32 16, float 7.500000e-01, i64 %lo59, ptr %hi60)
%77 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map3, i32 5, double 3.200000e+00)
%78 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map3, i32 7, double 5.200000e+00)
%lo62 = load i64, ptr @std.core.mem.thread_allocator, align 8