]> Nishi Git Mirror - gwion.git/commitdiff
:art: Fork, initial
authorfennecdjay <astor.jeremie@wanadoo.fr>
Tue, 26 Mar 2019 13:20:37 +0000 (14:20 +0100)
committerfennecdjay <astor.jeremie@wanadoo.fr>
Tue, 26 Mar 2019 13:20:37 +0000 (14:20 +0100)
23 files changed:
.travis.yml
examples/spork_lamba.gw [new file with mode: 0644]
help/test.sh
include/gwion.h
include/import.h
include/object.h
include/opcode.h
include/parse.h
include/soundinfo.h
include/type.h
opcode.txt
src/emit/emit.c
src/gwion.c
src/lib/func.c
src/lib/object.c
src/lib/shred.c
src/parse/check.c
src/soundinfo.c [new file with mode: 0644]
src/vm/shreduler.c
src/vm/vm.c
src/vm/vm_code.c
tests/tree/fork.gw [new file with mode: 0644]
util

index e0e55e6328ff00a2e26e51264dea5528e7c5315a..803224ac6c033631e8e3970743f05d70f161a7e6 100644 (file)
@@ -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 (file)
index 0000000..bf63f32
--- /dev/null
@@ -0,0 +1,2 @@
+spork \ a { <<<a>>>;}(1);
+me.yield();
index aab1648fbff4903820e1b0eeb61f1515bce76039..636854b1733dca0836af0ea500d4eb2504df6870 100644 (file)
@@ -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=$?
index 11ae35a17921167b234e58b36f15b2633c2d8ab3..32f57ff572b9c53aa90c49d546bbbac2aa753736 100644 (file)
@@ -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
index 51cfa3418f1b506f94c81c8ae95cbec2108f1c7f..8928f5ff3835b3d41b630018abb7c5c1fb082b61 100644 (file)
@@ -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
index 850a0ad6879aa36f38b04f9b95943a6ee398684d..b5ce5093dd20889f6a5c44cb625e1e38b02873b0 100644 (file)
@@ -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);
index d43d3c18129b5c139e970cd81441bd2945cc3985..27c1ff82e08d98e48693955a686871c0e998fbba 100644 (file)
@@ -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
index bf79aa3e0561894f8b04c6518088ef159e8ada81..245d483f270d7a2de4a5310459ea3463d713d515 100644 (file)
@@ -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
index 33a861e1b3e175f3c910f02d974e6846929a8eb8..b2537711d26e29697068dcc04ca380b43da20d7d 100644 (file)
@@ -5,4 +5,5 @@ struct SoundInfo_ {
   uint8_t in, out;
   m_str arg;
 };
+struct SoundInfo_ *soundinfo_cpy(const struct SoundInfo_ *src);
 #endif
index cda59b784f2f73f468079b3ed7ed936e73a99b0b..37dd9c1537bade3d478a34872cbaba1d006ac913 100644 (file)
@@ -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);
index 92d958b38bc95bf33f5a900b3e41a9f53765cb06..00a918a244cd7d537b01ecaba841fa9788ab1592 100644 (file)
@@ -126,9 +126,11 @@ Next
 FuncUsrEnd
 FuncMemberEnd
 SporkIni
+ForkIni
 SporkFunc
 SporkThis
 SporkExp
+ForkEnd
 SporkEnd
 BranchEqInt
 BranchNeqInt
index b3f72218ac6c5553dc60c4850cd221c9a292f8ec..72abcc8415f54f9cb3966de7897fa078ce0c4ade 100644 (file)
@@ -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
index d60af87621d7e686802f9ff954739bb70a7bfba4..473d635c83c5b6151e63e59af3364da22d4fe09c 100644 (file)
@@ -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();
index 479959994c6bc7f34dbad6757e7b86e4a0fede16..584f9967c5e60f5c9fe9eb007edb0ab1a1e8d786 100644 (file)
@@ -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;
 }
index 5c4c7e68570af1cceafee20a7d50ece7c1458462..f9968b7506f731f99539762626f3f46c2b816673 100644 (file)
@@ -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)) {
index ba7225e3e5113873309acaafeded49054cdce144..b583b27f6631c5442590a487c5e2be70ea8cad7b 100644 (file)
@@ -2,6 +2,7 @@
 #include <libgen.h>
 #include "gwion_util.h"
 #include "gwion_ast.h"
+#include "gwion_thread.h"
 #include "oo.h"
 #include "vm.h"
 #include "env.h"
 #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;
 }
index 342aee79f3f48b0275d17580662c85d55bff3911..e2308522c441398fc92b1e07d8bf0b526cb145cc 100644 (file)
@@ -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 (file)
index 0000000..ef8dee6
--- /dev/null
@@ -0,0 +1,17 @@
+#include <gwion_util.h>
+#include <soundinfo.h>
+
+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;
+}
index 0bf67b6a9973467026df7bb0ab974b531216fd4b..10043559de408ff7172731dda26e7f01aedab597 100644 (file)
@@ -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);
   }
 }
 
index c78f51e9553ccba2ae725654884b4b0b3210db84..5be7524b15ed53da99b611c193360fb4ba5e94bb 100644 (file)
@@ -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, &&regpop, &&regtomem, &&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()
index fbac5529fc078e2a76d94222c4c3ce2f9294798f..7f8be57a582ecebd09c1e0ede54d773001648c1b 100644 (file)
@@ -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 (file)
index 0000000..fd7d603
--- /dev/null
@@ -0,0 +1,14 @@
+fork \a b { <<<me.id(), " fork ", a, " " , b>>>; return 9; }(1, 2) 
+@=> Fork @e;
+fork \a b { <<<me.id(), " fork ", a, " " , b>>>; }(1, 2) @=> Fork @f;
+//fork \a b { <<<me.id(), " fork ", a, " " , b>>>; }(1, 2) @=> Fork @g;
+//fork \a { <<<me.id(), " ", a>>>; }(1) @=> Fork @h;
+
+<<<"before wait">>>;
+e.join();
+f.join();
+//g.join();
+//h.join();
+<<<e.i>>>;
+<<<"after wait">>>;
+<<<me>>>;
diff --git a/util b/util
index b846edc401451e7291655a03940094550a339551..a25a0c0e88bfdf69041c658ff14f7992d78ddcb4 160000 (submodule)
--- a/util
+++ b/util
@@ -1 +1 @@
-Subproject commit b846edc401451e7291655a03940094550a339551
+Subproject commit a25a0c0e88bfdf69041c658ff14f7992d78ddcb4