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.

vm.c 9.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. #include "vm/vm.h"
  2. #include <string.h>
  3. #include <stdio.h>
  4. static l2_word alloc_val(struct l2_vm *vm) {
  5. size_t id = l2_bitset_set_next(&vm->valueset);
  6. if (id >= vm->valuessize) {
  7. if (vm->valuessize == 0) {
  8. vm->valuessize = 16;
  9. }
  10. while (id > vm->valuessize) {
  11. vm->valuessize *= 2;
  12. }
  13. vm->values = realloc(vm->values, sizeof(*vm->values) * vm->valuessize);
  14. }
  15. return (l2_word)id;
  16. }
  17. static float u32_to_float(uint32_t num) {
  18. float f;
  19. memcpy(&f, &num, sizeof(num));
  20. return f;
  21. }
  22. static double u32s_to_double(uint32_t high, uint32_t low) {
  23. double d;
  24. uint64_t num = (uint64_t)high << 32 | (uint64_t)low;
  25. memcpy(&d, &num, sizeof(num));
  26. return d;
  27. }
  28. static void gc_mark_array(struct l2_vm *vm, struct l2_vm_value *val);
  29. static void gc_mark_namespace(struct l2_vm *vm, struct l2_vm_value *val);
  30. static void gc_mark(struct l2_vm *vm, l2_word id) {
  31. struct l2_vm_value *val = &vm->values[id];
  32. if (val->flags & L2_VAL_MARKED) {
  33. return;
  34. }
  35. printf("GC MARK %i\n", id);
  36. val->flags |= L2_VAL_MARKED;
  37. int typ = l2_vm_value_type(val);
  38. if (typ == L2_VAL_TYPE_ARRAY) {
  39. gc_mark_array(vm, val);
  40. } else if (typ == L2_VAL_TYPE_NAMESPACE) {
  41. gc_mark_namespace(vm, val);
  42. } else if (typ == L2_VAL_TYPE_FUNCTION) {
  43. gc_mark(vm, val->func.namespace);
  44. }
  45. }
  46. static void gc_mark_array(struct l2_vm *vm, struct l2_vm_value *val) {
  47. if (val->data == NULL) {
  48. return;
  49. }
  50. struct l2_vm_array *arr = (struct l2_vm_array *)val->data;
  51. for (size_t i = 0; i < arr->len; ++i) {
  52. gc_mark(vm, arr->data[i]);
  53. }
  54. }
  55. static void gc_mark_namespace(struct l2_vm *vm, struct l2_vm_value *val) {
  56. if (val->data == NULL) {
  57. return;
  58. }
  59. struct l2_vm_namespace *ns = (struct l2_vm_namespace *)val->data;
  60. for (size_t i = 0; i < ns->size; ++i) {
  61. l2_word key = ns->data[i];
  62. if (key == 0 || key == ~(l2_word)0) {
  63. continue;
  64. }
  65. gc_mark(vm, ns->data[ns->size + i]);
  66. }
  67. if (ns->parent != 0) {
  68. gc_mark(vm, ns->parent);
  69. }
  70. }
  71. static void gc_free(struct l2_vm *vm, l2_word id) {
  72. struct l2_vm_value *val = &vm->values[id];
  73. l2_bitset_unset(&vm->valueset, id);
  74. int typ = l2_vm_value_type(val);
  75. if (typ == L2_VAL_TYPE_ARRAY || typ == L2_VAL_TYPE_BUFFER || typ == L2_VAL_TYPE_NAMESPACE) {
  76. free(val->data);
  77. // Don't need to do anything more; the next round of GC will free
  78. // whichever values were only referenced by the array
  79. }
  80. }
  81. static size_t gc_sweep(struct l2_vm *vm) {
  82. size_t freed = 0;
  83. // Skip ID 0, because that should always exist
  84. for (size_t i = 1; i < vm->valuessize; ++i) {
  85. if (!l2_bitset_get(&vm->valueset, i)) {
  86. continue;
  87. }
  88. struct l2_vm_value *val = &vm->values[i];
  89. if (!(val->flags & L2_VAL_MARKED)) {
  90. printf("GC FREE %zi\n", i);
  91. gc_free(vm, i);
  92. freed += 1;
  93. } else {
  94. val->flags &= ~L2_VAL_MARKED;
  95. }
  96. }
  97. return freed;
  98. }
  99. void l2_vm_init(struct l2_vm *vm, l2_word *ops, size_t opcount) {
  100. vm->ops = ops;
  101. vm->opcount = opcount;
  102. vm->iptr = 0;
  103. vm->sptr = 0;
  104. vm->nsptr = 0;
  105. vm->values = NULL;
  106. vm->valuessize = 0;
  107. l2_bitset_init(&vm->valueset);
  108. // It's wasteful to allocate new 'none' variables all the time,
  109. // variable ID 0 should be the only 'none' variable in the system
  110. l2_word none_id = alloc_val(vm);
  111. vm->values[none_id].flags = L2_VAL_TYPE_NONE | L2_VAL_CONST;
  112. // Need to allocate a root namespace
  113. l2_word root = alloc_val(vm);
  114. vm->values[root].flags = L2_VAL_TYPE_NAMESPACE;
  115. vm->values[root].data = NULL; // Will be allocated on first insert
  116. vm->nstack[vm->nsptr] = root;
  117. vm->nsptr += 1;
  118. }
  119. void l2_vm_free(struct l2_vm *vm) {
  120. // Skip ID 0, because that's always NONE
  121. for (size_t i = 1; i < vm->valuessize; ++i) {
  122. if (!l2_bitset_get(&vm->valueset, i)) {
  123. continue;
  124. }
  125. gc_free(vm, i);
  126. }
  127. free(vm->values);
  128. l2_bitset_free(&vm->valueset);
  129. }
  130. size_t l2_vm_gc(struct l2_vm *vm) {
  131. for (l2_word nsptr = 0; nsptr < vm->nsptr; ++nsptr) {
  132. struct l2_vm_value *val = &vm->values[vm->nstack[nsptr]];
  133. val->flags |= L2_VAL_MARKED;
  134. gc_mark_namespace(vm, val);
  135. }
  136. return gc_sweep(vm);
  137. }
  138. void l2_vm_run(struct l2_vm *vm) {
  139. while ((enum l2_opcode)vm->ops[vm->iptr] != L2_OP_HALT) {
  140. l2_vm_step(vm);
  141. }
  142. }
  143. void l2_vm_step(struct l2_vm *vm) {
  144. enum l2_opcode opcode = (enum l2_opcode)vm->ops[vm->iptr++];
  145. l2_word word;
  146. switch (opcode) {
  147. case L2_OP_NOP:
  148. break;
  149. case L2_OP_PUSH:
  150. vm->stack[vm->sptr] = vm->ops[vm->iptr];
  151. vm->sptr += 1;
  152. vm->iptr += 1;
  153. break;
  154. case L2_OP_PUSH_2:
  155. vm->stack[vm->sptr] = vm->ops[vm->iptr];
  156. vm->stack[vm->sptr + 1] = vm->ops[vm->iptr + 1];
  157. vm->sptr += 2;
  158. vm->iptr += 2;
  159. break;
  160. case L2_OP_POP:
  161. vm->sptr -= 1;
  162. break;
  163. case L2_OP_DUP:
  164. vm->stack[vm->sptr] = vm->ops[vm->sptr - 1];
  165. vm->sptr += 1;
  166. break;
  167. case L2_OP_ADD:
  168. vm->stack[vm->sptr - 2] += vm->stack[vm->sptr - 1];
  169. vm->sptr -= 1;
  170. break;
  171. case L2_OP_FUNC_CALL:
  172. {
  173. l2_word func_id = vm->stack[--vm->sptr];
  174. l2_word argc = vm->stack[--vm->sptr];
  175. struct l2_vm_value *func = &vm->values[func_id];
  176. l2_word arr_id = alloc_val(vm);
  177. vm->values[arr_id].flags = L2_VAL_TYPE_ARRAY;
  178. vm->values[arr_id].data = malloc(
  179. sizeof(struct l2_vm_array) + sizeof(l2_word) * argc);
  180. struct l2_vm_array *arr = vm->values[arr_id].data;
  181. arr->len = argc;
  182. arr->size = argc;
  183. vm->sptr -= argc;
  184. for (l2_word i = 0; i < argc; ++i) {
  185. arr->data[i] = vm->stack[vm->sptr + i];
  186. }
  187. enum l2_value_flags typ = l2_vm_value_type(func);
  188. // C functions are called differently from language functions
  189. if (typ == L2_VAL_TYPE_CFUNCTION) {
  190. vm->stack[vm->sptr++] = func->cfunc(vm, arr);
  191. break;
  192. }
  193. // Don't interpret a non-function as a function
  194. if (typ != L2_VAL_TYPE_FUNCTION) {
  195. // TODO: Error mechanism
  196. break;
  197. }
  198. vm->stack[vm->sptr++] = vm->iptr;
  199. vm->stack[vm->sptr++] = arr_id;
  200. l2_word ns_id = alloc_val(vm);
  201. vm->values[ns_id].flags = L2_VAL_TYPE_NAMESPACE;
  202. vm->values[ns_id].data = calloc(1, sizeof(struct l2_vm_namespace));
  203. struct l2_vm_namespace *ns = vm->values[ns_id].data;
  204. ns->parent = func->func.namespace;
  205. vm->nstack[vm->nsptr++] = ns_id;
  206. vm->iptr = func->func.pos;
  207. }
  208. break;
  209. case L2_OP_RJMP:
  210. word = vm->stack[vm->sptr - 1];
  211. vm->sptr -= 1;
  212. vm->iptr += word;
  213. break;
  214. case L2_OP_STACK_FRAME_LOOKUP:
  215. {
  216. l2_word key = vm->stack[vm->sptr - 1];
  217. struct l2_vm_value *ns = &vm->values[vm->nstack[vm->nsptr - 1]];
  218. vm->stack[vm->sptr - 1] = l2_vm_namespace_get(vm, ns, key);
  219. }
  220. break;
  221. case L2_OP_STACK_FRAME_SET:
  222. {
  223. l2_word key = vm->stack[vm->sptr - 1];
  224. l2_word val = vm->stack[vm->sptr - 2];
  225. struct l2_vm_value *ns = &vm->values[vm->nstack[vm->nsptr - 1]];
  226. l2_vm_namespace_set(ns, key, val);
  227. vm->sptr -= 1;
  228. }
  229. break;
  230. case L2_OP_RET:
  231. {
  232. l2_word retval = vm->stack[--vm->sptr];
  233. vm->sptr -= 1; // Discard arguments array
  234. l2_word retaddr = vm->stack[--vm->sptr];
  235. vm->stack[vm->sptr++] = retval;
  236. vm->nsptr -= 1; // Pop function stack frame
  237. vm->iptr = retaddr;
  238. }
  239. break;
  240. case L2_OP_ALLOC_INTEGER_32:
  241. word = alloc_val(vm);
  242. vm->values[word].flags = L2_VAL_TYPE_INTEGER;
  243. vm->values[word].integer = vm->stack[--vm->sptr];
  244. vm->stack[vm->sptr++] = word;
  245. break;
  246. case L2_OP_ALLOC_INTEGER_64:
  247. word = alloc_val(vm);
  248. vm->values[word].flags = L2_VAL_TYPE_INTEGER;
  249. vm->values[word].integer = (int64_t)(
  250. (uint64_t)vm->stack[vm->sptr - 1] << 32 |
  251. (uint64_t)vm->stack[vm->sptr - 2]);
  252. vm->sptr -= 2;
  253. vm->stack[vm->sptr] = word;
  254. vm->sptr += 1;
  255. break;
  256. case L2_OP_ALLOC_REAL_32:
  257. word = alloc_val(vm);
  258. vm->values[word].flags = L2_VAL_TYPE_REAL;
  259. vm->values[word].real = u32_to_float(vm->stack[--vm->sptr]);
  260. vm->stack[vm->sptr] = word;
  261. vm->sptr += 1;
  262. break;
  263. case L2_OP_ALLOC_REAL_64:
  264. word = alloc_val(vm);
  265. vm->values[word].flags = L2_VAL_TYPE_REAL;
  266. vm->values[word].real = u32s_to_double(vm->stack[vm->sptr - 1], vm->stack[vm->sptr - 2]);
  267. vm->sptr -= 2;
  268. vm->stack[vm->sptr] = word;
  269. vm->sptr += 1;
  270. break;
  271. case L2_OP_ALLOC_BUFFER_STATIC:
  272. {
  273. word = alloc_val(vm);
  274. l2_word length = vm->stack[--vm->sptr];
  275. l2_word offset = vm->stack[--vm->sptr];
  276. vm->values[word].flags = L2_VAL_TYPE_BUFFER;
  277. vm->values[word].data = malloc(sizeof(struct l2_vm_buffer) + length);
  278. ((struct l2_vm_buffer *)vm->values[word].data)->len = length;
  279. memcpy(
  280. (unsigned char *)vm->values[word].data + sizeof(struct l2_vm_buffer),
  281. vm->ops + offset, length);
  282. vm->stack[vm->sptr] = word;
  283. vm->sptr += 1;
  284. }
  285. break;
  286. case L2_OP_ALLOC_BUFFER_ZERO:
  287. {
  288. word = alloc_val(vm);
  289. l2_word length = vm->stack[--vm->sptr];
  290. vm->values[word].flags = L2_VAL_TYPE_BUFFER;
  291. vm->values[word].data = calloc(1, sizeof(struct l2_vm_buffer) + length);
  292. ((struct l2_vm_buffer *)vm->values[word].data)->len = length;
  293. vm->stack[vm->sptr] = word;
  294. vm->sptr += 1;
  295. }
  296. break;
  297. case L2_OP_ALLOC_ARRAY:
  298. word = alloc_val(vm);
  299. vm->values[word].flags = L2_VAL_TYPE_ARRAY;
  300. vm->values[word].data = NULL; // Will be allocated on first insert
  301. vm->stack[vm->sptr] = word;
  302. vm->sptr += 1;
  303. break;
  304. case L2_OP_ALLOC_NAMESPACE:
  305. word = alloc_val(vm);
  306. vm->values[word].flags = L2_VAL_TYPE_NAMESPACE;
  307. vm->values[word].data = NULL; // Will be allocated on first insert
  308. vm->stack[vm->sptr] = word;
  309. vm->sptr += 1;
  310. break;
  311. case L2_OP_ALLOC_FUNCTION:
  312. word = alloc_val(vm);
  313. vm->values[word].flags = L2_VAL_TYPE_FUNCTION;
  314. vm->values[word].func.pos = vm->stack[--vm->sptr];
  315. vm->values[word].func.namespace = vm->nstack[vm->nsptr - 1];
  316. vm->stack[vm->sptr] = word;
  317. vm->sptr += 1;
  318. break;
  319. case L2_OP_NAMESPACE_SET:
  320. {
  321. l2_word key = vm->stack[--vm->sptr];
  322. l2_word val = vm->stack[vm->sptr - 1];
  323. l2_word ns = vm->stack[vm->sptr - 2];
  324. l2_vm_namespace_set(&vm->values[ns], key, val);
  325. }
  326. break;
  327. case L2_OP_NAMESPACE_LOOKUP:
  328. {
  329. l2_word key = vm->stack[--vm->sptr];
  330. l2_word ns = vm->stack[--vm->sptr];
  331. vm->stack[vm->sptr++] = l2_vm_namespace_get(vm, &vm->values[ns], key);
  332. }
  333. break;
  334. case L2_OP_HALT:
  335. break;
  336. }
  337. }