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 10KB

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