X-Git-Url: https://perl5.git.perl.org/perl5.git/blobdiff_plain/9a18979311347ab1c45e2ef16113bb5abe4cbd26..2d7f66116e374c78dcf18cb5b9fea7b79ac82b5b:/sv.c diff --git a/sv.c b/sv.c index 54f939f..7dedbca 100644 --- a/sv.c +++ b/sv.c @@ -125,11 +125,6 @@ # define ASSERT_UTF8_CACHE(cache) NOOP #endif -#ifdef PERL_OLD_COPY_ON_WRITE -#define SV_COW_NEXT_SV(sv) INT2PTR(SV *,SvUVX(sv)) -#define SV_COW_NEXT_SV_SET(current,next) SvUV_set(current, PTR2UV(next)) -#endif - /* ============================================================================ =head1 Allocation and deallocation of SVs. @@ -408,6 +403,34 @@ S_del_sv(pTHX_ SV *p) #endif /* DEBUGGING */ +/* + * Bodyless IVs and NVs! + * + * Since 5.9.2, we can avoid allocating a body for SVt_IV-type SVs. + * Since the larger IV-holding variants of SVs store their integer + * values in their respective bodies, the family of SvIV() accessor + * macros would naively have to branch on the SV type to find the + * integer value either in the HEAD or BODY. In order to avoid this + * expensive branch, a clever soul has deployed a great hack: + * We set up the SvANY pointer such that instead of pointing to a + * real body, it points into the memory before the location of the + * head. We compute this pointer such that the location of + * the integer member of the hypothetical body struct happens to + * be the same as the location of the integer member of the bodyless + * SV head. This now means that the SvIV() family of accessors can + * always read from the (hypothetical or real) body via SvANY. + * + * Since the 5.21 dev series, we employ the same trick for NVs + * if the architecture can support it (NVSIZE <= IVSIZE). + */ + +/* The following two macros compute the necessary offsets for the above + * trick and store them in SvANY for SvIV() (and friends) to use. */ +#define SET_SVANY_FOR_BODYLESS_IV(sv) \ + SvANY(sv) = (XPVIV*)((char*)&(sv->sv_u.svu_iv) - STRUCT_OFFSET(XPVIV, xiv_iv)) + +#define SET_SVANY_FOR_BODYLESS_NV(sv) \ + SvANY(sv) = (XPVNV*)((char*)&(sv->sv_u.svu_nv) - STRUCT_OFFSET(XPVNV, xnv_u.xnv_nv)) /* =head1 SV Manipulation Functions @@ -1290,8 +1313,8 @@ Perl_sv_upgrade(pTHX_ SV *const sv, svtype new_type) break; case SVt_PV: assert(new_type > SVt_PV); - assert(SVt_IV < SVt_PV); - assert(SVt_NV < SVt_PV); + STATIC_ASSERT_STMT(SVt_IV < SVt_PV); + STATIC_ASSERT_STMT(SVt_NV < SVt_PV); break; case SVt_PVIV: break; @@ -1302,10 +1325,6 @@ Perl_sv_upgrade(pTHX_ SV *const sv, svtype new_type) there's no way that it can be safely upgraded, because perl.c expects to Safefree(SvANY(PL_mess_sv)) */ assert(sv != PL_mess_sv); - /* This flag bit is used to mean other things in other scalar types. - Given that it only has meaning inside the pad, it shouldn't be set - on anything that can get upgraded. */ - assert(!SvPAD_TYPED(sv)); break; default: if (UNLIKELY(old_type_details->cant_upgrade)) @@ -1328,13 +1347,13 @@ Perl_sv_upgrade(pTHX_ SV *const sv, svtype new_type) switch (new_type) { case SVt_IV: assert(old_type == SVt_NULL); - SvANY(sv) = (XPVIV*)((char*)&(sv->sv_u.svu_iv) - STRUCT_OFFSET(XPVIV, xiv_iv)); + SET_SVANY_FOR_BODYLESS_IV(sv); SvIV_set(sv, 0); return; case SVt_NV: assert(old_type == SVt_NULL); #if NVSIZE <= IVSIZE - SvANY(sv) = (XPVNV*)((char*)&(sv->sv_u.svu_nv) - STRUCT_OFFSET(XPVNV, xnv_u.xnv_nv)); + SET_SVANY_FOR_BODYLESS_NV(sv); #else SvANY(sv) = new_XNV(); #endif @@ -1401,6 +1420,7 @@ Perl_sv_upgrade(pTHX_ SV *const sv, svtype new_type) no route from NV to PVIV, NOK can never be true */ assert(!SvNOKp(sv)); assert(!SvNOK(sv)); + /* FALLTHROUGH */ case SVt_PVIO: case SVt_PVFM: case SVt_PVGV: @@ -1563,15 +1583,18 @@ Perl_sv_grow(pTHX_ SV *const sv, STRLEN newlen) s = SvPVX_mutable(sv); } -#ifdef PERL_NEW_COPY_ON_WRITE +#ifdef PERL_COPY_ON_WRITE /* the new COW scheme uses SvPVX(sv)[SvLEN(sv)-1] (if spare) * to store the COW count. So in general, allocate one more byte than * asked for, to make it likely this byte is always spare: and thus * make more strings COW-able. * If the new size is a big power of two, don't bother: we assume the * caller wanted a nice 2^N sized block and will be annoyed at getting - * 2^N+1 */ - if (newlen & 0xff) + * 2^N+1. + * Only increment if the allocation isn't MEM_SIZE_MAX, + * otherwise it will wrap to 0. + */ + if (newlen & 0xff && newlen != MEM_SIZE_MAX) newlen++; #endif @@ -1589,7 +1612,9 @@ Perl_sv_grow(pTHX_ SV *const sv, STRLEN newlen) /* Don't round up on the first allocation, as odds are pretty good that * the initial request is accurate as to what is really needed */ if (SvLEN(sv)) { - newlen = PERL_STRLEN_ROUNDUP(newlen); + STRLEN rounded = PERL_STRLEN_ROUNDUP(newlen); + if (rounded > newlen) + newlen = rounded; } #endif if (SvLEN(sv) && s) { @@ -1649,6 +1674,7 @@ Perl_sv_setiv(pTHX_ SV *const sv, const IV i) /* diag_listed_as: Can't coerce %s to %s in %s */ Perl_croak(aTHX_ "Can't coerce %s to integer in %s", sv_reftype(sv,0), OP_DESC(PL_op)); + break; default: NOOP; } (void)SvIOK_only(sv); /* validate number */ @@ -1760,6 +1786,7 @@ Perl_sv_setnv(pTHX_ SV *const sv, const NV num) /* diag_listed_as: Can't coerce %s to %s in %s */ Perl_croak(aTHX_ "Can't coerce %s to number in %s", sv_reftype(sv,0), OP_DESC(PL_op)); + break; default: NOOP; } SvNV_set(sv, num); @@ -1798,7 +1825,7 @@ S_sv_display(pTHX_ SV *const sv, char *tmpbuf, STRLEN tmpbuf_size) { if (DO_UTF8(sv)) { SV *dsv = newSVpvs_flags("", SVs_TEMP); - pv = sv_uni_display(dsv, sv, 10, UNI_DISPLAY_ISPRINT); + pv = sv_uni_display(dsv, sv, 32, UNI_DISPLAY_ISPRINT); } else { char *d = tmpbuf; const char * const limit = tmpbuf + tmpbuf_size - 8; @@ -1909,6 +1936,7 @@ Perl_looks_like_number(pTHX_ SV *const sv) { const char *sbegin; STRLEN len; + int numtype; PERL_ARGS_ASSERT_LOOKS_LIKE_NUMBER; @@ -1917,7 +1945,8 @@ Perl_looks_like_number(pTHX_ SV *const sv) } else return SvFLAGS(sv) & (SVf_NOK|SVp_NOK|SVf_IOK|SVp_IOK); - return grok_number(sbegin, len, NULL); + numtype = grok_number(sbegin, len, NULL); + return ((numtype & IS_NUMBER_TRAILING)) ? 0 : numtype; } STATIC bool @@ -2078,6 +2107,10 @@ S_sv_2iuv_non_preserve(pTHX_ SV *const sv /* If numtype is infnan, set the NV of the sv accordingly. * If numtype is anything else, try setting the NV using Atof(PV). */ +#ifdef USING_MSVC6 +# pragma warning(push) +# pragma warning(disable:4756;disable:4056) +#endif static void S_sv_setnv(pTHX_ SV* sv, int numtype) { @@ -2102,6 +2135,9 @@ S_sv_setnv(pTHX_ SV* sv, int numtype) SvPOK_on(sv); /* PV is okay, though. */ } } +#ifdef USING_MSVC6 +# pragma warning(pop) +#endif STATIC bool S_sv_2iuv_common(pTHX_ SV *const sv) @@ -2134,6 +2170,7 @@ S_sv_2iuv_common(pTHX_ SV *const sv) SvIV_set(sv, I_V(SvNVX(sv))); if (SvNVX(sv) == (NV) SvIVX(sv) #ifndef NV_PRESERVES_UV + && SvIVX(sv) != IV_MIN /* avoid negating IV_MIN below */ && (((UV)1 << NV_PRESERVES_UV_BITS) > (UV)(SvIVX(sv) > 0 ? SvIVX(sv) : -SvIVX(sv))) /* Don't flag it as "accurately an integer" if the number @@ -2221,6 +2258,8 @@ S_sv_2iuv_common(pTHX_ SV *const sv) sv_upgrade(sv, SVt_PVNV); if ((numtype & (IS_NUMBER_INFINITY | IS_NUMBER_NAN))) { + if (ckWARN(WARN_NUMERIC) && ((numtype & IS_NUMBER_TRAILING))) + not_a_number(sv); S_sv_setnv(aTHX_ sv, numtype); return FALSE; } @@ -2249,7 +2288,8 @@ S_sv_2iuv_common(pTHX_ SV *const sv) } else { /* 2s complement assumption */ if (value <= (UV)IV_MIN) { - SvIV_set(sv, -(IV)value); + SvIV_set(sv, value == (UV)IV_MIN + ? IV_MIN : -(IV)value); } else { /* Too negative for an IV. This is a double upgrade, but I'm assuming it will be rare. */ @@ -2455,11 +2495,6 @@ Perl_sv_2iv_flags(pTHX_ SV *const sv, const I32 flags) } if (SvTHINKFIRST(sv)) { -#ifdef PERL_OLD_COPY_ON_WRITE - if (SvIsCOW(sv)) { - sv_force_normal_flags(sv, 0); - } -#endif if (SvREADONLY(sv) && !SvOK(sv)) { if (ckWARN(WARN_UNINITIALIZED)) report_uninit(sv); @@ -2543,11 +2578,6 @@ Perl_sv_2uv_flags(pTHX_ SV *const sv, const I32 flags) } if (SvTHINKFIRST(sv)) { -#ifdef PERL_OLD_COPY_ON_WRITE - if (SvIsCOW(sv)) { - sv_force_normal_flags(sv, 0); - } -#endif if (SvREADONLY(sv) && !SvOK(sv)) { if (ckWARN(WARN_UNINITIALIZED)) report_uninit(sv); @@ -2629,11 +2659,6 @@ Perl_sv_2nv_flags(pTHX_ SV *const sv, const I32 flags) } return PTR2NV(SvRV(sv)); } -#ifdef PERL_OLD_COPY_ON_WRITE - if (SvIsCOW(sv)) { - sv_force_normal_flags(sv, 0); - } -#endif if (SvREADONLY(sv) && !SvOK(sv)) { if (ckWARN(WARN_UNINITIALIZED)) report_uninit(sv); @@ -2708,7 +2733,7 @@ Perl_sv_2nv_flags(pTHX_ SV *const sv, const I32 flags) SvNOK_on(sv); } else { /* value has been set. It may not be precise. */ - if ((numtype & IS_NUMBER_NEG) && (value > (UV)IV_MIN)) { + if ((numtype & IS_NUMBER_NEG) && (value >= (UV)IV_MIN)) { /* 2s complement assumption for (UV)IV_MIN */ SvNOK_on(sv); /* Integer is too negative. */ } else { @@ -2716,6 +2741,10 @@ Perl_sv_2nv_flags(pTHX_ SV *const sv, const I32 flags) SvIOKp_on(sv); if (numtype & IS_NUMBER_NEG) { + /* -IV_MIN is undefined, but we should never reach + * this point with both IS_NUMBER_NEG and value == + * (UV)IV_MIN */ + assert(value != (UV)IV_MIN); SvIV_set(sv, -(IV)value); } else if (value <= (UV)IV_MAX) { SvIV_set(sv, (IV)value); @@ -2793,8 +2822,8 @@ Perl_sv_2nv_flags(pTHX_ SV *const sv, const I32 flags) =for apidoc sv_2num Return an SV with the numeric value of the source SV, doing any necessary -reference or overload conversion. You must use the C macro to -access this function. +reference or overload conversion. The caller is expected to have handled +get-magic already. =cut */ @@ -2837,7 +2866,7 @@ S_uiv_2buf(char *const buf, const IV iv, UV uv, const int is_uv, char **const pe uv = iv; sign = 0; } else { - uv = -iv; + uv = (iv == IV_MIN) ? (UV)iv : (UV)(-iv); sign = 1; } do { @@ -2852,45 +2881,44 @@ S_uiv_2buf(char *const buf, const IV iv, UV uv, const int is_uv, char **const pe /* Helper for sv_2pv_flags and sv_vcatpvfn_flags. If the NV is an * infinity or a not-a-number, writes the appropriate strings to the * buffer, including a zero byte. On success returns the written length, - * excluding the zero byte, on failure (not an infinity, not a nan, or the - * maxlen too small) returns zero. + * excluding the zero byte, on failure (not an infinity, not a nan) + * returns zero, assert-fails on maxlen being too short. * * XXX for "Inf", "-Inf", and "NaN", we could have three read-only * shared string constants we point to, instead of generating a new * string for each instance. */ STATIC size_t -S_infnan_2pv(NV nv, char* buffer, size_t maxlen) { +S_infnan_2pv(NV nv, char* buffer, size_t maxlen, char plus) { + char* s = buffer; assert(maxlen >= 4); - if (maxlen < 4) /* "Inf\0", "NaN\0" */ - return 0; - else { - char* s = buffer; - if (Perl_isinf(nv)) { - if (nv < 0) { - if (maxlen < 5) /* "-Inf\0" */ - return 0; - *s++ = '-'; - } - *s++ = 'I'; - *s++ = 'n'; - *s++ = 'f'; - } else if (Perl_isnan(nv)) { - *s++ = 'N'; - *s++ = 'a'; - *s++ = 'N'; - /* XXX optionally output the payload mantissa bits as - * "(unsigned)" (to match the nan("...") C99 function, - * or maybe as "(0xhhh...)" would make more sense... - * provide a format string so that the user can decide? - * NOTE: would affect the maxlen and assert() logic.*/ + if (Perl_isinf(nv)) { + if (nv < 0) { + if (maxlen < 5) /* "-Inf\0" */ + return 0; + *s++ = '-'; + } else if (plus) { + *s++ = '+'; } - - else - return 0; - assert((s == buffer + 3) || (s == buffer + 4)); - *s++ = 0; - return s - buffer - 1; /* -1: excluding the zero byte */ + *s++ = 'I'; + *s++ = 'n'; + *s++ = 'f'; + } + else if (Perl_isnan(nv)) { + *s++ = 'N'; + *s++ = 'a'; + *s++ = 'N'; + /* XXX optionally output the payload mantissa bits as + * "(unsigned)" (to match the nan("...") C99 function, + * or maybe as "(0xhhh...)" would make more sense... + * provide a format string so that the user can decide? + * NOTE: would affect the maxlen and assert() logic.*/ } + else { + return 0; + } + assert((s == buffer + 3) || (s == buffer + 4)); + *s++ = 0; + return s - buffer - 1; /* -1: excluding the zero byte */ } /* @@ -3084,7 +3112,7 @@ Perl_sv_2pv_flags(pTHX_ SV *const sv, STRLEN *const lp, const I32 flags) STRLEN size = 5; /* "-Inf\0" */ s = SvGROW_mutable(sv, size); - len = S_infnan_2pv(SvNVX(sv), s, size); + len = S_infnan_2pv(SvNVX(sv), s, size, 0); if (len > 0) { s += len; SvPOK_on(sv); @@ -3111,7 +3139,8 @@ Perl_sv_2pv_flags(pTHX_ SV *const sv, STRLEN *const lp, const I32 flags) #else { bool local_radix; - DECLARE_STORE_LC_NUMERIC_SET_TO_NEEDED(); + DECLARATION_FOR_LC_NUMERIC_MANIPULATION; + STORE_LC_NUMERIC_SET_TO_NEEDED(); local_radix = PL_numeric_local && @@ -3213,14 +3242,6 @@ include SV_GMAGIC. */ void -Perl_sv_copypv(pTHX_ SV *const dsv, SV *const ssv) -{ - PERL_ARGS_ASSERT_SV_COPYPV; - - sv_copypv_flags(dsv, ssv, 0); -} - -void Perl_sv_copypv_flags(pTHX_ SV *const dsv, SV *const ssv, const I32 flags) { STRLEN len; @@ -3451,8 +3472,8 @@ Perl_sv_utf8_upgrade_flags_grow(pTHX_ SV *const sv, const I32 flags, STRLEN extr S_sv_uncow(aTHX_ sv, 0); } - if (PL_encoding && !(flags & SV_UTF8_NO_ENCODING)) { - sv_recode_to_utf8(sv, PL_encoding); + if (IN_ENCODING && !(flags & SV_UTF8_NO_ENCODING)) { + sv_recode_to_utf8(sv, _get_encoding()); if (extra) SvGROW(sv, SvCUR(sv) + extra); return SvCUR(sv); } @@ -3491,7 +3512,7 @@ Perl_sv_utf8_upgrade_flags_grow(pTHX_ SV *const sv, const I32 flags, STRLEN extr if (extra) SvGROW(sv, SvCUR(sv) + extra); return SvCUR(sv); -must_be_utf8: + must_be_utf8: /* Here, the string should be converted to utf8, either because of an * input flag (two_byte_count = 0), or because a character that @@ -4246,7 +4267,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, SV* sstr, const I32 flags) PERL_ARGS_ASSERT_SV_SETSV_FLAGS; - if (sstr == dstr) + if (UNLIKELY( sstr == dstr )) return; if (SvIS_FREED(dstr)) { @@ -4254,7 +4275,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, SV* sstr, const I32 flags) " to a freed scalar %p", SVfARG(sstr), (void *)dstr); } SV_CHECK_THINKFIRST_COW_DROP(dstr); - if (!sstr) + if (UNLIKELY( !sstr )) sstr = &PL_sv_undef; if (SvIS_FREED(sstr)) { Perl_croak(aTHX_ "panic: attempt to copy freed scalar %p to %p", @@ -4268,7 +4289,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, SV* sstr, const I32 flags) switch (stype) { case SVt_NULL: undef_sstr: - if (dtype != SVt_PVGV && dtype != SVt_PVLV) { + if (LIKELY( dtype != SVt_PVGV && dtype != SVt_PVLV )) { (void)SvOK_off(dstr); return; } @@ -4277,7 +4298,13 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, SV* sstr, const I32 flags) if (SvIOK(sstr)) { switch (dtype) { case SVt_NULL: - sv_upgrade(dstr, SVt_IV); + /* For performance, we inline promoting to type SVt_IV. */ + /* We're starting from SVt_NULL, so provided that define is + * actual 0, we don't have to unset any SV type flags + * to promote to SVt_IV. */ + STATIC_ASSERT_STMT(SVt_NULL == 0); + SET_SVANY_FOR_BODYLESS_IV(dstr); + SvFLAGS(dstr) |= SVt_IV; break; case SVt_NV: case SVt_PV: @@ -4305,7 +4332,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, SV* sstr, const I32 flags) break; case SVt_NV: - if (SvNOK(sstr)) { + if (LIKELY( SvNOK(sstr) )) { switch (dtype) { case SVt_NULL: case SVt_IV: @@ -4394,7 +4421,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, SV* sstr, const I32 flags) dtype = SvTYPE(dstr); sflags = SvFLAGS(sstr); - if (dtype == SVt_PVCV) { + if (UNLIKELY( dtype == SVt_PVCV )) { /* Assigning to a subroutine sets the prototype. */ if (SvOK(sstr)) { STRLEN len; @@ -4410,7 +4437,9 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, SV* sstr, const I32 flags) SvOK_off(dstr); } } - else if (dtype == SVt_PVAV || dtype == SVt_PVHV || dtype == SVt_PVFM) { + else if (UNLIKELY(dtype == SVt_PVAV || dtype == SVt_PVHV + || dtype == SVt_PVFM)) + { const char * const type = sv_reftype(dstr,0); if (PL_op) /* diag_listed_as: Cannot copy to %s */ @@ -4592,14 +4621,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, SV* sstr, const I32 flags) } else if (flags & SV_COW_SHARED_HASH_KEYS && -#ifdef PERL_OLD_COPY_ON_WRITE - ( sflags & SVf_IsCOW - || ( (sflags & CAN_COW_MASK) == CAN_COW_FLAGS - && (SvFLAGS(dstr) & CAN_COW_MASK) == CAN_COW_FLAGS - && SvTYPE(sstr) >= SVt_PVIV && len - ) - ) -#elif defined(PERL_NEW_COPY_ON_WRITE) +#ifdef PERL_COPY_ON_WRITE (sflags & SVf_IsCOW ? (!len || ( (CHECK_COWBUF_THRESHOLD(cur,len) || SvLEN(dstr) < cur+1) @@ -4626,13 +4648,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, SV* sstr, const I32 flags) #ifdef PERL_ANY_COW if (!(sflags & SVf_IsCOW)) { SvIsCOW_on(sstr); -# ifdef PERL_OLD_COPY_ON_WRITE - /* Make the source SV into a loop of 1. - (about to become 2) */ - SV_COW_NEXT_SV_SET(sstr, sstr); -# else CowREFCNT(sstr) = 0; -# endif } #endif if (SvPVX_const(dstr)) { /* we know that dtype >= SVt_PV */ @@ -4641,18 +4657,10 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, SV* sstr, const I32 flags) #ifdef PERL_ANY_COW if (len) { -# ifdef PERL_OLD_COPY_ON_WRITE - assert (SvTYPE(dstr) >= SVt_PVIV); - /* SvIsCOW_normal */ - /* splice us in between source and next-after-source. */ - SV_COW_NEXT_SV_SET(dstr, SV_COW_NEXT_SV(sstr)); - SV_COW_NEXT_SV_SET(sstr, dstr); -# else if (sflags & SVf_IsCOW) { sv_buf_to_rw(sstr); } CowREFCNT(sstr)++; -# endif SvPV_set(dstr, SvPVX_mutable(sstr)); sv_buf_to_ro(sstr); } else @@ -4737,18 +4745,14 @@ Perl_sv_setsv_mg(pTHX_ SV *const dstr, SV *const sstr) } #ifdef PERL_ANY_COW -# ifdef PERL_OLD_COPY_ON_WRITE -# define SVt_COW SVt_PVIV -# else # define SVt_COW SVt_PV -# endif SV * Perl_sv_setsv_cow(pTHX_ SV *dstr, SV *sstr) { STRLEN cur = SvCUR(sstr); STRLEN len = SvLEN(sstr); char *new_pv; -#if defined(PERL_DEBUG_READONLY_COW) && defined(PERL_NEW_COPY_ON_WRITE) +#if defined(PERL_DEBUG_READONLY_COW) && defined(PERL_COPY_ON_WRITE) const bool already = cBOOL(SvIsCOW(sstr)); #endif @@ -4774,12 +4778,6 @@ Perl_sv_setsv_cow(pTHX_ SV *dstr, SV *sstr) assert (SvPOK(sstr)); assert (SvPOKp(sstr)); -# ifdef PERL_OLD_COPY_ON_WRITE - assert (!SvIOK(sstr)); - assert (!SvIOKp(sstr)); - assert (!SvNOK(sstr)); - assert (!SvNOKp(sstr)); -# endif if (SvIsCOW(sstr)) { @@ -4790,32 +4788,20 @@ Perl_sv_setsv_cow(pTHX_ SV *dstr, SV *sstr) new_pv = HEK_KEY(share_hek_hek(SvSHARED_HEK_FROM_PV(SvPVX_const(sstr)))); goto common_exit; } -# ifdef PERL_OLD_COPY_ON_WRITE - SV_COW_NEXT_SV_SET(dstr, SV_COW_NEXT_SV(sstr)); -# else assert(SvCUR(sstr)+1 < SvLEN(sstr)); assert(CowREFCNT(sstr) < SV_COW_REFCNT_MAX); -# endif } else { assert ((SvFLAGS(sstr) & CAN_COW_MASK) == CAN_COW_FLAGS); SvUPGRADE(sstr, SVt_COW); SvIsCOW_on(sstr); DEBUG_C(PerlIO_printf(Perl_debug_log, "Fast copy on write: Converting sstr to COW\n")); -# ifdef PERL_OLD_COPY_ON_WRITE - SV_COW_NEXT_SV_SET(dstr, sstr); -# else CowREFCNT(sstr) = 0; -# endif } -# ifdef PERL_OLD_COPY_ON_WRITE - SV_COW_NEXT_SV_SET(sstr, dstr); -# else # ifdef PERL_DEBUG_READONLY_COW if (already) sv_buf_to_rw(sstr); # endif CowREFCNT(sstr)++; -# endif new_pv = SvPVX_mutable(sstr); sv_buf_to_ro(sstr); @@ -5071,44 +5057,6 @@ Perl_sv_usepvn_flags(pTHX_ SV *const sv, char *ptr, const STRLEN len, const U32 SvSETMAGIC(sv); } -#ifdef PERL_OLD_COPY_ON_WRITE -/* Need to do this *after* making the SV normal, as we need the buffer - pointer to remain valid until after we've copied it. If we let go too early, - another thread could invalidate it by unsharing last of the same hash key - (which it can do by means other than releasing copy-on-write Svs) - or by changing the other copy-on-write SVs in the loop. */ -STATIC void -S_sv_release_COW(pTHX_ SV *sv, const char *pvx, SV *after) -{ - PERL_ARGS_ASSERT_SV_RELEASE_COW; - - { /* this SV was SvIsCOW_normal(sv) */ - /* we need to find the SV pointing to us. */ - SV *current = SV_COW_NEXT_SV(after); - - if (current == sv) { - /* The SV we point to points back to us (there were only two of us - in the loop.) - Hence other SV is no longer copy on write either. */ - SvIsCOW_off(after); - sv_buf_to_rw(after); - } else { - /* We need to follow the pointers around the loop. */ - SV *next; - while ((next = SV_COW_NEXT_SV(current)) != sv) { - assert (next); - current = next; - /* don't loop forever if the structure is bust, and we have - a pointer into a closed loop. */ - assert (current != after); - assert (SvPVX_const(current) == pvx); - } - /* Make the SV before us point to the SV after us. */ - SV_COW_NEXT_SV_SET(current, after); - } - } -} -#endif /* =for apidoc sv_force_normal_flags @@ -5141,12 +5089,6 @@ S_sv_uncow(pTHX_ SV * const sv, const U32 flags) const char * const pvx = SvPVX_const(sv); const STRLEN len = SvLEN(sv); const STRLEN cur = SvCUR(sv); -# ifdef PERL_OLD_COPY_ON_WRITE - /* next COW sv in the loop. If len is 0 then this is a shared-hash - key scalar, so we mustn't attempt to call SV_COW_NEXT_SV(), as - we'll fail an assertion. */ - SV * const next = len ? SV_COW_NEXT_SV(sv) : 0; -# endif if (DEBUG_C_TEST) { PerlIO_printf(Perl_debug_log, @@ -5155,23 +5097,28 @@ S_sv_uncow(pTHX_ SV * const sv, const U32 flags) sv_dump(sv); } SvIsCOW_off(sv); -# ifdef PERL_NEW_COPY_ON_WRITE - if (len && CowREFCNT(sv) == 0) - /* We own the buffer ourselves. */ - sv_buf_to_rw(sv); +# ifdef PERL_COPY_ON_WRITE + if (len) { + /* Must do this first, since the CowREFCNT uses SvPVX and + we need to write to CowREFCNT, or de-RO the whole buffer if we are + the only owner left of the buffer. */ + sv_buf_to_rw(sv); /* NOOP if RO-ing not supported */ + { + U8 cowrefcnt = CowREFCNT(sv); + if(cowrefcnt != 0) { + cowrefcnt--; + CowREFCNT(sv) = cowrefcnt; + sv_buf_to_ro(sv); + goto copy_over; + } + } + /* Else we are the only owner of the buffer. */ + } else # endif { - /* This SV doesn't own the buffer, so need to Newx() a new one: */ -# ifdef PERL_NEW_COPY_ON_WRITE - /* Must do this first, since the macro uses SvPVX. */ - if (len) { - sv_buf_to_rw(sv); - CowREFCNT(sv)--; - sv_buf_to_ro(sv); - } -# endif + copy_over: SvPV_set(sv, NULL); SvCUR_set(sv, 0); SvLEN_set(sv, 0); @@ -5185,9 +5132,6 @@ S_sv_uncow(pTHX_ SV * const sv, const U32 flags) *SvEND(sv) = '\0'; } if (len) { -# ifdef PERL_OLD_COPY_ON_WRITE - sv_release_COW(sv, pvx, next); -# endif } else { unshare_hek(SvSHARED_HEK_FROM_PV(pvx)); } @@ -5615,8 +5559,6 @@ Perl_sv_magicext(pTHX_ SV *const sv, SV *const obj, const int how, PERL_ARGS_ASSERT_SV_MAGICEXT; - if (SvTYPE(sv)==SVt_PVAV) { assert (!AvPAD_NAMELIST(sv)); } - SvUPGRADE(sv, SVt_PVMG); Newxz(mg, 1, MAGIC); mg->mg_moremagic = SvMAGIC(sv); @@ -5690,10 +5632,6 @@ Perl_sv_magicext_mglob(pTHX_ SV *sv) vivify_defelem(sv); sv = LvTARG(sv); } -#ifdef PERL_OLD_COPY_ON_WRITE - if (SvIsCOW(sv)) - sv_force_normal_flags(sv, 0); -#endif return sv_magicext(sv, NULL, PERL_MAGIC_regex_global, &PL_vtbl_mglob, 0, 0); } @@ -5739,10 +5677,6 @@ Perl_sv_magic(pTHX_ SV *const sv, SV *const obj, const int how, vtable = (vtable_index == magic_vtable_max) ? NULL : PL_magic_vtables + vtable_index; -#ifdef PERL_OLD_COPY_ON_WRITE - if (SvIsCOW(sv)) - sv_force_normal_flags(sv, 0); -#endif if (SvREADONLY(sv)) { if ( !PERL_MAGIC_TYPE_READONLY_ACCEPTABLE(how) @@ -5894,6 +5828,45 @@ Perl_sv_rvweaken(pTHX_ SV *const sv) return sv; } +/* +=for apidoc sv_get_backrefs + +If the sv is the target of a weak reference then it returns the back +references structure associated with the sv; otherwise return NULL. + +When returning a non-null result the type of the return is relevant. If it +is an AV then the elements of the AV are the weak reference RVs which +point at this item. If it is any other type then the item itself is the +weak reference. + +See also Perl_sv_add_backref(), Perl_sv_del_backref(), +Perl_sv_kill_backrefs() + +=cut +*/ + +SV * +Perl_sv_get_backrefs(SV *const sv) +{ + SV *backrefs= NULL; + + PERL_ARGS_ASSERT_SV_GET_BACKREFS; + + /* find slot to store array or singleton backref */ + + if (SvTYPE(sv) == SVt_PVHV) { + if (SvOOK(sv)) { + struct xpvhv_aux * const iter = HvAUX((HV *)sv); + backrefs = (SV *)iter->xhv_backreferences; + } + } else if (SvMAGICAL(sv)) { + MAGIC *mg = mg_find(sv, PERL_MAGIC_backref); + if (mg) + backrefs = mg->mg_obj; + } + return backrefs; +} + /* Give tsv backref magic if it hasn't already got it, then push a * back-reference to sv onto the array associated with the backref magic. * @@ -6214,8 +6187,6 @@ Perl_sv_insert_flags(pTHX_ SV *const bigstr, const STRLEN offset, const STRLEN l PERL_ARGS_ASSERT_SV_INSERT_FLAGS; - if (!bigstr) - Perl_croak(aTHX_ "Can't modify nonexistent substring"); SvPV_force_flags(bigstr, curlen, flags); (void)SvPOK_only_UTF8(bigstr); if (offset + len > curlen) { @@ -6333,33 +6304,10 @@ Perl_sv_replace(pTHX_ SV *const sv, SV *const nsv) StructCopy(nsv,sv,SV); #endif if(SvTYPE(sv) == SVt_IV) { - SvANY(sv) - = (XPVIV*)((char*)&(sv->sv_u.svu_iv) - STRUCT_OFFSET(XPVIV, xiv_iv)); + SET_SVANY_FOR_BODYLESS_IV(sv); } -#ifdef PERL_OLD_COPY_ON_WRITE - if (SvIsCOW_normal(nsv)) { - /* We need to follow the pointers around the loop to make the - previous SV point to sv, rather than nsv. */ - SV *next; - SV *current = nsv; - while ((next = SV_COW_NEXT_SV(current)) != nsv) { - assert(next); - current = next; - assert(SvPVX_const(current) == SvPVX_const(nsv)); - } - /* Make the SV before us point to the SV after us. */ - if (DEBUG_C_TEST) { - PerlIO_printf(Perl_debug_log, "previous is\n"); - sv_dump(current); - PerlIO_printf(Perl_debug_log, - "move it from 0x%"UVxf" to 0x%"UVxf"\n", - (UV) SV_COW_NEXT_SV(current), (UV) sv); - } - SV_COW_NEXT_SV_SET(current, sv); - } -#endif SvREFCNT(sv) = refcnt; SvFLAGS(nsv) |= SVTYPEMASK; /* Mark as freed */ SvREFCNT(nsv) = 0; @@ -6430,7 +6378,8 @@ Perl_sv_clear(pTHX_ SV *const orig_sv) SV* iter_sv = NULL; SV* next_sv = NULL; SV *sv = orig_sv; - STRLEN hash_index; + STRLEN hash_index = 0; /* initialise to make Coverity et al happy. + Not strictly necessary */ PERL_ARGS_ASSERT_SV_CLEAR; @@ -6456,7 +6405,9 @@ Perl_sv_clear(pTHX_ SV *const orig_sv) goto free_head; } - assert(!SvOBJECT(sv) || type >= SVt_PVMG); /* objs are always >= MG */ + /* objs are always >= MG, but pad names use the SVs_OBJECT flag + for another purpose */ + assert(!SvOBJECT(sv) || type >= SVt_PVMG); if (type >= SVt_PVMG) { if (SvOBJECT(sv)) { @@ -6470,19 +6421,12 @@ Perl_sv_clear(pTHX_ SV *const orig_sv) if (SvMAGIC(sv)) mg_free(sv); } - else if (type == SVt_PVMG && SvPAD_OUR(sv)) { - SvREFCNT_dec(SvOURSTASH(sv)); - } - else if (type == SVt_PVAV && AvPAD_NAMELIST(sv)) { - assert(!SvMAGICAL(sv)); - } else if (SvMAGIC(sv)) { + else if (SvMAGIC(sv)) { /* Free back-references before other types of magic. */ sv_unmagic(sv, PERL_MAGIC_backref); mg_free(sv); } SvMAGICAL_off(sv); - if (type == SVt_PVMG && SvPAD_TYPED(sv)) - SvREFCNT_dec(SvSTASH(sv)); } switch (type) { /* case SVt_INVLIST: */ @@ -6526,17 +6470,19 @@ Perl_sv_clear(pTHX_ SV *const orig_sv) PL_last_swash_hv = NULL; } if (HvTOTALKEYS((HV*)sv) > 0) { - const char *name; + const HEK *hek; /* this statement should match the one at the beginning of * hv_undef_flags() */ if ( PL_phase != PERL_PHASE_DESTRUCT - && (name = HvNAME((HV*)sv))) + && (hek = HvNAME_HEK((HV*)sv))) { if (PL_stashcache) { - DEBUG_o(Perl_deb(aTHX_ "sv_clear clearing PL_stashcache for '%"SVf"'\n", - SVfARG(sv))); + DEBUG_o(Perl_deb(aTHX_ + "sv_clear clearing PL_stashcache for '%"HEKf + "'\n", + HEKfARG(hek))); (void)hv_deletehek(PL_stashcache, - HvNAME_HEK((HV*)sv), G_DISCARD); + hek, G_DISCARD); } hv_name_set((HV*)sv, NULL, 0, 0); } @@ -6587,6 +6533,7 @@ Perl_sv_clear(pTHX_ SV *const orig_sv) else if (LvTYPE(sv) != 't') /* unless tie: unrefcnted fake SV** */ SvREFCNT_dec(LvTARG(sv)); if (isREGEXP(sv)) goto freeregexp; + /* FALLTHROUGH */ case SVt_PVGV: if (isGV_with_GP(sv)) { if(GvCVu((const GV *)sv) && (stash = GvSTASH(MUTABLE_GV(sv))) @@ -6611,6 +6558,7 @@ Perl_sv_clear(pTHX_ SV *const orig_sv) PL_statgv = NULL; else if ((const GV *)sv == PL_stderrgv) PL_stderrgv = NULL; + /* FALLTHROUGH */ case SVt_PVMG: case SVt_PVNV: case SVt_PVIV: @@ -6646,24 +6594,17 @@ Perl_sv_clear(pTHX_ SV *const orig_sv) sv_dump(sv); } if (SvLEN(sv)) { -# ifdef PERL_OLD_COPY_ON_WRITE - sv_release_COW(sv, SvPVX_const(sv), SV_COW_NEXT_SV(sv)); -# else if (CowREFCNT(sv)) { sv_buf_to_rw(sv); CowREFCNT(sv)--; sv_buf_to_ro(sv); SvLEN_set(sv, 0); } -# endif } else { unshare_hek(SvSHARED_HEK_FROM_PV(SvPVX_const(sv))); } } -# ifdef PERL_OLD_COPY_ON_WRITE - else -# endif if (SvLEN(sv)) { Safefree(SvPVX_mutable(sv)); } @@ -7262,7 +7203,7 @@ the start of the string, to a count of the equivalent number of bytes; if lenp is non-zero, it does the same to lenp, but this time starting from the offset, rather than from the start of the string. Handles type coercion. -I is passed to C, and usually should be +C is passed to C, and usually should be C to handle magic. =cut @@ -7539,7 +7480,7 @@ S_sv_pos_b2u_midway(pTHX_ const U8 *const s, const U8 *const target, Converts the offset from a count of bytes from the start of the string, to a count of the equivalent number of UTF-8 chars. Handles type coercion. -I is passed to C, and usually should be +C is passed to C, and usually should be C to handle magic. =cut @@ -7740,15 +7681,15 @@ Perl_sv_eq_flags(pTHX_ SV *sv1, SV *sv2, const U32 flags) if (cur1 && cur2 && SvUTF8(sv1) != SvUTF8(sv2) && !IN_BYTES) { /* Differing utf8ness. * Do not UTF8size the comparands as a side-effect. */ - if (PL_encoding) { + if (IN_ENCODING) { if (SvUTF8(sv1)) { svrecode = newSVpvn(pv2, cur2); - sv_recode_to_utf8(svrecode, PL_encoding); + sv_recode_to_utf8(svrecode, _get_encoding()); pv2 = SvPV_const(svrecode, cur2); } else { svrecode = newSVpvn(pv1, cur1); - sv_recode_to_utf8(svrecode, PL_encoding); + sv_recode_to_utf8(svrecode, _get_encoding()); pv1 = SvPV_const(svrecode, cur1); } /* Now both are in UTF-8. */ @@ -7831,9 +7772,9 @@ Perl_sv_cmp_flags(pTHX_ SV *const sv1, SV *const sv2, /* Differing utf8ness. * Do not UTF8size the comparands as a side-effect. */ if (SvUTF8(sv1)) { - if (PL_encoding) { + if (IN_ENCODING) { svrecode = newSVpvn(pv2, cur2); - sv_recode_to_utf8(svrecode, PL_encoding); + sv_recode_to_utf8(svrecode, _get_encoding()); pv2 = SvPV_const(svrecode, cur2); } else { @@ -7843,9 +7784,9 @@ Perl_sv_cmp_flags(pTHX_ SV *const sv1, SV *const sv2, } } else { - if (PL_encoding) { + if (IN_ENCODING) { svrecode = newSVpvn(pv1, cur1); - sv_recode_to_utf8(svrecode, PL_encoding); + sv_recode_to_utf8(svrecode, _get_encoding()); pv1 = SvPV_const(svrecode, cur1); } else { @@ -7990,10 +7931,6 @@ Perl_sv_collxfrm_flags(pTHX_ SV *const sv, STRLEN *const nxp, const I32 flags) s = SvPV_flags_const(sv, len, flags); if ((xf = mem_collxfrm(s, len, &xlen))) { if (! mg) { -#ifdef PERL_OLD_COPY_ON_WRITE - if (SvIsCOW(sv)) - sv_force_normal_flags(sv, 0); -#endif mg = sv_magicext(sv, 0, PERL_MAGIC_collxfrm, &PL_vtbl_collxfrm, 0, 0); assert(mg); @@ -8217,10 +8154,11 @@ Perl_sv_gets(pTHX_ SV *const sv, PerlIO *const fp, I32 append) the size we read (e.g. CRLF or a gzip layer). */ Stat_t st; - if (!PerlLIO_fstat(PerlIO_fileno(fp), &st) && S_ISREG(st.st_mode)) { + int fd = PerlIO_fileno(fp); + if (fd >= 0 && (PerlLIO_fstat(fd, &st) == 0) && S_ISREG(st.st_mode)) { const Off_t offset = PerlIO_tell(fp); if (offset != (Off_t) -1 && st.st_size + append > offset) { -#ifdef PERL_NEW_COPY_ON_WRITE +#ifdef PERL_COPY_ON_WRITE /* Add an extra byte for the sake of copy-on-write's * buffer reference count. */ (void) SvGROW(sv, (STRLEN)((st.st_size - offset) + append + 2)); @@ -8307,16 +8245,6 @@ Perl_sv_gets(pTHX_ SV *const sv, PerlIO *const fp, I32 append) amount left, otherwise this is the amount it can hold. */ -#if defined(__VMS) && defined(PERLIO_IS_STDIO) - /* An ungetc()d char is handled separately from the regular - * buffer, so we getc() it back out and stuff it in the buffer. - */ - i = PerlIO_getc(fp); - if (i == EOF) return 0; - *(--((*fp)->_ptr)) = (unsigned char) i; - (*fp)->_cnt++; -#endif - /* Here is some breathtakingly efficient cheating */ /* When you read the following logic resist the urge to think @@ -8505,13 +8433,13 @@ Perl_sv_gets(pTHX_ SV *const sv, PerlIO *const fp, I32 append) goto thats_all_folks; } -thats_all_folks: + thats_all_folks: /* check if we have actually found the separator - only really applies * when rslen > 1 */ if ((rslen > 1 && (STRLEN)(bp - (STDCHAR*)SvPVX_const(sv)) < rslen) || memNE((char*)bp - rslen, rsptr, rslen)) goto screamer; /* go back to the fray */ -thats_really_all_folks: + thats_really_all_folks: if (shortbuffered) cnt += shortbuffered; DEBUG_P(PerlIO_printf(Perl_debug_log, @@ -8539,7 +8467,7 @@ thats_really_all_folks: STDCHAR buf[8192]; #endif -screamer2: + screamer2: if (rslen) { const STDCHAR * const bpe = buf + sizeof(buf); bp = buf; @@ -9255,7 +9183,7 @@ Perl_newSVpvf_nocontext(const char *const pat, ...) =for apidoc newSVpvf Creates a new SV and initializes it with the string formatted like -C. +C. =cut */ @@ -9322,7 +9250,22 @@ Perl_newSViv(pTHX_ const IV i) SV *sv; new_SV(sv); - sv_setiv(sv,i); + + /* Inlining ONLY the small relevant subset of sv_setiv here + * for performance. Makes a significant difference. */ + + /* We're starting from SVt_FIRST, so provided that's + * actual 0, we don't have to unset any SV type flags + * to promote to SVt_IV. */ + STATIC_ASSERT_STMT(SVt_FIRST == 0); + + SET_SVANY_FOR_BODYLESS_IV(sv); + SvFLAGS(sv) |= SVt_IV; + (void)SvIOK_on(sv); + + SvIV_set(sv, i); + SvTAINT(sv); + return sv; } @@ -9340,8 +9283,29 @@ Perl_newSVuv(pTHX_ const UV u) { SV *sv; + /* Inlining ONLY the small relevant subset of sv_setuv here + * for performance. Makes a significant difference. */ + + /* Using ivs is more efficient than using uvs - see sv_setuv */ + if (u <= (UV)IV_MAX) { + return newSViv((IV)u); + } + new_SV(sv); - sv_setuv(sv,u); + + /* We're starting from SVt_FIRST, so provided that's + * actual 0, we don't have to unset any SV type flags + * to promote to SVt_IV. */ + STATIC_ASSERT_STMT(SVt_FIRST == 0); + + SET_SVANY_FOR_BODYLESS_IV(sv); + SvFLAGS(sv) |= SVt_IV; + (void)SvIOK_on(sv); + (void)SvIsUV_on(sv); + + SvUV_set(sv, u); + SvTAINT(sv); + return sv; } @@ -9378,13 +9342,25 @@ SV is B incremented. SV * Perl_newRV_noinc(pTHX_ SV *const tmpRef) { - SV *sv = newSV_type(SVt_IV); + SV *sv; PERL_ARGS_ASSERT_NEWRV_NOINC; + new_SV(sv); + + /* We're starting from SVt_FIRST, so provided that's + * actual 0, we don't have to unset any SV type flags + * to promote to SVt_IV. */ + STATIC_ASSERT_STMT(SVt_FIRST == 0); + + SET_SVANY_FOR_BODYLESS_IV(sv); + SvFLAGS(sv) |= SVt_IV; + SvROK_on(sv); + SvIV_set(sv, 0); + SvTEMP_off(tmpRef); SvRV_set(sv, tmpRef); - SvROK_on(sv); + return sv; } @@ -9967,7 +9943,7 @@ Perl_newSVrv(pTHX_ SV *const rv, const char *const classname) SV_CHECK_THINKFIRST_COW_DROP(rv); - if (SvTYPE(rv) >= SVt_PVMG) { + if (UNLIKELY( SvTYPE(rv) >= SVt_PVMG )) { const U32 refcnt = SvREFCNT(rv); SvREFCNT(rv) = 0; sv_clear(rv); @@ -10504,8 +10480,10 @@ Perl_sv_catpvf_mg_nocontext(SV *const sv, const char *const pat, ...) /* =for apidoc sv_catpvf -Processes its arguments like C and appends the formatted -output to an SV. If the appended data contains "wide" characters +Processes its arguments like C, and appends the formatted +output to an SV. As with C called with a non-null C-style +variable argument list, argument reordering is not supported. +If the appended data contains "wide" characters (including, but not limited to, SVs with a UTF-8 PV formatted with %s, and characters >255 formatted with %c), the original SV might get upgraded to UTF-8. Handles 'get' magic, but not 'set' magic. See @@ -10529,7 +10507,8 @@ Perl_sv_catpvf(pTHX_ SV *const sv, const char *const pat, ...) /* =for apidoc sv_vcatpvf -Processes its arguments like C and appends the formatted output +Processes its arguments like C called with a non-null C-style +variable argument list, and appends the formatted to an SV. Does not handle 'set' magic. See C. Usually used via its frontend C. @@ -10608,16 +10587,16 @@ Perl_sv_vsetpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen, /* - * Warn of missing argument to sprintf, and then return a defined value - * to avoid inappropriate "use of uninit" warnings [perl #71000]. + * Warn of missing argument to sprintf. The value used in place of such + * arguments should be &PL_sv_no; an undefined value would yield + * inappropriate "use of uninit" warnings [perl #71000]. */ -STATIC SV* -S_vcatpvfn_missing_argument(pTHX) { +STATIC void +S_warn_vcatpvfn_missing_argument(pTHX) { if (ckWARN(WARN_MISSING)) { Perl_warner(aTHX_ packWARN(WARN_MISSING), "Missing argument in %s", PL_op ? OP_DESC(PL_op) : "sv_vcatpvfn()"); } - return &PL_sv_no; } @@ -10652,7 +10631,7 @@ S_F0convert(NV nv, char *const endbuf, STRLEN *const len) PERL_ARGS_ASSERT_F0CONVERT; if (UNLIKELY(Perl_isinfnan(nv))) { - STRLEN n = S_infnan_2pv(nv, endbuf - *len, *len); + STRLEN n = S_infnan_2pv(nv, endbuf - *len, *len, 0); *len = n; return endbuf - n; } @@ -10683,8 +10662,13 @@ S_F0convert(NV nv, char *const endbuf, STRLEN *const len) =for apidoc sv_vcatpvfn_flags Processes its arguments like C and appends the formatted output -to an SV. Uses an array of SVs if the C style variable argument list is -missing (NULL). When running with taint checks enabled, indicates via +to an SV. Uses an array of SVs if the C-style variable argument list is +missing (NULL). Argument reordering (using format specifiers like C<%2$d> +or C<%*2$d>) is supported only when using an array of SVs; using a C-style +C argument list with a format string that uses argument reordering +will yield an exception. + +When running with taint checks enabled, indicates via C if results are untrustworthy (often due to the use of locales). @@ -10710,32 +10694,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen, sv_vcatpvfn_flags(sv, pat, patlen, args, svargs, svmax, maybe_tainted, SV_GMAGIC|SV_SMAGIC); } -#if DOUBLEKIND == DOUBLE_IS_IEEE_754_32_BIT_LITTLE_ENDIAN || \ - DOUBLEKIND == DOUBLE_IS_IEEE_754_64_BIT_LITTLE_ENDIAN || \ - DOUBLEKIND == DOUBLE_IS_IEEE_754_128_BIT_LITTLE_ENDIAN -# define DOUBLE_LITTLE_ENDIAN -#endif - -#if LONG_DOUBLEKIND == LONG_DOUBLE_IS_IEEE_754_128_BIT_LITTLE_ENDIAN || \ - LONG_DOUBLEKIND == LONG_DOUBLE_IS_X86_80_BIT_LITTLE_ENDIAN || \ - LONG_DOUBLEKIND == LONG_DOUBLE_IS_DOUBLEDOUBLE_128_BIT_LITTLE_ENDIAN -# define LONGDOUBLE_LITTLE_ENDIAN -#endif - -#if LONG_DOUBLEKIND == LONG_DOUBLE_IS_IEEE_754_128_BIT_BIG_ENDIAN || \ - LONG_DOUBLEKIND == LONG_DOUBLE_IS_X86_80_BIT_BIG_ENDIAN || \ - LONG_DOUBLEKIND == LONG_DOUBLE_IS_DOUBLEDOUBLE_128_BIT_BIG_ENDIAN -# define LONGDOUBLE_BIG_ENDIAN -#endif - -#if LONG_DOUBLEKIND == LONG_DOUBLE_IS_X86_80_BIT_LITTLE_ENDIAN || \ - LONG_DOUBLEKIND == LONG_DOUBLE_IS_X86_80_BIT_BIG_ENDIAN -# define LONGDOUBLE_X86_80_BIT -#endif - -#if LONG_DOUBLEKIND == LONG_DOUBLE_IS_DOUBLEDOUBLE_128_BIT_LITTLE_ENDIAN || \ - LONG_DOUBLEKIND == LONG_DOUBLE_IS_DOUBLEDOUBLE_128_BIT_BIG_ENDIAN -# define LONGDOUBLE_DOUBLEDOUBLE +#ifdef LONGDOUBLE_DOUBLEDOUBLE /* The first double can be as large as 2**1023, or '1' x '0' x 1023. * The second double can be as small as 2**-1074, or '0' x 1073 . '1'. * The sum of them can be '1' . '0' x 2096 . '1', with implied radix point @@ -11071,6 +11030,17 @@ S_hextract(pTHX_ const NV nv, int* exponent, U8* vhex, U8* vend) return v; } +/* Helper for sv_vcatpvfn_flags(). */ +#define FETCH_VCATPVFN_ARGUMENT(var, in_range, expr) \ + STMT_START { \ + if (in_range) \ + (var) = (expr); \ + else { \ + (var) = &PL_sv_no; /* [perl #71000] */ \ + arg_missing = TRUE; \ + } \ + } STMT_END + void Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen, va_list *const args, SV **const svargs, const I32 svmax, bool *const maybe_tainted, @@ -11093,7 +11063,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p bool no_redundant_warning = FALSE; /* did we use any explicit format parameter index? */ bool hexfp = FALSE; /* hexadecimal floating point? */ - DECLARATION_FOR_STORE_LC_NUMERIC_SET_TO_NEEDED; + DECLARATION_FOR_LC_NUMERIC_MANIPULATION; PERL_ARGS_ASSERT_SV_VCATPVFN_FLAGS; PERL_UNUSED_ARG(maybe_tainted); @@ -11126,7 +11096,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p sv_catsv_nomg(sv, *svargs); } else - S_vcatpvfn_missing_argument(aTHX); + S_warn_vcatpvfn_missing_argument(aTHX); return; } if (args && patlen == 3 && pat[0] == '%' && @@ -11200,6 +11170,8 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p STRLEN precis = 0; const I32 osvix = svix; bool is_utf8 = FALSE; /* is this item utf8? */ + bool used_explicit_ix = FALSE; + bool arg_missing = FALSE; #ifdef HAS_LDBL_SPRINTF_BUG /* This is to try to fix a bug with irix/nonstop-ux/powerux and with sfio - Allen */ @@ -11252,6 +11224,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p #ifndef FV_ISFINITE # define FV_ISFINITE(x) Perl_isfinite((NV)(x)) #endif + NV nv; STRLEN have; STRLEN need; STRLEN gap; @@ -11362,13 +11335,12 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p if ( (width = expect_number(&q)) ) { if (*q == '$') { + if (args) + Perl_croak_nocontext( + "Cannot yet reorder sv_catpvfn() arguments from va_list"); ++q; efix = width; - if (!no_redundant_warning) - /* I've forgotten if it's a better - micro-optimization to always set this or to - only set it if it's unset */ - no_redundant_warning = TRUE; + used_explicit_ix = TRUE; } else { goto gotwidth; } @@ -11409,9 +11381,15 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p tryasterisk: if (*q == '*') { q++; - if ( (ewix = expect_number(&q)) ) - if (*q++ != '$') + if ( (ewix = expect_number(&q)) ) { + if (*q++ == '$') { + if (args) + Perl_croak_nocontext( + "Cannot yet reorder sv_catpvfn() arguments from va_list"); + used_explicit_ix = TRUE; + } else goto unknown; + } asterisk = TRUE; } if (*q == 'v') { @@ -11439,11 +11417,11 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p if (args) vecsv = va_arg(*args, SV*); else if (evix) { - vecsv = (evix > 0 && evix <= svmax) - ? svargs[evix-1] : S_vcatpvfn_missing_argument(aTHX); + FETCH_VCATPVFN_ARGUMENT( + vecsv, evix > 0 && evix <= svmax, svargs[evix-1]); } else { - vecsv = svix < svmax - ? svargs[svix++] : S_vcatpvfn_missing_argument(aTHX); + FETCH_VCATPVFN_ARGUMENT( + vecsv, svix < svmax, svargs[svix++]); } dotstr = SvPV_const(vecsv, dotstrlen); /* Keep the DO_UTF8 test *after* the SvPV call, else things go @@ -11475,16 +11453,27 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p q++; if (*q == '*') { q++; - if ( ((epix = expect_number(&q))) && (*q++ != '$') ) - goto unknown; - /* XXX: todo, support specified precision parameter */ - if (epix) - goto unknown; + if ( (epix = expect_number(&q)) ) { + if (*q++ == '$') { + if (args) + Perl_croak_nocontext( + "Cannot yet reorder sv_catpvfn() arguments from va_list"); + used_explicit_ix = TRUE; + } else + goto unknown; + } if (args) - i = va_arg(*args, int); - else - i = (ewix ? ewix <= svmax : svix < svmax) - ? SvIVx(svargs[ewix ? ewix-1 : svix++]) : 0; + i = va_arg(*args, int); + else { + SV *precsv; + if (epix) + FETCH_VCATPVFN_ARGUMENT( + precsv, epix > 0 && epix <= svmax, svargs[epix-1]); + else + FETCH_VCATPVFN_ARGUMENT( + precsv, svix < svmax, svargs[svix++]); + i = precsv == &PL_sv_no ? 0 : SvIVx(precsv); + } precis = i; has_precis = !(i < 0); } @@ -11551,23 +11540,25 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p q++; break; #endif -#if IVSIZE >= 8 || defined(HAS_LONG_DOUBLE) +#if (IVSIZE >= 8 || defined(HAS_LONG_DOUBLE)) || \ + (IVSIZE == 4 && !defined(HAS_LONG_DOUBLE)) case 'L': /* Ld */ /* FALLTHROUGH */ -#ifdef USE_QUADMATH +# ifdef USE_QUADMATH case 'Q': /* FALLTHROUGH */ -#endif -#if IVSIZE >= 8 +# endif +# if IVSIZE >= 8 case 'q': /* qd */ -#endif +# endif intsize = 'q'; q++; break; #endif case 'l': ++q; -#if IVSIZE >= 8 || defined(HAS_LONG_DOUBLE) +#if (IVSIZE >= 8 || defined(HAS_LONG_DOUBLE)) || \ + (IVSIZE == 4 && !defined(HAS_LONG_DOUBLE)) if (*q == 'l') { /* lld, llf */ intsize = 'q'; ++q; @@ -11609,17 +11600,18 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p if (!vectorize && !args) { if (efix) { const I32 i = efix-1; - argsv = (i >= 0 && i < svmax) - ? svargs[i] : S_vcatpvfn_missing_argument(aTHX); + FETCH_VCATPVFN_ARGUMENT(argsv, i >= 0 && i < svmax, svargs[i]); } else { - argsv = (svix >= 0 && svix < svmax) - ? svargs[svix++] : S_vcatpvfn_missing_argument(aTHX); + FETCH_VCATPVFN_ARGUMENT(argsv, svix >= 0 && svix < svmax, + svargs[svix++]); } } if (argsv && strchr("BbcDdiOopuUXx",*q)) { /* XXX va_arg(*args) case? need peek, use va_copy? */ SvGETMAGIC(argsv); + if (UNLIKELY(SvAMAGIC(argsv))) + argsv = sv_2num(argsv); infnan = UNLIKELY(isinfnansv(argsv)); } @@ -11714,7 +11706,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p if (vectorize) { STRLEN ulen; if (!veclen) - continue; + goto donevalidconversion; if (vec_utf8) uv = utf8n_to_uvchr(vecstr, veclen, &ulen, UTF8_ALLOW_ANYUV); @@ -11773,7 +11765,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p esignbuf[esignlen++] = plus; } else { - uv = -iv; + uv = (iv == IV_MIN) ? (UV)iv : (UV)(-iv); esignbuf[esignlen++] = '-'; } } @@ -11819,7 +11811,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p STRLEN ulen; vector: if (!veclen) - continue; + goto donevalidconversion; if (vec_utf8) uv = utf8n_to_uvchr(vecstr, veclen, &ulen, UTF8_ALLOW_ANYUV); @@ -11991,19 +11983,25 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p #ifdef USE_QUADMATH fv = intsize == 'q' ? va_arg(*args, NV) : va_arg(*args, double); + nv = fv; #elif LONG_DOUBLESIZE > DOUBLESIZE - if (intsize == 'q') + if (intsize == 'q') { fv = va_arg(*args, long double); - else - NV_TO_FV(va_arg(*args, double), fv); + nv = fv; + } else { + nv = va_arg(*args, double); + NV_TO_FV(nv, fv); + } #else - fv = va_arg(*args, double); + nv = va_arg(*args, double); + fv = nv; #endif } else { if (!infnan) SvGETMAGIC(argsv); - NV_TO_FV(SvNV_nomg(argsv), fv); + nv = SvNV_nomg(argsv); + NV_TO_FV(nv, fv); } need = 0; @@ -12150,7 +12148,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p goto float_converted; } } else if ( c == 'f' && !precis ) { - if ((eptr = F0convert(fv, ebuf + sizeof ebuf, &elen))) + if ((eptr = F0convert(nv, ebuf + sizeof ebuf, &elen))) break; } } @@ -12178,10 +12176,8 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p * should be output as 0x0.0000000000001p-1022 to * match its internal structure. */ - /* Note: fv can be (and often is) long double. - * Here it is explicitly cast to NV. */ - vend = S_hextract(aTHX_ (NV)fv, &exponent, vhex, NULL); - S_hextract(aTHX_ (NV)fv, &exponent, vhex, vend); + vend = S_hextract(aTHX_ nv, &exponent, vhex, NULL); + S_hextract(aTHX_ nv, &exponent, vhex, vend); #if NVSIZE > DOUBLESIZE # ifdef HEXTRACT_HAS_IMPLICIT_BIT @@ -12233,12 +12229,14 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p #endif if (precis > 0) { - v = vhex + precis + 1; - if (v < vend) { + if ((SSize_t)(precis + 1) < vend - vhex) { + bool round; + + v = vhex + precis + 1; /* Round away from zero: if the tail * beyond the precis xdigits is equal to * or greater than 0x8000... */ - bool round = *v > 0x8; + round = *v > 0x8; if (!round && *v == 0x8) { for (v++; v < vend; v++) { if (*v) { @@ -12336,8 +12334,25 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p elen = width; } } - else - elen = S_infnan_2pv(fv, PL_efloatbuf, PL_efloatsize); + else { + elen = S_infnan_2pv(nv, PL_efloatbuf, PL_efloatsize, plus); + if (elen) { + /* Not affecting infnan output: precision, alt, fill. */ + if (elen < width) { + if (left) { + /* Pack the back with spaces. */ + memset(PL_efloatbuf + elen, ' ', width - elen); + } else { + /* Move it to the right. */ + Move(PL_efloatbuf, PL_efloatbuf + width - elen, + elen, char); + /* Pad the front with spaces. */ + memset(PL_efloatbuf, ' ', width - elen); + } + elen = width; + } + } + } if (elen == 0) { char *ptr = ebuf + sizeof ebuf; @@ -12396,7 +12411,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p if (!qfmt) Perl_croak_nocontext("panic: quadmath invalid format \"%s\"", ptr); elen = quadmath_snprintf(PL_efloatbuf, PL_efloatsize, - qfmt, fv); + qfmt, nv); if ((IV)elen == -1) Perl_croak_nocontext("panic: quadmath_snprintf failed, format \"%s|'", qfmt); if (qfmt != ptr) @@ -12458,7 +12473,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p } else sv_setuv_mg(argsv, has_utf8 ? (UV)sv_len_utf8(sv) : (UV)i); - continue; /* not "break" */ + goto donevalidconversion; /* UNKNOWN */ @@ -12583,6 +12598,12 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p esignlen = 0; goto vector; } + + donevalidconversion: + if (used_explicit_ix) + no_redundant_warning = TRUE; + if (arg_missing) + S_warn_vcatpvfn_missing_argument(aTHX); } /* Now that we've consumed all our printf format arguments (svix) @@ -13123,7 +13144,7 @@ Perl_ptr_table_clear(pTHX_ PTR_TBL_t *const tbl) if (tbl && tbl->tbl_items) { struct ptr_tbl_arena *arena = tbl->tbl_arena; - Zero(tbl->tbl_ary, tbl->tbl_max + 1, struct ptr_tbl_ent **); + Zero(tbl->tbl_ary, tbl->tbl_max + 1, struct ptr_tbl_ent *); while (arena) { struct ptr_tbl_arena *next = arena->next; @@ -13314,7 +13335,9 @@ S_sv_dup_common(pTHX_ const SV *const sstr, CLONE_PARAMS *const param) #endif /* don't clone objects whose class has asked us not to */ - if (SvOBJECT(sstr) && ! (SvFLAGS(SvSTASH(sstr)) & SVphv_CLONEABLE)) { + if (SvOBJECT(sstr) + && ! (SvFLAGS(SvSTASH(sstr)) & SVphv_CLONEABLE)) + { SvFLAGS(dstr) = 0; return dstr; } @@ -13324,7 +13347,7 @@ S_sv_dup_common(pTHX_ const SV *const sstr, CLONE_PARAMS *const param) SvANY(dstr) = NULL; break; case SVt_IV: - SvANY(dstr) = (XPVIV*)((char*)&(dstr->sv_u.svu_iv) - STRUCT_OFFSET(XPVIV, xiv_iv)); + SET_SVANY_FOR_BODYLESS_IV(dstr); if(SvROK(sstr)) { Perl_rvpv_dup(aTHX_ dstr, sstr, param); } else { @@ -13333,7 +13356,7 @@ S_sv_dup_common(pTHX_ const SV *const sstr, CLONE_PARAMS *const param) break; case SVt_NV: #if NVSIZE <= IVSIZE - SvANY(dstr) = (XPVNV*)((char*)&(dstr->sv_u.svu_nv) - STRUCT_OFFSET(XPVNV, xnv_u.xnv_nv)); + SET_SVANY_FOR_BODYLESS_NV(dstr); #else SvANY(dstr) = new_XNV(); #endif @@ -13399,11 +13422,7 @@ S_sv_dup_common(pTHX_ const SV *const sstr, CLONE_PARAMS *const param) missing by always going for the destination. FIXME - instrument and check that assumption */ if (sv_type >= SVt_PVMG) { - if ((sv_type == SVt_PVMG) && SvPAD_OUR(dstr)) { - SvOURSTASH_set(dstr, hv_dup_inc(SvOURSTASH(dstr), param)); - } else if (sv_type == SVt_PVAV && AvPAD_NAMELIST(dstr)) { - NOOP; - } else if (SvMAGIC(dstr)) + if (SvMAGIC(dstr)) SvMAGIC_set(dstr, mg_dup(SvMAGIC(dstr), param)); if (SvOBJECT(dstr) && SvSTASH(dstr)) SvSTASH_set(dstr, hv_dup_inc(SvSTASH(dstr), param)); @@ -13502,7 +13521,7 @@ S_sv_dup_common(pTHX_ const SV *const sstr, CLONE_PARAMS *const param) } items = AvMAX((const AV *)sstr) - AvFILLp((const AV *)sstr); while (items-- > 0) { - *dst_ary++ = &PL_sv_undef; + *dst_ary++ = NULL; } } else { @@ -13743,17 +13762,22 @@ Perl_cx_dup(pTHX_ PERL_CONTEXT *cxs, I32 ix, I32 max, CLONE_PARAMS* param) case CXt_LOOP_LAZYSV: ncx->blk_loop.state_u.lazysv.end = sv_dup_inc(ncx->blk_loop.state_u.lazysv.end, param); - /* We are taking advantage of av_dup_inc and sv_dup_inc - actually being the same function, and order equivalence of - the two unions. + /* Fallthrough: duplicate lazysv.cur by using the ary.ary + duplication code instead. + We are taking advantage of (1) av_dup_inc and sv_dup_inc + actually being the same function, and (2) order + equivalence of the two unions. We can assert the later [but only at run time :-(] */ assert ((void *) &ncx->blk_loop.state_u.ary.ary == (void *) &ncx->blk_loop.state_u.lazysv.cur); + /* FALLTHROUGH */ case CXt_LOOP_FOR: ncx->blk_loop.state_u.ary.ary = av_dup_inc(ncx->blk_loop.state_u.ary.ary, param); + /* FALLTHROUGH */ case CXt_LOOP_LAZYIV: case CXt_LOOP_PLAIN: + /* code common to all CXt_LOOP_* types */ if (CxPADLOOP(ncx)) { ncx->blk_loop.itervar_u.oldcomppad = (PAD*)ptr_table_fetch(PL_ptr_table, @@ -13904,14 +13928,16 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param) case SAVEt_CLEARPADRANGE: break; case SAVEt_HELEM: /* hash element */ + case SAVEt_SV: /* scalar reference */ sv = (const SV *)POPPTR(ss,ix); - TOPPTR(nss,ix) = sv_dup_inc(sv, param); + TOPPTR(nss,ix) = SvREFCNT_inc(sv_dup_inc(sv, param)); /* FALLTHROUGH */ case SAVEt_ITEM: /* normal string */ case SAVEt_GVSV: /* scalar slot in GV */ - case SAVEt_SV: /* scalar reference */ sv = (const SV *)POPPTR(ss,ix); TOPPTR(nss,ix) = sv_dup_inc(sv, param); + if (type == SAVEt_SV) + break; /* FALLTHROUGH */ case SAVEt_FREESV: case SAVEt_MORTALIZESV: @@ -13919,6 +13945,11 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param) sv = (const SV *)POPPTR(ss,ix); TOPPTR(nss,ix) = sv_dup_inc(sv, param); break; + case SAVEt_FREEPADNAME: + ptr = POPPTR(ss,ix); + TOPPTR(nss,ix) = padname_dup((PADNAME *)ptr, param); + PadnameREFCNT((PADNAME *)TOPPTR(nss,ix))++; + break; case SAVEt_SHARED_PVREF: /* char* in shared space */ c = (char*)POPPTR(ss,ix); TOPPTR(nss,ix) = savesharedpv(c); @@ -13929,6 +13960,8 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param) case SAVEt_SVREF: /* scalar reference */ sv = (const SV *)POPPTR(ss,ix); TOPPTR(nss,ix) = sv_dup_inc(sv, param); + if (type == SAVEt_SVREF) + SvREFCNT_inc_simple_void((SV *)TOPPTR(nss,ix)); ptr = POPPTR(ss,ix); TOPPTR(nss,ix) = svp_dup_inc((SV**)ptr, proto_perl);/* XXXXX */ break; @@ -14081,7 +14114,7 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param) break; case SAVEt_AELEM: /* array element */ sv = (const SV *)POPPTR(ss,ix); - TOPPTR(nss,ix) = sv_dup_inc(sv, param); + TOPPTR(nss,ix) = SvREFCNT_inc(sv_dup_inc(sv, param)); i = POPINT(ss,ix); TOPINT(nss,ix) = i; av = (const AV *)POPPTR(ss,ix); @@ -14126,11 +14159,13 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param) ptr = POPPTR(ss,ix); TOPPTR(nss,ix) = parser_dup((const yy_parser*)ptr, param); break; - case SAVEt_GP_ALIASED_SV: - ptr = POPPTR(ss,ix); - TOPPTR(nss,ix) = gp_dup((GP *)ptr, param); - ((GP *)ptr)->gp_refcnt++; + case SAVEt_GP_ALIASED_SV: { + GP * gp_ptr = (GP *)POPPTR(ss,ix); + GP * new_gp_ptr = gp_dup(gp_ptr, param); + TOPPTR(nss,ix) = new_gp_ptr; + new_gp_ptr->gp_refcnt++; break; + } default: Perl_croak(aTHX_ "panic: ss_dup inconsistency (%"IVdf")", (IV) type); @@ -14288,9 +14323,14 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags, PL_sig_pending = 0; PL_parser = NULL; Zero(&PL_debug_pad, 1, struct perl_debug_pad); + Zero(&PL_padname_undef, 1, PADNAME); + Zero(&PL_padname_const, 1, PADNAME); # ifdef DEBUG_LEAKING_SCALARS PL_sv_serial = (((UV)my_perl >> 2) & 0xfff) * 1000000; # endif +# ifdef PERL_TRACE_OPS + Zero(PL_op_exec_cnt, OP_max+2, UV); +# endif #else /* !DEBUGGING */ Zero(my_perl, 1, PerlInterpreter); #endif /* DEBUGGING */ @@ -14430,6 +14470,8 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags, PL_subline = proto_perl->Isubline; + PL_cv_has_eval = proto_perl->Icv_has_eval; + #ifdef FCRYPT PL_cryptseen = proto_perl->Icryptseen; #endif @@ -14568,6 +14610,8 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags, ptr_table_store(PL_ptr_table, &proto_perl->Isv_undef, &PL_sv_undef); ptr_table_store(PL_ptr_table, &proto_perl->Isv_no, &PL_sv_no); ptr_table_store(PL_ptr_table, &proto_perl->Isv_yes, &PL_sv_yes); + ptr_table_store(PL_ptr_table, &proto_perl->Ipadname_const, + &PL_padname_const); /* create (a non-shared!) shared string table */ PL_strtab = newHV(); @@ -14620,6 +14664,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags, /* magical thingies */ PL_encoding = sv_dup(proto_perl->Iencoding, param); + PL_lex_encoding = sv_dup(proto_perl->Ilex_encoding, param); sv_setpvs(PERL_DEBUG_PAD(0), ""); /* For regex debugging. */ sv_setpvs(PERL_DEBUG_PAD(1), ""); /* ext/re needs these */ @@ -14682,6 +14727,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags, PL_endav = av_dup_inc(proto_perl->Iendav, param); PL_checkav = av_dup_inc(proto_perl->Icheckav, param); PL_initav = av_dup_inc(proto_perl->Iinitav, param); + PL_savebegin = proto_perl->Isavebegin; PL_isarev = hv_dup_inc(proto_perl->Iisarev, param); @@ -14761,6 +14807,11 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags, PL_subname = sv_dup_inc(proto_perl->Isubname, param); +#ifdef USE_LOCALE_CTYPE + /* Should we warn if uses locale? */ + PL_warn_locale = sv_dup_inc(proto_perl->Iwarn_locale, param); +#endif + #ifdef USE_LOCALE_COLLATE PL_collation_name = SAVEPV(proto_perl->Icollation_name); #endif /* USE_LOCALE_COLLATE */ @@ -14786,9 +14837,10 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags, for (i = 0; i < POSIX_CC_COUNT; i++) { PL_XPosix_ptrs[i] = sv_dup_inc(proto_perl->IXPosix_ptrs[i], param); } + PL_GCB_invlist = sv_dup_inc(proto_perl->IGCB_invlist, param); + PL_SB_invlist = sv_dup_inc(proto_perl->ISB_invlist, param); + PL_WB_invlist = sv_dup_inc(proto_perl->IWB_invlist, param); PL_utf8_mark = sv_dup_inc(proto_perl->Iutf8_mark, param); - PL_utf8_X_regular_begin = sv_dup_inc(proto_perl->Iutf8_X_regular_begin, param); - PL_utf8_X_extend = sv_dup_inc(proto_perl->Iutf8_X_extend, param); PL_utf8_toupper = sv_dup_inc(proto_perl->Iutf8_toupper, param); PL_utf8_totitle = sv_dup_inc(proto_perl->Iutf8_totitle, param); PL_utf8_tolower = sv_dup_inc(proto_perl->Iutf8_tolower, param); @@ -15077,6 +15129,8 @@ Perl_init_constants(pTHX) SvLEN_set(&PL_sv_yes, 0); SvIV_set(&PL_sv_yes, 1); SvNV_set(&PL_sv_yes, 1); + + PadnamePV(&PL_padname_const) = (char *)PL_No; } /* @@ -15115,6 +15169,7 @@ Perl_sv_recode_to_utf8(pTHX_ SV *sv, SV *encoding) nsv = sv_newmortal(); SvSetSV_nosteal(nsv, sv); } + save_re_context(); PUSHMARK(sp); EXTEND(SP, 3); PUSHs(encoding); @@ -15180,11 +15235,12 @@ Perl_sv_cat_decode(pTHX_ SV *dsv, SV *encoding, PERL_ARGS_ASSERT_SV_CAT_DECODE; - if (SvPOK(ssv) && SvPOK(dsv) && SvROK(encoding) && offset) { + if (SvPOK(ssv) && SvPOK(dsv) && SvROK(encoding)) { SV *offsv; dSP; ENTER; SAVETMPS; + save_re_context(); PUSHMARK(sp); EXTEND(SP, 6); PUSHs(encoding); @@ -15314,16 +15370,15 @@ Perl_varname(pTHX_ const GV *const gv, const char gvtype, PADOFFSET targ, } else { CV * const cv = gv ? ((CV *)gv) : find_runcv(NULL); - SV *sv; - AV *av; + PADNAME *sv; assert(!cv || SvTYPE(cv) == SVt_PVCV || SvTYPE(cv) == SVt_PVFM); if (!cv || !CvPADLIST(cv)) return NULL; - av = *PadlistARRAY(CvPADLIST(cv)); - sv = *av_fetch(av, targ, FALSE); - sv_setsv_flags(name, sv, 0); + sv = padnamelist_fetch(PadlistNAMES(CvPADLIST(cv)), targ); + sv_setpvn(name, PadnamePV(sv), PadnameLEN(sv)); + SvUTF8_on(name); } if (subscript_type == FUV_SUBSCRIPT_HASH) { @@ -15358,6 +15413,8 @@ warning, then following the direct child of the op may yield an OP_PADSV or OP_GV that gives the name of the undefined variable. On the other hand, with OP_ADD there are two branches to follow, so we only print the variable name if we get an exact match. +desc_p points to a string pointer holding the description of the op. +This may be updated if needed. The name is returned as a mortal SV. @@ -15369,13 +15426,15 @@ PL_comppad/PL_curpad points to the currently executing pad. STATIC SV * S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv, - bool match) + bool match, const char **desc_p) { dVAR; SV *sv; const GV *gv; const OP *o, *o2, *kid; + PERL_ARGS_ASSERT_FIND_UNINIT_VAR; + if (!obase || (match && (!uninit_sv || uninit_sv == &PL_sv_undef || uninit_sv == &PL_sv_placeholder))) return NULL; @@ -15415,7 +15474,7 @@ S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv, } else if (obase == PL_op) /* @{expr}, %{expr} */ return find_uninit_var(cUNOPx(obase)->op_first, - uninit_sv, match); + uninit_sv, match, desc_p); else /* @{expr}, %{expr} as a sub-expression */ return NULL; } @@ -15450,7 +15509,7 @@ S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv, return varname(gv, '$', 0, NULL, 0, FUV_SUBSCRIPT_NONE); } /* ${expr} */ - return find_uninit_var(cUNOPx(obase)->op_first, uninit_sv, 1); + return find_uninit_var(cUNOPx(obase)->op_first, uninit_sv, 1, desc_p); case OP_PADSV: if (match && PAD_SVl(obase->op_targ) != uninit_sv) @@ -15500,7 +15559,7 @@ S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv, if (!o || o->op_type != OP_NULL || ! (o->op_targ == OP_AELEM || o->op_targ == OP_HELEM)) break; - return find_uninit_var(cBINOPo->op_last, uninit_sv, match); + return find_uninit_var(cBINOPo->op_last, uninit_sv, match, desc_p); case OP_AELEM: case OP_HELEM: @@ -15509,7 +15568,8 @@ S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv, if (PL_op == obase) /* $a[uninit_expr] or $h{uninit_expr} */ - return find_uninit_var(cBINOPx(obase)->op_last, uninit_sv, match); + return find_uninit_var(cBINOPx(obase)->op_last, + uninit_sv, match, desc_p); gv = NULL; o = cBINOPx(obase)->op_first; @@ -15598,18 +15658,214 @@ S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv, NOT_REACHED; /* NOTREACHED */ } + case OP_MULTIDEREF: { + /* If we were executing OP_MULTIDEREF when the undef warning + * triggered, then it must be one of the index values within + * that triggered it. If not, then the only possibility is that + * the value retrieved by the last aggregate lookup might be the + * culprit. For the former, we set PL_multideref_pc each time before + * using an index, so work though the item list until we reach + * that point. For the latter, just work through the entire item + * list; the last aggregate retrieved will be the candidate. + */ + + /* the named aggregate, if any */ + PADOFFSET agg_targ = 0; + GV *agg_gv = NULL; + /* the last-seen index */ + UV index_type; + PADOFFSET index_targ; + GV *index_gv; + IV index_const_iv = 0; /* init for spurious compiler warn */ + SV *index_const_sv; + int depth = 0; /* how many array/hash lookups we've done */ + + UNOP_AUX_item *items = cUNOP_AUXx(obase)->op_aux; + UNOP_AUX_item *last = NULL; + UV actions = items->uv; + bool is_hv; + + if (PL_op == obase) { + last = PL_multideref_pc; + assert(last >= items && last <= items + items[-1].uv); + } + + assert(actions); + + while (1) { + is_hv = FALSE; + switch (actions & MDEREF_ACTION_MASK) { + + case MDEREF_reload: + actions = (++items)->uv; + continue; + + case MDEREF_HV_padhv_helem: /* $lex{...} */ + is_hv = TRUE; + /* FALLTHROUGH */ + case MDEREF_AV_padav_aelem: /* $lex[...] */ + agg_targ = (++items)->pad_offset; + agg_gv = NULL; + break; + + case MDEREF_HV_gvhv_helem: /* $pkg{...} */ + is_hv = TRUE; + /* FALLTHROUGH */ + case MDEREF_AV_gvav_aelem: /* $pkg[...] */ + agg_targ = 0; + agg_gv = (GV*)UNOP_AUX_item_sv(++items); + assert(isGV_with_GP(agg_gv)); + break; + + case MDEREF_HV_gvsv_vivify_rv2hv_helem: /* $pkg->{...} */ + case MDEREF_HV_padsv_vivify_rv2hv_helem: /* $lex->{...} */ + ++items; + /* FALLTHROUGH */ + case MDEREF_HV_pop_rv2hv_helem: /* expr->{...} */ + case MDEREF_HV_vivify_rv2hv_helem: /* vivify, ->{...} */ + agg_targ = 0; + agg_gv = NULL; + is_hv = TRUE; + break; + + case MDEREF_AV_gvsv_vivify_rv2av_aelem: /* $pkg->[...] */ + case MDEREF_AV_padsv_vivify_rv2av_aelem: /* $lex->[...] */ + ++items; + /* FALLTHROUGH */ + case MDEREF_AV_pop_rv2av_aelem: /* expr->[...] */ + case MDEREF_AV_vivify_rv2av_aelem: /* vivify, ->[...] */ + agg_targ = 0; + agg_gv = NULL; + } /* switch */ + + index_targ = 0; + index_gv = NULL; + index_const_sv = NULL; + + index_type = (actions & MDEREF_INDEX_MASK); + switch (index_type) { + case MDEREF_INDEX_none: + break; + case MDEREF_INDEX_const: + if (is_hv) + index_const_sv = UNOP_AUX_item_sv(++items) + else + index_const_iv = (++items)->iv; + break; + case MDEREF_INDEX_padsv: + index_targ = (++items)->pad_offset; + break; + case MDEREF_INDEX_gvsv: + index_gv = (GV*)UNOP_AUX_item_sv(++items); + assert(isGV_with_GP(index_gv)); + break; + } + + if (index_type != MDEREF_INDEX_none) + depth++; + + if ( index_type == MDEREF_INDEX_none + || (actions & MDEREF_FLAG_last) + || (last && items == last) + ) + break; + + actions >>= MDEREF_SHIFT; + } /* while */ + + if (PL_op == obase) { + /* index was undef */ + + *desc_p = ( (actions & MDEREF_FLAG_last) + && (obase->op_private + & (OPpMULTIDEREF_EXISTS|OPpMULTIDEREF_DELETE))) + ? + (obase->op_private & OPpMULTIDEREF_EXISTS) + ? "exists" + : "delete" + : is_hv ? "hash element" : "array element"; + assert(index_type != MDEREF_INDEX_none); + if (index_gv) + return varname(index_gv, '$', 0, NULL, 0, FUV_SUBSCRIPT_NONE); + if (index_targ) + return varname(NULL, '$', index_targ, + NULL, 0, FUV_SUBSCRIPT_NONE); + assert(is_hv); /* AV index is an IV and can't be undef */ + /* can a const HV index ever be undef? */ + return NULL; + } + + /* the SV returned by pp_multideref() was undef, if anything was */ + + if (depth != 1) + break; + + if (agg_targ) + sv = PAD_SV(agg_targ); + else if (agg_gv) + sv = is_hv ? MUTABLE_SV(GvHV(agg_gv)) : MUTABLE_SV(GvAV(agg_gv)); + else + break; + + if (index_type == MDEREF_INDEX_const) { + if (match) { + if (SvMAGICAL(sv)) + break; + if (is_hv) { + HE* he = hv_fetch_ent(MUTABLE_HV(sv), index_const_sv, 0, 0); + if (!he || HeVAL(he) != uninit_sv) + break; + } + else { + SV * const * const svp = + av_fetch(MUTABLE_AV(sv), index_const_iv, FALSE); + if (!svp || *svp != uninit_sv) + break; + } + } + return is_hv + ? varname(agg_gv, '%', agg_targ, + index_const_sv, 0, FUV_SUBSCRIPT_HASH) + : varname(agg_gv, '@', agg_targ, + NULL, index_const_iv, FUV_SUBSCRIPT_ARRAY); + } + else { + /* index is an var */ + if (is_hv) { + SV * const keysv = find_hash_subscript((const HV*)sv, uninit_sv); + if (keysv) + return varname(agg_gv, '%', agg_targ, + keysv, 0, FUV_SUBSCRIPT_HASH); + } + else { + const I32 index + = find_array_subscript((const AV *)sv, uninit_sv); + if (index >= 0) + return varname(agg_gv, '@', agg_targ, + NULL, index, FUV_SUBSCRIPT_ARRAY); + } + if (match) + break; + return varname(agg_gv, + is_hv ? '%' : '@', + agg_targ, NULL, 0, FUV_SUBSCRIPT_WITHIN); + } + NOT_REACHED; /* NOTREACHED */ + } + case OP_AASSIGN: /* only examine RHS */ - return find_uninit_var(cBINOPx(obase)->op_first, uninit_sv, match); + return find_uninit_var(cBINOPx(obase)->op_first, uninit_sv, + match, desc_p); case OP_OPEN: o = cUNOPx(obase)->op_first; if ( o->op_type == OP_PUSHMARK || (o->op_type == OP_NULL && o->op_targ == OP_PUSHMARK) ) - o = OP_SIBLING(o); + o = OpSIBLING(o); - if (!OP_HAS_SIBLING(o)) { + if (!OpHAS_SIBLING(o)) { /* one-arg version of open is highly magical */ if (o->op_type == OP_GV) { /* open FOO; */ @@ -15652,7 +15908,7 @@ S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv, && ( o->op_type == OP_PUSHMARK || (o->op_type == OP_NULL && o->op_targ == OP_PUSHMARK))) - o = OP_SIBLING(OP_SIBLING(o)); + o = OpSIBLING(OpSIBLING(o)); goto do_op2; @@ -15783,7 +16039,7 @@ S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv, * it replaced are still in the tree, so we work on them instead. */ o2 = NULL; - for (kid=o; kid; kid = OP_SIBLING(kid)) { + for (kid=o; kid; kid = OpSIBLING(kid)) { const OPCODE type = kid->op_type; if ( (type == OP_CONST && SvOK(cSVOPx_sv(kid))) || (type == OP_NULL && ! (kid->op_flags & OPf_KIDS)) @@ -15799,14 +16055,14 @@ S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv, o2 = kid; } if (o2) - return find_uninit_var(o2, uninit_sv, match); + return find_uninit_var(o2, uninit_sv, match, desc_p); /* scan all args */ while (o) { - sv = find_uninit_var(o, uninit_sv, 1); + sv = find_uninit_var(o, uninit_sv, 1, desc_p); if (sv) return sv; - o = OP_SIBLING(o); + o = OpSIBLING(o); } break; } @@ -15825,40 +16081,40 @@ Print appropriate "Use of uninitialized variable" warning. void Perl_report_uninit(pTHX_ const SV *uninit_sv) { + const char *desc = NULL; + SV* varname = NULL; + if (PL_op) { - SV* varname = NULL; - const char *desc; + desc = PL_op->op_type == OP_STRINGIFY && PL_op->op_folded + ? "join or string" + : OP_DESC(PL_op); if (uninit_sv && PL_curpad) { - varname = find_uninit_var(PL_op, uninit_sv,0); + varname = find_uninit_var(PL_op, uninit_sv, 0, &desc); if (varname) sv_insert(varname, 0, 0, " ", 1); } - desc = PL_op->op_type == OP_STRINGIFY && PL_op->op_folded - ? "join or string" - : OP_DESC(PL_op); - /* PL_warn_uninit_sv is constant */ - GCC_DIAG_IGNORE(-Wformat-nonliteral); - /* diag_listed_as: Use of uninitialized value%s */ - Perl_warner(aTHX_ packWARN(WARN_UNINITIALIZED), PL_warn_uninit_sv, - SVfARG(varname ? varname : &PL_sv_no), - " in ", desc); - GCC_DIAG_RESTORE; - } - else { - /* PL_warn_uninit is constant */ - GCC_DIAG_IGNORE(-Wformat-nonliteral); - Perl_warner(aTHX_ packWARN(WARN_UNINITIALIZED), PL_warn_uninit, - "", "", ""); - GCC_DIAG_RESTORE; } + else if (PL_curstackinfo->si_type == PERLSI_SORT + && CxMULTICALL(&cxstack[cxstack_ix])) + { + /* we've reached the end of a sort block or sub, + * and the uninit value is probably what that code returned */ + desc = "sort"; + } + + /* PL_warn_uninit_sv is constant */ + GCC_DIAG_IGNORE(-Wformat-nonliteral); + if (desc) + /* diag_listed_as: Use of uninitialized value%s */ + Perl_warner(aTHX_ packWARN(WARN_UNINITIALIZED), PL_warn_uninit_sv, + SVfARG(varname ? varname : &PL_sv_no), + " in ", desc); + else + Perl_warner(aTHX_ packWARN(WARN_UNINITIALIZED), PL_warn_uninit, + "", "", ""); + GCC_DIAG_RESTORE; } /* - * Local variables: - * c-indentation-style: bsd - * c-basic-offset: 4 - * indent-tabs-mode: nil - * End: - * * ex: set ts=8 sts=4 sw=4 et: */