Upgrade to Time-HiRes-1.85
[p5sagit/p5-mst-13.2.git] / sv.c
diff --git a/sv.c b/sv.c
index 55bb674..f918d5a 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -357,7 +357,7 @@ and split it into a list of free SVs.
 void
 Perl_sv_add_arena(pTHX_ char *ptr, U32 size, U32 flags)
 {
-    SV* sva = (SV*)ptr;
+    SV* const sva = (SV*)ptr;
     register SV* sv;
     register SV* svend;
 
@@ -520,7 +520,7 @@ do_clean_all(pTHX_ SV *sv)
     DEBUG_D((PerlIO_printf(Perl_debug_log, "Cleaning loops: SV at 0x%"UVxf"\n", PTR2UV(sv)) ));
     SvFLAGS(sv) |= SVf_BREAK;
     if (PL_comppad == (AV*)sv) {
-       PL_comppad = Nullav;
+       PL_comppad = NULL;
        PL_curpad = Null(SV**);
     }
     SvREFCNT_dec(sv);
@@ -640,8 +640,8 @@ Perl_sv_free_arenas(pTHX)
 STATIC void *
 S_more_bodies (pTHX_ size_t size, svtype sv_type)
 {
-    void **arena_root  = &PL_body_arenaroots[sv_type];
-    void **root                = &PL_body_roots[sv_type];
+    void ** const arena_root   = &PL_body_arenaroots[sv_type];
+    void ** const root         = &PL_body_roots[sv_type];
     char *start;
     const char *end;
     const size_t count = PERL_ARENA_SIZE / size;
@@ -675,7 +675,7 @@ S_more_bodies (pTHX_ size_t size, svtype sv_type)
 
 #define new_body_inline(xpv, size, sv_type) \
     STMT_START { \
-       void **r3wt = &PL_body_roots[sv_type]; \
+       void ** const r3wt = &PL_body_roots[sv_type]; \
        LOCK_SV_MUTEX; \
        xpv = *((void **)(r3wt)) \
          ? *((void **)(r3wt)) : S_more_bodies(aTHX_ size, sv_type); \
@@ -704,7 +704,7 @@ S_new_body(pTHX_ size_t size, svtype sv_type)
 
 #define del_body(thing, root)                  \
     STMT_START {                               \
-       void **thing_copy = (void **)thing;     \
+       void ** const thing_copy = (void **)thing;\
        LOCK_SV_MUTEX;                          \
        *thing_copy = *root;                    \
        *root = (void*)thing_copy;              \
@@ -1413,9 +1413,9 @@ S_not_a_number(pTHX_ SV *sv)
          /* each *s can expand to 4 chars + "...\0",
             i.e. need room for 8 chars */
        
-         const char *s, *end;
-         for (s = SvPVX_const(sv), end = s + SvCUR(sv); s < end && d < limit;
-              s++) {
+         const char *s = SvPVX_const(sv);
+         const char * const end = s + SvCUR(sv);
+         for ( ; s < end && d < limit; s++ ) {
               int ch = *s & 0xFF;
               if (ch & 128 && !isPRINT_LC(ch)) {
                    *d++ = 'M';
@@ -1625,71 +1625,14 @@ S_sv_2iuv_non_preserve(pTHX_ register SV *sv, I32 numtype)
 }
 #endif /* !NV_PRESERVES_UV*/
 
-/*
-=for apidoc sv_2iv_flags
-
-Return the integer value of an SV, doing any necessary string
-conversion.  If flags includes SV_GMAGIC, does an mg_get() first.
-Normally used via the C<SvIV(sv)> and C<SvIVx(sv)> macros.
-
-=cut
-*/
-
-IV
-Perl_sv_2iv_flags(pTHX_ register SV *sv, I32 flags)
-{
-    if (!sv)
-       return 0;
-    if (SvGMAGICAL(sv)) {
-       if (flags & SV_GMAGIC)
-           mg_get(sv);
-       if (SvIOKp(sv))
-           return SvIVX(sv);
-       if (SvNOKp(sv)) {
-           return I_V(SvNVX(sv));
-       }
-       if (SvPOKp(sv) && SvLEN(sv))
-           return asIV(sv);
-       if (!SvROK(sv)) {
-           if (!(SvFLAGS(sv) & SVs_PADTMP)) {
-               if (!PL_localizing && ckWARN(WARN_UNINITIALIZED))
-                   report_uninit(sv);
-           }
-           return 0;
-       }
-    }
-    if (SvTHINKFIRST(sv)) {
-       if (SvROK(sv)) {
-           if (SvAMAGIC(sv)) {
-               SV * const tmpstr=AMG_CALLun(sv,numer);
-               if (tmpstr && (!SvROK(tmpstr) || (SvRV(tmpstr) != SvRV(sv)))) {
-                   return SvIV(tmpstr);
-               }
-           }
-           return PTR2IV(SvRV(sv));
-       }
-       if (SvIsCOW(sv)) {
-           sv_force_normal_flags(sv, 0);
-       }
-       if (SvREADONLY(sv) && !SvOK(sv)) {
-           if (ckWARN(WARN_UNINITIALIZED))
-               report_uninit(sv);
-           return 0;
-       }
-    }
-    if (SvIOKp(sv)) {
-       if (SvIsUV(sv)) {
-           return (IV)(SvUVX(sv));
-       }
-       else {
-           return SvIVX(sv);
-       }
-    }
+STATIC bool
+S_sv_2iuv_common(pTHX_ SV *sv) {
     if (SvNOKp(sv)) {
        /* erm. not sure. *should* never get NOKp (without NOK) from sv_2nv
         * without also getting a cached IV/UV from it at the same time
         * (ie PV->NV conversion should detect loss of accuracy and cache
-        * IV or UV at same time to avoid this.  NWC */
+        * IV or UV at same time to avoid this. */
+       /* IV-over-UV optimisation - choose to cache IV if possible */
 
        if (SvTYPE(sv) == SVt_NV)
            sv_upgrade(sv, SVt_PVNV);
@@ -1762,14 +1705,14 @@ Perl_sv_2iv_flags(pTHX_ register SV *sv, I32 flags)
     else if (SvPOKp(sv) && SvLEN(sv)) {
        UV value;
        const int numtype = grok_number(SvPVX_const(sv), SvCUR(sv), &value);
-       /* We want to avoid a possible problem when we cache an IV which
+       /* We want to avoid a possible problem when we cache an IV/ a UV which
           may be later translated to an NV, and the resulting NV is not
           the same as the direct translation of the initial string
           (eg 123.456 can shortcut to the IV 123 with atol(), but we must
           be careful to ensure that the value with the .456 is around if the
           NV value is requested in the future).
        
-          This means that if we cache such an IV, we need to cache the
+          This means that if we cache such an IV/a UV, we need to cache the
           NV as well.  Moreover, we trade speed for space, and do not
           cache the NV if we are sure it's not needed.
         */
@@ -1801,6 +1744,7 @@ Perl_sv_2iv_flags(pTHX_ register SV *sv, I32 flags)
                if (value <= (UV)IV_MAX) {
                    SvIV_set(sv, (IV)value);
                } else {
+                   /* it didn't overflow, and it was positive. */
                    SvUV_set(sv, value);
                    SvIsUV_on(sv);
                }
@@ -1841,40 +1785,38 @@ Perl_sv_2iv_flags(pTHX_ register SV *sv, I32 flags)
                                  PTR2UV(sv), SvNVX(sv)));
 #endif
 
-
 #ifdef NV_PRESERVES_UV
-           (void)SvIOKp_on(sv);
-           (void)SvNOK_on(sv);
-           if (SvNVX(sv) < (NV)IV_MAX + 0.5) {
-               SvIV_set(sv, I_V(SvNVX(sv)));
-               if ((NV)(SvIVX(sv)) == SvNVX(sv)) {
-                   SvIOK_on(sv);
-               } else {
-                   /* Integer is imprecise. NOK, IOKp */
-               }
-               /* UV will not work better than IV */
-           } else {
-               if (SvNVX(sv) > (NV)UV_MAX) {
-                   SvIsUV_on(sv);
-                   /* Integer is inaccurate. NOK, IOKp, is UV */
-                   SvUV_set(sv, UV_MAX);
-                   SvIsUV_on(sv);
-               } else {
-                   SvUV_set(sv, U_V(SvNVX(sv)));
-                   /* 0xFFFFFFFFFFFFFFFF not an issue in here */
-                   if ((NV)(SvUVX(sv)) == SvNVX(sv)) {
-                       SvIOK_on(sv);
-                       SvIsUV_on(sv);
-                   } else {
-                       /* Integer is imprecise. NOK, IOKp, is UV */
-                       SvIsUV_on(sv);
-                   }
-               }
-           }
+            (void)SvIOKp_on(sv);
+            (void)SvNOK_on(sv);
+            if (SvNVX(sv) < (NV)IV_MAX + 0.5) {
+                SvIV_set(sv, I_V(SvNVX(sv)));
+                if ((NV)(SvIVX(sv)) == SvNVX(sv)) {
+                    SvIOK_on(sv);
+                } else {
+                    /* Integer is imprecise. NOK, IOKp */
+                }
+                /* UV will not work better than IV */
+            } else {
+                if (SvNVX(sv) > (NV)UV_MAX) {
+                    SvIsUV_on(sv);
+                    /* Integer is inaccurate. NOK, IOKp, is UV */
+                    SvUV_set(sv, UV_MAX);
+                } else {
+                    SvUV_set(sv, U_V(SvNVX(sv)));
+                    /* 0xFFFFFFFFFFFFFFFF not an issue in here, NVs
+                       NV preservse UV so can do correct comparison.  */
+                    if ((NV)(SvUVX(sv)) == SvNVX(sv)) {
+                        SvIOK_on(sv);
+                    } else {
+                        /* Integer is imprecise. NOK, IOKp, is UV */
+                    }
+                }
+               SvIsUV_on(sv);
+            }
 #else /* NV_PRESERVES_UV */
             if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
                 == (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT)) {
-                /* The IV slot will have been set from value returned by
+                /* The IV/UV slot will have been set from value returned by
                    grok_number above.  The NV slot has just been set using
                    Atof.  */
                SvNOK_on(sv);
@@ -1908,31 +1850,33 @@ Perl_sv_2iv_flags(pTHX_ register SV *sv, I32 flags)
             }
 #endif /* NV_PRESERVES_UV */
        }
-    } else  {
-       if (!PL_localizing && !(SvFLAGS(sv) & SVs_PADTMP) && ckWARN(WARN_UNINITIALIZED))
-           report_uninit(sv);
+    }
+    else  {
+       if (!(SvFLAGS(sv) & SVs_PADTMP)) {
+           if (!PL_localizing && ckWARN(WARN_UNINITIALIZED))
+               report_uninit(sv);
+       }
        if (SvTYPE(sv) < SVt_IV)
            /* Typically the caller expects that sv_any is not NULL now.  */
            sv_upgrade(sv, SVt_IV);
-       return 0;
+       /* Return 0 from the caller.  */
+       return TRUE;
     }
-    DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%"UVxf" 2iv(%"IVdf")\n",
-       PTR2UV(sv),SvIVX(sv)));
-    return SvIsUV(sv) ? (IV)SvUVX(sv) : SvIVX(sv);
+    return FALSE;
 }
 
 /*
-=for apidoc sv_2uv_flags
+=for apidoc sv_2iv_flags
 
-Return the unsigned integer value of an SV, doing any necessary string
+Return the integer value of an SV, doing any necessary string
 conversion.  If flags includes SV_GMAGIC, does an mg_get() first.
-Normally used via the C<SvUV(sv)> and C<SvUVx(sv)> macros.
+Normally used via the C<SvIV(sv)> and C<SvIVx(sv)> macros.
 
 =cut
 */
 
-UV
-Perl_sv_2uv_flags(pTHX_ register SV *sv, I32 flags)
+IV
+Perl_sv_2iv_flags(pTHX_ register SV *sv, I32 flags)
 {
     if (!sv)
        return 0;
@@ -1940,26 +1884,48 @@ Perl_sv_2uv_flags(pTHX_ register SV *sv, I32 flags)
        if (flags & SV_GMAGIC)
            mg_get(sv);
        if (SvIOKp(sv))
-           return SvUVX(sv);
-       if (SvNOKp(sv))
-           return U_V(SvNVX(sv));
-       if (SvPOKp(sv) && SvLEN(sv))
-           return asUV(sv);
-       if (!SvROK(sv)) {
-           if (!(SvFLAGS(sv) & SVs_PADTMP)) {
-               if (!PL_localizing && ckWARN(WARN_UNINITIALIZED))
-                   report_uninit(sv);
+           return SvIVX(sv);
+       if (SvNOKp(sv)) {
+           return I_V(SvNVX(sv));
+       }
+       if (SvPOKp(sv) && SvLEN(sv)) {
+           UV value;
+           const int numtype
+               = grok_number(SvPVX_const(sv), SvCUR(sv), &value);
+
+           if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
+               == IS_NUMBER_IN_UV) {
+               /* It's definitely an integer */
+               if (numtype & IS_NUMBER_NEG) {
+                   if (value < (UV)IV_MIN)
+                       return -(IV)value;
+               } else {
+                   if (value < (UV)IV_MAX)
+                       return (IV)value;
+               }
            }
-           return 0;
+           if (!numtype) {
+               if (ckWARN(WARN_NUMERIC))
+                   not_a_number(sv);
+           }
+           return I_V(Atof(SvPVX_const(sv)));
+       }
+        if (SvROK(sv)) {
+           goto return_rok;
        }
+       assert(SvTYPE(sv) >= SVt_PVMG);
+       /* This falls through to the report_uninit inside S_sv_2iuv_common.  */
     }
     if (SvTHINKFIRST(sv)) {
        if (SvROK(sv)) {
-         SV* tmpstr;
-          if (SvAMAGIC(sv) && (tmpstr=AMG_CALLun(sv,numer)) &&
-                (!SvROK(tmpstr) || (SvRV(tmpstr) != SvRV(sv))))
-             return SvUV(tmpstr);
-         return PTR2UV(SvRV(sv));
+       return_rok:
+           if (SvAMAGIC(sv)) {
+               SV * const tmpstr=AMG_CALLun(sv,numer);
+               if (tmpstr && (!SvROK(tmpstr) || (SvRV(tmpstr) != SvRV(sv)))) {
+                   return SvIV(tmpstr);
+               }
+           }
+           return PTR2IV(SvRV(sv));
        }
        if (SvIsCOW(sv)) {
            sv_force_normal_flags(sv, 0);
@@ -1970,231 +1936,83 @@ Perl_sv_2uv_flags(pTHX_ register SV *sv, I32 flags)
            return 0;
        }
     }
-    if (SvIOKp(sv)) {
-       if (SvIsUV(sv)) {
-           return SvUVX(sv);
-       }
-       else {
-           return (UV)SvIVX(sv);
-       }
-    }
-    if (SvNOKp(sv)) {
-       /* erm. not sure. *should* never get NOKp (without NOK) from sv_2nv
-        * without also getting a cached IV/UV from it at the same time
-        * (ie PV->NV conversion should detect loss of accuracy and cache
-        * IV or UV at same time to avoid this. */
-       /* IV-over-UV optimisation - choose to cache IV if possible */
-
-       if (SvTYPE(sv) == SVt_NV)
-           sv_upgrade(sv, SVt_PVNV);
-
-       (void)SvIOKp_on(sv);    /* Must do this first, to clear any SvOOK */
-       if (SvNVX(sv) < (NV)IV_MAX + 0.5) {
-           SvIV_set(sv, I_V(SvNVX(sv)));
-           if (SvNVX(sv) == (NV) SvIVX(sv)
-#ifndef NV_PRESERVES_UV
-               && (((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
-                  came from a (by definition imprecise) NV operation, and
-                  we're outside the range of NV integer precision */
-#endif
-               ) {
-               SvIOK_on(sv);  /* Can this go wrong with rounding? NWC */
-               DEBUG_c(PerlIO_printf(Perl_debug_log,
-                                     "0x%"UVxf" uv(%"NVgf" => %"IVdf") (precise)\n",
-                                     PTR2UV(sv),
-                                     SvNVX(sv),
-                                     SvIVX(sv)));
-
-           } else {
-               /* IV not precise.  No need to convert from PV, as NV
-                  conversion would already have cached IV if it detected
-                  that PV->IV would be better than PV->NV->IV
-                  flags already correct - don't set public IOK.  */
-               DEBUG_c(PerlIO_printf(Perl_debug_log,
-                                     "0x%"UVxf" uv(%"NVgf" => %"IVdf") (imprecise)\n",
-                                     PTR2UV(sv),
-                                     SvNVX(sv),
-                                     SvIVX(sv)));
-           }
-           /* Can the above go wrong if SvIVX == IV_MIN and SvNVX < IV_MIN,
-              but the cast (NV)IV_MIN rounds to a the value less (more
-              negative) than IV_MIN which happens to be equal to SvNVX ??
-              Analogous to 0xFFFFFFFFFFFFFFFF rounding up to NV (2**64) and
-              NV rounding back to 0xFFFFFFFFFFFFFFFF, so UVX == UV(NVX) and
-              (NV)UVX == NVX are both true, but the values differ. :-(
-              Hopefully for 2s complement IV_MIN is something like
-              0x8000000000000000 which will be exact. NWC */
-       }
-       else {
-           SvUV_set(sv, U_V(SvNVX(sv)));
-           if (
-               (SvNVX(sv) == (NV) SvUVX(sv))
-#ifndef  NV_PRESERVES_UV
-               /* Make sure it's not 0xFFFFFFFFFFFFFFFF */
-               /*&& (SvUVX(sv) != UV_MAX) irrelevant with code below */
-               && (((UV)1 << NV_PRESERVES_UV_BITS) > SvUVX(sv))
-               /* Don't flag it as "accurately an integer" if the number
-                  came from a (by definition imprecise) NV operation, and
-                  we're outside the range of NV integer precision */
-#endif
-               )
-               SvIOK_on(sv);
-           SvIsUV_on(sv);
-           DEBUG_c(PerlIO_printf(Perl_debug_log,
-                                 "0x%"UVxf" 2uv(%"UVuf" => %"IVdf") (as unsigned)\n",
-                                 PTR2UV(sv),
-                                 SvUVX(sv),
-                                 SvUVX(sv)));
-       }
+    if (!SvIOKp(sv)) {
+       if (S_sv_2iuv_common(aTHX_ sv))
+           return 0;
     }
-    else if (SvPOKp(sv) && SvLEN(sv)) {
-       UV value;
-       const int numtype = grok_number(SvPVX_const(sv), SvCUR(sv), &value);
+    DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%"UVxf" 2iv(%"IVdf")\n",
+       PTR2UV(sv),SvIVX(sv)));
+    return SvIsUV(sv) ? (IV)SvUVX(sv) : SvIVX(sv);
+}
 
-       /* We want to avoid a possible problem when we cache a UV which
-          may be later translated to an NV, and the resulting NV is not
-          the translation of the initial data.
-       
-          This means that if we cache such a UV, we need to cache the
-          NV as well.  Moreover, we trade speed for space, and do not
-          cache the NV if not needed.
-        */
+/*
+=for apidoc sv_2uv_flags
 
-       /* SVt_PVNV is one higher than SVt_PVIV, hence this order  */
-       if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
-            == IS_NUMBER_IN_UV) {
-           /* It's definitely an integer, only upgrade to PVIV */
-           if (SvTYPE(sv) < SVt_PVIV)
-               sv_upgrade(sv, SVt_PVIV);
-           (void)SvIOK_on(sv);
-       } else if (SvTYPE(sv) < SVt_PVNV)
-           sv_upgrade(sv, SVt_PVNV);
+Return the unsigned integer value of an SV, doing any necessary string
+conversion.  If flags includes SV_GMAGIC, does an mg_get() first.
+Normally used via the C<SvUV(sv)> and C<SvUVx(sv)> macros.
 
-       /* If NV preserves UV then we only use the UV value if we know that
-          we aren't going to call atof() below. If NVs don't preserve UVs
-          then the value returned may have more precision than atof() will
-          return, even though it isn't accurate.  */
-       if ((numtype & (IS_NUMBER_IN_UV
-#ifdef NV_PRESERVES_UV
-                       | IS_NUMBER_NOT_INT
-#endif
-           )) == IS_NUMBER_IN_UV) {
-           /* This won't turn off the public IOK flag if it was set above  */
-           (void)SvIOKp_on(sv);
+=cut
+*/
 
-           if (!(numtype & IS_NUMBER_NEG)) {
-               /* positive */;
-               if (value <= (UV)IV_MAX) {
-                   SvIV_set(sv, (IV)value);
-               } else {
-                   /* it didn't overflow, and it was positive. */
-                   SvUV_set(sv, value);
-                   SvIsUV_on(sv);
-               }
-           } else {
-               /* 2s complement assumption  */
-               if (value <= (UV)IV_MIN) {
-                   SvIV_set(sv, -(IV)value);
-               } else {
-                   /* Too negative for an IV.  This is a double upgrade, but
-                      I'm assuming it will be rare.  */
-                   if (SvTYPE(sv) < SVt_PVNV)
-                       sv_upgrade(sv, SVt_PVNV);
-                   SvNOK_on(sv);
-                   SvIOK_off(sv);
-                   SvIOKp_on(sv);
-                   SvNV_set(sv, -(NV)value);
-                   SvIV_set(sv, IV_MIN);
-               }
+UV
+Perl_sv_2uv_flags(pTHX_ register SV *sv, I32 flags)
+{
+    if (!sv)
+       return 0;
+    if (SvGMAGICAL(sv)) {
+       if (flags & SV_GMAGIC)
+           mg_get(sv);
+       if (SvIOKp(sv))
+           return SvUVX(sv);
+       if (SvNOKp(sv))
+           return U_V(SvNVX(sv));
+       if (SvPOKp(sv) && SvLEN(sv)) {
+           UV value;
+           const int numtype
+               = grok_number(SvPVX_const(sv), SvCUR(sv), &value);
+
+           if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
+               == IS_NUMBER_IN_UV) {
+               /* It's definitely an integer */
+               if (!(numtype & IS_NUMBER_NEG))
+                   return value;
            }
-       }
-       
-       if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
-           != IS_NUMBER_IN_UV) {
-           /* It wasn't an integer, or it overflowed the UV. */
-           SvNV_set(sv, Atof(SvPVX_const(sv)));
-
-            if (! numtype && ckWARN(WARN_NUMERIC))
+           if (!numtype) {
+               if (ckWARN(WARN_NUMERIC))
                    not_a_number(sv);
-
-#if defined(USE_LONG_DOUBLE)
-            DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%"UVxf" 2uv(%" PERL_PRIgldbl ")\n",
-                                  PTR2UV(sv), SvNVX(sv)));
-#else
-            DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%"UVxf" 2uv(%"NVgf")\n",
-                                  PTR2UV(sv), SvNVX(sv)));
-#endif
-
-#ifdef NV_PRESERVES_UV
-            (void)SvIOKp_on(sv);
-            (void)SvNOK_on(sv);
-            if (SvNVX(sv) < (NV)IV_MAX + 0.5) {
-                SvIV_set(sv, I_V(SvNVX(sv)));
-                if ((NV)(SvIVX(sv)) == SvNVX(sv)) {
-                    SvIOK_on(sv);
-                } else {
-                    /* Integer is imprecise. NOK, IOKp */
-                }
-                /* UV will not work better than IV */
-            } else {
-                if (SvNVX(sv) > (NV)UV_MAX) {
-                    SvIsUV_on(sv);
-                    /* Integer is inaccurate. NOK, IOKp, is UV */
-                    SvUV_set(sv, UV_MAX);
-                    SvIsUV_on(sv);
-                } else {
-                    SvUV_set(sv, U_V(SvNVX(sv)));
-                    /* 0xFFFFFFFFFFFFFFFF not an issue in here, NVs
-                       NV preservse UV so can do correct comparison.  */
-                    if ((NV)(SvUVX(sv)) == SvNVX(sv)) {
-                        SvIOK_on(sv);
-                        SvIsUV_on(sv);
-                    } else {
-                        /* Integer is imprecise. NOK, IOKp, is UV */
-                        SvIsUV_on(sv);
-                    }
-                }
-            }
-#else /* NV_PRESERVES_UV */
-            if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
-                == (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT)) {
-                /* The UV slot will have been set from value returned by
-                   grok_number above.  The NV slot has just been set using
-                   Atof.  */
-               SvNOK_on(sv);
-                assert (SvIOKp(sv));
-            } else {
-                if (((UV)1 << NV_PRESERVES_UV_BITS) >
-                    U_V(SvNVX(sv) > 0 ? SvNVX(sv) : -SvNVX(sv))) {
-                    /* Small enough to preserve all bits. */
-                    (void)SvIOKp_on(sv);
-                    SvNOK_on(sv);
-                    SvIV_set(sv, I_V(SvNVX(sv)));
-                    if ((NV)(SvIVX(sv)) == SvNVX(sv))
-                        SvIOK_on(sv);
-                    /* Assumption: first non-preserved integer is < IV_MAX,
-                       this NV is in the preserved range, therefore: */
-                    if (!(U_V(SvNVX(sv) > 0 ? SvNVX(sv) : -SvNVX(sv))
-                          < (UV)IV_MAX)) {
-                        Perl_croak(aTHX_ "sv_2uv assumed (U_V(fabs((double)SvNVX(sv))) < (UV)IV_MAX) but SvNVX(sv)=%"NVgf" U_V is 0x%"UVxf", IV_MAX is 0x%"UVxf"\n", SvNVX(sv), U_V(SvNVX(sv)), (UV)IV_MAX);
-                    }
-                } else
-                    sv_2iuv_non_preserve (sv, numtype);
-            }
-#endif /* NV_PRESERVES_UV */
+           }
+           return U_V(Atof(SvPVX_const(sv)));
        }
+        if (SvROK(sv)) {
+           goto return_rok;
+       }
+       assert(SvTYPE(sv) >= SVt_PVMG);
+       /* This falls through to the report_uninit inside S_sv_2iuv_common.  */
     }
-    else  {
-       if (!(SvFLAGS(sv) & SVs_PADTMP)) {
-           if (!PL_localizing && ckWARN(WARN_UNINITIALIZED))
+    if (SvTHINKFIRST(sv)) {
+       if (SvROK(sv)) {
+       return_rok:
+           if (SvAMAGIC(sv)) {
+               SV *const tmpstr = AMG_CALLun(sv,numer);
+               if (tmpstr && (!SvROK(tmpstr) || (SvRV(tmpstr) != SvRV(sv)))) {
+                   return SvUV(tmpstr);
+               }
+           }
+           return PTR2UV(SvRV(sv));
+       }
+       if (SvIsCOW(sv)) {
+           sv_force_normal_flags(sv, 0);
+       }
+       if (SvREADONLY(sv) && !SvOK(sv)) {
+           if (ckWARN(WARN_UNINITIALIZED))
                report_uninit(sv);
+           return 0;
        }
-       if (SvTYPE(sv) < SVt_IV)
-           /* Typically the caller expects that sv_any is not NULL now.  */
-           sv_upgrade(sv, SVt_IV);
-       return 0;
+    }
+    if (!SvIOKp(sv)) {
+       if (S_sv_2iuv_common(aTHX_ sv))
+           return 0;
     }
 
     DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%"UVxf" 2uv(%"UVuf")\n",
@@ -2232,22 +2050,23 @@ Perl_sv_2nv(pTHX_ register SV *sv)
                return (NV)SvUVX(sv);
            else
                return (NV)SvIVX(sv);
-       }       
-        if (!SvROK(sv)) {
-           if (!(SvFLAGS(sv) & SVs_PADTMP)) {
-               if (!PL_localizing && ckWARN(WARN_UNINITIALIZED))
-                   report_uninit(sv);
-           }
-            return (NV)0;
-        }
-    }
-    if (SvTHINKFIRST(sv)) {
+       }
+        if (SvROK(sv)) {
+           goto return_rok;
+       }
+       assert(SvTYPE(sv) >= SVt_PVMG);
+       /* This falls through to the report_uninit near the end of the
+          function. */
+    } else if (SvTHINKFIRST(sv)) {
        if (SvROK(sv)) {
-         SV* tmpstr;
-          if (SvAMAGIC(sv) && (tmpstr=AMG_CALLun(sv,numer)) &&
-                (!SvROK(tmpstr) || (SvRV(tmpstr) != SvRV(sv))))
-             return SvNV(tmpstr);
-         return PTR2NV(SvRV(sv));
+       return_rok:
+           if (SvAMAGIC(sv)) {
+               SV *const tmpstr = AMG_CALLun(sv,numer);
+                if (tmpstr && (!SvROK(tmpstr) || (SvRV(tmpstr) != SvRV(sv)))) {
+                   return SvNV(tmpstr);
+               }
+           }
+           return PTR2NV(SvRV(sv));
        }
        if (SvIsCOW(sv)) {
            sv_force_normal_flags(sv, 0);
@@ -2259,10 +2078,8 @@ Perl_sv_2nv(pTHX_ register SV *sv)
        }
     }
     if (SvTYPE(sv) < SVt_NV) {
-       if (SvTYPE(sv) == SVt_IV)
-           sv_upgrade(sv, SVt_PVNV);
-       else
-           sv_upgrade(sv, SVt_NV);
+       /* The logic to use SVt_PVNV if necessary is in sv_upgrade.  */
+       sv_upgrade(sv, SVt_NV);
 #ifdef USE_LONG_DOUBLE
        DEBUG_c({
            STORE_NUMERIC_LOCAL_SET_STANDARD();
@@ -2356,11 +2173,10 @@ Perl_sv_2nv(pTHX_ register SV *sv)
                     if (SvNVX(sv) < (NV)IV_MAX + 0.5) {
                         if (SvIVX(sv) == I_V(nv)) {
                             SvNOK_on(sv);
-                            SvIOK_on(sv);
                         } else {
-                            SvIOK_on(sv);
                             /* It had no "." so it must be integer.  */
                         }
+                       SvIOK_on(sv);
                     } else {
                         /* between IV_MAX and NV(UV_MAX).
                            Could be slightly > UV_MAX */
@@ -2372,10 +2188,8 @@ Perl_sv_2nv(pTHX_ register SV *sv)
 
                             if (value == nv_as_uv && SvUVX(sv) != UV_MAX) {
                                 SvNOK_on(sv);
-                                SvIOK_on(sv);
-                            } else {
-                                SvIOK_on(sv);
                             }
+                           SvIOK_on(sv);
                         }
                     }
                 }
@@ -2386,11 +2200,10 @@ Perl_sv_2nv(pTHX_ register SV *sv)
     else  {
        if (!PL_localizing && !(SvFLAGS(sv) & SVs_PADTMP) && ckWARN(WARN_UNINITIALIZED))
            report_uninit(sv);
-       if (SvTYPE(sv) < SVt_NV)
-           /* Typically the caller expects that sv_any is not NULL now.  */
-           /* XXX Ilya implies that this is a bug in callers that assume this
-              and ideally should be fixed.  */
-           sv_upgrade(sv, SVt_NV);
+       assert (SvTYPE(sv) >= SVt_NV);
+       /* Typically the caller expects that sv_any is not NULL now.  */
+       /* XXX Ilya implies that this is a bug in callers that assume this
+          and ideally should be fixed.  */
        return 0.0;
     }
 #if defined(USE_LONG_DOUBLE)
@@ -2411,55 +2224,6 @@ Perl_sv_2nv(pTHX_ register SV *sv)
     return SvNVX(sv);
 }
 
-/* asIV(): extract an integer from the string value of an SV.
- * Caller must validate PVX  */
-
-STATIC IV
-S_asIV(pTHX_ SV *sv)
-{
-    UV value;
-    const int numtype = grok_number(SvPVX_const(sv), SvCUR(sv), &value);
-
-    if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
-       == IS_NUMBER_IN_UV) {
-       /* It's definitely an integer */
-       if (numtype & IS_NUMBER_NEG) {
-           if (value < (UV)IV_MIN)
-               return -(IV)value;
-       } else {
-           if (value < (UV)IV_MAX)
-               return (IV)value;
-       }
-    }
-    if (!numtype) {
-       if (ckWARN(WARN_NUMERIC))
-           not_a_number(sv);
-    }
-    return I_V(Atof(SvPVX_const(sv)));
-}
-
-/* asUV(): extract an unsigned integer from the string value of an SV
- * Caller must validate PVX  */
-
-STATIC UV
-S_asUV(pTHX_ SV *sv)
-{
-    UV value;
-    const int numtype = grok_number(SvPVX_const(sv), SvCUR(sv), &value);
-
-    if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
-       == IS_NUMBER_IN_UV) {
-       /* It's definitely an integer */
-       if (!(numtype & IS_NUMBER_NEG))
-           return value;
-    }
-    if (!numtype) {
-       if (ckWARN(WARN_NUMERIC))
-           not_a_number(sv);
-    }
-    return U_V(Atof(SvPVX_const(sv)));
-}
-
 /* uiv_2buf(): private routine for use by sv_2pv_flags(): print an IV or
  * UV as a string towards the end of buf, and return pointers to start and
  * end of it.
@@ -2492,6 +2256,86 @@ S_uiv_2buf(char *buf, IV iv, UV uv, int is_uv, char **peob)
     return ptr;
 }
 
+/* stringify_regexp(): private routine for use by sv_2pv_flags(): converts
+ * a regexp to its stringified form.
+ */
+
+static char *
+S_stringify_regexp(pTHX_ SV *sv, MAGIC *mg, STRLEN *lp) {
+    const regexp * const re = (regexp *)mg->mg_obj;
+
+    if (!mg->mg_ptr) {
+       const char *fptr = "msix";
+       char reflags[6];
+       char ch;
+       int left = 0;
+       int right = 4;
+       bool need_newline = 0;
+       U16 reganch = (U16)((re->reganch & PMf_COMPILETIME) >> 12);
+
+       while((ch = *fptr++)) {
+           if(reganch & 1) {
+               reflags[left++] = ch;
+           }
+           else {
+               reflags[right--] = ch;
+           }
+           reganch >>= 1;
+       }
+       if(left != 4) {
+           reflags[left] = '-';
+           left = 5;
+       }
+
+       mg->mg_len = re->prelen + 4 + left;
+       /*
+        * If /x was used, we have to worry about a regex ending with a
+        * comment later being embedded within another regex. If so, we don't
+        * want this regex's "commentization" to leak out to the right part of
+        * the enclosing regex, we must cap it with a newline.
+        *
+        * So, if /x was used, we scan backwards from the end of the regex. If
+        * we find a '#' before we find a newline, we need to add a newline
+        * ourself. If we find a '\n' first (or if we don't find '#' or '\n'),
+        * we don't need to add anything.  -jfriedl
+        */
+       if (PMf_EXTENDED & re->reganch) {
+           const char *endptr = re->precomp + re->prelen;
+           while (endptr >= re->precomp) {
+               const char c = *(endptr--);
+               if (c == '\n')
+                   break; /* don't need another */
+               if (c == '#') {
+                   /* we end while in a comment, so we need a newline */
+                   mg->mg_len++; /* save space for it */
+                   need_newline = 1; /* note to add it */
+                   break;
+               }
+           }
+       }
+
+       Newx(mg->mg_ptr, mg->mg_len + 1 + left, char);
+       mg->mg_ptr[0] = '(';
+       mg->mg_ptr[1] = '?';
+       Copy(reflags, mg->mg_ptr+2, left, char);
+       *(mg->mg_ptr+left+2) = ':';
+       Copy(re->precomp, mg->mg_ptr+3+left, re->prelen, char);
+       if (need_newline)
+           mg->mg_ptr[mg->mg_len - 2] = '\n';
+       mg->mg_ptr[mg->mg_len - 1] = ')';
+       mg->mg_ptr[mg->mg_len] = 0;
+    }
+    PL_reginterp_cnt += re->program[0].next_off;
+    
+    if (re->reganch & ROPT_UTF8)
+       SvUTF8_on(sv);
+    else
+       SvUTF8_off(sv);
+    if (lp)
+       *lp = mg->mg_len;
+    return mg->mg_ptr;
+}
+
 /*
 =for apidoc sv_2pv_flags
 
@@ -2509,10 +2353,6 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
 {
     register char *s;
     int olderrno;
-    SV *tsv;
-    char tbuf[64];     /* Must fit sprintf/Gconvert of longest IV/NV */
-    char *tmpbuf = tbuf;
-    STRLEN len = 0;    /* Hush gcc. len is always initialised before use.  */
 
     if (!sv) {
        if (lp)
@@ -2531,55 +2371,83 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
                return (char *)SvPVX_const(sv);
            return SvPVX(sv);
        }
-       if (SvIOKp(sv)) {
-           len = SvIsUV(sv) ? my_sprintf(tmpbuf,"%"UVuf, (UV)SvUVX(sv))
-               : my_sprintf(tmpbuf,"%"IVdf, (IV)SvIVX(sv));
-           tsv = Nullsv;
-           goto tokensave_has_len;
-       }
-       if (SvNOKp(sv)) {
-           Gconvert(SvNVX(sv), NV_DIG, 0, tmpbuf);
-           tsv = Nullsv;
-           goto tokensave;
-       }
-        if (!SvROK(sv)) {
-           if (!(SvFLAGS(sv) & SVs_PADTMP)) {
-               if (!PL_localizing && ckWARN(WARN_UNINITIALIZED))
-                   report_uninit(sv);
+       if (SvIOKp(sv) || SvNOKp(sv)) {
+           char tbuf[64];  /* Must fit sprintf/Gconvert of longest IV/NV */
+           STRLEN len;
+
+           if (SvIOKp(sv)) {
+               len = SvIsUV(sv) ? my_sprintf(tbuf,"%"UVuf, (UV)SvUVX(sv))
+                   : my_sprintf(tbuf,"%"IVdf, (IV)SvIVX(sv));
+           } else {
+               Gconvert(SvNVX(sv), NV_DIG, 0, tbuf);
+               len = strlen(tbuf);
            }
-           if (lp)
-               *lp = 0;
-            return (char *)"";
-        }
-    }
-    if (SvTHINKFIRST(sv)) {
-       if (SvROK(sv)) {
-           SV* tmpstr;
+           if (SvROK(sv)) {    /* XXX Skip this when sv_pvn_force calls */
+               /* Sneaky stuff here */
+               SV * const tsv = newSVpvn(tbuf, len);
 
-            if (SvAMAGIC(sv) && (tmpstr=AMG_CALLun(sv,string)) &&
-                (!SvROK(tmpstr) || (SvRV(tmpstr) != SvRV(sv)))) {
-               /* Unwrap this:  */
-               /* char *pv = lp ? SvPV(tmpstr, *lp) : SvPV_nolen(tmpstr); */
+               sv_2mortal(tsv);
+               if (lp)
+                   *lp = SvCUR(tsv);
+               return SvPVX(tsv);
+           }
+           else {
+               dVAR;
 
-                char *pv;
-               if ((SvFLAGS(tmpstr) & (SVf_POK)) == SVf_POK) {
-                   if (flags & SV_CONST_RETURN) {
-                       pv = (char *) SvPVX_const(tmpstr);
+#ifdef FIXNEGATIVEZERO
+               if (len == 2 && tbuf[0] == '-' && tbuf[1] == '0') {
+                   tbuf[0] = '0';
+                   tbuf[1] = 0;
+                   len = 1;
+               }
+#endif
+               SvUPGRADE(sv, SVt_PV);
+               if (lp)
+                   *lp = len;
+               s = SvGROW_mutable(sv, len + 1);
+               SvCUR_set(sv, len);
+               SvPOKp_on(sv);
+               return memcpy(s, tbuf, len + 1);
+           }
+       }
+        if (SvROK(sv)) {
+           goto return_rok;
+       }
+       assert(SvTYPE(sv) >= SVt_PVMG);
+       /* This falls through to the report_uninit near the end of the
+          function. */
+    } else if (SvTHINKFIRST(sv)) {
+       if (SvROK(sv)) {
+       return_rok:
+            if (SvAMAGIC(sv)) {
+               SV *const tmpstr = AMG_CALLun(sv,string);
+               if (tmpstr && (!SvROK(tmpstr) || (SvRV(tmpstr) != SvRV(sv)))) {
+                   /* Unwrap this:  */
+                   /* char *pv = lp ? SvPV(tmpstr, *lp) : SvPV_nolen(tmpstr);
+                    */
+
+                   char *pv;
+                   if ((SvFLAGS(tmpstr) & (SVf_POK)) == SVf_POK) {
+                       if (flags & SV_CONST_RETURN) {
+                           pv = (char *) SvPVX_const(tmpstr);
+                       } else {
+                           pv = (flags & SV_MUTABLE_RETURN)
+                               ? SvPVX_mutable(tmpstr) : SvPVX(tmpstr);
+                       }
+                       if (lp)
+                           *lp = SvCUR(tmpstr);
                    } else {
-                       pv = (flags & SV_MUTABLE_RETURN)
-                           ? SvPVX_mutable(tmpstr) : SvPVX(tmpstr);
+                       pv = sv_2pv_flags(tmpstr, lp, flags);
                    }
-                   if (lp)
-                       *lp = SvCUR(tmpstr);
-               } else {
-                   pv = sv_2pv_flags(tmpstr, lp, flags);
+                   if (SvUTF8(tmpstr))
+                       SvUTF8_on(sv);
+                   else
+                       SvUTF8_off(sv);
+                   return pv;
                }
-                if (SvUTF8(tmpstr))
-                    SvUTF8_on(sv);
-                else
-                    SvUTF8_off(sv);
-                return pv;
-            } else {
+           }
+           {
+               SV *tsv;
                MAGIC *mg;
                const SV *const referent = (SV*)SvRV(sv);
 
@@ -2590,83 +2458,7 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
                                (SVs_OBJECT|SVf_OK|SVs_GMG|SVs_SMG|SVs_RMG))
                               == (SVs_OBJECT|SVs_SMG))
                           && (mg = mg_find(referent, PERL_MAGIC_qr))) {
-                   const regexp *re = (regexp *)mg->mg_obj;
-
-                   if (!mg->mg_ptr) {
-                       const char *fptr = "msix";
-                       char reflags[6];
-                       char ch;
-                       int left = 0;
-                       int right = 4;
-                       char need_newline = 0;
-                       U16 reganch =
-                           (U16)((re->reganch & PMf_COMPILETIME) >> 12);
-
-                       while((ch = *fptr++)) {
-                           if(reganch & 1) {
-                               reflags[left++] = ch;
-                           }
-                           else {
-                               reflags[right--] = ch;
-                           }
-                           reganch >>= 1;
-                       }
-                       if(left != 4) {
-                           reflags[left] = '-';
-                           left = 5;
-                       }
-
-                       mg->mg_len = re->prelen + 4 + left;
-                       /*
-                        * If /x was used, we have to worry about a regex
-                        * ending with a comment later being embedded
-                        * within another regex. If so, we don't want this
-                        * regex's "commentization" to leak out to the
-                        * right part of the enclosing regex, we must cap
-                        * it with a newline.
-                        *
-                        * So, if /x was used, we scan backwards from the
-                        * end of the regex. If we find a '#' before we
-                        * find a newline, we need to add a newline
-                        * ourself. If we find a '\n' first (or if we
-                        * don't find '#' or '\n'), we don't need to add
-                        * anything.  -jfriedl
-                        */
-                       if (PMf_EXTENDED & re->reganch) {
-                           const char *endptr = re->precomp + re->prelen;
-                           while (endptr >= re->precomp) {
-                               const char c = *(endptr--);
-                               if (c == '\n')
-                                   break; /* don't need another */
-                               if (c == '#') {
-                                   /* we end while in a comment, so we
-                                      need a newline */
-                                   mg->mg_len++; /* save space for it */
-                                   need_newline = 1; /* note to add it */
-                                   break;
-                               }
-                           }
-                       }
-
-                       Newx(mg->mg_ptr, mg->mg_len + 1 + left, char);
-                       Copy("(?", mg->mg_ptr, 2, char);
-                       Copy(reflags, mg->mg_ptr+2, left, char);
-                       Copy(":", mg->mg_ptr+left+2, 1, char);
-                       Copy(re->precomp, mg->mg_ptr+3+left, re->prelen, char);
-                       if (need_newline)
-                           mg->mg_ptr[mg->mg_len - 2] = '\n';
-                       mg->mg_ptr[mg->mg_len - 1] = ')';
-                       mg->mg_ptr[mg->mg_len] = 0;
-                   }
-                   PL_reginterp_cnt += re->program[0].next_off;
-
-                   if (re->reganch & ROPT_UTF8)
-                       SvUTF8_on(sv);
-                   else
-                       SvUTF8_off(sv);
-                   if (lp)
-                       *lp = mg->mg_len;
-                   return mg->mg_ptr;
+                   return S_stringify_regexp(aTHX_ sv, mg, lp);
                } else {
                    const char *const typestr = sv_reftype(referent, 0);
 
@@ -2750,7 +2542,7 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
        if (!PL_localizing && !(SvFLAGS(sv) & SVs_PADTMP) && ckWARN(WARN_UNINITIALIZED))
            report_uninit(sv);
        if (lp)
-       *lp = 0;
+           *lp = 0;
        if (SvTYPE(sv) < SVt_PV)
            /* Typically the caller expects that sv_any is not NULL now.  */
            sv_upgrade(sv, SVt_PV);
@@ -2770,39 +2562,6 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
     if (flags & SV_MUTABLE_RETURN)
        return SvPVX_mutable(sv);
     return SvPVX(sv);
-
-  tokensave:
-    len = strlen(tmpbuf);
- tokensave_has_len:
-    assert (!tsv);
-    if (SvROK(sv)) {   /* XXX Skip this when sv_pvn_force calls */
-       /* Sneaky stuff here */
-
-       if (!tsv)
-           tsv = newSVpvn(tmpbuf, len);
-       sv_2mortal(tsv);
-       if (lp)
-           *lp = SvCUR(tsv);
-       return SvPVX(tsv);
-    }
-    else {
-        dVAR;
-
-#ifdef FIXNEGATIVEZERO
-       if (len == 2 && tmpbuf[0] == '-' && tmpbuf[1] == '0') {
-           tmpbuf[0] = '0';
-           tmpbuf[1] = 0;
-           len = 1;
-       }
-#endif
-       SvUPGRADE(sv, SVt_PV);
-       if (lp)
-           *lp = len;
-       s = SvGROW_mutable(sv, len + 1);
-       SvCUR_set(sv, len);
-       SvPOKp_on(sv);
-       return memcpy(s, tmpbuf, len + 1);
-    }
 }
 
 /*
@@ -2971,25 +2730,23 @@ Perl_sv_utf8_upgrade_flags(pTHX_ register SV *sv, I32 flags)
         * had a FLAG in SVs to signal if there are any hibit
         * chars in the PV.  Given that there isn't such a flag
         * make the loop as fast as possible. */
-       const U8 *s = (U8 *) SvPVX_const(sv);
+       const U8 * const s = (U8 *) SvPVX_const(sv);
        const U8 * const e = (U8 *) SvEND(sv);
        const U8 *t = s;
-       int hibit = 0;
        
        while (t < e) {
            const U8 ch = *t++;
-           if ((hibit = !NATIVE_IS_INVARIANT(ch)))
+           /* Check for hi bit */
+           if (!NATIVE_IS_INVARIANT(ch)) {
+               STRLEN len = SvCUR(sv) + 1; /* Plus the \0 */
+               U8 * const recoded = bytes_to_utf8((U8*)s, &len);
+
+               SvPV_free(sv); /* No longer using what was there before. */
+               SvPV_set(sv, (char*)recoded);
+               SvCUR_set(sv, len - 1);
+               SvLEN_set(sv, len); /* No longer know the real size. */
                break;
-       }
-       if (hibit) {
-           STRLEN len = SvCUR(sv) + 1; /* Plus the \0 */
-           U8 * const recoded = bytes_to_utf8((U8*)s, &len);
-
-           SvPV_free(sv); /* No longer using what was there before. */
-
-           SvPV_set(sv, (char*)recoded);
-           SvCUR_set(sv, len - 1);
-           SvLEN_set(sv, len); /* No longer know the real size. */
+           }
        }
        /* Mark as UTF-8 even if no hibit - saves scanning loop */
        SvUTF8_on(sv);
@@ -3621,7 +3378,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
            SvIV_set(dstr, SvIVX(sstr));
        }
        if (SvVOK(sstr)) {
-           MAGIC *smg = mg_find(sstr,PERL_MAGIC_vstring);
+           const MAGIC * const smg = mg_find(sstr,PERL_MAGIC_vstring);
            sv_magic(dstr, NULL, PERL_MAGIC_vstring,
                        smg->mg_ptr, smg->mg_len);
            SvRMAGICAL_on(dstr);
@@ -4127,10 +3884,10 @@ and C<sv_catsv_nomg> are implemented in terms of this function.
 void
 Perl_sv_catsv_flags(pTHX_ SV *dsv, register SV *ssv, I32 flags)
 {
-    const char *spv;
-    STRLEN slen;
     if (ssv) {
-       if ((spv = SvPV_const(ssv, slen))) {
+       STRLEN slen;
+       const char *spv = SvPV_const(ssv, slen);
+       if (spv) {
            /*  sutf8 and dutf8 were type bool, but under USE_ITHREADS,
                gcc version 2.95.2 20000220 (Debian GNU/Linux) for
                Linux xxx 2.2.17 on sparc64 with gcc -O2, we erroneously
@@ -4148,7 +3905,7 @@ Perl_sv_catsv_flags(pTHX_ SV *dsv, register SV *ssv, I32 flags)
            if (dutf8 != sutf8) {
                if (dutf8) {
                    /* Not modifying source SV, so taking a temporary copy. */
-                   SV* csv = sv_2mortal(newSVpvn(spv, slen));
+                   SV* const csv = sv_2mortal(newSVpvn(spv, slen));
 
                    sv_utf8_upgrade(csv);
                    spv = SvPV_const(csv, slen);
@@ -6113,7 +5870,7 @@ thats_really_all_folks:
 
 screamer2:
        if (rslen) {
-            register const STDCHAR *bpe = buf + sizeof(buf);
+            register const STDCHAR * const bpe = buf + sizeof(buf);
            bp = buf;
            while ((i = PerlIO_getc(fp)) != EOF && (*bp++ = (STDCHAR)i) != rslast && bp < bpe)
                ; /* keep reading */
@@ -7504,7 +7261,7 @@ S_sv_unglob(pTHX_ SV *sv)
        gp_free((GV*)sv);
     if (GvSTASH(sv)) {
        sv_del_backref((SV*)GvSTASH(sv), sv);
-       GvSTASH(sv) = Nullhv;
+       GvSTASH(sv) = NULL;
     }
     sv_unmagic(sv, PERL_MAGIC_glob);
     Safefree(GvNAME(sv));
@@ -7860,8 +7617,13 @@ S_expect_number(pTHX_ char** pattern)
     case '1': case '2': case '3':
     case '4': case '5': case '6':
     case '7': case '8': case '9':
-       while (isDIGIT(**pattern))
-           var = var * 10 + (*(*pattern)++ - '0');
+       var = *(*pattern)++ - '0';
+       while (isDIGIT(**pattern)) {
+           I32 tmp = var * 10 + (*(*pattern)++ - '0');
+           if (tmp < var)
+               Perl_croak(aTHX_ "Integer overflow in format string for %s", (PL_op ? OP_NAME(PL_op) : "sv_vcatpvfn"));
+           var = tmp;
+       }
     }
     return var;
 }
@@ -8203,31 +7965,48 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            if (vectorarg) {
                if (args)
                    vecsv = va_arg(*args, SV*);
-               else
-                   vecsv = (evix ? evix <= svmax : svix < svmax) ?
-                       svargs[evix ? evix-1 : svix++] : &PL_sv_undef;
+               else if (evix) {
+                   vecsv = (evix > 0 && evix <= svmax)
+                       ? svargs[evix-1] : &PL_sv_undef;
+               } else {
+                   vecsv = svix < svmax ? svargs[svix++] : &PL_sv_undef;
+               }
                dotstr = SvPV_const(vecsv, dotstrlen);
+               /* Keep the DO_UTF8 test *after* the SvPV call, else things go
+                  bad with tied or overloaded values that return UTF8.  */
                if (DO_UTF8(vecsv))
                    is_utf8 = TRUE;
+               else if (has_utf8) {
+                   vecsv = sv_mortalcopy(vecsv);
+                   sv_utf8_upgrade(vecsv);
+                   dotstr = SvPV_const(vecsv, dotstrlen);
+                   is_utf8 = TRUE;
+               }                   
            }
            if (args) {
                VECTORIZE_ARGS
            }
-           else if (efix ? efix <= svmax : svix < svmax) {
+           else if (efix ? (efix > 0 && efix <= svmax) : svix < svmax) {
                vecsv = svargs[efix ? efix-1 : svix++];
                vecstr = (U8*)SvPV_const(vecsv,veclen);
                vec_utf8 = DO_UTF8(vecsv);
-               /* if this is a version object, we need to return the
-                * stringified representation (which the SvPVX_const has
-                * already done for us), but not vectorize the args
+
+               /* if this is a version object, we need to convert
+                * back into v-string notation and then let the
+                * vectorize happen normally
                 */
-               if ( *q == 'd' && sv_derived_from(vecsv,"version") )
-               {
-                       q++; /* skip past the rest of the %vd format */
-                       eptr = (const char *) vecstr;
-                       elen = veclen;
-                       vectorize=FALSE;
-                       goto string;
+               if (sv_derived_from(vecsv, "version")) {
+                   char *version = savesvpv(vecsv);
+                   vecsv = sv_newmortal();
+                   /* scan_vstring is expected to be called during
+                    * tokenization, so we need to fake up the end
+                    * of the buffer for it
+                    */
+                   PL_bufend = version + veclen;
+                   scan_vstring(version, vecsv);
+                   vecstr = (U8*)SvPV_const(vecsv, veclen);
+                   vec_utf8 = DO_UTF8(vecsv);
+                   Safefree(version);
                }
            }
            else {
@@ -8326,12 +8105,14 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
        if (*q == '%') {
            eptr = q++;
            elen = 1;
+           if (vectorize) {
+               c = '%';
+               goto unknown;
+           }
            goto string;
        }
 
-       if (vectorize)
-           argsv = vecsv;
-       else if (!args) {
+       if (!vectorize && !args) {
            if (efix) {
                const I32 i = efix-1;
                argsv = (i >= 0 && i < svmax) ? svargs[i] : &PL_sv_undef;
@@ -8346,7 +8127,9 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            /* STRINGS */
 
        case 'c':
-           uv = (args && !vectorize) ? va_arg(*args, int) : SvIVx(argsv);
+           if (vectorize)
+               goto unknown;
+           uv = (args) ? va_arg(*args, int) : SvIVx(argsv);
            if ((uv > 255 ||
                 (!UNI_IS_INVARIANT(uv) && SvUTF8(sv)))
                && !IN_BYTES) {
@@ -8362,7 +8145,9 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            goto string;
 
        case 's':
-           if (args && !vectorize) {
+           if (vectorize)
+               goto unknown;
+           if (args) {
                eptr = va_arg(*args, char*);
                if (eptr)
 #ifdef MACOS_TRADITIONAL
@@ -8393,7 +8178,6 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            }
 
        string:
-           vectorize = FALSE;
            if (has_precis && elen > precis)
                elen = precis;
            break;
@@ -8608,6 +8392,8 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
        case 'e': case 'E':
        case 'f':
        case 'g': case 'G':
+           if (vectorize)
+               goto unknown;
 
            /* This is evil, but floating point is even more evil */
 
@@ -8640,7 +8426,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            }
 
            /* now we need (long double) if intsize == 'q', else (double) */
-           nv = (args && !vectorize) ?
+           nv = (args) ?
 #if LONG_DOUBLESIZE > DOUBLESIZE
                intsize == 'q' ?
                    va_arg(*args, long double) :
@@ -8651,7 +8437,6 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                : SvNVx(argsv);
 
            need = 0;
-           vectorize = FALSE;
            if (c != 'e' && c != 'E') {
                i = PERL_INT_MIN;
                /* FIXME: if HAS_LONG_DOUBLE but not USE_LONG_DOUBLE this
@@ -8809,8 +8594,10 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            /* SPECIAL */
 
        case 'n':
+           if (vectorize)
+               goto unknown;
            i = SvCUR(sv) - origlen;
-           if (args && !vectorize) {
+           if (args) {
                switch (intsize) {
                case 'h':       *(va_arg(*args, short*)) = i; break;
                default:        *(va_arg(*args, int*)) = i; break;
@@ -8823,7 +8610,6 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            }
            else
                sv_setuv_mg(argsv, (UV)i);
-           vectorize = FALSE;
            continue;   /* not "break" */
 
            /* UNKNOWN */
@@ -9252,11 +9038,8 @@ Perl_ptr_table_new(pTHX)
     return tbl;
 }
 
-#if (PTRSIZE == 8)
-#  define PTR_TABLE_HASH(ptr) (PTR2UV(ptr) >> 3)
-#else
-#  define PTR_TABLE_HASH(ptr) (PTR2UV(ptr) >> 2)
-#endif
+#define PTR_TABLE_HASH(ptr) \
+  ((PTR2UV(ptr) >> 3) ^ (PTR2UV(ptr) >> (3 + 7)) ^ (PTR2UV(ptr) >> (3 + 17)))
 
 /* 
    we use the PTE_SVSLOT 'reservation' made above, both here (in the
@@ -9268,18 +9051,24 @@ Perl_ptr_table_new(pTHX)
 
 /* map an existing pointer using a table */
 
-void *
-Perl_ptr_table_fetch(pTHX_ PTR_TBL_t *tbl, const void *sv)
-{
+STATIC PTR_TBL_ENT_t *
+S_ptr_table_find(pTHX_ PTR_TBL_t *tbl, const void *sv) {
     PTR_TBL_ENT_t *tblent;
     const UV hash = PTR_TABLE_HASH(sv);
     assert(tbl);
     tblent = tbl->tbl_ary[hash & tbl->tbl_max];
     for (; tblent; tblent = tblent->next) {
        if (tblent->oldval == sv)
-           return tblent->newval;
+           return tblent;
     }
-    return (void*)NULL;
+    return 0;
+}
+
+void *
+Perl_ptr_table_fetch(pTHX_ PTR_TBL_t *tbl, const void *sv)
+{
+    PTR_TBL_ENT_t const *const tblent = S_ptr_table_find(aTHX_ tbl, sv);
+    return tblent ? tblent->newval : (void *) 0;
 }
 
 /* add a new entry to a pointer-mapping table */
@@ -9287,29 +9076,22 @@ Perl_ptr_table_fetch(pTHX_ PTR_TBL_t *tbl, const void *sv)
 void
 Perl_ptr_table_store(pTHX_ PTR_TBL_t *tbl, const void *oldsv, void *newsv)
 {
-    PTR_TBL_ENT_t *tblent, **otblent;
-    /* XXX this may be pessimal on platforms where pointers aren't good
-     * hash values e.g. if they grow faster in the most significant
-     * bits */
-    const UV hash = PTR_TABLE_HASH(oldsv);
-    bool empty = 1;
+    PTR_TBL_ENT_t *tblent = S_ptr_table_find(aTHX_ tbl, oldsv);
 
-    assert(tbl);
-    otblent = &tbl->tbl_ary[hash & tbl->tbl_max];
-    for (tblent = *otblent; tblent; empty=0, tblent = tblent->next) {
-       if (tblent->oldval == oldsv) {
-           tblent->newval = newsv;
-           return;
-       }
+    if (tblent) {
+       tblent->newval = newsv;
+    } else {
+       const UV entry = PTR_TABLE_HASH(oldsv) & tbl->tbl_max;
+
+       new_body_inline(tblent, sizeof(struct ptr_tbl_ent), PTE_SVSLOT);
+       tblent->oldval = oldsv;
+       tblent->newval = newsv;
+       tblent->next = tbl->tbl_ary[entry];
+       tbl->tbl_ary[entry] = tblent;
+       tbl->tbl_items++;
+       if (tblent->next && tbl->tbl_items > tbl->tbl_max)
+           ptr_table_split(tbl);
     }
-    new_body_inline(tblent, sizeof(struct ptr_tbl_ent), PTE_SVSLOT);
-    tblent->oldval = oldsv;
-    tblent->newval = newsv;
-    tblent->next = *otblent;
-    *otblent = tblent;
-    tbl->tbl_items++;
-    if (!empty && tbl->tbl_items > tbl->tbl_max)
-       ptr_table_split(tbl);
 }
 
 /* double the hash bucket size of an existing ptr table */
@@ -9349,34 +9131,22 @@ Perl_ptr_table_split(pTHX_ PTR_TBL_t *tbl)
 void
 Perl_ptr_table_clear(pTHX_ PTR_TBL_t *tbl)
 {
-    register PTR_TBL_ENT_t **array;
-    register PTR_TBL_ENT_t *entry;
-    UV riter = 0;
-    UV max;
+    if (tbl && tbl->tbl_items) {
+       register PTR_TBL_ENT_t **array = tbl->tbl_ary;
+       UV riter = tbl->tbl_max;
 
-    if (!tbl || !tbl->tbl_items) {
-        return;
-    }
+       do {
+           PTR_TBL_ENT_t *entry = array[riter];
 
-    array = tbl->tbl_ary;
-    entry = array[0];
-    max = tbl->tbl_max;
+           while (entry) {
+               PTR_TBL_ENT_t * const oentry = entry;
+               entry = entry->next;
+               del_pte(oentry);
+           }
+       } while (riter--);
 
-    for (;;) {
-        if (entry) {
-            PTR_TBL_ENT_t *oentry = entry;
-            entry = entry->next;
-            del_pte(oentry);
-        }
-        if (!entry) {
-            if (++riter > max) {
-                break;
-            }
-            entry = array[riter];
-        }
+       tbl->tbl_items = 0;
     }
-
-    tbl->tbl_items = 0;
 }
 
 /* clear and free a ptr table */
@@ -9544,9 +9314,9 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
            case SVt_PVNV:
            case SVt_PVIV:
            case SVt_PV:
-               assert(sv_type_details->copy);
+               assert(sv_type_details->size);
                if (sv_type_details->arena) {
-                   new_body_inline(new_body, sv_type_details->copy, sv_type);
+                   new_body_inline(new_body, sv_type_details->size, sv_type);
                    new_body
                        = (void*)((char*)new_body - sv_type_details->offset);
                } else {
@@ -9684,8 +9454,8 @@ Perl_sv_dup(pTHX_ SV *sstr, CLONE_PARAMS* param)
                            ++i;
                        }
                        if (SvOOK(sstr)) {
-                           struct xpvhv_aux *saux = HvAUX(sstr);
-                           struct xpvhv_aux *daux = HvAUX(dstr);
+                           struct xpvhv_aux * const saux = HvAUX(sstr);
+                           struct xpvhv_aux * const daux = HvAUX(dstr);
                            /* This flag isn't copied.  */
                            /* SvOOK_on(hv) attacks the IV flags.  */
                            SvFLAGS(dstr) |= SVf_OOK;
@@ -9785,7 +9555,7 @@ Perl_cx_dup(pTHX_ PERL_CONTEXT *cxs, I32 ix, I32 max, CLONE_PARAMS* param)
                                           : cv_dup(cx->blk_sub.cv,param));
                ncx->blk_sub.argarray   = (cx->blk_sub.hasargs
                                           ? av_dup_inc(cx->blk_sub.argarray, param)
-                                          : Nullav);
+                                          : NULL);
                ncx->blk_sub.savearray  = av_dup_inc(cx->blk_sub.savearray, param);
                ncx->blk_sub.olddepth   = cx->blk_sub.olddepth;
                ncx->blk_sub.hasargs    = cx->blk_sub.hasargs;
@@ -10810,7 +10580,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 #endif
 
     /* swatch cache */
-    PL_last_swash_hv   = Nullhv;       /* reinits on demand */
+    PL_last_swash_hv   = NULL; /* reinits on demand */
     PL_last_swash_klen = 0;
     PL_last_swash_key[0]= '\0';
     PL_last_swash_tmps = (U8*)NULL;
@@ -11462,7 +11232,7 @@ S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
                        break;
                }
                else {
-                   SV ** const svp = av_fetch((AV*)sv, SvIV(cSVOPx_sv(kid)), FALSE);
+                   SV * const * const svp = av_fetch((AV*)sv, SvIV(cSVOPx_sv(kid)), FALSE);
                    if (!svp || *svp != uninit_sv)
                        break;
                }
@@ -11473,7 +11243,6 @@ S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
            else
                return varname(gv, '@', o->op_targ, Nullsv,
                            SvIV(cSVOPx_sv(kid)), FUV_SUBSCRIPT_ARRAY);
-           ;
        }
        else  {
            /* index is an expression;