A placeholder.
[p5sagit/p5-mst-13.2.git] / sv.c
diff --git a/sv.c b/sv.c
index c14809b..6b6e063 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -63,7 +63,7 @@ static void do_clean_all(pTHXo_ SV *sv);
 #define del_SV(p) \
     STMT_START {                                       \
        LOCK_SV_MUTEX;                                  \
-       if (PL_debug & 32768)                           \
+       if (DEBUG_D_TEST)                               \
            del_sv(p);                                  \
        else                                            \
            plant_SV(p);                                \
@@ -73,7 +73,7 @@ static void do_clean_all(pTHXo_ SV *sv);
 STATIC void
 S_del_sv(pTHX_ SV *p)
 {
-    if (PL_debug & 32768) {
+    if (DEBUG_D_TEST) {
        SV* sva;
        SV* sv;
        SV* svend;
@@ -137,6 +137,7 @@ S_more_sv(pTHX)
     if (PL_nice_chunk) {
        sv_add_arena(PL_nice_chunk, PL_nice_chunk_size, 0);
        PL_nice_chunk = Nullch;
+        PL_nice_chunk_size = 0;
     }
     else {
        char *chunk;                /* must use New here to match call to */
@@ -147,20 +148,24 @@ S_more_sv(pTHX)
     return sv;
 }
 
-STATIC void
+STATIC I32
 S_visit(pTHX_ SVFUNC_t f)
 {
     SV* sva;
     SV* sv;
     register SV* svend;
+    I32 visited = 0;
 
     for (sva = PL_sv_arenaroot; sva; sva = (SV*)SvANY(sva)) {
        svend = &sva[SvREFCNT(sva)];
        for (sv = sva + 1; sv < svend; ++sv) {
-           if (SvTYPE(sv) != SVTYPEMASK)
+           if (SvTYPE(sv) != SVTYPEMASK && SvREFCNT(sv)) {
                (FCALL)(aTHXo_ sv);
+               ++visited;
+           }
        }
     }
+    return visited;
 }
 
 void
@@ -181,12 +186,14 @@ Perl_sv_clean_objs(pTHX)
     PL_in_clean_objs = FALSE;
 }
 
-void
+I32
 Perl_sv_clean_all(pTHX)
 {
+    I32 cleaned;
     PL_in_clean_all = TRUE;
-    visit(do_clean_all);
+    cleaned = visit(do_clean_all);
     PL_in_clean_all = FALSE;
+    return cleaned;
 }
 
 void
@@ -1424,12 +1431,12 @@ S_not_a_number(pTHX_ SV *sv)
 {
     char tmpbuf[64];
     char *d = tmpbuf;
-    char *s;
     char *limit = tmpbuf + sizeof(tmpbuf) - 8;
                   /* each *s can expand to 4 chars + "...\0",
                      i.e. need room for 8 chars */
 
-    for (s = SvPVX(sv); *s && d < limit; s++) {
+    char *s, *end;
+    for (s = SvPVX(sv), end = s + SvCUR(sv); s < end && d < limit; s++) {
        int ch = *s & 0xFF;
        if (ch & 128 && !isPRINT_LC(ch)) {
            *d++ = 'M';
@@ -1452,6 +1459,10 @@ S_not_a_number(pTHX_ SV *sv)
            *d++ = '\\';
            *d++ = '\\';
        }
+       else if (ch == '\0') {
+           *d++ = '\\';
+           *d++ = '0';
+       }
        else if (isPRINT_LC(ch))
            *d++ = ch;
        else {
@@ -1459,7 +1470,7 @@ S_not_a_number(pTHX_ SV *sv)
            *d++ = toCTRL(ch);
        }
     }
-    if (*s) {
+    if (s < end) {
        *d++ = '.';
        *d++ = '.';
        *d++ = '.';
@@ -1475,15 +1486,32 @@ S_not_a_number(pTHX_ SV *sv)
                    "Argument \"%s\" isn't numeric", tmpbuf);
 }
 
-/* the number can be converted to integer with atol() or atoll() although */
-#define IS_NUMBER_TO_INT_BY_ATOL     0x01 /* integer (may have decimals) */
-#define IS_NUMBER_TO_INT_BY_STRTOL   0x02 /* it may exceed IV_MAX */
-#define IS_NUMBER_TO_INT_BY_ATOF     0x04 /* seen something like 123e4 */
-#define IS_NUMBER_LONGER_THAN_IV_MAX 0x08 /* more digits than IV_MAX */
-#define IS_NUMBER_AS_LONG_AS_IV_MAX  0x10 /* may(be not) larger than IV_MAX */
-#define IS_NUMBER_NOT_INT           0x20 /* seen a decimal point or e */
-#define IS_NUMBER_NEG               0x40 /* seen a leading - */
-#define IS_NUMBER_INFINITY          0x80 /* /^\s*-?Infinity\s*$/i */
+/*
+=for apidoc looks_like_number
+
+Test if an the content of an SV looks like a number (or is a
+number). C<Inf> and C<Infinity> are treated as numbers (so will not
+issue a non-numeric warning), even if your atof() doesn't grok them.
+
+=cut
+*/
+
+I32
+Perl_looks_like_number(pTHX_ SV *sv)
+{
+    register char *sbegin;
+    STRLEN len;
+
+    if (SvPOK(sv)) {
+       sbegin = SvPVX(sv);
+       len = SvCUR(sv);
+    }
+    else if (SvPOKp(sv))
+       sbegin = SvPV(sv, len);
+    else
+       return 1; /* Historic.  Wrong?  */
+    return grok_number(sbegin, len, NULL);
+}
 
 /* Actually, ISO C leaves conversion of UV to IV undefined, but
    until proven guilty, assume that things are not that bad... */
@@ -1562,87 +1590,6 @@ S_not_a_number(pTHX_ SV *sv)
 #define IS_NUMBER_IV_AND_UV 2
 #define IS_NUMBER_OVERFLOW_IV 4
 #define IS_NUMBER_OVERFLOW_UV 5
-/* Hopefully your optimiser will consider inlining these two functions.  */
-STATIC int
-S_sv_2inuv_non_preserve (pTHX_ register SV *sv, I32 numtype) {
-    NV nv = SvNVX(sv);         /* Code simpler and had compiler problems if */
-    UV nv_as_uv = U_V(nv);     /*  these are not in simple variables.   */
-    DEBUG_c(PerlIO_printf(Perl_debug_log,"sv_2inuv_non '%s', IV=0x%"UVxf" NV=%g inttype=%"UVXf"\n", SvPVX(sv), SvIVX(sv), nv, (UV)numtype));
-    if (nv_as_uv <= (UV)IV_MAX) {
-       (void)SvIOKp_on(sv);
-       (void)SvNOKp_on(sv);
-       /* Within suitable range to fit in an IV,  atol won't overflow */
-       /* XXX quite sure? Is that your final answer? not really, I'm
-          trusting that nv_as_uv to round down if NV is (IV_MAX + 1) */
-       SvIVX(sv) = (IV)Atol(SvPVX(sv));
-       if (numtype & IS_NUMBER_NOT_INT) {
-           /* I believe that even if the original PV had decimals, they
-              are lost beyond the limit of the FP precision.
-              However, neither is canonical, so both only get p flags.
-              NWC, 2000/11/25 */
-           /* Both already have p flags, so do nothing */
-       } else if (SvIVX(sv) == I_V(nv)) {
-           SvNOK_on(sv);
-           SvIOK_on(sv);
-       } else {
-           SvIOK_on(sv);
-           /* It had no "." so it must be integer.  assert (get in here from
-              sv_2iv and sv_2uv only for ndef HAS_STRTOL and
-              IS_NUMBER_AS_LONG_AS_IV_MAX) or my logic is faulty and all
-              conversion routines need audit.  */
-       }
-       return nv < 0 ? IS_NUMBER_UNDERFLOW_UV : IS_NUMBER_IV_AND_UV;
-    }
-    /* between IV_MAX and NV(UV_MAX). Could be slightly> UV_MAX */
-    (void)SvIOKp_on(sv);
-    (void)SvNOKp_on(sv);
-#ifdef HAS_STRTOUL
-    {
-       int save_errno = errno;
-       errno = 0;
-       SvUVX(sv) = Strtoul(SvPVX(sv), Null(char**), 10);
-       if (errno == 0) {
-           if (numtype & IS_NUMBER_NOT_INT) {
-               /* UV and NV both imprecise.  */
-               SvIsUV_on(sv);
-           } else if (SvUVX(sv) == nv_as_uv && SvUVX(sv) != UV_MAX) {
-               SvNOK_on(sv);
-               SvIOK_on(sv);
-               SvIsUV_on(sv);
-           } else {
-               SvIOK_on(sv);
-               SvIsUV_on(sv);
-           }
-           errno = save_errno;
-           return IS_NUMBER_OVERFLOW_IV;
-       }
-       errno = save_errno;
-       SvNOK_on(sv);
-       /* Must have just overflowed UV, but not enough that an NV could spot
-          this.. */
-       return IS_NUMBER_OVERFLOW_UV;
-    }
-#else
-    /* We've just lost integer precision, nothing we could do. */
-    SvUVX(sv) = nv_as_uv;
-    DEBUG_c(PerlIO_printf(Perl_debug_log,"sv_2niuv_non UV? '%s', UV=0x%"UVxf" NV=%g U_V(NV)=0x%"UVxf" inttype=%"UVXf"\n", SvPVX(sv), SvIVX(sv), nv, nv_as_uv, (UV)numtype));
-    /* UV and NV slots equally valid only if we have casting symmetry. */
-    if (numtype & IS_NUMBER_NOT_INT) {
-       SvIsUV_on(sv);
-    } else if (SvUVX(sv) == nv_as_uv && SvUVX(sv) != UV_MAX) {
-       /* UV_MAX can cast up to NV (UV_MAX+1), that NV casts down to UV_MAX
-          UV_MAX ought to be 0xFF...FFF which won't preserve (We only
-          get to this point if NVs don't preserve UVs) */
-       SvNOK_on(sv);
-       SvIOK_on(sv);
-       SvIsUV_on(sv);
-    } else {
-       /* As above, I believe UV at least as good as NV */
-       SvIsUV_on(sv);
-    }
-#endif /* HAS_STRTOUL */
-    return IS_NUMBER_OVERFLOW_IV;
-}
 
 /* For sv_2nv these three cases are "SvNOK and don't bother casting"  */
 STATIC int
@@ -1662,35 +1609,33 @@ S_sv_2iuv_non_preserve (pTHX_ register SV *sv, I32 numtype)
        SvUVX(sv) = UV_MAX;
        return IS_NUMBER_OVERFLOW_UV;
     }
-    if (!(numtype & (IS_NUMBER_TO_INT_BY_ATOL | IS_NUMBER_TO_INT_BY_STRTOL))) {
-       (void)SvIOKp_on(sv);
-       (void)SvNOK_on(sv);
-       /* Can't use strtol etc to convert this string */
-       if (SvNVX(sv) <= (UV)IV_MAX) {
-           SvIVX(sv) = I_V(SvNVX(sv));
-           if ((NV)(SvIVX(sv)) == SvNVX(sv)) {
-               SvIOK_on(sv); /* Integer is precise. NOK, IOK */
-           } else {
-               /* Integer is imprecise. NOK, IOKp */
-           }
-           return SvNVX(sv) < 0 ? IS_NUMBER_UNDERFLOW_UV : IS_NUMBER_IV_AND_UV;
-       }
-       SvIsUV_on(sv);
-       SvUVX(sv) = U_V(SvNVX(sv));
-       if ((NV)(SvUVX(sv)) == SvNVX(sv)) {
-           if (SvUVX(sv) == UV_MAX) {
-               /* As we know that NVs don't preserve UVs, UV_MAX cannot
-                  possibly be preserved by NV. Hence, it must be overflow.
-                  NOK, IOKp */
-               return IS_NUMBER_OVERFLOW_UV;
-           }
-           SvIOK_on(sv); /* Integer is precise. NOK, UOK */
-       } else {
-           /* Integer is imprecise. NOK, IOKp */
-       }
-       return IS_NUMBER_OVERFLOW_IV;
+    (void)SvIOKp_on(sv);
+    (void)SvNOK_on(sv);
+    /* Can't use strtol etc to convert this string.  (See truth table in
+       sv_2iv  */
+    if (SvNVX(sv) <= (UV)IV_MAX) {
+        SvIVX(sv) = I_V(SvNVX(sv));
+        if ((NV)(SvIVX(sv)) == SvNVX(sv)) {
+            SvIOK_on(sv); /* Integer is precise. NOK, IOK */
+        } else {
+            /* Integer is imprecise. NOK, IOKp */
+        }
+        return SvNVX(sv) < 0 ? IS_NUMBER_UNDERFLOW_UV : IS_NUMBER_IV_AND_UV;
     }
-    return S_sv_2inuv_non_preserve(aTHX_ sv, numtype);
+    SvIsUV_on(sv);
+    SvUVX(sv) = U_V(SvNVX(sv));
+    if ((NV)(SvUVX(sv)) == SvNVX(sv)) {
+        if (SvUVX(sv) == UV_MAX) {
+            /* As we know that NVs don't preserve UVs, UV_MAX cannot
+               possibly be preserved by NV. Hence, it must be overflow.
+               NOK, IOKp */
+            return IS_NUMBER_OVERFLOW_UV;
+        }
+        SvIOK_on(sv); /* Integer is precise. NOK, UOK */
+    } else {
+        /* Integer is imprecise. NOK, IOKp */
+    }
+    return IS_NUMBER_OVERFLOW_IV;
 }
 #endif /* NV_PRESERVES_UV*/
 
@@ -1720,7 +1665,7 @@ Perl_sv_2iv(pTHX_ register SV *sv)
        if (SvROK(sv)) {
          SV* tmpstr;
           if (SvAMAGIC(sv) && (tmpstr=AMG_CALLun(sv,numer)) &&
-                  (SvRV(tmpstr) != SvRV(sv)))
+                (SvTYPE(tmpstr) != SVt_RV || (SvRV(tmpstr) != SvRV(sv))))
              return SvIV(tmpstr);
          return PTR2IV(SvRV(sv));
        }
@@ -1818,123 +1763,156 @@ Perl_sv_2iv(pTHX_ register SV *sv)
        }
     }
     else if (SvPOKp(sv) && SvLEN(sv)) {
-       I32 numtype = looks_like_number(sv);
-
+       UV value;
+       int numtype = grok_number(SvPVX(sv), SvCUR(sv), &value);
        /* We want to avoid a possible problem when we cache an IV which
           may be later translated to an NV, and the resulting NV is not
-          the translation of the initial data.
+          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
           NV as well.  Moreover, we trade speed for space, and do not
           cache the NV if we are sure it's not needed.
         */
 
-       if ((numtype & ~IS_NUMBER_NEG) == IS_NUMBER_TO_INT_BY_ATOL) {
-           /* The NV may be reconstructed from IV - safe to cache IV,
-               which may be calculated by atol(). */
+       /* 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 defintately an integer, only upgrade to PVIV */
            if (SvTYPE(sv) < SVt_PVIV)
                sv_upgrade(sv, SVt_PVIV);
            (void)SvIOK_on(sv);
-           SvIVX(sv) = Atol(SvPVX(sv));
-       } else {
-#ifdef HAS_STRTOL
-           IV i;
-           int save_errno = errno;
-           /* Is it an integer that we could convert with strtol?
-              So try it, and if it doesn't set errno then it's pukka.
-              This should be faster than going atof and then thinking.  */
-           if (((numtype & (IS_NUMBER_TO_INT_BY_STRTOL | IS_NUMBER_NOT_INT))
-                 == IS_NUMBER_TO_INT_BY_STRTOL)
-               /* && is a sequence point. Without it not sure if I'm trying
-                  to do too much between sequence points and hence going
-                  undefined */
-               && ((errno = 0), 1) /* , 1 so always true */
-               && ((i = Strtol(SvPVX(sv), Null(char**), 10)), 1)
-               && (errno == 0)) {
-               if (SvTYPE(sv) < SVt_PVIV)
-                   sv_upgrade(sv, SVt_PVIV);
-               (void)SvIOK_on(sv);
-               SvIVX(sv) = i;
-               errno = save_errno;
-           } else
-#endif
-           {
-               NV d;
-#ifdef HAS_STRTOL
-               /* Hopefully trace flow will optimise this away where possible
-                */
-               errno = save_errno;
-#endif
-               /* It wasn't an integer, or it overflowed, or we don't have
-                  strtol. Do things the slow way - check if it's a UV etc. */
-               d = Atof(SvPVX(sv));
+       } else if (SvTYPE(sv) < SVt_PVNV)
+           sv_upgrade(sv, SVt_PVNV);
 
-               if (SvTYPE(sv) < SVt_PVNV)
-                   sv_upgrade(sv, SVt_PVNV);
-               SvNVX(sv) = d;
+       /* 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 value isn't perfectly 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);
+
+           if (!(numtype & IS_NUMBER_NEG)) {
+               /* positive */;
+               if (value <= (UV)IV_MAX) {
+                   SvIVX(sv) = (IV)value;
+               } else {
+                   SvUVX(sv) = value;
+                   SvIsUV_on(sv);
+               }
+           } else {
+               /* 2s complement assumption  */
+               if (value <= (UV)IV_MIN) {
+                   SvIVX(sv) = -(IV)value;
+               } else {
+                   /* Too negative for an IV.  This is a double upgrade, but
+                      I'm assuming it will be be rare.  */
+                   if (SvTYPE(sv) < SVt_PVNV)
+                       sv_upgrade(sv, SVt_PVNV);
+                   SvNOK_on(sv);
+                   SvIOK_off(sv);
+                   SvIOKp_on(sv);
+                   SvNVX(sv) = -(NV)value;
+                   SvIVX(sv) = IV_MIN;
+               }
+           }
+       }
+       /* For !NV_PRESERVES_UV and IS_NUMBER_IN_UV and IS_NUMBER_NOT_INT we
+           will be in the previous block to set the IV slot, and the next
+           block to set the NV slot.  So no else here.  */
+       
+       if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
+           != IS_NUMBER_IN_UV) {
+           /* It wasn't an (integer that doesn't overflow the UV). */
+           SvNVX(sv) = Atof(SvPVX(sv));
 
-               if (! numtype && ckWARN(WARN_NUMERIC))
-                   not_a_number(sv);
+           if (! numtype && ckWARN(WARN_NUMERIC))
+               not_a_number(sv);
 
 #if defined(USE_LONG_DOUBLE)
-               DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%"UVxf" 2iv(%" PERL_PRIgldbl ")\n",
-                                     PTR2UV(sv), SvNVX(sv)));
+           DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%"UVxf" 2iv(%" PERL_PRIgldbl ")\n",
+                                 PTR2UV(sv), SvNVX(sv)));
 #else
-               DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%"UVxf" 2iv(%g)\n",
-                                     PTR2UV(sv), SvNVX(sv)));
+           DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%"UVxf" 2iv(%g)\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) {
-                   SvIVX(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 */
+           (void)SvIOKp_on(sv);
+           (void)SvNOK_on(sv);
+           if (SvNVX(sv) < (NV)IV_MAX + 0.5) {
+               SvIVX(sv) = I_V(SvNVX(sv));
+               if ((NV)(SvIVX(sv)) == SvNVX(sv)) {
+                   SvIOK_on(sv);
                } else {
-                   if (SvNVX(sv) > (NV)UV_MAX) {
-                       SvIsUV_on(sv);
-                       /* Integer is inaccurate. NOK, IOKp, is UV */
-                       SvUVX(sv) = UV_MAX;
+                   /* 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 */
+                   SvUVX(sv) = UV_MAX;
+                   SvIsUV_on(sv);
+               } else {
+                   SvUVX(sv) = U_V(SvNVX(sv));
+                   /* 0xFFFFFFFFFFFFFFFF not an issue in here */
+                   if ((NV)(SvUVX(sv)) == SvNVX(sv)) {
+                       SvIOK_on(sv);
                        SvIsUV_on(sv);
                    } else {
-                       SvUVX(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);
-                       }
+                       /* Integer is imprecise. NOK, IOKp, is UV */
+                       SvIsUV_on(sv);
                    }
-                   goto ret_iv_max;
                }
+               goto ret_iv_max;
+           }
 #else /* NV_PRESERVES_UV */
-               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);
-                   SvIVX(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_2iv assumed (U_V(fabs(SvNVX(sv))) < (UV)IV_MAX) but SvNVX(sv)=%g U_V is 0x%"UVxf", IV_MAX is 0x%"UVxf"\n", SvNVX(sv), U_V(SvNVX(sv)), (UV)IV_MAX);
-                   }
-               } else if (sv_2iuv_non_preserve (sv, numtype)
-                          >= IS_NUMBER_OVERFLOW_IV)
-                   goto ret_iv_max;
+            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
+                   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);
+                    SvIVX(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_2iv assumed (U_V(fabs(SvNVX(sv))) < (UV)IV_MAX) but SvNVX(sv)=%g U_V is 0x%"UVxf", IV_MAX is 0x%"UVxf"\n", SvNVX(sv), U_V(SvNVX(sv)), (UV)IV_MAX);
+                    }
+                } else {
+                    /* IN_UV NOT_INT
+                         0      0      already failed to read UV.
+                         0      1       already failed to read UV.
+                         1      0       you won't get here in this case. IV/UV
+                                       slot set, public IOK, Atof() unneeded.
+                         1      1       already read UV.
+                       so there's no point in sv_2iuv_non_preserve() attempting
+                       to use atol, strtol, strtoul etc.  */
+                    if (sv_2iuv_non_preserve (sv, numtype)
+                        >= IS_NUMBER_OVERFLOW_IV)
+                    goto ret_iv_max;
+                }
+            }
 #endif /* NV_PRESERVES_UV */
-           }
        }
     } else  {
        if (ckWARN(WARN_UNINITIALIZED) && !PL_localizing && !(SvFLAGS(sv) & SVs_PADTMP))
@@ -1974,7 +1952,7 @@ Perl_sv_2uv(pTHX_ register SV *sv)
        if (SvROK(sv)) {
          SV* tmpstr;
           if (SvAMAGIC(sv) && (tmpstr=AMG_CALLun(sv,numer)) &&
-                  (SvRV(tmpstr) != SvRV(sv)))
+                (SvTYPE(tmpstr) != SVt_RV || (SvRV(tmpstr) != SvRV(sv))))
              return SvUV(tmpstr);
          return PTR2UV(SvRV(sv));
        }
@@ -2067,7 +2045,8 @@ Perl_sv_2uv(pTHX_ register SV *sv)
        }
     }
     else if (SvPOKp(sv) && SvLEN(sv)) {
-       I32 numtype = looks_like_number(sv);
+       UV value;
+       int numtype = grok_number(SvPVX(sv), SvCUR(sv), &value);
 
        /* 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
@@ -2078,136 +2057,128 @@ Perl_sv_2uv(pTHX_ register SV *sv)
           cache the NV if not needed.
         */
 
-       if ((numtype & ~IS_NUMBER_NEG) == IS_NUMBER_TO_INT_BY_ATOL) {
-           /* The NV may be reconstructed from IV - safe to cache IV,
-               which may be calculated by atol(). */
+       /* 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 defintately an integer, only upgrade to PVIV */
            if (SvTYPE(sv) < SVt_PVIV)
                sv_upgrade(sv, SVt_PVIV);
            (void)SvIOK_on(sv);
-           SvIVX(sv) = Atol(SvPVX(sv));
-       } else {
-#ifdef HAS_STRTOUL
-           UV u;
-           char *num_begin = SvPVX(sv);
-           int save_errno = errno;
-       
-           /* seems that strtoul taking numbers that start with - is
-              implementation dependant, and can't be relied upon.  */
-           if (numtype & IS_NUMBER_NEG) {
-               /* Not totally defensive. assumine that looks_like_num
-                  didn't lie about a - sign */
-               while (isSPACE(*num_begin))
-                   num_begin++;
-               if (*num_begin == '-')
-                   num_begin++;
-           }
+       } else if (SvTYPE(sv) < SVt_PVNV)
+           sv_upgrade(sv, SVt_PVNV);
 
-           /* Is it an integer that we could convert with strtoul?
-              So try it, and if it doesn't set errno then it's pukka.
-              This should be faster than going atof and then thinking.  */
-           if (((numtype & (IS_NUMBER_TO_INT_BY_STRTOL | IS_NUMBER_NOT_INT))
-                == IS_NUMBER_TO_INT_BY_STRTOL)
-               && ((errno = 0), 1) /* always true */
-               && ((u = Strtoul(num_begin, Null(char**), 10)), 1) /* ditto */
-               && (errno == 0)
-               /* If known to be negative, check it didn't undeflow IV
-                  XXX possibly we should put more negative values as NVs
-                  direct rather than go via atof below */
-               && ((numtype & IS_NUMBER_NEG) ? (u <= (UV)IV_MIN) : 1)) {
-               errno = save_errno;
-
-               if (SvTYPE(sv) < SVt_PVIV)
-                   sv_upgrade(sv, SVt_PVIV);
-               (void)SvIOK_on(sv);
-
-               /* If it's negative must use IV.
-                  IV-over-UV optimisation */
-               if (numtype & IS_NUMBER_NEG) {
-                   SvIVX(sv) = -(IV)u;
-               } else if (u <= (UV) IV_MAX) {
-                   SvIVX(sv) = (IV)u;
+       /* 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);
+
+           if (!(numtype & IS_NUMBER_NEG)) {
+               /* positive */;
+               if (value <= (UV)IV_MAX) {
+                   SvIVX(sv) = (IV)value;
                } else {
                    /* it didn't overflow, and it was positive. */
-                   SvUVX(sv) = u;
+                   SvUVX(sv) = value;
                    SvIsUV_on(sv);
                }
-           } else
-#endif
-           {
-               NV d;
-#ifdef HAS_STRTOUL
-               /* Hopefully trace flow will optimise this away where possible
-                */
-               errno = save_errno;
-#endif
-               /* It wasn't an integer, or it overflowed, or we don't have
-                  strtol. Do things the slow way - check if it's a IV etc. */
-               d = Atof(SvPVX(sv));
-
-               if (SvTYPE(sv) < SVt_PVNV)
-                   sv_upgrade(sv, SVt_PVNV);
-               SvNVX(sv) = d;
+           } else {
+               /* 2s complement assumption  */
+               if (value <= (UV)IV_MIN) {
+                   SvIVX(sv) = -(IV)value;
+               } else {
+                   /* Too negative for an IV.  This is a double upgrade, but
+                      I'm assuming it will be be rare.  */
+                   if (SvTYPE(sv) < SVt_PVNV)
+                       sv_upgrade(sv, SVt_PVNV);
+                   SvNOK_on(sv);
+                   SvIOK_off(sv);
+                   SvIOKp_on(sv);
+                   SvNVX(sv) = -(NV)value;
+                   SvIVX(sv) = IV_MIN;
+               }
+           }
+       }
+       
+       if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
+           != IS_NUMBER_IN_UV) {
+           /* It wasn't an integer, or it overflowed the UV. */
+           SvNVX(sv) = Atof(SvPVX(sv));
 
-               if (! numtype && ckWARN(WARN_NUMERIC))
+            if (! numtype && 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)));
+            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(%g)\n",
-                                     PTR2UV(sv), SvNVX(sv)));
+            DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%"UVxf" 2uv(%g)\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) {
-                   SvIVX(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 */
-                       SvUVX(sv) = UV_MAX;
-                       SvIsUV_on(sv);
-                   } else {
-                       SvUVX(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);
-                       }
-                   }
-               }
+            (void)SvIOKp_on(sv);
+            (void)SvNOK_on(sv);
+            if (SvNVX(sv) < (NV)IV_MAX + 0.5) {
+                SvIVX(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 */
+                    SvUVX(sv) = UV_MAX;
+                    SvIsUV_on(sv);
+                } else {
+                    SvUVX(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 (((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);
-                   SvIVX(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(SvNVX(sv))) < (UV)IV_MAX) but SvNVX(sv)=%g 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);
+            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);
+                    SvIVX(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(SvNVX(sv))) < (UV)IV_MAX) but SvNVX(sv)=%g 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 */
-           }
        }
     }
     else  {
@@ -2236,7 +2207,8 @@ Perl_sv_2nv(pTHX_ register SV *sv)
        if (SvNOKp(sv))
            return SvNVX(sv);
        if (SvPOKp(sv) && SvLEN(sv)) {
-           if (ckWARN(WARN_NUMERIC) && !SvIOKp(sv) && !looks_like_number(sv))
+           if (ckWARN(WARN_NUMERIC) && !SvIOKp(sv) &&
+               !grok_number(SvPVX(sv), SvCUR(sv), NULL))
                not_a_number(sv);
            return Atof(SvPVX(sv));
        }
@@ -2258,7 +2230,7 @@ Perl_sv_2nv(pTHX_ register SV *sv)
        if (SvROK(sv)) {
          SV* tmpstr;
           if (SvAMAGIC(sv) && (tmpstr=AMG_CALLun(sv,numer)) &&
-                  (SvRV(tmpstr) != SvRV(sv)))
+                (SvTYPE(tmpstr) != SVt_RV || (SvRV(tmpstr) != SvRV(sv))))
              return SvNV(tmpstr);
          return PTR2NV(SvRV(sv));
        }
@@ -2276,7 +2248,7 @@ Perl_sv_2nv(pTHX_ register SV *sv)
            sv_upgrade(sv, SVt_PVNV);
        else
            sv_upgrade(sv, SVt_NV);
-#if defined(USE_LONG_DOUBLE)
+#ifdef USE_LONG_DOUBLE
        DEBUG_c({
            STORE_NUMERIC_LOCAL_SET_STANDARD();
            PerlIO_printf(Perl_debug_log,
@@ -2295,9 +2267,10 @@ Perl_sv_2nv(pTHX_ register SV *sv)
     }
     else if (SvTYPE(sv) < SVt_PVNV)
        sv_upgrade(sv, SVt_PVNV);
-    if (SvIOKp(sv) &&
-           (!SvPOKp(sv) || !strchr(SvPVX(sv),'.') || !looks_like_number(sv)))
-    {
+    if (SvNOKp(sv) && !(SvIOK(sv) || SvPOK(sv))) {
+       SvNOK_on(sv);
+    }
+    else if (SvIOKp(sv)) {
        SvNVX(sv) = SvIsUV(sv) ? (NV)SvUVX(sv) : (NV)SvIVX(sv);
 #ifdef NV_PRESERVES_UV
        SvNOK_on(sv);
@@ -2312,12 +2285,20 @@ Perl_sv_2nv(pTHX_ register SV *sv)
 #endif
     }
     else if (SvPOKp(sv) && SvLEN(sv)) {
-       if (ckWARN(WARN_NUMERIC) && !SvIOKp(sv) && !looks_like_number(sv))
+       UV value;
+       int numtype = grok_number(SvPVX(sv), SvCUR(sv), &value);
+       if (ckWARN(WARN_NUMERIC) && !SvIOKp(sv) && !numtype)
            not_a_number(sv);
-       SvNVX(sv) = Atof(SvPVX(sv));
 #ifdef NV_PRESERVES_UV
+       if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
+           == IS_NUMBER_IN_UV) {
+           /* It's defintately an integer */
+           SvNVX(sv) = (numtype & IS_NUMBER_NEG) ? -(NV)value : (NV)value;
+       } else
+           SvNVX(sv) = Atof(SvPVX(sv));
        SvNOK_on(sv);
 #else
+       SvNVX(sv) = Atof(SvPVX(sv));
        /* Only set the public NV OK flag if this NV preserves the value in
           the PV at least as well as an IV/UV would.
           Not sure how to do this 100% reliably. */
@@ -2325,25 +2306,66 @@ Perl_sv_2nv(pTHX_ register SV *sv)
           wonky. We shouldn't be in here with NV_PRESERVES_UV_BITS ==
           UV_BITS */
        if (((UV)1 << NV_PRESERVES_UV_BITS) >
-           U_V(SvNVX(sv) > 0 ? SvNVX(sv) : -SvNVX(sv)))
+           U_V(SvNVX(sv) > 0 ? SvNVX(sv) : -SvNVX(sv))) {
            SvNOK_on(sv); /* Definitely small enough to preserve all bits */
-       else if (SvNVX(sv) < (NV)IV_MIN || SvNVX(sv) > (NV)UV_MAX) {
-               /* Definitely too large/small to fit in an integer, so no loss
-                  of precision going to integer in the future via NV */
-           SvNOK_on(sv);
-       } else {
-           /* Is it something we can run through strtol etc (ie no
-              trailing exponent part)? */
-           int numtype = looks_like_number(sv);
-           /* XXX probably should cache this if called above */
-
-           if (!(numtype &
-                 (IS_NUMBER_TO_INT_BY_ATOL | IS_NUMBER_TO_INT_BY_STRTOL))) {
-               /* Can't use strtol etc to convert this string, so don't try */
-               SvNOK_on(sv);
-           } else
-               sv_2inuv_non_preserve (sv, numtype);
-       }
+       } else if (!(numtype & IS_NUMBER_IN_UV)) {
+            /* Can't use strtol etc to convert this string, so don't try.
+               sv_2iv and sv_2uv will use the NV to convert, not the PV.  */
+            SvNOK_on(sv);
+        } else {
+            /* value has been set.  It may not be precise.  */
+           if ((numtype & IS_NUMBER_NEG) && (value > (UV)IV_MIN)) {
+               /* 2s complement assumption for (UV)IV_MIN  */
+                SvNOK_on(sv); /* Integer is too negative.  */
+            } else {
+                SvNOKp_on(sv);
+                SvIOKp_on(sv);
+
+                if (numtype & IS_NUMBER_NEG) {
+                    SvIVX(sv) = -(IV)value;
+                } else if (value <= (UV)IV_MAX) {
+                   SvIVX(sv) = (IV)value;
+               } else {
+                   SvUVX(sv) = value;
+                   SvIsUV_on(sv);
+               }
+
+                if (numtype & IS_NUMBER_NOT_INT) {
+                    /* I believe that even if the original PV had decimals,
+                       they are lost beyond the limit of the FP precision.
+                       However, neither is canonical, so both only get p
+                       flags.  NWC, 2000/11/25 */
+                    /* Both already have p flags, so do nothing */
+                } else {
+                    NV nv = SvNVX(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.  */
+                        }
+                    } else {
+                        /* between IV_MAX and NV(UV_MAX).
+                           Could be slightly > UV_MAX */
+
+                        if (numtype & IS_NUMBER_NOT_INT) {
+                            /* UV and NV both imprecise.  */
+                        } else {
+                            UV nv_as_uv = U_V(nv);
+
+                            if (value == nv_as_uv && SvUVX(sv) != UV_MAX) {
+                                SvNOK_on(sv);
+                                SvIOK_on(sv);
+                            } else {
+                                SvIOK_on(sv);
+                            }
+                        }
+                    }
+                }
+            }
+        }
 #endif /* NV_PRESERVES_UV */
     }
     else  {
@@ -2374,31 +2396,43 @@ Perl_sv_2nv(pTHX_ register SV *sv)
     return SvNVX(sv);
 }
 
+/* Caller must validate PVX  */
 STATIC IV
 S_asIV(pTHX_ SV *sv)
 {
-    I32 numtype = looks_like_number(sv);
-    NV d;
+    UV value;
+    int numtype = grok_number(SvPVX(sv), SvCUR(sv), &value);
 
-    if (numtype & IS_NUMBER_TO_INT_BY_ATOL)
-       return Atol(SvPVX(sv));
+    if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
+       == IS_NUMBER_IN_UV) {
+       /* It's defintately 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);
     }
-    d = Atof(SvPVX(sv));
-    return I_V(d);
+    return I_V(Atof(SvPVX(sv)));
 }
 
 STATIC UV
 S_asUV(pTHX_ SV *sv)
 {
-    I32 numtype = looks_like_number(sv);
+    UV value;
+    int numtype = grok_number(SvPVX(sv), SvCUR(sv), &value);
 
-#ifdef HAS_STRTOUL
-    if (numtype & IS_NUMBER_TO_INT_BY_ATOL)
-       return Strtoul(SvPVX(sv), Null(char**), 10);
-#endif
+    if ((numtype & (IS_NUMBER_IN_UV | IS_NUMBER_NOT_INT))
+       == IS_NUMBER_IN_UV) {
+       /* It's defintately an integer */
+       if (!(numtype & IS_NUMBER_NEG))
+           return value;
+    }
     if (!numtype) {
        if (ckWARN(WARN_NUMERIC))
            not_a_number(sv);
@@ -2406,183 +2440,6 @@ S_asUV(pTHX_ SV *sv)
     return U_V(Atof(SvPVX(sv)));
 }
 
-/*
- * Returns a combination of (advisory only - can get false negatives)
- * IS_NUMBER_TO_INT_BY_ATOL, IS_NUMBER_TO_INT_BY_ATOF
- * IS_NUMBER_LONGER_THAN_IV_MAX, IS_NUMBER_AS_LONG_AS_IV_MAX
- * IS_NUMBER_NOT_INT, IS_NUMBER_NEG, IS_NUMBER_INFINITY
- * 0 if does not look like number.
- *
- * (atol and strtol stop when they hit a decimal point. strtol will return
- * LONG_MAX and LONG_MIN when given out of range values. ANSI says they should
- * do this, and vendors have had 11 years to get it right.
- * However, will try to make it still work with only atol
- *
- * IS_NUMBER_TO_INT_BY_ATOL    123456789 or 123456789.3  definitely < IV_MAX
- * IS_NUMBER_TO_INT_BY_STRTOL  123456789 or 123456789.3  if digits = IV_MAX
- * IS_NUMBER_TO_INT_BY_ATOF    123456789e0               or >> IV_MAX
- * IS_NUMBER_LONGER_THAN_IV_MAX          lots of digits, don't bother with atol
- * IS_NUMBER_AS_LONG_AS_IV_MAX   atol might hit LONG_MAX, might not.
- * IS_NUMBER_NOT_INT           saw "." or "e"
- * IS_NUMBER_NEG
- * IS_NUMBER_INFINITY
- */
-
-/*
-=for apidoc looks_like_number
-
-Test if an the content of an SV looks like a number (or is a
-number). C<Inf> and C<Infinity> are treated as numbers (so will not
-issue a non-numeric warning), even if your atof() doesn't grok them.
-
-=cut
-*/
-
-I32
-Perl_looks_like_number(pTHX_ SV *sv)
-{
-    register char *s;
-    register char *send;
-    register char *sbegin;
-    register char *nbegin;
-    I32 numtype = 0;
-    I32 sawinf  = 0;
-    STRLEN len;
-
-    if (SvPOK(sv)) {
-       sbegin = SvPVX(sv);
-       len = SvCUR(sv);
-    }
-    else if (SvPOKp(sv))
-       sbegin = SvPV(sv, len);
-    else
-       return 1;
-    send = sbegin + len;
-
-    s = sbegin;
-    while (isSPACE(*s))
-       s++;
-    if (*s == '-') {
-       s++;
-       numtype = IS_NUMBER_NEG;
-    }
-    else if (*s == '+')
-       s++;
-
-    nbegin = s;
-    /*
-     * we return IS_NUMBER_TO_INT_BY_ATOL if the number can converted to
-     * integer with atol() without overflow, IS_NUMBER_TO_INT_BY_STRTOL if
-     * possibly slightly larger than max int, IS_NUMBER_TO_INT_BY_ATOF if you
-     * will need (int)atof().
-     */
-
-    /* next must be digit or the radix separator or beginning of infinity */
-    if (isDIGIT(*s)) {
-        do {
-           s++;
-        } while (isDIGIT(*s));
-
-       /* Aaargh. long long really is irritating.
-          In the gospel according to ANSI 1989, it is an axiom that "long"
-          is the longest integer type, and that if you don't know how long
-          something is you can cast it to long, and nothing will be lost
-          (except possibly speed of execution if long is slower than the
-          type is was).
-          Now, one can't be sure if the old rules apply, or long long
-          (or some other newfangled thing) is actually longer than the
-          (formerly) longest thing.
-       */
-       /* This lot will work for 64 bit  *as long as* either
-          either long is 64 bit
-          or     we can find both strtol/strtoq and strtoul/strtouq
-          If not, we really should refuse to let the user use 64 bit IVs
-          By "64 bit" I really mean IVs that don't get preserved by NVs
-          It also should work for 128 bit IVs. Can any lend me a machine to
-          test this?
-       */
-       if (s - nbegin > TYPE_DIGITS(UV)) /* Cannot cache ato[ul]() */
-           numtype |= IS_NUMBER_TO_INT_BY_ATOF | IS_NUMBER_LONGER_THAN_IV_MAX;
-       else if (s - nbegin < BIT_DIGITS(((sizeof (IV)>sizeof (long))
-                                         ? sizeof(long) : sizeof (IV))*8-1))
-           numtype |= IS_NUMBER_TO_INT_BY_ATOL;
-       else
-           /* Can't be sure either way. (For 64 bit UV, 63 bit IV is 1 decimal
-              digit less (IV_MAX=  9223372036854775807,
-                          UV_MAX= 18446744073709551615) so be cautious  */
-           numtype |= IS_NUMBER_TO_INT_BY_STRTOL | IS_NUMBER_AS_LONG_AS_IV_MAX;
-
-        if (*s == '.'
-#ifdef USE_LOCALE_NUMERIC
-           || IS_NUMERIC_RADIX(*s)
-#endif
-           ) {
-           s++;
-           numtype |= IS_NUMBER_NOT_INT;
-            while (isDIGIT(*s))  /* optional digits after the radix */
-                s++;
-        }
-    }
-    else if (*s == '.'
-#ifdef USE_LOCALE_NUMERIC
-           || IS_NUMERIC_RADIX(*s)
-#endif
-           ) {
-        s++;
-       numtype |= IS_NUMBER_TO_INT_BY_ATOL | IS_NUMBER_NOT_INT;
-        /* no digits before the radix means we need digits after it */
-        if (isDIGIT(*s)) {
-           do {
-               s++;
-            } while (isDIGIT(*s));
-        }
-        else
-           return 0;
-    }
-    else if (*s == 'I' || *s == 'i') {
-       s++; if (*s != 'N' && *s != 'n') return 0;
-       s++; if (*s != 'F' && *s != 'f') return 0;
-       s++; if (*s == 'I' || *s == 'i') {
-           s++; if (*s != 'N' && *s != 'n') return 0;
-           s++; if (*s != 'I' && *s != 'i') return 0;
-           s++; if (*s != 'T' && *s != 't') return 0;
-           s++; if (*s != 'Y' && *s != 'y') return 0;
-           s++;
-       }
-       sawinf = 1;
-    }
-    else
-        return 0;
-
-    if (sawinf)
-       numtype = (numtype & IS_NUMBER_NEG) /* Keep track of sign  */
-         | IS_NUMBER_INFINITY | IS_NUMBER_NOT_INT;
-    else {
-       /* we can have an optional exponent part */
-       if (*s == 'e' || *s == 'E') {
-           numtype &= IS_NUMBER_NEG;
-           numtype |= IS_NUMBER_TO_INT_BY_ATOF | IS_NUMBER_NOT_INT;
-           s++;
-           if (*s == '+' || *s == '-')
-               s++;
-           if (isDIGIT(*s)) {
-               do {
-                   s++;
-               } while (isDIGIT(*s));
-           }
-           else
-               return 0;
-       }
-    }
-    while (isSPACE(*s))
-       s++;
-    if (s >= send)
-       return numtype;
-    if (len == 10 && memEQ(sbegin, "0 but true", 10))
-       return IS_NUMBER_TO_INT_BY_ATOL;
-    return 0;
-}
-
 char *
 Perl_sv_2pv_nolen(pTHX_ register SV *sv)
 {
@@ -2619,6 +2476,12 @@ uiv_2buf(char *buf, IV iv, UV uv, int is_uv, char **peob)
 char *
 Perl_sv_2pv(pTHX_ register SV *sv, STRLEN *lp)
 {
+    return sv_2pv_flags(sv, lp, SV_GMAGIC);
+}
+
+char *
+Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
+{
     register char *s;
     int olderrno;
     SV *tsv;
@@ -2630,7 +2493,8 @@ Perl_sv_2pv(pTHX_ register SV *sv, STRLEN *lp)
        return "";
     }
     if (SvGMAGICAL(sv)) {
-       mg_get(sv);
+       if (flags & SV_GMAGIC)
+           mg_get(sv);
        if (SvPOKp(sv)) {
            *lp = SvCUR(sv);
            return SvPVX(sv);
@@ -2661,7 +2525,7 @@ Perl_sv_2pv(pTHX_ register SV *sv, STRLEN *lp)
        if (SvROK(sv)) {
            SV* tmpstr;
             if (SvAMAGIC(sv) && (tmpstr=AMG_CALLun(sv,string)) &&
-                    (SvRV(tmpstr) != SvRV(sv)))
+                (SvTYPE(tmpstr) != SVt_RV || (SvRV(tmpstr) != SvRV(sv))))
                return SvPV(tmpstr,*lp);
            sv = (SV*)SvRV(sv);
            if (!sv)
@@ -2675,7 +2539,7 @@ Perl_sv_2pv(pTHX_ register SV *sv, STRLEN *lp)
                           (SVs_OBJECT|SVf_OK|SVs_GMG|SVs_SMG|SVs_RMG))
                          == (SVs_OBJECT|SVs_RMG))
                         && strEQ(s=HvNAME(SvSTASH(sv)), "Regexp")
-                        && (mg = mg_find(sv, 'r'))) {
+                        && (mg = mg_find(sv, PERL_MAGIC_qr))) {
                        regexp *re = (regexp *)mg->mg_obj;
 
                        if (!mg->mg_ptr) {
@@ -2871,7 +2735,8 @@ Perl_sv_2pvbyte_nolen(pTHX_ register SV *sv)
 char *
 Perl_sv_2pvbyte(pTHX_ register SV *sv, STRLEN *lp)
 {
-    return sv_2pv(sv,lp);
+    sv_utf8_downgrade(sv,0);
+    return SvPV(sv,*lp);
 }
 
 char *
@@ -2900,7 +2765,7 @@ Perl_sv_2bool(pTHX_ register SV *sv)
     if (SvROK(sv)) {
        SV* tmpsv;
         if (SvAMAGIC(sv) && (tmpsv=AMG_CALLun(sv,bool_)) &&
-                (SvRV(tmpsv) != SvRV(sv)))
+                (SvTYPE(tmpsv) != SVt_RV || (SvRV(tmpsv) != SvRV(sv))))
            return SvTRUE(tmpsv);
       return SvRV(sv) != 0;
     }
@@ -2930,45 +2795,80 @@ Perl_sv_2bool(pTHX_ register SV *sv)
 =for apidoc sv_utf8_upgrade
 
 Convert the PV of an SV to its UTF8-encoded form.
+Forces the SV to string form it it is not already.
+Always sets the SvUTF8 flag to avoid future validity checks even
+if all the bytes have hibit clear.
 
 =cut
 */
 
-void
+STRLEN
 Perl_sv_utf8_upgrade(pTHX_ register SV *sv)
 {
-    char *s, *t, *e;
+    return sv_utf8_upgrade_flags(sv, SV_GMAGIC);
+}
+
+/*
+=for apidoc sv_utf8_upgrade_flags
+
+Convert the PV of an SV to its UTF8-encoded form.
+Forces the SV to string form it it is not already.
+Always sets the SvUTF8 flag to avoid future validity checks even
+if all the bytes have hibit clear. If C<flags> has C<SV_GMAGIC> bit set,
+will C<mg_get> on C<sv> if appropriate, else not. C<sv_utf8_upgrade> and
+C<sv_utf8_upgrade_nomg> are implemented in terms of this function.
+
+=cut
+*/
+
+STRLEN
+Perl_sv_utf8_upgrade_flags(pTHX_ register SV *sv, I32 flags)
+{
+    U8 *s, *t, *e;
     int  hibit = 0;
 
-    if (!sv || !SvPOK(sv) || SvUTF8(sv))
-       return;
+    if (!sv)
+       return 0;
+
+    if (!SvPOK(sv)) {
+       STRLEN len = 0;
+       (void) sv_2pv_flags(sv,&len, flags);
+       if (!SvPOK(sv))
+            return len;
+    }
+
+    if (SvUTF8(sv))
+       return SvCUR(sv);
+
+    if (SvREADONLY(sv) && SvFAKE(sv)) {
+       sv_force_normal(sv);
+    }
 
     /* This function could be much more efficient if we had a FLAG in SVs
      * to signal if there are any hibit chars in the PV.
      * Given that there isn't make loop fast as possible
      */
-    s = SvPVX(sv);
-    e = SvEND(sv);
+    s = (U8 *) SvPVX(sv);
+    e = (U8 *) SvEND(sv);
     t = s;
     while (t < e) {
-       if ((hibit = UTF8_IS_CONTINUED(*t++)))
+       U8 ch = *t++;
+       if ((hibit = !NATIVE_IS_INVARIANT(ch)))
            break;
     }
-
     if (hibit) {
        STRLEN len;
-       if (SvREADONLY(sv) && SvFAKE(sv)) {
-           sv_force_normal(sv);
-           s = SvPVX(sv);
-       }
+
        len = SvCUR(sv) + 1; /* Plus the \0 */
        SvPVX(sv) = (char*)bytes_to_utf8((U8*)s, &len);
        SvCUR(sv) = len - 1;
        if (SvLEN(sv) != 0)
            Safefree(s); /* No longer using what was there before. */
        SvLEN(sv) = len; /* No longer know the real size. */
-       SvUTF8_on(sv);
     }
+    /* Mark as UTF-8 even if no hibit - saves scanning loop */
+    SvUTF8_on(sv);
+    return SvCUR(sv);
 }
 
 /*
@@ -2987,12 +2887,37 @@ Perl_sv_utf8_downgrade(pTHX_ register SV* sv, bool fail_ok)
 {
     if (SvPOK(sv) && SvUTF8(sv)) {
         if (SvCUR(sv)) {
-           char *c = SvPVX(sv);
-           STRLEN len = SvCUR(sv);
+           U8 *s;
+           STRLEN len;
 
-           if (!utf8_to_bytes((U8*)c, &len)) {
+           if (SvREADONLY(sv) && SvFAKE(sv))
+               sv_force_normal(sv);
+           s = (U8 *) SvPV(sv, len);
+           if (!utf8_to_bytes(s, &len)) {
                if (fail_ok)
                    return FALSE;
+#ifdef USE_BYTES_DOWNGRADES
+               else if (IN_BYTES) {
+                   U8 *d = s;
+                   U8 *e = (U8 *) SvEND(sv);
+                   int first = 1;
+                   while (s < e) {
+                       UV ch = utf8n_to_uvchr(s,(e-s),&len,0);
+                       if (first && ch > 255) {
+                           if (PL_op)
+                               Perl_warner(aTHX_ WARN_UTF8, "Wide character in byte %s",
+                                          PL_op_desc[PL_op->op_type]);
+                           else
+                               Perl_warner(aTHX_ WARN_UTF8, "Wide character in byte");
+                           first = 0;
+                       }
+                       *d++ = ch;
+                       s += len;
+                   }
+                   *d = '\0';
+                   len = (d - (U8 *) SvPVX(sv));
+               }
+#endif
                else {
                    if (PL_op)
                        Perl_croak(aTHX_ "Wide character in %s",
@@ -3003,9 +2928,8 @@ Perl_sv_utf8_downgrade(pTHX_ register SV* sv, bool fail_ok)
            }
            SvCUR(sv) = len;
        }
-       SvUTF8_off(sv);
     }
-
+    SvUTF8_off(sv);
     return TRUE;
 }
 
@@ -3013,7 +2937,8 @@ Perl_sv_utf8_downgrade(pTHX_ register SV* sv, bool fail_ok)
 =for apidoc sv_utf8_encode
 
 Convert the PV of an SV to UTF8-encoded, but then turn off the C<SvUTF8>
-flag so that it looks like bytes again. Nothing calls this.
+flag so that it looks like octets again. Used as a building block
+for encode_utf8 in Encode.xs
 
 =cut
 */
@@ -3021,29 +2946,43 @@ flag so that it looks like bytes again. Nothing calls this.
 void
 Perl_sv_utf8_encode(pTHX_ register SV *sv)
 {
-    sv_utf8_upgrade(sv);
+    (void) sv_utf8_upgrade(sv);
     SvUTF8_off(sv);
 }
 
+/*
+=for apidoc sv_utf8_decode
+
+Convert the octets in the PV from UTF-8 to chars. Scan for validity and then
+turn of SvUTF8 if needed so that we see characters. Used as a building block
+for decode_utf8 in Encode.xs
+
+=cut
+*/
+
+
+
 bool
 Perl_sv_utf8_decode(pTHX_ register SV *sv)
 {
     if (SvPOK(sv)) {
-        char *c;
-        char *e;
-        bool has_utf = FALSE;
+        U8 *c;
+        U8 *e;
+
+       /* The octets may have got themselves encoded - get them back as bytes */
         if (!sv_utf8_downgrade(sv, TRUE))
            return FALSE;
 
         /* it is actually just a matter of turning the utf8 flag on, but
          * we want to make sure everything inside is valid utf8 first.
          */
-        c = SvPVX(sv);
-       if (!is_utf8_string((U8*)c, SvCUR(sv)+1))
+        c = (U8 *) SvPVX(sv);
+       if (!is_utf8_string(c, SvCUR(sv)+1))
            return FALSE;
-        e = SvEND(sv);
+        e = (U8 *) SvEND(sv);
         while (c < e) {
-            if (UTF8_IS_CONTINUED(*c++)) {
+           U8 ch = *c++;
+            if (!UTF8_IS_INVARIANT(ch)) {
                SvUTF8_on(sv);
                break;
            }
@@ -3069,9 +3008,30 @@ C<sv_setsv_mg>.
 =cut
 */
 
+/* sv_setsv() is aliased to Perl_sv_setsv_macro; this function provided
+   for binary compatibility only
+*/
 void
 Perl_sv_setsv(pTHX_ SV *dstr, register SV *sstr)
 {
+    sv_setsv_flags(dstr, sstr, SV_GMAGIC);
+}
+
+/*
+=for apidoc sv_setsv_flags
+
+Copies the contents of the source SV C<ssv> into the destination SV C<dsv>.
+The source SV may be destroyed if it is mortal.  Does not handle 'set'
+magic.  If C<flags> has C<SV_GMAGIC> bit set, will C<mg_get> on C<ssv> if
+appropriate, else not. C<sv_setsv> and C<sv_setsv_nomg> are implemented
+in terms of this function.
+
+=cut
+*/
+
+void
+Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
+{
     register U32 sflags;
     register int dtype;
     register int stype;
@@ -3190,7 +3150,7 @@ Perl_sv_setsv(pTHX_ SV *dstr, register SV *sstr)
                char *name = GvNAME(sstr);
                STRLEN len = GvNAMELEN(sstr);
                sv_upgrade(dstr, SVt_PVGV);
-               sv_magic(dstr, dstr, '*', Nullch, 0);
+               sv_magic(dstr, dstr, PERL_MAGIC_glob, Nullch, 0);
                GvSTASH(dstr) = (HV*)SvREFCNT_inc(GvSTASH(sstr));
                GvNAME(dstr) = savepvn(name, len);
                GvNAMELEN(dstr) = len;
@@ -3201,6 +3161,13 @@ Perl_sv_setsv(pTHX_ SV *dstr, register SV *sstr)
                     && GvCV(dstr) && PL_sortcop == CvSTART(GvCV(dstr)))
                Perl_croak(aTHX_ "Can't redefine active sort subroutine %s",
                      GvNAME(dstr));
+
+#ifdef GV_SHARED_CHECK
+                if (GvSHARED((GV*)dstr)) {
+                    Perl_croak(aTHX_ PL_no_modify);
+                }
+#endif
+
            (void)SvOK_off(dstr);
            GvINTRO_off(dstr);          /* one-shot flag */
            gp_free((GV*)dstr);
@@ -3218,7 +3185,7 @@ Perl_sv_setsv(pTHX_ SV *dstr, register SV *sstr)
        /* FALL THROUGH */
 
     default:
-       if (SvGMAGICAL(sstr)) {
+       if (SvGMAGICAL(sstr) && (flags & SV_GMAGIC)) {
            mg_get(sstr);
            if (SvTYPE(sstr) != stype) {
                stype = SvTYPE(sstr);
@@ -3241,13 +3208,14 @@ Perl_sv_setsv(pTHX_ SV *dstr, register SV *sstr)
                SV *dref = 0;
                int intro = GvINTRO(dstr);
 
+#ifdef GV_SHARED_CHECK
+                if (GvSHARED((GV*)dstr)) {
+                    Perl_croak(aTHX_ PL_no_modify);
+                }
+#endif
+
                if (intro) {
-                   GP *gp;
-                   gp_free((GV*)dstr);
                    GvINTRO_off(dstr);  /* one-shot flag */
-                   Newz(602,gp, 1, GP);
-                   GvGP(dstr) = gp_ref(gp);
-                   GvSV(dstr) = NEWSV(72,0);
                    GvLINE(dstr) = CopLINE(PL_curcop);
                    GvEGV(dstr) = (GV*)dstr;
                }
@@ -3295,7 +3263,6 @@ Perl_sv_setsv(pTHX_ SV *dstr, register SV *sstr)
                            if (!GvCVGEN((GV*)dstr) &&
                                (CvROOT(cv) || CvXSUB(cv)))
                            {
-                               SV *const_sv;
                                /* ahem, death to those who redefine
                                 * active sort subs */
                                if (PL_curstackinfo->si_type == PERLSI_SORT &&
@@ -3462,8 +3429,8 @@ Perl_sv_setsv(pTHX_ SV *dstr, register SV *sstr)
        if (sflags & SVf_IOK)
            (void)SvIOK_only(dstr);
        else {
-           SvOK_off(dstr);
-           SvIOKp_on(dstr);
+           (void)SvOK_off(dstr);
+           (void)SvIOKp_on(dstr);
        }
        /* XXXX Do we want to set IsUV for IV(ROK)?  Be extra safe... */
        if (sflags & SVf_IVisUV)
@@ -3481,7 +3448,7 @@ Perl_sv_setsv(pTHX_ SV *dstr, register SV *sstr)
        if (sflags & SVf_NOK)
            (void)SvNOK_only(dstr);
        else {
-           SvOK_off(dstr);
+           (void)SvOK_off(dstr);
            SvNOKp_on(dstr);
        }
        SvNVX(dstr) = SvNVX(sstr);
@@ -3526,16 +3493,18 @@ void
 Perl_sv_setpvn(pTHX_ register SV *sv, register const char *ptr, register STRLEN len)
 {
     register char *dptr;
-    {
-        /* len is STRLEN which is unsigned, need to copy to signed */
-       IV iv = len;
-       assert(iv >= 0);
-    }
+
     SV_CHECK_THINKFIRST(sv);
     if (!ptr) {
        (void)SvOK_off(sv);
        return;
     }
+    else {
+        /* len is STRLEN which is unsigned, need to copy to signed */
+       IV iv = len;
+       if (iv < 0)
+           Perl_croak(aTHX_ "panic: sv_setpvn called with negative strlen");
+    }
     (void)SvUPGRADE(sv, SVt_PV);
 
     SvGROW(sv, len + 1);
@@ -3733,27 +3702,50 @@ Perl_sv_chop(pTHX_ register SV *sv, register char *ptr) /* like set but assuming
 =for apidoc sv_catpvn
 
 Concatenates the string onto the end of the string which is in the SV.  The
-C<len> indicates number of bytes to copy.  Handles 'get' magic, but not
-'set' magic.  See C<sv_catpvn_mg>.
+C<len> indicates number of bytes to copy.  If the SV has the UTF8
+status set, then the bytes appended should be valid UTF8.
+Handles 'get' magic, but not 'set' magic.  See C<sv_catpvn_mg>.
 
 =cut
 */
 
+/* sv_catpvn() is aliased to Perl_sv_catpvn_macro; this function provided
+   for binary compatibility only
+*/
 void
-Perl_sv_catpvn(pTHX_ register SV *sv, register const char *ptr, register STRLEN len)
+Perl_sv_catpvn(pTHX_ SV *dsv, const char* sstr, STRLEN slen)
 {
-    STRLEN tlen;
-    char *junk;
+    sv_catpvn_flags(dsv, sstr, slen, SV_GMAGIC);
+}
 
-    junk = SvPV_force(sv, tlen);
-    SvGROW(sv, tlen + len + 1);
-    if (ptr == junk)
-       ptr = SvPVX(sv);
-    Move(ptr,SvPVX(sv)+tlen,len,char);
-    SvCUR(sv) += len;
-    *SvEND(sv) = '\0';
-    (void)SvPOK_only_UTF8(sv);         /* validate pointer */
-    SvTAINT(sv);
+/*
+=for apidoc sv_catpvn_flags
+
+Concatenates the string onto the end of the string which is in the SV.  The
+C<len> indicates number of bytes to copy.  If the SV has the UTF8
+status set, then the bytes appended should be valid UTF8.
+If C<flags> has C<SV_GMAGIC> bit set, will C<mg_get> on C<dsv> if
+appropriate, else not. C<sv_catpvn> and C<sv_catpvn_nomg> are implemented
+in terms of this function.
+
+=cut
+*/
+
+void
+Perl_sv_catpvn_flags(pTHX_ register SV *dsv, register const char *sstr, register STRLEN slen, I32 flags)
+{
+    STRLEN dlen;
+    char *dstr;
+
+    dstr = SvPV_force_flags(dsv, dlen, flags);
+    SvGROW(dsv, dlen + slen + 1);
+    if (sstr == dstr)
+       sstr = SvPVX(dsv);
+    Move(sstr, SvPVX(dsv) + dlen, slen, char);
+    SvCUR(dsv) += slen;
+    *SvEND(dsv) = '\0';
+    (void)SvPOK_only_UTF8(dsv);                /* validate pointer */
+    SvTAINT(dsv);
 }
 
 /*
@@ -3780,36 +3772,52 @@ not 'set' magic.  See C<sv_catsv_mg>.
 
 =cut */
 
+/* sv_catsv() is aliased to Perl_sv_catsv_macro; this function provided
+   for binary compatibility only
+*/
+void
+Perl_sv_catsv(pTHX_ SV *dstr, register SV *sstr)
+{
+    sv_catsv_flags(dstr, sstr, SV_GMAGIC);
+}
+
+/*
+=for apidoc sv_catsv_flags
+
+Concatenates the string from SV C<ssv> onto the end of the string in
+SV C<dsv>.  Modifies C<dsv> but not C<ssv>.  If C<flags> has C<SV_GMAGIC>
+bit set, will C<mg_get> on the SVs if appropriate, else not. C<sv_catsv>
+and C<sv_catsv_nomg> are implemented in terms of this function.
+
+=cut */
+
 void
-Perl_sv_catsv(pTHX_ SV *dsv, register SV *ssv)
+Perl_sv_catsv_flags(pTHX_ SV *dsv, register SV *ssv, I32 flags)
 {
     char *spv;
     STRLEN slen;
     if (!ssv)
        return;
     if ((spv = SvPV(ssv, slen))) {
-       bool dutf8 = DO_UTF8(dsv);
        bool sutf8 = DO_UTF8(ssv);
+       bool dutf8;
 
-       if (dutf8 == sutf8)
-           sv_catpvn(dsv,spv,slen);
-       else {
+       if (SvGMAGICAL(dsv) && (flags & SV_GMAGIC))
+           mg_get(dsv);
+       dutf8 = DO_UTF8(dsv);
+
+       if (dutf8 != sutf8) {
            if (dutf8) {
                /* Not modifying source SV, so taking a temporary copy. */
-               SV* csv = sv_2mortal(newSVsv(ssv));
-               char *cpv;
-               STRLEN clen;
+               SV* csv = sv_2mortal(newSVpvn(spv, slen));
 
                sv_utf8_upgrade(csv);
-               cpv = SvPV(csv,clen);
-               sv_catpvn(dsv,cpv,clen);
-           }
-           else {
-               sv_utf8_upgrade(dsv);
-               sv_catpvn(dsv,spv,slen);
-               SvUTF8_on(dsv); /* If dsv has no wide characters. */
+               spv = SvPV(csv, slen);
            }
+           else
+               sv_utf8_upgrade_nomg(dsv);
        }
+       sv_catpvn_nomg(dsv, spv, slen);
     }
 }
 
@@ -3832,10 +3840,10 @@ Perl_sv_catsv_mg(pTHX_ SV *dsv, register SV *ssv)
 =for apidoc sv_catpv
 
 Concatenates the string onto the end of the string which is in the SV.
-Handles 'get' magic, but not 'set' magic.  See C<sv_catpv_mg>.
+If the SV has the UTF8 status set, then the bytes appended should be
+valid UTF8.  Handles 'get' magic, but not 'set' magic.  See C<sv_catpv_mg>.
 
-=cut
-*/
+=cut */
 
 void
 Perl_sv_catpv(pTHX_ register SV *sv, register const char *ptr)
@@ -3901,12 +3909,23 @@ Perl_sv_magic(pTHX_ register SV *sv, SV *obj, int how, const char *name, I32 nam
     MAGIC* mg;
 
     if (SvREADONLY(sv)) {
-       if (PL_curcop != &PL_compiling && !strchr("gBf", how))
+       if (PL_curcop != &PL_compiling
+           /* XXX this used to be !strchr("gBf", how), which seems to
+            * implicity be equal to !strchr("gBf\0", how), ie \0 matches
+            * too. I find this suprising, but have hadded PERL_MAGIC_sv
+            * to the list of things to check - DAPM 19-May-01 */
+           && how != PERL_MAGIC_regex_global
+           && how != PERL_MAGIC_bm
+           && how != PERL_MAGIC_fm
+           && how != PERL_MAGIC_sv
+          )
+       {
            Perl_croak(aTHX_ PL_no_modify);
+       }
     }
-    if (SvMAGICAL(sv) || (how == 't' && SvTYPE(sv) >= SVt_PVMG)) {
+    if (SvMAGICAL(sv) || (how == PERL_MAGIC_taint && SvTYPE(sv) >= SVt_PVMG)) {
        if (SvMAGIC(sv) && (mg = mg_find(sv, how))) {
-           if (how == 't')
+           if (how == PERL_MAGIC_taint)
                mg->mg_len |= 1;
            return;
        }
@@ -3916,134 +3935,148 @@ Perl_sv_magic(pTHX_ register SV *sv, SV *obj, int how, const char *name, I32 nam
     }
     Newz(702,mg, 1, MAGIC);
     mg->mg_moremagic = SvMAGIC(sv);
-
     SvMAGIC(sv) = mg;
-    if (!obj || obj == sv || how == '#' || how == 'r')
+
+    /* Some magic sontains a reference loop, where the sv and object refer to
+       each other.  To prevent a avoid a reference loop that would prevent such
+       objects being freed, we look for such loops and if we find one we avoid
+       incrementing the object refcount. */
+    if (!obj || obj == sv ||
+       how == PERL_MAGIC_arylen ||
+       how == PERL_MAGIC_qr ||
+       (SvTYPE(obj) == SVt_PVGV &&
+           (GvSV(obj) == sv || GvHV(obj) == (HV*)sv || GvAV(obj) == (AV*)sv ||
+           GvCV(obj) == (CV*)sv || GvIOp(obj) == (IO*)sv ||
+           GvFORM(obj) == (CV*)sv)))
+    {
        mg->mg_obj = obj;
+    }
     else {
        mg->mg_obj = SvREFCNT_inc(obj);
        mg->mg_flags |= MGf_REFCOUNTED;
     }
     mg->mg_type = how;
     mg->mg_len = namlen;
-    if (name)
+    if (name) {
        if (namlen >= 0)
            mg->mg_ptr = savepvn(name, namlen);
        else if (namlen == HEf_SVKEY)
            mg->mg_ptr = (char*)SvREFCNT_inc((SV*)name);
+    }
 
     switch (how) {
-    case 0:
+    case PERL_MAGIC_sv:
        mg->mg_virtual = &PL_vtbl_sv;
        break;
-    case 'A':
+    case PERL_MAGIC_overload:
         mg->mg_virtual = &PL_vtbl_amagic;
         break;
-    case 'a':
+    case PERL_MAGIC_overload_elem:
         mg->mg_virtual = &PL_vtbl_amagicelem;
         break;
-    case 'c':
+    case PERL_MAGIC_overload_table:
         mg->mg_virtual = &PL_vtbl_ovrld;
         break;
-    case 'B':
+    case PERL_MAGIC_bm:
        mg->mg_virtual = &PL_vtbl_bm;
        break;
-    case 'D':
+    case PERL_MAGIC_regdata:
        mg->mg_virtual = &PL_vtbl_regdata;
        break;
-    case 'd':
+    case PERL_MAGIC_regdatum:
        mg->mg_virtual = &PL_vtbl_regdatum;
        break;
-    case 'E':
+    case PERL_MAGIC_env:
        mg->mg_virtual = &PL_vtbl_env;
        break;
-    case 'f':
+    case PERL_MAGIC_fm:
        mg->mg_virtual = &PL_vtbl_fm;
        break;
-    case 'e':
+    case PERL_MAGIC_envelem:
        mg->mg_virtual = &PL_vtbl_envelem;
        break;
-    case 'g':
+    case PERL_MAGIC_regex_global:
        mg->mg_virtual = &PL_vtbl_mglob;
        break;
-    case 'I':
+    case PERL_MAGIC_isa:
        mg->mg_virtual = &PL_vtbl_isa;
        break;
-    case 'i':
+    case PERL_MAGIC_isaelem:
        mg->mg_virtual = &PL_vtbl_isaelem;
        break;
-    case 'k':
+    case PERL_MAGIC_nkeys:
        mg->mg_virtual = &PL_vtbl_nkeys;
        break;
-    case 'L':
+    case PERL_MAGIC_dbfile:
        SvRMAGICAL_on(sv);
        mg->mg_virtual = 0;
        break;
-    case 'l':
+    case PERL_MAGIC_dbline:
        mg->mg_virtual = &PL_vtbl_dbline;
        break;
 #ifdef USE_THREADS
-    case 'm':
+    case PERL_MAGIC_mutex:
        mg->mg_virtual = &PL_vtbl_mutex;
        break;
 #endif /* USE_THREADS */
 #ifdef USE_LOCALE_COLLATE
-    case 'o':
+    case PERL_MAGIC_collxfrm:
         mg->mg_virtual = &PL_vtbl_collxfrm;
         break;
 #endif /* USE_LOCALE_COLLATE */
-    case 'P':
+    case PERL_MAGIC_tied:
        mg->mg_virtual = &PL_vtbl_pack;
        break;
-    case 'p':
-    case 'q':
+    case PERL_MAGIC_tiedelem:
+    case PERL_MAGIC_tiedscalar:
        mg->mg_virtual = &PL_vtbl_packelem;
        break;
-    case 'r':
+    case PERL_MAGIC_qr:
        mg->mg_virtual = &PL_vtbl_regexp;
        break;
-    case 'S':
+    case PERL_MAGIC_sig:
        mg->mg_virtual = &PL_vtbl_sig;
        break;
-    case 's':
+    case PERL_MAGIC_sigelem:
        mg->mg_virtual = &PL_vtbl_sigelem;
        break;
-    case 't':
+    case PERL_MAGIC_taint:
        mg->mg_virtual = &PL_vtbl_taint;
        mg->mg_len = 1;
        break;
-    case 'U':
+    case PERL_MAGIC_uvar:
        mg->mg_virtual = &PL_vtbl_uvar;
        break;
-    case 'v':
+    case PERL_MAGIC_vec:
        mg->mg_virtual = &PL_vtbl_vec;
        break;
-    case 'x':
+    case PERL_MAGIC_substr:
        mg->mg_virtual = &PL_vtbl_substr;
        break;
-    case 'y':
+    case PERL_MAGIC_defelem:
        mg->mg_virtual = &PL_vtbl_defelem;
        break;
-    case '*':
+    case PERL_MAGIC_glob:
        mg->mg_virtual = &PL_vtbl_glob;
        break;
-    case '#':
+    case PERL_MAGIC_arylen:
        mg->mg_virtual = &PL_vtbl_arylen;
        break;
-    case '.':
+    case PERL_MAGIC_pos:
        mg->mg_virtual = &PL_vtbl_pos;
        break;
-    case '<':
+    case PERL_MAGIC_backref:
        mg->mg_virtual = &PL_vtbl_backref;
        break;
-    case '~':  /* Reserved for use by extensions not perl internals.   */
+    case PERL_MAGIC_ext:
+       /* Reserved for use by extensions not perl internals.           */
        /* Useful for attaching extension internal data to perl vars.   */
        /* Note that multiple extensions may clash if magical scalars   */
        /* etc holding private data from one are passed to another.     */
        SvRMAGICAL_on(sv);
        break;
     default:
-       Perl_croak(aTHX_ "Don't know how to handle magic of type '%c'", how);
+       Perl_croak(aTHX_ "Don't know how to handle magic of type \\%o", how);
     }
     mg_magical(sv);
     if (SvGMAGICAL(sv))
@@ -4072,11 +4105,12 @@ Perl_sv_unmagic(pTHX_ SV *sv, int type)
            *mgp = mg->mg_moremagic;
            if (vtbl && vtbl->svt_free)
                CALL_FPTR(vtbl->svt_free)(aTHX_ sv, mg);
-           if (mg->mg_ptr && mg->mg_type != 'g')
+           if (mg->mg_ptr && mg->mg_type != PERL_MAGIC_regex_global) {
                if (mg->mg_len >= 0)
                    Safefree(mg->mg_ptr);
                else if (mg->mg_len == HEf_SVKEY)
                    SvREFCNT_dec((SV*)mg->mg_ptr);
+            }
            if (mg->mg_flags & MGf_REFCOUNTED)
                SvREFCNT_dec(mg->mg_obj);
            Safefree(mg);
@@ -4086,7 +4120,7 @@ Perl_sv_unmagic(pTHX_ SV *sv, int type)
     }
     if (!SvMAGIC(sv)) {
        SvMAGICAL_off(sv);
-       SvFLAGS(sv) |= (SvFLAGS(sv) & (SVp_IOK|SVp_NOK|SVp_POK)) >> PRIVSHIFT;
+       SvFLAGS(sv) |= (SvFLAGS(sv) & (SVp_NOK|SVp_POK)) >> PRIVSHIFT;
     }
 
     return 0;
@@ -4125,11 +4159,11 @@ S_sv_add_backref(pTHX_ SV *tsv, SV *sv)
 {
     AV *av;
     MAGIC *mg;
-    if (SvMAGICAL(tsv) && (mg = mg_find(tsv, '<')))
+    if (SvMAGICAL(tsv) && (mg = mg_find(tsv, PERL_MAGIC_backref)))
        av = (AV*)mg->mg_obj;
     else {
        av = newAV();
-       sv_magic(tsv, (SV*)av, '<', NULL, 0);
+       sv_magic(tsv, (SV*)av, PERL_MAGIC_backref, NULL, 0);
        SvREFCNT_dec(av);           /* for sv_magic */
     }
     av_push(av,sv);
@@ -4143,7 +4177,7 @@ S_sv_del_backref(pTHX_ SV *sv)
     I32 i;
     SV *tsv = SvRV(sv);
     MAGIC *mg;
-    if (!SvMAGICAL(tsv) || !(mg = mg_find(tsv, '<')))
+    if (!SvMAGICAL(tsv) || !(mg = mg_find(tsv, PERL_MAGIC_backref)))
        Perl_croak(aTHX_ "panic: del_backref");
     av = (AV *)mg->mg_obj;
     svp = AvARRAY(av);
@@ -4302,7 +4336,7 @@ Perl_sv_clear(pTHX_ register SV *sv)
 
     if (SvOBJECT(sv)) {
        if (PL_defstash) {              /* Still have a symbol table? */
-           djSP;
+           dSP;
            CV* destructor;
            SV tmpref;
 
@@ -4349,8 +4383,12 @@ Perl_sv_clear(pTHX_ register SV *sv)
                --PL_sv_objcount;       /* XXX Might want something more general */
        }
     }
-    if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv))
-       mg_free(sv);
+    if (SvTYPE(sv) >= SVt_PVMG) {
+       if (SvMAGIC(sv))
+           mg_free(sv);
+       if (SvFLAGS(sv) & SVpad_TYPED)
+           SvREFCNT_dec(SvSTASH(sv));
+    }
     stash = NULL;
     switch (SvTYPE(sv)) {
     case SVt_PVIO:
@@ -4637,8 +4675,9 @@ Perl_sv_pos_b2u(pTHX_ register SV *sv, I32* offsetp)
     len = 0;
     while (s < send) {
        STRLEN n;
-
-       if (utf8_to_uv(s, UTF8SKIP(s), &n, 0)) {
+       /* Call utf8n_to_uvchr() to validate the sequence */
+       utf8n_to_uvchr(s, UTF8SKIP(s), &n, 0);
+       if (n > 0) {
            s += n;
            len++;
        }
@@ -4666,8 +4705,7 @@ Perl_sv_eq(pTHX_ register SV *sv1, register SV *sv2)
     char *pv2;
     STRLEN cur2;
     I32  eq     = 0;
-    bool pv1tmp = FALSE;
-    bool pv2tmp = FALSE;
+    char *tpv   = Nullch;
 
     if (!sv1) {
        pv1 = "";
@@ -4684,41 +4722,35 @@ Perl_sv_eq(pTHX_ register SV *sv1, register SV *sv2)
        pv2 = SvPV(sv2, cur2);
 
     /* do not utf8ize the comparands as a side-effect */
-    if (cur1 && cur2 && SvUTF8(sv1) != SvUTF8(sv2) && !IN_BYTE) {
+    if (cur1 && cur2 && SvUTF8(sv1) != SvUTF8(sv2) && !IN_BYTES) {
+       bool is_utf8 = TRUE;
+        /* UTF-8ness differs */
        if (PL_hints & HINT_UTF8_DISTINCT)
            return FALSE;
 
        if (SvUTF8(sv1)) {
-           (void)utf8_to_bytes((U8*)(pv1 = savepvn(pv1, cur1)), &cur1);
-           {
-               IV scur1 = cur1;
-               if (scur1 < 0) {
-                   Safefree(pv1);
-                   return 0;
-               }
-           }
-           pv1tmp = TRUE;
+           /* sv1 is the UTF-8 one , If is equal it must be downgrade-able */
+           char *pv = (char*)bytes_from_utf8((U8*)pv1, &cur1, &is_utf8);
+           if (pv != pv1)
+               pv1 = tpv = pv;
        }
        else {
-           (void)utf8_to_bytes((U8*)(pv2 = savepvn(pv2, cur2)), &cur2);
-           {
-               IV scur2 = cur2;
-               if (scur2 < 0) {
-                   Safefree(pv2);
-                   return 0;
-               }
-           }
-           pv2tmp = TRUE;
+           /* sv2 is the UTF-8 one , If is equal it must be downgrade-able */
+           char *pv = (char *)bytes_from_utf8((U8*)pv2, &cur2, &is_utf8);
+           if (pv != pv2)
+               pv2 = tpv = pv;
+       }
+       if (is_utf8) {
+           /* Downgrade not possible - cannot be eq */
+           return FALSE;
        }
     }
 
     if (cur1 == cur2)
        eq = memEQ(pv1, pv2, cur1);
        
-    if (pv1tmp)
-       Safefree(pv1);
-    if (pv2tmp)
-       Safefree(pv2);
+    if (tpv != Nullch)
+       Safefree(tpv);
 
     return eq;
 }
@@ -4757,7 +4789,7 @@ Perl_sv_cmp(pTHX_ register SV *sv1, register SV *sv2)
        pv2 = SvPV(sv2, cur2);
 
     /* do not utf8ize the comparands as a side-effect */
-    if (cur1 && cur2 && SvUTF8(sv1) != SvUTF8(sv2) && !IN_BYTE) {
+    if (cur1 && cur2 && SvUTF8(sv1) != SvUTF8(sv2) && !IN_BYTES) {
        if (PL_hints & HINT_UTF8_DISTINCT)
            return SvUTF8(sv1) ? 1 : -1;
 
@@ -4854,7 +4886,7 @@ Perl_sv_cmp_locale(pTHX_ register SV *sv1, register SV *sv2)
 
 #ifdef USE_LOCALE_COLLATE
 /*
- * Any scalar variable may carry an 'o' magic that contains the
+ * Any scalar variable may carry PERL_MAGIC_collxfrm magic that contains the
  * scalar data of the variable transformed to such a format that
  * a normal memory comparison can be used to compare the data
  * according to the locale settings.
@@ -4864,7 +4896,7 @@ Perl_sv_collxfrm(pTHX_ SV *sv, STRLEN *nxp)
 {
     MAGIC *mg;
 
-    mg = SvMAGICAL(sv) ? mg_find(sv, 'o') : (MAGIC *) NULL;
+    mg = SvMAGICAL(sv) ? mg_find(sv, PERL_MAGIC_collxfrm) : (MAGIC *) NULL;
     if (!mg || !mg->mg_ptr || *(U32*)mg->mg_ptr != PL_collation_ix) {
        char *s, *xf;
        STRLEN len, xlen;
@@ -4879,8 +4911,8 @@ Perl_sv_collxfrm(pTHX_ SV *sv, STRLEN *nxp)
                return xf + sizeof(PL_collation_ix);
            }
            if (! mg) {
-               sv_magic(sv, 0, 'o', 0, 0);
-               mg = mg_find(sv, 'o');
+               sv_magic(sv, 0, PERL_MAGIC_collxfrm, 0, 0);
+               mg = mg_find(sv, PERL_MAGIC_collxfrm);
                assert(mg);
            }
            mg->mg_ptr = xf;
@@ -4922,7 +4954,7 @@ Perl_sv_gets(pTHX_ register SV *sv, register PerlIO *fp, I32 append)
     register STDCHAR rslast;
     register STDCHAR *bp;
     register I32 cnt;
-    I32 i;
+    I32 i = 0;
 
     SV_CHECK_THINKFIRST(sv);
     (void)SvUPGRADE(sv, SVt_PV);
@@ -5283,7 +5315,7 @@ Perl_sv_inc(pTHX_ register SV *sv)
        /* Got to punt this an an integer if needs be, but we don't issue
           warnings. Probably ought to make the sv_iv_please() that does
           the conversion if possible, and silently.  */
-       I32 numtype = looks_like_number(sv);
+       int numtype = grok_number(SvPVX(sv), SvCUR(sv), NULL);
        if (numtype && !(numtype & IS_NUMBER_INFINITY)) {
            /* Need to try really hard to see if it's an integer.
               9.22337203685478e+18 is an integer.
@@ -5426,7 +5458,7 @@ Perl_sv_dec(pTHX_ register SV *sv)
     }
 #ifdef PERL_PRESERVE_IVUV
     {
-       I32 numtype = looks_like_number(sv);
+       int numtype = grok_number(SvPVX(sv), SvCUR(sv), NULL);
        if (numtype && !(numtype & IS_NUMBER_INFINITY)) {
            /* Need to try really hard to see if it's an integer.
               9.22337203685478e+18 is an integer.
@@ -5596,6 +5628,12 @@ Perl_newSVpvn_share(pTHX_ const char *src, I32 len, U32 hash)
         len = -len;
         is_utf8 = TRUE;
     }
+    if (is_utf8 && !(PL_hints & HINT_UTF8_DISTINCT)) {
+       STRLEN tmplen = len;
+       /* See the note in hv.c:hv_fetch() --jhi */
+       src = (char*)bytes_from_utf8((U8*)src, &tmplen, &is_utf8);
+       len = tmplen;
+    }
     if (!hash)
        PERL_HASH(hash, src, len);
     new_SV(sv);
@@ -6048,6 +6086,23 @@ Get a sensible string out of the SV somehow.
 char *
 Perl_sv_pvn_force(pTHX_ SV *sv, STRLEN *lp)
 {
+    return sv_pvn_force_flags(sv, lp, SV_GMAGIC);
+}
+
+/*
+=for apidoc sv_pvn_force_flags
+
+Get a sensible string out of the SV somehow.
+If C<flags> has C<SV_GMAGIC> bit set, will C<mg_get> on C<sv> if
+appropriate, else not. C<sv_pvn_force> and C<sv_pvn_force_nomg> are
+implemented in terms of this function.
+
+=cut
+*/
+
+char *
+Perl_sv_pvn_force_flags(pTHX_ SV *sv, STRLEN *lp, I32 flags)
+{
     char *s;
 
     if (SvTHINKFIRST(sv) && !SvROK(sv))
@@ -6062,7 +6117,7 @@ Perl_sv_pvn_force(pTHX_ SV *sv, STRLEN *lp)
                PL_op_name[PL_op->op_type]);
        }
        else
-           s = sv_2pv(sv, lp);
+           s = sv_2pv_flags(sv, lp, flags);
        if (s != SvPVX(sv)) {   /* Almost, but not quite, sv_setpvn() */
            STRLEN len = *lp;
        
@@ -6087,18 +6142,21 @@ Perl_sv_pvn_force(pTHX_ SV *sv, STRLEN *lp)
 char *
 Perl_sv_pvbyte(pTHX_ SV *sv)
 {
+    sv_utf8_downgrade(sv,0);
     return sv_pv(sv);
 }
 
 char *
 Perl_sv_pvbyten(pTHX_ SV *sv, STRLEN *lp)
 {
+    sv_utf8_downgrade(sv,0);
     return sv_pvn(sv,lp);
 }
 
 char *
 Perl_sv_pvbyten_force(pTHX_ SV *sv, STRLEN *lp)
 {
+    sv_utf8_downgrade(sv,0);
     return sv_pvn_force(sv,lp);
 }
 
@@ -6323,6 +6381,25 @@ Perl_sv_setref_iv(pTHX_ SV *rv, const char *classname, IV iv)
 }
 
 /*
+=for apidoc sv_setref_uv
+
+Copies an unsigned integer into a new SV, optionally blessing the SV.  The C<rv>
+argument will be upgraded to an RV.  That RV will be modified to point to
+the new SV.  The C<classname> argument indicates the package for the
+blessing.  Set C<classname> to C<Nullch> to avoid the blessing.  The new SV
+will be returned and will have a reference count of 1.
+
+=cut
+*/
+
+SV*
+Perl_sv_setref_uv(pTHX_ SV *rv, const char *classname, UV uv)
+{
+    sv_setuv(newSVrv(rv,classname), uv);
+    return rv;
+}
+
+/*
 =for apidoc sv_setref_nv
 
 Copies a double into a new SV, optionally blessing the SV.  The C<rv>
@@ -6416,7 +6493,7 @@ S_sv_unglob(pTHX_ SV *sv)
        SvREFCNT_dec(GvSTASH(sv));
        GvSTASH(sv) = Nullhv;
     }
-    sv_unmagic(sv, '*');
+    sv_unmagic(sv, PERL_MAGIC_glob);
     Safefree(GvNAME(sv));
     GvMULTI_off(sv);
 
@@ -6483,14 +6560,14 @@ Perl_sv_unref(pTHX_ SV *sv)
 void
 Perl_sv_taint(pTHX_ SV *sv)
 {
-    sv_magic((sv), Nullsv, 't', Nullch, 0);
+    sv_magic((sv), Nullsv, PERL_MAGIC_taint, Nullch, 0);
 }
 
 void
 Perl_sv_untaint(pTHX_ SV *sv)
 {
     if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
-       MAGIC *mg = mg_find(sv, 't');
+       MAGIC *mg = mg_find(sv, PERL_MAGIC_taint);
        if (mg)
            mg->mg_len &= ~1;
     }
@@ -6500,7 +6577,7 @@ bool
 Perl_sv_tainted(pTHX_ SV *sv)
 {
     if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
-       MAGIC *mg = mg_find(sv, 't');
+       MAGIC *mg = mg_find(sv, PERL_MAGIC_taint);
        if (mg && ((mg->mg_len & 1) || ((mg->mg_len & 2) && mg->mg_obj == sv)))
            return TRUE;
     }
@@ -6642,12 +6719,15 @@ Perl_sv_catpvf_mg_nocontext(SV *sv, const char* pat, ...)
 /*
 =for apidoc sv_catpvf
 
-Processes its arguments like C<sprintf> and appends the formatted output
-to an SV.  Handles 'get' magic, but not 'set' magic.  C<SvSETMAGIC()> must
-typically be called after calling this function to handle 'set' magic.
+Processes its arguments like C<sprintf> and appends the formatted
+output to an SV.  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.
+C<SvSETMAGIC()> must typically be called after calling this function
+to handle 'set' magic.
 
-=cut
-*/
+=cut */
 
 void
 Perl_sv_catpvf(pTHX_ SV *sv, const char* pat, ...)
@@ -6704,6 +6784,21 @@ Perl_sv_vsetpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
     sv_vcatpvfn(sv, pat, patlen, args, svargs, svmax, maybe_tainted);
 }
 
+STATIC I32
+S_expect_number(pTHX_ char** pattern)
+{
+    I32 var = 0;
+    switch (**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');
+    }
+    return var;
+}
+#define EXPECT_NUMBER(pattern, var) (var = S_expect_number(aTHX_ &pattern))
+
 /*
 =for apidoc sv_vcatpvfn
 
@@ -6725,7 +6820,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
     STRLEN origlen;
     I32 svix = 0;
     static char nullstr[] = "(null)";
-    SV *argsv;
+    SV *argsv = Nullsv;
 
     /* no matter what, this is a string now */
     (void)SvPV_force(sv, origlen);
@@ -6764,7 +6859,8 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
        bool alt = FALSE;
        bool left = FALSE;
        bool vectorize = FALSE;
-       bool utf = FALSE;
+       bool vectorarg = FALSE;
+       bool vec_utf = FALSE;
        char fill = ' ';
        char plus = 0;
        char intsize = 0;
@@ -6792,7 +6888,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
        STRLEN veclen = 0;
        char c;
        int i;
-       unsigned base;
+       unsigned base = 0;
        IV iv;
        UV uv;
        NV nv;
@@ -6801,10 +6897,13 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
        STRLEN gap;
        char *dotstr = ".";
        STRLEN dotstrlen = 1;
-       I32 epix = 0; /* explicit parameter index */
+       I32 efix = 0; /* explicit format parameter index */
        I32 ewix = 0; /* explicit width index */
+       I32 epix = 0; /* explicit precision index */
+       I32 evix = 0; /* explicit vector index */
        bool asterisk = FALSE;
 
+       /* echo everything up to the next format specification */
        for (q = p; q < patend && *q != '%'; ++q) ;
        if (q > p) {
            sv_catpvn(sv, p, q - p);
@@ -6813,6 +6912,25 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
        if (q++ >= patend)
            break;
 
+/*
+    We allow format specification elements in this order:
+       \d+\$              explicit format parameter index
+       [-+ 0#]+           flags
+       \*?(\d+\$)?v       vector with optional (optionally specified) arg
+       \d+|\*(\d+\$)?     width using optional (optionally specified) arg
+       \.(\d*|\*(\d+\$)?) precision using optional (optionally specified) arg
+       [hlqLV]            size
+    [%bcdefginopsux_DFOUX] format (mandatory)
+*/
+       if (EXPECT_NUMBER(q, width)) {
+           if (*q == '$') {
+               ++q;
+               efix = width;
+           } else {
+               goto gotwidth;
+           }
+       }
+
        /* FLAGS */
 
        while (*q) {
@@ -6836,63 +6954,60 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                q++;
                continue;
 
-           case '*':                   /* printf("%*vX",":",$ipv6addr) */
-               if (q[1] != 'v')
-                   break;
-               q++;
-               if (args)
-                   vecsv = va_arg(*args, SV*);
-               else if (svix < svmax)
-                   vecsv = svargs[svix++];
-               else
-                   continue;
-               dotstr = SvPVx(vecsv,dotstrlen);
-               if (DO_UTF8(vecsv))
-                   is_utf = TRUE;
-               /* FALL THROUGH */
-
-           case 'v':
-               vectorize = TRUE;
-               q++;
-               continue;
-
            default:
                break;
            }
            break;
        }
 
-       /* WIDTH */
-
-    scanwidth:
-
+      tryasterisk:
        if (*q == '*') {
-           if (asterisk)
-               goto unknown;
+           q++;
+           if (EXPECT_NUMBER(q, ewix))
+               if (*q++ != '$')
+                   goto unknown;
            asterisk = TRUE;
+       }
+       if (*q == 'v') {
            q++;
+           if (vectorize)
+               goto unknown;
+           if ((vectorarg = asterisk)) {
+               evix = ewix;
+               ewix = 0;
+               asterisk = FALSE;
+           }
+           vectorize = TRUE;
+           goto tryasterisk;
        }
 
-       switch (*q) {
-       case '1': case '2': case '3':
-       case '4': case '5': case '6':
-       case '7': case '8': case '9':
-           width = 0;
-           while (isDIGIT(*q))
-               width = width * 10 + (*q++ - '0');
-           if (*q == '$') {
-               if (asterisk && ewix == 0) {
-                   ewix  = width;
-                   width = 0;
-                   q++;
-                   goto scanwidth;
-               } else if (epix == 0) {
-                   epix  = width;
-                   width = 0;
-                   q++;
-                   goto scanwidth;
-               } else
-                   goto unknown;
+       if (!asterisk)
+           EXPECT_NUMBER(q, width);
+
+       if (vectorize) {
+           if (vectorarg) {
+               if (args)
+                   vecsv = va_arg(*args, SV*);
+               else
+                   vecsv = (evix ? evix <= svmax : svix < svmax) ?
+                       svargs[ewix ? ewix-1 : svix++] : &PL_sv_undef;
+               dotstr = SvPVx(vecsv, dotstrlen);
+               if (DO_UTF8(vecsv))
+                   is_utf = TRUE;
+           }
+           if (args) {
+               vecsv = va_arg(*args, SV*);
+               vecstr = (U8*)SvPVx(vecsv,veclen);
+               vec_utf = DO_UTF8(vecsv);
+           }
+           else if (efix ? efix <= svmax : svix < svmax) {
+               vecsv = svargs[efix ? efix-1 : svix++];
+               vecstr = (U8*)SvPVx(vecsv,veclen);
+               vec_utf = DO_UTF8(vecsv);
+           }
+           else {
+               vecstr = (U8*)"";
+               veclen = 0;
            }
        }
 
@@ -6905,19 +7020,22 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            left |= (i < 0);
            width = (i < 0) ? -i : i;
        }
+      gotwidth:
 
        /* PRECISION */
 
        if (*q == '.') {
            q++;
            if (*q == '*') {
+               q++;
+               if (EXPECT_NUMBER(q, epix) && *q++ != '$')
+                   goto unknown;
                if (args)
                    i = va_arg(*args, int);
                else
                    i = (ewix ? ewix <= svmax : svix < svmax)
                        ? SvIVx(svargs[ewix ? ewix-1 : svix++]) : 0;
                precis = (i < 0) ? 0 : i;
-               q++;
            }
            else {
                precis = 0;
@@ -6927,23 +7045,6 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            has_precis = TRUE;
        }
 
-       if (vectorize) {
-           if (args) {
-               vecsv = va_arg(*args, SV*);
-               vecstr = (U8*)SvPVx(vecsv,veclen);
-               utf = DO_UTF8(vecsv);
-           }
-           else if (epix ? epix <= svmax : svix < svmax) {
-               vecsv = svargs[epix ? epix-1 : svix++];
-               vecstr = (U8*)SvPVx(vecsv,veclen);
-               utf = DO_UTF8(vecsv);
-           }
-           else {
-               vecstr = (U8*)"";
-               veclen = 0;
-           }
-       }
-
        /* SIZE */
 
        switch (*q) {
@@ -6975,24 +7076,27 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
 
        /* CONVERSION */
 
+       if (*q == '%') {
+           eptr = q++;
+           elen = 1;
+           goto string;
+       }
+
+       if (!args)
+           argsv = (efix ? efix <= svmax : svix < svmax) ?
+                   svargs[efix ? efix-1 : svix++] : &PL_sv_undef;
+
        switch (c = *q++) {
 
            /* STRINGS */
 
-       case '%':
-           eptr = q - 1;
-           elen = 1;
-           goto string;
-
        case 'c':
-           if (args)
-               uv = va_arg(*args, int);
-           else
-               uv = (epix ? epix <= svmax : svix < svmax) ?
-                   SvIVx(svargs[epix ? epix-1 : svix++]) : 0;
-           if ((uv > 255 || (uv > 127 && SvUTF8(sv))) && !IN_BYTE) {
+           uv = args ? va_arg(*args, int) : SvIVx(argsv);
+           if ((uv > 255 ||
+                (!UNI_IS_INVARIANT(uv) && SvUTF8(sv)))
+               && !IN_BYTES) {
                eptr = (char*)utf8buf;
-               elen = uv_to_utf8((U8*)eptr, uv) - utf8buf;
+               elen = uvchr_to_utf8((U8*)eptr, uv) - utf8buf;
                is_utf = TRUE;
            }
            else {
@@ -7018,8 +7122,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                    elen = sizeof nullstr - 1;
                }
            }
-           else if (epix ? epix <= svmax : svix < svmax) {
-               argsv = svargs[epix ? epix-1 : svix++];
+           else {
                eptr = SvPVx(argsv, elen);
                if (DO_UTF8(argsv)) {
                    if (has_precis && precis < elen) {
@@ -7043,7 +7146,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
             */
            if (!args)
                goto unknown;
-           argsv = va_arg(*args,SV*);
+           argsv = va_arg(*args, SV*);
            eptr = SvPVx(argsv, elen);
            if (DO_UTF8(argsv))
                is_utf = TRUE;
@@ -7059,11 +7162,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
        case 'p':
            if (alt)
                goto unknown;
-           if (args)
-               uv = PTR2UV(va_arg(*args, void*));
-           else
-               uv = (epix ? epix <= svmax : svix < svmax) ?
-                   PTR2UV(svargs[epix ? epix-1 : svix++]) : 0;
+           uv = PTR2UV(args ? va_arg(*args, void*) : argsv);
            base = 16;
            goto integer;
 
@@ -7078,12 +7177,10 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
        case 'i':
            if (vectorize) {
                STRLEN ulen;
-               if (!veclen) {
-                   vectorize = FALSE;
-                   break;
-               }
-               if (utf)
-                   iv = (IV)utf8_to_uv(vecstr, veclen, &ulen, 0);
+               if (!veclen)
+                   continue;
+               if (vec_utf)
+                   iv = (IV)utf8n_to_uvchr(vecstr, veclen, &ulen, 0);
                else {
                    iv = *vecstr;
                    ulen = 1;
@@ -7103,8 +7200,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                }
            }
            else {
-               iv = (epix ? epix <= svmax : svix < svmax) ?
-                   SvIVx(svargs[epix ? epix-1 : svix++]) : 0;
+               iv = SvIVx(argsv);
                switch (intsize) {
                case 'h':       iv = (short)iv; break;
                default:        break;
@@ -7161,12 +7257,10 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            if (vectorize) {
                STRLEN ulen;
        vector:
-               if (!veclen) {
-                   vectorize = FALSE;
-                   break;
-               }
-               if (utf)
-                   uv = utf8_to_uv(vecstr, veclen, &ulen, 0);
+               if (!veclen)
+                   continue;
+               if (vec_utf)
+                   uv = utf8n_to_uvchr(vecstr, veclen, &ulen, 0);
                else {
                    uv = *vecstr;
                    ulen = 1;
@@ -7186,8 +7280,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                }
            }
            else {
-               uv = (epix ? epix <= svmax : svix < svmax) ?
-                   SvUVx(svargs[epix ? epix-1 : svix++]) : 0;
+               uv = SvUVx(argsv);
                switch (intsize) {
                case 'h':       uv = (unsigned short)uv; break;
                default:        break;
@@ -7276,11 +7369,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            /* This is evil, but floating point is even more evil */
 
            vectorize = FALSE;
-           if (args)
-               nv = va_arg(*args, NV);
-           else
-               nv = (epix ? epix <= svmax : svix < svmax) ?
-                   SvNVx(svargs[epix ? epix-1 : svix++]) : 0.0;
+           nv = args ? va_arg(*args, NV) : SvNVx(argsv);
 
            need = 0;
            if (c != 'e' && c != 'E') {
@@ -7360,8 +7449,8 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
 #endif
                }
            }
-           else if (epix ? epix <= svmax : svix < svmax)
-               sv_setuv_mg(svargs[epix ? epix-1 : svix++], (UV)i);
+           else
+               sv_setuv_mg(argsv, (UV)i);
            continue;   /* not "break" */
 
            /* UNKNOWN */
@@ -7396,7 +7485,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            /* ... right here, because formatting flags should not apply */
            SvGROW(sv, SvCUR(sv) + elen + 1);
            p = SvEND(sv);
-           memcpy(p, eptr, elen);
+           Copy(eptr, p, elen, char);
            p += elen;
            *p = '\0';
            SvCUR(sv) = p - SvPVX(sv);
@@ -7426,7 +7515,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                *p++ = '0';
        }
        if (elen) {
-           memcpy(p, eptr, elen);
+           Copy(eptr, p, elen, char);
            p += elen;
        }
        if (gap && left) {
@@ -7435,7 +7524,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
        }
        if (vectorize) {
            if (veclen) {
-               memcpy(p, dotstr, dotstrlen);
+               Copy(dotstr, p, dotstrlen, char);
                p += dotstrlen;
            }
            else
@@ -7545,8 +7634,8 @@ Perl_gp_dup(pTHX_ GP *gp)
 MAGIC *
 Perl_mg_dup(pTHX_ MAGIC *mg)
 {
-    MAGIC *mgret = (MAGIC*)NULL;
-    MAGIC *mgprev;
+    MAGIC *mgprev = (MAGIC*)NULL;
+    MAGIC *mgret;
     if (!mg)
        return (MAGIC*)NULL;
     /* look for it in the table first */
@@ -7557,15 +7646,15 @@ Perl_mg_dup(pTHX_ MAGIC *mg)
     for (; mg; mg = mg->mg_moremagic) {
        MAGIC *nmg;
        Newz(0, nmg, 1, MAGIC);
-       if (!mgret)
-           mgret = nmg;
-       else
+       if (mgprev)
            mgprev->mg_moremagic = nmg;
+       else
+           mgret = nmg;
        nmg->mg_virtual = mg->mg_virtual;       /* XXX copy dynamic vtable? */
        nmg->mg_private = mg->mg_private;
        nmg->mg_type    = mg->mg_type;
        nmg->mg_flags   = mg->mg_flags;
-       if (mg->mg_type == 'r') {
+       if (mg->mg_type == PERL_MAGIC_qr) {
            nmg->mg_obj = (SV*)re_dup((REGEXP*)mg->mg_obj);
        }
        else {
@@ -7575,10 +7664,12 @@ Perl_mg_dup(pTHX_ MAGIC *mg)
        }
        nmg->mg_len     = mg->mg_len;
        nmg->mg_ptr     = mg->mg_ptr;   /* XXX random ptr? */
-       if (mg->mg_ptr && mg->mg_type != 'g') {
+       if (mg->mg_ptr && mg->mg_type != PERL_MAGIC_regex_global) {
            if (mg->mg_len >= 0) {
                nmg->mg_ptr     = SAVEPVN(mg->mg_ptr, mg->mg_len);
-               if (mg->mg_type == 'c' && AMT_AMAGIC((AMT*)mg->mg_ptr)) {
+               if (mg->mg_type == PERL_MAGIC_overload_table &&
+                       AMT_AMAGIC((AMT*)mg->mg_ptr))
+               {
                    AMT *amtp = (AMT*)mg->mg_ptr;
                    AMT *namtp = (AMT*)nmg->mg_ptr;
                    I32 i;
@@ -7679,10 +7770,110 @@ 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;
+    register PTR_TBL_ENT_t *oentry = Null(PTR_TBL_ENT_t*);
+    UV riter = 0;
+    UV max;
+
+    if (!tbl || !tbl->tbl_items) {
+        return;
+    }
+
+    array = tbl->tbl_ary;
+    entry = array[0];
+    max = tbl->tbl_max;
+
+    for (;;) {
+        if (entry) {
+            oentry = entry;
+            entry = entry->next;
+            Safefree(oentry);
+        }
+        if (!entry) {
+            if (++riter > max) {
+                break;
+            }
+            entry = array[riter];
+        }
+    }
+
+    tbl->tbl_items = 0;
+}
+
+void
+Perl_ptr_table_free(pTHX_ PTR_TBL_t *tbl)
+{
+    if (!tbl) {
+        return;
+    }
+    ptr_table_clear(tbl);
+    Safefree(tbl->tbl_ary);
+    Safefree(tbl);
+}
+
 #ifdef DEBUGGING
 char *PL_watch_pvx;
 #endif
 
+STATIC SV *
+S_gv_share(pTHX_ SV *sstr)
+{
+    GV *gv = (GV*)sstr;
+    SV *sv = &PL_sv_no; /* just need SvREADONLY-ness */
+
+    if (GvIO(gv) || GvFORM(gv)) {
+        GvSHARED_off(gv); /* GvIOs cannot be shared. nor can GvFORMs */
+    }
+    else if (!GvCV(gv)) {
+        GvCV(gv) = (CV*)sv;
+    }
+    else {
+        /* CvPADLISTs cannot be shared */
+        if (!CvXSUB(GvCV(gv))) {
+            GvSHARED_off(gv);
+        }
+    }
+
+    if (!GvSHARED(gv)) {
+#if 0
+        PerlIO_printf(Perl_debug_log, "gv_share: unable to share %s::%s\n",
+                      HvNAME(GvSTASH(gv)), GvNAME(gv));
+#endif
+        return Nullsv;
+    }
+
+    /*
+     * write attempts will die with
+     * "Modification of a read-only value attempted"
+     */
+    if (!GvSV(gv)) {
+        GvSV(gv) = sv;
+    }
+    else {
+        SvREADONLY_on(GvSV(gv));
+    }
+
+    if (!GvAV(gv)) {
+        GvAV(gv) = (AV*)sv;
+    }
+    else {
+        SvREADONLY_on(GvAV(gv));
+    }
+
+    if (!GvHV(gv)) {
+        GvHV(gv) = (HV*)sv;
+    }
+    else {
+        SvREADONLY_on(GvAV(gv));
+    }
+
+    return sstr; /* he_dup() will SvREFCNT_inc() */
+}
+
 SV *
 Perl_sv_dup(pTHX_ SV *sstr)
 {
@@ -7724,14 +7915,18 @@ Perl_sv_dup(pTHX_ SV *sstr)
        break;
     case SVt_RV:
        SvANY(dstr)     = new_XRV();
-       SvRV(dstr)      = sv_dup_inc(SvRV(sstr));
+       SvRV(dstr)      = SvRV(sstr) && SvWEAKREF(SvRV(sstr))
+                       ? sv_dup(SvRV(sstr))
+                       : sv_dup_inc(SvRV(sstr));
        break;
     case SVt_PV:
        SvANY(dstr)     = new_XPV();
        SvCUR(dstr)     = SvCUR(sstr);
        SvLEN(dstr)     = SvLEN(sstr);
        if (SvROK(sstr))
-           SvRV(dstr)  = sv_dup_inc(SvRV(sstr));
+           SvRV(dstr)  = SvWEAKREF(SvRV(sstr))
+                       ? sv_dup(SvRV(sstr))
+                       : sv_dup_inc(SvRV(sstr));
        else if (SvPVX(sstr) && SvLEN(sstr))
            SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
        else
@@ -7743,7 +7938,9 @@ Perl_sv_dup(pTHX_ SV *sstr)
        SvLEN(dstr)     = SvLEN(sstr);
        SvIVX(dstr)     = SvIVX(sstr);
        if (SvROK(sstr))
-           SvRV(dstr)  = sv_dup_inc(SvRV(sstr));
+           SvRV(dstr)  = SvWEAKREF(SvRV(sstr))
+                       ? sv_dup(SvRV(sstr))
+                       : sv_dup_inc(SvRV(sstr));
        else if (SvPVX(sstr) && SvLEN(sstr))
            SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
        else
@@ -7756,7 +7953,9 @@ Perl_sv_dup(pTHX_ SV *sstr)
        SvIVX(dstr)     = SvIVX(sstr);
        SvNVX(dstr)     = SvNVX(sstr);
        if (SvROK(sstr))
-           SvRV(dstr)  = sv_dup_inc(SvRV(sstr));
+           SvRV(dstr)  = SvWEAKREF(SvRV(sstr))
+                       ? sv_dup(SvRV(sstr))
+                       : sv_dup_inc(SvRV(sstr));
        else if (SvPVX(sstr) && SvLEN(sstr))
            SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
        else
@@ -7771,7 +7970,9 @@ Perl_sv_dup(pTHX_ SV *sstr)
        SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr));
        SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr));
        if (SvROK(sstr))
-           SvRV(dstr)  = sv_dup_inc(SvRV(sstr));
+           SvRV(dstr)  = SvWEAKREF(SvRV(sstr))
+                       ? sv_dup(SvRV(sstr))
+                       : sv_dup_inc(SvRV(sstr));
        else if (SvPVX(sstr) && SvLEN(sstr))
            SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
        else
@@ -7786,7 +7987,9 @@ Perl_sv_dup(pTHX_ SV *sstr)
        SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr));
        SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr));
        if (SvROK(sstr))
-           SvRV(dstr)  = sv_dup_inc(SvRV(sstr));
+           SvRV(dstr)  = SvWEAKREF(SvRV(sstr))
+                       ? sv_dup(SvRV(sstr))
+                       : sv_dup_inc(SvRV(sstr));
        else if (SvPVX(sstr) && SvLEN(sstr))
            SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
        else
@@ -7804,7 +8007,9 @@ Perl_sv_dup(pTHX_ SV *sstr)
        SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr));
        SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr));
        if (SvROK(sstr))
-           SvRV(dstr)  = sv_dup_inc(SvRV(sstr));
+           SvRV(dstr)  = SvWEAKREF(SvRV(sstr))
+                       ? sv_dup(SvRV(sstr))
+                       : sv_dup_inc(SvRV(sstr));
        else if (SvPVX(sstr) && SvLEN(sstr))
            SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
        else
@@ -7815,6 +8020,18 @@ Perl_sv_dup(pTHX_ SV *sstr)
        LvTYPE(dstr)    = LvTYPE(sstr);
        break;
     case SVt_PVGV:
+       if (GvSHARED((GV*)sstr)) {
+            SV *share;
+            if ((share = gv_share(sstr))) {
+                del_SV(dstr);
+                dstr = share;
+#if 0
+                PerlIO_printf(Perl_debug_log, "sv_dup: sharing %s::%s\n",
+                              HvNAME(GvSTASH(share)), GvNAME(share));
+#endif
+                break;
+            }
+       }
        SvANY(dstr)     = new_XPVGV();
        SvCUR(dstr)     = SvCUR(sstr);
        SvLEN(dstr)     = SvLEN(sstr);
@@ -7823,7 +8040,9 @@ Perl_sv_dup(pTHX_ SV *sstr)
        SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr));
        SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr));
        if (SvROK(sstr))
-           SvRV(dstr)  = sv_dup_inc(SvRV(sstr));
+           SvRV(dstr)  = SvWEAKREF(SvRV(sstr))
+                       ? sv_dup(SvRV(sstr))
+                       : sv_dup_inc(SvRV(sstr));
        else if (SvPVX(sstr) && SvLEN(sstr))
            SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
        else
@@ -7844,7 +8063,9 @@ Perl_sv_dup(pTHX_ SV *sstr)
        SvMAGIC(dstr)   = mg_dup(SvMAGIC(sstr));
        SvSTASH(dstr)   = hv_dup_inc(SvSTASH(sstr));
        if (SvROK(sstr))
-           SvRV(dstr)  = sv_dup_inc(SvRV(sstr));
+           SvRV(dstr)  = SvWEAKREF(SvRV(sstr))
+                       ? sv_dup(SvRV(sstr))
+                       : sv_dup_inc(SvRV(sstr));
        else if (SvPVX(sstr) && SvLEN(sstr))
            SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
        else
@@ -7938,6 +8159,8 @@ Perl_sv_dup(pTHX_ SV *sstr)
        }
        HvPMROOT((HV*)dstr)     = HvPMROOT((HV*)sstr);          /* XXX */
        HvNAME((HV*)dstr)       = SAVEPV(HvNAME((HV*)sstr));
+       if(HvNAME((HV*)dstr))
+           av_push(PL_clone_callbacks, dstr);
        break;
     case SVt_PVFM:
        SvANY(dstr)     = new_XPVFM();
@@ -7962,7 +8185,7 @@ dup_pvcv:
        CvROOT(dstr)    = OpREFCNT_inc(CvROOT(sstr));
        CvXSUB(dstr)    = CvXSUB(sstr);
        CvXSUBANY(dstr) = CvXSUBANY(sstr);
-       CvGV(dstr)      = gv_dup_inc(CvGV(sstr));
+       CvGV(dstr)      = gv_dup(CvGV(sstr));
        CvDEPTH(dstr)   = CvDEPTH(sstr);
        if (CvPADLIST(sstr) && !AvREAL(CvPADLIST(sstr))) {
            /* XXX padlists are real, but pretend to be not */
@@ -7973,7 +8196,10 @@ dup_pvcv:
        }
        else
            CvPADLIST(dstr)     = av_dup_inc(CvPADLIST(sstr));
-       CvOUTSIDE(dstr) = cv_dup_inc(CvOUTSIDE(sstr));
+       if (!CvANON(sstr) || CvCLONED(sstr))
+           CvOUTSIDE(dstr)     = cv_dup_inc(CvOUTSIDE(sstr));
+       else
+           CvOUTSIDE(dstr)     = cv_dup(CvOUTSIDE(sstr));
        CvFLAGS(dstr)   = CvFLAGS(sstr);
        break;
     default:
@@ -8027,7 +8253,7 @@ Perl_cx_dup(pTHX_ PERL_CONTEXT *cxs, I32 ix, I32 max)
                ncx->blk_sub.argarray   = (cx->blk_sub.hasargs
                                           ? av_dup_inc(cx->blk_sub.argarray)
                                           : Nullav);
-               ncx->blk_sub.savearray  = av_dup(cx->blk_sub.savearray);
+               ncx->blk_sub.savearray  = av_dup_inc(cx->blk_sub.savearray);
                ncx->blk_sub.olddepth   = cx->blk_sub.olddepth;
                ncx->blk_sub.hasargs    = cx->blk_sub.hasargs;
                ncx->blk_sub.lval       = cx->blk_sub.lval;
@@ -8281,6 +8507,7 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl)
            TOPIV(nss,ix) = iv;
             break;
        case SAVEt_FREESV:
+       case SAVEt_MORTALIZESV:
            sv = (SV*)POPPTR(ss,ix);
            TOPPTR(nss,ix) = sv_dup_inc(sv);
            break;
@@ -8568,6 +8795,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     while (i-- > 0) {
        PL_origargv[i]  = SAVEPV(proto_perl->Iorigargv[i]);
     }
+    PL_clone_callbacks = newAV();   /* Setup array of objects to callbackon */
     PL_envgv           = gv_dup(proto_perl->Ienvgv);
     PL_incgv           = gv_dup(proto_perl->Iincgv);
     PL_hintgv          = gv_dup(proto_perl->Ihintgv);
@@ -8614,7 +8842,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_defgv           = gv_dup(proto_perl->Idefgv);
     PL_argvgv          = gv_dup(proto_perl->Iargvgv);
     PL_argvoutgv       = gv_dup(proto_perl->Iargvoutgv);
-    PL_argvout_stack   = av_dup(proto_perl->Iargvout_stack);
+    PL_argvout_stack   = av_dup_inc(proto_perl->Iargvout_stack);
 
     /* shortcuts to regexp stuff */
     PL_replgv          = gv_dup(proto_perl->Ireplgv);
@@ -8825,7 +9053,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_numeric_name    = SAVEPV(proto_perl->Inumeric_name);
     PL_numeric_standard        = proto_perl->Inumeric_standard;
     PL_numeric_local   = proto_perl->Inumeric_local;
-    PL_numeric_radix   = proto_perl->Inumeric_radix;
+    PL_numeric_radix_sv        = sv_dup_inc(proto_perl->Inumeric_radix_sv);
 #endif /* !USE_LOCALE_NUMERIC */
 
     /* utf8 character classes */
@@ -8869,7 +9097,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
     if (proto_perl->Ipsig_pend) {
        Newz(0, PL_psig_pend, SIG_SIZE, int);
-    } 
+    }
     else {
        PL_psig_pend    = (int*)NULL;
     }
@@ -8889,7 +9117,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
     /* thrdvar.h stuff */
 
-    if (flags & 1) {
+    if (flags & CLONEf_COPY_STACKS) {
        /* next allocation will be PL_tmps_stack[PL_tmps_ix+1] */
        PL_tmps_ix              = proto_perl->Ttmps_ix;
        PL_tmps_max             = proto_perl->Ttmps_max;
@@ -9039,7 +9267,6 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_regendp         = (I32*)NULL;
     PL_reglastparen    = (U32*)NULL;
     PL_regtill         = Nullch;
-    PL_regprev         = '\n';
     PL_reg_start_tmp   = (char**)NULL;
     PL_reg_start_tmpl  = 0;
     PL_regdata         = (struct reg_data*)NULL;
@@ -9075,6 +9302,29 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_reginterp_cnt   = 0;
     PL_reg_starttry    = 0;
 
+    if (!(flags & CLONEf_KEEP_PTR_TABLE)) {
+        ptr_table_free(PL_ptr_table);
+        PL_ptr_table = NULL;
+    }
+    
+    while(av_len(PL_clone_callbacks) != -1) {
+        HV* stash = (HV*) av_shift(PL_clone_callbacks);
+        CV* cloner = (CV*) gv_fetchmethod_autoload(stash,"CLONE",0);
+        if(cloner) {
+            dSP;
+            cloner = GvCV(cloner);
+            ENTER;
+            SAVETMPS;
+            PUSHMARK(SP);
+            XPUSHs(newSVpv(HvNAME(stash),0));
+            PUTBACK;
+            call_sv((SV*)cloner, G_DISCARD);
+            FREETMPS;
+            LEAVE;
+            
+        }
+    }
+
 #ifdef PERL_OBJECT
     return (PerlInterpreter*)pPerl;
 #else
@@ -9105,7 +9355,7 @@ do_clean_objs(pTHXo_ SV *sv)
     SV* rv;
 
     if (SvROK(sv) && SvOBJECT(rv = SvRV(sv))) {
-       DEBUG_D((PerlIO_printf(Perl_debug_log, "Cleaning object ref:\n "), sv_dump(sv));)
+       DEBUG_D((PerlIO_printf(Perl_debug_log, "Cleaning object ref:\n "), sv_dump(sv)));
        if (SvWEAKREF(sv)) {
            sv_del_backref(sv);
            SvWEAKREF_off(sv);
@@ -9131,7 +9381,7 @@ do_clean_named_objs(pTHXo_ SV *sv)
             (GvIO(sv) && SvOBJECT(GvIO(sv))) ||
             (GvCV(sv) && SvOBJECT(GvCV(sv))) )
        {
-           DEBUG_D((PerlIO_printf(Perl_debug_log, "Cleaning named glob object:\n "), sv_dump(sv));)
+           DEBUG_D((PerlIO_printf(Perl_debug_log, "Cleaning named glob object:\n "), sv_dump(sv)));
            SvREFCNT_dec(sv);
        }
     }
@@ -9141,7 +9391,7 @@ do_clean_named_objs(pTHXo_ SV *sv)
 static void
 do_clean_all(pTHXo_ SV *sv)
 {
-    DEBUG_D((PerlIO_printf(Perl_debug_log, "Cleaning loops: SV at 0x%"UVxf"\n", PTR2UV(sv)) );)
+    DEBUG_D((PerlIO_printf(Perl_debug_log, "Cleaning loops: SV at 0x%"UVxf"\n", PTR2UV(sv)) ));
     SvFLAGS(sv) |= SVf_BREAK;
     SvREFCNT_dec(sv);
 }