From a790a3865505302dfe4d89aaa9817af19a3f014a Mon Sep 17 00:00:00 2001 From: FelixBrendel Date: Wed, 30 Oct 2019 00:47:52 +0100 Subject: [PATCH] trying not to leak memory --- 3rd/ftb | 2 +- bin/import1.slime | 4 ++++ bin/import2.slime | 8 +++++++ bin/pre.slime.expanded | 2 +- bin/slime.rdbg | Bin 480 -> 696 bytes bin/tests/alists.slime | 16 +++++++------- bin/tests/singular_imports.slime | 17 +++++++++++++++ build.bat | 8 ++++++- include/define_macros.hpp | 21 ++++++++++++++++++ include/libslime.h | 5 +++++ me-management.org | 36 +++++++++++++++++++++++++++++++ src/built_ins.cpp | 36 ++++++++++++++++++++----------- src/define_macros.hpp | 21 ++++++++++++++++++ src/defines.cpp | 35 ------------------------------ src/eval.cpp | 6 +++--- src/libslime.cpp | 3 +++ src/lisp_object.cpp | 6 ++++++ src/main.cpp | 3 +++ src/memory.cpp | 24 +++++++++++++++------ src/parse.cpp | 15 ++++++------- src/structs.cpp | 9 +++++++- src/testing.cpp | 3 ++- 22 files changed, 203 insertions(+), 77 deletions(-) create mode 100644 bin/import1.slime create mode 100644 bin/import2.slime create mode 100644 bin/tests/singular_imports.slime create mode 100644 me-management.org diff --git a/3rd/ftb b/3rd/ftb index a205395..43da71f 160000 --- a/3rd/ftb +++ b/3rd/ftb @@ -1 +1 @@ -Subproject commit a20539587c9547084629fb730e12dab21ea8ccca +Subproject commit 43da71f8094e24c544c12352e02eb76c746e1c93 diff --git a/bin/import1.slime b/bin/import1.slime new file mode 100644 index 0000000..a8b3392 --- /dev/null +++ b/bin/import1.slime @@ -0,0 +1,4 @@ +(define a 10) + +(define (get-a-1) + a) diff --git a/bin/import2.slime b/bin/import2.slime new file mode 100644 index 0000000..eeb9ff5 --- /dev/null +++ b/bin/import2.slime @@ -0,0 +1,8 @@ +(import "import1.slime") + + +(define (set-a-2 s) + (set! a s)) + +(define (get-a-2) + a) diff --git a/bin/pre.slime.expanded b/bin/pre.slime.expanded index f3b2e56..9b8ced5 100644 --- a/bin/pre.slime.expanded +++ b/bin/pre.slime.expanded @@ -88,7 +88,7 @@ (define (range (:from 0) :to) :doc "Returns a sequence of numbers starting with the number defined\nby the key =from= and ends with the number defined in =to=." (when (< from to) (pair from (range :from (+ 1 from) :to to)))) -(define (range-while (:from 0) to) :doc "Returns a sequence of numbers starting with the number defined\nby the key 'from' and ends with the number defined in 'to'." (define result (list (copy from))) (define head result) (mutate from (increment from)) (while (< from to) (begin (mutate head (pair (first head) (pair (copy from) nil))) (define head (rest head)) (mutate from (increment from)))) result) +(define (range-while (:from 0) :to) :doc "Returns a sequence of numbers starting with the number defined\nby the key 'from' and ends with the number defined in 'to'." (define result (list (copy from))) (define head result) (set! from (increment from)) (while (< from to) (begin (mutate head (pair (first head) (pair (copy from) nil))) (define head (rest head)) (set! from (increment from)))) result) (define (map fun seq) :doc "Takes a function and a sequence as arguments and returns a new\nsequence which contains the results of using the first sequences\nelemens as argument to that function." (if (null? seq) seq (pair (fun (first seq)) (map fun (rest seq))))) diff --git a/bin/slime.rdbg b/bin/slime.rdbg index 27c535c3544ddbf8c0620032f7a5c7a56e41106a..019307339de1a6bf064fc87f7ad5002f5a8d3079 100644 GIT binary patch literal 696 zcmaixO-sZu5QZy=pa&2B13~;?-HHev_TWJm_9|YDlr$aNXqtp%y0rh^nRa(kVcWuF zI@9N!&Sc(}&#S8>NtO%o;tCKejUdIVcnF1vM%N&6ZHKoMS|GB2j_G_PD;7ertn6j} zmy8R1VlMJVeFJ9F7^ft|0N%fCP&3$7;xHPkM2%<|m( z2jDim3=tTe?zooPGI=*zbbBi@1ldvR$k#C&m2e+|tV) zQ?f&{LZUn(Z@`vVaYlwx@hZu$Z#m%40b*ltlWuCT7&mP1vC@O@Je&~D@%)KvA5f&v pcB#$gm1`_s{L9AoL1rXE#B4x6X7}ei&O*x*7tqp~{o#m7egKM1;|c%( delta 107 zcmdnN`ha NUL 2> NUL echo ---------- Compiling ---------- -call ..\timecmd cl ../src/main.cpp /D_PROFILING /D_DEBUG /D_DONT_BREAK_ON_ERRORS /Zi /std:c++latest /Fe%exeName% /W3 /wd4003 /nologo /EHsc /link /NODEFAULTLIB:libucrt libucrtd.lib +call ..\timecmd cl ^ + ../src/main.cpp ^ + /I../3rd/ ^ + /D_PROFILING /D_DEBUG /D_DONT_BREAK_ON_ERRORS ^ + /Zi /std:c++latest /Fe%exeName% /W3 /wd4003 /nologo /EHsc ^ + /link /NODEFAULTLIB:libucrt libucrtd.lib + rem call ..\timecmd clang-cl ../src/main.cpp -o %exeName% /O2 /std:c++latest /W3 /Zi /EHsc if %errorlevel% == 0 ( diff --git a/include/define_macros.hpp b/include/define_macros.hpp index e997113..3756045 100644 --- a/include/define_macros.hpp +++ b/include/define_macros.hpp @@ -128,3 +128,24 @@ #define in_caller_env fluid_let( \ Globals::Current_Execution::envi_stack.next_index, \ Globals::Current_Execution::envi_stack.next_index-1) + + +/* + * iterate over lisp vectors + */ +#define for_lisp_vector(v) \ + if (!v); else \ + if (int it_index = 0); else \ + for (auto it = v->value.vector.data; \ + it_index < v->value.vector.length; \ + it=v->value.vector.data+(++it_index)) + +/* + * iterate over lisp lists + */ +#define for_lisp_list(l) \ + if (!l); else \ + if (int it_index = 0); else \ + for (Lisp_Object* head = l, *it; \ + Memory::get_type(head) == Lisp_Object_Type::Pair && (it = head->value.pair.first); \ + head = head->value.pair.rest, ++it_index) diff --git a/include/libslime.h b/include/libslime.h index d130045..714612d 100644 --- a/include/libslime.h +++ b/include/libslime.h @@ -1,3 +1,5 @@ +#pragma once + #include #include "ftb/arraylist.hpp" #include "ftb/hashmap.hpp" @@ -182,11 +184,13 @@ namespace Slime { void visualize_lisp_machine(); void generate_docs(String* path); + void log_error(); namespace Memory { extern Lisp_Object* nil; extern Lisp_Object* t; + Environment* create_child_environment(Environment* parent); Environment* create_built_ins_environment(); Lisp_Object* create_lisp_object_cfunction(bool is_special); Lisp_Object* get_or_create_lisp_object_keyword(const char* identifier); @@ -196,6 +200,7 @@ namespace Slime { void free_everything(); String* create_string(const char*); Lisp_Object* create_lisp_object_number(double); + Lisp_Object* create_lisp_object_pointer(void*); Lisp_Object* get_or_create_lisp_object_symbol(String* identifier); Lisp_Object* get_or_create_lisp_object_symbol(const char*); Lisp_Object* get_or_create_lisp_object_keyword(String* identifier); diff --git a/me-management.org b/me-management.org new file mode 100644 index 0000000..7b16623 --- /dev/null +++ b/me-management.org @@ -0,0 +1,36 @@ +* mallocs + +|------------------------------------------+------------------------| +| location | always freed | +|------------------------------------------+------------------------| +| [[file:3rd\ftb\arraylist.hpp::11]]: | yes | +| [[file:.\3rd\ftb\bucket_allocator.hpp::17]]: | yes | +| [[file:.\3rd\ftb\bucket_allocator.hpp::44]]: | yes | +| [[file:.\3rd\ftb\bucket_allocator.hpp::46]]: | yes | +| [[file:.\src\io.cpp::49]]: | yes | +| [[file:.\src\io.cpp::164]]: | yes | +| [[file:.\src\io.cpp::209]]: | yes | +| [[file:.\src\io.cpp::285]]: | yes | +| [[file:.\src\memory.cpp::158]]: | yes in free_everything | +| [[file:.\src\platform.cpp::3]]: | yes | +| [[file:.\src\platform.cpp::27]]: | yes | +| [[file:.\src\platform.cpp::47]]: | yes | +| [[file:.\src\platform.cpp::81]]: | yes | +|------------------------------------------+------------------------| + +* news + +|----------------------------------+-------------------------------------------------------------------------------------| +| location | always deleted | +|----------------------------------+-------------------------------------------------------------------------------------| +| [[file:.\src\eval.cpp::262]]: | ::new (&(result->positional.symbols)) Array_List; | +| [[file:.\src\eval.cpp::263]]: | ::new (&(result->keyword.keywords)) Array_List; | +| [[file:.\src\eval.cpp:264]]: | ::new (&(result->keyword.values)) Array_List; | +| [[file:.\src\io.cpp:284]]: | // allocate a new block of memory size char (1 byte) instead of wide char (2 bytes) | +| [[file:.\src\io.cpp:306]]: | wchar_t* wc = new wchar_t[cSize]; | +| [[file:.\src\memory.cpp:336]]: | // node->value.lambdaWrapper = new Lambda_Wrapper(function); | +| [[file:.\src\memory.cpp:383]]: | // inject a new array list; | +| [[file:.\src\parse.cpp:195]]: | // better for keeping track of the encountered new lines and | +| [[file:.\src\parse.cpp:196]]: | // characters since last new line so we can update the parser | +| [[file:.\src\parse.cpp:208]]: | /* new col = (count chars since last \n) + 1 */ | +|----------------------------------+-------------------------------------------------------------------------------------| diff --git a/src/built_ins.cpp b/src/built_ins.cpp index e6f62f6..6760db2 100644 --- a/src/built_ins.cpp +++ b/src/built_ins.cpp @@ -69,35 +69,47 @@ proc built_in_load(String* file_name) -> Lisp_Object* { } create_generic_error("The file to load '%s' was not found in the load path.", Memory::get_c_str(file_name)); + return nullptr; } } Lisp_Object* result = Memory::nil; - Array_List program; + Array_List* program; try program = Parser::parse_program(Memory::create_string(fullpath), file_content); - for (int i = 0; i < program.next_index; ++i) { - try result = eval_expr(program.data[i]); + for (int i = 0; i < program->next_index; ++i) { + try result = eval_expr(program->data[i]); } + delete program; + return result; } proc built_in_import(String* file_name) -> Lisp_Object* { - // create new empty environment Environment* new_env; - try new_env = Memory::create_child_environment(get_root_environment()); - get_current_environment()->parents.append(new_env); - push_environment(new_env); - defer { - pop_environment(); - }; + new_env = Memory::file_to_env_map.get_object(Memory::get_c_str(file_name)); + + if (!new_env) { + // create new empty environment + try new_env = Memory::create_child_environment(get_root_environment()); + // TODO(Felix): check absoulute paths in the map, not just + // relative ones + Memory::file_to_env_map.set_object(Memory::get_c_str(file_name), new_env); + push_environment(new_env); + defer { + pop_environment(); + }; + + Lisp_Object* res; + try res = built_in_load(file_name); + } - Lisp_Object* res = built_in_load(file_name); + get_current_environment()->parents.append(new_env); - return res; + return Memory::nil; } proc load_built_ins_into_environment() -> void { diff --git a/src/define_macros.hpp b/src/define_macros.hpp index 5783c33..4701889 100644 --- a/src/define_macros.hpp +++ b/src/define_macros.hpp @@ -128,3 +128,24 @@ #define in_caller_env fluid_let( \ Globals::Current_Execution::envi_stack.next_index, \ Globals::Current_Execution::envi_stack.next_index-1) + + +/* + * iterate over lisp vectors + */ +#define for_lisp_vector(v) \ + if (!v); else \ + if (int it_index = 0); else \ + for (auto it = v->value.vector.data; \ + it_index < v->value.vector.length; \ + it=v->value.vector.data+(++it_index)) + +/* + * iterate over lisp lists + */ +#define for_lisp_list(l) \ + if (!l); else \ + if (int it_index = 0); else \ + for (Lisp_Object* head = l, *it; \ + Memory::get_type(head) == Lisp_Object_Type::Pair && (it = head->value.pair.first); \ + head = head->value.pair.rest, ++it_index) diff --git a/src/defines.cpp b/src/defines.cpp index 7de1c50..a334642 100644 --- a/src/defines.cpp +++ b/src/defines.cpp @@ -16,41 +16,6 @@ # define if_linux if constexpr (true) #endif -/* - * iterate over lisp vectors - */ -#define for_lisp_vector(v) \ - if (!v); else \ - if (int it_index = 0); else \ - for (auto it = v->value.vector.data; \ - it_index < v->value.vector.length; \ - it=v->value.vector.data+(++it_index)) - -/* - * iterate over lisp lists - */ -#define for_lisp_list(l) \ - if (!l); else \ - if (int it_index = 0); else \ - for (Lisp_Object* head = l, *it; \ - Memory::get_type(head) == Lisp_Object_Type::Pair && (it = head->value.pair.first); \ - head = head->value.pair.rest, ++it_index) - - - -/* - #define assert(cond) \ - if_debug { \ - if (!cond) { \ - if (log_level == Log_Level::Debug) { \ - printf("Assertion failed: %s %d", __FILE__, __LINE__); \ - } \ - debug_break(); \ - } \ - } else {} \ -*/ - - #define console_normal "\x1B[0m" #define console_red "\x1B[31m" #define console_green "\x1B[32m" diff --git a/src/eval.cpp b/src/eval.cpp index f5ffbfe..4d4f11f 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -259,9 +259,9 @@ proc create_arguments_from_lambda_list_and_inject(Lisp_Object* arguments, Lisp_O result = &function->value.function.args; } - ::new (&(result->positional.symbols)) Array_List; - ::new (&(result->keyword.keywords)) Array_List; - ::new (&(result->keyword.values)) Array_List; + ::new (&result->positional.symbols) Array_List; + ::new (&result->keyword.keywords) Array_List; + ::new (&result->keyword.values) Array_List; // first init the fields // result->positional = create_positional_argument_list(16); diff --git a/src/libslime.cpp b/src/libslime.cpp index 0f309fe..be4dee1 100644 --- a/src/libslime.cpp +++ b/src/libslime.cpp @@ -1,7 +1,10 @@ #define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_DEPRECATE +#define _CRTDBG_MAP_ALLOC #include +#include + #include #include #include diff --git a/src/lisp_object.cpp b/src/lisp_object.cpp index e3248a6..69ce60f 100644 --- a/src/lisp_object.cpp +++ b/src/lisp_object.cpp @@ -39,3 +39,9 @@ proc append_to_keyword_argument_list(Keyword_Arguments* args, args->keywords.append(keyword); args->values.append(default_value); } + +Lisp_Object::~Lisp_Object() { + if (Memory::get_type(this) == Lisp_Object_Type::HashMap) { + this->value.hashMap.~Hash_Map(); + } +} diff --git a/src/main.cpp b/src/main.cpp index 4c1eddd..68375c6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,10 +1,13 @@ #include "libslime.cpp" + int main(int argc, char* argv[]) { if (argc > 1) { if (Slime::string_equal(argv[1], "--run-tests")) { int res = Slime::run_all_tests(); // Slime::interprete_file((char*)"generate-docs.slime"); + + _CrtDumpMemoryLeaks(); return res ? 0 : 1; } diff --git a/src/memory.cpp b/src/memory.cpp index 002461d..d5befeb 100644 --- a/src/memory.cpp +++ b/src/memory.cpp @@ -6,6 +6,8 @@ namespace Memory { Hash_Map global_symbol_table; Hash_Map global_keyword_table; + + Hash_Map file_to_env_map; // ------------------ // lisp_objects // ------------------ @@ -177,13 +179,23 @@ namespace Memory { free_spots_in_string_memory.next_index = 0; - ::new((&global_symbol_table)) Hash_Map; - ::new((&global_keyword_table)) Hash_Map; + global_symbol_table.~Hash_Map(); + global_keyword_table.~Hash_Map(); + file_to_env_map.~Hash_Map(); + + ::new(&global_symbol_table) Hash_Map; + ::new(&global_keyword_table) Hash_Map; + ::new(&file_to_env_map) Hash_Map; try_void Parser::standard_in = create_string("stdin"); - object_memory.reset(); - environment_memory.reset(); + + object_memory.~Bucket_Allocator(); + // environment_memory.~Bucket_Allocator(); + + ::new(&object_memory) Bucket_Allocator; + ::new(&environment_memory) Bucket_Allocator; + next_free_spot_in_string_memory = string_memory; @@ -373,7 +385,7 @@ namespace Memory { return copy_lisp_object(n); } - proc create_child_environment(Environment* parent) -> Environment* { + proc create_child_environment(Environment* parent) -> Environment* { Environment* env = environment_memory.allocate(); @@ -404,7 +416,7 @@ namespace Memory { try load_built_ins_into_environment(); - built_in_load(Memory::create_string("pre.slime")); + try built_in_load(Memory::create_string("pre.slime")); return ret; } diff --git a/src/parse.cpp b/src/parse.cpp index 4ecd10f..2f2650d 100644 --- a/src/parse.cpp +++ b/src/parse.cpp @@ -98,7 +98,6 @@ namespace Parser { // get the atom String* ret = Memory::create_string("", atom_length); - // char* atom = (char*)malloc(atom_length*sizeof(char)+1); // plus null char strcpy(&ret->data, text+(*index_in_text)); // restore the original string @@ -448,7 +447,7 @@ namespace Parser { } - proc write_expanded_file(String* file_name, Array_List program) -> void { + proc write_expanded_file(String* file_name, Array_List* program) -> void { const char* ext = ".expanded"; char* newName = (char*)calloc(10 + file_name->length, sizeof(char)); strcpy(newName, Memory::get_c_str(file_name)); @@ -465,21 +464,21 @@ namespace Parser { exit(1); } - for (int i = 0; i < program.next_index; ++i) { + for (int i = 0; i < program->next_index; ++i) { // a macro will parse as nil for now, so we skip those - if (program.data[i] == Memory::nil) + if (program->data[i] == Memory::nil) continue; - print(program.data[i], true, f); + print(program->data[i], true, f); fprintf(f, "\n\n"); } } - proc parse_program(String* file_name, char* text) -> Array_List { + proc parse_program(String* file_name, char* text) -> Array_List* { parser_file = file_name; parser_line = 1; parser_col = 0; - Array_List program; + Array_List* program = new Array_List; int index_in_text = 0; @@ -490,7 +489,7 @@ namespace Parser { try_struct { parsed = parse_expression(text, &index_in_text); } - program.append(parsed); + program->append(parsed); } break; case ';': case ' ': diff --git a/src/structs.cpp b/src/structs.cpp index e52a2ab..d69062b 100644 --- a/src/structs.cpp +++ b/src/structs.cpp @@ -103,6 +103,11 @@ struct Arguments { struct Environment { Array_List parents; Hash_Map hm; + + ~Environment() { + parents.~Array_List(); + hm.~Hash_Map(); + } }; struct Function { @@ -123,7 +128,7 @@ struct Lisp_Object { u64 flags; Lisp_Object* userType; // keyword String* docstring; - union { + union value { Symbol symbol; // used for symbols and keywords double number; String* string; @@ -134,7 +139,9 @@ struct Lisp_Object { void* pointer; Continuation continuation; Hash_Map hashMap; + ~value() {} } value; + ~Lisp_Object(); }; struct Error { diff --git a/src/testing.cpp b/src/testing.cpp index a135732..7643eb7 100644 --- a/src/testing.cpp +++ b/src/testing.cpp @@ -596,7 +596,7 @@ proc test_file(const char* file) -> testresult { pop_environment(); }; - built_in_load(Memory::create_string(file)); + try built_in_load(Memory::create_string(file)); assert_no_error(); return pass; @@ -654,6 +654,7 @@ proc run_all_tests() -> bool { invoke_test_script("automata"); invoke_test_script("sicp"); invoke_test_script("hashmaps"); + invoke_test_script("singular_imports"); // Memory::print_status();