Add debugging features
This commit is contained in:
@@ -8,6 +8,7 @@ VM_OBJS=$(O)/vm/main.o \
|
||||
$(O)/vm/unit.o \
|
||||
$(O)/vm/stack.o \
|
||||
$(O)/vm/error.o \
|
||||
$(O)/vm/debug.o \
|
||||
$(O)/core/vector.o \
|
||||
$(O)/core/hash.o
|
||||
COMPILER_OBJS=$(O)/compiler/main.o \
|
||||
|
||||
+3
-1
@@ -304,8 +304,10 @@ void emit(struct function *fn, struct context *ctx, struct node *expr) {
|
||||
emit_insn(fn, OP(OP_CAR, 0));
|
||||
} else if (!strcmp(n0->n_ident, "cdr") && c0 == 1) {
|
||||
emit_insn(fn, OP(OP_CDR, 0));
|
||||
} else if (!strcmp(n0->n_ident, "trace") && c0 == 1) {
|
||||
} else if (!strcmp(n0->n_ident, "debug/trace") && c0 == 1) {
|
||||
emit_insn(fn, OP(OP_DEBUG, OP_DEBUG_TRACE));
|
||||
} else if (!strcmp(n0->n_ident, "debug/break")) {
|
||||
emit_insn(fn, OP(OP_DEBUG, OP_DEBUG_BREAKPOINT));
|
||||
} else {
|
||||
size_t index;
|
||||
int kind;
|
||||
|
||||
@@ -46,3 +46,4 @@
|
||||
|
||||
#define OP_DEBUG 0x80
|
||||
#define OP_DEBUG_TRACE 0x01
|
||||
#define OP_DEBUG_BREAKPOINT 0x02
|
||||
|
||||
@@ -3,4 +3,11 @@
|
||||
|
||||
(define a (cons 1 (cons 2 (cons 3 (cons 4 nil)))))
|
||||
|
||||
(define (f x)
|
||||
(debug/break)
|
||||
(+ x 1))
|
||||
|
||||
(print (f 1))
|
||||
|
||||
(print (list-ref a 1))
|
||||
(print (list-ref a 1))
|
||||
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "error.h"
|
||||
#include "debug.h"
|
||||
#include "vmstate.h"
|
||||
#include "vmval.h"
|
||||
#include "unit.h"
|
||||
|
||||
int debug_breakpoint(struct vm *vm) {
|
||||
struct vm_func_entry *func;
|
||||
struct vm_unit *unit;
|
||||
uint64_t w0;
|
||||
uint32_t opcode;
|
||||
char line[256];
|
||||
char *p;
|
||||
|
||||
unit = vector_ref(&vm->units, vm->lp);
|
||||
func = vector_ref(&unit->functions, vm->fp);
|
||||
opcode = func->bytecode[vm->ip];
|
||||
|
||||
fprintf(stderr, "%02zx:%02zx:%04zx: %08x\n", vm->lp, vm->fp, vm->ip, opcode);
|
||||
|
||||
while (1) {
|
||||
fprintf(stderr, ">> ");
|
||||
if (!fgets(line, sizeof(line), stdin)) {
|
||||
return 0;
|
||||
}
|
||||
if ((p = strchr(line, '\n')) != NULL) {
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
if (!strcmp(line, "s")) {
|
||||
vm->flags |= VM_SINGLESTEP;
|
||||
return 0;
|
||||
} else if (!strcmp(line, "c")) {
|
||||
vm->flags &= ~VM_SINGLESTEP;
|
||||
return 0;
|
||||
} else if (!strcmp(line, "q")) {
|
||||
return -ERR_ERROR_EXIT;
|
||||
} else if (!strcmp(line, "regs")) {
|
||||
fprintf(stderr, " lp = 0x%04zx, fp = 0x%04zx\n", vm->lp, vm->fp);
|
||||
fprintf(stderr, " ip = 0x%04zx\n", vm->ip);
|
||||
fprintf(stderr, " dsp = 0x%04zx\n", vm->data_stack.sp);
|
||||
fprintf(stderr, " csp = 0x%04zx, cbp = 0x%04zx\n", vm->call_stack.sp, vm->bp);
|
||||
} else if (!strcmp(line, "locals")) {
|
||||
fprintf(stderr, "Local variables:\n");
|
||||
for (size_t i = 0; i < func->local_count; ++i) {
|
||||
w0 = vm->call_stack.data[vm->bp - i - 1];
|
||||
fprintf(stderr, "[bp - %zu]: ", i + 1);
|
||||
vm_print(stderr, w0);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
fprintf(stderr, "Arguments:\n");
|
||||
for (size_t i = 0; i < func->argc; ++i) {
|
||||
w0 = vm->call_stack.data[vm->bp + i];
|
||||
fprintf(stderr, "[bp + %zu]: ", i);
|
||||
vm_print(stderr, w0);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
} else if (!strcmp(line, "bt")) {
|
||||
fprintf(stderr, "Call frame trace:\n");
|
||||
size_t bp, lp, fp, ip, sp;
|
||||
size_t count;
|
||||
struct vm_func_entry *f;
|
||||
struct vm_unit *u;
|
||||
|
||||
bp = vm->bp;
|
||||
lp = vm->lp;
|
||||
fp = vm->fp;
|
||||
ip = vm->ip;
|
||||
count = 0;
|
||||
while (1) {
|
||||
u = vector_ref(&vm->units, lp);
|
||||
f = vector_ref(&u->functions, fp);
|
||||
sp = bp + f->argc;
|
||||
fprintf(stderr, "%2zu: %02zx:%02zx:%04zx: %08x\n",
|
||||
count, lp, fp, ip, f->bytecode[ip]);
|
||||
|
||||
if (count == 5) {
|
||||
break;
|
||||
}
|
||||
bp = vm->call_stack.data[sp + 3];
|
||||
lp = vm->call_stack.data[sp + 2];
|
||||
fp = vm->call_stack.data[sp + 1];
|
||||
ip = vm->call_stack.data[sp + 0];
|
||||
++count;
|
||||
|
||||
if (bp == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,8 @@ const char *vm_strerror(int e) {
|
||||
case -ERR_STACK_UNDERFLOW: return "Stack underflow";
|
||||
case -ERR_STACK_OVERFLOW: return "Stack overflow";
|
||||
case -ERR_NOT_FOUND: return "Unit not found";
|
||||
case -ERR_INVALID_STATE: return "Invalid VM state";
|
||||
case -ERR_ERROR_EXIT: return "Program exited with an error";
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
struct vm;
|
||||
|
||||
int debug_breakpoint(struct vm *vm);
|
||||
@@ -11,5 +11,7 @@
|
||||
#define ERR_STACK_UNDERFLOW 9
|
||||
#define ERR_STACK_OVERFLOW 10
|
||||
#define ERR_NOT_FOUND 11
|
||||
#define ERR_INVALID_STATE 12
|
||||
#define ERR_ERROR_EXIT 13
|
||||
|
||||
const char *vm_strerror(int e);
|
||||
|
||||
+3
-3
@@ -4,7 +4,7 @@
|
||||
#include "list.h"
|
||||
#include "vector.h"
|
||||
|
||||
struct vm_state;
|
||||
struct vm;
|
||||
struct vm_ref_entry;
|
||||
|
||||
struct vm_unresolved_ref {
|
||||
@@ -29,11 +29,11 @@ struct vm_unit_info {
|
||||
struct vm_unit *unit;
|
||||
};
|
||||
|
||||
int vm_load_unit_file(struct vm_state *vm,
|
||||
int vm_load_unit_file(struct vm *vm,
|
||||
struct vm_unit_info *info,
|
||||
struct list_head *refs,
|
||||
FILE *fp);
|
||||
int vm_load_unit(struct vm_state *vm,
|
||||
int vm_load_unit(struct vm *vm,
|
||||
struct vm_unit_info *info,
|
||||
struct list_head *refs,
|
||||
const char *name);
|
||||
|
||||
+26
-12
@@ -10,8 +10,18 @@
|
||||
#define MAXARG 12
|
||||
#define MAXLOC 64
|
||||
|
||||
#define VM_SINGLESTEP (1 << 0)
|
||||
|
||||
struct vm_value;
|
||||
|
||||
enum vm_state {
|
||||
STATE_INIT = 0,
|
||||
STATE_RUNNING,
|
||||
STATE_BREAKPOINT,
|
||||
STATE_EXITED,
|
||||
STATE_ERROR
|
||||
};
|
||||
|
||||
static inline uint64_t encode_ref(struct vm_value *ref) {
|
||||
uintptr_t addr = (uintptr_t) ref;
|
||||
assert(!(addr & 1));
|
||||
@@ -22,29 +32,33 @@ static inline uint64_t encode_ref(struct vm_value *ref) {
|
||||
}
|
||||
}
|
||||
|
||||
struct vm_state {
|
||||
struct vm {
|
||||
struct stack data_stack;
|
||||
struct stack call_stack;
|
||||
|
||||
struct vector units;
|
||||
size_t bp, lp, fp, ip;
|
||||
|
||||
uint32_t flags;
|
||||
|
||||
enum vm_state state;
|
||||
};
|
||||
|
||||
int vm_state_init(struct vm_state *vm, size_t stack_size);
|
||||
void vm_state_free(struct vm_state *vm);
|
||||
int vm_init(struct vm *vm, size_t stack_size);
|
||||
void vm_free(struct vm *vm);
|
||||
|
||||
struct vm_unit *vm_add_unit(struct vm_state *vm, size_t stack_size);
|
||||
struct vm_unit *vm_add_unit(struct vm *vm, size_t stack_size);
|
||||
|
||||
// Bytecode interpretation
|
||||
int vm_eval_step(struct vm_state *vm);
|
||||
int vm_eval_unit(struct vm_state *vm, size_t index);
|
||||
int vm_eval_step(struct vm *vm);
|
||||
int vm_eval_unit(struct vm *vm, size_t index);
|
||||
|
||||
// Stack operation
|
||||
int vm_pop(struct vm_state *vm, uint64_t *w);
|
||||
int vm_pop_integer(struct vm_state *vm, int64_t *v);
|
||||
int vm_pop(struct vm *vm, uint64_t *w);
|
||||
int vm_pop_integer(struct vm *vm, int64_t *v);
|
||||
|
||||
int vm_push_integer(struct vm_state *vm, int64_t v);
|
||||
int vm_push_bool(struct vm_state *vm, int v);
|
||||
int vm_push_ref(struct vm_state *vm, struct vm_value *obj);
|
||||
int vm_push_integer(struct vm *vm, int64_t v);
|
||||
int vm_push_bool(struct vm *vm, int v);
|
||||
int vm_push_ref(struct vm *vm, struct vm_value *obj);
|
||||
|
||||
uint64_t vm_get_arg(struct vm_state *vm, size_t index);
|
||||
uint64_t vm_get_arg(struct vm *vm, size_t index);
|
||||
|
||||
+2
-1
@@ -2,6 +2,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "vmstring.h"
|
||||
#include "vmstate.h"
|
||||
@@ -76,4 +77,4 @@ struct vm_value *vm_cons(uint64_t w0, uint64_t w1);
|
||||
struct vm_value *vm_makestr(const char *str);
|
||||
struct vm_value *vm_func(size_t lib_index, size_t fn_index);
|
||||
|
||||
void vm_print(uint64_t w);
|
||||
void vm_print(FILE *dst, uint64_t w);
|
||||
|
||||
@@ -12,14 +12,14 @@
|
||||
#include "vmstate.h"
|
||||
#include "vmval.h"
|
||||
|
||||
static int c_print(struct vm_state *vm) {
|
||||
static int c_print(struct vm *vm) {
|
||||
uint64_t w;
|
||||
int res;
|
||||
|
||||
if ((res = vm_pop(vm, &w)) != 0) {
|
||||
return res;
|
||||
}
|
||||
vm_print(w);
|
||||
vm_print(stdout, w);
|
||||
printf("\n");
|
||||
vm_unref(w);
|
||||
return 0;
|
||||
@@ -210,7 +210,7 @@ static int vm_load_exports(struct vm_unit_info *info,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vm_load_unit_file(struct vm_state *vm,
|
||||
int vm_load_unit_file(struct vm *vm,
|
||||
struct vm_unit_info *info,
|
||||
struct list_head *refs,
|
||||
FILE *fp) {
|
||||
@@ -251,7 +251,7 @@ int vm_load_unit_file(struct vm_state *vm,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vm_load_unit(struct vm_state *vm,
|
||||
int vm_load_unit(struct vm *vm,
|
||||
struct vm_unit_info *info,
|
||||
struct list_head *refs,
|
||||
const char *name) {
|
||||
|
||||
@@ -31,11 +31,11 @@ static int execute_file(const char *filename) {
|
||||
struct list_head unresolved;
|
||||
struct vm_export_entry *export;
|
||||
struct vm_ref_entry *ref_entry;
|
||||
struct vm_state vm;
|
||||
struct vm vm;
|
||||
struct vm_unit_info *info;
|
||||
struct vm_unresolved_ref *ref;
|
||||
|
||||
if ((res = vm_state_init(&vm, 4096)) != 0) {
|
||||
if ((res = vm_init(&vm, 4096)) != 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -112,11 +112,12 @@ static int execute_file(const char *filename) {
|
||||
hash_free(&unit_map);
|
||||
|
||||
// Start execution
|
||||
vm.state = STATE_RUNNING;
|
||||
if ((res = vm_eval_unit(&vm, 0)) != 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
vm_state_free(&vm);
|
||||
vm_free(&vm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ struct vm_func_entry *unit_add_function(struct vm_unit *u) {
|
||||
}
|
||||
|
||||
void unit_free(struct vm_unit *u) {
|
||||
printf("Release unit\n");
|
||||
struct vm_func_entry *func;
|
||||
|
||||
vector_free(&u->ref_table);
|
||||
|
||||
+5
-5
@@ -2,11 +2,11 @@
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
int vm_pop(struct vm_state *vm, uint64_t *w) {
|
||||
int vm_pop(struct vm *vm, uint64_t *w) {
|
||||
return stack_pop(&vm->data_stack, w);
|
||||
}
|
||||
|
||||
int vm_pop_integer(struct vm_state *vm, int64_t *v) {
|
||||
int vm_pop_integer(struct vm *vm, int64_t *v) {
|
||||
int res;
|
||||
uint64_t w;
|
||||
if ((res = stack_pop(&vm->data_stack, &w)) != 0) {
|
||||
@@ -22,11 +22,11 @@ int vm_pop_integer(struct vm_state *vm, int64_t *v) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vm_push_integer(struct vm_state *vm, int64_t v) {
|
||||
int vm_push_integer(struct vm *vm, int64_t v) {
|
||||
return stack_push(&vm->data_stack, v & ~FLAG_REF);
|
||||
}
|
||||
|
||||
int vm_push_bool(struct vm_state *vm, int v) {
|
||||
int vm_push_bool(struct vm *vm, int v) {
|
||||
if (v) {
|
||||
return stack_push(&vm->data_stack, 1);
|
||||
} else {
|
||||
@@ -34,6 +34,6 @@ int vm_push_bool(struct vm_state *vm, int v) {
|
||||
}
|
||||
}
|
||||
|
||||
int vm_push_ref(struct vm_state *vm, struct vm_value *obj) {
|
||||
int vm_push_ref(struct vm *vm, struct vm_value *obj) {
|
||||
return stack_push(&vm->data_stack, encode_ref(obj));
|
||||
}
|
||||
|
||||
+55
-19
@@ -1,3 +1,4 @@
|
||||
#include "debug.h"
|
||||
#include "error.h"
|
||||
#include "op.h"
|
||||
#include "unit.h"
|
||||
@@ -16,7 +17,7 @@ static inline int64_t sximm(uint32_t in) {
|
||||
}
|
||||
}
|
||||
|
||||
static int vm_push_context(struct vm_state *vm) {
|
||||
static int vm_push_context(struct vm *vm) {
|
||||
int res;
|
||||
if ((res = stack_push(&vm->call_stack, vm->bp)) != 0) {
|
||||
return res;
|
||||
@@ -33,7 +34,7 @@ static int vm_push_context(struct vm_state *vm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vm_pop_context(struct vm_state *vm) {
|
||||
static int vm_pop_context(struct vm *vm) {
|
||||
int res;
|
||||
if ((res = stack_pop(&vm->call_stack, &vm->ip)) != 0) {
|
||||
return res;
|
||||
@@ -50,7 +51,7 @@ static int vm_pop_context(struct vm_state *vm) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vm_state_init(struct vm_state *vm, size_t stack_size) {
|
||||
int vm_init(struct vm *vm, size_t stack_size) {
|
||||
int res;
|
||||
|
||||
if ((res = stack_init(&vm->data_stack, stack_size)) != 0) {
|
||||
@@ -62,6 +63,8 @@ int vm_state_init(struct vm_state *vm, size_t stack_size) {
|
||||
|
||||
vector_init(&vm->units, sizeof(struct vm_unit));
|
||||
|
||||
vm->state = STATE_INIT;
|
||||
vm->flags = 0;
|
||||
vm->lp = 0;
|
||||
vm->fp = 0;
|
||||
vm->ip = 0;
|
||||
@@ -69,7 +72,7 @@ int vm_state_init(struct vm_state *vm, size_t stack_size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vm_state_free(struct vm_state *vm) {
|
||||
void vm_free(struct vm *vm) {
|
||||
struct vm_unit *unit;
|
||||
stack_free(&vm->data_stack);
|
||||
stack_free(&vm->call_stack);
|
||||
@@ -80,7 +83,7 @@ void vm_state_free(struct vm_state *vm) {
|
||||
vector_free(&vm->units);
|
||||
}
|
||||
|
||||
struct vm_unit *vm_add_unit(struct vm_state *vm, size_t global_pool_size) {
|
||||
struct vm_unit *vm_add_unit(struct vm *vm, size_t global_pool_size) {
|
||||
struct vm_unit *unit = vector_append(&vm->units);
|
||||
if (!unit) {
|
||||
return unit;
|
||||
@@ -96,7 +99,7 @@ struct vm_unit *vm_add_unit(struct vm_state *vm, size_t global_pool_size) {
|
||||
}
|
||||
|
||||
// Call an entry from function table of a unit
|
||||
int vm_call_unit_index(struct vm_state *vm, size_t lib_index, size_t fn_index) {
|
||||
int vm_call_unit_index(struct vm *vm, size_t lib_index, size_t fn_index) {
|
||||
struct vm_func_entry *func;
|
||||
struct vm_unit *unit;
|
||||
int res;
|
||||
@@ -136,26 +139,26 @@ int vm_call_unit_index(struct vm_state *vm, size_t lib_index, size_t fn_index) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t *vm_local_ref(struct vm_state *vm, size_t index) {
|
||||
static uint64_t *vm_local_ref(struct vm *vm, size_t index) {
|
||||
// TODO index sanity checks
|
||||
// [bp - index - 1]
|
||||
++index;
|
||||
return &vm->call_stack.data[vm->bp - index];
|
||||
}
|
||||
|
||||
static uint64_t *vm_arg_ref(struct vm_state *vm, size_t index) {
|
||||
static uint64_t *vm_arg_ref(struct vm *vm, size_t index) {
|
||||
// [bp + index]
|
||||
return &vm->call_stack.data[vm->bp + index];
|
||||
}
|
||||
|
||||
int vm_call_ref(struct vm_state *vm, struct vm_value *ref) {
|
||||
int vm_call_ref(struct vm *vm, struct vm_value *ref) {
|
||||
if (ref->type != VT_FUNC) {
|
||||
return -ERR_OPERAND_TYPE;
|
||||
}
|
||||
return vm_call_unit_index(vm, ref->v_func.lib_index, ref->v_func.fn_index);
|
||||
}
|
||||
|
||||
static int vm_read_ext_ref(struct vm_state *vm, struct vm_ref_entry *ref, uint64_t *w) {
|
||||
static int vm_read_ext_ref(struct vm *vm, struct vm_ref_entry *ref, uint64_t *w) {
|
||||
struct vm_unit *unit;
|
||||
int res;
|
||||
unit = vector_ref(&vm->units, ref->unit_index);
|
||||
@@ -173,26 +176,29 @@ static int vm_read_ext_ref(struct vm_state *vm, struct vm_ref_entry *ref, uint64
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vm_eval_debug(struct vm_state *vm, struct vm_func_entry *func, uint32_t arg) {
|
||||
static int vm_eval_debug(struct vm *vm, struct vm_func_entry *func, uint32_t arg) {
|
||||
(void) func;
|
||||
uint64_t w0;
|
||||
int res;
|
||||
switch (arg) {
|
||||
case 0x01:
|
||||
case OP_DEBUG_TRACE:
|
||||
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
|
||||
return res;
|
||||
}
|
||||
printf("trace: ");
|
||||
vm_print(w0);
|
||||
vm_print(stdout, w0);
|
||||
printf("\n");
|
||||
vm_unref(w0);
|
||||
return 0;
|
||||
case OP_DEBUG_BREAKPOINT:
|
||||
vm->state = STATE_BREAKPOINT;
|
||||
return 0;
|
||||
default:
|
||||
return -ERR_OPCODE_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
int vm_eval_step(struct vm_state *vm) {
|
||||
int vm_eval_step(struct vm *vm) {
|
||||
uint64_t w0, w1;
|
||||
int64_t sw0, sw1;
|
||||
uint64_t *wr0;
|
||||
@@ -202,13 +208,16 @@ int vm_eval_step(struct vm_state *vm) {
|
||||
struct vm_value *v0;
|
||||
int res;
|
||||
|
||||
if (vm->state != STATE_RUNNING) {
|
||||
return -ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
assert(vm->lp < vm->units.size);
|
||||
struct vm_unit *unit = vector_ref(&vm->units, vm->lp);
|
||||
assert(vm->fp < unit->functions.size);
|
||||
struct vm_func_entry *func = vector_ref(&unit->functions, vm->fp);
|
||||
uint32_t opcode = func->bytecode[vm->ip++];
|
||||
|
||||
printf("%02zx:%02zx:%02zx: %08x\n", vm->lp, vm->fp, vm->ip, opcode);
|
||||
switch (opcode >> 24) {
|
||||
case OP_ADD:
|
||||
if ((res = vm_pop_integer(vm, &sw0)) != 0) {
|
||||
@@ -368,7 +377,7 @@ int vm_eval_step(struct vm_state *vm) {
|
||||
}
|
||||
r0 = vector_ref(&unit->ref_table, i0);
|
||||
if (r0->flags & REF_NATIVE) {
|
||||
int (*func) (struct vm_state *) = (void *) r0->ref_native;
|
||||
int (*func) (struct vm *) = (void *) r0->ref_native;
|
||||
if (!func) {
|
||||
return -ERR_OPERAND_TYPE;
|
||||
}
|
||||
@@ -447,8 +456,9 @@ int vm_eval_step(struct vm_state *vm) {
|
||||
}
|
||||
}
|
||||
|
||||
int vm_eval_unit(struct vm_state *vm, size_t index) {
|
||||
struct vm_unit *unit;
|
||||
int vm_eval_unit(struct vm *vm, size_t index) {
|
||||
struct vm_unit *unit, *curr_unit;
|
||||
struct vm_func_entry *curr_func;
|
||||
size_t csp;
|
||||
int res;
|
||||
|
||||
@@ -459,11 +469,37 @@ int vm_eval_unit(struct vm_state *vm, size_t index) {
|
||||
|
||||
// Run until return
|
||||
while (vm->call_stack.sp != csp) {
|
||||
if (vm->flags & VM_SINGLESTEP) {
|
||||
curr_unit = vector_ref(&vm->units, vm->lp);
|
||||
curr_func = vector_ref(&curr_unit->functions, vm->fp);
|
||||
|
||||
// Check if it's a breakpoint instruction and skip it
|
||||
if (curr_func->bytecode[vm->ip] == (uint32_t) OP(OP_DEBUG, OP_DEBUG_BREAKPOINT)) {
|
||||
++vm->ip;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((res = debug_breakpoint(vm)) != 0) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
if (vm->state == STATE_BREAKPOINT) {
|
||||
if ((res = debug_breakpoint(vm)) != 0) {
|
||||
return res;
|
||||
}
|
||||
vm->state = STATE_RUNNING;
|
||||
} else if (vm->state == STATE_ERROR) {
|
||||
res = -ERR_ERROR_EXIT;
|
||||
break;
|
||||
} else if (vm->state == STATE_EXITED) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((res = vm_eval_step(vm)) != 0) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
unit->is_loaded = 1;
|
||||
|
||||
return 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
+16
-16
@@ -3,51 +3,51 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void vm_print2(uint64_t w, int cdepth);
|
||||
static void vm_print2(FILE *fp, uint64_t w, int cdepth);
|
||||
|
||||
static void vm_print_ref(struct vm_value *value, int cdepth) {
|
||||
static void vm_print_ref(FILE *fp, struct vm_value *value, int cdepth) {
|
||||
uint64_t w0;
|
||||
if (!value) {
|
||||
printf("nil");
|
||||
fprintf(fp, "nil");
|
||||
return;
|
||||
}
|
||||
switch (value->type) {
|
||||
case VT_STRING:
|
||||
printf("\"%s\"", vm_cstr(&value->v_string));
|
||||
fprintf(fp, "\"%s\"", vm_cstr(&value->v_string));
|
||||
break;
|
||||
case VT_CONS:
|
||||
if (!cdepth) {
|
||||
printf("(");
|
||||
}
|
||||
vm_print2(value->v_cons.fat_ar, 0);
|
||||
vm_print2(fp, value->v_cons.fat_ar, 0);
|
||||
w0 = value->v_cons.fat_dr;
|
||||
if (!null_q(w0)) {
|
||||
printf(" ");
|
||||
fprintf(fp, " ");
|
||||
if (cons_q(w0)) {
|
||||
vm_print2(w0, cdepth + 1);
|
||||
vm_print2(fp, w0, cdepth + 1);
|
||||
} else {
|
||||
printf(". ");
|
||||
vm_print2(w0, cdepth + 1);
|
||||
fprintf(fp, ". ");
|
||||
vm_print2(fp, w0, cdepth + 1);
|
||||
}
|
||||
}
|
||||
if (!cdepth) {
|
||||
printf(")");
|
||||
fprintf(fp, ")");
|
||||
}
|
||||
break;
|
||||
case VT_FUNC:
|
||||
printf("<function %zu:%zu>", value->v_func.lib_index, value->v_func.fn_index);
|
||||
fprintf(fp, "<function %zu:%zu>", value->v_func.lib_index, value->v_func.fn_index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void vm_print2(uint64_t w, int cdepth) {
|
||||
static void vm_print2(FILE *fp, uint64_t w, int cdepth) {
|
||||
if (w & FLAG_REF) {
|
||||
vm_print_ref((void *) (w << 1), cdepth);
|
||||
vm_print_ref(fp, (void *) (w << 1), cdepth);
|
||||
} else {
|
||||
if (w & (1ULL << 62)) {
|
||||
w |= 1ULL << 63;
|
||||
}
|
||||
printf("%ld", (int64_t) w);
|
||||
fprintf(fp, "%ld", (int64_t) w);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +131,6 @@ struct vm_value *vm_func(size_t lib_index, size_t fn_index) {
|
||||
return v;
|
||||
}
|
||||
|
||||
void vm_print(uint64_t w) {
|
||||
vm_print2(w, 0);
|
||||
void vm_print(FILE *fp, uint64_t w) {
|
||||
vm_print2(fp, w, 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user