From ffb0021d04cc95cbff389ab577cdf97b5fc472c7 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Thu, 16 Nov 2023 23:18:43 +0100 Subject: [PATCH] Use backtrace on windows. Updated backtrace API --- lib/std/collections/bitset.c3 | 4 +- lib/std/collections/list.c3 | 4 +- lib/std/collections/map.c3 | 8 +- lib/std/collections/object.c3 | 4 +- lib/std/collections/priorityqueue.c3 | 4 +- lib/std/core/allocators/arena_allocator.c3 | 8 +- lib/std/core/allocators/dynamic_arena.c3 | 12 +- lib/std/core/allocators/heap_allocator.c3 | 10 +- lib/std/core/allocators/libc_allocator.c3 | 10 +- lib/std/core/allocators/on_stack_allocator.c3 | 12 +- lib/std/core/allocators/temp_allocator.c3 | 20 ++-- lib/std/core/allocators/tracking_allocator.c3 | 112 +++++++++++++----- lib/std/core/dstring.c3 | 46 +++---- lib/std/core/mem.c3 | 44 +++---- lib/std/core/mem_allocator.c3 | 90 +++++++------- lib/std/core/string.c3 | 60 +++++----- lib/std/io/stream/bytebuffer.c3 | 8 +- lib/std/os/backtrace.c3 | 7 +- releasenotes.md | 1 + src/version.h | 2 +- test/test_suite/dynamic/inherit.c3t | 32 +---- .../dynamic/overlapping_function.c3t | 27 +---- test/test_suite/errors/error_regression_2.c3t | 12 +- test/test_suite/stdlib/map.c3t | 8 +- 24 files changed, 272 insertions(+), 273 deletions(-) diff --git a/lib/std/collections/bitset.c3 b/lib/std/collections/bitset.c3 index 554081897..ec0c35c74 100644 --- a/lib/std/collections/bitset.c3 +++ b/lib/std/collections/bitset.c3 @@ -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; } diff --git a/lib/std/collections/list.c3 b/lib/std/collections/list.c3 index c7e37cd2a..3dc3bfc31 100644 --- a/lib/std/collections/list.c3 +++ b/lib/std/collections/list.c3 @@ -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 { diff --git a/lib/std/collections/map.c3 b/lib/std/collections/map.c3 index 105f511cf..53930d7d6 100644 --- a/lib/std/collections/map.c3 +++ b/lib/std/collections/map.c3 @@ -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; } diff --git a/lib/std/collections/object.c3 b/lib/std/collections/object.c3 index cb3a4c45f..abc3d4053 100644 --- a/lib/std/collections/object.c3 +++ b/lib/std/collections/object.c3 @@ -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; } diff --git a/lib/std/collections/priorityqueue.c3 b/lib/std/collections/priorityqueue.c3 index fd125c44d..a6410a119 100644 --- a/lib/std/collections/priorityqueue.c3 +++ b/lib/std/collections/priorityqueue.c3 @@ -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 diff --git a/lib/std/core/allocators/arena_allocator.c3 b/lib/std/core/allocators/arena_allocator.c3 index 1ca7e8a58..4a967ebe6 100644 --- a/lib/std/core/allocators/arena_allocator.c3 +++ b/lib/std/core/allocators/arena_allocator.c3 @@ -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; } \ No newline at end of file diff --git a/lib/std/core/allocators/dynamic_arena.c3 b/lib/std/core/allocators/dynamic_arena.c3 index 0278d5406..eb3aba50a 100644 --- a/lib/std/core/allocators/dynamic_arena.c3 +++ b/lib/std/core/allocators/dynamic_arena.c3 @@ -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); diff --git a/lib/std/core/allocators/heap_allocator.c3 b/lib/std/core/allocators/heap_allocator.c3 index 650598193..a298cbaaa 100644 --- a/lib/std/core/allocators/heap_allocator.c3 +++ b/lib/std/core/allocators/heap_allocator.c3 @@ -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) { diff --git a/lib/std/core/allocators/libc_allocator.c3 b/lib/std/core/allocators/libc_allocator.c3 index 085a218ca..15dd25748 100644 --- a/lib/std/core/allocators/libc_allocator.c3 +++ b/lib/std/core/allocators/libc_allocator.c3 @@ -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) { diff --git a/lib/std/core/allocators/on_stack_allocator.c3 b/lib/std/core/allocators/on_stack_allocator.c3 index 4c1cde3fb..6434a32d2 100644 --- a/lib/std/core/allocators/on_stack_allocator.c3 +++ b/lib/std/core/allocators/on_stack_allocator.c3 @@ -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; diff --git a/lib/std/core/allocators/temp_allocator.c3 b/lib/std/core/allocators/temp_allocator.c3 index 97af5554a..d46927d7b 100644 --- a/lib/std/core/allocators/temp_allocator.c3 +++ b/lib/std/core/allocators/temp_allocator.c3 @@ -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; diff --git a/lib/std/core/allocators/tracking_allocator.c3 b/lib/std/core/allocators/tracking_allocator.c3 index 4db22385b..b8704b3f4 100644 --- a/lib/std/core/allocators/tracking_allocator.c3 +++ b/lib/std/core/allocators/tracking_allocator.c3 @@ -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(); @@ -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)!; + } \ No newline at end of file diff --git a/lib/std/core/dstring.c3 b/lib/std/core/dstring.c3 index a2db4dd33..14e406356 100644 --- a/lib/std/core/dstring.c3 +++ b/lib/std/core/dstring.c3 @@ -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) diff --git a/lib/std/core/mem.c3 b/lib/std/core/mem.c3 index 72f8128fa..3055a7f7a 100644 --- a/lib/std/core/mem.c3 +++ b/lib/std/core/mem.c3 @@ -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)!!; } diff --git a/lib/std/core/mem_allocator.c3 b/lib/std/core/mem_allocator.c3 index 84fdf642c..ca40d2fdb 100644 --- a/lib/std/core/mem_allocator.c3 +++ b/lib/std/core/mem_allocator.c3 @@ -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); } diff --git a/lib/std/core/string.c3 b/lib/std/core/string.c3 index 3800cf1f2..aa8ea42f5 100644 --- a/lib/std/core/string.c3 +++ b/lib/std/core/string.c3 @@ -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; diff --git a/lib/std/io/stream/bytebuffer.c3 b/lib/std/io/stream/bytebuffer.c3 index 4ac5d6370..0338483f9 100644 --- a/lib/std/io/stream/bytebuffer.c3 +++ b/lib/std/io/stream/bytebuffer.c3 @@ -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]; } diff --git a/lib/std/os/backtrace.c3 b/lib/std/os/backtrace.c3 index c99728589..2afc95ec8 100644 --- a/lib/std/os/backtrace.c3 +++ b/lib/std/os/backtrace.c3 @@ -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(); 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 {}; +} \ No newline at end of file diff --git a/releasenotes.md b/releasenotes.md index c9d5f0bee..006e5caee 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -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. diff --git a/src/version.h b/src/version.h index 9da4ab102..33c1a3fd0 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.704" +#define COMPILER_VERSION "0.4.705" diff --git a/test/test_suite/dynamic/inherit.c3t b/test/test_suite/dynamic/inherit.c3t index c71483c30..4de10d8a6 100644 --- a/test/test_suite/dynamic/inherit.c3t +++ b/test/test_suite/dynamic/inherit.c3t @@ -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 diff --git a/test/test_suite/dynamic/overlapping_function.c3t b/test/test_suite/dynamic/overlapping_function.c3t index c399c6c88..edc538b9b 100644 --- a/test/test_suite/dynamic/overlapping_function.c3t +++ b/test/test_suite/dynamic/overlapping_function.c3t @@ -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 diff --git a/test/test_suite/errors/error_regression_2.c3t b/test/test_suite/errors/error_regression_2.c3t index a2d1d8334..95edda84f 100644 --- a/test/test_suite/errors/error_regression_2.c3t +++ b/test/test_suite/errors/error_regression_2.c3t @@ -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 diff --git a/test/test_suite/stdlib/map.c3t b/test/test_suite/stdlib/map.c3t index 49eb1039f..bafafc3f8 100644 --- a/test/test_suite/stdlib/map.c3t +++ b/test/test_suite/stdlib/map.c3t @@ -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