Managing bigint memory

This commit is contained in:
Krzosa Karol
2022-06-06 16:49:41 +02:00
parent 06d6ec7525
commit dc56bd54f3
6 changed files with 165 additions and 62 deletions

View File

@@ -3,9 +3,17 @@
// a copy of which can be found in the LICENSE file. // a copy of which can be found in the LICENSE file.
struct Token; struct Token;
Allocator *bigint_allocator;
global S64 bigint_allocation_count; global S64 bigint_allocation_count;
function void parsing_error(Token *token, const char *str, ...); function void parsing_error(Token *token, const char *str, ...);
#define malloc_arena(x) (bigint_allocation_count++, exp_alloc(&pernament_arena, x))
#define Set_BigInt_Allocator(x) BigInt_Allocator bigint_allocator(x)
struct BigInt_Allocator{
BigInt_Allocator(Allocator *allocator){bigint_allocator = allocator;}
~BigInt_Allocator(){bigint_allocator = 0;}
};
#define malloc_arena(x) (bigint_allocation_count++, exp_alloc(bigint_allocator, x, AF_ZeroMemory))
#define ALLOC_DIGITS(_digits) (uint64_t *)((_digits) ? malloc_arena(sizeof(uint64_t) * (_digits)) : NULL) #define ALLOC_DIGITS(_digits) (uint64_t *)((_digits) ? malloc_arena(sizeof(uint64_t) * (_digits)) : NULL)
#define FATAL_ERROR(x) parsing_error(0, x) #define FATAL_ERROR(x) parsing_error(0, x)
@@ -95,6 +103,33 @@ bigint_mul(const BigInt *a, const BigInt *b){
return result; return result;
} }
function BigInt
bigint_add(const BigInt *a, const BigInt *b){
BigInt result;
bigint_add(&result, a, b);
return result;
}
function BigInt
bigint_copy(Allocator *allocator, BigInt *src){
BigInt dest = {};
if (src->digit_count == 0){
bigint_init_unsigned(&dest, 0);
return dest;
}
if(src->digit_count == 1){
dest.digit_count = 1;
dest.digit = src->digit;
dest.is_negative = src->is_negative;
return dest;
}
dest.is_negative = src->is_negative;
dest.digit_count = src->digit_count;
dest.digits = exp_alloc_array(allocator, uint64_t, dest.digit_count, AF_ZeroMemory);
memcpy(dest.digits, src->digits, sizeof(uint64_t) * dest.digit_count);
return dest;
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// //
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@@ -671,6 +706,8 @@ bool mul_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result)
void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2) void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2)
{ {
assert(dest != op1);
assert(dest != op2);
if (op1->digit_count == 0) if (op1->digit_count == 0)
{ {
return bigint_init_bigint(dest, op2); return bigint_init_bigint(dest, op2);
@@ -893,6 +930,8 @@ static void mul_scalar(BigInt *dest, const BigInt *op, uint64_t scalar)
void bigint_mul(BigInt *dest, const BigInt *op1, const BigInt *op2) void bigint_mul(BigInt *dest, const BigInt *op1, const BigInt *op2)
{ {
assert(dest != op1);
assert(dest != op2);
if (op1->digit_count == 0 || op2->digit_count == 0) if (op1->digit_count == 0 || op2->digit_count == 0)
{ {
return bigint_init_unsigned(dest, 0); return bigint_init_unsigned(dest, 0);
@@ -1958,6 +1997,7 @@ void bigint_print(BigInt *bigint, uint64_t base)
const char *bigint_to_error_string(Allocator *allocator, const BigInt *bigint, uint64_t base) const char *bigint_to_error_string(Allocator *allocator, const BigInt *bigint, uint64_t base)
{ {
Set_BigInt_Allocator(allocator);
if (bigint->digit_count == 0) if (bigint->digit_count == 0)
{ {
return "0"; return "0";
@@ -2021,6 +2061,7 @@ const char *bigint_to_error_string(Allocator *allocator, const BigInt *bigint, u
*(current++) = *ptr; *(current++) = *ptr;
} }
*(current++) = '\0'; *(current++) = '\0';
return out; return out;
} }

View File

@@ -108,7 +108,6 @@ For now I don't thing it should be overloadable.
int main(){ int main(){
// test_big_int(); // test_big_int();
test_os_memory(); test_os_memory();
thread_ctx_init(); thread_ctx_init();
test_unicode(); test_unicode();

View File

@@ -319,7 +319,7 @@ function Ast_Atom *
ast_int(Token *pos, BigInt val){ ast_int(Token *pos, BigInt val){
AST_NEW(Atom, VALUE, pos, AST_EXPR | AST_ATOM); AST_NEW(Atom, VALUE, pos, AST_EXPR | AST_ATOM);
result->type = untyped_int; result->type = untyped_int;
bigint_init_bigint(&result->big_int_val, &val); result->big_int_val = bigint_copy(pctx->perm, &val);
return result; return result;
} }

View File

@@ -86,7 +86,7 @@ enum Token_Kind{
TK_Pointer = TK_Mul, TK_Pointer = TK_Mul,
TK_Dereference = TK_BitAnd, TK_Dereference = TK_BitAnd,
OPEN_SCOPE = 128, OPEN_SCOPE = 128,
CLOSE_SCOPE, CLOSE_SCOPE,
SAME_SCOPE, SAME_SCOPE,
@@ -125,6 +125,7 @@ struct Lex_Stream{
}; };
struct Lexer{ struct Lexer{
Allocator *arena;
Lex_Stream stream; Lex_Stream stream;
Array<Token> tokens; Array<Token> tokens;
Intern_Table interns; Intern_Table interns;
@@ -205,17 +206,23 @@ token_error(Token *t, String error_val){
} }
function void function void
lex_parse_u64(Token *t){ lex_parse_u64(Lexer *lexer, Token *t){
Scratch scratch;
Set_BigInt_Allocator(scratch);
t->kind = TK_Integer; t->kind = TK_Integer;
BigInt m = bigint_u64(1); // @leak, it accumulates and potentially needs allocation BigInt m = bigint_u64(1); // @leak, it accumulates and potentially needs allocation
BigInt val10 = bigint_u64(10); BigInt val10 = bigint_u64(10);
BigInt result = bigint_u64(0);
for(S64 i = t->len - 1; i >= 0; --i){ for(S64 i = t->len - 1; i >= 0; --i){
BigInt val = bigint_u64(t->str[i] - '0'); // I dont think this is a leak, too small BigInt val = bigint_u64(t->str[i] - '0'); // I dont think this is a leak, too small
BigInt new_val = bigint_mul(&val, &m); // @leak BigInt new_val = bigint_mul(&val, &m); // @leak
bigint_add(&t->int_val, &t->int_val, &new_val); result = bigint_add(&result, &new_val); // @leak
bigint_mul(&m, &m, &val10); m = bigint_mul(&m, &val10); // @leak
} }
t->int_val = bigint_copy(lexer->arena, &result);
} }
function void function void
@@ -332,7 +339,10 @@ lex_unwind_indent_stack(Token *t, Lex_Stream *s, Array<Token> *array){
} }
function void function void
lex__stream(Intern_Table *table, Array<Token> *array, Lex_Stream *s){ lex__stream(Lexer *lexer, Lex_Stream *s){
Intern_Table *table = &lexer->interns;
Array<Token> *array = &lexer->tokens;
B32 beginning = true; B32 beginning = true;
for(;;){ for(;;){
if(lexc(s) == 0 || s->iter >= s->stream.len){ if(lexc(s) == 0 || s->iter >= s->stream.len){
@@ -594,7 +604,7 @@ lex__stream(Intern_Table *table, Array<Token> *array, Lex_Stream *s){
} }
lex_set_len(s, &t); lex_set_len(s, &t);
if(found_dot) lex_parse_f64(&t); if(found_dot) lex_parse_f64(&t);
else lex_parse_u64(&t); else lex_parse_u64(lexer, &t);
} break; } break;
@@ -633,6 +643,7 @@ lex__stream(Intern_Table *table, Array<Token> *array, Lex_Stream *s){
function void function void
lex_init(Allocator *token_string_arena, Allocator *map_allocator, Lexer *l){ lex_init(Allocator *token_string_arena, Allocator *map_allocator, Lexer *l){
l->arena = token_string_arena;
l->tokens = array_make<Token>(token_string_arena, 1024*2); l->tokens = array_make<Token>(token_string_arena, 1024*2);
l->interns= intern_table_make(token_string_arena, map_allocator, 1024); l->interns= intern_table_make(token_string_arena, map_allocator, 1024);
} }
@@ -657,7 +668,7 @@ lex_restream(Lexer *lexer, String istream, String file){
Scratch scratch; Scratch scratch;
lexer->stream.indent_stack.allocator = scratch; lexer->stream.indent_stack.allocator = scratch;
lexer->stream.indent_stack.add(&token_null); lexer->stream.indent_stack.add(&token_null);
lex__stream(&lexer->interns, &lexer->tokens, &lexer->stream); lex__stream(lexer, &lexer->stream);
} }
function Lexer function Lexer

View File

@@ -21,7 +21,7 @@ unary_test :: ()
// var := -true // var := -true
// var := +true // var := +true
binary_test :: () binary_test :: (thing: S32 = 1051514424242424242442424242424252525252)
int_val :: 1000 int_val :: 1000
add :: int_val + 10 + 2.242 + 124 add :: int_val + 10 + 2.242 + 124
mul :: 4 * 2 mul :: 4 * 2
@@ -30,10 +30,13 @@ binary_test :: ()
bit_xor :: 8 ^ 7 bit_xor :: 8 ^ 7
character :: 'ó character :: 'ó
boolean_equals :: true == false boolean_equals :: true == false
boolean_var: Bool = boolean_equals boolean_var: Bool = boolean_equals
cast_value :: cast(4242: S32) cast_value :: 4242 + cast(32: S32) + cast(42: S32)
value: S32 = cast_value
bvar2 := int_val > 1 bvar2 := int_val > 1
if int_val < 1 if int_val < 1

View File

@@ -72,7 +72,7 @@ value_float(BigInt a){
} }
function void function void
check_value_boundaries(Token *pos, Value *a){ check_value_bounds(Token *pos, Value *a){
if(!is_int(a->type)) return; if(!is_int(a->type)) return;
Scratch scratch; Scratch scratch;
@@ -101,25 +101,77 @@ convert_untyped(Token *pos, Value a, Ast_Resolved_Type *new_type){
else parsing_error(pos, "Type mismatch when converting from %s to %s", docname(a.type), docname(new_type)); else parsing_error(pos, "Type mismatch when converting from %s to %s", docname(a.type), docname(new_type));
a.type = new_type; a.type = new_type;
check_value_boundaries(pos, &a); check_value_bounds(pos, &a);
return a; return a;
} }
/*
Type resolution cases
val := expr
convert untyped to typed default
check bounds
make new symbol
CONST :: expr
make new symbol
call(default:type = expr)
val: type = expr
convert untyped to typed based on type
make sure expr.type == type
check bounds
expr == expr
expr * expr
make sure compatible types, floats with ints are ok(convert to float)
if only one of them is typed convert the untyped to typed
if both types typed make sure they are the same
check bounds
!expr
make sure correct type
return bool
call(expr, expr)
convert untyped to matching typed
check if types match
cast(expr: type)
convert from untyped to typed
convert between typed to other typed
check if types compatible
*/
function void function void
match_values(Value *a, Value *b){ match_values(Token *pos, Value *a, Value *b){
// @todo: We want match values to convert when int and float => float if(is_typed(a->type) && is_typed(b->type)){
// but also we want to unify types when one of them is typed and other untyped??? if(a->type != b->type){
// Lastly maybe check if typed types are the same parsing_error(pos, "Type mismatch in match_values - left: %s right: %s", docname(a->type), docname(b->type));
if(is_int(a->type) && is_float(b->type)) }
}
if(is_untyped(a->type) && is_typed(b->type)){
assert(is_typed(b->type));
*a = convert_untyped(pos, *a, b->type);
}
else if(is_typed(a->type) && is_untyped(b->type)){
assert(is_typed(a->type));
*b = convert_untyped(pos, *b, a->type);
}
else if(is_int(a->type) && is_float(b->type)){
*a = value_float(a->big_int_val); *a = value_float(a->big_int_val);
else if(is_float(a->type) && is_int(b->type)) }
else if(is_float(a->type) && is_int(b->type)){
*b = value_float(b->big_int_val); *b = value_float(b->big_int_val);
}
} }
function Value function Value
compare_values(Token *pos, Token_Kind op, Value a, Value b){ compare_values(Token *pos, Token_Kind op, Value a, Value b){
if(!(is_numeric(a.type) && is_numeric(b.type))) parsing_error(pos, "Constant application of binary %s on values of type %s and %s is not allowed", name(op), docname(a.type), docname(a.type)); if(!(is_numeric(a.type) && is_numeric(b.type))) parsing_error(pos, "Constant application of binary %s on values of type %s and %s is not allowed", name(op), docname(a.type), docname(a.type));
match_values(&a, &b); match_values(pos, &a, &b);
B32 result = 0; B32 result = 0;
switch(a.type->kind){ switch(a.type->kind){
@@ -137,8 +189,8 @@ compare_values(Token *pos, Token_Kind op, Value a, Value b){
}break; }break;
CASE_BOOL:{ CASE_BOOL:{
switch(op){ switch(op){
case TK_Equals: result = a.bool_val == b.bool_val; break; case TK_Equals: result = a.bool_val == b.bool_val; break;
case TK_NotEquals: result = a.bool_val != b.bool_val; break; case TK_NotEquals: result = a.bool_val != b.bool_val; break;
invalid_default_case; invalid_default_case;
} }
}break; }break;
@@ -164,13 +216,13 @@ compare_values(Token *pos, Token_Kind op, Value a, Value b){
function Value function Value
eval_binary(Token *pos, Token_Kind op, Value a, Value b){ eval_binary(Token *pos, Token_Kind op, Value a, Value b){
if(!(is_numeric(a.type) && is_numeric(b.type))) parsing_error(pos, "Constant application of binary %s on values of type %s and %s is not allowed", name(op), docname(a.type), docname(a.type));
match_values(&a, &b);
if(token_is_compare(op)){ if(token_is_compare(op)){
return compare_values(pos, op, a, b); return compare_values(pos, op, a, b);
} }
if(!(is_numeric(a.type) && is_numeric(b.type))) parsing_error(pos, "Constant application of binary %s on values of type %s and %s is not allowed", name(op), docname(a.type), docname(a.type));
match_values(pos, &a, &b);
Value result = {}; Value result = {};
result.type = a.type; result.type = a.type;
switch(a.type->kind){ switch(a.type->kind){
@@ -285,6 +337,29 @@ try_untyping(Operand *op){
} }
} }
function void
resolve_var(Token *pos, Operand *expr, Ast_Resolved_Type *type = 0){
if(type == expr->type) {
assert(expr->type);
return;
}
if(!type)
try_untyping(expr);
else if(!expr->type)
expr->type = type;
else if(is_untyped(expr->type))
expr->value = convert_untyped(pos, expr->value, type);
if(type && expr->type != type){
parsing_error(pos, "Assigning but incompatible types, expression: %s expected var type: %s", docname(expr->type), docname(type));
}
type_complete(expr->type);
check_value_bounds(pos, &expr->value);
assert(expr->type);
}
#define rewrite_into_const(ast,T,s) _rewrite_into_const(ast,sizeof(T),s) #define rewrite_into_const(ast,T,s) _rewrite_into_const(ast,sizeof(T),s)
function void function void
_rewrite_into_const(Ast *node, U64 ast_size, Value value){ _rewrite_into_const(Ast *node, U64 ast_size, Value value){
@@ -395,11 +470,7 @@ resolve_lambda(Ast_Lambda *lambda, Sym *sym = 0){
For(lambda->args){ For(lambda->args){
Ast_Resolved_Type *type = resolve_typespec(it->typespec, AST_CANT_BE_NULL); Ast_Resolved_Type *type = resolve_typespec(it->typespec, AST_CANT_BE_NULL);
Operand default_value = resolve_expr(it->default_value, type); Operand default_value = resolve_expr(it->default_value, type);
resolve_var(it->pos, &default_value, type);
if(default_value.type){
default_value.value = convert_untyped(it->pos, default_value.value, type);
if(default_value.type != type) parsing_error(it->pos, "Default value type and type declaration differ, expected %s got instead %s", docname(type), docname(default_value.type));
}
args.add(type); args.add(type);
} }
@@ -422,6 +493,7 @@ resolve_lambda(Ast_Lambda *lambda, Sym *sym = 0){
For(lambda->args){ For(lambda->args){
S64 i = lambda->args.get_index(&it); S64 i = lambda->args.get_index(&it);
Ast_Resolved_Type *type = args[i]; Ast_Resolved_Type *type = args[i];
sym_var(it->name, type, it, INSERT_INTO_SCOPE); sym_var(it->name, type, it, INSERT_INTO_SCOPE);
} }
For(lambda->block->stmts){ For(lambda->block->stmts){
@@ -671,7 +743,7 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res
} }
if(original_type != type) assert(expr.type == type); if(original_type != type) assert(expr.type == type);
check_value_boundaries(node->pos, &expr.value); check_value_bounds(node->pos, &expr.value);
return expr; return expr;
BREAK(); BREAK();
} }
@@ -713,9 +785,10 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res
assert(node->left->kind == AST_IDENT); assert(node->left->kind == AST_IDENT);
Operand right = resolve_expr(node->right); Operand right = resolve_expr(node->right);
try_untyping(&right); resolve_var(node->pos, &right);
assert(right.type);
Ast_Atom *atom = (Ast_Atom *)node->left; auto atom = (Ast_Atom *)node->left;
sym_var(atom->intern_val, right, node, INSERT_INTO_SCOPE); sym_var(atom->intern_val, right, node, INSERT_INTO_SCOPE);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@@ -822,29 +895,12 @@ resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *lambda_to_res
else{ else{
Operand left = resolve_expr(node->left); Operand left = resolve_expr(node->left);
Operand right = resolve_expr(node->right); Operand right = resolve_expr(node->right);
Value value = eval_binary(node->pos, node->op, left.value, right.value);
if(left.is_const && right.is_const){ if(left.is_const && right.is_const){
Value value = eval_binary(node->pos, node->op, left.value, right.value);
rewrite_into_const(node, Ast_Binary, value); rewrite_into_const(node, Ast_Binary, value);
result = operand_const_rvalue(value); result = operand_const_rvalue(value);
} }
else{ else result = operand_rvalue(left.type);
if(is_untyped(left.type)){
assert(is_typed(right.type));
left.value = convert_untyped(node->pos, left.value, right.type);
}
else if(is_untyped(right.type)){
assert(is_typed(left.type));
right.value = convert_untyped(node->pos, right.value, left.type);
}
if(left.type != right.type){
parsing_error(node->pos, "Type mismatch in binary operation %s - left: %s right: %s", name(node->op), docname(left.type), docname(right.type));
}
else{
result = operand_rvalue(left.type);
}
}
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@@ -907,14 +963,8 @@ resolve_binding(Ast *ast, Sym *sym){
Ast_Resolved_Type *type = resolve_typespec(node->typespec, AST_CAN_BE_NULL); Ast_Resolved_Type *type = resolve_typespec(node->typespec, AST_CAN_BE_NULL);
Operand expr = resolve_expr(node->expr, type); Operand expr = resolve_expr(node->expr, type);
assert(expr.type != 0 || type != 0); assert(expr.type != 0 || type != 0);
resolve_var(node->pos, &expr, type);
if(!type) try_untyping(&expr); assert(expr.type);
else if(!expr.type) expr.type = type;
else if(type == expr.type);
else if(is_untyped(expr.type)) expr.value = convert_untyped(node->pos, expr.value, type);
else invalid_codepath;
type_complete(expr.type);
return expr; return expr;
BREAK(); BREAK();
} }
@@ -945,7 +995,6 @@ resolve_sym(Sym *sym){
sym->state = SYM_RESOLVING; sym->state = SYM_RESOLVING;
{ {
Operand op = resolve_binding(sym->ast, sym); Operand op = resolve_binding(sym->ast, sym);
sym->type = op.type;
sym->value = op.value; sym->value = op.value;
} }
sym->state = SYM_RESOLVED; sym->state = SYM_RESOLVED;