No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 
 
 

505 líneas
16 KiB

  1. namespace Slime::Memory {
  2. // ------------------
  3. // global symbol / keyword table
  4. // ------------------
  5. Hash_Map<char*, Lisp_Object*> global_symbol_table;
  6. Hash_Map<char*, Lisp_Object*> global_keyword_table;
  7. Hash_Map<char*, Environment*> file_to_env_map;
  8. // ------------------
  9. // lisp_objects
  10. // ------------------
  11. Bucket_Allocator<Lisp_Object> object_memory;
  12. // ------------------
  13. // environments
  14. // ------------------
  15. Bucket_Allocator<Environment> environment_memory;
  16. // NOTE(Felix): we are doing hashmaps separately so we don't have
  17. // to malloc them every time, and if two lisp objects have the
  18. // same hashmap, it will not cause double free problems when
  19. // freeing all at the end. It also plays nice with garbage
  20. // collection
  21. // ------------------
  22. // Hashmaps
  23. // ------------------
  24. Bucket_Allocator<Hash_Map<Lisp_Object*, Lisp_Object*>> hashmap_memory;
  25. // ------------------
  26. // immutables
  27. // ------------------
  28. Lisp_Object* nil = nullptr;
  29. Lisp_Object* t = nullptr;
  30. proc print_status() {
  31. // printf("Memory Status:\n"
  32. // " - %f%% of the object_memory is used\n"
  33. // " - %d of %d total Lisp_Objects are in use\n"
  34. // " - %d holes in used memory (fragmentation)\n",
  35. // (1.0*next_index_in_object_memory - free_spots_in_object_memory.next_index)/object_memory_size,
  36. // next_index_in_object_memory - free_spots_in_object_memory.next_index, object_memory_size,
  37. // free_spots_in_object_memory.next_index);
  38. // printf("Memory Status:\n"
  39. // " - %f%% of the string_memory is used\n"
  40. // " - %d holes in used memory (fragmentation)\n",
  41. // (1.0*(size_t)next_free_spot_in_string_memory - (size_t)string_memory)/string_memory_size,
  42. // free_spots_in_string_memory.next_index);
  43. }
  44. inline proc get_c_str(String str) -> char* {
  45. return str.data;
  46. }
  47. inline proc get_c_str(Lisp_Object* str) -> char* {
  48. assert_type(str, Lisp_Object_Type::String);
  49. return get_c_str(str->value.string);
  50. }
  51. proc hash(String str) -> u64 {
  52. // TODO(Felix): When parsing symbols or keywords, compute the
  53. // hash while reading them in.
  54. u64 value = str.data[0] << 7;
  55. for (u32 i = 1; i < str.length; ++i) {
  56. char c = str.data[i];
  57. value = (1000003 * value) ^ c;
  58. }
  59. value ^= str.length;
  60. return value;
  61. }
  62. proc create_string(const char* str, u32 len) -> String {
  63. String s = {
  64. len,
  65. (char*)malloc(sizeof(char) * len + 1)
  66. };
  67. strcpy(s.data, str);
  68. return s;
  69. }
  70. proc create_string (const char* str) -> String {
  71. return create_string(str, (u32)strlen(str));
  72. }
  73. proc duplicate_string(String str) -> String {
  74. return create_string(str.data, str.length);
  75. }
  76. proc create_lisp_object() -> Lisp_Object* {
  77. Lisp_Object* object = object_memory.allocate();
  78. object->type = Lisp_Object_Type::Invalid_Under_Construction;
  79. return object;
  80. }
  81. proc free_everything() -> void {
  82. object_memory.for_each([](Lisp_Object* lo){
  83. switch (lo->type) {
  84. case Lisp_Object_Type::Function: {
  85. lo->value.function->args.positional.symbols.dealloc();
  86. lo->value.function->args.keyword.keywords.dealloc();
  87. lo->value.function->args.keyword.values.dealloc();
  88. free(lo->value.function);
  89. } break;
  90. case Lisp_Object_Type::Symbol:
  91. case Lisp_Object_Type::Keyword:
  92. case Lisp_Object_Type::String: {
  93. free(lo->value.string.data);
  94. } break;
  95. default: break;
  96. }
  97. });
  98. environment_memory.for_each([](Environment* env){
  99. env->parents.dealloc();
  100. env->hm.dealloc();
  101. });
  102. hashmap_memory.for_each([](Hash_Map<Lisp_Object*, Lisp_Object*>* hm){
  103. hm->dealloc();
  104. });
  105. for_hash_map(Globals::docs) {
  106. free(value);
  107. }
  108. // free the exe dir:
  109. free(Globals::load_path.data[0]);
  110. // Globals::load_path.dealloc();
  111. Globals::user_types.dealloc();
  112. Globals::docs.dealloc();
  113. Globals::Current_Execution::envi_stack.dealloc();
  114. Globals::Current_Execution::cs.dealloc();
  115. Globals::Current_Execution::ams.dealloc();
  116. Globals::Current_Execution::pcs.dealloc();
  117. Globals::Current_Execution::nass.dealloc();
  118. Globals::Current_Execution::ats.dealloc();
  119. Globals::Current_Execution::mes.dealloc();
  120. free(Parser::standard_in.data);
  121. object_memory.dealloc();
  122. environment_memory.dealloc();
  123. hashmap_memory.dealloc();
  124. global_symbol_table.dealloc();
  125. global_keyword_table.dealloc();
  126. file_to_env_map.dealloc();
  127. }
  128. proc create_child_environment(Environment* parent) -> Environment* {
  129. Environment* env = environment_memory.allocate();
  130. // inject a new array list;
  131. env->parents.alloc();
  132. env->hm.alloc();
  133. if (parent)
  134. env->parents.append(parent);
  135. new(&env->hm) Hash_Map<void*, Lisp_Object*>;
  136. return env;
  137. }
  138. proc create_empty_environment() -> Environment* {
  139. Environment* ret;
  140. try ret = create_child_environment(nullptr);
  141. return ret;
  142. }
  143. proc load_pre() -> void {
  144. String file_name = Memory::create_string("pre.slime");
  145. defer_free(file_name.data);
  146. try_void built_in_load(file_name);
  147. }
  148. proc init() -> void {
  149. profile_this();
  150. object_memory.alloc(1024, 8);
  151. environment_memory.alloc(1024, 8);
  152. hashmap_memory.alloc(256, 8);
  153. system_shutdown_hook << [&] {
  154. if_debug {
  155. Slime::Memory::free_everything();
  156. }
  157. };
  158. char* exe_path = get_exe_dir();
  159. global_symbol_table.alloc();
  160. global_keyword_table.alloc();
  161. file_to_env_map.alloc();
  162. Globals::Current_Execution::envi_stack.alloc();
  163. Globals::Current_Execution::cs.alloc();
  164. Globals::Current_Execution::nass.alloc();
  165. Globals::Current_Execution::pcs.alloc();
  166. Globals::Current_Execution::ams.alloc();
  167. Globals::Current_Execution::ats.alloc();
  168. Globals::Current_Execution::mes.alloc();
  169. Globals::docs.alloc();
  170. Globals::user_types.alloc();
  171. // Globals::load_path.alloc();
  172. add_to_load_path(exe_path);
  173. add_to_load_path("../bin/");
  174. // init nil
  175. try_void nil = create_lisp_object();
  176. nil->type = Lisp_Object_Type::Nil;
  177. // init t
  178. try_void t = create_lisp_object();
  179. t->type = Lisp_Object_Type::T;
  180. try_void Parser::standard_in = create_string("stdin");
  181. Globals::Current_Execution::envi_stack.next_index = 0;
  182. Environment* env;
  183. try_void env = create_built_ins_environment();
  184. push_environment(env);
  185. }
  186. proc create_lisp_object(void* ptr) -> Lisp_Object* {
  187. Lisp_Object* node;
  188. try node = create_lisp_object();
  189. node->type = Lisp_Object_Type::Pointer;
  190. node->value.pointer = ptr;
  191. return node;
  192. }
  193. proc create_lisp_object_hash_map() -> Lisp_Object* {
  194. Lisp_Object* node;
  195. try node = create_lisp_object();
  196. node->type = Lisp_Object_Type::HashMap;
  197. node->value.hashMap = hashmap_memory.allocate();
  198. node->value.hashMap->alloc();
  199. return node;
  200. }
  201. proc create_lisp_object(f64 number) -> Lisp_Object* {
  202. Lisp_Object* node;
  203. try node = create_lisp_object();
  204. node->type = Lisp_Object_Type::Number;
  205. node->value.number = number;
  206. return node;
  207. }
  208. proc create_lisp_object(String str) -> Lisp_Object* {
  209. Lisp_Object* node;
  210. try node = create_lisp_object();
  211. node->type = Lisp_Object_Type::String;
  212. node->value.string = str;
  213. return node;
  214. }
  215. proc create_lisp_object(const char* str) -> Lisp_Object* {
  216. Lisp_Object* node;
  217. try node = create_lisp_object();
  218. node->type = Lisp_Object_Type::String;
  219. node->value.string = create_string(str);
  220. return node;
  221. }
  222. proc allocate_vector(u32 size) -> Lisp_Object* {
  223. Lisp_Object* ret = object_memory.allocate(size);
  224. if (!ret) {
  225. create_out_of_memory_error("The vector is too big to fit in a memory bucket.");
  226. return nullptr;
  227. }
  228. return ret;
  229. }
  230. proc create_lisp_object_vector(u32 length, Lisp_Object* element_list) -> Lisp_Object* {
  231. try assert_type(element_list, Lisp_Object_Type::Pair);
  232. Lisp_Object* node;
  233. try node = create_lisp_object();
  234. node->type = Lisp_Object_Type::Vector;
  235. node->value.vector.length = length;
  236. try node->value.vector.data = allocate_vector(length);
  237. Lisp_Object* head = element_list;
  238. u32 i = 0;
  239. while (head != Memory::nil) {
  240. node->value.vector.data[i] = *head->value.pair.first;
  241. head = head->value.pair.rest;
  242. ++i;
  243. }
  244. return node;
  245. }
  246. proc create_lisp_object_vector(Lisp_Object* e1) -> Lisp_Object* {
  247. Lisp_Object* node;
  248. try node = create_lisp_object();
  249. node->type = Lisp_Object_Type::Vector;
  250. node->value.vector.length = 1;
  251. try node->value.vector.data = allocate_vector(1);
  252. node->value.vector.data[0] = *e1;
  253. return node;
  254. }
  255. proc create_lisp_object_vector(Lisp_Object* e1, Lisp_Object* e2) -> Lisp_Object* {
  256. Lisp_Object* node;
  257. try node = create_lisp_object();
  258. node->type = Lisp_Object_Type::Vector;
  259. node->value.vector.length = 2;
  260. try node->value.vector.data = allocate_vector(2);
  261. node->value.vector.data[0] = *e1;
  262. node->value.vector.data[1] = *e2;
  263. return node;
  264. }
  265. proc create_lisp_object_vector(Lisp_Object* e1, Lisp_Object* e2, Lisp_Object* e3) -> Lisp_Object* {
  266. Lisp_Object* node;
  267. try node = create_lisp_object();
  268. node->type = Lisp_Object_Type::Vector;
  269. node->value.vector.length = 3;
  270. try node->value.vector.data = allocate_vector(3);
  271. node->value.vector.data[0] = *e1;
  272. node->value.vector.data[1] = *e2;
  273. node->value.vector.data[2] = *e3;
  274. return node;
  275. }
  276. inline proc _create_symbol(char* identifier) -> Lisp_Object* {
  277. Lisp_Object* node;
  278. try node = create_lisp_object();
  279. node->type = Lisp_Object_Type::Symbol;
  280. node->value.symbol = create_string(identifier);
  281. global_symbol_table.set_object((char*)node->value.symbol.data, node);
  282. return node;
  283. }
  284. inline proc get_symbol(String identifier) -> Lisp_Object* {
  285. return get_symbol(identifier.data);
  286. }
  287. inline proc get_symbol(const char* identifier) -> Lisp_Object* {
  288. if (Lisp_Object* ret = global_symbol_table.get_object((char*)identifier))
  289. return (Lisp_Object*)ret;
  290. return _create_symbol((char*)identifier);
  291. }
  292. inline proc _create_keyword(char* identifier) -> Lisp_Object* {
  293. Lisp_Object* node;
  294. try node = create_lisp_object();
  295. node->type = Lisp_Object_Type::Keyword;
  296. node->value.symbol = create_string(identifier);
  297. global_keyword_table.set_object((char*)node->value.symbol.data, node);
  298. return node;
  299. }
  300. inline proc get_keyword(String identifier) -> Lisp_Object* {
  301. return get_keyword(identifier.data);
  302. }
  303. inline proc get_keyword(const char* identifier) -> Lisp_Object* {
  304. if (Lisp_Object* ret = global_keyword_table.get_object((char*)identifier))
  305. return ret;
  306. return _create_keyword((char*)identifier);
  307. }
  308. proc create_lisp_object_cfunction(C_Function_Type type) -> Lisp_Object* {
  309. Lisp_Object* node;
  310. try node = create_lisp_object();
  311. node->type = Lisp_Object_Type::Function;
  312. node->value.function = (Function*)malloc(sizeof(Function));
  313. node->value.function->type.c_function_type = type;
  314. node->value.function->args.keyword.keywords.alloc();
  315. node->value.function->args.keyword.values.alloc();
  316. node->value.function->args.positional.symbols.alloc();
  317. node->value.function->is_c = true;
  318. return node;
  319. }
  320. proc create_lisp_object_function(Lisp_Function_Type ft) -> Lisp_Object* {
  321. Lisp_Object* func;
  322. try func = Memory::create_lisp_object();
  323. func->type = Lisp_Object_Type::Function;
  324. func->value.function = (Function*)malloc(sizeof(Function));
  325. func->value.function->args.keyword.keywords.alloc();
  326. func->value.function->args.keyword.values.alloc();
  327. func->value.function->args.positional.symbols.alloc();
  328. func->value.function->type.lisp_function_type = ft;
  329. func->value.function->is_c = false;
  330. return func;
  331. }
  332. proc create_lisp_object_pair(Lisp_Object* first, Lisp_Object* rest) -> Lisp_Object* {
  333. Lisp_Object* node;
  334. try node = create_lisp_object();
  335. node->type = Lisp_Object_Type::Pair;
  336. node->value.pair.first = first;
  337. node->value.pair.rest = rest;
  338. return node;
  339. }
  340. proc copy_lisp_object(Lisp_Object* n) -> Lisp_Object* {
  341. // QUESTION(Felix): If argument is a list (cons), should we do
  342. // a full copy?
  343. // we don't copy singleton objects
  344. if (n == Memory::nil || n == Memory::t) {
  345. return n;
  346. } else {
  347. Lisp_Object_Type type = n->type;
  348. if (type == Lisp_Object_Type::Symbol ||
  349. type == Lisp_Object_Type::Keyword ||
  350. type == Lisp_Object_Type::Function)
  351. {
  352. return n;
  353. } else if (type == Lisp_Object_Type::String) {
  354. Lisp_Object* target;
  355. try target = create_lisp_object();
  356. *target = *n;
  357. target->value.string = create_string(target->value.string.data);
  358. return target;
  359. } else {
  360. Lisp_Object* target;
  361. try target = create_lisp_object();
  362. *target = *n;
  363. return target;
  364. }
  365. }
  366. }
  367. proc copy_lisp_object_except_pairs(Lisp_Object* n) -> Lisp_Object* {
  368. if (n->type == Lisp_Object_Type::Pair)
  369. return n;
  370. return copy_lisp_object(n);
  371. }
  372. proc create_built_ins_environment() -> Environment* {
  373. Environment* ret;
  374. try ret = create_empty_environment();
  375. push_environment(ret);
  376. defer {
  377. pop_environment();
  378. };
  379. try load_built_ins_into_environment();
  380. return ret;
  381. }
  382. inline proc create_list(Lisp_Object* o1) -> Lisp_Object* {
  383. Lisp_Object* ret;
  384. try ret = create_lisp_object_pair(o1, nil);
  385. return ret;
  386. }
  387. inline proc create_list(Lisp_Object* o1, Lisp_Object* o2) -> Lisp_Object* {
  388. Lisp_Object* ret;
  389. try ret = create_lisp_object_pair(o1, create_list(o2));
  390. return ret;
  391. }
  392. inline proc create_list(Lisp_Object* o1, Lisp_Object* o2, Lisp_Object* o3) -> Lisp_Object* {
  393. Lisp_Object* ret;
  394. try ret = create_lisp_object_pair(o1, create_list(o2, o3));
  395. return ret;
  396. }
  397. inline proc create_list(Lisp_Object* o1, Lisp_Object* o2, Lisp_Object* o3, Lisp_Object* o4) -> Lisp_Object* {
  398. Lisp_Object* ret;
  399. try ret = create_lisp_object_pair(o1, create_list(o2, o3, o4));
  400. return ret;
  401. }
  402. inline proc create_list(Lisp_Object* o1, Lisp_Object* o2, Lisp_Object* o3, Lisp_Object* o4, Lisp_Object* o5) -> Lisp_Object* {
  403. Lisp_Object* ret;
  404. try ret = create_lisp_object_pair(o1, create_list(o2, o3, o4, o5));
  405. return ret;
  406. }
  407. inline proc create_list(Lisp_Object* o1, Lisp_Object* o2, Lisp_Object* o3, Lisp_Object* o4, Lisp_Object* o5, Lisp_Object* o6) -> Lisp_Object* {
  408. Lisp_Object* ret;
  409. try ret = create_lisp_object_pair(o1, create_list(o2, o3, o4, o5, o6));
  410. return ret;
  411. }
  412. }