X-Git-Url: https://perl5.git.perl.org/perl5.git/blobdiff_plain/e830ead6522d515d0446426f6fbd3f73a7e49697..0d2925a66a645be5c94e85ffc665c445ed1ca94c:/cop.h diff --git a/cop.h b/cop.h index 9f17b2c..172c265 100644 --- a/cop.h +++ b/cop.h @@ -1,12 +1,138 @@ /* cop.h * - * Copyright (c) 1991-2001, Larry Wall + * Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + * 2000, 2001, 2002, 2003, 2004, by Larry Wall and others * * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. * + * Control ops (cops) are one of the three ops OP_NEXTSTATE, OP_DBSTATE, + * and OP_SETSTATE that (loosely speaking) are separate statements. + * They hold information important for lexical state and error reporting. + * At run time, PL_curcop is set to point to the most recently executed cop, + * and thus can be used to determine our current state. */ +/* A jmpenv packages the state required to perform a proper non-local jump. + * Note that there is a start_env initialized when perl starts, and top_env + * points to this initially, so top_env should always be non-null. + * + * Existence of a non-null top_env->je_prev implies it is valid to call + * longjmp() at that runlevel (we make sure start_env.je_prev is always + * null to ensure this). + * + * je_mustcatch, when set at any runlevel to TRUE, means eval ops must + * establish a local jmpenv to handle exception traps. Care must be taken + * to restore the previous value of je_mustcatch before exiting the + * stack frame iff JMPENV_PUSH was not called in that stack frame. + * GSAR 97-03-27 + */ + +struct jmpenv { + struct jmpenv * je_prev; + Sigjmp_buf je_buf; /* only for use if !je_throw */ + int je_ret; /* last exception thrown */ + bool je_mustcatch; /* need to call longjmp()? */ +}; + +typedef struct jmpenv JMPENV; + +#ifdef OP_IN_REGISTER +#define OP_REG_TO_MEM PL_opsave = op +#define OP_MEM_TO_REG op = PL_opsave +#else +#define OP_REG_TO_MEM NOOP +#define OP_MEM_TO_REG NOOP +#endif + +/* + * How to build the first jmpenv. + * + * top_env needs to be non-zero. It points to an area + * in which longjmp() stuff is stored, as C callstack + * info there at least is thread specific this has to + * be per-thread. Otherwise a 'die' in a thread gives + * that thread the C stack of last thread to do an eval {}! + */ + +#define JMPENV_BOOTSTRAP \ + STMT_START { \ + Zero(&PL_start_env, 1, JMPENV); \ + PL_start_env.je_ret = -1; \ + PL_start_env.je_mustcatch = TRUE; \ + PL_top_env = &PL_start_env; \ + } STMT_END + +/* + * PERL_FLEXIBLE_EXCEPTIONS + * + * All the flexible exceptions code has been removed. + * See the following threads for details: + * + * http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2004-07/msg00378.html + * + * Joshua's original patches (which weren't applied) and discussion: + * + * http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/1998-02/msg01396.html + * http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/1998-02/msg01489.html + * http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/1998-02/msg01491.html + * http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/1998-02/msg01608.html + * http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/1998-02/msg02144.html + * http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/1998-02/msg02998.html + * + * Chip's reworked patch and discussion: + * + * http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/1999-03/msg00520.html + * + * The flaw in these patches (which went unnoticed at the time) was + * that they moved some code that could potentially die() out of the + * region protected by the setjmp()s. This caused exceptions within + * END blocks and such to not be handled by the correct setjmp(). + * + * The original patches that introduces flexible exceptions were: + * + * http://public.activestate.com/cgi-bin/perlbrowse?patch=3386 + * http://public.activestate.com/cgi-bin/perlbrowse?patch=5162 + */ + +#define dJMPENV JMPENV cur_env + +#define JMPENV_PUSH(v) \ + STMT_START { \ + DEBUG_l(Perl_deb(aTHX_ "Setting up jumplevel %p, was %p\n", \ + &cur_env, PL_top_env)); \ + cur_env.je_prev = PL_top_env; \ + OP_REG_TO_MEM; \ + cur_env.je_ret = PerlProc_setjmp(cur_env.je_buf, SCOPE_SAVES_SIGNAL_MASK); \ + OP_MEM_TO_REG; \ + PL_top_env = &cur_env; \ + cur_env.je_mustcatch = FALSE; \ + (v) = cur_env.je_ret; \ + } STMT_END + +#define JMPENV_POP \ + STMT_START { \ + DEBUG_l(Perl_deb(aTHX_ "popping jumplevel was %p, now %p\n", \ + PL_top_env, cur_env.je_prev)); \ + PL_top_env = cur_env.je_prev; \ + } STMT_END + +#define JMPENV_JUMP(v) \ + STMT_START { \ + OP_REG_TO_MEM; \ + if (PL_top_env->je_prev) \ + PerlProc_longjmp(PL_top_env->je_buf, (v)); \ + if ((v) == 2) \ + PerlProc_exit(STATUS_NATIVE_EXPORT); \ + PerlIO_printf(PerlIO_stderr(), "panic: top_env\n"); \ + PerlProc_exit(1); \ + } STMT_END + +#define CATCH_GET (PL_top_env->je_mustcatch) +#define CATCH_SET(v) (PL_top_env->je_mustcatch = (v)) + + + struct cop { BASEOP char * cop_label; /* label for this construct */ @@ -30,13 +156,25 @@ struct cop { # define CopFILE(c) ((c)->cop_file) # define CopFILEGV(c) (CopFILE(c) \ ? gv_fetchfile(CopFILE(c)) : Nullgv) -# define CopFILE_set(c,pv) ((c)->cop_file = savepv(pv)) + +# ifdef NETWARE +# define CopFILE_set(c,pv) ((c)->cop_file = savepv(pv)) +# else +# define CopFILE_set(c,pv) ((c)->cop_file = savesharedpv(pv)) +# endif + # define CopFILESV(c) (CopFILE(c) \ ? GvSV(gv_fetchfile(CopFILE(c))) : Nullsv) # define CopFILEAV(c) (CopFILE(c) \ ? GvAV(gv_fetchfile(CopFILE(c))) : Nullav) # define CopSTASHPV(c) ((c)->cop_stashpv) -# define CopSTASHPV_set(c,pv) ((c)->cop_stashpv = ((pv) ? savepv(pv) : Nullch)) + +# ifdef NETWARE +# define CopSTASHPV_set(c,pv) ((c)->cop_stashpv = ((pv) ? savepv(pv) : Nullch)) +# else +# define CopSTASHPV_set(c,pv) ((c)->cop_stashpv = savesharedpv(pv)) +# endif + # define CopSTASH(c) (CopSTASHPV(c) \ ? gv_stashpv(CopSTASHPV(c),GV_ADD) : Nullhv) # define CopSTASH_set(c,hv) CopSTASHPV_set(c, (hv) ? HvNAME(hv) : Nullch) @@ -44,6 +182,17 @@ struct cop { && (CopSTASHPV(c) == HvNAME(hv) \ || (CopSTASHPV(c) && HvNAME(hv) \ && strEQ(CopSTASHPV(c), HvNAME(hv))))) +# ifdef NETWARE +# define CopSTASH_free(c) SAVECOPSTASH_FREE(c) +# else +# define CopSTASH_free(c) PerlMemShared_free(CopSTASHPV(c)) +# endif + +# ifdef NETWARE +# define CopFILE_free(c) SAVECOPFILE_FREE(c) +# else +# define CopFILE_free(c) (PerlMemShared_free(CopFILE(c)),(CopFILE(c) = Nullch)) +# endif #else # define CopFILEGV(c) ((c)->cop_filegv) # define CopFILEGV_set(c,gv) ((c)->cop_filegv = (GV*)SvREFCNT_inc(gv)) @@ -57,6 +206,9 @@ struct cop { /* cop_stash is not refcounted */ # define CopSTASHPV_set(c,pv) CopSTASH_set((c), gv_stashpv(pv,GV_ADD)) # define CopSTASH_eq(c,hv) (CopSTASH(c) == (hv)) +# define CopSTASH_free(c) +# define CopFILE_free(c) (SvREFCNT_dec(CopFILEGV(c)),(CopFILEGV(c) = Nullgv)) + #endif /* USE_ITHREADS */ #define CopSTASH_ne(c,hv) (!CopSTASH_eq(c,hv)) @@ -65,6 +217,13 @@ struct cop { #define CopLINE_dec(c) (--CopLINE(c)) #define CopLINE_set(c,l) (CopLINE(c) = (l)) +/* OutCopFILE() is CopFILE for output (caller, die, warn, etc.) */ +#ifdef MACOS_TRADITIONAL +# define OutCopFILE(c) MacPerl_MPWFileName(CopFILE(c)) +#else +# define OutCopFILE(c) CopFILE(c) +#endif + /* * Here we have some enormously heavy (or at least ponderous) wizardry. */ @@ -74,46 +233,62 @@ struct block_sub { CV * cv; GV * gv; GV * dfoutgv; -#ifndef USE_5005THREADS AV * savearray; -#endif /* USE_5005THREADS */ AV * argarray; - U16 olddepth; + long olddepth; U8 hasargs; U8 lval; /* XXX merge lval and hasargs? */ - SV ** oldcurpad; + PAD *oldcomppad; + OP * retop; /* op to execute on exit from sub */ }; -#define PUSHSUB(cx) \ +/* base for the next two macros. Don't use directly. + * Note that the refcnt of the cv is incremented twice; The CX one is + * decremented by LEAVESUB, the other by LEAVE. */ + +#define PUSHSUB_BASE(cx) \ cx->blk_sub.cv = cv; \ cx->blk_sub.olddepth = CvDEPTH(cv); \ cx->blk_sub.hasargs = hasargs; \ + cx->blk_sub.retop = Nullop; \ + if (!CvDEPTH(cv)) { \ + (void)SvREFCNT_inc(cv); \ + (void)SvREFCNT_inc(cv); \ + SAVEFREESV(cv); \ + } + + +#define PUSHSUB(cx) \ + PUSHSUB_BASE(cx) \ cx->blk_sub.lval = PL_op->op_private & \ (OPpLVAL_INTRO|OPpENTERSUB_INARGS); +/* variant for use by OP_DBSTATE, where op_private holds hint bits */ +#define PUSHSUB_DB(cx) \ + PUSHSUB_BASE(cx) \ + cx->blk_sub.lval = 0; + + #define PUSHFORMAT(cx) \ cx->blk_sub.cv = cv; \ cx->blk_sub.gv = gv; \ + cx->blk_sub.retop = Nullop; \ cx->blk_sub.hasargs = 0; \ cx->blk_sub.dfoutgv = PL_defoutgv; \ (void)SvREFCNT_inc(cx->blk_sub.dfoutgv) -#ifdef USE_5005THREADS -# define POP_SAVEARRAY() NOOP -#else -# define POP_SAVEARRAY() \ +#define POP_SAVEARRAY() \ STMT_START { \ SvREFCNT_dec(GvAV(PL_defgv)); \ GvAV(PL_defgv) = cx->blk_sub.savearray; \ } STMT_END -#endif /* USE_5005THREADS */ /* junk in @_ spells trouble when cloning CVs and in pp_caller(), so don't * leave any (a fast av_clear(ary), basically) */ #define CLEAR_ARGARRAY(ary) \ STMT_START { \ AvMAX(ary) += AvARRAY(ary) - AvALLOC(ary); \ - SvPVX(ary) = (char*)AvALLOC(ary); \ + SvPV_set(ary, (char*)AvALLOC(ary)); \ AvFILLp(ary) = -1; \ } STMT_END @@ -128,7 +303,7 @@ struct block_sub { cx->blk_sub.argarray = newAV(); \ av_extend(cx->blk_sub.argarray, fill); \ AvFLAGS(cx->blk_sub.argarray) = AVf_REIFY; \ - cx->blk_sub.oldcurpad[0] = (SV*)cx->blk_sub.argarray; \ + CX_CURPAD_SV(cx->blk_sub, 0) = (SV*)cx->blk_sub.argarray; \ } \ else { \ CLEAR_ARGARRAY(cx->blk_sub.argarray); \ @@ -157,6 +332,7 @@ struct block_eval { OP * old_eval_root; SV * cur_text; CV * cv; + OP * retop; /* op to execute on exit from eval */ }; #define PUSHEVAL(cx,n,fgv) \ @@ -167,6 +343,7 @@ struct block_eval { cx->blk_eval.old_eval_root = PL_eval_root; \ cx->blk_eval.cur_text = PL_linestr; \ cx->blk_eval.cv = Nullcv; /* set by doeval(), as applicable */ \ + cx->blk_eval.retop = Nullop; \ } STMT_END #define POPEVAL(cx) \ @@ -187,7 +364,7 @@ struct block_loop { OP * last_op; #ifdef USE_ITHREADS void * iterdata; - SV ** oldcurpad; + PAD *oldcomppad; #else SV ** itervar; #endif @@ -202,18 +379,23 @@ struct block_loop { # define CxITERVAR(c) \ ((c)->blk_loop.iterdata \ ? (CxPADLOOP(cx) \ - ? &((c)->blk_loop.oldcurpad)[INT2PTR(PADOFFSET, (c)->blk_loop.iterdata)] \ + ? &CX_CURPAD_SV( (c)->blk_loop, \ + INT2PTR(PADOFFSET, (c)->blk_loop.iterdata)) \ : &GvSV((GV*)(c)->blk_loop.iterdata)) \ : (SV**)NULL) # define CX_ITERDATA_SET(cx,idata) \ - cx->blk_loop.oldcurpad = PL_curpad; \ + CX_CURPAD_SAVE(cx->blk_loop); \ if ((cx->blk_loop.iterdata = (idata))) \ - cx->blk_loop.itersave = SvREFCNT_inc(*CxITERVAR(cx)); + cx->blk_loop.itersave = SvREFCNT_inc(*CxITERVAR(cx)); \ + else \ + cx->blk_loop.itersave = Nullsv; #else # define CxITERVAR(c) ((c)->blk_loop.itervar) # define CX_ITERDATA_SET(cx,ivar) \ if ((cx->blk_loop.itervar = (SV**)(ivar))) \ - cx->blk_loop.itersave = SvREFCNT_inc(*CxITERVAR(cx)); + cx->blk_loop.itersave = SvREFCNT_inc(*CxITERVAR(cx)); \ + else \ + cx->blk_loop.itersave = Nullsv; #endif #define PUSHLOOP(cx, dat, s) \ @@ -241,7 +423,6 @@ struct block_loop { struct block { I32 blku_oldsp; /* stack pointer to copy stuff down to */ COP * blku_oldcop; /* old curcop pointer */ - I32 blku_oldretsp; /* return stack index */ I32 blku_oldmarksp; /* mark stack index */ I32 blku_oldscopesp; /* scope stack index */ PMOP * blku_oldpm; /* values of pattern match vars */ @@ -255,7 +436,6 @@ struct block { }; #define blk_oldsp cx_u.cx_blk.blku_oldsp #define blk_oldcop cx_u.cx_blk.blku_oldcop -#define blk_oldretsp cx_u.cx_blk.blku_oldretsp #define blk_oldmarksp cx_u.cx_blk.blku_oldmarksp #define blk_oldscopesp cx_u.cx_blk.blku_oldscopesp #define blk_oldpm cx_u.cx_blk.blku_oldpm @@ -271,9 +451,8 @@ struct block { cx->blk_oldcop = PL_curcop, \ cx->blk_oldmarksp = PL_markstack_ptr - PL_markstack, \ cx->blk_oldscopesp = PL_scopestack_ix, \ - cx->blk_oldretsp = PL_retstack_ix, \ cx->blk_oldpm = PL_curpm, \ - cx->blk_gimme = gimme; \ + cx->blk_gimme = (U8)gimme; \ DEBUG_l( PerlIO_printf(Perl_debug_log, "Entering block %ld, type %s\n", \ (long)cxstack_ix, PL_block_type[CxTYPE(cx)]); ) @@ -283,9 +462,9 @@ struct block { PL_curcop = cx->blk_oldcop, \ PL_markstack_ptr = PL_markstack + cx->blk_oldmarksp, \ PL_scopestack_ix = cx->blk_oldscopesp, \ - PL_retstack_ix = cx->blk_oldretsp, \ pm = cx->blk_oldpm, \ gimme = cx->blk_gimme; \ + DEBUG_SCOPE("POPBLOCK"); \ DEBUG_l( PerlIO_printf(Perl_debug_log, "Leaving block %ld, type %s\n", \ (long)cxstack_ix+1,PL_block_type[CxTYPE(cx)]); ) @@ -294,8 +473,8 @@ struct block { PL_stack_sp = PL_stack_base + cx->blk_oldsp, \ PL_markstack_ptr = PL_markstack + cx->blk_oldmarksp, \ PL_scopestack_ix = cx->blk_oldscopesp, \ - PL_retstack_ix = cx->blk_oldretsp, \ - PL_curpm = cx->blk_oldpm + PL_curpm = cx->blk_oldpm; \ + DEBUG_SCOPE("TOPBLOCK"); /* substitution context */ struct subst { @@ -388,7 +567,9 @@ struct context { #define CXINC (cxstack_ix < cxstack_max ? ++cxstack_ix : (cxstack_ix = cxinc())) -/* "gimme" values */ +/* +=head1 "Gimme" Values +*/ /* =for apidoc AmU||G_SCALAR @@ -520,3 +701,7 @@ typedef struct stackinfo PERL_SI; POPSTACK; \ } \ } STMT_END + +#define IN_PERL_COMPILETIME (PL_curcop == &PL_compiling) +#define IN_PERL_RUNTIME (PL_curcop != &PL_compiling) +