diff --git a/src/assembler/asm.c b/src/assembler/asm.c index e5ed2447..e77067a5 100644 --- a/src/assembler/asm.c +++ b/src/assembler/asm.c @@ -86,6 +86,7 @@ static const DstInstructionDef dst_ops[] = { {"call", DOP_CALL}, {"clo", DOP_CLOSURE}, {"cmp", DOP_COMPARE}, + {"debug", DOP_DEBUG}, {"div", DOP_DIVIDE}, {"divim", DOP_DIVIDE_IMMEDIATE}, {"divi", DOP_DIVIDE_INTEGER}, diff --git a/src/core/bytecode.c b/src/core/bytecode.c index b199ce15..7dc5996e 100644 --- a/src/core/bytecode.c +++ b/src/core/bytecode.c @@ -85,7 +85,8 @@ enum DstInstructionType dst_instructions[DOP_INSTRUCTION_COUNT] = { DIT_SSS, /* DOP_PUT, */ DIT_SSU, /* DOP_GET_INDEX, */ DIT_SSU, /* DOP_PUT_INDEX, */ - DIT_SS /* DOP_LENGTH */ + DIT_SS, /* DOP_LENGTH */ + DIT_0 /* DOP_DEBUG */ }; /* Verify some bytecode */ diff --git a/src/core/corelib.c b/src/core/corelib.c index 80b5d84c..959ffedd 100644 --- a/src/core/corelib.c +++ b/src/core/corelib.c @@ -192,6 +192,9 @@ int dst_core_fiber_status(DstArgs args) { case DST_FIBER_ERROR: status = ":error"; break; + case DST_FIBER_DEBUG: + status = ":debug"; + break; } return dst_return(args, dst_csymbolv(status)); } diff --git a/src/core/fiber.c b/src/core/fiber.c index f6971a5f..4bab1ef0 100644 --- a/src/core/fiber.c +++ b/src/core/fiber.c @@ -38,6 +38,7 @@ DstFiber *dst_fiber(int32_t capacity) { } fiber->parent = NULL; fiber->maxstack = DST_STACK_MAX; + fiber->flags = DST_FIBER_MASK_DEBUG; return dst_fiber_reset(fiber); } diff --git a/src/core/vm.c b/src/core/vm.c index 451fab68..4e172e07 100644 --- a/src/core/vm.c +++ b/src/core/vm.c @@ -30,19 +30,16 @@ DstFiber *dst_vm_fiber = NULL; int dst_vm_stackn = 0; /* Helper to ensure proper fiber is activated after returning */ -static int dst_update_fiber() { +static int dst_update_fiber(uint32_t mask) { if (dst_vm_fiber->frame == 0) { dst_vm_fiber->status = DST_FIBER_DEAD; } while (dst_vm_fiber->status == DST_FIBER_DEAD || - dst_vm_fiber->status == DST_FIBER_ERROR) { + dst_vm_fiber->status == DST_FIBER_ERROR || + dst_vm_fiber->status == DST_FIBER_DEBUG || + dst_vm_fiber->flags & mask) { if (NULL != dst_vm_fiber->parent) { dst_vm_fiber = dst_vm_fiber->parent; - if (dst_vm_fiber->status == DST_FIBER_ALIVE) { - /* If the parent thread is still alive, - we are inside a cfunction */ - return 1; - } } else { /* The root thread has terminated */ return 1; @@ -139,6 +136,7 @@ static void *op_lookup[255] = { &&label_DOP_GET_INDEX, &&label_DOP_PUT_INDEX, &&label_DOP_LENGTH, + &&label_DOP_DEBUG, &&label_unknown_op }; #else @@ -204,16 +202,13 @@ static void *op_lookup[255] = { vm_init_fiber_state(); - /* Main interpreter loop. It is large, but it is - * is maintainable. Adding new opcodes is mostly just adding newcases - * to this loop, adding the opcode to opcodes.h, and adding it to the assembler. - * Some opcodes, especially ones that do arithmetic, are almost entirely - * templated by the above macros. */ + /* Main interpreter loop. Sematically is a switch on + * (*pc & 0xFF) inside of an infinte loop. */ VM_START(); VM_DEFAULT(); - retreg = dst_wrap_string(dst_formatc("unknown opcode %d", *pc & 0xFF)); - goto vm_error; + VM_OP(DOP_DEBUG) + goto vm_debug; VM_OP(DOP_NOOP) pc++; @@ -707,60 +702,78 @@ static void *op_lookup[255] = { vm_return_cfunc: { dst_fiber_popframe(dst_vm_fiber); - if (dst_update_fiber()) { - *returnreg = retreg; - dst_vm_stackn--; - return 0; - } + if (dst_update_fiber(DST_FIBER_MASK_RETURN)) goto vm_exit_value; stack = dst_vm_fiber->data + dst_vm_fiber->frame; stack[oparg(1, 0xFF)] = retreg; pc++; vm_checkgc_next(); } + /* Return from a cfunction that is in tail position (pop 2 stack frames) */ vm_return_cfunc_tail: { dst_fiber_popframe(dst_vm_fiber); - if (dst_update_fiber()) { - *returnreg = retreg; - dst_vm_stackn--; - return 0; - } - /* Fall through to normal return */ + if (dst_update_fiber(DST_FIBER_MASK_RETURN)) goto vm_exit_value; + goto vm_return; } /* Handle returning from stack frame. Expect return value in retreg */ vm_return: { dst_fiber_popframe(dst_vm_fiber); - if (dst_update_fiber()) { - *returnreg = retreg; - dst_vm_stackn--; - return 0; - } - stack = dst_vm_fiber->data + dst_vm_fiber->frame; - func = dst_stack_frame(stack)->func; - pc = dst_stack_frame(stack)->pc; - stack[oparg(1, 0xFF)] = retreg; - pc++; - vm_checkgc_next(); + if (dst_update_fiber(DST_FIBER_MASK_RETURN)) goto vm_exit_value; + goto vm_reset; } /* Handle errors from c functions and vm opcodes */ vm_error: { dst_vm_fiber->status = DST_FIBER_ERROR; - if (dst_update_fiber()) { - *returnreg = retreg; - dst_vm_stackn--; - return 1; - } + if (dst_update_fiber(DST_FIBER_MASK_ERROR)) goto vm_exit_error; + goto vm_reset; + } + + /* Handle debugger interrupts */ + vm_debug: + { + dst_vm_fiber->status = DST_FIBER_DEBUG; + if (dst_update_fiber(DST_FIBER_MASK_DEBUG)) goto vm_exit_debug; + goto vm_reset; + } + + /* Reset state of machine */ + vm_reset: + { stack = dst_vm_fiber->data + dst_vm_fiber->frame; func = dst_stack_frame(stack)->func; pc = dst_stack_frame(stack)->pc; stack[oparg(1, 0xFF)] = retreg; pc++; vm_checkgc_next(); + } + + /* Exit loop with return value */ + vm_exit_value: + { + *returnreg = retreg; + dst_vm_stackn--; + return 0; + } + + /* Exit loop with error value */ + vm_exit_error: + { + *returnreg = retreg; + dst_vm_stackn--; + return 1; + } + + /* Exit loop with debug */ + vm_exit_debug: + { + *returnreg = dst_wrap_nil(); + dst_vm_stackn--; + return 2; } VM_END() diff --git a/src/include/dst/dstopcodes.h b/src/include/dst/dstopcodes.h index 1a68794d..4a5d2cec 100644 --- a/src/include/dst/dstopcodes.h +++ b/src/include/dst/dstopcodes.h @@ -118,6 +118,7 @@ enum DstOpCode { DOP_GET_INDEX, DOP_PUT_INDEX, DOP_LENGTH, + DOP_DEBUG, DOP_INSTRUCTION_COUNT }; diff --git a/src/include/dst/dsttypes.h b/src/include/dst/dsttypes.h index ba610524..f5abfbf7 100644 --- a/src/include/dst/dsttypes.h +++ b/src/include/dst/dsttypes.h @@ -305,6 +305,11 @@ struct DstArgs { Dst *ret; }; +/* Fiber signal masks */ +#define DST_FIBER_MASK_RETURN 1 +#define DST_FIBER_MASK_ERROR 2 +#define DST_FIBER_MASK_DEBUG 4 + /* A lightweight green thread in dst. Does not correspond to * operating system threads. */ struct DstFiber { @@ -315,12 +320,14 @@ struct DstFiber { int32_t stacktop; /* Top of stack. Where values are pushed and popped from. */ int32_t capacity; int32_t maxstack; /* Arbitrary defined limit for stack overflow */ + uint32_t flags; /* Various flags */ enum { DST_FIBER_PENDING, DST_FIBER_NEW, DST_FIBER_ALIVE, DST_FIBER_DEAD, - DST_FIBER_ERROR + DST_FIBER_ERROR, + DST_FIBER_DEBUG } status; };