Add "state" feature
[p5sagit/p5-mst-13.2.git] / sv.c
diff --git a/sv.c b/sv.c
index e84b0e5..dcc7a89 100644 (file)
--- a/sv.c
+++ b/sv.c
  *   lib/utf8.t lib/Unicode/Collate/t/index.t
  * --jhi
  */
-#define ASSERT_UTF8_CACHE(cache) \
+#   define ASSERT_UTF8_CACHE(cache) \
     STMT_START { if (cache) { assert((cache)[0] <= (cache)[1]); \
                              assert((cache)[2] <= (cache)[3]); \
                              assert((cache)[3] <= (cache)[1]);} \
                              } STMT_END
 #else
-#define ASSERT_UTF8_CACHE(cache) NOOP
+#   define ASSERT_UTF8_CACHE(cache) NOOP
 #endif
 
 #ifdef PERL_OLD_COPY_ON_WRITE
@@ -678,6 +678,7 @@ Perl_sv_free_arenas(pTHX)
 void*
 Perl_get_arena(pTHX_ int arena_size)
 {
+    dVAR;
     struct arena_desc* adesc;
     struct arena_set *newroot, **aroot = (struct arena_set**) &PL_body_arenas;
     int curr;
@@ -692,7 +693,7 @@ Perl_get_arena(pTHX_ int arena_size)
        newroot->set_size = ARENAS_PER_SET;
        newroot->next = *aroot;
        *aroot = newroot;
-       DEBUG_m(PerlIO_printf(Perl_debug_log, "new arenaset %p\n", *aroot));
+       DEBUG_m(PerlIO_printf(Perl_debug_log, "new arenaset %p\n", (void*)*aroot));
     }
 
     /* ok, now have arena-set with at least 1 empty/available arena-desc */
@@ -1717,8 +1718,29 @@ Perl_looks_like_number(pTHX_ SV *sv)
     return grok_number(sbegin, len, NULL);
 }
 
+STATIC bool
+S_glob_2number(pTHX_ GV * const gv)
+{
+    const U32 wasfake = SvFLAGS(gv) & SVf_FAKE;
+    SV *const buffer = sv_newmortal();
+
+    /* FAKE globs can get coerced, so need to turn this off temporarily if it
+       is on.  */
+    SvFAKE_off(gv);
+    gv_efullname3(buffer, gv, "*");
+    SvFLAGS(gv) |= wasfake;
+
+    /* We know that all GVs stringify to something that is not-a-number,
+       so no need to test that.  */
+    if (ckWARN(WARN_NUMERIC))
+       not_a_number(buffer);
+    /* We just want something true to return, so that S_sv_2iuv_common
+       can tail call us and return true.  */
+    return TRUE;
+}
+
 STATIC char *
-S_glob_2inpuv(pTHX_ GV *gv, STRLEN *len, bool want_number)
+S_glob_2pv(pTHX_ GV * const gv, STRLEN * const len)
 {
     const U32 wasfake = SvFLAGS(gv) & SVf_FAKE;
     SV *const buffer = sv_newmortal();
@@ -1729,17 +1751,9 @@ S_glob_2inpuv(pTHX_ GV *gv, STRLEN *len, bool want_number)
     gv_efullname3(buffer, gv, "*");
     SvFLAGS(gv) |= wasfake;
 
-    if (want_number) {
-       /* We know that all GVs stringify to something that is not-a-number,
-          so no need to test that.  */
-       if (ckWARN(WARN_NUMERIC))
-           not_a_number(buffer);
-       /* We just want something true to return, so that S_sv_2iuv_common
-          can tail call us and return true.  */
-       return (char *) 1;
-    } else {
-       return SvPV(buffer, *len);
-    }
+    assert(SvPOK(buffer));
+    *len = SvCUR(buffer);
+    return SvPVX(buffer);
 }
 
 /* Actually, ISO C leaves conversion of UV to IV undefined, but
@@ -2050,7 +2064,7 @@ S_sv_2iuv_common(pTHX_ SV *sv) {
                 if ((NV)(SvIVX(sv)) == SvNVX(sv)) {
                     SvIOK_on(sv);
                 } else {
-                   /*EMPTY*/;  /* Integer is imprecise. NOK, IOKp */
+                   NOOP;  /* Integer is imprecise. NOK, IOKp */
                 }
                 /* UV will not work better than IV */
             } else {
@@ -2065,7 +2079,7 @@ S_sv_2iuv_common(pTHX_ SV *sv) {
                     if ((NV)(SvUVX(sv)) == SvNVX(sv)) {
                         SvIOK_on(sv);
                     } else {
-                       /*EMPTY*/;   /* Integer is imprecise. NOK, IOKp, is UV */
+                       NOOP;   /* Integer is imprecise. NOK, IOKp, is UV */
                     }
                 }
                SvIsUV_on(sv);
@@ -2109,9 +2123,8 @@ S_sv_2iuv_common(pTHX_ SV *sv) {
        }
     }
     else  {
-       if (isGV_with_GP(sv)) {
-           return (bool)PTR2IV(glob_2inpuv((GV *)sv, NULL, TRUE));
-       }
+       if (isGV_with_GP(sv))
+           return glob_2number((GV *)sv);
 
        if (!(SvFLAGS(sv) & SVs_PADTMP)) {
            if (!PL_localizing && ckWARN(WARN_UNINITIALIZED))
@@ -2461,7 +2474,7 @@ Perl_sv_2nv(pTHX_ register SV *sv)
     }
     else  {
        if (isGV_with_GP(sv)) {
-           glob_2inpuv((GV *)sv, NULL, TRUE);
+           glob_2number((GV *)sv);
            return 0.0;
        }
 
@@ -2644,8 +2657,14 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
            STRLEN len;
 
            if (SvIOKp(sv)) {
-               len = SvIsUV(sv) ? my_sprintf(tbuf,"%"UVuf, (UV)SvUVX(sv))
-                   : my_sprintf(tbuf,"%"IVdf, (IV)SvIVX(sv));
+               len = SvIsUV(sv)
+#ifdef USE_SNPRINTF
+                   ? snprintf(tbuf, sizeof(tbuf), "%"UVuf, (UV)SvUVX(sv))
+                   : snprintf(tbuf, sizeof(tbuf), "%"IVdf, (IV)SvIVX(sv));
+#else
+                   ? my_sprintf(tbuf, "%"UVuf, (UV)SvUVX(sv))
+                   : my_sprintf(tbuf, "%"IVdf, (IV)SvIVX(sv));
+#endif /* #ifdef USE_SNPRINTF */
            } else {
                Gconvert(SvNVX(sv), NV_DIG, 0, tbuf);
                len = strlen(tbuf);
@@ -2797,9 +2816,8 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
 #endif
     }
     else {
-       if (isGV_with_GP(sv)) {
-           return glob_2inpuv((GV *)sv, lp, FALSE);
-       }
+       if (isGV_with_GP(sv))
+           return glob_2pv((GV *)sv, lp);
 
        if (!PL_localizing && !(SvFLAGS(sv) & SVs_PADTMP) && ckWARN(WARN_UNINITIALIZED))
            report_uninit(sv);
@@ -3283,7 +3301,7 @@ S_glob_assign_ref(pTHX_ SV *dstr, SV *sstr) {
                           it was a const and its value changed. */
                        if (CvCONST(cv) && CvCONST((CV*)sref)
                            && cv_const_sv(cv) == cv_const_sv((CV*)sref)) {
-                           /*EMPTY*/
+                           NOOP;
                            /* They are 2 constant subroutines generated from
                               the same constant. This probably means that
                               they are really the "same" proxy subroutine
@@ -3305,8 +3323,9 @@ S_glob_assign_ref(pTHX_ SV *dstr, SV *sstr) {
                        }
                    }
                if (!intro)
-                   cv_ckproto(cv, (GV*)dstr,
-                              SvPOK(sref) ? SvPVX_const(sref) : NULL);
+                   cv_ckproto_len(cv, (GV*)dstr,
+                                  SvPOK(sref) ? SvPVX_const(sref) : NULL,
+                                  SvPOK(sref) ? SvCUR(sref) : 0);
            }
            GvCVGEN(dstr) = 0; /* Switch off cacheness. */
            GvASSUMECV_on(dstr);
@@ -3881,21 +3900,27 @@ Perl_sv_setpv_mg(pTHX_ register SV *sv, register const char *ptr)
 }
 
 /*
-=for apidoc sv_usepvn
-
-Tells an SV to use C<ptr> to find its string value.  Normally the string is
-stored inside the SV but sv_usepvn allows the SV to use an outside string.
-The C<ptr> should point to memory that was allocated by C<malloc>.  The
-string length, C<len>, must be supplied.  This function will realloc the
-memory pointed to by C<ptr>, so that pointer should not be freed or used by
-the programmer after giving it to sv_usepvn.  Does not handle 'set' magic.
-See C<sv_usepvn_mg>.
+=for apidoc sv_usepvn_flags
+
+Tells an SV to use C<ptr> to find its string value.  Normally the
+string is stored inside the SV but sv_usepvn allows the SV to use an
+outside string.  The C<ptr> should point to memory that was allocated
+by C<malloc>.  The string length, C<len>, must be supplied.  By default
+this function will realloc (i.e. move) the memory pointed to by C<ptr>,
+so that pointer should not be freed or used by the programmer after
+giving it to sv_usepvn, and neither should any pointers from "behind"
+that pointer (e.g. ptr + 1) be used.
+
+If C<flags> & SV_SMAGIC is true, will call SvSETMAGIC. If C<flags> &
+SV_HAS_TRAILING_NUL is true, then C<ptr[len]> must be NUL, and the realloc
+will be skipped. (i.e. the buffer is actually at least 1 byte longer than
+C<len>, and already meets the requirements for storing in C<SvPVX>)
 
 =cut
 */
 
 void
-Perl_sv_usepvn(pTHX_ register SV *sv, register char *ptr, register STRLEN len)
+Perl_sv_usepvn_flags(pTHX_ SV *sv, char *ptr, STRLEN len, U32 flags)
 {
     dVAR;
     STRLEN allocate;
@@ -3903,34 +3928,43 @@ Perl_sv_usepvn(pTHX_ register SV *sv, register char *ptr, register STRLEN len)
     SvUPGRADE(sv, SVt_PV);
     if (!ptr) {
        (void)SvOK_off(sv);
+       if (flags & SV_SMAGIC)
+           SvSETMAGIC(sv);
        return;
     }
     if (SvPVX_const(sv))
        SvPV_free(sv);
 
-    allocate = PERL_STRLEN_ROUNDUP(len + 1);
-    ptr = saferealloc (ptr, allocate);
+    if (flags & SV_HAS_TRAILING_NUL)
+       assert(ptr[len] == '\0');
+
+    allocate = (flags & SV_HAS_TRAILING_NUL)
+       ? len + 1: PERL_STRLEN_ROUNDUP(len + 1);
+    if (flags & SV_HAS_TRAILING_NUL) {
+       /* It's long enough - do nothing.
+          Specfically Perl_newCONSTSUB is relying on this.  */
+    } else {
+#ifdef DEBUGGING
+       /* Force a move to shake out bugs in callers.  */
+       char *new_ptr = safemalloc(allocate);
+       Copy(ptr, new_ptr, len, char);
+       PoisonFree(ptr,len,char);
+       Safefree(ptr);
+       ptr = new_ptr;
+#else
+       ptr = saferealloc (ptr, allocate);
+#endif
+    }
     SvPV_set(sv, ptr);
     SvCUR_set(sv, len);
     SvLEN_set(sv, allocate);
-    *SvEND(sv) = '\0';
+    if (!(flags & SV_HAS_TRAILING_NUL)) {
+       *SvEND(sv) = '\0';
+    }
     (void)SvPOK_only_UTF8(sv);         /* validate pointer */
     SvTAINT(sv);
-}
-
-/*
-=for apidoc sv_usepvn_mg
-
-Like C<sv_usepvn>, but also handles 'set' magic.
-
-=cut
-*/
-
-void
-Perl_sv_usepvn_mg(pTHX_ register SV *sv, register char *ptr, register STRLEN len)
-{
-    sv_usepvn(sv,ptr,len);
-    SvSETMAGIC(sv);
+    if (flags & SV_SMAGIC)
+       SvSETMAGIC(sv);
 }
 
 #ifdef PERL_OLD_COPY_ON_WRITE
@@ -5043,10 +5077,8 @@ Perl_sv_clear(pTHX_ register SV *sv)
        }
     }
     if (type >= SVt_PVMG) {
-       HV *ourstash;
-       if ((type == SVt_PVMG || type == SVt_PVGV) &&
-           (ourstash = OURSTASH(sv))) {
-           SvREFCNT_dec(ourstash);
+       if ((type == SVt_PVMG || type == SVt_PVGV) && SvPAD_OUR(sv)) {
+           SvREFCNT_dec(OURSTASH(sv));
        } else if (SvMAGIC(sv))
            mg_free(sv);
        if (type == SVt_PVMG && SvPAD_TYPED(sv))
@@ -5315,7 +5347,7 @@ Perl_sv_len_utf8(pTHX_ register SV *sv)
                        PL_utf8cache = 0;
                        Perl_croak(aTHX_ "panic: sv_len_utf8 cache %"UVf
                                   " real %"UVf" for %"SVf,
-                                  (UV) ulen, (UV) real, sv);
+                                  (UV) ulen, (UV) real, (void*)sv);
                    }
                }
            }
@@ -5339,13 +5371,11 @@ Perl_sv_len_utf8(pTHX_ register SV *sv)
 /* Walk forwards to find the byte corresponding to the passed in UTF-8
    offset.  */
 static STRLEN
-S_sv_pos_u2b_forwards(pTHX_ const U8 *const start, const U8 *const send,
+S_sv_pos_u2b_forwards(const U8 *const start, const U8 *const send,
                      STRLEN uoffset)
 {
     const U8 *s = start;
 
-    PERL_UNUSED_CONTEXT;
-
     while (s < send && uoffset--)
        s += UTF8SKIP(s);
     if (s > send) {
@@ -5360,7 +5390,7 @@ S_sv_pos_u2b_forwards(pTHX_ const U8 *const start, const U8 *const send,
    whether to walk forwards or backwards to find the byte corresponding to
    the passed in UTF-8 offset.  */
 static STRLEN
-S_sv_pos_u2b_midway(pTHX_ const U8 *const start, const U8 *send,
+S_sv_pos_u2b_midway(const U8 *const start, const U8 *send,
                      STRLEN uoffset, STRLEN uend)
 {
     STRLEN backw = uend - uoffset;
@@ -5368,7 +5398,7 @@ S_sv_pos_u2b_midway(pTHX_ const U8 *const start, const U8 *send,
        /* The assumption is that going forwards is twice the speed of going
           forward (that's where the 2 * backw comes from).
           (The real figure of course depends on the UTF-8 data.)  */
-       return S_sv_pos_u2b_forwards(aTHX_ start, send, uoffset);
+       return sv_pos_u2b_forwards(start, send, uoffset);
     }
 
     while (backw--) {
@@ -5419,12 +5449,12 @@ S_sv_pos_u2b_cached(pTHX_ SV *sv, MAGIC **mgp, const U8 *const start,
                if ((*mgp)->mg_len != -1) {
                    /* And we know the end too.  */
                    boffset = boffset0
-                       + S_sv_pos_u2b_midway(aTHX_ start + boffset0, send,
+                       + sv_pos_u2b_midway(start + boffset0, send,
                                              uoffset - uoffset0,
                                              (*mgp)->mg_len - uoffset0);
                } else {
                    boffset = boffset0
-                       + S_sv_pos_u2b_forwards(aTHX_ start + boffset0,
+                       + sv_pos_u2b_forwards(start + boffset0,
                                                send, uoffset - uoffset0);
                }
            }
@@ -5437,13 +5467,13 @@ S_sv_pos_u2b_cached(pTHX_ SV *sv, MAGIC **mgp, const U8 *const start,
                }
 
                boffset = boffset0
-                   + S_sv_pos_u2b_midway(aTHX_ start + boffset0,
+                   + sv_pos_u2b_midway(start + boffset0,
                                          start + cache[1],
                                          uoffset - uoffset0,
                                          cache[0] - uoffset0);
            } else {
                boffset = boffset0
-                   + S_sv_pos_u2b_midway(aTHX_ start + boffset0,
+                   + sv_pos_u2b_midway(start + boffset0,
                                          start + cache[3],
                                          uoffset - uoffset0,
                                          cache[2] - uoffset0);
@@ -5455,7 +5485,7 @@ S_sv_pos_u2b_cached(pTHX_ SV *sv, MAGIC **mgp, const U8 *const start,
            /* In fact, offset0 is either 0, or less than offset, so don't
               need to worry about the other possibility.  */
            boffset = boffset0
-               + S_sv_pos_u2b_midway(aTHX_ start + boffset0, send,
+               + sv_pos_u2b_midway(start + boffset0, send,
                                      uoffset - uoffset0,
                                      (*mgp)->mg_len - uoffset0);
            found = TRUE;
@@ -5464,7 +5494,7 @@ S_sv_pos_u2b_cached(pTHX_ SV *sv, MAGIC **mgp, const U8 *const start,
 
     if (!found || PL_utf8cache < 0) {
        const STRLEN real_boffset
-           = boffset0 + S_sv_pos_u2b_forwards(aTHX_ start + boffset0,
+           = boffset0 + sv_pos_u2b_forwards(start + boffset0,
                                               send, uoffset - uoffset0);
 
        if (found && PL_utf8cache < 0) {
@@ -5475,7 +5505,7 @@ S_sv_pos_u2b_cached(pTHX_ SV *sv, MAGIC **mgp, const U8 *const start,
                PL_utf8cache = 0;
                Perl_croak(aTHX_ "panic: sv_pos_u2b_cache cache %"UVf
                           " real %"UVf" for %"SVf,
-                          (UV) boffset, (UV) real_boffset, sv);
+                          (UV) boffset, (UV) real_boffset, (void*)sv);
            }
        }
        boffset = real_boffset;
@@ -5519,16 +5549,16 @@ Perl_sv_pos_u2b(pTHX_ register SV *sv, I32* offsetp, I32* lenp)
        STRLEN uoffset = (STRLEN) *offsetp;
        const U8 * const send = start + len;
        MAGIC *mg = NULL;
-       STRLEN boffset = S_sv_pos_u2b_cached(aTHX_ sv, &mg, start, send,
+       const STRLEN boffset = sv_pos_u2b_cached(sv, &mg, start, send,
                                             uoffset, 0, 0);
 
        *offsetp = (I32) boffset;
 
        if (lenp) {
            /* Convert the relative offset to absolute.  */
-           STRLEN uoffset2 = uoffset + (STRLEN) *lenp;
-           STRLEN boffset2
-               = S_sv_pos_u2b_cached(aTHX_ sv, &mg, start, send, uoffset2,
+           const STRLEN uoffset2 = uoffset + (STRLEN) *lenp;
+           const STRLEN boffset2
+               = sv_pos_u2b_cached(sv, &mg, start, send, uoffset2,
                                      uoffset, boffset) - boffset;
 
            *lenp = boffset2;
@@ -5608,7 +5638,7 @@ S_utf8_mg_pos_cache_update(pTHX_ SV *sv, MAGIC **mgp, STRLEN byte, STRLEN utf8,
            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, sv);
+                      " real %"UVf" for %"SVf, (UV) utf8, (UV) realutf8, (void*)sv);
        }
     }
 
@@ -5855,7 +5885,7 @@ Perl_sv_pos_b2u(pTHX_ register SV* sv, I32* offsetp)
                PL_utf8cache = 0;
                Perl_croak(aTHX_ "panic: sv_pos_b2u cache %"UVf
                           " real %"UVf" for %"SVf,
-                          (UV) len, (UV) real_len, sv);
+                          (UV) len, (UV) real_len, (void*)sv);
            }
        }
        len = real_len;
@@ -6501,7 +6531,7 @@ screamer2:
             *
             * - jik 9/25/96
             */
-           if (!(cnt < sizeof(buf) && PerlIO_eof(fp)))
+           if (!(cnt < (I32)sizeof(buf) && PerlIO_eof(fp)))
                goto screamer2;
        }
 
@@ -6951,12 +6981,15 @@ Perl_newSVhek(pTHX_ const HEK *hek)
            SvUTF8_on (sv);
            Safefree (as_utf8); /* bytes_to_utf8() allocates a new string */
            return sv;
-       } else if (flags & HVhek_REHASH) {
+       } else if (flags & (HVhek_REHASH|HVhek_UNSHARED)) {
            /* We don't have a pointer to the hv, so we have to replicate the
               flag into every HEK. This hv is using custom a hasing
               algorithm. Hence we can't return a shared string scalar, as
               that would contain the (wrong) hash value, and might get passed
-              into an hv routine with a regular hash  */
+              into an hv routine with a regular hash.
+              Similarly, a hash that isn't using shared hash keys has to have
+              the flag in every key so that we know not to try to call
+              share_hek_kek on it.  */
 
            SV * const sv = newSVpvn (HEK_KEY(hek), HEK_LEN(hek));
            if (HEK_UTF8(hek))
@@ -7338,7 +7371,7 @@ Perl_sv_2io(pTHX_ SV *sv)
        else
            io = 0;
        if (!io)
-           Perl_croak(aTHX_ "Bad filehandle: %"SVf, sv);
+           Perl_croak(aTHX_ "Bad filehandle: %"SVf, (void*)sv);
        break;
     }
     return io;
@@ -7430,7 +7463,7 @@ Perl_sv_2cv(pTHX_ SV *sv, HV **st, GV **gvp, I32 lref)
            LEAVE;
            if (!GvCVu(gv))
                Perl_croak(aTHX_ "Unable to create sub named \"%"SVf"\"",
-                          sv);
+                          (void*)sv);
        }
        return GvCVu(gv);
     }
@@ -9235,8 +9268,13 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                 * --jhi */
 #if defined(HAS_LONG_DOUBLE)
                elen = ((intsize == 'q')
+# ifdef USE_SNPRINTF
+                       ? snprintf(PL_efloatbuf, PL_efloatsize, ptr, nv)
+                       : snprintf(PL_efloatbuf, PL_efloatsize, ptr, (double)nv));
+# else
                        ? my_sprintf(PL_efloatbuf, ptr, nv)
                        : my_sprintf(PL_efloatbuf, ptr, (double)nv));
+# endif /* #ifdef USE_SNPRINTF */
 #else
                elen = my_sprintf(PL_efloatbuf, ptr, nv);
 #endif
@@ -9287,7 +9325,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                                       (UV)c & 0xFF);
                } else
                    sv_catpvs(msg, "end of string");
-               Perl_warner(aTHX_ packWARN(WARN_PRINTF), "%"SVf, msg); /* yes, this is reentrant */
+               Perl_warner(aTHX_ packWARN(WARN_PRINTF), "%"SVf, (void*)msg); /* yes, this is reentrant */
            }
 
            /* output mangled stuff ... */
@@ -9608,7 +9646,7 @@ Perl_gp_dup(pTHX_ GP *gp, CLONE_PARAMS* param)
     ret->gp_cv         = cv_dup_inc(gp->gp_cv, param);
     ret->gp_cvgen      = gp->gp_cvgen;
     ret->gp_line       = gp->gp_line;
-    ret->gp_file       = gp->gp_file;          /* points to COP.cop_file */
+    ret->gp_file_hek   = hek_dup(gp->gp_file_hek, param);
     return ret;
 }
 
@@ -9959,7 +9997,7 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* param)
 
            case SVt_PVGV:
                if (GvUNIQUE((GV*)sstr)) {
-                   /*EMPTY*/;   /* Do sharing here, and fall through */
+                   NOOP;   /* Do sharing here, and fall through */
                }
            case SVt_PVIO:
            case SVt_PVFM:
@@ -10004,9 +10042,8 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* param)
               missing by always going for the destination.
               FIXME - instrument and check that assumption  */
            if (sv_type >= SVt_PVMG) {
-               HV *ourstash;
-               if ((sv_type == SVt_PVMG) && (ourstash = OURSTASH(dstr))) {
-                   OURSTASH_set(dstr, hv_dup_inc(ourstash, param));
+               if ((sv_type == SVt_PVMG) && SvPAD_OUR(dstr)) {
+                   OURSTASH_set(dstr, hv_dup_inc(OURSTASH(dstr), param));
                } else if (SvMAGIC(dstr))
                    SvMAGIC_set(dstr, mg_dup(SvMAGIC(dstr), param));
                if (SvSTASH(dstr))
@@ -10070,7 +10107,7 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* param)
                    if (IoDIRP(dstr)) {
                        IoDIRP(dstr)    = dirp_dup(IoDIRP(dstr));
                    } else {
-                       /*EMPTY*/;
+                       NOOP;
                        /* IoDIRP(dstr) is already a copy of IoDIRP(sstr)  */
                    }
                }
@@ -10578,7 +10615,12 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
            i = POPINT(ss,ix);
            TOPINT(nss,ix) = i;
            ptr = POPPTR(ss,ix);
-           TOPPTR(nss,ix) = Perl_refcounted_he_dup(aTHX_ ptr, param);
+           if (ptr) {
+               HINTS_REFCNT_LOCK;
+               ((struct refcounted_he *)ptr)->refcounted_he_refcnt++;
+               HINTS_REFCNT_UNLOCK;
+           }
+           TOPPTR(nss,ix) = ptr;
            if (i & HINT_LOCALIZE_HH) {
                hv = (HV*)POPPTR(ss,ix);
                TOPPTR(nss,ix) = hv_dup_inc(hv, param);
@@ -10626,8 +10668,6 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
                    = pv_dup(old_state->re_state_bostr);
                new_state->re_state_reginput
                    = pv_dup(old_state->re_state_reginput);
-               new_state->re_state_regbol
-                   = pv_dup(old_state->re_state_regbol);
                new_state->re_state_regeol
                    = pv_dup(old_state->re_state_regeol);
                new_state->re_state_regstartp
@@ -10639,8 +10679,6 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
                new_state->re_state_reglastcloseparen
                    = any_dup(old_state->re_state_reglastcloseparen,
                              proto_perl);
-               new_state->re_state_regtill
-                   = pv_dup(old_state->re_state_regtill);
                /* XXX This just has to be broken. The old save_re_context
                   code did SAVEGENERICPV(PL_reg_start_tmp);
                   PL_reg_start_tmp is char **.
@@ -10654,14 +10692,6 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
                /* I assume that it only ever "worked" because no-one called
                   (pseudo)fork while the regexp engine had re-entered itself.
                */
-               new_state->re_state_reg_call_cc
-                   = any_dup(old_state->re_state_reg_call_cc, proto_perl);
-               new_state->re_state_reg_re
-                   = any_dup(old_state->re_state_reg_re, proto_perl);
-               new_state->re_state_reg_ganch
-                   = pv_dup(old_state->re_state_reg_ganch);
-               new_state->re_state_reg_sv
-                   = sv_dup(old_state->re_state_reg_sv, param);
 #ifdef PERL_OLD_COPY_ON_WRITE
                new_state->re_state_nrs
                    = sv_dup(old_state->re_state_nrs, param);
@@ -10676,12 +10706,14 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
                    = pv_dup(old_state->re_state_reg_oldsaved);
                new_state->re_state_reg_poscache
                    = pv_dup(old_state->re_state_reg_poscache);
-#ifdef DEBUGGING
                new_state->re_state_reg_starttry
                    = pv_dup(old_state->re_state_reg_starttry);
-#endif
                break;
            }
+       case SAVEt_COMPILE_WARNINGS:
+           ptr = POPPTR(ss,ix);
+           TOPPTR(nss,ix) = DUP_WARNINGS((STRLEN*)ptr);
+           break;
        default:
            Perl_croak(aTHX_ "panic: ss_dup inconsistency (%"IVdf")", (IV) i);
        }
@@ -10901,7 +10933,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     SvREFCNT(&PL_sv_no)                = (~(U32)0)/2;
     SvFLAGS(&PL_sv_no)         = SVp_IOK|SVf_IOK|SVp_NOK|SVf_NOK
                                  |SVp_POK|SVf_POK|SVf_READONLY|SVt_PVNV;
-    SvPV_set(&PL_sv_no, SAVEPVN(PL_No, 0));
+    SvPV_set(&PL_sv_no, savepvn(PL_No, 0));
     SvCUR_set(&PL_sv_no, 0);
     SvLEN_set(&PL_sv_no, 1);
     SvIV_set(&PL_sv_no, 0);
@@ -10912,7 +10944,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     SvREFCNT(&PL_sv_yes)       = (~(U32)0)/2;
     SvFLAGS(&PL_sv_yes)                = SVp_IOK|SVf_IOK|SVp_NOK|SVf_NOK
                                  |SVp_POK|SVf_POK|SVf_READONLY|SVt_PVNV;
-    SvPV_set(&PL_sv_yes, SAVEPVN(PL_Yes, 1));
+    SvPV_set(&PL_sv_yes, savepvn(PL_Yes, 1));
     SvCUR_set(&PL_sv_yes, 1);
     SvLEN_set(&PL_sv_yes, 2);
     SvIV_set(&PL_sv_yes, 1);
@@ -10935,12 +10967,14 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     ptr_table_store(PL_ptr_table, proto_perl->Icompiling.cop_file, PL_compiling.cop_file);
 
     ptr_table_store(PL_ptr_table, &proto_perl->Icompiling, &PL_compiling);
-    if (!specialWARN(PL_compiling.cop_warnings))
-       PL_compiling.cop_warnings = sv_dup_inc(PL_compiling.cop_warnings, param);
+    PL_compiling.cop_warnings = DUP_WARNINGS(PL_compiling.cop_warnings);
     if (!specialCopIO(PL_compiling.cop_io))
        PL_compiling.cop_io = sv_dup_inc(PL_compiling.cop_io, param);
-    PL_compiling.cop_hints
-       = Perl_refcounted_he_dup(aTHX_ PL_compiling.cop_hints, param);
+    if (PL_compiling.cop_hints) {
+       HINTS_REFCNT_LOCK;
+       PL_compiling.cop_hints->refcounted_he_refcnt++;
+       HINTS_REFCNT_UNLOCK;
+    }
     PL_curcop          = (COP*)any_dup(proto_perl->Tcurcop, proto_perl);
 
     /* pseudo environmental stuff */
@@ -11719,16 +11753,17 @@ STATIC I32
 S_find_array_subscript(pTHX_ AV *av, SV* val)
 {
     dVAR;
-    SV** svp;
-    I32 i;
     if (!av || SvMAGICAL(av) || !AvARRAY(av) ||
                        (AvFILLp(av) > FUV_MAX_SEARCH_SIZE))
        return -1;
 
-    svp = AvARRAY(av);
-    for (i=AvFILLp(av); i>=0; i--) {
-       if (svp[i] == val && svp[i] != &PL_sv_undef)
-           return i;
+    if (val != &PL_sv_undef) {
+       SV ** const svp = AvARRAY(av);
+       I32 i;
+
+       for (i=AvFILLp(av); i>=0; i--)
+           if (svp[i] == val)
+               return i;
     }
     return -1;
 }
@@ -11870,7 +11905,7 @@ S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
                subscript_type = FUV_SUBSCRIPT_HASH;
        }
        else {
-           index = S_find_array_subscript(aTHX_ (AV*)sv, uninit_sv);
+           index = find_array_subscript((AV*)sv, uninit_sv);
            if (index >= 0)
                subscript_type = FUV_SUBSCRIPT_ARRAY;
        }
@@ -12084,13 +12119,14 @@ S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
         * or are optimized away, then it's unambiguous */
        o2 = NULL;
        for (kid=o; kid; kid = kid->op_sibling) {
-           if (kid &&
-               (    (kid->op_type == OP_CONST && SvOK(cSVOPx_sv(kid)))
-                 || (kid->op_type == OP_NULL  && ! (kid->op_flags & OPf_KIDS))
-                 || (kid->op_type == OP_PUSHMARK)
+           if (kid) {
+               const OPCODE type = kid->op_type;
+               if ( (type == OP_CONST && SvOK(cSVOPx_sv(kid)))
+                 || (type == OP_NULL  && ! (kid->op_flags & OPf_KIDS))
+                 || (type == OP_PUSHMARK)
                )
-           )
                continue;
+           }
            if (o2) { /* more than one found */
                o2 = NULL;
                break;