Removing heap allocations, Porting to Unix

This commit is contained in:
Krzosa Karol
2022-10-09 10:34:23 +02:00
parent aa2b4d90e4
commit b22e1ac0db
13 changed files with 260 additions and 269 deletions

View File

@@ -6,9 +6,7 @@ The language is currently **very debuggable**. It can produce readable C code wi
## Using Windows API example
* More examples can be found in /examples and /modules, especially checkout:
* examples/raymarcher.core
* examples/drawing_to_screen_using_windows_api.core
More examples can be found in /examples and /modules:
``` odin
#import "KERNEL32.core"

280
base.cpp
View File

@@ -1,7 +1,79 @@
#if defined(__clang__)
# define COMPILER_CLANG 1
# if defined(_WIN32)
# define OS_WINDOWS 1
# elif defined(__linux__)
# define OS_LINUX 1
# else
# error Couldnt figure out the platform automatically
# endif
#elif defined(_MSC_VER)
# define COMPILER_MSVC 1
# define OS_WINDOWS 1
#elif defined(__GNUC__)
# define COMPILER_GCC 1
# if defined(__linux__)
# define OS_LINUX 1
# endif
#else
# error Couldnt figure out the compiler
#endif
#if defined(OS_MAC)
#define OS_UNIX 1
#endif
#if defined(OS_LINUX)
#define OS_UNIX 1
#endif
#if !defined(COMPILER_MSVC)
# define COMPILER_MSVC 0
#endif
#if !defined(COMPILER_GCC)
# define COMPILER_GCC 0
#endif
#if !defined(COMPILER_CLANG)
# define COMPILER_CLANG 0
#endif
#if !defined(OS_WINDOWS)
# define OS_WINDOWS 0
#endif
#if !defined(OS_LINUX)
# define OS_LINUX 0
#endif
#if !defined(OS_MAC)
# define OS_MAC 0
#endif
#if !defined(OS_UNIX)
# define OS_UNIX 0
#endif
#if OS_WINDOWS
#define OS_NAME "Win32"_s
#define OS_NAME_LOWER "win32"_s
#elif OS_LINUX
#define OS_NAME "Linux"_s
#define OS_NAME_LOWER "linux"_s
#elif OS_MAC
#define OS_NAME "Mac"_s
#define OS_NAME_LOWER "mac"_s
#else
#error Couldnt figure out the OS with C macros!
#endif
#if OS_WINDOWS
#define NOMINMAX
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#define Breakpoint __debugbreak()
#define force_inline __forceinline
#else
#define Breakpoint (*(volatile int *)0 = 0)
#define force_inline inline
#endif
#include <stdlib.h>
#include <float.h>
#include <stdint.h>
typedef int8_t S8;
@@ -16,12 +88,10 @@ typedef S8 B8;
typedef S16 B16;
typedef S32 B32;
typedef S64 B64;
typedef U64 SizeU;
typedef S64 SizeS;
typedef float F32;
typedef double F64;
#define U64MAX UINT64_MAX
#define U32MAX UINT32_MAX
#define U16MAX UINT16_MAX
@@ -46,13 +116,12 @@ typedef double F64;
#define api
#define function static
#define global static
#define force_inline __forceinline
#define assert(x) do{if(!(x))__debugbreak();}while(0)
#define assert_msg(x,...) assert(x)
#define invalid_codepath assert_msg(0, "Invalid codepath")
#define invalid_return do{assert_msg(0, "Invalid codepath"); return {};}while(0)
#define assert(x) do{if(!(x))Breakpoint;}while(0)
#define assert_message(x,...) assert(x)
#define invalid_codepath assert_message(0, "Invalid codepath")
#define invalid_return do{assert_message(0, "Invalid codepath"); return {};}while(0)
#define invalid_default_case default: invalid_codepath
#define not_implemented assert_msg(0, "Not implemented")
#define not_implemented assert_message(0, "Not implemented")
#define unused(x) ((void)x)
#define buff_cap(x) (sizeof(x)/sizeof((x)[0]))
#define is_flag_set(val,flag) ((val) & (flag))
@@ -66,59 +135,6 @@ typedef double F64;
#define JOIN(X,Y) JOIN1(X,Y)
#define string_expand(x) (int)x.len, x.str
#if defined(__clang__)
# define COMPILER_CLANG 1
# if defined(_WIN32)
# define OS_WINDOWS 1
# elif defined(__linux__)
# define OS_LINUX 1
# else
# error Couldnt figure out the platform automatically
# endif
#elif defined(_MSC_VER)
# define COMPILER_MSVC 1
# define OS_WINDOWS 1
#elif defined(__GNUC__)
# define COMPILER_GCC 1
# if defined(__linux__)
# define OS_LINUX 1
# endif
#else
# error Couldnt figure out the compiler
#endif
#if !defined(COMPILER_MSVC)
# define COMPILER_MSVC 0
#endif
#if !defined(COMPILER_GCC)
# define COMPILER_GCC 0
#endif
#if !defined(COMPILER_CLANG)
# define COMPILER_CLANG 0
#endif
#if !defined(OS_WINDOWS)
# define OS_WINDOWS 0
#endif
#if !defined(OS_LINUX)
# define OS_LINUX 0
#endif
#if !defined(OS_MAC)
# define OS_MAC 0
#endif
#if OS_WINDOWS
#define OS_NAME "Win32"_s
#define OS_NAME_LOWER "win32"_s
#elif OS_LINUX
#define OS_NAME "Linux"_s
#define OS_NAME_LOWER "linux"_s
#elif OS_MAC
#define OS_NAME "Mac"_s
#define OS_NAME_LOWER "mac"_s
#else
#error Couldnt figure out the OS with C macros!
#endif
struct String{
U8 *str;
S64 len;
@@ -210,42 +226,42 @@ union Rect2I {
//-----------------------------------------------------------------------------
// Utilities
//-----------------------------------------------------------------------------
function SizeU
get_align_offset(SizeU size, SizeU align){
SizeU mask = align - 1;
SizeU val = size & mask;
function size_t
get_align_offset(size_t size, size_t align){
size_t mask = align - 1;
size_t val = size & mask;
if(val){
val = align - val;
}
return val;
}
function SizeU
align_up(SizeU size, SizeU align){
SizeU result = size + get_align_offset(size, align);
function size_t
align_up(size_t size, size_t align){
size_t result = size + get_align_offset(size, align);
return result;
}
function SizeU
align_down(SizeU size, SizeU align){
function size_t
align_down(size_t size, size_t align){
size += 1; // Make sure 8 when align is 8 doesn't get rounded down to 0
SizeU result = size - (align - get_align_offset(size, align));
size_t result = size - (align - get_align_offset(size, align));
return result;
}
function void
memory_copy(void *dst, void *src, SizeU size){
memory_copy(void *dst, void *src, size_t size){
U8 *d = (U8*)dst;
U8 *s = (U8*)src;
for(SizeU i = 0; i < size; i++){
for(size_t i = 0; i < size; i++){
d[i] = s[i];
}
}
function void
memory_zero(void *p, SizeU size){
memory_zero(void *p, size_t size){
U8 *pp = (U8 *)p;
for(SizeU i = 0; i < size; i++)
for(size_t i = 0; i < size; i++)
pp[i] = 0;
}
@@ -480,47 +496,47 @@ enum Alloc_Flag{
};
struct Allocator;
typedef void *Allocator_Proc(Allocator*, Allocation_Kind, void *, SizeU);
typedef void *Allocator_Proc(Allocator*, Allocation_Kind, void *, size_t);
struct Allocator{Allocator_Kind kind; Allocator_Proc *proc; String debug_name;};
//-----------------------------------------------------------------------------
// Memory OS
//-----------------------------------------------------------------------------
struct OS_Memory{
SizeU commit, reserve;
size_t commit, reserve;
U8 *data;
};
function OS_Memory os_reserve(SizeU size);
function B32 os_commit(OS_Memory *m, SizeU size);
function OS_Memory os_reserve(size_t size);
function B32 os_commit(OS_Memory *m, size_t size);
function void os_release(OS_Memory *m);
function B32 os_decommit_pos(OS_Memory *m, SizeU pos);
function B32 os_decommit_pos(OS_Memory *m, size_t pos);
//-----------------------------------------------------------------------------
// Memory arenas
//-----------------------------------------------------------------------------
global const SizeU default_reserve_size = gib(4);
global const SizeU default_alignment = 8;
global const SizeU additional_commit_size = mib(1);
global const size_t default_reserve_size = gib(4);
global const size_t default_alignment = 8;
global const size_t additional_commit_size = mib(1);
struct Arena:Allocator{
OS_Memory memory;
SizeU alignment;
SizeU len;
size_t alignment;
size_t len;
// Personal arena memes so we can compute correct size when resizing
// Also a pointer so that we can make sure it didn't change
SizeU old_size;
size_t old_size;
void *debug_prev_pointer;
};
function void arena_init(Arena *arena, String debug_name);
function void
arena_pop_pos(Arena *arena, SizeU pos){
arena_pop_pos(Arena *arena, size_t pos){
pos = clamp_top(pos, arena->len);
arena->len = pos;
}
function void *
arena_pop(Arena *arena, SizeU size){
arena_pop(Arena *arena, size_t size){
size = clamp_top(size, arena->len);
arena->len -= size;
return arena->memory.data + arena->len;
@@ -537,8 +553,8 @@ arena_clear(Arena *arena){
}
function void *
arena_push_size(Arena *a, SizeU size){
SizeU generous_size = size + a->alignment;
arena_push_size(Arena *a, size_t size){
size_t generous_size = size + a->alignment;
if(a->len+generous_size>a->memory.commit){
if(a->memory.reserve == 0){
arena_init(a, "Zero initialized arena"_s);
@@ -555,7 +571,7 @@ arena_push_size(Arena *a, SizeU size){
}
force_inline void *
arena_allocator_proc(Allocator *a, Allocation_Kind kind, void *old_pointer, SizeU size){
arena_allocator_proc(Allocator *a, Allocation_Kind kind, void *old_pointer, size_t size){
Arena *arena = (Arena *)a;
switch(kind){
case Allocation_Alloc: return arena_push_size(arena, size);
@@ -573,7 +589,7 @@ arena_allocator_proc(Allocator *a, Allocation_Kind kind, void *old_pointer, Size
}
force_inline void *
personal_arena_allocator_proc(Allocator *a, Allocation_Kind kind, void *old_pointer, SizeU size){
personal_arena_allocator_proc(Allocator *a, Allocation_Kind kind, void *old_pointer, size_t size){
Arena *arena = (Arena *)a;
arena->alignment = 1;
@@ -614,59 +630,6 @@ arena_make_personal(String debug_name){
return arena;
}
//-----------------------------------------------------------------------------
// OS Heap allocator
//-----------------------------------------------------------------------------
struct OS_Heap:Allocator{
HANDLE handle;
};
function void *
os_heap_allocator_proc(Allocator *a, Allocation_Kind kind, void *old_pointer, SizeU size){
OS_Heap *heap = (OS_Heap *)a;
switch(kind){
case Allocation_FreeAll:{
invalid_codepath;
return 0;
}
case Allocation_Destroy:{
BOOL result = HeapDestroy(heap->handle);
assert(result != 0);
heap->handle = 0;
heap->proc = 0;
return 0;
}
case Allocation_Free:{
BOOL result = HeapFree(heap->handle, 0, old_pointer);
assert(result != 0);
return 0;
}
case Allocation_Alloc:{
void *result = HeapAlloc(heap->handle, 0, size);
assert(result);
return result;
}
case Allocation_Resize:{
void *result = HeapReAlloc(heap->handle, 0, old_pointer, size);
assert(result);
return result;
}
default: invalid_codepath;
}
return 0;
}
function OS_Heap // max_size == 0 == growing heap
win32_os_heap_create(B32 multithreaded, SizeU initial_size, SizeU max_size, String debug_name){
OS_Heap result = {};
result.debug_name = debug_name;
result.proc = os_heap_allocator_proc;
result.kind = Allocator_OSHeap;
result.handle = HeapCreate(multithreaded ? 0 : HEAP_NO_SERIALIZE, initial_size, max_size);
assert(result.handle);
return result;
}
enum Log_Kind{Log_Kind_Normal, Log_Kind_Error, Log_Kind_Trace};
typedef void Log_Proc(Log_Kind kind, String string, char *file, int line);
//-----------------------------------------------------------------------------
@@ -684,7 +647,6 @@ struct Thread_Ctx{
thread_local Thread_Ctx thread_ctx;
global Arena pernament_arena;
global OS_Heap os_process_heap;
#define REPORT_ALLOCATIONS 0
#define report_file_and_line() report__file_and_line(__FILE__, __LINE__)
@@ -698,7 +660,7 @@ report__file_and_line(const char *file, int line){
// Implicit scratch stack
//-----------------------------------------------------------------------------
struct Scratch{
SizeU saved_pos;
size_t saved_pos;
Arena *arena;
Scratch(Allocator *conflict = 0){
@@ -749,7 +711,7 @@ struct Scoped_Allocator{
#define exp_destroy(a) (report_file_and_line(), exp__destroy(a))
force_inline void *
exp__alloc(Allocator *a, SizeU size, Alloc_Flag flag = AF_None){
exp__alloc(Allocator *a, size_t size, Alloc_Flag flag = AF_None){
#if REPORT_ALLOCATIONS
printf("Alloc(%s) %s:%d %u\n", a->debug_name.str, thread_ctx.file, thread_ctx.line, (U32)size);
#endif
@@ -759,7 +721,7 @@ exp__alloc(Allocator *a, SizeU size, Alloc_Flag flag = AF_None){
return result;
}
force_inline void *
exp__resize(Allocator *a, void *pointer, SizeU size){
exp__resize(Allocator *a, void *pointer, size_t size){
#if REPORT_ALLOCATIONS
printf("Resize(%s) %s:%d %u\n", a->debug_name.str, thread_ctx.file, thread_ctx.line, (U32)size);
#endif
@@ -801,10 +763,6 @@ thread_ctx_init(){
arena_init(thread_ctx.scratch, "Scratch1"_s);
arena_init(thread_ctx.scratch+1, "Scratch2"_s);
arena_init(&pernament_arena, "Pernament Arena"_s);
os_process_heap.proc = os_heap_allocator_proc;
os_process_heap.handle = GetProcessHeap();
os_process_heap.debug_name = "Win32 Process Heap"_s;
os_process_heap.kind = Allocator_OSHeap;
}
@@ -847,7 +805,7 @@ struct Array{
S64 get_index(T *item){
assert((data <= item) && ((data + len) > item));
SizeU offset = item - data;
size_t offset = item - data;
return (S64)offset;
}
@@ -1145,12 +1103,12 @@ function void
map_test(){
Scratch scratch;
Map map = {scratch};
const SizeU size = 1025;
for(SizeU i = 1; i < size; i++){
const size_t size = 1025;
for(size_t i = 1; i < size; i++){
map_insert(&map, i, (void *)i);
}
for(SizeU i = 1; i < size; i++){
SizeU val = (SizeU)map_get(&map, i);
for(size_t i = 1; i < size; i++){
size_t val = (size_t)map_get(&map, i);
assert(val == i);
}
}
@@ -1208,7 +1166,7 @@ test_intern_table(){
}
function Arena
arena_sub(Allocator *base, SizeU size, String debug_name) {
arena_sub(Allocator *base, size_t size, String debug_name) {
Arena result = {};
result.memory.data = (U8 *)exp_alloc(base, size);
result.memory.commit = size;
@@ -1443,7 +1401,7 @@ T pop(List<T> *list){
template<class T>
T *merge(Arena *arena, List<T> *list){
int len = length(list);
T *result = push_array(arena, T, len);
T *result = exp_alloc_array(arena, T, len);
int i = 0;
For_Linked_List(list->first){

View File

@@ -141,7 +141,7 @@ struct String_Builder{
assert(!last && !first);
}
void push_block(SizeU size){
void push_block(size_t size){
String_Builder_Block *block = 0;
if(first_free){
block = first_free;
@@ -218,7 +218,7 @@ function String
string_flatten(Allocator *a, String_Builder *b, String_Builder_Flag flags = String_Builder_Flag_None){
// @Note(Krzosa): Compute size to allocate
S64 size = 1;
if(is_flag_set(flags, String_Builder_Flag_AddSize)) size += sizeof(SizeU);
if(is_flag_set(flags, String_Builder_Flag_AddSize)) size += sizeof(size_t);
For_Linked_List(b->first){
size += it->len;
}
@@ -308,8 +308,8 @@ string_get_prefix(String string, S64 len) {
function String
string_slice(String string, S64 first_index, S64 one_past_last_index) {
assert_msg(first_index < one_past_last_index, "string_slice, first_index is bigger then one_past_last_index");
assert_msg(string.len > 0, "Slicing string of length 0! Might be an error!");
assert_message(first_index < one_past_last_index, "string_slice, first_index is bigger then one_past_last_index");
assert_message(string.len > 0, "Slicing string of length 0! Might be an error!");
String result = string;
if (string.len > 0) {
if (one_past_last_index > first_index) {

View File

@@ -1,6 +1,7 @@
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the GNU LGPLv3.0 license
// a copy of which can be found in the LICENSE file.
#include <string.h>
#define Set_BigInt_Allocator(x) BigInt_Allocator bigint_allocator(x)
struct BigInt_Allocator{

View File

@@ -236,7 +236,7 @@ How does current declaration order resolver works:
struct Ast_Scope: Ast{
String debug_name; // Dont use
List<Ast_Scope *> implicit_imports;
Array<Ast_Decl *> decls;
List<Ast_Decl *> decls;
Array<Ast *> stmts;
U32 visit_id;
@@ -301,7 +301,7 @@ struct Ast_Decl: Ast{
#define ast_new(T,kind,pos,flags) (T *)_ast_new(sizeof(T), kind, pos, flags)
function Ast *
_ast_new(SizeU size, Ast_Kind kind, Token *pos, Ast_Flag flags = 0){
_ast_new(size_t size, Ast_Kind kind, Token *pos, Ast_Flag flags = 0){
Ast *result = (Ast *)exp_alloc(pctx->perm, size, AF_ZeroMemory);
result->flags = flags;
result->kind = kind;
@@ -471,7 +471,6 @@ ast_array(Token *pos, Ast_Expr *expr){
function Ast_Scope *
begin_decl_scope(Allocator *scratch, Token *pos){
AST_NEW(Scope, SCOPE, pos, AST_DECL);
result->decls = {scratch};
result->file = pctx->currently_parsed_file;
result->module = pctx->currently_parsed_file->module;
result->scope_id = pctx->scope_ids++;
@@ -483,7 +482,6 @@ begin_decl_scope(Allocator *scratch, Token *pos){
function void
finalize_decl_scope(Ast_Scope *scope){
scope->decls = scope->decls.tight_copy(pctx->perm);
pctx->currently_parsed_scope = scope->parent_scope;
}
@@ -491,7 +489,6 @@ function Ast_Scope *
begin_stmt_scope(Allocator *scratch, Token *pos){
AST_NEW(Scope, SCOPE, pos, AST_STMT);
result->stmts = {scratch};
result->decls = {pctx->heap};
result->file = pctx->currently_parsed_file;
result->module = pctx->currently_parsed_file->module;
result->scope_id = pctx->scope_ids++;
@@ -559,7 +556,6 @@ ast_type(Token *pos, Intern_String name, Ast_Type *type){
function Ast_Scope *
ast_decl_scope(Token *pos, Allocator *allocator, Ast_File *file){
AST_NEW(Scope, SCOPE, pos, AST_DECL);
result->decls = {allocator};
result->file = file;
result->scope_id = pctx->scope_ids++;

View File

@@ -37,7 +37,7 @@ function String
string_scope_name(Allocator *a, Ast_Scope *scope){
String string = {};
if(scope->parent_scope) string = string_scope_name(a, scope->parent_scope);
assert_msg(scope->scope_id != 0, "Scope id is equal to 0 which is invalid, scope didn't initialize id");
assert_message(scope->scope_id != 0, "Scope id is equal to 0 which is invalid, scope didn't initialize id");
string = string_fmt(a, "%QS%u_", string, scope->scope_id);
return string;
}
@@ -673,9 +673,9 @@ gen_ast(Ast *ast){
gen("%Q{", node->unique_name);
global_indent++;
is_inside_struct++;
For(node->scope->decls){
Iter(&node->scope->decls){
genln("");
gen_ast(it);
gen_ast(it.item[0]);
}
is_inside_struct--;
@@ -688,10 +688,10 @@ gen_ast(Ast *ast){
gen("/*enum %Q{", node->name);
// @todo add typespec
global_indent++;
For(node->scope->decls){
genln("%Q", it->name);
Iter(&node->scope->decls){
genln("%Q", it.item[0]->name);
gen(" = ");
gen_value(it->pos, it->value);
gen_value(it.item[0]->pos, it.item[0]->value);
gen(",");
}
global_indent--;

View File

@@ -196,7 +196,6 @@ add_module(Token *pos, Intern_String filename, B32 command_line_module){
result->debug_name = string_skip_to_last_slash(result->absolute_file_path);
result->module = result; // @warning: self referential
result->file = result; // @warning: self referential
result->decls = {pctx->heap};
result->parent_scope = 0;
result->scope_id = pctx->scope_ids++;
@@ -210,11 +209,12 @@ resolve_everything_in_module(Ast_Module *module){
if(module->state == MODULE_RESOLVED) return;
resolving_time_begin = os_time();
Iter_Named(&module->all_loaded_files, file){
For(file.item[0]->decls){
resolve_name(file.item[0], it->pos, it->name);
Iter(&file.item[0]->decls){
Ast_Decl *decl = it.item[0];
resolve_name(file.item[0], decl->pos, decl->name);
if(it->kind == AST_STRUCT){
type_complete(it->type_val);
if(decl->kind == AST_STRUCT){
type_complete(decl->type_val);
}
}
}

View File

@@ -45,8 +45,8 @@ Intern_String intern_it;
//-----------------------------------------------------------------------------
// Type globals
//-----------------------------------------------------------------------------
const SizeU pointer_size = sizeof(SizeU);
const SizeU pointer_align = __alignof(SizeU);
const uintptr_t pointer_size = sizeof(uintptr_t);
const uintptr_t pointer_align = __alignof(uintptr_t);
global Ast_Type type__void = {TYPE_VOID};
global Ast_Type type__string = {TYPE_STRING, sizeof(String), __alignof(String)};
global Ast_Type type__bool = {TYPE_BOOL, sizeof(bool), __alignof(bool)};

View File

@@ -1,10 +1,14 @@
/*
First doable version:
Current:
- [ ] Foreign import that would link library
- [ ] String in Language.core
- [ ] Way to import and force evaluate #import_lazy #import ?
- [ ] Unix port
- [ ] Imports are leaking names ! Multimedia leaks windows stuff
- [ ] Test and bulletproof any, slices
- [ ] Include multiple pattern matched imports "unix_" and "linux_" both should be included on linux
In the future
@@ -12,7 +16,6 @@ In the future
- [ ] Add ability to do i: int = 0 inside for loops for i: int = 0, i < 10, i+=1
- [ ] Complicated c declaration generation
- [ ] Way to import and force evaluate #import_lazy #import ?
- [ ] Expand macros
- [ ] Defer
@@ -37,15 +40,16 @@ In the future
- [ ] Parametric Polymorphism
- [ ] Conditional compilation #if (maybe just do something like a conditional load or import?) #import "windows.kl" when os == "windows"
- [ ] Any
- [ ] Assigning to any values like ints etc. should work perhaps? But what type they should have?
- [ ] Slice of Any should work well
Maybe later
Ideas
- [ ] #test construct that would gather all tests and run them on start of program or something
- [ ] Inject stack traces into the program
- [ ] Constant arrays that evaluate fully at compile time
- [ ] Rust like enum where you associate values(other structs) with key
- [ ] Cast from array to pointer?
- [ ] Ternary operator?
- [ ] Optionally pass size and alignment calculations to C ?
-------------------------------------------------------------------------------
2022.09.29 - Function overloads, operator overloads, namespaces idea
@@ -117,36 +121,6 @@ For modules it's a bit different cause they should be distributed as valid.
-------------------------------------------------------------------------------
- [ ] Probably need to give Ast_Expr a Value field, then I can express Type nicely
- [ ] I would love for String, slice, Any etc. to have their struct declarations in source files, I also would want for stuff like string.str to work without weird special cases
- [ ] Var args with Any
- [ ] #test construct that would gather all tests and run them on start of program or something
- [ ] Foreign import that would link library
- [ ] Kilobyte, Megabyte, Gigabyte
- [ ] Cast from array to pointer?
- [ ] Fix field access, cant cast, cant index
- [ ] Add parent_scope to Ast_Type, Add name to Ast_Type?
- [ ] Optional function renaming in codegen
- [ ] Using in structs to embed members, then casting offsets to that embedded member
- [ ] Comma notation when declaring variables thing1, thing2: S32 :: probably want to unify it with var unpacking
- [ ] Add single line lambda expressions
- [ ] Ternary operator
- [ ] Write up on order independent declarations
- [ ] constructor => thing :: (i: S32) -> {i = i, thing = 10}
- [ ] Default values in structs??? Should compound stmts bring values from default values?? Maybe not? Whats the alternative
@ideas
- [ ] Var args using Any array - args: []Any - delete vargs
- [ ] Constant arrays that evaluate fully at compile time
- [ ] Rust like enum where you associate values(other structs) with keys
- [ ] Compound that zeros values - .{} , Compound that assumes defaults from struct definition - {}
- [ ] Inject stack traces into the program
## Done
@@ -247,7 +221,15 @@ For modules it's a bit different cause they should be distributed as valid.
#include "base.cpp"
#include "base_unicode.cpp"
#if OS_WINDOWS
#include "os_windows.cpp"
#elif OS_UNIX
#include "os_unix.cpp"
#else
#error Couldnt figure out OS using macros
#endif
#include "c3_big_int.h"
#include "core_compiler.h"
#include "core_types.h"
@@ -307,5 +289,5 @@ int main(int argument_count, char **arguments){
compile_file(it.absolute_path, COMPILE_AND_RUN | COMPILE_TESTING);
}
}
__debugbreak();
return 0;
}

View File

@@ -53,7 +53,7 @@ compiler_error(Token *token1, Token *token2, const char *str, ...){
if(token1) printf("\n%s:%d token_di:%u", token1->file.str, (S32)token1->line + 1, token1->di);
if(token2) printf("\n%s:%d token_di:%u", token2->file.str, (S32)token2->line + 1, token2->di);
__debugbreak();
Breakpoint;
}
function void
@@ -72,7 +72,7 @@ compiler_error(Token *token, const char *str, ...){
if(token) printf("\n%s:%d token_di:%u", token->file.str, (S32)token->line + 1, token->di);
__debugbreak();
Breakpoint;
}
function Token *
@@ -678,7 +678,7 @@ parse_struct(Token *pos){
Ast_Decl *decl = ast_var(token, typespec, token->intern_val, 0);
decl->flags = set_flag(decl->flags, AST_AGGREGATE_CHILD);
scope->decls.add(decl);
add(pctx->perm, &scope->decls, decl);
}while(token_match(SAME_SCOPE));
token_expect(CLOSE_SCOPE);
@@ -702,7 +702,7 @@ parse_enum(Token *pos){
if(token_match(TK_DoubleColon)) value = parse_expr();
Ast_Decl *member = ast_const(name, name->intern_val, value);
member->flags = set_flag(member->flags, AST_AGGREGATE_CHILD);
scope->decls.add(member);
add(pctx->perm, &scope->decls, member);
}while(token_match(SAME_SCOPE));
finalize_decl_scope(scope);
token_expect(CLOSE_SCOPE);
@@ -753,7 +753,6 @@ register_ast_file(Token *pos, String absolute_file_path, Ast_Module *module, B32
file->module = module;
file->parent_scope = 0;
file->file = file; // @warning: self referential!
file->decls = {pctx->heap};
file->pos = pos;
file->debug_name = string_skip_to_last_slash(absolute_file_path);
add(pctx->perm, &file->module->all_loaded_files, file);

View File

@@ -443,9 +443,10 @@ inside_scope_search(Scope_Search *search, Ast_Scope *scope, int level){
scope->visit_id = search->scope_visit_id;
// Search for declarations in current scope
For(scope->decls){
if(it->name == search->name){
search->results.add(it);
Iter(&scope->decls){
Ast_Decl *decl = it.item[0];
if(decl->name == search->name){
search->results.add(decl);
if(search->exit_on_find){
return;
}
@@ -591,7 +592,7 @@ insert_into_scope(Ast_Scope *scope, Ast_Decl *decl){
}
}
scope->decls.add(decl);
add(pctx->perm, &scope->decls, decl);
}
//
@@ -1686,13 +1687,14 @@ resolve_decl(Ast_Decl *ast){
node->type_val = type_enum(node, type_of_enum);
S64 value = 1;
For(node->scope->decls){
Iter(&node->scope->decls){
Ast_Decl *decl = it.item[0];
Operand op = {};
if(it->expr){
op = require_const_int(it->expr, AST_CANT_BE_NULL);
if(decl->expr){
op = require_const_int(decl->expr, AST_CANT_BE_NULL);
value = bigint_as_signed(&op.big_int_val) + 1;
} else{
it->state = DECL_RESOLVED;
decl->state = DECL_RESOLVED;
op.type = node->type_val;
bigint_init_signed(&op.big_int_val, value);
if(is_flag_set(node->flags, AST_FLAG)){
@@ -1702,7 +1704,7 @@ resolve_decl(Ast_Decl *ast){
}
}
it->value = op.value;
decl->value = op.value;
}
BREAK();
}

View File

@@ -58,7 +58,7 @@ force_inline B32 is_numeric(Ast_Type *type){
// Hash consed types
//-----------------------------------------------------------------------------
function Ast_Type *
type_new(Allocator *allocator, Ast_Type_Kind kind, SizeU size, SizeU align){
type_new(Allocator *allocator, Ast_Type_Kind kind, size_t size, size_t align){
Ast_Type *result = exp_alloc_type(allocator, Ast_Type, AF_ZeroMemory);
result->kind = kind;
result->size = size;
@@ -230,19 +230,20 @@ type_struct_complete(Ast_Type *type, Ast_Decl *node){
Array<Ast_Resolved_Member> members = {scratch};
type->kind = TYPE_COMPLETING;
size_t members_size = 0;
For(node->scope->decls){
resolve_decl(it);
assert(it->type->kind != TYPE_INCOMPLETE);
assert(is_pow2(it->type->align));
Iter(&node->scope->decls){
Ast_Decl *decl = it.item[0];
resolve_decl(decl);
assert(decl->type->kind != TYPE_INCOMPLETE);
assert(is_pow2(decl->type->align));
Ast_Resolved_Member m = {};
m.offset = type->size;
members_size += it->type->size;
type->align = max(type->align, it->type->align);
type->size = it->type->size + align_up(type->size, it->type->align);
members_size += decl->type->size;
type->align = max(type->align, decl->type->align);
type->size = decl->type->size + align_up(type->size, decl->type->align);
m.name = it->name;
m.value = it->value;
m.name = decl->name;
m.value = decl->value;
members.add(m);
}
type->size = align_up(type->size, type->align);

View File

@@ -1,27 +1,28 @@
//-----------------------------------------------------------------------------
// Memory
//-----------------------------------------------------------------------------
const SizeU os_page_size = 4096;
const size_t os_page_size = 4096;
function OS_Memory
os_reserve(SizeU size){
os_reserve(size_t size){
OS_Memory result = {};
SizeU adjusted_size = align_up(size, os_page_size);
size_t adjusted_size = align_up(size, os_page_size);
result.data = (U8*)VirtualAlloc(0, adjusted_size, MEM_RESERVE, PAGE_READWRITE);
assert_msg(result.data, "Failed to reserve virtual memory");
assert_message(result.data, "Failed to reserve virtual memory");
result.reserve = adjusted_size;
return result;
}
function B32
os_commit(OS_Memory *m, SizeU size){
SizeU commit = align_up(size, os_page_size);
SizeU total_commit = m->commit + commit;
os_commit(OS_Memory *m, size_t size){
size_t commit = align_up(size, os_page_size);
size_t total_commit = m->commit + commit;
total_commit = clamp_top(total_commit, m->reserve);
SizeU adjusted_commit = total_commit - m->commit;
size_t adjusted_commit = total_commit - m->commit;
if(adjusted_commit != 0){
void *result = VirtualAlloc((U8*)m->data + m->commit, adjusted_commit, MEM_COMMIT, PAGE_READWRITE);
assert_msg(result, "Failed to commit more memory");
assert_message(result, "Failed to commit more memory");
m->commit += adjusted_commit;
return true;
}
@@ -31,7 +32,7 @@ os_commit(OS_Memory *m, SizeU size){
function void
os_release(OS_Memory *m){
BOOL result = VirtualFree(m->data, 0, MEM_RELEASE);
assert_msg(result != 0, "Failed to release OS_Memory");
assert_message(result != 0, "Failed to release OS_Memory");
if(result){
m->data = 0;
m->commit = 0;
@@ -40,10 +41,10 @@ os_release(OS_Memory *m){
}
function B32
os_decommit_pos(OS_Memory *m, SizeU pos){
SizeU aligned = align_down(pos, os_page_size);
SizeU adjusted_pos = clamp_top(aligned, m->commit);
SizeU size_to_decommit = m->commit - adjusted_pos;
os_decommit_pos(OS_Memory *m, size_t pos){
size_t aligned = align_down(pos, os_page_size);
size_t adjusted_pos = clamp_top(aligned, m->commit);
size_t size_to_decommit = m->commit - adjusted_pos;
if(size_to_decommit){
U8 *base_address = m->data + adjusted_pos;
BOOL result = VirtualFree(base_address, size_to_decommit, MEM_DECOMMIT);
@@ -247,3 +248,56 @@ os_list_dir(Allocator *a, String dir, U32 flags = LIST_NO_FLAGS){
return result;
}
//-----------------------------------------------------------------------------
// OS Heap allocator
//-----------------------------------------------------------------------------
struct OS_Heap:Allocator{
void *handle;
};
function void *
os_heap_allocator_proc(Allocator *a, Allocation_Kind kind, void *old_pointer, size_t size){
OS_Heap *heap = (OS_Heap *)a;
switch(kind){
case Allocation_FreeAll:{
invalid_codepath;
return 0;
}
case Allocation_Destroy:{
BOOL result = HeapDestroy(heap->handle);
assert(result != 0);
heap->handle = 0;
heap->proc = 0;
return 0;
}
case Allocation_Free:{
BOOL result = HeapFree(heap->handle, 0, old_pointer);
assert(result != 0);
return 0;
}
case Allocation_Alloc:{
void *result = HeapAlloc(heap->handle, 0, size);
assert(result);
return result;
}
case Allocation_Resize:{
void *result = HeapReAlloc(heap->handle, 0, old_pointer, size);
assert(result);
return result;
}
default: invalid_codepath;
}
return 0;
}
function OS_Heap // max_size == 0 == growing heap
win32_os_heap_create(B32 multithreaded, size_t initial_size, size_t max_size, String debug_name){
OS_Heap result = {};
result.debug_name = debug_name;
result.proc = os_heap_allocator_proc;
result.kind = Allocator_OSHeap;
result.handle = HeapCreate(multithreaded ? 0 : HEAP_NO_SERIALIZE, initial_size, max_size);
assert(result.handle);
return result;
}