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

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