2022-03-22 18:13:06 +00:00
|
|
|
|
|
|
|
/////////////////////////////////////////
|
|
|
|
// Memory Functions
|
|
|
|
|
|
|
|
void
|
|
|
|
memory_zero_no_simd(u8* base, u64 size)
|
|
|
|
{
|
|
|
|
for (u64 i = 0; i < size; i++) base[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
memory_copy_no_simd(u8* from, u8* to, u64 size)
|
|
|
|
{
|
|
|
|
for (u64 i = 0; i < size; i++) to[i] = from[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(PLATFORM_HAS_SIMD)
|
|
|
|
|
|
|
|
// TODO(PS):
|
|
|
|
// TODO(PS):
|
|
|
|
// TODO(PS):
|
|
|
|
|
|
|
|
void
|
|
|
|
memory_zero_simd(u8* base, u64 size)
|
|
|
|
{
|
|
|
|
memory_zero_no_simd(base, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
memory_copy_simd(u8* from, u8* to, u64 size)
|
|
|
|
{
|
|
|
|
memory_copy_no_simd(from, to, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
# define memory_zero(b,s) memory_zero_simd((b),(s))
|
|
|
|
# define memory_copy(f,t,s) memory_copy_simd((f),(t),(s))
|
|
|
|
|
|
|
|
#else
|
|
|
|
# define memory_zero(b,s) memory_zero_no_simd((b),(s))
|
|
|
|
# define memory_copy(f,t,s) memory_copy_no_simd((f),(t),(s))
|
|
|
|
|
|
|
|
#endif // defined(PLATFORM_HAS_SIMD)
|
|
|
|
|
|
|
|
#define zero_struct(s) memory_zero((u8*)(&s), sizeof(s))
|
|
|
|
|
|
|
|
u64
|
|
|
|
size_to_pages(u64 size)
|
|
|
|
{
|
|
|
|
u64 page_size = platform_page_size();
|
|
|
|
u64 rem = size % page_size;
|
|
|
|
if (rem != 0 || size < page_size)
|
|
|
|
{
|
|
|
|
u64 grow = page_size - rem;
|
|
|
|
size += grow;
|
|
|
|
}
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////
|
|
|
|
// Allocator
|
|
|
|
//
|
|
|
|
// A generic interface for any memory-providing construct
|
|
|
|
//
|
|
|
|
// To implement a complete allocator, all that is really required
|
|
|
|
// is to create its Allocator_Alloc function
|
|
|
|
|
|
|
|
typedef struct Allocator Allocator;
|
|
|
|
|
|
|
|
typedef u8* Allocator_Alloc(Allocator* allocator, u64 size);
|
|
|
|
typedef void Allocator_Free(Allocator* allocator, u8* base, u64 size);
|
|
|
|
typedef u8* Allocator_Realloc(Allocator* allocator, u8* base, u64 old_size, u64 new_size);
|
|
|
|
typedef void Allocator_Clear(Allocator* allocator);
|
|
|
|
|
|
|
|
struct Allocator
|
|
|
|
{
|
|
|
|
Allocator_Alloc* alloc;
|
|
|
|
Allocator_Free* free;
|
|
|
|
Allocator_Realloc* realloc;
|
|
|
|
Allocator_Clear* clear;
|
|
|
|
|
|
|
|
Allocator* parent;
|
|
|
|
|
|
|
|
u8* allocator_data;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define allocator_alloc(a,s) (a)->alloc((a),(s))
|
|
|
|
#define allocator_alloc_struct(a,t) (t*)(a)->alloc((a),sizeof(t))
|
|
|
|
#define allocator_alloc_array(a,t,c) (t*)(a)->alloc((a),sizeof(t)*(c))
|
|
|
|
|
|
|
|
#define allocator_free(a,b,s) (a)->free((a),(b),(s))
|
|
|
|
#define allocator_free_struct(a,b,t) (a)->free((a),(b),sizeof(t))
|
|
|
|
#define allocator_free_array(a,b,t,c) (a)->free((a),(b),sizeof(t)*(c))
|
|
|
|
|
|
|
|
#define allocator_realloc(a,b,os,ns) (a)->realloc((a),(b),(os),(ns))
|
|
|
|
#define allocator_realloc_array(a,b,t,oc,nc) (t*)(a)->realloc((a),(b),sizeof(t)*(oc),sizeof(t)*(nc))
|
|
|
|
|
|
|
|
#define allocator_clear(a) (a)->clear(a)
|
|
|
|
|
|
|
|
/////////////////////////////////////////
|
|
|
|
// Bump Allocator
|
|
|
|
|
|
|
|
struct Allocator_Bump
|
|
|
|
{
|
|
|
|
u8* base;
|
|
|
|
u64 at;
|
|
|
|
u64 size_committed;
|
|
|
|
u64 size_reserved;
|
|
|
|
};
|
|
|
|
|
|
|
|
internal u8*
|
|
|
|
bump_allocator_alloc(Allocator* allocator, u64 size)
|
|
|
|
{
|
|
|
|
Allocator_Bump* bump = (Allocator_Bump*)allocator->allocator_data;
|
|
|
|
|
|
|
|
u64 at_after = bump->at + size;
|
|
|
|
// TODO(PS): align up to 8 bytes
|
|
|
|
|
|
|
|
if (at_after >= bump->size_committed)
|
|
|
|
{
|
|
|
|
// determine new size of the arena
|
|
|
|
u64 new_size = bump->size_committed * 2;
|
|
|
|
if (new_size == 0) new_size = platform_page_size();
|
|
|
|
if (new_size < at_after) new_size = size_to_pages(at_after);
|
|
|
|
|
|
|
|
if (allocator->parent)
|
|
|
|
{
|
|
|
|
bump->base = allocator_realloc(
|
|
|
|
allocator->parent,
|
|
|
|
bump->base,
|
|
|
|
bump->size_committed,
|
|
|
|
new_size
|
|
|
|
);
|
|
|
|
if (bump->base != 0)
|
|
|
|
{
|
|
|
|
bump->size_reserved = new_size;
|
|
|
|
bump->size_committed = new_size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-03-27 10:47:18 +00:00
|
|
|
if (new_size <= bump->size_reserved)
|
2022-03-22 18:13:06 +00:00
|
|
|
{
|
|
|
|
u64 next_page = size_to_pages(bump->at);
|
2022-03-27 10:47:18 +00:00
|
|
|
if (bump->at == 0 && bump->size_committed == 0) next_page = 0;
|
2022-03-22 18:13:06 +00:00
|
|
|
u64 commit_amt = new_size - next_page;
|
2022-03-27 10:47:18 +00:00
|
|
|
u8* new_page = platform_mem_commit(bump->base + next_page, commit_amt);
|
|
|
|
if (new_page != 0)
|
|
|
|
{
|
|
|
|
bump->size_committed = new_size;
|
|
|
|
}
|
2022-03-22 18:13:06 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
invalid_code_path; // out of reserved memory
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-27 10:47:18 +00:00
|
|
|
u8* result = bump->base + bump->at;
|
2022-03-22 18:13:06 +00:00
|
|
|
bump->at = at_after;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal u8*
|
|
|
|
bump_allocator_realloc(Allocator* allocator, u8* base, u64 old_size, u64 new_size)
|
|
|
|
{
|
|
|
|
u8* result = bump_allocator_alloc(allocator, new_size);
|
|
|
|
memory_copy(base, result, old_size);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void
|
|
|
|
bump_allocator_clear(Allocator* allocator)
|
|
|
|
{
|
|
|
|
if (!allocator->allocator_data) return;
|
|
|
|
Allocator_Bump* bump = (Allocator_Bump*)allocator->allocator_data;
|
|
|
|
bump->at = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal Allocator*
|
|
|
|
bump_allocator_create_()
|
|
|
|
{
|
|
|
|
u64 size_needed = sizeof(Allocator) + sizeof(Allocator_Bump);
|
|
|
|
|
|
|
|
u8* base = platform_mem_reserve(size_needed);
|
|
|
|
base = platform_mem_commit(base, size_needed);
|
|
|
|
|
|
|
|
Allocator* result = (Allocator*)base;
|
|
|
|
zero_struct(*result);
|
|
|
|
|
|
|
|
Allocator_Bump* bump = (Allocator_Bump*)base + sizeof(Allocator);
|
|
|
|
zero_struct(*bump);
|
|
|
|
|
|
|
|
result->alloc = bump_allocator_alloc;
|
|
|
|
result->realloc = bump_allocator_realloc;
|
|
|
|
result->clear = bump_allocator_clear;
|
|
|
|
result->allocator_data = (u8*)bump;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal Allocator*
|
|
|
|
bump_allocator_create_reserve(u64 reserve_size)
|
|
|
|
{
|
|
|
|
Allocator* result = bump_allocator_create_();
|
|
|
|
Allocator_Bump* bump = (Allocator_Bump*)result->allocator_data;
|
|
|
|
|
|
|
|
u64 reserve_pages = size_to_pages(reserve_size);
|
|
|
|
bump->base = platform_mem_reserve(reserve_pages);
|
|
|
|
if (bump->base != 0) bump->size_reserved = reserve_pages;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal Allocator*
|
|
|
|
bump_allocator_create_child(Allocator* parent, u64 init_size)
|
|
|
|
{
|
|
|
|
Allocator* result = bump_allocator_create_();
|
|
|
|
result->parent = parent;
|
|
|
|
|
|
|
|
Allocator_Bump* bump = (Allocator_Bump*)result->allocator_data;
|
|
|
|
bump->base = allocator_alloc(result->parent, init_size);
|
|
|
|
if (bump->base != 0)
|
|
|
|
{
|
|
|
|
bump->size_reserved = init_size;
|
|
|
|
bump->size_committed = init_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|