namespace Memory { // ------------------ // lisp_objects // ------------------ int object_memory_size; Int_Array_List* free_spots_in_object_memory; Lisp_Object* object_memory; int next_index_in_object_memory = 0; // ------------------ // environments // ------------------ int environment_memory_size; Int_Array_List* free_spots_in_environment_memory; Environment* environment_memory; int next_index_in_environment_memory = 0; // ------------------ // strings // ------------------ int string_memory_size; // = 4096 * 1024; // == 98304kb == 96mb // free_spots_in_string_memory is an arraylist of pointers into // the string_memory, where dead String objects live (which give // information about their size) Void_Ptr_Array_List* free_spots_in_string_memory; String* string_memory; String* next_free_spot_in_string_memory; // ------------------ // immutables // ------------------ Lisp_Object* nil = nullptr; Lisp_Object* t = nullptr; proc print_status() { printf("Memory Status:\n" " - %f%% of the object_memory is used\n" " - %d of %d total Lisp_Objects are in use\n" " - %d holes in used memory (fragmentation)\n", (1.0*next_index_in_object_memory - free_spots_in_object_memory->next_index)/object_memory_size, next_index_in_object_memory - free_spots_in_object_memory->next_index, object_memory_size, free_spots_in_object_memory->next_index); printf("Memory Status:\n" " - %f%% of the string_memory is used\n" " - %d holes in used memory (fragmentation)\n", (1.0*(size_t)next_free_spot_in_string_memory - (size_t)string_memory)/string_memory_size, free_spots_in_string_memory->next_index); } inline proc get_c_str(String* str) -> char* { return &str->data; } inline proc get_c_str(Lisp_Object* str) -> char* { assert_type(str, Lisp_Object_Type::String); return get_c_str(str->value.string); } inline proc get_type(Lisp_Object* node) -> Lisp_Object_Type { // the type is in the bits 0 to 5 (including) return (Lisp_Object_Type) ((u64)node->flags & (u64)0b11111); } inline proc set_type(Lisp_Object* node, Lisp_Object_Type type) { // the type is in the bits 0 to 5 (including) u64 bitmask = (u64)-1; bitmask -= 0b11111; bitmask += (u64) type; node->flags = (u64)(node->flags) | bitmask; } proc hash(String* str) -> u64 { // TODO(Felix): When parsing symbols or keywords, compute the // hash while reading them in. u64 value = str->data << 7; for (int i = 1; i < str->length; ++i) { char c = ((char*)&str->data)[i]; value = (1000003 * value) ^ c; } value ^= str->length; return value; } proc create_string(const char* str, int len) -> String* { // TODO(Felix): check the holes first, not just always append // at the end String* ret = next_free_spot_in_string_memory; ret->length = len; strcpy(&ret->data, str); // now update the next_free_spot_in_string_memory pointer: // overstrep the counter and the first char (thik of it as if // we were overstepping the last ('\0') char) and then we only // need to overstep 'len' more chars next_free_spot_in_string_memory += 1; // overstep the other chars next_free_spot_in_string_memory = ((String*)((char*)next_free_spot_in_string_memory)+len); return ret; } proc delete_string(String* str) { append_to_array_list(free_spots_in_string_memory, (void*)str); } proc duplicate_string(String* str) -> String* { return create_string(get_c_str(str), str->length); } proc create_string (const char* str) -> String* { return create_string(str, (int)strlen(str)); } // proc create_string_formatted (const char* format, ...) -> String* { // // HACK(Felix): the length of all strings is 200!!!!!!!!!! // // HACK(Felix): the length of all strings is 200!!!!!!!!!! // int length = 200; // String* ret = create_string("", length); // int written_length; // va_list args; // va_start(args, format); // written_length = vsnprintf(&ret->data, length, format, args); // va_end(args); // ret->length = written_length; // return ret; // } proc create_lisp_object() -> Lisp_Object* { int index; // if we have no free spots then append at the end if (free_spots_in_object_memory->next_index == 0) { // if we still have space if (object_memory_size == next_index_in_object_memory) { create_out_of_memory_error( "There is not enough space in the lisp object" "memory to allocate additional lisp objects. " "Maybe try increasing the Memory size when " "calling Memory::init()"); return nullptr; } index = next_index_in_object_memory++; } else { // else fill a free spot, and remove the free spot index = free_spots_in_object_memory->data[free_spots_in_object_memory->next_index--]; } Lisp_Object* object = object_memory+index; object->flags = 0; object->sourceCodeLocation = nullptr; object->userType = nullptr; return object; } proc init(int oms, int ems, int sms) { object_memory_size = oms; environment_memory_size = ems; string_memory_size = sms; free_spots_in_object_memory = create_Int_array_list(); free_spots_in_environment_memory = create_Int_array_list(); free_spots_in_string_memory = create_Void_Ptr_array_list(); object_memory = (Lisp_Object*)malloc(object_memory_size * sizeof(Lisp_Object)); environment_memory = (Environment*)malloc(environment_memory_size * sizeof(Environment)); string_memory = (String*)malloc(string_memory_size * sizeof(char)); next_free_spot_in_string_memory = string_memory; // init nil try_void nil = create_lisp_object(); set_type(nil, Lisp_Object_Type::Nil); // init t try_void t = create_lisp_object(); set_type(t, Lisp_Object_Type::T); try_void Globals::root_environment = create_built_ins_environment(); try_void Parser::standard_in = create_string("stdin"); } proc reset() -> void { free_spots_in_object_memory->next_index = 0; free_spots_in_environment_memory->next_index = 0; free_spots_in_string_memory->next_index = 0; // because t and nil are always there we start the index at 2 next_index_in_object_memory = 2; next_index_in_environment_memory = 0; next_free_spot_in_string_memory = string_memory; Globals::root_environment = create_built_ins_environment(); } proc create_lisp_object_number(double number) -> Lisp_Object* { Lisp_Object* node; try node = create_lisp_object(); set_type(node, Lisp_Object_Type::Number); node->value.number = number; return node; } proc create_lisp_object_string(String* str) -> Lisp_Object* { Lisp_Object* node; try node = create_lisp_object(); set_type(node, Lisp_Object_Type::String); node->value.string = str; return node; } proc create_lisp_object_string(const char* str) -> Lisp_Object* { Lisp_Object* node; try node = create_lisp_object(); set_type(node, Lisp_Object_Type::String); node->value.string = create_string(str); return node; } proc get_or_create_lisp_object_symbol(String* identifier) -> Lisp_Object* { // TODO(Felix): if we already have it stored somewhere then // reuse it and dont create new one Lisp_Object* node; try node = create_lisp_object(); set_type(node, Lisp_Object_Type::Symbol); // node->value.symbol = new(Symbol); node->value.symbol.identifier = identifier; node->value.symbol.hash = hash(identifier); return node; } proc get_or_create_lisp_object_symbol(const char* identifier) -> Lisp_Object* { // TODO(Felix): This is really bad: we create a new string // even if the symbol/keyword is already existing, just to // check IF it exists and then never deleting it. return get_or_create_lisp_object_symbol( Memory::create_string(identifier)); } proc get_or_create_lisp_object_keyword(String* keyword) -> Lisp_Object* { // TODO(Felix): if we already have it stored somewhere then // reuse it and dont create new one Lisp_Object* node; try node = create_lisp_object(); set_type(node, Lisp_Object_Type::Keyword); // node->value.keyword = new(Keyword); node->value.symbol.identifier = keyword; node->value.symbol.hash = hash(keyword); return node; } proc get_or_create_lisp_object_keyword(const char* keyword) -> Lisp_Object* { // TODO(Felix): This is really bad: we create a new string // even if the symbol/keyword is already existing, just to // check IF it exists and then never deleting it. return get_or_create_lisp_object_keyword( Memory::create_string(keyword)); } proc create_lisp_object_cfunction(std::function function) -> Lisp_Object* { Lisp_Object* node; try node = create_lisp_object(); set_type(node, Lisp_Object_Type::CFunction); // node->value.lambdaWrapper = new Lambda_Wrapper(function); node->value.cFunction = new(cFunction); node->value.cFunction->function = function; return node; } proc create_lisp_object_pair(Lisp_Object* first, Lisp_Object* rest) -> Lisp_Object* { Lisp_Object* node; try node = create_lisp_object(); set_type(node, Lisp_Object_Type::Pair); // node->value.pair = new(Pair); node->value.pair.first = first; node->value.pair.rest = rest; return node; } proc copy_lisp_object(Lisp_Object* n) -> Lisp_Object* { Lisp_Object* target; try target = create_lisp_object(); *target = *n; return target; } proc create_child_environment(Environment* parent) -> Environment* { int index; // if we have no free spots then append at the end if (free_spots_in_environment_memory->next_index == 0) { // if we still have space if (environment_memory_size == next_index_in_environment_memory) { create_out_of_memory_error( "There is not enough space in the environment" "memory to allocate additional environments. " "Maybe try increasing the Memory size when " "calling Memory::init()"); return nullptr; } index = next_index_in_environment_memory++; } else { // else fill a free spot, and remove the free spot index = free_spots_in_environment_memory->data[free_spots_in_environment_memory->next_index--]; } Environment* env = environment_memory+index; int start_capacity = 16; env->parents = create_Environment_array_list(); if (parent) append_to_array_list(env->parents, parent); env->capacity = start_capacity; env->next_index = 0; env->keys = (char**)malloc(start_capacity * sizeof(char*)); env->values = (Lisp_Object**)malloc(start_capacity * sizeof(Lisp_Object*)); return env; } proc create_empty_environment() -> Environment* { Environment* ret; try ret = create_child_environment(nullptr); return ret; } proc create_built_ins_environment() -> Environment* { Environment* ret; try ret = create_child_environment(nullptr); load_built_ins_into_environment(ret); return ret; } inline proc create_list(Lisp_Object* o1) -> Lisp_Object* { Lisp_Object* ret; try ret = create_lisp_object_pair(o1, nil); return ret; } inline proc create_list(Lisp_Object* o1, Lisp_Object* o2) -> Lisp_Object* { Lisp_Object* ret; try ret = create_lisp_object_pair(o1, create_list(o2)); return ret; } inline proc create_list(Lisp_Object* o1, Lisp_Object* o2, Lisp_Object* o3) -> Lisp_Object* { Lisp_Object* ret; try ret = create_lisp_object_pair(o1, create_list(o2, o3)); return ret; } inline proc create_list(Lisp_Object* o1, Lisp_Object* o2, Lisp_Object* o3, Lisp_Object* o4) -> Lisp_Object* { Lisp_Object* ret; try ret = create_lisp_object_pair(o1, create_list(o2, o3, o4)); return ret; } inline proc create_list(Lisp_Object* o1, Lisp_Object* o2, Lisp_Object* o3, Lisp_Object* o4, Lisp_Object* o5) -> Lisp_Object* { Lisp_Object* ret; try ret = create_lisp_object_pair(o1, create_list(o2, o3, o4, o5)); return ret; } inline proc create_list(Lisp_Object* o1, Lisp_Object* o2, Lisp_Object* o3, Lisp_Object* o4, Lisp_Object* o5, Lisp_Object* o6) -> Lisp_Object* { Lisp_Object* ret; try ret = create_lisp_object_pair(o1, create_list(o2, o3, o4, o5, o6)); return ret; } }