This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
silence APItest deprecation warning
[perl5.git] / sv.c
diff --git a/sv.c b/sv.c
index 3a3f46e..3a0cf89 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -1,7 +1,8 @@
 /*    sv.c
  *
  *    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- *    2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 by Larry Wall and others
+ *    2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 by Larry Wall
+ *    and others
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
@@ -146,8 +147,7 @@ Private API to rest of sv.c
 
     new_SV(),  del_SV(),
 
-    new_XIV(), del_XIV(),
-    new_XNV(), del_XNV(),
+    new_XPVNV(), del_XPVGV(),
     etc
 
 Public API:
@@ -156,7 +156,7 @@ Public API:
 
 =cut
 
-============================================================================ */
+ * ========================================================================= */
 
 /*
  * "A time to plant, and a time to uproot what was planted..."
@@ -293,7 +293,7 @@ S_new_SV(pTHX_ const char *file, int line, const char *func)
                    : 0
            );
     sv->sv_debug_inpad = 0;
-    sv->sv_debug_cloned = 0;
+    sv->sv_debug_parent = NULL;
     sv->sv_debug_file = PL_curcop ? savepv(CopFILE(PL_curcop)): NULL;
 
     sv->sv_debug_serial = PL_sv_serial++;
@@ -352,10 +352,9 @@ S_del_sv(pTHX_ SV *p)
            }
        }
        if (!ok) {
-           if (ckWARN_d(WARN_INTERNAL))        
-               Perl_warner(aTHX_ packWARN(WARN_INTERNAL),
-                           "Attempt to free non-arena SV: 0x%"UVxf
-                            pTHX__FORMAT, PTR2UV(p) pTHX__VALUE);
+           Perl_ck_warner_d(aTHX_ packWARN(WARN_INTERNAL),
+                            "Attempt to free non-arena SV: 0x%"UVxf
+                            pTHX__FORMAT, PTR2UV(p) pTHX__VALUE);
            return;
        }
     }
@@ -607,7 +606,7 @@ Perl_sv_clean_all(pTHX)
 struct arena_desc {
     char       *arena;         /* the raw storage, allocated aligned */
     size_t      size;          /* its size ~4k typ */
-    U32                misc;           /* type, and in future other things. */
+    svtype     utype;          /* bodytype stored in arena */
 };
 
 struct arena_set;
@@ -689,7 +688,6 @@ Perl_sv_free_arenas(pTHX)
   2. regular body arenas
   3. arenas for reduced-size bodies
   4. Hash-Entry arenas
-  5. pte arenas (thread related)
 
   Arena types 2 & 3 are chained by body-type off an array of
   arena-root pointers, which is indexed by svtype.  Some of the
@@ -706,67 +704,6 @@ Perl_sv_free_arenas(pTHX)
   are decremented to point at the unused 'ghost' memory, knowing that
   the pointers are used with offsets to the real memory.
 
-  HE, HEK arenas are managed separately, with separate code, but may
-  be merge-able later..
-
-  PTE arenas are not sv-bodies, but they share these mid-level
-  mechanics, so are considered here.  The new mid-level mechanics rely
-  on the sv_type of the body being allocated, so we just reserve one
-  of the unused body-slots for PTEs, then use it in those (2) PTE
-  contexts below (line ~10k)
-*/
-
-/* get_arena(size): this creates custom-sized arenas
-   TBD: export properly for hv.c: S_more_he().
-*/
-void*
-Perl_get_arena(pTHX_ const size_t arena_size, const U32 misc)
-{
-    dVAR;
-    struct arena_desc* adesc;
-    struct arena_set *aroot = (struct arena_set*) PL_body_arenas;
-    unsigned int curr;
-
-    /* shouldnt need this
-    if (!arena_size)   arena_size = PERL_ARENA_SIZE;
-    */
-
-    /* may need new arena-set to hold new arena */
-    if (!aroot || aroot->curr >= aroot->set_size) {
-       struct arena_set *newroot;
-       Newxz(newroot, 1, struct arena_set);
-       newroot->set_size = ARENAS_PER_SET;
-       newroot->next = aroot;
-       aroot = newroot;
-       PL_body_arenas = (void *) newroot;
-       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 */
-    curr = aroot->curr++;
-    adesc = &(aroot->set[curr]);
-    assert(!adesc->arena);
-    
-    Newx(adesc->arena, arena_size, char);
-    adesc->size = arena_size;
-    adesc->misc = misc;
-    DEBUG_m(PerlIO_printf(Perl_debug_log, "arena %d added: %p size %"UVuf"\n", 
-                         curr, (void*)adesc->arena, (UV)arena_size));
-
-    return adesc->arena;
-}
-
-
-/* return a thing to the free list */
-
-#define del_body(thing, root)                  \
-    STMT_START {                               \
-       void ** const thing_copy = (void **)thing;\
-       *thing_copy = *root;                    \
-       *root = (void*)thing_copy;              \
-    } STMT_END
-
-/* 
 
 =head1 SV-Body Allocation
 
@@ -782,25 +719,29 @@ type.  Most body types use the former pair, the latter pair is used to
 allocate body types with "ghost fields".
 
 "ghost fields" are fields that are unused in certain types, and
-consequently dont need to actually exist.  They are declared because
+consequently don't need to actually exist.  They are declared because
 they're part of a "base type", which allows use of functions as
 methods.  The simplest examples are AVs and HVs, 2 aggregate types
 which don't use the fields which support SCALAR semantics.
 
-For these types, the arenas are carved up into *_allocated size
+For these types, the arenas are carved up into appropriately sized
 chunks, we thus avoid wasted memory for those unaccessed members.
 When bodies are allocated, we adjust the pointer back in memory by the
-size of the bit not allocated, so it's as if we allocated the full
+size of the part not allocated, so it's as if we allocated the full
 structure.  (But things will all go boom if you write to the part that
 is "not there", because you'll be overwriting the last members of the
 preceding structure in memory.)
 
-We calculate the correction using the STRUCT_OFFSET macro. For
-example, if xpv_allocated is the same structure as XPV then the two
-OFFSETs sum to zero, and the pointer is unchanged. If the allocated
-structure is smaller (no initial NV actually allocated) then the net
-effect is to subtract the size of the NV from the pointer, to return a
-new pointer as if an initial NV were actually allocated.
+We calculate the correction using the STRUCT_OFFSET macro on the first
+member present. If the allocated structure is smaller (no initial NV
+actually allocated) then the net effect is to subtract the size of the NV
+from the pointer, to return a new pointer as if an initial NV were actually
+allocated. (We were using structures named *_allocated for this, but
+this turned out to be a subtle bug, because a structure without an NV
+could have a lower alignment constraint, but the compiler is allowed to
+optimised accesses based on the alignment constraint of the actual pointer
+to the full structure, for example, using a single 64 bit load instruction
+because it "knows" that two adjacent 32 bit members will be 8-byte aligned.)
 
 This is the same trick as was used for NV and IV bodies. Ironically it
 doesn't need to be used for NV bodies any more, because NV is now at
@@ -809,11 +750,11 @@ they are no longer allocated.
 
 In turn, the new_body_* allocators call S_new_body(), which invokes
 new_body_inline macro, which takes a lock, and takes a body off the
-linked list at PL_body_roots[sv_type], calling S_more_bodies() if
+linked list at PL_body_roots[sv_type], calling Perl_more_bodies() if
 necessary to refresh an empty list.  Then the lock is released, and
 the body is returned.
 
-S_more_bodies calls get_arena(), and carves it up into an array of N
+Perl_more_bodies allocates a new arena, and carves it up into an array of N
 bodies, which it strings into a linked list.  It looks up arena-size
 and body-size from the body_details table described below, thus
 supporting the multiple body-types.
@@ -821,10 +762,6 @@ supporting the multiple body-types.
 If PURIFY is defined, or PERL_ARENA_SIZE=0, arenas are not used, and
 the (new|del)_X*V macros are mapped directly to malloc/free.
 
-*/
-
-/* 
-
 For each sv-type, struct body_details bodies_by_type[] carries
 parameters which control these aspects of SV handling:
 
@@ -834,11 +771,11 @@ zero, forcing individual mallocs and frees.
 
 Body_size determines how big a body is, and therefore how many fit into
 each arena.  Offset carries the body-pointer adjustment needed for
-*_allocated body types, and is used in *_allocated macros.
+"ghost fields", and is used in *_allocated macros.
 
 But its main purpose is to parameterize info needed in
 Perl_sv_upgrade().  The info here dramatically simplifies the function
-vs the implementation in 5.8.7, making it table-driven.  All fields
+vs the implementation in 5.8.8, making it table-driven.  All fields
 are used for this, except for arena_size.
 
 For the sv-types that have no bodies, arenas are not used, so those
@@ -848,13 +785,6 @@ PL_body_roots[HE_SVSLOT=SVt_NULL] is filled by S_more_he, but the
 bodies_by_type[SVt_NULL] slot is not used, as the table is not
 available in hv.c.
 
-PTEs also use arenas, but are never seen in Perl_sv_upgrade. Nonetheless,
-they get their own slot in bodies_by_type[PTE_SVSLOT =SVt_IV], so they can
-just use the same allocation semantics.  At first, PTEs were also
-overloaded to a non-body sv-type, but this yielded hard-to-find malloc
-bugs, so was simplified by claiming a new slot.  This choice has no
-consequence at this time.
-
 */
 
 struct body_details {
@@ -900,26 +830,6 @@ struct body_details {
     ? FIT_ARENAn (count, body_size)                    \
     : FIT_ARENA0 (body_size)
 
-/* A macro to work out the offset needed to subtract from a pointer to (say)
-
-typedef struct {
-    STRLEN     xpv_cur;
-    STRLEN     xpv_len;
-} xpv_allocated;
-
-to make its members accessible via a pointer to (say)
-
-struct xpv {
-    NV         xnv_nv;
-    STRLEN     xpv_cur;
-    STRLEN     xpv_len;
-};
-
-*/
-
-#define relative_STRUCT_OFFSET(longer, shorter, member) \
-    (STRUCT_OFFSET(shorter, member) - STRUCT_OFFSET(longer, member))
-
 /* Calculate the length to copy. Specifically work out the length less any
    final padding the compiler needed to add.  See the comment in sv_upgrade
    for why copying the padding proved to be a bug.  */
@@ -929,55 +839,57 @@ struct xpv {
        + sizeof (((type*)SvANY((const SV *)0))->last_member)
 
 static const struct body_details bodies_by_type[] = {
-    { sizeof(HE), 0, 0, SVt_NULL,
-      FALSE, NONV, NOARENA, FIT_ARENA(0, sizeof(HE)) },
+    /* HEs use this offset for their arena.  */
+    { 0, 0, 0, SVt_NULL, FALSE, NONV, NOARENA, 0 },
 
     /* The bind placeholder pretends to be an RV for now.
        Also it's marked as "can't upgrade" to stop anyone using it before it's
        implemented.  */
     { 0, 0, 0, SVt_BIND, TRUE, NONV, NOARENA, 0 },
 
-    /* IVs are in the head, so the allocation size is 0.
-       However, the slot is overloaded for PTEs.  */
-    { sizeof(struct ptr_tbl_ent), /* This is used for PTEs.  */
+    /* IVs are in the head, so the allocation size is 0.  */
+    { 0,
       sizeof(IV), /* This is used to copy out the IV body.  */
       STRUCT_OFFSET(XPVIV, xiv_iv), SVt_IV, FALSE, NONV,
-      NOARENA /* IVS don't need an arena  */,
-      /* But PTEs need to know the size of their arena  */
-      FIT_ARENA(0, sizeof(struct ptr_tbl_ent))
+      NOARENA /* IVS don't need an arena  */, 0
     },
 
     /* 8 bytes on most ILP32 with IEEE doubles */
-    { sizeof(NV), sizeof(NV), 0, SVt_NV, FALSE, HADNV, HASARENA,
-      FIT_ARENA(0, sizeof(NV)) },
+    { sizeof(NV), sizeof(NV),
+      STRUCT_OFFSET(XPVNV, xnv_u),
+      SVt_NV, FALSE, HADNV, HASARENA, FIT_ARENA(0, sizeof(NV)) },
 
     /* 8 bytes on most ILP32 with IEEE doubles */
-    { sizeof(xpv_allocated),
-      copy_length(XPV, xpv_len)
-      - relative_STRUCT_OFFSET(xpv_allocated, XPV, xpv_cur),
-      + relative_STRUCT_OFFSET(xpv_allocated, XPV, xpv_cur),
-      SVt_PV, FALSE, NONV, HASARENA, FIT_ARENA(0, sizeof(xpv_allocated)) },
+    { sizeof(XPV) - STRUCT_OFFSET(XPV, xpv_cur),
+      copy_length(XPV, xpv_len) - STRUCT_OFFSET(XPV, xpv_cur),
+      + STRUCT_OFFSET(XPV, xpv_cur),
+      SVt_PV, FALSE, NONV, HASARENA,
+      FIT_ARENA(0, sizeof(XPV) - STRUCT_OFFSET(XPV, xpv_cur)) },
 
     /* 12 */
-    { sizeof(xpviv_allocated),
-      copy_length(XPVIV, xiv_u)
-      - relative_STRUCT_OFFSET(xpviv_allocated, XPVIV, xpv_cur),
-      + relative_STRUCT_OFFSET(xpviv_allocated, XPVIV, xpv_cur),
-      SVt_PVIV, FALSE, NONV, HASARENA, FIT_ARENA(0, sizeof(xpviv_allocated)) },
+    { sizeof(XPVIV) - STRUCT_OFFSET(XPV, xpv_cur),
+      copy_length(XPVIV, xiv_u) - STRUCT_OFFSET(XPV, xpv_cur),
+      + STRUCT_OFFSET(XPV, xpv_cur),
+      SVt_PVIV, FALSE, NONV, HASARENA,
+      FIT_ARENA(0, sizeof(XPVIV) - STRUCT_OFFSET(XPV, xpv_cur)) },
 
     /* 20 */
-    { sizeof(XPVNV), copy_length(XPVNV, xiv_u), 0, SVt_PVNV, FALSE, HADNV,
-      HASARENA, FIT_ARENA(0, sizeof(XPVNV)) },
+    { sizeof(XPVNV) - STRUCT_OFFSET(XPV, xpv_cur),
+      copy_length(XPVNV, xnv_u) - STRUCT_OFFSET(XPV, xpv_cur),
+      + STRUCT_OFFSET(XPV, xpv_cur),
+      SVt_PVNV, FALSE, HADNV, HASARENA,
+      FIT_ARENA(0, sizeof(XPVNV) - STRUCT_OFFSET(XPV, xpv_cur)) },
 
     /* 28 */
-    { sizeof(XPVMG), copy_length(XPVMG, xmg_stash), 0, SVt_PVMG, FALSE, HADNV,
+    { sizeof(XPVMG), copy_length(XPVMG, xnv_u), 0, SVt_PVMG, FALSE, HADNV,
       HASARENA, FIT_ARENA(0, sizeof(XPVMG)) },
 
     /* something big */
-    { sizeof(struct regexp_allocated), sizeof(struct regexp_allocated),
-      + relative_STRUCT_OFFSET(struct regexp_allocated, regexp, xpv_cur),
+    { sizeof(regexp),
+      sizeof(regexp),
+      0,
       SVt_REGEXP, FALSE, NONV, HASARENA,
-      FIT_ARENA(0, sizeof(struct regexp_allocated))
+      FIT_ARENA(0, sizeof(regexp))
     },
 
     /* 48 */
@@ -988,111 +900,90 @@ static const struct body_details bodies_by_type[] = {
     { sizeof(XPVLV), sizeof(XPVLV), 0, SVt_PVLV, TRUE, HADNV,
       HASARENA, FIT_ARENA(0, sizeof(XPVLV)) },
 
-    { sizeof(xpvav_allocated),
-      copy_length(XPVAV, xmg_stash)
-      - relative_STRUCT_OFFSET(xpvav_allocated, XPVAV, xav_fill),
-      + relative_STRUCT_OFFSET(xpvav_allocated, XPVAV, xav_fill),
-      SVt_PVAV, TRUE, NONV, HASARENA, FIT_ARENA(0, sizeof(xpvav_allocated)) },
+    { sizeof(XPVAV),
+      copy_length(XPVAV, xav_alloc),
+      0,
+      SVt_PVAV, TRUE, NONV, HASARENA,
+      FIT_ARENA(0, sizeof(XPVAV)) },
 
-    { sizeof(xpvhv_allocated),
-      copy_length(XPVHV, xmg_stash)
-      - relative_STRUCT_OFFSET(xpvhv_allocated, XPVHV, xhv_fill),
-      + relative_STRUCT_OFFSET(xpvhv_allocated, XPVHV, xhv_fill),
-      SVt_PVHV, TRUE, NONV, HASARENA, FIT_ARENA(0, sizeof(xpvhv_allocated)) },
+    { sizeof(XPVHV),
+      copy_length(XPVHV, xhv_max),
+      0,
+      SVt_PVHV, TRUE, NONV, HASARENA,
+      FIT_ARENA(0, sizeof(XPVHV)) },
 
     /* 56 */
-    { sizeof(xpvcv_allocated), sizeof(xpvcv_allocated),
-      + relative_STRUCT_OFFSET(xpvcv_allocated, XPVCV, xpv_cur),
-      SVt_PVCV, TRUE, NONV, HASARENA, FIT_ARENA(0, sizeof(xpvcv_allocated)) },
-
-    { sizeof(xpvfm_allocated), sizeof(xpvfm_allocated),
-      + relative_STRUCT_OFFSET(xpvfm_allocated, XPVFM, xpv_cur),
-      SVt_PVFM, TRUE, NONV, NOARENA, FIT_ARENA(20, sizeof(xpvfm_allocated)) },
+    { sizeof(XPVCV),
+      sizeof(XPVCV),
+      0,
+      SVt_PVCV, TRUE, NONV, HASARENA,
+      FIT_ARENA(0, sizeof(XPVCV)) },
+
+    { sizeof(XPVFM),
+      sizeof(XPVFM),
+      0,
+      SVt_PVFM, TRUE, NONV, NOARENA,
+      FIT_ARENA(20, sizeof(XPVFM)) },
 
     /* XPVIO is 84 bytes, fits 48x */
-    { sizeof(xpvio_allocated), sizeof(xpvio_allocated),
-      + relative_STRUCT_OFFSET(xpvio_allocated, XPVIO, xpv_cur),
-      SVt_PVIO, TRUE, NONV, HASARENA, FIT_ARENA(24, sizeof(xpvio_allocated)) },
+    { sizeof(XPVIO),
+      sizeof(XPVIO),
+      0,
+      SVt_PVIO, TRUE, NONV, HASARENA,
+      FIT_ARENA(24, sizeof(XPVIO)) },
 };
 
-#define new_body_type(sv_type)         \
-    (void *)((char *)S_new_body(aTHX_ sv_type))
-
-#define del_body_type(p, sv_type)      \
-    del_body(p, &PL_body_roots[sv_type])
-
-
 #define new_body_allocated(sv_type)            \
     (void *)((char *)S_new_body(aTHX_ sv_type) \
             - bodies_by_type[sv_type].offset)
 
-#define del_body_allocated(p, sv_type)         \
-    del_body(p + bodies_by_type[sv_type].offset, &PL_body_roots[sv_type])
-
+/* return a thing to the free list */
 
-#define my_safemalloc(s)       (void*)safemalloc(s)
-#define my_safecalloc(s)       (void*)safecalloc(s, 1)
-#define my_safefree(p) safefree((char*)p)
+#define del_body(thing, root)                          \
+    STMT_START {                                       \
+       void ** const thing_copy = (void **)thing;      \
+       *thing_copy = *root;                            \
+       *root = (void*)thing_copy;                      \
+    } STMT_END
 
 #ifdef PURIFY
 
-#define new_XNV()      my_safemalloc(sizeof(XPVNV))
-#define del_XNV(p)     my_safefree(p)
-
-#define new_XPVNV()    my_safemalloc(sizeof(XPVNV))
-#define del_XPVNV(p)   my_safefree(p)
+#define new_XNV()      safemalloc(sizeof(XPVNV))
+#define new_XPVNV()    safemalloc(sizeof(XPVNV))
+#define new_XPVMG()    safemalloc(sizeof(XPVMG))
 
-#define new_XPVAV()    my_safemalloc(sizeof(XPVAV))
-#define del_XPVAV(p)   my_safefree(p)
-
-#define new_XPVHV()    my_safemalloc(sizeof(XPVHV))
-#define del_XPVHV(p)   my_safefree(p)
-
-#define new_XPVMG()    my_safemalloc(sizeof(XPVMG))
-#define del_XPVMG(p)   my_safefree(p)
-
-#define new_XPVGV()    my_safemalloc(sizeof(XPVGV))
-#define del_XPVGV(p)   my_safefree(p)
+#define del_XPVGV(p)   safefree(p)
 
 #else /* !PURIFY */
 
-#define new_XNV()      new_body_type(SVt_NV)
-#define del_XNV(p)     del_body_type(p, SVt_NV)
-
-#define new_XPVNV()    new_body_type(SVt_PVNV)
-#define del_XPVNV(p)   del_body_type(p, SVt_PVNV)
-
-#define new_XPVAV()    new_body_allocated(SVt_PVAV)
-#define del_XPVAV(p)   del_body_allocated(p, SVt_PVAV)
-
-#define new_XPVHV()    new_body_allocated(SVt_PVHV)
-#define del_XPVHV(p)   del_body_allocated(p, SVt_PVHV)
+#define new_XNV()      new_body_allocated(SVt_NV)
+#define new_XPVNV()    new_body_allocated(SVt_PVNV)
+#define new_XPVMG()    new_body_allocated(SVt_PVMG)
 
-#define new_XPVMG()    new_body_type(SVt_PVMG)
-#define del_XPVMG(p)   del_body_type(p, SVt_PVMG)
-
-#define new_XPVGV()    new_body_type(SVt_PVGV)
-#define del_XPVGV(p)   del_body_type(p, SVt_PVGV)
+#define del_XPVGV(p)   del_body(p + bodies_by_type[SVt_PVGV].offset,   \
+                                &PL_body_roots[SVt_PVGV])
 
 #endif /* PURIFY */
 
 /* no arena for you! */
 
 #define new_NOARENA(details) \
-       my_safemalloc((details)->body_size + (details)->offset)
+       safemalloc((details)->body_size + (details)->offset)
 #define new_NOARENAZ(details) \
-       my_safecalloc((details)->body_size + (details)->offset)
+       safecalloc((details)->body_size + (details)->offset, 1)
 
-STATIC void *
-S_more_bodies (pTHX_ const svtype sv_type)
+void *
+Perl_more_bodies (pTHX_ const svtype sv_type, const size_t body_size,
+                 const size_t arena_size)
 {
     dVAR;
     void ** const root = &PL_body_roots[sv_type];
-    const struct body_details * const bdp = &bodies_by_type[sv_type];
-    const size_t body_size = bdp->body_size;
+    struct arena_desc *adesc;
+    struct arena_set *aroot = (struct arena_set *) PL_body_arenas;
+    unsigned int curr;
     char *start;
     const char *end;
-    const size_t arena_size = Perl_malloc_good_size(bdp->arena_size);
+    const size_t good_arena_size = Perl_malloc_good_size(arena_size);
 #if defined(DEBUGGING) && !defined(PERL_GLOBAL_STRUCT_PRIVATE)
     static bool done_sanity_check;
 
@@ -1108,37 +999,68 @@ S_more_bodies (pTHX_ const svtype sv_type)
     }
 #endif
 
-    assert(bdp->arena_size);
+    assert(arena_size);
 
-    start = (char*) Perl_get_arena(aTHX_ arena_size, sv_type);
+    /* may need new arena-set to hold new arena */
+    if (!aroot || aroot->curr >= aroot->set_size) {
+       struct arena_set *newroot;
+       Newxz(newroot, 1, struct arena_set);
+       newroot->set_size = ARENAS_PER_SET;
+       newroot->next = aroot;
+       aroot = newroot;
+       PL_body_arenas = (void *) newroot;
+       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 */
+    curr = aroot->curr++;
+    adesc = &(aroot->set[curr]);
+    assert(!adesc->arena);
+    
+    Newx(adesc->arena, good_arena_size, char);
+    adesc->size = good_arena_size;
+    adesc->utype = sv_type;
+    DEBUG_m(PerlIO_printf(Perl_debug_log, "arena %d added: %p size %"UVuf"\n", 
+                         curr, (void*)adesc->arena, (UV)good_arena_size));
 
-    end = start + arena_size - 2 * body_size;
+    start = (char *) adesc->arena;
+
+    /* Get the address of the byte after the end of the last body we can fit.
+       Remember, this is integer division:  */
+    end = start + good_arena_size / body_size * body_size;
 
     /* computed count doesnt reflect the 1st slot reservation */
 #if defined(MYMALLOC) || defined(HAS_MALLOC_GOOD_SIZE)
     DEBUG_m(PerlIO_printf(Perl_debug_log,
                          "arena %p end %p arena-size %d (from %d) type %d "
                          "size %d ct %d\n",
-                         (void*)start, (void*)end, (int)arena_size,
-                         (int)bdp->arena_size, sv_type, (int)body_size,
-                         (int)arena_size / (int)body_size));
+                         (void*)start, (void*)end, (int)good_arena_size,
+                         (int)arena_size, sv_type, (int)body_size,
+                         (int)good_arena_size / (int)body_size));
 #else
     DEBUG_m(PerlIO_printf(Perl_debug_log,
                          "arena %p end %p arena-size %d type %d size %d ct %d\n",
                          (void*)start, (void*)end,
-                         (int)bdp->arena_size, sv_type, (int)body_size,
-                         (int)bdp->arena_size / (int)body_size));
+                         (int)arena_size, sv_type, (int)body_size,
+                         (int)good_arena_size / (int)body_size));
 #endif
     *root = (void *)start;
 
-    while (start <= end) {
+    while (1) {
+       /* Where the next body would start:  */
        char * const next = start + body_size;
+
+       if (next >= end) {
+           /* This is the last body:  */
+           assert(next == end);
+
+           *(void **)start = 0;
+           return *root;
+       }
+
        *(void**) start = (void *)next;
        start = next;
     }
-    *(void **)start = 0;
-
-    return *root;
 }
 
 /* grab a new thing from the free list, allocating more if necessary.
@@ -1149,7 +1071,9 @@ S_more_bodies (pTHX_ const svtype sv_type)
     STMT_START { \
        void ** const r3wt = &PL_body_roots[sv_type]; \
        xpv = (PTR_TBL_ENT_t*) (*((void **)(r3wt))      \
-         ? *((void **)(r3wt)) : more_bodies(sv_type)); \
+         ? *((void **)(r3wt)) : Perl_more_bodies(aTHX_ sv_type, \
+                                            bodies_by_type[sv_type].body_size,\
+                                            bodies_by_type[sv_type].arena_size)); \
        *(r3wt) = *(void**)(xpv); \
     } STMT_END
 
@@ -1193,13 +1117,22 @@ Perl_sv_upgrade(pTHX_ register SV *const sv, svtype new_type)
 
     PERL_ARGS_ASSERT_SV_UPGRADE;
 
+    if (old_type == new_type)
+       return;
+
+    /* This clause was purposefully added ahead of the early return above to
+       the shared string hackery for (sort {$a <=> $b} keys %hash), with the
+       inference by Nick I-S that it would fix other troublesome cases. See
+       changes 7162, 7163 (f130fd4589cf5fbb24149cd4db4137c8326f49c1 and parent)
+
+       Given that shared hash key scalars are no longer PVIV, but PV, there is
+       no longer need to unshare so as to free up the IVX slot for its proper
+       purpose. So it's safe to move the early return earlier.  */
+
     if (new_type != SVt_PV && SvIsCOW(sv)) {
        sv_force_normal_flags(sv, 0);
     }
 
-    if (old_type == new_type)
-       return;
-
     old_body = SvANY(sv);
 
     /* Copying structures onto other structures that have been neatly zeroed
@@ -1344,13 +1277,6 @@ Perl_sv_upgrade(pTHX_ register SV *const sv, svtype new_type)
            HvSHAREKEYS_on(sv);         /* key-sharing on by default */
 #endif
            HvMAX(sv) = 7; /* (start with 8 buckets) */
-           if (old_type_details->body_size) {
-               HvFILL(sv) = 0;
-           } else {
-               /* It will have been zeroed when the new body was allocated.
-                  Lets not write to it, in case it confuses a write-back
-                  cache.  */
-           }
        }
 
        /* SVt_NULL isn't the only thing upgraded to AV or HV.
@@ -1372,6 +1298,10 @@ Perl_sv_upgrade(pTHX_ register SV *const sv, svtype new_type)
        break;
 
 
+    case SVt_REGEXP:
+       /* This ensures that SvTHINKFIRST(sv) is true, and hence that
+          sv_force_normal_flags(sv) is called.  */
+       SvFAKE_on(sv);
     case SVt_PVIV:
        /* XXX Is this still needed?  Was it ever needed?   Surely as there is
           no route from NV to PVIV, NOK can never be true  */
@@ -1382,7 +1312,6 @@ Perl_sv_upgrade(pTHX_ register SV *const sv, svtype new_type)
     case SVt_PVGV:
     case SVt_PVCV:
     case SVt_PVLV:
-    case SVt_REGEXP:
     case SVt_PVMG:
     case SVt_PVNV:
     case SVt_PV:
@@ -1429,8 +1358,18 @@ Perl_sv_upgrade(pTHX_ register SV *const sv, svtype new_type)
            SvNV_set(sv, 0);
 #endif
 
-       if (new_type == SVt_PVIO)
+       if (new_type == SVt_PVIO) {
+           IO * const io = MUTABLE_IO(sv);
+           GV *iogv = gv_fetchpvs("IO::File::", GV_ADD, SVt_PVHV);
+
+           SvOBJECT_on(io);
+           /* Clear the stashcache because a new IO could overrule a package
+              name */
+           hv_clear(PL_stashcache);
+
+           SvSTASH_set(io, MUTABLE_HV(SvREFCNT_inc(GvHV(iogv))));
            IoPAGE_LEN(sv) = 60;
+       }
        if (old_type < SVt_PV) {
            /* referant will be NULL unless the old type was SVt_IV emulating
               SVt_RV */
@@ -1442,14 +1381,14 @@ Perl_sv_upgrade(pTHX_ register SV *const sv, svtype new_type)
                   (unsigned long)new_type);
     }
 
-    if (old_type_details->arena) {
-       /* If there was an old body, then we need to free it.
-          Note that there is an assumption that all bodies of types that
-          can be upgraded came from arenas. Only the more complex non-
-          upgradable types are allowed to be directly malloc()ed.  */
+    if (old_type > SVt_IV) {
 #ifdef PURIFY
-       my_safefree(old_body);
+       safefree(old_body);
 #else
+       /* Note that there is an assumption that all bodies of types that
+          can be upgraded came from arenas. Only the more complex non-
+          upgradable types are allowed to be directly malloc()ed.  */
+       assert(old_type_details->arena);
        del_body((void*)((char*)old_body + old_type_details->offset),
                 &PL_body_roots[old_type]);
 #endif
@@ -1535,6 +1474,10 @@ Perl_sv_grow(pTHX_ register SV *const sv, register STRLEN newlen)
        s = SvPVX_mutable(sv);
 
     if (newlen > SvLEN(sv)) {          /* need more room? */
+       STRLEN minlen = SvCUR(sv);
+       minlen += (minlen >> PERL_STRLEN_EXPAND_SHIFT) + 10;
+       if (newlen < minlen)
+           newlen = minlen;
 #ifndef Perl_safesysmalloc_size
        newlen = PERL_STRLEN_ROUNDUP(newlen);
 #endif
@@ -1704,7 +1647,7 @@ Perl_sv_setnv(pTHX_ register SV *const sv, const NV num)
     case SVt_PVFM:
     case SVt_PVIO:
        Perl_croak(aTHX_ "Can't coerce %s to number in %s", sv_reftype(sv,0),
-                  OP_NAME(PL_op));
+                  OP_DESC(PL_op));
     default: NOOP;
     }
     SvNV_set(sv, num);
@@ -1858,27 +1801,6 @@ S_glob_2number(pTHX_ GV * const gv)
     return TRUE;
 }
 
-STATIC char *
-S_glob_2pv(pTHX_ GV * const gv, STRLEN * const len)
-{
-    const U32 wasfake = SvFLAGS(gv) & SVf_FAKE;
-    SV *const buffer = sv_newmortal();
-
-    PERL_ARGS_ASSERT_GLOB_2PV;
-
-    /* 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;
-
-    assert(SvPOK(buffer));
-    if (len) {
-       *len = SvCUR(buffer);
-    }
-    return SvPVX(buffer);
-}
-
 /* Actually, ISO C leaves conversion of UV to IV undefined, but
    until proven guilty, assume that things are not that bad... */
 
@@ -2347,7 +2269,10 @@ Perl_sv_2iv_flags(pTHX_ register SV *const sv, const I32 flags)
        if (SvROK(sv)) {
        return_rok:
            if (SvAMAGIC(sv)) {
-               SV * const tmpstr=AMG_CALLun(sv,numer);
+               SV * tmpstr;
+               if (flags & SV_SKIP_OVERLOAD)
+                   return 0;
+               tmpstr=AMG_CALLun(sv,numer);
                if (tmpstr && (!SvROK(tmpstr) || (SvRV(tmpstr) != SvRV(sv)))) {
                    return SvIV(tmpstr);
                }
@@ -2423,7 +2348,10 @@ Perl_sv_2uv_flags(pTHX_ register SV *const sv, const I32 flags)
        if (SvROK(sv)) {
        return_rok:
            if (SvAMAGIC(sv)) {
-               SV *const tmpstr = AMG_CALLun(sv,numer);
+               SV *tmpstr;
+               if (flags & SV_SKIP_OVERLOAD)
+                   return 0;
+               tmpstr = AMG_CALLun(sv,numer);
                if (tmpstr && (!SvROK(tmpstr) || (SvRV(tmpstr) != SvRV(sv)))) {
                    return SvUV(tmpstr);
                }
@@ -2450,17 +2378,17 @@ Perl_sv_2uv_flags(pTHX_ register SV *const sv, const I32 flags)
 }
 
 /*
-=for apidoc sv_2nv
+=for apidoc sv_2nv_flags
 
 Return the num value of an SV, doing any necessary string or integer
-conversion, magic etc. Normally used via the C<SvNV(sv)> and C<SvNVx(sv)>
-macros.
+conversion. If flags includes SV_GMAGIC, does an mg_get() first.
+Normally used via the C<SvNV(sv)> and C<SvNVx(sv)> macros.
 
 =cut
 */
 
 NV
-Perl_sv_2nv(pTHX_ register SV *const sv)
+Perl_sv_2nv_flags(pTHX_ register SV *const sv, const I32 flags)
 {
     dVAR;
     if (!sv)
@@ -2468,7 +2396,8 @@ Perl_sv_2nv(pTHX_ register SV *const sv)
     if (SvGMAGICAL(sv) || (SvTYPE(sv) == SVt_PVGV && SvVALID(sv))) {
        /* FBMs use the same flag bit as SVf_IVisUV, so must let them
           cache IVs just in case.  */
-       mg_get(sv);
+       if (flags & SV_GMAGIC)
+           mg_get(sv);
        if (SvNOKp(sv))
            return SvNVX(sv);
        if ((SvPOKp(sv) && SvLEN(sv)) && !SvIOKp(sv)) {
@@ -2493,7 +2422,10 @@ Perl_sv_2nv(pTHX_ register SV *const sv)
        if (SvROK(sv)) {
        return_rok:
            if (SvAMAGIC(sv)) {
-               SV *const tmpstr = AMG_CALLun(sv,numer);
+               SV *tmpstr;
+               if (flags & SV_SKIP_OVERLOAD)
+                   return 0;
+               tmpstr = AMG_CALLun(sv,numer);
                 if (tmpstr && (!SvROK(tmpstr) || (SvRV(tmpstr) != SvRV(sv)))) {
                    return SvNV(tmpstr);
                }
@@ -2693,6 +2625,7 @@ Perl_sv_2num(pTHX_ register SV *const sv)
        return sv;
     if (SvAMAGIC(sv)) {
        SV * const tmpsv = AMG_CALLun(sv,numer);
+       TAINT_IF(tmpsv && SvTAINTED(tmpsv));
        if (tmpsv && (!SvROK(tmpsv) || (SvRV(tmpsv) != SvRV(sv))))
            return sv_2num(tmpsv);
     }
@@ -2810,7 +2743,11 @@ Perl_sv_2pv_flags(pTHX_ register SV *const sv, STRLEN *const lp, const I32 flags
        if (SvROK(sv)) {
        return_rok:
             if (SvAMAGIC(sv)) {
-               SV *const tmpstr = AMG_CALLun(sv,string);
+               SV *tmpstr;
+               if (flags & SV_SKIP_OVERLOAD)
+                   return NULL;
+               tmpstr = AMG_CALLun(sv,string);
+               TAINT_IF(tmpstr && SvTAINTED(tmpstr));
                if (tmpstr && (!SvROK(tmpstr) || (SvRV(tmpstr) != SvRV(sv)))) {
                    /* Unwrap this:  */
                    /* char *pv = lp ? SvPV(tmpstr, *lp) : SvPV_nolen(tmpstr);
@@ -2958,7 +2895,7 @@ Perl_sv_2pv_flags(pTHX_ register SV *const sv, STRLEN *const lp, const I32 flags
        *s = '\0';
     }
     else if (SvNOKp(sv)) {
-       const int olderrno = errno;
+       dSAVE_ERRNO;
        if (SvTYPE(sv) < SVt_PVNV)
            sv_upgrade(sv, SVt_PVNV);
        /* The +20 is pure guesswork.  Configure test needed. --jhi */
@@ -2972,7 +2909,7 @@ Perl_sv_2pv_flags(pTHX_ register SV *const sv, STRLEN *const lp, const I32 flags
        {
            Gconvert(SvNVX(sv), NV_DIG, 0, s);
        }
-       errno = olderrno;
+       RESTORE_ERRNO;
 #ifdef FIXNEGATIVEZERO
         if (*s == '-' && s[1] == '0' && !s[2]) {
            s[0] = '0';
@@ -2986,8 +2923,29 @@ Perl_sv_2pv_flags(pTHX_ register SV *const sv, STRLEN *const lp, const I32 flags
 #endif
     }
     else {
-       if (isGV_with_GP(sv))
-           return glob_2pv(MUTABLE_GV(sv), lp);
+       if (isGV_with_GP(sv)) {
+           GV *const gv = MUTABLE_GV(sv);
+           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;
+
+           if (SvPOK(buffer)) {
+               if (lp) {
+                   *lp = SvCUR(buffer);
+               }
+               return SvPVX(buffer);
+           }
+           else {
+               if (lp)
+                   *lp = 0;
+               return (char *)"";
+           }
+       }
 
        if (lp)
            *lp = 0;
@@ -3111,7 +3069,7 @@ Perl_sv_2bool(pTHX_ register SV *const sv)
        if (SvAMAGIC(sv)) {
            SV * const tmpsv = AMG_CALLun(sv,bool_);
            if (tmpsv && (!SvROK(tmpsv) || (SvRV(tmpsv) != SvRV(sv))))
-               return (bool)SvTRUE(tmpsv);
+               return cBOOL(SvTRUE(tmpsv));
        }
        return SvRV(sv) != 0;
     }
@@ -3146,33 +3104,71 @@ Perl_sv_2bool(pTHX_ register SV *const sv)
 
 Converts the PV of an SV to its UTF-8-encoded form.
 Forces the SV to string form if it is not already.
+Will C<mg_get> on C<sv> if appropriate.
 Always sets the SvUTF8 flag to avoid future validity checks even
-if all the bytes have hibit clear.
+if the whole string is the same in UTF-8 as not.
+Returns the number of bytes in the converted string
 
 This is not as a general purpose byte encoding to Unicode interface:
 use the Encode extension for that.
 
+=for apidoc sv_utf8_upgrade_nomg
+
+Like sv_utf8_upgrade, but doesn't do magic on C<sv>
+
 =for apidoc sv_utf8_upgrade_flags
 
 Converts the PV of an SV to its UTF-8-encoded form.
 Forces the SV to string form if 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
+if all the bytes are invariant in UTF-8. If C<flags> has C<SV_GMAGIC> bit set,
+will C<mg_get> on C<sv> if appropriate, else not.
+Returns the number of bytes in the converted string
+C<sv_utf8_upgrade> and
 C<sv_utf8_upgrade_nomg> are implemented in terms of this function.
 
 This is not as a general purpose byte encoding to Unicode interface:
 use the Encode extension for that.
 
 =cut
+
+The grow version is currently not externally documented.  It adds a parameter,
+extra, which is the number of unused bytes the string of 'sv' is guaranteed to
+have free after it upon return.  This allows the caller to reserve extra space
+that it intends to fill, to avoid extra grows.
+
+Also externally undocumented for the moment is the flag SV_FORCE_UTF8_UPGRADE,
+which can be used to tell this function to not first check to see if there are
+any characters that are different in UTF-8 (variant characters) which would
+force it to allocate a new string to sv, but to assume there are.  Typically
+this flag is used by a routine that has already parsed the string to find that
+there are such characters, and passes this information on so that the work
+doesn't have to be repeated.
+
+(One might think that the calling routine could pass in the position of the
+first such variant, so it wouldn't have to be found again.  But that is not the
+case, because typically when the caller is likely to use this flag, it won't be
+calling this routine unless it finds something that won't fit into a byte.
+Otherwise it tries to not upgrade and just use bytes.  But some things that
+do fit into a byte are variants in utf8, and the caller may not have been
+keeping track of these.)
+
+If the routine itself changes the string, it adds a trailing NUL.  Such a NUL
+isn't guaranteed due to having other routines do the work in some input cases,
+or if the input is already flagged as being in utf8.
+
+The speed of this could perhaps be improved for many cases if someone wanted to
+write a fast function that counts the number of variant characters in a string,
+especially if it could return the position of the first one.
+
 */
 
 STRLEN
-Perl_sv_utf8_upgrade_flags(pTHX_ register SV *const sv, const I32 flags)
+Perl_sv_utf8_upgrade_flags_grow(pTHX_ register SV *const sv, const I32 flags, STRLEN extra)
 {
     dVAR;
 
-    PERL_ARGS_ASSERT_SV_UTF8_UPGRADE_FLAGS;
+    PERL_ARGS_ASSERT_SV_UTF8_UPGRADE_FLAGS_GROW;
 
     if (sv == &PL_sv_undef)
        return 0;
@@ -3180,14 +3176,17 @@ Perl_sv_utf8_upgrade_flags(pTHX_ register SV *const sv, const I32 flags)
        STRLEN len = 0;
        if (SvREADONLY(sv) && (SvPOKp(sv) || SvIOKp(sv) || SvNOKp(sv))) {
            (void) sv_2pv_flags(sv,&len, flags);
-           if (SvUTF8(sv))
+           if (SvUTF8(sv)) {
+               if (extra) SvGROW(sv, SvCUR(sv) + extra);
                return len;
+           }
        } else {
            (void) SvPV_force(sv,len);
        }
     }
 
     if (SvUTF8(sv)) {
+       if (extra) SvGROW(sv, SvCUR(sv) + extra);
        return SvCUR(sv);
     }
 
@@ -3195,42 +3194,206 @@ Perl_sv_utf8_upgrade_flags(pTHX_ register SV *const sv, const I32 flags)
         sv_force_normal_flags(sv, 0);
     }
 
-    if (PL_encoding && !(flags & SV_UTF8_NO_ENCODING))
+    if (PL_encoding && !(flags & SV_UTF8_NO_ENCODING)) {
         sv_recode_to_utf8(sv, PL_encoding);
-    else { /* Assume Latin-1/EBCDIC */
+       if (extra) SvGROW(sv, SvCUR(sv) + extra);
+       return SvCUR(sv);
+    }
+
+    if (SvCUR(sv) == 0) {
+       if (extra) SvGROW(sv, extra);
+    } else { /* Assume Latin-1/EBCDIC */
        /* This function could be much more efficient if we
-        * had a FLAG in SVs to signal if there are any hibit
+        * had a FLAG in SVs to signal if there are any variant
         * chars in the PV.  Given that there isn't such a flag
-        * make the loop as fast as possible. */
-       const U8 * const s = (U8 *) SvPVX_const(sv);
-       const U8 * const e = (U8 *) SvEND(sv);
-       const U8 *t = s;
+        * make the loop as fast as possible (although there are certainly ways
+        * to speed this up, eg. through vectorization) */
+       U8 * s = (U8 *) SvPVX_const(sv);
+       U8 * e = (U8 *) SvEND(sv);
+       U8 *t = s;
+       STRLEN two_byte_count = 0;
        
+       if (flags & SV_FORCE_UTF8_UPGRADE) goto must_be_utf8;
+
+       /* See if really will need to convert to utf8.  We mustn't rely on our
+        * incoming SV being well formed and having a trailing '\0', as certain
+        * code in pp_formline can send us partially built SVs. */
+
        while (t < e) {
            const U8 ch = *t++;
-           /* Check for hi bit */
-           if (!NATIVE_IS_INVARIANT(ch)) {
-               STRLEN len = SvCUR(sv);
-               /* *Currently* bytes_to_utf8() adds a '\0' after every string
-                  it converts. This isn't documented. It's not clear if it's
-                  a bad thing to be doing, and should be changed to do exactly
-                  what the documentation says. If so, this code will have to
-                  be changed.
-                  As is, we mustn't rely on our incoming SV being well formed
-                  and having a trailing '\0', as certain code in pp_formline
-                  can send us partially built SVs. */
-               U8 * const recoded = bytes_to_utf8((U8*)s, &len);
-
-               SvPV_free(sv); /* No longer using what was there before. */
-               SvPV_set(sv, (char*)recoded);
-               SvCUR_set(sv, len);
-               SvLEN_set(sv, len + 1); /* No longer know the real size. */
-               break;
-           }
+           if (NATIVE_IS_INVARIANT(ch)) continue;
+
+           t--;    /* t already incremented; re-point to first variant */
+           two_byte_count = 1;
+           goto must_be_utf8;
        }
-       /* Mark as UTF-8 even if no hibit - saves scanning loop */
+
+       /* utf8 conversion not needed because all are invariants.  Mark as
+        * UTF-8 even if no variant - saves scanning loop */
        SvUTF8_on(sv);
+       return SvCUR(sv);
+
+must_be_utf8:
+
+       /* Here, the string should be converted to utf8, either because of an
+        * input flag (two_byte_count = 0), or because a character that
+        * requires 2 bytes was found (two_byte_count = 1).  t points either to
+        * the beginning of the string (if we didn't examine anything), or to
+        * the first variant.  In either case, everything from s to t - 1 will
+        * occupy only 1 byte each on output.
+        *
+        * There are two main ways to convert.  One is to create a new string
+        * and go through the input starting from the beginning, appending each
+        * converted value onto the new string as we go along.  It's probably
+        * best to allocate enough space in the string for the worst possible
+        * case rather than possibly running out of space and having to
+        * reallocate and then copy what we've done so far.  Since everything
+        * from s to t - 1 is invariant, the destination can be initialized
+        * with these using a fast memory copy
+        *
+        * The other way is to figure out exactly how big the string should be
+        * by parsing the entire input.  Then you don't have to make it big
+        * enough to handle the worst possible case, and more importantly, if
+        * the string you already have is large enough, you don't have to
+        * allocate a new string, you can copy the last character in the input
+        * string to the final position(s) that will be occupied by the
+        * converted string and go backwards, stopping at t, since everything
+        * before that is invariant.
+        *
+        * There are advantages and disadvantages to each method.
+        *
+        * In the first method, we can allocate a new string, do the memory
+        * copy from the s to t - 1, and then proceed through the rest of the
+        * string byte-by-byte.
+        *
+        * In the second method, we proceed through the rest of the input
+        * string just calculating how big the converted string will be.  Then
+        * there are two cases:
+        *  1)  if the string has enough extra space to handle the converted
+        *      value.  We go backwards through the string, converting until we
+        *      get to the position we are at now, and then stop.  If this
+        *      position is far enough along in the string, this method is
+        *      faster than the other method.  If the memory copy were the same
+        *      speed as the byte-by-byte loop, that position would be about
+        *      half-way, as at the half-way mark, parsing to the end and back
+        *      is one complete string's parse, the same amount as starting
+        *      over and going all the way through.  Actually, it would be
+        *      somewhat less than half-way, as it's faster to just count bytes
+        *      than to also copy, and we don't have the overhead of allocating
+        *      a new string, changing the scalar to use it, and freeing the
+        *      existing one.  But if the memory copy is fast, the break-even
+        *      point is somewhere after half way.  The counting loop could be
+        *      sped up by vectorization, etc, to move the break-even point
+        *      further towards the beginning.
+        *  2)  if the string doesn't have enough space to handle the converted
+        *      value.  A new string will have to be allocated, and one might
+        *      as well, given that, start from the beginning doing the first
+        *      method.  We've spent extra time parsing the string and in
+        *      exchange all we've gotten is that we know precisely how big to
+        *      make the new one.  Perl is more optimized for time than space,
+        *      so this case is a loser.
+        * So what I've decided to do is not use the 2nd method unless it is
+        * guaranteed that a new string won't have to be allocated, assuming
+        * the worst case.  I also decided not to put any more conditions on it
+        * than this, for now.  It seems likely that, since the worst case is
+        * twice as big as the unknown portion of the string (plus 1), we won't
+        * be guaranteed enough space, causing us to go to the first method,
+        * unless the string is short, or the first variant character is near
+        * the end of it.  In either of these cases, it seems best to use the
+        * 2nd method.  The only circumstance I can think of where this would
+        * be really slower is if the string had once had much more data in it
+        * than it does now, but there is still a substantial amount in it  */
+
+       {
+           STRLEN invariant_head = t - s;
+           STRLEN size = invariant_head + (e - t) * 2 + 1 + extra;
+           if (SvLEN(sv) < size) {
+
+               /* Here, have decided to allocate a new string */
+
+               U8 *dst;
+               U8 *d;
+
+               Newx(dst, size, U8);
+
+               /* If no known invariants at the beginning of the input string,
+                * set so starts from there.  Otherwise, can use memory copy to
+                * get up to where we are now, and then start from here */
+
+               if (invariant_head <= 0) {
+                   d = dst;
+               } else {
+                   Copy(s, dst, invariant_head, char);
+                   d = dst + invariant_head;
+               }
+
+               while (t < e) {
+                   const UV uv = NATIVE8_TO_UNI(*t++);
+                   if (UNI_IS_INVARIANT(uv))
+                       *d++ = (U8)UNI_TO_NATIVE(uv);
+                   else {
+                       *d++ = (U8)UTF8_EIGHT_BIT_HI(uv);
+                       *d++ = (U8)UTF8_EIGHT_BIT_LO(uv);
+                   }
+               }
+               *d = '\0';
+               SvPV_free(sv); /* No longer using pre-existing string */
+               SvPV_set(sv, (char*)dst);
+               SvCUR_set(sv, d - dst);
+               SvLEN_set(sv, size);
+           } else {
+
+               /* Here, have decided to get the exact size of the string.
+                * Currently this happens only when we know that there is
+                * guaranteed enough space to fit the converted string, so
+                * don't have to worry about growing.  If two_byte_count is 0,
+                * then t points to the first byte of the string which hasn't
+                * been examined yet.  Otherwise two_byte_count is 1, and t
+                * points to the first byte in the string that will expand to
+                * two.  Depending on this, start examining at t or 1 after t.
+                * */
+
+               U8 *d = t + two_byte_count;
+
+
+               /* Count up the remaining bytes that expand to two */
+
+               while (d < e) {
+                   const U8 chr = *d++;
+                   if (! NATIVE_IS_INVARIANT(chr)) two_byte_count++;
+               }
+
+               /* The string will expand by just the number of bytes that
+                * occupy two positions.  But we are one afterwards because of
+                * the increment just above.  This is the place to put the
+                * trailing NUL, and to set the length before we decrement */
+
+               d += two_byte_count;
+               SvCUR_set(sv, d - s);
+               *d-- = '\0';
+
+
+               /* Having decremented d, it points to the position to put the
+                * very last byte of the expanded string.  Go backwards through
+                * the string, copying and expanding as we go, stopping when we
+                * get to the part that is invariant the rest of the way down */
+
+               e--;
+               while (e >= t) {
+                   const U8 ch = NATIVE8_TO_UNI(*e--);
+                   if (UNI_IS_INVARIANT(ch)) {
+                       *d-- = UNI_TO_NATIVE(ch);
+                   } else {
+                       *d-- = (U8)UTF8_EIGHT_BIT_LO(ch);
+                       *d-- = (U8)UTF8_EIGHT_BIT_HI(ch);
+                   }
+               }
+           }
+       }
     }
+
+    /* Mark as UTF-8 even if no variant - saves scanning loop */
+    SvUTF8_on(sv);
     return SvCUR(sv);
 }
 
@@ -3238,7 +3401,8 @@ Perl_sv_utf8_upgrade_flags(pTHX_ register SV *const sv, const I32 flags)
 =for apidoc sv_utf8_downgrade
 
 Attempts to convert the PV of an SV from characters to bytes.
-If the PV contains a character beyond byte, this conversion will fail;
+If the PV contains a character that cannot fit
+in a byte, this conversion will fail;
 in this case, either returns false or, if C<fail_ok> is not
 true, croaks.
 
@@ -3300,7 +3464,7 @@ Perl_sv_utf8_encode(pTHX_ register SV *const sv)
         sv_force_normal_flags(sv, 0);
     }
     if (SvREADONLY(sv)) {
-       Perl_croak(aTHX_ "%s", PL_no_modify);
+       Perl_croak_no_modify(aTHX);
     }
     (void) sv_utf8_upgrade(sv);
     SvUTF8_off(sv);
@@ -3416,12 +3580,6 @@ S_glob_assign_glob(pTHX_ SV *const dstr, SV *const sstr, const int dtype)
        SvFAKE_on(dstr);        /* can coerce to non-glob */
     }
 
-#ifdef GV_UNIQUE_CHECK
-    if (GvUNIQUE((const GV *)dstr)) {
-       Perl_croak(aTHX_ "%s", PL_no_modify);
-    }
-#endif
-
     if(GvGP(MUTABLE_GV(sstr))) {
         /* If source has method cache entry, clear it */
         if(GvCVGEN(sstr)) {
@@ -3475,12 +3633,6 @@ S_glob_assign_ref(pTHX_ SV *const dstr, SV *const sstr)
 
     PERL_ARGS_ASSERT_GLOB_ASSIGN_REF;
 
-#ifdef GV_UNIQUE_CHECK
-    if (GvUNIQUE((const GV *)dstr)) {
-       Perl_croak(aTHX_ "%s", PL_no_modify);
-    }
-#endif
-
     if (intro) {
        GvINTRO_off(dstr);      /* one-shot flag */
        GvLINE(dstr) = CopLINE(PL_curcop);
@@ -3505,6 +3657,7 @@ S_glob_assign_ref(pTHX_ SV *const dstr, SV *const sstr)
        goto common;
     case SVt_PVFM:
        location = (SV **) &GvFORM(dstr);
+       goto common;
     default:
        location = &GvSV(dstr);
        import_flag = GVf_IMPORTED_SV;
@@ -3570,6 +3723,10 @@ S_glob_assign_ref(pTHX_ SV *const dstr, SV *const sstr)
            && CopSTASH_ne(PL_curcop, GvSTASH(dstr))) {
            GvFLAGS(dstr) |= import_flag;
        }
+       if (stype == SVt_PVAV && strEQ(GvNAME((GV*)dstr), "ISA")) {
+           sv_magic(sref, dstr, PERL_MAGIC_isa, NULL, 0);
+           mro_isa_changed_in(GvSTASH(dstr));
+       }
        break;
     }
     SvREFCNT_dec(dref);
@@ -3686,7 +3843,6 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags)
        }
        /* Fall through */
 #endif
-    case SVt_REGEXP:
     case SVt_PV:
        if (dtype < SVt_PV)
            sv_upgrade(dstr, SVt_PV);
@@ -3703,12 +3859,17 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags)
        {
        const char * const type = sv_reftype(sstr,0);
        if (PL_op)
-           Perl_croak(aTHX_ "Bizarre copy of %s in %s", type, OP_NAME(PL_op));
+           Perl_croak(aTHX_ "Bizarre copy of %s in %s", type, OP_DESC(PL_op));
        else
            Perl_croak(aTHX_ "Bizarre copy of %s", type);
        }
        break;
 
+    case SVt_REGEXP:
+       if (dtype < SVt_REGEXP)
+           sv_upgrade(dstr, SVt_REGEXP);
+       break;
+
        /* case SVt_BIND: */
     case SVt_PVLV:
     case SVt_PVGV:
@@ -3758,7 +3919,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags)
     } else if (dtype == SVt_PVAV || dtype == SVt_PVHV) {
        const char * const type = sv_reftype(dstr,0);
        if (PL_op)
-           Perl_croak(aTHX_ "Cannot copy to %s in %s", type, OP_NAME(PL_op));
+           Perl_croak(aTHX_ "Cannot copy to %s in %s", type, OP_DESC(PL_op));
        else
            Perl_croak(aTHX_ "Cannot copy to %s", type);
     } else if (sflags & SVf_ROK) {
@@ -3799,9 +3960,8 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags)
     }
     else if (dtype == SVt_PVGV && isGV_with_GP(dstr)) {
        if (!(sflags & SVf_OK)) {
-           if (ckWARN(WARN_MISC))
-               Perl_warner(aTHX_ packWARN(WARN_MISC),
-                           "Undefined value assigned to typeglob");
+           Perl_ck_warner(aTHX_ packWARN(WARN_MISC),
+                          "Undefined value assigned to typeglob");
        }
        else {
            GV *gv = gv_fetchsv(sstr, GV_ADD, SVt_PVGV);
@@ -3812,6 +3972,9 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags)
            }
        }
     }
+    else if (dtype == SVt_REGEXP && stype == SVt_REGEXP) {
+       reg_temp_copy((REGEXP*)dstr, (REGEXP*)sstr);
+    }
     else if (sflags & SVp_POK) {
         bool isSwipe = 0;
 
@@ -3862,14 +4025,12 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags)
                 (!(flags & SV_NOSTEAL)) &&
                                        /* and we're allowed to steal temps */
                  SvREFCNT(sstr) == 1 &&   /* and no other references to it? */
-                 SvLEN(sstr)   &&        /* and really is a string */
-                               /* and won't be needed again, potentially */
-             !(PL_op && PL_op->op_type == OP_AASSIGN))
+                 SvLEN(sstr))             /* and really is a string */
 #ifdef PERL_OLD_COPY_ON_WRITE
             && ((flags & SV_COW_SHARED_HASH_KEYS)
                ? (!((sflags & CAN_COW_MASK) == CAN_COW_FLAGS
                     && (SvFLAGS(dstr) & CAN_COW_MASK) == CAN_COW_FLAGS
-                    && SvTYPE(sstr) >= SVt_PVIV))
+                    && SvTYPE(sstr) >= SVt_PVIV && SvTYPE(sstr) != SVt_PVFM))
                : 1)
 #endif
             ) {
@@ -3892,12 +4053,6 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags)
             }
 #ifdef PERL_OLD_COPY_ON_WRITE
             if (!isSwipe) {
-                /* I believe I should acquire a global SV mutex if
-                   it's a COW sv (not a shared hash key) to stop
-                   it going un copy-on-write.
-                   If the source SV has gone un copy on write between up there
-                   and down here, then (assert() that) it is of the correct
-                   form to make it copy on write again */
                 if ((sflags & (SVf_FAKE | SVf_READONLY))
                     != (SVf_FAKE | SVf_READONLY)) {
                     SvREADONLY_on(sstr);
@@ -3940,7 +4095,6 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags)
                 SvCUR_set(dstr, cur);
                 SvREADONLY_on(dstr);
                 SvFAKE_on(dstr);
-                /* Relesase a global SV mutex.  */
             }
             else
                 {      /* Passes the swipe test.  */
@@ -4344,7 +4498,6 @@ Perl_sv_force_normal_flags(pTHX_ register SV *const sv, const U32 flags)
 
 #ifdef PERL_OLD_COPY_ON_WRITE
     if (SvREADONLY(sv)) {
-        /* At this point I believe I should acquire a global SV mutex.  */
        if (SvFAKE(sv)) {
            const char * const pvx = SvPVX_const(sv);
            const STRLEN len = SvLEN(sv);
@@ -4384,8 +4537,7 @@ Perl_sv_force_normal_flags(pTHX_ register SV *const sv, const U32 flags)
             }
        }
        else if (IN_PERL_RUNTIME)
-           Perl_croak(aTHX_ "%s", PL_no_modify);
-        /* At this point I believe that I can drop the global SV mutex.  */
+           Perl_croak_no_modify(aTHX);
     }
 #else
     if (SvREADONLY(sv)) {
@@ -4402,13 +4554,52 @@ Perl_sv_force_normal_flags(pTHX_ register SV *const sv, const U32 flags)
            unshare_hek(SvSHARED_HEK_FROM_PV(pvx));
        }
        else if (IN_PERL_RUNTIME)
-           Perl_croak(aTHX_ "%s", PL_no_modify);
+           Perl_croak_no_modify(aTHX);
     }
 #endif
     if (SvROK(sv))
        sv_unref_flags(sv, flags);
     else if (SvFAKE(sv) && SvTYPE(sv) == SVt_PVGV)
        sv_unglob(sv);
+    else if (SvFAKE(sv) && SvTYPE(sv) == SVt_REGEXP) {
+       /* Need to downgrade the REGEXP to a simple(r) scalar. This is analagous
+          to sv_unglob. We only need it here, so inline it.  */
+       const svtype new_type = SvMAGIC(sv) || SvSTASH(sv) ? SVt_PVMG : SVt_PV;
+       SV *const temp = newSV_type(new_type);
+       void *const temp_p = SvANY(sv);
+
+       if (new_type == SVt_PVMG) {
+           SvMAGIC_set(temp, SvMAGIC(sv));
+           SvMAGIC_set(sv, NULL);
+           SvSTASH_set(temp, SvSTASH(sv));
+           SvSTASH_set(sv, NULL);
+       }
+       SvCUR_set(temp, SvCUR(sv));
+       /* Remember that SvPVX is in the head, not the body. */
+       if (SvLEN(temp)) {
+           SvLEN_set(temp, SvLEN(sv));
+           /* This signals "buffer is owned by someone else" in sv_clear,
+              which is the least effort way to stop it freeing the buffer.
+           */
+           SvLEN_set(sv, SvLEN(sv)+1);
+       } else {
+           /* Their buffer is already owned by someone else. */
+           SvPVX(sv) = savepvn(SvPVX(sv), SvCUR(sv));
+           SvLEN_set(temp, SvCUR(sv)+1);
+       }
+
+       /* Now swap the rest of the bodies. */
+
+       SvFLAGS(sv) &= ~(SVf_FAKE|SVTYPEMASK);
+       SvFLAGS(sv) |= new_type;
+       SvANY(sv) = SvANY(temp);
+
+       SvFLAGS(temp) &= ~(SVTYPEMASK);
+       SvFLAGS(temp) |= SVt_REGEXP|SVf_FAKE;
+       SvANY(temp) = temp_p;
+
+       SvREFCNT_dec(temp);
+    }
 }
 
 /*
@@ -4591,7 +4782,8 @@ Perl_sv_catsv_flags(pTHX_ SV *const dsv, register SV *const ssv, const I32 flags
                    spv = SvPV_const(csv, slen);
                }
                else
-                   sv_utf8_upgrade_nomg(dsv);
+                   /* Leave enough space for the cat that's about to happen */
+                   sv_utf8_upgrade_flags_grow(dsv, 0, slen);
            }
            sv_catpvn_nomg(dsv, spv, slen);
        }
@@ -4815,7 +5007,7 @@ Perl_sv_magic(pTHX_ register SV *const sv, SV *const obj, const int how,
            && how != PERL_MAGIC_backref
           )
        {
-           Perl_croak(aTHX_ "%s", PL_no_modify);
+           Perl_croak_no_modify(aTHX);
        }
     }
     if (SvMAGICAL(sv) || (how == PERL_MAGIC_taint && SvTYPE(sv) >= SVt_PVMG)) {
@@ -4898,8 +5090,6 @@ Perl_sv_magic(pTHX_ register SV *const sv, SV *const obj, const int how,
     case PERL_MAGIC_qr:
        vtable = &PL_vtbl_regexp;
        break;
-    case PERL_MAGIC_hints:
-       /* As this vtable is all NULL, we can reuse it.  */
     case PERL_MAGIC_sig:
        vtable = &PL_vtbl_sig;
        break;
@@ -4942,6 +5132,9 @@ Perl_sv_magic(pTHX_ register SV *const sv, SV *const obj, const int how,
     case PERL_MAGIC_hintselem:
        vtable = &PL_vtbl_hintselem;
        break;
+    case PERL_MAGIC_hints:
+       vtable = &PL_vtbl_hints;
+       break;
     case PERL_MAGIC_ext:
        /* Reserved for use by extensions not perl internals.           */
        /* Useful for attaching extension internal data to perl vars.   */
@@ -4991,7 +5184,7 @@ Perl_sv_unmagic(pTHX_ SV *const sv, const int type)
             const MGVTBL* const vtbl = mg->mg_virtual;
            *mgp = mg->mg_moremagic;
            if (vtbl && vtbl->svt_free)
-               CALL_FPTR(vtbl->svt_free)(aTHX_ sv, mg);
+               vtbl->svt_free(aTHX_ sv, mg);
            if (mg->mg_ptr && mg->mg_type != PERL_MAGIC_regex_global) {
                if (mg->mg_len > 0)
                    Safefree(mg->mg_ptr);
@@ -5007,12 +5200,14 @@ Perl_sv_unmagic(pTHX_ SV *const sv, const int type)
        else
            mgp = &mg->mg_moremagic;
     }
-    if (!SvMAGIC(sv)) {
+    if (SvMAGIC(sv)) {
+       if (SvMAGICAL(sv))      /* if we're under save_magic, wait for restore_magic; */
+           mg_magical(sv);     /*    else fix the flags now */
+    }
+    else {
        SvMAGICAL_off(sv);
        SvFLAGS(sv) |= (SvFLAGS(sv) & (SVp_IOK|SVp_NOK|SVp_POK)) >> PRIVSHIFT;
-       SvMAGIC_set(sv, NULL);
     }
-
     return 0;
 }
 
@@ -5040,8 +5235,7 @@ Perl_sv_rvweaken(pTHX_ SV *const sv)
     if (!SvROK(sv))
        Perl_croak(aTHX_ "Can't weaken a nonreference");
     else if (SvWEAKREF(sv)) {
-       if (ckWARN(WARN_MISC))
-           Perl_warner(aTHX_ packWARN(WARN_MISC), "Reference is already weak");
+       Perl_ck_warner(aTHX_ packWARN(WARN_MISC), "Reference is already weak");
        return sv;
     }
     tsv = SvRV(sv);
@@ -5053,6 +5247,13 @@ Perl_sv_rvweaken(pTHX_ SV *const sv)
 
 /* Give tsv backref magic if it hasn't already got it, then push a
  * back-reference to sv onto the array associated with the backref magic.
+ *
+ * As an optimisation, if there's only one backref and it's not an AV,
+ * store it directly in the HvAUX or mg_obj slot, avoiding the need to
+ * allocate an AV. (Whether the slot holds an AV tells us whether this is
+ * active.)
+ *
+ * If an HV's backref is stored in magic, it is moved back to HvAUX.
  */
 
 /* A discussion about the backreferences array and its refcount:
@@ -5062,61 +5263,86 @@ Perl_sv_rvweaken(pTHX_ SV *const sv)
  * structure, from the xhv_backreferences field. (A HV without hv_aux will
  * have the standard magic instead.) The array is created with a refcount
  * of 2. This means that if during global destruction the array gets
- * picked on first to have its refcount decremented by the random zapper,
- * it won't actually be freed, meaning it's still theere for when its
- * parent gets freed.
- * When the parent SV is freed, in the case of magic, the magic is freed,
- * Perl_magic_killbackrefs is called which decrements one refcount, then
- * mg_obj is freed which kills the second count.
- * In the vase of a HV being freed, one ref is removed by
- * Perl_hv_kill_backrefs, the other by Perl_sv_kill_backrefs, which it
- * calls.
+ * picked on before its parent to have its refcount decremented by the
+ * random zapper, it won't actually be freed, meaning it's still there for
+ * when its parent gets freed.
+ *
+ * When the parent SV is freed, the extra ref is killed by
+ * Perl_sv_kill_backrefs.  The other ref is killed, in the case of magic,
+ * by mg_free() / MGf_REFCOUNTED, or for a hash, by Perl_hv_kill_backrefs.
+ *
+ * When a single backref SV is stored directly, it is not reference
+ * counted.
  */
 
 void
 Perl_sv_add_backref(pTHX_ SV *const tsv, SV *const sv)
 {
     dVAR;
-    AV *av;
+    SV **svp;
+    AV *av = NULL;
+    MAGIC *mg = NULL;
 
     PERL_ARGS_ASSERT_SV_ADD_BACKREF;
 
-    if (SvTYPE(tsv) == SVt_PVHV) {
-       AV **const avp = Perl_hv_backreferences_p(aTHX_ MUTABLE_HV(tsv));
-
-       av = *avp;
-       if (!av) {
-           /* There is no AV in the offical place - try a fixup.  */
-           MAGIC *const mg = mg_find(tsv, PERL_MAGIC_backref);
+    /* find slot to store array or singleton backref */
 
-           if (mg) {
-               /* Aha. They've got it stowed in magic.  Bring it back.  */
-               av = MUTABLE_AV(mg->mg_obj);
-               /* Stop mg_free decreasing the refernce count.  */
+    if (SvTYPE(tsv) == SVt_PVHV) {
+       svp = (SV**)Perl_hv_backreferences_p(aTHX_ MUTABLE_HV(tsv));
+
+       if (!*svp) {
+           if ((mg = mg_find(tsv, PERL_MAGIC_backref))) {
+               /* Aha. They've got it stowed in magic instead.
+                * Move it back to xhv_backreferences */
+               *svp = mg->mg_obj;
+               /* Stop mg_free decreasing the reference count.  */
                mg->mg_obj = NULL;
                /* Stop mg_free even calling the destructor, given that
                   there's no AV to free up.  */
                mg->mg_virtual = 0;
                sv_unmagic(tsv, PERL_MAGIC_backref);
-           } else {
-               av = newAV();
-               AvREAL_off(av);
-               SvREFCNT_inc_simple_void(av); /* see discussion above */
+               mg = NULL;
            }
-           *avp = av;
        }
     } else {
-       const MAGIC *const mg
-           = SvMAGICAL(tsv) ? mg_find(tsv, PERL_MAGIC_backref) : NULL;
-       if (mg)
-           av = MUTABLE_AV(mg->mg_obj);
-       else {
-           av = newAV();
-           AvREAL_off(av);
-           sv_magic(tsv, MUTABLE_SV(av), PERL_MAGIC_backref, NULL, 0);
-           /* av now has a refcnt of 2; see discussion above */
+       if (! ((mg =
+           (SvMAGICAL(tsv) ? mg_find(tsv, PERL_MAGIC_backref) : NULL))))
+       {
+           sv_magic(tsv, NULL, PERL_MAGIC_backref, NULL, 0);
+           mg = mg_find(tsv, PERL_MAGIC_backref);
        }
+       svp = &(mg->mg_obj);
     }
+
+    /* create or retrieve the array */
+
+    if (   (!*svp && SvTYPE(sv) == SVt_PVAV)
+       || (*svp && SvTYPE(*svp) != SVt_PVAV)
+    ) {
+       /* create array */
+       av = newAV();
+       AvREAL_off(av);
+       SvREFCNT_inc_simple_void(av);
+       /* av now has a refcnt of 2; see discussion above */
+       if (*svp) {
+           /* move single existing backref to the array */
+           av_extend(av, 1);
+           AvARRAY(av)[++AvFILLp(av)] = *svp; /* av_push() */
+       }
+       *svp = (SV*)av;
+       if (mg)
+           mg->mg_flags |= MGf_REFCOUNTED;
+    }
+    else
+       av = MUTABLE_AV(*svp);
+
+    if (!av) {
+       /* optimisation: store single backref directly in HvAUX or mg_obj */
+       *svp = sv;
+       return;
+    }
+    /* push new backref */
+    assert(SvTYPE(av) == SVt_PVAV);
     if (AvFILLp(av) >= AvMAX(av)) {
         av_extend(av, AvFILLp(av)+1);
     }
@@ -5127,95 +5353,139 @@ Perl_sv_add_backref(pTHX_ SV *const tsv, SV *const sv)
  * with the SV we point to.
  */
 
-STATIC void
-S_sv_del_backref(pTHX_ SV *const tsv, SV *const sv)
+void
+Perl_sv_del_backref(pTHX_ SV *const tsv, SV *const sv)
 {
     dVAR;
-    AV *av = NULL;
-    SV **svp;
+    SV **svp = NULL;
     I32 i;
 
     PERL_ARGS_ASSERT_SV_DEL_BACKREF;
 
     if (SvTYPE(tsv) == SVt_PVHV && SvOOK(tsv)) {
-       av = *Perl_hv_backreferences_p(aTHX_ MUTABLE_HV(tsv));
-       /* We mustn't attempt to "fix up" the hash here by moving the
-          backreference array back to the hv_aux structure, as that is stored
-          in the main HvARRAY(), and hfreentries assumes that no-one
-          reallocates HvARRAY() while it is running.  */
+       svp = (SV**)Perl_hv_backreferences_p(aTHX_ MUTABLE_HV(tsv));
     }
-    if (!av) {
-       const MAGIC *const mg
+    if (!svp || !*svp) {
+       MAGIC *const mg
            = SvMAGICAL(tsv) ? mg_find(tsv, PERL_MAGIC_backref) : NULL;
-       if (mg)
-           av = MUTABLE_AV(mg->mg_obj);
+       svp =  mg ? &(mg->mg_obj) : NULL;
     }
 
-    if (!av)
+    if (!svp || !*svp)
        Perl_croak(aTHX_ "panic: del_backref");
 
-    assert(!SvIS_FREED(av));
-
-    svp = AvARRAY(av);
-    /* We shouldn't be in here more than once, but for paranoia reasons lets
-       not assume this.  */
-    for (i = AvFILLp(av); i >= 0; i--) {
-       if (svp[i] == sv) {
-           const SSize_t fill = AvFILLp(av);
-           if (i != fill) {
-               /* We weren't the last entry.
-                  An unordered list has this property that you can take the
-                  last element off the end to fill the hole, and it's still
-                  an unordered list :-)
-               */
-               svp[i] = svp[fill];
+    if (SvTYPE(*svp) == SVt_PVAV) {
+       int count = 0;
+       AV * const av = (AV*)*svp;
+       assert(!SvIS_FREED(av));
+       svp = AvARRAY(av);
+       for (i = AvFILLp(av); i >= 0; i--) {
+           if (svp[i] == sv) {
+               const SSize_t fill = AvFILLp(av);
+               if (i != fill) {
+                   /* We weren't the last entry.
+                      An unordered list has this property that you can take the
+                      last element off the end to fill the hole, and it's still
+                      an unordered list :-)
+                   */
+                   svp[i] = svp[fill];
+               }
+               svp[fill] = NULL;
+               AvFILLp(av) = fill - 1;
+               count++;
+#ifndef DEBUGGING
+               break; /* should only be one */
+#endif
            }
-           svp[fill] = NULL;
-           AvFILLp(av) = fill - 1;
        }
+       assert(count == 1);
+    }
+    else {
+       /* optimisation: only a single backref, stored directly */
+       if (*svp != sv)
+           Perl_croak(aTHX_ "panic: del_backref");
+       *svp = NULL;
     }
+
 }
 
-int
+void
 Perl_sv_kill_backrefs(pTHX_ SV *const sv, AV *const av)
 {
-    SV **svp = AvARRAY(av);
+    SV **svp;
+    SV **last;
+    bool is_array;
 
     PERL_ARGS_ASSERT_SV_KILL_BACKREFS;
-    PERL_UNUSED_ARG(sv);
 
-    assert(!svp || !SvIS_FREED(av));
-    if (svp) {
-       SV *const *const last = svp + AvFILLp(av);
+    if (!av)
+       return;
+
+    is_array = (SvTYPE(av) == SVt_PVAV);
+    if (is_array) {
+       assert(!SvIS_FREED(av));
+       svp = AvARRAY(av);
+       if (svp)
+           last = svp + AvFILLp(av);
+    }
+    else {
+       /* optimisation: only a single backref, stored directly */
+       svp = (SV**)&av;
+       last = svp;
+    }
 
+    if (svp) {
        while (svp <= last) {
            if (*svp) {
                SV *const referrer = *svp;
                if (SvWEAKREF(referrer)) {
                    /* XXX Should we check that it hasn't changed? */
+                   assert(SvROK(referrer));
                    SvRV_set(referrer, 0);
                    SvOK_off(referrer);
                    SvWEAKREF_off(referrer);
                    SvSETMAGIC(referrer);
                } else if (SvTYPE(referrer) == SVt_PVGV ||
                           SvTYPE(referrer) == SVt_PVLV) {
+                   assert(SvTYPE(sv) == SVt_PVHV); /* stash backref */
                    /* You lookin' at me?  */
                    assert(GvSTASH(referrer));
                    assert(GvSTASH(referrer) == (const HV *)sv);
                    GvSTASH(referrer) = 0;
+               } else if (SvTYPE(referrer) == SVt_PVCV ||
+                          SvTYPE(referrer) == SVt_PVFM) {
+                   if (SvTYPE(sv) == SVt_PVHV) { /* stash backref */
+                       /* You lookin' at me?  */
+                       assert(CvSTASH(referrer));
+                       assert(CvSTASH(referrer) == (const HV *)sv);
+                       CvSTASH(referrer) = 0;
+                   }
+                   else {
+                       assert(SvTYPE(sv) == SVt_PVGV);
+                       /* You lookin' at me?  */
+                       assert(CvGV(referrer));
+                       assert(CvGV(referrer) == (const GV *)sv);
+                       anonymise_cv_maybe(MUTABLE_GV(sv),
+                                               MUTABLE_CV(referrer));
+                   }
+
                } else {
                    Perl_croak(aTHX_
                               "panic: magic_killbackrefs (flags=%"UVxf")",
                               (UV)SvFLAGS(referrer));
                }
 
-               *svp = NULL;
+               if (is_array)
+                   *svp = NULL;
            }
            svp++;
        }
     }
-    SvREFCNT_dec(av); /* remove extra count added by sv_add_backref() */
-    return 0;
+    if (is_array) {
+       AvFILLp(av) = -1;
+       SvREFCNT_dec(av); /* remove extra count added by sv_add_backref() */
+    }
+    return;
 }
 
 /*
@@ -5338,8 +5608,8 @@ Perl_sv_replace(pTHX_ register SV *const sv, register SV *const nsv)
 
     SV_CHECK_THINKFIRST_COW_DROP(sv);
     if (SvREFCNT(nsv) != 1) {
-       Perl_croak(aTHX_ "panic: reference miscount on nsv in sv_replace() (%"
-                  UVuf " != 1)", (UV) SvREFCNT(nsv));
+       Perl_croak(aTHX_ "panic: reference miscount on nsv in sv_replace()"
+                  " (%" UVuf " != 1)", (UV) SvREFCNT(nsv));
     }
     if (SvMAGICAL(sv)) {
        if (SvMAGICAL(nsv))
@@ -5396,6 +5666,45 @@ Perl_sv_replace(pTHX_ register SV *const sv, register SV *const nsv)
     del_SV(nsv);
 }
 
+/* We're about to free a GV which has a CV that refers back to us.
+ * If that CV will outlive us, make it anonymous (i.e. fix up its CvGV
+ * field) */
+
+STATIC void
+S_anonymise_cv_maybe(pTHX_ GV *gv, CV* cv)
+{
+    char *stash;
+    SV *gvname;
+    GV *anongv;
+
+    PERL_ARGS_ASSERT_ANONYMISE_CV_MAYBE;
+
+    /* be assertive! */
+    assert(SvREFCNT(gv) == 0);
+    assert(isGV(gv) && isGV_with_GP(gv));
+    assert(GvGP(gv));
+    assert(!CvANON(cv));
+    assert(CvGV(cv) == gv);
+
+    /* will the CV shortly be freed by gp_free() ? */
+    if (GvCV(gv) == cv && GvGP(gv)->gp_refcnt < 2 && SvREFCNT(cv) < 2) {
+       SvANY(cv)->xcv_gv = NULL;
+       return;
+    }
+
+    /* if not, anonymise: */
+    stash  = GvSTASH(gv) ? HvNAME(GvSTASH(gv)) : NULL;
+    gvname = Perl_newSVpvf(aTHX_ "%s::__ANON__",
+                                       stash ? stash : "__ANON__");
+    anongv = gv_fetchsv(gvname, GV_ADDMULTI, SVt_PVCV);
+    SvREFCNT_dec(gvname);
+
+    CvANON_on(cv);
+    CvCVGV_RC_on(cv);
+    SvANY(cv)->xcv_gv = MUTABLE_GV(SvREFCNT_inc(anongv));
+}
+
+
 /*
 =for apidoc sv_clear
 
@@ -5425,15 +5734,9 @@ Perl_sv_clear(pTHX_ register SV *const sv)
 
     if (type <= SVt_IV) {
        /* See the comment in sv.h about the collusion between this early
-          return and the overloading of the NULL and IV slots in the size
-          table.  */
-       if (SvROK(sv)) {
-           SV * const target = SvRV(sv);
-           if (SvWEAKREF(sv))
-               sv_del_backref(target, sv);
-           else
-               SvREFCNT_dec(target);
-       }
+          return and the overloading of the NULL slots in the size table.  */
+       if (SvROK(sv))
+           goto free_rv;
        SvFLAGS(sv) &= SVf_BREAK;
        SvFLAGS(sv) |= SVTYPEMASK;
        return;
@@ -5449,7 +5752,15 @@ Perl_sv_clear(pTHX_ register SV *const sv)
                CV* destructor;
                stash = SvSTASH(sv);
                destructor = StashHANDLER(stash,DESTROY);
-               if (destructor) {
+               if (destructor
+                       /* A constant subroutine can have no side effects, so
+                          don't bother calling it.  */
+                       && !CvCONST(destructor)
+                       /* Don't bother calling an empty destructor */
+                       && (CvISXSUB(destructor)
+                       || (CvSTART(destructor)
+                           && (CvSTART(destructor)->op_next->op_type != OP_LEAVESUB))))
+               {
                    SV* const tmpref = newRV(sv);
                    SvREADONLY_on(tmpref);   /* DESTROY() could be naughty */
                    ENTER;
@@ -5505,7 +5816,8 @@ Perl_sv_clear(pTHX_ register SV *const sv)
        if (IoIFP(sv) &&
            IoIFP(sv) != PerlIO_stdin() &&
            IoIFP(sv) != PerlIO_stdout() &&
-           IoIFP(sv) != PerlIO_stderr())
+           IoIFP(sv) != PerlIO_stderr() &&
+           !(IoFLAGS(sv) & IOf_FAKE_DIRP))
        {
            io_close(MUTABLE_IO(sv), FALSE);
        }
@@ -5523,6 +5835,10 @@ Perl_sv_clear(pTHX_ register SV *const sv)
     case SVt_PVCV:
     case SVt_PVFM:
        cv_undef(MUTABLE_CV(sv));
+       /* If we're in a stash, we don't own a reference to it. However it does
+          have a back reference to us, which needs to be cleared.  */
+       if ((stash = CvSTASH(sv)))
+           sv_del_backref(MUTABLE_SV(stash), sv);
        goto freescalar;
     case SVt_PVHV:
        if (PL_last_swash_hv == (const HV *)sv) {
@@ -5577,17 +5893,19 @@ Perl_sv_clear(pTHX_ register SV *const sv)
            /* Don't even bother with turning off the OOK flag.  */
        }
        if (SvROK(sv)) {
-           SV * const target = SvRV(sv);
-           if (SvWEAKREF(sv))
-               sv_del_backref(target, sv);
-           else
-               SvREFCNT_dec(target);
+       free_rv:
+           {
+               SV * const target = SvRV(sv);
+               if (SvWEAKREF(sv))
+                   sv_del_backref(target, sv);
+               else
+                   SvREFCNT_dec(target);
+           }
        }
 #ifdef PERL_OLD_COPY_ON_WRITE
-       else if (SvPVX_const(sv)) {
+       else if (SvPVX_const(sv)
+                && !(SvTYPE(sv) == SVt_PVIO && !(IoFLAGS(sv) & IOf_FAKE_DIRP))) {
             if (SvIsCOW(sv)) {
-                /* I believe I need to grab the global SV mutex here and
-                   then recheck the COW status.  */
                 if (DEBUG_C_TEST) {
                     PerlIO_printf(Perl_debug_log, "Copy on write: clear\n");
                     sv_dump(sv);
@@ -5598,14 +5916,14 @@ Perl_sv_clear(pTHX_ register SV *const sv)
                    unshare_hek(SvSHARED_HEK_FROM_PV(SvPVX_const(sv)));
                }
 
-                /* And drop it here.  */
                 SvFAKE_off(sv);
             } else if (SvLEN(sv)) {
                 Safefree(SvPVX_const(sv));
             }
        }
 #else
-       else if (SvPVX_const(sv) && SvLEN(sv))
+       else if (SvPVX_const(sv) && SvLEN(sv)
+                && !(SvTYPE(sv) == SVt_PVIO && !(IoFLAGS(sv) & IOf_FAKE_DIRP)))
            Safefree(SvPVX_mutable(sv));
        else if (SvPVX_const(sv) && SvREADONLY(sv) && SvFAKE(sv)) {
            unshare_hek(SvSHARED_HEK_FROM_PV(SvPVX_const(sv)));
@@ -5625,7 +5943,7 @@ Perl_sv_clear(pTHX_ register SV *const sv)
                 &PL_body_roots[type]);
     }
     else if (sv_type_details->body_size) {
-       my_safefree(SvANY(sv));
+       safefree(SvANY(sv));
     }
 }
 
@@ -5715,10 +6033,9 @@ Perl_sv_free2(pTHX_ SV *const sv)
 
 #ifdef DEBUGGING
     if (SvTEMP(sv)) {
-       if (ckWARN_d(WARN_DEBUGGING))
-           Perl_warner(aTHX_ packWARN(WARN_DEBUGGING),
-                       "Attempt to free temp prematurely: SV 0x%"UVxf
-                        pTHX__FORMAT, PTR2UV(sv) pTHX__VALUE);
+       Perl_ck_warner_d(aTHX_ packWARN(WARN_DEBUGGING),
+                        "Attempt to free temp prematurely: SV 0x%"UVxf
+                        pTHX__FORMAT, PTR2UV(sv) pTHX__VALUE);
        return;
     }
 #endif
@@ -5766,7 +6083,7 @@ UTF-8 bytes as a single character. Handles magic and type coercion.
 */
 
 /*
- * The length is cached in PERL_UTF8_magic, in the mg_len field.  Also the
+ * The length is cached in PERL_MAGIC_utf8, in the mg_len field.  Also the
  * mg_ptr is used, by sv_pos_u2b() and sv_pos_b2u() - see the comments below.
  * (Note that the mg_len is not the length of the mg_ptr field.
  * This allows the cache to store the character length of the string without
@@ -5791,32 +6108,26 @@ Perl_sv_len_utf8(pTHX_ register SV *const sv)
            STRLEN ulen;
            MAGIC *mg = SvMAGICAL(sv) ? mg_find(sv, PERL_MAGIC_utf8) : NULL;
 
-           if (mg && mg->mg_len != -1) {
-               ulen = mg->mg_len;
+           if (mg && (mg->mg_len != -1 || mg->mg_ptr)) {
+               if (mg->mg_len != -1)
+                   ulen = mg->mg_len;
+               else {
+                   /* We can use the offset cache for a headstart.
+                      The longer value is stored in the first pair.  */
+                   STRLEN *cache = (STRLEN *) mg->mg_ptr;
+
+                   ulen = cache[0] + Perl_utf8_length(aTHX_ s + cache[1],
+                                                      s + len);
+               }
+               
                if (PL_utf8cache < 0) {
                    const STRLEN real = Perl_utf8_length(aTHX_ s, s + len);
-                   if (real != ulen) {
-                       /* 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: sv_len_utf8 cache %"UVuf
-                                  " real %"UVuf" for %"SVf,
-                                  (UV) ulen, (UV) real, SVfARG(sv));
-                   }
+                   assert_uft8_cache_coherent("sv_len_utf8", ulen, real, sv);
                }
            }
            else {
                ulen = Perl_utf8_length(aTHX_ s, s + len);
-               if (!SvREADONLY(sv)) {
-                   if (!mg) {
-                       mg = sv_magicext(sv, 0, PERL_MAGIC_utf8,
-                                        &PL_vtbl_utf8, 0, 0);
-                   }
-                   assert(mg);
-                   mg->mg_len = ulen;
-               }
+               utf8_mg_len_cache_update(sv, &mg, ulen);
            }
            return ulen;
        }
@@ -5828,19 +6139,27 @@ Perl_sv_len_utf8(pTHX_ register SV *const sv)
    offset.  */
 static STRLEN
 S_sv_pos_u2b_forwards(const U8 *const start, const U8 *const send,
-                     STRLEN uoffset)
+                     STRLEN *const uoffset_p, bool *const at_end)
 {
     const U8 *s = start;
+    STRLEN uoffset = *uoffset_p;
 
     PERL_ARGS_ASSERT_SV_POS_U2B_FORWARDS;
 
-    while (s < send && uoffset--)
+    while (s < send && uoffset) {
+       --uoffset;
        s += UTF8SKIP(s);
-    if (s > send) {
+    }
+    if (s == send) {
+       *at_end = TRUE;
+    }
+    else if (s > send) {
+       *at_end = TRUE;
        /* This is the existing behaviour. Possibly it should be a croak, as
           it's actually a bounds error  */
        s = send;
     }
+    *uoffset_p -= uoffset;
     return s - start;
 }
 
@@ -5849,7 +6168,7 @@ S_sv_pos_u2b_forwards(const U8 *const start, const U8 *const send,
    the passed in UTF-8 offset.  */
 static STRLEN
 S_sv_pos_u2b_midway(const U8 *const start, const U8 *send,
-                     const STRLEN uoffset, const STRLEN uend)
+                   STRLEN uoffset, const STRLEN uend)
 {
     STRLEN backw = uend - uoffset;
 
@@ -5859,7 +6178,14 @@ S_sv_pos_u2b_midway(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 sv_pos_u2b_forwards(start, send, uoffset);
+       const U8 *s = start;
+
+       while (s < send && uoffset--)
+           s += UTF8SKIP(s);
+       assert (s <= send);
+       if (s > send)
+           s = send;
+       return s - start;
     }
 
     while (backw--) {
@@ -5880,18 +6206,24 @@ S_sv_pos_u2b_midway(const U8 *const start, const U8 *send,
    created if necessary, and the found value offered to it for update.  */
 static STRLEN
 S_sv_pos_u2b_cached(pTHX_ SV *const sv, MAGIC **const mgp, const U8 *const start,
-                   const U8 *const send, const STRLEN uoffset,
+                   const U8 *const send, STRLEN uoffset,
                    STRLEN uoffset0, STRLEN boffset0)
 {
     STRLEN boffset = 0; /* Actually always set, but let's keep gcc happy.  */
     bool found = FALSE;
+    bool at_end = FALSE;
 
     PERL_ARGS_ASSERT_SV_POS_U2B_CACHED;
 
     assert (uoffset >= uoffset0);
 
-    if (SvMAGICAL(sv) && !SvREADONLY(sv) && PL_utf8cache
-       && (*mgp || (*mgp = mg_find(sv, PERL_MAGIC_utf8)))) {
+    if (!uoffset)
+       return 0;
+
+    if (!SvREADONLY(sv)
+       && PL_utf8cache
+       && (*mgp || (SvTYPE(sv) >= SVt_PVMG &&
+                    (*mgp = mg_find(sv, PERL_MAGIC_utf8))))) {
        if ((*mgp)->mg_ptr) {
            STRLEN *cache = (STRLEN *) (*mgp)->mg_ptr;
            if (cache[0] == uoffset) {
@@ -5917,9 +6249,11 @@ S_sv_pos_u2b_cached(pTHX_ SV *const sv, MAGIC **const mgp, const U8 *const start
                                              uoffset - uoffset0,
                                              (*mgp)->mg_len - uoffset0);
                } else {
+                   uoffset -= uoffset0;
                    boffset = boffset0
                        + sv_pos_u2b_forwards(start + boffset0,
-                                               send, uoffset - uoffset0);
+                                             send, &uoffset, &at_end);
+                   uoffset += uoffset0;
                }
            }
            else if (cache[2] < uoffset) {
@@ -5957,87 +6291,142 @@ S_sv_pos_u2b_cached(pTHX_ SV *const sv, MAGIC **const mgp, const U8 *const start
     }
 
     if (!found || PL_utf8cache < 0) {
-       const STRLEN real_boffset
-           = boffset0 + sv_pos_u2b_forwards(start + boffset0,
-                                              send, uoffset - uoffset0);
-
-       if (found && PL_utf8cache < 0) {
-           if (real_boffset != boffset) {
-               /* 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: sv_pos_u2b_cache cache %"UVuf
-                          " real %"UVuf" for %"SVf,
-                          (UV) boffset, (UV) real_boffset, SVfARG(sv));
-           }
-       }
+       STRLEN real_boffset;
+       uoffset -= uoffset0;
+       real_boffset = boffset0 + sv_pos_u2b_forwards(start + boffset0,
+                                                     send, &uoffset, &at_end);
+       uoffset += uoffset0;
+
+       if (found && PL_utf8cache < 0)
+           assert_uft8_cache_coherent("sv_pos_u2b_cache", boffset,
+                                      real_boffset, sv);
        boffset = real_boffset;
     }
 
-    if (PL_utf8cache)
-       utf8_mg_pos_cache_update(sv, mgp, boffset, uoffset, send - start);
+    if (PL_utf8cache) {
+       if (at_end)
+           utf8_mg_len_cache_update(sv, mgp, uoffset);
+       else
+           utf8_mg_pos_cache_update(sv, mgp, boffset, uoffset, send - start);
+    }
     return boffset;
 }
 
 
 /*
-=for apidoc sv_pos_u2b
+=for apidoc sv_pos_u2b_flags
 
 Converts the value pointed to by offsetp from a count of UTF-8 chars from
 the start of the string, to a count of the equivalent number of bytes; if
 lenp is non-zero, it does the same to lenp, but this time starting from
-the offset, rather than from the start of the string. Handles magic and
-type coercion.
+the offset, rather than from the start of the string. Handles type coercion.
+I<flags> is passed to C<SvPV_flags>, and usually should be
+C<SV_GMAGIC|SV_CONST_RETURN> to handle magic.
 
 =cut
 */
 
 /*
- * sv_pos_u2b() uses, like sv_pos_b2u(), the mg_ptr of the potential
- * PERL_UTF8_magic of the sv to store the mapping between UTF-8 and
+ * sv_pos_u2b_flags() uses, like sv_pos_b2u(), the mg_ptr of the potential
+ * PERL_MAGIC_utf8 of the sv to store the mapping between UTF-8 and
  * byte offsets.  See also the comments of S_utf8_mg_pos_cache_update().
  *
  */
 
-void
-Perl_sv_pos_u2b(pTHX_ register SV *const sv, I32 *const offsetp, I32 *const lenp)
+STRLEN
+Perl_sv_pos_u2b_flags(pTHX_ SV *const sv, STRLEN uoffset, STRLEN *const lenp,
+                     U32 flags)
 {
     const U8 *start;
     STRLEN len;
+    STRLEN boffset;
 
-    PERL_ARGS_ASSERT_SV_POS_U2B;
-
-    if (!sv)
-       return;
+    PERL_ARGS_ASSERT_SV_POS_U2B_FLAGS;
 
-    start = (U8*)SvPV_const(sv, len);
+    start = (U8*)SvPV_flags(sv, len, flags);
     if (len) {
-       STRLEN uoffset = (STRLEN) *offsetp;
        const U8 * const send = start + len;
        MAGIC *mg = NULL;
-       const STRLEN boffset = sv_pos_u2b_cached(sv, &mg, start, send,
-                                            uoffset, 0, 0);
+       boffset = sv_pos_u2b_cached(sv, &mg, start, send, uoffset, 0, 0);
 
-       *offsetp = (I32) boffset;
-
-       if (lenp) {
+       if (lenp
+           && *lenp /* don't bother doing work for 0, as its bytes equivalent
+                       is 0, and *lenp is already set to that.  */) {
            /* Convert the relative offset to absolute.  */
-           const STRLEN uoffset2 = uoffset + (STRLEN) *lenp;
+           const STRLEN uoffset2 = uoffset + *lenp;
            const STRLEN boffset2
                = sv_pos_u2b_cached(sv, &mg, start, send, uoffset2,
                                      uoffset, boffset) - boffset;
 
            *lenp = boffset2;
        }
+    } else {
+       if (lenp)
+           *lenp = 0;
+       boffset = 0;
     }
-    else {
-        *offsetp = 0;
-        if (lenp)
-             *lenp = 0;
+
+    return boffset;
+}
+
+/*
+=for apidoc sv_pos_u2b
+
+Converts the value pointed to by offsetp from a count of UTF-8 chars from
+the start of the string, to a count of the equivalent number of bytes; if
+lenp is non-zero, it does the same to lenp, but this time starting from
+the offset, rather than from the start of the string. Handles magic and
+type coercion.
+
+Use C<sv_pos_u2b_flags> in preference, which correctly handles strings longer
+than 2Gb.
+
+=cut
+*/
+
+/*
+ * sv_pos_u2b() uses, like sv_pos_b2u(), the mg_ptr of the potential
+ * PERL_MAGIC_utf8 of the sv to store the mapping between UTF-8 and
+ * byte offsets.  See also the comments of S_utf8_mg_pos_cache_update().
+ *
+ */
+
+/* This function is subject to size and sign problems */
+
+void
+Perl_sv_pos_u2b(pTHX_ register SV *const sv, I32 *const offsetp, I32 *const lenp)
+{
+    PERL_ARGS_ASSERT_SV_POS_U2B;
+
+    if (lenp) {
+       STRLEN ulen = (STRLEN)*lenp;
+       *offsetp = (I32)sv_pos_u2b_flags(sv, (STRLEN)*offsetp, &ulen,
+                                        SV_GMAGIC|SV_CONST_RETURN);
+       *lenp = (I32)ulen;
+    } else {
+       *offsetp = (I32)sv_pos_u2b_flags(sv, (STRLEN)*offsetp, NULL,
+                                        SV_GMAGIC|SV_CONST_RETURN);
     }
+}
 
-    return;
+static void
+S_utf8_mg_len_cache_update(pTHX_ SV *const sv, MAGIC **const mgp,
+                          const STRLEN ulen)
+{
+    PERL_ARGS_ASSERT_UTF8_MG_LEN_CACHE_UPDATE;
+    if (SvREADONLY(sv))
+       return;
+
+    if (!*mgp && (SvTYPE(sv) < SVt_PVMG ||
+                 !(*mgp = mg_find(sv, PERL_MAGIC_utf8)))) {
+       *mgp = sv_magicext(sv, 0, PERL_MAGIC_utf8, &PL_vtbl_utf8, 0, 0);
+    }
+    assert(*mgp);
+
+    (*mgp)->mg_len = ulen;
+    /* For now, treat "overflowed" as "still unknown". See RT #72924.  */
+    if (ulen != (STRLEN) (*mgp)->mg_len)
+       (*mgp)->mg_len = -1;
 }
 
 /* Create and update the UTF8 magic offset cache, with the proffered utf8/
@@ -6074,7 +6463,8 @@ S_utf8_mg_pos_cache_update(pTHX_ SV *const sv, MAGIC **const mgp, const STRLEN b
     if (SvREADONLY(sv))
        return;
 
-    if (!*mgp) {
+    if (!*mgp && (SvTYPE(sv) < SVt_PVMG ||
+                 !(*mgp = mg_find(sv, PERL_MAGIC_utf8)))) {
        *mgp = sv_magicext(sv, 0, PERL_MAGIC_utf8, (MGVTBL*)&PL_vtbl_utf8, 0,
                           0);
        (*mgp)->mg_len = -1;
@@ -6087,18 +6477,18 @@ S_utf8_mg_pos_cache_update(pTHX_ SV *const sv, MAGIC **const mgp, const STRLEN b
     }
     assert(cache);
 
-    if (PL_utf8cache < 0) {
+    if (PL_utf8cache < 0 && SvPOKp(sv)) {
+       /* SvPOKp() because it's possible that sv has string overloading, and
+          therefore is a reference, hence SvPVX() is actually a pointer.
+          This cures the (very real) symptoms of RT 69422, but I'm not actually
+          sure whether we should even be caching the results of UTF-8
+          operations on overloading, given that nothing stops overloading
+          returning a different value every time it's called.  */
        const U8 *start = (const U8 *) SvPVX_const(sv);
        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 %"UVuf
-                      " real %"UVuf" for %"SVf, (UV) utf8, (UV) realutf8, SVfARG(sv));
-       }
+       assert_uft8_cache_coherent("utf8_mg_pos_cache_update", utf8, realutf8,
+                                  sv);
     }
 
     /* Cache is held with the later position first, to simplify the code
@@ -6238,7 +6628,7 @@ Handles magic and type coercion.
 
 /*
  * sv_pos_b2u() uses, like sv_pos_u2b(), the mg_ptr of the potential
- * PERL_UTF8_magic of the sv to store the mapping between UTF-8 and
+ * PERL_MAGIC_utf8 of the sv to store the mapping between UTF-8 and
  * byte offsets.
  *
  */
@@ -6265,8 +6655,11 @@ Perl_sv_pos_b2u(pTHX_ register SV *const sv, I32 *const offsetp)
 
     send = s + byte;
 
-    if (SvMAGICAL(sv) && !SvREADONLY(sv) && PL_utf8cache
-       && (mg = mg_find(sv, PERL_MAGIC_utf8))) {
+    if (!SvREADONLY(sv)
+       && PL_utf8cache
+       && SvTYPE(sv) >= SVt_PVMG
+       && (mg = mg_find(sv, PERL_MAGIC_utf8)))
+    {
        if (mg->mg_ptr) {
            STRLEN * const cache = (STRLEN *) mg->mg_ptr;
            if (cache[1] == byte) {
@@ -6316,23 +6709,37 @@ Perl_sv_pos_b2u(pTHX_ register SV *const sv, I32 *const offsetp)
     if (!found || PL_utf8cache < 0) {
        const STRLEN real_len = utf8_length(s, send);
 
-       if (found && PL_utf8cache < 0) {
-           if (len != real_len) {
-               /* 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: sv_pos_b2u cache %"UVuf
-                          " real %"UVuf" for %"SVf,
-                          (UV) len, (UV) real_len, SVfARG(sv));
-           }
-       }
+       if (found && PL_utf8cache < 0)
+           assert_uft8_cache_coherent("sv_pos_b2u", len, real_len, sv);
        len = real_len;
     }
     *offsetp = len;
 
-    if (PL_utf8cache)
-       utf8_mg_pos_cache_update(sv, &mg, byte, len, blen);
+    if (PL_utf8cache) {
+       if (blen == byte)
+           utf8_mg_len_cache_update(sv, &mg, len);
+       else
+           utf8_mg_pos_cache_update(sv, &mg, byte, len, blen);
+    }
+}
+
+static void
+S_assert_uft8_cache_coherent(pTHX_ const char *const func, STRLEN from_cache,
+                            STRLEN real, SV *const sv)
+{
+    PERL_ARGS_ASSERT_ASSERT_UFT8_CACHE_COHERENT;
+
+    /* As this is debugging only code, save space by keeping this test here,
+       rather than inlining it in all the callers.  */
+    if (from_cache == real)
+       return;
+
+    /* 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: %s cache %"UVuf" real %"UVuf" for %"SVf,
+              func, (UV) from_cache, (UV) real, SVfARG(sv));
 }
 
 /*
@@ -6694,6 +7101,9 @@ Perl_sv_gets(pTHX_ register SV *const sv, register PerlIO *const fp, I32 append)
     }
 
     SvPOK_only(sv);
+    if (!append) {
+        SvCUR_set(sv,0);
+    }
     if (PerlIO_isutf8(fp))
        SvUTF8_on(sv);
 
@@ -7010,16 +7420,34 @@ return_string_or_null:
 }
 
 /*
-=for apidoc sv_inc
+=for apidoc sv_inc
+
+Auto-increment of the value in the SV, doing string to numeric conversion
+if necessary. Handles 'get' magic and operator overloading.
+
+=cut
+*/
+
+void
+Perl_sv_inc(pTHX_ register SV *const sv)
+{
+    if (!sv)
+       return;
+    SvGETMAGIC(sv);
+    sv_inc_nomg(sv);
+}
+
+/*
+=for apidoc sv_inc_nomg
 
 Auto-increment of the value in the SV, doing string to numeric conversion
-if necessary. Handles 'get' magic.
+if necessary. Handles operator overloading. Skips handling 'get' magic.
 
 =cut
 */
 
 void
-Perl_sv_inc(pTHX_ register SV *const sv)
+Perl_sv_inc_nomg(pTHX_ register SV *const sv)
 {
     dVAR;
     register char *d;
@@ -7027,13 +7455,12 @@ Perl_sv_inc(pTHX_ register SV *const sv)
 
     if (!sv)
        return;
-    SvGETMAGIC(sv);
     if (SvTHINKFIRST(sv)) {
        if (SvIsCOW(sv))
            sv_force_normal_flags(sv, 0);
        if (SvREADONLY(sv)) {
            if (IN_PERL_RUNTIME)
-               Perl_croak(aTHX_ "%s", PL_no_modify);
+               Perl_croak_no_modify(aTHX);
        }
        if (SvROK(sv)) {
            IV i;
@@ -7075,10 +7502,10 @@ Perl_sv_inc(pTHX_ register SV *const sv)
     if (flags & SVp_NOK) {
        const NV was = SvNVX(sv);
        if (NV_OVERFLOWS_INTEGERS_AT &&
-           was >= NV_OVERFLOWS_INTEGERS_AT && ckWARN(WARN_IMPRECISION)) {
-           Perl_warner(aTHX_ packWARN(WARN_IMPRECISION),
-                       "Lost precision when incrementing %" NVff " by 1",
-                       was);
+           was >= NV_OVERFLOWS_INTEGERS_AT) {
+           Perl_ck_warner(aTHX_ packWARN(WARN_IMPRECISION),
+                          "Lost precision when incrementing %" NVff " by 1",
+                          was);
        }
        (void)SvNOK_only(sv);
         SvNV_set(sv, was + 1.0);
@@ -7095,7 +7522,7 @@ Perl_sv_inc(pTHX_ register SV *const sv)
     d = SvPVX(sv);
     while (isALPHA(*d)) d++;
     while (isDIGIT(*d)) d++;
-    if (*d) {
+    if (d < SvEND(sv)) {
 #ifdef PERL_PRESERVE_IVUV
        /* Got to punt this as an integer if needs be, but we don't issue
           warnings. Probably ought to make the sv_iv_please() that does
@@ -7177,7 +7604,7 @@ Perl_sv_inc(pTHX_ register SV *const sv)
 =for apidoc sv_dec
 
 Auto-decrement of the value in the SV, doing string to numeric conversion
-if necessary. Handles 'get' magic.
+if necessary. Handles 'get' magic and operator overloading.
 
 =cut
 */
@@ -7186,17 +7613,35 @@ void
 Perl_sv_dec(pTHX_ register SV *const sv)
 {
     dVAR;
+    if (!sv)
+       return;
+    SvGETMAGIC(sv);
+    sv_dec_nomg(sv);
+}
+
+/*
+=for apidoc sv_dec_nomg
+
+Auto-decrement of the value in the SV, doing string to numeric conversion
+if necessary. Handles operator overloading. Skips handling 'get' magic.
+
+=cut
+*/
+
+void
+Perl_sv_dec_nomg(pTHX_ register SV *const sv)
+{
+    dVAR;
     int flags;
 
     if (!sv)
        return;
-    SvGETMAGIC(sv);
     if (SvTHINKFIRST(sv)) {
        if (SvIsCOW(sv))
            sv_force_normal_flags(sv, 0);
        if (SvREADONLY(sv)) {
            if (IN_PERL_RUNTIME)
-               Perl_croak(aTHX_ "%s", PL_no_modify);
+               Perl_croak_no_modify(aTHX);
        }
        if (SvROK(sv)) {
            IV i;
@@ -7241,10 +7686,10 @@ Perl_sv_dec(pTHX_ register SV *const sv)
        {
            const NV was = SvNVX(sv);
            if (NV_OVERFLOWS_INTEGERS_AT &&
-               was <= -NV_OVERFLOWS_INTEGERS_AT && ckWARN(WARN_IMPRECISION)) {
-               Perl_warner(aTHX_ packWARN(WARN_IMPRECISION),
-                           "Lost precision when decrementing %" NVff " by 1",
-                           was);
+               was <= -NV_OVERFLOWS_INTEGERS_AT) {
+               Perl_ck_warner(aTHX_ packWARN(WARN_IMPRECISION),
+                              "Lost precision when decrementing %" NVff " by 1",
+                              was);
            }
            (void)SvNOK_only(sv);
            SvNV_set(sv, was - 1.0);
@@ -7295,6 +7740,16 @@ Perl_sv_dec(pTHX_ register SV *const sv)
     sv_setnv(sv,Atof(SvPVX_const(sv)) - 1.0);  /* punt */
 }
 
+/* this define is used to eliminate a chunk of duplicated but shared logic
+ * it has the suffix __SV_C to signal that it isnt API, and isnt meant to be
+ * used anywhere but here - yves
+ */
+#define PUSH_EXTEND_MORTAL__SV_C(AnSv) \
+    STMT_START {      \
+       EXTEND_MORTAL(1); \
+       PL_tmps_stack[++PL_tmps_ix] = (AnSv); \
+    } STMT_END
+
 /*
 =for apidoc sv_mortalcopy
 
@@ -7319,8 +7774,7 @@ Perl_sv_mortalcopy(pTHX_ SV *const oldstr)
 
     new_SV(sv);
     sv_setsv(sv,oldstr);
-    EXTEND_MORTAL(1);
-    PL_tmps_stack[++PL_tmps_ix] = sv;
+    PUSH_EXTEND_MORTAL__SV_C(sv);
     SvTEMP_on(sv);
     return sv;
 }
@@ -7344,8 +7798,7 @@ Perl_sv_newmortal(pTHX)
 
     new_SV(sv);
     SvFLAGS(sv) = SVs_TEMP;
-    EXTEND_MORTAL(1);
-    PL_tmps_stack[++PL_tmps_ix] = sv;
+    PUSH_EXTEND_MORTAL__SV_C(sv);
     return sv;
 }
 
@@ -7359,7 +7812,8 @@ string.  You are responsible for ensuring that the source string is at least
 C<len> bytes long.  If the C<s> argument is NULL the new SV will be undefined.
 Currently the only flag bits accepted are C<SVf_UTF8> and C<SVs_TEMP>.
 If C<SVs_TEMP> is set, then C<sv2mortal()> is called on the result before
-returning. If C<SVf_UTF8> is set, then it will be set on the new SV.
+returning. If C<SVf_UTF8> is set, C<s> is considered to be in UTF-8 and the
+C<SVf_UTF8> flag will be set on the new SV.
 C<newSVpvn_utf8()> is a convenience wrapper for this function, defined as
 
     #define newSVpvn_utf8(s, len, u)                   \
@@ -7379,8 +7833,22 @@ Perl_newSVpvn_flags(pTHX_ const char *const s, const STRLEN len, const U32 flags
     assert(!(flags & ~(SVf_UTF8|SVs_TEMP)));
     new_SV(sv);
     sv_setpvn(sv,s,len);
-    SvFLAGS(sv) |= (flags & SVf_UTF8);
-    return (flags & SVs_TEMP) ? sv_2mortal(sv) : sv;
+
+    /* This code used to a sv_2mortal(), however we now unroll the call to sv_2mortal()
+     * and do what it does outselves here.
+     * Since we have asserted that flags can only have the SVf_UTF8 and/or SVs_TEMP flags
+     * set above we can use it to enable the sv flags directly (bypassing SvTEMP_on), which
+     * in turn means we dont need to mask out the SVf_UTF8 flag below, which means that we
+     * eleminate quite a few steps than it looks - Yves (explaining patch by gfx)
+     */
+
+    SvFLAGS(sv) |= flags;
+
+    if(flags & SVs_TEMP){
+       PUSH_EXTEND_MORTAL__SV_C(sv);
+    }
+
+    return sv;
 }
 
 /*
@@ -7403,8 +7871,7 @@ Perl_sv_2mortal(pTHX_ register SV *const sv)
        return NULL;
     if (SvREADONLY(sv) && SvIMMORTAL(sv))
        return sv;
-    EXTEND_MORTAL(1);
-    PL_tmps_stack[++PL_tmps_ix] = sv;
+    PUSH_EXTEND_MORTAL__SV_C(sv);
     SvTEMP_on(sv);
     return sv;
 }
@@ -7768,8 +8235,7 @@ Perl_newSVsv(pTHX_ register SV *const old)
     if (!old)
        return NULL;
     if (SvTYPE(old) == SVTYPEMASK) {
-        if (ckWARN_d(WARN_INTERNAL))
-           Perl_warner(aTHX_ packWARN(WARN_INTERNAL), "semi-panic: attempt to dup freed string");
+       Perl_ck_warner_d(aTHX_ packWARN(WARN_INTERNAL), "semi-panic: attempt to dup freed string");
        return NULL;
     }
     new_SV(sv);
@@ -7936,7 +8402,7 @@ Perl_sv_2io(pTHX_ SV *const sv)
 
 Using various gambits, try to get a CV from an SV; in addition, try if
 possible to set C<*st> and C<*gvp> to the stash and GV associated with it.
-The flags in C<lref> are passed to sv_fetchsv.
+The flags in C<lref> are passed to gv_fetchsv.
 
 =cut
 */
@@ -8107,14 +8573,14 @@ Perl_sv_pvn_force_flags(pTHX_ SV *const sv, STRLEN *const lp, const I32 flags)
            const char * const ref = sv_reftype(sv,0);
            if (PL_op)
                Perl_croak(aTHX_ "Can't coerce readonly %s to string in %s",
-                          ref, OP_NAME(PL_op));
+                          ref, OP_DESC(PL_op));
            else
                Perl_croak(aTHX_ "Can't coerce readonly %s to string", ref);
        }
        if ((SvTYPE(sv) > SVt_PVLV && SvTYPE(sv) != SVt_PVFM)
            || isGV_with_GP(sv))
            Perl_croak(aTHX_ "Can't coerce %s to string in %s", sv_reftype(sv,0),
-               OP_NAME(PL_op));
+               OP_DESC(PL_op));
        s = sv_2pv_flags(sv, &len, flags);
        if (lp)
            *lp = len;
@@ -8482,7 +8948,7 @@ Perl_sv_bless(pTHX_ SV *const sv, HV *const stash)
        if (SvIsCOW(tmpRef))
            sv_force_normal_flags(tmpRef, 0);
        if (SvREADONLY(tmpRef))
-           Perl_croak(aTHX_ "%s", PL_no_modify);
+           Perl_croak_no_modify(aTHX);
        if (SvOBJECT(tmpRef)) {
            if (SvTYPE(tmpRef) != SVt_PVIO)
                --PL_sv_objcount;
@@ -8931,6 +9397,22 @@ Perl_sv_vsetpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
     sv_vcatpvfn(sv, pat, patlen, args, svargs, svmax, maybe_tainted);
 }
 
+
+/*
+ * Warn of missing argument to sprintf, and then return a defined value
+ * to avoid inappropriate "use of uninit" warnings [perl #71000].
+ */
+#define WARN_MISSING WARN_UNINITIALIZED /* Not sure we want a new category */
+STATIC SV*
+S_vcatpvfn_missing_argument(pTHX) {
+    if (ckWARN(WARN_MISSING)) {
+       Perl_warner(aTHX_ packWARN(WARN_MISSING), "Missing argument in %s",
+               PL_op ? OP_DESC(PL_op) : "sv_vcatpvfn()");
+    }
+    return &PL_sv_no;
+}
+
+
 STATIC I32
 S_expect_number(pTHX_ char **const pattern)
 {
@@ -8947,7 +9429,7 @@ S_expect_number(pTHX_ char **const pattern)
        while (isDIGIT(**pattern)) {
            const I32 tmp = var * 10 + (*(*pattern)++ - '0');
            if (tmp < var)
-               Perl_croak(aTHX_ "Integer overflow in format string for %s", (PL_op ? OP_NAME(PL_op) : "sv_vcatpvfn"));
+               Perl_croak(aTHX_ "Integer overflow in format string for %s", (PL_op ? OP_DESC(PL_op) : "sv_vcatpvfn"));
            var = tmp;
        }
     }
@@ -9043,6 +9525,8 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
        else if (svix < svmax) {
            sv_catsv(sv, *svargs);
        }
+       else
+           S_vcatpvfn_missing_argument(aTHX);
        return;
     }
     if (args && patlen == 3 && pat[0] == '%' &&
@@ -9062,13 +9546,8 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
        pp = pat + 2;
        while (*pp >= '0' && *pp <= '9')
            digits = 10 * digits + (*pp++ - '0');
-       if (pp - pat == (int)patlen - 1) {
-           NV nv;
-
-           if (svix < svmax)
-               nv = SvNV(*svargs);
-           else
-               return;
+       if (pp - pat == (int)patlen - 1 && svix < svmax) {
+           const NV nv = SvNV(*svargs);
            if (*pp == 'g') {
                /* Add check for digits != 0 because it seems that some
                   gconverts are buggy in this case, and we don't yet have
@@ -9214,9 +9693,8 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
                    goto string;
                }
                else if (n) {
-                   if (ckWARN_d(WARN_INTERNAL))
-                       Perl_warner(aTHX_ packWARN(WARN_INTERNAL),
-                       "internal %%<num>p might conflict with future printf extensions");
+                   Perl_ck_warner_d(aTHX_ packWARN(WARN_INTERNAL),
+                                    "internal %%<num>p might conflict with future printf extensions");
                }
            }
            q = r; 
@@ -9297,9 +9775,10 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
                    vecsv = va_arg(*args, SV*);
                else if (evix) {
                    vecsv = (evix > 0 && evix <= svmax)
-                       ? svargs[evix-1] : &PL_sv_undef;
+                       ? svargs[evix-1] : S_vcatpvfn_missing_argument(aTHX);
                } else {
-                   vecsv = svix < svmax ? svargs[svix++] : &PL_sv_undef;
+                   vecsv = svix < svmax
+                       ? svargs[svix++] : S_vcatpvfn_missing_argument(aTHX);
                }
                dotstr = SvPV_const(vecsv, dotstrlen);
                /* Keep the DO_UTF8 test *after* the SvPV call, else things go
@@ -9446,10 +9925,11 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
        if (!vectorize && !args) {
            if (efix) {
                const I32 i = efix-1;
-               argsv = (i >= 0 && i < svmax) ? svargs[i] : &PL_sv_undef;
+               argsv = (i >= 0 && i < svmax)
+                   ? svargs[i] : S_vcatpvfn_missing_argument(aTHX);
            } else {
                argsv = (svix >= 0 && svix < svmax)
-                   ? svargs[svix++] : &PL_sv_undef;
+                   ? svargs[svix++] : S_vcatpvfn_missing_argument(aTHX);
            }
        }
 
@@ -9481,12 +9961,6 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
            if (args) {
                eptr = va_arg(*args, char*);
                if (eptr)
-#ifdef MACOS_TRADITIONAL
-                 /* On MacOS, %#s format is used for Pascal strings */
-                 if (alt)
-                   elen = *eptr++;
-                 else
-#endif
                    elen = strlen(eptr);
                else {
                    eptr = (char *)nullstr;
@@ -9496,9 +9970,10 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
            else {
                eptr = SvPV_const(argsv, elen);
                if (DO_UTF8(argsv)) {
-                   I32 old_precis = precis;
+                   STRLEN old_precis = precis;
                    if (has_precis && precis < elen) {
-                       I32 p = precis;
+                       STRLEN ulen = sv_len_utf8(argsv);
+                       I32 p = precis > ulen ? ulen : precis;
                        sv_pos_u2b(argsv, &p, 0); /* sticks at end */
                        precis = p;
                    }
@@ -9513,7 +9988,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
            }
 
        string:
-           if (has_precis && elen > precis)
+           if (has_precis && precis < elen)
                elen = precis;
            break;
 
@@ -10091,6 +10566,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen,
            goto vector;
        }
     }
+    SvTAINT(sv);
 }
 
 /* =========================================================================
@@ -10107,7 +10583,7 @@ ptr_table_* functions.
 
 =cut
 
-============================================================================*/
+ * =========================================================================*/
 
 
 #if defined(USE_ITHREADS)
@@ -10120,19 +10596,19 @@ ptr_table_* functions.
 
 /* Certain cases in Perl_ss_dup have been merged, by relying on the fact
    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))
+   If this changes, please unmerge ss_dup.
+   Likewise, sv_dup_inc_multiple() relies on this fact.  */
+#define sv_dup_inc_NN(s,t)     SvREFCNT_inc_NN(sv_dup_inc(s,t))
 #define av_dup(s,t)    MUTABLE_AV(sv_dup((const SV *)s,t))
-#define av_dup_inc(s,t)        MUTABLE_AV(SvREFCNT_inc(sv_dup((const SV *)s,t)))
+#define av_dup_inc(s,t)        MUTABLE_AV(sv_dup_inc((const SV *)s,t))
 #define hv_dup(s,t)    MUTABLE_HV(sv_dup((const SV *)s,t))
-#define hv_dup_inc(s,t)        MUTABLE_HV(SvREFCNT_inc(sv_dup((const SV *)s,t)))
+#define hv_dup_inc(s,t)        MUTABLE_HV(sv_dup_inc((const SV *)s,t))
 #define cv_dup(s,t)    MUTABLE_CV(sv_dup((const SV *)s,t))
-#define cv_dup_inc(s,t)        MUTABLE_CV(SvREFCNT_inc(sv_dup((const SV *)s,t)))
+#define cv_dup_inc(s,t)        MUTABLE_CV(sv_dup_inc((const SV *)s,t))
 #define io_dup(s,t)    MUTABLE_IO(sv_dup((const SV *)s,t))
-#define io_dup_inc(s,t)        MUTABLE_IO(SvREFCNT_inc(sv_dup((const SV *)s,t)))
+#define io_dup_inc(s,t)        MUTABLE_IO(sv_dup_inc((const SV *)s,t))
 #define gv_dup(s,t)    MUTABLE_GV(sv_dup((const SV *)s,t))
-#define gv_dup_inc(s,t)        MUTABLE_GV(SvREFCNT_inc(sv_dup((const SV *)s,t)))
+#define gv_dup_inc(s,t)        MUTABLE_GV(sv_dup_inc((const SV *)s,t))
 #define SAVEPV(p)      ((p) ? savepv(p) : NULL)
 #define SAVEPVN(p,n)   ((p) ? savepvn(p,n) : NULL)
 
@@ -10251,6 +10727,10 @@ Perl_parser_dup(pTHX_ const yy_parser *const proto, CLONE_PARAMS *const param)
     Copy(proto->nexttype, parser->nexttype, 5, I32);
     parser->nexttoke   = proto->nexttoke;
 #endif
+
+    /* XXX should clone saved_curcop here, but we aren't passed
+     * proto_perl; so do it in perl_clone_using instead */
+
     return parser;
 }
 
@@ -10312,7 +10792,8 @@ Perl_gp_dup(pTHX_ GP *const gp, CLONE_PARAMS *const param)
     ptr_table_store(PL_ptr_table, gp, ret);
 
     /* clone */
-    ret->gp_refcnt     = 0;                    /* must be before any other dups! */
+    /* ret->gp_refcnt must be 0 before any other dups are called. We're relying
+       on Newxz() to do this for us.  */
     ret->gp_sv         = sv_dup_inc(gp->gp_sv, param);
     ret->gp_io         = io_dup_inc(gp->gp_io, param);
     ret->gp_form       = cv_dup_inc(gp->gp_form, param);
@@ -10331,75 +10812,74 @@ Perl_gp_dup(pTHX_ GP *const gp, CLONE_PARAMS *const param)
 MAGIC *
 Perl_mg_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *const param)
 {
-    MAGIC *mgprev = (MAGIC*)NULL;
-    MAGIC *mgret;
+    MAGIC *mgret = NULL;
+    MAGIC **mgprev_p = &mgret;
 
     PERL_ARGS_ASSERT_MG_DUP;
 
-    if (!mg)
-       return (MAGIC*)NULL;
-    /* look for it in the table first */
-    mgret = (MAGIC*)ptr_table_fetch(PL_ptr_table, mg);
-    if (mgret)
-       return mgret;
-
     for (; mg; mg = mg->mg_moremagic) {
        MAGIC *nmg;
-       Newxz(nmg, 1, MAGIC);
-       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 ((param->flags & CLONEf_JOIN_IN)
+               && mg->mg_type == PERL_MAGIC_backref)
+           /* when joining, we let the individual SVs add themselves to
+            * backref as needed. */
+           continue;
+
+       Newx(nmg, 1, MAGIC);
+       *mgprev_p = nmg;
+       mgprev_p = &(nmg->mg_moremagic);
+
+       /* There was a comment "XXX copy dynamic vtable?" but as we don't have
+          dynamic vtables, I'm not sure why Sarathy wrote it. The comment dates
+          from the original commit adding Perl_mg_dup() - revision 4538.
+          Similarly there is the annotation "XXX random ptr?" next to the
+          assignment to nmg->mg_ptr.  */
+       *nmg = *mg;
+
        /* FIXME for plugins
-       if (mg->mg_type == PERL_MAGIC_qr) {
-           nmg->mg_obj = MUTABLE_SV(CALLREGDUPE((REGEXP*)mg->mg_obj, param));
+       if (nmg->mg_type == PERL_MAGIC_qr) {
+           nmg->mg_obj = MUTABLE_SV(CALLREGDUPE((REGEXP*)nmg->mg_obj, param));
        }
        else
        */
-       if(mg->mg_type == PERL_MAGIC_backref) {
-           /* The backref AV has its reference count deliberately bumped by
-              1.  */
-           nmg->mg_obj
-               = SvREFCNT_inc(av_dup_inc((const AV *) mg->mg_obj, param));
-       }
-       else {
-           nmg->mg_obj = (mg->mg_flags & MGf_REFCOUNTED)
-                             ? sv_dup_inc(mg->mg_obj, param)
-                             : sv_dup(mg->mg_obj, param);
-       }
-       nmg->mg_len     = mg->mg_len;
-       nmg->mg_ptr     = mg->mg_ptr;   /* XXX random ptr? */
-       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 == PERL_MAGIC_overload_table &&
-                       AMT_AMAGIC((AMT*)mg->mg_ptr))
+       nmg->mg_obj = (nmg->mg_flags & MGf_REFCOUNTED)
+                         ? nmg->mg_type == PERL_MAGIC_backref
+                               /* The backref AV has its reference
+                                * count deliberately bumped by 1 */
+                               ? SvREFCNT_inc(av_dup_inc((const AV *)
+                                                   nmg->mg_obj, param))
+                               : sv_dup_inc(nmg->mg_obj, param)
+                         : sv_dup(nmg->mg_obj, param);
+
+       if (nmg->mg_ptr && nmg->mg_type != PERL_MAGIC_regex_global) {
+           if (nmg->mg_len > 0) {
+               nmg->mg_ptr     = SAVEPVN(nmg->mg_ptr, nmg->mg_len);
+               if (nmg->mg_type == PERL_MAGIC_overload_table &&
+                       AMT_AMAGIC((AMT*)nmg->mg_ptr))
                {
-                   const AMT * const amtp = (AMT*)mg->mg_ptr;
                    AMT * const namtp = (AMT*)nmg->mg_ptr;
-                   I32 i;
-                   for (i = 1; i < NofAMmeth; i++) {
-                       namtp->table[i] = cv_dup_inc(amtp->table[i], param);
-                   }
+                   sv_dup_inc_multiple((SV**)(namtp->table),
+                                       (SV**)(namtp->table), NofAMmeth, param);
                }
            }
-           else if (mg->mg_len == HEf_SVKEY)
-               nmg->mg_ptr = (char*)sv_dup_inc((const SV *)mg->mg_ptr, param);
+           else if (nmg->mg_len == HEf_SVKEY)
+               nmg->mg_ptr = (char*)sv_dup_inc((const SV *)nmg->mg_ptr, param);
        }
-       if ((mg->mg_flags & MGf_DUP) && mg->mg_virtual && mg->mg_virtual->svt_dup) {
-           CALL_FPTR(nmg->mg_virtual->svt_dup)(aTHX_ nmg, param);
+       if ((nmg->mg_flags & MGf_DUP) && nmg->mg_virtual && nmg->mg_virtual->svt_dup) {
+           nmg->mg_virtual->svt_dup(aTHX_ nmg, param);
        }
-       mgprev = nmg;
     }
     return mgret;
 }
 
 #endif /* USE_ITHREADS */
 
+struct ptr_tbl_arena {
+    struct ptr_tbl_arena *next;
+    struct ptr_tbl_ent array[1023/3]; /* as ptr_tbl_ent has 3 pointers.  */
+};
+
 /* create a new pointer-mapping table */
 
 PTR_TBL_t *
@@ -10408,9 +10888,12 @@ Perl_ptr_table_new(pTHX)
     PTR_TBL_t *tbl;
     PERL_UNUSED_CONTEXT;
 
-    Newxz(tbl, 1, PTR_TBL_t);
+    Newx(tbl, 1, PTR_TBL_t);
     tbl->tbl_max       = 511;
     tbl->tbl_items     = 0;
+    tbl->tbl_arena     = NULL;
+    tbl->tbl_arena_next        = NULL;
+    tbl->tbl_arena_end = NULL;
     Newxz(tbl->tbl_ary, tbl->tbl_max + 1, PTR_TBL_ENT_t*);
     return tbl;
 }
@@ -10418,14 +10901,6 @@ Perl_ptr_table_new(pTHX)
 #define PTR_TABLE_HASH(ptr) \
   ((PTR2UV(ptr) >> 3) ^ (PTR2UV(ptr) >> (3 + 7)) ^ (PTR2UV(ptr) >> (3 + 17)))
 
-/* 
-   we use the PTE_SVSLOT 'reservation' made above, both here (in the
-   following define) and at call to new_body_inline made below in 
-   Perl_ptr_table_store()
- */
-
-#define del_pte(p)     del_body_type(p, PTE_SVSLOT)
-
 /* map an existing pointer using a table */
 
 STATIC PTR_TBL_ENT_t *
@@ -10470,7 +10945,18 @@ Perl_ptr_table_store(pTHX_ PTR_TBL_t *const tbl, const void *const oldsv, void *
     } else {
        const UV entry = PTR_TABLE_HASH(oldsv) & tbl->tbl_max;
 
-       new_body_inline(tblent, PTE_SVSLOT);
+       if (tbl->tbl_arena_next == tbl->tbl_arena_end) {
+           struct ptr_tbl_arena *new_arena;
+
+           Newx(new_arena, 1, struct ptr_tbl_arena);
+           new_arena->next = tbl->tbl_arena;
+           tbl->tbl_arena = new_arena;
+           tbl->tbl_arena_next = new_arena->array;
+           tbl->tbl_arena_end = new_arena->array
+               + sizeof(new_arena->array) / sizeof(new_arena->array[0]);
+       }
+
+       tblent = tbl->tbl_arena_next++;
 
        tblent->oldval = oldsv;
        tblent->newval = newsv;
@@ -10500,43 +10986,47 @@ Perl_ptr_table_split(pTHX_ PTR_TBL_t *const tbl)
     tbl->tbl_max = --newsize;
     tbl->tbl_ary = ary;
     for (i=0; i < oldsize; i++, ary++) {
-       PTR_TBL_ENT_t **curentp, **entp, *ent;
-       if (!*ary)
+       PTR_TBL_ENT_t **entp = ary;
+       PTR_TBL_ENT_t *ent = *ary;
+       PTR_TBL_ENT_t **curentp;
+       if (!ent)
            continue;
        curentp = ary + oldsize;
-       for (entp = ary, ent = *ary; ent; ent = *entp) {
+       do {
            if ((newsize & PTR_TABLE_HASH(ent->oldval)) != i) {
                *entp = ent->next;
                ent->next = *curentp;
                *curentp = ent;
-               continue;
            }
            else
                entp = &ent->next;
-       }
+           ent = *entp;
+       } while (ent);
     }
 }
 
 /* remove all the entries from a ptr table */
+/* Deprecated - will be removed post 5.14 */
 
 void
 Perl_ptr_table_clear(pTHX_ PTR_TBL_t *const tbl)
 {
     if (tbl && tbl->tbl_items) {
-       register PTR_TBL_ENT_t * const * const array = tbl->tbl_ary;
-       UV riter = tbl->tbl_max;
+       struct ptr_tbl_arena *arena = tbl->tbl_arena;
 
-       do {
-           PTR_TBL_ENT_t *entry = array[riter];
+       Zero(tbl->tbl_ary, tbl->tbl_max + 1, struct ptr_tbl_ent **);
 
-           while (entry) {
-               PTR_TBL_ENT_t * const oentry = entry;
-               entry = entry->next;
-               del_pte(oentry);
-           }
-       } while (riter--);
+       while (arena) {
+           struct ptr_tbl_arena *next = arena->next;
+
+           Safefree(arena);
+           arena = next;
+       };
 
        tbl->tbl_items = 0;
+       tbl->tbl_arena = NULL;
+       tbl->tbl_arena_next = NULL;
+       tbl->tbl_arena_end = NULL;
     }
 }
 
@@ -10545,10 +11035,21 @@ Perl_ptr_table_clear(pTHX_ PTR_TBL_t *const tbl)
 void
 Perl_ptr_table_free(pTHX_ PTR_TBL_t *const tbl)
 {
+    struct ptr_tbl_arena *arena;
+
     if (!tbl) {
         return;
     }
-    ptr_table_clear(tbl);
+
+    arena = tbl->tbl_arena;
+
+    while (arena) {
+       struct ptr_tbl_arena *next = arena->next;
+
+       Safefree(arena);
+       arena = next;
+    }
+
     Safefree(tbl->tbl_ary);
     Safefree(tbl);
 }
@@ -10561,10 +11062,16 @@ Perl_rvpv_dup(pTHX_ SV *const dstr, const SV *const sstr, CLONE_PARAMS *const pa
     PERL_ARGS_ASSERT_RVPV_DUP;
 
     if (SvROK(sstr)) {
-       SvRV_set(dstr, SvWEAKREF(sstr)
-                      ? sv_dup(SvRV_const(sstr), param)
-                      : sv_dup_inc(SvRV_const(sstr), param));
-
+       if (SvWEAKREF(sstr)) {
+           SvRV_set(dstr, sv_dup(SvRV_const(sstr), param));
+           if (param->flags & CLONEf_JOIN_IN) {
+               /* if joining, we add any back references individually rather
+                * than copying the whole backref array */
+               Perl_sv_add_backref(aTHX_ SvRV(dstr), dstr);
+           }
+       }
+       else
+           SvRV_set(dstr, sv_dup_inc(SvRV_const(sstr), param));
     }
     else if (SvPVX_const(sstr)) {
        /* Has something there */
@@ -10601,18 +11108,30 @@ Perl_rvpv_dup(pTHX_ SV *const dstr, const SV *const sstr, CLONE_PARAMS *const pa
     }
 }
 
+/* duplicate a list of SVs. source and dest may point to the same memory.  */
+static SV **
+S_sv_dup_inc_multiple(pTHX_ SV *const *source, SV **dest,
+                     SSize_t items, CLONE_PARAMS *const param)
+{
+    PERL_ARGS_ASSERT_SV_DUP_INC_MULTIPLE;
+
+    while (items-- > 0) {
+       *dest++ = sv_dup_inc(*source++, param);
+    }
+
+    return dest;
+}
+
 /* duplicate an SV of any type (including AV, HV etc) */
 
-SV *
-Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
+static SV *
+S_sv_dup_common(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
 {
     dVAR;
     SV *dstr;
 
-    PERL_ARGS_ASSERT_SV_DUP;
+    PERL_ARGS_ASSERT_SV_DUP_COMMON;
 
-    if (!sstr)
-       return NULL;
     if (SvTYPE(sstr) == SVTYPEMASK) {
 #ifdef DEBUG_LEAKING_SCALARS_ABORT
        abort();
@@ -10629,9 +11148,12 @@ Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
            something that is bad **/
        if (SvTYPE(sstr) == SVt_PVHV) {
            const HEK * const hvname = HvNAME_HEK(sstr);
-           if (hvname)
+           if (hvname) {
                /** don't clone stashes if they already exist **/
-               return MUTABLE_SV(gv_stashpvn(HEK_KEY(hvname), HEK_LEN(hvname), 0));
+               dstr = MUTABLE_SV(gv_stashpvn(HEK_KEY(hvname), HEK_LEN(hvname), 0));
+               ptr_table_store(PL_ptr_table, sstr, dstr);
+               return dstr;
+           }
         }
     }
 
@@ -10642,7 +11164,7 @@ Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
     dstr->sv_debug_optype = sstr->sv_debug_optype;
     dstr->sv_debug_line = sstr->sv_debug_line;
     dstr->sv_debug_inpad = sstr->sv_debug_inpad;
-    dstr->sv_debug_cloned = 1;
+    dstr->sv_debug_parent = (SV*)sstr;
     dstr->sv_debug_file = savepv(sstr->sv_debug_file);
 #endif
 
@@ -10696,9 +11218,6 @@ Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
                break;
 
            case SVt_PVGV:
-               if (GvUNIQUE((const GV *)sstr)) {
-                   NOOP;   /* Do sharing here, and fall through */
-               }
            case SVt_PVIO:
            case SVt_PVFM:
            case SVt_PVHV:
@@ -10733,7 +11252,8 @@ Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
 #endif
 
            if (sv_type != SVt_PVAV && sv_type != SVt_PVHV
-               && !isGV_with_GP(dstr))
+               && !isGV_with_GP(dstr)
+               && !(sv_type == SVt_PVIO && !(IoFLAGS(dstr) & IOf_FAKE_DIRP)))
                Perl_rvpv_dup(aTHX_ dstr, sstr, param);
 
            /* The Copy above means that all the source (unduplicated) pointers
@@ -10774,25 +11294,22 @@ Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
                    LvTARG(dstr) = sv_dup_inc(LvTARG(dstr), param);
            case SVt_PVGV:
                if(isGV_with_GP(sstr)) {
-                   if (GvNAME_HEK(dstr))
-                       GvNAME_HEK(dstr) = hek_dup(GvNAME_HEK(dstr), param);
+                   GvNAME_HEK(dstr) = hek_dup(GvNAME_HEK(dstr), param);
                    /* Don't call sv_add_backref here as it's going to be
                       created as part of the magic cloning of the symbol
-                      table.  */
+                      table--unless this is during a join and the stash
+                      is not actually being cloned.  */
                    /* Danger Will Robinson - GvGP(dstr) isn't initialised
                       at the point of this comment.  */
                    GvSTASH(dstr) = hv_dup(GvSTASH(dstr), param);
+                   if (param->flags & CLONEf_JOIN_IN)
+                       Perl_sv_add_backref(aTHX_ MUTABLE_SV(GvSTASH(dstr)), dstr);
                    GvGP(dstr)  = gp_dup(GvGP(sstr), param);
                    (void)GpREFCNT_inc(GvGP(dstr));
                } else
                    Perl_rvpv_dup(aTHX_ dstr, sstr, param);
                break;
            case SVt_PVIO:
-               IoIFP(dstr)     = fp_dup(IoIFP(dstr), IoTYPE(dstr), param);
-               if (IoOFP(dstr) == IoIFP(sstr))
-                   IoOFP(dstr) = IoIFP(dstr);
-               else
-                   IoOFP(dstr) = fp_dup(IoOFP(dstr), IoTYPE(dstr), param);
                /* PL_parser->rsfp_filters entries have fake IoDIRP() */
                if(IoFLAGS(dstr) & IOf_FAKE_DIRP) {
                    /* I have no idea why fake dirp (rsfps)
@@ -10811,13 +11328,19 @@ Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
                        NOOP;
                        /* IoDIRP(dstr) is already a copy of IoDIRP(sstr)  */
                    }
+                   IoIFP(dstr) = fp_dup(IoIFP(sstr), IoTYPE(dstr), param);
                }
+               if (IoOFP(dstr) == IoIFP(sstr))
+                   IoOFP(dstr) = IoIFP(dstr);
+               else
+                   IoOFP(dstr) = fp_dup(IoOFP(dstr), IoTYPE(dstr), param);
                IoTOP_NAME(dstr)        = SAVEPV(IoTOP_NAME(dstr));
                IoFMT_NAME(dstr)        = SAVEPV(IoFMT_NAME(dstr));
                IoBOTTOM_NAME(dstr)     = SAVEPV(IoBOTTOM_NAME(dstr));
                break;
            case SVt_PVAV:
-               if (AvARRAY((const AV *)sstr)) {
+               /* avoid cloning an empty array */
+               if (AvARRAY((const AV *)sstr) && AvFILLp((const AV *)sstr) >= 0) {
                    SV **dst_ary, **src_ary;
                    SSize_t items = AvFILLp((const AV *)sstr) + 1;
 
@@ -10827,8 +11350,8 @@ Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
                    AvARRAY(MUTABLE_AV(dstr)) = dst_ary;
                    AvALLOC((const AV *)dstr) = dst_ary;
                    if (AvREAL((const AV *)sstr)) {
-                       while (items-- > 0)
-                           *dst_ary++ = sv_dup_inc(*src_ary++, param);
+                       dst_ary = sv_dup_inc_multiple(src_ary, dst_ary, items,
+                                                     param);
                    }
                    else {
                        while (items-- > 0)
@@ -10842,6 +11365,8 @@ Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
                else {
                    AvARRAY(MUTABLE_AV(dstr))   = NULL;
                    AvALLOC((const AV *)dstr)   = (SV**)NULL;
+                   AvMAX(  (const AV *)dstr)   = -1;
+                   AvFILLp((const AV *)dstr)   = -1;
                }
                break;
            case SVt_PVHV:
@@ -10870,17 +11395,30 @@ Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
                        SvFLAGS(dstr) |= SVf_OOK;
 
                        hvname = saux->xhv_name;
-                       daux->xhv_name = hvname ? hek_dup(hvname, param) : hvname;
+                       daux->xhv_name = hek_dup(hvname, param);
 
                        daux->xhv_riter = saux->xhv_riter;
                        daux->xhv_eiter = saux->xhv_eiter
                            ? he_dup(saux->xhv_eiter,
-                                       (bool)!!HvSHAREKEYS(sstr), param) : 0;
+                                       cBOOL(HvSHAREKEYS(sstr)), param) : 0;
                        /* backref array needs refcnt=2; see sv_add_backref */
                        daux->xhv_backreferences =
-                           saux->xhv_backreferences
-                           ? MUTABLE_AV(SvREFCNT_inc(
-                                                     sv_dup_inc((const SV *)saux->xhv_backreferences, param)))
+                           (param->flags & CLONEf_JOIN_IN)
+                               /* when joining, we let the individual GVs and
+                                * CVs add themselves to backref as
+                                * needed. This avoids pulling in stuff
+                                * that isn't required, and simplifies the
+                                * case where stashes aren't cloned back
+                                * if they already exist in the parent
+                                * thread */
+                           ? NULL
+                           : saux->xhv_backreferences
+                               ? (SvTYPE(saux->xhv_backreferences) == SVt_PVAV)
+                                   ? MUTABLE_AV(SvREFCNT_inc(
+                                         sv_dup_inc((const SV *)
+                                           saux->xhv_backreferences, param)))
+                                   : MUTABLE_AV(sv_dup((const SV *)
+                                           saux->xhv_backreferences, param))
                                : 0;
 
                         daux->xhv_mro_meta = saux->xhv_mro_meta
@@ -10899,23 +11437,30 @@ Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
                if (!(param->flags & CLONEf_COPY_STACKS)) {
                    CvDEPTH(dstr) = 0;
                }
+               /*FALLTHROUGH*/
            case SVt_PVFM:
                /* NOTE: not refcounted */
                CvSTASH(dstr)   = hv_dup(CvSTASH(dstr), param);
+               if ((param->flags & CLONEf_JOIN_IN) && CvSTASH(dstr))
+                   Perl_sv_add_backref(aTHX_ MUTABLE_SV(CvSTASH(dstr)), dstr);
                OP_REFCNT_LOCK;
                if (!CvISXSUB(dstr))
                    CvROOT(dstr) = OpREFCNT_inc(CvROOT(dstr));
                OP_REFCNT_UNLOCK;
                if (CvCONST(dstr) && CvISXSUB(dstr)) {
-                   CvXSUBANY(dstr).any_ptr = GvUNIQUE(CvGV(dstr)) ?
-                       SvREFCNT_inc(CvXSUBANY(dstr).any_ptr) :
+                   CvXSUBANY(dstr).any_ptr =
                        sv_dup_inc((const SV *)CvXSUBANY(dstr).any_ptr, param);
                }
                /* don't dup if copying back - CvGV isn't refcounted, so the
                 * duped GV may never be freed. A bit of a hack! DAPM */
-               CvGV(dstr)      = (param->flags & CLONEf_JOIN_IN) ?
-                   NULL : gv_dup(CvGV(dstr), param) ;
-               PAD_DUP(CvPADLIST(dstr), CvPADLIST(sstr), param);
+               SvANY(MUTABLE_CV(dstr))->xcv_gv =
+                   CvCVGV_RC(dstr)
+                   ? gv_dup_inc(CvGV(sstr), param)
+                   : (param->flags & CLONEf_JOIN_IN)
+                       ? NULL
+                       : gv_dup(CvGV(sstr), param);
+
+               CvPADLIST(dstr) = padlist_dup(CvPADLIST(sstr), param);
                CvOUTSIDE(dstr) =
                    CvWEAKOUTSIDE(sstr)
                    ? cv_dup(    CvOUTSIDE(dstr), param)
@@ -10933,6 +11478,41 @@ Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
     return dstr;
  }
 
+SV *
+Perl_sv_dup_inc(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
+{
+    PERL_ARGS_ASSERT_SV_DUP_INC;
+    return sstr ? SvREFCNT_inc(sv_dup_common(sstr, param)) : NULL;
+}
+
+SV *
+Perl_sv_dup(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
+{
+    SV *dstr = sstr ? sv_dup_common(sstr, param) : NULL;
+    PERL_ARGS_ASSERT_SV_DUP;
+
+    /* Track every SV that (at least initially) had a reference count of 0.
+       We need to do this by holding an actual reference to it in this array.
+       If we attempt to cheat, turn AvREAL_off(), and store only pointers
+       (akin to the stashes hash, and the perl stack), we come unstuck if
+       a weak reference (or other SV legitimately SvREFCNT() == 0 for this
+       thread) is manipulated in a CLONE method, because CLONE runs before the
+       unreferenced array is walked to find SVs still with SvREFCNT() == 0
+       (and fix things up by giving each a reference via the temps stack).
+       Instead, during CLONE, if the 0-referenced SV has SvREFCNT_inc() and
+       then SvREFCNT_dec(), it will be cleaned up (and added to the free list)
+       before the walk of unreferenced happens and a reference to that is SV
+       added to the temps stack. At which point we have the same SV considered
+       to be in use, and free to be re-used. Not good.
+    */
+    if (dstr && !(param->flags & CLONEf_COPY_STACKS) && !SvREFCNT(dstr)) {
+       assert(param->unreferenced);
+       av_push(param->unreferenced, SvREFCNT_inc(dstr));
+    }
+
+    return dstr;
+}
+
 /* duplicate a context */
 
 PERL_CONTEXT *
@@ -11059,6 +11639,8 @@ Perl_si_dup(pTHX_ PERL_SI *si, CLONE_PARAMS* param)
 #define TOPLONG(ss,ix) ((ss)[ix].any_long)
 #define POPIV(ss,ix)   ((ss)[--(ix)].any_iv)
 #define TOPIV(ss,ix)   ((ss)[ix].any_iv)
+#define POPUV(ss,ix)   ((ss)[--(ix)].any_uv)
+#define TOPUV(ss,ix)   ((ss)[ix].any_uv)
 #define POPBOOL(ss,ix) ((ss)[--(ix)].any_bool)
 #define TOPBOOL(ss,ix) ((ss)[ix].any_bool)
 #define POPPTR(ss,ix)  ((ss)[--(ix)].any_ptr)
@@ -11131,9 +11713,13 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
     Newxz(nss, max, ANY);
 
     while (ix > 0) {
-       const I32 type = POPINT(ss,ix);
-       TOPINT(nss,ix) = type;
+       const UV uv = POPUV(ss,ix);
+       const U8 type = (U8)uv & SAVE_MASK;
+
+       TOPUV(nss,ix) = uv;
        switch (type) {
+       case SAVEt_CLEARSV:
+           break;
        case SAVEt_HELEM:               /* hash element */
            sv = (const SV *)POPPTR(ss,ix);
            TOPPTR(nss,ix) = sv_dup_inc(sv, param);
@@ -11180,14 +11766,10 @@ 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;
        case SAVEt_I32:                         /* I32 reference */
-       case SAVEt_I16:                         /* I16 reference */
-       case SAVEt_I8:                          /* I8 reference */
        case SAVEt_COP_ARYBASE:                 /* call CopARYBASE_set */
            ptr = POPPTR(ss,ix);
            TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
@@ -11211,6 +11793,12 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
        case SAVEt_VPTR:                        /* random* reference */
            ptr = POPPTR(ss,ix);
            TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
+           /* Fall through */
+       case SAVEt_INT_SMALL:
+       case SAVEt_I32_SMALL:
+       case SAVEt_I16:                         /* I16 reference */
+       case SAVEt_I8:                          /* I8 reference */
+       case SAVEt_BOOL:
            ptr = POPPTR(ss,ix);
            TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
            break;
@@ -11222,12 +11810,14 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
            TOPPTR(nss,ix) = pv_dup(c);
            break;
        case SAVEt_GP:                          /* scalar reference */
+           gv = (const GV *)POPPTR(ss,ix);
+           TOPPTR(nss,ix) = gv_dup_inc(gv, param);
            gp = (GP*)POPPTR(ss,ix);
            TOPPTR(nss,ix) = gp = gp_dup(gp, param);
            (void)GpREFCNT_inc(gp);
-           gv = (const GV *)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = gv_dup_inc(gv, param);
-            break;
+           i = POPINT(ss,ix);
+           TOPINT(nss,ix) = i;
+           break;
        case SAVEt_FREEOP:
            ptr = POPPTR(ss,ix);
            if (ptr && (((OP*)ptr)->op_private & OPpREFCOUNTED)) {
@@ -11254,15 +11844,13 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
            else
                TOPPTR(nss,ix) = NULL;
            break;
-       case SAVEt_FREEPV:
-           c = (char*)POPPTR(ss,ix);
-           TOPPTR(nss,ix) = pv_dup_inc(c);
-           break;
        case SAVEt_DELETE:
            hv = (const HV *)POPPTR(ss,ix);
            TOPPTR(nss,ix) = hv_dup_inc(hv, param);
            i = POPINT(ss,ix);
            TOPINT(nss,ix) = i;
+           /* Fall through */
+       case SAVEt_FREEPV:
            c = (char*)POPPTR(ss,ix);
            TOPPTR(nss,ix) = pv_dup_inc(c);
            break;
@@ -11288,9 +11876,7 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
            break;
        case SAVEt_REGCONTEXT:
        case SAVEt_ALLOC:
-           i = POPINT(ss,ix);
-           TOPINT(nss,ix) = i;
-           ix -= i;
+           ix -= uv >> SAVE_TIGHT_SHIFT;
            break;
        case SAVEt_AELEM:               /* array element */
            sv = (const SV *)POPPTR(ss,ix);
@@ -11327,12 +11913,6 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
            sv = (const SV *)POPPTR(ss,ix);
            TOPPTR(nss,ix) = sv_dup_inc(sv, param);
            break;
-       case SAVEt_BOOL:
-           ptr = POPPTR(ss,ix);
-           TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
-           longval = (long)POPBOOL(ss,ix);
-           TOPBOOL(nss,ix) = (bool)longval;
-           break;
        case SAVEt_SET_SVFLAGS:
            i = POPINT(ss,ix);
            TOPINT(nss,ix) = i;
@@ -11540,27 +12120,40 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PerlInterpreter * const my_perl = (PerlInterpreter*)(*ipM->pMalloc)(ipM, sizeof(PerlInterpreter));
 
     PERL_ARGS_ASSERT_PERL_CLONE_USING;
+#else          /* !PERL_IMPLICIT_SYS */
+    IV i;
+    CLONE_PARAMS clone_params;
+    CLONE_PARAMS* param = &clone_params;
+    PerlInterpreter * const my_perl = (PerlInterpreter*)PerlMem_malloc(sizeof(PerlInterpreter));
+
+    PERL_ARGS_ASSERT_PERL_CLONE;
+#endif         /* PERL_IMPLICIT_SYS */
 
     /* for each stash, determine whether its objects should be cloned */
     S_visit(proto_perl, do_mark_cloneable_stash, SVt_PVHV, SVTYPEMASK);
     PERL_SET_THX(my_perl);
 
-#  ifdef DEBUGGING
+#ifdef DEBUGGING
     PoisonNew(my_perl, 1, PerlInterpreter);
     PL_op = NULL;
     PL_curcop = NULL;
     PL_markstack = 0;
     PL_scopestack = 0;
+    PL_scopestack_name = 0;
     PL_savestack = 0;
     PL_savestack_ix = 0;
     PL_savestack_max = -1;
     PL_sig_pending = 0;
     PL_parser = NULL;
     Zero(&PL_debug_pad, 1, struct perl_debug_pad);
-#  else        /* !DEBUGGING */
+#  ifdef DEBUG_LEAKING_SCALARS
+    PL_sv_serial = (((U32)my_perl >> 2) & 0xfff) * 1000000;
+#  endif
+#else  /* !DEBUGGING */
     Zero(my_perl, 1, PerlInterpreter);
-#  endif       /* DEBUGGING */
+#endif /* DEBUGGING */
 
+#ifdef PERL_IMPLICIT_SYS
     /* host pointers */
     PL_Mem             = ipM;
     PL_MemShared       = ipMS;
@@ -11571,36 +12164,16 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_Dir             = ipD;
     PL_Sock            = ipS;
     PL_Proc            = ipP;
-#else          /* !PERL_IMPLICIT_SYS */
-    IV i;
-    CLONE_PARAMS clone_params;
-    CLONE_PARAMS* param = &clone_params;
-    PerlInterpreter * const my_perl = (PerlInterpreter*)PerlMem_malloc(sizeof(PerlInterpreter));
-
-    PERL_ARGS_ASSERT_PERL_CLONE;
-
-    /* for each stash, determine whether its objects should be cloned */
-    S_visit(proto_perl, do_mark_cloneable_stash, SVt_PVHV, SVTYPEMASK);
-    PERL_SET_THX(my_perl);
-
-#    ifdef DEBUGGING
-    PoisonNew(my_perl, 1, PerlInterpreter);
-    PL_op = NULL;
-    PL_curcop = NULL;
-    PL_markstack = 0;
-    PL_scopestack = 0;
-    PL_savestack = 0;
-    PL_savestack_ix = 0;
-    PL_savestack_max = -1;
-    PL_sig_pending = 0;
-    PL_parser = NULL;
-    Zero(&PL_debug_pad, 1, struct perl_debug_pad);
-#    else      /* !DEBUGGING */
-    Zero(my_perl, 1, PerlInterpreter);
-#    endif     /* DEBUGGING */
 #endif         /* PERL_IMPLICIT_SYS */
+
     param->flags = flags;
+    /* Nothing in the core code uses this, but we make it available to
+       extensions (using mg_dup).  */
     param->proto_perl = proto_perl;
+    /* Likely nothing will use this, but it is initialised to be consistent
+       with Perl_clone_params_new().  */
+    param->proto_perl = my_perl;
+    param->unreferenced = NULL;
 
     INIT_TRACK_MEMPOOL(my_perl->Imemory_debug_header, my_perl);
 
@@ -11658,6 +12231,9 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     SvNV_set(&PL_sv_yes, 1);
     ptr_table_store(PL_ptr_table, &proto_perl->Isv_yes, &PL_sv_yes);
 
+    /* dbargs array probably holds garbage */
+    PL_dbargs          = NULL;
+
     /* create (a non-shared!) shared string table */
     PL_strtab          = newHV();
     HvSHAREKEYS_off(PL_strtab);
@@ -11691,6 +12267,17 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_origargv                = proto_perl->Iorigargv;
 
     param->stashes      = newAV();  /* Setup array of objects to call clone on */
+    /* This makes no difference to the implementation, as it always pushes
+       and shifts pointers to other SVs without changing their reference
+       count, with the array becoming empty before it is freed. However, it
+       makes it conceptually clear what is going on, and will avoid some
+       work inside av.c, filling slots between AvFILL() and AvMAX() with
+       &PL_sv_undef, and SvREFCNT_dec()ing those.  */
+    AvREAL_off(param->stashes);
+
+    if (!(flags & CLONEf_COPY_STACKS)) {
+       param->unreferenced = newAV();
+    }
 
     /* Set tainting stuff before PerlIO_debug can possibly get called */
     PL_tainting                = proto_perl->Itainting;
@@ -11711,6 +12298,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     /* switches */
     PL_minus_c         = proto_perl->Iminus_c;
     PL_patchlevel      = sv_dup_inc(proto_perl->Ipatchlevel, param);
+    PL_apiversion      = sv_dup_inc(proto_perl->Iapiversion, param);
     PL_localpatches    = proto_perl->Ilocalpatches;
     PL_splitstr                = proto_perl->Isplitstr;
     PL_minus_n         = proto_perl->Iminus_n;
@@ -11784,7 +12372,6 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_DBsingle                = sv_dup(proto_perl->IDBsingle, param);
     PL_DBtrace         = sv_dup(proto_perl->IDBtrace, param);
     PL_DBsignal                = sv_dup(proto_perl->IDBsignal, param);
-    PL_dbargs          = av_dup(proto_perl->Idbargs, param);
 
     /* symbol tables */
     PL_defstash                = hv_dup_inc(proto_perl->Idefstash, param);
@@ -11908,6 +12495,13 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
     PL_parser          = parser_dup(proto_perl->Iparser, param);
 
+    /* XXX this only works if the saved cop has already been cloned */
+    if (proto_perl->Iparser) {
+       PL_parser->saved_curcop = (COP*)any_dup(
+                                   proto_perl->Iparser->saved_curcop,
+                                   proto_perl);
+    }
+
     PL_subline         = proto_perl->Isubline;
     PL_subname         = sv_dup_inc(proto_perl->Isubname, param);
 
@@ -11936,7 +12530,6 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
     /* utf8 character classes */
     PL_utf8_alnum      = sv_dup_inc(proto_perl->Iutf8_alnum, param);
-    PL_utf8_alnumc     = sv_dup_inc(proto_perl->Iutf8_alnumc, param);
     PL_utf8_ascii      = sv_dup_inc(proto_perl->Iutf8_ascii, param);
     PL_utf8_alpha      = sv_dup_inc(proto_perl->Iutf8_alpha, param);
     PL_utf8_space      = sv_dup_inc(proto_perl->Iutf8_space, param);
@@ -11949,6 +12542,16 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_utf8_punct      = sv_dup_inc(proto_perl->Iutf8_punct, param);
     PL_utf8_xdigit     = sv_dup_inc(proto_perl->Iutf8_xdigit, param);
     PL_utf8_mark       = sv_dup_inc(proto_perl->Iutf8_mark, param);
+    PL_utf8_X_begin    = sv_dup_inc(proto_perl->Iutf8_X_begin, param);
+    PL_utf8_X_extend   = sv_dup_inc(proto_perl->Iutf8_X_extend, param);
+    PL_utf8_X_prepend  = sv_dup_inc(proto_perl->Iutf8_X_prepend, param);
+    PL_utf8_X_non_hangul       = sv_dup_inc(proto_perl->Iutf8_X_non_hangul, param);
+    PL_utf8_X_L        = sv_dup_inc(proto_perl->Iutf8_X_L, param);
+    PL_utf8_X_LV       = sv_dup_inc(proto_perl->Iutf8_X_LV, param);
+    PL_utf8_X_LVT      = sv_dup_inc(proto_perl->Iutf8_X_LVT, param);
+    PL_utf8_X_T        = sv_dup_inc(proto_perl->Iutf8_X_T, param);
+    PL_utf8_X_V        = sv_dup_inc(proto_perl->Iutf8_X_V, param);
+    PL_utf8_X_LV_LVT_V = sv_dup_inc(proto_perl->Iutf8_X_LV_LVT_V, param);
     PL_utf8_toupper    = sv_dup_inc(proto_perl->Iutf8_toupper, param);
     PL_utf8_totitle    = sv_dup_inc(proto_perl->Iutf8_totitle, param);
     PL_utf8_tolower    = sv_dup_inc(proto_perl->Iutf8_tolower, param);
@@ -11983,6 +12586,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_unlockhook      = proto_perl->Iunlockhook;
     PL_threadhook      = proto_perl->Ithreadhook;
     PL_destroyhook     = proto_perl->Idestroyhook;
+    PL_signalhook      = proto_perl->Isignalhook;
 
 #ifdef THREADS_HAVE_PIDS
     PL_ppid            = proto_perl->Ippid;
@@ -11997,7 +12601,6 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
     PL_glob_index      = proto_perl->Iglob_index;
     PL_srand_called    = proto_perl->Isrand_called;
-    PL_bitcount                = NULL; /* reinits on demand */
 
     if (proto_perl->Ipsig_pend) {
        Newxz(PL_psig_pend, SIG_SIZE, int);
@@ -12006,13 +12609,11 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
        PL_psig_pend    = (int*)NULL;
     }
 
-    if (proto_perl->Ipsig_ptr) {
-       Newxz(PL_psig_ptr,  SIG_SIZE, SV*);
-       Newxz(PL_psig_name, SIG_SIZE, SV*);
-       for (i = 1; i < SIG_SIZE; i++) {
-           PL_psig_ptr[i]  = sv_dup_inc(proto_perl->Ipsig_ptr[i], param);
-           PL_psig_name[i] = sv_dup_inc(proto_perl->Ipsig_name[i], param);
-       }
+    if (proto_perl->Ipsig_name) {
+       Newx(PL_psig_name, 2 * SIG_SIZE, SV*);
+       sv_dup_inc_multiple(proto_perl->Ipsig_name, PL_psig_name, 2 * SIG_SIZE,
+                           param);
+       PL_psig_ptr = PL_psig_name + SIG_SIZE;
     }
     else {
        PL_psig_ptr     = (SV**)NULL;
@@ -12026,12 +12627,9 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
        PL_tmps_ix              = proto_perl->Itmps_ix;
        PL_tmps_max             = proto_perl->Itmps_max;
        PL_tmps_floor           = proto_perl->Itmps_floor;
-       Newxz(PL_tmps_stack, PL_tmps_max, SV*);
-       i = 0;
-       while (i <= PL_tmps_ix) {
-           PL_tmps_stack[i]    = sv_dup_inc(proto_perl->Itmps_stack[i], param);
-           ++i;
-       }
+       Newx(PL_tmps_stack, PL_tmps_max, SV*);
+       sv_dup_inc_multiple(proto_perl->Itmps_stack, PL_tmps_stack,
+                           PL_tmps_ix+1, param);
 
        /* next PUSHMARK() sets *(PL_markstack_ptr+1) */
        i = proto_perl->Imarkstack_max - proto_perl->Imarkstack;
@@ -12050,6 +12648,10 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
        Newxz(PL_scopestack, PL_scopestack_max, I32);
        Copy(proto_perl->Iscopestack, PL_scopestack, PL_scopestack_ix, I32);
 
+#ifdef DEBUGGING
+       Newxz(PL_scopestack_name, PL_scopestack_max, const char *);
+       Copy(proto_perl->Iscopestack_name, PL_scopestack_name, PL_scopestack_ix, const char *);
+#endif
        /* NOTE: si_dup() looks at PL_markstack */
        PL_curstackinfo         = si_dup(proto_perl->Icurstackinfo, param);
 
@@ -12073,20 +12675,6 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     else {
        init_stacks();
        ENTER;                  /* perl_destruct() wants to LEAVE; */
-
-       /* although we're not duplicating the tmps stack, we should still
-        * add entries for any SVs on the tmps stack that got cloned by a
-        * non-refcount means (eg a temp in @_); otherwise they will be
-        * orphaned
-        */
-       for (i = 0; i<= proto_perl->Itmps_ix; i++) {
-           SV * const nsv = MUTABLE_SV(ptr_table_fetch(PL_ptr_table,
-                   proto_perl->Itmps_stack[i]));
-           if (nsv && !SvREFCNT(nsv)) {
-               EXTEND_MORTAL(1);
-               PL_tmps_stack[++PL_tmps_ix] = SvREFCNT_inc_simple(nsv);
-           }
-       }
     }
 
     PL_start_env       = proto_perl->Istart_env;       /* XXXXXX */
@@ -12116,6 +12704,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_bodytarget      = sv_dup_inc(proto_perl->Ibodytarget, param);
     PL_formtarget      = sv_dup(proto_perl->Iformtarget, param);
 
+    PL_restartjmpenv   = proto_perl->Irestartjmpenv;
     PL_restartop       = proto_perl->Irestartop;
     PL_in_eval         = proto_perl->Iin_eval;
     PL_delaymagic      = proto_perl->Idelaymagic;
@@ -12151,6 +12740,9 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
     /* Pluggable optimizer */
     PL_peepp           = proto_perl->Ipeepp;
+    PL_rpeepp          = proto_perl->Irpeepp;
+    /* op_free() hook */
+    PL_opfreehook      = proto_perl->Iopfreehook;
 
     PL_stashcache       = newHV();
 
@@ -12164,10 +12756,8 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
          PTR2UV(PL_watchok));
     }
 
-    if (!(flags & CLONEf_KEEP_PTR_TABLE)) {
-        ptr_table_free(PL_ptr_table);
-        PL_ptr_table = NULL;
-    }
+    PL_registered_mros  = hv_dup_inc(proto_perl->Iregistered_mros, param);
+    PL_blockhooks      = av_dup_inc(proto_perl->Iblockhooks, param);
 
     /* Call the ->CLONE method, if it exists, for each of the stashes
        identified by sv_dup() above.
@@ -12188,6 +12778,15 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
        }
     }
 
+    if (!(flags & CLONEf_KEEP_PTR_TABLE)) {
+        ptr_table_free(PL_ptr_table);
+        PL_ptr_table = NULL;
+    }
+
+    if (!(flags & CLONEf_COPY_STACKS)) {
+       unreferenced_to_tmp_stack(param->unreferenced);
+    }
+
     SvREFCNT_dec(param->stashes);
 
     /* orphaned? eg threads->new inside BEGIN or use */
@@ -12199,6 +12798,109 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     return my_perl;
 }
 
+static void
+S_unreferenced_to_tmp_stack(pTHX_ AV *const unreferenced)
+{
+    PERL_ARGS_ASSERT_UNREFERENCED_TO_TMP_STACK;
+    
+    if (AvFILLp(unreferenced) > -1) {
+       SV **svp = AvARRAY(unreferenced);
+       SV **const last = svp + AvFILLp(unreferenced);
+       SSize_t count = 0;
+
+       do {
+           if (SvREFCNT(*svp) == 1)
+               ++count;
+       } while (++svp <= last);
+
+       EXTEND_MORTAL(count);
+       svp = AvARRAY(unreferenced);
+
+       do {
+           if (SvREFCNT(*svp) == 1) {
+               /* Our reference is the only one to this SV. This means that
+                  in this thread, the scalar effectively has a 0 reference.
+                  That doesn't work (cleanup never happens), so donate our
+                  reference to it onto the save stack. */
+               PL_tmps_stack[++PL_tmps_ix] = *svp;
+           } else {
+               /* As an optimisation, because we are already walking the
+                  entire array, instead of above doing either
+                  SvREFCNT_inc(*svp) or *svp = &PL_sv_undef, we can instead
+                  release our reference to the scalar, so that at the end of
+                  the array owns zero references to the scalars it happens to
+                  point to. We are effectively converting the array from
+                  AvREAL() on to AvREAL() off. This saves the av_clear()
+                  (triggered by the SvREFCNT_dec(unreferenced) below) from
+                  walking the array a second time.  */
+               SvREFCNT_dec(*svp);
+           }
+
+       } while (++svp <= last);
+       AvREAL_off(unreferenced);
+    }
+    SvREFCNT_dec(unreferenced);
+}
+
+void
+Perl_clone_params_del(CLONE_PARAMS *param)
+{
+    /* This seemingly funky ordering keeps the build with PERL_GLOBAL_STRUCT
+       happy: */
+    PerlInterpreter *const to = param->new_perl;
+    dTHXa(to);
+    PerlInterpreter *const was = PERL_GET_THX;
+
+    PERL_ARGS_ASSERT_CLONE_PARAMS_DEL;
+
+    if (was != to) {
+       PERL_SET_THX(to);
+    }
+
+    SvREFCNT_dec(param->stashes);
+    if (param->unreferenced)
+       unreferenced_to_tmp_stack(param->unreferenced);
+
+    Safefree(param);
+
+    if (was != to) {
+       PERL_SET_THX(was);
+    }
+}
+
+CLONE_PARAMS *
+Perl_clone_params_new(PerlInterpreter *const from, PerlInterpreter *const to)
+{
+    dVAR;
+    /* Need to play this game, as newAV() can call safesysmalloc(), and that
+       does a dTHX; to get the context from thread local storage.
+       FIXME - under PERL_CORE Newx(), Safefree() and friends should expand to
+       a version that passes in my_perl.  */
+    PerlInterpreter *const was = PERL_GET_THX;
+    CLONE_PARAMS *param;
+
+    PERL_ARGS_ASSERT_CLONE_PARAMS_NEW;
+
+    if (was != to) {
+       PERL_SET_THX(to);
+    }
+
+    /* Given that we've set the context, we can do this unshared.  */
+    Newx(param, 1, CLONE_PARAMS);
+
+    param->flags = 0;
+    param->proto_perl = from;
+    param->new_perl = to;
+    param->stashes = (AV *)Perl_newSV_type(to, SVt_PVAV);
+    AvREAL_off(param->stashes);
+    param->unreferenced = (AV *)Perl_newSV_type(to, SVt_PVAV);
+
+    if (was != to) {
+       PERL_SET_THX(was);
+    }
+    return param;
+}
+
 #endif /* USE_ITHREADS */
 
 /*
@@ -12808,6 +13510,14 @@ S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv,
          Need a better fix at dome point. DAPM 11/2007 */
        break;
 
+    case OP_FLIP:
+    case OP_FLOP:
+    {
+       GV * const gv = gv_fetchpvs(".", GV_NOTQUAL, SVt_PV);
+       if (gv && GvSV(gv) == uninit_sv)
+           return newSVpvs_flags("$.", SVs_TEMP);
+       goto do_op;
+    }
 
     case OP_POS:
        /* def-ness of rval pos() is independent of the def-ness of its arg */