This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Change of email address.
[perl5.git] / mg.c
diff --git a/mg.c b/mg.c
index b477386..30ac035 100644 (file)
--- a/mg.c
+++ b/mg.c
@@ -1,7 +1,7 @@
 /*    mg.c
  *
  *    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- *    2000, 2001, 2002, 2003, 2004, 2005, 2006, by Larry Wall and others
+ *    2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, by Larry Wall and others
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
@@ -56,7 +56,7 @@ tie.
 #endif
 
 #if defined(HAS_SIGACTION) && defined(SA_SIGINFO)
-Signal_t Perl_csighandler(int sig, ...);
+Signal_t Perl_csighandler(int sig, siginfo_t *, void *);
 #else
 Signal_t Perl_csighandler(int sig);
 #endif
@@ -85,6 +85,9 @@ S_save_magic(pTHX_ I32 mgs_ix, SV *sv)
 {
     dVAR;
     MGS* mgs;
+
+    PERL_ARGS_ASSERT_SAVE_MAGIC;
+
     assert(SvMAGICAL(sv));
     /* Turning READONLY off for a copy-on-write scalar (including shared
        hash keys) is a bad idea.  */
@@ -100,7 +103,10 @@ S_save_magic(pTHX_ I32 mgs_ix, SV *sv)
 
     SvMAGICAL_off(sv);
     SvREADONLY_off(sv);
-    SvFLAGS(sv) |= (SvFLAGS(sv) & (SVp_IOK|SVp_NOK|SVp_POK)) >> PRIVSHIFT;
+    if (!(SvFLAGS(sv) & (SVf_IOK|SVf_NOK|SVf_POK))) {
+       /* No public flags are set, so promote any private flags to public.  */
+       SvFLAGS(sv) |= (SvFLAGS(sv) & (SVp_IOK|SVp_NOK|SVp_POK)) >> PRIVSHIFT;
+    }
 }
 
 /*
@@ -115,17 +121,57 @@ void
 Perl_mg_magical(pTHX_ SV *sv)
 {
     const MAGIC* mg;
+    PERL_ARGS_ASSERT_MG_MAGICAL;
     PERL_UNUSED_CONTEXT;
-    for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
-       const MGVTBL* const vtbl = mg->mg_virtual;
-       if (vtbl) {
-           if (vtbl->svt_get && !(mg->mg_flags & MGf_GSKIP))
-               SvGMAGICAL_on(sv);
-           if (vtbl->svt_set)
-               SvSMAGICAL_on(sv);
-           if (!(SvFLAGS(sv) & (SVs_GMG|SVs_SMG)) || vtbl->svt_clear)
-               SvRMAGICAL_on(sv);
-       }
+    if ((mg = SvMAGIC(sv))) {
+       SvRMAGICAL_off(sv);
+       do {
+           const MGVTBL* const vtbl = mg->mg_virtual;
+           if (vtbl) {
+               if (vtbl->svt_get && !(mg->mg_flags & MGf_GSKIP))
+                   SvGMAGICAL_on(sv);
+               if (vtbl->svt_set)
+                   SvSMAGICAL_on(sv);
+               if (vtbl->svt_clear)
+                   SvRMAGICAL_on(sv);
+           }
+       } while ((mg = mg->mg_moremagic));
+       if (!(SvFLAGS(sv) & (SVs_GMG|SVs_SMG)))
+           SvRMAGICAL_on(sv);
+    }
+}
+
+
+/* is this container magic (%ENV, $1 etc), or value magic (pos, taint etc)? */
+
+STATIC bool
+S_is_container_magic(const MAGIC *mg)
+{
+    assert(mg);
+    switch (mg->mg_type) {
+    case PERL_MAGIC_bm:
+    case PERL_MAGIC_fm:
+    case PERL_MAGIC_regex_global:
+    case PERL_MAGIC_nkeys:
+#ifdef USE_LOCALE_COLLATE
+    case PERL_MAGIC_collxfrm:
+#endif
+    case PERL_MAGIC_qr:
+    case PERL_MAGIC_taint:
+    case PERL_MAGIC_vec:
+    case PERL_MAGIC_vstring:
+    case PERL_MAGIC_utf8:
+    case PERL_MAGIC_substr:
+    case PERL_MAGIC_defelem:
+    case PERL_MAGIC_arylen:
+    case PERL_MAGIC_pos:
+    case PERL_MAGIC_backref:
+    case PERL_MAGIC_arylen_p:
+    case PERL_MAGIC_rhash:
+    case PERL_MAGIC_symtab:
+       return 0;
+    default:
+       return 1;
     }
 }
 
@@ -148,6 +194,8 @@ Perl_mg_get(pTHX_ SV *sv)
     /* guard against sv having being freed midway by holding a private
        reference. */
 
+    PERL_ARGS_ASSERT_MG_GET;
+
     /* sv_2mortal has this side effect of turning on the TEMP flag, which can
        cause the SV's buffer to get stolen (and maybe other stuff).
        So restore it.
@@ -226,6 +274,8 @@ Perl_mg_set(pTHX_ SV *sv)
     MAGIC* mg;
     MAGIC* nextmg;
 
+    PERL_ARGS_ASSERT_MG_SET;
+
     save_magic(mgs_ix, sv);
 
     for (mg = SvMAGIC(sv); mg; mg = nextmg) {
@@ -235,6 +285,8 @@ Perl_mg_set(pTHX_ SV *sv)
            mg->mg_flags &= ~MGf_GSKIP; /* setting requires another read */
            (SSPTR(mgs_ix, MGS*))->mgs_flags = 0;
        }
+       if (PL_localizing == 2 && !S_is_container_magic(mg))
+           continue;
        if (vtbl && vtbl->svt_set)
            CALL_FPTR(vtbl->svt_set)(aTHX_ sv, mg);
     }
@@ -258,6 +310,8 @@ Perl_mg_length(pTHX_ SV *sv)
     MAGIC* mg;
     STRLEN len;
 
+    PERL_ARGS_ASSERT_MG_LENGTH;
+
     for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
         const MGVTBL * const vtbl = mg->mg_virtual;
        if (vtbl && vtbl->svt_len) {
@@ -270,12 +324,15 @@ Perl_mg_length(pTHX_ SV *sv)
        }
     }
 
-    if (DO_UTF8(sv)) {
+    {
+       /* You can't know whether it's UTF-8 until you get the string again...
+        */
         const U8 *s = (U8*)SvPV_const(sv, len);
-       len = utf8_length(s, s + len);
+
+       if (DO_UTF8(sv)) {
+           len = utf8_length(s, s + len);
+       }
     }
-    else
-        (void)SvPV_const(sv, len);
     return len;
 }
 
@@ -284,6 +341,8 @@ Perl_mg_size(pTHX_ SV *sv)
 {
     MAGIC* mg;
 
+    PERL_ARGS_ASSERT_MG_SIZE;
+
     for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
         const MGVTBL* const vtbl = mg->mg_virtual;
        if (vtbl && vtbl->svt_len) {
@@ -323,6 +382,8 @@ Perl_mg_clear(pTHX_ SV *sv)
     const I32 mgs_ix = SSNEW(sizeof(MGS));
     MAGIC* mg;
 
+    PERL_ARGS_ASSERT_MG_CLEAR;
+
     save_magic(mgs_ix, sv);
 
     for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
@@ -372,6 +433,9 @@ Perl_mg_copy(pTHX_ SV *sv, SV *nsv, const char *key, I32 klen)
 {
     int count = 0;
     MAGIC* mg;
+
+    PERL_ARGS_ASSERT_MG_COPY;
+
     for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
         const MGVTBL* const vtbl = mg->mg_virtual;
        if ((mg->mg_flags & MGf_COPY) && vtbl->svt_copy){
@@ -409,32 +473,13 @@ Perl_mg_localize(pTHX_ SV *sv, SV *nsv)
 {
     dVAR;
     MAGIC *mg;
+
+    PERL_ARGS_ASSERT_MG_LOCALIZE;
+
     for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
-       MGVTBL* const vtbl = mg->mg_virtual;
-       switch (mg->mg_type) {
-       /* value magic types: don't copy */
-       case PERL_MAGIC_bm:
-       case PERL_MAGIC_fm:
-       case PERL_MAGIC_regex_global:
-       case PERL_MAGIC_nkeys:
-#ifdef USE_LOCALE_COLLATE
-       case PERL_MAGIC_collxfrm:
-#endif
-       case PERL_MAGIC_qr:
-       case PERL_MAGIC_taint:
-       case PERL_MAGIC_vec:
-       case PERL_MAGIC_vstring:
-       case PERL_MAGIC_utf8:
-       case PERL_MAGIC_substr:
-       case PERL_MAGIC_defelem:
-       case PERL_MAGIC_arylen:
-       case PERL_MAGIC_pos:
-       case PERL_MAGIC_backref:
-       case PERL_MAGIC_arylen_p:
-       case PERL_MAGIC_rhash:
-       case PERL_MAGIC_symtab:
+       const MGVTBL* const vtbl = mg->mg_virtual;
+       if (!S_is_container_magic(mg))
            continue;
-       }
                
        if ((mg->mg_flags & MGf_LOCAL) && vtbl->svt_local)
            (void)CALL_FPTR(vtbl->svt_local)(aTHX_ nsv, mg);
@@ -467,6 +512,9 @@ Perl_mg_free(pTHX_ SV *sv)
 {
     MAGIC* mg;
     MAGIC* moremagic;
+
+    PERL_ARGS_ASSERT_MG_FREE;
+
     for (mg = SvMAGIC(sv); mg; mg = moremagic) {
         const MGVTBL* const vtbl = mg->mg_virtual;
        moremagic = mg->mg_moremagic;
@@ -481,8 +529,10 @@ Perl_mg_free(pTHX_ SV *sv)
        if (mg->mg_flags & MGf_REFCOUNTED)
            SvREFCNT_dec(mg->mg_obj);
        Safefree(mg);
+       SvMAGIC_set(sv, moremagic);
     }
     SvMAGIC_set(sv, NULL);
+    SvMAGICAL_off(sv);
     return 0;
 }
 
@@ -494,12 +544,24 @@ Perl_magic_regdata_cnt(pTHX_ SV *sv, MAGIC *mg)
     dVAR;
     PERL_UNUSED_ARG(sv);
 
+    PERL_ARGS_ASSERT_MAGIC_REGDATA_CNT;
+
     if (PL_curpm) {
        register const REGEXP * const rx = PM_GETRE(PL_curpm);
        if (rx) {
-           return mg->mg_obj
-               ? rx->nparens       /* @+ */
-               : rx->lastparen;    /* @- */
+           if (mg->mg_obj) {                   /* @+ */
+               /* return the number possible */
+               return RX_NPARENS(rx);
+           } else {                            /* @- */
+               I32 paren = RX_LASTPAREN(rx);
+
+               /* return the last filled */
+               while ( paren >= 0
+                       && (RX_OFFS(rx)[paren].start == -1
+                           || RX_OFFS(rx)[paren].end == -1) )
+                   paren--;
+               return (U32)paren;
+           }
        }
     }
 
@@ -510,6 +572,9 @@ int
 Perl_magic_regdatum_get(pTHX_ SV *sv, MAGIC *mg)
 {
     dVAR;
+
+    PERL_ARGS_ASSERT_MAGIC_REGDATUM_GET;
+
     if (PL_curpm) {
        register const REGEXP * const rx = PM_GETRE(PL_curpm);
        if (rx) {
@@ -518,9 +583,9 @@ Perl_magic_regdatum_get(pTHX_ SV *sv, MAGIC *mg)
            register I32 t;
            if (paren < 0)
                return 0;
-           if (paren <= (I32)rx->nparens &&
-               (s = rx->startp[paren]) != -1 &&
-               (t = rx->endp[paren]) != -1)
+           if (paren <= (I32)RX_NPARENS(rx) &&
+               (s = RX_OFFS(rx)[paren].start) != -1 &&
+               (t = RX_OFFS(rx)[paren].end) != -1)
                {
                    register I32 i;
                    if (mg->mg_obj)             /* @+ */
@@ -529,7 +594,7 @@ Perl_magic_regdatum_get(pTHX_ SV *sv, MAGIC *mg)
                        i = s;
 
                    if (i > 0 && RX_MATCH_UTF8(rx)) {
-                       const char * const b = rx->subbeg;
+                       const char * const b = RX_SUBBEG(rx);
                        if (b)
                            i = utf8_length((U8*)b, (U8*)(b+i));
                    }
@@ -544,6 +609,7 @@ Perl_magic_regdatum_get(pTHX_ SV *sv, MAGIC *mg)
 int
 Perl_magic_regdatum_set(pTHX_ SV *sv, MAGIC *mg)
 {
+    PERL_ARGS_ASSERT_MAGIC_REGDATUM_SET;
     PERL_UNUSED_ARG(sv);
     PERL_UNUSED_ARG(mg);
     Perl_croak(aTHX_ PL_no_modify);
@@ -556,83 +622,69 @@ Perl_magic_len(pTHX_ SV *sv, MAGIC *mg)
     dVAR;
     register I32 paren;
     register I32 i;
-    register const REGEXP *rx;
-    I32 s1, t1;
+    register const REGEXP * rx;
+    const char * const remaining = mg->mg_ptr + 1;
+
+    PERL_ARGS_ASSERT_MAGIC_LEN;
 
     switch (*mg->mg_ptr) {
+    case '\020':               
+      if (*remaining == '\0') { /* ^P */
+          break;
+      } else if (strEQ(remaining, "REMATCH")) { /* $^PREMATCH */
+          goto do_prematch;
+      } else if (strEQ(remaining, "OSTMATCH")) { /* $^POSTMATCH */
+          goto do_postmatch;
+      }
+      break;
+    case '\015': /* $^MATCH */
+       if (strEQ(remaining, "ATCH")) {
+        goto do_match;
+    } else {
+        break;
+    }
+    case '`':
+      do_prematch:
+      paren = RX_BUFF_IDX_PREMATCH;
+      goto maybegetparen;
+    case '\'':
+      do_postmatch:
+      paren = RX_BUFF_IDX_POSTMATCH;
+      goto maybegetparen;
+    case '&':
+      do_match:
+      paren = RX_BUFF_IDX_FULLMATCH;
+      goto maybegetparen;
     case '1': case '2': case '3': case '4':
-    case '5': case '6': case '7': case '8': case '9': case '&':
+    case '5': case '6': case '7': case '8': case '9':
+      paren = atoi(mg->mg_ptr);
+    maybegetparen:
        if (PL_curpm && (rx = PM_GETRE(PL_curpm))) {
+      getparen:
+        i = CALLREG_NUMBUF_LENGTH((REGEXP * const)rx, sv, paren);
 
-           paren = atoi(mg->mg_ptr); /* $& is in [0] */
-         getparen:
-           if (paren <= (I32)rx->nparens &&
-               (s1 = rx->startp[paren]) != -1 &&
-               (t1 = rx->endp[paren]) != -1)
-           {
-               i = t1 - s1;
-             getlen:
-               if (i > 0 && RX_MATCH_UTF8(rx)) {
-                   const char * const s = rx->subbeg + s1;
-                   const U8 *ep;
-                   STRLEN el;
-
-                    i = t1 - s1;
-                   if (is_utf8_string_loclen((U8*)s, i, &ep, &el))
-                       i = el;
-               }
                if (i < 0)
                    Perl_croak(aTHX_ "panic: magic_len: %"IVdf, (IV)i);
                return i;
-           }
-           else {
+       } else {
                if (ckWARN(WARN_UNINITIALIZED))
                    report_uninit(sv);
-           }
-       }
-       else {
-           if (ckWARN(WARN_UNINITIALIZED))
-               report_uninit(sv);
+               return 0;
        }
-       return 0;
     case '+':
        if (PL_curpm && (rx = PM_GETRE(PL_curpm))) {
-           paren = rx->lastparen;
+           paren = RX_LASTPAREN(rx);
            if (paren)
                goto getparen;
        }
        return 0;
     case '\016': /* ^N */
        if (PL_curpm && (rx = PM_GETRE(PL_curpm))) {
-           paren = rx->lastcloseparen;
+           paren = RX_LASTCLOSEPAREN(rx);
            if (paren)
                goto getparen;
        }
        return 0;
-    case '`':
-       if (PL_curpm && (rx = PM_GETRE(PL_curpm))) {
-           if (rx->startp[0] != -1) {
-               i = rx->startp[0];
-               if (i > 0) {
-                   s1 = 0;
-                   t1 = i;
-                   goto getlen;
-               }
-           }
-       }
-       return 0;
-    case '\'':
-       if (PL_curpm && (rx = PM_GETRE(PL_curpm))) {
-           if (rx->endp[0] != -1) {
-               i = rx->sublen - rx->endp[0];
-               if (i > 0) {
-                   s1 = rx->endp[0];
-                   t1 = rx->sublen;
-                   goto getlen;
-               }
-           }
-       }
-       return 0;
     }
     magic_get(sv,mg);
     if (!SvPOK(sv) && SvNIOK(sv)) {
@@ -654,17 +706,46 @@ Perl_magic_len(pTHX_ SV *sv, MAGIC *mg)
     } \
 } STMT_END
 
+void
+Perl_emulate_cop_io(pTHX_ const COP *const c, SV *const sv)
+{
+    PERL_ARGS_ASSERT_EMULATE_COP_IO;
+
+    if (!(CopHINTS_get(c) & (HINT_LEXICAL_IO_IN|HINT_LEXICAL_IO_OUT)))
+       sv_setsv(sv, &PL_sv_undef);
+    else {
+       sv_setpvs(sv, "");
+       SvUTF8_off(sv);
+       if ((CopHINTS_get(c) & HINT_LEXICAL_IO_IN)) {
+           SV *const value = Perl_refcounted_he_fetch(aTHX_
+                                                      c->cop_hints_hash,
+                                                      0, "open<", 5, 0, 0);
+           assert(value);
+           sv_catsv(sv, value);
+       }
+       sv_catpvs(sv, "\0");
+       if ((CopHINTS_get(c) & HINT_LEXICAL_IO_OUT)) {
+           SV *const value = Perl_refcounted_he_fetch(aTHX_
+                                                      c->cop_hints_hash,
+                                                      0, "open>", 5, 0, 0);
+           assert(value);
+           sv_catsv(sv, value);
+       }
+    }
+}
+
 int
 Perl_magic_get(pTHX_ SV *sv, MAGIC *mg)
 {
     dVAR;
     register I32 paren;
     register char *s = NULL;
-    register I32 i;
     register REGEXP *rx;
     const char * const remaining = mg->mg_ptr + 1;
     const char nextchar = *remaining;
 
+    PERL_ARGS_ASSERT_MAGIC_GET;
+
     switch (*mg->mg_ptr) {
     case '\001':               /* ^A */
        sv_setsv(sv, PL_bodytarget);
@@ -747,10 +828,7 @@ Perl_magic_get(pTHX_ SV *sv, MAGIC *mg)
        sv_setiv(sv, (IV)PL_hints);
        break;
     case '\011':               /* ^I */ /* NOT \t in EBCDIC */
-       if (PL_inplace)
-           sv_setpv(sv, PL_inplace);
-       else
-           sv_setsv(sv, &PL_sv_undef);
+       sv_setpv(sv, PL_inplace); /* Will undefine sv if PL_inplace is NULL */
        break;
     case '\017':               /* ^O & ^OPEN */
        if (nextchar == '\0') {
@@ -758,22 +836,21 @@ Perl_magic_get(pTHX_ SV *sv, MAGIC *mg)
            SvTAINTED_off(sv);
        }
        else if (strEQ(remaining, "PEN")) {
-           if (!(CopHINTS_get(&PL_compiling) & HINT_LEXICAL_IO))
-               sv_setsv(sv, &PL_sv_undef);
-            else {
-               sv_setsv(sv,
-                        Perl_refcounted_he_fetch(aTHX_
-                                                 PL_compiling.cop_hints_hash,
-                                                 0, "open", 4, 0, 0));
-           }
+           Perl_emulate_cop_io(aTHX_ &PL_compiling, sv);
        }
        break;
-    case '\020':               /* ^P */
-       sv_setiv(sv, (IV)PL_perldb);
+    case '\020':               
+       if (nextchar == '\0') {       /* ^P */
+           sv_setiv(sv, (IV)PL_perldb);
+       } else if (strEQ(remaining, "REMATCH")) { /* $^PREMATCH */
+           goto do_prematch_fetch;
+       } else if (strEQ(remaining, "OSTMATCH")) { /* $^POSTMATCH */
+           goto do_postmatch_fetch;
+       }
        break;
     case '\023':               /* ^S */
        if (nextchar == '\0') {
-           if (PL_lex_state != LEX_NOTPARSING)
+           if (PL_parser && PL_parser->lex_state != LEX_NOTPARSING)
                SvOK_off(sv);
            else if (PL_in_eval)
                sv_setiv(sv, PL_in_eval & ~(EVAL_INREQUIRE));
@@ -836,87 +913,54 @@ Perl_magic_get(pTHX_ SV *sv, MAGIC *mg)
            SvPOK_only(sv);
        }
        break;
+    case '\015': /* $^MATCH */
+       if (strEQ(remaining, "ATCH")) {
     case '1': case '2': case '3': case '4':
     case '5': case '6': case '7': case '8': case '9': case '&':
-       if (PL_curpm && (rx = PM_GETRE(PL_curpm))) {
-           I32 s1, t1;
-
-           /*
-            * Pre-threads, this was paren = atoi(GvENAME((GV*)mg->mg_obj));
-            * XXX Does the new way break anything?
-            */
-           paren = atoi(mg->mg_ptr); /* $& is in [0] */
-         getparen:
-           if (paren <= (I32)rx->nparens &&
-               (s1 = rx->startp[paren]) != -1 &&
-               (t1 = rx->endp[paren]) != -1)
-           {
-               i = t1 - s1;
-               s = rx->subbeg + s1;
-               assert(rx->subbeg);
-
-             getrx:
-               if (i >= 0) {
-                   const int oldtainted = PL_tainted;
-                   TAINT_NOT;
-                   sv_setpvn(sv, s, i);
-                   PL_tainted = oldtainted;
-                   if (RX_MATCH_UTF8(rx) && is_utf8_string((U8*)s, i))
-                       SvUTF8_on(sv);
-                   else
-                       SvUTF8_off(sv);
-                   if (PL_tainting) {
-                       if (RX_MATCH_TAINTED(rx)) {
-                           MAGIC* const mg = SvMAGIC(sv);
-                           MAGIC* mgt;
-                           PL_tainted = 1;
-                           SvMAGIC_set(sv, mg->mg_moremagic);
-                           SvTAINT(sv);
-                           if ((mgt = SvMAGIC(sv))) {
-                               mg->mg_moremagic = mgt;
-                               SvMAGIC_set(sv, mg);
-                           }
-                       } else
-                           SvTAINTED_off(sv);
-                   }
-                   break;
-               }
+           if (PL_curpm && (rx = PM_GETRE(PL_curpm))) {
+               /*
+                * Pre-threads, this was paren = atoi(GvENAME((GV*)mg->mg_obj));
+                * XXX Does the new way break anything?
+                */
+               paren = atoi(mg->mg_ptr); /* $& is in [0] */
+               CALLREG_NUMBUF_FETCH(rx,paren,sv);
+               break;
            }
+           sv_setsv(sv,&PL_sv_undef);
        }
-       sv_setsv(sv,&PL_sv_undef);
        break;
     case '+':
        if (PL_curpm && (rx = PM_GETRE(PL_curpm))) {
-           paren = rx->lastparen;
-           if (paren)
-               goto getparen;
+           if (RX_LASTPAREN(rx)) {
+               CALLREG_NUMBUF_FETCH(rx,RX_LASTPAREN(rx),sv);
+               break;
+           }
        }
        sv_setsv(sv,&PL_sv_undef);
        break;
     case '\016':               /* ^N */
        if (PL_curpm && (rx = PM_GETRE(PL_curpm))) {
-           paren = rx->lastcloseparen;
-           if (paren)
-               goto getparen;
+           if (RX_LASTCLOSEPAREN(rx)) {
+               CALLREG_NUMBUF_FETCH(rx,RX_LASTCLOSEPAREN(rx),sv);
+               break;
+           }
+
        }
        sv_setsv(sv,&PL_sv_undef);
        break;
     case '`':
+      do_prematch_fetch:
        if (PL_curpm && (rx = PM_GETRE(PL_curpm))) {
-           if ((s = rx->subbeg) && rx->startp[0] != -1) {
-               i = rx->startp[0];
-               goto getrx;
-           }
+           CALLREG_NUMBUF_FETCH(rx,-2,sv);
+           break;
        }
        sv_setsv(sv,&PL_sv_undef);
        break;
     case '\'':
+      do_postmatch_fetch:
        if (PL_curpm && (rx = PM_GETRE(PL_curpm))) {
-           if (rx->subbeg && rx->endp[0] != -1) {
-               s = rx->subbeg + rx->endp[0];
-               i = rx->sublen - rx->endp[0];
-               goto getrx;
-           }
+           CALLREG_NUMBUF_FETCH(rx,-1,sv);
+           break;
        }
        sv_setsv(sv,&PL_sv_undef);
        break;
@@ -941,7 +985,7 @@ Perl_magic_get(pTHX_ SV *sv, MAGIC *mg)
            sv_setpv(sv,s);
        else {
            sv_setpv(sv,GvENAME(PL_defoutgv));
-           sv_catpv(sv,"_TOP");
+           sv_catpvs(sv,"_TOP");
        }
        break;
     case '~':
@@ -1038,6 +1082,8 @@ Perl_magic_getuvar(pTHX_ SV *sv, MAGIC *mg)
 {
     struct ufuncs * const uf = (struct ufuncs *)mg->mg_ptr;
 
+    PERL_ARGS_ASSERT_MAGIC_GETUVAR;
+
     if (uf && uf->uf_val)
        (*uf->uf_val)(aTHX_ uf->uf_index, sv);
     return 0;
@@ -1052,6 +1098,8 @@ Perl_magic_setenv(pTHX_ SV *sv, MAGIC *mg)
     const char * const ptr = MgPV_const(mg,klen);
     my_setenv(ptr, s);
 
+    PERL_ARGS_ASSERT_MAGIC_SETENV;
+
 #ifdef DYNAMIC_ENV_FETCH
      /* We just undefd an environment var.  Is a replacement */
      /* waiting in the wings? */
@@ -1131,6 +1179,7 @@ Perl_magic_setenv(pTHX_ SV *sv, MAGIC *mg)
 int
 Perl_magic_clearenv(pTHX_ SV *sv, MAGIC *mg)
 {
+    PERL_ARGS_ASSERT_MAGIC_CLEARENV;
     PERL_UNUSED_ARG(sv);
     my_setenv(MgPV_nolen_const(mg),NULL);
     return 0;
@@ -1140,6 +1189,7 @@ int
 Perl_magic_set_all_env(pTHX_ SV *sv, MAGIC *mg)
 {
     dVAR;
+    PERL_ARGS_ASSERT_MAGIC_SET_ALL_ENV;
     PERL_UNUSED_ARG(mg);
 #if defined(VMS)
     Perl_die(aTHX_ "Can't make list assignment to %%ENV on this system");
@@ -1162,6 +1212,7 @@ int
 Perl_magic_clear_all_env(pTHX_ SV *sv, MAGIC *mg)
 {
     dVAR;
+    PERL_ARGS_ASSERT_MAGIC_CLEAR_ALL_ENV;
     PERL_UNUSED_ARG(sv);
     PERL_UNUSED_ARG(mg);
 #if defined(VMS)
@@ -1187,6 +1238,9 @@ Perl_magic_getsig(pTHX_ SV *sv, MAGIC *mg)
     dVAR;
     /* Are we fetching a signal entry? */
     const I32 i = whichsig(MgPV_nolen_const(mg));
+
+    PERL_ARGS_ASSERT_MAGIC_GETSIG;
+
     if (i > 0) {
        if(PL_psig_ptr[i])
            sv_setsv(sv,PL_psig_ptr[i]);
@@ -1202,7 +1256,7 @@ Perl_magic_getsig(pTHX_ SV *sv, MAGIC *mg)
 #endif
            /* cache state so we don't fetch it again */
            if(sigstate == (Sighandler_t) SIG_IGN)
-               sv_setpv(sv,"IGNORE");
+               sv_setpvs(sv,"IGNORE");
            else
                sv_setsv(sv,&PL_sv_undef);
            PL_psig_ptr[i] = SvREFCNT_inc_simple_NN(sv);
@@ -1219,6 +1273,7 @@ Perl_magic_clearsig(pTHX_ SV *sv, MAGIC *mg)
      */
     dVAR;
     register const char * const s = MgPV_nolen_const(mg);
+    PERL_ARGS_ASSERT_MAGIC_CLEARSIG;
     PERL_UNUSED_ARG(sv);
     if (*s == '_') {
        SV** svp = NULL;
@@ -1244,7 +1299,7 @@ Perl_magic_clearsig(pTHX_ SV *sv, MAGIC *mg)
            sigaddset(&set,i);
            sigprocmask(SIG_BLOCK, &set, &save);
            ENTER;
-           save_sv = newSVpv((char *)(&save), sizeof(sigset_t));
+           save_sv = newSVpvn((char *)(&save), sizeof(sigset_t));
            SAVEFREESV(save_sv);
            SAVEDESTRUCTOR_X(restore_sigmask, save_sv);
 #endif
@@ -1275,19 +1330,9 @@ Perl_magic_clearsig(pTHX_ SV *sv, MAGIC *mg)
     return 0;
 }
 
-static void
-S_raise_signal(pTHX_ int sig)
-{
-    dVAR;
-    /* Set a flag to say this signal is pending */
-    PL_psig_pend[sig]++;
-    /* And one to say _a_ signal is pending */
-    PL_sig_pending = 1;
-}
-
 Signal_t
 #if defined(HAS_SIGACTION) && defined(SA_SIGINFO)
-Perl_csighandler(int sig, ...)
+Perl_csighandler(int sig, siginfo_t *sip PERL_UNUSED_DECL, void *uap PERL_UNUSED_DECL)
 #else
 Perl_csighandler(int sig)
 #endif
@@ -1309,7 +1354,7 @@ Perl_csighandler(int sig)
             exit(1);
 #endif
 #endif
-   if (
+    if (
 #ifdef SIGILL
           sig == SIGILL ||
 #endif
@@ -1322,9 +1367,24 @@ Perl_csighandler(int sig)
           (PL_signals & PERL_SIGNALS_UNSAFE_FLAG))
        /* Call the perl level handler now--
         * with risk we may be in malloc() etc. */
+#if defined(HAS_SIGACTION) && defined(SA_SIGINFO)
+       (*PL_sighandlerp)(sig, NULL, NULL);
+#else
        (*PL_sighandlerp)(sig);
-   else
-       S_raise_signal(aTHX_ sig);
+#endif
+    else {
+       /* Set a flag to say this signal is pending, that is awaiting delivery after
+        * the current Perl opcode completes */
+       PL_psig_pend[sig]++;
+
+#ifndef SIG_PENDING_DIE_COUNT
+#  define SIG_PENDING_DIE_COUNT 120
+#endif
+       /* And one to say _a_ signal is pending */
+       if (++PL_sig_pending >= SIG_PENDING_DIE_COUNT)
+           Perl_croak(aTHX_ "Maximal count of pending signals (%lu) exceeded",
+                      (unsigned long)SIG_PENDING_DIE_COUNT);
+    }
 }
 
 #if defined(FAKE_PERSISTENT_SIGNAL_HANDLERS) || defined(FAKE_DEFAULT_SIGNAL_HANDLERS)
@@ -1359,7 +1419,11 @@ Perl_despatch_signals(pTHX)
            PERL_BLOCKSIG_ADD(set, sig);
            PL_psig_pend[sig] = 0;
            PERL_BLOCKSIG_BLOCK(set);
+#if defined(HAS_SIGACTION) && defined(SA_SIGINFO)
+           (*PL_sighandlerp)(sig, NULL, NULL);
+#else
            (*PL_sighandlerp)(sig);
+#endif
            PERL_BLOCKSIG_UNBLOCK(set);
        }
     }
@@ -1381,8 +1445,10 @@ Perl_magic_setsig(pTHX_ SV *sv, MAGIC *mg)
     sigset_t set, save;
     SV* save_sv;
 #endif
-
     register const char *s = MgPV_const(mg,len);
+
+    PERL_ARGS_ASSERT_MAGIC_SETSIG;
+
     if (*s == '_') {
        if (strEQ(s,"__DIE__"))
            svp = &PL_diehook;
@@ -1410,7 +1476,7 @@ Perl_magic_setsig(pTHX_ SV *sv, MAGIC *mg)
        sigaddset(&set,i);
        sigprocmask(SIG_BLOCK, &set, &save);
        ENTER;
-       save_sv = newSVpv((char *)(&save), sizeof(sigset_t));
+       save_sv = newSVpvn((char *)(&save), sizeof(sigset_t));
        SAVEFREESV(save_sv);
        SAVEDESTRUCTOR_X(restore_sigmask, save_sv);
 #endif
@@ -1431,7 +1497,7 @@ Perl_magic_setsig(pTHX_ SV *sv, MAGIC *mg)
        PL_psig_name[i] = newSVpvn(s, len);
        SvREADONLY_on(PL_psig_name[i]);
     }
-    if (SvTYPE(sv) == SVt_PVGV || SvROK(sv)) {
+    if (isGV_with_GP(sv) || SvROK(sv)) {
        if (i) {
            (void)rsignal(i, PL_csighandlerp);
 #ifdef HAS_SIGPROCMASK
@@ -1444,7 +1510,7 @@ Perl_magic_setsig(pTHX_ SV *sv, MAGIC *mg)
            SvREFCNT_dec(to_dec);
        return 0;
     }
-    s = SvPV_force(sv,len);
+    s = SvOK(sv) ? SvPV_force(sv,len) : "DEFAULT";
     if (strEQ(s,"IGNORE")) {
        if (i) {
 #ifdef FAKE_PERSISTENT_SIGNAL_HANDLERS
@@ -1473,7 +1539,8 @@ Perl_magic_setsig(pTHX_ SV *sv, MAGIC *mg)
         * tell whether HINT_STRICT_REFS is in force or not.
         */
        if (!strchr(s,':') && !strchr(s,'\''))
-           Perl_sv_insert(aTHX_ sv, 0, 0, STR_WITH_LEN("main::"));
+           Perl_sv_insert_flags(aTHX_ sv, 0, 0, STR_WITH_LEN("main::"),
+                                SV_GMAGIC);
        if (i)
            (void)rsignal(i, PL_csighandlerp);
        else
@@ -1493,9 +1560,61 @@ int
 Perl_magic_setisa(pTHX_ SV *sv, MAGIC *mg)
 {
     dVAR;
+    HV* stash;
+
+    PERL_ARGS_ASSERT_MAGIC_SETISA;
     PERL_UNUSED_ARG(sv);
-    PERL_UNUSED_ARG(mg);
-    PL_sub_generation++;
+
+    /* Bail out if destruction is going on */
+    if(PL_dirty) return 0;
+
+    /* Skip _isaelem because _isa will handle it shortly */
+    if (PL_delaymagic & DM_ARRAY && mg->mg_type == PERL_MAGIC_isaelem)
+       return 0;
+
+    /* XXX Once it's possible, we need to
+       detect that our @ISA is aliased in
+       other stashes, and act on the stashes
+       of all of the aliases */
+
+    /* The first case occurs via setisa,
+       the second via setisa_elem, which
+       calls this same magic */
+    stash = GvSTASH(
+        SvTYPE(mg->mg_obj) == SVt_PVGV
+            ? (GV*)mg->mg_obj
+            : (GV*)mg_find(mg->mg_obj, PERL_MAGIC_isa)->mg_obj
+    );
+
+    if (stash)
+       mro_isa_changed_in(stash);
+
+    return 0;
+}
+
+int
+Perl_magic_clearisa(pTHX_ SV *sv, MAGIC *mg)
+{
+    dVAR;
+    HV* stash;
+
+    PERL_ARGS_ASSERT_MAGIC_CLEARISA;
+
+    /* Bail out if destruction is going on */
+    if(PL_dirty) return 0;
+
+    av_clear((AV*)sv);
+
+    /* XXX see comments in magic_setisa */
+    stash = GvSTASH(
+        SvTYPE(mg->mg_obj) == SVt_PVGV
+            ? (GV*)mg->mg_obj
+            : (GV*)mg_find(mg->mg_obj, PERL_MAGIC_isa)->mg_obj
+    );
+
+    if (stash)
+       mro_isa_changed_in(stash);
+
     return 0;
 }
 
@@ -1503,9 +1622,9 @@ int
 Perl_magic_setamagic(pTHX_ SV *sv, MAGIC *mg)
 {
     dVAR;
+    PERL_ARGS_ASSERT_MAGIC_SETAMAGIC;
     PERL_UNUSED_ARG(sv);
     PERL_UNUSED_ARG(mg);
-    /* HV_badAMAGIC_on(Sv_STASH(sv)); */
     PL_amagic_generation++;
 
     return 0;
@@ -1516,6 +1635,8 @@ Perl_magic_getnkeys(pTHX_ SV *sv, MAGIC *mg)
 {
     HV * const hv = (HV*)LvTARG(sv);
     I32 i = 0;
+
+    PERL_ARGS_ASSERT_MAGIC_GETNKEYS;
     PERL_UNUSED_ARG(mg);
 
     if (hv) {
@@ -1535,6 +1656,7 @@ Perl_magic_getnkeys(pTHX_ SV *sv, MAGIC *mg)
 int
 Perl_magic_setnkeys(pTHX_ SV *sv, MAGIC *mg)
 {
+    PERL_ARGS_ASSERT_MAGIC_SETNKEYS;
     PERL_UNUSED_ARG(mg);
     if (LvTARG(sv)) {
        hv_ksplit((HV*)LvTARG(sv), SvIV(sv));
@@ -1549,18 +1671,20 @@ S_magic_methcall(pTHX_ SV *sv, const MAGIC *mg, const char *meth, I32 flags, int
     dVAR;
     dSP;
 
+    PERL_ARGS_ASSERT_MAGIC_METHCALL;
+
     PUSHMARK(SP);
     EXTEND(SP, n);
     PUSHs(SvTIED_obj(sv, mg));
     if (n > 1) {
        if (mg->mg_ptr) {
            if (mg->mg_len >= 0)
-               PUSHs(sv_2mortal(newSVpvn(mg->mg_ptr, mg->mg_len)));
+               mPUSHp(mg->mg_ptr, mg->mg_len);
            else if (mg->mg_len == HEf_SVKEY)
                PUSHs((SV*)mg->mg_ptr);
        }
        else if (mg->mg_type == PERL_MAGIC_tiedelem) {
-           PUSHs(sv_2mortal(newSViv(mg->mg_len)));
+           mPUSHi(mg->mg_len);
        }
     }
     if (n > 2) {
@@ -1576,6 +1700,8 @@ S_magic_methpack(pTHX_ SV *sv, const MAGIC *mg, const char *meth)
 {
     dVAR; dSP;
 
+    PERL_ARGS_ASSERT_MAGIC_METHPACK;
+
     ENTER;
     SAVETMPS;
     PUSHSTACKi(PERLSI_MAGIC);
@@ -1593,6 +1719,8 @@ S_magic_methpack(pTHX_ SV *sv, const MAGIC *mg, const char *meth)
 int
 Perl_magic_getpack(pTHX_ SV *sv, MAGIC *mg)
 {
+    PERL_ARGS_ASSERT_MAGIC_GETPACK;
+
     if (mg->mg_ptr)
        mg->mg_flags |= MGf_GSKIP;
     magic_methpack(sv,mg,"FETCH");
@@ -1603,6 +1731,9 @@ int
 Perl_magic_setpack(pTHX_ SV *sv, MAGIC *mg)
 {
     dVAR; dSP;
+
+    PERL_ARGS_ASSERT_MAGIC_SETPACK;
+
     ENTER;
     PUSHSTACKi(PERLSI_MAGIC);
     magic_methcall(sv, mg, "STORE", G_SCALAR|G_DISCARD, 3, sv);
@@ -1614,6 +1745,8 @@ Perl_magic_setpack(pTHX_ SV *sv, MAGIC *mg)
 int
 Perl_magic_clearpack(pTHX_ SV *sv, MAGIC *mg)
 {
+    PERL_ARGS_ASSERT_MAGIC_CLEARPACK;
+
     return magic_methpack(sv,mg,"DELETE");
 }
 
@@ -1622,19 +1755,23 @@ U32
 Perl_magic_sizepack(pTHX_ SV *sv, MAGIC *mg)
 {
     dVAR; dSP;
-    U32 retval = 0;
+    I32 retval = 0;
+
+    PERL_ARGS_ASSERT_MAGIC_SIZEPACK;
 
     ENTER;
     SAVETMPS;
     PUSHSTACKi(PERLSI_MAGIC);
     if (magic_methcall(sv, mg, "FETCHSIZE", G_SCALAR, 2, NULL)) {
        sv = *PL_stack_sp--;
-       retval = (U32) SvIV(sv)-1;
+       retval = SvIV(sv)-1;
+       if (retval < -1)
+           Perl_croak(aTHX_ "FETCHSIZE returned a negative value");
     }
     POPSTACK;
     FREETMPS;
     LEAVE;
-    return retval;
+    return (U32) retval;
 }
 
 int
@@ -1642,6 +1779,8 @@ Perl_magic_wipepack(pTHX_ SV *sv, MAGIC *mg)
 {
     dVAR; dSP;
 
+    PERL_ARGS_ASSERT_MAGIC_WIPEPACK;
+
     ENTER;
     PUSHSTACKi(PERLSI_MAGIC);
     PUSHMARK(SP);
@@ -1660,6 +1799,8 @@ Perl_magic_nextpack(pTHX_ SV *sv, MAGIC *mg, SV *key)
     dVAR; dSP;
     const char * const meth = SvOK(key) ? "NEXTKEY" : "FIRSTKEY";
 
+    PERL_ARGS_ASSERT_MAGIC_NEXTPACK;
+
     ENTER;
     SAVETMPS;
     PUSHSTACKi(PERLSI_MAGIC);
@@ -1682,6 +1823,8 @@ Perl_magic_nextpack(pTHX_ SV *sv, MAGIC *mg, SV *key)
 int
 Perl_magic_existspack(pTHX_ SV *sv, const MAGIC *mg)
 {
+    PERL_ARGS_ASSERT_MAGIC_EXISTSPACK;
+
     return magic_methpack(sv,mg,"EXISTS");
 }
 
@@ -1693,6 +1836,8 @@ Perl_magic_scalarpack(pTHX_ HV *hv, MAGIC *mg)
     SV * const tied = SvTIED_obj((SV*)hv, mg);
     HV * const pkg = SvSTASH((SV*)SvRV(tied));
    
+    PERL_ARGS_ASSERT_MAGIC_SCALARPACK;
+
     if (!gv_fetchmethod_autoload(pkg, "SCALAR", FALSE)) {
         SV *key;
         if (HvEITER_get(hv))
@@ -1730,6 +1875,9 @@ Perl_magic_setdbline(pTHX_ SV *sv, MAGIC *mg)
     const I32 i = SvTRUE(sv);
     SV ** const svp = av_fetch(GvAV(gv),
                     atoi(MgPV_nolen_const(mg)), FALSE);
+
+    PERL_ARGS_ASSERT_MAGIC_SETDBLINE;
+
     if (svp && SvIOKp(*svp)) {
        OP * const o = INT2PTR(OP*,SvIVX(*svp));
        if (o) {
@@ -1748,6 +1896,9 @@ Perl_magic_getarylen(pTHX_ SV *sv, const MAGIC *mg)
 {
     dVAR;
     const AV * const obj = (AV*)mg->mg_obj;
+
+    PERL_ARGS_ASSERT_MAGIC_GETARYLEN;
+
     if (obj) {
        sv_setiv(sv, AvFILL(obj) + CopARYBASE_get(PL_curcop));
     } else {
@@ -1761,6 +1912,9 @@ Perl_magic_setarylen(pTHX_ SV *sv, MAGIC *mg)
 {
     dVAR;
     AV * const obj = (AV*)mg->mg_obj;
+
+    PERL_ARGS_ASSERT_MAGIC_SETARYLEN;
+
     if (obj) {
        av_fill(obj, SvIV(sv) - CopARYBASE_get(PL_curcop));
     } else {
@@ -1775,7 +1929,10 @@ int
 Perl_magic_freearylen_p(pTHX_ SV *sv, MAGIC *mg)
 {
     dVAR;
+
+    PERL_ARGS_ASSERT_MAGIC_FREEARYLEN_P;
     PERL_UNUSED_ARG(sv);
+
     /* during global destruction, mg_obj may already have been freed */
     if (PL_in_clean_all)
        return 0;
@@ -1798,6 +1955,8 @@ Perl_magic_getpos(pTHX_ SV *sv, MAGIC *mg)
 {
     dVAR;
     SV* const lsv = LvTARG(sv);
+
+    PERL_ARGS_ASSERT_MAGIC_GETPOS;
     PERL_UNUSED_ARG(mg);
 
     if (SvTYPE(lsv) >= SVt_PVMG && SvMAGIC(lsv)) {
@@ -1822,8 +1981,9 @@ Perl_magic_setpos(pTHX_ SV *sv, MAGIC *mg)
     SSize_t pos;
     STRLEN len;
     STRLEN ulen = 0;
-    MAGIC *found;
+    MAGICfound;
 
+    PERL_ARGS_ASSERT_MAGIC_SETPOS;
     PERL_UNUSED_ARG(mg);
 
     if (SvTYPE(lsv) >= SVt_PVMG && SvMAGIC(lsv))
@@ -1838,7 +1998,7 @@ Perl_magic_setpos(pTHX_ SV *sv, MAGIC *mg)
         sv_force_normal_flags(lsv, 0);
 #endif
        found = sv_magicext(lsv, NULL, PERL_MAGIC_regex_global, &PL_vtbl_mglob,
-                        NULL, 0);
+                           NULL, 0);
     }
     else if (!SvOK(sv)) {
        found->mg_len = -1;
@@ -1875,29 +2035,6 @@ Perl_magic_setpos(pTHX_ SV *sv, MAGIC *mg)
 }
 
 int
-Perl_magic_setglob(pTHX_ SV *sv, MAGIC *mg)
-{
-    GV* gv;
-    PERL_UNUSED_ARG(mg);
-
-    if (!SvOK(sv))
-       return 0;
-    if (SvFLAGS(sv) & SVp_SCREAM
-       && (SvTYPE(sv) == SVt_PVGV || SvTYPE(sv) == SVt_PVGV)) {
-       /* We're actually already a typeglob, so don't need the stuff below.
-        */
-       return 0;
-    }
-    gv =  gv_fetchsv(sv, GV_ADD, SVt_PVGV);
-    if (sv == (SV*)gv)
-       return 0;
-    if (GvGP(sv))
-       gp_free((GV*)sv);
-    GvGP(sv) = gp_ref(GvGP(gv));
-    return 0;
-}
-
-int
 Perl_magic_getsubstr(pTHX_ SV *sv, MAGIC *mg)
 {
     STRLEN len;
@@ -1905,6 +2042,8 @@ Perl_magic_getsubstr(pTHX_ SV *sv, MAGIC *mg)
     const char * const tmps = SvPV_const(lsv,len);
     I32 offs = LvTARGOFF(sv);
     I32 rem = LvTARGLEN(sv);
+
+    PERL_ARGS_ASSERT_MAGIC_GETSUBSTR;
     PERL_UNUSED_ARG(mg);
 
     if (SvUTF8(lsv))
@@ -1928,6 +2067,8 @@ Perl_magic_setsubstr(pTHX_ SV *sv, MAGIC *mg)
     SV * const lsv = LvTARG(sv);
     I32 lvoff = LvTARGOFF(sv);
     I32 lvlen = LvTARGLEN(sv);
+
+    PERL_ARGS_ASSERT_MAGIC_SETSUBSTR;
     PERL_UNUSED_ARG(mg);
 
     if (DO_UTF8(sv)) {
@@ -1958,7 +2099,10 @@ int
 Perl_magic_gettaint(pTHX_ SV *sv, MAGIC *mg)
 {
     dVAR;
+
+    PERL_ARGS_ASSERT_MAGIC_GETTAINT;
     PERL_UNUSED_ARG(sv);
+
     TAINT_IF((PL_localizing != 1) && (mg->mg_len & 1));
     return 0;
 }
@@ -1967,14 +2111,15 @@ int
 Perl_magic_settaint(pTHX_ SV *sv, MAGIC *mg)
 {
     dVAR;
+
+    PERL_ARGS_ASSERT_MAGIC_SETTAINT;
     PERL_UNUSED_ARG(sv);
-    /* update taint status unless we're restoring at scope exit */
-    if (PL_localizing != 2) {
-       if (PL_tainted)
-           mg->mg_len |= 1;
-       else
-           mg->mg_len &= ~1;
-    }
+
+    /* update taint status */
+    if (PL_tainted)
+       mg->mg_len |= 1;
+    else
+       mg->mg_len &= ~1;
     return 0;
 }
 
@@ -1982,6 +2127,8 @@ int
 Perl_magic_getvec(pTHX_ SV *sv, MAGIC *mg)
 {
     SV * const lsv = LvTARG(sv);
+
+    PERL_ARGS_ASSERT_MAGIC_GETVEC;
     PERL_UNUSED_ARG(mg);
 
     if (lsv)
@@ -1995,6 +2142,7 @@ Perl_magic_getvec(pTHX_ SV *sv, MAGIC *mg)
 int
 Perl_magic_setvec(pTHX_ SV *sv, MAGIC *mg)
 {
+    PERL_ARGS_ASSERT_MAGIC_SETVEC;
     PERL_UNUSED_ARG(mg);
     do_vecset(sv);     /* XXX slurp this routine */
     return 0;
@@ -2005,6 +2153,9 @@ Perl_magic_getdefelem(pTHX_ SV *sv, MAGIC *mg)
 {
     dVAR;
     SV *targ = NULL;
+
+    PERL_ARGS_ASSERT_MAGIC_GETDEFELEM;
+
     if (LvTARGLEN(sv)) {
        if (mg->mg_obj) {
            SV * const ahv = LvTARG(sv);
@@ -2036,6 +2187,7 @@ Perl_magic_getdefelem(pTHX_ SV *sv, MAGIC *mg)
 int
 Perl_magic_setdefelem(pTHX_ SV *sv, MAGIC *mg)
 {
+    PERL_ARGS_ASSERT_MAGIC_SETDEFELEM;
     PERL_UNUSED_ARG(mg);
     if (LvTARGLEN(sv))
        vivify_defelem(sv);
@@ -2053,6 +2205,8 @@ Perl_vivify_defelem(pTHX_ SV *sv)
     MAGIC *mg;
     SV *value = NULL;
 
+    PERL_ARGS_ASSERT_VIVIFY_DEFELEM;
+
     if (!LvTARGLEN(sv) || !(mg = mg_find(sv, PERL_MAGIC_defelem)))
        return;
     if (mg->mg_obj) {
@@ -2061,7 +2215,7 @@ Perl_vivify_defelem(pTHX_ SV *sv)
         if (he)
             value = HeVAL(he);
        if (!value || value == &PL_sv_undef)
-           Perl_croak(aTHX_ PL_no_helem_sv, mg->mg_obj);
+           Perl_croak(aTHX_ PL_no_helem_sv, SVfARG(mg->mg_obj));
     }
     else {
        AV* const av = (AV*)LvTARG(sv);
@@ -2085,12 +2239,14 @@ Perl_vivify_defelem(pTHX_ SV *sv)
 int
 Perl_magic_killbackrefs(pTHX_ SV *sv, MAGIC *mg)
 {
+    PERL_ARGS_ASSERT_MAGIC_KILLBACKREFS;
     return Perl_sv_kill_backrefs(aTHX_ sv, (AV*)mg->mg_obj);
 }
 
 int
 Perl_magic_setmglob(pTHX_ SV *sv, MAGIC *mg)
 {
+    PERL_ARGS_ASSERT_MAGIC_SETMGLOB;
     PERL_UNUSED_CONTEXT;
     mg->mg_len = -1;
     SvSCREAM_off(sv);
@@ -2098,28 +2254,12 @@ Perl_magic_setmglob(pTHX_ SV *sv, MAGIC *mg)
 }
 
 int
-Perl_magic_setbm(pTHX_ SV *sv, MAGIC *mg)
-{
-    PERL_UNUSED_ARG(mg);
-    sv_unmagic(sv, PERL_MAGIC_bm);
-    SvVALID_off(sv);
-    return 0;
-}
-
-int
-Perl_magic_setfm(pTHX_ SV *sv, MAGIC *mg)
-{
-    PERL_UNUSED_ARG(mg);
-    sv_unmagic(sv, PERL_MAGIC_fm);
-    SvCOMPILED_off(sv);
-    return 0;
-}
-
-int
 Perl_magic_setuvar(pTHX_ SV *sv, MAGIC *mg)
 {
     const struct ufuncs * const uf = (struct ufuncs *)mg->mg_ptr;
 
+    PERL_ARGS_ASSERT_MAGIC_SETUVAR;
+
     if (uf && uf->uf_set)
        (*uf->uf_set)(aTHX_ uf->uf_index, sv);
     return 0;
@@ -2128,26 +2268,27 @@ Perl_magic_setuvar(pTHX_ SV *sv, MAGIC *mg)
 int
 Perl_magic_setregexp(pTHX_ SV *sv, MAGIC *mg)
 {
-    PERL_UNUSED_ARG(mg);
-    sv_unmagic(sv, PERL_MAGIC_qr);
-    return 0;
-}
+    const char type = mg->mg_type;
 
-int
-Perl_magic_freeregexp(pTHX_ SV *sv, MAGIC *mg)
-{
-    dVAR;
-    regexp * const re = (regexp *)mg->mg_obj;
-    PERL_UNUSED_ARG(sv);
+    PERL_ARGS_ASSERT_MAGIC_SETREGEXP;
 
-    ReREFCNT_dec(re);
-    return 0;
+    if (type == PERL_MAGIC_qr) {
+    } else if (type == PERL_MAGIC_bm) {
+       SvTAIL_off(sv);
+       SvVALID_off(sv);
+    } else {
+       assert(type == PERL_MAGIC_fm);
+       SvCOMPILED_off(sv);
+    }
+    return sv_unmagic(sv, type);
 }
 
 #ifdef USE_LOCALE_COLLATE
 int
 Perl_magic_setcollxfrm(pTHX_ SV *sv, MAGIC *mg)
 {
+    PERL_ARGS_ASSERT_MAGIC_SETCOLLXFRM;
+
     /*
      * RenE<eacute> Descartes said "I think not."
      * and vanished with a faint plop.
@@ -2167,6 +2308,7 @@ Perl_magic_setcollxfrm(pTHX_ SV *sv, MAGIC *mg)
 int
 Perl_magic_setutf8(pTHX_ SV *sv, MAGIC *mg)
 {
+    PERL_ARGS_ASSERT_MAGIC_SETUTF8;
     PERL_UNUSED_CONTEXT;
     PERL_UNUSED_ARG(sv);
     Safefree(mg->mg_ptr);      /* The mg_ptr holds the pos cache. */
@@ -2180,9 +2322,45 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg)
 {
     dVAR;
     register const char *s;
+    register I32 paren;
+    register const REGEXP * rx;
+    const char * const remaining = mg->mg_ptr + 1;
     I32 i;
     STRLEN len;
+
+    PERL_ARGS_ASSERT_MAGIC_SET;
+
     switch (*mg->mg_ptr) {
+    case '\015': /* $^MATCH */
+      if (strEQ(remaining, "ATCH"))
+          goto do_match;
+    case '`': /* ${^PREMATCH} caught below */
+      do_prematch:
+      paren = RX_BUFF_IDX_PREMATCH;
+      goto setparen;
+    case '\'': /* ${^POSTMATCH} caught below */
+      do_postmatch:
+      paren = RX_BUFF_IDX_POSTMATCH;
+      goto setparen;
+    case '&':
+      do_match:
+      paren = RX_BUFF_IDX_FULLMATCH;
+      goto setparen;
+    case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+      paren = atoi(mg->mg_ptr);
+      setparen:
+       if (PL_curpm && (rx = PM_GETRE(PL_curpm))) {
+            CALLREG_NUMBUF_STORE((REGEXP * const)rx,paren,sv);
+            break;
+       } else {
+            /* Croak with a READONLY error when a numbered match var is
+             * set without a previous pattern match. Unless it's C<local $1>
+             */
+            if (!PL_localizing) {
+                Perl_croak(aTHX_ PL_no_modify);
+            }
+        }
     case '\001':       /* ^A */
        sv_setsv(PL_bodytarget, sv);
        break;
@@ -2251,18 +2429,48 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg)
            }
        }
        else if (strEQ(mg->mg_ptr, "\017PEN")) {
-           PL_compiling.cop_hints |= HINT_LEXICAL_IO;
-           PL_hints |= HINT_LOCALIZE_HH | HINT_LEXICAL_IO;
+           STRLEN len;
+           const char *const start = SvPV(sv, len);
+           const char *out = (const char*)memchr(start, '\0', len);
+           SV *tmp;
+           struct refcounted_he *tmp_he;
+
+
+           PL_compiling.cop_hints |= HINT_LEXICAL_IO_IN | HINT_LEXICAL_IO_OUT;
+           PL_hints
+               |= HINT_LOCALIZE_HH | HINT_LEXICAL_IO_IN | HINT_LEXICAL_IO_OUT;
+
+           /* Opening for input is more common than opening for output, so
+              ensure that hints for input are sooner on linked list.  */
+           tmp = out ? newSVpvn_flags(out + 1, start + len - out - 1,
+                                      SVs_TEMP | SvUTF8(sv))
+               : newSVpvn_flags("", 0, SVs_TEMP | SvUTF8(sv));
+
+           tmp_he
+               = Perl_refcounted_he_new(aTHX_ PL_compiling.cop_hints_hash, 
+                                        newSVpvs_flags("open>", SVs_TEMP),
+                                        tmp);
+
+           /* The UTF-8 setting is carried over  */
+           sv_setpvn(tmp, start, out ? (STRLEN)(out - start) : len);
+
            PL_compiling.cop_hints_hash
-               = Perl_refcounted_he_new(aTHX_ PL_compiling.cop_hints_hash,
-                                        sv_2mortal(newSVpvs("open")), sv);
+               = Perl_refcounted_he_new(aTHX_ tmp_he,
+                                        newSVpvs_flags("open<", SVs_TEMP),
+                                        tmp);
        }
        break;
     case '\020':       /* ^P */
-       PL_perldb = SvIV(sv);
-       if (PL_perldb && !PL_DBsingle)
-           init_debugger();
-       break;
+      if (*remaining == '\0') { /* ^P */
+          PL_perldb = SvIV(sv);
+          if (PL_perldb && !PL_DBsingle)
+              init_debugger();
+          break;
+      } else if (strEQ(remaining, "REMATCH")) { /* $^PREMATCH */
+          goto do_prematch;
+      } else if (strEQ(remaining, "OSTMATCH")) { /* $^POSTMATCH */
+          goto do_postmatch;
+      }
     case '\024':       /* ^T */
 #ifdef BIG_TIME
        PL_basetime = (Time_t)(SvNOK(sv) ? SvNVX(sv) : sv_2nv(sv));
@@ -2299,11 +2507,16 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg)
                        accumulate |= ptr[i] ;
                        any_fatals |= (ptr[i] & 0xAA) ;
                    }
-                   if (!accumulate)
-                       PL_compiling.cop_warnings = pWARN_NONE;
+                   if (!accumulate) {
+                       if (!specialWARN(PL_compiling.cop_warnings))
+                           PerlMemShared_free(PL_compiling.cop_warnings);
+                       PL_compiling.cop_warnings = pWARN_NONE;
+                   }
                    /* Yuck. I can't see how to abstract this:  */
                    else if (isWARN_on(((STRLEN *)SvPV_nolen_const(sv)) - 1,
                                       WARN_ALL) && !any_fatals) {
+                       if (!specialWARN(PL_compiling.cop_warnings))
+                           PerlMemShared_free(PL_compiling.cop_warnings);
                        PL_compiling.cop_warnings = pWARN_ALL;
                        PL_dowarn |= G_WARN_ONCE ;
                    }
@@ -2591,15 +2804,14 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg)
            setproctitle("%s", s);
 #   endif
        }
-#endif
-#if defined(__hpux) && defined(PSTAT_SETCMD)
+#elif defined(__hpux) && defined(PSTAT_SETCMD)
        if (PL_origalen != 1) {
             union pstun un;
             s = SvPV_const(sv, len);
             un.pst_command = (char *)s;
             pstat(PSTAT_SETCMD, un, len, 0, 0);
        }
-#endif
+#else
        if (PL_origalen > 1) {
            /* PL_origalen is set in perl_parse(). */
            s = SvPV_force(sv,len);
@@ -2610,20 +2822,26 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg)
            }
            else {
                /* Shorter than original, will be padded. */
+#ifdef PERL_DARWIN
+               /* Special case for Mac OS X: see [perl #38868] */
+               const int pad = 0;
+#else
+               /* Is the space counterintuitive?  Yes.
+                * (You were expecting \0?)
+                * Does it work?  Seems to.  (In Linux 2.4.20 at least.)
+                * --jhi */
+               const int pad = ' ';
+#endif
                Copy(s, PL_origargv[0], len, char);
                PL_origargv[0][len] = 0;
                memset(PL_origargv[0] + len + 1,
-                      /* Is the space counterintuitive?  Yes.
-                       * (You were expecting \0?)  
-                       * Does it work?  Seems to.  (In Linux 2.4.20 at least.)
-                       * --jhi */
-                      (int)' ',
-                      PL_origalen - len - 1);
+                      pad,  PL_origalen - len - 1);
            }
            PL_origargv[0][PL_origalen-1] = 0;
            for (i = 1; i < PL_origargc; i++)
                PL_origargv[i] = 0;
        }
+#endif
        UNLOCK_DOLLARZERO_MUTEX;
        break;
 #endif
@@ -2635,6 +2853,8 @@ I32
 Perl_whichsig(pTHX_ const char *sig)
 {
     register char* const* sigv;
+
+    PERL_ARGS_ASSERT_WHICHSIG;
     PERL_UNUSED_CONTEXT;
 
     for (sigv = (char* const*)PL_sig_name; *sigv; sigv++)
@@ -2653,7 +2873,7 @@ Perl_whichsig(pTHX_ const char *sig)
 
 Signal_t
 #if defined(HAS_SIGACTION) && defined(SA_SIGINFO)
-Perl_sighandler(int sig, ...)
+Perl_sighandler(int sig, siginfo_t *sip, void *uap PERL_UNUSED_DECL)
 #else
 Perl_sighandler(int sig)
 #endif
@@ -2731,32 +2951,26 @@ Perl_sighandler(int sig)
         struct sigaction oact;
 
         if (sigaction(sig, 0, &oact) == 0 && oact.sa_flags & SA_SIGINFO) {
-             siginfo_t *sip;
-             va_list args;
-
-             va_start(args, sig);
-             sip = (siginfo_t*)va_arg(args, siginfo_t*);
              if (sip) {
                   HV *sih = newHV();
                   SV *rv  = newRV_noinc((SV*)sih);
                   /* The siginfo fields signo, code, errno, pid, uid,
                    * addr, status, and band are defined by POSIX/SUSv3. */
-                  hv_store(sih, "signo",   5, newSViv(sip->si_signo),  0);
-                  hv_store(sih, "code",    4, newSViv(sip->si_code),   0);
+                  (void)hv_stores(sih, "signo", newSViv(sip->si_signo));
+                  (void)hv_stores(sih, "code", newSViv(sip->si_code));
 #if 0 /* XXX TODO: Configure scan for the existence of these, but even that does not help if the SA_SIGINFO is not implemented according to the spec. */
-                  hv_store(sih, "errno",   5, newSViv(sip->si_errno),  0);
-                  hv_store(sih, "status",  6, newSViv(sip->si_status), 0);
-                  hv_store(sih, "uid",     3, newSViv(sip->si_uid),    0);
-                  hv_store(sih, "pid",     3, newSViv(sip->si_pid),    0);
-                  hv_store(sih, "addr",    4, newSVuv(PTR2UV(sip->si_addr)),   0);
-                  hv_store(sih, "band",    4, newSViv(sip->si_band),   0);
+                  hv_stores(sih, "errno",      newSViv(sip->si_errno));
+                  hv_stores(sih, "status",     newSViv(sip->si_status));
+                  hv_stores(sih, "uid",        newSViv(sip->si_uid));
+                  hv_stores(sih, "pid",        newSViv(sip->si_pid));
+                  hv_stores(sih, "addr",       newSVuv(PTR2UV(sip->si_addr)));
+                  hv_stores(sih, "band",       newSViv(sip->si_band));
 #endif
                   EXTEND(SP, 2);
                   PUSHs((SV*)rv);
-                  PUSHs(newSVpv((char *)sip, sizeof(*sip)));
+                  mPUSHp((char *)sip, sizeof(*sip));
              }
 
-              va_end(args);
         }
     }
 #endif
@@ -2864,6 +3078,8 @@ S_unwind_handler_stack(pTHX_ const void *p)
     dVAR;
     const U32 flags = *(const U32*)p;
 
+    PERL_ARGS_ASSERT_UNWIND_HANDLER_STACK;
+
     if (flags & 1)
        PL_savestack_ix -= 5; /* Unprotect save in progress. */
 #if !defined(PERL_IMPLICIT_CONTEXT)
@@ -2886,7 +3102,10 @@ int
 Perl_magic_sethint(pTHX_ SV *sv, MAGIC *mg)
 {
     dVAR;
-    assert(mg->mg_len == HEf_SVKEY);
+    SV *key = (mg->mg_len == HEf_SVKEY) ? (SV *)mg->mg_ptr
+       : newSVpvn_flags(mg->mg_ptr, mg->mg_len, SVs_TEMP);
+
+    PERL_ARGS_ASSERT_MAGIC_SETHINT;
 
     /* mg->mg_obj isn't being used.  If needed, it would be possible to store
        an alternative leaf in there, with PL_compiling.cop_hints being used if
@@ -2898,13 +3117,12 @@ Perl_magic_sethint(pTHX_ SV *sv, MAGIC *mg)
        forgetting to do it, and consequent subtle errors.  */
     PL_hints |= HINT_LOCALIZE_HH;
     PL_compiling.cop_hints_hash
-       = Perl_refcounted_he_new(aTHX_ PL_compiling.cop_hints_hash,
-                                (SV *)mg->mg_ptr, sv);
+       = Perl_refcounted_he_new(aTHX_ PL_compiling.cop_hints_hash, key, sv);
     return 0;
 }
 
 /*
-=for apidoc magic_sethint
+=for apidoc magic_clearhint
 
 Triggered by a delete from %^H, records the key to
 C<PL_compiling.cop_hints_hash>.
@@ -2915,6 +3133,8 @@ int
 Perl_magic_clearhint(pTHX_ SV *sv, MAGIC *mg)
 {
     dVAR;
+
+    PERL_ARGS_ASSERT_MAGIC_CLEARHINT;
     PERL_UNUSED_ARG(sv);
 
     assert(mg->mg_len == HEf_SVKEY);