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.1KB

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