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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. #include "vm/vm.h"
  2. #include <string.h>
  3. #include <stdio.h>
  4. #include <stdarg.h>
  5. #include "vm/builtins.h"
  6. static int stdio_inited = 0;
  7. static struct l2_io_file_writer std_output;
  8. static struct l2_io_file_writer std_error;
  9. static l2_word alloc_val(struct l2_vm *vm) {
  10. size_t id = l2_bitset_set_next(&vm->valueset);
  11. if (id >= vm->valuessize) {
  12. if (vm->valuessize == 0) {
  13. vm->valuessize = 16;
  14. }
  15. while (id >= vm->valuessize) {
  16. vm->valuessize *= 2;
  17. }
  18. vm->values = realloc(vm->values, sizeof(*vm->values) * vm->valuessize);
  19. }
  20. return (l2_word)id;
  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. val->flags |= L2_VAL_MARKED;
  36. int typ = l2_vm_value_type(val);
  37. if (typ == L2_VAL_TYPE_ARRAY) {
  38. gc_mark_array(vm, val);
  39. } else if (typ == L2_VAL_TYPE_NAMESPACE) {
  40. gc_mark_namespace(vm, val);
  41. } else if (typ == L2_VAL_TYPE_FUNCTION) {
  42. gc_mark(vm, val->func.ns);
  43. }
  44. }
  45. static void gc_mark_array(struct l2_vm *vm, struct l2_vm_value *val) {
  46. if (val->array == NULL) {
  47. return;
  48. }
  49. for (size_t i = 0; i < val->array->len; ++i) {
  50. gc_mark(vm, val->array->data[i]);
  51. }
  52. }
  53. static void gc_mark_namespace(struct l2_vm *vm, struct l2_vm_value *val) {
  54. if (val->extra.ns_parent != 0) {
  55. gc_mark(vm, val->extra.ns_parent);
  56. }
  57. if (val->ns == NULL) {
  58. return;
  59. }
  60. for (size_t i = 0; i < val->ns->size; ++i) {
  61. l2_word key = val->ns->data[i];
  62. if (key == 0 || key == ~(l2_word)0) {
  63. continue;
  64. }
  65. gc_mark(vm, val->ns->data[val->ns->size + i]);
  66. }
  67. }
  68. static void gc_free(struct l2_vm *vm, l2_word id) {
  69. struct l2_vm_value *val = &vm->values[id];
  70. l2_bitset_unset(&vm->valueset, id);
  71. // Don't need to do anything more; the next round of GC will free
  72. // whichever values were only referenced by the array
  73. int typ = l2_vm_value_type(val);
  74. if (typ == L2_VAL_TYPE_ARRAY) {
  75. free(val->array);
  76. } else if (typ == L2_VAL_TYPE_BUFFER) {
  77. free(val->buffer);
  78. } else if (typ == L2_VAL_TYPE_NAMESPACE) {
  79. free(val->ns);
  80. } else if (typ == L2_VAL_TYPE_ERROR) {
  81. free(val->error);
  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. gc_free(vm, i);
  94. freed += 1;
  95. } else {
  96. val->flags &= ~L2_VAL_MARKED;
  97. }
  98. }
  99. return freed;
  100. }
  101. void l2_vm_init(struct l2_vm *vm, l2_word *ops, size_t opcount) {
  102. if (!stdio_inited) {
  103. std_output.w.write = l2_io_file_write;
  104. std_output.f = stdout;
  105. std_error.w.write = l2_io_file_write;
  106. std_error.f = stderr;
  107. stdio_inited = 1;
  108. }
  109. vm->std_output = &std_output.w;
  110. vm->std_error = &std_error.w;
  111. vm->ops = ops;
  112. vm->opcount = opcount;
  113. vm->iptr = 0;
  114. vm->sptr = 0;
  115. vm->fsptr = 0;
  116. vm->values = NULL;
  117. vm->valuessize = 0;
  118. l2_bitset_init(&vm->valueset);
  119. // It's wasteful to allocate new 'none' variables all the time,
  120. // variable ID 0 should be the only 'none' variable in the system
  121. l2_word none_id = alloc_val(vm);
  122. vm->values[none_id].flags = L2_VAL_TYPE_NONE | L2_VAL_CONST;
  123. // Need to allocate a builtins namespace
  124. l2_word builtins = alloc_val(vm);
  125. vm->values[builtins].extra.ns_parent = 0;
  126. vm->values[builtins].ns = NULL; // Will be allocated on first insert
  127. vm->values[builtins].flags = L2_VAL_TYPE_NAMESPACE;
  128. vm->fstack[vm->fsptr].ns = builtins;
  129. vm->fstack[vm->fsptr].retptr = 0;
  130. vm->fsptr += 1;
  131. // Need to allocate a root namespace
  132. l2_word root = alloc_val(vm);
  133. vm->values[root].extra.ns_parent = builtins;
  134. vm->values[root].ns = NULL;
  135. vm->values[root].flags = L2_VAL_TYPE_NAMESPACE;
  136. vm->fstack[vm->fsptr].ns = root;
  137. vm->fstack[vm->fsptr].retptr = 0;
  138. vm->fsptr += 1;
  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. l2_word l2_vm_error(struct l2_vm *vm, const char *fmt, ...) {
  157. l2_word id = alloc_val(vm);
  158. struct l2_vm_value *val = &vm->values[id];
  159. val->flags = L2_VAL_CONST | L2_VAL_TYPE_ERROR;
  160. char buf[256];
  161. va_list va;
  162. va_start(va, fmt);
  163. int n = vsnprintf(buf, sizeof(buf), fmt, va);
  164. if (n < 0) {
  165. const char *message = "Failed to generate error message!";
  166. val->error = malloc(strlen(message) + 1);
  167. strcpy(val->error, message);
  168. va_end(va);
  169. return id;
  170. } else if ((size_t)n + 1 < sizeof(buf)) {
  171. val->error = malloc(n + 1);
  172. strcpy(val->error, buf);
  173. va_end(va);
  174. return id;
  175. }
  176. val->error = malloc(n + 1);
  177. vsnprintf(val->error, n + 1, fmt, va);
  178. va_end(va);
  179. return id;
  180. }
  181. void l2_vm_free(struct l2_vm *vm) {
  182. // Skip ID 0, because that's always NONE
  183. for (size_t i = 1; i < vm->valuessize; ++i) {
  184. if (!l2_bitset_get(&vm->valueset, i)) {
  185. continue;
  186. }
  187. gc_free(vm, i);
  188. }
  189. free(vm->values);
  190. l2_bitset_free(&vm->valueset);
  191. }
  192. size_t l2_vm_gc(struct l2_vm *vm) {
  193. for (l2_word sptr = 0; sptr < vm->sptr; ++sptr) {
  194. gc_mark(vm, vm->stack[sptr]);
  195. }
  196. for (l2_word fsptr = 0; fsptr < vm->fsptr; ++fsptr) {
  197. gc_mark(vm, vm->fstack[fsptr].ns);
  198. }
  199. return gc_sweep(vm);
  200. }
  201. void l2_vm_run(struct l2_vm *vm) {
  202. while ((enum l2_opcode)vm->ops[vm->iptr] != L2_OP_HALT) {
  203. l2_vm_step(vm);
  204. }
  205. }
  206. void l2_vm_step(struct l2_vm *vm) {
  207. enum l2_opcode opcode = (enum l2_opcode)vm->ops[vm->iptr++];
  208. l2_word word;
  209. switch (opcode) {
  210. case L2_OP_NOP:
  211. break;
  212. case L2_OP_POP:
  213. vm->sptr -= 1;
  214. break;
  215. case L2_OP_SWAP_POP:
  216. vm->stack[vm->sptr - 2] = vm->stack[vm->sptr - 1];
  217. vm->sptr -= 1;
  218. break;
  219. case L2_OP_DUP:
  220. vm->stack[vm->sptr] = vm->ops[vm->sptr - 1];
  221. vm->sptr += 1;
  222. break;
  223. case L2_OP_ADD:
  224. vm->stack[vm->sptr - 2] += vm->stack[vm->sptr - 1];
  225. vm->sptr -= 1;
  226. break;
  227. case L2_OP_FUNC_CALL:
  228. {
  229. l2_word argc = vm->ops[vm->iptr++];
  230. l2_word arr_id = alloc_val(vm);
  231. vm->values[arr_id].flags = L2_VAL_TYPE_ARRAY;
  232. vm->values[arr_id].array = malloc(
  233. sizeof(struct l2_vm_array) + sizeof(l2_word) * argc);
  234. struct l2_vm_array *arr = vm->values[arr_id].array;
  235. arr->len = argc;
  236. arr->size = argc;
  237. vm->sptr -= argc;
  238. for (l2_word i = 0; i < argc; ++i) {
  239. arr->data[i] = vm->stack[vm->sptr + i];
  240. }
  241. l2_word func_id = vm->stack[--vm->sptr];
  242. struct l2_vm_value *func = &vm->values[func_id];
  243. l2_word stack_base = vm->sptr;
  244. enum l2_value_type typ = l2_vm_value_type(func);
  245. // C functions are called differently from language functions
  246. if (typ == L2_VAL_TYPE_CFUNCTION) {
  247. vm->stack[vm->sptr++] = func->cfunc(vm, arr);
  248. break;
  249. }
  250. // Don't interpret a non-function as a function
  251. if (typ != L2_VAL_TYPE_FUNCTION) {
  252. vm->stack[vm->sptr++] = l2_vm_error(vm, "Attempt to call non-function");
  253. break;
  254. }
  255. vm->stack[vm->sptr++] = arr_id;
  256. l2_word ns_id = alloc_val(vm);
  257. func = &vm->values[func_id]; // func might be stale after alloc
  258. vm->values[ns_id].extra.ns_parent = func->func.ns;
  259. vm->values[ns_id].ns = NULL;
  260. vm->values[ns_id].flags = L2_VAL_TYPE_NAMESPACE;
  261. vm->fstack[vm->fsptr].ns = ns_id;
  262. vm->fstack[vm->fsptr].retptr = vm->iptr;
  263. vm->fstack[vm->fsptr].sptr = stack_base;
  264. vm->fsptr += 1;
  265. vm->iptr = func->func.pos;
  266. }
  267. break;
  268. case L2_OP_RJMP:
  269. vm->iptr += vm->ops[vm->iptr] + 1;
  270. break;
  271. case L2_OP_STACK_FRAME_LOOKUP:
  272. {
  273. l2_word key = vm->ops[vm->iptr++];
  274. struct l2_vm_value *ns = &vm->values[vm->fstack[vm->fsptr - 1].ns];
  275. vm->stack[vm->sptr++] = l2_vm_namespace_get(vm, ns, key);
  276. }
  277. break;
  278. case L2_OP_STACK_FRAME_SET:
  279. {
  280. l2_word key = vm->ops[vm->iptr++];
  281. l2_word val = vm->stack[vm->sptr - 1];
  282. struct l2_vm_value *ns = &vm->values[vm->fstack[vm->fsptr - 1].ns];
  283. l2_vm_namespace_set(ns, key, val);
  284. }
  285. break;
  286. case L2_OP_STACK_FRAME_REPLACE:
  287. {
  288. l2_word key = vm->ops[vm->iptr++];
  289. l2_word val = vm->stack[vm->sptr - 1];
  290. struct l2_vm_value *ns = &vm->values[vm->fstack[vm->fsptr - 1].ns];
  291. l2_vm_namespace_replace(vm, ns, key, val); // TODO: error if returns -1
  292. }
  293. break;
  294. case L2_OP_RET:
  295. {
  296. l2_word retval = vm->stack[--vm->sptr];
  297. l2_word retptr = vm->fstack[vm->fsptr - 1].retptr;
  298. l2_word sptr = vm->fstack[vm->fsptr - 1].sptr;
  299. vm->fsptr -= 1;
  300. vm->sptr = sptr;
  301. vm->stack[vm->sptr++] = retval;
  302. vm->iptr = retptr;
  303. }
  304. break;
  305. case L2_OP_ALLOC_NONE:
  306. vm->stack[vm->sptr++] = 0;
  307. break;
  308. case L2_OP_ALLOC_ATOM:
  309. word = alloc_val(vm);
  310. vm->values[word].flags = L2_VAL_TYPE_ATOM;
  311. vm->values[word].atom = vm->ops[vm->iptr++];
  312. vm->stack[vm->sptr++] = word;
  313. break;
  314. case L2_OP_ALLOC_REAL:
  315. {
  316. word = alloc_val(vm);
  317. l2_word high = vm->ops[vm->iptr++];
  318. l2_word low = vm->ops[vm->iptr++];
  319. vm->values[word].flags = L2_VAL_TYPE_REAL;
  320. vm->values[word].real = u32s_to_double(high, low);
  321. vm->stack[vm->sptr++] = word;
  322. }
  323. break;
  324. case L2_OP_ALLOC_BUFFER_STATIC:
  325. {
  326. word = alloc_val(vm);
  327. l2_word length = vm->ops[vm->iptr++];
  328. l2_word offset = vm->ops[vm->iptr++];
  329. vm->values[word].flags = L2_VAL_TYPE_BUFFER;
  330. vm->values[word].buffer = malloc(sizeof(struct l2_vm_buffer) + length);
  331. vm->values[word].buffer->len = length;
  332. memcpy(
  333. (unsigned char *)vm->values[word].buffer + sizeof(struct l2_vm_buffer),
  334. vm->ops + offset, length);
  335. vm->stack[vm->sptr] = word;
  336. vm->sptr += 1;
  337. }
  338. break;
  339. case L2_OP_ALLOC_ARRAY:
  340. {
  341. l2_word count = vm->ops[vm->iptr++];
  342. l2_word arr_id = alloc_val(vm);
  343. struct l2_vm_value *arr = &vm->values[arr_id];
  344. arr->flags = L2_VAL_TYPE_ARRAY;
  345. if (count == 0) {
  346. arr->array = NULL;
  347. vm->stack[vm->sptr++] = arr_id;
  348. break;
  349. }
  350. arr->array = malloc(sizeof(struct l2_vm_array) + count * sizeof(l2_word));
  351. arr->array->len = count;
  352. arr->array->size = count;
  353. for (l2_word i = 0; i < count; ++i) {
  354. arr->array->data[count - 1 - i] = vm->stack[--vm->sptr];
  355. }
  356. vm->stack[vm->sptr++] = arr_id;
  357. }
  358. break;
  359. case L2_OP_ALLOC_NAMESPACE:
  360. word = alloc_val(vm);
  361. vm->values[word].flags = L2_VAL_TYPE_NAMESPACE;
  362. vm->values[word].extra.ns_parent = 0;
  363. vm->values[word].ns = NULL; // Will be allocated on first insert
  364. vm->stack[vm->sptr] = word;
  365. vm->sptr += 1;
  366. break;
  367. case L2_OP_ALLOC_FUNCTION:
  368. word = alloc_val(vm);
  369. vm->values[word].flags = L2_VAL_TYPE_FUNCTION;
  370. vm->values[word].func.pos = vm->ops[vm->iptr++];
  371. vm->values[word].func.ns = vm->fstack[vm->fsptr - 1].ns;
  372. vm->stack[vm->sptr] = word;
  373. vm->sptr += 1;
  374. break;
  375. case L2_OP_NAMESPACE_SET:
  376. {
  377. l2_word key = vm->ops[vm->iptr++];
  378. l2_word val = vm->stack[vm->sptr - 1];
  379. l2_word ns = vm->stack[vm->sptr - 2];
  380. l2_vm_namespace_set(&vm->values[ns], key, val);
  381. }
  382. break;
  383. case L2_OP_NAMESPACE_LOOKUP:
  384. {
  385. l2_word key = vm->ops[vm->iptr++];
  386. l2_word ns = vm->stack[--vm->sptr];
  387. vm->stack[vm->sptr++] = l2_vm_namespace_get(vm, &vm->values[ns], key);
  388. }
  389. break;
  390. case L2_OP_ARRAY_LOOKUP:
  391. {
  392. l2_word key = vm->ops[vm->iptr++];
  393. l2_word arr = vm->stack[--vm->sptr];
  394. // TODO: Error if out of bounds or incorrect type
  395. vm->stack[vm->sptr++] = vm->values[arr].array->data[key];
  396. }
  397. break;
  398. case L2_OP_ARRAY_SET:
  399. {
  400. l2_word key = vm->ops[vm->iptr++];
  401. l2_word val = vm->stack[vm->sptr - 1];
  402. l2_word arr = vm->stack[vm->sptr - 2];
  403. // TODO: Error if out of bounds or incorrect type
  404. vm->values[arr].array->data[key] = val;
  405. }
  406. break;
  407. case L2_OP_DYNAMIC_LOOKUP:
  408. {
  409. l2_word key_id = vm->stack[--vm->sptr];
  410. l2_word container_id = vm->stack[--vm->sptr];
  411. struct l2_vm_value *key = &vm->values[key_id];
  412. struct l2_vm_value *container = &vm->values[container_id];
  413. if (
  414. l2_vm_value_type(key) == L2_VAL_TYPE_REAL &&
  415. l2_vm_value_type(container) == L2_VAL_TYPE_ARRAY) {
  416. // TODO: Error if out of bounds
  417. vm->stack[vm->sptr++] = container->array->data[(size_t)key->real];
  418. } else if (
  419. l2_vm_value_type(key) == L2_VAL_TYPE_ATOM &&
  420. l2_vm_value_type(container) == L2_VAL_TYPE_NAMESPACE) {
  421. // TODO: Error if out of bounds
  422. vm->stack[vm->sptr++] = l2_vm_namespace_get(vm, container, key->atom);
  423. } else {
  424. // TODO: error
  425. }
  426. }
  427. break;
  428. case L2_OP_DYNAMIC_SET:
  429. {
  430. l2_word val = vm->stack[--vm->sptr];
  431. l2_word key_id = vm->stack[--vm->sptr];
  432. l2_word container_id = vm->stack[--vm->sptr];
  433. vm->stack[vm->sptr++] = val;
  434. struct l2_vm_value *key = &vm->values[key_id];
  435. struct l2_vm_value *container = &vm->values[container_id];
  436. if (
  437. l2_vm_value_type(key) == L2_VAL_TYPE_REAL &&
  438. l2_vm_value_type(container) == L2_VAL_TYPE_ARRAY) {
  439. // TODO: Error if out of bounds
  440. container->array->data[(size_t)key->real] = val;
  441. } else if (
  442. l2_vm_value_type(key) == L2_VAL_TYPE_ATOM &&
  443. l2_vm_value_type(container) == L2_VAL_TYPE_NAMESPACE) {
  444. // TODO: Error if out of bounds
  445. l2_vm_namespace_set(container, key->atom, val);
  446. } else {
  447. // TODO: error
  448. }
  449. }
  450. break;
  451. case L2_OP_HALT:
  452. break;
  453. }
  454. }