X-Git-Url: https://perl5.git.perl.org/perl5.git/blobdiff_plain/c5bed6a7fce592c2ad5feb351b09e8f9ce8c18c5..91c3081c6723940aaa1f980c9771b998eb7ba73c:/cop.h diff --git a/cop.h b/cop.h index 7c4c721..39a6b01 100644 --- a/cop.h +++ b/cop.h @@ -1,7 +1,7 @@ /* cop.h * - * Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - * 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, by Larry Wall and others + * Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + * 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 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. @@ -139,7 +139,7 @@ struct cop { /* On LP64 putting this here takes advantage of the fact that BASEOP isn't an exact multiple of 8 bytes to save structure padding. */ line_t cop_line; /* line # of this command */ - char * cop_label; /* label for this construct */ + /* label for this construct is now stored in cop_hints_hash */ #ifdef USE_ITHREADS char * cop_stashpv; /* package line was compiled in */ char * cop_file; /* file name the following line # is from */ @@ -191,18 +191,12 @@ struct cop { ? gv_stashpv(CopSTASHPV(c),GV_ADD) : NULL) # define CopSTASH_set(c,hv) CopSTASHPV_set(c, (hv) ? HvNAME_get(hv) : NULL) # define CopSTASH_eq(c,hv) ((hv) && stashpv_hvname_match(c,hv)) -# define CopLABEL(c) ((c)->cop_label) -# define CopLABEL_set(c,pv) (CopLABEL(c) = (pv)) # ifdef NETWARE # define CopSTASH_free(c) SAVECOPSTASH_FREE(c) # define CopFILE_free(c) SAVECOPFILE_FREE(c) -# define CopLABEL_free(c) SAVECOPLABEL_FREE(c) -# define CopLABEL_alloc(pv) ((pv)?savepv(pv):NULL) # else # define CopSTASH_free(c) PerlMemShared_free(CopSTASHPV(c)) # define CopFILE_free(c) (PerlMemShared_free(CopFILE(c)),(CopFILE(c) = NULL)) -# define CopLABEL_free(c) (PerlMemShared_free(CopLABEL(c)),(CopLABEL(c) = NULL)) -# define CopLABEL_alloc(pv) ((pv)?savesharedpv(pv):NULL) # endif #else # define CopFILEGV(c) ((c)->cop_filegv) @@ -219,19 +213,17 @@ struct cop { # define CopFILE(c) (CopFILEGV(c) && GvSV(CopFILEGV(c)) \ ? SvPVX(GvSV(CopFILEGV(c))) : NULL) # define CopSTASH(c) ((c)->cop_stash) -# define CopLABEL(c) ((c)->cop_label) # define CopSTASH_set(c,hv) ((c)->cop_stash = (hv)) # define CopSTASHPV(c) (CopSTASH(c) ? HvNAME_get(CopSTASH(c)) : NULL) /* 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 CopLABEL_alloc(pv) ((pv)?savepv(pv):NULL) -# define CopLABEL_set(c,pv) (CopLABEL(c) = (pv)) # define CopSTASH_free(c) # define CopFILE_free(c) (SvREFCNT_dec(CopFILEGV(c)),(CopFILEGV(c) = NULL)) -# define CopLABEL_free(c) (Safefree(CopLABEL(c)),(CopLABEL(c) = NULL)) #endif /* USE_ITHREADS */ +#define CopLABEL(c) Perl_fetch_cop_label(aTHX_ (c)->cop_hints_hash, NULL, NULL) +#define CopLABEL_alloc(pv) ((pv)?savepv(pv):NULL) #define CopSTASH_ne(c,hv) (!CopSTASH_eq(c,hv)) #define CopLINE(c) ((c)->cop_line) @@ -306,8 +298,8 @@ struct block_format { #define PUSHSUB_BASE(cx) \ ENTRY_PROBE(GvENAME(CvGV(cv)), \ - CopFILE((COP*)CvSTART(cv)), \ - CopLINE((COP*)CvSTART(cv))); \ + CopFILE((const COP *)CvSTART(cv)), \ + CopLINE((const COP *)CvSTART(cv))); \ \ cx->blk_sub.cv = cv; \ cx->blk_sub.olddepth = CvDEPTH(cv); \ @@ -355,9 +347,9 @@ struct block_format { #define POPSUB(cx,sv) \ STMT_START { \ - RETURN_PROBE(GvENAME(CvGV((CV*)cx->blk_sub.cv)), \ - CopFILE((COP*)CvSTART((CV*)cx->blk_sub.cv)), \ - CopLINE((COP*)CvSTART((CV*)cx->blk_sub.cv))); \ + RETURN_PROBE(GvENAME(CvGV((const CV*)cx->blk_sub.cv)), \ + CopFILE((COP*)CvSTART((const CV*)cx->blk_sub.cv)), \ + CopLINE((COP*)CvSTART((const CV*)cx->blk_sub.cv))); \ \ if (CxHASARGS(cx)) { \ POP_SAVEARRAY(); \ @@ -368,14 +360,14 @@ struct block_format { cx->blk_sub.argarray = newAV(); \ av_extend(cx->blk_sub.argarray, fill); \ AvREIFY_only(cx->blk_sub.argarray); \ - CX_CURPAD_SV(cx->blk_sub, 0) = (SV*)cx->blk_sub.argarray; \ + CX_CURPAD_SV(cx->blk_sub, 0) = MUTABLE_SV(cx->blk_sub.argarray); \ } \ else { \ CLEAR_ARGARRAY(cx->blk_sub.argarray); \ } \ } \ - sv = (SV*)cx->blk_sub.cv; \ - if (sv && (CvDEPTH((CV*)sv) = cx->blk_sub.olddepth)) \ + sv = MUTABLE_SV(cx->blk_sub.cv); \ + if (sv && (CvDEPTH((const CV*)sv) = cx->blk_sub.olddepth)) \ sv = NULL; \ } STMT_END @@ -407,7 +399,7 @@ struct block_eval { #define CxOLD_IN_EVAL(cx) (((cx)->blk_u16) & 0x7F) #define CxOLD_OP_TYPE(cx) (((cx)->blk_u16) >> 7) -#define PUSHEVAL(cx,n,fgv) \ +#define PUSHEVAL(cx,n) \ STMT_START { \ assert(!(PL_in_eval & ~0x7F)); \ assert(!(PL_op->op_type & ~0x1FF)); \ @@ -436,59 +428,47 @@ struct block_loop { /* (except for non_ithreads we need to modify next_op in pp_ctl.c, hence why next_op is conditionally defined below.) */ #ifdef USE_ITHREADS - void * iterdata; - PAD *oldcomppad; + PAD *oldcomppad; /* Also used for the GV, if targoffset is 0 */ + /* This is also accesible via cx->blk_loop.my_op->op_targ */ + PADOFFSET targoffset; #else OP * next_op; SV ** itervar; #endif - SV * itersave; - /* (from inspection of source code) for a .. range of strings this is the - current string. */ - SV * iterlval; - /* (from inspection of source code) for a foreach loop this is the array - being iterated over. For a .. range of numbers it's the current value. - A check is often made on the SvTYPE of iterary to determine whether - we are iterating over an array or a range. (numbers or strings) */ - AV * iterary; - IV iterix; - /* (from inspection of source code) for a .. range of numbers this is the - maximum value. */ - IV itermax; + union { + struct { /* valid if type is LOOP_FOR or LOOP_PLAIN (but {NULL,0})*/ + AV * ary; /* use the stack if this is NULL */ + IV ix; + } ary; + struct { /* valid if type is LOOP_LAZYIV */ + IV cur; + IV end; + } lazyiv; + struct { /* valid if type if LOOP_LAZYSV */ + SV * cur; + SV * end; /* maxiumum value (or minimum in reverse) */ + } lazysv; + } state_u; }; -/* It might be possible to squeeze this structure further. As best I can tell - itermax and iterlval are never used at the same time, so it might be possible - to make them into a union. However, I'm not confident that there are enough - flag bits/NULLable pointers in this structure alone to encode which is - active. There is, however, U8 of space free in struct block, which could be - used. Right now it may not be worth squeezing this structure further, as it's - the largest part of struct block, and currently struct block is 64 bytes on - an ILP32 system, which will give good cache alignment. -*/ #ifdef USE_ITHREADS # define CxITERVAR(c) \ - ((c)->blk_loop.iterdata \ - ? (CxPADLOOP(cx) \ - ? &CX_CURPAD_SV( (c)->blk_loop, \ - INT2PTR(PADOFFSET, (c)->blk_loop.iterdata)) \ - : &GvSV((GV*)(c)->blk_loop.iterdata)) \ + ((c)->blk_loop.oldcomppad \ + ? (CxPADLOOP(c) \ + ? &CX_CURPAD_SV( (c)->blk_loop, (c)->blk_loop.targoffset ) \ + : &GvSV((GV*)(c)->blk_loop.oldcomppad)) \ : (SV**)NULL) -# define CX_ITERDATA_SET(cx,idata) \ - CX_CURPAD_SAVE(cx->blk_loop); \ - if ((cx->blk_loop.iterdata = (idata))) \ - cx->blk_loop.itersave = SvREFCNT_inc(*CxITERVAR(cx)); \ +# define CX_ITERDATA_SET(cx,idata,o) \ + if ((cx->blk_loop.targoffset = (o))) \ + CX_CURPAD_SAVE(cx->blk_loop); \ else \ - cx->blk_loop.itersave = NULL; + cx->blk_loop.oldcomppad = (idata); #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)); \ - else \ - cx->blk_loop.itersave = NULL; +# define CX_ITERDATA_SET(cx,ivar,o) \ + cx->blk_loop.itervar = (SV**)(ivar); #endif -#define CxLABEL(c) (0 + (c)->blk_oldcop->cop_label) +#define CxLABEL(c) (0 + CopLABEL((c)->blk_oldcop)) #define CxHASARGS(c) (((c)->cx_type & CXp_HASARGS) == CXp_HASARGS) #define CxLVAL(c) (0 + (c)->blk_u16) @@ -500,29 +480,29 @@ struct block_loop { # define CX_LOOP_NEXTOP_GET(cx) ((cx)->blk_loop.next_op + 0) #endif -#define PUSHLOOP(cx, dat, s) \ +#define PUSHLOOP_PLAIN(cx, s) \ + cx->blk_loop.resetsp = s - PL_stack_base; \ + cx->blk_loop.my_op = cLOOP; \ + PUSHLOOP_OP_NEXT; \ + cx->blk_loop.state_u.ary.ary = NULL; \ + cx->blk_loop.state_u.ary.ix = 0; \ + CX_ITERDATA_SET(cx, NULL, 0); + +#define PUSHLOOP_FOR(cx, dat, s, offset) \ cx->blk_loop.resetsp = s - PL_stack_base; \ cx->blk_loop.my_op = cLOOP; \ PUSHLOOP_OP_NEXT; \ - cx->blk_loop.iterlval = NULL; \ - cx->blk_loop.iterary = NULL; \ - cx->blk_loop.iterix = -1; \ - CX_ITERDATA_SET(cx,dat); + cx->blk_loop.state_u.ary.ary = NULL; \ + cx->blk_loop.state_u.ary.ix = 0; \ + CX_ITERDATA_SET(cx, dat, offset); #define POPLOOP(cx) \ - SvREFCNT_dec(cx->blk_loop.iterlval); \ - if (CxITERVAR(cx)) { \ - if (SvPADMY(cx->blk_loop.itersave)) { \ - SV ** const s_v_p = CxITERVAR(cx); \ - sv_2mortal(*s_v_p); \ - *s_v_p = cx->blk_loop.itersave; \ - } \ - else { \ - SvREFCNT_dec(cx->blk_loop.itersave); \ - } \ + if (CxTYPE(cx) == CXt_LOOP_LAZYSV) { \ + SvREFCNT_dec(cx->blk_loop.state_u.lazysv.cur); \ + SvREFCNT_dec(cx->blk_loop.state_u.lazysv.end); \ } \ - if (cx->blk_loop.iterary && cx->blk_loop.iterary != PL_curstack)\ - SvREFCNT_dec(cx->blk_loop.iterary); + if (CxTYPE(cx) == CXt_LOOP_FOR) \ + SvREFCNT_dec(cx->blk_loop.state_u.ary.ary); /* given/when context */ struct block_givwhen { @@ -601,11 +581,10 @@ struct block { /* substitution context */ struct subst { U8 sbu_type; /* what kind of context this is */ - U8 sbu_once; /* Actually both booleans, but U8/U16 */ + U8 sbu_rflags; U16 sbu_rxtainted; /* matches struct block */ I32 sbu_iters; I32 sbu_maxiters; - I32 sbu_rflags; I32 sbu_oldsave; char * sbu_orig; SV * sbu_dstr; @@ -631,12 +610,12 @@ struct subst { #define sb_rxres cx_u.cx_subst.sbu_rxres #define sb_rx cx_u.cx_subst.sbu_rx -#define PUSHSUBST(cx) CXINC, cx = &cxstack[cxstack_ix], \ +#ifdef PERL_CORE +# define PUSHSUBST(cx) CXINC, cx = &cxstack[cxstack_ix], \ cx->sb_iters = iters, \ cx->sb_maxiters = maxiters, \ cx->sb_rflags = r_flags, \ cx->sb_oldsave = oldsave, \ - cx->sb_once = once, \ cx->sb_rxtainted = rxtainted, \ cx->sb_orig = orig, \ cx->sb_dstr = dstr, \ @@ -646,15 +625,16 @@ struct subst { cx->sb_strend = strend, \ cx->sb_rxres = NULL, \ cx->sb_rx = rx, \ - cx->cx_type = CXt_SUBST; \ + cx->cx_type = CXt_SUBST | (once ? CXp_ONCE : 0); \ rxres_save(&cx->sb_rxres, rx); \ (void)ReREFCNT_inc(rx) -#define CxONCE(cx) (0 + cx->sb_once) - -#define POPSUBST(cx) cx = &cxstack[cxstack_ix--]; \ +# define POPSUBST(cx) cx = &cxstack[cxstack_ix--]; \ rxres_free(&cx->sb_rxres); \ ReREFCNT_dec(cx->sb_rx) +#endif + +#define CxONCE(cx) ((cx)->cx_type & CXp_ONCE) struct context { union { @@ -664,16 +644,27 @@ struct context { }; #define cx_type cx_u.cx_subst.sbu_type +/* If you re-order these, there is also an array of uppercase names in perl.h + and a static array of context names in pp_ctl.c */ #define CXTYPEMASK 0xf #define CXt_NULL 0 -#define CXt_SUB 1 -#define CXt_EVAL 2 -#define CXt_LOOP 3 -#define CXt_SUBST 4 -#define CXt_BLOCK 5 -#define CXt_FORMAT 6 -#define CXt_GIVEN 7 -#define CXt_WHEN 8 +#define CXt_WHEN 1 +#define CXt_BLOCK 2 +/* When micro-optimising :-) keep GIVEN next to the LOOPs, as these 5 share a + jump table in pp_ctl.c + The first 4 don't have a 'case' in at least one switch statement in pp_ctl.c +*/ +#define CXt_GIVEN 3 +/* This is first so that CXt_LOOP_FOR|CXt_LOOP_LAZYIV is CXt_LOOP_LAZYIV */ +#define CXt_LOOP_FOR 4 +#define CXt_LOOP_PLAIN 5 +#define CXt_LOOP_LAZYSV 6 +#define CXt_LOOP_LAZYIV 7 +#define CXt_SUB 8 +#define CXt_FORMAT 9 +#define CXt_EVAL 10 +#define CXt_SUBST 11 +/* SUBST doesn't feature in all switch statements. */ /* private flags for CXt_SUB and CXt_NULL However, this is checked in many places which do not check the type, so @@ -691,25 +682,24 @@ struct context { /* private flags for CXt_LOOP */ #define CXp_FOR_DEF 0x10 /* foreach using $_ */ -#define CXp_FOREACH 0x20 /* a foreach loop */ #ifdef USE_ITHREADS -# define CXp_PADVAR 0x40 /* itervar lives on pad, iterdata has pad - offset; if not set, iterdata holds GV* */ -# define CxPADLOOP(c) (((c)->cx_type & (CXt_LOOP|CXp_PADVAR)) \ - == (CXt_LOOP|CXp_PADVAR)) +# define CxPADLOOP(c) ((c)->blk_loop.targoffset) #endif +/* private flags for CXt_SUBST */ +#define CXp_ONCE 0x10 /* What was sbu_once in struct subst */ + #define CxTYPE(c) ((c)->cx_type & CXTYPEMASK) +#define CxTYPE_is_LOOP(c) (((c)->cx_type & 0xC) == 0x4) #define CxMULTICALL(c) (((c)->cx_type & CXp_MULTICALL) \ == CXp_MULTICALL) #define CxREALEVAL(c) (((c)->cx_type & (CXTYPEMASK|CXp_REAL)) \ == (CXt_EVAL|CXp_REAL)) #define CxTRYBLOCK(c) (((c)->cx_type & (CXTYPEMASK|CXp_TRYBLOCK)) \ == (CXt_EVAL|CXp_TRYBLOCK)) -#define CxFOREACH(c) (((c)->cx_type & (CXTYPEMASK|CXp_FOREACH)) \ - == (CXt_LOOP|CXp_FOREACH)) -#define CxFOREACHDEF(c) (((c)->cx_type & (CXTYPEMASK|CXp_FOREACH|CXp_FOR_DEF))\ - == (CXt_LOOP|CXp_FOREACH|CXp_FOR_DEF)) +#define CxFOREACH(c) (CxTYPE_is_LOOP(c) && CxTYPE(c) != CXt_LOOP_PLAIN) +#define CxFOREACHDEF(c) ((CxTYPE_is_LOOP(c) && CxTYPE(c) != CXt_LOOP_PLAIN) \ + && ((c)->cx_type & CXp_FOR_DEF)) #define CXINC (cxstack_ix < cxstack_max ? ++cxstack_ix : (cxstack_ix = cxinc()))