This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Exterminate! 2 pieces of superfluous code related to UV setting.
[perl5.git] / sv.c
diff --git a/sv.c b/sv.c
index 029d0fa..e4deb9d 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -1032,7 +1032,7 @@ static const struct body_details bodies_by_type[] = {
 #define new_NOARENAZ(details) \
        my_safecalloc((details)->body_size + (details)->offset)
 
-#ifdef DEBUGGING
+#if defined(DEBUGGING) && !defined(PERL_GLOBAL_STRUCT_PRIVATE)
 static bool done_sanity_check;
 #endif
 
@@ -1048,7 +1048,9 @@ S_more_bodies (pTHX_ svtype sv_type)
 
     assert(bdp->arena_size);
 
-#ifdef DEBUGGING
+#if defined(DEBUGGING) && !defined(PERL_GLOBAL_STRUCT_PRIVATE)
+    /* PERL_GLOBAL_STRUCT_PRIVATE cannot coexist with global
+     * variables like done_sanity_check. */
     if (!done_sanity_check) {
        unsigned int i = SVt_LAST;
 
@@ -1090,8 +1092,8 @@ S_more_bodies (pTHX_ svtype sv_type)
     STMT_START { \
        void ** const r3wt = &PL_body_roots[sv_type]; \
        LOCK_SV_MUTEX; \
-       xpv = *((void **)(r3wt)) \
-         ? *((void **)(r3wt)) : more_bodies(sv_type); \
+       xpv = (PTR_TBL_ENT_t*) (*((void **)(r3wt))      \
+         ? *((void **)(r3wt)) : more_bodies(sv_type)); \
        *(r3wt) = *(void**)(xpv); \
        UNLOCK_SV_MUTEX; \
     } STMT_END
@@ -1120,12 +1122,12 @@ You generally want to use the C<SvUPGRADE> macro wrapper. See also C<svtype>.
 */
 
 void
-Perl_sv_upgrade(pTHX_ register SV *sv, U32 new_type)
+Perl_sv_upgrade(pTHX_ register SV *sv, svtype new_type)
 {
     dVAR;
     void*      old_body;
     void*      new_body;
-    const U32  old_type = SvTYPE(sv);
+    const svtype old_type = SvTYPE(sv);
     const struct body_details *new_type_details;
     const struct body_details *const old_type_details
        = bodies_by_type + old_type;
@@ -1275,13 +1277,11 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 new_type)
            assert(SvPVX_const(sv) == 0);
        }
 
-       /* Could put this in the else clause below, as PVMG must have SvPVX
-          0 already (the assertion above)  */
-       SvPV_set(sv, NULL);
-
        if (old_type >= SVt_PVMG) {
            SvMAGIC_set(sv, ((XPVMG*)old_body)->xmg_u.xmg_magic);
            SvSTASH_set(sv, ((XPVMG*)old_body)->xmg_stash);
+       } else {
+           sv->sv_u.svu_array = NULL; /* or svu_hash  */
        }
        break;
 
@@ -1448,10 +1448,10 @@ Perl_sv_grow(pTHX_ register SV *sv, register STRLEN newlen)
                return s;
            } else
 #endif
-           s = saferealloc(s, newlen);
+           s = (char*)saferealloc(s, newlen);
        }
        else {
-           s = safemalloc(newlen);
+           s = (char*)safemalloc(newlen);
            if (SvPVX_const(sv) && SvCUR(sv)) {
                Move(SvPVX_const(sv), s, (newlen < SvCUR(sv)) ? newlen : SvCUR(sv), char);
            }
@@ -1496,6 +1496,7 @@ Perl_sv_setiv(pTHX_ register SV *sv, IV i)
     case SVt_PVIO:
        Perl_croak(aTHX_ "Can't coerce %s to integer in %s", sv_reftype(sv,0),
                   OP_DESC(PL_op));
+    default: NOOP;
     }
     (void)SvIOK_only(sv);                      /* validate number */
     SvIV_set(sv, i);
@@ -1557,8 +1558,6 @@ Like C<sv_setuv>, but also handles 'set' magic.
 void
 Perl_sv_setuv_mg(pTHX_ register SV *sv, UV u)
 {
-    sv_setiv(sv, 0);
-    SvIsUV_on(sv);
     sv_setuv(sv,u);
     SvSETMAGIC(sv);
 }
@@ -1596,6 +1595,7 @@ Perl_sv_setnv(pTHX_ register SV *sv, NV num)
     case SVt_PVIO:
        Perl_croak(aTHX_ "Can't coerce %s to number in %s", sv_reftype(sv,0),
                   OP_NAME(PL_op));
+    default: NOOP;
     }
     SvNV_set(sv, num);
     (void)SvNOK_only(sv);                      /* validate number */
@@ -1847,6 +1847,7 @@ STATIC int
 S_sv_2iuv_non_preserve(pTHX_ register SV *sv, I32 numtype)
 {
     dVAR;
+    PERL_UNUSED_ARG(numtype); /* Used only under DEBUGGING? */
     DEBUG_c(PerlIO_printf(Perl_debug_log,"sv_2iuv_non '%s', IV=0x%"UVxf" NV=%"NVgf" inttype=%"UVXf"\n", SvPVX_const(sv), SvIVX(sv), SvNVX(sv), (UV)numtype));
     if (SvNVX(sv) < (NV)IV_MIN) {
        (void)SvIOKp_on(sv);
@@ -2539,87 +2540,6 @@ S_uiv_2buf(char *buf, IV iv, UV uv, int is_uv, char **peob)
     return ptr;
 }
 
-/* stringify_regexp(): private routine for use by sv_2pv_flags(): converts
- * a regexp to its stringified form.
- */
-
-static char *
-S_stringify_regexp(pTHX_ SV *sv, MAGIC *mg, STRLEN *lp) {
-    dVAR;
-    const regexp * const re = (regexp *)mg->mg_obj;
-
-    if (!mg->mg_ptr) {
-       const char *fptr = "msix";
-       char reflags[6];
-       char ch;
-       int left = 0;
-       int right = 4;
-       bool need_newline = 0;
-       U16 reganch = (U16)((re->reganch & PMf_COMPILETIME) >> 12);
-
-       while((ch = *fptr++)) {
-           if(reganch & 1) {
-               reflags[left++] = ch;
-           }
-           else {
-               reflags[right--] = ch;
-           }
-           reganch >>= 1;
-       }
-       if(left != 4) {
-           reflags[left] = '-';
-           left = 5;
-       }
-
-       mg->mg_len = re->prelen + 4 + left;
-       /*
-        * If /x was used, we have to worry about a regex ending with a
-        * comment later being embedded within another regex. If so, we don't
-        * want this regex's "commentization" to leak out to the right part of
-        * the enclosing regex, we must cap it with a newline.
-        *
-        * So, if /x was used, we scan backwards from the end of the regex. If
-        * we find a '#' before we find a newline, we need to add a newline
-        * ourself. If we find a '\n' first (or if we don't find '#' or '\n'),
-        * we don't need to add anything.  -jfriedl
-        */
-       if (PMf_EXTENDED & re->reganch) {
-           const char *endptr = re->precomp + re->prelen;
-           while (endptr >= re->precomp) {
-               const char c = *(endptr--);
-               if (c == '\n')
-                   break; /* don't need another */
-               if (c == '#') {
-                   /* we end while in a comment, so we need a newline */
-                   mg->mg_len++; /* save space for it */
-                   need_newline = 1; /* note to add it */
-                   break;
-               }
-           }
-       }
-
-       Newx(mg->mg_ptr, mg->mg_len + 1 + left, char);
-       mg->mg_ptr[0] = '(';
-       mg->mg_ptr[1] = '?';
-       Copy(reflags, mg->mg_ptr+2, left, char);
-       *(mg->mg_ptr+left+2) = ':';
-       Copy(re->precomp, mg->mg_ptr+3+left, re->prelen, char);
-       if (need_newline)
-           mg->mg_ptr[mg->mg_len - 2] = '\n';
-       mg->mg_ptr[mg->mg_len - 1] = ')';
-       mg->mg_ptr[mg->mg_len] = 0;
-    }
-    PL_reginterp_cnt += re->program[0].next_off;
-    
-    if (re->reganch & ROPT_UTF8)
-       SvUTF8_on(sv);
-    else
-       SvUTF8_off(sv);
-    if (lp)
-       *lp = mg->mg_len;
-    return mg->mg_ptr;
-}
-
 /*
 =for apidoc sv_2pv_flags
 
@@ -2684,7 +2604,7 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
                s = SvGROW_mutable(sv, len + 1);
                SvCUR_set(sv, len);
                SvPOKp_on(sv);
-               return memcpy(s, tbuf, len + 1);
+               return (char*)memcpy(s, tbuf, len + 1);
            }
        }
         if (SvROK(sv)) {
@@ -2724,35 +2644,93 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
                }
            }
            {
-               SV *tsv;
+               STRLEN len;
+               char *retval;
+               char *buffer;
                MAGIC *mg;
                const SV *const referent = (SV*)SvRV(sv);
 
                if (!referent) {
-                   tsv = sv_2mortal(newSVpvs("NULLREF"));
+                   len = 7;
+                   retval = buffer = savepvn("NULLREF", len);
                } else if (SvTYPE(referent) == SVt_PVMG
                           && ((SvFLAGS(referent) &
                                (SVs_OBJECT|SVf_OK|SVs_GMG|SVs_SMG|SVs_RMG))
                               == (SVs_OBJECT|SVs_SMG))
-                          && (mg = mg_find(referent, PERL_MAGIC_qr))) {
-                   return stringify_regexp(sv, mg, lp);
+                          && (mg = mg_find(referent, PERL_MAGIC_qr)))
+                {
+                    char *str = NULL;
+                    I32 haseval = 0;
+                    U32 flags = 0;
+                    (str) = CALLREG_AS_STR(mg,lp,&flags,&haseval);
+                    if (flags & 1)
+                       SvUTF8_on(sv);
+                    else
+                       SvUTF8_off(sv);
+                    PL_reginterp_cnt += haseval;
+                   return str;
                } else {
                    const char *const typestr = sv_reftype(referent, 0);
+                   const STRLEN typelen = strlen(typestr);
+                   UV addr = PTR2UV(referent);
+                   const char *stashname = NULL;
+                   STRLEN stashnamelen = 0; /* hush, gcc */
+                   const char *buffer_end;
 
-                   tsv = sv_newmortal();
                    if (SvOBJECT(referent)) {
-                       const char *const name = HvNAME_get(SvSTASH(referent));
-                       Perl_sv_setpvf(aTHX_ tsv, "%s=%s(0x%"UVxf")",
-                                      name ? name : "__ANON__" , typestr,
-                                      PTR2UV(referent));
+                       const HEK *const name = HvNAME_HEK(SvSTASH(referent));
+
+                       if (name) {
+                           stashname = HEK_KEY(name);
+                           stashnamelen = HEK_LEN(name);
+
+                           if (HEK_UTF8(name)) {
+                               SvUTF8_on(sv);
+                           } else {
+                               SvUTF8_off(sv);
+                           }
+                       } else {
+                           stashname = "__ANON__";
+                           stashnamelen = 8;
+                       }
+                       len = stashnamelen + 1 /* = */ + typelen + 3 /* (0x */
+                           + 2 * sizeof(UV) + 2 /* )\0 */;
+                   } else {
+                       len = typelen + 3 /* (0x */
+                           + 2 * sizeof(UV) + 2 /* )\0 */;
                    }
-                   else
-                       Perl_sv_setpvf(aTHX_ tsv, "%s(0x%"UVxf")", typestr,
-                                      PTR2UV(referent));
+
+                   Newx(buffer, len, char);
+                   buffer_end = retval = buffer + len;
+
+                   /* Working backwards  */
+                   *--retval = '\0';
+                   *--retval = ')';
+                   do {
+                       *--retval = PL_hexdigit[addr & 15];
+                   } while (addr >>= 4);
+                   *--retval = 'x';
+                   *--retval = '0';
+                   *--retval = '(';
+
+                   retval -= typelen;
+                   memcpy(retval, typestr, typelen);
+
+                   if (stashname) {
+                       *--retval = '=';
+                       retval -= stashnamelen;
+                       memcpy(retval, stashname, stashnamelen);
+                   }
+                   /* retval may not neccesarily have reached the start of the
+                      buffer here.  */
+                   assert (retval >= buffer);
+
+                   len = buffer_end - retval - 1; /* -1 for that \0  */
                }
                if (lp)
-                   *lp = SvCUR(tsv);
-               return SvPVX(tsv);
+                   *lp = len;
+               SAVEFREEPV(buffer);
+               return retval;
            }
        }
        if (SvREADONLY(sv) && !SvOK(sv)) {
@@ -2766,7 +2744,6 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
     if (SvIOK(sv) || ((SvIOKp(sv) && !SvNOKp(sv)))) {
        /* I'm assuming that if both IV and NV are equally valid then
           converting the IV is going to be more efficient */
-       const U32 isIOK = SvIOK(sv);
        const U32 isUIOK = SvIsUV(sv);
        char buf[TYPE_CHARS(UV)];
        char *ebuf, *ptr;
@@ -2780,12 +2757,6 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
        SvCUR_set(sv, ebuf - ptr);
        s = SvEND(sv);
        *s = '\0';
-       if (isIOK)
-           SvIOK_on(sv);
-       else
-           SvIOKp_on(sv);
-       if (isUIOK)
-           SvIsUV_on(sv);
     }
     else if (SvNOKp(sv)) {
        const int olderrno = errno;
@@ -2796,7 +2767,7 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
        /* some Xenix systems wipe out errno here */
 #ifdef apollo
        if (SvNVX(sv) == 0.0)
-           (void)strcpy(s,"0");
+           my_strlcpy(s, "0", SvLEN(sv));
        else
 #endif /*apollo*/
        {
@@ -2805,7 +2776,7 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
        errno = olderrno;
 #ifdef FIXNEGATIVEZERO
         if (*s == '-' && s[1] == '0' && !s[2])
-           strcpy(s,"0");
+           my_strlcpy(s, "0", SvLEN(s));
 #endif
        while (*s) s++;
 #ifdef hcx
@@ -3313,9 +3284,10 @@ S_glob_assign_ref(pTHX_ SV *dstr, SV *sstr) {
                                         || sv_cmp(cv_const_sv(cv),
                                                   cv_const_sv((CV*)sref))))) {
                            Perl_warner(aTHX_ packWARN(WARN_REDEFINE),
-                                       CvCONST(cv)
-                                       ? "Constant subroutine %s::%s redefined"
-                                       : "Subroutine %s::%s redefined",
+                                       (const char *)
+                                       (CvCONST(cv)
+                                        ? "Constant subroutine %s::%s redefined"
+                                        : "Subroutine %s::%s redefined"),
                                        HvNAME_get(GvSTASH((GV*)dstr)),
                                        GvENAME((GV*)dstr));
                        }
@@ -3348,13 +3320,22 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
     dVAR;
     register U32 sflags;
     register int dtype;
-    register int stype;
+    register svtype stype;
 
     if (sstr == dstr)
        return;
+
+    if (SvIS_FREED(dstr)) {
+       Perl_croak(aTHX_ "panic: attempt to copy value %" SVf
+                  " to a freed scalar %p", sstr, dstr);
+    }
     SV_CHECK_THINKFIRST_COW_DROP(dstr);
     if (!sstr)
        sstr = &PL_sv_undef;
+    if (SvIS_FREED(sstr)) {
+       Perl_croak(aTHX_ "panic: attempt to copy freed scalar %p to %p", sstr,
+                  dstr);
+    }
     stype = SvTYPE(sstr);
     dtype = SvTYPE(dstr);
 
@@ -3472,7 +3453,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
     case SVt_PVBM:
        if (SvGMAGICAL(sstr) && (flags & SV_GMAGIC)) {
            mg_get(sstr);
-           if ((int)SvTYPE(sstr) != stype) {
+           if (SvTYPE(sstr) != stype) {
                stype = SvTYPE(sstr);
                if (stype == SVt_PVGV && dtype <= SVt_PVGV) {
                    glob_assign_glob(dstr, sstr, dtype);
@@ -3483,16 +3464,28 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
        if (stype == SVt_PVLV)
            SvUPGRADE(dstr, SVt_PVNV);
        else
-           SvUPGRADE(dstr, (U32)stype);
+           SvUPGRADE(dstr, (svtype)stype);
     }
 
     /* dstr may have been upgraded.  */
     dtype = SvTYPE(dstr);
     sflags = SvFLAGS(sstr);
 
-    if (sflags & SVf_ROK) {
-       if (dtype == SVt_PVGV &&
-           SvROK(sstr) && SvTYPE(SvRV(sstr)) == SVt_PVGV) {
+    if (dtype == SVt_PVCV) {
+       /* Assigning to a subroutine sets the prototype.  */
+       if (SvOK(sstr)) {
+           STRLEN len;
+           const char *const ptr = SvPV_const(sstr, len);
+
+            SvGROW(dstr, len + 1);
+            Copy(ptr, SvPVX(dstr), len + 1, char);
+            SvCUR_set(dstr, len);
+           SvPOK_only(dstr);
+       } else {
+           SvOK_off(dstr);
+       }
+    } else if (sflags & SVf_ROK) {
+       if (dtype == SVt_PVGV && SvTYPE(SvRV(sstr)) == SVt_PVGV) {
            sstr = SvRV(sstr);
            if (sstr == dstr) {
                if (GvIMPORTED(dstr) != GVf_IMPORTED
@@ -3520,7 +3513,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
        }
        (void)SvOK_off(dstr);
        SvRV_set(dstr, SvREFCNT_inc(SvRV(sstr)));
-       SvFLAGS(dstr) |= sflags & (SVf_ROK|SVf_AMAGIC);
+       SvFLAGS(dstr) |= sflags & SVf_ROK;
        assert(!(sflags & SVp_NOK));
        assert(!(sflags & SVp_IOK));
        assert(!(sflags & SVf_NOK));
@@ -3549,6 +3542,9 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
         * possible small lose on short strings, but a big win on long ones.
         * It might even be a win on short strings if SvPVX_const(dstr)
         * has to be allocated and SvPVX_const(sstr) has to be freed.
+        * Likewise if we can set up COW rather than doing an actual copy, we
+        * drop to the else clause, as the swipe code and the COW setup code
+        * have much in common.
         */
 
        /* Whichever path we take through the next code, we want this true,
@@ -3556,10 +3552,28 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
        (void)SvPOK_only(dstr);
 
        if (
-           /* We're not already COW  */
-            ((sflags & (SVf_FAKE | SVf_READONLY)) != (SVf_FAKE | SVf_READONLY)
+           /* If we're already COW then this clause is not true, and if COW
+              is allowed then we drop down to the else and make dest COW 
+              with us.  If caller hasn't said that we're allowed to COW
+              shared hash keys then we don't do the COW setup, even if the
+              source scalar is a shared hash key scalar.  */
+            (((flags & SV_COW_SHARED_HASH_KEYS)
+              ? (sflags & (SVf_FAKE|SVf_READONLY)) != (SVf_FAKE|SVf_READONLY)
+              : 1 /* If making a COW copy is forbidden then the behaviour we
+                      desire is as if the source SV isn't actually already
+                      COW, even if it is.  So we act as if the source flags
+                      are not COW, rather than actually testing them.  */
+             )
 #ifndef PERL_OLD_COPY_ON_WRITE
-            /* or we are, but dstr isn't a suitable target.  */
+            /* The change that added SV_COW_SHARED_HASH_KEYS makes the logic
+               when PERL_OLD_COPY_ON_WRITE is defined a little wrong.
+               Conceptually PERL_OLD_COPY_ON_WRITE being defined should
+               override SV_COW_SHARED_HASH_KEYS, because it means "always COW"
+               but in turn, it's somewhat dead code, never expected to go
+               live, but more kept as a placeholder on how to do it better
+               in a newer implementation.  */
+            /* If we are COW and dstr is a suitable target then we drop down
+               into the else and make dest a COW of us.  */
             || (SvFLAGS(dstr) & CAN_COW_MASK) != CAN_COW_FLAGS
 #endif
             )
@@ -3673,8 +3687,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
            if (sflags & SVf_IVisUV)
                SvIsUV_on(dstr);
        }
-       SvFLAGS(dstr) |= sflags & (SVf_IOK|SVp_IOK|SVf_NOK|SVp_NOK|SVf_UTF8
-                                  |SVf_AMAGIC);
+       SvFLAGS(dstr) |= sflags & (SVf_IOK|SVp_IOK|SVf_NOK|SVp_NOK|SVf_UTF8);
        {
            const MAGIC * const smg = SvVSTRING_mg(sstr);
            if (smg) {
@@ -3686,8 +3699,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
     }
     else if (sflags & (SVp_IOK|SVp_NOK)) {
        (void)SvOK_off(dstr);
-       SvFLAGS(dstr) |= sflags & (SVf_IOK|SVp_IOK|SVf_IVisUV|SVf_NOK|SVp_NOK
-                                  |SVf_AMAGIC);
+       SvFLAGS(dstr) |= sflags & (SVf_IOK|SVp_IOK|SVf_IVisUV|SVf_NOK|SVp_NOK);
        if (sflags & SVp_IOK) {
            /* XXXX Do we want to set IsUV for IV(ROK)?  Be extra safe... */
            SvIV_set(dstr, SvIVX(sstr));
@@ -3707,7 +3719,6 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
            SvFAKE_off(sstr);
            gv_efullname3(dstr, (GV *)sstr, "*");
            SvFLAGS(sstr) |= wasfake;
-           SvFLAGS(dstr) |= sflags & SVf_AMAGIC;
        }
        else
            (void)SvOK_off(dstr);
@@ -3933,8 +3944,10 @@ Perl_sv_usepvn_flags(pTHX_ SV *sv, char *ptr, STRLEN len, U32 flags)
     if (SvPVX_const(sv))
        SvPV_free(sv);
 
+#ifdef DEBUGGING
     if (flags & SV_HAS_TRAILING_NUL)
        assert(ptr[len] == '\0');
+#endif
 
     allocate = (flags & SV_HAS_TRAILING_NUL)
        ? len + 1: PERL_STRLEN_ROUNDUP(len + 1);
@@ -3944,13 +3957,13 @@ Perl_sv_usepvn_flags(pTHX_ SV *sv, char *ptr, STRLEN len, U32 flags)
     } else {
 #ifdef DEBUGGING
        /* Force a move to shake out bugs in callers.  */
-       char *new_ptr = safemalloc(allocate);
+       char *new_ptr = (char*)safemalloc(allocate);
        Copy(ptr, new_ptr, len, char);
        PoisonFree(ptr,len,char);
        Safefree(ptr);
        ptr = new_ptr;
 #else
-       ptr = saferealloc (ptr, allocate);
+       ptr = (char*) saferealloc (ptr, allocate);
 #endif
     }
     SvPV_set(sv, ptr);
@@ -4476,6 +4489,9 @@ Perl_sv_magic(pTHX_ register SV *sv, SV *obj, int how, const char *name, I32 nam
     case PERL_MAGIC_regdata:
        vtable = &PL_vtbl_regdata;
        break;
+    case PERL_MAGIC_regdata_names:
+       vtable = &PL_vtbl_regdata_names;
+       break;
     case PERL_MAGIC_regdatum:
        vtable = &PL_vtbl_regdatum;
        break;
@@ -4642,7 +4658,8 @@ Perl_sv_unmagic(pTHX_ SV *sv, int type)
 Weaken a reference: set the C<SvWEAKREF> flag on this RV; give the
 referred-to SV C<PERL_MAGIC_backref> magic if it hasn't already; and
 push a back-reference to this RV onto the array of backreferences
-associated with that magic.
+associated with that magic. If the RV is magical, set magic will be
+called after the RV is cleared.
 
 =cut
 */
@@ -4795,6 +4812,7 @@ Perl_sv_kill_backrefs(pTHX_ SV *sv, AV *av)
                    SvRV_set(referrer, 0);
                    SvOK_off(referrer);
                    SvWEAKREF_off(referrer);
+                   SvSETMAGIC(referrer);
                } else if (SvTYPE(referrer) == SVt_PVGV ||
                           SvTYPE(referrer) == SVt_PVLV) {
                    /* You lookin' at me?  */
@@ -5343,8 +5361,8 @@ Perl_sv_len_utf8(pTHX_ register SV *sv)
                        */
                        SAVEI8(PL_utf8cache);
                        PL_utf8cache = 0;
-                       Perl_croak(aTHX_ "panic: sv_len_utf8 cache %"UVf
-                                  " real %"UVf" for %"SVf,
+                       Perl_croak(aTHX_ "panic: sv_len_utf8 cache %"UVuf
+                                  " real %"UVuf" for %"SVf,
                                   (UV) ulen, (UV) real, (void*)sv);
                    }
                }
@@ -5501,8 +5519,8 @@ S_sv_pos_u2b_cached(pTHX_ SV *sv, MAGIC **mgp, const U8 *const start,
                   infinitely while printing error messages.  */
                SAVEI8(PL_utf8cache);
                PL_utf8cache = 0;
-               Perl_croak(aTHX_ "panic: sv_pos_u2b_cache cache %"UVf
-                          " real %"UVf" for %"SVf,
+               Perl_croak(aTHX_ "panic: sv_pos_u2b_cache cache %"UVuf
+                          " real %"UVuf" for %"SVf,
                           (UV) boffset, (UV) real_boffset, (void*)sv);
            }
        }
@@ -5617,26 +5635,15 @@ S_utf8_mg_pos_cache_update(pTHX_ SV *sv, MAGIC **mgp, STRLEN byte, STRLEN utf8,
 
     if (PL_utf8cache < 0) {
        const U8 *start = (const U8 *) SvPVX_const(sv);
-       const U8 *const end = start + byte;
-       STRLEN realutf8 = 0;
-
-       while (start < end) {
-           start += UTF8SKIP(start);
-           realutf8++;
-       }
-
-       /* Can't use S_sv_pos_b2u_forwards as it will scream warnings on
-          surrogates.  FIXME - is it inconsistent that b2u warns, but u2b
-          doesn't?  I don't know whether this difference was introduced with
-          the caching code in 5.8.1.  */
+       const STRLEN realutf8 = utf8_length(start, start + byte);
 
        if (realutf8 != utf8) {
            /* Need to turn the assertions off otherwise we may recurse
               infinitely while printing error messages.  */
            SAVEI8(PL_utf8cache);
            PL_utf8cache = 0;
-           Perl_croak(aTHX_ "panic: utf8_mg_pos_cache_update cache %"UVf
-                      " real %"UVf" for %"SVf, (UV) utf8, (UV) realutf8, (void*)sv);
+           Perl_croak(aTHX_ "panic: utf8_mg_pos_cache_update cache %"UVuf
+                      " real %"UVuf" for %"SVf, (UV) utf8, (UV) realutf8, (void*)sv);
        }
     }
 
@@ -5739,29 +5746,6 @@ S_utf8_mg_pos_cache_update(pTHX_ SV *sv, MAGIC **mgp, STRLEN byte, STRLEN utf8,
     ASSERT_UTF8_CACHE(cache);
 }
 
-/* If we don't know the character offset of the end of a region, our only
-   option is to walk forwards to the target byte offset.  */
-static STRLEN
-S_sv_pos_b2u_forwards(pTHX_ const U8 *s, const U8 *const target)
-{
-    STRLEN len = 0;
-    while (s < target) {
-       STRLEN n = 1;
-
-       /* Call utf8n_to_uvchr() to validate the sequence
-        * (unless a simple non-UTF character) */
-       if (!UTF8_IS_INVARIANT(*s))
-           utf8n_to_uvchr(s, UTF8SKIP(s), &n, 0);
-       if (n > 0) {
-           s += n;
-           len++;
-       }
-       else
-           break;
-    }
-    return len;
-}
-
 /* We already know all of the way, now we may be able to walk back.  The same
    assumption is made as in S_sv_pos_u2b_midway(), namely that walking
    backward is half the speed of walking forward. */
@@ -5773,7 +5757,7 @@ S_sv_pos_b2u_midway(pTHX_ const U8 *s, const U8 *const target, const U8 *end,
     STRLEN backw = end - target;
 
     if (forw < 2 * backw) {
-       return S_sv_pos_b2u_forwards(aTHX_ s, target);
+       return utf8_length(s, target);
     }
 
     while (end > target) {
@@ -5846,8 +5830,7 @@ Perl_sv_pos_b2u(pTHX_ register SV* sv, I32* offsetp)
                        + S_sv_pos_b2u_midway(aTHX_ s + cache[1], send,
                                              s + blen, mg->mg_len - cache[0]);
                } else {
-                   len = cache[0]
-                       + S_sv_pos_b2u_forwards(aTHX_ s + cache[1], send);
+                   len = cache[0] + utf8_length(s + cache[1], send);
                }
            }
            else if (cache[3] < byte) {
@@ -5873,7 +5856,7 @@ Perl_sv_pos_b2u(pTHX_ register SV* sv, I32* offsetp)
        }
     }
     if (!found || PL_utf8cache < 0) {
-       const STRLEN real_len = S_sv_pos_b2u_forwards(aTHX_ s, send);
+       const STRLEN real_len = utf8_length(s, send);
 
        if (found && PL_utf8cache < 0) {
            if (len != real_len) {
@@ -5881,8 +5864,8 @@ Perl_sv_pos_b2u(pTHX_ register SV* sv, I32* offsetp)
                   infinitely while printing error messages.  */
                SAVEI8(PL_utf8cache);
                PL_utf8cache = 0;
-               Perl_croak(aTHX_ "panic: sv_pos_b2u cache %"UVf
-                          " real %"UVf" for %"SVf,
+               Perl_croak(aTHX_ "panic: sv_pos_b2u cache %"UVuf
+                          " real %"UVuf" for %"SVf,
                           (UV) len, (UV) real_len, (void*)sv);
            }
        }
@@ -5919,8 +5902,16 @@ Perl_sv_eq(pTHX_ register SV *sv1, register SV *sv2)
        pv1 = "";
        cur1 = 0;
     }
-    else
+    else {
+       /* if pv1 and pv2 are the same, second SvPV_const call may
+        * invalidate pv1, so we may need to make a copy */
+       if (sv1 == sv2 && (SvTHINKFIRST(sv1) || SvGMAGICAL(sv1))) {
+           pv1 = SvPV_const(sv1, cur1);
+           sv1 = sv_2mortal(newSVpvn(pv1, cur1));
+           if (SvUTF8(sv2)) SvUTF8_on(sv1);
+       }
        pv1 = SvPV_const(sv1, cur1);
+    }
 
     if (!sv2){
        pv2 = "";
@@ -6916,7 +6907,7 @@ Perl_newSVpv(pTHX_ const char *s, STRLEN len)
     register SV *sv;
 
     new_SV(sv);
-    sv_setpvn(sv,s,len ? len : strlen(s));
+    sv_setpvn(sv, s, len || s == NULL ? len : strlen(s));
     return sv;
 }
 
@@ -7613,7 +7604,7 @@ Returns a string describing what the SV is a reference to.
 =cut
 */
 
-char *
+const char *
 Perl_sv_reftype(pTHX_ const SV *sv, int ob)
 {
     /* The fact that I don't need to downcast to char * everywhere, only in ?:
@@ -8590,7 +8581,10 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            switch (*q) {
            case ' ':
            case '+':
-               plus = *q++;
+               if (plus == '+' && *q == ' ') /* '+' over ' ' */
+                   q++;
+               else
+                   plus = *q++;
                continue;
 
            case '-':
@@ -8727,14 +8721,15 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                else
                    i = (ewix ? ewix <= svmax : svix < svmax)
                        ? SvIVx(svargs[ewix ? ewix-1 : svix++]) : 0;
-               precis = (i < 0) ? 0 : i;
+               precis = i;
+               has_precis = !(i < 0);
            }
            else {
                precis = 0;
                while (isDIGIT(*q))
                    precis = precis * 10 + (*q++ - '0');
+               has_precis = TRUE;
            }
-           has_precis = TRUE;
        }
 
        /* SIZE */
@@ -8850,13 +8845,17 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            else {
                eptr = SvPVx_const(argsv, elen);
                if (DO_UTF8(argsv)) {
+                   I32 old_precis = precis;
                    if (has_precis && precis < elen) {
                        I32 p = precis;
                        sv_pos_u2b(argsv, &p, 0); /* sticks at end */
                        precis = p;
                    }
                    if (width) { /* fudge width (can't fudge elen) */
-                       width += elen - sv_len_utf8(argsv);
+                       if (has_precis && precis < elen)
+                           width += precis - old_precis;
+                       else
+                           width += elen - sv_len_utf8(argsv);
                    }
                    is_utf8 = TRUE;
                }
@@ -8953,6 +8952,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
            base = 10;
            goto uns_integer;
 
+       case 'B':
        case 'b':
            base = 2;
            goto uns_integer;
@@ -9015,18 +9015,18 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
        integer:
            {
                char *ptr = ebuf + sizeof ebuf;
+               bool tempalt = uv ? alt : FALSE; /* Vectors can't change alt */
+               zeros = 0;
+
                switch (base) {
                    unsigned dig;
                case 16:
-                   if (!uv)
-                       alt = FALSE;
-                   p = (char*)((c == 'X')
-                               ? "0123456789ABCDEF" : "0123456789abcdef");
+                   p = (char *)((c == 'X') ? PL_hexdigit + 16 : PL_hexdigit);
                    do {
                        dig = uv & 15;
                        *--ptr = p[dig];
                    } while (uv >>= 4);
-                   if (alt) {
+                   if (tempalt) {
                        esignbuf[esignlen++] = '0';
                        esignbuf[esignlen++] = c;  /* 'x' or 'X' */
                    }
@@ -9040,15 +9040,13 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                        *--ptr = '0';
                    break;
                case 2:
-                   if (!uv)
-                       alt = FALSE;
                    do {
                        dig = uv & 1;
                        *--ptr = '0' + dig;
                    } while (uv >>= 1);
-                   if (alt) {
+                   if (tempalt) {
                        esignbuf[esignlen++] = '0';
-                       esignbuf[esignlen++] = 'b';
+                       esignbuf[esignlen++] = c;
                    }
                    break;
                default:                /* it had better be ten or less */
@@ -9063,8 +9061,13 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                if (has_precis) {
                    if (precis > elen)
                        zeros = precis - elen;
-                   else if (precis == 0 && elen == 1 && *eptr == '0')
+                   else if (precis == 0 && elen == 1 && *eptr == '0'
+                            && !(base == 8 && alt)) /* "%#.0o" prints "0" */
                        elen = 0;
+
+               /* a precision nullifies the 0 flag. */
+                   if (fill == '0')
+                       fill = ' ';
                }
            }
            break;
@@ -9442,8 +9445,8 @@ ptr_table_* functions.
 
 
 /* Certain cases in Perl_ss_dup have been merged, by relying on the fact
-   that currently av_dup and hv_dup are the same as sv_dup. If this changes,
-   please unmerge ss_dup.  */
+   that currently av_dup, gv_dup and hv_dup are the same as sv_dup.
+   If this changes, please unmerge ss_dup.  */
 #define sv_dup_inc(s,t)        SvREFCNT_inc(sv_dup(s,t))
 #define sv_dup_inc_NN(s,t)     SvREFCNT_inc_NN(sv_dup(s,t))
 #define av_dup(s,t)    (AV*)sv_dup((SV*)s,t)
@@ -9460,134 +9463,6 @@ ptr_table_* functions.
 #define SAVEPVN(p,n)   ((p) ? savepvn(p,n) : NULL)
 
 
-/* Duplicate a regexp. Required reading: pregcomp() and pregfree() in
-   regcomp.c. AMS 20010712 */
-
-REGEXP *
-Perl_re_dup(pTHX_ const REGEXP *r, CLONE_PARAMS *param)
-{
-    dVAR;
-    REGEXP *ret;
-    int i, len, npar;
-    struct reg_substr_datum *s;
-
-    if (!r)
-       return (REGEXP *)NULL;
-
-    if ((ret = (REGEXP *)ptr_table_fetch(PL_ptr_table, r)))
-       return ret;
-
-    len = r->offsets[0];
-    npar = r->nparens+1;
-
-    Newxc(ret, sizeof(regexp) + (len+1)*sizeof(regnode), char, regexp);
-    Copy(r->program, ret->program, len+1, regnode);
-
-    Newx(ret->startp, npar, I32);
-    Copy(r->startp, ret->startp, npar, I32);
-    Newx(ret->endp, npar, I32);
-    Copy(r->startp, ret->startp, npar, I32);
-
-    Newx(ret->substrs, 1, struct reg_substr_data);
-    for (s = ret->substrs->data, i = 0; i < 3; i++, s++) {
-       s->min_offset = r->substrs->data[i].min_offset;
-       s->max_offset = r->substrs->data[i].max_offset;
-       s->substr     = sv_dup_inc(r->substrs->data[i].substr, param);
-       s->utf8_substr = sv_dup_inc(r->substrs->data[i].utf8_substr, param);
-    }
-
-    ret->regstclass = NULL;
-    if (r->data) {
-       struct reg_data *d;
-        const int count = r->data->count;
-       int i;
-
-       Newxc(d, sizeof(struct reg_data) + count*sizeof(void *),
-               char, struct reg_data);
-       Newx(d->what, count, U8);
-
-       d->count = count;
-       for (i = 0; i < count; i++) {
-           d->what[i] = r->data->what[i];
-           switch (d->what[i]) {
-               /* legal options are one of: sfpont
-                  see also regcomp.h and pregfree() */
-           case 's':
-               d->data[i] = sv_dup_inc((SV *)r->data->data[i], param);
-               break;
-           case 'p':
-               d->data[i] = av_dup_inc((AV *)r->data->data[i], param);
-               break;
-           case 'f':
-               /* This is cheating. */
-               Newx(d->data[i], 1, struct regnode_charclass_class);
-               StructCopy(r->data->data[i], d->data[i],
-                           struct regnode_charclass_class);
-               ret->regstclass = (regnode*)d->data[i];
-               break;
-           case 'o':
-               /* Compiled op trees are readonly, and can thus be
-                  shared without duplication. */
-               OP_REFCNT_LOCK;
-               d->data[i] = (void*)OpREFCNT_inc((OP*)r->data->data[i]);
-               OP_REFCNT_UNLOCK;
-               break;
-           case 'n':
-               d->data[i] = r->data->data[i];
-               break;
-           case 't':
-               d->data[i] = r->data->data[i];
-               OP_REFCNT_LOCK;
-               ((reg_trie_data*)d->data[i])->refcount++;
-               OP_REFCNT_UNLOCK;
-               break;
-           case 'T':
-               d->data[i] = r->data->data[i];
-               OP_REFCNT_LOCK;
-               ((reg_ac_data*)d->data[i])->refcount++;
-               OP_REFCNT_UNLOCK;
-               /* Trie stclasses are readonly and can thus be shared
-                * without duplication. We free the stclass in pregfree
-                * when the corresponding reg_ac_data struct is freed.
-                */
-               ret->regstclass= r->regstclass;
-               break;
-            default:
-               Perl_croak(aTHX_ "panic: re_dup unknown data code '%c'", r->data->what[i]);
-           }
-       }
-
-       ret->data = d;
-    }
-    else
-       ret->data = NULL;
-
-    Newx(ret->offsets, 2*len+1, U32);
-    Copy(r->offsets, ret->offsets, 2*len+1, U32);
-
-    ret->precomp        = SAVEPVN(r->precomp, r->prelen);
-    ret->refcnt         = r->refcnt;
-    ret->minlen         = r->minlen;
-    ret->prelen         = r->prelen;
-    ret->nparens        = r->nparens;
-    ret->lastparen      = r->lastparen;
-    ret->lastcloseparen = r->lastcloseparen;
-    ret->reganch        = r->reganch;
-
-    ret->sublen         = r->sublen;
-
-    if (RX_MATCH_COPIED(ret))
-       ret->subbeg  = SAVEPVN(r->subbeg, r->sublen);
-    else
-       ret->subbeg = NULL;
-#ifdef PERL_OLD_COPY_ON_WRITE
-    ret->saved_copy = NULL;
-#endif
-
-    ptr_table_store(PL_ptr_table, r, ret);
-    return ret;
-}
-
 /* duplicate a file handle */
 
 PerlIO *
@@ -9682,7 +9557,7 @@ Perl_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS* param)
        nmg->mg_type    = mg->mg_type;
        nmg->mg_flags   = mg->mg_flags;
        if (mg->mg_type == PERL_MAGIC_qr) {
-           nmg->mg_obj = (SV*)re_dup((REGEXP*)mg->mg_obj, param);
+           nmg->mg_obj = (SV*)CALLREGDUPE((REGEXP*)mg->mg_obj, param);
        }
        else if(mg->mg_type == PERL_MAGIC_backref) {
            /* The backref AV has its reference count deliberately bumped by
@@ -10129,7 +10004,7 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* param)
                    src_ary = AvARRAY((AV*)sstr);
                    Newxz(dst_ary, AvMAX((AV*)sstr)+1, SV*);
                    ptr_table_store(PL_ptr_table, src_ary, dst_ary);
-                   SvPV_set(dstr, (char*)dst_ary);
+                   AvARRAY((AV*)dstr) = dst_ary;
                    AvALLOC((AV*)dstr) = dst_ary;
                    if (AvREAL((AV*)sstr)) {
                        while (items-- > 0)
@@ -10145,7 +10020,7 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* param)
                    }
                }
                else {
-                   SvPV_set(dstr, NULL);
+                   AvARRAY((AV*)dstr)  = NULL;
                    AvALLOC((AV*)dstr)  = (SV**)NULL;
                }
                break;
@@ -10192,7 +10067,7 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* param)
                    }
                }
                else
-                   SvPV_set(dstr, NULL);
+                   HvARRAY((HV*)dstr) = NULL;
                break;
            case SVt_PVCV:
                if (!(param->flags & CLONEf_COPY_STACKS)) {
@@ -10292,9 +10167,7 @@ Perl_cx_dup(pTHX_ PERL_CONTEXT *cxs, I32 ix, I32 max, CLONE_PARAMS* param)
            case CXt_LOOP:
                ncx->blk_loop.label     = cx->blk_loop.label;
                ncx->blk_loop.resetsp   = cx->blk_loop.resetsp;
-               ncx->blk_loop.redo_op   = cx->blk_loop.redo_op;
-               ncx->blk_loop.next_op   = cx->blk_loop.next_op;
-               ncx->blk_loop.last_op   = cx->blk_loop.last_op;
+               ncx->blk_loop.my_op     = cx->blk_loop.my_op;
                ncx->blk_loop.iterdata  = (CxPADLOOP(cx)
                                           ? cx->blk_loop.iterdata
                                           : gv_dup((GV*)cx->blk_loop.iterdata, param));
@@ -10420,6 +10293,7 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
     long longval;
     GP *gp;
     IV iv;
+    I32 i;
     char *c = NULL;
     void (*dptr) (void*);
     void (*dxptr) (pTHX_ void*);
@@ -10427,13 +10301,20 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
     Newxz(nss, max, ANY);
 
     while (ix > 0) {
-       I32 i = POPINT(ss,ix);
-       TOPINT(nss,ix) = i;
-       switch (i) {
+       const I32 type = POPINT(ss,ix);
+       TOPINT(nss,ix) = type;
+       switch (type) {
+       case SAVEt_HELEM:               /* hash element */
+           sv = (SV*)POPPTR(ss,ix);
+           TOPPTR(nss,ix) = sv_dup_inc(sv, param);
+           /* fall through */
        case SAVEt_ITEM:                        /* normal string */
         case SAVEt_SV:                         /* scalar reference */
            sv = (SV*)POPPTR(ss,ix);
            TOPPTR(nss,ix) = sv_dup_inc(sv, param);
+           /* fall through */
+       case SAVEt_FREESV:
+       case SAVEt_MORTALIZESV:
            sv = (SV*)POPPTR(ss,ix);
            TOPPTR(nss,ix) = sv_dup_inc(sv, param);
            break;
@@ -10452,10 +10333,13 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
            break;
         case SAVEt_HV:                         /* hash reference */
         case SAVEt_AV:                         /* array reference */
-           sv = POPPTR(ss,ix);
+           sv = (SV*) POPPTR(ss,ix);
            TOPPTR(nss,ix) = sv_dup_inc(sv, param);
-           gv = (GV*)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = gv_dup(gv, param);
+           /* fall through */
+       case SAVEt_COMPPAD:
+       case SAVEt_NSTAB:
+           sv = (SV*) POPPTR(ss,ix);
+           TOPPTR(nss,ix) = sv_dup(sv, param);
            break;
        case SAVEt_INT:                         /* int reference */
            ptr = POPPTR(ss,ix);
@@ -10466,6 +10350,8 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
        case SAVEt_LONG:                        /* long reference */
            ptr = POPPTR(ss,ix);
            TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
+           /* fall through */
+       case SAVEt_CLEARSV:
            longval = (long)POPLONG(ss,ix);
            TOPLONG(nss,ix) = longval;
            break;
@@ -10505,28 +10391,13 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
            c = (char*)POPPTR(ss,ix);
            TOPPTR(nss,ix) = pv_dup(c);
            break;
-       case SAVEt_NSTAB:
-           gv = (GV*)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = gv_dup(gv, param);
-           break;
        case SAVEt_GP:                          /* scalar reference */
            gp = (GP*)POPPTR(ss,ix);
            TOPPTR(nss,ix) = gp = gp_dup(gp, param);
            (void)GpREFCNT_inc(gp);
            gv = (GV*)POPPTR(ss,ix);
            TOPPTR(nss,ix) = gv_dup_inc(gv, param);
-            c = (char*)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = pv_dup(c);
-           iv = POPIV(ss,ix);
-           TOPIV(nss,ix) = iv;
-           iv = POPIV(ss,ix);
-           TOPIV(nss,ix) = iv;
             break;
-       case SAVEt_FREESV:
-       case SAVEt_MORTALIZESV:
-           sv = (SV*)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = sv_dup_inc(sv, param);
-           break;
        case SAVEt_FREEOP:
            ptr = POPPTR(ss,ix);
            if (ptr && (((OP*)ptr)->op_private & OPpREFCOUNTED)) {
@@ -10541,7 +10412,9 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
                case OP_LEAVEWRITE:
                    TOPPTR(nss,ix) = ptr;
                    o = (OP*)ptr;
+                   OP_REFCNT_LOCK;
                    OpREFCNT_inc(o);
+                   OP_REFCNT_UNLOCK;
                    break;
                default:
                    TOPPTR(nss,ix) = NULL;
@@ -10555,15 +10428,13 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
            c = (char*)POPPTR(ss,ix);
            TOPPTR(nss,ix) = pv_dup_inc(c);
            break;
-       case SAVEt_CLEARSV:
-           longval = POPLONG(ss,ix);
-           TOPLONG(nss,ix) = longval;
-           break;
        case SAVEt_DELETE:
            hv = (HV*)POPPTR(ss,ix);
            TOPPTR(nss,ix) = hv_dup_inc(hv, param);
            c = (char*)POPPTR(ss,ix);
            TOPPTR(nss,ix) = pv_dup_inc(c);
+           /* fall through */
+       case SAVEt_STACK_POS:           /* Position on Perl stack */
            i = POPINT(ss,ix);
            TOPINT(nss,ix) = i;
            break;
@@ -10589,10 +10460,6 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
            TOPINT(nss,ix) = i;
            ix -= i;
            break;
-       case SAVEt_STACK_POS:           /* Position on Perl stack */
-           i = POPINT(ss,ix);
-           TOPINT(nss,ix) = i;
-           break;
        case SAVEt_AELEM:               /* array element */
            sv = (SV*)POPPTR(ss,ix);
            TOPPTR(nss,ix) = sv_dup_inc(sv, param);
@@ -10601,14 +10468,6 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
            av = (AV*)POPPTR(ss,ix);
            TOPPTR(nss,ix) = av_dup_inc(av, param);
            break;
-       case SAVEt_HELEM:               /* hash element */
-           sv = (SV*)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = sv_dup_inc(sv, param);
-           sv = (SV*)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = sv_dup_inc(sv, param);
-           hv = (HV*)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = hv_dup_inc(hv, param);
-           break;
        case SAVEt_OP:
            ptr = POPPTR(ss,ix);
            TOPPTR(nss,ix) = ptr;
@@ -10628,10 +10487,6 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
                TOPPTR(nss,ix) = hv_dup_inc(hv, param);
            }
            break;
-       case SAVEt_COMPPAD:
-           av = (AV*)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = av_dup(av, param);
-           break;
        case SAVEt_PADSV:
            longval = (long)POPLONG(ss,ix);
            TOPLONG(nss,ix) = longval;
@@ -10673,13 +10528,14 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
                new_state->re_state_regeol
                    = pv_dup(old_state->re_state_regeol);
                new_state->re_state_regstartp
-                   = any_dup(old_state->re_state_regstartp, proto_perl);
+                   = (I32*) any_dup(old_state->re_state_regstartp, proto_perl);
                new_state->re_state_regendp
-                   = any_dup(old_state->re_state_regendp, proto_perl);
+                   = (I32*) any_dup(old_state->re_state_regendp, proto_perl);
                new_state->re_state_reglastparen
-                   = any_dup(old_state->re_state_reglastparen, proto_perl);
+                   = (U32*) any_dup(old_state->re_state_reglastparen, 
+                             proto_perl);
                new_state->re_state_reglastcloseparen
-                   = any_dup(old_state->re_state_reglastcloseparen,
+                   = (U32*)any_dup(old_state->re_state_reglastcloseparen,
                              proto_perl);
                /* XXX This just has to be broken. The old save_re_context
                   code did SAVEGENERICPV(PL_reg_start_tmp);
@@ -10699,11 +10555,14 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
                    = sv_dup(old_state->re_state_nrs, param);
 #endif
                new_state->re_state_reg_magic
-                   = any_dup(old_state->re_state_reg_magic, proto_perl);
+                   = (MAGIC*) any_dup(old_state->re_state_reg_magic, 
+                              proto_perl);
                new_state->re_state_reg_oldcurpm
-                   = any_dup(old_state->re_state_reg_oldcurpm, proto_perl);
+                   = (PMOP*) any_dup(old_state->re_state_reg_oldcurpm, 
+                             proto_perl);
                new_state->re_state_reg_curpm
-                   = any_dup(old_state->re_state_reg_curpm, proto_perl);
+                   = (PMOP*)  any_dup(old_state->re_state_reg_curpm, 
+                              proto_perl);
                new_state->re_state_reg_oldsaved
                    = pv_dup(old_state->re_state_reg_oldsaved);
                new_state->re_state_reg_poscache
@@ -10717,7 +10576,8 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
            TOPPTR(nss,ix) = DUP_WARNINGS((STRLEN*)ptr);
            break;
        default:
-           Perl_croak(aTHX_ "panic: ss_dup inconsistency (%"IVdf")", (IV) i);
+           Perl_croak(aTHX_
+                      "panic: ss_dup inconsistency (%"IVdf")", (IV) type);
        }
     }
 
@@ -11040,6 +10900,12 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     sv_setpvn(PERL_DEBUG_PAD(1), "", 0);       /* ext/re needs these */
     sv_setpvn(PERL_DEBUG_PAD(2), "", 0);       /* even without DEBUGGING. */
 
+   
+    /* RE engine related */
+    Zero(&PL_reg_state, 1, struct re_save_state);
+    PL_reginterp_cnt   = 0;
+    PL_regmatch_slab   = NULL;
+    
     /* Clone the regex array */
     PL_regex_padav = newAV();
     {
@@ -11053,7 +10919,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
                SvREPADTMP(regex)
                    ? sv_dup_inc(regex, param)
                    : SvREFCNT_inc(
-                       newSViv(PTR2IV(re_dup(
+                       newSViv(PTR2IV(CALLREGDUPE(
                                INT2PTR(REGEXP *, SvIVX(regex)), param))))
                ;
            av_push(PL_regex_padav, sv);
@@ -11096,6 +10962,8 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_beginav         = av_dup_inc(proto_perl->Ibeginav, param);
     PL_beginav_save    = av_dup_inc(proto_perl->Ibeginav_save, param);
     PL_checkav_save    = av_dup_inc(proto_perl->Icheckav_save, param);
+    PL_unitcheckav      = av_dup_inc(proto_perl->Iunitcheckav, param);
+    PL_unitcheckav_save = av_dup_inc(proto_perl->Iunitcheckav_save, param);
     PL_endav           = av_dup_inc(proto_perl->Iendav, param);
     PL_checkav         = av_dup_inc(proto_perl->Icheckav, param);
     PL_initav          = av_dup_inc(proto_perl->Iinitav, param);
@@ -11118,7 +10986,9 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
     /* current interpreter roots */
     PL_main_cv         = cv_dup_inc(proto_perl->Imain_cv, param);
+    OP_REFCNT_LOCK;
     PL_main_root       = OpREFCNT_inc(proto_perl->Imain_root);
+    OP_REFCNT_UNLOCK;
     PL_main_start      = proto_perl->Imain_start;
     PL_eval_root       = proto_perl->Ieval_root;
     PL_eval_start      = proto_perl->Ieval_start;
@@ -11384,7 +11254,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
     PL_glob_index      = proto_perl->Iglob_index;
     PL_srand_called    = proto_perl->Isrand_called;
-    PL_uudmap['M']     = 0;            /* reinits on demand */
+    PL_uudmap[(U32) 'M']       = 0;    /* reinits on demand */
     PL_bitcount                = NULL; /* reinits on demand */
 
     if (proto_perl->Ipsig_pend) {
@@ -11538,15 +11408,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_colorset                = 0;            /* reinits PL_colors[] */
     /*PL_colors[6]     = {0,0,0,0,0,0};*/
 
-    /* RE engine - function pointers */
-    PL_regcompp                = proto_perl->Tregcompp;
-    PL_regexecp                = proto_perl->Tregexecp;
-    PL_regint_start    = proto_perl->Tregint_start;
-    PL_regint_string   = proto_perl->Tregint_string;
-    PL_regfree         = proto_perl->Tregfree;
-    Zero(&PL_reg_state, 1, struct re_save_state);
-    PL_reginterp_cnt   = 0;
-    PL_regmatch_slab   = NULL;
+
 
     /* Pluggable optimizer */
     PL_peepp           = proto_perl->Tpeepp;