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

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