From: Jérémie Astor Date: Wed, 21 Apr 2021 23:18:44 +0000 (+0200) Subject: :wrench: Introduce perform X-Git-Tag: nightly~728 X-Git-Url: http://10.10.0.4:5575/?a=commitdiff_plain;h=7855dea8301c1db73fcb2418649d1e41eba1e482;p=gwion.git :wrench: Introduce perform --- diff --git a/ast b/ast index 742af1c3..039b3761 160000 --- a/ast +++ b/ast @@ -1 +1 @@ -Subproject commit 742af1c3723d56bef451ca480904689927ac7f7f +Subproject commit 039b37610ecc8f3ed162e6a9f7a20b1612109dea diff --git a/include/opcode.h b/include/opcode.h index 77410da2..fab83001 100644 --- a/include/opcode.h +++ b/include/opcode.h @@ -186,6 +186,7 @@ enum { eTryIni, eTryEnd, eHandleEffect, + ePerformEffect, eNoOp, eEOC, eUnroll2, @@ -378,6 +379,7 @@ enum { #define TryIni (f_instr)eTryIni #define TryEnd (f_instr)eTryEnd #define HandleEffect (f_instr)eHandleEffect +#define PerformEffect (f_instr)ePerformEffect #define NoOp (f_instr)eNoOp #define EOC (f_instr)eEOC #define Unroll2 (f_instr)eUnroll2 diff --git a/include/vm.h b/include/vm.h index 1911d73e..3e3b8cf2 100644 --- a/include/vm.h +++ b/include/vm.h @@ -107,4 +107,5 @@ ANN m_str code_name_set(MemPool p, const m_str, const m_str); ANN m_str code_name(const m_str, const bool); ANN uint32_t gw_rand(uint32_t s[2]); ANN void gw_seed(uint32_t s[2], const uint64_t); +ANN void handle(VM_Shred shred, const m_str effect); #endif diff --git a/plug b/plug index 035fcc8a..cef9b411 160000 --- a/plug +++ b/plug @@ -1 +1 @@ -Subproject commit 035fcc8a3deddce84a262b4bfee2360dc8bfbfbc +Subproject commit cef9b411504a524d73b2e282de45bbd30fd22751 diff --git a/src/emit/emit.c b/src/emit/emit.c index baad0e3f..21874c26 100644 --- a/src/emit/emit.c +++ b/src/emit/emit.c @@ -630,6 +630,12 @@ ANN static m_bool emit_prim_id(const Emitter emit, const Symbol *data) { return emit_symbol(emit, prim_self(data)); } +ANN static m_bool emit_prim_perform(const Emitter emit, const Symbol *xid) { + const Instr instr = emit_add_instr(emit, PerformEffect); + instr->m_val = (m_uint)s_name(*xid); + return GW_OK; +} + ANN static m_bool emit_prim_num(const Emitter emit, const m_uint *num) { regpushi(emit, *num); return GW_OK; diff --git a/src/lib/array.c b/src/lib/array.c index 27134307..92f7b4a8 100644 --- a/src/lib/array.c +++ b/src/lib/array.c @@ -329,7 +329,7 @@ static INSTR(ArraySlice) { const m_int op = start < end ? 1 : -1; const m_uint sz = op > 0 ? end - start : start - end; if(bounds(in, start) < 0 || bounds(in, end) < 0) - Except(shred, "OutOfBoundsArraySliceException"); + handle(shred, "OutOfBoundsArraySliceException"); const M_Object out = new_array(shred->info->vm->gwion->mp, array->type_ref, sz); for(m_int i = start, j = 0; i != end; i += op, ++j) { m_bit buf[ARRAY_SIZE(in)]; diff --git a/src/lib/engine.c b/src/lib/engine.c index e1c8260e..5525687c 100644 --- a/src/lib/engine.c +++ b/src/lib/engine.c @@ -75,7 +75,7 @@ static OP_CHECK(opck_basic_ctor) { static INSTR(PredicateCheck) { if(!*(m_uint*)REG(-SZ_INT)) - Except(shred, "predicate failed"); + handle(shred, "predicate failed"); } ANN static m_bool import_core_libs(const Gwi gwi) { diff --git a/src/lib/instr.c b/src/lib/instr.c index a8b91321..cd362e7f 100644 --- a/src/lib/instr.c +++ b/src/lib/instr.c @@ -56,7 +56,7 @@ INSTR(GTmpl) { struct dottmpl_ *dt = (struct dottmpl_*)instr->m_val; const Func f = *(Func*)REG(-SZ_INT); if(!f) - Except(shred, _("EmptyFuncPointerException")); + handle(shred, "EmptyFuncPointerException"); if(f->code) { *(VM_Code*)(shred->reg -SZ_INT) = f->code; return; @@ -81,7 +81,7 @@ if(f->code) { dt->def = f->def; const Func_Def def = traverse_tmpl(emit, dt, f->value_ref->from->owner); if(!def) - Except(shred, "MissigTmplPtrException[internal]"); + handle(shred, "MissigTmplPtrException"); *(VM_Code*)(shred->reg -SZ_INT) = def->base->func->code; } @@ -115,7 +115,7 @@ INSTR(DotTmpl) { return; } } while((t = t->info->parent)); - Except(shred, "MissigTmplException[internal]"); + handle(shred, "MissigTmplException"); } #define VAL (*(m_uint*)(byte + SZ_INT)) diff --git a/src/lib/modules.c b/src/lib/modules.c index cd94424a..92cd7ee4 100644 --- a/src/lib/modules.c +++ b/src/lib/modules.c @@ -248,14 +248,14 @@ static INSTR(UsrUGenTick) { shred->reg -= SZ_INT*2 - offset; const M_Object o = *(M_Object*)(shred->reg + SZ_INT - offset); if(!o) - Except(shred, "[NullPtrException]"); + handle(shred, "NullPtrException"); struct UUGen_ *uu = UGEN(o)->module.gen.data; if(uu->shred) free_vm_shred(uu->shred); UGEN(o)->module.gen.tick = usrugen_tick; const VM_Code code = *(VM_Code*)(shred->reg-offset); if(!code) - Except(shred, "[NullTickException]"); + handle(shred, "NullTickException"); uu->shred = new_vm_shred(shred->info->vm->gwion->mp, *(VM_Code*)(shred->reg-offset)); vmcode_addref(*(VM_Code*)(shred->reg - offset)); uu->shred->info->vm = shred->info->vm; diff --git a/src/lib/ptr.c b/src/lib/ptr.c index b981136f..81585305 100644 --- a/src/lib/ptr.c +++ b/src/lib/ptr.c @@ -90,7 +90,7 @@ static OP_CHECK(opck_ptr_implicit) { static INSTR(instr_ptr_deref) { const m_bit *o = *(m_bit**)REG(-SZ_INT); if(!o) - Except(shred, _("EmptyPointerException")); + handle(shred, _("EmptyPointerException")); if(instr->m_val2) memcpy(REG(-SZ_INT), &o, SZ_INT); else { diff --git a/src/lib/string.c b/src/lib/string.c index 25b80dfc..63e96112 100644 --- a/src/lib/string.c +++ b/src/lib/string.c @@ -84,7 +84,7 @@ static INSTR(StringSlice) { if(end < 0) end = strsz + end; if(bounds(str, start) < 0 || bounds(str, end) < 0) - Except(shred, "OutOfBoundsStringSlice"); + handle(shred, "OutOfBoundsStringSlice"); const m_int op = start < end ? 1 : -1; const m_uint sz = op > 0 ? end - start : start - end; char c[sz + 1]; diff --git a/src/lib/ugen.c b/src/lib/ugen.c index 428a53a6..cc94d445 100644 --- a/src/lib/ugen.c +++ b/src/lib/ugen.c @@ -185,7 +185,7 @@ ANN void ugen_disconnect(const restrict UGen lhs, const restrict UGen rhs) { #define TRIG_EX \ if(!UGEN(rhs)->module.gen.trig) { \ release_connect(shred); \ - Except(shred, "NonTriggerException"); \ + handle(shred, "NonTriggerException"); \ } #define describe_connect_instr(name, func, tgt, opt) \ static INSTR(name##func) { \ diff --git a/src/lib/vararg.c b/src/lib/vararg.c index 644c71bd..c6e38455 100644 --- a/src/lib/vararg.c +++ b/src/lib/vararg.c @@ -108,7 +108,7 @@ static OP_CHECK(opck_vararg_cast) { static INSTR(VarargCast) { const M_Object o = *(M_Object*)REG(-SZ_INT); if(!*(m_uint*)(o->data + SZ_INT)) - Except(shred, "Using Vararg outside varloop"); + handle(shred, "Using Vararg outside varloop"); struct Vararg_* arg = *(struct Vararg_**)o->data; const Type t = (Type)instr->m_val, u = (Type)vector_at(&arg->t, *(m_uint*)(o->data + SZ_INT*4)); @@ -118,7 +118,7 @@ static INSTR(VarargCast) { for(m_uint i = 0; i < t->size; i += SZ_INT) *(m_uint*)REG(i - SZ_INT) = *(m_uint*)(arg->d + *(m_uint*)(o->data + SZ_INT*3) + i); } else - Except(shred, "InvalidVariadicAccess"); + handle(shred, "InvalidVariadicAccess"); } static OP_EMIT(opem_vararg_cast) { diff --git a/src/parse/check.c b/src/parse/check.c index 0b76cd67..6cdb5918 100644 --- a/src/parse/check.c +++ b/src/parse/check.c @@ -345,6 +345,10 @@ ANN static Type check_prim_id(const Env env, const Symbol *data) { return prim_id_non_res(env, data); } +ANN static Type check_prim_perform(const Env env, const Symbol *data NUSED) { + return env->gwion->type[et_void]; +} + ANN static Type check_prim_interp(const Env env, const Exp* exp) { CHECK_OO(check_exp(env, *exp)) return env->gwion->type[et_string]; diff --git a/src/vm/vm.c b/src/vm/vm.c index 18a641f84..b83b1f36 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -40,13 +40,66 @@ uint32_t gw_rand(uint32_t s[2]) { return ret; } +ANN static bool unwind(VM_Shred shred, const Symbol effect) { + if(!shred->info->frame.ptr || !map_size(&shred->info->frame)) + return true; + if(shred->code->handlers.ptr) { + const m_uint start = VKEY(&shred->info->frame, VLEN(&shred->info->frame) - 1); + if(start > shred->pc) + return true; + const Map m = &shred->code->handlers; + m_uint pc = 0; + for(m_uint i = 0; i < map_size(m); i++) { + if(start > shred->pc) + 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); + if(!instr->m_val2 || (Symbol)instr->m_val2 == effect) { + pc = next + 1; + break; + } + } + } + if(!pc) // outside of a try statement + return true; + shred->reg = (m_bit*)VVAL(&shred->info->frame, VLEN(&shred->info->frame) - 1); + shredule(shred->tick->shreduler, shred, 0); + shred->pc = pc;//VKEY(m, i); + return false; + } + // there might be no more stack to unwind + map_remove(&shred->info->frame, VLEN(&shred->info->frame)-1); + 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); +} + +ANN void handle(VM_Shred shred, const m_str effect) { + // remove from the shreduler + // TODO: get shred->mem and shred->reg offsets + 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); + } + // I guess the VM could have *trace mode* + // which would happen here from the top +} + + void vm_remove(const VM* vm, const m_uint index) { const Vector v = (Vector)&vm->shreduler->shreds; LOOP_OPTIM for(m_uint i = vector_size(v) + 1; --i;) { const VM_Shred sh = (VM_Shred)vector_at(v, i - 1); if(sh && sh->tick->xid == index) - Except(sh, "MsgRemove"); + handle(sh, "MsgRemove"); } } @@ -144,60 +197,7 @@ ANN static VM_Shred init_fork_shred(const VM_Shred shred, const VM_Code code, co return ME(o); } -ANN static bool unwind(VM_Shred shred, const Symbol effect) { - // there is an handler - if(!map_size(&shred->info->frame)) - return true; - if(shred->code->handlers.ptr) { - const m_uint start = VKEY(&shred->info->frame, VLEN(&shred->info->frame) - 1); - if(start > shred->pc) - return true; - const Map m = &shred->code->handlers; - m_uint pc = 0; - for(m_uint i = 0; i < map_size(m); i++) { - if(start > shred->pc) - 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); - if(!instr->m_val2 || (Symbol)instr->m_val2 == effect) { - pc = next + 1; - break; - } - } - } - if(!pc) // outside of a try statement - return true; - shred->reg = (m_bit*)VVAL(&shred->info->frame, VLEN(&shred->info->frame) - 1); - shredule(shred->tick->shreduler, shred, 0); - shred->pc = pc;//VKEY(m, i); - return false; - } - // there might be no more stack to unwind - map_remove(&shred->info->frame, VLEN(&shred->info->frame)-1); - 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); -} - -ANN void handle(VM_Shred shred, const Symbol xid) { - // remove from the shreduler - // TODO: get shred->mem and shred->reg offsets - shreduler_remove(shred->tick->shreduler, shred, false); - // do the unwiding - if(unwind(shred, xid)) { - vm_shred_exit(shred); - puts(s_name(xid)); - } - // I guess the VM could have *trace mode* - // which would happen here from the top -} - -#define TEST0(t, pos) if(!*(t*)(reg-pos)){ shred->pc = PC; handle(shred, insert_symbol(vm->gwion->st, "ZeroDivideException")); break; } +#define TEST0(t, pos) if(!*(t*)(reg-pos)){ shred->pc = PC; handle(shred, "ZeroDivideException"); break; } #define ADVANCE() byte += BYTECODE_SZ; @@ -384,7 +384,7 @@ ANN void vm_run(const VM* vm) { // lgtm [cpp/use-of-goto] &&upvalueint, &&upvaluefloat, &&upvalueother, &&upvalueaddr, &&dotfunc, &&gcini, &&gcadd, &&gcend, - &&gacktype, &&gackend, &&gack, &&try_ini, &&try_end, &&handleeffect, &&noop, &&eoc, &&unroll2, &&other, &®pushimm + &&gacktype, &&gackend, &&gack, &&try_ini, &&try_end, &&handleeffect, &&performeffect, &&noop, &&eoc, &&unroll2, &&other, &®pushimm }; const Shreduler s = vm->shreduler; register VM_Shred shred; @@ -697,7 +697,7 @@ regtomemother: overflow: if(overflow_(mem + VAL2, shred)) { shred->pc = PC; - exception(shred, "StackOverflow"); + handle(shred, "StackOverflow"); continue; } PRAGMA_PUSH() @@ -798,10 +798,10 @@ arrayaccess: register const m_int idx = *(m_int*)(reg + VAL); a.obj = *(M_Object*)(reg-VAL2); if(idx < 0 || (m_uint)idx >= m_vector_size(ARRAY(a.obj))) { - gw_err(_(" ... at index [%" INT_F "]\n"), idx); - gw_err(_(" ... at dimension [%" INT_F "]\n"), VAL); + gw_err(_("{-} ... at index {W}[{Y}%" INT_F "{W}]{0}\n"), idx); +// gw_err(_(" ... at dimension [%" INT_F "]\n"), VAL); VM_OUT - exception(shred, "ArrayOutofBounds"); + handle(shred, "ArrayOutofBounds"); continue; // or break ? } DISPATCH() @@ -865,7 +865,7 @@ except: * grep for GWOP_EXCEPT and Except, exception... */ if(!*(m_bit**)(reg+(m_int)(VAL))) { shred->pc = PC; - exception(shred, "NullPtrException"); + handle(shred, "NullPtrException"); continue; } DISPATCH(); @@ -895,7 +895,7 @@ dotaddr: #define UNION_CHECK\ register const m_bit *data = (*(M_Object*)(reg-SZ_INT))->data;\ if(*(m_uint*)data != VAL) {\ - exception(shred, "invalid union acces");\ + handle(shred, "invalid union acces");\ continue;\ } @@ -1013,6 +1013,11 @@ try_ini: try_end: map_remove(&shred->info->frame, VLEN(&shred->info->frame)-1); handleeffect: +// this should check the *xid* of the exception + DISPATCH(); +performeffect: + handle(shred, (m_str)VAL); + break; // this should check the *xid* of the exception noop: DISPATCH();