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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  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(struct l2_vm *vm, l2_word id) {
  29. printf("GC MARK %i\n", id);
  30. struct l2_vm_value *val = &vm->values[id];
  31. val->flags |= L2_VAL_MARKED;
  32. int typ = val->flags & 0x0f;
  33. if (typ == L2_VAL_TYPE_ARRAY) {
  34. if (val->data == NULL) {
  35. return;
  36. }
  37. struct l2_vm_array *arr = (struct l2_vm_array *)val->data;
  38. for (size_t i = 0; i < arr->len; ++i) {
  39. gc_mark(vm, arr->data[i]);
  40. }
  41. } else if (typ == L2_VAL_TYPE_NAMESPACE) {
  42. if (val->data == NULL) {
  43. return;
  44. }
  45. struct l2_vm_namespace *ns = (struct l2_vm_namespace *)val->data;
  46. for (size_t i = 0; i < ns->size; ++i) {
  47. l2_word key = ns->data[i];
  48. if (key == 0 || key == ~(l2_word)0) {
  49. continue;
  50. }
  51. gc_mark(vm, ns->data[ns->size + i]);
  52. }
  53. }
  54. }
  55. static void gc_free(struct l2_vm *vm, l2_word id) {
  56. printf("GC FREE %i\n", id);
  57. struct l2_vm_value *val = &vm->values[id];
  58. l2_bitset_unset(&vm->valueset, id);
  59. int typ = val->flags & 0x0f;
  60. if (typ == L2_VAL_TYPE_ARRAY || typ == L2_VAL_TYPE_BUFFER || typ == L2_VAL_TYPE_NAMESPACE) {
  61. free(val->data);
  62. // Don't need to do anything more; the next round of GC will free
  63. // whichever values were only referenced by the array
  64. }
  65. }
  66. static size_t gc_sweep(struct l2_vm *vm) {
  67. size_t freed = 0;
  68. // Skip ID 0, because that should always exist
  69. for (size_t i = 1; i < vm->valuessize; ++i) {
  70. if (!l2_bitset_get(&vm->valueset, i)) {
  71. continue;
  72. }
  73. struct l2_vm_value *val = &vm->values[i];
  74. if (!(val->flags & L2_VAL_MARKED)) {
  75. gc_free(vm, i);
  76. freed += 1;
  77. } else {
  78. val->flags &= ~L2_VAL_MARKED;
  79. }
  80. }
  81. return freed;
  82. }
  83. void l2_vm_init(struct l2_vm *vm, l2_word *ops, size_t opcount) {
  84. vm->ops = ops;
  85. vm->opcount = opcount;
  86. vm->iptr = 0;
  87. vm->sptr = 0;
  88. vm->values = NULL;
  89. vm->valuessize = 0;
  90. l2_bitset_init(&vm->valueset);
  91. // It's wasteful to allocate new 'none' variables all the time,
  92. // variable ID 0 should be the only 'none' variable in the system
  93. l2_word none_id = alloc_val(vm);
  94. vm->values[none_id].flags = L2_VAL_TYPE_NONE | L2_VAL_CONST;
  95. }
  96. void l2_vm_free(struct l2_vm *vm) {
  97. // Skip ID 0, because that should always exist
  98. for (size_t i = 1; i < vm->valuessize; ++i) {
  99. if (!l2_bitset_get(&vm->valueset, i)) {
  100. continue;
  101. }
  102. gc_free(vm, i);
  103. }
  104. free(vm->values);
  105. l2_bitset_free(&vm->valueset);
  106. }
  107. size_t l2_vm_gc(struct l2_vm *vm) {
  108. for (l2_word sptr = 0; sptr < vm->sptr; ++sptr) {
  109. if (vm->stackflags[sptr]) {
  110. gc_mark(vm, vm->stack[sptr]);
  111. }
  112. }
  113. return gc_sweep(vm);
  114. }
  115. void l2_vm_run(struct l2_vm *vm) {
  116. while ((enum l2_opcode)vm->ops[vm->iptr] != L2_OP_HALT) {
  117. l2_vm_step(vm);
  118. }
  119. }
  120. void l2_vm_step(struct l2_vm *vm) {
  121. enum l2_opcode opcode = (enum l2_opcode)vm->ops[vm->iptr++];
  122. l2_word word;
  123. switch (opcode) {
  124. case L2_OP_NOP:
  125. break;
  126. case L2_OP_PUSH:
  127. vm->stack[vm->sptr] = vm->ops[vm->iptr];
  128. vm->stackflags[vm->sptr] = 0;
  129. vm->sptr += 1;
  130. vm->iptr += 1;
  131. break;
  132. case L2_OP_POP:
  133. vm->sptr -= 1;
  134. break;
  135. case L2_OP_DUP:
  136. vm->stack[vm->sptr] = vm->ops[vm->sptr - 1];
  137. vm->stackflags[vm->sptr] = 0;
  138. vm->sptr += 1;
  139. break;
  140. case L2_OP_ADD:
  141. vm->stack[vm->sptr - 2] += vm->stack[vm->sptr - 1];
  142. vm->stackflags[vm->sptr - 2] = 0;
  143. vm->sptr -= 1;
  144. break;
  145. case L2_OP_CALL:
  146. word = vm->stack[vm->sptr - 1];
  147. vm->stack[vm->sptr - 1] = vm->iptr + 1;
  148. vm->stackflags[vm->sptr - 1] = 0;
  149. vm->iptr = word;
  150. break;
  151. case L2_OP_RET:
  152. vm->iptr = vm->stack[vm->sptr - 1];
  153. vm->sptr -= 1;
  154. break;
  155. case L2_OP_ALLOC_INTEGER_32:
  156. word = alloc_val(vm);
  157. vm->values[word].flags = L2_VAL_TYPE_INTEGER;
  158. vm->values[word].integer = vm->stack[--vm->sptr];
  159. vm->stack[vm->sptr] = word;
  160. vm->stackflags[vm->sptr] = 1;
  161. vm->sptr += 1;
  162. break;
  163. case L2_OP_ALLOC_INTEGER_64:
  164. word = alloc_val(vm);
  165. vm->values[word].flags = L2_VAL_TYPE_INTEGER;
  166. vm->values[word].integer = (int64_t)(
  167. (uint64_t)vm->stack[vm->sptr - 1] << 32 |
  168. (uint64_t)vm->stack[vm->sptr - 2]);
  169. vm->sptr -= 2;
  170. vm->stack[vm->sptr] = word;
  171. vm->stackflags[vm->sptr] = 1;
  172. vm->sptr += 1;
  173. break;
  174. case L2_OP_ALLOC_REAL_32:
  175. word = alloc_val(vm);
  176. vm->values[word].flags = L2_VAL_TYPE_REAL;
  177. vm->values[word].real = u32_to_float(vm->stack[--vm->sptr]);
  178. vm->stack[vm->sptr] = word;
  179. vm->stackflags[vm->sptr] = 1;
  180. vm->sptr += 1;
  181. break;
  182. case L2_OP_ALLOC_REAL_64:
  183. word = alloc_val(vm);
  184. vm->values[word].flags = L2_VAL_TYPE_REAL;
  185. vm->values[word].real = u32s_to_double(vm->stack[vm->sptr - 1], vm->stack[vm->sptr - 2]);
  186. vm->sptr -= 2;
  187. vm->stack[vm->sptr] = word;
  188. vm->stackflags[vm->sptr] = 1;
  189. vm->sptr += 1;
  190. break;
  191. case L2_OP_ALLOC_BUFFER_STATIC:
  192. {
  193. word = alloc_val(vm);
  194. l2_word length = vm->stack[--vm->sptr];
  195. l2_word offset = vm->stack[--vm->sptr];
  196. vm->values[word].flags = L2_VAL_TYPE_BUFFER;
  197. vm->values[word].data = malloc(sizeof(struct l2_vm_buffer) + length);
  198. ((struct l2_vm_buffer *)vm->values[word].data)->len = length;
  199. memcpy(
  200. (unsigned char *)vm->values[word].data + sizeof(struct l2_vm_buffer),
  201. vm->ops + offset, length);
  202. vm->stack[vm->sptr] = word;
  203. vm->stackflags[vm->sptr] = 1;
  204. vm->sptr += 1;
  205. }
  206. break;
  207. case L2_OP_ALLOC_BUFFER_ZERO:
  208. {
  209. word = alloc_val(vm);
  210. l2_word length = vm->stack[--vm->sptr];
  211. vm->values[word].flags = L2_VAL_TYPE_BUFFER;
  212. vm->values[word].data = calloc(1, sizeof(struct l2_vm_buffer) + length);
  213. ((struct l2_vm_buffer *)vm->values[word].data)->len = length;
  214. vm->stack[vm->sptr] = word;
  215. vm->stackflags[vm->sptr] = 1;
  216. vm->sptr += 1;
  217. }
  218. case L2_OP_ALLOC_ARRAY:
  219. word = alloc_val(vm);
  220. vm->values[word].flags = L2_VAL_TYPE_ARRAY;
  221. vm->values[word].data = NULL; // Will be allocated on first insert
  222. vm->stack[vm->sptr] = word;
  223. vm->stackflags[vm->sptr] = 1;
  224. vm->sptr += 1;
  225. break;
  226. case L2_OP_ALLOC_NAMESPACE:
  227. word = alloc_val(vm);
  228. vm->values[word].flags = L2_VAL_TYPE_NAMESPACE;
  229. vm->values[word].data = NULL; // Will be allocated on first insert
  230. vm->stack[vm->sptr] = word;
  231. vm->stackflags[vm->sptr] = 1;
  232. vm->sptr += 1;
  233. break;
  234. case L2_OP_HALT:
  235. break;
  236. }
  237. }