You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

413 rivejä
14 KiB

  1. namespace Memory {
  2. // ------------------
  3. // lisp_objects
  4. // ------------------
  5. int object_memory_size;
  6. Int_Array_List* free_spots_in_object_memory;
  7. Lisp_Object* object_memory;
  8. int next_index_in_object_memory = 0;
  9. // ------------------
  10. // environments
  11. // ------------------
  12. int environment_memory_size;
  13. Int_Array_List* free_spots_in_environment_memory;
  14. Environment* environment_memory;
  15. int next_index_in_environment_memory = 0;
  16. // ------------------
  17. // strings
  18. // ------------------
  19. int string_memory_size; // = 4096 * 1024; // == 98304kb == 96mb
  20. // free_spots_in_string_memory is an arraylist of pointers into
  21. // the string_memory, where dead String objects live (which give
  22. // information about their size)
  23. Void_Ptr_Array_List* free_spots_in_string_memory;
  24. String* string_memory;
  25. String* next_free_spot_in_string_memory;
  26. // ------------------
  27. // immutables
  28. // ------------------
  29. Lisp_Object* nil = nullptr;
  30. Lisp_Object* t = nullptr;
  31. proc print_status() {
  32. printf("Memory Status:\n"
  33. " - %f%% of the object_memory is used\n"
  34. " - %d of %d total Lisp_Objects are in use\n"
  35. " - %d holes in used memory (fragmentation)\n",
  36. (1.0*next_index_in_object_memory - free_spots_in_object_memory->next_index)/object_memory_size,
  37. next_index_in_object_memory - free_spots_in_object_memory->next_index, object_memory_size,
  38. free_spots_in_object_memory->next_index);
  39. printf("Memory Status:\n"
  40. " - %f%% of the string_memory is used\n"
  41. " - %d holes in used memory (fragmentation)\n",
  42. (1.0*(size_t)next_free_spot_in_string_memory - (size_t)string_memory)/string_memory_size,
  43. free_spots_in_string_memory->next_index);
  44. }
  45. inline proc get_c_str(String* str) -> char* {
  46. return &str->data;
  47. }
  48. inline proc get_c_str(Lisp_Object* str) -> char* {
  49. assert_type(str, Lisp_Object_Type::String);
  50. return get_c_str(str->value.string);
  51. }
  52. inline proc get_type(Lisp_Object* node) -> Lisp_Object_Type {
  53. // the type is in the bits 0 to 5 (including)
  54. return (Lisp_Object_Type) ((u64)node->flags & (u64)0b11111);
  55. }
  56. inline proc set_type(Lisp_Object* node, Lisp_Object_Type type) {
  57. // the type is in the bits 0 to 5 (including)
  58. u64 bitmask = (u64)-1;
  59. bitmask -= 0b11111;
  60. bitmask += (u64) type;
  61. node->flags = (u64)(node->flags) | bitmask;
  62. }
  63. proc hash(String* str) -> u64 {
  64. // TODO(Felix): When parsing symbols or keywords, compute the
  65. // hash while reading them in.
  66. u64 value = str->data << 7;
  67. for (int i = 1; i < str->length; ++i) {
  68. char c = ((char*)&str->data)[i];
  69. value = (1000003 * value) ^ c;
  70. }
  71. value ^= str->length;
  72. return value;
  73. }
  74. proc create_string(const char* str, int len) -> String* {
  75. // TODO(Felix): check the holes first, not just always append
  76. // at the end
  77. String* ret = next_free_spot_in_string_memory;
  78. ret->length = len;
  79. strcpy(&ret->data, str);
  80. // now update the next_free_spot_in_string_memory pointer:
  81. // overstrep the counter and the first char (thik of it as if
  82. // we were overstepping the last ('\0') char) and then we only
  83. // need to overstep 'len' more chars
  84. next_free_spot_in_string_memory += 1;
  85. // overstep the other chars
  86. next_free_spot_in_string_memory = ((String*)((char*)next_free_spot_in_string_memory)+len);
  87. return ret;
  88. }
  89. proc delete_string(String* str) {
  90. append_to_array_list(free_spots_in_string_memory, (void*)str);
  91. }
  92. proc duplicate_string(String* str) -> String* {
  93. return create_string(get_c_str(str), str->length);
  94. }
  95. proc create_string (const char* str) -> String* {
  96. return create_string(str, (int)strlen(str));
  97. }
  98. // proc create_string_formatted (const char* format, ...) -> String* {
  99. // // HACK(Felix): the length of all strings is 200!!!!!!!!!!
  100. // // HACK(Felix): the length of all strings is 200!!!!!!!!!!
  101. // int length = 200;
  102. // String* ret = create_string("", length);
  103. // int written_length;
  104. // va_list args;
  105. // va_start(args, format);
  106. // written_length = vsnprintf(&ret->data, length, format, args);
  107. // va_end(args);
  108. // ret->length = written_length;
  109. // return ret;
  110. // }
  111. proc create_lisp_object() -> Lisp_Object* {
  112. int index;
  113. // if we have no free spots then append at the end
  114. if (free_spots_in_object_memory->next_index == 0) {
  115. // if we still have space
  116. if (object_memory_size == next_index_in_object_memory) {
  117. create_out_of_memory_error(
  118. "There is not enough space in the lisp object "
  119. "memory to allocate additional lisp objects. "
  120. "Maybe try increasing the Memory size when "
  121. "calling Memory::init()");
  122. return nullptr;
  123. }
  124. index = next_index_in_object_memory++;
  125. } else {
  126. // else fill a free spot, and remove the free spot
  127. index = free_spots_in_object_memory->data[free_spots_in_object_memory->next_index--];
  128. }
  129. Lisp_Object* object = object_memory+index;
  130. object->flags = 0;
  131. object->sourceCodeLocation = nullptr;
  132. object->userType = nullptr;
  133. object->docstring = nullptr;
  134. return object;
  135. }
  136. proc init(int oms, int ems, int sms) {
  137. object_memory_size = oms;
  138. environment_memory_size = ems;
  139. string_memory_size = sms;
  140. free_spots_in_object_memory = create_Int_array_list();
  141. free_spots_in_environment_memory = create_Int_array_list();
  142. free_spots_in_string_memory = create_Void_Ptr_array_list();
  143. object_memory = (Lisp_Object*)malloc(object_memory_size * sizeof(Lisp_Object));
  144. environment_memory = (Environment*)malloc(environment_memory_size * sizeof(Environment));
  145. string_memory = (String*)malloc(string_memory_size * sizeof(char));
  146. next_free_spot_in_string_memory = string_memory;
  147. // init nil
  148. try_void nil = create_lisp_object();
  149. set_type(nil, Lisp_Object_Type::Nil);
  150. // init t
  151. try_void t = create_lisp_object();
  152. set_type(t, Lisp_Object_Type::T);
  153. try_void Globals::root_environment = create_built_ins_environment();
  154. try_void Parser::standard_in = create_string("stdin");
  155. }
  156. proc reset() -> void {
  157. free_spots_in_object_memory->next_index = 0;
  158. free_spots_in_environment_memory->next_index = 0;
  159. free_spots_in_string_memory->next_index = 0;
  160. // because t and nil are always there we start the index at 2
  161. next_index_in_object_memory = 2;
  162. next_index_in_environment_memory = 0;
  163. next_free_spot_in_string_memory = string_memory;
  164. Globals::root_environment = create_built_ins_environment();
  165. }
  166. proc create_lisp_object_number(double number) -> Lisp_Object* {
  167. Lisp_Object* node;
  168. try node = create_lisp_object();
  169. set_type(node, Lisp_Object_Type::Number);
  170. node->value.number = number;
  171. return node;
  172. }
  173. proc create_lisp_object_string(String* str) -> Lisp_Object* {
  174. Lisp_Object* node;
  175. try node = create_lisp_object();
  176. set_type(node, Lisp_Object_Type::String);
  177. node->value.string = str;
  178. return node;
  179. }
  180. proc create_lisp_object_string(const char* str) -> Lisp_Object* {
  181. Lisp_Object* node;
  182. try node = create_lisp_object();
  183. set_type(node, Lisp_Object_Type::String);
  184. node->value.string = create_string(str);
  185. return node;
  186. }
  187. proc get_or_create_lisp_object_symbol(String* identifier) -> Lisp_Object* {
  188. // TODO(Felix): if we already have it stored somewhere then
  189. // reuse it and dont create new one
  190. Lisp_Object* node;
  191. try node = create_lisp_object();
  192. set_type(node, Lisp_Object_Type::Symbol);
  193. // node->value.symbol = new(Symbol);
  194. node->value.symbol.identifier = identifier;
  195. node->value.symbol.hash = hash(identifier);
  196. return node;
  197. }
  198. proc get_or_create_lisp_object_symbol(const char* identifier) -> Lisp_Object* {
  199. // TODO(Felix): This is really bad: we create a new string
  200. // even if the symbol/keyword is already existing, just to
  201. // check IF it exists and then never deleting it.
  202. return get_or_create_lisp_object_symbol(
  203. Memory::create_string(identifier));
  204. }
  205. proc get_or_create_lisp_object_keyword(String* keyword) -> Lisp_Object* {
  206. // TODO(Felix): if we already have it stored somewhere then
  207. // reuse it and dont create new one
  208. Lisp_Object* node;
  209. try node = create_lisp_object();
  210. set_type(node, Lisp_Object_Type::Keyword);
  211. // node->value.keyword = new(Keyword);
  212. node->value.symbol.identifier = keyword;
  213. node->value.symbol.hash = hash(keyword);
  214. return node;
  215. }
  216. proc get_or_create_lisp_object_keyword(const char* keyword) -> Lisp_Object* {
  217. // TODO(Felix): This is really bad: we create a new string
  218. // even if the symbol/keyword is already existing, just to
  219. // check IF it exists and then never deleting it.
  220. return get_or_create_lisp_object_keyword(
  221. Memory::create_string(keyword));
  222. }
  223. proc create_lisp_object_cfunction(std::function<Lisp_Object* (Lisp_Object*, Environment*)> function) -> Lisp_Object* {
  224. Lisp_Object* node;
  225. try node = create_lisp_object();
  226. set_type(node, Lisp_Object_Type::CFunction);
  227. // node->value.lambdaWrapper = new Lambda_Wrapper(function);
  228. node->value.cFunction = new(cFunction);
  229. node->value.cFunction->function = function;
  230. return node;
  231. }
  232. proc create_lisp_object_pair(Lisp_Object* first, Lisp_Object* rest) -> Lisp_Object* {
  233. Lisp_Object* node;
  234. try node = create_lisp_object();
  235. set_type(node, Lisp_Object_Type::Pair);
  236. // node->value.pair = new(Pair);
  237. node->value.pair.first = first;
  238. node->value.pair.rest = rest;
  239. return node;
  240. }
  241. proc copy_lisp_object(Lisp_Object* n) -> Lisp_Object* {
  242. // TODO(Felix): If argument is a list (pair), do a FULL copy,
  243. // we don't copy singleton objects
  244. if (
  245. n == Memory::nil || n == Memory::t ||
  246. Memory::get_type(n) == Lisp_Object_Type::Symbol ||
  247. Memory::get_type(n) == Lisp_Object_Type::Keyword
  248. )
  249. return n;
  250. Lisp_Object* target;
  251. try target = create_lisp_object();
  252. *target = *n;
  253. return target;
  254. }
  255. proc copy_lisp_object_except_pairs(Lisp_Object* n) -> Lisp_Object* {
  256. if (get_type(n) == Lisp_Object_Type::Pair)
  257. return n;
  258. return copy_lisp_object(n);
  259. }
  260. proc create_child_environment(Environment* parent) -> Environment* {
  261. int index;
  262. // if we have no free spots then append at the end
  263. if (free_spots_in_environment_memory->next_index == 0) {
  264. // if we still have space
  265. if (environment_memory_size == next_index_in_environment_memory) {
  266. create_out_of_memory_error(
  267. "There is not enough space in the environment "
  268. "memory to allocate additional environments. "
  269. "Maybe try increasing the Memory size when "
  270. "calling Memory::init()");
  271. return nullptr;
  272. }
  273. index = next_index_in_environment_memory++;
  274. } else {
  275. // else fill a free spot, and remove the free spot
  276. index = free_spots_in_environment_memory->data[free_spots_in_environment_memory->next_index--];
  277. }
  278. Environment* env = environment_memory+index;
  279. int start_capacity = 16;
  280. env->parents = create_Environment_array_list();
  281. if (parent)
  282. append_to_array_list(env->parents, parent);
  283. env->capacity = start_capacity;
  284. env->next_index = 0;
  285. env->keys = (char**)malloc(start_capacity * sizeof(char*));
  286. env->values = (Lisp_Object**)malloc(start_capacity * sizeof(Lisp_Object*));
  287. return env;
  288. }
  289. proc create_empty_environment() -> Environment* {
  290. Environment* ret;
  291. try ret = create_child_environment(nullptr);
  292. return ret;
  293. }
  294. proc create_built_ins_environment() -> Environment* {
  295. Environment* ret;
  296. try ret = create_empty_environment();
  297. load_built_ins_into_environment(ret);
  298. Parser::environment_for_macros = ret;
  299. // save the current working directory
  300. char* cwd = get_cwd();
  301. defer {
  302. free(cwd);
  303. };
  304. // get the direction of the exe
  305. char* exe_path = get_exe_dir();
  306. change_cwd(exe_path);
  307. free(exe_path);
  308. built_in_load(Memory::create_string("pre.slime"), ret);
  309. change_cwd(cwd);
  310. return ret;
  311. }
  312. inline proc create_list(Lisp_Object* o1) -> Lisp_Object* {
  313. Lisp_Object* ret;
  314. try ret = create_lisp_object_pair(o1, nil);
  315. return ret;
  316. }
  317. inline proc create_list(Lisp_Object* o1, Lisp_Object* o2) -> Lisp_Object* {
  318. Lisp_Object* ret;
  319. try ret = create_lisp_object_pair(o1, create_list(o2));
  320. return ret;
  321. }
  322. inline proc create_list(Lisp_Object* o1, Lisp_Object* o2, Lisp_Object* o3) -> Lisp_Object* {
  323. Lisp_Object* ret;
  324. try ret = create_lisp_object_pair(o1, create_list(o2, o3));
  325. return ret;
  326. }
  327. inline proc create_list(Lisp_Object* o1, Lisp_Object* o2, Lisp_Object* o3, Lisp_Object* o4) -> Lisp_Object* {
  328. Lisp_Object* ret;
  329. try ret = create_lisp_object_pair(o1, create_list(o2, o3, o4));
  330. return ret;
  331. }
  332. inline proc create_list(Lisp_Object* o1, Lisp_Object* o2, Lisp_Object* o3, Lisp_Object* o4, Lisp_Object* o5) -> Lisp_Object* {
  333. Lisp_Object* ret;
  334. try ret = create_lisp_object_pair(o1, create_list(o2, o3, o4, o5));
  335. return ret;
  336. }
  337. inline proc create_list(Lisp_Object* o1, Lisp_Object* o2, Lisp_Object* o3, Lisp_Object* o4, Lisp_Object* o5, Lisp_Object* o6) -> Lisp_Object* {
  338. Lisp_Object* ret;
  339. try ret = create_lisp_object_pair(o1, create_list(o2, o3, o4, o5, o6));
  340. return ret;
  341. }
  342. }