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

378 строки
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. return object;
  134. }
  135. proc init(int oms, int ems, int sms) {
  136. object_memory_size = oms;
  137. environment_memory_size = ems;
  138. string_memory_size = sms;
  139. free_spots_in_object_memory = create_Int_array_list();
  140. free_spots_in_environment_memory = create_Int_array_list();
  141. free_spots_in_string_memory = create_Void_Ptr_array_list();
  142. object_memory = (Lisp_Object*)malloc(object_memory_size * sizeof(Lisp_Object));
  143. environment_memory = (Environment*)malloc(environment_memory_size * sizeof(Environment));
  144. string_memory = (String*)malloc(string_memory_size * sizeof(char));
  145. next_free_spot_in_string_memory = string_memory;
  146. // init nil
  147. try_void nil = create_lisp_object();
  148. set_type(nil, Lisp_Object_Type::Nil);
  149. // init t
  150. try_void t = create_lisp_object();
  151. set_type(t, Lisp_Object_Type::T);
  152. try_void Globals::root_environment = create_built_ins_environment();
  153. try_void Parser::standard_in = create_string("stdin");
  154. }
  155. proc reset() -> void {
  156. free_spots_in_object_memory->next_index = 0;
  157. free_spots_in_environment_memory->next_index = 0;
  158. free_spots_in_string_memory->next_index = 0;
  159. // because t and nil are always there we start the index at 2
  160. next_index_in_object_memory = 2;
  161. next_index_in_environment_memory = 0;
  162. next_free_spot_in_string_memory = string_memory;
  163. Globals::root_environment = create_built_ins_environment();
  164. }
  165. proc create_lisp_object_number(double number) -> Lisp_Object* {
  166. Lisp_Object* node;
  167. try node = create_lisp_object();
  168. set_type(node, Lisp_Object_Type::Number);
  169. node->value.number = number;
  170. return node;
  171. }
  172. proc create_lisp_object_string(String* str) -> Lisp_Object* {
  173. Lisp_Object* node;
  174. try node = create_lisp_object();
  175. set_type(node, Lisp_Object_Type::String);
  176. node->value.string = str;
  177. return node;
  178. }
  179. proc create_lisp_object_string(const char* str) -> Lisp_Object* {
  180. Lisp_Object* node;
  181. try node = create_lisp_object();
  182. set_type(node, Lisp_Object_Type::String);
  183. node->value.string = create_string(str);
  184. return node;
  185. }
  186. proc get_or_create_lisp_object_symbol(String* identifier) -> Lisp_Object* {
  187. // TODO(Felix): if we already have it stored somewhere then
  188. // reuse it and dont create new one
  189. Lisp_Object* node;
  190. try node = create_lisp_object();
  191. set_type(node, Lisp_Object_Type::Symbol);
  192. // node->value.symbol = new(Symbol);
  193. node->value.symbol.identifier = identifier;
  194. node->value.symbol.hash = hash(identifier);
  195. return node;
  196. }
  197. proc get_or_create_lisp_object_symbol(const char* identifier) -> Lisp_Object* {
  198. // TODO(Felix): This is really bad: we create a new string
  199. // even if the symbol/keyword is already existing, just to
  200. // check IF it exists and then never deleting it.
  201. return get_or_create_lisp_object_symbol(
  202. Memory::create_string(identifier));
  203. }
  204. proc get_or_create_lisp_object_keyword(String* keyword) -> Lisp_Object* {
  205. // TODO(Felix): if we already have it stored somewhere then
  206. // reuse it and dont create new one
  207. Lisp_Object* node;
  208. try node = create_lisp_object();
  209. set_type(node, Lisp_Object_Type::Keyword);
  210. // node->value.keyword = new(Keyword);
  211. node->value.symbol.identifier = keyword;
  212. node->value.symbol.hash = hash(keyword);
  213. return node;
  214. }
  215. proc get_or_create_lisp_object_keyword(const char* keyword) -> Lisp_Object* {
  216. // TODO(Felix): This is really bad: we create a new string
  217. // even if the symbol/keyword is already existing, just to
  218. // check IF it exists and then never deleting it.
  219. return get_or_create_lisp_object_keyword(
  220. Memory::create_string(keyword));
  221. }
  222. proc create_lisp_object_cfunction(std::function<Lisp_Object* (Lisp_Object*, Environment*)> function) -> Lisp_Object* {
  223. Lisp_Object* node;
  224. try node = create_lisp_object();
  225. set_type(node, Lisp_Object_Type::CFunction);
  226. // node->value.lambdaWrapper = new Lambda_Wrapper(function);
  227. node->value.cFunction = new(cFunction);
  228. node->value.cFunction->function = function;
  229. return node;
  230. }
  231. proc create_lisp_object_pair(Lisp_Object* first, Lisp_Object* rest) -> Lisp_Object* {
  232. Lisp_Object* node;
  233. try node = create_lisp_object();
  234. set_type(node, Lisp_Object_Type::Pair);
  235. // node->value.pair = new(Pair);
  236. node->value.pair.first = first;
  237. node->value.pair.rest = rest;
  238. return node;
  239. }
  240. proc copy_lisp_object(Lisp_Object* n) -> Lisp_Object* {
  241. Lisp_Object* target;
  242. try target = create_lisp_object();
  243. *target = *n;
  244. return target;
  245. }
  246. proc create_child_environment(Environment* parent) -> Environment* {
  247. int index;
  248. // if we have no free spots then append at the end
  249. if (free_spots_in_environment_memory->next_index == 0) {
  250. // if we still have space
  251. if (environment_memory_size == next_index_in_environment_memory) {
  252. create_out_of_memory_error(
  253. "There is not enough space in the environment"
  254. "memory to allocate additional environments. "
  255. "Maybe try increasing the Memory size when "
  256. "calling Memory::init()");
  257. return nullptr;
  258. }
  259. index = next_index_in_environment_memory++;
  260. } else {
  261. // else fill a free spot, and remove the free spot
  262. index = free_spots_in_environment_memory->data[free_spots_in_environment_memory->next_index--];
  263. }
  264. Environment* env = environment_memory+index;
  265. int start_capacity = 16;
  266. env->parents = create_Environment_array_list();
  267. if (parent)
  268. append_to_array_list(env->parents, parent);
  269. env->capacity = start_capacity;
  270. env->next_index = 0;
  271. env->keys = (char**)malloc(start_capacity * sizeof(char*));
  272. env->values = (Lisp_Object**)malloc(start_capacity * sizeof(Lisp_Object*));
  273. return env;
  274. }
  275. proc create_empty_environment() -> Environment* {
  276. Environment* ret;
  277. try ret = create_child_environment(nullptr);
  278. return ret;
  279. }
  280. proc create_built_ins_environment() -> Environment* {
  281. Environment* ret;
  282. try ret = create_child_environment(nullptr);
  283. load_built_ins_into_environment(ret);
  284. return ret;
  285. }
  286. inline proc create_list(Lisp_Object* o1) -> Lisp_Object* {
  287. Lisp_Object* ret;
  288. try ret = create_lisp_object_pair(o1, nil);
  289. return ret;
  290. }
  291. inline proc create_list(Lisp_Object* o1, Lisp_Object* o2) -> Lisp_Object* {
  292. Lisp_Object* ret;
  293. try ret = create_lisp_object_pair(o1, create_list(o2));
  294. return ret;
  295. }
  296. inline proc create_list(Lisp_Object* o1, Lisp_Object* o2, Lisp_Object* o3) -> Lisp_Object* {
  297. Lisp_Object* ret;
  298. try ret = create_lisp_object_pair(o1, create_list(o2, o3));
  299. return ret;
  300. }
  301. inline proc create_list(Lisp_Object* o1, Lisp_Object* o2, Lisp_Object* o3, Lisp_Object* o4) -> Lisp_Object* {
  302. Lisp_Object* ret;
  303. try ret = create_lisp_object_pair(o1, create_list(o2, o3, o4));
  304. return ret;
  305. }
  306. inline proc create_list(Lisp_Object* o1, Lisp_Object* o2, Lisp_Object* o3, Lisp_Object* o4, Lisp_Object* o5) -> Lisp_Object* {
  307. Lisp_Object* ret;
  308. try ret = create_lisp_object_pair(o1, create_list(o2, o3, o4, o5));
  309. return ret;
  310. }
  311. inline proc create_list(Lisp_Object* o1, Lisp_Object* o2, Lisp_Object* o3, Lisp_Object* o4, Lisp_Object* o5, Lisp_Object* o6) -> Lisp_Object* {
  312. Lisp_Object* ret;
  313. try ret = create_lisp_object_pair(o1, create_list(o2, o3, o4, o5, o6));
  314. return ret;
  315. }
  316. }