VM_Code code;
uint memoize;
uint unroll;
+ uint line;
+ bool debug;
};
struct Emitter_ {
#define __GWI
#ifdef GWION_DOC
-#include "lint.h"
+#include "gwfmt.h"
#define gwiheader(a,...) do { lint_nl(a->lint); lint_indent(a->lint); lint(a->lint, "{-}#!+ {/}%s{0}\n", __VA_ARGS__); } while(0)
#define gwidoc(a,...) do { lint_nl(a->lint); lint_indent(a->lint); lint(a->lint, "{-}#!- {/}%s{0}\n", __VA_ARGS__); } while(0)
#define gwinote(a,...) do { lint_indent(a->lint); lint(a->lint, "{-}#!- {/}%s{0}\n", __VA_ARGS__); } while(0)
const Value v = nspc_lookup_value1(t->info->value->from->owner, insert_symbol(gwion->st, t->name));
return v->type;
}
+
+ANN void gwion_set_debug(const Gwion gwion, const bool dbg);
#endif
eHandleEffect,
ePerformEffect,
eNoOp,
+ eDebugLine,
+ eDebugValue,
+ eDebugPush,
+ eDebugPop,
eEOC,
eUnroll2,
eOP_MAX,
#define HandleEffect (f_instr)eHandleEffect
#define PerformEffect (f_instr)ePerformEffect
#define NoOp (f_instr)eNoOp
+#define DebugLine (f_instr)eDebugLine
+#define DebugValue (f_instr)eDebugValue
+#define DebugPush (f_instr)eDebugPush
+#define DebugPop (f_instr)eDebugPop
#define EOC (f_instr)eEOC
#define Unroll2 (f_instr)eUnroll2
#define OP_MAX (f_instr)eOP_MAX
struct VM_Code_ {
m_bit *bytecode;
union {
- Vector instr;
+ struct Vector_ instr;
m_uint native_func;
};
size_t stack_depth;
typedef struct Emitter_ * Emitter;
typedef struct VM_Shred_* VM_Shred;
+typedef struct Debugger_ {
+ struct Vector_ breakpoint;
+ Nspc nspc;
+ bool step;
+} Debugger;
+
typedef struct VM_ {
Shreduler shreduler;
struct Vector_ ugen;
struct Gwion_* gwion;
VM_Shred cleaner_shred;
struct VM_ *parent;
+ Debugger debugger;
uint32_t rand[2];
} VM;
-
struct ShredInfo_ {
VM* vm;
struct M_Object_* me;
- m_str name;
Vector args;
MemPool mp;
VM_Code orig;
struct Vector_ frame;
+ struct Vector_ line;
};
struct ShredTick_ {
-Subproject commit 27eb025e264a6251f595c0177b51ee58987324f5
+Subproject commit 9a2bcfb85e5ca94cc6f2697f5a41c09c1c18db3f
HandleEffect
PerformEffect
NoOp
+DebugLine
+DebugValue
+DebugPush
+DebugPop
EOC
Unroll2
OP_MAX
DRIVER, SRATE, NINPUT, NOUTPUT,
// pp options
DEFINE, UNDEF, INCLUDE,
+ DEBUG,
NOPTIONS
};
ARG_STDIN,
ARG_DEFINE,
ARG_UNDEF,
- ARG_INCLUDE
+ ARG_INCLUDE,
+ ARG_DEBUG
};
ANN static void arg_init(Arg* arg) {
vector_release(&arg->config);
}
+static inline bool _get_debug(const m_str dbg) {
+ if(!dbg || !strcmp(dbg, "true"))
+ return true;
+ if(!strcmp(dbg, "false"))
+ return false;
+ return atoi(dbg) ? true : false;
+}
+
+ANN static inline void get_debug(const Gwion gwion, const m_str dbg) {
+ const bool is_dbg = _get_debug(dbg);
+ gwion_set_debug(gwion, is_dbg);
+}
+
ANN void arg_compile(const Gwion gwion, Arg *arg) {
const Vector v = &arg->add;
for(m_uint i = 0; i < vector_size(v); i++) {
case ARG_INCLUDE:
pparg_inc(gwion->ppa, (m_str)VPTR(v, ++i));
break;
+ case ARG_DEBUG:
+ get_debug(gwion, (m_str)VPTR(v, ++i));
+ break;
}
}
}
CMDOPT_TAKESARG, NULL,
"add ARG to include path", &opt[INCLUDE]
);
+ cmdapp_set(app,
+ 'G', "debug",
+ CMDOPT_MAYTAKEARG, NULL,
+ "set/unset debug mode", &opt[DEBUG]
+ );
}
static inline void add2arg(Arg *const arg, const char *data, const enum arg_type type) {
case 'I':
add2arg(_arg, option->value, ARG_INCLUDE);
break;
+// debug
+ case 'G':
+ add2arg(_arg, option->value, ARG_DEBUG);
+ break;
}
}
}
return env_push_global(emit->env);
}
+static inline void emit_debug(const Emitter emit, const Value v) {
+ if(!emit->info->debug)
+ return;
+ const Instr instr = emit_add_instr(emit, DebugValue);
+ instr->m_val = (m_uint)v;
+}
+
ANEW static Frame* new_frame(MemPool p) {
Frame* frame = mp_calloc(p, Frame);
vector_init(&frame->stack);
instr->m_val = (m_uint)offset;
}
vector_pop(&emit->info->pure);
+ if(emit->info->debug)
+ emit_add_instr(emit, DebugPop);
}
ANN static inline void emit_push_code(const Emitter emit, const m_str name) {
vector_add(&emit->stack, (vtype)emit->code);
emit->code = new_code(emit, name);
+ if(emit->info->debug)
+ emit_add_instr(emit, DebugLine);
}
ANN static inline void emit_pop_code(const Emitter emit) {
ANN static inline void emit_push_scope(const Emitter emit) {
frame_push(emit->code->frame);
vector_add(&emit->info->pure, 0);
+ if(emit->info->debug)
+ emit_add_instr(emit, DebugPush);
}
ANN static inline m_uint emit_code_size(const Emitter emit) {
f_instr *exec = (f_instr*)allocmember;
if(!vflag(v, vflag_member)) {
v->from->offset = emit_local(emit, type);
+ emit_debug(emit, v);
exec = (f_instr*)(allocword);
if(GET_FLAG(v, late)) { // ref or emit_var ?
const Instr clean = emit_add_instr(emit, MemSetImm);
DECL_EXP_FUNC(emit, m_bool, Emitter)
-
ANN2(1) /*static */m_bool emit_exp(const Emitter emit, /* const */Exp e) {
Exp exp = e;
do {
+ if(emit->info->debug && emit->info->line < e->pos.first.line) {
+ const Instr instr = emit_add_instr(emit, DebugLine);
+ instr->m_val = emit->info->line = e->pos.first.line;
+ }
CHECK_BB(emit_exp_func[exp->exp_type](emit, &exp->d));
if(exp->cast_to)
CHECK_BB(emit_implicit_cast(emit, exp, exp->cast_to));
}
ANN static m_bool emit_stmt_code(const Emitter emit, const Stmt_Code stmt) {
+ emit_push_scope(emit);
++emit->env->scope->depth;
const m_bool ret = stmt->stmt_list ? emit_stmt_list(emit, stmt->stmt_list) : 1;
+ emit_pop_scope(emit);
--emit->env->scope->depth;
return ret;
}
loop_idx->m_val = offset + SZ_INT;
loop_idx->m_val2 = -1;
stmt->v->from->offset = offset + SZ_INT *2;
+ emit_debug(emit, stmt->v);
if(stmt->idx)
stmt->idx->v->from->offset = offset + SZ_INT;
if(n) {
ANN static m_bool case_value(const Emitter emit, const Exp base, const Exp e) {
const Value v = e->d.prim.value;
v->from->offset = emit_local(emit, base->type);
+ emit_debug(emit, v);
const Instr instr = emit_add_instr(emit, Reg2Mem4);
instr->m_val = v->from->offset;
instr->m_val2 = base->type->size;
const Type type = a->var_decl->value->type;
emit->code->stack_depth += type->size;
a->var_decl->value->from->offset = emit_localn(emit, type);
+ emit_debug(emit, a->var_decl->value);
} while((a = a->next));
}
nspc_remref(gwion->env->global_nspc, gwion);
return gwion->env->curr = gwion->env->global_nspc = nspc;
}
+
+ANN void gwion_set_debug(const Gwion gwion, const bool dbg) {
+ gwion->emit->info->debug = dbg;
+}
aai.data = init_array(shred, info, &num_obj);
const M_Object ref = do_alloc_array(shred, &aai);
if(!ref) {
- gw_err("[Gwion](VM): (note: in shred[id=%" UINT_F ":%s])\n", shred->tick->xid, shred->info->name);
+ gw_err("[Gwion](VM): (note: in shred[id=%" UINT_F ":%s])\n", shred->tick->xid, shred->code->name);
vm_shred_exit(shred);
return; // TODO make exception vararg
}
ANN static void code_prepare(const VM_Code code) {
m_bit *byte = code->bytecode;
- for(m_uint i = 0; i < vector_size(code->instr); ++i) {
+ for(m_uint i = 0; i < vector_size(&code->instr); ++i) {
if(*(m_bit*)(byte + i *BYTECODE_SZ) == eFuncReturn) {
*(m_bit*)(byte + i * BYTECODE_SZ)= eOP_MAX;
*(f_instr*)(byte + (i*BYTECODE_SZ) + SZ_INT*2) = UURet;
const m_str str = code_name((src), 0); \
*(m_uint*)RETURN = (m_uint)new_string(shred->info->mp, shred, str); \
}
-describe_name(, s->info->name)
+describe_name(, s->info->orig->name)
describe_name(_code, s->code->name)
#define describe_path_and_dir(name, src) \
}\
*(m_uint*)RETURN = (m_uint)new_string(shred->info->mp, shred, c); \
}
-describe_path_and_dir(, s->info->name)
+describe_path_and_dir(, s->info->orig->name)
describe_path_and_dir(_code, s->code->name)
static DTOR(shred_dtor) {
return ret;
}
-ANN static bool unwind(VM_Shred shred, const Symbol effect) {
- if(!shred->info->frame.ptr || !vector_size(&shred->info->frame))
+ANN static inline void shred_unwind(VM_Shred shred) {
+ shred->pc = *(m_uint*) (shred->mem - SZ_INT * 2);
+ shred->code = *(VM_Code*)(shred->mem - SZ_INT * 3);
+ shred->mem -= (*(m_uint*)(shred->mem - SZ_INT * 4) + SZ_INT * 4);
+}
+
+ANN static bool unwind(VM_Shred shred, const Symbol effect, const m_uint size) {
+ if(!size)
return true;
if(shred->code->handlers.ptr) {
- const m_uint start = VKEY(&shred->info->frame, VLEN(&shred->info->frame) - 1);
+ const m_uint start = VKEY(&shred->info->frame, size - 1);
if(start > shred->pc)
return true;
const Map m = &shred->code->handlers;
break;
if(start < shred->pc && VKEY(m, i) > shred->pc) {
const m_uint next = VKEY(m, i);
- const Instr instr = (Instr)vector_at(shred->code->instr, next + 1);
+ const Instr instr = (Instr)vector_at(&shred->code->instr, next + 1);
if(!instr->m_val2 || (Symbol)instr->m_val2 == effect) {
pc = next + 1;
break;
shred->reg = (m_bit*)VPTR(&shred->info->frame, VLEN(&shred->info->frame) - 1);
shredule(shred->tick->shreduler, shred, 0);
shred->pc = pc;//VKEY(m, i);
+ // should we pop?
+ VLEN(&shred->info->frame) = size;
return false;
}
// there might be no more stack to unwind
- vector_pop(&shred->info->frame);
- vector_pop(&shred->info->frame);
if(shred->mem == (m_bit*)shred + sizeof(struct VM_Shred_) + SIZEOF_REG)
return true;
- // literally unwind
- shred->pc = *(m_uint*) (shred->mem - SZ_INT * 2);
- shred->code = *(VM_Code*)(shred->mem - SZ_INT * 3);
- shred->mem -= (*(m_uint*)(shred->mem - SZ_INT * 4) + SZ_INT * 4);
- return unwind(shred, effect);
+ shred_unwind(shred);
+ return unwind(shred, effect, size - 2);
+}
+
+ANN static void trace(VM_Shred shred, const m_uint size) {
+ const m_uint line = vector_at(&shred->info->line, size-1);
+ m_uint i;
+ for(i = size; --i;) {
+ if(VPTR(&shred->info->line, i-1))
+ break;
+ }
+ loc_t loc = {.first={.line=line, .column=1},.last={.line=line, .column=1}};
+ gw_err(" {-B}┃{0} in function {+}%s{0}{-}:{0}\n", shred->code->name);
+ gwerr_secondary("called from here", code_name(shred->code->name, true), loc);
+ if(shred->mem == (m_bit*)shred + sizeof(struct VM_Shred_) + SIZEOF_REG)
+ return;
+ shred_unwind(shred);
+ trace(shred, i);
}
ANN void handle(VM_Shred shred, const m_str effect) {
- // remove from the shreduler
- // TODO: get shred->mem and shred->reg offsets
+ m_bit *const reg = shred->reg;
+ m_bit *const mem = shred->mem;
+ const m_uint size = shred->info->frame.ptr ?
+ vector_size(&shred->info->frame) : 0;
+ const VM_Code code = shred->code;
shreduler_remove(shred->tick->shreduler, shred, false);
- // do the unwiding
- if(unwind(shred, insert_symbol(shred->info->vm->gwion->st, effect))) {
- vm_shred_exit(shred);
- gw_err("{-C}shred{W}[{Y}% 5" UINT_F "{W}]{-}: {-R}Unhandled {+R}%s{0}\n", shred->tick->xid, effect);
+ if(!unwind(shred, insert_symbol(shred->info->vm->gwion->st, effect), size))
+ return;
+ gw_err("{-C}shred{W}[{Y}% 5" UINT_F "{W}]{-}: {-R}Unhandled {+R}%s{0}\n", shred->tick->xid, effect);
+ if(shred->info->line.ptr) { // trace if available
+ shred->reg = reg;
+ shred->mem = mem;
+ shred->code = code;
+ trace(shred, vector_size(&shred->info->line));
}
- // I guess the VM could have *trace mode*
- // which would happen here from the top
+ vm_shred_exit(shred);
}
&&upvalueint, &&upvaluefloat, &&upvalueother, &&upvalueaddr,
&&dotfunc,
&&gcini, &&gcadd, &&gcend,
- &&gacktype, &&gackend, &&gack, &&try_ini, &&try_end, &&handleeffect, &&performeffect, &&noop, &&eoc, &&unroll2, &&other, &®pushimm
+ &&gacktype, &&gackend, &&gack, &&try_ini, &&try_end, &&handleeffect, &&performeffect, &&noop,
+ &&debugline, &&debugvalue, &&debugpush, &&debugpop,
+ &&eoc, &&unroll2, &&other, &®pushimm
};
const Shreduler s = vm->shreduler;
register VM_Shred shred;
// this should check the *xid* of the exception
DISPATCH();
performeffect:
+ VM_OUT
handle(shred, (m_str)VAL);
break;
-// this should check the *xid* of the exception
noop:
DISPATCH();
other:
reg = shred->reg;
mem = shred->mem;
PC_DISPATCH(shred->pc)
+debugline:
+ if(!shred->info->line.ptr) {// from a problem with spork it seems
+ vector_init(&shred->info->line);
+ vector_add(&shred->info->line, VAL);
+ } else if(!VAL) {
+ vector_add(&shred->info->line, VAL);
+ } else {
+ const m_uint sz = vector_size(&shred->info->line);
+ vector_set(&shred->info->line, sz - 1, VAL);
+ }
+ DISPATCH();
+debugvalue:
+ DISPATCH();
+debugpush:
+ if(!shred->info->line.ptr)
+ vector_init(&shred->info->line);
+ vector_add(&shred->info->line, 0);
+ DISPATCH();
+debugpop:
+ vector_pop(&shred->info->line);
+ DISPATCH();
eoc:
VM_OUT
vm_shred_exit(shred);
ANN void free_vmcode(VM_Code a, Gwion gwion) {
if(!a->builtin) {
- _mp_free(gwion->mp, vector_size(a->instr) * BYTECODE_SZ, a->bytecode);
+ _mp_free(gwion->mp, vector_size(&a->instr) * BYTECODE_SZ, a->bytecode);
if(likely(!a->callback)) {
if(a->closure) {
if(!a->is_memoize)
else
memoize_end(gwion->mp, a->memoize);
}
- free_code_instr(a->instr, gwion);
+ free_code_instr(&a->instr, gwion);
}
if(a->handlers.ptr)
map_release(&a->handlers);
- free_vector(gwion->mp, a->instr);
+ vector_release(&a->instr);
}
free_mstr(gwion->mp, a->name);
mp_free(gwion->mp , VM_Code, a);
}
ANN static m_bit* tobytecode(MemPool p, const VM_Code code) {
- const Vector v = code->instr;
+ const Vector v = &code->instr;
const m_uint sz = vector_size(v);
m_bit *ptr = _mp_malloc(p, sz * BYTECODE_SZ);
struct Vector_ nop;
VM_Code code = mp_calloc(p, VM_Code);
code->name = mstrdup(p, name);
if(instr) {
- code->instr = vector_copy(p, instr);
+// code->instr = vector_copy(p, instr);
+ vector_init(&code->instr);
+ vector_copy2(instr, &code->instr);
code->bytecode = tobytecode(p, code);
}
code->stack_depth = stack_depth;
VM_Code vmcode_callback(MemPool mp, VM_Code base) {
char name[strlen(base->name) + 11];
sprintf(name, "%s(callback)", base->name);
- const Instr instr = (Instr)vector_back(base->instr);
+ const Instr instr = (Instr)vector_back(&base->instr);
instr->opcode = eEOC;
- VM_Code code = new_vmcode(mp, base->instr, base->stack_depth, base->builtin, name);
+ VM_Code code = new_vmcode(mp, &base->instr, base->stack_depth, base->builtin, name);
code->closure = base->closure;
code->callback = 1;
instr->opcode = eFuncReturn;
char d[SIZEOF_MEM];
};
-static inline struct ShredInfo_ *new_shredinfo(MemPool p, const m_str name) {
+static inline struct ShredInfo_ *new_shredinfo(MemPool p, const VM_Code c) {
struct ShredInfo_ *info = mp_calloc(p, ShredInfo);
info->mp = p;
- info->name = mstrdup(p, name);
+ info->orig = c;
return info;
}
static inline void free_shredinfo(MemPool mp, struct ShredInfo_ *info) {
- free_mstr(mp, info->name);
- if(info->args) {
+ if(info->args) { // could be a struct
const Vector v = info->args;
LOOP_OPTIM
for(m_uint i = vector_size(v) + 1; --i;)
xfree((void*)vector_at(v, i - 1));
free_vector(mp, v);
}
+ if(info->line.ptr)
+ vector_release(&info->line);
mp_free(mp, ShredInfo, info);
}
shred->code = c;
shred->reg = (m_bit*)shred + sizeof(struct VM_Shred_);
shred->base = shred->mem = shred->reg + SIZEOF_REG;
- shred->info = new_shredinfo(p, c->name);
- shred->info->orig = c;
+ shred->info = new_shredinfo(p, c);
vector_init(&shred->gc);
return shred;
}