This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Document that the regexp engine is not currently reentrant
[perl5.git] / sv.c
diff --git a/sv.c b/sv.c
index a915dd9..d1a4a6c 100644 (file)
--- a/sv.c
+++ b/sv.c
 #endif
 
 #ifdef PERL_UTF8_CACHE_ASSERT
-/* The cache element 0 is the Unicode offset;
- * the cache element 1 is the byte offset of the element 0;
- * the cache element 2 is the Unicode length of the substring;
- * the cache element 3 is the byte length of the substring;
- * The checking of the substring side would be good
- * but substr() has enough code paths to make my head spin;
- * if adding more checks watch out for the following tests:
+/* if adding more checks watch out for the following tests:
  *   t/op/index.t t/op/length.t t/op/pat.t t/op/substr.t
  *   lib/utf8.t lib/Unicode/Collate/t/index.t
  * --jhi
  */
 #define ASSERT_UTF8_CACHE(cache) \
-       STMT_START { if (cache) { assert((cache)[0] <= (cache)[1]); } } STMT_END
+    STMT_START { if (cache) { assert((cache)[0] <= (cache)[1]); \
+                             assert((cache)[2] <= (cache)[3]); \
+                             assert((cache)[3] <= (cache)[1]);} \
+                             } STMT_END
 #else
 #define ASSERT_UTF8_CACHE(cache) NOOP
 #endif
 
 =head1 Allocation and deallocation of SVs.
 
-An SV (or AV, HV, etc.) is allocated in two parts: the head (struct sv,
-av, hv...) contains type and reference count information, as well as a
-pointer to the body (struct xrv, xpv, xpviv...), which contains fields
-specific to each type.
+An SV (or AV, HV, etc.) is allocated in two parts: the head (struct
+sv, av, hv...) contains type and reference count information, and for
+many types, a pointer to the body (struct xrv, xpv, xpviv...), which
+contains fields specific to each type.  Some types store all they need
+in the head, so don't have a body.
 
-In all but the most memory-paranoid configuations (ex: PURIFY), this
-allocation is done using arenas, which by default are approximately 4K
-chunks of memory parcelled up into N heads or bodies (of same size).
+In all but the most memory-paranoid configuations (ex: PURIFY), heads
+and bodies are allocated out of arenas, which by default are
+approximately 4K chunks of memory parcelled up into N heads or bodies.
 Sv-bodies are allocated by their sv-type, guaranteeing size
 consistency needed to allocate safely from arrays.
 
-The first slot in each arena is reserved, and is used to hold a link
-to the next arena.  In the case of heads, the unused first slot also
-contains some flags and a note of the number of slots.  Snaked through
-each arena chain is a linked list of free items; when this becomes
-empty, an extra arena is allocated and divided up into N items which
-are threaded into the free list.
+For SV-heads, the first slot in each arena is reserved, and holds a
+link to the next arena, some flags, and a note of the number of slots.
+Snaked through each arena chain is a linked list of free items; when
+this becomes empty, an extra arena is allocated and divided up into N
+items which are threaded into the free list.
+
+SV-bodies are similar, but they use arena-sets by default, which
+separate the link and info from the arena itself, and reclaim the 1st
+slot in the arena.  SV-bodies are further described later.
 
 The following global variables are associated with arenas:
 
     PL_sv_arenaroot    pointer to list of SV arenas
     PL_sv_root         pointer to list of free SV structures
 
-    PL_body_arenaroots[]  array of pointers to list of arenas, 1 per svtype
-    PL_body_roots[]      array of pointers to list of free bodies of svtype
-                         arrays are indexed by the svtype needed
-
-Note that some of the larger and more rarely used body types (eg
-xpvio) are not allocated using arenas, but are instead just
-malloc()/free()ed as required.
+    PL_body_arenas     head of linked-list of body arenas
+    PL_body_roots[]    array of pointers to list of free bodies of svtype
+                       arrays are indexed by the svtype needed
 
-In addition, a few SV heads are not allocated from an arena, but are
-instead directly created as static or auto variables, eg PL_sv_undef.
+A few special SV heads are not allocated from an arena, but are
+instead directly created in the interpreter structure, eg PL_sv_undef.
 The size of arenas can be changed from the default by setting
 PERL_ARENA_SIZE appropriately at compile time.
 
@@ -103,13 +100,6 @@ to return the SV to the free list with error checking.) new_SV() calls
 more_sv() / sv_add_arena() to add an extra arena if the free list is empty.
 SVs in the free list have their SvTYPE field set to all ones.
 
-Similarly, there are macros new_XIV()/del_XIV(), new_XNV()/del_XNV() etc
-that allocate and return individual body types. Normally these are mapped
-to the arena-manipulating functions new_xiv()/del_xiv() etc, but may be
-instead mapped directly to malloc()/free() if PURIFY is defined. The
-new/del functions remove from, or add to, the appropriate PL_foo_root
-list, and call more_xiv() etc to add a new arena if the list is empty.
-
 At the time of very final cleanup, sv_free_arenas() is called from
 perl_destruct() to physically free all the arenas allocated since the
 start of the interpreter.
@@ -159,13 +149,10 @@ Public API:
 
     sv_report_used(), sv_clean_objs(), sv_clean_all(), sv_free_arenas()
 
-
 =cut
 
 ============================================================================ */
 
-
-
 /*
  * "A time to plant, and a time to uproot what was planted..."
  */
@@ -203,10 +190,10 @@ Perl_offer_nice_chunk(pTHX_ void *chunk, U32 chunk_size)
 #  define SvARENA_CHAIN(sv)    ((sv)->sv_u.svu_rv)
 /* Whilst I'd love to do this, it seems that things like to check on
    unreferenced scalars
-#  define POSION_SV_HEAD(sv)   Poison(sv, 1, struct STRUCT_SV)
+#  define POSION_SV_HEAD(sv)   PoisonNew(sv, 1, struct STRUCT_SV)
 */
-#  define POSION_SV_HEAD(sv)   Poison(&SvANY(sv), 1, void *), \
-                               Poison(&SvREFCNT(sv), 1, U32)
+#  define POSION_SV_HEAD(sv)   PoisonNew(&SvANY(sv), 1, void *), \
+                               PoisonNew(&SvREFCNT(sv), 1, U32)
 #else
 #  define SvARENA_CHAIN(sv)    SvANY(sv)
 #  define POSION_SV_HEAD(sv)
@@ -226,7 +213,7 @@ Perl_offer_nice_chunk(pTHX_ void *chunk, U32 chunk_size)
 #define uproot_SV(p) \
     STMT_START {                                       \
        (p) = PL_sv_root;                               \
-       PL_sv_root = (SV*)SvARENA_CHAIN(p);                     \
+       PL_sv_root = (SV*)SvARENA_CHAIN(p);             \
        ++PL_sv_count;                                  \
     } STMT_END
 
@@ -247,7 +234,7 @@ S_more_sv(pTHX)
     }
     else {
        char *chunk;                /* must use New here to match call to */
-       Newx(chunk,PERL_ARENA_SIZE,char);   /* Safefree() in sv_free_arenas()     */
+       Newx(chunk,PERL_ARENA_SIZE,char);  /* Safefree() in sv_free_arenas() */
        sv_add_arena(chunk, PERL_ARENA_SIZE, 0);
     }
     uproot_SV(sv);
@@ -445,6 +432,8 @@ Perl_sv_report_used(pTHX)
 {
 #ifdef DEBUGGING
     visit(do_report_used, 0, 0);
+#else
+    PERL_UNUSED_CONTEXT;
 #endif
 }
 
@@ -480,7 +469,7 @@ static void
 do_clean_named_objs(pTHX_ SV *sv)
 {
     dVAR;
-    if (SvTYPE(sv) == SVt_PVGV && GvGP(sv)) {
+    if (SvTYPE(sv) == SVt_PVGV && isGV_with_GP(sv) && GvGP(sv)) {
        if ((
 #ifdef PERL_DONT_CREATE_GVSV
             GvSV(sv) &&
@@ -530,7 +519,7 @@ do_clean_all(pTHX_ SV *sv)
     SvFLAGS(sv) |= SVf_BREAK;
     if (PL_comppad == (AV*)sv) {
        PL_comppad = NULL;
-       PL_curpad = Null(SV**);
+       PL_curpad = NULL;
     }
     SvREFCNT_dec(sv);
 }
@@ -567,14 +556,9 @@ Perl_sv_clean_all(pTHX)
   The cost is 1 arena-set malloc per ~320 arena-mallocs, + the unused
   memory in the last arena-set (1/2 on average).  In trade, we get
   back the 1st slot in each arena (ie 1.7% of a CV-arena, less for
-  others)
-
-  union arena is declared with a fixed size, but is intended to vary
-  by type, allowing their use for big, rare body-types where theres
-  currently too much wastage (unused arena slots)
+  smaller types).  The recovery of the wasted space allows use of
+  small arenas for large, rare body types,
 */
-#define ARENASETS 1
-
 struct arena_desc {
     char       *arena;         /* the raw storage, allocated aligned */
     size_t      size;          /* its size ~4k typ */
@@ -600,18 +584,6 @@ struct arena_set {
     struct arena_desc set[ARENAS_PER_SET];
 };
 
-#if !ARENASETS
-
-static void 
-S_free_arena(pTHX_ void **root) {
-    while (root) {
-       void ** const next = *(void **)root;
-       Safefree(root);
-       root = next;
-    }
-}
-#endif
-
 /*
 =for apidoc sv_free_arenas
 
@@ -640,12 +612,11 @@ Perl_sv_free_arenas(pTHX)
            Safefree(sva);
     }
 
-#if ARENASETS
     {
        struct arena_set *next, *aroot = (struct arena_set*) PL_body_arenas;
        
        for (; aroot; aroot = next) {
-           int max = aroot->curr;
+           const int max = aroot->curr;
            for (i=0; i<max; i++) {
                assert(aroot->set[i].arena);
                Safefree(aroot->set[i].arena);
@@ -654,11 +625,9 @@ Perl_sv_free_arenas(pTHX)
            Safefree(aroot);
        }
     }
-#else
-    S_free_arena(aTHX_ (void**) PL_body_arenas);
-#endif
+    PL_body_arenas = 0;
 
-    for (i=0; i<SVt_LAST; i++)
+    for (i=0; i<PERL_ARENA_ROOTS_SIZE; i++)
        PL_body_roots[i] = 0;
 
     Safefree(PL_nice_chunk);
@@ -703,123 +672,42 @@ Perl_sv_free_arenas(pTHX)
   contexts below (line ~10k)
 */
 
-/* get_arena(size): when ARENASETS is enabled, this creates
-   custom-sized arenas, otherwize it uses PERL_ARENA_SIZE, as
-   previously done.
+/* get_arena(size): this creates custom-sized arenas
    TBD: export properly for hv.c: S_more_he().
 */
 void*
 Perl_get_arena(pTHX_ int arena_size)
 {
-#if !ARENASETS
-    union arena* arp;
-
-    /* allocate and attach arena */
-    Newx(arp, PERL_ARENA_SIZE, char);
-    arp->next = PL_body_arenas;
-    PL_body_arenas = arp;
-    return arp;
-
-#else
     struct arena_desc* adesc;
-    struct arena_set *newroot, *aroot = (struct arena_set*) PL_body_arenas;
+    struct arena_set *newroot, **aroot = (struct arena_set**) &PL_body_arenas;
     int curr;
 
-    if (!arena_size)
-       arena_size = PERL_ARENA_SIZE;
+    /* 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) {
+    if (!*aroot || (*aroot)->curr >= (*aroot)->set_size) {
        Newxz(newroot, 1, struct arena_set);
        newroot->set_size = ARENAS_PER_SET;
-       newroot->next = aroot;
-       aroot = newroot;
-       DEBUG_m(PerlIO_printf(Perl_debug_log, "new arenaset %p\n", aroot));
+       newroot->next = *aroot;
+       *aroot = newroot;
+       DEBUG_m(PerlIO_printf(Perl_debug_log, "new arenaset %p\n", *aroot));
     }
 
     /* ok, now have arena-set with at least 1 empty/available arena-desc */
-    curr = aroot->curr++;
-    adesc = &aroot->set[curr];
+    curr = (*aroot)->curr++;
+    adesc = &((*aroot)->set[curr]);
     assert(!adesc->arena);
     
-    /* old fixed-size way
-       Newxz(adesc->arena, 1, union arena);
-       adesc->size = sizeof(union arena);
-    */
-    /* new buggy way    */
     Newxz(adesc->arena, arena_size, char);
     adesc->size = arena_size;
-
-    /* adesc->count = sizeof(struct arena)/size; */
-    
-    DEBUG_m(PerlIO_printf(Perl_debug_log, "arena %d added: %p\n", curr, aroot));
+    DEBUG_m(PerlIO_printf(Perl_debug_log, "arena %d added: %p size %d\n", 
+                         curr, adesc->arena, arena_size));
 
     return adesc->arena;
-#endif
 }
 
-STATIC void *
-S_more_bodies (pTHX_ size_t size, svtype sv_type)
-{
-    dVAR;
-    void ** const root = &PL_body_roots[sv_type];
-    char *start;
-    const char *end;
-    const size_t count = PERL_ARENA_SIZE / size;
-
-    start = (char*) Perl_get_arena(aTHX_ PERL_ARENA_SIZE); /* get a raw arena */
-
-    end = start + (count-1) * size;
-
-#if !ARENASETS
-    /* The initial slot is used to link the arenas together, so it isn't to be
-       linked into the list of ready-to-use bodies.  */
-    start += size;
-#endif
-
-    *root = (void *)start;
-
-    while (start < end) {
-       char * const next = start + size;
-       *(void**) start = (void *)next;
-       start = next;
-    }
-    *(void **)start = 0;
-
-    return *root;
-}
-
-/* grab a new thing from the free list, allocating more if necessary */
-
-/* 1st, the inline version  */
-
-#define new_body_inline(xpv, size, sv_type) \
-    STMT_START { \
-       void ** const r3wt = &PL_body_roots[sv_type]; \
-       LOCK_SV_MUTEX; \
-       xpv = *((void **)(r3wt)) \
-         ? *((void **)(r3wt)) : S_more_bodies(aTHX_ size, sv_type); \
-       *(r3wt) = *(void**)(xpv); \
-       UNLOCK_SV_MUTEX; \
-    } STMT_END
-
-/* now use the inline version in the proper function */
-
-#ifndef PURIFY
-
-/* This isn't being used with -DPURIFY, so don't declare it. Otherwise
-   compilers issue warnings.  */
-
-STATIC void *
-S_new_body(pTHX_ size_t size, svtype sv_type)
-{
-    dVAR;
-    void *xpv;
-    new_body_inline(xpv, size, sv_type);
-    return xpv;
-}
-
-#endif
 
 /* return a thing to the free list */
 
@@ -833,54 +721,111 @@ S_new_body(pTHX_ size_t size, svtype sv_type)
     } STMT_END
 
 /* 
-   Revisiting type 3 arenas, there are 4 body-types which have some
-   members that are never accessed.  They are XPV, XPVIV, XPVAV,
-   XPVHV, which have corresponding types: xpv_allocated,
-   xpviv_allocated, xpvav_allocated, xpvhv_allocated,
-
-   For these types, the arenas are carved up into *_allocated size
-   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 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.
-
-   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 the
-   start of the structure. IV bodies don't need it either, because they are
-   no longer allocated.  */
-
-/* The following 2 arrays hide the above details in a pair of
-   lookup-tables, allowing us to be body-type agnostic.
-
-   size maps svtype to its body's allocated size.
-   offset maps svtype to the body-pointer adjustment needed
-
-   NB: elements in latter are 0 or <0, and are added during
-   allocation, and subtracted during deallocation.  It may be clearer
-   to invert the values, and call it shrinkage_by_svtype.
+
+=head1 SV-Body Allocation
+
+Allocation of SV-bodies is similar to SV-heads, differing as follows;
+the allocation mechanism is used for many body types, so is somewhat
+more complicated, it uses arena-sets, and has no need for still-live
+SV detection.
+
+At the outermost level, (new|del)_X*V macros return bodies of the
+appropriate type.  These macros call either (new|del)_body_type or
+(new|del)_body_allocated macro pairs, depending on specifics of the
+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
+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
+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
+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.
+
+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
+the start of the structure. IV bodies don't need it either, because
+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
+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
+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.
+
+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:
+
+Arena_size determines whether arenas are used for this body type, and if
+so, how big they are.  PURIFY or PERL_ARENA_SIZE=0 set this field to
+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.
+
+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
+are used for this, except for arena_size.
+
+For the sv-types that have no bodies, arenas are not used, so those
+PL_body_roots[sv_type] are unused, and can be overloaded.  In
+something of a special case, SVt_NULL is borrowed for HE arenas;
+PL_body_roots[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[SVt_NULL], 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 {
-    size_t size;       /* Size to allocate  */
-    size_t copy;       /* Size of structure to copy (may be shorter)  */
-    size_t offset;
-    bool cant_upgrade; /* Can upgrade this type */
-    bool zero_nv;      /* zero the NV when upgrading from this */
-    bool arena;                /* Allocated from an arena */
+    U8 body_size;      /* Size to allocate  */
+    U8 copy;           /* Size of structure to copy (may be shorter)  */
+    U8 offset;
+    unsigned int type : 4;         /* We have space for a sanity check.  */
+    unsigned int cant_upgrade : 1;  /* Cannot upgrade this type */
+    unsigned int zero_nv : 1;      /* zero the NV when upgrading from this */
+    unsigned int arena : 1;        /* Allocated from an arena */
+    size_t arena_size;             /* Size of arena to allocate */
 };
 
 #define HADNV FALSE
 #define NONV TRUE
 
+
 #ifdef PURIFY
 /* With -DPURFIY we allocate everything directly, and don't use arenas.
    This seems a rather elegant way to simplify some of the code below.  */
@@ -890,6 +835,25 @@ struct body_details {
 #endif
 #define NOARENA FALSE
 
+/* Size the arenas to exactly fit a given number of bodies.  A count
+   of 0 fits the max number bodies into a PERL_ARENA_SIZE.block,
+   simplifying the default.  If count > 0, the arena is sized to fit
+   only that many bodies, allowing arenas to be used for large, rare
+   bodies (XPVFM, XPVIO) without undue waste.  The arena size is
+   limited by PERL_ARENA_SIZE, so we can safely oversize the
+   declarations.
+ */
+#define FIT_ARENA0(body_size)                          \
+    ((size_t)(PERL_ARENA_SIZE / body_size) * body_size)
+#define FIT_ARENAn(count,body_size)                    \
+    ( count * body_size <= PERL_ARENA_SIZE)            \
+    ? count * body_size                                        \
+    : FIT_ARENA0 (body_size)
+#define FIT_ARENA(count,body_size)                     \
+    count                                              \
+    ? 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 {
@@ -919,66 +883,95 @@ struct xpv {
        + sizeof (((type*)SvANY((SV*)0))->last_member)
 
 static const struct body_details bodies_by_type[] = {
-    {0, 0, 0, FALSE, NONV, NOARENA},
-    /* IVs are in the head, so the allocation size is 0  */
-    {0, sizeof(IV), STRUCT_OFFSET(XPVIV, xiv_iv), FALSE, NONV, NOARENA},
+    { sizeof(HE), 0, 0, SVt_NULL,
+      FALSE, NONV, NOARENA, FIT_ARENA(0, sizeof(HE)) },
+
+    /* 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.  */
+      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))
+    },
+
     /* 8 bytes on most ILP32 with IEEE doubles */
-    {sizeof(NV), sizeof(NV), 0, FALSE, HADNV, HASARENA},
-    /* RVs are in the head now */
-    /* However, this slot is overloaded and used by the pte  */
-    {0, 0, 0, FALSE, NONV, NOARENA},
+    { sizeof(NV), sizeof(NV), 0, SVt_NV, FALSE, HADNV, HASARENA,
+      FIT_ARENA(0, sizeof(NV)) },
+
+    /* RVs are in the head now.  */
+    { 0, 0, 0, SVt_RV, FALSE, NONV, NOARENA, 0 },
+
     /* 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),
-     FALSE, NONV, HASARENA},
+    { 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)) },
+
     /* 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),
-     FALSE, NONV, HASARENA},
+    { 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)) },
+
     /* 20 */
-    {sizeof(XPVNV), copy_length(XPVNV, xiv_u), 0, FALSE, HADNV, HASARENA},
+    { sizeof(XPVNV), copy_length(XPVNV, xiv_u), 0, SVt_PVNV, FALSE, HADNV,
+      HASARENA, FIT_ARENA(0, sizeof(XPVNV)) },
+
     /* 28 */
-    {sizeof(XPVMG), copy_length(XPVMG, xmg_stash), 0, FALSE, HADNV, HASARENA},
+    { sizeof(XPVMG), copy_length(XPVMG, xmg_stash), 0, SVt_PVMG, FALSE, HADNV,
+      HASARENA, FIT_ARENA(0, sizeof(XPVMG)) },
+    
     /* 36 */
-    {sizeof(XPVBM), sizeof(XPVBM), 0, TRUE, HADNV, HASARENA},
+    { sizeof(XPVBM), sizeof(XPVBM), 0, SVt_PVBM, TRUE, HADNV,
+      HASARENA, FIT_ARENA(0, sizeof(XPVBM)) },
+
     /* 48 */
-    {sizeof(XPVGV), sizeof(XPVGV), 0, TRUE, HADNV, HASARENA},
+    { sizeof(XPVGV), sizeof(XPVGV), 0, SVt_PVGV, TRUE, HADNV,
+      HASARENA, FIT_ARENA(0, sizeof(XPVGV)) },
+    
     /* 64 */
-    {sizeof(XPVLV), sizeof(XPVLV), 0, TRUE, HADNV, HASARENA},
-    /* 20 */
-    {sizeof(xpvav_allocated),
-     copy_length(XPVAV, xmg_stash)
-     - relative_STRUCT_OFFSET(xpvav_allocated, XPVAV, xav_fill),
-     + relative_STRUCT_OFFSET(xpvav_allocated, XPVAV, xav_fill),
-     TRUE, HADNV, HASARENA},
-    /* 20 */
-    {sizeof(xpvhv_allocated),
-     copy_length(XPVHV, xmg_stash)
-     - relative_STRUCT_OFFSET(xpvhv_allocated, XPVHV, xhv_fill),
-     + relative_STRUCT_OFFSET(xpvhv_allocated, XPVHV, xhv_fill),
-     TRUE, HADNV, HASARENA},
-    /* 76 */
-    {sizeof(XPVCV), sizeof(XPVCV), 0, TRUE, HADNV, HASARENA},
-    /* 80 */
-    {sizeof(XPVFM), sizeof(XPVFM), 0, TRUE, HADNV, NOARENA},
-    /* 84 */
-    {sizeof(XPVIO), sizeof(XPVIO), 0, TRUE, HADNV, NOARENA}
+    { 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, HADNV, HASARENA, FIT_ARENA(0, sizeof(xpvav_allocated)) },
+
+    { 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, HADNV, HASARENA, FIT_ARENA(0, sizeof(xpvhv_allocated)) },
+
+    /* 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)) },
+
+    /* XPVIO is 84 bytes, fits 48x */
+    { sizeof(XPVIO), sizeof(XPVIO), 0, SVt_PVIO, TRUE, HADNV,
+      HASARENA, FIT_ARENA(24, sizeof(XPVIO)) },
 };
 
-#define new_body_type(sv_type)                 \
-    (void *)((char *)S_new_body(aTHX_ bodies_by_type[sv_type].size, sv_type)\
-            - bodies_by_type[sv_type].offset)
+#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_ bodies_by_type[sv_type].size, sv_type)\
+    (void *)((char *)S_new_body(aTHX_ sv_type) \
             - bodies_by_type[sv_type].offset)
 
 #define del_body_allocated(p, sv_type)         \
@@ -1034,9 +1027,85 @@ static const struct body_details bodies_by_type[] = {
 /* no arena for you! */
 
 #define new_NOARENA(details) \
-       my_safemalloc((details)->size + (details)->offset)
+       my_safemalloc((details)->body_size + (details)->offset)
 #define new_NOARENAZ(details) \
-       my_safecalloc((details)->size + (details)->offset)
+       my_safecalloc((details)->body_size + (details)->offset)
+
+#ifdef DEBUGGING
+static bool done_sanity_check;
+#endif
+
+STATIC void *
+S_more_bodies (pTHX_ svtype sv_type)
+{
+    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;
+    char *start;
+    const char *end;
+
+    assert(bdp->arena_size);
+
+#ifdef DEBUGGING
+    if (!done_sanity_check) {
+       unsigned int i = SVt_LAST;
+
+       done_sanity_check = TRUE;
+
+       while (i--)
+           assert (bodies_by_type[i].type == i);
+    }
+#endif
+
+    start = (char*) Perl_get_arena(aTHX_ bdp->arena_size);
+
+    end = start + bdp->arena_size - body_size;
+
+    /* computed count doesnt reflect the 1st slot reservation */
+    DEBUG_m(PerlIO_printf(Perl_debug_log,
+                         "arena %p end %p arena-size %d type %d size %d ct %d\n",
+                         start, end, bdp->arena_size, sv_type, body_size,
+                         bdp->arena_size / body_size));
+
+    *root = (void *)start;
+
+    while (start < end) {
+       char * const next = start + body_size;
+       *(void**) start = (void *)next;
+       start = next;
+    }
+    *(void **)start = 0;
+
+    return *root;
+}
+
+/* grab a new thing from the free list, allocating more if necessary.
+   The inline version is used for speed in hot routines, and the
+   function using it serves the rest (unless PURIFY).
+*/
+#define new_body_inline(xpv, sv_type) \
+    STMT_START { \
+       void ** const r3wt = &PL_body_roots[sv_type]; \
+       LOCK_SV_MUTEX; \
+       xpv = *((void **)(r3wt)) \
+         ? *((void **)(r3wt)) : more_bodies(sv_type); \
+       *(r3wt) = *(void**)(xpv); \
+       UNLOCK_SV_MUTEX; \
+    } STMT_END
+
+#ifndef PURIFY
+
+STATIC void *
+S_new_body(pTHX_ svtype sv_type)
+{
+    dVAR;
+    void *xpv;
+    new_body_inline(xpv, sv_type);
+    return xpv;
+}
+
+#endif
 
 /*
 =for apidoc sv_upgrade
@@ -1055,9 +1124,9 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 new_type)
     void*      old_body;
     void*      new_body;
     const U32  old_type = SvTYPE(sv);
+    const struct body_details *new_type_details;
     const struct body_details *const old_type_details
        = bodies_by_type + old_type;
-    const struct body_details *new_type_details = bodies_by_type + new_type;
 
     if (new_type != SVt_PV && SvIsCOW(sv)) {
        sv_force_normal_flags(sv, 0);
@@ -1116,13 +1185,11 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 new_type)
        if (new_type < SVt_PVIV) {
            new_type = (new_type == SVt_NV)
                ? SVt_PVNV : SVt_PVIV;
-           new_type_details = bodies_by_type + new_type;
        }
        break;
     case SVt_NV:
        if (new_type < SVt_PVNV) {
            new_type = SVt_PVNV;
-           new_type_details = bodies_by_type + new_type;
        }
        break;
     case SVt_RV:
@@ -1144,19 +1211,22 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 new_type)
        /* This flag bit is used to mean other things in other scalar types.
           Given that it only has meaning inside the pad, it shouldn't be set
           on anything that can get upgraded.  */
-       assert((SvFLAGS(sv) & SVpad_TYPED) == 0);
+       assert(!SvPAD_TYPED(sv));
        break;
     default:
        if (old_type_details->cant_upgrade)
-           Perl_croak(aTHX_ "Can't upgrade that kind of scalar");
+           Perl_croak(aTHX_ "Can't upgrade %s (%" UVuf ") to %" UVuf,
+                      sv_reftype(sv, 0), (UV) old_type, (UV) new_type);
     }
+    new_type_details = bodies_by_type + new_type;
 
     SvFLAGS(sv) &= ~SVTYPEMASK;
     SvFLAGS(sv) |= new_type;
 
+    /* This can't happen, as SVt_NULL is <= all values of new_type, so one of
+       the return statements above will have triggered.  */
+    assert (new_type != SVt_NULL);
     switch (new_type) {
-    case SVt_NULL:
-       Perl_croak(aTHX_ "Can't upgrade to undef");
     case SVt_IV:
        assert(old_type == SVt_NULL);
        SvANY(sv) = (XPVIV*)((char*)&(sv->sv_u.svu_iv) - STRUCT_OFFSET(XPVIV, xiv_iv));
@@ -1173,21 +1243,28 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 new_type)
        SvRV_set(sv, 0);
        return;
     case SVt_PVHV:
-       SvANY(sv) = new_XPVHV();
-       HvFILL(sv)      = 0;
-       HvMAX(sv)       = 0;
-       HvTOTALKEYS(sv) = 0;
-
-       goto hv_av_common;
-
     case SVt_PVAV:
-       SvANY(sv) = new_XPVAV();
-       AvMAX(sv)       = -1;
-       AvFILLp(sv)     = -1;
-       AvALLOC(sv)     = 0;
-       AvREAL_only(sv);
+       assert(new_type_details->body_size);
+
+#ifndef PURIFY 
+       assert(new_type_details->arena);
+       assert(new_type_details->arena_size);
+       /* This points to the start of the allocated area.  */
+       new_body_inline(new_body, new_type);
+       Zero(new_body, new_type_details->body_size, char);
+       new_body = ((char *)new_body) - new_type_details->offset;
+#else
+       /* We always allocated the full length item with PURIFY. To do this
+          we fake things so that arena is false for all 16 types..  */
+       new_body = new_NOARENAZ(new_type_details);
+#endif
+       SvANY(sv) = new_body;
+       if (new_type == SVt_PVAV) {
+           AvMAX(sv)   = -1;
+           AvFILLp(sv) = -1;
+           AvREAL_only(sv);
+       }
 
-    hv_av_common:
        /* SVt_NULL isn't the only thing upgraded to AV or HV.
           The target created by newSVrv also is, and it can have magic.
           However, it never has SvPVX set.
@@ -1201,11 +1278,8 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 new_type)
        SvPV_set(sv, NULL);
 
        if (old_type >= SVt_PVMG) {
-           SvMAGIC_set(sv, ((XPVMG*)old_body)->xmg_magic);
+           SvMAGIC_set(sv, ((XPVMG*)old_body)->xmg_u.xmg_magic);
            SvSTASH_set(sv, ((XPVMG*)old_body)->xmg_stash);
-       } else {
-           SvMAGIC_set(sv, NULL);
-           SvSTASH_set(sv, NULL);
        }
        break;
 
@@ -1225,13 +1299,13 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 new_type)
     case SVt_PVNV:
     case SVt_PV:
 
-       assert(new_type_details->size);
+       assert(new_type_details->body_size);
        /* We always allocated the full length item with PURIFY. To do this
           we fake things so that arena is false for all 16 types..  */
        if(new_type_details->arena) {
            /* This points to the start of the allocated area.  */
-           new_body_inline(new_body, new_type_details->size, new_type);
-           Zero(new_body, new_type_details->size, char);
+           new_body_inline(new_body, new_type);
+           Zero(new_body, new_type_details->body_size, char);
            new_body = ((char *)new_body) - new_type_details->offset;
        } else {
            new_body = new_NOARENAZ(new_type_details);
@@ -1239,9 +1313,21 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 new_type)
        SvANY(sv) = new_body;
 
        if (old_type_details->copy) {
-           Copy((char *)old_body + old_type_details->offset,
-                (char *)new_body + old_type_details->offset,
-                old_type_details->copy, char);
+           /* There is now the potential for an upgrade from something without
+              an offset (PVNV or PVMG) to something with one (PVCV, PVFM)  */
+           int offset = old_type_details->offset;
+           int length = old_type_details->copy;
+
+           if (new_type_details->offset > old_type_details->offset) {
+               const int difference
+                   = new_type_details->offset - old_type_details->offset;
+               offset += difference;
+               length -= difference;
+           }
+           assert (length >= 0);
+               
+           Copy((char *)old_body + offset, (char *)new_body + offset, length,
+                char);
        }
 
 #ifndef NV_ZERO_IS_ALLBITS_ZERO
@@ -1264,8 +1350,11 @@ Perl_sv_upgrade(pTHX_ register SV *sv, U32 new_type)
                   (unsigned long)new_type);
     }
 
-    if (old_type_details->size) {
-       /* If the old body had an allocated size, then we need to free it.  */
+    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.  */
 #ifdef PURIFY
        my_safefree(old_body);
 #else
@@ -1287,6 +1376,7 @@ wrapper instead.
 int
 Perl_sv_backoff(pTHX_ register SV *sv)
 {
+    PERL_UNUSED_CONTEXT;
     assert(SvOOK(sv));
     assert(SvTYPE(sv) != SVt_PVHV);
     assert(SvTYPE(sv) != SVt_PVAV);
@@ -1316,6 +1406,10 @@ Perl_sv_grow(pTHX_ register SV *sv, register STRLEN newlen)
 {
     register char *s;
 
+    if (PL_madskills && newlen >= 0x100000) {
+       PerlIO_printf(Perl_debug_log,
+                     "Allocation too large: %"UVxf"\n", (UV)newlen);
+    }
 #ifdef HAS_64K_LIMIT
     if (newlen >= 0x10000) {
        PerlIO_printf(Perl_debug_log,
@@ -1623,6 +1717,31 @@ Perl_looks_like_number(pTHX_ SV *sv)
     return grok_number(sbegin, len, NULL);
 }
 
+STATIC char *
+S_glob_2inpuv(pTHX_ GV *gv, STRLEN *len, bool want_number)
+{
+    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 (want_number) {
+       /* We know that all GVs stringify to something that is not-a-number,
+          so no need to test that.  */
+       if (ckWARN(WARN_NUMERIC))
+           not_a_number(buffer);
+       /* We just want something true to return, so that S_sv_2iuv_common
+          can tail call us and return true.  */
+       return (char *) 1;
+    } else {
+       return SvPV(buffer, *len);
+    }
+}
+
 /* Actually, ISO C leaves conversion of UV to IV undefined, but
    until proven guilty, assume that things are not that bad... */
 
@@ -1773,6 +1892,13 @@ S_sv_2iuv_common(pTHX_ SV *sv) {
           certainly cast into the IV range at IV_MAX, whereas the correct
           answer is the UV IV_MAX +1. Hence < ensures that dodgy boundary
           cases go to UV */
+#if defined(NAN_COMPARE_BROKEN) && defined(Perl_isnan)
+       if (Perl_isnan(SvNVX(sv))) {
+           SvUV_set(sv, 0);
+           SvIsUV_on(sv);
+           return FALSE;
+       }
+#endif
        if (SvNVX(sv) < (NV)IV_MAX + 0.5) {
            SvIV_set(sv, I_V(SvNVX(sv)));
            if (SvNVX(sv) == (NV) SvIVX(sv)
@@ -1924,7 +2050,7 @@ S_sv_2iuv_common(pTHX_ SV *sv) {
                 if ((NV)(SvIVX(sv)) == SvNVX(sv)) {
                     SvIOK_on(sv);
                 } else {
-                    /* Integer is imprecise. NOK, IOKp */
+                   /*EMPTY*/;  /* Integer is imprecise. NOK, IOKp */
                 }
                 /* UV will not work better than IV */
             } else {
@@ -1939,7 +2065,7 @@ S_sv_2iuv_common(pTHX_ SV *sv) {
                     if ((NV)(SvUVX(sv)) == SvNVX(sv)) {
                         SvIOK_on(sv);
                     } else {
-                        /* Integer is imprecise. NOK, IOKp, is UV */
+                       /*EMPTY*/;   /* Integer is imprecise. NOK, IOKp, is UV */
                     }
                 }
                SvIsUV_on(sv);
@@ -1983,6 +2109,10 @@ S_sv_2iuv_common(pTHX_ SV *sv) {
        }
     }
     else  {
+       if (isGV_with_GP(sv)) {
+           return (bool)PTR2IV(glob_2inpuv((GV *)sv, NULL, TRUE));
+       }
+
        if (!(SvFLAGS(sv) & SVs_PADTMP)) {
            if (!PL_localizing && ckWARN(WARN_UNINITIALIZED))
                report_uninit(sv);
@@ -2171,7 +2301,7 @@ Perl_sv_2nv(pTHX_ register SV *sv)
        mg_get(sv);
        if (SvNOKp(sv))
            return SvNVX(sv);
-       if (SvPOKp(sv) && SvLEN(sv)) {
+       if ((SvPOKp(sv) && SvLEN(sv)) && !SvIOKp(sv)) {
            if (!SvIOKp(sv) && ckWARN(WARN_NUMERIC) &&
                !grok_number(SvPVX_const(sv), SvCUR(sv), NULL))
                not_a_number(sv);
@@ -2330,6 +2460,11 @@ Perl_sv_2nv(pTHX_ register SV *sv)
 #endif /* NV_PRESERVES_UV */
     }
     else  {
+       if (isGV_with_GP(sv)) {
+           glob_2inpuv((GV *)sv, NULL, TRUE);
+           return 0.0;
+       }
+
        if (!PL_localizing && !(SvFLAGS(sv) & SVs_PADTMP) && ckWARN(WARN_UNINITIALIZED))
            report_uninit(sv);
        assert (SvTYPE(sv) >= SVt_NV);
@@ -2515,16 +2650,8 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
                Gconvert(SvNVX(sv), NV_DIG, 0, tbuf);
                len = strlen(tbuf);
            }
-           if (SvROK(sv)) {    /* XXX Skip this when sv_pvn_force calls */
-               /* Sneaky stuff here */
-               SV * const tsv = newSVpvn(tbuf, len);
-
-               sv_2mortal(tsv);
-               if (lp)
-                   *lp = SvCUR(tsv);
-               return SvPVX(tsv);
-           }
-           else {
+           assert(!SvROK(sv));
+           {
                dVAR;
 
 #ifdef FIXNEGATIVEZERO
@@ -2670,6 +2797,10 @@ Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
 #endif
     }
     else {
+       if (isGV_with_GP(sv)) {
+           return glob_2inpuv((GV *)sv, lp, FALSE);
+       }
+
        if (!PL_localizing && !(SvFLAGS(sv) & SVs_PADTMP) && ckWARN(WARN_UNINITIALIZED))
            report_uninit(sv);
        if (lp)
@@ -2800,8 +2931,12 @@ Perl_sv_2bool(pTHX_ register SV *sv)
        else {
            if (SvNOKp(sv))
                return SvNVX(sv) != 0.0;
-           else
-               return FALSE;
+           else {
+               if (isGV_with_GP(sv))
+                   return TRUE;
+               else
+                   return FALSE;
+           }
        }
     }
 }
@@ -3034,20 +3169,27 @@ copy-ish functions and macros use this underneath.
 */
 
 static void
-S_glob_assign(pTHX_ SV *dstr, SV *sstr, const int dtype)
+S_glob_assign_glob(pTHX_ SV *dstr, SV *sstr, const int dtype)
 {
     if (dtype != SVt_PVGV) {
        const char * const name = GvNAME(sstr);
        const STRLEN len = GvNAMELEN(sstr);
        /* don't upgrade SVt_PVLV: it can hold a glob */
-       if (dtype != SVt_PVLV)
+       if (dtype != SVt_PVLV) {
+           if (dtype >= SVt_PV) {
+               SvPV_free(dstr);
+               SvPV_set(dstr, 0);
+               SvLEN_set(dstr, 0);
+               SvCUR_set(dstr, 0);
+           }
            sv_upgrade(dstr, SVt_PVGV);
-       sv_magic(dstr, dstr, PERL_MAGIC_glob, NULL, 0);
+           (void)SvOK_off(dstr);
+           SvSCREAM_on(dstr);
+       }
        GvSTASH(dstr) = GvSTASH(sstr);
        if (GvSTASH(dstr))
            Perl_sv_add_backref(aTHX_ (SV*)GvSTASH(dstr), dstr);
-       GvNAME(dstr) = savepvn(name, len);
-       GvNAMELEN(dstr) = len;
+       gv_name_set((GV *)dstr, name, len, GV_ADD);
        SvFAKE_on(dstr);        /* can coerce to non-glob */
     }
 
@@ -3057,9 +3199,11 @@ S_glob_assign(pTHX_ SV *dstr, SV *sstr, const int dtype)
     }
 #endif
 
+    gp_free((GV*)dstr);
+    SvSCREAM_off(dstr);
     (void)SvOK_off(dstr);
+    SvSCREAM_on(dstr);
     GvINTRO_off(dstr);         /* one-shot flag */
-    gp_free((GV*)dstr);
     GvGP(dstr) = gp_ref(GvGP(sstr));
     if (SvTAINTED(sstr))
        SvTAINT(dstr);
@@ -3073,10 +3217,14 @@ S_glob_assign(pTHX_ SV *dstr, SV *sstr, const int dtype)
 }
 
 static void
-S_pvgv_assign(pTHX_ SV *dstr, SV *sstr) {
+S_glob_assign_ref(pTHX_ SV *dstr, SV *sstr) {
     SV * const sref = SvREFCNT_inc(SvRV(sstr));
     SV *dref = NULL;
     const int intro = GvINTRO(dstr);
+    SV **location;
+    U8 import_flag = 0;
+    const U32 stype = SvTYPE(sref);
+
 
 #ifdef GV_UNIQUE_CHECK
     if (GvUNIQUE((GV*)dstr)) {
@@ -3090,45 +3238,43 @@ S_pvgv_assign(pTHX_ SV *dstr, SV *sstr) {
        GvEGV(dstr) = (GV*)dstr;
     }
     GvMULTI_on(dstr);
-    switch (SvTYPE(sref)) {
-    case SVt_PVAV:
-       if (intro)
-           SAVEGENERICSV(GvAV(dstr));
-       else
-           dref = (SV*)GvAV(dstr);
-       GvAV(dstr) = (AV*)sref;
-       if (!GvIMPORTED_AV(dstr)
-           && CopSTASH_ne(PL_curcop, GvSTASH(dstr)))
-           {
-               GvIMPORTED_AV_on(dstr);
-           }
-       break;
-    case SVt_PVHV:
-       if (intro)
-           SAVEGENERICSV(GvHV(dstr));
-       else
-           dref = (SV*)GvHV(dstr);
-       GvHV(dstr) = (HV*)sref;
-       if (!GvIMPORTED_HV(dstr)
-           && CopSTASH_ne(PL_curcop, GvSTASH(dstr)))
-           {
-               GvIMPORTED_HV_on(dstr);
-           }
-       break;
+    switch (stype) {
     case SVt_PVCV:
+       location = (SV **) &GvCV(dstr);
+       import_flag = GVf_IMPORTED_CV;
+       goto common;
+    case SVt_PVHV:
+       location = (SV **) &GvHV(dstr);
+       import_flag = GVf_IMPORTED_HV;
+       goto common;
+    case SVt_PVAV:
+       location = (SV **) &GvAV(dstr);
+       import_flag = GVf_IMPORTED_AV;
+       goto common;
+    case SVt_PVIO:
+       location = (SV **) &GvIOp(dstr);
+       goto common;
+    case SVt_PVFM:
+       location = (SV **) &GvFORM(dstr);
+    default:
+       location = &GvSV(dstr);
+       import_flag = GVf_IMPORTED_SV;
+    common:
        if (intro) {
-           if (GvCVGEN(dstr) && GvCV(dstr) != (CV*)sref) {
-               SvREFCNT_dec(GvCV(dstr));
-               GvCV(dstr) = NULL;
-               GvCVGEN(dstr) = 0; /* Switch off cacheness. */
-               PL_sub_generation++;
+           if (stype == SVt_PVCV) {
+               if (GvCVGEN(dstr) && GvCV(dstr) != (CV*)sref) {
+                   SvREFCNT_dec(GvCV(dstr));
+                   GvCV(dstr) = NULL;
+                   GvCVGEN(dstr) = 0; /* Switch off cacheness. */
+                   PL_sub_generation++;
+               }
            }
-           SAVEGENERICSV(GvCV(dstr));
+           SAVEGENERICSV(*location);
        }
        else
-           dref = (SV*)GvCV(dstr);
-       if (GvCV(dstr) != (CV*)sref) {
-           CV* const cv = GvCV(dstr);
+           dref = *location;
+       if (stype == SVt_PVCV && *location != sref) {
+           CV* const cv = (CV*)*location;
            if (cv) {
                if (!GvCVGEN((GV*)dstr) &&
                    (CvROOT(cv) || CvXSUB(cv)))
@@ -3137,6 +3283,7 @@ S_pvgv_assign(pTHX_ SV *dstr, SV *sstr) {
                           it was a const and its value changed. */
                        if (CvCONST(cv) && CvCONST((CV*)sref)
                            && cv_const_sv(cv) == cv_const_sv((CV*)sref)) {
+                           /*EMPTY*/
                            /* They are 2 constant subroutines generated from
                               the same constant. This probably means that
                               they are really the "same" proxy subroutine
@@ -3161,42 +3308,18 @@ S_pvgv_assign(pTHX_ SV *dstr, SV *sstr) {
                    cv_ckproto(cv, (GV*)dstr,
                               SvPOK(sref) ? SvPVX_const(sref) : NULL);
            }
-           GvCV(dstr) = (CV*)sref;
            GvCVGEN(dstr) = 0; /* Switch off cacheness. */
            GvASSUMECV_on(dstr);
            PL_sub_generation++;
        }
-       if (!GvIMPORTED_CV(dstr) && CopSTASH_ne(PL_curcop, GvSTASH(dstr))) {
-           GvIMPORTED_CV_on(dstr);
-       }
-       break;
-    case SVt_PVIO:
-       if (intro)
-           SAVEGENERICSV(GvIOp(dstr));
-       else
-           dref = (SV*)GvIOp(dstr);
-       GvIOp(dstr) = (IO*)sref;
-       break;
-    case SVt_PVFM:
-       if (intro)
-           SAVEGENERICSV(GvFORM(dstr));
-       else
-           dref = (SV*)GvFORM(dstr);
-       GvFORM(dstr) = (CV*)sref;
-       break;
-    default:
-       if (intro)
-           SAVEGENERICSV(GvSV(dstr));
-       else
-           dref = (SV*)GvSV(dstr);
-       GvSV(dstr) = sref;
-       if (!GvIMPORTED_SV(dstr) && CopSTASH_ne(PL_curcop, GvSTASH(dstr))) {
-           GvIMPORTED_SV_on(dstr);
+       *location = sref;
+       if (import_flag && !(GvFLAGS(dstr) & import_flag)
+           && CopSTASH_ne(PL_curcop, GvSTASH(dstr))) {
+           GvFLAGS(dstr) |= import_flag;
        }
        break;
     }
-    if (dref)
-       SvREFCNT_dec(dref);
+    SvREFCNT_dec(dref);
     if (SvTAINTED(sstr))
        SvTAINT(dstr);
     return;
@@ -3243,8 +3366,6 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
                sv_upgrade(dstr, SVt_IV);
                break;
            case SVt_NV:
-               sv_upgrade(dstr, SVt_PVNV);
-               break;
            case SVt_RV:
            case SVt_PV:
                sv_upgrade(dstr, SVt_PVIV);
@@ -3290,21 +3411,6 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
     case SVt_RV:
        if (dtype < SVt_RV)
            sv_upgrade(dstr, SVt_RV);
-       else if (dtype == SVt_PVGV &&
-                SvROK(sstr) && SvTYPE(SvRV(sstr)) == SVt_PVGV) {
-           sstr = SvRV(sstr);
-           if (sstr == dstr) {
-               if (GvIMPORTED(dstr) != GVf_IMPORTED
-                   && CopSTASH_ne(PL_curcop, GvSTASH(dstr)))
-               {
-                   GvIMPORTED_on(dstr);
-               }
-               GvMULTI_on(dstr);
-               return;
-           }
-           S_glob_assign(aTHX_ dstr, sstr, dtype);
-           return;
-       }
        break;
     case SVt_PVFM:
 #ifdef PERL_OLD_COPY_ON_WRITE
@@ -3327,10 +3433,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
        if (dtype < SVt_PVNV)
            sv_upgrade(dstr, SVt_PVNV);
        break;
-    case SVt_PVAV:
-    case SVt_PVHV:
-    case SVt_PVCV:
-    case SVt_PVIO:
+    default:
        {
        const char * const type = sv_reftype(sstr,0);
        if (PL_op)
@@ -3342,18 +3445,20 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
 
     case SVt_PVGV:
        if (dtype <= SVt_PVGV) {
-           S_glob_assign(aTHX_ dstr, sstr, dtype);
+           glob_assign_glob(dstr, sstr, dtype);
            return;
        }
-       /* FALL THROUGH */
+       /*FALLTHROUGH*/
 
-    default:
+    case SVt_PVMG:
+    case SVt_PVLV:
+    case SVt_PVBM:
        if (SvGMAGICAL(sstr) && (flags & SV_GMAGIC)) {
            mg_get(sstr);
            if ((int)SvTYPE(sstr) != stype) {
                stype = SvTYPE(sstr);
                if (stype == SVt_PVGV && dtype <= SVt_PVGV) {
-                   S_glob_assign(aTHX_ dstr, sstr, dtype);
+                   glob_assign_glob(dstr, sstr, dtype);
                    return;
                }
            }
@@ -3364,12 +3469,30 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
            SvUPGRADE(dstr, (U32)stype);
     }
 
+    /* dstr may have been upgraded.  */
+    dtype = SvTYPE(dstr);
     sflags = SvFLAGS(sstr);
 
     if (sflags & SVf_ROK) {
+       if (dtype == SVt_PVGV &&
+           SvROK(sstr) && SvTYPE(SvRV(sstr)) == SVt_PVGV) {
+           sstr = SvRV(sstr);
+           if (sstr == dstr) {
+               if (GvIMPORTED(dstr) != GVf_IMPORTED
+                   && CopSTASH_ne(PL_curcop, GvSTASH(dstr)))
+               {
+                   GvIMPORTED_on(dstr);
+               }
+               GvMULTI_on(dstr);
+               return;
+           }
+           glob_assign_glob(dstr, sstr, dtype);
+           return;
+       }
+
        if (dtype >= SVt_PV) {
            if (dtype == SVt_PVGV) {
-               S_pvgv_assign(aTHX_ dstr, sstr);
+               glob_assign_ref(dstr, sstr);
                return;
            }
            if (SvPVX_const(dstr)) {
@@ -3386,6 +3509,21 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
        assert(!(sflags & SVf_NOK));
        assert(!(sflags & SVf_IOK));
     }
+    else if (dtype == SVt_PVGV) {
+       if (!(sflags & SVf_OK)) {
+           if (ckWARN(WARN_MISC))
+               Perl_warner(aTHX_ packWARN(WARN_MISC),
+                           "Undefined value assigned to typeglob");
+       }
+       else {
+           GV *gv = gv_fetchsv(sstr, GV_ADD, SVt_PVGV);
+           if (dstr != (SV*)gv) {
+               if (GvGP(dstr))
+                   gp_free((GV*)dstr);
+               GvGP(dstr) = gp_ref(GvGP(gv));
+           }
+       }
+    }
     else if (sflags & SVp_POK) {
         bool isSwipe = 0;
 
@@ -3518,7 +3656,8 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
            if (sflags & SVf_IVisUV)
                SvIsUV_on(dstr);
        }
-       SvFLAGS(dstr) |= sflags & (SVf_IOK|SVp_IOK|SVf_NOK|SVp_NOK|SVf_UTF8);
+       SvFLAGS(dstr) |= sflags & (SVf_IOK|SVp_IOK|SVf_NOK|SVp_NOK|SVf_UTF8
+                                  |SVf_AMAGIC);
        {
            const MAGIC * const smg = SvVOK(sstr);
            if (smg) {
@@ -3530,20 +3669,28 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV *sstr, I32 flags)
     }
     else if (sflags & (SVp_IOK|SVp_NOK)) {
        (void)SvOK_off(dstr);
-       SvFLAGS(dstr) |= sflags & (SVf_IOK|SVp_IOK|SVf_IVisUV|SVf_NOK|SVp_NOK);
+       SvFLAGS(dstr) |= sflags & (SVf_IOK|SVp_IOK|SVf_IVisUV|SVf_NOK|SVp_NOK
+                                  |SVf_AMAGIC);
        if (sflags & SVp_IOK) {
            /* XXXX Do we want to set IsUV for IV(ROK)?  Be extra safe... */
            SvIV_set(dstr, SvIVX(sstr));
        }
        if (sflags & SVp_NOK) {
-           SvFLAGS(dstr) |= sflags & (SVf_NOK|SVp_NOK);
            SvNV_set(dstr, SvNVX(sstr));
        }
     }
     else {
-       if (dtype == SVt_PVGV) {
-           if (ckWARN(WARN_MISC))
-               Perl_warner(aTHX_ packWARN(WARN_MISC), "Undefined value assigned to typeglob");
+       if (isGV_with_GP(sstr)) {
+           /* This stringification rule for globs is spread in 3 places.
+              This feels bad. FIXME.  */
+           const U32 wasfake = sflags & SVf_FAKE;
+
+           /* FAKE globs can get coerced, so need to turn this off
+              temporarily if it is on.  */
+           SvFAKE_off(sstr);
+           gv_efullname3(dstr, (GV *)sstr, "*");
+           SvFLAGS(sstr) |= wasfake;
+           SvFLAGS(dstr) |= sflags & SVf_AMAGIC;
        }
        else
            (void)SvOK_off(dstr);
@@ -4183,7 +4330,7 @@ Perl_sv_magicext(pTHX_ SV* sv, SV* obj, int how, MGVTBL *vtable,
        mg->mg_obj = obj;
     }
     else {
-       mg->mg_obj = SvREFCNT_inc(obj);
+       mg->mg_obj = SvREFCNT_inc_simple(obj);
        mg->mg_flags |= MGf_REFCOUNTED;
     }
 
@@ -4207,7 +4354,7 @@ Perl_sv_magicext(pTHX_ SV* sv, SV* obj, int how, MGVTBL *vtable,
        if (namlen > 0)
            mg->mg_ptr = savepvn(name, namlen);
        else if (namlen == HEf_SVKEY)
-           mg->mg_ptr = (char*)SvREFCNT_inc((SV*)name);
+           mg->mg_ptr = (char*)SvREFCNT_inc_simple_NN((SV*)name);
        else
            mg->mg_ptr = (char *) name;
     }
@@ -4267,8 +4414,13 @@ Perl_sv_magic(pTHX_ register SV *sv, SV *obj, int how, const char *name, I32 nam
            /* sv_magic() refuses to add a magic of the same 'how' as an
               existing one
             */
-           if (how == PERL_MAGIC_taint)
+           if (how == PERL_MAGIC_taint) {
                mg->mg_len |= 1;
+               /* Any scalar which already had taint magic on which someone
+                  (erroneously?) did SvIOK_on() or similar will now be
+                  incorrectly sporting public "OK" flags.  */
+               SvFLAGS(sv) &= ~(SVf_IOK|SVf_NOK|SVf_POK);
+           }
            return;
        }
     }
@@ -4337,6 +4489,8 @@ Perl_sv_magic(pTHX_ register SV *sv, SV *obj, int how, const char *name, I32 nam
     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;
@@ -4367,9 +4521,6 @@ Perl_sv_magic(pTHX_ register SV *sv, SV *obj, int how, const char *name, I32 nam
     case PERL_MAGIC_defelem:
        vtable = &PL_vtbl_defelem;
        break;
-    case PERL_MAGIC_glob:
-       vtable = &PL_vtbl_glob;
-       break;
     case PERL_MAGIC_arylen:
        vtable = &PL_vtbl_arylen;
        break;
@@ -4379,6 +4530,9 @@ Perl_sv_magic(pTHX_ register SV *sv, SV *obj, int how, const char *name, I32 nam
     case PERL_MAGIC_backref:
        vtable = &PL_vtbl_backref;
        break;
+    case PERL_MAGIC_hintselem:
+       vtable = &PL_vtbl_hintselem;
+       break;
     case PERL_MAGIC_ext:
        /* Reserved for use by extensions not perl internals.           */
        /* Useful for attaching extension internal data to perl vars.   */
@@ -4419,7 +4573,7 @@ Perl_sv_unmagic(pTHX_ SV *sv, int type)
     MAGIC** mgp;
     if (SvTYPE(sv) < SVt_PVMG || !SvMAGIC(sv))
        return 0;
-    mgp = &SvMAGIC(sv);
+    mgp = &(((XPVMG*) SvANY(sv))->xmg_u.xmg_magic);
     for (mg = *mgp; mg; mg = *mgp) {
        if (mg->mg_type == type) {
             const MGVTBL* const vtbl = mg->mg_virtual;
@@ -4431,7 +4585,7 @@ Perl_sv_unmagic(pTHX_ SV *sv, int type)
                    Safefree(mg->mg_ptr);
                else if (mg->mg_len == HEf_SVKEY)
                    SvREFCNT_dec((SV*)mg->mg_ptr);
-               else if (mg->mg_type == PERL_MAGIC_utf8 && mg->mg_ptr)
+               else if (mg->mg_type == PERL_MAGIC_utf8)
                    Safefree(mg->mg_ptr);
             }
            if (mg->mg_flags & MGf_REFCOUNTED)
@@ -4443,7 +4597,7 @@ Perl_sv_unmagic(pTHX_ SV *sv, int type)
     }
     if (!SvMAGIC(sv)) {
        SvMAGICAL_off(sv);
-       SvFLAGS(sv) |= (SvFLAGS(sv) & (SVp_NOK|SVp_POK)) >> PRIVSHIFT;
+       SvFLAGS(sv) |= (SvFLAGS(sv) & (SVp_IOK|SVp_NOK|SVp_POK)) >> PRIVSHIFT;
        SvMAGIC_set(sv, NULL);
     }
 
@@ -4511,7 +4665,7 @@ Perl_sv_add_backref(pTHX_ SV *tsv, SV *sv)
            } else {
                av = newAV();
                AvREAL_off(av);
-               SvREFCNT_inc(av);
+               SvREFCNT_inc_simple_void(av);
            }
            *avp = av;
        }
@@ -4831,8 +4985,12 @@ Perl_sv_clear(pTHX_ register SV *sv)
     assert(sv);
     assert(SvREFCNT(sv) == 0);
 
-    if (type <= SVt_IV)
+    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.  */
        return;
+    }
 
     if (SvOBJECT(sv)) {
        if (PL_defstash) {              /* Still have a symbol table? */
@@ -4885,9 +5043,13 @@ Perl_sv_clear(pTHX_ register SV *sv)
        }
     }
     if (type >= SVt_PVMG) {
-       if (SvMAGIC(sv))
+       HV *ourstash;
+       if ((type == SVt_PVMG || type == SVt_PVGV) &&
+           (ourstash = OURSTASH(sv))) {
+           SvREFCNT_dec(ourstash);
+       } else if (SvMAGIC(sv))
            mg_free(sv);
-       if (type == SVt_PVMG && SvFLAGS(sv) & SVpad_TYPED)
+       if (type == SVt_PVMG && SvPAD_TYPED(sv))
            SvREFCNT_dec(SvSTASH(sv));
     }
     switch (type) {
@@ -4930,7 +5092,9 @@ Perl_sv_clear(pTHX_ register SV *sv)
        goto freescalar;
     case SVt_PVGV:
        gp_free((GV*)sv);
-       Safefree(GvNAME(sv));
+       if (GvNAME_HEK(sv)) {
+           unshare_hek(GvNAME_HEK(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 (GvSTASH(sv))
@@ -4947,7 +5111,7 @@ Perl_sv_clear(pTHX_ register SV *sv)
     case SVt_PV:
     case SVt_RV:
        if (SvROK(sv)) {
-           SV *target = SvRV(sv);
+           SV * const target = SvRV(sv);
            if (SvWEAKREF(sv))
                sv_del_backref(target, sv);
            else
@@ -4990,7 +5154,7 @@ Perl_sv_clear(pTHX_ register SV *sv)
        del_body(((char *)SvANY(sv) + sv_type_details->offset),
                 &PL_body_roots[type]);
     }
-    else if (sv_type_details->size) {
+    else if (sv_type_details->body_size) {
        my_safefree(SvANY(sv));
     }
 }
@@ -5007,6 +5171,7 @@ instead.
 SV *
 Perl_sv_newref(pTHX_ SV *sv)
 {
+    PERL_UNUSED_CONTEXT;
     if (sv)
        (SvREFCNT(sv))++;
     return sv;
@@ -5114,8 +5279,10 @@ 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
- * mg_ptr is used, by sv_pos_u2b(), see the comments of S_utf8_mg_pos_init().
- * (Note that the mg_len is not the length of the mg_ptr field.)
+ * 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
+ * needing to malloc() extra storage to attach to the mg_ptr.)
  *
  */
 
@@ -5129,185 +5296,196 @@ Perl_sv_len_utf8(pTHX_ register SV *sv)
        return mg_length(sv);
     else
     {
-       STRLEN len, ulen;
+       STRLEN len;
        const U8 *s = (U8*)SvPV_const(sv, len);
-       MAGIC *mg = SvMAGICAL(sv) ? mg_find(sv, PERL_MAGIC_utf8) : 0;
 
-       if (mg && mg->mg_len != -1 && (mg->mg_len > 0 || len == 0)) {
-           ulen = mg->mg_len;
-#ifdef PERL_UTF8_CACHE_ASSERT
-           assert(ulen == Perl_utf8_length(aTHX_ s, s + len));
-#endif
-       }
-       else {
-           ulen = Perl_utf8_length(aTHX_ s, s + len);
-           if (!mg && !SvREADONLY(sv)) {
-               sv_magic(sv, 0, PERL_MAGIC_utf8, 0, 0);
-               mg = mg_find(sv, PERL_MAGIC_utf8);
-               assert(mg);
+       if (PL_utf8cache) {
+           STRLEN ulen;
+           MAGIC *mg = SvMAGICAL(sv) ? mg_find(sv, PERL_MAGIC_utf8) : 0;
+
+           if (mg && mg->mg_len != -1) {
+               ulen = mg->mg_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 %"UVf
+                                  " real %"UVf" for %"SVf,
+                                  (UV) ulen, (UV) real, sv);
+                   }
+               }
            }
-           if (mg)
-               mg->mg_len = ulen;
+           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;
+               }
+           }
+           return ulen;
        }
-       return ulen;
+       return Perl_utf8_length(aTHX_ s, s + len);
     }
 }
 
-/* S_utf8_mg_pos_init() is used to initialize the mg_ptr field of
- * a PERL_UTF8_magic.  The mg_ptr is used to store the mapping
- * between UTF-8 and byte offsets.  There are two (substr offset and substr
- * length, the i offset, PERL_MAGIC_UTF8_CACHESIZE) times two (UTF-8 offset
- * and byte offset) cache positions.
- *
- * The mg_len field is used by sv_len_utf8(), see its comments.
- * Note that the mg_len is not the length of the mg_ptr field.
- *
- */
-STATIC bool
-S_utf8_mg_pos_init(pTHX_ SV *sv, MAGIC **mgp, STRLEN **cachep, I32 i,
-                  I32 offsetp, const U8 *s, const U8 *start)
+/* Walk forwards to find the byte corresponding to the passed in UTF-8
+   offset.  */
+static STRLEN
+S_sv_pos_u2b_forwards(pTHX_ const U8 *const start, const U8 *const send,
+                     STRLEN uoffset)
 {
-    bool found = FALSE;
+    const U8 *s = start;
 
-    if (SvMAGICAL(sv) && !SvREADONLY(sv)) {
-       if (!*mgp)
-           *mgp = sv_magicext(sv, 0, PERL_MAGIC_utf8, (MGVTBL*)&PL_vtbl_utf8, 0, 0);
-       assert(*mgp);
+    PERL_UNUSED_CONTEXT;
 
-       if ((*mgp)->mg_ptr)
-           *cachep = (STRLEN *) (*mgp)->mg_ptr;
-       else {
-           Newxz(*cachep, PERL_MAGIC_UTF8_CACHESIZE * 2, STRLEN);
-           (*mgp)->mg_ptr = (char *) *cachep;
-       }
-       assert(*cachep);
+    while (s < send && uoffset--)
+       s += UTF8SKIP(s);
+    if (s > send) {
+       /* This is the existing behaviour. Possibly it should be a croak, as
+          it's actually a bounds error  */
+       s = send;
+    }
+    return s - start;
+}
 
-       (*cachep)[i]   = offsetp;
-       (*cachep)[i+1] = s - start;
-       found = TRUE;
+/* Given the length of the string in both bytes and UTF-8 characters, decide
+   whether to walk forwards or backwards to find the byte corresponding to
+   the passed in UTF-8 offset.  */
+static STRLEN
+S_sv_pos_u2b_midway(pTHX_ const U8 *const start, const U8 *send,
+                     STRLEN uoffset, STRLEN uend)
+{
+    STRLEN backw = uend - uoffset;
+    if (uoffset < 2 * backw) {
+       /* The assumption is that going forwards is twice the speed of going
+          forward (that's where the 2 * backw comes from).
+          (The real figure of course depends on the UTF-8 data.)  */
+       return S_sv_pos_u2b_forwards(aTHX_ start, send, uoffset);
     }
 
-    return found;
+    while (backw--) {
+       send--;
+       while (UTF8_IS_CONTINUATION(*send))
+           send--;
+    }
+    return send - start;
 }
 
-/*
- * S_utf8_mg_pos() is used to query and update mg_ptr field of
- * a PERL_UTF8_magic.  The mg_ptr is used to store the mapping
- * between UTF-8 and byte offsets.  See also the comments of
- * S_utf8_mg_pos_init().
- *
- */
-STATIC bool
-S_utf8_mg_pos(pTHX_ SV *sv, MAGIC **mgp, STRLEN **cachep, I32 i, I32 *offsetp, I32 uoff, const U8 **sp, const U8 *start, const U8 *send)
-{
+/* For the string representation of the given scalar, find the byte
+   corresponding to the passed in UTF-8 offset.  uoffset0 and boffset0
+   give another position in the string, *before* the sought offset, which
+   (which is always true, as 0, 0 is a valid pair of positions), which should
+   help reduce the amount of linear searching.
+   If *mgp is non-NULL, it should point to the UTF-8 cache magic, which
+   will be used to reduce the amount of linear searching. The cache will be
+   created if necessary, and the found value offered to it for update.  */
+static STRLEN
+S_sv_pos_u2b_cached(pTHX_ SV *sv, MAGIC **mgp, const U8 *const start,
+                   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;
 
-    if (SvMAGICAL(sv) && !SvREADONLY(sv)) {
-       if (!*mgp)
-           *mgp = mg_find(sv, PERL_MAGIC_utf8);
-       if (*mgp && (*mgp)->mg_ptr) {
-           *cachep = (STRLEN *) (*mgp)->mg_ptr;
-           ASSERT_UTF8_CACHE(*cachep);
-           if ((*cachep)[i] == (STRLEN)uoff)   /* An exact match. */
-                 found = TRUE;
-           else {                      /* We will skip to the right spot. */
-                STRLEN forw  = 0;
-                STRLEN backw = 0;
-                const U8* p = NULL;
-
-                /* The assumption is that going backward is half
-                 * the speed of going forward (that's where the
-                 * 2 * backw in the below comes from).  (The real
-                 * figure of course depends on the UTF-8 data.) */
-
-                if ((*cachep)[i] > (STRLEN)uoff) {
-                     forw  = uoff;
-                     backw = (*cachep)[i] - (STRLEN)uoff;
-
-                     if (forw < 2 * backw)
-                          p = start;
-                     else
-                          p = start + (*cachep)[i+1];
-                }
-                /* Try this only for the substr offset (i == 0),
-                 * not for the substr length (i == 2). */
-                else if (i == 0) { /* (*cachep)[i] < uoff */
-                     const STRLEN ulen = sv_len_utf8(sv);
-
-                     if ((STRLEN)uoff < ulen) {
-                          forw  = (STRLEN)uoff - (*cachep)[i];
-                          backw = ulen - (STRLEN)uoff;
-
-                          if (forw < 2 * backw)
-                               p = start + (*cachep)[i+1];
-                          else
-                               p = send;
-                     }
-
-                     /* If the string is not long enough for uoff,
-                      * we could extend it, but not at this low a level. */
-                }
-
-                if (p) {
-                     if (forw < 2 * backw) {
-                          while (forw--)
-                               p += UTF8SKIP(p);
-                     }
-                     else {
-                          while (backw--) {
-                               p--;
-                               while (UTF8_IS_CONTINUATION(*p))
-                                    p--;
-                          }
-                     }
-
-                     /* Update the cache. */
-                     (*cachep)[i]   = (STRLEN)uoff;
-                     (*cachep)[i+1] = p - start;
-
-                     /* Drop the stale "length" cache */
-                     if (i == 0) {
-                         (*cachep)[2] = 0;
-                         (*cachep)[3] = 0;
-                     }
-
-                     found = TRUE;
-                }
-           }
-           if (found) {        /* Setup the return values. */
-                *offsetp = (*cachep)[i+1];
-                *sp = start + *offsetp;
-                if (*sp >= send) {
-                     *sp = send;
-                     *offsetp = send - start;
-                }
-                else if (*sp < start) {
-                     *sp = start;
-                     *offsetp = 0;
-                }
+    assert (uoffset >= uoffset0);
+
+    if (SvMAGICAL(sv) && !SvREADONLY(sv) && PL_utf8cache
+       && (*mgp || (*mgp = mg_find(sv, PERL_MAGIC_utf8)))) {
+       if ((*mgp)->mg_ptr) {
+           STRLEN *cache = (STRLEN *) (*mgp)->mg_ptr;
+           if (cache[0] == uoffset) {
+               /* An exact match. */
+               return cache[1];
+           }
+           if (cache[2] == uoffset) {
+               /* An exact match. */
+               return cache[3];
+           }
+
+           if (cache[0] < uoffset) {
+               /* The cache already knows part of the way.   */
+               if (cache[0] > uoffset0) {
+                   /* The cache knows more than the passed in pair  */
+                   uoffset0 = cache[0];
+                   boffset0 = cache[1];
+               }
+               if ((*mgp)->mg_len != -1) {
+                   /* And we know the end too.  */
+                   boffset = boffset0
+                       + S_sv_pos_u2b_midway(aTHX_ start + boffset0, send,
+                                             uoffset - uoffset0,
+                                             (*mgp)->mg_len - uoffset0);
+               } else {
+                   boffset = boffset0
+                       + S_sv_pos_u2b_forwards(aTHX_ start + boffset0,
+                                               send, uoffset - uoffset0);
+               }
+           }
+           else if (cache[2] < uoffset) {
+               /* We're between the two cache entries.  */
+               if (cache[2] > uoffset0) {
+                   /* and the cache knows more than the passed in pair  */
+                   uoffset0 = cache[2];
+                   boffset0 = cache[3];
+               }
+
+               boffset = boffset0
+                   + S_sv_pos_u2b_midway(aTHX_ start + boffset0,
+                                         start + cache[1],
+                                         uoffset - uoffset0,
+                                         cache[0] - uoffset0);
+           } else {
+               boffset = boffset0
+                   + S_sv_pos_u2b_midway(aTHX_ start + boffset0,
+                                         start + cache[3],
+                                         uoffset - uoffset0,
+                                         cache[2] - uoffset0);
            }
+           found = TRUE;
        }
-#ifdef PERL_UTF8_CACHE_ASSERT
-       if (found) {
-            U8 *s = start;
-            I32 n = uoff;
+       else if ((*mgp)->mg_len != -1) {
+           /* If we can take advantage of a passed in offset, do so.  */
+           /* In fact, offset0 is either 0, or less than offset, so don't
+              need to worry about the other possibility.  */
+           boffset = boffset0
+               + S_sv_pos_u2b_midway(aTHX_ start + boffset0, send,
+                                     uoffset - uoffset0,
+                                     (*mgp)->mg_len - uoffset0);
+           found = TRUE;
+       }
+    }
 
-            while (n-- && s < send)
-                 s += UTF8SKIP(s);
+    if (!found || PL_utf8cache < 0) {
+       const STRLEN real_boffset
+           = boffset0 + S_sv_pos_u2b_forwards(aTHX_ start + boffset0,
+                                              send, uoffset - uoffset0);
 
-            if (i == 0) {
-                 assert(*offsetp == s - start);
-                 assert((*cachep)[0] == (STRLEN)uoff);
-                 assert((*cachep)[1] == *offsetp);
-            }
-            ASSERT_UTF8_CACHE(*cachep);
+       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 %"UVf
+                          " real %"UVf" for %"SVf,
+                          (UV) boffset, (UV) real_boffset, sv);
+           }
        }
-#endif
+       boffset = real_boffset;
     }
 
-    return found;
+    S_utf8_mg_pos_cache_update(aTHX_ sv, mgp, boffset, uoffset, send - start);
+    return boffset;
 }
 
+
 /*
 =for apidoc sv_pos_u2b
 
@@ -5323,7 +5501,7 @@ type coercion.
 /*
  * 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
- * byte offsets.  See also the comments of S_utf8_mg_pos().
+ * byte offsets.  See also the comments of S_utf8_mg_pos_cache_update().
  *
  */
 
@@ -5338,42 +5516,23 @@ Perl_sv_pos_u2b(pTHX_ register SV *sv, I32* offsetp, I32* lenp)
 
     start = (U8*)SvPV_const(sv, len);
     if (len) {
-       STRLEN boffset = 0;
-       STRLEN *cache = NULL;
-       const U8 *s = start;
-       I32 uoffset = *offsetp;
-       const U8 * const send = s + len;
+       STRLEN uoffset = (STRLEN) *offsetp;
+       const U8 * const send = start + len;
        MAGIC *mg = NULL;
-       bool found = utf8_mg_pos(sv, &mg, &cache, 0, offsetp, *offsetp, &s, start, send);
-
-        if (!found && uoffset > 0) {
-             while (s < send && uoffset--)
-                  s += UTF8SKIP(s);
-             if (s >= send)
-                  s = send;
-              if (utf8_mg_pos_init(sv, &mg, &cache, 0, *offsetp, s, start))
-                  boffset = cache[1];
-             *offsetp = s - start;
-        }
-        if (lenp) {
-             found = FALSE;
-             start = s;
-              if (utf8_mg_pos(sv, &mg, &cache, 2, lenp, *lenp, &s, start, send)) {
-                  *lenp -= boffset;
-                  found = TRUE;
-              }
-             if (!found && *lenp > 0) {
-                  I32 ulen = *lenp;
-                  if (ulen > 0)
-                       while (s < send && ulen--)
-                            s += UTF8SKIP(s);
-                  if (s >= send)
-                       s = send;
-                   utf8_mg_pos_init(sv, &mg, &cache, 2, *lenp, s, start);
-             }
-             *lenp = s - start;
-        }
-        ASSERT_UTF8_CACHE(cache);
+       STRLEN boffset = S_sv_pos_u2b_cached(aTHX_ sv, &mg, start, send,
+                                            uoffset, 0, 0);
+
+       *offsetp = (I32) boffset;
+
+       if (lenp) {
+           /* Convert the relative offset to absolute.  */
+           STRLEN uoffset2 = uoffset + (STRLEN) *lenp;
+           STRLEN boffset2
+               = S_sv_pos_u2b_cached(aTHX_ sv, &mg, start, send, uoffset2,
+                                     uoffset, boffset) - boffset;
+
+           *lenp = boffset2;
+       }
     }
     else {
         *offsetp = 0;
@@ -5384,6 +5543,221 @@ Perl_sv_pos_u2b(pTHX_ register SV *sv, I32* offsetp, I32* lenp)
     return;
 }
 
+/* Create and update the UTF8 magic offset cache, with the proffered utf8/
+   byte length pairing. The (byte) length of the total SV is passed in too,
+   as blen, because for some (more esoteric) SVs, the call to SvPV_const()
+   may not have updated SvCUR, so we can't rely on reading it directly.
+
+   The proffered utf8/byte length pairing isn't used if the cache already has
+   two pairs, and swapping either for the proffered pair would increase the
+   RMS of the intervals between known byte offsets.
+
+   The cache itself consists of 4 STRLEN values
+   0: larger UTF-8 offset
+   1: corresponding byte offset
+   2: smaller UTF-8 offset
+   3: corresponding byte offset
+
+   Unused cache pairs have the value 0, 0.
+   Keeping the cache "backwards" means that the invariant of
+   cache[0] >= cache[2] is maintained even with empty slots, which means that
+   the code that uses it doesn't need to worry if only 1 entry has actually
+   been set to non-zero.  It also makes the "position beyond the end of the
+   cache" logic much simpler, as the first slot is always the one to start
+   from.   
+*/
+static void
+S_utf8_mg_pos_cache_update(pTHX_ SV *sv, MAGIC **mgp, STRLEN byte, STRLEN utf8,
+                          STRLEN blen)
+{
+    STRLEN *cache;
+    if (SvREADONLY(sv))
+       return;
+
+    if (!*mgp) {
+       *mgp = sv_magicext(sv, 0, PERL_MAGIC_utf8, (MGVTBL*)&PL_vtbl_utf8, 0,
+                          0);
+       (*mgp)->mg_len = -1;
+    }
+    assert(*mgp);
+
+    if (!(cache = (STRLEN *)(*mgp)->mg_ptr)) {
+       Newxz(cache, PERL_MAGIC_UTF8_CACHESIZE * 2, STRLEN);
+       (*mgp)->mg_ptr = (char *) cache;
+    }
+    assert(cache);
+
+    if (PL_utf8cache < 0) {
+       const U8 *start = (const U8 *) SvPVX_const(sv);
+       const U8 *const end = start + byte;
+       STRLEN realutf8 = 0;
+
+       while (start < end) {
+           start += UTF8SKIP(start);
+           realutf8++;
+       }
+
+       /* Can't use S_sv_pos_b2u_forwards as it will scream warnings on
+          surrogates.  FIXME - is it inconsistent that b2u warns, but u2b
+          doesn't?  I don't know whether this difference was introduced with
+          the caching code in 5.8.1.  */
+
+       if (realutf8 != utf8) {
+           /* Need to turn the assertions off otherwise we may recurse
+              infinitely while printing error messages.  */
+           SAVEI8(PL_utf8cache);
+           PL_utf8cache = 0;
+           Perl_croak(aTHX_ "panic: utf8_mg_pos_cache_update cache %"UVf
+                      " real %"UVf" for %"SVf, (UV) utf8, (UV) realutf8, sv);
+       }
+    }
+
+    /* Cache is held with the later position first, to simplify the code
+       that deals with unbounded ends.  */
+       
+    ASSERT_UTF8_CACHE(cache);
+    if (cache[1] == 0) {
+       /* Cache is totally empty  */
+       cache[0] = utf8;
+       cache[1] = byte;
+    } else if (cache[3] == 0) {
+       if (byte > cache[1]) {
+           /* New one is larger, so goes first.  */
+           cache[2] = cache[0];
+           cache[3] = cache[1];
+           cache[0] = utf8;
+           cache[1] = byte;
+       } else {
+           cache[2] = utf8;
+           cache[3] = byte;
+       }
+    } else {
+#define THREEWAY_SQUARE(a,b,c,d) \
+           ((float)((d) - (c))) * ((float)((d) - (c))) \
+           + ((float)((c) - (b))) * ((float)((c) - (b))) \
+              + ((float)((b) - (a))) * ((float)((b) - (a)))
+
+       /* Cache has 2 slots in use, and we know three potential pairs.
+          Keep the two that give the lowest RMS distance. Do the
+          calcualation in bytes simply because we always know the byte
+          length.  squareroot has the same ordering as the positive value,
+          so don't bother with the actual square root.  */
+       const float existing = THREEWAY_SQUARE(0, cache[3], cache[1], blen);
+       if (byte > cache[1]) {
+           /* New position is after the existing pair of pairs.  */
+           const float keep_earlier
+               = THREEWAY_SQUARE(0, cache[3], byte, blen);
+           const float keep_later
+               = THREEWAY_SQUARE(0, cache[1], byte, blen);
+
+           if (keep_later < keep_earlier) {
+               if (keep_later < existing) {
+                   cache[2] = cache[0];
+                   cache[3] = cache[1];
+                   cache[0] = utf8;
+                   cache[1] = byte;
+               }
+           }
+           else {
+               if (keep_earlier < existing) {
+                   cache[0] = utf8;
+                   cache[1] = byte;
+               }
+           }
+       }
+       else if (byte > cache[3]) {
+           /* New position is between the existing pair of pairs.  */
+           const float keep_earlier
+               = THREEWAY_SQUARE(0, cache[3], byte, blen);
+           const float keep_later
+               = THREEWAY_SQUARE(0, byte, cache[1], blen);
+
+           if (keep_later < keep_earlier) {
+               if (keep_later < existing) {
+                   cache[2] = utf8;
+                   cache[3] = byte;
+               }
+           }
+           else {
+               if (keep_earlier < existing) {
+                   cache[0] = utf8;
+                   cache[1] = byte;
+               }
+           }
+       }
+       else {
+           /* New position is before the existing pair of pairs.  */
+           const float keep_earlier
+               = THREEWAY_SQUARE(0, byte, cache[3], blen);
+           const float keep_later
+               = THREEWAY_SQUARE(0, byte, cache[1], blen);
+
+           if (keep_later < keep_earlier) {
+               if (keep_later < existing) {
+                   cache[2] = utf8;
+                   cache[3] = byte;
+               }
+           }
+           else {
+               if (keep_earlier < existing) {
+                   cache[0] = cache[2];
+                   cache[1] = cache[3];
+                   cache[2] = utf8;
+                   cache[3] = byte;
+               }
+           }
+       }
+    }
+    ASSERT_UTF8_CACHE(cache);
+}
+
+/* If we don't know the character offset of the end of a region, our only
+   option is to walk forwards to the target byte offset.  */
+static STRLEN
+S_sv_pos_b2u_forwards(pTHX_ const U8 *s, const U8 *const target)
+{
+    STRLEN len = 0;
+    while (s < target) {
+       STRLEN n = 1;
+
+       /* Call utf8n_to_uvchr() to validate the sequence
+        * (unless a simple non-UTF character) */
+       if (!UTF8_IS_INVARIANT(*s))
+           utf8n_to_uvchr(s, UTF8SKIP(s), &n, 0);
+       if (n > 0) {
+           s += n;
+           len++;
+       }
+       else
+           break;
+    }
+    return len;
+}
+
+/* We already know all of the way, now we may be able to walk back.  The same
+   assumption is made as in S_sv_pos_u2b_midway(), namely that walking
+   backward is half the speed of walking forward. */
+static STRLEN
+S_sv_pos_b2u_midway(pTHX_ const U8 *s, const U8 *const target, const U8 *end,
+                   STRLEN endu)
+{
+    const STRLEN forw = target - s;
+    STRLEN backw = end - target;
+
+    if (forw < 2 * backw) {
+       return S_sv_pos_b2u_forwards(aTHX_ s, target);
+    }
+
+    while (end > target) {
+       end--;
+       while (UTF8_IS_CONTINUATION(*end)) {
+           end--;
+       }
+       endu--;
+    }
+    return endu;
+}
+
 /*
 =for apidoc sv_pos_b2u
 
@@ -5397,121 +5771,98 @@ 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
- * byte offsets.  See also the comments of S_utf8_mg_pos().
+ * byte offsets.
  *
  */
-
 void
 Perl_sv_pos_b2u(pTHX_ register SV* sv, I32* offsetp)
 {
     const U8* s;
-    STRLEN len;
+    const STRLEN byte = *offsetp;
+    STRLEN len = 0; /* Actually always set, but let's keep gcc happy.  */
+    STRLEN blen;
+    MAGIC* mg = NULL;
+    const U8* send;
+    bool found = FALSE;
 
     if (!sv)
        return;
 
-    s = (const U8*)SvPV_const(sv, len);
-    if ((I32)len < *offsetp)
-       Perl_croak(aTHX_ "panic: sv_pos_b2u: bad byte offset");
-    else {
-       const U8* send = s + *offsetp;
-       MAGIC* mg = NULL;
-       STRLEN *cache = NULL;
-
-       len = 0;
-
-       if (SvMAGICAL(sv) && !SvREADONLY(sv)) {
-           mg = mg_find(sv, PERL_MAGIC_utf8);
-           if (mg && mg->mg_ptr) {
-               cache = (STRLEN *) mg->mg_ptr;
-               if (cache[1] == (STRLEN)*offsetp) {
-                    /* An exact match. */
-                    *offsetp = cache[0];
+    s = (const U8*)SvPV_const(sv, blen);
 
-                   return;
-               }
-               else if (cache[1] < (STRLEN)*offsetp) {
-                   /* We already know part of the way. */
-                   len = cache[0];
-                   s  += cache[1];
-                   /* Let the below loop do the rest. */
-               }
-               else { /* cache[1] > *offsetp */
-                   /* We already know all of the way, now we may
-                    * be able to walk back.  The same assumption
-                    * is made as in S_utf8_mg_pos(), namely that
-                    * walking backward is twice slower than
-                    * walking forward. */
-                   const STRLEN forw  = *offsetp;
-                   STRLEN backw = cache[1] - *offsetp;
-
-                   if (!(forw < 2 * backw)) {
-                       const U8 *p = s + cache[1];
-                       STRLEN ubackw = 0;
-                       
-                       cache[1] -= backw;
-
-                       while (backw--) {
-                           p--;
-                           while (UTF8_IS_CONTINUATION(*p)) {
-                               p--;
-                               backw--;
-                           }
-                           ubackw++;
-                       }
+    if (blen < byte)
+       Perl_croak(aTHX_ "panic: sv_pos_b2u: bad byte offset");
 
-                       cache[0] -= ubackw;
-                       *offsetp = cache[0];
+    send = s + byte;
 
-                       /* Drop the stale "length" cache */
-                       cache[2] = 0;
-                       cache[3] = 0;
+    if (SvMAGICAL(sv) && !SvREADONLY(sv) && PL_utf8cache
+       && (mg = mg_find(sv, PERL_MAGIC_utf8))) {
+       if (mg->mg_ptr) {
+           STRLEN * const cache = (STRLEN *) mg->mg_ptr;
+           if (cache[1] == byte) {
+               /* An exact match. */
+               *offsetp = cache[0];
+               return;
+           }
+           if (cache[3] == byte) {
+               /* An exact match. */
+               *offsetp = cache[2];
+               return;
+           }
 
-                       return;
-                   }
+           if (cache[1] < byte) {
+               /* We already know part of the way. */
+               if (mg->mg_len != -1) {
+                   /* Actually, we know the end too.  */
+                   len = cache[0]
+                       + S_sv_pos_b2u_midway(aTHX_ s + cache[1], send,
+                                             s + blen, mg->mg_len - cache[0]);
+               } else {
+                   len = cache[0]
+                       + S_sv_pos_b2u_forwards(aTHX_ s + cache[1], send);
                }
            }
-           ASSERT_UTF8_CACHE(cache);
-       }
+           else if (cache[3] < byte) {
+               /* We're between the two cached pairs, so we do the calculation
+                  offset by the byte/utf-8 positions for the earlier pair,
+                  then add the utf-8 characters from the string start to
+                  there.  */
+               len = S_sv_pos_b2u_midway(aTHX_ s + cache[3], send,
+                                         s + cache[1], cache[0] - cache[2])
+                   + cache[2];
 
-       while (s < send) {
-           STRLEN n = 1;
-
-           /* Call utf8n_to_uvchr() to validate the sequence
-            * (unless a simple non-UTF character) */
-           if (!UTF8_IS_INVARIANT(*s))
-               utf8n_to_uvchr(s, UTF8SKIP(s), &n, 0);
-           if (n > 0) {
-               s += n;
-               len++;
            }
-           else
-               break;
-       }
+           else { /* cache[3] > byte */
+               len = S_sv_pos_b2u_midway(aTHX_ s, send, s + cache[3],
+                                         cache[2]);
 
-       if (!SvREADONLY(sv)) {
-           if (!mg) {
-               sv_magic(sv, 0, PERL_MAGIC_utf8, 0, 0);
-               mg = mg_find(sv, PERL_MAGIC_utf8);
            }
-           assert(mg);
+           ASSERT_UTF8_CACHE(cache);
+           found = TRUE;
+       } else if (mg->mg_len != -1) {
+           len = S_sv_pos_b2u_midway(aTHX_ s, send, s + blen, mg->mg_len);
+           found = TRUE;
+       }
+    }
+    if (!found || PL_utf8cache < 0) {
+       const STRLEN real_len = S_sv_pos_b2u_forwards(aTHX_ s, send);
 
-           if (!mg->mg_ptr) {
-               Newxz(cache, PERL_MAGIC_UTF8_CACHESIZE * 2, STRLEN);
-               mg->mg_ptr = (char *) cache;
+       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 %"UVf
+                          " real %"UVf" for %"SVf,
+                          (UV) len, (UV) real_len, sv);
            }
-           assert(cache);
-
-           cache[0] = len;
-           cache[1] = *offsetp;
-           /* Drop the stale "length" cache */
-           cache[2] = 0;
-           cache[3] = 0;
        }
-
-       *offsetp = len;
+       len = real_len;
     }
-    return;
+    *offsetp = len;
+
+    S_utf8_mg_pos_cache_update(aTHX_ sv, &mg, byte, len, blen);
 }
 
 /*
@@ -5600,9 +5951,7 @@ Perl_sv_eq(pTHX_ register SV *sv1, register SV *sv2)
     if (cur1 == cur2)
        eq = (pv1 == pv2) || memEQ(pv1, pv2, cur1);
        
-    if (svrecode)
-        SvREFCNT_dec(svrecode);
-
+    SvREFCNT_dec(svrecode);
     if (tpv)
        Safefree(tpv);
 
@@ -5685,9 +6034,7 @@ Perl_sv_cmp(pTHX_ register SV *sv1, register SV *sv2)
        }
     }
 
-    if (svrecode)
-        SvREFCNT_dec(svrecode);
-
+    SvREFCNT_dec(svrecode);
     if (tpv)
        Safefree(tpv);
 
@@ -5746,7 +6093,7 @@ Perl_sv_cmp_locale(pTHX_ register SV *sv1, register SV *sv2)
      */
 
   raw_compare:
-    /* FALL THROUGH */
+    /*FALLTHROUGH*/
 
 #endif /* USE_LOCALE_COLLATE */
 
@@ -5791,8 +6138,12 @@ Perl_sv_collxfrm(pTHX_ SV *sv, STRLEN *nxp)
                return xf + sizeof(PL_collation_ix);
            }
            if (! mg) {
-               sv_magic(sv, 0, PERL_MAGIC_collxfrm, 0, 0);
-               mg = mg_find(sv, PERL_MAGIC_collxfrm);
+#ifdef PERL_OLD_COPY_ON_WRITE
+               if (SvIsCOW(sv))
+                   sv_force_normal_flags(sv, 0);
+#endif
+               mg = sv_magicext(sv, 0, PERL_MAGIC_collxfrm, &PL_vtbl_collxfrm,
+                                0, 0);
                assert(mg);
            }
            mg->mg_ptr = xf;
@@ -6710,7 +7061,7 @@ Perl_vnewSVpvf(pTHX_ const char* pat, va_list* args)
     dVAR;
     register SV *sv;
     new_SV(sv);
-    sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*));
+    sv_vsetpvfn(sv, pat, strlen(pat), args, NULL, 0, NULL);
     return sv;
 }
 
@@ -6802,10 +7153,10 @@ Perl_newRV_noinc(pTHX_ SV *tmpRef)
  */
 
 SV *
-Perl_newRV(pTHX_ SV *tmpRef)
+Perl_newRV(pTHX_ SV *sv)
 {
     dVAR;
-    return newRV_noinc(SvREFCNT_inc(tmpRef));
+    return newRV_noinc(SvREFCNT_inc_simple_NN(sv));
 }
 
 /*
@@ -6992,8 +7343,11 @@ Perl_sv_2cv(pTHX_ SV *sv, HV **st, GV **gvp, I32 lref)
     GV *gv = NULL;
     CV *cv = NULL;
 
-    if (!sv)
-       return *st = NULL, *gvp = NULL, NULL;
+    if (!sv) {
+       *st = NULL;
+       *gvp = NULL;
+       return NULL;
+    }
     switch (SvTYPE(sv)) {
     case SVt_PVCV:
        *st = CvSTASH(sv);
@@ -7054,8 +7408,7 @@ Perl_sv_2cv(pTHX_ SV *sv, HV **st, GV **gvp, I32 lref)
             * declaration! */
            newSUB(start_subparse(FALSE, 0),
                   newSVOP(OP_CONST, 0, tmpsv),
-                  Nullop,
-                  Nullop);
+                  NULL, NULL);
            LEAVE;
            if (!GvCVu(gv))
                Perl_croak(aTHX_ "Unable to create sub named \"%"SVf"\"",
@@ -7335,9 +7688,11 @@ Perl_newSVrv(pTHX_ SV *rv, const char *classname)
        sv_clear(rv);
        SvFLAGS(rv) = 0;
        SvREFCNT(rv) = refcnt;
-    }
 
-    if (SvTYPE(rv) < SVt_RV)
+       sv_upgrade(rv, SVt_RV);
+    } else if (SvROK(rv)) {
+       SvREFCNT_dec(SvRV(rv));
+    } else if (SvTYPE(rv) < SVt_RV)
        sv_upgrade(rv, SVt_RV);
     else if (SvTYPE(rv) > SVt_RV) {
        SvPV_free(rv);
@@ -7497,7 +7852,7 @@ Perl_sv_bless(pTHX_ SV *sv, HV *stash)
     if (SvTYPE(tmpRef) != SVt_PVIO)
        ++PL_sv_objcount;
     SvUPGRADE(tmpRef, SVt_PVMG);
-    SvSTASH_set(tmpRef, (HV*)SvREFCNT_inc(stash));
+    SvSTASH_set(tmpRef, (HV*)SvREFCNT_inc_simple(stash));
 
     if (Gv_AMG(stash))
        SvAMAGIC_on(sv);
@@ -7521,18 +7876,24 @@ S_sv_unglob(pTHX_ SV *sv)
 {
     dVAR;
     void *xpvmg;
+    SV * const temp = sv_newmortal();
 
     assert(SvTYPE(sv) == SVt_PVGV);
     SvFAKE_off(sv);
-    if (GvGP(sv))
+    gv_efullname3(temp, (GV *) sv, "*");
+
+    if (GvGP(sv)) {
        gp_free((GV*)sv);
+    }
     if (GvSTASH(sv)) {
        sv_del_backref((SV*)GvSTASH(sv), sv);
        GvSTASH(sv) = NULL;
     }
-    sv_unmagic(sv, PERL_MAGIC_glob);
-    Safefree(GvNAME(sv));
     GvMULTI_off(sv);
+    if (GvNAME_HEK(sv)) {
+       unshare_hek(GvNAME_HEK(sv));
+    }
+    SvSCREAM_off(sv);
 
     /* need to keep SvANY(sv) in the right arena */
     xpvmg = new_XPVMG();
@@ -7542,6 +7903,10 @@ S_sv_unglob(pTHX_ SV *sv)
 
     SvFLAGS(sv) &= ~SVTYPEMASK;
     SvFLAGS(sv) |= SVt_PVMG;
+
+    /* Intentionally not calling any local SET magic, as this isn't so much a
+       set operation as merely an internal storage change.  */
+    sv_setsv_flags(sv, temp, 0);
 }
 
 /*
@@ -7713,7 +8078,7 @@ Usually used via its frontend C<sv_setpvf>.
 void
 Perl_sv_vsetpvf(pTHX_ SV *sv, const char* pat, va_list* args)
 {
-    sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*));
+    sv_vsetpvfn(sv, pat, strlen(pat), args, NULL, 0, NULL);
 }
 
 /*
@@ -7746,7 +8111,7 @@ Usually used via its frontend C<sv_setpvf_mg>.
 void
 Perl_sv_vsetpvf_mg(pTHX_ SV *sv, const char* pat, va_list* args)
 {
-    sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*));
+    sv_vsetpvfn(sv, pat, strlen(pat), args, NULL, 0, NULL);
     SvSETMAGIC(sv);
 }
 
@@ -7819,7 +8184,7 @@ Usually used via its frontend C<sv_catpvf>.
 void
 Perl_sv_vcatpvf(pTHX_ SV *sv, const char* pat, va_list* args)
 {
-    sv_vcatpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*));
+    sv_vcatpvfn(sv, pat, strlen(pat), args, NULL, 0, NULL);
 }
 
 /*
@@ -7852,7 +8217,7 @@ Usually used via its frontend C<sv_catpvf_mg>.
 void
 Perl_sv_vcatpvf_mg(pTHX_ SV *sv, const char* pat, va_list* args)
 {
-    sv_vcatpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*));
+    sv_vcatpvfn(sv, pat, strlen(pat), args, NULL, 0, NULL);
     SvSETMAGIC(sv);
 }
 
@@ -7885,7 +8250,7 @@ S_expect_number(pTHX_ char** pattern)
     case '7': case '8': case '9':
        var = *(*pattern)++ - '0';
        while (isDIGIT(**pattern)) {
-           I32 tmp = var * 10 + (*(*pattern)++ - '0');
+           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"));
            var = tmp;
@@ -8060,7 +8425,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
        const char *eptr = NULL;
        STRLEN elen = 0;
        SV *vecsv = NULL;
-       const U8 *vecstr = Null(U8*);
+       const U8 *vecstr = NULL;
        STRLEN veclen = 0;
        char c = 0;
        int i;
@@ -8347,7 +8712,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
 #endif
 #if defined(HAS_QUAD) || defined(HAS_LONG_DOUBLE)
        case 'L':                       /* Ld */
-           /* FALL THROUGH */
+           /*FALLTHROUGH*/
 #ifdef HAS_QUAD
        case 'q':                       /* qd */
 #endif
@@ -8363,9 +8728,9 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                break;
             }
 #endif
-           /* FALL THROUGH */
+           /*FALLTHROUGH*/
        case 'h':
-           /* FALL THROUGH */
+           /*FALLTHROUGH*/
        case 'V':
            intsize = *q++;
            break;
@@ -8468,7 +8833,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
 #else
            intsize = 'l';
 #endif
-           /* FALL THROUGH */
+           /*FALLTHROUGH*/
        case 'd':
        case 'i':
 #if vdNUMBER
@@ -8534,7 +8899,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
 #else
            intsize = 'l';
 #endif
-           /* FALL THROUGH */
+           /*FALLTHROUGH*/
        case 'u':
            base = 10;
            goto uns_integer;
@@ -8549,7 +8914,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
 #else
            intsize = 'l';
 #endif
-           /* FALL THROUGH */
+           /*FALLTHROUGH*/
        case 'o':
            base = 8;
            goto uns_integer;
@@ -8659,7 +9024,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
 
        case 'F':
            c = 'f';            /* maybe %F isn't supported here */
-           /* FALL THROUGH */
+           /*FALLTHROUGH*/
        case 'e': case 'E':
        case 'f':
        case 'g': case 'G':
@@ -8680,7 +9045,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
                break;
 /* [perl #20339] - we should accept and ignore %lf rather than die */
            case 'l':
-               /* FALL THROUGH */
+               /*FALLTHROUGH*/
            default:
 #if defined(USE_LONG_DOUBLE)
                intsize = args ? 0 : 'q';
@@ -8690,7 +9055,7 @@ Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV
 #if defined(HAS_LONG_DOUBLE)
                break;
 #else
-               /* FALL THROUGH */
+               /*FALLTHROUGH*/
 #endif
            case 'h':
                goto unknown;
@@ -9019,12 +9384,14 @@ ptr_table_* functions.
 
 #if defined(USE_ITHREADS)
 
+/* XXX Remove this so it doesn't have to go thru the macro and return for nothing */
 #ifndef GpREFCNT_inc
 #  define GpREFCNT_inc(gp)     ((gp) ? (++(gp)->gp_refcnt, (gp)) : (GP*)NULL)
 #endif
 
 
 #define sv_dup_inc(s,t)        SvREFCNT_inc(sv_dup(s,t))
+#define sv_dup_inc_NN(s,t)     SvREFCNT_inc_NN(sv_dup(s,t))
 #define av_dup(s,t)    (AV*)sv_dup((SV*)s,t)
 #define av_dup_inc(s,t)        (AV*)SvREFCNT_inc(sv_dup((SV*)s,t))
 #define hv_dup(s,t)    (HV*)sv_dup((SV*)s,t)
@@ -9184,6 +9551,7 @@ Perl_fp_dup(pTHX_ PerlIO *fp, char type, CLONE_PARAMS *param)
 DIR *
 Perl_dirp_dup(pTHX_ DIR *dp)
 {
+    PERL_UNUSED_CONTEXT;
     if (!dp)
        return (DIR*)NULL;
     /* XXX TODO */
@@ -9196,6 +9564,7 @@ GP *
 Perl_gp_dup(pTHX_ GP *gp, CLONE_PARAMS* param)
 {
     GP *ret;
+
     if (!gp)
        return (GP*)NULL;
     /* look for it in the table first */
@@ -9296,6 +9665,8 @@ PTR_TBL_t *
 Perl_ptr_table_new(pTHX)
 {
     PTR_TBL_t *tbl;
+    PERL_UNUSED_CONTEXT;
+
     Newxz(tbl, 1, PTR_TBL_t);
     tbl->tbl_max       = 511;
     tbl->tbl_items     = 0;
@@ -9317,7 +9688,7 @@ Perl_ptr_table_new(pTHX)
 /* map an existing pointer using a table */
 
 STATIC PTR_TBL_ENT_t *
-S_ptr_table_find(pTHX_ PTR_TBL_t *tbl, const void *sv) {
+S_ptr_table_find(PTR_TBL_t *tbl, const void *sv) {
     PTR_TBL_ENT_t *tblent;
     const UV hash = PTR_TABLE_HASH(sv);
     assert(tbl);
@@ -9326,14 +9697,15 @@ S_ptr_table_find(pTHX_ PTR_TBL_t *tbl, const void *sv) {
        if (tblent->oldval == sv)
            return tblent;
     }
-    return 0;
+    return NULL;
 }
 
 void *
 Perl_ptr_table_fetch(pTHX_ PTR_TBL_t *tbl, const void *sv)
 {
-    PTR_TBL_ENT_t const *const tblent = S_ptr_table_find(aTHX_ tbl, sv);
-    return tblent ? tblent->newval : (void *) 0;
+    PTR_TBL_ENT_t const *const tblent = ptr_table_find(tbl, sv);
+    PERL_UNUSED_CONTEXT;
+    return tblent ? tblent->newval : NULL;
 }
 
 /* add a new entry to a pointer-mapping table */
@@ -9341,14 +9713,16 @@ Perl_ptr_table_fetch(pTHX_ PTR_TBL_t *tbl, const void *sv)
 void
 Perl_ptr_table_store(pTHX_ PTR_TBL_t *tbl, const void *oldsv, void *newsv)
 {
-    PTR_TBL_ENT_t *tblent = S_ptr_table_find(aTHX_ tbl, oldsv);
+    PTR_TBL_ENT_t *tblent = ptr_table_find(tbl, oldsv);
+    PERL_UNUSED_CONTEXT;
 
     if (tblent) {
        tblent->newval = newsv;
     } else {
        const UV entry = PTR_TABLE_HASH(oldsv) & tbl->tbl_max;
 
-       new_body_inline(tblent, sizeof(struct ptr_tbl_ent), PTE_SVSLOT);
+       new_body_inline(tblent, PTE_SVSLOT);
+
        tblent->oldval = oldsv;
        tblent->newval = newsv;
        tblent->next = tbl->tbl_ary[entry];
@@ -9368,6 +9742,7 @@ Perl_ptr_table_split(pTHX_ PTR_TBL_t *tbl)
     const UV oldsize = tbl->tbl_max + 1;
     UV newsize = oldsize * 2;
     UV i;
+    PERL_UNUSED_CONTEXT;
 
     Renew(ary, newsize, PTR_TBL_ENT_t*);
     Zero(&ary[oldsize], newsize-oldsize, PTR_TBL_ENT_t*);
@@ -9451,7 +9826,10 @@ Perl_rvpv_dup(pTHX_ SV *dstr, const SV *sstr, CLONE_PARAMS* param)
        }
        else {
            /* Special case - not normally malloced for some reason */
-           if ((SvREADONLY(sstr) && SvFAKE(sstr))) {
+           if (isGV_with_GP(sstr)) {
+               /* Don't need to do anything here.  */
+           }
+           else if ((SvREADONLY(sstr) && SvFAKE(sstr))) {
                /* A "shared" PV - clone it as "shared" PV */
                SvPV_set(dstr,
                         HEK_KEY(hek_dup(SvSHARED_HEK_FROM_PV(SvPVX_const(sstr)),
@@ -9464,7 +9842,7 @@ Perl_rvpv_dup(pTHX_ SV *dstr, const SV *sstr, CLONE_PARAMS* param)
        }
     }
     else {
-       /* Copy the Null */
+       /* Copy the NULL */
        if (SvTYPE(dstr) == SVt_RV)
            SvRV_set(dstr, NULL);
        else
@@ -9555,13 +9933,12 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* param)
 
            switch (sv_type) {
            default:
-               Perl_croak(aTHX_ "Bizarre SvTYPE [%" IVdf "]",
-                          (IV)SvTYPE(sstr));
+               Perl_croak(aTHX_ "Bizarre SvTYPE [%" IVdf "]", (IV)SvTYPE(sstr));
                break;
 
            case SVt_PVGV:
                if (GvUNIQUE((GV*)sstr)) {
-                   /* Do sharing here, and fall through */
+                   /*EMPTY*/;   /* Do sharing here, and fall through */
                }
            case SVt_PVIO:
            case SVt_PVFM:
@@ -9574,9 +9951,9 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* param)
            case SVt_PVNV:
            case SVt_PVIV:
            case SVt_PV:
-               assert(sv_type_details->size);
+               assert(sv_type_details->body_size);
                if (sv_type_details->arena) {
-                   new_body_inline(new_body, sv_type_details->size, sv_type);
+                   new_body_inline(new_body, sv_type);
                    new_body
                        = (void*)((char*)new_body - sv_type_details->offset);
                } else {
@@ -9593,10 +9970,11 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* param)
 #else
            Copy(((char*)SvANY(sstr)),
                 ((char*)SvANY(dstr)),
-                sv_type_details->size + sv_type_details->offset, char);
+                sv_type_details->body_size + sv_type_details->offset, char);
 #endif
 
-           if (sv_type != SVt_PVAV && sv_type != SVt_PVHV)
+           if (sv_type != SVt_PVAV && sv_type != SVt_PVHV
+               && !isGV_with_GP(dstr))
                Perl_rvpv_dup(aTHX_ dstr, sstr, param);
 
            /* The Copy above means that all the source (unduplicated) pointers
@@ -9605,7 +9983,10 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* param)
               missing by always going for the destination.
               FIXME - instrument and check that assumption  */
            if (sv_type >= SVt_PVMG) {
-               if (SvMAGIC(dstr))
+               HV *ourstash;
+               if ((sv_type == SVt_PVMG) && (ourstash = OURSTASH(dstr))) {
+                   OURSTASH_set(dstr, hv_dup_inc(ourstash, param));
+               } else if (SvMAGIC(dstr))
                    SvMAGIC_set(dstr, mg_dup(SvMAGIC(dstr), param));
                if (SvSTASH(dstr))
                    SvSTASH_set(dstr, hv_dup_inc(SvSTASH(dstr), param));
@@ -9633,12 +10014,19 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* param)
                    LvTARG(dstr) = sv_dup_inc(LvTARG(dstr), param);
                break;
            case SVt_PVGV:
-               GvNAME(dstr)    = SAVEPVN(GvNAME(dstr), GvNAMELEN(dstr));
-               GvSTASH(dstr)   = hv_dup(GvSTASH(dstr), param);
+               if (GvNAME_HEK(dstr))
+                   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.  */
-               GvGP(dstr)      = gp_dup(GvGP(dstr), param);
-               (void)GpREFCNT_inc(GvGP(dstr));
+               GvSTASH(dstr)   = hv_dup(GvSTASH(dstr), param);
+               if(isGV_with_GP(sstr)) {
+                   /* Danger Will Robinson - GvGP(dstr) isn't initialised
+                      at the point of this comment.  */
+                   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);
@@ -9647,8 +10035,6 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* param)
                else
                    IoOFP(dstr) = fp_dup(IoOFP(dstr), IoTYPE(dstr), param);
                /* PL_rsfp_filters entries have fake IoDIRP() */
-               if (IoDIRP(dstr) && !(IoFLAGS(dstr) & IOf_FAKE_DIRP))
-                   IoDIRP(dstr)        = dirp_dup(IoDIRP(dstr));
                if(IoFLAGS(dstr) & IOf_FAKE_DIRP) {
                    /* I have no idea why fake dirp (rsfps)
                       should be treated differently but otherwise
@@ -9660,6 +10046,12 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* param)
                    IoTOP_GV(dstr)      = gv_dup(IoTOP_GV(dstr), param);
                    IoFMT_GV(dstr)      = gv_dup(IoFMT_GV(dstr), param);
                    IoBOTTOM_GV(dstr)   = gv_dup(IoBOTTOM_GV(dstr), param);
+                   if (IoDIRP(dstr)) {
+                       IoDIRP(dstr)    = dirp_dup(IoDIRP(dstr));
+                   } else {
+                       /*EMPTY*/;
+                       /* IoDIRP(dstr) is already a copy of IoDIRP(sstr)  */
+                   }
                }
                IoTOP_NAME(dstr)        = SAVEPV(IoTOP_NAME(dstr));
                IoFMT_NAME(dstr)        = SAVEPV(IoFMT_NAME(dstr));
@@ -9744,14 +10136,18 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* param)
                        av_push(param->stashes, dstr);
                }
                break;
-           case SVt_PVFM:
            case SVt_PVCV:
+               if (!(param->flags & CLONEf_COPY_STACKS)) {
+                   CvDEPTH(dstr) = 0;
+               }
+           case SVt_PVFM:
                /* NOTE: not refcounted */
                CvSTASH(dstr)   = hv_dup(CvSTASH(dstr), param);
                OP_REFCNT_LOCK;
-               CvROOT(dstr)    = OpREFCNT_inc(CvROOT(dstr));
+               if (!CvISXSUB(dstr))
+                   CvROOT(dstr) = OpREFCNT_inc(CvROOT(dstr));
                OP_REFCNT_UNLOCK;
-               if (CvCONST(dstr)) {
+               if (CvCONST(dstr) && CvISXSUB(dstr)) {
                    CvXSUBANY(dstr).any_ptr = GvUNIQUE(CvGV(dstr)) ?
                        SvREFCNT_inc(CvXSUBANY(dstr).any_ptr) :
                        sv_dup_inc((SV *)CvXSUBANY(dstr).any_ptr, param);
@@ -9760,15 +10156,12 @@ Perl_sv_dup(pTHX_ const SV *sstr, CLONE_PARAMS* param)
                 * 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) ;
-               if (!(param->flags & CLONEf_COPY_STACKS)) {
-                   CvDEPTH(dstr) = 0;
-               }
                PAD_DUP(CvPADLIST(dstr), CvPADLIST(sstr), param);
                CvOUTSIDE(dstr) =
                    CvWEAKOUTSIDE(sstr)
                    ? cv_dup(    CvOUTSIDE(dstr), param)
                    : cv_dup_inc(CvOUTSIDE(dstr), param);
-               if (!CvXSUB(dstr))
+               if (!CvISXSUB(dstr))
                    CvFILE(dstr) = SAVEPV(CvFILE(dstr));
                break;
            }
@@ -10115,12 +10508,12 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
                    OpREFCNT_inc(o);
                    break;
                default:
-                   TOPPTR(nss,ix) = Nullop;
+                   TOPPTR(nss,ix) = NULL;
                    break;
                }
            }
            else
-               TOPPTR(nss,ix) = Nullop;
+               TOPPTR(nss,ix) = NULL;
            break;
        case SAVEt_FREEPV:
            c = (char*)POPPTR(ss,ix);
@@ -10187,6 +10580,12 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
        case SAVEt_HINTS:
            i = POPINT(ss,ix);
            TOPINT(nss,ix) = i;
+           ptr = POPPTR(ss,ix);
+           TOPPTR(nss,ix) = Perl_refcounted_he_dup(aTHX_ ptr, param);
+           if (i & HINT_LOCALIZE_HH) {
+               hv = (HV*)POPPTR(ss,ix);
+               TOPPTR(nss,ix) = hv_dup_inc(hv, param);
+           }
            break;
        case SAVEt_COMPPAD:
            av = (AV*)POPPTR(ss,ix);
@@ -10336,17 +10735,17 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
     IV i;
     CLONE_PARAMS clone_params;
-    CLONE_PARAMS* param = &clone_params;
+    CLONE_PARAMS* const param = &clone_params;
 
-    PerlInterpreter *my_perl = (PerlInterpreter*)(*ipM->pMalloc)(ipM, sizeof(PerlInterpreter));
+    PerlInterpreter * const my_perl = (PerlInterpreter*)(*ipM->pMalloc)(ipM, sizeof(PerlInterpreter));
     /* 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
-    Poison(my_perl, 1, PerlInterpreter);
-    PL_op = Nullop;
-    PL_curcop = (COP *)Nullop;
+    PoisonNew(my_perl, 1, PerlInterpreter);
+    PL_op = NULL;
+    PL_curcop = NULL;
     PL_markstack = 0;
     PL_scopestack = 0;
     PL_savestack = 0;
@@ -10372,15 +10771,15 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     IV i;
     CLONE_PARAMS clone_params;
     CLONE_PARAMS* param = &clone_params;
-    PerlInterpreter *my_perl = (PerlInterpreter*)PerlMem_malloc(sizeof(PerlInterpreter));
+    PerlInterpreter * const my_perl = (PerlInterpreter*)PerlMem_malloc(sizeof(PerlInterpreter));
     /* 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
-    Poison(my_perl, 1, PerlInterpreter);
-    PL_op = Nullop;
-    PL_curcop = (COP *)Nullop;
+    PoisonNew(my_perl, 1, PerlInterpreter);
+    PL_op = NULL;
+    PL_curcop = NULL;
     PL_markstack = 0;
     PL_scopestack = 0;
     PL_savestack = 0;
@@ -10471,6 +10870,8 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
        PL_compiling.cop_warnings = sv_dup_inc(PL_compiling.cop_warnings, param);
     if (!specialCopIO(PL_compiling.cop_io))
        PL_compiling.cop_io = sv_dup_inc(PL_compiling.cop_io, param);
+    PL_compiling.cop_hints
+       = Perl_refcounted_he_dup(aTHX_ PL_compiling.cop_hints, param);
     PL_curcop          = (COP*)any_dup(proto_perl->Tcurcop, proto_perl);
 
     /* pseudo environmental stuff */
@@ -10524,7 +10925,6 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_formfeed                = sv_dup(proto_perl->Iformfeed, param);
 
     PL_maxsysfd                = proto_perl->Imaxsysfd;
-    PL_multiline       = proto_perl->Imultiline;
     PL_statusvalue     = proto_perl->Istatusvalue;
 #ifdef VMS
     PL_statusvalue_vms = proto_perl->Istatusvalue_vms;
@@ -10543,8 +10943,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
        const I32 len = av_len((AV*)proto_perl->Iregex_padav);
        SV* const * const regexen = AvARRAY((AV*)proto_perl->Iregex_padav);
        IV i;
-       av_push(PL_regex_padav,
-               sv_dup_inc(regexen[0],param));
+       av_push(PL_regex_padav, sv_dup_inc_NN(regexen[0],param));
        for(i = 1; i <= len; i++) {
            const SV * const regex = regexen[i];
            SV * const sv =
@@ -10721,9 +11120,26 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     i = (PL_lex_casemods < 12 ? 12 : PL_lex_casemods);
     PL_lex_casestack   = SAVEPVN(proto_perl->Ilex_casestack,i);
 
+#ifdef PERL_MAD
+    Copy(proto_perl->Inexttoke, PL_nexttoke, 5, NEXTTOKE);
+    PL_lasttoke                = proto_perl->Ilasttoke;
+    PL_realtokenstart  = proto_perl->Irealtokenstart;
+    PL_faketokens      = proto_perl->Ifaketokens;
+    PL_thismad         = proto_perl->Ithismad;
+    PL_thistoken       = proto_perl->Ithistoken;
+    PL_thisopen                = proto_perl->Ithisopen;
+    PL_thisstuff       = proto_perl->Ithisstuff;
+    PL_thisclose       = proto_perl->Ithisclose;
+    PL_thiswhite       = proto_perl->Ithiswhite;
+    PL_nextwhite       = proto_perl->Inextwhite;
+    PL_skipwhite       = proto_perl->Iskipwhite;
+    PL_endwhite                = proto_perl->Iendwhite;
+    PL_curforce                = proto_perl->Icurforce;
+#else
     Copy(proto_perl->Inextval, PL_nextval, 5, YYSTYPE);
     Copy(proto_perl->Inexttype, PL_nexttype, 5,        I32);
     PL_nexttoke                = proto_perl->Inexttoke;
+#endif
 
     /* XXX This is probably masking the deeper issue of why
      * SvANY(proto_perl->Ilinestr) can be NULL at this point. For test case:
@@ -10953,7 +11369,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
                    proto_perl->Ttmps_stack[i]);
            if (nsv && !SvREFCNT(nsv)) {
                EXTEND_MORTAL(1);
-               PL_tmps_stack[++PL_tmps_ix] = SvREFCNT_inc(nsv);
+               PL_tmps_stack[++PL_tmps_ix] = SvREFCNT_inc_simple(nsv);
            }
        }
     }
@@ -10993,9 +11409,9 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_localizing      = proto_perl->Tlocalizing;
 
     PL_errors          = sv_dup_inc(proto_perl->Terrors, param);
-    PL_hv_fetch_ent_mh = Nullhe;
+    PL_hv_fetch_ent_mh = NULL;
     PL_modcount                = proto_perl->Tmodcount;
-    PL_lastgotoprobe   = Nullop;
+    PL_lastgotoprobe   = NULL;
     PL_dumpindent      = proto_perl->Tdumpindent;
 
     PL_sortcop         = (OP*)any_dup(proto_perl->Tsortcop, proto_perl);
@@ -11038,7 +11454,6 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_regnarrate      = 0;
     PL_regprogram      = (regnode*)NULL;
     PL_regindent       = 0;
-    PL_regcc           = (CURCUR*)NULL;
     PL_reg_call_cc     = (struct re_cc_state*)NULL;
     PL_reg_re          = (regexp*)NULL;
     PL_reg_ganch       = NULL;
@@ -11067,6 +11482,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
     PL_reginterp_cnt   = 0;
     PL_reg_starttry    = 0;
+    PL_regmatch_slab   = NULL;
 
     /* Pluggable optimizer */
     PL_peepp           = proto_perl->Tpeepp;
@@ -11101,7 +11517,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
     /* orphaned? eg threads->new inside BEGIN or use */
     if (PL_compcv && ! SvREFCNT(PL_compcv)) {
-       (void)SvREFCNT_inc(PL_compcv);
+       SvREFCNT_inc_simple_void(PL_compcv);
        SAVEFREESV(PL_compcv);
     }
 
@@ -11419,7 +11835,7 @@ S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
 
        /* attempt to find a match within the aggregate */
        if (hash) {
-           keysv = S_find_hash_subscript(aTHX_ (HV*)sv, uninit_sv);
+           keysv = find_hash_subscript((HV*)sv, uninit_sv);
            if (keysv)
                subscript_type = FUV_SUBSCRIPT_HASH;
        }
@@ -11540,13 +11956,13 @@ S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
            /* index is an expression;
             * attempt to find a match within the aggregate */
            if (obase->op_type == OP_HELEM) {
-               SV * const keysv = S_find_hash_subscript(aTHX_ (HV*)sv, uninit_sv);
+               SV * const keysv = find_hash_subscript((HV*)sv, uninit_sv);
                if (keysv)
                    return varname(gv, '%', o->op_targ,
                                                keysv, 0, FUV_SUBSCRIPT_HASH);
            }
            else {
-               const I32 index = S_find_array_subscript(aTHX_ (AV*)sv, uninit_sv);
+               const I32 index = find_array_subscript((AV*)sv, uninit_sv);
                if (index >= 0)
                    return varname(gv, '@', o->op_targ,
                                        NULL, index, FUV_SUBSCRIPT_ARRAY);
@@ -11558,7 +11974,6 @@ S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
                ? '@' : '%',
                o->op_targ, NULL, 0, FUV_SUBSCRIPT_WITHIN);
        }
-
        break;
 
     case OP_AASSIGN:
@@ -11623,7 +12038,7 @@ S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
     case OP_CHOMP:
        if (SvROK(PL_rs) && uninit_sv == SvRV(PL_rs))
            return sv_2mortal(newSVpvs("${$/}"));
-       /* FALL THROUGH */
+       /*FALLTHROUGH*/
 
     default:
     do_op:
@@ -11637,7 +12052,7 @@ S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
 
        /* if all except one arg are constant, or have no side-effects,
         * or are optimized away, then it's unambiguous */
-       o2 = Nullop;
+       o2 = NULL;
        for (kid=o; kid; kid = kid->op_sibling) {
            if (kid &&
                (    (kid->op_type == OP_CONST && SvOK(cSVOPx_sv(kid)))
@@ -11647,7 +12062,7 @@ S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match)
            )
                continue;
            if (o2) { /* more than one found */
-               o2 = Nullop;
+               o2 = NULL;
                break;
            }
            o2 = kid;