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

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