mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
@pool now has an optional reserve parameter, some minor changes to the temp_allocator API
This commit is contained in:
@@ -35,6 +35,9 @@ struct TempAllocator (Allocator)
|
||||
TempAllocatorPage* last_page;
|
||||
TempAllocator* derived;
|
||||
bool allocated;
|
||||
usz reserve_size;
|
||||
usz realloc_size;
|
||||
usz min_size;
|
||||
usz used;
|
||||
usz capacity;
|
||||
usz original_capacity;
|
||||
@@ -62,15 +65,20 @@ macro usz TempAllocatorPage.pagesize(&self) => self.size & ~PAGE_IS_ALIGNED;
|
||||
macro bool TempAllocatorPage.is_aligned(&self) => self.size & PAGE_IS_ALIGNED == PAGE_IS_ALIGNED;
|
||||
|
||||
<*
|
||||
@require size >= 16
|
||||
@require size >= 64
|
||||
@require realloc_size >= 64
|
||||
@require allocator.type != TempAllocator.typeid : "You may not create a temp allocator with a TempAllocator as the backing allocator."
|
||||
@require min_size > TempAllocator.sizeof + 64 : "Min size must meaningfully hold the data + some bytes"
|
||||
*>
|
||||
fn TempAllocator*? new_temp_allocator(Allocator allocator, usz size)
|
||||
fn TempAllocator*? new_temp_allocator(Allocator allocator, usz size, usz reserve = temp_allocator_reserve_size, usz min_size = temp_allocator_min_size, usz realloc_size = temp_allocator_realloc_size)
|
||||
{
|
||||
TempAllocator* temp = allocator::alloc_with_padding(allocator, TempAllocator, size)!;
|
||||
temp.last_page = null;
|
||||
temp.backing_allocator = allocator;
|
||||
temp.used = 0;
|
||||
temp.min_size = min_size;
|
||||
temp.realloc_size = realloc_size;
|
||||
temp.reserve_size = reserve;
|
||||
temp.allocated = true;
|
||||
temp.derived = null;
|
||||
temp.original_capacity = temp.capacity = size;
|
||||
@@ -78,19 +86,18 @@ fn TempAllocator*? new_temp_allocator(Allocator allocator, usz size)
|
||||
}
|
||||
<*
|
||||
@require !self.derived
|
||||
@require min_size > TempAllocator.sizeof + 64 : "Min size must meaningfully hold the data + some bytes"
|
||||
@require mult > 0 : "The multiple can never be zero"
|
||||
*>
|
||||
fn TempAllocator*? TempAllocator.derive_allocator(&self, usz min_size, usz buffer, usz mult)
|
||||
fn TempAllocator*? TempAllocator.derive_allocator(&self, usz reserve = 0)
|
||||
{
|
||||
if (!reserve) reserve = self.reserve_size;
|
||||
usz remaining = self.capacity - self.used;
|
||||
void* mem @noinit;
|
||||
usz size @noinit;
|
||||
if (min_size + buffer > remaining)
|
||||
if (self.min_size + reserve > remaining)
|
||||
{
|
||||
return self.derived = new_temp_allocator(self.backing_allocator, min_size * mult)!;
|
||||
return self.derived = new_temp_allocator(self.backing_allocator, self.realloc_size, self.reserve_size, self.min_size, self.realloc_size)!;
|
||||
}
|
||||
usz start = mem::aligned_offset(self.used + buffer, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
usz start = mem::aligned_offset(self.used + reserve, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
void* ptr = &self.data[start];
|
||||
TempAllocator* temp = (TempAllocator*)ptr;
|
||||
$if env::ADDRESS_SANITIZER:
|
||||
@@ -99,6 +106,9 @@ fn TempAllocator*? TempAllocator.derive_allocator(&self, usz min_size, usz buffe
|
||||
temp.last_page = null;
|
||||
temp.backing_allocator = self.backing_allocator;
|
||||
temp.used = 0;
|
||||
temp.min_size = self.min_size;
|
||||
temp.reserve_size = self.reserve_size;
|
||||
temp.realloc_size = self.realloc_size;
|
||||
temp.allocated = false;
|
||||
temp.derived = null;
|
||||
temp.original_capacity = temp.capacity = self.capacity - start - TempAllocator.sizeof;
|
||||
|
||||
@@ -576,11 +576,20 @@ 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
|
||||
<*
|
||||
@require pool_size >= 64
|
||||
@require realloc_size >= 64
|
||||
@require allocator.type != TempAllocator.typeid : "You may not create a temp allocator with a TempAllocator as the backing allocator."
|
||||
@require min_size > TempAllocator.sizeof + 64 : "Min size must meaningfully hold the data + some bytes"
|
||||
*>
|
||||
macro void @pool_init(Allocator allocator, usz pool_size,
|
||||
usz reserve_size = allocator::temp_allocator_reserve_size,
|
||||
usz min_size = allocator::temp_allocator_min_size,
|
||||
usz realloc_size = allocator::temp_allocator_realloc_size; @body) @builtin
|
||||
{
|
||||
Allocator current = allocator::current_temp;
|
||||
TempAllocator* top = allocator::top_temp;
|
||||
allocator::create_temp_allocator(allocator, pool_size, buffer_size);
|
||||
allocator::create_temp_allocator(allocator, pool_size, reserve_size, min_size, realloc_size);
|
||||
defer
|
||||
{
|
||||
allocator::destroy_temp_allocators();
|
||||
@@ -589,9 +598,19 @@ macro void @pool_init(Allocator allocator, usz pool_size, usz buffer_size; @body
|
||||
}
|
||||
@body();
|
||||
}
|
||||
macro void @pool(;@body) @builtin
|
||||
|
||||
<*
|
||||
Create a new temporary allocator.
|
||||
|
||||
The `reserve` parameter allows you to determine how many bytes should be reserved for
|
||||
allocations on the current temporary allocator, if allocations are made inside of the pool scope.
|
||||
It is made available for optimization, and can usually be ignored.
|
||||
|
||||
@param reserve : "The amount of bytes to reserve for out-of-order allocations, 0 gives the default."
|
||||
*>
|
||||
macro void @pool(usz reserve = 0; @body) @builtin
|
||||
{
|
||||
PoolState state = allocator::push_pool() @inline;
|
||||
PoolState state = allocator::push_pool(reserve) @inline;
|
||||
defer
|
||||
{
|
||||
allocator::pop_pool(state) @inline;
|
||||
|
||||
@@ -407,13 +407,13 @@ 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();
|
||||
usz temp_allocator_new_mult = 4;
|
||||
usz temp_allocator_reserve_size = temp_allocator_default_reserve_size();
|
||||
usz temp_allocator_realloc_size = temp_allocator_default_min_size() * 4;
|
||||
|
||||
fn PoolState push_pool()
|
||||
fn PoolState push_pool(usz reserve = 0)
|
||||
{
|
||||
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)!!;
|
||||
current_temp = ((TempAllocator*)old).derive_allocator(reserve)!!;
|
||||
return (PoolState)old.ptr;
|
||||
}
|
||||
|
||||
@@ -453,7 +453,7 @@ macro usz temp_allocator_default_min_size() @local
|
||||
$endswitch
|
||||
}
|
||||
|
||||
macro usz temp_allocator_default_buffer_size() @local
|
||||
macro usz temp_allocator_default_reserve_size() @local
|
||||
{
|
||||
$switch env::MEMORY_ENV:
|
||||
$case NORMAL: return 1024;
|
||||
@@ -475,14 +475,15 @@ fn Allocator create_temp_allocator_on_demand() @private
|
||||
auto_create_temp = true;
|
||||
abort("Use '@pool_init()' to enable the temp allocator on a new thread. A temp allocator is only implicitly created on the main thread.");
|
||||
}
|
||||
return create_temp_allocator(temp_base_allocator, temp_allocator_size());
|
||||
return create_temp_allocator(temp_base_allocator, temp_allocator_size(), temp_allocator_reserve_size, temp_allocator_min_size, temp_allocator_realloc_size);
|
||||
}
|
||||
|
||||
<*
|
||||
@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
|
||||
fn Allocator create_temp_allocator(Allocator allocator, usz size, usz reserve, usz min_size, usz realloc_size) @private
|
||||
{
|
||||
return current_temp = top_temp = allocator::new_temp_allocator(allocator, size)!!;
|
||||
return current_temp = top_temp = allocator::new_temp_allocator(allocator, size, reserve, min_size, realloc_size)!!;
|
||||
}
|
||||
|
||||
macro Allocator temp()
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
- Deprecate `String.is_zstr` and `String.quick_zstr` #2188.
|
||||
- Add comparison with `==` for ZString types.
|
||||
- `is_array_or_slice_of_char` and `is_arrayptr_or_slice_of_char` are replaced by constant `@` variants.
|
||||
- `@pool` now has an optional `reserve` parameter, some minor changes to the temp_allocator API
|
||||
|
||||
## 0.7.2 Change list
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ entry:
|
||||
%retparam = alloca i64, align 8
|
||||
%error_var4 = alloca i64, align 8
|
||||
%error_var10 = alloca i64, align 8
|
||||
%1 = call ptr @std.core.mem.allocator.push_pool() #3
|
||||
%1 = call ptr @std.core.mem.allocator.push_pool(i64 0) #3
|
||||
store ptr %1, ptr %state, align 8
|
||||
store i32 %0, ptr %taddr, align 4
|
||||
%2 = insertvalue %any undef, ptr %taddr, 0
|
||||
|
||||
@@ -231,7 +231,7 @@ after_check18: ; preds = %entry, %after_check
|
||||
%48 = insertvalue %any %47, i64 ptrtoint (ptr @"$ct.sa$double" to i64), 1
|
||||
store %any %48, ptr %varargslots57, align 16
|
||||
%49 = call i64 @std.io.printfn(ptr %retparam61, ptr @.str.12, i64 2, ptr %varargslots57, i64 1)
|
||||
%50 = call ptr @std.core.mem.allocator.push_pool() #4
|
||||
%50 = call ptr @std.core.mem.allocator.push_pool(i64 0) #4
|
||||
store ptr %50, ptr %state, align 8
|
||||
call void @llvm.memset.p0.i64(ptr align 8 %map3, i8 0, i64 48, i1 false)
|
||||
%lo64 = load i64, ptr @std.core.mem.allocator.thread_allocator, align 8
|
||||
|
||||
@@ -231,7 +231,7 @@ after_check18: ; preds = %entry, %after_check
|
||||
%48 = insertvalue %any %47, i64 ptrtoint (ptr @"$ct.sa$double" to i64), 1
|
||||
store %any %48, ptr %varargslots57, align 16
|
||||
%49 = call i64 @std.io.printfn(ptr %retparam61, ptr @.str.12, i64 2, ptr %varargslots57, i64 1)
|
||||
%50 = call ptr @std.core.mem.allocator.push_pool() #4
|
||||
%50 = call ptr @std.core.mem.allocator.push_pool(i64 0) #4
|
||||
store ptr %50, ptr %state, align 8
|
||||
call void @llvm.memset.p0.i64(ptr align 8 %map3, i8 0, i64 48, i1 false)
|
||||
%lo64 = load i64, ptr @std.core.mem.allocator.thread_allocator, align 8
|
||||
|
||||
Reference in New Issue
Block a user