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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  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. printf("GC MARK %i\n", id);
  32. struct l2_vm_value *val = &vm->values[id];
  33. val->flags |= L2_VAL_MARKED;
  34. int typ = l2_vm_value_type(val);
  35. if (typ == L2_VAL_TYPE_ARRAY) {
  36. gc_mark_array(vm, val);
  37. } else if (typ == L2_VAL_TYPE_NAMESPACE) {
  38. gc_mark_namespace(vm, val);
  39. } else if (typ == L2_VAL_TYPE_FUNCTION) {
  40. gc_mark_namespace(vm, &vm->values[val->func.namespace]);
  41. }
  42. }
  43. static void gc_mark_array(struct l2_vm *vm, struct l2_vm_value *val) {
  44. if (val->data == NULL) {
  45. return;
  46. }
  47. struct l2_vm_array *arr = (struct l2_vm_array *)val->data;
  48. for (size_t i = 0; i < arr->len; ++i) {
  49. gc_mark(vm, arr->data[i]);
  50. }
  51. }
  52. static void gc_mark_namespace(struct l2_vm *vm, struct l2_vm_value *val) {
  53. if (val->data == NULL) {
  54. return;
  55. }
  56. struct l2_vm_namespace *ns = (struct l2_vm_namespace *)val->data;
  57. for (size_t i = 0; i < ns->size; ++i) {
  58. l2_word key = ns->data[i];
  59. if (key == 0 || key == ~(l2_word)0) {
  60. continue;
  61. }
  62. gc_mark(vm, ns->data[ns->size + i]);
  63. }
  64. }
  65. static void gc_free(struct l2_vm *vm, l2_word id) {
  66. struct l2_vm_value *val = &vm->values[id];
  67. l2_bitset_unset(&vm->valueset, id);
  68. int typ = l2_vm_value_type(val);
  69. if (typ == L2_VAL_TYPE_ARRAY || typ == L2_VAL_TYPE_BUFFER || typ == L2_VAL_TYPE_NAMESPACE) {
  70. free(val->data);
  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. }
  74. }
  75. static size_t gc_sweep(struct l2_vm *vm) {
  76. size_t freed = 0;
  77. // Skip ID 0, because that should always exist
  78. for (size_t i = 1; i < vm->valuessize; ++i) {
  79. if (!l2_bitset_get(&vm->valueset, i)) {
  80. continue;
  81. }
  82. struct l2_vm_value *val = &vm->values[i];
  83. if (!(val->flags & L2_VAL_MARKED)) {
  84. gc_free(vm, i);
  85. freed += 1;
  86. } else {
  87. val->flags &= ~L2_VAL_MARKED;
  88. }
  89. }
  90. return freed;
  91. }
  92. void l2_vm_init(struct l2_vm *vm, l2_word *ops, size_t opcount) {
  93. vm->ops = ops;
  94. vm->opcount = opcount;
  95. vm->iptr = 0;
  96. vm->sptr = 0;
  97. vm->nsptr = 0;
  98. vm->values = NULL;
  99. vm->valuessize = 0;
  100. l2_bitset_init(&vm->valueset);
  101. // It's wasteful to allocate new 'none' variables all the time,
  102. // variable ID 0 should be the only 'none' variable in the system
  103. l2_word none_id = alloc_val(vm);
  104. vm->values[none_id].flags = L2_VAL_TYPE_NONE | L2_VAL_CONST;
  105. }
  106. void l2_vm_free(struct l2_vm *vm) {
  107. // Skip ID 0, because that's always NONE
  108. for (size_t i = 1; i < vm->valuessize; ++i) {
  109. if (!l2_bitset_get(&vm->valueset, i)) {
  110. continue;
  111. }
  112. gc_free(vm, i);
  113. }
  114. free(vm->values);
  115. l2_bitset_free(&vm->valueset);
  116. }
  117. size_t l2_vm_gc(struct l2_vm *vm) {
  118. for (l2_word nsptr = 0; nsptr < vm->nsptr; ++nsptr) {
  119. struct l2_vm_value *val = &vm->values[vm->nstack[nsptr]];
  120. val->flags |= L2_VAL_MARKED;
  121. gc_mark_namespace(vm, val);
  122. }
  123. return gc_sweep(vm);
  124. }
  125. void l2_vm_run(struct l2_vm *vm) {
  126. while ((enum l2_opcode)vm->ops[vm->iptr] != L2_OP_HALT) {
  127. l2_vm_step(vm);
  128. }
  129. }
  130. void l2_vm_step(struct l2_vm *vm) {
  131. enum l2_opcode opcode = (enum l2_opcode)vm->ops[vm->iptr++];
  132. l2_word word;
  133. switch (opcode) {
  134. case L2_OP_NOP:
  135. break;
  136. case L2_OP_PUSH:
  137. vm->stack[vm->sptr] = vm->ops[vm->iptr];
  138. vm->sptr += 1;
  139. vm->iptr += 1;
  140. break;
  141. case L2_OP_PUSH_2:
  142. vm->stack[vm->sptr] = vm->ops[vm->iptr];
  143. vm->stack[vm->sptr + 1] = vm->ops[vm->iptr + 1];
  144. vm->sptr += 2;
  145. vm->iptr += 2;
  146. break;
  147. case L2_OP_POP:
  148. vm->sptr -= 1;
  149. break;
  150. case L2_OP_DUP:
  151. vm->stack[vm->sptr] = vm->ops[vm->sptr - 1];
  152. vm->sptr += 1;
  153. break;
  154. case L2_OP_ADD:
  155. vm->stack[vm->sptr - 2] += vm->stack[vm->sptr - 1];
  156. vm->sptr -= 1;
  157. break;
  158. case L2_OP_CALL:
  159. word = vm->stack[vm->sptr - 1];
  160. vm->stack[vm->sptr - 1] = vm->iptr + 1;
  161. vm->iptr = word;
  162. break;
  163. case L2_OP_RJMP:
  164. word = vm->stack[vm->sptr - 1];
  165. vm->sptr -= 1;
  166. vm->iptr += word;
  167. break;
  168. case L2_OP_GEN_STACK_FRAME:
  169. word = alloc_val(vm);
  170. vm->values[word].flags = L2_VAL_TYPE_NAMESPACE;
  171. vm->values[word].data = NULL; // Will be allocated on first insert
  172. vm->nstack[vm->nsptr] = word;
  173. vm->nsptr += 1;
  174. break;
  175. case L2_OP_STACK_FRAME_LOOKUP:
  176. {
  177. l2_word key = vm->stack[vm->sptr - 1];
  178. struct l2_vm_value *ns = &vm->values[vm->nstack[vm->nsptr - 1]];
  179. vm->stack[vm->sptr - 1] = l2_vm_namespace_get(ns, key);
  180. }
  181. break;
  182. case L2_OP_STACK_FRAME_SET:
  183. {
  184. l2_word key = vm->stack[vm->sptr - 1];
  185. l2_word val = vm->stack[vm->sptr - 2];
  186. struct l2_vm_value *ns = &vm->values[vm->nstack[vm->nsptr - 1]];
  187. l2_vm_namespace_set(ns, key, val);
  188. vm->sptr -= 1;
  189. }
  190. break;
  191. case L2_OP_RET:
  192. vm->nsptr -= 1;
  193. vm->iptr = vm->stack[vm->sptr - 1];
  194. vm->sptr -= 1;
  195. vm->nsptr -= 1;
  196. break;
  197. case L2_OP_ALLOC_INTEGER_32:
  198. word = alloc_val(vm);
  199. vm->values[word].flags = L2_VAL_TYPE_INTEGER;
  200. vm->values[word].integer = vm->stack[--vm->sptr];
  201. vm->stack[vm->sptr] = word;
  202. vm->sptr += 1;
  203. break;
  204. case L2_OP_ALLOC_INTEGER_64:
  205. word = alloc_val(vm);
  206. vm->values[word].flags = L2_VAL_TYPE_INTEGER;
  207. vm->values[word].integer = (int64_t)(
  208. (uint64_t)vm->stack[vm->sptr - 1] << 32 |
  209. (uint64_t)vm->stack[vm->sptr - 2]);
  210. vm->sptr -= 2;
  211. vm->stack[vm->sptr] = word;
  212. vm->sptr += 1;
  213. break;
  214. case L2_OP_ALLOC_REAL_32:
  215. word = alloc_val(vm);
  216. vm->values[word].flags = L2_VAL_TYPE_REAL;
  217. vm->values[word].real = u32_to_float(vm->stack[--vm->sptr]);
  218. vm->stack[vm->sptr] = word;
  219. vm->sptr += 1;
  220. break;
  221. case L2_OP_ALLOC_REAL_64:
  222. word = alloc_val(vm);
  223. vm->values[word].flags = L2_VAL_TYPE_REAL;
  224. vm->values[word].real = u32s_to_double(vm->stack[vm->sptr - 1], vm->stack[vm->sptr - 2]);
  225. vm->sptr -= 2;
  226. vm->stack[vm->sptr] = word;
  227. vm->sptr += 1;
  228. break;
  229. case L2_OP_ALLOC_BUFFER_STATIC:
  230. {
  231. word = alloc_val(vm);
  232. l2_word length = vm->stack[--vm->sptr];
  233. l2_word offset = vm->stack[--vm->sptr];
  234. vm->values[word].flags = L2_VAL_TYPE_BUFFER;
  235. vm->values[word].data = malloc(sizeof(struct l2_vm_buffer) + length);
  236. ((struct l2_vm_buffer *)vm->values[word].data)->len = length;
  237. memcpy(
  238. (unsigned char *)vm->values[word].data + sizeof(struct l2_vm_buffer),
  239. vm->ops + offset, length);
  240. vm->stack[vm->sptr] = word;
  241. vm->sptr += 1;
  242. }
  243. break;
  244. case L2_OP_ALLOC_BUFFER_ZERO:
  245. {
  246. word = alloc_val(vm);
  247. l2_word length = vm->stack[--vm->sptr];
  248. vm->values[word].flags = L2_VAL_TYPE_BUFFER;
  249. vm->values[word].data = calloc(1, sizeof(struct l2_vm_buffer) + length);
  250. ((struct l2_vm_buffer *)vm->values[word].data)->len = length;
  251. vm->stack[vm->sptr] = word;
  252. vm->sptr += 1;
  253. }
  254. break;
  255. case L2_OP_ALLOC_ARRAY:
  256. word = alloc_val(vm);
  257. vm->values[word].flags = L2_VAL_TYPE_ARRAY;
  258. vm->values[word].data = NULL; // Will be allocated on first insert
  259. vm->stack[vm->sptr] = word;
  260. vm->sptr += 1;
  261. break;
  262. case L2_OP_ALLOC_NAMESPACE:
  263. word = alloc_val(vm);
  264. vm->values[word].flags = L2_VAL_TYPE_NAMESPACE;
  265. vm->values[word].data = NULL; // Will be allocated on first insert
  266. vm->stack[vm->sptr] = word;
  267. vm->sptr += 1;
  268. break;
  269. case L2_OP_ALLOC_FUNCTION:
  270. word = alloc_val(vm);
  271. vm->values[word].flags = L2_VAL_TYPE_FUNCTION;
  272. vm->values[word].func.pos = vm->stack[--vm->sptr];
  273. vm->values[word].func.namespace = vm->nstack[vm->nsptr - 1];
  274. vm->stack[vm->sptr] = word;
  275. vm->sptr += 1;
  276. break;
  277. case L2_OP_NAMESPACE_SET:
  278. {
  279. l2_word key = vm->stack[vm->sptr - 1];
  280. l2_word val = vm->stack[vm->sptr - 2];
  281. l2_word ns = vm->stack[vm->sptr - 3];
  282. l2_vm_namespace_set(&vm->values[ns], key, val);
  283. vm->sptr -= 1;
  284. }
  285. break;
  286. case L2_OP_HALT:
  287. break;
  288. }
  289. }