From 13c922836e5452849602af3f69d8c2bff04fd320 Mon Sep 17 00:00:00 2001 From: fennecdjay Date: Tue, 26 Mar 2019 14:20:37 +0100 Subject: [PATCH] :art: Fork, initial --- .travis.yml | 2 +- examples/spork_lamba.gw | 2 + help/test.sh | 6 ++- include/gwion.h | 1 + include/import.h | 14 ++----- include/object.h | 3 +- include/opcode.h | 4 ++ include/parse.h | 1 + include/soundinfo.h | 1 + include/type.h | 2 +- opcode.txt | 2 + src/emit/emit.c | 81 +++++++++++++++++++++-------------------- src/gwion.c | 10 +++++ src/lib/func.c | 10 +++-- src/lib/object.c | 3 +- src/lib/shred.c | 77 +++++++++++++++++++++++++++++++++++---- src/parse/check.c | 23 +++++------- src/soundinfo.c | 17 +++++++++ src/vm/shreduler.c | 8 ++-- src/vm/vm.c | 34 ++++++++++++++--- src/vm/vm_code.c | 4 +- tests/tree/fork.gw | 14 +++++++ util | 2 +- 23 files changed, 228 insertions(+), 93 deletions(-) create mode 100644 examples/spork_lamba.gw create mode 100644 src/soundinfo.c create mode 100644 tests/tree/fork.gw diff --git a/.travis.yml b/.travis.yml index e0e55e63..803224ac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,7 @@ env: matrix: allow_failures: - - os: osx + - os: windows compiler: - gcc diff --git a/examples/spork_lamba.gw b/examples/spork_lamba.gw new file mode 100644 index 00000000..bf63f327 --- /dev/null +++ b/examples/spork_lamba.gw @@ -0,0 +1,2 @@ +spork \ a { <<>>;}(1); +me.yield(); diff --git a/help/test.sh b/help/test.sh index aab1648f..636854b1 100644 --- a/help/test.sh +++ b/help/test.sh @@ -89,9 +89,11 @@ assert_fishy() { assert_leak() { grep "All heap blocks were freed -- no leaks are possible" "$2.valgrind.log" > /dev/null && return 0 - [ "$suppressions" -eq 0 ] && echo "mem leak" > "$2.log" && return 1 + #[ "$suppressions" -eq 0 ] && echo "mem leak" > "$2.log" && return 1 + #[ -z "$suppressions" ] && echo "mem leak" > "$2.log" && return 1 heap=$(grep "in use at exit:" "$2.valgrind.log" | cut -d ":" -f2) supp=$(grep "suppressed: .* bytes" "$2.valgrind.log" | cut -d ":" -f2) + #[ -z "$supp" ] && echo "mem leak" > "$2.log" && return 1 [ "$heap" = "$supp" ] && return 0 echo "mem leak" > "$2.log" return 1 @@ -180,7 +182,7 @@ test_gw(){ if [ "$VALGRIND" == "NO_VALGRIND" ] then ./gwion "$GWOPT" -d "$DRIVER" "$file" > "$slog" 2>"$elog" |: else - "$VALGRIND" --log-file="$vlog" \ + "$VALGRIND" --suppressions=supp --log-file="$vlog" \ ./gwion "$GWOPT" -d "$DRIVER" "$file" > "$slog" 2>"$elog" |: fi ret=$? diff --git a/include/gwion.h b/include/gwion.h index 11ae35a1..32f57ff5 100644 --- a/include/gwion.h +++ b/include/gwion.h @@ -14,6 +14,7 @@ struct Gwion_ { VM* vm; }; ANN m_bool gwion_ini(const Gwion, struct Arg_*); +ANN VM* gwion_cpy(const VM*); ANN void gwion_run(const Gwion gwion); ANN void gwion_end(const Gwion gwion); #endif diff --git a/include/import.h b/include/import.h index 51cfa341..8928f5ff 100644 --- a/include/import.h +++ b/include/import.h @@ -3,21 +3,15 @@ #define DLARG_MAX 6 typedef void (*f_xtor)(const M_Object o, const m_bit*, const VM_Shred); -//typedef void (*f_xtor)(const M_Object o, const VM_Shred); typedef void (*f_mfun)(const M_Object o, const m_bit* RETURN, const VM_Shred sh); -//typedef void (*f_sfun)(const m_bit* RETURN, const VM_Shred sh); typedef void (*f_sfun)(const m_bit*, const m_bit* RETURN, const VM_Shred sh); typedef void (*f_xfun)(); typedef struct Gwi_* Gwi; #define MFUN(a) ANN void a(const M_Object o __attribute__((unused)), const m_bit* RETURN __attribute__((unused)), const VM_Shred shred __attribute__((unused))) #define SFUN(a) ANN void a(const M_Object o __attribute__((unused)), const m_bit* RETURN __attribute__((unused)), const VM_Shred shred __attribute__((unused))) -//#define SFUN(a) ANN void a(const m_bit* mem __attribute__((unused)), const m_bit* RETURN -//__attribute__((unused)), const VM_Shred shred __attribute__((unused))) -#define CTOR(a) ANN void a(const M_Object o, const m_bit* _ __attribute__((unused)), const VM_Shred shred __attribute__((unused))) -//#define CTOR(a) ANN void a(const M_Object o, const VM_Shred shred __attribute__((unused))) -#define DTOR(a) ANN void a(const M_Object o, const m_bit* _ __attribute__((unused)), const VM_Shred shred __attribute__((unused))) -//#define DTOR(a) ANN void a(const M_Object o, const VM_Shred shred __attribute__((unused))) +#define CTOR(a) ANN void a(const M_Object o __attribute__((unused)), const m_bit* _ __attribute__((unused)), const VM_Shred shred __attribute__((unused))) +#define DTOR(a) ANN void a(const M_Object o __attribute__((unused)), const m_bit* _ __attribute__((unused)), const VM_Shred shred __attribute__((unused))) #define OP_CHECK(a) ANN Type a(const Env env __attribute__((unused)), void* data __attribute__((unused))) #define OP_EMIT(a) ANN m_bool a(const Emitter emit __attribute__((unused)), void* data __attribute__((unused))) #ifdef GWION_BUILTIN @@ -78,7 +72,5 @@ OP_CHECK(opck_new); OP_EMIT(opem_basic_cast); OP_EMIT(opem_new); - -ANN /*static */ Type_List str2tl(const Env env, const m_str s, m_uint *depth); - +ANN Type_List str2tl(const Env env, const m_str s, m_uint *depth); #endif diff --git a/include/object.h b/include/object.h index 850a0ad6..b5ce5093 100644 --- a/include/object.h +++ b/include/object.h @@ -17,7 +17,8 @@ ANEW M_Object new_M_UGen(void); ANN ANEW M_Object new_array(const Type t, const m_uint length); ANEW M_Object new_string(const VM_Shred, const m_str); ANEW M_Object new_string2(const VM_Shred, const m_str); -ANEW M_Object new_shred(const VM_Shred); +ANEW M_Object new_shred(const VM_Shred, const m_bool); +ANN void fork_launch(const M_Object, const m_uint); ANN void __release(const M_Object, const VM_Shred); ANN void exception(const VM_Shred, const m_str); ANN void broadcast(const M_Object); diff --git a/include/opcode.h b/include/opcode.h index d43d3c18..27c1ff82 100644 --- a/include/opcode.h +++ b/include/opcode.h @@ -129,9 +129,11 @@ enum { eFuncUsrEnd, eFuncMemberEnd, eSporkIni, + eForkIni, eSporkFunc, eSporkThis, eSporkExp, + eForkEnd, eSporkEnd, eBranchEqInt, eBranchNeqInt, @@ -292,9 +294,11 @@ enum { #define FuncUsrEnd (f_instr)eFuncUsrEnd #define FuncMemberEnd (f_instr)eFuncMemberEnd #define SporkIni (f_instr)eSporkIni +#define ForkIni (f_instr)eForkIni #define SporkFunc (f_instr)eSporkFunc #define SporkThis (f_instr)eSporkThis #define SporkExp (f_instr)eSporkExp +#define ForkEnd (f_instr)eForkEnd #define SporkEnd (f_instr)eSporkEnd #define BranchEqInt (f_instr)eBranchEqInt #define BranchNeqInt (f_instr)eBranchNeqInt diff --git a/include/parse.h b/include/parse.h index bf79aa3e..245d483f 100644 --- a/include/parse.h +++ b/include/parse.h @@ -48,4 +48,5 @@ ANN static m_bool prefix##_stmt_##name(const Env env, const type stmt) { GWDEBUG ANN m_uint union_push(const Env, const Stmt_Union); ANN void union_pop(const Env, const Stmt_Union, const m_uint); +ANN m_bool check_stmt(const Env env, const Stmt stmt); #endif diff --git a/include/soundinfo.h b/include/soundinfo.h index 33a861e1..b2537711 100644 --- a/include/soundinfo.h +++ b/include/soundinfo.h @@ -5,4 +5,5 @@ struct SoundInfo_ { uint8_t in, out; m_str arg; }; +struct SoundInfo_ *soundinfo_cpy(const struct SoundInfo_ *src); #endif diff --git a/include/type.h b/include/type.h index cda59b78..37dd9c15 100644 --- a/include/type.h +++ b/include/type.h @@ -20,7 +20,7 @@ struct Type_ { }; Type t_void, t_int, t_float, t_dur, t_time, t_now, t_complex, t_polar, t_vec3, t_vec4, - t_null, t_object, t_shred, t_event, t_ugen, t_string, t_ptr, t_array, t_gack, + t_null, t_object, t_shred, t_fork, t_event, t_ugen, t_string, t_ptr, t_array, t_gack, t_function, t_fptr, t_vararg, t_lambda, t_class, t_union; ANN2(2) ANEW Type new_type(const m_uint xid, const m_str name, const Type); diff --git a/opcode.txt b/opcode.txt index 92d958b3..00a918a2 100644 --- a/opcode.txt +++ b/opcode.txt @@ -126,9 +126,11 @@ Next FuncUsrEnd FuncMemberEnd SporkIni +ForkIni SporkFunc SporkThis SporkExp +ForkEnd SporkEnd BranchEqInt BranchNeqInt diff --git a/src/emit/emit.c b/src/emit/emit.c index b3f72218..72abcc84 100644 --- a/src/emit/emit.c +++ b/src/emit/emit.c @@ -835,28 +835,19 @@ ANN m_bool emit_exp_call1(const Emitter emit, const Func f) { GWDEBUG_EXE return GW_OK; } -ANN2(1,2) static m_bool emit_exp_spork_finish(const Emitter emit, const VM_Code code, - const m_uint depth, const m_bool f) { - const Instr ini = emit_add_instr(emit, SporkIni); - ini->m_val = (m_uint)code; - if(!f) { - const m_uint member = GET_FLAG(code, member) ? SZ_INT : 0; - const Instr pop = emit_add_instr(emit, RegPop); - pop->m_val = depth + member; - if(depth) { - const Instr spork = emit_add_instr(emit, SporkFunc); - spork->m_val = depth; - } - if(member) { - const Instr m = emit_add_instr(emit, SporkThis); - m->m_val = depth; - } - } else { - const Instr spork = emit_add_instr(emit, SporkExp); +ANN2(1,2) static void emit_exp_spork_finish(const Emitter emit, const VM_Code code, + const m_uint depth) { + const m_uint member = GET_FLAG(code, member) ? SZ_INT : 0; + const Instr pop = emit_add_instr(emit, RegPop); + pop->m_val = depth + member; + if(depth) { + const Instr spork = emit_add_instr(emit, SporkFunc); spork->m_val = depth; } - emit_add_instr(emit, SporkEnd); - return GW_OK; + if(member) { + const Instr m = emit_add_instr(emit, SporkThis); + m->m_val = depth; + } } static inline void stack_alloc(const Emitter emit) { @@ -884,7 +875,9 @@ static m_bool scoped_stmt(const Emitter emit, const Stmt stmt, const m_bool pop) } #define SPORK_FUNC_PREFIX "spork~func:%i" +#define FORK_FUNC_PREFIX "fork~func:%i" #define SPORK_CODE_PREFIX "spork~code:%i" +#define FORK_CODE_PREFIX "fork~code:%i" static void push_spork_code(const Emitter emit, const m_str prefix, const int pos) { char c[strlen(SPORK_FUNC_PREFIX) + num_digit(pos) + 1]; @@ -893,8 +886,6 @@ static void push_spork_code(const Emitter emit, const m_str prefix, const int po } ANN static m_bool spork_func(const Emitter emit, const Exp_Call* exp) { GWDEBUG_EXE - CHECK_BB(prepare_call(emit, exp)) - push_spork_code(emit, SPORK_FUNC_PREFIX, exp->self->pos); if(GET_FLAG(exp->m_func, member)) SET_FLAG(emit->code, member); if(exp->m_func->code) { @@ -904,26 +895,38 @@ ANN static m_bool spork_func(const Emitter emit, const Exp_Call* exp) { GWDEBUG_ const Instr p = emit_add_instr(emit, PushStaticCode); p->m_val = (m_uint)exp->m_func; } - CHECK_BB(emit_exp_call1(emit, exp->m_func)) - const VM_Code code = finalyze(emit); - const m_uint size = exp->m_func->def->stack_depth - (GET_FLAG(exp->m_func, - member) ? SZ_INT : 0); - return emit_exp_spork_finish(emit, code, size, 0); -} - -ANN static m_bool spork_code(const Emitter emit, const Stmt stmt) { GWDEBUG_EXE - emit_add_instr(emit, RegPushImm); - push_spork_code(emit, SPORK_CODE_PREFIX, stmt->pos); - if(!SAFE_FLAG(emit->env->func, member)) - stack_alloc_this(emit); - CHECK_BB(scoped_stmt(emit, stmt, 0)) - const VM_Code code = finalyze(emit); - return emit_exp_spork_finish(emit, code, emit->code->stack_depth, 1); + return emit_exp_call1(emit, exp->m_func); } ANN m_bool emit_exp_spork(const Emitter emit, const Exp_Unary* unary) { - return unary->code ? spork_code(emit, unary->code) : - spork_func(emit, &unary->exp->d.exp_call); + const m_bool is_spork = unary->op == op_spork; + if(unary->code) { + emit_add_instr(emit, RegPushImm); + push_spork_code(emit, is_spork ? SPORK_CODE_PREFIX : FORK_CODE_PREFIX, unary->code->pos); + if(!SAFE_FLAG(emit->env->func, member)) + stack_alloc_this(emit); + CHECK_BB(scoped_stmt(emit, unary->code, 0)) + } else { + CHECK_BB(prepare_call(emit, &unary->exp->d.exp_call)) + push_spork_code(emit, is_spork ? SPORK_FUNC_PREFIX : FORK_CODE_PREFIX, unary->exp->pos); + CHECK_BB(spork_func(emit, &unary->exp->d.exp_call)) + } + const VM_Code code = finalyze(emit); + const Instr ini = emit_add_instr(emit, unary->op == op_spork ? SporkIni : ForkIni); + ini->m_val = (m_uint)code; + ini->m_val2 = is_spork; + if(unary->code) { + const Instr spork = emit_add_instr(emit, is_spork ? SporkExp : ForkEnd); + spork->m_val = emit->code->stack_depth; + emit_add_instr(emit, is_spork ? SporkEnd : ForkEnd); + } else { + const Func f = unary->exp->d.exp_call.m_func; + const m_uint size = f->def->stack_depth - (GET_FLAG(f, member) ? SZ_INT : 0); + emit_exp_spork_finish(emit, code, size); + const Instr end = emit_add_instr(emit, is_spork ? SporkEnd : ForkEnd); + end->m_val2 = unary->exp->d.exp_call.m_func->def->ret_type->size; + } + return GW_OK; } ANN static m_bool emit_exp_unary(const Emitter emit, const Exp_Unary* unary) { GWDEBUG_EXE diff --git a/src/gwion.c b/src/gwion.c index d60af876..473d635c 100644 --- a/src/gwion.c +++ b/src/gwion.c @@ -52,6 +52,16 @@ ANN static inline void gwion_compile(const Gwion gwion, const Vector v) { compile_filename(gwion, (m_str)vector_at(v, i)); } + +ANN VM* gwion_cpy(const VM* src) { + const Gwion gwion = mp_alloc(Gwion); + gwion->vm = new_vm(); + gwion->vm->gwion = gwion; + gwion->vm->bbq->si = soundinfo_cpy(src->bbq->si); + gwion->emit = src->gwion->emit; + gwion->env = src->gwion->env; + return gwion->vm; +} ANN m_bool gwion_ini(const Gwion gwion, Arg* arg) { gwion->vm = new_vm(); gwion->emit = new_emitter(); diff --git a/src/lib/func.c b/src/lib/func.c index 47995999..584f9967 100644 --- a/src/lib/func.c +++ b/src/lib/func.c @@ -14,6 +14,7 @@ #include "nspc.h" #include "operator.h" #include "traverse.h" +#include "parse.h" ANN Type check_exp_call1(const Env env, const Exp_Call *exp); ANN m_bool emit_exp_spork(const Emitter, const Exp_Unary*); @@ -159,10 +160,11 @@ ANN Type check_exp_unary_spork(const Env env, const Stmt code); static OP_CHECK(opck_spork) { const Exp_Unary* unary = (Exp_Unary*)data; if(unary->exp && unary->exp->exp_type == ae_exp_call) - return t_shred; - else if(unary->code) - return check_exp_unary_spork(env, unary->code); - else + return unary->op == op_spork ? t_shred : t_fork; + else if(unary->code) { + CHECK_BO(check_stmt(env, unary->code)) + return unary->op == op_spork ? t_shred : t_fork; + } else ERR_O(unary->self->pos, "only function calls can be sporked...") return NULL; } diff --git a/src/lib/object.c b/src/lib/object.c index 5c4c7e68..f9968b75 100644 --- a/src/lib/object.c +++ b/src/lib/object.c @@ -75,7 +75,8 @@ ANN void __release(const M_Object obj, const VM_Shred shred) { struct scope_iter iter = { &t->nspc->info->value, 0, 0 };\ Value v; while(scope_iter(&iter, &v) > 0) { - if(!GET_FLAG(v, static) && isa(v->type, t_object) > 0) + if(!GET_FLAG(v, static) && !GET_FLAG(v, pure) && + isa(v->type, t_object) > 0) release(*(M_Object*)(obj->data + v->offset), shred); } if(GET_FLAG(t, dtor)) { diff --git a/src/lib/shred.c b/src/lib/shred.c index ba7225e3..b583b27f 100644 --- a/src/lib/shred.c +++ b/src/lib/shred.c @@ -2,6 +2,7 @@ #include #include "gwion_util.h" #include "gwion_ast.h" +#include "gwion_thread.h" #include "oo.h" #include "vm.h" #include "env.h" @@ -9,10 +10,21 @@ #include "instr.h" #include "object.h" #include "import.h" +#include "shreduler_private.h" +#include "gwion.h" + +static m_int o_fork_thread, o_fork_retsize, o_fork_retval; +#define FORK_THREAD(o) *(THREAD_TYPE*)(o->data + o_fork_thread) +#define FORK_RETSIZE(o) *(m_int*)(o->data + o_fork_retsize) +#define FORK_RETVAL(o) (o->data + o_fork_retval) -M_Object new_shred(const VM_Shred shred) { - const M_Object obj = new_object(NULL, t_shred); +M_Object new_shred(const VM_Shred shred, m_bool is_spork) { + const M_Object obj = new_object(NULL, is_spork ? t_shred : t_fork); ME(obj) = shred; + if(!is_spork) { +// *(M_Object*)(obj->data + o_fork_ev) = new_object(NULL, t_event); +// EV_SHREDS(*(M_Object*)(obj->data + o_fork_ev)) = new_vector(); + } return obj; } @@ -39,17 +51,15 @@ static MFUN(shred_yield) { const VM_Shred s = ME(o); const Shreduler sh = shred->info->vm->shreduler; shredule(sh, s, .5); -// shred->mem += (m_bit*)o - shred->mem; -// shred->mem -= SZ_INT;//!!! } -#include "shreduler_private.h" + static SFUN(vm_shred_from_id) { const m_int index = *(m_int*)MEM(0); const VM_Shred s = (VM_Shred)vector_at(&shred->info->vm->shreduler->shreds, (vtype)index); if(s) { *(M_Object*)RETURN = s->info->me; - s->info->me->ref++; - vector_add(&shred->gc, (vtype) s->info->me); +// s->info->me->ref++; +// vector_add(&shred->gc, (vtype) s->info->me); } else *(m_uint*)RETURN = 0; } @@ -86,9 +96,41 @@ static MFUN(shred##name##_dir) { \ describe_path_and_dir(, s->info->name) describe_path_and_dir(_code, s->code->name) +static DTOR(shred_dtor) { free_vm_shred(*(VM_Shred*)o->data); } + +static DTOR(fork_dtor) { + mp_free(Gwion, ME(o)->info->vm->gwion); + free_vm(ME(o)->info->vm); +} + +static MFUN(fork_join) { + /* int pret = */ THREAD_JOIN(FORK_THREAD(o)); + release(o, shred); +} + +void fork_retval(const M_Object o) { + const m_uint sz = FORK_RETSIZE(o); + memcpy(FORK_RETVAL(o), ME(o)->reg - sz, sz); +} + +static ANN void* fork_run(void* data) { + M_Object me = (M_Object)data; + VM *vm = ME(me)->info->vm; + vm_run(vm); + fork_retval(me); + THREAD_RETURN(NULL); +} + +void fork_launch(const M_Object o, const m_uint sz) { + ++o->ref; + FORK_RETSIZE(o) = sz; + THREAD_CREATE(FORK_THREAD(o), fork_run, o); +} + +#include "nspc.h" GWION_IMPORT(shred) { CHECK_OB((t_shred = gwi_mk_type(gwi, "Shred", SZ_INT, t_object))) - CHECK_BB(gwi_class_ini(gwi, t_shred, NULL, NULL)) + CHECK_BB(gwi_class_ini(gwi, t_shred, NULL, shred_dtor)) gwi_item_ini(gwi, "int", "@me"); CHECK_BB(gwi_item_end(gwi, ae_flag_member, NULL)) @@ -136,5 +178,24 @@ GWION_IMPORT(shred) { gwi_item_ini(gwi, "Shred", "me"); gwi_item_end(gwi, ae_flag_const, NULL); SET_FLAG((t_shred), abstract); + + CHECK_OB((t_fork = gwi_mk_type(gwi, "Fork", SZ_INT, t_shred))) + CHECK_BB(gwi_class_ini(gwi, t_fork, NULL, fork_dtor)) + gwi_item_ini(gwi, "int", "@thread"); + CHECK_BB((o_fork_thread = gwi_item_end(gwi, ae_flag_const, NULL))) + gwi_item_ini(gwi, "int", "retsize"); + CHECK_BB((o_fork_retsize = gwi_item_end(gwi, ae_flag_const, NULL))) + o_fork_retval = t_fork->nspc->info->offset; + CHECK_BB(gwi_union_ini(gwi, NULL)) + CHECK_BB(gwi_union_add(gwi, "int", "i")) + CHECK_BB(gwi_union_add(gwi, "float", "f")) + CHECK_BB(gwi_union_add(gwi, "Vec3", "v")) + CHECK_BB(gwi_union_add(gwi, "Vec4", "w")) + CHECK_BB(gwi_union_add(gwi, "VarObject", "o")) + CHECK_BB(gwi_union_end(gwi, ae_flag_const)) + gwi_func_ini(gwi, "int", "join", fork_join); + CHECK_BB(gwi_func_end(gwi, 0)) + CHECK_BB(gwi_class_end(gwi)) + SET_FLAG((t_fork), abstract); return GW_OK; } diff --git a/src/parse/check.c b/src/parse/check.c index 342aee79..e2308522 100644 --- a/src/parse/check.c +++ b/src/parse/check.c @@ -25,7 +25,6 @@ return op_ret; ANN static Type check_exp(const Env env, Exp exp); -ANN static m_bool check_stmt(const Env env, const Stmt stmt); ANN static m_bool check_stmt_list(const Env env, Stmt_List list); ANN m_bool check_class_def(const Env env, const Class_Def class_def); @@ -670,15 +669,6 @@ ANN static Type check_exp_call(const Env env, Exp_Call* exp) { GWDEBUG_EXE return check_exp_call1(env, exp); } -ANN static inline m_bool check_exp_unary_spork1(const Env env, const Stmt code) { - RET_NSPC(check_stmt(env, code)) -} - -ANN Type check_exp_unary_spork(const Env env, const Stmt code) { GWDEBUG_EXE - CHECK_BO(check_exp_unary_spork1(env, code)) - return t_shred; -} - ANN static Type check_exp_unary(const Env env, const Exp_Unary* unary) { GWDEBUG_EXE struct Op_Import opi = { .op=unary->op, .rhs=unary->exp ? check_exp(env, unary->exp) : NULL, .data=(uintptr_t)unary }; @@ -901,9 +891,11 @@ if(env->func->value_ref->type == t_lambda) { if(isa(ret_type, t_null) > 0 && isa(env->func->def->ret_type, t_object) > 0) return GW_OK; - if(isa(ret_type, env->func->def->ret_type) < 0) + if(env->func->def->ret_type && isa(ret_type, env->func->def->ret_type) < 0) ERR_B(stmt->self->pos, "invalid return type '%s' -- expecting '%s'", ret_type->name, env->func->def->ret_type->name) + else //! set defulat return type for lambdas + env->func->def->ret_type = ret_type; return GW_OK; } @@ -971,8 +963,13 @@ ANN m_bool check_stmt_union(const Env env, const Stmt_Union stmt) { GWDEBUG_EXE Decl_List l = stmt->l; do { CHECK_OB(check_exp(env, l->self)) - if(isa(l->self->type, t_object) > 0 && !GET_FLAG(l->self->d.exp_decl.td, ref)) + if(isa(l->self->type, t_object) > 0) { + if(!GET_FLAG(l->self->d.exp_decl.td, ref)) ERR_B(l->self->pos, "In union, Objects must be declared as reference (use '@')") + Var_Decl_List list = l->self->d.exp_decl.list; + do SET_FLAG(list->self->value, pure); + while((list = list->next)); + } if(l->self->type->size > stmt->s) stmt->s = l->self->type->size; } while((l = l->next)); @@ -993,7 +990,7 @@ static const _exp_func stmt_func[] = { (_exp_func)dummy_func, (_exp_func)check_stmt_type, (_exp_func)check_stmt_union, }; -ANN static m_bool check_stmt(const Env env, const Stmt stmt) { GWDEBUG_EXE +ANN m_bool check_stmt(const Env env, const Stmt stmt) { GWDEBUG_EXE return stmt_func[stmt->stmt_type](env, &stmt->d); } diff --git a/src/soundinfo.c b/src/soundinfo.c new file mode 100644 index 00000000..ef8dee6d --- /dev/null +++ b/src/soundinfo.c @@ -0,0 +1,17 @@ +#include +#include + +struct SoundInfo_ *new_soundinfo(void) { + struct SoundInfo_ *si = mp_alloc(SoundInfo); + si->in = si->out = 2; + si->sr = 48000; + return si; +} + +struct SoundInfo_ *soundinfo_cpy(const struct SoundInfo_ *src) { + struct SoundInfo_ *si = mp_alloc(SoundInfo); + si->in = src->in; + si->out = src->out; + si->sr = src->sr; + return si; +} diff --git a/src/vm/shreduler.c b/src/vm/shreduler.c index 0bf67b6a..10043559 100644 --- a/src/vm/shreduler.c +++ b/src/vm/shreduler.c @@ -51,11 +51,11 @@ ANN static void unwind(const VM_Shred shred) { } } -ANN static void shreduler_child(const Shreduler s, const Vector v) { +ANN static void shreduler_child(const Vector v) { for(m_uint i = vector_size(v) + 1; --i;) { const VM_Shred child = (VM_Shred)vector_at(v, i - 1); unwind(child); - shreduler_remove(s, child, 1); + shreduler_remove(child->info->vm->shreduler, child, 1); } } @@ -63,7 +63,7 @@ ANN static void shreduler_erase(const Shreduler s, struct ShredTick_ *tk) { if(tk->parent) shreduler_parent(tk->self, &tk->parent->child); if(tk->child.ptr) - shreduler_child(s, &tk->child); + shreduler_child(&tk->child); vector_rem2(&s->shreds, (vtype)tk->self); } @@ -81,7 +81,7 @@ ANN void shreduler_remove(const Shreduler s, const VM_Shred out, const m_bool er tk->prev = tk->next = NULL; if(erase) { shreduler_erase(s, tk); - free_vm_shred(out); + _release(out->info->me, out); } } diff --git a/src/vm/vm.c b/src/vm/vm.c index c78f51e9..5be7524b 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -80,11 +80,21 @@ ANN void free_vm(VM* vm) { ANN m_uint vm_add_shred(const VM* vm, const VM_Shred shred) { shred->info->vm = (VM*)vm; - shred->info->me = new_shred(shred); + shred->info->me = new_shred(shred, 1); shreduler_add(vm->shreduler, shred); shredule(vm->shreduler, shred, .5); return shred->tick->xid; } +#include "gwion.h" +static int n; +ANN m_uint vm_fork(const VM* src, const VM_Shred shred) { + VM* vm = shred->info->vm = gwion_cpy(src); + shred->info->me = new_shred(shred, 0); + shreduler_add(vm->shreduler, shred); + shredule(vm->shreduler, shred, .5); +shred->tick->xid += (n += 100); + return shred->tick->xid; +} __attribute__((hot)) ANN static inline void vm_ugen_init(const VM* vm) { @@ -125,7 +135,8 @@ ANN static inline m_bool overflow_(const m_bit* mem, const VM_Shred c) { return mem > (((m_bit*)c + sizeof(struct VM_Shred_) + SIZEOF_REG) + (SIZEOF_MEM) - (MEM_STEP)); } -ANN static inline VM_Shred init_spork_shred(const VM_Shred shred, const VM_Code code) { +ANN static inline VM_Shred init_spork_shred(const VM_Shred shred, const Instr instr) { + const VM_Code code = (VM_Code)instr->m_val; const VM_Shred sh = new_vm_shred(code); ADD_REF(code) sh->tick->parent = shred->tick; @@ -133,7 +144,14 @@ ANN static inline VM_Shred init_spork_shred(const VM_Shred shred, const VM_Code vector_init(&shred->tick->child); vector_add(&shred->tick->child, (vtype)sh); sh->base = shred->base; - vm_add_shred(shred->info->vm, sh); + return sh; +} + +ANN static inline VM_Shred init_fork_shred(const VM_Shred shred, const Instr instr) { + const VM_Code code = (VM_Code)instr->m_val; + const VM_Shred sh = new_vm_shred(code); + ADD_REF(code) + sh->base = shred->base; return sh; } @@ -259,7 +277,7 @@ ANN void vm_run(const VM* vm) { // lgtm [cpp/use-of-goto] &&timeadv, &&setcode, &&funcptr, &&funcmember, &&funcusr, &®pop, &®tomem, &&overflow, &&next, &&funcusrend, &&funcmemberend, - &&sporkini, &&sporkfunc, &&sporkthis, &&sporkexp, &&sporkend, + &&sporkini, &&sporkini, &&sporkfunc, &&sporkthis, &&sporkexp, &&forkend, &&sporkend, &&brancheqint, &&branchneint, &&brancheqfloat, &&branchnefloat, &&decintaddr, &&initloop, &&arraytop, &&newobj, @@ -597,7 +615,11 @@ funcmemberend: pc = shred->pc; DISPATCH() sporkini: - a.child = init_spork_shred(shred, (VM_Code)instr->m_val); + a.child = (instr->m_val2 ? init_spork_shred : init_fork_shred)(shred, instr); + if(instr->m_val2) + vm_add_shred(vm, a.child); + else + vm_fork(vm, a.child); DISPATCH() sporkfunc: // LOOP_OPTIM @@ -614,6 +636,8 @@ sporkexp: for(m_uint i = 0; i < instr->m_val; i+= SZ_INT) *(m_uint*)(a.child->mem + i) = *(m_uint*)(mem+i); DISPATCH() +forkend: + fork_launch(a.child->info->me, instr->m_val2); sporkend: *(M_Object*)(reg-SZ_INT) = a.child->info->me; DISPATCH() diff --git a/src/vm/vm_code.c b/src/vm/vm_code.c index fbac5529..7f8be57a 100644 --- a/src/vm/vm_code.c +++ b/src/vm/vm_code.c @@ -28,7 +28,7 @@ ANN static void free_array_info(ArrayInfo* info) { ANN static void free_code_instr(const Vector v) { for(m_uint i = vector_size(v) + 1; --i;) { const Instr instr = (Instr)vector_at(v, i - 1); - if(instr->opcode == (m_uint)SporkIni) + if(instr->opcode == eSporkIni || instr->opcode == eForkIni) REM_REF((VM_Code)instr->m_val) else if(instr->execute == ArrayAlloc) free_array_info((ArrayInfo*)instr->m_val); @@ -44,7 +44,7 @@ ANN static void free_code_instr(const Vector v) { else if(instr->execute == SwitchIni) { free_vector((Vector)instr->m_val); free_map((Map)instr->m_val2); - } else if(instr->opcode == (m_uint)InitLoopCounter) + } else if(instr->opcode == eInitLoopCounter) free((m_int*)instr->m_val); else if(instr->execute == VarargIni) { if(instr->m_val2) diff --git a/tests/tree/fork.gw b/tests/tree/fork.gw new file mode 100644 index 00000000..fd7d6031 --- /dev/null +++ b/tests/tree/fork.gw @@ -0,0 +1,14 @@ +fork \a b { <<>>; return 9; }(1, 2) +@=> Fork @e; +fork \a b { <<>>; }(1, 2) @=> Fork @f; +//fork \a b { <<>>; }(1, 2) @=> Fork @g; +//fork \a { <<>>; }(1) @=> Fork @h; + +<<<"before wait">>>; +e.join(); +f.join(); +//g.join(); +//h.join(); +<<>>; +<<<"after wait">>>; +<<>>; diff --git a/util b/util index b846edc4..a25a0c0e 160000 --- a/util +++ b/util @@ -1 +1 @@ -Subproject commit b846edc401451e7291655a03940094550a339551 +Subproject commit a25a0c0e88bfdf69041c658ff14f7992d78ddcb4 -- 2.43.0