X-Git-Url: https://perl5.git.perl.org/perl5.git/blobdiff_plain/748a93069b3d16374a9859d1456065dd3ae11394..6124d23f33100dc3c406774873984a1b51f6ab02:/pp.h diff --git a/pp.h b/pp.h index 9f80c29..1d9a933 100644 --- a/pp.h +++ b/pp.h @@ -1,143 +1,325 @@ /* pp.h * - * Copyright (c) 1991-1994, Larry Wall + * Copyright (c) 1991-2001, Larry Wall * * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. * */ +#ifdef USE_5005THREADS +#define ARGS thr +#define dARGS struct perl_thread *thr; +#else #define ARGS -#define ARGSproto void #define dARGS -#define PP(s) OP* s(ARGS) dARGS +#endif /* USE_5005THREADS */ + +#define PP(s) OP * Perl_##s(pTHX) + +/* +=for apidoc AmU||SP +Stack pointer. This is usually handled by C. See C and +C. + +=for apidoc AmU||MARK +Stack marker variable for the XSUB. See C. + +=for apidoc Ams||PUSHMARK +Opening bracket for arguments on a callback. See C and +L. + +=for apidoc Ams||dSP +Declares a local copy of perl's stack pointer for the XSUB, available via +the C macro. See C. + +=for apidoc ms||djSP + +Declare Just C. This is actually identical to C, and declares +a local copy of perl's stack pointer, available via the C macro. +See C. (Available for backward source code compatibility with the +old (Perl 5.005) thread model.) + +=for apidoc Ams||dMARK +Declare a stack marker variable, C, for the XSUB. See C and +C. + +=for apidoc Ams||dORIGMARK +Saves the original stack mark for the XSUB. See C. + +=for apidoc AmU||ORIGMARK +The original stack mark for the XSUB. See C. + +=for apidoc Ams||SPAGAIN +Refetch the stack pointer. Used after a callback. See L. +=cut */ + +#undef SP /* Solaris 2.7 i386 has this in /usr/include/sys/reg.h */ #define SP sp #define MARK mark #define TARG targ -#define PUSHMARK(p) if (++markstack_ptr == markstack_max) \ +#define PUSHMARK(p) if (++PL_markstack_ptr == PL_markstack_max) \ markstack_grow(); \ - *markstack_ptr = (p) - stack_base + *PL_markstack_ptr = (p) - PL_stack_base -#define TOPMARK (*markstack_ptr) -#define POPMARK (*markstack_ptr--) +#define TOPMARK (*PL_markstack_ptr) +#define POPMARK (*PL_markstack_ptr--) -#define dSP register SV **sp = stack_sp -#define dMARK register SV **mark = stack_base + POPMARK -#define dORIGMARK I32 origmark = mark - stack_base -#define SETORIGMARK origmark = mark - stack_base -#define ORIGMARK (stack_base + origmark) +#define dSP register SV **sp = PL_stack_sp +#define djSP dSP +#define dMARK register SV **mark = PL_stack_base + POPMARK +#define dORIGMARK I32 origmark = mark - PL_stack_base +#define SETORIGMARK origmark = mark - PL_stack_base +#define ORIGMARK (PL_stack_base + origmark) -#define SPAGAIN sp = stack_sp -#define MSPAGAIN sp = stack_sp; mark = ORIGMARK +#define SPAGAIN sp = PL_stack_sp +#define MSPAGAIN sp = PL_stack_sp; mark = ORIGMARK -#define GETTARGETSTACKED targ = (op->op_flags & OPf_STACKED ? POPs : PAD_SV(op->op_targ)) +#define GETTARGETSTACKED targ = (PL_op->op_flags & OPf_STACKED ? POPs : PAD_SV(PL_op->op_targ)) #define dTARGETSTACKED SV * GETTARGETSTACKED -#define GETTARGET targ = PAD_SV(op->op_targ) +#define GETTARGET targ = PAD_SV(PL_op->op_targ) #define dTARGET SV * GETTARGET -#define GETATARGET targ = (op->op_flags & OPf_STACKED ? sp[-1] : PAD_SV(op->op_targ)) +#define GETATARGET targ = (PL_op->op_flags & OPf_STACKED ? sp[-1] : PAD_SV(PL_op->op_targ)) #define dATARGET SV * GETATARGET #define dTARG SV *targ -#define NORMAL op->op_next -#define DIE return die +#define NORMAL PL_op->op_next +#define DIE return Perl_die + +/* +=for apidoc Ams||PUTBACK +Closing bracket for XSUB arguments. This is usually handled by C. +See C and L for other uses. + +=for apidoc Amn|SV*|POPs +Pops an SV off the stack. + +=for apidoc Amn|char*|POPp +Pops a string off the stack. Deprecated. New code should provide +a STRLEN n_a and use POPpx. + +=for apidoc Amn|char*|POPpx +Pops a string off the stack. +Requires a variable STRLEN n_a in scope. + +=for apidoc Amn|char*|POPpbytex +Pops a string off the stack which must consist of bytes i.e. characters < 256. +Requires a variable STRLEN n_a in scope. -#define PUTBACK stack_sp = sp +=for apidoc Amn|NV|POPn +Pops a double off the stack. + +=for apidoc Amn|IV|POPi +Pops an integer off the stack. + +=for apidoc Amn|long|POPl +Pops a long off the stack. + +=cut +*/ + +#define PUTBACK PL_stack_sp = sp #define RETURN return PUTBACK, NORMAL #define RETURNOP(o) return PUTBACK, o #define RETURNX(x) return x, PUTBACK, NORMAL #define POPs (*sp--) -#define POPp (SvPVx(POPs, na)) +#define POPp (SvPVx(POPs, PL_na)) /* deprecated */ +#define POPpx (SvPVx(POPs, n_a)) +#define POPpbytex (SvPVbytex(POPs, n_a)) #define POPn (SvNVx(POPs)) #define POPi ((IV)SvIVx(POPs)) +#define POPu ((UV)SvUVx(POPs)) #define POPl ((long)SvIVx(POPs)) +#define POPul ((unsigned long)SvIVx(POPs)) +#ifdef HAS_QUAD +#define POPq ((Quad_t)SvIVx(POPs)) +#define POPuq ((Uquad_t)SvUVx(POPs)) +#endif #define TOPs (*sp) -#define TOPp (SvPV(TOPs, na)) +#define TOPm1s (*(sp-1)) +#define TOPp1s (*(sp+1)) +#define TOPp (SvPV(TOPs, PL_na)) /* deprecated */ +#define TOPpx (SvPV(TOPs, n_a)) #define TOPn (SvNV(TOPs)) #define TOPi ((IV)SvIV(TOPs)) +#define TOPu ((UV)SvUV(TOPs)) #define TOPl ((long)SvIV(TOPs)) +#define TOPul ((unsigned long)SvUV(TOPs)) +#ifdef HAS_QUAD +#define TOPq ((Quad_t)SvIV(TOPs)) +#define TOPuq ((Uquad_t)SvUV(TOPs)) +#endif /* Go to some pains in the rare event that we must extend the stack. */ -#define EXTEND(p,n) do { if (stack_max - p < (n)) { \ - sp = stack_grow(sp,p, (int) (n)); \ - } } while (0) -/* Same thing, but update mark register too. */ -#define MEXTEND(p,n) do {if (stack_max - p < (n)) { \ - int markoff = mark - stack_base; \ - sp = stack_grow(sp,p,(int) (n)); \ - mark = stack_base + markoff; \ - } } while (0) +/* +=for apidoc Am|void|EXTEND|SP|int nitems +Used to extend the argument stack for an XSUB's return values. Once +used, guarantees that there is room for at least C to be pushed +onto the stack. -#define PUSHs(s) (*++sp = (s)) -#define PUSHTARG do { SvSETMAGIC(TARG); PUSHs(TARG); } while (0) -#define PUSHp(p,l) do { sv_setpvn(TARG, (p), (l)); PUSHTARG; } while (0) -#define PUSHn(n) do { sv_setnv(TARG, (double)(n)); PUSHTARG; } while (0) -#define PUSHi(i) do { sv_setiv(TARG, (IV)(i)); PUSHTARG; } while (0) +=for apidoc Am|void|PUSHs|SV* sv +Push an SV onto the stack. The stack must have room for this element. +Does not handle 'set' magic. See C. -#define XPUSHs(s) do { EXTEND(sp,1); (*++sp = (s)); } while (0) -#define XPUSHTARG do { SvSETMAGIC(TARG); XPUSHs(TARG); } while (0) -#define XPUSHp(p,l) do { sv_setpvn(TARG, (p), (l)); XPUSHTARG; } while (0) -#define XPUSHn(n) do { sv_setnv(TARG, (double)(n)); XPUSHTARG; } while (0) -#define XPUSHi(i) do { sv_setiv(TARG, (IV)(i)); XPUSHTARG; } while (0) +=for apidoc Am|void|PUSHp|char* str|STRLEN len +Push a string onto the stack. The stack must have room for this element. +The C indicates the length of the string. Handles 'set' magic. See +C. -#define SETs(s) (*sp = s) -#define SETTARG do { SvSETMAGIC(TARG); SETs(TARG); } while (0) -#define SETp(p,l) do { sv_setpvn(TARG, (p), (l)); SETTARG; } while (0) -#define SETn(n) do { sv_setnv(TARG, (double)(n)); SETTARG; } while (0) -#define SETi(i) do { sv_setiv(TARG, (IV)(i)); SETTARG; } while (0) +=for apidoc Am|void|PUSHn|NV nv +Push a double onto the stack. The stack must have room for this element. +Handles 'set' magic. See C. -#ifdef OVERLOAD -#define SETsv(sv) do { sv_setsv(TARG, (sv)); SETTARG; } while (0) -#endif /* OVERLOAD */ +=for apidoc Am|void|PUSHi|IV iv +Push an integer onto the stack. The stack must have room for this element. +Handles 'set' magic. See C. -#define dTOPss SV *sv = TOPs -#define dPOPss SV *sv = POPs -#define dTOPnv double value = TOPn -#define dPOPnv double value = POPn -#define dTOPiv IV value = TOPi -#define dPOPiv IV value = POPi +=for apidoc Am|void|PUSHu|UV uv +Push an unsigned integer onto the stack. The stack must have room for this +element. See C. -#define dPOPPOPssrl SV *right = POPs; SV *left = POPs -#define dPOPPOPnnrl double right = POPn; double left = POPn -#define dPOPPOPiirl IV right = POPi; IV left = POPi +=for apidoc Am|void|XPUSHs|SV* sv +Push an SV onto the stack, extending the stack if necessary. Does not +handle 'set' magic. See C. -#define dPOPTOPssrl SV *right = POPs; SV *left = TOPs -#define dPOPTOPnnrl double right = POPn; double left = TOPn -#define dPOPTOPiirl IV right = POPi; IV left = TOPi +=for apidoc Am|void|XPUSHp|char* str|STRLEN len +Push a string onto the stack, extending the stack if necessary. The C +indicates the length of the string. Handles 'set' magic. See +C. -#define RETPUSHYES RETURNX(PUSHs(&sv_yes)) -#define RETPUSHNO RETURNX(PUSHs(&sv_no)) -#define RETPUSHUNDEF RETURNX(PUSHs(&sv_undef)) +=for apidoc Am|void|XPUSHn|NV nv +Push a double onto the stack, extending the stack if necessary. Handles +'set' magic. See C. -#define RETSETYES RETURNX(SETs(&sv_yes)) -#define RETSETNO RETURNX(SETs(&sv_no)) -#define RETSETUNDEF RETURNX(SETs(&sv_undef)) +=for apidoc Am|void|XPUSHi|IV iv +Push an integer onto the stack, extending the stack if necessary. Handles +'set' magic. See C. + +=for apidoc Am|void|XPUSHu|UV uv +Push an unsigned integer onto the stack, extending the stack if necessary. +See C. + +=cut +*/ + +#define EXTEND(p,n) STMT_START { if (PL_stack_max - p < (n)) { \ + sp = stack_grow(sp,p, (int) (n)); \ + } } STMT_END + +/* Same thing, but update mark register too. */ +#define MEXTEND(p,n) STMT_START {if (PL_stack_max - p < (n)) { \ + int markoff = mark - PL_stack_base; \ + sp = stack_grow(sp,p,(int) (n)); \ + mark = PL_stack_base + markoff; \ + } } STMT_END -#define ARGTARG op->op_targ -#define MAXARG op->op_private +#define PUSHs(s) (*++sp = (s)) +#define PUSHTARG STMT_START { SvSETMAGIC(TARG); PUSHs(TARG); } STMT_END +#define PUSHp(p,l) STMT_START { sv_setpvn(TARG, (p), (l)); PUSHTARG; } STMT_END +#define PUSHn(n) STMT_START { sv_setnv(TARG, (NV)(n)); PUSHTARG; } STMT_END +#define PUSHi(i) STMT_START { sv_setiv(TARG, (IV)(i)); PUSHTARG; } STMT_END +#define PUSHu(u) STMT_START { sv_setuv(TARG, (UV)(u)); PUSHTARG; } STMT_END + +#define XPUSHs(s) STMT_START { EXTEND(sp,1); (*++sp = (s)); } STMT_END +#define XPUSHTARG STMT_START { SvSETMAGIC(TARG); XPUSHs(TARG); } STMT_END +#define XPUSHp(p,l) STMT_START { sv_setpvn(TARG, (p), (l)); XPUSHTARG; } STMT_END +#define XPUSHn(n) STMT_START { sv_setnv(TARG, (NV)(n)); XPUSHTARG; } STMT_END +#define XPUSHi(i) STMT_START { sv_setiv(TARG, (IV)(i)); XPUSHTARG; } STMT_END +#define XPUSHu(u) STMT_START { sv_setuv(TARG, (UV)(u)); XPUSHTARG; } STMT_END +#define XPUSHundef STMT_START { SvOK_off(TARG); XPUSHs(TARG); } STMT_END -#define SWITCHSTACK(f,t) AvFILL(f) = sp - stack_base; \ - stack_base = AvARRAY(t); \ - stack_max = stack_base + AvMAX(t); \ - sp = stack_sp = stack_base + AvFILL(t); \ - stack = t; +#define SETs(s) (*sp = s) +#define SETTARG STMT_START { SvSETMAGIC(TARG); SETs(TARG); } STMT_END +#define SETp(p,l) STMT_START { sv_setpvn(TARG, (p), (l)); SETTARG; } STMT_END +#define SETn(n) STMT_START { sv_setnv(TARG, (NV)(n)); SETTARG; } STMT_END +#define SETi(i) STMT_START { sv_setiv(TARG, (IV)(i)); SETTARG; } STMT_END +#define SETu(u) STMT_START { sv_setuv(TARG, (UV)(u)); SETTARG; } STMT_END -#ifdef OVERLOAD +#define dTOPss SV *sv = TOPs +#define dPOPss SV *sv = POPs +#define dTOPnv NV value = TOPn +#define dPOPnv NV value = POPn +#define dTOPiv IV value = TOPi +#define dPOPiv IV value = POPi +#define dTOPuv UV value = TOPu +#define dPOPuv UV value = POPu +#ifdef HAS_QUAD +#define dTOPqv Quad_t value = TOPu +#define dPOPqv Quad_t value = POPu +#define dTOPuqv Uquad_t value = TOPuq +#define dPOPuqv Uquad_t value = POPuq +#endif + +#define dPOPXssrl(X) SV *right = POPs; SV *left = CAT2(X,s) +#define dPOPXnnrl(X) NV right = POPn; NV left = CAT2(X,n) +#define dPOPXiirl(X) IV right = POPi; IV left = CAT2(X,i) + +#define USE_LEFT(sv) \ + (SvOK(sv) || SvGMAGICAL(sv) || !(PL_op->op_flags & OPf_STACKED)) +#define dPOPXnnrl_ul(X) \ + NV right = POPn; \ + SV *leftsv = CAT2(X,s); \ + NV left = USE_LEFT(leftsv) ? SvNV(leftsv) : 0.0 +#define dPOPXiirl_ul(X) \ + IV right = POPi; \ + SV *leftsv = CAT2(X,s); \ + IV left = USE_LEFT(leftsv) ? SvIV(leftsv) : 0 + +#define dPOPPOPssrl dPOPXssrl(POP) +#define dPOPPOPnnrl dPOPXnnrl(POP) +#define dPOPPOPnnrl_ul dPOPXnnrl_ul(POP) +#define dPOPPOPiirl dPOPXiirl(POP) +#define dPOPPOPiirl_ul dPOPXiirl_ul(POP) + +#define dPOPTOPssrl dPOPXssrl(TOP) +#define dPOPTOPnnrl dPOPXnnrl(TOP) +#define dPOPTOPnnrl_ul dPOPXnnrl_ul(TOP) +#define dPOPTOPiirl dPOPXiirl(TOP) +#define dPOPTOPiirl_ul dPOPXiirl_ul(TOP) + +#define RETPUSHYES RETURNX(PUSHs(&PL_sv_yes)) +#define RETPUSHNO RETURNX(PUSHs(&PL_sv_no)) +#define RETPUSHUNDEF RETURNX(PUSHs(&PL_sv_undef)) + +#define RETSETYES RETURNX(SETs(&PL_sv_yes)) +#define RETSETNO RETURNX(SETs(&PL_sv_no)) +#define RETSETUNDEF RETURNX(SETs(&PL_sv_undef)) + +#define ARGTARG PL_op->op_targ + + /* See OPpTARGET_MY: */ +#define MAXARG (PL_op->op_private & 15) + +#define SWITCHSTACK(f,t) \ + STMT_START { \ + AvFILLp(f) = sp - PL_stack_base; \ + PL_stack_base = AvARRAY(t); \ + PL_stack_max = PL_stack_base + AvMAX(t); \ + sp = PL_stack_sp = PL_stack_base + AvFILLp(t); \ + PL_curstack = t; \ + } STMT_END + +#define EXTEND_MORTAL(n) \ + STMT_START { \ + if (PL_tmps_ix + (n) >= PL_tmps_max) \ + tmps_grow(n); \ + } STMT_END #define AMGf_noright 1 #define AMGf_noleft 2 #define AMGf_assign 4 #define AMGf_unary 8 -#define tryAMAGICbinW(meth,assign,set) do { \ - if (amagic_generation) { \ +#define tryAMAGICbinW(meth,assign,set) STMT_START { \ + if (PL_amagic_generation) { \ SV* tmpsv; \ SV* right= *(sp); SV* left= *(sp-1);\ if ((SvAMAGIC(left)||SvAMAGIC(right))&&\ @@ -148,46 +330,73 @@ SPAGAIN; \ (void)POPs; set(tmpsv); RETURN; } \ } \ - } while (0) + } STMT_END #define tryAMAGICbin(meth,assign) tryAMAGICbinW(meth,assign,SETsv) #define tryAMAGICbinSET(meth,assign) tryAMAGICbinW(meth,assign,SETs) -#define AMG_CALLun(sv,meth) amagic_call(sv,&sv_undef, \ +#define AMG_CALLun(sv,meth) amagic_call(sv,&PL_sv_undef, \ CAT2(meth,_amg),AMGf_noright | AMGf_unary) #define AMG_CALLbinL(left,right,meth) \ amagic_call(left,right,CAT2(meth,_amg),AMGf_noright) -#define tryAMAGICunW(meth,set) do { \ - if (amagic_generation) { \ +#define tryAMAGICunW(meth,set,shift,ret) STMT_START { \ + if (PL_amagic_generation) { \ SV* tmpsv; \ - SV* arg= *(sp); \ + SV* arg= sp[shift]; \ + if(0) goto am_again; /* shut up unused warning */ \ + am_again: \ if ((SvAMAGIC(arg))&&\ (tmpsv=AMG_CALLun(arg,meth))) {\ - SPAGAIN; \ - set(tmpsv); RETURN; } \ + SPAGAIN; if (shift) sp += shift; \ + set(tmpsv); ret; } \ } \ - } while (0) - -#define tryAMAGICun(meth) tryAMAGICunW(meth,SETsv) -#define tryAMAGICunSET(meth) tryAMAGICunW(meth,SETs) - -#define opASSIGN (op->op_flags & OPf_STACKED) + } STMT_END + +#define FORCE_SETs(sv) STMT_START { sv_setsv(TARG, (sv)); SETTARG; } STMT_END + +#define tryAMAGICun(meth) tryAMAGICunW(meth,SETsvUN,0,RETURN) +#define tryAMAGICunSET(meth) tryAMAGICunW(meth,SETs,0,RETURN) +#define tryAMAGICunTARGET(meth, shift) \ + { dSP; sp--; /* get TARGET from below PL_stack_sp */ \ + { dTARGETSTACKED; \ + { dSP; tryAMAGICunW(meth,FORCE_SETs,shift,RETURN);}}} + +#define setAGAIN(ref) sv = ref; \ + if (!SvROK(ref)) \ + Perl_croak(aTHX_ "Overloaded dereference did not return a reference"); \ + if (ref != arg && SvRV(ref) != SvRV(arg)) { \ + arg = ref; \ + goto am_again; \ + } + +#define tryAMAGICunDEREF(meth) tryAMAGICunW(meth,setAGAIN,0,(void)0) + +#define opASSIGN (PL_op->op_flags & OPf_STACKED) +#define SETsv(sv) STMT_START { \ + if (opASSIGN || (SvFLAGS(TARG) & SVs_PADMY)) \ + { sv_setsv(TARG, (sv)); SETTARG; } \ + else SETs(sv); } STMT_END + +#define SETsvUN(sv) STMT_START { \ + if (SvFLAGS(TARG) & SVs_PADMY) \ + { sv_setsv(TARG, (sv)); SETTARG; } \ + else SETs(sv); } STMT_END /* newSVsv does not behave as advertised, so we copy missing * information by hand */ - -#define RvDEEPCP(rv) do { SV* ref=SvRV(rv); \ - if (SvREFCNT(ref)>1) { \ - SvREFCNT_dec(ref); \ +/* SV* ref causes confusion with the member variable + changed SV* ref to SV* tmpRef */ +#define RvDEEPCP(rv) STMT_START { SV* tmpRef=SvRV(rv); \ + if (SvREFCNT(tmpRef)>1) { \ + SvREFCNT_dec(tmpRef); \ SvRV(rv)=AMG_CALLun(rv,copy); \ - } } while (0) -#else + } } STMT_END -#define tryAMAGICbin(a,b) -#define tryAMAGICbinSET(a,b) -#define tryAMAGICun(a) -#define tryAMAGICunSET(a) +/* +=for apidoc mU||LVRET +True if this op will be the return value of an lvalue subroutine -#endif /* OVERLOAD */ +=cut */ +#define LVRET ((PL_op->op_private & OPpMAYBE_LVSUB) && is_lvalue_sub())