This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
SvUTF8() for globs.
[perl5.git] / sv.c
diff --git a/sv.c b/sv.c
index bc0ef20..2d09ade 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -413,7 +413,7 @@ S_visit(pTHX_ SVFUNC_t f, const U32 flags, const U32 mask)
        register const SV * const svend = &sva[SvREFCNT(sva)];
        register SV* sv;
        for (sv = sva + 1; sv < svend; ++sv) {
-           if (SvTYPE(sv) != SVTYPEMASK
+           if (SvTYPE(sv) != (svtype)SVTYPEMASK
                    && (sv->sv_flags & mask) == flags
                    && SvREFCNT(sv))
            {
@@ -432,7 +432,7 @@ S_visit(pTHX_ SVFUNC_t f, const U32 flags, const U32 mask)
 static void
 do_report_used(pTHX_ SV *const sv)
 {
-    if (SvTYPE(sv) != SVTYPEMASK) {
+    if (SvTYPE(sv) != (svtype)SVTYPEMASK) {
        PerlIO_printf(Perl_debug_log, "****\n");
        sv_dump(sv);
     }
@@ -893,37 +893,31 @@ static const struct body_details bodies_by_type[] = {
       NOARENA /* IVS don't need an arena  */, 0
     },
 
-    /* 8 bytes on most ILP32 with IEEE doubles */
     { sizeof(NV), sizeof(NV),
       STRUCT_OFFSET(XPVNV, xnv_u),
       SVt_NV, FALSE, HADNV, HASARENA, FIT_ARENA(0, sizeof(NV)) },
 
-    /* 8 bytes on most ILP32 with IEEE doubles */
     { sizeof(XPV) - STRUCT_OFFSET(XPV, xpv_cur),
       copy_length(XPV, xpv_len) - STRUCT_OFFSET(XPV, xpv_cur),
       + STRUCT_OFFSET(XPV, xpv_cur),
       SVt_PV, FALSE, NONV, HASARENA,
       FIT_ARENA(0, sizeof(XPV) - STRUCT_OFFSET(XPV, xpv_cur)) },
 
-    /* 12 */
     { sizeof(XPVIV) - STRUCT_OFFSET(XPV, xpv_cur),
       copy_length(XPVIV, xiv_u) - STRUCT_OFFSET(XPV, xpv_cur),
       + STRUCT_OFFSET(XPV, xpv_cur),
       SVt_PVIV, FALSE, NONV, HASARENA,
       FIT_ARENA(0, sizeof(XPVIV) - STRUCT_OFFSET(XPV, xpv_cur)) },
 
-    /* 20 */
     { sizeof(XPVNV) - STRUCT_OFFSET(XPV, xpv_cur),
       copy_length(XPVNV, xnv_u) - STRUCT_OFFSET(XPV, xpv_cur),
       + STRUCT_OFFSET(XPV, xpv_cur),
       SVt_PVNV, FALSE, HADNV, HASARENA,
       FIT_ARENA(0, sizeof(XPVNV) - STRUCT_OFFSET(XPV, xpv_cur)) },
 
-    /* 28 */
     { sizeof(XPVMG), copy_length(XPVMG, xnv_u), 0, SVt_PVMG, FALSE, HADNV,
       HASARENA, FIT_ARENA(0, sizeof(XPVMG)) },
 
-    /* something big */
     { sizeof(regexp),
       sizeof(regexp),
       0,
@@ -931,11 +925,9 @@ static const struct body_details bodies_by_type[] = {
       FIT_ARENA(0, sizeof(regexp))
     },
 
-    /* 48 */
     { sizeof(XPVGV), sizeof(XPVGV), 0, SVt_PVGV, TRUE, HADNV,
       HASARENA, FIT_ARENA(0, sizeof(XPVGV)) },
     
-    /* 64 */
     { sizeof(XPVLV), sizeof(XPVLV), 0, SVt_PVLV, TRUE, HADNV,
       HASARENA, FIT_ARENA(0, sizeof(XPVLV)) },
 
@@ -951,7 +943,6 @@ static const struct body_details bodies_by_type[] = {
       SVt_PVHV, TRUE, NONV, HASARENA,
       FIT_ARENA(0, sizeof(XPVHV)) },
 
-    /* 56 */
     { sizeof(XPVCV),
       sizeof(XPVCV),
       0,
@@ -964,7 +955,6 @@ static const struct body_details bodies_by_type[] = {
       SVt_PVFM, TRUE, NONV, NOARENA,
       FIT_ARENA(20, sizeof(XPVFM)) },
 
-    /* XPVIO is 84 bytes, fits 48x */
     { sizeof(XPVIO),
       sizeof(XPVIO),
       0,
@@ -2267,7 +2257,7 @@ Perl_sv_2iv_flags(pTHX_ register SV *const sv, const I32 flags)
     dVAR;
     if (!sv)
        return 0;
-    if (SvGMAGICAL(sv) || (SvTYPE(sv) == SVt_PVGV && SvVALID(sv))) {
+    if (SvGMAGICAL(sv) || SvVALID(sv)) {
        /* FBMs use the space for SvIVX and SvNVX for other purposes, and use
           the same flag bit as SVf_IVisUV, so must not let them cache IVs.
           In practice they are extremely unlikely to actually get anywhere
@@ -2356,7 +2346,7 @@ Perl_sv_2uv_flags(pTHX_ register SV *const sv, const I32 flags)
     dVAR;
     if (!sv)
        return 0;
-    if (SvGMAGICAL(sv) || (SvTYPE(sv) == SVt_PVGV && SvVALID(sv))) {
+    if (SvGMAGICAL(sv) || SvVALID(sv)) {
        /* FBMs use the space for SvIVX and SvNVX for other purposes, and use
           the same flag bit as SVf_IVisUV, so must not let them cache IVs.  */
        if (flags & SV_GMAGIC)
@@ -2436,7 +2426,7 @@ Perl_sv_2nv_flags(pTHX_ register SV *const sv, const I32 flags)
     dVAR;
     if (!sv)
        return 0.0;
-    if (SvGMAGICAL(sv) || (SvTYPE(sv) == SVt_PVGV && SvVALID(sv))) {
+    if (SvGMAGICAL(sv) || SvVALID(sv)) {
        /* FBMs use the space for SvIVX and SvNVX for other purposes, and use
           the same flag bit as SVf_IVisUV, so must not let them cache NVs.  */
        if (flags & SV_GMAGIC)
@@ -2971,6 +2961,7 @@ Perl_sv_2pv_flags(pTHX_ register SV *const sv, STRLEN *const lp, const I32 flags
                if (lp) {
                    *lp = SvCUR(buffer);
                }
+                if ( SvUTF8(buffer) ) SvUTF8_on(sv);
                return SvPVX(buffer);
            }
            else {
@@ -4088,8 +4079,6 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags)
        /* case SVt_BIND: */
     case SVt_PVLV:
     case SVt_PVGV:
-       /* SvVALID means that this PVGV is playing at being an FBM.  */
-
     case SVt_PVMG:
        if (SvGMAGICAL(sstr) && (flags & SV_GMAGIC)) {
            mg_get(sstr);
@@ -4173,7 +4162,7 @@ Perl_sv_setsv_flags(pTHX_ SV *dstr, register SV* sstr, const I32 flags)
                           "Undefined value assigned to typeglob");
        }
        else {
-           GV *gv = gv_fetchsv(sstr, GV_ADD, SVt_PVGV);
+           GV *gv = gv_fetchsv_nomg(sstr, GV_ADD, SVt_PVGV);
            if (dstr != (const SV *)gv) {
                const char * const name = GvNAME((const GV *)dstr);
                const STRLEN len = GvNAMELEN(dstr);
@@ -4778,7 +4767,7 @@ Perl_sv_force_normal_flags(pTHX_ register SV *const sv, const U32 flags)
     }
 #else
     if (SvREADONLY(sv)) {
-       if (SvFAKE(sv)) {
+       if (SvFAKE(sv) && !isGV_with_GP(sv)) {
            const char * const pvx = SvPVX_const(sv);
            const STRLEN len = SvCUR(sv);
            SvFAKE_off(sv);
@@ -5107,7 +5096,7 @@ space is allocated.)  The reference count for the new SV is set to 1.
 In 5.9.3, newSV() replaces the older NEWSV() API, and drops the first
 parameter, I<x>, a debug aid which allowed callers to identify themselves.
 This aid has been superseded by a new build option, PERL_MEM_LOG (see
-L<perlhack/PERL_MEM_LOG>).  The older API is still there for use in XS
+L<perlhacktips/PERL_MEM_LOG>).  The older API is still there for use in XS
 modules supporting older perls.
 
 =cut
@@ -5241,9 +5230,25 @@ Perl_sv_magic(pTHX_ register SV *const sv, SV *const obj, const int how,
     dVAR;
     const MGVTBL *vtable;
     MAGIC* mg;
+    unsigned int flags;
+    unsigned int vtable_index;
 
     PERL_ARGS_ASSERT_SV_MAGIC;
 
+    if (how < 0 || (unsigned)how > C_ARRAY_LENGTH(PL_magic_data)
+       || ((flags = PL_magic_data[how]),
+           (vtable_index = flags & PERL_MAGIC_VTABLE_MASK)
+           > magic_vtable_max))
+       Perl_croak(aTHX_ "Don't know how to handle magic of type \\%o", how);
+
+    /* PERL_MAGIC_ext is reserved for use by extensions not perl internals.
+       Useful for attaching extension internal data to perl vars.
+       Note that multiple extensions may clash if magical scalars
+       etc holding private data from one are passed to another. */
+
+    vtable = (vtable_index == magic_vtable_max)
+       ? NULL : PL_magic_vtables + vtable_index;
+
 #ifdef PERL_OLD_COPY_ON_WRITE
     if (SvIsCOW(sv))
         sv_force_normal_flags(sv, 0);
@@ -5255,11 +5260,7 @@ Perl_sv_magic(pTHX_ register SV *const sv, SV *const obj, const int how,
            !(SvFAKE(sv) && SvTYPE(sv) < SVt_PVMG)
 
            && IN_PERL_RUNTIME
-           && how != PERL_MAGIC_regex_global
-           && how != PERL_MAGIC_bm
-           && how != PERL_MAGIC_fm
-           && how != PERL_MAGIC_sv
-           && how != PERL_MAGIC_backref
+           && !PERL_MAGIC_TYPE_READONLY_ACCEPTABLE(how)
           )
        {
            Perl_croak_no_modify(aTHX);
@@ -5281,127 +5282,6 @@ Perl_sv_magic(pTHX_ register SV *const sv, SV *const obj, const int how,
        }
     }
 
-    switch (how) {
-    case PERL_MAGIC_sv:
-       vtable = &PL_vtbl_sv;
-       break;
-    case PERL_MAGIC_overload:
-        vtable = &PL_vtbl_amagic;
-        break;
-    case PERL_MAGIC_overload_elem:
-        vtable = &PL_vtbl_amagicelem;
-        break;
-    case PERL_MAGIC_overload_table:
-        vtable = &PL_vtbl_ovrld;
-        break;
-    case PERL_MAGIC_bm:
-       vtable = &PL_vtbl_bm;
-       break;
-    case PERL_MAGIC_regdata:
-       vtable = &PL_vtbl_regdata;
-       break;
-    case PERL_MAGIC_regdatum:
-       vtable = &PL_vtbl_regdatum;
-       break;
-    case PERL_MAGIC_env:
-       vtable = &PL_vtbl_env;
-       break;
-    case PERL_MAGIC_fm:
-       vtable = &PL_vtbl_fm;
-       break;
-    case PERL_MAGIC_envelem:
-       vtable = &PL_vtbl_envelem;
-       break;
-    case PERL_MAGIC_regex_global:
-       vtable = &PL_vtbl_mglob;
-       break;
-    case PERL_MAGIC_isa:
-       vtable = &PL_vtbl_isa;
-       break;
-    case PERL_MAGIC_isaelem:
-       vtable = &PL_vtbl_isaelem;
-       break;
-    case PERL_MAGIC_nkeys:
-       vtable = &PL_vtbl_nkeys;
-       break;
-    case PERL_MAGIC_dbfile:
-       vtable = NULL;
-       break;
-    case PERL_MAGIC_dbline:
-       vtable = &PL_vtbl_dbline;
-       break;
-#ifdef USE_LOCALE_COLLATE
-    case PERL_MAGIC_collxfrm:
-        vtable = &PL_vtbl_collxfrm;
-        break;
-#endif /* USE_LOCALE_COLLATE */
-    case PERL_MAGIC_tied:
-       vtable = &PL_vtbl_pack;
-       break;
-    case PERL_MAGIC_tiedelem:
-    case PERL_MAGIC_tiedscalar:
-       vtable = &PL_vtbl_packelem;
-       break;
-    case PERL_MAGIC_qr:
-       vtable = &PL_vtbl_regexp;
-       break;
-    case PERL_MAGIC_sig:
-       vtable = &PL_vtbl_sig;
-       break;
-    case PERL_MAGIC_sigelem:
-       vtable = &PL_vtbl_sigelem;
-       break;
-    case PERL_MAGIC_taint:
-       vtable = &PL_vtbl_taint;
-       break;
-    case PERL_MAGIC_uvar:
-       vtable = &PL_vtbl_uvar;
-       break;
-    case PERL_MAGIC_vec:
-       vtable = &PL_vtbl_vec;
-       break;
-    case PERL_MAGIC_arylen_p:
-    case PERL_MAGIC_rhash:
-    case PERL_MAGIC_symtab:
-    case PERL_MAGIC_vstring:
-    case PERL_MAGIC_checkcall:
-       vtable = NULL;
-       break;
-    case PERL_MAGIC_utf8:
-       vtable = &PL_vtbl_utf8;
-       break;
-    case PERL_MAGIC_substr:
-       vtable = &PL_vtbl_substr;
-       break;
-    case PERL_MAGIC_defelem:
-       vtable = &PL_vtbl_defelem;
-       break;
-    case PERL_MAGIC_arylen:
-       vtable = &PL_vtbl_arylen;
-       break;
-    case PERL_MAGIC_pos:
-       vtable = &PL_vtbl_pos;
-       break;
-    case PERL_MAGIC_backref:
-       vtable = &PL_vtbl_backref;
-       break;
-    case PERL_MAGIC_hintselem:
-       vtable = &PL_vtbl_hintselem;
-       break;
-    case PERL_MAGIC_hints:
-       vtable = &PL_vtbl_hints;
-       break;
-    case PERL_MAGIC_ext:
-       /* Reserved for use by extensions not perl internals.           */
-       /* Useful for attaching extension internal data to perl vars.   */
-       /* Note that multiple extensions may clash if magical scalars   */
-       /* etc holding private data from one are passed to another.     */
-       vtable = NULL;
-       break;
-    default:
-       Perl_croak(aTHX_ "Don't know how to handle magic of type \\%o", how);
-    }
-
     /* Rest of work is done else where */
     mg = sv_magicext(sv,obj,how,vtable,name,namlen);
 
@@ -5516,6 +5396,7 @@ Perl_sv_rvweaken(pTHX_ SV *const sv)
        Perl_ck_warner(aTHX_ packWARN(WARN_MISC), "Reference is already weak");
        return sv;
     }
+    else if (SvREADONLY(sv)) croak_no_modify();
     tsv = SvRV(sv);
     Perl_sv_add_backref(aTHX_ tsv, sv);
     SvWEAKREF_on(sv);
@@ -6038,7 +5919,7 @@ Perl_sv_clear(pTHX_ SV *const orig_sv)
        type = SvTYPE(sv);
 
        assert(SvREFCNT(sv) == 0);
-       assert(SvTYPE(sv) != SVTYPEMASK);
+       assert(SvTYPE(sv) != (svtype)SVTYPEMASK);
 
        if (type <= SVt_IV) {
            /* See the comment in sv.h about the collusion between this
@@ -6292,7 +6173,8 @@ Perl_sv_clear(pTHX_ SV *const orig_sv)
                }
            } else if (SvTYPE(iter_sv) == SVt_PVHV) {
                sv = Perl_hfree_next_entry(aTHX_ (HV*)iter_sv, &hash_index);
-               if (!sv) { /* no more elements of current HV to free */
+               if (!sv && !HvTOTALKEYS((HV *)iter_sv)) {
+                   /* no more elements of current HV to free */
                    sv = iter_sv;
                    type = SvTYPE(sv);
                    /* Restore previous value of iter_sv, squirrelled away */
@@ -7967,7 +7849,7 @@ Perl_sv_inc_nomg(pTHX_ register SV *const sv)
     if (!sv)
        return;
     if (SvTHINKFIRST(sv)) {
-       if (SvIsCOW(sv))
+       if (SvIsCOW(sv) || isGV_with_GP(sv))
            sv_force_normal_flags(sv, 0);
        if (SvREADONLY(sv)) {
            if (IN_PERL_RUNTIME)
@@ -8148,7 +8030,7 @@ Perl_sv_dec_nomg(pTHX_ register SV *const sv)
     if (!sv)
        return;
     if (SvTHINKFIRST(sv)) {
-       if (SvIsCOW(sv))
+       if (SvIsCOW(sv) || isGV_with_GP(sv))
            sv_force_normal_flags(sv, 0);
        if (SvREADONLY(sv)) {
            if (IN_PERL_RUNTIME)
@@ -8474,7 +8356,7 @@ Perl_newSVhek(pTHX_ const HEK *const hek)
               into an hv routine with a regular hash.
               Similarly, a hash that isn't using shared hash keys has to have
               the flag in every key so that we know not to try to call
-              share_hek_kek on it.  */
+              share_hek_hek on it.  */
 
            SV * const sv = newSVpvn (HEK_KEY(hek), HEK_LEN(hek));
            if (HEK_UTF8(hek))
@@ -8759,7 +8641,7 @@ Perl_newSVsv(pTHX_ register SV *const old)
 
     if (!old)
        return NULL;
-    if (SvTYPE(old) == SVTYPEMASK) {
+    if (SvTYPE(old) == (svtype)SVTYPEMASK) {
        Perl_ck_warner_d(aTHX_ packWARN(WARN_INTERNAL), "semi-panic: attempt to dup freed string");
        return NULL;
     }
@@ -8957,18 +8839,9 @@ Perl_sv_2cv(pTHX_ SV *sv, HV **const st, GV **const gvp, const I32 lref)
        *st = NULL;
        *gvp = NULL;
        return NULL;
-    case SVt_PVGV:
-       if (isGV_with_GP(sv)) {
-           gv = MUTABLE_GV(sv);
-           *gvp = gv;
-           *st = GvESTASH(gv);
-           goto fix_gv;
-       }
-       /* FALL THROUGH */
-
     default:
+       SvGETMAGIC(sv);
        if (SvROK(sv)) {
-           SvGETMAGIC(sv);
            if (SvAMAGIC(sv))
                sv = amagic_deref_call(sv, to_cv_amg);
            /* At this point I'd like to do SPAGAIN, but really I need to
@@ -8987,11 +8860,11 @@ Perl_sv_2cv(pTHX_ SV *sv, HV **const st, GV **const gvp, const I32 lref)
                Perl_croak(aTHX_ "Not a subroutine reference");
        }
        else if (isGV_with_GP(sv)) {
-           SvGETMAGIC(sv);
            gv = MUTABLE_GV(sv);
        }
-       else
-           gv = gv_fetchsv(sv, lref, SVt_PVCV); /* Calls get magic */
+       else {
+           gv = gv_fetchsv_nomg(sv, lref, SVt_PVCV);
+       }
        *gvp = gv;
        if (!gv) {
            *st = NULL;
@@ -9003,8 +8876,7 @@ Perl_sv_2cv(pTHX_ SV *sv, HV **const st, GV **const gvp, const I32 lref)
            return NULL;
        }
        *st = GvESTASH(gv);
-    fix_gv:
-       if (lref && !GvCVu(gv)) {
+       if (lref & ~GV_ADDMG && !GvCVu(gv)) {
            SV *tmpsv;
            ENTER;
            tmpsv = newSV(0);
@@ -9595,6 +9467,7 @@ Perl_sv_unref_flags(pTHX_ SV *const ref, const U32 flags)
 =for apidoc sv_untaint
 
 Untaint an SV. Use C<SvTAINTED_off> instead.
+
 =cut
 */
 
@@ -9614,6 +9487,7 @@ Perl_sv_untaint(pTHX_ SV *const sv)
 =for apidoc sv_tainted
 
 Test an SV for taintedness. Use C<SvTAINTED> instead.
+
 =cut
 */
 
@@ -11799,7 +11673,7 @@ S_sv_dup_common(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
 
     PERL_ARGS_ASSERT_SV_DUP_COMMON;
 
-    if (SvTYPE(sstr) == SVTYPEMASK) {
+    if (SvTYPE(sstr) == (svtype)SVTYPEMASK) {
 #ifdef DEBUG_LEAKING_SCALARS_ABORT
        abort();
 #endif
@@ -12134,11 +12008,11 @@ S_sv_dup_common(pTHX_ const SV *const sstr, CLONE_PARAMS *const param)
                    OP_REFCNT_LOCK;
                    CvROOT(dstr) = OpREFCNT_inc(CvROOT(dstr));
                    OP_REFCNT_UNLOCK;
-                   CvFILE(dstr) = SAVEPV(CvFILE(dstr));
                } else if (CvCONST(dstr)) {
                    CvXSUBANY(dstr).any_ptr =
                        sv_dup_inc((const SV *)CvXSUBANY(dstr).any_ptr, param);
                }
+               if (CvDYNFILE(dstr)) CvFILE(dstr) = SAVEPV(CvFILE(dstr));
                /* don't dup if copying back - CvGV isn't refcounted, so the
                 * duped GV may never be freed. A bit of a hack! DAPM */
                SvANY(MUTABLE_CV(dstr))->xcv_gv =
@@ -12457,7 +12331,6 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
            TOPLONG(nss,ix) = longval;
            break;
        case SAVEt_I32:                         /* I32 reference */
-       case SAVEt_COP_ARYBASE:                 /* call CopARYBASE_set */
            ptr = POPPTR(ss,ix);
            TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
            i = POPINT(ss,ix);
@@ -12822,6 +12695,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PoisonNew(my_perl, 1, PerlInterpreter);
     PL_op = NULL;
     PL_curcop = NULL;
+    PL_defstash = NULL; /* may be used by perl malloc() */
     PL_markstack = 0;
     PL_scopestack = 0;
     PL_scopestack_name = 0;
@@ -12875,67 +12749,23 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_hash_seed       = proto_perl->Ihash_seed;
     PL_rehash_seed     = proto_perl->Irehash_seed;
 
-#ifdef USE_REENTRANT_API
-    /* XXX: things like -Dm will segfault here in perlio, but doing
-     *  PERL_SET_CONTEXT(proto_perl);
-     * breaks too many other things
-     */
-    Perl_reentrant_init(aTHX);
-#endif
-
-    /* create SV map for pointer relocation */
-    PL_ptr_table = ptr_table_new();
-
-    /* initialize these special pointers as early as possible */
     SvANY(&PL_sv_undef)                = NULL;
     SvREFCNT(&PL_sv_undef)     = (~(U32)0)/2;
     SvFLAGS(&PL_sv_undef)      = SVf_READONLY|SVt_NULL;
-    ptr_table_store(PL_ptr_table, &proto_perl->Isv_undef, &PL_sv_undef);
-
-    SvANY(&PL_sv_no)           = new_XPVNV();
     SvREFCNT(&PL_sv_no)                = (~(U32)0)/2;
     SvFLAGS(&PL_sv_no)         = SVp_IOK|SVf_IOK|SVp_NOK|SVf_NOK
                                  |SVp_POK|SVf_POK|SVf_READONLY|SVt_PVNV;
-    SvPV_set(&PL_sv_no, savepvn(PL_No, 0));
-    SvCUR_set(&PL_sv_no, 0);
-    SvLEN_set(&PL_sv_no, 1);
-    SvIV_set(&PL_sv_no, 0);
-    SvNV_set(&PL_sv_no, 0);
-    ptr_table_store(PL_ptr_table, &proto_perl->Isv_no, &PL_sv_no);
 
     SvANY(&PL_sv_yes)          = new_XPVNV();
     SvREFCNT(&PL_sv_yes)       = (~(U32)0)/2;
     SvFLAGS(&PL_sv_yes)                = SVp_IOK|SVf_IOK|SVp_NOK|SVf_NOK
                                  |SVp_POK|SVf_POK|SVf_READONLY|SVt_PVNV;
-    SvPV_set(&PL_sv_yes, savepvn(PL_Yes, 1));
-    SvCUR_set(&PL_sv_yes, 1);
-    SvLEN_set(&PL_sv_yes, 2);
-    SvIV_set(&PL_sv_yes, 1);
-    SvNV_set(&PL_sv_yes, 1);
-    ptr_table_store(PL_ptr_table, &proto_perl->Isv_yes, &PL_sv_yes);
 
     /* dbargs array probably holds garbage */
     PL_dbargs          = NULL;
 
-    /* create (a non-shared!) shared string table */
-    PL_strtab          = newHV();
-    HvSHAREKEYS_off(PL_strtab);
-    hv_ksplit(PL_strtab, HvTOTALKEYS(proto_perl->Istrtab));
-    ptr_table_store(PL_ptr_table, proto_perl->Istrtab, PL_strtab);
-
     PL_compiling = proto_perl->Icompiling;
 
-    /* These two PVs will be free'd special way so must set them same way op.c does */
-    PL_compiling.cop_stashpv = savesharedpv(PL_compiling.cop_stashpv);
-    ptr_table_store(PL_ptr_table, proto_perl->Icompiling.cop_stashpv, PL_compiling.cop_stashpv);
-
-    PL_compiling.cop_file    = savesharedpv(PL_compiling.cop_file);
-    ptr_table_store(PL_ptr_table, proto_perl->Icompiling.cop_file, PL_compiling.cop_file);
-
-    ptr_table_store(PL_ptr_table, &proto_perl->Icompiling, &PL_compiling);
-    PL_compiling.cop_warnings = DUP_WARNINGS(PL_compiling.cop_warnings);
-    CopHINTHASH_set(&PL_compiling, cophh_copy(CopHINTHASH_get(&PL_compiling)));
-    PL_curcop          = (COP*)any_dup(proto_perl->Icurcop, proto_perl);
 #ifdef PERL_DEBUG_READONLY_OPS
     PL_slabs = NULL;
     PL_slab_count = 0;
@@ -12945,39 +12775,12 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_origargc                = proto_perl->Iorigargc;
     PL_origargv                = proto_perl->Iorigargv;
 
-    param->stashes      = newAV();  /* Setup array of objects to call clone on */
-    /* This makes no difference to the implementation, as it always pushes
-       and shifts pointers to other SVs without changing their reference
-       count, with the array becoming empty before it is freed. However, it
-       makes it conceptually clear what is going on, and will avoid some
-       work inside av.c, filling slots between AvFILL() and AvMAX() with
-       &PL_sv_undef, and SvREFCNT_dec()ing those.  */
-    AvREAL_off(param->stashes);
-
-    if (!(flags & CLONEf_COPY_STACKS)) {
-       param->unreferenced = newAV();
-    }
-
     /* Set tainting stuff before PerlIO_debug can possibly get called */
     PL_tainting                = proto_perl->Itainting;
     PL_taint_warn      = proto_perl->Itaint_warn;
 
-#ifdef PERLIO_LAYERS
-    /* Clone PerlIO tables as soon as we can handle general xx_dup() */
-    PerlIO_clone(aTHX_ proto_perl, param);
-#endif
-
-    PL_envgv           = gv_dup(proto_perl->Ienvgv, param);
-    PL_incgv           = gv_dup(proto_perl->Iincgv, param);
-    PL_hintgv          = gv_dup(proto_perl->Ihintgv, param);
-    PL_origfilename    = SAVEPV(proto_perl->Iorigfilename);
-    PL_diehook         = sv_dup_inc(proto_perl->Idiehook, param);
-    PL_warnhook                = sv_dup_inc(proto_perl->Iwarnhook, param);
-
-    /* switches */
     PL_minus_c         = proto_perl->Iminus_c;
-    PL_patchlevel      = sv_dup_inc(proto_perl->Ipatchlevel, param);
-    PL_apiversion      = sv_dup_inc(proto_perl->Iapiversion, param);
+
     PL_localpatches    = proto_perl->Ilocalpatches;
     PL_splitstr                = proto_perl->Isplitstr;
     PL_minus_n         = proto_perl->Iminus_n;
@@ -12990,16 +12793,12 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_dowarn          = proto_perl->Idowarn;
     PL_sawampersand    = proto_perl->Isawampersand;
     PL_unsafe          = proto_perl->Iunsafe;
-    PL_inplace         = SAVEPV(proto_perl->Iinplace);
-    PL_e_script                = sv_dup_inc(proto_perl->Ie_script, param);
     PL_perldb          = proto_perl->Iperldb;
     PL_perl_destruct_level = proto_perl->Iperl_destruct_level;
     PL_exit_flags       = proto_perl->Iexit_flags;
 
-    /* magical thingies */
     /* XXX time(&PL_basetime) when asked for? */
     PL_basetime                = proto_perl->Ibasetime;
-    PL_formfeed                = sv_dup(proto_perl->Iformfeed, param);
 
     PL_maxsysfd                = proto_perl->Imaxsysfd;
     PL_statusvalue     = proto_perl->Istatusvalue;
@@ -13008,149 +12807,38 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 #else
     PL_statusvalue_posix = proto_perl->Istatusvalue_posix;
 #endif
-    PL_encoding                = sv_dup(proto_perl->Iencoding, param);
 
-    sv_setpvs(PERL_DEBUG_PAD(0), "");  /* For regex debugging. */
-    sv_setpvs(PERL_DEBUG_PAD(1), "");  /* ext/re needs these */
-    sv_setpvs(PERL_DEBUG_PAD(2), "");  /* even without DEBUGGING. */
-
-   
     /* RE engine related */
     Zero(&PL_reg_state, 1, struct re_save_state);
     PL_reginterp_cnt   = 0;
     PL_regmatch_slab   = NULL;
-    
-    /* Clone the regex array */
-    /* ORANGE FIXME for plugins, probably in the SV dup code.
-       newSViv(PTR2IV(CALLREGDUPE(
-       INT2PTR(REGEXP *, SvIVX(regex)), param))))
-    */
-    PL_regex_padav = av_dup_inc(proto_perl->Iregex_padav, param);
-    PL_regex_pad = AvARRAY(PL_regex_padav);
-
-    /* shortcuts to various I/O objects */
-    PL_ofsgv            = gv_dup_inc(proto_perl->Iofsgv, param);
-    PL_stdingv         = gv_dup(proto_perl->Istdingv, param);
-    PL_stderrgv                = gv_dup(proto_perl->Istderrgv, param);
-    PL_defgv           = gv_dup(proto_perl->Idefgv, param);
-    PL_argvgv          = gv_dup(proto_perl->Iargvgv, param);
-    PL_argvoutgv       = gv_dup(proto_perl->Iargvoutgv, param);
-    PL_argvout_stack   = av_dup_inc(proto_perl->Iargvout_stack, param);
-
-    /* shortcuts to regexp stuff */
-    PL_replgv          = gv_dup(proto_perl->Ireplgv, param);
-
-    /* shortcuts to misc objects */
-    PL_errgv           = gv_dup(proto_perl->Ierrgv, param);
-
-    /* shortcuts to debugging objects */
-    PL_DBgv            = gv_dup(proto_perl->IDBgv, param);
-    PL_DBline          = gv_dup(proto_perl->IDBline, param);
-    PL_DBsub           = gv_dup(proto_perl->IDBsub, param);
-    PL_DBsingle                = sv_dup(proto_perl->IDBsingle, param);
-    PL_DBtrace         = sv_dup(proto_perl->IDBtrace, param);
-    PL_DBsignal                = sv_dup(proto_perl->IDBsignal, param);
-
-    /* symbol tables */
-    PL_defstash                = hv_dup_inc(proto_perl->Idefstash, param);
-    PL_curstash                = hv_dup(proto_perl->Icurstash, param);
-    PL_debstash                = hv_dup(proto_perl->Idebstash, param);
-    PL_globalstash     = hv_dup(proto_perl->Iglobalstash, param);
-    PL_curstname       = sv_dup_inc(proto_perl->Icurstname, param);
-
-    PL_beginav         = av_dup_inc(proto_perl->Ibeginav, param);
-    PL_beginav_save    = av_dup_inc(proto_perl->Ibeginav_save, param);
-    PL_checkav_save    = av_dup_inc(proto_perl->Icheckav_save, param);
-    PL_unitcheckav      = av_dup_inc(proto_perl->Iunitcheckav, param);
-    PL_unitcheckav_save = av_dup_inc(proto_perl->Iunitcheckav_save, param);
-    PL_endav           = av_dup_inc(proto_perl->Iendav, param);
-    PL_checkav         = av_dup_inc(proto_perl->Icheckav, param);
-    PL_initav          = av_dup_inc(proto_perl->Iinitav, param);
 
     PL_sub_generation  = proto_perl->Isub_generation;
-    PL_isarev          = hv_dup_inc(proto_perl->Iisarev, param);
 
     /* funky return mechanisms */
     PL_forkprocess     = proto_perl->Iforkprocess;
 
-    /* subprocess state */
-    PL_fdpid           = av_dup_inc(proto_perl->Ifdpid, param);
-
     /* internal state */
     PL_maxo            = proto_perl->Imaxo;
-    if (proto_perl->Iop_mask)
-       PL_op_mask      = SAVEPVN(proto_perl->Iop_mask, PL_maxo);
-    else
-       PL_op_mask      = NULL;
-    /* PL_asserting        = proto_perl->Iasserting; */
 
-    /* current interpreter roots */
-    PL_main_cv         = cv_dup_inc(proto_perl->Imain_cv, param);
-    OP_REFCNT_LOCK;
-    PL_main_root       = OpREFCNT_inc(proto_perl->Imain_root);
-    OP_REFCNT_UNLOCK;
     PL_main_start      = proto_perl->Imain_start;
     PL_eval_root       = proto_perl->Ieval_root;
     PL_eval_start      = proto_perl->Ieval_start;
 
-    /* runtime control stuff */
-    PL_curcopdb                = (COP*)any_dup(proto_perl->Icurcopdb, proto_perl);
-
     PL_filemode                = proto_perl->Ifilemode;
     PL_lastfd          = proto_perl->Ilastfd;
     PL_oldname         = proto_perl->Ioldname;         /* XXX not quite right */
     PL_Argv            = NULL;
     PL_Cmd             = NULL;
     PL_gensym          = proto_perl->Igensym;
-    PL_preambleav      = av_dup_inc(proto_perl->Ipreambleav, param);
+
     PL_laststatval     = proto_perl->Ilaststatval;
     PL_laststype       = proto_perl->Ilaststype;
     PL_mess_sv         = NULL;
 
-    PL_ors_sv          = sv_dup_inc(proto_perl->Iors_sv, param);
-
-    /* interpreter atexit processing */
-    PL_exitlistlen     = proto_perl->Iexitlistlen;
-    if (PL_exitlistlen) {
-       Newx(PL_exitlist, PL_exitlistlen, PerlExitListEntry);
-       Copy(proto_perl->Iexitlist, PL_exitlist, PL_exitlistlen, PerlExitListEntry);
-    }
-    else
-       PL_exitlist     = (PerlExitListEntry*)NULL;
-
-    PL_my_cxt_size = proto_perl->Imy_cxt_size;
-    if (PL_my_cxt_size) {
-       Newx(PL_my_cxt_list, PL_my_cxt_size, void *);
-       Copy(proto_perl->Imy_cxt_list, PL_my_cxt_list, PL_my_cxt_size, void *);
-#ifdef PERL_GLOBAL_STRUCT_PRIVATE
-       Newx(PL_my_cxt_keys, PL_my_cxt_size, const char *);
-       Copy(proto_perl->Imy_cxt_keys, PL_my_cxt_keys, PL_my_cxt_size, char *);
-#endif
-    }
-    else {
-       PL_my_cxt_list  = (void**)NULL;
-#ifdef PERL_GLOBAL_STRUCT_PRIVATE
-       PL_my_cxt_keys  = (const char**)NULL;
-#endif
-    }
-    PL_modglobal       = hv_dup_inc(proto_perl->Imodglobal, param);
-    PL_custom_op_names  = hv_dup_inc(proto_perl->Icustom_op_names,param);
-    PL_custom_op_descs  = hv_dup_inc(proto_perl->Icustom_op_descs,param);
-    PL_custom_ops      = hv_dup_inc(proto_perl->Icustom_ops, param);
-
     PL_profiledata     = NULL;
 
-    PL_compcv                  = cv_dup(proto_perl->Icompcv, param);
-
-    PAD_CLONE_VARS(proto_perl, param);
-
-#ifdef HAVE_INTERP_INTERN
-    sys_intern_dup(&proto_perl->Isys_intern, &PL_sys_intern);
-#endif
-
-    /* more statics moved here */
     PL_generation      = proto_perl->Igeneration;
-    PL_DBcv            = cv_dup(proto_perl->IDBcv, param);
 
     PL_in_clean_objs   = proto_perl->Iin_clean_objs;
     PL_in_clean_all    = proto_perl->Iin_clean_all;
@@ -13164,25 +12852,12 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_evalseq         = proto_perl->Ievalseq;
     PL_origenviron     = proto_perl->Iorigenviron;     /* XXX not quite right */
     PL_origalen                = proto_perl->Iorigalen;
-#ifdef PERL_USES_PL_PIDSTATUS
-    PL_pidstatus       = newHV();                      /* XXX flag for cloning? */
-#endif
-    PL_osname          = SAVEPV(proto_perl->Iosname);
+
     PL_sighandlerp     = proto_perl->Isighandlerp;
 
     PL_runops          = proto_perl->Irunops;
 
-    PL_parser          = parser_dup(proto_perl->Iparser, param);
-
-    /* XXX this only works if the saved cop has already been cloned */
-    if (proto_perl->Iparser) {
-       PL_parser->saved_curcop = (COP*)any_dup(
-                                   proto_perl->Iparser->saved_curcop,
-                                   proto_perl);
-    }
-
-    PL_subline         = proto_perl->Isubline;
-    PL_subname         = sv_dup_inc(proto_perl->Isubname, param);
+    PL_subline         = proto_perl->Isubline;
 
 #ifdef FCRYPT
     PL_cryptseen       = proto_perl->Icryptseen;
@@ -13194,53 +12869,16 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
 #ifdef USE_LOCALE_COLLATE
     PL_collation_ix    = proto_perl->Icollation_ix;
-    PL_collation_name  = SAVEPV(proto_perl->Icollation_name);
     PL_collation_standard      = proto_perl->Icollation_standard;
     PL_collxfrm_base   = proto_perl->Icollxfrm_base;
     PL_collxfrm_mult   = proto_perl->Icollxfrm_mult;
 #endif /* USE_LOCALE_COLLATE */
 
 #ifdef USE_LOCALE_NUMERIC
-    PL_numeric_name    = SAVEPV(proto_perl->Inumeric_name);
     PL_numeric_standard        = proto_perl->Inumeric_standard;
     PL_numeric_local   = proto_perl->Inumeric_local;
-    PL_numeric_radix_sv        = sv_dup_inc(proto_perl->Inumeric_radix_sv, param);
 #endif /* !USE_LOCALE_NUMERIC */
 
-    /* utf8 character classes */
-    PL_utf8_alnum      = sv_dup_inc(proto_perl->Iutf8_alnum, param);
-    PL_utf8_ascii      = sv_dup_inc(proto_perl->Iutf8_ascii, param);
-    PL_utf8_alpha      = sv_dup_inc(proto_perl->Iutf8_alpha, param);
-    PL_utf8_space      = sv_dup_inc(proto_perl->Iutf8_space, param);
-    PL_utf8_cntrl      = sv_dup_inc(proto_perl->Iutf8_cntrl, param);
-    PL_utf8_graph      = sv_dup_inc(proto_perl->Iutf8_graph, param);
-    PL_utf8_digit      = sv_dup_inc(proto_perl->Iutf8_digit, param);
-    PL_utf8_upper      = sv_dup_inc(proto_perl->Iutf8_upper, param);
-    PL_utf8_lower      = sv_dup_inc(proto_perl->Iutf8_lower, param);
-    PL_utf8_print      = sv_dup_inc(proto_perl->Iutf8_print, param);
-    PL_utf8_punct      = sv_dup_inc(proto_perl->Iutf8_punct, param);
-    PL_utf8_xdigit     = sv_dup_inc(proto_perl->Iutf8_xdigit, param);
-    PL_utf8_mark       = sv_dup_inc(proto_perl->Iutf8_mark, param);
-    PL_utf8_X_begin    = sv_dup_inc(proto_perl->Iutf8_X_begin, param);
-    PL_utf8_X_extend   = sv_dup_inc(proto_perl->Iutf8_X_extend, param);
-    PL_utf8_X_prepend  = sv_dup_inc(proto_perl->Iutf8_X_prepend, param);
-    PL_utf8_X_non_hangul       = sv_dup_inc(proto_perl->Iutf8_X_non_hangul, param);
-    PL_utf8_X_L        = sv_dup_inc(proto_perl->Iutf8_X_L, param);
-    PL_utf8_X_LV       = sv_dup_inc(proto_perl->Iutf8_X_LV, param);
-    PL_utf8_X_LVT      = sv_dup_inc(proto_perl->Iutf8_X_LVT, param);
-    PL_utf8_X_T        = sv_dup_inc(proto_perl->Iutf8_X_T, param);
-    PL_utf8_X_V        = sv_dup_inc(proto_perl->Iutf8_X_V, param);
-    PL_utf8_X_LV_LVT_V = sv_dup_inc(proto_perl->Iutf8_X_LV_LVT_V, param);
-    PL_utf8_toupper    = sv_dup_inc(proto_perl->Iutf8_toupper, param);
-    PL_utf8_totitle    = sv_dup_inc(proto_perl->Iutf8_totitle, param);
-    PL_utf8_tolower    = sv_dup_inc(proto_perl->Iutf8_tolower, param);
-    PL_utf8_tofold     = sv_dup_inc(proto_perl->Iutf8_tofold, param);
-    PL_utf8_idstart    = sv_dup_inc(proto_perl->Iutf8_idstart, param);
-    PL_utf8_xidstart   = sv_dup_inc(proto_perl->Iutf8_xidstart, param);
-    PL_utf8_idcont     = sv_dup_inc(proto_perl->Iutf8_idcont, param);
-    PL_utf8_xidcont    = sv_dup_inc(proto_perl->Iutf8_xidcont, param);
-    PL_utf8_foldable   = hv_dup_inc(proto_perl->Iutf8_foldable, param);
-
     /* Did the locale setup indicate UTF-8? */
     PL_utf8locale      = proto_perl->Iutf8locale;
     /* Unicode features (see perlrun/-C) */
@@ -13284,6 +12922,327 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
     PL_glob_index      = proto_perl->Iglob_index;
     PL_srand_called    = proto_perl->Isrand_called;
 
+    if (flags & CLONEf_COPY_STACKS) {
+       /* next allocation will be PL_tmps_stack[PL_tmps_ix+1] */
+       PL_tmps_ix              = proto_perl->Itmps_ix;
+       PL_tmps_max             = proto_perl->Itmps_max;
+       PL_tmps_floor           = proto_perl->Itmps_floor;
+
+       /* next push_scope()/ENTER sets PL_scopestack[PL_scopestack_ix]
+        * NOTE: unlike the others! */
+       PL_scopestack_ix        = proto_perl->Iscopestack_ix;
+       PL_scopestack_max       = proto_perl->Iscopestack_max;
+
+       /* next SSPUSHFOO() sets PL_savestack[PL_savestack_ix]
+        * NOTE: unlike the others! */
+       PL_savestack_ix         = proto_perl->Isavestack_ix;
+       PL_savestack_max        = proto_perl->Isavestack_max;
+    }
+
+    PL_start_env       = proto_perl->Istart_env;       /* XXXXXX */
+    PL_top_env         = &PL_start_env;
+
+    PL_op              = proto_perl->Iop;
+
+    PL_Sv              = NULL;
+    PL_Xpv             = (XPV*)NULL;
+    my_perl->Ina       = proto_perl->Ina;
+
+    PL_statbuf         = proto_perl->Istatbuf;
+    PL_statcache       = proto_perl->Istatcache;
+
+#ifdef HAS_TIMES
+    PL_timesbuf                = proto_perl->Itimesbuf;
+#endif
+
+    PL_tainted         = proto_perl->Itainted;
+    PL_curpm           = proto_perl->Icurpm;   /* XXX No PMOP ref count */
+
+    PL_chopset         = proto_perl->Ichopset; /* XXX never deallocated */
+
+    PL_restartjmpenv   = proto_perl->Irestartjmpenv;
+    PL_restartop       = proto_perl->Irestartop;
+    PL_in_eval         = proto_perl->Iin_eval;
+    PL_delaymagic      = proto_perl->Idelaymagic;
+    PL_phase           = proto_perl->Iphase;
+    PL_localizing      = proto_perl->Ilocalizing;
+
+    PL_hv_fetch_ent_mh = NULL;
+    PL_modcount                = proto_perl->Imodcount;
+    PL_lastgotoprobe   = NULL;
+    PL_dumpindent      = proto_perl->Idumpindent;
+
+    PL_efloatbuf       = NULL;         /* reinits on demand */
+    PL_efloatsize      = 0;                    /* reinits on demand */
+
+    /* regex stuff */
+
+    PL_regdummy                = proto_perl->Iregdummy;
+    PL_colorset                = 0;            /* reinits PL_colors[] */
+    /*PL_colors[6]     = {0,0,0,0,0,0};*/
+
+    /* Pluggable optimizer */
+    PL_peepp           = proto_perl->Ipeepp;
+    PL_rpeepp          = proto_perl->Irpeepp;
+    /* op_free() hook */
+    PL_opfreehook      = proto_perl->Iopfreehook;
+
+#ifdef USE_REENTRANT_API
+    /* XXX: things like -Dm will segfault here in perlio, but doing
+     *  PERL_SET_CONTEXT(proto_perl);
+     * breaks too many other things
+     */
+    Perl_reentrant_init(aTHX);
+#endif
+
+    /* create SV map for pointer relocation */
+    PL_ptr_table = ptr_table_new();
+
+    /* initialize these special pointers as early as possible */
+    ptr_table_store(PL_ptr_table, &proto_perl->Isv_undef, &PL_sv_undef);
+
+    SvANY(&PL_sv_no)           = new_XPVNV();
+    SvPV_set(&PL_sv_no, savepvn(PL_No, 0));
+    SvCUR_set(&PL_sv_no, 0);
+    SvLEN_set(&PL_sv_no, 1);
+    SvIV_set(&PL_sv_no, 0);
+    SvNV_set(&PL_sv_no, 0);
+    ptr_table_store(PL_ptr_table, &proto_perl->Isv_no, &PL_sv_no);
+
+    SvPV_set(&PL_sv_yes, savepvn(PL_Yes, 1));
+    SvCUR_set(&PL_sv_yes, 1);
+    SvLEN_set(&PL_sv_yes, 2);
+    SvIV_set(&PL_sv_yes, 1);
+    SvNV_set(&PL_sv_yes, 1);
+    ptr_table_store(PL_ptr_table, &proto_perl->Isv_yes, &PL_sv_yes);
+
+    /* create (a non-shared!) shared string table */
+    PL_strtab          = newHV();
+    HvSHAREKEYS_off(PL_strtab);
+    hv_ksplit(PL_strtab, HvTOTALKEYS(proto_perl->Istrtab));
+    ptr_table_store(PL_ptr_table, proto_perl->Istrtab, PL_strtab);
+
+    /* These two PVs will be free'd special way so must set them same way op.c does */
+    PL_compiling.cop_stashpv = savesharedpv(PL_compiling.cop_stashpv);
+    ptr_table_store(PL_ptr_table, proto_perl->Icompiling.cop_stashpv, PL_compiling.cop_stashpv);
+
+    PL_compiling.cop_file    = savesharedpv(PL_compiling.cop_file);
+    ptr_table_store(PL_ptr_table, proto_perl->Icompiling.cop_file, PL_compiling.cop_file);
+
+    ptr_table_store(PL_ptr_table, &proto_perl->Icompiling, &PL_compiling);
+    PL_compiling.cop_warnings = DUP_WARNINGS(PL_compiling.cop_warnings);
+    CopHINTHASH_set(&PL_compiling, cophh_copy(CopHINTHASH_get(&PL_compiling)));
+    PL_curcop          = (COP*)any_dup(proto_perl->Icurcop, proto_perl);
+
+    param->stashes      = newAV();  /* Setup array of objects to call clone on */
+    /* This makes no difference to the implementation, as it always pushes
+       and shifts pointers to other SVs without changing their reference
+       count, with the array becoming empty before it is freed. However, it
+       makes it conceptually clear what is going on, and will avoid some
+       work inside av.c, filling slots between AvFILL() and AvMAX() with
+       &PL_sv_undef, and SvREFCNT_dec()ing those.  */
+    AvREAL_off(param->stashes);
+
+    if (!(flags & CLONEf_COPY_STACKS)) {
+       param->unreferenced = newAV();
+    }
+
+#ifdef PERLIO_LAYERS
+    /* Clone PerlIO tables as soon as we can handle general xx_dup() */
+    PerlIO_clone(aTHX_ proto_perl, param);
+#endif
+
+    PL_envgv           = gv_dup(proto_perl->Ienvgv, param);
+    PL_incgv           = gv_dup(proto_perl->Iincgv, param);
+    PL_hintgv          = gv_dup(proto_perl->Ihintgv, param);
+    PL_origfilename    = SAVEPV(proto_perl->Iorigfilename);
+    PL_diehook         = sv_dup_inc(proto_perl->Idiehook, param);
+    PL_warnhook                = sv_dup_inc(proto_perl->Iwarnhook, param);
+
+    /* switches */
+    PL_patchlevel      = sv_dup_inc(proto_perl->Ipatchlevel, param);
+    PL_apiversion      = sv_dup_inc(proto_perl->Iapiversion, param);
+    PL_inplace         = SAVEPV(proto_perl->Iinplace);
+    PL_e_script                = sv_dup_inc(proto_perl->Ie_script, param);
+
+    /* magical thingies */
+    PL_formfeed                = sv_dup(proto_perl->Iformfeed, param);
+
+    PL_encoding                = sv_dup(proto_perl->Iencoding, param);
+
+    sv_setpvs(PERL_DEBUG_PAD(0), "");  /* For regex debugging. */
+    sv_setpvs(PERL_DEBUG_PAD(1), "");  /* ext/re needs these */
+    sv_setpvs(PERL_DEBUG_PAD(2), "");  /* even without DEBUGGING. */
+
+   
+    /* Clone the regex array */
+    /* ORANGE FIXME for plugins, probably in the SV dup code.
+       newSViv(PTR2IV(CALLREGDUPE(
+       INT2PTR(REGEXP *, SvIVX(regex)), param))))
+    */
+    PL_regex_padav = av_dup_inc(proto_perl->Iregex_padav, param);
+    PL_regex_pad = AvARRAY(PL_regex_padav);
+
+    /* shortcuts to various I/O objects */
+    PL_ofsgv            = gv_dup_inc(proto_perl->Iofsgv, param);
+    PL_stdingv         = gv_dup(proto_perl->Istdingv, param);
+    PL_stderrgv                = gv_dup(proto_perl->Istderrgv, param);
+    PL_defgv           = gv_dup(proto_perl->Idefgv, param);
+    PL_argvgv          = gv_dup(proto_perl->Iargvgv, param);
+    PL_argvoutgv       = gv_dup(proto_perl->Iargvoutgv, param);
+    PL_argvout_stack   = av_dup_inc(proto_perl->Iargvout_stack, param);
+
+    /* shortcuts to regexp stuff */
+    PL_replgv          = gv_dup(proto_perl->Ireplgv, param);
+
+    /* shortcuts to misc objects */
+    PL_errgv           = gv_dup(proto_perl->Ierrgv, param);
+
+    /* shortcuts to debugging objects */
+    PL_DBgv            = gv_dup(proto_perl->IDBgv, param);
+    PL_DBline          = gv_dup(proto_perl->IDBline, param);
+    PL_DBsub           = gv_dup(proto_perl->IDBsub, param);
+    PL_DBsingle                = sv_dup(proto_perl->IDBsingle, param);
+    PL_DBtrace         = sv_dup(proto_perl->IDBtrace, param);
+    PL_DBsignal                = sv_dup(proto_perl->IDBsignal, param);
+
+    /* symbol tables */
+    PL_defstash                = hv_dup_inc(proto_perl->Idefstash, param);
+    PL_curstash                = hv_dup(proto_perl->Icurstash, param);
+    PL_debstash                = hv_dup(proto_perl->Idebstash, param);
+    PL_globalstash     = hv_dup(proto_perl->Iglobalstash, param);
+    PL_curstname       = sv_dup_inc(proto_perl->Icurstname, param);
+
+    PL_beginav         = av_dup_inc(proto_perl->Ibeginav, param);
+    PL_beginav_save    = av_dup_inc(proto_perl->Ibeginav_save, param);
+    PL_checkav_save    = av_dup_inc(proto_perl->Icheckav_save, param);
+    PL_unitcheckav      = av_dup_inc(proto_perl->Iunitcheckav, param);
+    PL_unitcheckav_save = av_dup_inc(proto_perl->Iunitcheckav_save, param);
+    PL_endav           = av_dup_inc(proto_perl->Iendav, param);
+    PL_checkav         = av_dup_inc(proto_perl->Icheckav, param);
+    PL_initav          = av_dup_inc(proto_perl->Iinitav, param);
+
+    PL_isarev          = hv_dup_inc(proto_perl->Iisarev, param);
+
+    /* subprocess state */
+    PL_fdpid           = av_dup_inc(proto_perl->Ifdpid, param);
+
+    if (proto_perl->Iop_mask)
+       PL_op_mask      = SAVEPVN(proto_perl->Iop_mask, PL_maxo);
+    else
+       PL_op_mask      = NULL;
+    /* PL_asserting        = proto_perl->Iasserting; */
+
+    /* current interpreter roots */
+    PL_main_cv         = cv_dup_inc(proto_perl->Imain_cv, param);
+    OP_REFCNT_LOCK;
+    PL_main_root       = OpREFCNT_inc(proto_perl->Imain_root);
+    OP_REFCNT_UNLOCK;
+
+    /* runtime control stuff */
+    PL_curcopdb                = (COP*)any_dup(proto_perl->Icurcopdb, proto_perl);
+
+    PL_preambleav      = av_dup_inc(proto_perl->Ipreambleav, param);
+
+    PL_ors_sv          = sv_dup_inc(proto_perl->Iors_sv, param);
+
+    /* interpreter atexit processing */
+    PL_exitlistlen     = proto_perl->Iexitlistlen;
+    if (PL_exitlistlen) {
+       Newx(PL_exitlist, PL_exitlistlen, PerlExitListEntry);
+       Copy(proto_perl->Iexitlist, PL_exitlist, PL_exitlistlen, PerlExitListEntry);
+    }
+    else
+       PL_exitlist     = (PerlExitListEntry*)NULL;
+
+    PL_my_cxt_size = proto_perl->Imy_cxt_size;
+    if (PL_my_cxt_size) {
+       Newx(PL_my_cxt_list, PL_my_cxt_size, void *);
+       Copy(proto_perl->Imy_cxt_list, PL_my_cxt_list, PL_my_cxt_size, void *);
+#ifdef PERL_GLOBAL_STRUCT_PRIVATE
+       Newx(PL_my_cxt_keys, PL_my_cxt_size, const char *);
+       Copy(proto_perl->Imy_cxt_keys, PL_my_cxt_keys, PL_my_cxt_size, char *);
+#endif
+    }
+    else {
+       PL_my_cxt_list  = (void**)NULL;
+#ifdef PERL_GLOBAL_STRUCT_PRIVATE
+       PL_my_cxt_keys  = (const char**)NULL;
+#endif
+    }
+    PL_modglobal       = hv_dup_inc(proto_perl->Imodglobal, param);
+    PL_custom_op_names  = hv_dup_inc(proto_perl->Icustom_op_names,param);
+    PL_custom_op_descs  = hv_dup_inc(proto_perl->Icustom_op_descs,param);
+    PL_custom_ops      = hv_dup_inc(proto_perl->Icustom_ops, param);
+
+    PL_compcv                  = cv_dup(proto_perl->Icompcv, param);
+
+    PAD_CLONE_VARS(proto_perl, param);
+
+#ifdef HAVE_INTERP_INTERN
+    sys_intern_dup(&proto_perl->Isys_intern, &PL_sys_intern);
+#endif
+
+    PL_DBcv            = cv_dup(proto_perl->IDBcv, param);
+
+#ifdef PERL_USES_PL_PIDSTATUS
+    PL_pidstatus       = newHV();                      /* XXX flag for cloning? */
+#endif
+    PL_osname          = SAVEPV(proto_perl->Iosname);
+    PL_parser          = parser_dup(proto_perl->Iparser, param);
+
+    /* XXX this only works if the saved cop has already been cloned */
+    if (proto_perl->Iparser) {
+       PL_parser->saved_curcop = (COP*)any_dup(
+                                   proto_perl->Iparser->saved_curcop,
+                                   proto_perl);
+    }
+
+    PL_subname         = sv_dup_inc(proto_perl->Isubname, param);
+
+#ifdef USE_LOCALE_COLLATE
+    PL_collation_name  = SAVEPV(proto_perl->Icollation_name);
+#endif /* USE_LOCALE_COLLATE */
+
+#ifdef USE_LOCALE_NUMERIC
+    PL_numeric_name    = SAVEPV(proto_perl->Inumeric_name);
+    PL_numeric_radix_sv        = sv_dup_inc(proto_perl->Inumeric_radix_sv, param);
+#endif /* !USE_LOCALE_NUMERIC */
+
+    /* utf8 character classes */
+    PL_utf8_alnum      = sv_dup_inc(proto_perl->Iutf8_alnum, param);
+    PL_utf8_alpha      = sv_dup_inc(proto_perl->Iutf8_alpha, param);
+    PL_utf8_space      = sv_dup_inc(proto_perl->Iutf8_space, param);
+    PL_utf8_graph      = sv_dup_inc(proto_perl->Iutf8_graph, param);
+    PL_utf8_digit      = sv_dup_inc(proto_perl->Iutf8_digit, param);
+    PL_utf8_upper      = sv_dup_inc(proto_perl->Iutf8_upper, param);
+    PL_utf8_lower      = sv_dup_inc(proto_perl->Iutf8_lower, param);
+    PL_utf8_print      = sv_dup_inc(proto_perl->Iutf8_print, param);
+    PL_utf8_punct      = sv_dup_inc(proto_perl->Iutf8_punct, param);
+    PL_utf8_xdigit     = sv_dup_inc(proto_perl->Iutf8_xdigit, param);
+    PL_utf8_mark       = sv_dup_inc(proto_perl->Iutf8_mark, param);
+    PL_utf8_X_begin    = sv_dup_inc(proto_perl->Iutf8_X_begin, param);
+    PL_utf8_X_extend   = sv_dup_inc(proto_perl->Iutf8_X_extend, param);
+    PL_utf8_X_prepend  = sv_dup_inc(proto_perl->Iutf8_X_prepend, param);
+    PL_utf8_X_non_hangul       = sv_dup_inc(proto_perl->Iutf8_X_non_hangul, param);
+    PL_utf8_X_L        = sv_dup_inc(proto_perl->Iutf8_X_L, param);
+    PL_utf8_X_LV       = sv_dup_inc(proto_perl->Iutf8_X_LV, param);
+    PL_utf8_X_LVT      = sv_dup_inc(proto_perl->Iutf8_X_LVT, param);
+    PL_utf8_X_T        = sv_dup_inc(proto_perl->Iutf8_X_T, param);
+    PL_utf8_X_V        = sv_dup_inc(proto_perl->Iutf8_X_V, param);
+    PL_utf8_X_LV_LVT_V = sv_dup_inc(proto_perl->Iutf8_X_LV_LVT_V, param);
+    PL_utf8_toupper    = sv_dup_inc(proto_perl->Iutf8_toupper, param);
+    PL_utf8_totitle    = sv_dup_inc(proto_perl->Iutf8_totitle, param);
+    PL_utf8_tolower    = sv_dup_inc(proto_perl->Iutf8_tolower, param);
+    PL_utf8_tofold     = sv_dup_inc(proto_perl->Iutf8_tofold, param);
+    PL_utf8_idstart    = sv_dup_inc(proto_perl->Iutf8_idstart, param);
+    PL_utf8_xidstart   = sv_dup_inc(proto_perl->Iutf8_xidstart, param);
+    PL_utf8_perl_idstart = sv_dup_inc(proto_perl->Iutf8_perl_idstart, param);
+    PL_utf8_idcont     = sv_dup_inc(proto_perl->Iutf8_idcont, param);
+    PL_utf8_xidcont    = sv_dup_inc(proto_perl->Iutf8_xidcont, param);
+    PL_utf8_foldable   = sv_dup_inc(proto_perl->Iutf8_foldable, param);
+
+
     if (proto_perl->Ipsig_pend) {
        Newxz(PL_psig_pend, SIG_SIZE, int);
     }
@@ -13302,13 +13261,7 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
        PL_psig_name    = (SV**)NULL;
     }
 
-    /* intrpvar.h stuff */
-
     if (flags & CLONEf_COPY_STACKS) {
-       /* next allocation will be PL_tmps_stack[PL_tmps_ix+1] */
-       PL_tmps_ix              = proto_perl->Itmps_ix;
-       PL_tmps_max             = proto_perl->Itmps_max;
-       PL_tmps_floor           = proto_perl->Itmps_floor;
        Newx(PL_tmps_stack, PL_tmps_max, SV*);
        sv_dup_inc_multiple(proto_perl->Itmps_stack, PL_tmps_stack,
                            PL_tmps_ix+1, param);
@@ -13325,8 +13278,6 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
 
        /* next push_scope()/ENTER sets PL_scopestack[PL_scopestack_ix]
         * NOTE: unlike the others! */
-       PL_scopestack_ix        = proto_perl->Iscopestack_ix;
-       PL_scopestack_max       = proto_perl->Iscopestack_max;
        Newxz(PL_scopestack, PL_scopestack_max, I32);
        Copy(proto_perl->Iscopestack, PL_scopestack, PL_scopestack_ix, I32);
 
@@ -13347,10 +13298,6 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
                                                   - proto_perl->Istack_base);
        PL_stack_max            = PL_stack_base + AvMAX(PL_curstack);
 
-       /* next SSPUSHFOO() sets PL_savestack[PL_savestack_ix]
-        * NOTE: unlike the others! */
-       PL_savestack_ix         = proto_perl->Isavestack_ix;
-       PL_savestack_max        = proto_perl->Isavestack_max;
        /*Newxz(PL_savestack, PL_savestack_max, ANY);*/
        PL_savestack            = ss_dup(proto_perl, param);
     }
@@ -13359,72 +13306,22 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
        ENTER;                  /* perl_destruct() wants to LEAVE; */
     }
 
-    PL_start_env       = proto_perl->Istart_env;       /* XXXXXX */
-    PL_top_env         = &PL_start_env;
-
-    PL_op              = proto_perl->Iop;
-
-    PL_Sv              = NULL;
-    PL_Xpv             = (XPV*)NULL;
-    my_perl->Ina       = proto_perl->Ina;
-
-    PL_statbuf         = proto_perl->Istatbuf;
-    PL_statcache       = proto_perl->Istatcache;
     PL_statgv          = gv_dup(proto_perl->Istatgv, param);
     PL_statname                = sv_dup_inc(proto_perl->Istatname, param);
-#ifdef HAS_TIMES
-    PL_timesbuf                = proto_perl->Itimesbuf;
-#endif
 
-    PL_tainted         = proto_perl->Itainted;
-    PL_curpm           = proto_perl->Icurpm;   /* XXX No PMOP ref count */
     PL_rs              = sv_dup_inc(proto_perl->Irs, param);
     PL_last_in_gv      = gv_dup(proto_perl->Ilast_in_gv, param);
     PL_defoutgv                = gv_dup_inc(proto_perl->Idefoutgv, param);
-    PL_chopset         = proto_perl->Ichopset; /* XXX never deallocated */
     PL_toptarget       = sv_dup_inc(proto_perl->Itoptarget, param);
     PL_bodytarget      = sv_dup_inc(proto_perl->Ibodytarget, param);
     PL_formtarget      = sv_dup(proto_perl->Iformtarget, param);
 
-    PL_restartjmpenv   = proto_perl->Irestartjmpenv;
-    PL_restartop       = proto_perl->Irestartop;
-    PL_in_eval         = proto_perl->Iin_eval;
-    PL_delaymagic      = proto_perl->Idelaymagic;
-    PL_phase           = proto_perl->Iphase;
-    PL_localizing      = proto_perl->Ilocalizing;
-
     PL_errors          = sv_dup_inc(proto_perl->Ierrors, param);
-    PL_hv_fetch_ent_mh = NULL;
-    PL_modcount                = proto_perl->Imodcount;
-    PL_lastgotoprobe   = NULL;
-    PL_dumpindent      = proto_perl->Idumpindent;
 
     PL_sortcop         = (OP*)any_dup(proto_perl->Isortcop, proto_perl);
     PL_sortstash       = hv_dup(proto_perl->Isortstash, param);
     PL_firstgv         = gv_dup(proto_perl->Ifirstgv, param);
     PL_secondgv                = gv_dup(proto_perl->Isecondgv, param);
-    PL_efloatbuf       = NULL;         /* reinits on demand */
-    PL_efloatsize      = 0;                    /* reinits on demand */
-
-    /* regex stuff */
-
-    PL_screamfirst     = NULL;
-    PL_screamnext      = NULL;
-    PL_maxscream       = -1;                   /* reinits on demand */
-    PL_lastscream      = NULL;
-
-
-    PL_regdummy                = proto_perl->Iregdummy;
-    PL_colorset                = 0;            /* reinits PL_colors[] */
-    /*PL_colors[6]     = {0,0,0,0,0,0};*/
-
-
-
-    /* Pluggable optimizer */
-    PL_peepp           = proto_perl->Ipeepp;
-    PL_rpeepp          = proto_perl->Irpeepp;
-    /* op_free() hook */
-    PL_opfreehook      = proto_perl->Iopfreehook;
 
     PL_stashcache       = newHV();
 
@@ -13933,6 +13830,19 @@ S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv,
                                    keysv, index, subscript_type);
       }
 
+    case OP_RV2SV:
+       if (cUNOPx(obase)->op_first->op_type == OP_GV) {
+           /* $global */
+           gv = cGVOPx_gv(cUNOPx(obase)->op_first);
+           if (!gv || !GvSTASH(gv))
+               break;
+           if (match && (GvSV(gv) != uninit_sv))
+               break;
+           return varname(gv, '$', 0, NULL, 0, FUV_SUBSCRIPT_NONE);
+       }
+       /* ${expr} */
+       return find_uninit_var(cUNOPx(obase)->op_first, uninit_sv, 1);
+
     case OP_PADSV:
        if (match && PAD_SVl(obase->op_targ) != uninit_sv)
            break;
@@ -13945,21 +13855,20 @@ S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv,
            break;
        return varname(gv, '$', 0, NULL, 0, FUV_SUBSCRIPT_NONE);
 
-    case OP_AELEMFAST:
-       if (obase->op_flags & OPf_SPECIAL) { /* lexical array */
-           if (match) {
-               SV **svp;
-               AV *av = MUTABLE_AV(PAD_SV(obase->op_targ));
-               if (!av || SvRMAGICAL(av))
-                   break;
-               svp = av_fetch(av, (I32)obase->op_private, FALSE);
-               if (!svp || *svp != uninit_sv)
-                   break;
-           }
-           return varname(NULL, '$', obase->op_targ,
-                   NULL, (I32)obase->op_private, FUV_SUBSCRIPT_ARRAY);
+    case OP_AELEMFAST_LEX:
+       if (match) {
+           SV **svp;
+           AV *av = MUTABLE_AV(PAD_SV(obase->op_targ));
+           if (!av || SvRMAGICAL(av))
+               break;
+           svp = av_fetch(av, (I32)obase->op_private, FALSE);
+           if (!svp || *svp != uninit_sv)
+               break;
        }
-       else {
+       return varname(NULL, '$', obase->op_targ,
+                      NULL, (I32)obase->op_private, FUV_SUBSCRIPT_ARRAY);
+    case OP_AELEMFAST:
+       {
            gv = cGVOPx_gv(obase);
            if (!gv)
                break;
@@ -13986,6 +13895,9 @@ S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv,
 
     case OP_AELEM:
     case OP_HELEM:
+    {
+       bool negate = FALSE;
+
        if (PL_op == obase)
            /* $a[uninit_expr] or $h{uninit_expr} */
            return find_uninit_var(cBINOPx(obase)->op_last, uninit_sv, match);
@@ -14011,28 +13923,43 @@ S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv,
        if (!sv)
            break;
 
+       if (kid && kid->op_type == OP_NEGATE) {
+           negate = TRUE;
+           kid = cUNOPx(kid)->op_first;
+       }
+
        if (kid && kid->op_type == OP_CONST && SvOK(cSVOPx_sv(kid))) {
            /* index is constant */
+           SV* kidsv;
+           if (negate) {
+               kidsv = sv_2mortal(newSVpvs("-"));
+               sv_catsv(kidsv, cSVOPx_sv(kid));
+           }
+           else
+               kidsv = cSVOPx_sv(kid);
            if (match) {
                if (SvMAGICAL(sv))
                    break;
                if (obase->op_type == OP_HELEM) {
-                   HE* he = hv_fetch_ent(MUTABLE_HV(sv), cSVOPx_sv(kid), 0, 0);
+                   HE* he = hv_fetch_ent(MUTABLE_HV(sv), kidsv, 0, 0);
                    if (!he || HeVAL(he) != uninit_sv)
                        break;
                }
                else {
-                   SV * const * const svp = av_fetch(MUTABLE_AV(sv), SvIV(cSVOPx_sv(kid)), FALSE);
+                   SV * const * const svp = av_fetch(MUTABLE_AV(sv),
+                       negate ? - SvIV(cSVOPx_sv(kid)) : SvIV(cSVOPx_sv(kid)),
+                       FALSE);
                    if (!svp || *svp != uninit_sv)
                        break;
                }
            }
            if (obase->op_type == OP_HELEM)
                return varname(gv, '%', o->op_targ,
-                           cSVOPx_sv(kid), 0, FUV_SUBSCRIPT_HASH);
+                           kidsv, 0, FUV_SUBSCRIPT_HASH);
            else
                return varname(gv, '@', o->op_targ, NULL,
-                           SvIV(cSVOPx_sv(kid)), FUV_SUBSCRIPT_ARRAY);
+                   negate ? - SvIV(cSVOPx_sv(kid)) : SvIV(cSVOPx_sv(kid)),
+                   FUV_SUBSCRIPT_ARRAY);
        }
        else  {
            /* index is an expression;
@@ -14058,6 +13985,7 @@ S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv,
                o->op_targ, NULL, 0, FUV_SUBSCRIPT_WITHIN);
        }
        break;
+    }
 
     case OP_AASSIGN:
        /* only examine RHS */
@@ -14114,7 +14042,6 @@ S_find_uninit_var(pTHX_ const OP *const obase, const SV *const uninit_sv,
 
 
     case OP_ENTEREVAL: /* could be eval $undef or $x='$undef'; eval $x */
-    case OP_RV2SV:
     case OP_CUSTOM: /* XS or custom code could trigger random warnings */
 
        /* the following ops are capable of returning PL_sv_undef even for