--- Coro/Coro/State.xs 2009/10/01 23:51:33 1.373 +++ Coro/Coro/State.xs 2009/10/02 19:55:59 1.374 @@ -1,3 +1,5 @@ +#define NDEBUG 1 + #include "libcoro/coro.c" #define PERL_NO_GET_CONTEXT @@ -14,6 +16,10 @@ #include #include +#ifndef SVs_PADSTALE +# define SVs_PADSTALE 0 +#endif + #ifdef WIN32 # undef setjmp # undef longjmp @@ -252,6 +258,9 @@ AV *on_enter; AV *on_leave; + /* swap_sv */ + AV *swap_sv; + /* times */ coro_ts t_cpu, t_real; @@ -552,6 +561,57 @@ /** load & save, init *******************************************************/ +/* swap sv heads, at least logically */ +static void +swap_svs (pTHX_ Coro__State c) +{ + int i; + + for (i = 0; i <= AvFILLp (c->swap_sv); ) + { + SV *a = AvARRAY (c->swap_sv)[i++]; + SV *b = AvARRAY (c->swap_sv)[i++]; + + const U32 keep = SVs_PADSTALE | SVs_PADTMP | SVs_PADMY; /* keep these flags */ + SV tmp; + + /* swap sv_any */ + SvANY (&tmp) = SvANY (a); SvANY (a) = SvANY (b); SvANY (b) = SvANY (&tmp); + + /* swap sv_flags */ + SvFLAGS (&tmp) = SvFLAGS (a); + SvFLAGS (a) = (SvFLAGS (a) & keep) | (SvFLAGS (b ) & ~keep); + SvFLAGS (b) = (SvFLAGS (b) & keep) | (SvFLAGS (&tmp) & ~keep); + +#if PERL_VERSION_ATLEAST (5,10,0) + /* perl 5.10 complicates this _quite_ a bit, but it also is + * is much faster, so no quarrels here. alternatively, we could + * sv_upgrade to avoid this. + */ + { + /* swap sv_u */ + tmp.sv_u = a->sv_u; a->sv_u = b->sv_u; b->sv_u = tmp.sv_u; + + /* if SvANY points to the head, we need to adjust the pointers, + * as the pointer for a still points to b, and maybe vice versa. + */ + #define svany_in_head(type) \ + (((1 << SVt_NULL) | (1 << SVt_BIND) | (1 << SVt_IV) | (1 << SVt_RV)) & (1 << (type))) + + if (svany_in_head (SvTYPE (a))) + SvANY (a) = (void *)((PTRV)SvANY (a) - (PTRV)b + (PTRV)a); + + if (svany_in_head (SvTYPE (b))) + SvANY (b) = (void *)((PTRV)SvANY (b) - (PTRV)a + (PTRV)b); + } +#endif + } +} + +#define SWAP_SVS(coro) \ + if (expect_false ((coro)->swap_sv)) \ + swap_svs (aTHX_ (coro)) + static void on_enterleave_call (pTHX_ SV *cb); @@ -607,11 +667,15 @@ for (i = 0; i <= AvFILLp (c->on_enter); ++i) on_enterleave_call (aTHX_ AvARRAY (c->on_enter)[i]); } + + SWAP_SVS (c); } static void save_perl (pTHX_ Coro__State c) { + SWAP_SVS (c); + if (expect_false (c->on_leave)) { int i; @@ -656,7 +720,6 @@ if (expect_true (CvDEPTH (cv))) { - EXTEND (SP, 3); PUSHs ((SV *)CvPADLIST (cv)); PUSHs (INT2PTR (SV *, (IV)CvDEPTH (cv))); PUSHs ((SV *)cv); @@ -928,10 +991,10 @@ return 1; } -static UNOP coro_setup_op; +static UNOP init_perl_op; static void NOINLINE /* noinline to keep it out of the transfer fast path */ -coro_setup (pTHX_ struct coro *coro) +init_perl (pTHX_ struct coro *coro) { /* * emulate part of the perl startup here. @@ -990,16 +1053,18 @@ slf_frame.check = slf_check_nop; /* signal pp_slf to not repeat */ /* and we have to provide the pp_slf op in any case, so pp_slf can skip it */ - coro_setup_op.op_next = PL_op; - coro_setup_op.op_type = OP_ENTERSUB; - coro_setup_op.op_ppaddr = pp_slf; + init_perl_op.op_next = PL_op; + init_perl_op.op_type = OP_ENTERSUB; + init_perl_op.op_ppaddr = pp_slf; /* no flags etc. required, as an init function won't be called */ - PL_op = (OP *)&coro_setup_op; + PL_op = (OP *)&init_perl_op; - /* copy throw, in case it was set before coro_setup */ + /* copy throw, in case it was set before init_perl */ CORO_THROW = coro->except; + SWAP_SVS (coro); + if (expect_false (enable_times)) { coro_times_update (); @@ -1029,7 +1094,7 @@ } static void -coro_destruct_perl (pTHX_ struct coro *coro) +destroy_perl (pTHX_ struct coro *coro) { SV *svf [9]; @@ -1044,6 +1109,9 @@ coro_unwind_stacks (aTHX); coro_destruct_stacks (aTHX); + /* restore swapped sv's */ + SWAP_SVS (coro); + // now save some sv's to be free'd later svf [0] = GvSV (PL_defgv); svf [1] = (SV *)GvAV (PL_defgv); @@ -1069,6 +1137,7 @@ SvREFCNT_dec (coro->rouse_cb); SvREFCNT_dec (coro->invoke_cb); SvREFCNT_dec (coro->invoke_av); + SvREFCNT_dec (coro->swap_sv); } } @@ -1494,7 +1563,7 @@ /* need to start coroutine */ next->flags &= ~CF_NEW; /* setup coroutine call */ - coro_setup (aTHX_ next); + init_perl (aTHX_ next); } else load_perl (aTHX_ next); @@ -1567,7 +1636,7 @@ && coro->mainstack != main_mainstack && coro->slot && !PL_dirty) - coro_destruct_perl (aTHX_ coro); + destroy_perl (aTHX_ coro); cctx_destroy (coro->cctx); SvREFCNT_dec (coro->startcv); @@ -3317,6 +3386,26 @@ coro_times_sub (SvSTATE (coro_current)); } +void +swap_sv (Coro::State coro, SV *sv, SV *swapsv) + CODE: +{ + struct coro *current = SvSTATE_current; + + if (current == coro) + SWAP_SVS (current); + + if (!coro->swap_sv) + coro->swap_sv = newAV (); + + av_push (coro->swap_sv, SvREFCNT_inc_NN (sv)); + av_push (coro->swap_sv, SvREFCNT_inc_NN (swapsv)); + + if (current == coro) + SWAP_SVS (current); +} + + MODULE = Coro::State PACKAGE = Coro BOOT: