From 84e65c63e7482590d535e86f7660a00ae8a0cecb Mon Sep 17 00:00:00 2001 From: dec05eba Date: Wed, 17 Jul 2019 19:23:16 +0200 Subject: Start on amal program Fix mutex issue in lhs expr which can cause a deadlock when a file has an error and throws and doesn't close the mutex and another thread waits for that mutex. The mutex can instead be removed and ignore race conditions which are uncommon. This should improve memory usage and performance. --- include/ast.h | 19 +++++++++++++------ include/bytecode/bytecode.h | 5 ++--- include/compiler.h | 15 +++++++-------- include/parser.h | 7 +++++-- include/program.h | 18 ++++++++++++++++++ include/std/buffer.h | 1 + include/std/hash_map.h | 2 +- include/std/scoped_allocator.h | 4 ---- 8 files changed, 47 insertions(+), 24 deletions(-) create mode 100644 include/program.h (limited to 'include') diff --git a/include/ast.h b/include/ast.h index 34e62b8..2925f6c 100644 --- a/include/ast.h +++ b/include/ast.h @@ -76,6 +76,7 @@ typedef enum { typedef struct { LhsExpr *type; AstResolveStatus status; + Parser *parser; /* Borrowed. This is the parser that is currently parsing the expression */ } AstResolveData; typedef struct { @@ -140,6 +141,11 @@ typedef struct { } value; } VariableType; +/* + Note: When resolving AST, more than one thread can end up resolving the same expressions at the same time. + This is intentional. Instead of using mutex for every expression and locking/unlocking everytime + which uses more memory and affects performance, we assume such race conditions are rare and let them happen. +*/ struct LhsExpr { bool is_extern; bool is_pub; @@ -147,10 +153,6 @@ struct LhsExpr { BufferView var_name; VariableType type; Ast *rhs_expr; - /* - TODO: Find a better way to store this. This most likely will use too much memory. - */ - amal_mutex *mutex; }; struct AssignmentExpr { @@ -204,7 +206,12 @@ struct WhileStatement { typedef struct { jmp_buf env; - amal_compiler *compiler; + amal_compiler *compiler; /* Borrowed */ + Parser *parser; /* Borrowed. This is the parser that belongs to the thread */ + /* + Borrowed. This is the current scope. Note that this scope can belong to another parser (and thread), + as such, @parser and scope_get_parser(@scope) parser may not be the same + */ Scope *scope; } AstCompilerContext; @@ -215,7 +222,7 @@ CHECK_RESULT int funcdecl_init(FunctionDecl *self, FunctionSignature *signature, CHECK_RESULT int funccall_init(FunctionCall *self, BufferView name, ScopedAllocator *allocator); CHECK_RESULT int structdecl_init(StructDecl *self, Scope *parent, ScopedAllocator *allocator); void structfield_init(StructField *self, BufferView name, BufferView type_name); -CHECK_RESULT int lhsexpr_init(LhsExpr *self, bool is_extern, bool is_pub, bool is_const, BufferView var_name, ScopedAllocator *allocator); +void lhsexpr_init(LhsExpr *self, bool is_extern, bool is_pub, bool is_const, BufferView var_name); void assignmentexpr_init(AssignmentExpr *self, Ast *lhs_expr, Ast *rhs_expr); void import_init(Import *self, BufferView path); CHECK_RESULT int string_init(String *self, BufferView str); diff --git a/include/bytecode/bytecode.h b/include/bytecode/bytecode.h index 600c9f2..739aa79 100644 --- a/include/bytecode/bytecode.h +++ b/include/bytecode/bytecode.h @@ -9,7 +9,6 @@ #include /*doc(Opcode) - # Opcode Variable length opcodes. Sizes range from 1 to 4 bytes. # Instruction formats Instructions can be in 6 different formats: @@ -50,12 +49,12 @@ typedef enum { typedef u8 AmalOpcodeType; typedef struct { - Buffer/**/ instructions; + Buffer/**/ data; } Bytecode; typedef struct { jmp_buf env; - Bytecode *bytecode; + Bytecode bytecode; Parser *parser; /* borrowed */ } BytecodeCompilerContext; diff --git a/include/compiler.h b/include/compiler.h index 3a31ad9..0ae8532 100644 --- a/include/compiler.h +++ b/include/compiler.h @@ -8,6 +8,7 @@ #include "std/thread.h" #include "compiler_options.h" #include "ast.h" +#include "program.h" #define AMAL_COMPILER_OK 0 /* General error */ @@ -32,6 +33,7 @@ typedef struct { struct amal_compiler { amal_default_types default_types; amal_compiler_options options; + amal_program *program; ScopedAllocator allocator; Scope root_scope; Buffer/**/ parsers; @@ -40,22 +42,19 @@ struct amal_compiler { ParserThreadData *threads; int usable_thread_count; bool started; - bool used; amal_mutex mutex; int generic_work_object_index; }; void amal_compiler_options_init(amal_compiler_options *self); -/* If @options is NULL, then default values are used */ -CHECK_RESULT int amal_compiler_init(amal_compiler *self, const amal_compiler_options *options); -CHECK_RESULT int amal_compiler_deinit(amal_compiler *self); /* -This function creates a copy of @filepath in the same thread it's called from -so it doesn't have to survive longer than this function call. + If @options is NULL, then default values are used. + You should run @amal_program_deinit even @amal_compiler_load_file fails, to cleanup memory. + This function creates a copy of @filepath so it doesn't have to survive longer than this function call. + The file has to be in utf-8 format and it can optionally have utf-8 BOM. */ -CHECK_RESULT int amal_compiler_load_file(amal_compiler *self, const char *filepath); +CHECK_RESULT int amal_compiler_load_file(amal_compiler_options *options, amal_program *program, const char *filepath); CHECK_RESULT int amal_compiler_internal_load_file(amal_compiler *self, const char *filepath, FileScopeReference **file_scope); -/* TODO: amal_compiler_unload_file */ #endif diff --git a/include/parser.h b/include/parser.h index 491815f..bc205f0 100644 --- a/include/parser.h +++ b/include/parser.h @@ -4,6 +4,7 @@ #include "std/buffer_view.h" #include "std/scoped_allocator.h" #include "std/thread.h" +#include "bytecode/bytecode.h" #include "tokenizer.h" #include "ast.h" #include "defs.h" @@ -39,17 +40,19 @@ struct Parser { LhsExpr file_decl; Scope *current_scope; bool has_func_parent; - ScopedAllocator *allocator; /* borrowed. Copied from @compiler for faster access to allocator */ + /* Borrowed from @compiler for faster access to allocator. The allocator is thread-specific */ + ScopedAllocator *allocator; amal_compiler *compiler; Ssa *ssa; bool started; TokenizerError error; ErrorContext error_context; jmp_buf parse_env; + Bytecode bytecode; }; CHECK_RESULT int parser_thread_data_init(ParserThreadData *self); -CHECK_RESULT int parser_thread_data_deinit(ParserThreadData *self); +void parser_thread_data_deinit(ParserThreadData *self); CHECK_RESULT int parser_thread_data_start(ParserThreadData *self, AmalThreadCallbackFunc callback_func, void *userdata); CHECK_RESULT int parser_thread_data_join(ParserThreadData *self, void **result); diff --git a/include/program.h b/include/program.h new file mode 100644 index 0000000..cbd9432 --- /dev/null +++ b/include/program.h @@ -0,0 +1,18 @@ +#ifndef AMAL_PROGRAM_H +#define AMAL_PROGRAM_H + +#include "std/buffer.h" +#include "bytecode/bytecode.h" + +typedef struct { + Buffer/*<...>*/ data; +} amal_program; + +void amal_program_init(amal_program *self); +void amal_program_deinit(amal_program *self); + +CHECK_RESULT int amal_program_append_bytecode(amal_program *self, Bytecode *bytecode); +CHECK_RESULT int amal_program_run(amal_program *self); +CHECK_RESULT int amal_program_save(amal_program *self, const char *filepath); + +#endif diff --git a/include/std/buffer.h b/include/std/buffer.h index af6b986..7a74d33 100644 --- a/include/std/buffer.h +++ b/include/std/buffer.h @@ -18,6 +18,7 @@ typedef struct { } Buffer; CHECK_RESULT int buffer_init(Buffer *self, struct ScopedAllocator *allocator); +void buffer_deinit(Buffer *self); /* @data can't be null. Use @buffer_append_empty if you want to change the size diff --git a/include/std/hash_map.h b/include/std/hash_map.h index 97b0745..9b31213 100644 --- a/include/std/hash_map.h +++ b/include/std/hash_map.h @@ -33,6 +33,6 @@ Expected @value size to be @self->value_type_size. */ CHECK_RESULT bool hash_map_get(HashMap *self, BufferView key, void *value); -int hash_compare_string(const void *a, const void *b); +int hash_map_compare_string(const void *a, const void *b); #endif diff --git a/include/std/scoped_allocator.h b/include/std/scoped_allocator.h index 60abcce..f037ea5 100644 --- a/include/std/scoped_allocator.h +++ b/include/std/scoped_allocator.h @@ -16,9 +16,6 @@ struct ScopedAllocator { ScopedAllocatorNode head; ScopedAllocatorNode *current; Buffer/**/ mems; - /* TODO: Use linked-list instead, since the elements are dynamically allocated anyways */ - /* Find another way to store mutexes */ - Buffer/**/ mutexes; }; CHECK_RESULT int scoped_allocator_node_init(ScopedAllocatorNode *self); @@ -28,6 +25,5 @@ CHECK_RESULT int scoped_allocator_init(ScopedAllocator *self); void scoped_allocator_deinit(ScopedAllocator *self); CHECK_RESULT int scoped_allocator_alloc(ScopedAllocator *self, usize size, void **mem); CHECK_RESULT int scoped_allocator_add_mem(ScopedAllocator *self, usize *result_index); -CHECK_RESULT int scoped_allocator_create_mutex(ScopedAllocator *self, amal_mutex **mutex); #endif -- cgit v1.2.3