mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
- Use @pool_init() to set up a temp pool on a thread. Only the main thread has implicit temp pool setup.
- `tmem` is now a variable.
This commit is contained in:
@@ -155,7 +155,7 @@ fn void? TrackingAllocator.fprint_report(&self, OutStream out) => @pool()
|
||||
Backtrace trace = backtrace::BACKTRACE_UNKNOWN;
|
||||
if (allocation.backtrace[3])
|
||||
{
|
||||
trace = backtrace::symbolize_backtrace(tmem(), allocation.backtrace[3:1]).get(0) ?? backtrace::BACKTRACE_UNKNOWN;
|
||||
trace = backtrace::symbolize_backtrace(tmem, allocation.backtrace[3:1]).get(0) ?? backtrace::BACKTRACE_UNKNOWN;
|
||||
}
|
||||
if (trace.function.len) leaks = true;
|
||||
io::fprintfn(out, "%13s %p %s:%d", allocation.size,
|
||||
@@ -194,7 +194,7 @@ fn void? TrackingAllocator.fprint_report(&self, OutStream out) => @pool()
|
||||
break;
|
||||
}
|
||||
}
|
||||
BacktraceList list = backtrace::symbolize_backtrace(tmem(), allocation.backtrace[3..(end - 1)])!;
|
||||
BacktraceList list = backtrace::symbolize_backtrace(tmem, allocation.backtrace[3..(end - 1)])!;
|
||||
io::fprintfn(out, "Allocation %d (%d bytes): ", i + 1, allocation.size)!;
|
||||
foreach (trace : list)
|
||||
{
|
||||
|
||||
@@ -81,7 +81,7 @@ macro concat(Allocator allocator, arr1, arr2) @nodiscard
|
||||
@require @typeis(arr1[0], $typeof(arr2[0])) : "Arrays must have the same type"
|
||||
@ensure return.len == arr1.len + arr2.len
|
||||
*>
|
||||
macro tconcat(arr1, arr2) @nodiscard => concat(tmem(), arr1, arr2);
|
||||
macro tconcat(arr1, arr2) @nodiscard => concat(tmem, arr1, arr2);
|
||||
|
||||
module std::core::array::slice{Type};
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ macro anycast(any v, $Type) @builtin
|
||||
|
||||
fn bool print_backtrace(String message, int backtraces_to_ignore) @if(env::NATIVE_STACKTRACE) => @stack_mem(0x1100; Allocator smem)
|
||||
{
|
||||
TempAllocator* t = allocator::current_temp;
|
||||
Allocator t = allocator::current_temp;
|
||||
TempAllocator* new_t = allocator::new_temp_allocator(smem, 0x1000)!!;
|
||||
allocator::current_temp = new_t;
|
||||
defer
|
||||
@@ -101,7 +101,7 @@ fn bool print_backtrace(String message, int backtraces_to_ignore) @if(env::NATIV
|
||||
void*[256] buffer;
|
||||
void*[] backtraces = backtrace::capture_current(&buffer);
|
||||
backtraces_to_ignore++;
|
||||
BacktraceList? backtrace = backtrace::symbolize_backtrace(tmem(), backtraces);
|
||||
BacktraceList? backtrace = backtrace::symbolize_backtrace(tmem, backtraces);
|
||||
if (catch backtrace) return false;
|
||||
if (backtrace.len() <= backtraces_to_ignore) return false;
|
||||
io::eprint("\nERROR: '");
|
||||
|
||||
@@ -24,7 +24,7 @@ fn DString DString.init(&self, Allocator allocator, usz capacity = MIN_CAPACITY)
|
||||
*>
|
||||
fn DString DString.tinit(&self, usz capacity = MIN_CAPACITY)
|
||||
{
|
||||
return self.init(tmem(), capacity) @inline;
|
||||
return self.init(tmem, capacity) @inline;
|
||||
}
|
||||
|
||||
fn DString new_with_capacity(Allocator allocator, usz capacity)
|
||||
@@ -32,7 +32,7 @@ fn DString new_with_capacity(Allocator allocator, usz capacity)
|
||||
return (DString){}.init(allocator, capacity);
|
||||
}
|
||||
|
||||
fn DString temp_with_capacity(usz capacity) => new_with_capacity(tmem(), capacity) @inline;
|
||||
fn DString temp_with_capacity(usz capacity) => new_with_capacity(tmem, capacity) @inline;
|
||||
|
||||
fn DString new(Allocator allocator, String c = "")
|
||||
{
|
||||
@@ -46,7 +46,7 @@ fn DString new(Allocator allocator, String c = "")
|
||||
return (DString)data;
|
||||
}
|
||||
|
||||
fn DString temp(String s = "") => new(tmem(), s) @inline;
|
||||
fn DString temp(String s = "") => new(tmem, s) @inline;
|
||||
|
||||
|
||||
fn void DString.replace_char(self, char ch, char replacement)
|
||||
@@ -108,7 +108,7 @@ fn DString DString.concat(self, Allocator allocator, DString b)
|
||||
return string;
|
||||
}
|
||||
|
||||
fn DString DString.tconcat(self, DString b) => self.concat(tmem(), b);
|
||||
fn DString DString.tconcat(self, DString b) => self.concat(tmem, b);
|
||||
|
||||
fn ZString DString.zstr_view(&self)
|
||||
{
|
||||
@@ -218,7 +218,7 @@ fn usz DString.append_char32(&self, Char32 c)
|
||||
return n;
|
||||
}
|
||||
|
||||
fn DString DString.tcopy(&self) => self.copy(tmem());
|
||||
fn DString DString.tcopy(&self) => self.copy(tmem);
|
||||
|
||||
fn DString DString.copy(self, Allocator allocator)
|
||||
{
|
||||
@@ -248,7 +248,7 @@ fn String DString.copy_str(self, Allocator allocator)
|
||||
return (String)self.copy_zstr(allocator)[:self.len()];
|
||||
}
|
||||
|
||||
fn String DString.tcopy_str(self) => self.copy_str(tmem()) @inline;
|
||||
fn String DString.tcopy_str(self) => self.copy_str(tmem) @inline;
|
||||
|
||||
fn bool DString.equals(self, DString other_string)
|
||||
{
|
||||
@@ -536,15 +536,13 @@ macro void DString.insert_at(&self, usz index, value)
|
||||
$endswitch
|
||||
}
|
||||
|
||||
import libc;
|
||||
fn usz? DString.appendf(&self, String format, args...) @maydiscard
|
||||
{
|
||||
if (!self.data()) self.tinit(format.len + 20);
|
||||
@pool()
|
||||
{
|
||||
Formatter formatter;
|
||||
formatter.init(&out_string_append_fn, self);
|
||||
return formatter.vprintf(format, args);
|
||||
};
|
||||
Formatter formatter;
|
||||
formatter.init(&out_string_append_fn, self);
|
||||
return formatter.vprintf(format, args);
|
||||
}
|
||||
|
||||
fn usz? DString.appendfn(&self, String format, args...) @maydiscard
|
||||
|
||||
@@ -571,6 +571,19 @@ fn void temp_pop(PoolState old_state)
|
||||
allocator::pop_pool(old_state) @inline;
|
||||
}
|
||||
|
||||
macro void @pool_init(Allocator allocator, usz pool_size, usz buffer_size; @body) @builtin
|
||||
{
|
||||
Allocator current = allocator::current_temp;
|
||||
TempAllocator* top = allocator::top_temp;
|
||||
allocator::create_temp_allocator(allocator, pool_size, buffer_size);
|
||||
defer
|
||||
{
|
||||
allocator::destroy_temp_allocators();
|
||||
allocator::top_temp = top;
|
||||
allocator::current_temp = current;
|
||||
}
|
||||
@body();
|
||||
}
|
||||
macro void @pool(;@body) @builtin
|
||||
{
|
||||
PoolState state = allocator::push_pool() @inline;
|
||||
@@ -636,7 +649,7 @@ fn void* malloc_aligned(usz size, usz alignment) @builtin @inline @nodiscard
|
||||
fn void* tmalloc(usz size, usz alignment = 0) @builtin @inline @nodiscard
|
||||
{
|
||||
if (!size) return null;
|
||||
return tmem().acquire(size, NO_ZERO, alignment)!!;
|
||||
return tmem.acquire(size, NO_ZERO, alignment)!!;
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -814,7 +827,7 @@ fn void* calloc_aligned(usz size, usz alignment) @builtin @inline @nodiscard
|
||||
fn void* tcalloc(usz size, usz alignment = 0) @builtin @inline @nodiscard
|
||||
{
|
||||
if (!size) return null;
|
||||
return tmem().acquire(size, ZERO, alignment)!!;
|
||||
return tmem.acquire(size, ZERO, alignment)!!;
|
||||
}
|
||||
|
||||
fn void* realloc(void *ptr, usz new_size) @builtin @inline @nodiscard
|
||||
@@ -841,7 +854,7 @@ fn void* trealloc(void* ptr, usz size, usz alignment = mem::DEFAULT_MEM_ALIGNMEN
|
||||
{
|
||||
if (!size) return null;
|
||||
if (!ptr) return tmalloc(size, alignment);
|
||||
return tmem().resize(ptr, size, alignment)!!;
|
||||
return tmem.resize(ptr, size, alignment)!!;
|
||||
}
|
||||
|
||||
module std::core::mem @if(env::NO_LIBC);
|
||||
|
||||
@@ -359,10 +359,12 @@ alias mem @builtin = thread_allocator ;
|
||||
tlocal Allocator thread_allocator @private = base_allocator();
|
||||
Allocator temp_base_allocator @private = base_allocator();
|
||||
|
||||
typedef PoolState = void*;
|
||||
typedef PoolState = TempAllocator*;
|
||||
|
||||
tlocal TempAllocator* current_temp;
|
||||
const LazyTempAllocator LAZY_TEMP @private = {};
|
||||
tlocal Allocator current_temp = &LAZY_TEMP;
|
||||
tlocal TempAllocator* top_temp;
|
||||
tlocal bool auto_create_temp = false;
|
||||
|
||||
usz temp_allocator_min_size = temp_allocator_default_min_size();
|
||||
usz temp_allocator_buffer_size = temp_allocator_default_buffer_size();
|
||||
@@ -370,16 +372,16 @@ usz temp_allocator_new_mult = 4;
|
||||
|
||||
fn PoolState push_pool()
|
||||
{
|
||||
TempAllocator* old = current_temp ?: create_temp_allocator();
|
||||
current_temp = current_temp.derive_allocator(temp_allocator_min_size, temp_allocator_buffer_size, temp_allocator_new_mult)!!;
|
||||
return (PoolState)old;
|
||||
Allocator old = top_temp ? current_temp : create_temp_allocator_on_demand();
|
||||
current_temp = ((TempAllocator*)old).derive_allocator(temp_allocator_min_size, temp_allocator_buffer_size, temp_allocator_new_mult)!!;
|
||||
return (PoolState)old.ptr;
|
||||
}
|
||||
|
||||
fn void pop_pool(PoolState old)
|
||||
{
|
||||
current_temp = (TempAllocator*)old;
|
||||
current_temp.reset();
|
||||
|
||||
TempAllocator* temp = (TempAllocator*)old;
|
||||
current_temp = temp;
|
||||
temp.reset();
|
||||
}
|
||||
|
||||
macro Allocator base_allocator() @private
|
||||
@@ -424,18 +426,36 @@ macro usz temp_allocator_default_buffer_size() @local
|
||||
macro Allocator heap() => thread_allocator;
|
||||
|
||||
<*
|
||||
@require !current_temp : "This should never be called when temp already exists"
|
||||
@require !top_temp : "This should never be called when temp already exists"
|
||||
*>
|
||||
fn TempAllocator* create_temp_allocator() @private
|
||||
fn Allocator create_temp_allocator_on_demand() @private
|
||||
{
|
||||
return top_temp = current_temp = allocator::new_temp_allocator(base_allocator(), temp_allocator_size())!!;
|
||||
if (!auto_create_temp)
|
||||
{
|
||||
auto_create_temp = true;
|
||||
abort("Only the main thread pool is implicitly created. Use '@pool_init()' to enable the temp allocator on other threads.");
|
||||
}
|
||||
return create_temp_allocator(base_allocator(), temp_allocator_size());
|
||||
}
|
||||
macro Allocator temp()
|
||||
<*
|
||||
@require !top_temp : "This should never be called when temp already exists"
|
||||
*>
|
||||
fn Allocator create_temp_allocator(Allocator allocator, usz size, usz buffer = temp_allocator_default_buffer_size()) @private
|
||||
{
|
||||
return current_temp ?: create_temp_allocator();
|
||||
return current_temp = top_temp = allocator::new_temp_allocator(allocator, size)!!;
|
||||
}
|
||||
|
||||
alias tmem @builtin = temp;
|
||||
macro Allocator temp()
|
||||
{
|
||||
return current_temp;
|
||||
}
|
||||
|
||||
alias tmem @builtin = current_temp;
|
||||
|
||||
fn void allow_implicit_temp_allocator_on_load_thread() @init(1) @local @if(env::LIBC)
|
||||
{
|
||||
auto_create_temp = true;
|
||||
}
|
||||
|
||||
fn void destroy_temp_allocators_after_exit() @finalizer(65535) @local @if(env::LIBC)
|
||||
{
|
||||
@@ -449,6 +469,27 @@ fn void destroy_temp_allocators()
|
||||
{
|
||||
if (!top_temp) return;
|
||||
top_temp.free();
|
||||
top_temp = null;
|
||||
current_temp = &LAZY_TEMP;
|
||||
}
|
||||
|
||||
import libc;
|
||||
typedef LazyTempAllocator (Allocator) @private = uptr;
|
||||
|
||||
fn void*? LazyTempAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz alignment) @dynamic
|
||||
{
|
||||
if (!top_temp) create_temp_allocator_on_demand();
|
||||
return top_temp.acquire(bytes, init_type, alignment);
|
||||
}
|
||||
|
||||
fn void*? LazyTempAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment) @dynamic
|
||||
{
|
||||
if (!top_temp) create_temp_allocator_on_demand();
|
||||
return top_temp.resize(old_ptr, new_bytes, alignment);
|
||||
}
|
||||
|
||||
fn void LazyTempAllocator.release(&self, void* old_ptr, bool aligned) @dynamic
|
||||
{
|
||||
}
|
||||
|
||||
const NullAllocator NULL_ALLOCATOR = {};
|
||||
|
||||
@@ -96,5 +96,5 @@ fn bool run_benchmarks(BenchmarkUnit[] benchmarks)
|
||||
|
||||
fn bool default_benchmark_runner(String[] args) => @pool()
|
||||
{
|
||||
return run_benchmarks(benchmark_collection_create(tmem()));
|
||||
return run_benchmarks(benchmark_collection_create(tmem));
|
||||
}
|
||||
|
||||
@@ -329,6 +329,6 @@ fn bool run_tests(String[] args, TestUnit[] tests) @private
|
||||
fn bool default_test_runner(String[] args) => @pool()
|
||||
{
|
||||
assert(test_context == null, "test suite is already running");
|
||||
return run_tests(args, test_collection_create(tmem()));
|
||||
return run_tests(args, test_collection_create(tmem));
|
||||
}
|
||||
|
||||
|
||||
@@ -278,7 +278,7 @@ fn String[] String.split(s, Allocator allocator, String needle, usz max = 0, boo
|
||||
@param max : "Max number of elements, 0 means no limit, defaults to 0"
|
||||
@param skip_empty : "True to skip empty elements"
|
||||
*>
|
||||
fn String[] String.tsplit(s, String needle, usz max = 0, bool skip_empty = false) => s.split(tmem(), needle, max, skip_empty) @inline;
|
||||
fn String[] String.tsplit(s, String needle, usz max = 0, bool skip_empty = false) => s.split(tmem, needle, max, skip_empty) @inline;
|
||||
|
||||
faultdef BUFFER_EXCEEDED;
|
||||
|
||||
@@ -516,10 +516,10 @@ fn String String.concat(s1, Allocator allocator, String s2)
|
||||
return (String)str[:full_len];
|
||||
}
|
||||
|
||||
fn String String.tconcat(s1, String s2) => s1.concat(tmem(), s2);
|
||||
fn String String.tconcat(s1, String s2) => s1.concat(tmem, s2);
|
||||
|
||||
|
||||
fn ZString String.zstr_tcopy(s) => s.zstr_copy(tmem()) @inline;
|
||||
fn ZString String.zstr_tcopy(s) => s.zstr_copy(tmem) @inline;
|
||||
|
||||
<*
|
||||
Copy this string, by duplicating the string, always adding a zero byte
|
||||
@@ -542,7 +542,7 @@ fn void String.free(&s, Allocator allocator)
|
||||
*s = "";
|
||||
}
|
||||
|
||||
fn String String.tcopy(s) => s.copy(tmem()) @inline;
|
||||
fn String String.tcopy(s) => s.copy(tmem) @inline;
|
||||
|
||||
fn String ZString.copy(z, Allocator allocator)
|
||||
{
|
||||
@@ -551,7 +551,7 @@ fn String ZString.copy(z, Allocator allocator)
|
||||
|
||||
fn String ZString.tcopy(z)
|
||||
{
|
||||
return z.str_view().copy(tmem()) @inline;
|
||||
return z.str_view().copy(tmem) @inline;
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -568,14 +568,14 @@ fn Char16[]? String.to_utf16(s, Allocator allocator)
|
||||
return data[:len16];
|
||||
}
|
||||
|
||||
fn Char16[]? String.to_temp_utf16(s) => s.to_utf16(tmem());
|
||||
fn Char16[]? String.to_temp_utf16(s) => s.to_utf16(tmem);
|
||||
|
||||
fn WString? String.to_wstring(s, Allocator allocator)
|
||||
{
|
||||
return (WString)s.to_utf16(allocator).ptr;
|
||||
}
|
||||
|
||||
fn WString? String.to_temp_wstring(s) => s.to_wstring(tmem());
|
||||
fn WString? String.to_temp_wstring(s) => s.to_wstring(tmem);
|
||||
|
||||
fn Char32[]? String.to_utf32(s, Allocator allocator)
|
||||
{
|
||||
@@ -586,7 +586,7 @@ fn Char32[]? String.to_utf32(s, Allocator allocator)
|
||||
return data[:codepoints];
|
||||
}
|
||||
|
||||
fn Char32[]? String.to_temp_utf32(s) => s.to_utf32(tmem());
|
||||
fn Char32[]? String.to_temp_utf32(s) => s.to_utf32(tmem);
|
||||
|
||||
<*
|
||||
Convert a string to ASCII lower case in place.
|
||||
@@ -608,7 +608,7 @@ fn String String.to_lower_copy(s, Allocator allocator)
|
||||
|
||||
fn String String.to_lower_tcopy(s)
|
||||
{
|
||||
return s.to_lower_copy(tmem());
|
||||
return s.to_lower_copy(tmem);
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -648,7 +648,7 @@ fn StringIterator String.iterator(s)
|
||||
*>
|
||||
fn String String.to_upper_tcopy(s)
|
||||
{
|
||||
return s.to_upper_copy(tmem());
|
||||
return s.to_upper_copy(tmem);
|
||||
}
|
||||
|
||||
fn String? from_utf32(Allocator allocator, Char32[] utf32)
|
||||
@@ -679,8 +679,8 @@ fn String? from_wstring(Allocator allocator, WString wstring)
|
||||
return from_utf16(allocator, utf16);
|
||||
}
|
||||
|
||||
fn String? tfrom_wstring(WString wstring) => from_wstring(tmem(), wstring) @inline;
|
||||
fn String? tfrom_utf16(Char16[] utf16) => from_utf16(tmem(), utf16) @inline;
|
||||
fn String? tfrom_wstring(WString wstring) => from_wstring(tmem, wstring) @inline;
|
||||
fn String? tfrom_utf16(Char16[] utf16) => from_utf16(tmem, utf16) @inline;
|
||||
|
||||
fn usz String.utf8_codepoints(s)
|
||||
{
|
||||
@@ -839,4 +839,4 @@ macro String from_struct(Allocator allocator, x)
|
||||
};
|
||||
}
|
||||
|
||||
macro String tfrom_struct(x) => from_struct(tmem(), x);
|
||||
macro String tfrom_struct(x) => from_struct(tmem, x);
|
||||
|
||||
Reference in New Issue
Block a user