This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
regcomp.c: Avoid function call overhead
[perl5.git] / regcomp.c
index ab0085f..d3635cc 100644 (file)
--- a/regcomp.c
+++ b/regcomp.c
@@ -93,6 +93,8 @@ EXTERN_C const struct regexp_engine my_reg_engine;
 
 #define HAS_NONLATIN1_FOLD_CLOSURE(i) \
  _HAS_NONLATIN1_FOLD_CLOSURE_ONLY_FOR_USE_BY_REGCOMP_DOT_C_AND_REGEXEC_DOT_C(i)
+#define HAS_NONLATIN1_SIMPLE_FOLD_CLOSURE(i) \
+ _HAS_NONLATIN1_SIMPLE_FOLD_CLOSURE_ONLY_FOR_USE_BY_REGCOMP_DOT_C_AND_REGEXEC_DOT_C(i)
 #define IS_NON_FINAL_FOLD(c) _IS_NON_FINAL_FOLD_ONLY_FOR_USE_BY_REGCOMP_DOT_C(c)
 #define IS_IN_SOME_FOLD_L1(c) _IS_IN_SOME_FOLD_ONLY_FOR_USE_BY_REGCOMP_DOT_C(c)
 
@@ -223,7 +225,7 @@ struct RExC_state_t {
 
 #define        ISMULT1(c)      ((c) == '*' || (c) == '+' || (c) == '?')
 #define        ISMULT2(s)      ((*s) == '*' || (*s) == '+' || (*s) == '?' || \
-       ((*s) == '{' && regcurly(s, FALSE)))
+       ((*s) == '{' && regcurly(s)))
 
 /*
  * Flags to be passed up and down.
@@ -893,7 +895,7 @@ S_ssc_anything(pTHX_ regnode_ssc *ssc)
 }
 
 STATIC int
-S_ssc_is_anything(pTHX_ const regnode_ssc *ssc)
+S_ssc_is_anything(const regnode_ssc *ssc)
 {
     /* Returns TRUE if the SSC 'ssc' can match the empty string and any code
      * point; FALSE otherwise.  Thus, this is used to see if using 'ssc' buys
@@ -965,8 +967,8 @@ S_ssc_init(pTHX_ const RExC_state_t *pRExC_state, regnode_ssc *ssc)
 }
 
 STATIC int
-S_ssc_is_cp_posixl_init(pTHX_ const RExC_state_t *pRExC_state,
-                              const regnode_ssc *ssc)
+S_ssc_is_cp_posixl_init(const RExC_state_t *pRExC_state,
+                        const regnode_ssc *ssc)
 {
     /* Returns TRUE if the SSC 'ssc' is in its initial state with regard only
      * to the list of code points matched, and locale posix classes; hence does
@@ -1046,15 +1048,16 @@ S_get_ANYOF_cp_list_for_ssc(pTHX_ const RExC_state_t *pRExC_state,
         }
     }
 
-    /* An ANYOF node contains a bitmap for the first 256 code points, and an
-     * inversion list for the others, but if there are code points that should
-     * match only conditionally on the target string being UTF-8, those are
-     * placed in the inversion list, and not the bitmap.  Since there are
-     * circumstances under which they could match, they are included in the
-     * SSC.  But if the ANYOF node is to be inverted, we have to exclude them
-     * here, so that when we invert below, the end result actually does include
-     * them.  (Think about "\xe0" =~ /[^\xc0]/di;).  We have to do this here
-     * before we add the unconditionally matched code points */
+    /* An ANYOF node contains a bitmap for the first NUM_ANYOF_CODE_POINTS
+     * code points, and an inversion list for the others, but if there are code
+     * points that should match only conditionally on the target string being
+     * UTF-8, those are placed in the inversion list, and not the bitmap.
+     * Since there are circumstances under which they could match, they are
+     * included in the SSC.  But if the ANYOF node is to be inverted, we have
+     * to exclude them here, so that when we invert below, the end result
+     * actually does include them.  (Think about "\xe0" =~ /[^\xc0]/di;).  We
+     * have to do this here before we add the unconditionally matched code
+     * points */
     if (ANYOF_FLAGS(node) & ANYOF_INVERT) {
         _invlist_intersection_complement_2nd(invlist,
                                              PL_UpperLatin1,
@@ -1062,7 +1065,7 @@ S_get_ANYOF_cp_list_for_ssc(pTHX_ const RExC_state_t *pRExC_state,
     }
 
     /* Add in the points from the bit map */
-    for (i = 0; i < 256; i++) {
+    for (i = 0; i < NUM_ANYOF_CODE_POINTS; i++) {
         if (ANYOF_BITMAP_TEST(node, i)) {
             invlist = add_cp_to_invlist(invlist, i);
             new_node_has_latin1 = TRUE;
@@ -1410,10 +1413,9 @@ S_ssc_cp_and(pTHX_ regnode_ssc *ssc, const UV cp)
 }
 
 PERL_STATIC_INLINE void
-S_ssc_clear_locale(pTHX_ regnode_ssc *ssc)
+S_ssc_clear_locale(regnode_ssc *ssc)
 {
     /* Set the SSC 'ssc' to not match any locale things */
-
     PERL_ARGS_ASSERT_SSC_CLEAR_LOCALE;
 
     assert(is_ANYOF_SYNTHETIC(ssc));
@@ -1427,7 +1429,8 @@ S_ssc_finalize(pTHX_ RExC_state_t *pRExC_state, regnode_ssc *ssc)
 {
     /* The inversion list in the SSC is marked mortal; now we need a more
      * permanent copy, which is stored the same way that is done in a regular
-     * ANYOF node, with the first 256 code points in a bit map */
+     * ANYOF node, with the first NUM_ANYOF_CODE_POINTS code points in a bit
+     * map */
 
     SV* invlist = invlist_clone(ssc->invlist);
 
@@ -1718,7 +1721,7 @@ S_dump_trie_interim_table(pTHX_ const struct _reg_trie_data *trie,
               May be the same as tail.
   tail       : item following the branch sequence
   count      : words in the sequence
-  flags      : currently the OP() type we will be building one of /EXACT(|F|Fl)/
+  flags      : currently the OP() type we will be building one of /EXACT(|F|FA|FU|FU_SS)/
   depth      : indent depth
 
 Inplace optimizes a sequence of 2 or more Branch-Exact nodes into a TRIE node.
@@ -1947,7 +1950,6 @@ S_make_trie(pTHX_ RExC_state_t *pRExC_state, regnode *startbranch,
                   regnode *first, regnode *last, regnode *tail,
                   U32 word_count, U32 flags, U32 depth)
 {
-    dVAR;
     /* first pass, loop through and scan words */
     reg_trie_data *trie;
     HV *widecharmap = NULL;
@@ -2982,8 +2984,8 @@ S_make_trie(pTHX_ RExC_state_t *pRExC_state, regnode *startbranch,
              : MADE_TRIE;
 }
 
-STATIC void
-S_make_trie_failtable(pTHX_ RExC_state_t *pRExC_state, regnode *source,  regnode *stclass, U32 depth)
+STATIC regnode *
+S_construct_ahocorasick_from_trie(pTHX_ RExC_state_t *pRExC_state, regnode *source, U32 depth)
 {
 /* The Trie is constructed and compressed now so we can build a fail array if
  * it's needed
@@ -3021,13 +3023,27 @@ S_make_trie_failtable(pTHX_ RExC_state_t *pRExC_state, regnode *source,  regnode
     U32 *fail;
     reg_ac_data *aho;
     const U32 data_slot = add_data( pRExC_state, STR_WITH_LEN("T"));
+    regnode *stclass;
     GET_RE_DEBUG_FLAGS_DECL;
 
-    PERL_ARGS_ASSERT_MAKE_TRIE_FAILTABLE;
+    PERL_ARGS_ASSERT_CONSTRUCT_AHOCORASICK_FROM_TRIE;
+    PERL_UNUSED_CONTEXT;
 #ifndef DEBUGGING
     PERL_UNUSED_ARG(depth);
 #endif
 
+    if ( OP(source) == TRIE ) {
+        struct regnode_1 *op = (struct regnode_1 *)
+            PerlMemShared_calloc(1, sizeof(struct regnode_1));
+        StructCopy(source,op,struct regnode_1);
+        stclass = (regnode *)op;
+    } else {
+        struct regnode_charclass *op = (struct regnode_charclass *)
+            PerlMemShared_calloc(1, sizeof(struct regnode_charclass));
+        StructCopy(source,op,struct regnode_charclass);
+        stclass = (regnode *)op;
+    }
+    OP(stclass)+=2; /* covert the TRIE type to its AHO-CORASICK equivalent */
 
     ARG_SET( stclass, data_slot );
     aho = (reg_ac_data *) PerlMemShared_calloc( 1, sizeof(reg_ac_data) );
@@ -3094,6 +3110,7 @@ S_make_trie_failtable(pTHX_ RExC_state_t *pRExC_state, regnode *source,  regnode
     });
     Safefree(q);
     /*RExC_seen |= REG_TRIEDFA_SEEN;*/
+    return stclass;
 }
 
 
@@ -3578,7 +3595,6 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
                        /* recursed: which subroutines have we recursed into */
                        /* and_withp: Valid if flags & SCF_DO_STCLASS_OR */
 {
-    dVAR;
     /* There must be at least this number of characters to match */
     SSize_t min = 0;
     I32 pars = 0, code;
@@ -4322,7 +4338,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
 
                     /* Some characters match above-Latin1 ones under /i.  This
                      * is true of EXACTFL ones when the locale is UTF-8 */
-                    if (HAS_NONLATIN1_FOLD_CLOSURE(uc)
+                    if (HAS_NONLATIN1_SIMPLE_FOLD_CLOSURE(uc)
                         && (! isASCII(uc) || (OP(scan) != EXACTFA
                                             && OP(scan) != EXACTFA_NO_TRIE)))
                     {
@@ -4763,13 +4779,13 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
                    /* It is counted once already... */
                    data->pos_min += minnext * (mincount - counted);
 #if 0
-PerlIO_printf(Perl_debug_log, "counted=%"UVdf" deltanext=%"UVdf
-                              " SSize_t_MAX=%"UVdf" minnext=%"UVdf
-                              " maxcount=%"UVdf" mincount=%"UVdf"\n",
+PerlIO_printf(Perl_debug_log, "counted=%"UVuf" deltanext=%"UVuf
+                              " SSize_t_MAX=%"UVuf" minnext=%"UVuf
+                              " maxcount=%"UVuf" mincount=%"UVuf"\n",
     (UV)counted, (UV)deltanext, (UV)SSize_t_MAX, (UV)minnext, (UV)maxcount,
     (UV)mincount);
 if (deltanext != SSize_t_MAX)
-PerlIO_printf(Perl_debug_log, "LHS=%"UVdf" RHS=%"UVdf"\n",
+PerlIO_printf(Perl_debug_log, "LHS=%"UVuf" RHS=%"UVuf"\n",
     (UV)(-counted * deltanext + (minnext + deltanext) * maxcount
           - minnext * mincount), (UV)(SSize_t_MAX - data->pos_delta));
 #endif
@@ -5029,7 +5045,8 @@ PerlIO_printf(Perl_debug_log, "LHS=%"UVdf" RHS=%"UVdf"\n",
        else if (  PL_regkind[OP(scan)] == BRANCHJ
                 /* Lookbehind, or need to calculate parens/evals/stclass: */
                   && (scan->flags || data || (flags & SCF_DO_STCLASS))
-                  && (OP(scan) == IFMATCH || OP(scan) == UNLESSM)) {
+                  && (OP(scan) == IFMATCH || OP(scan) == UNLESSM))
+        {
             if ( OP(scan) == UNLESSM &&
                  scan->flags == 0 &&
                  OP(NEXTOPER(NEXTOPER(scan))) == NOTHING &&
@@ -5117,8 +5134,11 @@ PerlIO_printf(Perl_debug_log, "LHS=%"UVdf" RHS=%"UVdf"\n",
                         */
                        ssc_init(pRExC_state, data->start_class);
                    }  else {
-                       /* AND before and after: combine and continue */
+                        /* AND before and after: combine and continue.  These
+                         * assertions are zero-length, so can match an EMPTY
+                         * string */
                        ssc_and(pRExC_state, data->start_class, (regnode_charclass *) &intrnl);
+                        ANYOF_FLAGS(data->start_class) |= ANYOF_EMPTY_STRING;
                    }
                 }
            }
@@ -5190,6 +5210,7 @@ PerlIO_printf(Perl_debug_log, "LHS=%"UVdf" RHS=%"UVdf"\n",
 
                 if (f & SCF_DO_STCLASS_AND) {
                     ssc_and(pRExC_state, data->start_class, (regnode_charclass *) &intrnl);
+                    ANYOF_FLAGS(data->start_class) |= ANYOF_EMPTY_STRING;
                 }
                 if (data) {
                     if (data_fake.flags & (SF_HAS_PAR|SF_IN_PAR))
@@ -5506,7 +5527,6 @@ S_add_data(RExC_state_t* const pRExC_state, const char* const s, const U32 n)
 void
 Perl_reginitcolors(pTHX)
 {
-    dVAR;
     const char * const s = PerlEnv_getenv("PERL_RE_COLORS");
     if (s) {
        char *t = savepv(s);
@@ -5560,8 +5580,6 @@ Perl_reginitcolors(pTHX)
 regexp_engine const *
 Perl_current_re_engine(pTHX)
 {
-    dVAR;
-
     if (IN_PERL_COMPILETIME) {
        HV * const table = GvHV(PL_hintgv);
        SV **ptr;
@@ -5588,7 +5606,6 @@ Perl_current_re_engine(pTHX)
 REGEXP *
 Perl_pregcomp(pTHX_ SV * const pattern, const U32 flags)
 {
-    dVAR;
     regexp_engine const *eng = current_re_engine();
     GET_RE_DEBUG_FLAGS_DECL;
 
@@ -5704,7 +5721,7 @@ S_concat_pat(pTHX_ RExC_state_t * const pRExC_state,
     /* if we know we have at least two args, create an empty string,
      * then concatenate args to that. For no args, return an empty string */
     if (!pat && pat_count != 1) {
-        pat = newSVpvn("", 0);
+        pat = newSVpvs("");
         SAVEFREESV(pat);
         alloced = TRUE;
     }
@@ -5740,7 +5757,7 @@ S_concat_pat(pTHX_ RExC_state_t * const pRExC_state,
             if (oplist) {
                 assert(oplist->op_type == OP_PADAV
                     || oplist->op_type == OP_RV2AV);
-                oplist = oplist->op_sibling;;
+                oplist = OP_SIBLING(oplist);
             }
 
             if (SvRMAGICAL(av)) {
@@ -5787,10 +5804,10 @@ S_concat_pat(pTHX_ RExC_state_t * const pRExC_state,
                 pRExC_state->code_blocks[n].src_regex = NULL;
                 n++;
                 code = 1;
-                oplist = oplist->op_sibling; /* skip CONST */
+                oplist = OP_SIBLING(oplist); /* skip CONST */
                 assert(oplist);
             }
-            oplist = oplist->op_sibling;;
+            oplist = OP_SIBLING(oplist);;
         }
 
        /* apply magic and QR overloading to arg */
@@ -5910,6 +5927,8 @@ S_has_runtime_code(pTHX_ RExC_state_t * const pRExC_state,
 {
     int n = 0;
     STRLEN s;
+    
+    PERL_UNUSED_CONTEXT;
 
     for (s = 0; s < plen; s++) {
        if (n < pRExC_state->num_code_blocks
@@ -6225,7 +6244,6 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count,
                    OP *expr, const regexp_engine* eng, REGEXP *old_re,
                     bool *is_bare_re, U32 orig_rx_flags, U32 pm_flags)
 {
-    dVAR;
     REGEXP *rx;
     struct regexp *r;
     regexp_internal *ri;
@@ -6287,7 +6305,7 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count,
        OP *o;
        int ncode = 0;
 
-       for (o = cLISTOPx(expr)->op_first; o; o = o->op_sibling)
+       for (o = cLISTOPx(expr)->op_first; o; o = OP_SIBLING(o))
            if (o->op_type == OP_NULL && (o->op_flags & OPf_SPECIAL))
                ncode++; /* count of DO blocks */
        if (ncode) {
@@ -6308,7 +6326,7 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count,
         if (expr->op_type == OP_CONST)
             n = 1;
         else
-            for (o = cLISTOPx(expr)->op_first; o; o = o->op_sibling) {
+            for (o = cLISTOPx(expr)->op_first; o; o = OP_SIBLING(o)) {
                 if (o->op_type == OP_CONST)
                     n++;
             }
@@ -6324,7 +6342,7 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count,
         if (expr->op_type == OP_CONST)
             new_patternp[n] = cSVOPx_sv(expr);
         else
-            for (o = cLISTOPx(expr)->op_first; o; o = o->op_sibling) {
+            for (o = cLISTOPx(expr)->op_first; o; o = OP_SIBLING(o)) {
                 if (o->op_type == OP_CONST)
                     new_patternp[n++] = cSVOPo_sv;
             }
@@ -6344,7 +6362,7 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count,
             assert(   expr->op_type == OP_PUSHMARK
                    || (expr->op_type == OP_NULL && expr->op_targ == OP_PUSHMARK)
                    || expr->op_type == OP_PADRANGE);
-            expr = expr->op_sibling;
+            expr = OP_SIBLING(expr);
     }
 
     pat = S_concat_pat(aTHX_ pRExC_state, NULL, new_patternp, pat_count,
@@ -6822,22 +6840,8 @@ reStudy:
        else if (PL_regkind[OP(first)] == TRIE &&
                ((reg_trie_data *)ri->data->data[ ARG(first) ])->minlen>0)
        {
-           regnode *trie_op;
-           /* this can happen only on restudy */
-           if ( OP(first) == TRIE ) {
-                struct regnode_1 *trieop = (struct regnode_1 *)
-                   PerlMemShared_calloc(1, sizeof(struct regnode_1));
-                StructCopy(first,trieop,struct regnode_1);
-                trie_op=(regnode *)trieop;
-            } else {
-                struct regnode_charclass *trieop = (struct regnode_charclass *)
-                   PerlMemShared_calloc(1, sizeof(struct regnode_charclass));
-                StructCopy(first,trieop,struct regnode_charclass);
-                trie_op=(regnode *)trieop;
-            }
-            OP(trie_op)+=2;
-            make_trie_failtable(pRExC_state, (regnode *)first, trie_op, 0);
-           ri->regstclass = trie_op;
+            /* this can happen only on restudy */
+            ri->regstclass = construct_ahocorasick_from_trie(pRExC_state, (regnode *)first, 0);
        }
 #endif
        else if (REGNODE_SIMPLE(OP(first)))
@@ -6860,6 +6864,7 @@ reStudy:
            goto again;
        }
        else if ((!sawopen || !RExC_sawback) &&
+            !sawlookahead &&
            (OP(first) == STAR &&
            PL_regkind[OP(NEXTOPER(first))] == REG_ANY) &&
             !(r->intflags & PREGf_ANCH) && !pRExC_state->num_code_blocks)
@@ -7830,7 +7835,7 @@ S_reg_scan_name(pTHX_ RExC_state_t *pRExC_state, U32 flags)
 /* The header definitions are in F<inline_invlist.c> */
 
 PERL_STATIC_INLINE UV*
-S__invlist_array_init(pTHX_ SV* const invlist, const bool will_have_0)
+S__invlist_array_init(SV* const invlist, const bool will_have_0)
 {
     /* Returns a pointer to the first element in the inversion list's array.
      * This is called upon initialization of an inversion list.  Where the
@@ -7856,7 +7861,7 @@ S__invlist_array_init(pTHX_ SV* const invlist, const bool will_have_0)
 }
 
 PERL_STATIC_INLINE UV*
-S_invlist_array(pTHX_ SV* const invlist)
+S_invlist_array(SV* const invlist)
 {
     /* Returns the pointer to the inversion list's array.  Every time the
      * length changes, this needs to be called in case malloc or realloc moved
@@ -7881,7 +7886,7 @@ S_invlist_set_len(pTHX_ SV* const invlist, const UV len, const bool offset)
 {
     /* Sets the current number of elements stored in the inversion list.
      * Updates SvCUR correspondingly */
-
+    PERL_UNUSED_CONTEXT;
     PERL_ARGS_ASSERT_INVLIST_SET_LEN;
 
     assert(SvTYPE(invlist) == SVt_INVLIST);
@@ -7894,11 +7899,10 @@ S_invlist_set_len(pTHX_ SV* const invlist, const UV len, const bool offset)
 }
 
 PERL_STATIC_INLINE IV*
-S_get_invlist_previous_index_addr(pTHX_ SV* invlist)
+S_get_invlist_previous_index_addr(SV* invlist)
 {
     /* Return the address of the IV that is reserved to hold the cached index
      * */
-
     PERL_ARGS_ASSERT_GET_INVLIST_PREVIOUS_INDEX_ADDR;
 
     assert(SvTYPE(invlist) == SVt_INVLIST);
@@ -7907,7 +7911,7 @@ S_get_invlist_previous_index_addr(pTHX_ SV* invlist)
 }
 
 PERL_STATIC_INLINE IV
-S_invlist_previous_index(pTHX_ SV* const invlist)
+S_invlist_previous_index(SV* const invlist)
 {
     /* Returns cached index of previous search */
 
@@ -7917,7 +7921,7 @@ S_invlist_previous_index(pTHX_ SV* const invlist)
 }
 
 PERL_STATIC_INLINE void
-S_invlist_set_previous_index(pTHX_ SV* const invlist, const IV index)
+S_invlist_set_previous_index(SV* const invlist, const IV index)
 {
     /* Caches <index> for later retrieval */
 
@@ -7929,7 +7933,7 @@ S_invlist_set_previous_index(pTHX_ SV* const invlist, const IV index)
 }
 
 PERL_STATIC_INLINE UV
-S_invlist_max(pTHX_ SV* const invlist)
+S_invlist_max(SV* const invlist)
 {
     /* Returns the maximum number of elements storable in the inversion list's
      * array, without having to realloc() */
@@ -8048,7 +8052,7 @@ S_invlist_extend(pTHX_ SV* const invlist, const UV new_max)
 }
 
 PERL_STATIC_INLINE void
-S_invlist_trim(pTHX_ SV* const invlist)
+S_invlist_trim(SV* const invlist)
 {
     PERL_ARGS_ASSERT_INVLIST_TRIM;
 
@@ -8147,7 +8151,7 @@ S__append_range_to_invlist(pTHX_ SV* const invlist,
 #ifndef PERL_IN_XSUB_RE
 
 IV
-Perl__invlist_search(pTHX_ SV* const invlist, const UV cp)
+Perl__invlist_search(SV* const invlist, const UV cp)
 {
     /* Searches the inversion list for the entry that contains the input code
      * point <cp>.  If <cp> is not in the list, -1 is returned.  Otherwise, the
@@ -8235,8 +8239,8 @@ Perl__invlist_search(pTHX_ SV* const invlist, const UV cp)
 }
 
 void
-Perl__invlist_populate_swatch(pTHX_ SV* const invlist,
-                                    const UV start, const UV end, U8* swatch)
+Perl__invlist_populate_swatch(SV* const invlist,
+                              const UV start, const UV end, U8* swatch)
 {
     /* populates a swatch of a swash the same way swatch_get() does in utf8.c,
      * but is used when the swash has an inversion list.  This makes this much
@@ -8948,7 +8952,7 @@ S_invlist_clone(pTHX_ SV* const invlist)
 }
 
 PERL_STATIC_INLINE STRLEN*
-S_get_invlist_iter_addr(pTHX_ SV* invlist)
+S_get_invlist_iter_addr(SV* invlist)
 {
     /* Return the address of the UV that contains the current iteration
      * position */
@@ -8961,7 +8965,7 @@ S_get_invlist_iter_addr(pTHX_ SV* invlist)
 }
 
 PERL_STATIC_INLINE void
-S_invlist_iterinit(pTHX_ SV* invlist)  /* Initialize iterator for invlist */
+S_invlist_iterinit(SV* invlist)        /* Initialize iterator for invlist */
 {
     PERL_ARGS_ASSERT_INVLIST_ITERINIT;
 
@@ -8969,7 +8973,7 @@ S_invlist_iterinit(pTHX_ SV* invlist)     /* Initialize iterator for invlist */
 }
 
 PERL_STATIC_INLINE void
-S_invlist_iterfinish(pTHX_ SV* invlist)
+S_invlist_iterfinish(SV* invlist)
 {
     /* Terminate iterator for invlist.  This is to catch development errors.
      * Any iteration that is interrupted before completed should call this
@@ -8985,7 +8989,7 @@ S_invlist_iterfinish(pTHX_ SV* invlist)
 }
 
 STATIC bool
-S_invlist_iternext(pTHX_ SV* invlist, UV* start, UV* end)
+S_invlist_iternext(SV* invlist, UV* start, UV* end)
 {
     /* An C<invlist_iterinit> call on <invlist> must be used to set this up.
      * This call sets in <*start> and <*end>, the next range in <invlist>.
@@ -9020,7 +9024,7 @@ S_invlist_iternext(pTHX_ SV* invlist, UV* start, UV* end)
 }
 
 PERL_STATIC_INLINE bool
-S_invlist_is_iterating(pTHX_ SV* const invlist)
+S_invlist_is_iterating(SV* const invlist)
 {
     PERL_ARGS_ASSERT_INVLIST_IS_ITERATING;
 
@@ -9028,7 +9032,7 @@ S_invlist_is_iterating(pTHX_ SV* const invlist)
 }
 
 PERL_STATIC_INLINE UV
-S_invlist_highest(pTHX_ SV* const invlist)
+S_invlist_highest(SV* const invlist)
 {
     /* Returns the highest code point that matches an inversion list.  This API
      * has an ambiguity, as it returns 0 under either the highest is actually
@@ -9458,7 +9462,6 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
      * RExC_parse beyond the '('.  Things like '(?' are indivisible tokens, and
      * this flag alerts us to the need to check for that */
 {
-    dVAR;
     regnode *ret;              /* Will be the head of the group. */
     regnode *br;
     regnode *lastbr;
@@ -9470,6 +9473,7 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
     bool is_open = 0;
     I32 freeze_paren = 0;
     I32 after_freeze = 0;
+    I32 num; /* numeric backreferences */
 
     char * parse_start = RExC_parse; /* MJD */
     char * const oregcomp_parse = RExC_parse;
@@ -9608,6 +9612,7 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
         else if (*RExC_parse == '?') { /* (?...) */
            bool is_logical = 0;
            const char * const seqstart = RExC_parse;
+            const char * endptr;
             if (has_intervening_patws) {
                 RExC_parse++;
                 vFAIL("In '(?...)', the '(' and '?' must be adjacent");
@@ -9787,8 +9792,7 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
                nextchar(pRExC_state);
                return ret;
                /*notreached*/
-            { /* named and numeric backreferences */
-                I32 num;
+            /* named and numeric backreferences */
             case '&':            /* (?&NAME) */
                 parse_start = RExC_parse - 1;
               named_recursion:
@@ -9818,12 +9822,21 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
            case '5': case '6': case '7': case '8': case '9':
                RExC_parse--;
               parse_recursion:
-               num = atoi(RExC_parse);
-               parse_start = RExC_parse - 1; /* MJD */
-               if (*RExC_parse == '-')
-                   RExC_parse++;
-               while (isDIGIT(*RExC_parse))
-                       RExC_parse++;
+                {
+                    bool is_neg = FALSE;
+                    parse_start = RExC_parse - 1; /* MJD */
+                    if (*RExC_parse == '-') {
+                        RExC_parse++;
+                        is_neg = TRUE;
+                    }
+                    num = grok_atou(RExC_parse, &endptr);
+                    if (endptr)
+                       RExC_parse = (char*)endptr;
+                    if (is_neg) {
+                        /* Some limit for num? */
+                        num = -num;
+                    }
+                }
                if (*RExC_parse!=')')
                    vFAIL("Expecting close bracket");
 
@@ -9870,7 +9883,7 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
                 *flagp |= POSTPONED;
                 nextchar(pRExC_state);
                 return ret;
-            } /* named and numeric backreferences */
+
             assert(0); /* NOT REACHED */
 
            case '?':           /* (??...) */
@@ -9963,6 +9976,8 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
                         REGTAIL(pRExC_state, ret, tail);
                        goto insert_if;
                    }
+                   /* Fall through to â€˜Unknown switch condition’ at the
+                      end of the if/else chain. */
                }
                else if ( RExC_parse[0] == '<'     /* (?(<NAME>)...) */
                         || RExC_parse[0] == '\'' ) /* (?('NAME')...) */
@@ -10000,9 +10015,9 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
                    RExC_parse++;
                    parno = 0;
                    if (RExC_parse[0] >= '1' && RExC_parse[0] <= '9' ) {
-                       parno = atoi(RExC_parse++);
-                       while (isDIGIT(*RExC_parse))
-                           RExC_parse++;
+                       parno = grok_atou(RExC_parse, &endptr);
+                       if (endptr)
+                            RExC_parse = (char*)endptr;
                    } else if (RExC_parse[0] == '&') {
                        SV *sv_dat;
                        RExC_parse++;
@@ -10019,10 +10034,9 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
                     /* (?(1)...) */
                    char c;
                    char *tmp;
-                   parno = atoi(RExC_parse++);
-
-                   while (isDIGIT(*RExC_parse))
-                       RExC_parse++;
+                   parno = grok_atou(RExC_parse, &endptr);
+                    if (endptr)
+                       RExC_parse = (char*)endptr;
                     ret = reganode(pRExC_state, GROUPP, parno);
 
                  insert_if_check_paren:
@@ -10087,10 +10101,8 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
                                     but I can't figure out why. -- dmq*/
                    return ret;
                }
-               else {
-                    RExC_parse += UTF ? UTF8SKIP(RExC_parse) : 1;
-                    vFAIL("Unknown switch condition (?(...))");
-               }
+                RExC_parse += UTF ? UTF8SKIP(RExC_parse) : 1;
+                vFAIL("Unknown switch condition (?(...))");
            }
            case '[':           /* (?[ ... ]) */
                 return handle_regex_sets(pRExC_state, NULL, flagp, depth,
@@ -10367,7 +10379,6 @@ S_reg(pTHX_ RExC_state_t *pRExC_state, I32 paren, I32 *flagp,U32 depth)
 STATIC regnode *
 S_regbranch(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, I32 first, U32 depth)
 {
-    dVAR;
     regnode *ret;
     regnode *chain = NULL;
     regnode *latest;
@@ -10449,7 +10460,6 @@ S_regbranch(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, I32 first, U32 depth)
 STATIC regnode *
 S_regpiece(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, U32 depth)
 {
-    dVAR;
     regnode *ret;
     char op;
     char *next;
@@ -10482,7 +10492,7 @@ S_regpiece(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, U32 depth)
 
     op = *RExC_parse;
 
-    if (op == '{' && regcurly(RExC_parse, FALSE)) {
+    if (op == '{' && regcurly(RExC_parse)) {
        maxpos = NULL;
 #ifdef RE_TRACK_PATTERN_OFFSETS
         parse_start = RExC_parse; /* MJD */
@@ -10498,15 +10508,16 @@ S_regpiece(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, U32 depth)
            next++;
        }
        if (*next == '}') {             /* got one */
+            const char* endptr;
            if (!maxpos)
                maxpos = next;
            RExC_parse++;
-           min = atoi(RExC_parse);
+           min = grok_atou(RExC_parse, &endptr);
            if (*maxpos == ',')
                maxpos++;
            else
                maxpos = RExC_parse;
-           max = atoi(maxpos);
+           max = grok_atou(maxpos, &endptr);
            if (!max && *maxpos != '0')
                max = REG_INFTY;                /* meaning "infinity" */
            else if (max >= REG_INFTY)
@@ -10758,7 +10769,7 @@ S_grok_bslash_N(pTHX_ RExC_state_t *pRExC_state, regnode** node_p,
 
     /* Disambiguate between \N meaning a named character versus \N meaning
      * [^\n].  The former is assumed when it can't be the latter. */
-    if (*p != '{' || regcurly(p, FALSE)) {
+    if (*p != '{' || regcurly(p)) {
        RExC_parse = p;
        if (! node_p) {
            /* no bare \N allowed in a charclass */
@@ -10980,7 +10991,7 @@ S_reg_recode(pTHX_ const char value, SV **encp)
 }
 
 PERL_STATIC_INLINE U8
-S_compute_EXACTish(pTHX_ RExC_state_t *pRExC_state)
+S_compute_EXACTish(RExC_state_t *pRExC_state)
 {
     U8 op;
 
@@ -11153,18 +11164,17 @@ S_alloc_maybe_populate_EXACT(pTHX_ RExC_state_t *pRExC_state,
 }
 
 
-/* return atoi(p), unless it's too big to sensibly be a backref,
+/* Parse backref decimal value, unless it's too big to sensibly be a backref,
  * in which case return I32_MAX (rather than possibly 32-bit wrapping) */
 
 static I32
 S_backref_value(char *p)
 {
-    char *q = p;
-
-    for (;isDIGIT(*q); q++) {} /* calculate length of num */
-    if (q - p == 0 || q - p > 9)
+    const char* endptr;
+    UV val = grok_atou(p, &endptr);
+    if (endptr == p || endptr == NULL || val > I32_MAX)
         return I32_MAX;
-    return atoi(p);
+    return (I32)val;
 }
 
 
@@ -11237,12 +11247,12 @@ S_backref_value(char *p)
 STATIC regnode *
 S_regatom(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, U32 depth)
 {
-    dVAR;
     regnode *ret = NULL;
     I32 flags = 0;
     char *parse_start = RExC_parse;
     U8 op;
     int invert = 0;
+    U8 arg;
 
     GET_RE_DEBUG_FLAGS_DECL;
 
@@ -11339,12 +11349,6 @@ tryagain:
        vFAIL("Internal urp");
                                /* Supposed to be caught earlier. */
        break;
-    case '{':
-       if (!regcurly(RExC_parse, FALSE)) {
-           RExC_parse++;
-           goto defchar;
-       }
-       /* FALLTHROUGH */
     case '?':
     case '+':
     case '*':
@@ -11365,7 +11369,6 @@ tryagain:
           literal text handling code.
        */
        switch ((U8)*++RExC_parse) {
-            U8 arg;
        /* Special Escapes */
        case 'A':
            RExC_seen_zerolen++;
@@ -11401,6 +11404,9 @@ tryagain:
            ret = reg_node(pRExC_state, CANY);
             RExC_seen |= REG_CANY_SEEN;
            *flagp |= HASWIDTH|SIMPLE;
+            if (SIZE_ONLY) {
+                ckWARNdep(RExC_parse+1, "\\C is deprecated");
+            }
            goto finish_meta_pat;
        case 'X':
            ret = reg_node(pRExC_state, CLUMP);
@@ -11883,7 +11889,7 @@ tryagain:
                        p++;
                        break;
                    case 'e':
-                         ender = ASCII_TO_NATIVE('\033');
+                       ender = ESC_NATIVE;
                        p++;
                        break;
                    case 'a':
@@ -12026,8 +12032,18 @@ tryagain:
                        goto normal_default;
                    } /* End of switch on '\' */
                    break;
+               case '{':
+                   /* Currently we don't warn when the lbrace is at the start
+                    * of a construct.  This catches it in the middle of a
+                    * literal string, or when its the first thing after
+                    * something like "\b" */
+                   if (! SIZE_ONLY
+                       && (len || (p > RExC_start && isALPHA_A(*(p -1)))))
+                   {
+                       ckWARNregdep(p + 1, "Unescaped left brace in regex is deprecated, passed through");
+                   }
+                   /*FALLTHROUGH*/
                default:    /* A literal character */
-
                  normal_default:
                    if (UTF8_IS_START(*p) && UTF) {
                        STRLEN numlen;
@@ -12401,7 +12417,7 @@ tryagain:
 }
 
 STATIC char *
-S_regpatws(pTHX_ RExC_state_t *pRExC_state, char *p , const bool recognize_comment )
+S_regpatws(RExC_state_t *pRExC_state, char *p , const bool recognize_comment )
 {
     /* Returns the next non-pattern-white space, non-comment character (the
      * latter only if 'recognize_comment is true) in the string p, which is
@@ -12456,14 +12472,16 @@ S_populate_ANYOF_from_invlist(pTHX_ regnode *node, SV** invlist_ptr)
             }
 
            /* Quit if are above what we should change */
-           if (start > 255) {
+           if (start >= NUM_ANYOF_CODE_POINTS) {
                break;
            }
 
            change_invlist = TRUE;
 
            /* Set all the bits in the range, up to the max that we are doing */
-           high = (end < 255) ? end : 255;
+           high = (end < NUM_ANYOF_CODE_POINTS - 1)
+                   ? end
+                   : NUM_ANYOF_CODE_POINTS - 1;
            for (i = start; i <= (int) high; i++) {
                if (! ANYOF_BITMAP_TEST(node, i)) {
                    ANYOF_BITMAP_SET(node, i);
@@ -12503,7 +12521,6 @@ S_populate_ANYOF_from_invlist(pTHX_ regnode *node, SV** invlist_ptr)
 PERL_STATIC_INLINE I32
 S_regpposixcc(pTHX_ RExC_state_t *pRExC_state, I32 value, const bool strict)
 {
-    dVAR;
     I32 namedclass = OOB_NAMEDCLASS;
 
     PERL_ARGS_ASSERT_REGPPOSIXCC;
@@ -12645,7 +12662,7 @@ S_regpposixcc(pTHX_ RExC_state_t *pRExC_state, I32 value, const bool strict)
 }
 
 STATIC bool
-S_could_it_be_a_POSIX_class(pTHX_ RExC_state_t *pRExC_state)
+S_could_it_be_a_POSIX_class(RExC_state_t *pRExC_state)
 {
     /* This applies some heuristics at the current parse position (which should
      * be at a '[') to see if what follows might be intended to be a [:posix:]
@@ -13198,9 +13215,10 @@ S_add_above_Latin1_folds(pTHX_ RExC_state_t *pRExC_state, const U8 cp, SV** invl
      * disk to find the possible matches.
      *
      * This should be called only for a Latin1-range code points, cp, which is
-     * known to be involved in a fold with other code points above Latin1.  It
-     * would give false results if /aa has been specified.  Multi-char folds
-     * are outside the scope of this, and must be handled specially.
+     * known to be involved in a simple fold with other code points above
+     * Latin1.  It would give false results if /aa has been specified.
+     * Multi-char folds are outside the scope of this, and must be handled
+     * specially.
      *
      * XXX It would be better to generate these via regen, in case a new
      * version of the Unicode standard adds new mappings, though that is not
@@ -13209,6 +13227,8 @@ S_add_above_Latin1_folds(pTHX_ RExC_state_t *pRExC_state, const U8 cp, SV** invl
 
     PERL_ARGS_ASSERT_ADD_ABOVE_LATIN1_FOLDS;
 
+    assert(HAS_NONLATIN1_SIMPLE_FOLD_CLOSURE(cp));
+
     switch (cp) {
         case 'k':
         case 'K':
@@ -13234,22 +13254,6 @@ S_add_above_Latin1_folds(pTHX_ RExC_state_t *pRExC_state, const U8 cp, SV** invl
         case LATIN_SMALL_LETTER_SHARP_S:
           *invlist = add_cp_to_invlist(*invlist, LATIN_CAPITAL_LETTER_SHARP_S);
             break;
-        case 'F': case 'f':
-        case 'I': case 'i':
-        case 'L': case 'l':
-        case 'T': case 't':
-        case 'A': case 'a':
-        case 'H': case 'h':
-        case 'J': case 'j':
-        case 'N': case 'n':
-        case 'W': case 'w':
-        case 'Y': case 'y':
-            /* These all are targets of multi-character folds from code points
-             * that require UTF8 to express, so they can't match unless the
-             * target string is in UTF-8, so no action here is necessary, as
-             * regexec.c properly handles the general case for UTF-8 matching
-             * and multi-char folds */
-            break;
         default:
             /* Use deprecated warning to increase the chances of this being
              * output */
@@ -13289,17 +13293,16 @@ S_regclass(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, U32 depth,
      * ignored in the recursion by means of a flag:
      * <RExC_in_multi_char_class>.)
      *
-     * ANYOF nodes contain a bit map for the first 256 characters, with the
-     * corresponding bit set if that character is in the list.  For characters
-     * above 255, a range list or swash is used.  There are extra bits for \w,
-     * etc. in locale ANYOFs, as what these match is not determinable at
-     * compile time
+     * ANYOF nodes contain a bit map for the first NUM_ANYOF_CODE_POINTS
+     * characters, with the corresponding bit set if that character is in the
+     * list.  For characters above this, a range list or swash is used.  There
+     * are extra bits for \w, etc. in locale ANYOFs, as what these match is not
+     * determinable at compile time
      *
      * Returns NULL, setting *flagp to RESTART_UTF8 if the sizing scan needs
      * to be restarted.  This can only happen if ret_invlist is non-NULL.
      */
 
-    dVAR;
     UV prevvalue = OOB_UNICODE, save_prevvalue = OOB_UNICODE;
     IV range = 0;
     UV value = OOB_UNICODE, save_value = OOB_UNICODE;
@@ -13481,8 +13484,14 @@ parseit:
         {
             namedclass = regpposixcc(pRExC_state, value, strict);
         }
-        else if (value == '\\') {
-           if (UTF) {
+        else if (value != '\\') {
+#ifdef EBCDIC
+            literal_endpoint++;
+#endif
+        }
+        else {
+            /* Is a backslash; get the code point of the char after it */
+           if (UTF && ! UTF8_IS_INVARIANT(RExC_parse)) {
                value = utf8n_to_uvchr((U8*)RExC_parse,
                                   RExC_end - RExC_parse,
                                   &numlen, UTF8_ALLOW_DEFAULT);
@@ -13564,7 +13573,6 @@ parseit:
                }
                if (!SIZE_ONLY) {
                     SV* invlist;
-                    char* formatted;
                     char* name;
 
                    if (UCHARAT(RExC_parse) == '^') {
@@ -13585,14 +13593,13 @@ parseit:
                      * will have its name be <__NAME_i>.  The design is
                      * discussed in commit
                      * 2f833f5208e26b208886e51e09e2c072b5eabb46 */
-                    formatted = Perl_form(aTHX_
+                    name = savepv(Perl_form(aTHX_
                                           "%s%.*s%s\n",
                                           (FOLD) ? "__" : "",
                                           (int)n,
                                           RExC_parse,
                                           (FOLD) ? "_i" : ""
-                                );
-                    name = savepvn(formatted, strlen(formatted));
+                                ));
 
                     /* Look up the property name, and get its swash and
                      * inversion list, if the property is found  */
@@ -13606,6 +13613,9 @@ parseit:
                                              &swash_init_flags
                                             );
                     if (! swash || ! (invlist = _get_swash_invlist(swash))) {
+                        HV* curpkg = (IN_PERL_COMPILETIME)
+                                      ? PL_curstash
+                                      : CopSTASH(PL_curcop);
                         if (swash) {
                             SvREFCNT_dec_NN(swash);
                             swash = NULL;
@@ -13621,6 +13631,22 @@ parseit:
                                 "Property '%"UTF8f"' is unknown",
                                 UTF8fARG(UTF, n, name));
                         }
+
+                        /* If the property name doesn't already have a package
+                         * name, add the current one to it so that it can be
+                         * referred to outside it. [perl #121777] */
+                        if (curpkg && ! instr(name, "::")) {
+                            char* pkgname = HvNAME(curpkg);
+                            if (strNE(pkgname, "main")) {
+                                char* full_name = Perl_form(aTHX_
+                                                            "%s::%s",
+                                                            pkgname,
+                                                            name);
+                                n = strlen(full_name);
+                                Safefree(name);
+                                name = savepvn(full_name, n);
+                            }
+                        }
                         Perl_sv_catpvf(aTHX_ listsv, "%cutf8::%"UTF8f"\n",
                                         (value == 'p' ? '+' : '!'),
                                         UTF8fARG(UTF, n, name));
@@ -13689,7 +13715,7 @@ parseit:
            case 't':   value = '\t';                   break;
            case 'f':   value = '\f';                   break;
            case 'b':   value = '\b';                   break;
-           case 'e':   value = ASCII_TO_NATIVE('\033');break;
+           case 'e':   value = ESC_NATIVE;             break;
            case 'a':   value = '\a';                   break;
            case 'o':
                RExC_parse--;   /* function expects to be pointed at the 'o' */
@@ -13795,10 +13821,6 @@ parseit:
                break;
            }   /* End of switch on char following backslash */
        } /* end of handling backslash escape sequences */
-#ifdef EBCDIC
-        else
-            literal_endpoint++;
-#endif
 
         /* Here, we have the current token in 'value' */
 
@@ -14075,7 +14097,7 @@ parseit:
                         AV* this_array;
                         STRLEN cp_count = utf8_length(foldbuf,
                                                       foldbuf + foldlen);
-                        SV* multi_fold = sv_2mortal(newSVpvn("", 0));
+                        SV* multi_fold = sv_2mortal(newSVpvs(""));
 
                         Perl_sv_catpvf(aTHX_ multi_fold, "\\x{%"UVXf"}", value);
 
@@ -14142,7 +14164,7 @@ parseit:
                 && ((prevvalue >= 'a' && value <= 'z')
                     || (prevvalue >= 'A' && value <= 'Z')))
             {
-                _invlist_intersection(this_range, PL_ASCII,
+                _invlist_intersection(this_range, PL_XPosix_ptrs[_CC_ASCII],
                                       &this_range);
 
                 /* Since this above only contains ascii, the intersection of it
@@ -14498,7 +14520,7 @@ parseit:
                             }
                         }
 
-                        if (HAS_NONLATIN1_FOLD_CLOSURE(j)
+                        if (HAS_NONLATIN1_SIMPLE_FOLD_CLOSURE(j)
                             && (! isASCII(j) || ! ASCII_FOLD_RESTRICTED))
                         {
                             add_above_Latin1_folds(pRExC_state,
@@ -14905,6 +14927,10 @@ parseit:
        swash = NULL;
     }
 
+    /* Note that the optimization of using 'swash' if it is the only thing in
+     * the class doesn't have us change swash at all, so it can include things
+     * that are also in the bitmap; otherwise we have purposely deleted that
+     * duplicate information */
     set_ANYOF_arg(pRExC_state, ret, cp_list,
                   (HAS_NONLOCALE_RUNTIME_PROPERTY_DEFINITION)
                    ? listsv : NULL,
@@ -14998,6 +15024,134 @@ S_set_ANYOF_arg(pTHX_ RExC_state_t* const pRExC_state,
     }
 }
 
+#if !defined(PERL_IN_XSUB_RE) || defined(PLUGGABLE_RE_EXTENSION)
+SV *
+Perl__get_regclass_nonbitmap_data(pTHX_ const regexp *prog,
+                                        const regnode* node,
+                                        bool doinit,
+                                        SV** listsvp,
+                                        SV** only_utf8_locale_ptr,
+                                        SV*  exclude_list)
+
+{
+    /* For internal core use only.
+     * Returns the swash for the input 'node' in the regex 'prog'.
+     * If <doinit> is 'true', will attempt to create the swash if not already
+     *   done.
+     * If <listsvp> is non-null, will return the printable contents of the
+     *    swash.  This can be used to get debugging information even before the
+     *    swash exists, by calling this function with 'doinit' set to false, in
+     *    which case the components that will be used to eventually create the
+     *    swash are returned  (in a printable form).
+     * If <exclude_list> is not NULL, it is an inversion list of things to
+     *    exclude from what's returned in <listsvp>.
+     * Tied intimately to how S_set_ANYOF_arg sets up the data structure.  Note
+     * that, in spite of this function's name, the swash it returns may include
+     * the bitmap data as well */
+
+    SV *sw  = NULL;
+    SV *si  = NULL;         /* Input swash initialization string */
+    SV*  invlist = NULL;
+
+    RXi_GET_DECL(prog,progi);
+    const struct reg_data * const data = prog ? progi->data : NULL;
+
+    PERL_ARGS_ASSERT__GET_REGCLASS_NONBITMAP_DATA;
+
+    assert(ANYOF_FLAGS(node)
+                        & (ANYOF_UTF8|ANYOF_NONBITMAP_NON_UTF8|ANYOF_LOC_FOLD));
+
+    if (data && data->count) {
+       const U32 n = ARG(node);
+
+       if (data->what[n] == 's') {
+           SV * const rv = MUTABLE_SV(data->data[n]);
+           AV * const av = MUTABLE_AV(SvRV(rv));
+           SV **const ary = AvARRAY(av);
+           U8 swash_init_flags = _CORE_SWASH_INIT_ACCEPT_INVLIST;
+
+           si = *ary;  /* ary[0] = the string to initialize the swash with */
+
+           /* Elements 3 and 4 are either both present or both absent. [3] is
+            * any inversion list generated at compile time; [4] indicates if
+            * that inversion list has any user-defined properties in it. */
+            if (av_tindex(av) >= 2) {
+                if (only_utf8_locale_ptr
+                    && ary[2]
+                    && ary[2] != &PL_sv_undef)
+                {
+                    *only_utf8_locale_ptr = ary[2];
+                }
+                else {
+                    assert(only_utf8_locale_ptr);
+                    *only_utf8_locale_ptr = NULL;
+                }
+
+                if (av_tindex(av) >= 3) {
+                    invlist = ary[3];
+                    if (SvUV(ary[4])) {
+                        swash_init_flags |= _CORE_SWASH_INIT_USER_DEFINED_PROPERTY;
+                    }
+                }
+                else {
+                    invlist = NULL;
+                }
+           }
+
+           /* Element [1] is reserved for the set-up swash.  If already there,
+            * return it; if not, create it and store it there */
+           if (ary[1] && SvROK(ary[1])) {
+               sw = ary[1];
+           }
+           else if (doinit && ((si && si != &PL_sv_undef)
+                                 || (invlist && invlist != &PL_sv_undef))) {
+               assert(si);
+               sw = _core_swash_init("utf8", /* the utf8 package */
+                                     "", /* nameless */
+                                     si,
+                                     1, /* binary */
+                                     0, /* not from tr/// */
+                                     invlist,
+                                     &swash_init_flags);
+               (void)av_store(av, 1, sw);
+           }
+       }
+    }
+
+    /* If requested, return a printable version of what this swash matches */
+    if (listsvp) {
+       SV* matches_string = newSVpvs("");
+
+        /* The swash should be used, if possible, to get the data, as it
+         * contains the resolved data.  But this function can be called at
+         * compile-time, before everything gets resolved, in which case we
+         * return the currently best available information, which is the string
+         * that will eventually be used to do that resolving, 'si' */
+       if ((! sw || (invlist = _get_swash_invlist(sw)) == NULL)
+            && (si && si != &PL_sv_undef))
+        {
+           sv_catsv(matches_string, si);
+       }
+
+       /* Add the inversion list to whatever we have.  This may have come from
+        * the swash, or from an input parameter */
+       if (invlist) {
+            if (exclude_list) {
+                SV* clone = invlist_clone(invlist);
+                _invlist_subtract(clone, exclude_list, &clone);
+                sv_catsv(matches_string, _invlist_contents(clone));
+                SvREFCNT_dec_NN(clone);
+            }
+            else {
+                sv_catsv(matches_string, _invlist_contents(invlist));
+            }
+       }
+       *listsvp = matches_string;
+    }
+
+    return sw;
+}
+#endif /* !defined(PERL_IN_XSUB_RE) || defined(PLUGGABLE_RE_EXTENSION) */
 
 /* reg_skipcomment()
 
@@ -15013,11 +15167,11 @@ S_set_ANYOF_arg(pTHX_ RExC_state_t* const pRExC_state,
 */
 
 PERL_STATIC_INLINE char*
-S_reg_skipcomment(pTHX_ RExC_state_t *pRExC_state, char* p)
+S_reg_skipcomment(RExC_state_t *pRExC_state, char* p)
 {
     PERL_ARGS_ASSERT_REG_SKIPCOMMENT;
 
-    assert(*p = '#');
+    assert(*p == '#');
 
     while (p < RExC_end) {
         if (*(++p) == '\n') {
@@ -15083,7 +15237,6 @@ S_nextchar(pTHX_ RExC_state_t *pRExC_state)
 STATIC regnode *                       /* Location. */
 S_reg_node(pTHX_ RExC_state_t *pRExC_state, U8 op)
 {
-    dVAR;
     regnode *ptr;
     regnode * const ret = RExC_emit;
     GET_RE_DEBUG_FLAGS_DECL;
@@ -15097,7 +15250,7 @@ S_reg_node(pTHX_ RExC_state_t *pRExC_state, U8 op)
     }
     if (RExC_emit >= RExC_emit_bound)
         Perl_croak(aTHX_ "panic: reg_node overrun trying to emit %d, %p>=%p",
-                  op, RExC_emit, RExC_emit_bound);
+                  op, (void*)RExC_emit, (void*)RExC_emit_bound);
 
     NODE_ALIGN_FILL(ret);
     ptr = ret;
@@ -15126,7 +15279,6 @@ S_reg_node(pTHX_ RExC_state_t *pRExC_state, U8 op)
 STATIC regnode *                       /* Location. */
 S_reganode(pTHX_ RExC_state_t *pRExC_state, U8 op, U32 arg)
 {
-    dVAR;
     regnode *ptr;
     regnode * const ret = RExC_emit;
     GET_RE_DEBUG_FLAGS_DECL;
@@ -15154,7 +15306,7 @@ S_reganode(pTHX_ RExC_state_t *pRExC_state, U8 op, U32 arg)
     }
     if (RExC_emit >= RExC_emit_bound)
         Perl_croak(aTHX_ "panic: reg_node overrun trying to emit %d, %p>=%p",
-                  op, RExC_emit, RExC_emit_bound);
+                  op, (void*)RExC_emit, (void*)RExC_emit_bound);
 
     NODE_ALIGN_FILL(ret);
     ptr = ret;
@@ -15184,8 +15336,6 @@ S_reganode(pTHX_ RExC_state_t *pRExC_state, U8 op, U32 arg)
 PERL_STATIC_INLINE STRLEN
 S_reguni(pTHX_ const RExC_state_t *pRExC_state, UV uv, char* s)
 {
-    dVAR;
-
     PERL_ARGS_ASSERT_REGUNI;
 
     return SIZE_ONLY ? UNISKIP(uv) : (uvchr_to_utf8((U8*)s, uv) - (U8*)s);
@@ -15199,7 +15349,6 @@ S_reguni(pTHX_ const RExC_state_t *pRExC_state, UV uv, char* s)
 STATIC void
 S_reginsert(pTHX_ RExC_state_t *pRExC_state, U8 op, regnode *opnd, U32 depth)
 {
-    dVAR;
     regnode *src;
     regnode *dst;
     regnode *place;
@@ -15208,6 +15357,7 @@ S_reginsert(pTHX_ RExC_state_t *pRExC_state, U8 op, regnode *opnd, U32 depth)
     GET_RE_DEBUG_FLAGS_DECL;
 
     PERL_ARGS_ASSERT_REGINSERT;
+    PERL_UNUSED_CONTEXT;
     PERL_UNUSED_ARG(depth);
 /* (PL_regkind[(U8)op] == CURLY ? EXTRA_STEP_2ARGS : 0); */
     DEBUG_PARSE_FMT("inst"," - %s",PL_reg_name[op]);
@@ -15290,7 +15440,6 @@ STATIC void
 S_regtail(pTHX_ RExC_state_t *pRExC_state, regnode *p,
                 const regnode *val,U32 depth)
 {
-    dVAR;
     regnode *scan;
     GET_RE_DEBUG_FLAGS_DECL;
 
@@ -15350,7 +15499,6 @@ STATIC U8
 S_regtail_study(pTHX_ RExC_state_t *pRExC_state, regnode *p,
                       const regnode *val,U32 depth)
 {
-    dVAR;
     regnode *scan;
     U8 exact = PSEUDO;
 #ifdef EXPERIMENTAL_INPLACESCAN
@@ -15513,7 +15661,6 @@ void
 Perl_regdump(pTHX_ const regexp *r)
 {
 #ifdef DEBUGGING
-    dVAR;
     SV * const sv = sv_newmortal();
     SV *dsv= sv_newmortal();
     RXi_GET_DECL(r,ri);
@@ -15612,7 +15759,6 @@ void
 Perl_regprop(pTHX_ const regexp *prog, SV *sv, const regnode *o, const regmatch_info *reginfo)
 {
 #ifdef DEBUGGING
-    dVAR;
     int k;
 
     /* Should be synchronized with * ANYOF_ #xdefines in regcomp.h */
@@ -15715,9 +15861,11 @@ Perl_regprop(pTHX_ const regexp *prog, SV *sv, const regnode *o, const regmatch_
         );
         if ( IS_ANYOF_TRIE(op) || trie->bitmap ) {
             sv_catpvs(sv, "[");
-            (void) put_latin1_charclass_innards(sv, IS_ANYOF_TRIE(op)
-                                                   ? ANYOF_BITMAP(o)
-                                                   : TRIE_BITMAP(trie));
+            (void) put_charclass_bitmap_innards(sv,
+                                                (IS_ANYOF_TRIE(op))
+                                                 ? ANYOF_BITMAP(o)
+                                                 : TRIE_BITMAP(trie),
+                                                NULL);
             sv_catpvs(sv, "]");
         }
 
@@ -15781,6 +15929,7 @@ Perl_regprop(pTHX_ const regexp *prog, SV *sv, const regnode *o, const regmatch_
     else if (k == ANYOF) {
        const U8 flags = ANYOF_FLAGS(o);
        int do_sep = 0;
+        SV* bitmap_invlist;  /* Will hold what the bit map contains */
 
 
        if (flags & ANYOF_LOCALE_FLAGS)
@@ -15791,8 +15940,10 @@ Perl_regprop(pTHX_ const regexp *prog, SV *sv, const regnode *o, const regmatch_
        if (flags & ANYOF_INVERT)
            sv_catpvs(sv, "^");
 
-       /* output what the standard cp 0-255 bitmap matches */
-        do_sep = put_latin1_charclass_innards(sv, ANYOF_BITMAP(o));
+        /* output what the standard cp 0-NUM_ANYOF_CODE_POINTS-1 bitmap matches
+         * */
+        do_sep = put_charclass_bitmap_innards(sv, ANYOF_BITMAP(o),
+                                                            &bitmap_invlist);
 
         /* output any special charclass tests (used entirely under use
          * locale) * */
@@ -15831,9 +15982,12 @@ Perl_regprop(pTHX_ const regexp *prog, SV *sv, const regnode *o, const regmatch_
                                                been output */
                 SV *only_utf8_locale;
 
-                /* Get the stuff that wasn't in the bitmap */
+                /* Get the stuff that wasn't in the bitmap.  'bitmap_invlist'
+                 * is used to guarantee that nothing in the bitmap gets
+                 * returned */
                 (void) _get_regclass_nonbitmap_data(prog, o, FALSE,
-                                                    &lv, &only_utf8_locale);
+                                                    &lv, &only_utf8_locale,
+                                                    bitmap_invlist);
                 if (lv && lv != &PL_sv_undef) {
                     char *s = savesvpv(lv);
                     char * const origs = s;
@@ -15907,6 +16061,8 @@ Perl_regprop(pTHX_ const regexp *prog, SV *sv, const regnode *o, const regmatch_
                 }
             }
        }
+        SvREFCNT_dec(bitmap_invlist);
+
 
        Perl_sv_catpvf(aTHX_ sv, "%s]", PL_colors[1]);
     }
@@ -15941,7 +16097,6 @@ Perl_regprop(pTHX_ const regexp *prog, SV *sv, const regnode *o, const regmatch_
 SV *
 Perl_re_intuit_string(pTHX_ REGEXP * const r)
 {                              /* Assume that RE_INTUIT is set */
-    dVAR;
     struct regexp *const prog = ReANY(r);
     GET_RE_DEBUG_FLAGS_DECL;
 
@@ -15989,7 +16144,6 @@ Perl_pregfree(pTHX_ REGEXP *r)
 void
 Perl_pregfree2(pTHX_ REGEXP *rx)
 {
-    dVAR;
     struct regexp *const r = ReANY(rx);
     GET_RE_DEBUG_FLAGS_DECL;
 
@@ -16118,7 +16272,6 @@ Perl_reg_temp_copy (pTHX_ REGEXP *ret_x, REGEXP *rx)
 void
 Perl_regfree_internal(pTHX_ REGEXP * const rx)
 {
-    dVAR;
     struct regexp *const r = ReANY(rx);
     RXi_GET_DECL(r,ri);
     GET_RE_DEBUG_FLAGS_DECL;
@@ -16171,6 +16324,9 @@ Perl_regfree_internal(pTHX_ REGEXP * const rx)
                      Used in stclass optimization only */
                     U32 refcount;
                     reg_ac_data *aho=(reg_ac_data*)ri->data->data[n];
+#ifdef USE_ITHREADS
+                    dVAR;
+#endif
                     OP_REFCNT_LOCK;
                     refcount = --aho->refcount;
                     OP_REFCNT_UNLOCK;
@@ -16179,7 +16335,16 @@ Perl_regfree_internal(pTHX_ REGEXP * const rx)
                         PerlMemShared_free(aho->fail);
                         /* do this last!!!! */
                         PerlMemShared_free(ri->data->data[n]);
-                        PerlMemShared_free(ri->regstclass);
+                        /* we should only ever get called once, so
+                         * assert as much, and also guard the free
+                         * which /might/ happen twice. At the least
+                         * it will make code anlyzers happy and it
+                         * doesn't cost much. - Yves */
+                        assert(ri->regstclass);
+                        if (ri->regstclass) {
+                            PerlMemShared_free(ri->regstclass);
+                            ri->regstclass = 0;
+                        }
                     }
                 }
                 break;
@@ -16188,6 +16353,9 @@ Perl_regfree_internal(pTHX_ REGEXP * const rx)
                    /* trie structure. */
                    U32 refcount;
                    reg_trie_data *trie=(reg_trie_data*)ri->data->data[n];
+#ifdef USE_ITHREADS
+                    dVAR;
+#endif
                     OP_REFCNT_LOCK;
                     refcount = --trie->refcount;
                     OP_REFCNT_UNLOCK;
@@ -16438,7 +16606,6 @@ Perl_regdupe_internal(pTHX_ REGEXP * const rx, CLONE_PARAMS *param)
 regnode *
 Perl_regnext(pTHX_ regnode *p)
 {
-    dVAR;
     I32 offset;
 
     if (!p)
@@ -16494,8 +16661,6 @@ S_re_croak2(pTHX_ bool utf8, const char* pat1,const char* pat2,...)
 void
 Perl_save_re_context(pTHX)
 {
-    dVAR;
-
     /* Save $1..$n (#18107: UTF-8 s/(\w+)/uc($1)/e); AMS 20021106. */
     if (PL_curpm) {
        const REGEXP * const rx = PM_GETRE(PL_curpm);
@@ -16528,11 +16693,11 @@ S_put_byte(pTHX_ SV *sv, int c)
 
     if (!isPRINT(c)) {
         switch (c) {
-            case '\r': Perl_sv_catpvf(aTHX_ sv, "\\r"); break;
+            case '\a': Perl_sv_catpvf(aTHX_ sv, "\\a"); break;
+            case '\f': Perl_sv_catpvf(aTHX_ sv, "\\f"); break;
             case '\n': Perl_sv_catpvf(aTHX_ sv, "\\n"); break;
+            case '\r': Perl_sv_catpvf(aTHX_ sv, "\\r"); break;
             case '\t': Perl_sv_catpvf(aTHX_ sv, "\\t"); break;
-            case '\f': Perl_sv_catpvf(aTHX_ sv, "\\f"); break;
-            case '\a': Perl_sv_catpvf(aTHX_ sv, "\\a"); break;
 
             default:
                 Perl_sv_catpvf(aTHX_ sv, "\\x{%x}", c);
@@ -16552,65 +16717,143 @@ S_put_range(pTHX_ SV *sv, UV start, UV end)
 {
 
     /* Appends to 'sv' a displayable version of the range of code points from
-     * 'start' to 'end' */
+     * 'start' to 'end'.  It assumes that only ASCII printables are displayable
+     * as-is (though some of these will be escaped by put_byte()). */
 
     assert(start <= end);
 
     PERL_ARGS_ASSERT_PUT_RANGE;
 
-    if (end - start < 3) {  /* Individual chars in short ranges */
-        for (; start <= end; start++)
-            put_byte(sv, start);
-    }
-    else if (   end > 255
-             || ! isALPHANUMERIC(start)
-             || ! isALPHANUMERIC(end)
-             || isDIGIT(start) != isDIGIT(end)
-             || isUPPER(start) != isUPPER(end)
-             || isLOWER(start) != isLOWER(end)
-
-                /* This final test should get optimized out except on EBCDIC
-                 * platforms, where it causes ranges that cross discontinuities
-                 * like i/j to be shown as hex instead of the misleading,
-                 * e.g. H-K (since that range includes more than H, I, J, K).
-                 * */
-             || (end - start) != NATIVE_TO_ASCII(end) - NATIVE_TO_ASCII(start))
-    {
+    while (start <= end) {
+        if (end - start < 3) {  /* Individual chars in short ranges */
+            for (; start <= end; start++) {
+                put_byte(sv, start);
+            }
+            break;
+        }
+
+        /* For small ranges that include printable ASCII characters, it's more
+         * legible to print those characters rather than hex values.  For
+         * larger ranges that include more than printables, it's probably
+         * clearer to just give the start and end points of the range in hex,
+         * and that's all we can do if there aren't any printables within the
+         * range
+         *
+         * On ASCII platforms the range of printables is contiguous.  If the
+         * entire range is printable, we print each character as such.  If the
+         * range is partially printable and partially not, it's less likely
+         * that the individual printables are meaningful, especially if all or
+         * almost all of them are in the range.  But we err on the side of the
+         * individual printables being meaningful by using the hex only if the
+         * range contains all but 2 of the printables.
+         *
+         * On EBCDIC platforms, the printables are scattered around so that the
+         * maximum range length containing only them is about 10.  Anything
+         * longer we treat as hex; otherwise we examine the range character by
+         * character to see */
+#ifdef EBCDIC
+        if (start < 256 && (((end < 255) ? end : 255) - start <= 10))
+#else
+        if ((isPRINT_A(start) && isPRINT_A(end))
+            || (end >= 0x7F && (isPRINT_A(start) && start > 0x21))
+            || ((end < 0x7D && isPRINT_A(end)) && start < 0x20))
+#endif
+        {
+            /* If the range beginning isn't an ASCII printable, we find the
+             * last such in the range, then split the output, so all the
+             * non-printables are in one subrange; then process the remaining
+             * portion as usual.  If the entire range isn't printables, we
+             * don't split, but drop down to print as hex */
+            if (! isPRINT_A(start)) {
+                UV temp_end = start + 1;
+                while (temp_end <= end && ! isPRINT_A(temp_end)) {
+                    temp_end++;
+                }
+                if (temp_end <= end) {
+                    put_range(sv, start, temp_end - 1);
+                    start = temp_end;
+                    continue;
+                }
+            }
+
+            /* If the range beginning is a digit, output a subrange of just the
+             * digits, then process the remaining portion as usual */
+            if (isDIGIT_A(start)) {
+                put_byte(sv, start);
+                sv_catpvs(sv, "-");
+                while (start <= end && isDIGIT_A(start)) start++;
+                put_byte(sv, start - 1);
+                continue;
+            }
+
+            /* Similarly for alphabetics.  Because in both ASCII and EBCDIC,
+             * the code points for upper and lower A-Z and a-z aren't
+             * intermixed, the resulting subrange will consist solely of either
+             * upper- or lower- alphabetics */
+            if (isALPHA_A(start)) {
+                put_byte(sv, start);
+                sv_catpvs(sv, "-");
+                while (start <= end && isALPHA_A(start)) start++;
+                put_byte(sv, start - 1);
+                continue;
+            }
+
+            /* We output any remaining printables as individual characters */
+            if (isPUNCT_A(start) || isSPACE_A(start)) {
+                while (start <= end && (isPUNCT_A(start) || isSPACE_A(start))) {
+                    put_byte(sv, start);
+                    start++;
+                }
+                continue;
+            }
+        }
+
+        /* Here is a control or non-ascii.  Output the range or subrange as
+         * hex. */
         Perl_sv_catpvf(aTHX_ sv, "\\x{%02" UVXf "}-\\x{%02" UVXf "}",
                        start,
-                       (end < 256) ? end : 255);
-    }
-    else { /* Here, the ends of the range are both digits, or both uppercase,
-              or both lowercase; and there's no discontinuity in the range
-              (which could happen on EBCDIC platforms) */
-        put_byte(sv, start);
-        sv_catpvs(sv, "-");
-        put_byte(sv, end);
+                       (end < NUM_ANYOF_CODE_POINTS)
+                       ? end
+                       : NUM_ANYOF_CODE_POINTS - 1);
+        break;
     }
 }
 
 STATIC bool
-S_put_latin1_charclass_innards(pTHX_ SV *sv, char *bitmap)
+S_put_charclass_bitmap_innards(pTHX_ SV *sv, char *bitmap, SV** bitmap_invlist)
 {
     /* Appends to 'sv' a displayable version of the innards of the bracketed
      * character class whose bitmap is 'bitmap';  Returns 'TRUE' if it actually
-     * output anything */
+     * output anything.  'bitmap_invlist', if not NULL, will contain an
+     * inversion list of what is in the bit map */
 
     int i;
     bool has_output_anything = FALSE;
 
-    PERL_ARGS_ASSERT_PUT_LATIN1_CHARCLASS_INNARDS;
+    PERL_ARGS_ASSERT_PUT_CHARCLASS_BITMAP_INNARDS;
+
+    if (bitmap_invlist) {
+        *bitmap_invlist = _new_invlist(128);  /* worst case is exactly
+                                                 every-other code point is in
+                                                 the list */
+    }
+    for (i = 0; i < NUM_ANYOF_CODE_POINTS; i++) {
+        if (BITMAP_TEST((U8 *) bitmap,i)) {
+            int j;
 
-    for (i = 0; i < 256; i++) {
-        if (i < 256 && BITMAP_TEST((U8 *) bitmap,i)) {
+            if (bitmap_invlist) {
+                *bitmap_invlist = add_cp_to_invlist(*bitmap_invlist, i);
+            }
 
             /* The character at index i should be output.  Find the next
              * character that should NOT be output */
-            int j;
-            for (j = i + 1; j <= 256; j++) {
+            for (j = i + 1; j < NUM_ANYOF_CODE_POINTS; j++) {
                 if (! BITMAP_TEST((U8 *) bitmap, j)) {
                     break;
                 }
+                if (bitmap_invlist) {
+                    *bitmap_invlist = add_cp_to_invlist(*bitmap_invlist, j);
+                }
             }
 
             /* Everything between them is a single range that should be output
@@ -16640,7 +16883,6 @@ S_dumpuntil(pTHX_ const regexp *r, const regnode *start, const regnode *node,
            const regnode *last, const regnode *plast,
            SV* sv, I32 indent, U32 depth)
 {
-    dVAR;
     U8 op = PSEUDO;    /* Arbitrary non-END op. */
     const regnode *next;
     const regnode *optstart= NULL;