From ca2d0ddd87703a42b40f70525da63f2d458684ff Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Astor?= Date: Thu, 12 Aug 2021 22:57:54 +0200 Subject: [PATCH] :art: Improve unwind --- include/shreduler_private.h | 6 +- plug | 2 +- src/gwion.c | 8 ++ src/lib/shred.c | 5 +- src/vm/shreduler.c | 21 +++- src/vm/vm.c | 188 ++++++++++++++++++++++-------------- 6 files changed, 152 insertions(+), 78 deletions(-) diff --git a/include/shreduler_private.h b/include/shreduler_private.h index 96899348..65185eef 100644 --- a/include/shreduler_private.h +++ b/include/shreduler_private.h @@ -4,9 +4,13 @@ struct Shreduler_ { struct BBQ_ * bbq; struct ShredTick_ *list; struct ShredTick_ *curr; - struct Vector_ shreds; + struct Vector_ active_shreds; MUTEX_TYPE mutex; size_t shred_ids; + struct Vector_ killed_shreds; bool loop; }; + +ANN Shreduler new_shreduler(const MemPool mp); +ANN void free_shreduler(const MemPool mp, const Shreduler s); #endif diff --git a/plug b/plug index a4a346eb..de59c050 160000 --- a/plug +++ b/plug @@ -1 +1 @@ -Subproject commit a4a346eb4a993b208af212b3cb5873e74f4bddd2 +Subproject commit de59c0509836ecb3eb7f5fbe2c621db137aa66ab diff --git a/src/gwion.c b/src/gwion.c index d2216c74..bd9f4f13 100644 --- a/src/gwion.c +++ b/src/gwion.c @@ -140,7 +140,15 @@ ANN void gwion_end_child(const VM_Shred shred, const Gwion gwion) { if (gwion->data->child2.ptr) fork_clean2(shred, &gwion->data->child2); } +ANN static inline void free_killed_shred(const Vector v) { + for (m_uint i = 0; i < vector_size(v); i++) { + const VM_Shred shred = (VM_Shred)vector_at(v, i); + free_vm_shred(shred); + } +} + ANN void gwion_end(const Gwion gwion) { + free_killed_shred(&gwion->vm->shreduler->killed_shreds); gwion_end_child(gwion->vm->cleaner_shred, gwion); free_env(gwion->env); if (gwion->vm->cleaner_shred) free_vm_shred(gwion->vm->cleaner_shred); diff --git a/src/lib/shred.c b/src/lib/shred.c index cefac600..6fb5beb3 100644 --- a/src/lib/shred.c +++ b/src/lib/shred.c @@ -84,9 +84,10 @@ static MFUN(shred_yield) { static SFUN(vm_shred_from_id) { const m_int index = *(m_int *)MEM(0); if (index > 0) { - for (m_uint i = 0; i < vector_size(&shred->tick->shreduler->shreds); ++i) { + const Vector v = &shred->tick->shreduler->active_shreds; + for (m_uint i = 0; i < vector_size(v); ++i) { const VM_Shred s = - (VM_Shred)vector_at(&shred->tick->shreduler->shreds, i); + (VM_Shred)vector_at(v, i); if (s->tick->xid == (m_uint)index) { *(M_Object *)RETURN = s->info->me; return; diff --git a/src/vm/shreduler.c b/src/vm/shreduler.c index 452b5a51..bc8e5668 100644 --- a/src/vm/shreduler.c +++ b/src/vm/shreduler.c @@ -26,7 +26,7 @@ ANN VM_Shred shreduler_get(const Shreduler s) { return tk->self; } } - if (!s->loop && !vector_size(&s->shreds)) bbq->is_running = 0; + if (!s->loop && !vector_size(&s->active_shreds)) bbq->is_running = 0; MUTEX_UNLOCK(s->mutex); return NULL; } @@ -42,7 +42,7 @@ ANN static void shreduler_erase(const Shreduler s, struct ShredTick_ *const tk) { if (tk->parent) vector_rem2(&tk->parent->child, (vtype)tk->self); if (tk->child.ptr) shreduler_child(&tk->child); - vector_rem2(&s->shreds, (vtype)tk->self); + vector_rem2(&s->active_shreds, (vtype)tk->self); } ANN void shreduler_remove(const Shreduler s, const VM_Shred out, @@ -99,6 +99,21 @@ ANN void shreduler_ini(const Shreduler s, const VM_Shred shred) { ANN void shreduler_add(const Shreduler s, const VM_Shred shred) { shreduler_ini(s, shred); shred->tick->xid = ++s->shred_ids; - vector_add(&s->shreds, (vtype)shred); + vector_add(&s->active_shreds, (vtype)shred); shredule(s, shred, GWION_EPSILON); } + +ANN Shreduler new_shreduler(const MemPool mp) { + Shreduler s = (Shreduler)mp_calloc(mp, Shreduler); + vector_init(&s->active_shreds); + vector_init(&s->killed_shreds); + MUTEX_SETUP(s->mutex); + return s; +} + +ANN void free_shreduler(const MemPool mp, const Shreduler s) { + vector_release(&s->active_shreds); + vector_release(&s->killed_shreds); + MUTEX_CLEANUP(s->mutex); + mp_free(mp, Shreduler, s); +} diff --git a/src/vm/vm.c b/src/vm/vm.c index b8574203..31c23a39 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -47,48 +47,68 @@ ANN static inline void shred_unwind(const VM_Shred shred) { shred->mem -= frame->push; } -ANN static bool unwind(VM_Shred shred, const Symbol effect, const m_uint size) { +ANN static void clean_values(const VM_Shred shred) { const VM_Code code = shred->code; - if (code->live_values.ptr) { - const uint16_t pc = shred->pc; - for (m_uint i = 0; i < m_vector_size(&code->live_values); i++) { - VMValue *vmval = (VMValue *)m_vector_addr(&code->live_values, i); - if (pc <= vmval->start) break; - if (pc >= vmval->end) continue; - m_bit *const data = &*(m_bit *)(shred->mem + vmval->offset); - compound_release(shred, vmval->t, data); - } + const uint16_t pc = shred->pc; + for (m_uint i = 0; i < m_vector_size(&code->live_values); i++) { + VMValue *vmval = (VMValue *)m_vector_addr(&code->live_values, i); + if (pc <= vmval->start) break; + if (pc >= vmval->end) continue; + m_bit *const data = &*(m_bit *)(shred->mem + vmval->offset); + compound_release(shred, vmval->t, data); } - if (!size) return true; - if (code->handlers.ptr) { - const m_uint start = VKEY(&shred->info->frame, size - 1); - if (start > shred->pc) return true; - const Map m = &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(&code->instr, next + 1); - if (!instr->m_val2 || (Symbol)instr->m_val2 == effect) { - pc = next + 1; - break; - } - } +} + +ANN static uint16_t find_pc(const VM_Shred shred, const Symbol effect, const m_uint size) { + const VM_Code code = shred->code; + const m_uint start = VKEY(&shred->info->frame, size - 1); + if (start > shred->pc) return true; + const Map m = &shred->code->handlers; + 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(&code->instr, next + 1); + if (!instr->m_val2 || (Symbol)instr->m_val2 == effect) + return next + 1; } - if (!pc) // outside of a try statement - return true; - 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 - if (shred->mem == (m_bit *)shred + sizeof(struct VM_Shred_) + SIZEOF_REG) - return true; + return 0; +} + +ANN static inline bool find_handle(const VM_Shred shred, const Symbol effect, const m_uint size) { + const m_uint start = VKEY(&shred->info->frame, size - 1); + if (start > shred->pc) return true; + const uint16_t pc = find_pc(shred, effect, size); + if (!pc) // outside of a try statement +// return true; + return false; + // we should clean values here + shred->reg = // restore reg + (m_bit *)VPTR(&shred->info->frame, VLEN(&shred->info->frame) - 1); + shredule(shred->tick->shreduler, shred, 0); + shred->pc = pc; // VKEY(m, i); + vector_pop(&shred->info->frame); +// return false; + return true; +} + +ANN static bool unwind(const VM_Shred shred, const Symbol effect, const m_uint size) { + const VM_Code code = shred->code; + if (code->live_values.ptr) + clean_values(shred); +// if (!size) return true; + if (!size) return false; + if (size) { + if (code->handlers.ptr) + return find_handle(shred, effect, size); + // there might be no more stack to unwind + if (shred->mem == (m_bit *)shred + sizeof(struct VM_Shred_) + SIZEOF_REG) +// return true; + return false; + } else +// return true; + return false; shred_unwind(shred); return unwind(shred, effect, size - 1); } @@ -114,29 +134,55 @@ ANN static void trace(VM_Shred shred, const m_uint size) { trace(shred, i); } +struct TraceStart { + const VM_Code code; + m_bit *const reg; + m_bit *const mem; +}; + +ANN static inline void shred_trace(const VM_Shred shred, const struct TraceStart *ts) { + shred->code = ts->code; + shred->reg = ts->reg; + shred->mem = ts->mem; + gw_err("\n{-/}here is the trace:\n"); + trace(shred, vector_size(&shred->info->line)); +} + +ANN static inline void add_to_killed(const VM_Shred shred) { + const Shreduler shreduler = shred->tick->shreduler; + vector_rem2(&shreduler->active_shreds, (m_uint)shred); + vector_add(&shreduler->killed_shreds, (m_uint)shred); +} + +ANN static inline void unhandled_pp(VM_Shred shred, const m_str effect) { + gw_err("{-C}shred{W}[{Y}% 5" UINT_F "{W}]{-}: {-R}Unhandled {+R}%s{0}\n", + shred->tick->xid, effect); +} + +ANN static inline void handle_fail(VM_Shred shred, const m_str effect, const struct TraceStart *ts) { + unhandled_pp(shred, effect); + if (shred->info->line.ptr) // trace if available + shred_trace(shred, ts); + add_to_killed(shred); +} + ANN void handle(VM_Shred shred, const m_str effect) { - m_bit *const reg = shred->reg; - m_bit *const mem = shred->mem; + shreduler_remove(shred->tick->shreduler, shred, false); + // store trace info + struct TraceStart ts = { + .code = shred->code, + .reg = shred->reg, + .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); + // maybe we should use a string to avoid the insert_symbol call 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; - gw_err("\n{-/}here is the trace:\n"); - trace(shred, vector_size(&shred->info->line)); - } - vm_shred_exit(shred); + handle_fail(shred, effect, &ts); } ANN bool vm_remove(const VM *vm, const m_uint index) { - const Vector v = (Vector)&vm->shreduler->shreds; + const Vector v = (Vector)&vm->shreduler->active_shreds; LOOP_OPTIM for (m_uint i = vector_size(v) + 1; --i;) { const VM_Shred sh = (VM_Shred)vector_at(v, i - 1); @@ -148,15 +194,6 @@ ANN bool vm_remove(const VM *vm, const m_uint index) { return false; } -ANN void free_vm(VM *vm) { - vector_release(&vm->shreduler->shreds); - vector_release(&vm->ugen); - if (vm->bbq) free_driver(vm->bbq, vm); - MUTEX_CLEANUP(vm->shreduler->mutex); - mp_free(vm->gwion->mp, Shreduler, vm->shreduler); - mp_free(vm->gwion->mp, VM, vm); -} - ANN void vm_add_shred(const VM *vm, const VM_Shred shred) { shred->info->vm = (VM *)vm; shred->info->me = new_shred(shred); @@ -1257,11 +1294,13 @@ vm_run(const VM *vm) { // lgtm [cpp/use-of-goto] } } +// remove me ANN void next_bbq_pos(const VM *vm) { Driver *const di = vm->bbq; if(++di->pos == 16777216-1) { - for(m_uint i = 0; i < vector_size(&vm->shreduler->shreds); i++) { - const VM_Shred shred = (VM_Shred)vector_at(&vm->shreduler->shreds, i); + const Vector v = &vm->shreduler->active_shreds; + for(m_uint i = 0; i < vector_size(v); i++) { + const VM_Shred shred = (VM_Shred)vector_at(v, i); shred->tick->wake_time -= 16777216.0; } di->pos = 0; @@ -1276,12 +1315,11 @@ static void vm_run_audio(const VM *vm) { VM *new_vm(MemPool p, const bool audio) { VM *vm = (VM *)mp_calloc(p, VM); vector_init(&vm->ugen); - vm->bbq = new_driver(p); - vm->bbq->run = audio ? vm_run_audio : vm_run; - vm->shreduler = (Shreduler)mp_calloc(p, Shreduler); - vector_init(&vm->shreduler->shreds); - MUTEX_SETUP(vm->shreduler->mutex); - vm->shreduler->bbq = vm->bbq; + vm->shreduler = new_shreduler(p); + vm->bbq = vm->shreduler->bbq = new_driver(p); + vm->bbq->run = audio + ? vm_run_audio + : vm_run; #ifndef __AFL_COMPILER gw_seed(vm->rand, (uint64_t)time(NULL)); #else @@ -1289,3 +1327,11 @@ VM *new_vm(MemPool p, const bool audio) { #endif return vm; } + +ANN void free_vm(VM *vm) { + const MemPool mp = vm->gwion->mp; + free_shreduler(mp, vm->shreduler); + if (vm->bbq) free_driver(vm->bbq, vm); + vector_release(&vm->ugen); + mp_free(mp, VM, vm); +} -- 2.43.0