Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

503 строки
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 (int 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, int 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, (int)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::docs.dealloc();
  112. Globals::Current_Execution::envi_stack.dealloc();
  113. Globals::Current_Execution::cs.dealloc();
  114. Globals::Current_Execution::ams.dealloc();
  115. Globals::Current_Execution::pcs.dealloc();
  116. Globals::Current_Execution::nass.dealloc();
  117. Globals::Current_Execution::ats.dealloc();
  118. Globals::Current_Execution::mes.dealloc();
  119. free(Parser::standard_in.data);
  120. object_memory.dealloc();
  121. environment_memory.dealloc();
  122. hashmap_memory.dealloc();
  123. global_symbol_table.dealloc();
  124. global_keyword_table.dealloc();
  125. file_to_env_map.dealloc();
  126. }
  127. proc create_child_environment(Environment* parent) -> Environment* {
  128. Environment* env = environment_memory.allocate();
  129. // inject a new array list;
  130. env->parents.alloc();
  131. env->hm.alloc();
  132. if (parent)
  133. env->parents.append(parent);
  134. new(&env->hm) Hash_Map<void*, Lisp_Object*>;
  135. return env;
  136. }
  137. proc create_empty_environment() -> Environment* {
  138. Environment* ret;
  139. try ret = create_child_environment(nullptr);
  140. return ret;
  141. }
  142. proc init() -> void {
  143. profile_this();
  144. object_memory.alloc(1024, 8);
  145. environment_memory.alloc(1024, 8);
  146. hashmap_memory.alloc(256, 8);
  147. system_shutdown_hook << [&] {
  148. if_debug {
  149. Slime::Memory::free_everything();
  150. }
  151. };
  152. char* exe_path = get_exe_dir();
  153. global_symbol_table.alloc();
  154. global_keyword_table.alloc();
  155. file_to_env_map.alloc();
  156. Globals::Current_Execution::envi_stack.alloc();
  157. Globals::Current_Execution::cs.alloc();
  158. Globals::Current_Execution::nass.alloc();
  159. Globals::Current_Execution::pcs.alloc();
  160. Globals::Current_Execution::ams.alloc();
  161. Globals::Current_Execution::ats.alloc();
  162. Globals::Current_Execution::mes.alloc();
  163. Globals::docs.alloc();
  164. Globals::load_path.alloc();
  165. add_to_load_path(exe_path);
  166. add_to_load_path("../bin/");
  167. // init nil
  168. try_void nil = create_lisp_object();
  169. nil->type = Lisp_Object_Type::Nil;
  170. // init t
  171. try_void t = create_lisp_object();
  172. t->type = Lisp_Object_Type::T;
  173. try_void Parser::standard_in = create_string("stdin");
  174. Globals::Current_Execution::envi_stack.next_index = 0;
  175. Environment* env;
  176. try_void env = create_built_ins_environment();
  177. push_environment(env);
  178. Environment* user_env;
  179. try_void user_env = Memory::create_child_environment(env);
  180. push_environment(user_env);
  181. }
  182. proc create_lisp_object(void* ptr) -> Lisp_Object* {
  183. Lisp_Object* node;
  184. try node = create_lisp_object();
  185. node->type = Lisp_Object_Type::Pointer;
  186. node->value.pointer = ptr;
  187. return node;
  188. }
  189. proc create_lisp_object_hash_map() -> Lisp_Object* {
  190. Lisp_Object* node;
  191. try node = create_lisp_object();
  192. node->type = Lisp_Object_Type::HashMap;
  193. node->value.hashMap = hashmap_memory.allocate();
  194. node->value.hashMap->alloc();
  195. return node;
  196. }
  197. proc create_lisp_object(double number) -> Lisp_Object* {
  198. Lisp_Object* node;
  199. try node = create_lisp_object();
  200. node->type = Lisp_Object_Type::Number;
  201. node->value.number = number;
  202. return node;
  203. }
  204. proc create_lisp_object(String str) -> Lisp_Object* {
  205. Lisp_Object* node;
  206. try node = create_lisp_object();
  207. node->type = Lisp_Object_Type::String;
  208. node->value.string = str;
  209. return node;
  210. }
  211. proc create_lisp_object(const char* str) -> Lisp_Object* {
  212. Lisp_Object* node;
  213. try node = create_lisp_object();
  214. node->type = Lisp_Object_Type::String;
  215. node->value.string = create_string(str);
  216. return node;
  217. }
  218. proc allocate_vector(int size) -> Lisp_Object* {
  219. Lisp_Object* ret = object_memory.allocate(size);
  220. if (!ret) {
  221. create_out_of_memory_error("The vector is too big to fit in a memory bucket.");
  222. return nullptr;
  223. }
  224. return ret;
  225. }
  226. proc create_lisp_object_vector(int length, Lisp_Object* element_list) -> Lisp_Object* {
  227. try assert_type(element_list, Lisp_Object_Type::Pair);
  228. Lisp_Object* node;
  229. try node = create_lisp_object();
  230. node->type = Lisp_Object_Type::Vector;
  231. node->value.vector.length = length;
  232. try node->value.vector.data = allocate_vector(length);
  233. Lisp_Object* head = element_list;
  234. int i = 0;
  235. while (head != Memory::nil) {
  236. node->value.vector.data[i] = *head->value.pair.first;
  237. head = head->value.pair.rest;
  238. ++i;
  239. }
  240. return node;
  241. }
  242. proc create_lisp_object_vector(Lisp_Object* e1) -> Lisp_Object* {
  243. Lisp_Object* node;
  244. try node = create_lisp_object();
  245. node->type = Lisp_Object_Type::Vector;
  246. node->value.vector.length = 1;
  247. try node->value.vector.data = allocate_vector(1);
  248. node->value.vector.data[0] = *e1;
  249. return node;
  250. }
  251. proc create_lisp_object_vector(Lisp_Object* e1, Lisp_Object* e2) -> Lisp_Object* {
  252. Lisp_Object* node;
  253. try node = create_lisp_object();
  254. node->type = Lisp_Object_Type::Vector;
  255. node->value.vector.length = 2;
  256. try node->value.vector.data = allocate_vector(2);
  257. node->value.vector.data[0] = *e1;
  258. node->value.vector.data[1] = *e2;
  259. return node;
  260. }
  261. proc create_lisp_object_vector(Lisp_Object* e1, Lisp_Object* e2, Lisp_Object* e3) -> Lisp_Object* {
  262. Lisp_Object* node;
  263. try node = create_lisp_object();
  264. node->type = Lisp_Object_Type::Vector;
  265. node->value.vector.length = 3;
  266. try node->value.vector.data = allocate_vector(3);
  267. node->value.vector.data[0] = *e1;
  268. node->value.vector.data[1] = *e2;
  269. node->value.vector.data[2] = *e3;
  270. return node;
  271. }
  272. inline proc _create_symbol(char* identifier) -> Lisp_Object* {
  273. Lisp_Object* node;
  274. try node = create_lisp_object();
  275. node->type = Lisp_Object_Type::Symbol;
  276. node->value.symbol = create_string(identifier);
  277. global_symbol_table.set_object((char*)node->value.symbol.data, node);
  278. return node;
  279. }
  280. inline proc get_symbol(String identifier) -> Lisp_Object* {
  281. return get_symbol(identifier.data);
  282. }
  283. inline proc get_symbol(const char* identifier) -> Lisp_Object* {
  284. if (Lisp_Object* ret = global_symbol_table.get_object((char*)identifier))
  285. return (Lisp_Object*)ret;
  286. return _create_symbol((char*)identifier);
  287. }
  288. inline proc _create_keyword(char* identifier) -> Lisp_Object* {
  289. Lisp_Object* node;
  290. try node = create_lisp_object();
  291. node->type = Lisp_Object_Type::Keyword;
  292. node->value.symbol = create_string(identifier);
  293. global_keyword_table.set_object((char*)node->value.symbol.data, node);
  294. return node;
  295. }
  296. inline proc get_keyword(String identifier) -> Lisp_Object* {
  297. return get_keyword(identifier.data);
  298. }
  299. inline proc get_keyword(const char* identifier) -> Lisp_Object* {
  300. if (Lisp_Object* ret = global_keyword_table.get_object((char*)identifier))
  301. return ret;
  302. return _create_keyword((char*)identifier);
  303. }
  304. proc create_lisp_object_cfunction(C_Function_Type type) -> Lisp_Object* {
  305. Lisp_Object* node;
  306. try node = create_lisp_object();
  307. node->type = Lisp_Object_Type::Function;
  308. node->value.function = (Function*)malloc(sizeof(Function));
  309. node->value.function->type.c_function_type = type;
  310. node->value.function->args.keyword.keywords.alloc();
  311. node->value.function->args.keyword.values.alloc();
  312. node->value.function->args.positional.symbols.alloc();
  313. node->value.function->is_c = true;
  314. return node;
  315. }
  316. proc create_lisp_object_function(Lisp_Function_Type ft) -> Lisp_Object* {
  317. Lisp_Object* func;
  318. try func = Memory::create_lisp_object();
  319. func->type = Lisp_Object_Type::Function;
  320. func->value.function = (Function*)malloc(sizeof(Function));
  321. func->value.function->args.keyword.keywords.alloc();
  322. func->value.function->args.keyword.values.alloc();
  323. func->value.function->args.positional.symbols.alloc();
  324. func->value.function->type.lisp_function_type = ft;
  325. func->value.function->is_c = false;
  326. return func;
  327. }
  328. proc create_lisp_object_pair(Lisp_Object* first, Lisp_Object* rest) -> Lisp_Object* {
  329. Lisp_Object* node;
  330. try node = create_lisp_object();
  331. node->type = Lisp_Object_Type::Pair;
  332. // node->value.pair = new(Pair);
  333. node->value.pair.first = first;
  334. node->value.pair.rest = rest;
  335. return node;
  336. }
  337. proc copy_lisp_object(Lisp_Object* n) -> Lisp_Object* {
  338. // TODO(Felix): If argument is a list (pair), do a FULL copy,
  339. // we don't copy singleton objects
  340. if (n == Memory::nil || n == Memory::t) {
  341. return n;
  342. } else {
  343. Lisp_Object_Type type = n->type;
  344. if (type == Lisp_Object_Type::Symbol ||
  345. type == Lisp_Object_Type::Keyword ||
  346. type == Lisp_Object_Type::Function)
  347. {
  348. return n;
  349. } else if (type == Lisp_Object_Type::String) {
  350. Lisp_Object* target;
  351. try target = create_lisp_object();
  352. *target = *n;
  353. target->value.string = create_string(target->value.string.data);
  354. return target;
  355. } else {
  356. Lisp_Object* target;
  357. try target = create_lisp_object();
  358. *target = *n;
  359. return target;
  360. }
  361. }
  362. }
  363. proc copy_lisp_object_except_pairs(Lisp_Object* n) -> Lisp_Object* {
  364. if (n->type == Lisp_Object_Type::Pair)
  365. return n;
  366. return copy_lisp_object(n);
  367. }
  368. proc create_built_ins_environment() -> Environment* {
  369. Environment* ret;
  370. try ret = create_empty_environment();
  371. push_environment(ret);
  372. defer {
  373. pop_environment();
  374. };
  375. try load_built_ins_into_environment();
  376. String file_name = Memory::create_string("pre.slime");
  377. try built_in_load(file_name);
  378. free(file_name.data);
  379. return ret;
  380. }
  381. inline proc create_list(Lisp_Object* o1) -> Lisp_Object* {
  382. Lisp_Object* ret;
  383. try ret = create_lisp_object_pair(o1, nil);
  384. return ret;
  385. }
  386. inline proc create_list(Lisp_Object* o1, Lisp_Object* o2) -> Lisp_Object* {
  387. Lisp_Object* ret;
  388. try ret = create_lisp_object_pair(o1, create_list(o2));
  389. return ret;
  390. }
  391. inline proc create_list(Lisp_Object* o1, Lisp_Object* o2, Lisp_Object* o3) -> Lisp_Object* {
  392. Lisp_Object* ret;
  393. try ret = create_lisp_object_pair(o1, create_list(o2, o3));
  394. return ret;
  395. }
  396. inline proc create_list(Lisp_Object* o1, Lisp_Object* o2, Lisp_Object* o3, Lisp_Object* o4) -> Lisp_Object* {
  397. Lisp_Object* ret;
  398. try ret = create_lisp_object_pair(o1, create_list(o2, o3, o4));
  399. return ret;
  400. }
  401. inline proc create_list(Lisp_Object* o1, Lisp_Object* o2, Lisp_Object* o3, Lisp_Object* o4, Lisp_Object* o5) -> Lisp_Object* {
  402. Lisp_Object* ret;
  403. try ret = create_lisp_object_pair(o1, create_list(o2, o3, o4, o5));
  404. return ret;
  405. }
  406. inline proc create_list(Lisp_Object* o1, Lisp_Object* o2, Lisp_Object* o3, Lisp_Object* o4, Lisp_Object* o5, Lisp_Object* o6) -> Lisp_Object* {
  407. Lisp_Object* ret;
  408. try ret = create_lisp_object_pair(o1, create_list(o2, o3, o4, o5, o6));
  409. return ret;
  410. }
  411. }