/* clone implementation, big, slow, useless, but not pointless */ static AV * clone_av (pTHX_ AV *av) { int i; AV *nav = newAV (); av_fill (nav, AvFILLp (av)); for (i = 0; i <= AvFILLp (av); ++i) AvARRAY (nav)[i] = SvREFCNT_inc (AvARRAY (av)[i]); return nav; } static struct coro * coro_clone (pTHX_ struct coro *coro) { perl_slots *slot, *nslot; struct coro *ncoro; if (coro->flags & (CF_RUNNING | CF_NEW)) croak ("Coro::State::clone cannot clone new or running states, caught"); if (coro->cctx) croak ("Coro::State::clone cannot clone a state running on a custom C context, caught"); /* TODO: maybe check slf_frame for prpeare_rransfer/check_nop? */ slot = coro->slot; if (slot->curstackinfo->si_type != PERLSI_MAIN) croak ("Coro::State::clone cannot clone a state running on a non-main stack, caught"); Newz (0, ncoro, 1, struct coro); Newz (0, nslot, 1, perl_slots); /* copy first, then fixup */ *ncoro = *coro; *nslot = *slot; ncoro->slot = nslot; nslot->curstackinfo = new_stackinfo (slot->stack_max - slot->stack_sp + 1, slot->curstackinfo->si_cxmax); nslot->curstackinfo->si_type = PERLSI_MAIN; nslot->curstackinfo->si_cxix = slot->curstackinfo->si_cxix; nslot->curstack = nslot->curstackinfo->si_stack; ncoro->mainstack = nslot->curstack; nslot->stack_base = AvARRAY (nslot->curstack); nslot->stack_sp = nslot->stack_base + (slot->stack_sp - slot->stack_base); nslot->stack_max = nslot->stack_base + AvMAX (nslot->curstack); Copy (slot->stack_base, nslot->stack_base, slot->stack_sp - slot->stack_base + 1, SV *); Copy (slot->curstackinfo->si_cxstack, nslot->curstackinfo->si_cxstack, nslot->curstackinfo->si_cxix + 1, PERL_CONTEXT); New (50, nslot->tmps_stack, nslot->tmps_max, SV *); Copy (slot->tmps_stack, nslot->tmps_stack, slot->tmps_ix + 1, SV *); New (54, nslot->markstack, slot->markstack_max - slot->markstack + 1, I32); nslot->markstack_ptr = nslot->markstack + (slot->markstack_ptr - slot->markstack); nslot->markstack_max = nslot->markstack + (slot->markstack_max - slot->markstack); Copy (slot->markstack, nslot->markstack, slot->markstack_ptr - slot->markstack + 1, I32); #ifdef SET_MARK_OFFSET //SET_MARK_OFFSET; /*TODO*/ #endif New (54, nslot->scopestack, slot->scopestack_max, I32); Copy (slot->scopestack, nslot->scopestack, slot->scopestack_ix + 1, I32); New (54, nslot->savestack, nslot->savestack_max, ANY); Copy (slot->savestack, nslot->savestack, slot->savestack_ix + 1, ANY); #if !PERL_VERSION_ATLEAST (5,10,0) New (54, nslot->retstack, nslot->retstack_max, OP *); Copy (slot->retstack, nslot->retstack, slot->retstack_max, OP *); #endif /* first fix up the padlists, by walking up our own saved state */ { SV **sp = nslot->stack_sp; AV *av; CV *cv; int i; /* now do the ugly restore mess */ while (expect_true (cv = (CV *)POPs)) { /* cv will be refcnt_inc'ed twice by the following two loops */ POPs; /* need to clone the padlist */ /* this simplistic hack is most likely wrong */ av = clone_av (aTHX_ (AV *)TOPs); AvREAL_off (av); for (i = 1; i <= AvFILLp (av); ++i) { SvREFCNT_dec (AvARRAY (av)[i]); AvARRAY (av)[i] = (SV *)clone_av (aTHX_ (AV *)AvARRAY (av)[i]); AvREIFY_only (AvARRAY (av)[i]); } TOPs = (SV *)av; POPs; } } /* easy things first, mortals */ { int i; for (i = 0; i <= nslot->tmps_ix; ++i) SvREFCNT_inc (nslot->tmps_stack [i]); } /* now fix up the context stack, modelled after cx_dup */ { I32 cxix = nslot->curstackinfo->si_cxix; PERL_CONTEXT *ccstk = nslot->curstackinfo->si_cxstack; while (expect_true (cxix >= 0)) { PERL_CONTEXT *cx = &ccstk[cxix--]; switch (CxTYPE (cx)) { case CXt_SUBST: croak ("Coro::State::clone cannot clone a state inside a substitution context, caught"); case CXt_SUB: if (cx->blk_sub.olddepth == 0) SvREFCNT_inc ((SV *)cx->blk_sub.cv); if (cx->blk_sub.hasargs) { SvREFCNT_inc ((SV *)cx->blk_sub.argarray); SvREFCNT_inc ((SV *)cx->blk_sub.savearray); } break; case CXt_EVAL: SvREFCNT_inc ((SV *)cx->blk_eval.old_namesv); SvREFCNT_inc ((SV *)cx->blk_eval.cur_text); break; case CXt_LOOP: /*TODO: cx->blk_loop.iterdata*/ SvREFCNT_inc ((SV *)cx->blk_loop.itersave); SvREFCNT_inc ((SV *)cx->blk_loop.iterlval); SvREFCNT_inc ((SV *)cx->blk_loop.iterary); break; case CXt_FORMAT: croak ("Coro::State::clone cannot clone a state inside a format, caught"); break; /* BLOCK, NULL etc. */ } } } /* now fix up the save stack */ /* modelled after ss_dup */ #define POPINT(ss,ix) ((ss)[--(ix)].any_i32) #define TOPINT(ss,ix) ((ss)[ix].any_i32) #define POPLONG(ss,ix) ((ss)[--(ix)].any_long) #define TOPLONG(ss,ix) ((ss)[ix].any_long) #define POPIV(ss,ix) ((ss)[--(ix)].any_iv) #define TOPIV(ss,ix) ((ss)[ix].any_iv) #define POPBOOL(ss,ix) ((ss)[--(ix)].any_bool) #define TOPBOOL(ss,ix) ((ss)[ix].any_bool) #define POPPTR(ss,ix) ((ss)[--(ix)].any_ptr) #define TOPPTR(ss,ix) ((ss)[ix].any_ptr) #define POPDPTR(ss,ix) ((ss)[--(ix)].any_dptr) #define TOPDPTR(ss,ix) ((ss)[ix].any_dptr) #define POPDXPTR(ss,ix) ((ss)[--(ix)].any_dxptr) #define TOPDXPTR(ss,ix) ((ss)[ix].any_dxptr) { ANY * const ss = nslot->savestack; const I32 max = nslot->savestack_max; I32 ix = nslot->savestack_ix; void *any_ptr; while (ix > 0) { const I32 type = POPINT (ss, ix); switch (type) { case SAVEt_HELEM: /* hash element */ SvREFCNT_inc ((SV *) POPPTR (ss, ix)); /* fall through */ case SAVEt_ITEM: /* normal string */ case SAVEt_SV: /* scalar reference */ SvREFCNT_inc ((SV *) POPPTR (ss, ix)); /* fall through */ case SAVEt_FREESV: case SAVEt_MORTALIZESV: SvREFCNT_inc ((SV *) POPPTR (ss, ix)); break; case SAVEt_SHARED_PVREF: /* char* in shared space */ abort (); #if 0 c = (char *) POPPTR (ss, ix); TOPPTR (ss, ix) = savesharedpv (c); ptr = POPPTR (ss, ix); TOPPTR (ss, ix) = any_dup (ptr, proto_perl); #endif break; case SAVEt_GENERIC_SVREF: /* generic sv */ case SAVEt_SVREF: /* scalar reference */ SvREFCNT_inc ((SV *) POPPTR (ss, ix)); POPPTR (ss, ix); break; case SAVEt_HV: /* hash reference */ case SAVEt_AV: /* array reference */ SvREFCNT_inc ((SV *) POPPTR (ss, ix)); /* fall through */ case SAVEt_COMPPAD: case SAVEt_NSTAB: SvREFCNT_inc ((SV *) POPPTR (ss, ix)); break; case SAVEt_INT: /* int reference */ POPPTR (ss, ix); POPINT (ss, ix); break; case SAVEt_LONG: /* long reference */ POPPTR (ss, ix); /* fall through */ case SAVEt_CLEARSV: POPLONG (ss, ix); break; case SAVEt_I32: /* I32 reference */ case SAVEt_I16: /* I16 reference */ case SAVEt_I8: /* I8 reference */ case SAVEt_COP_ARYBASE: /* call CopARYBASE_set */ POPPTR (ss, ix); POPINT (ss, ix); break; case SAVEt_IV: /* IV reference */ POPPTR (ss, ix); POPIV (ss, ix); break; case SAVEt_HPTR: /* HV* reference */ case SAVEt_APTR: /* AV* reference */ case SAVEt_SPTR: /* SV* reference */ POPPTR (ss, ix); SvREFCNT_inc ((SV *) POPPTR (ss, ix)); break; case SAVEt_VPTR: /* random* reference */ POPPTR (ss, ix); POPPTR (ss, ix); break; case SAVEt_GENERIC_PVREF: /* generic char* */ case SAVEt_PPTR: /* char* reference */ POPPTR (ss, ix); any_ptr = POPPTR (ss, ix); TOPPTR (ss, ix) = savepv ((char *) any_ptr); break; case SAVEt_GP: /* scalar reference */ ((GP *) POPPTR (ss, ix))->gp_refcnt++; SvREFCNT_inc ((SV *) POPPTR (ss, ix)); break; case SAVEt_FREEOP: abort (); #if 0 ptr = POPPTR (ss, ix); if (ptr && (((OP *) ptr)->op_private & OPpREFCOUNTED)) { /* these are assumed to be refcounted properly */ OP *o; switch (((OP *) ptr)->op_type) { case OP_LEAVESUB: case OP_LEAVESUBLV: case OP_LEAVEEVAL: case OP_LEAVE: case OP_SCOPE: case OP_LEAVEWRITE: TOPPTR (ss, ix) = ptr; o = (OP *) ptr; OP_REFCNT_LOCK; (void) OpREFCNT_inc (o); OP_REFCNT_UNLOCK; break; default: TOPPTR (ss, ix) = NULL; break; } } else TOPPTR (ss, ix) = NULL; #endif break; case SAVEt_FREEPV: any_ptr = POPPTR (ss, ix); TOPPTR (ss, ix) = savepv ((char *) any_ptr); break; case SAVEt_DELETE: SvREFCNT_inc ((SV *) POPPTR (ss, ix)); any_ptr = POPPTR (ss, ix); TOPPTR (ss, ix) = savepv ((char *) any_ptr); /* fall through */ case SAVEt_STACK_POS: /* Position on Perl stack */ POPINT (ss, ix); break; case SAVEt_DESTRUCTOR: POPPTR (ss, ix); POPDPTR (ss, ix); break; case SAVEt_DESTRUCTOR_X: POPPTR (ss, ix); POPDXPTR (ss, ix); break; case SAVEt_REGCONTEXT: case SAVEt_ALLOC: { I32 ni = POPINT (ss, ix); ix = ni; } break; case SAVEt_AELEM: /* array element */ SvREFCNT_inc ((SV *) POPPTR (ss, ix)); POPINT (ss, ix); SvREFCNT_inc ((SV *) POPPTR (ss, ix)); break; case SAVEt_OP: POPPTR (ss, ix); break; case SAVEt_HINTS: abort (); #if 0 { int i = POPINT (ss, ix); void *ptr = POPPTR (ss, ix); if (ptr) ((struct refcounted_he *)ptr)->refcounted_he_refcnt++; if (i & HINT_LOCALIZE_HH) SvREFCNT_inc ((SV *) POPPTR (ss, ix)); } #endif break; case SAVEt_PADSV: POPLONG (ss, ix); POPPTR (ss, ix); SvREFCNT_inc ((SV *) POPPTR (ss, ix)); break; case SAVEt_BOOL: POPPTR (ss, ix); POPBOOL (ss, ix); break; case SAVEt_SET_SVFLAGS: POPINT (ss, ix); POPINT (ss, ix); SvREFCNT_inc ((SV *) POPPTR (ss, ix)); break; case SAVEt_RE_STATE: abort (); #if 0 { const struct re_save_state *const old_state = (struct re_save_state *) (ss + ix - SAVESTACK_ALLOC_FOR_RE_SAVE_STATE); struct re_save_state *const new_state = (struct re_save_state *) (ss + ix - SAVESTACK_ALLOC_FOR_RE_SAVE_STATE); Copy (old_state, new_state, 1, struct re_save_state); ix -= SAVESTACK_ALLOC_FOR_RE_SAVE_STATE; new_state->re_state_bostr = pv_dup (old_state->re_state_bostr); new_state->re_state_reginput = pv_dup (old_state->re_state_reginput); new_state->re_state_regeol = pv_dup (old_state->re_state_regeol); new_state->re_state_regoffs = (regexp_paren_pair *) any_dup (old_state->re_state_regoffs, proto_perl); new_state->re_state_reglastparen = (U32 *) any_dup (old_state->re_state_reglastparen, proto_perl); new_state->re_state_reglastcloseparen = (U32 *) any_dup (old_state->re_state_reglastcloseparen, proto_perl); /* XXX This just has to be broken. The old save_re_context code did SAVEGENERICPV(PL_reg_start_tmp); PL_reg_start_tmp is char **. Look above to what the dup code does for SAVEt_GENERIC_PVREF It can never have worked. So this is merely a faithful copy of the exiting bug: */ new_state->re_state_reg_start_tmp = (char **) pv_dup ((char *) old_state->re_state_reg_start_tmp); /* I assume that it only ever "worked" because no-one called (pseudo)fork while the regexp engine had re-entered itself. */ #ifdef PERL_OLD_COPY_ON_WRITE new_state->re_state_nrs = sv_dup (old_state->re_state_nrs, param); #endif new_state->re_state_reg_magic = (MAGIC *) any_dup (old_state->re_state_reg_magic, proto_perl); new_state->re_state_reg_oldcurpm = (PMOP *) any_dup (old_state->re_state_reg_oldcurpm, proto_perl); new_state->re_state_reg_curpm = (PMOP *) any_dup (old_state->re_state_reg_curpm, proto_perl); new_state->re_state_reg_oldsaved = pv_dup (old_state->re_state_reg_oldsaved); new_state->re_state_reg_poscache = pv_dup (old_state->re_state_reg_poscache); new_state->re_state_reg_starttry = pv_dup (old_state->re_state_reg_starttry); break; } #endif case SAVEt_COMPILE_WARNINGS: abort (); #if 0 ptr = POPPTR (ss, ix); TOPPTR (ss, ix) = DUP_WARNINGS ((STRLEN *) ptr); break; #endif case SAVEt_PARSER: abort (); #if 0 ptr = POPPTR (ss, ix); TOPPTR (ss, ix) = parser_dup ((const yy_parser *) ptr, param); break; #endif default: croak ("panic: ss_dup inconsistency (%" IVdf ")", (IV) type); } } } SvREFCNT_inc (nslot->defsv); SvREFCNT_inc (nslot->defav); SvREFCNT_inc (nslot->errsv); SvREFCNT_inc (nslot->irsgv); SvREFCNT_inc (nslot->defoutgv); SvREFCNT_inc (nslot->rs); SvREFCNT_inc (nslot->compcv); SvREFCNT_inc (nslot->diehook); SvREFCNT_inc (nslot->warnhook); SvREFCNT_inc (ncoro->startcv); SvREFCNT_inc (ncoro->args); SvREFCNT_inc (ncoro->except); return ncoro; }