diff options
Diffstat (limited to 'src/bytecode/vm.h')
-rwxr-xr-x | src/bytecode/vm.h | 70 |
1 files changed, 41 insertions, 29 deletions
diff --git a/src/bytecode/vm.h b/src/bytecode/vm.h index b6f9848..23c3d89 100755 --- a/src/bytecode/vm.h +++ b/src/bytecode/vm.h | |||
@@ -8,13 +8,20 @@ | |||
8 | #include "debug.h" | 8 | #include "debug.h" |
9 | #include "hashtable.h" | 9 | #include "hashtable.h" |
10 | 10 | ||
11 | #define VM_FRAMES_CAP 64 | ||
11 | #define VM_STACK_CAP 1024 | 12 | #define VM_STACK_CAP 1024 |
12 | 13 | ||
13 | typedef struct VM { | 14 | typedef struct CallFrame { |
14 | // Program code. | 15 | // Current code being run. |
15 | Chunk *chunk; | 16 | Object procedure; |
16 | // Program counter. | 17 | // Current program counter for this call. |
17 | u8 *pc; | 18 | u8 *pc; |
19 | // Ref to stack. Is this really needed? | ||
20 | // Object *stack; | ||
21 | } CallFrame; | ||
22 | |||
23 | typedef struct VM { | ||
24 | CallFrame *frames; | ||
18 | // Stack. | 25 | // Stack. |
19 | Object *stack; | 26 | Object *stack; |
20 | // Global variables. | 27 | // Global variables. |
@@ -24,17 +31,22 @@ typedef struct VM { | |||
24 | void vm_init(VM *vm); | 31 | void vm_init(VM *vm); |
25 | void vm_free(VM *vm); | 32 | void vm_free(VM *vm); |
26 | void vm_reset(VM *vm); | 33 | void vm_reset(VM *vm); |
27 | void vm_interpret(VM *vm, Chunk *chunk); | 34 | void vm_interpret(VM *vm); |
28 | 35 | ||
29 | void | 36 | void |
30 | vm_init(VM *vm) { | 37 | vm_init(VM *vm) { |
31 | *vm = (VM){0}; | 38 | *vm = (VM){0}; |
39 | array_init(vm->frames, VM_FRAMES_CAP); | ||
40 | for (size_t i = 0; i < array_cap(vm->frames); i++) { | ||
41 | vm->frames[i] = (CallFrame){0}; | ||
42 | } | ||
32 | array_init(vm->stack, VM_STACK_CAP); | 43 | array_init(vm->stack, VM_STACK_CAP); |
33 | vm->globals = ht_init(); | 44 | vm->globals = ht_init(); |
34 | } | 45 | } |
35 | 46 | ||
36 | void | 47 | void |
37 | vm_free(VM *vm) { | 48 | vm_free(VM *vm) { |
49 | array_free(vm->frames); | ||
38 | array_free(vm->stack); | 50 | array_free(vm->stack); |
39 | ht_free(vm->globals); | 51 | ht_free(vm->globals); |
40 | } | 52 | } |
@@ -50,16 +62,16 @@ vm_reset(VM *vm) { | |||
50 | error_push((Error){ \ | 62 | error_push((Error){ \ |
51 | .type = ERR_TYPE_RUNTIME, \ | 63 | .type = ERR_TYPE_RUNTIME, \ |
52 | .value = ERR_WRONG_ARG_TYPE, \ | 64 | .value = ERR_WRONG_ARG_TYPE, \ |
53 | .line = vm->chunk->lines[vm->pc - vm->chunk->code - 1].line, \ | 65 | .line = chunk->lines[frame->pc - chunk->code - 1].line, \ |
54 | .col = vm->chunk->lines[vm->pc - vm->chunk->code - 1].col, \ | 66 | .col = chunk->lines[frame->pc - chunk->code - 1].col, \ |
55 | }) | 67 | }) |
56 | 68 | ||
57 | #define SYMBOL_NOT_FOUND_ERR() \ | 69 | #define SYMBOL_NOT_FOUND_ERR() \ |
58 | error_push((Error){ \ | 70 | error_push((Error){ \ |
59 | .type = ERR_TYPE_RUNTIME, \ | 71 | .type = ERR_TYPE_RUNTIME, \ |
60 | .value = ERR_SYMBOL_NOT_FOUND, \ | 72 | .value = ERR_SYMBOL_NOT_FOUND, \ |
61 | .line = vm->chunk->lines[vm->pc - vm->chunk->code - 1].line, \ | 73 | .line = chunk->lines[frame->pc - chunk->code - 1].line, \ |
62 | .col = vm->chunk->lines[vm->pc - vm->chunk->code - 1].col, \ | 74 | .col = chunk->lines[frame->pc - chunk->code - 1].col, \ |
63 | }) | 75 | }) |
64 | 76 | ||
65 | #define FIXNUM_ARITHMETIC_OP(OP) \ | 77 | #define FIXNUM_ARITHMETIC_OP(OP) \ |
@@ -123,11 +135,11 @@ vm_reset(VM *vm) { | |||
123 | } while (false) | 135 | } while (false) |
124 | 136 | ||
125 | void | 137 | void |
126 | vm_interpret(VM *vm, Chunk *chunk) { | 138 | vm_interpret(VM *vm) { |
127 | vm->chunk = chunk; | 139 | CallFrame *frame = &vm->frames[array_size(vm->frames) - 1]; |
128 | vm->pc = vm->chunk->code; | 140 | Chunk *chunk = frame->procedure.chunk; |
129 | 141 | ||
130 | if (vm->chunk->code == NULL || array_size(vm->chunk->code) == 0) { | 142 | if (chunk->code == NULL || array_size(chunk->code) == 0) { |
131 | error_push((Error){ | 143 | error_push((Error){ |
132 | .type = ERR_TYPE_RUNTIME, | 144 | .type = ERR_TYPE_RUNTIME, |
133 | .value = ERR_EMPTY_CHUNK, | 145 | .value = ERR_EMPTY_CHUNK, |
@@ -135,8 +147,8 @@ vm_interpret(VM *vm, Chunk *chunk) { | |||
135 | return; | 147 | return; |
136 | } | 148 | } |
137 | 149 | ||
138 | u8 *last = vm->chunk->code + array_size(vm->chunk->code); | 150 | u8 *last = chunk->code + array_size(chunk->code); |
139 | while (vm->pc < last) { | 151 | while (frame->pc < last) { |
140 | #ifdef DEBUG_TRACE_EXECUTION | 152 | #ifdef DEBUG_TRACE_EXECUTION |
141 | printf("stack: [ "); | 153 | printf("stack: [ "); |
142 | for (size_t i = 0; i < array_size(vm->stack); i++) { | 154 | for (size_t i = 0; i < array_size(vm->stack); i++) { |
@@ -146,13 +158,13 @@ vm_interpret(VM *vm, Chunk *chunk) { | |||
146 | } | 158 | } |
147 | } | 159 | } |
148 | printf(" ]\nop: "); | 160 | printf(" ]\nop: "); |
149 | disassemble_instruction(vm->chunk, (vm->pc - vm->chunk->code)); | 161 | disassemble_instruction(chunk, (frame->pc - chunk->code)); |
150 | #endif | 162 | #endif |
151 | u8 instruction = *vm->pc++; | 163 | u8 instruction = *frame->pc++; |
152 | switch (instruction) { | 164 | switch (instruction) { |
153 | case OP_CONSTANT: { | 165 | case OP_CONSTANT: { |
154 | u8 constant = *vm->pc++; | 166 | u8 constant = *frame->pc++; |
155 | Object obj = vm->chunk->constants[constant]; | 167 | Object obj = chunk->constants[constant]; |
156 | array_push(vm->stack, obj); | 168 | array_push(vm->stack, obj); |
157 | } break; | 169 | } break; |
158 | case OP_DEF: { | 170 | case OP_DEF: { |
@@ -197,17 +209,17 @@ vm_interpret(VM *vm, Chunk *chunk) { | |||
197 | case OP_LESS_EQUAL: { FIXNUM_COMPARE_OP(<=); } break; | 209 | case OP_LESS_EQUAL: { FIXNUM_COMPARE_OP(<=); } break; |
198 | case OP_GREATER_EQUAL: { FIXNUM_COMPARE_OP(>=); } break; | 210 | case OP_GREATER_EQUAL: { FIXNUM_COMPARE_OP(>=); } break; |
199 | case OP_JUMP: { | 211 | case OP_JUMP: { |
200 | u16 a = *vm->pc++; | 212 | u16 a = *frame->pc++; |
201 | u16 b = *vm->pc++; | 213 | u16 b = *frame->pc++; |
202 | s16 offset = (a << 8) | b; | 214 | s16 offset = (a << 8) | b; |
203 | vm->pc += offset; | 215 | frame->pc += offset; |
204 | } break; | 216 | } break; |
205 | case OP_JUMP_IF_FALSE: { | 217 | case OP_JUMP_IF_FALSE: { |
206 | u16 a = *vm->pc++; | 218 | u16 a = *frame->pc++; |
207 | u16 b = *vm->pc++; | 219 | u16 b = *frame->pc++; |
208 | s16 offset = (a << 8) | b; | 220 | s16 offset = (a << 8) | b; |
209 | if (IS_FALSE(array_pop(vm->stack))) { | 221 | if (IS_FALSE(array_pop(vm->stack))) { |
210 | vm->pc += offset; | 222 | frame->pc += offset; |
211 | } | 223 | } |
212 | } break; | 224 | } break; |
213 | case OP_DISPLAY: { | 225 | case OP_DISPLAY: { |
@@ -248,8 +260,8 @@ vm_interpret(VM *vm, Chunk *chunk) { | |||
248 | error_push((Error){ | 260 | error_push((Error){ |
249 | .type = ERR_TYPE_RUNTIME, | 261 | .type = ERR_TYPE_RUNTIME, |
250 | .value = ERR_NOT_IMPLEMENTED, | 262 | .value = ERR_NOT_IMPLEMENTED, |
251 | .line = vm->chunk->lines[vm->pc - vm->chunk->code - 1].line, | 263 | .line = chunk->lines[frame->pc - chunk->code - 1].line, |
252 | .col = vm->chunk->lines[vm->pc - vm->chunk->code - 1].col, | 264 | .col = chunk->lines[frame->pc - chunk->code - 1].col, |
253 | }); | 265 | }); |
254 | return; | 266 | return; |
255 | } break; | 267 | } break; |
@@ -259,8 +271,8 @@ vm_interpret(VM *vm, Chunk *chunk) { | |||
259 | error_push((Error){ | 271 | error_push((Error){ |
260 | .type = ERR_TYPE_RUNTIME, | 272 | .type = ERR_TYPE_RUNTIME, |
261 | .value = ERR_PC_OOB, | 273 | .value = ERR_PC_OOB, |
262 | .line = vm->chunk->lines[0].line, | 274 | .line = chunk->lines[0].line, |
263 | .col = vm->chunk->lines[0].col, | 275 | .col = chunk->lines[0].col, |
264 | }); | 276 | }); |
265 | } | 277 | } |
266 | 278 | ||