Add regnode LEXACT, for long strings
authorKarl Williamson <khw@cpan.org>
Wed, 25 Sep 2019 16:12:32 +0000 (10:12 -0600)
committerKarl Williamson <khw@cpan.org>
Sun, 29 Sep 2019 17:46:26 +0000 (11:46 -0600)
This commit adds a new regnode for strings that don't fit in a regular
one, and adds a structure for that regnode to use.  Actually using them
is deferred to the next commit.

This new regnode structure is needed because the previous structure only
allows for an 8 bit length field, 255 max bytes.  This commit puts the
length instead in a new field, the same place single-argument regnodes
put their argument.  Hence this long string is an extra 32 bits of
overhead, but at no string length is this node ever bigger than the
combination of the smaller nodes it replaces.

I also considered simply combining the original 8 bit length field
(which is now unused) with the first byte of the string field to get a
16 bit length, and have the actual string be offset by 1.  But I
rejected that because it would mean the string would usually not be
aligned, slowing down memory accesses.

This new LEXACT regnode can hold up to what 1024 regular EXACT ones hold,
using 4K fewer overhead bytes to do so.  That means it can handle
strings containing 262000 bytes.  The comments give ideas for expanding
that should it become necessary or desirable.

Besides the space advantage, any hardware acceleration in memcmp
can be done in much bigger chunks, and otherwise the memcmp inner loop
(often written in assembly) will run many more times in a row, and our
outer loop that calls it, correspondingly fewer.

pod/perldebguts.pod
regcomp.h
regcomp.sym
regexec.c
regnodes.h

index 1e23b84..f4e368d 100644 (file)
@@ -660,6 +660,11 @@ will be lost.
 
  EXACT            str        Match this string (flags field is the
                              length).
+
+ # In a long string node, the U32 argument is the length, and is
+ # immediately followed by the string.
+ LEXACT           len:str 1  Match this long string (preceded by length;
+                             flags unused).
  EXACTL           str        Like EXACT, but /l is in effect (used so
                              locale-related warnings can be checked
                              for).
index 9bdd945..43cf1d3 100644 (file)
--- a/regcomp.h
+++ b/regcomp.h
@@ -156,6 +156,14 @@ struct regnode_string {
     char string[1];
 };
 
+struct regnode_lstring { /* Constructed this way to keep the string aligned. */
+    U8 flags;
+    U8  type;
+    U16 next_off;
+    U32 str_len;    /* Only 16 bits allowed before would overflow 'next_off' */
+    char string[1];
+};
+
 /* Argument bearing node - workhorse, 
    arg1 is often for the data field */
 struct regnode_1 {
@@ -330,21 +338,45 @@ struct regnode_ssc {
 #define FLAGS(p)       ((p)->flags)    /* Caution: Doesn't apply to all      \
                                           regnode types.  For some, it's the \
                                           character set of the regnode */
+#define        STR_LENs(p)     (__ASSERT_(OP(p) != LEXACT) ((struct regnode_string *)p)->str_len)
+#define        STRINGs(p)      (__ASSERT_(OP(p) != LEXACT) ((struct regnode_string *)p)->string)
+#define        OPERANDs(p)     STRINGs(p)
+
+/* Long strings.  Currently limited to length 18 bits, which handles a 262000
+ * byte string.  The limiting factor is the 16 bit 'next_off' field, which
+ * points to the next regnode, so the furthest away it can be is 2**16.  On
+ * most architectures, regnodes are 2**2 bytes long, so that yields 2**18
+ * bytes.  Should a longer string be desired, we could increase it to 26 bits
+ * fairly easily, by changing this node to have longj type which causes the ARG
+ * field to be used for the link to the next regnode (although code would have
+ * to be changed to account for this), and then use a combination of the flags
+ * and next_off fields for the length.  To get 34 bit length, also change the
+ * node to be an ARG2L, using the second 32 bit field for the length, and not
+ * using the flags nor next_off fields at all.  One could have an llstring node
+ * and even an lllstring type. */
+#define        STR_LENl(p)     (__ASSERT_(OP(p) == LEXACT) (((struct regnode_lstring *)p)->str_len))
+#define        STRINGl(p)      (__ASSERT_(OP(p) == LEXACT) (((struct regnode_lstring *)p)->string))
+#define        OPERANDl(p)     STRINGl(p)
+
+#define        STR_LEN(p)      ((OP(p) == LEXACT) ? STR_LENl(p) : STR_LENs(p))
+#define        STRING(p)       ((OP(p) == LEXACT) ? STRINGl(p)  : STRINGs(p))
 #define        OPERAND(p)      STRING(p)
 
-#define        STR_LEN(p)      (((struct regnode_string *)p)->str_len)
-#define        STRING(p)       (((struct regnode_string *)p)->string)
-
 /* The number of (smallest) regnode equivalents that a string of length l bytes
  * occupies */
 #define STR_SZ(l)      (((l) + sizeof(regnode) - 1) / sizeof(regnode))
 
 /* The number of (smallest) regnode equivalents that the EXACTISH node 'p'
  * occupies */
-#define NODE_SZ_STR(p) (STR_SZ(STR_LEN(p))+1)
+#define NODE_SZ_STR(p) (STR_SZ(STR_LEN(p)) + 1 + regarglen[(p)->type])
 
 #define setSTR_LEN(p,v)                                                     \
-            ((struct regnode_string *)(p))->str_len = (v);
+    STMT_START{                                                             \
+        if (OP(p) == LEXACT)                                                \
+            ((struct regnode_lstring *)(p))->str_len = (v);                 \
+        else                                                                \
+            ((struct regnode_string *)(p))->str_len = (v);                  \
+    } STMT_END
 
 #undef NODE_ALIGN
 #undef ARG_LOC
index 8a2fb24..5512c0f 100644 (file)
@@ -117,6 +117,10 @@ BRANCH      BRANCH,     node 0 V  ; Match this alternative, or the next...
 # NOTE: the relative ordering of these types is important do not change it
 
 EXACT       EXACT,      str       ; Match this string (flags field is the length).
+
+#* In a long string node, the U32 argument is the length, and is
+#* immediately followed by the string.
+LEXACT      EXACT,  len:str 1; Match this long string (preceded by length; flags unused).
 EXACTL      EXACT,      str       ; Like EXACT, but /l is in effect (used so locale-related warnings can be checked for).
 EXACTF      EXACT,      str       ; Like EXACT, but match using /id rules; (string not UTF-8, not guaranteed to be folded).
 EXACTFL     EXACT,      str       ; Like EXACT, but match using /il rules; (string not likely to be folded).
index a6e5f87..23ef50d 100644 (file)
--- a/regexec.c
+++ b/regexec.c
@@ -2298,8 +2298,8 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s,
          * first character.  c2 is its fold.  This logic will not work for
          * Unicode semantics and the german sharp ss, which hence should
          * not be compiled into a node that gets here. */
-        pat_string = STRING(c);
-        ln  = STR_LEN(c);      /* length to match in octets/bytes */
+        pat_string = STRINGs(c);
+        ln  = STR_LENs(c);     /* length to match in octets/bytes */
 
         /* We know that we have to match at least 'ln' bytes (which is the
          * same as characters, since not utf8).  If we have to match 3
@@ -2374,8 +2374,8 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s,
         /* If one of the operands is in utf8, we can't use the simpler folding
          * above, due to the fact that many different characters can have the
          * same fold, or portion of a fold, or different- length fold */
-        pat_string = STRING(c);
-        ln  = STR_LEN(c);      /* length to match in octets/bytes */
+        pat_string = STRINGs(c);
+        ln  = STR_LENs(c);     /* length to match in octets/bytes */
         pat_end = pat_string + ln;
         lnc = is_utf8_pat       /* length to match in characters */
                 ? utf8_length((U8 *) pat_string, (U8 *) pat_end)
@@ -4262,7 +4262,7 @@ S_setup_EXACTISH_ST_c1_c2(pTHX_ const regnode * const text_node, int *c1p,
         }
     }
     else { /* an EXACTFish node */
-        U8 *pat_end = pat + STR_LEN(text_node);
+        U8 *pat_end = pat + STR_LENs(text_node);
 
         /* An EXACTFL node has at least some characters unfolded, because what
          * they match is not known until now.  So, now is the time to fold
@@ -6274,6 +6274,9 @@ S_regmatch(pTHX_ regmatch_info *reginfo, char *startpos, regnode *prog)
         }
 #undef  ST
 
+        {
+           char *s;
+
        case EXACTL:             /*  /abc/l       */
             _CHECK_AND_WARN_PROBLEMATIC_LOCALE;
 
@@ -6292,11 +6295,11 @@ S_regmatch(pTHX_ regmatch_info *reginfo, char *startpos, regnode *prog)
                 sayNO;
             }
             /* FALLTHROUGH */
-       case EXACT: {            /*  /abc/        */
-           char *s;
+
+       case EXACT:             /*  /abc/        */
           do_exact:
-           s = STRING(scan);
-           ln = STR_LEN(scan);
+           s = STRINGs(scan);
+           ln = STR_LENs(scan);
            if (utf8_target != is_utf8_pat) {
                /* The target and the pattern have differing utf8ness. */
                char *l = locinput;
@@ -6448,8 +6451,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, char *startpos, regnode *prog)
            fold_utf8_flags = 0;
 
          do_exactf:
-           s = STRING(scan);
-           ln = STR_LEN(scan);
+           s = STRINGs(scan);
+           ln = STR_LENs(scan);
 
            if (   utf8_target
                 || is_utf8_pat
@@ -9363,6 +9366,11 @@ S_regrepeat(pTHX_ regexp *prog, char **startposp, const regnode *p,
        else
            scan = this_eol;
        break;
+
+      {
+        U8 * string;
+        Size_t str_len;
+
     case EXACTL:
         _CHECK_AND_WARN_PROBLEMATIC_LOCALE;
         if (utf8_target && UTF8_IS_ABOVE_LATIN1(*scan)) {
@@ -9377,9 +9385,11 @@ S_regrepeat(pTHX_ regexp *prog, char **startposp, const regnode *p,
         /* FALLTHROUGH */
     case EXACT:
       do_exact:
-        assert(STR_LEN(p) == reginfo->is_utf8_pat ? UTF8SKIP(STRING(p)) : 1);
+       string = (U8 *) STRINGs(p);
+        str_len = STR_LENs(p);
+        assert(str_len == reginfo->is_utf8_pat ? UTF8SKIP(string) : 1);
 
-       c = (U8)*STRING(p);
+       c = *string;
 
         /* Can use a simple find if the pattern char to match on is invariant
          * under UTF-8, or both target and pattern aren't UTF-8.  Note that we
@@ -9401,8 +9411,8 @@ S_regrepeat(pTHX_ regexp *prog, char **startposp, const regnode *p,
                  * string EQ */
                 while (hardcount < max
                        && scan < this_eol
-                       && (scan_char_len = UTF8SKIP(scan)) <= STR_LEN(p)
-                       && memEQ(scan, STRING(p), scan_char_len))
+                       && (scan_char_len = UTF8SKIP(scan)) <= str_len
+                       && memEQ(scan, string, scan_char_len))
                 {
                     scan += scan_char_len;
                     hardcount++;
@@ -9412,7 +9422,7 @@ S_regrepeat(pTHX_ regexp *prog, char **startposp, const regnode *p,
 
                 /* Target isn't utf8; convert the character in the UTF-8
                  * pattern to non-UTF8, and do a simple find */
-                c = EIGHT_BIT_UTF8_TO_NATIVE(c, *(STRING(p) + 1));
+                c = EIGHT_BIT_UTF8_TO_NATIVE(c, *(string + 1));
                 scan = (char *) find_span_end((U8 *) scan, (U8 *) this_eol, (U8) c);
             } /* else pattern char is above Latin1, can't possibly match the
                  non-UTF-8 target */
@@ -9436,6 +9446,7 @@ S_regrepeat(pTHX_ regexp *prog, char **startposp, const regnode *p,
            }
        }
        break;
+      }
 
     case EXACTFAA_NO_TRIE: /* This node only generated for non-utf8 patterns */
         assert(! reginfo->is_utf8_pat);
@@ -9486,7 +9497,7 @@ S_regrepeat(pTHX_ regexp *prog, char **startposp, const regnode *p,
         int c1, c2;
         U8 c1_utf8[UTF8_MAXBYTES+1], c2_utf8[UTF8_MAXBYTES+1];
 
-        assert(STR_LEN(p) == reginfo->is_utf8_pat ? UTF8SKIP(STRING(p)) : 1);
+        assert(STR_LENs(p) == reginfo->is_utf8_pat ? UTF8SKIP(STRINGs(p)) : 1);
 
         if (S_setup_EXACTISH_ST_c1_c2(aTHX_ p, &c1, c1_utf8, &c2, c2_utf8,
                                         reginfo))
@@ -9494,10 +9505,10 @@ S_regrepeat(pTHX_ regexp *prog, char **startposp, const regnode *p,
             if (c1 == CHRTEST_VOID) {
                 /* Use full Unicode fold matching */
                 char *tmpeol = loceol;
-                STRLEN pat_len = reginfo->is_utf8_pat ? UTF8SKIP(STRING(p)) : 1;
+                STRLEN pat_len = reginfo->is_utf8_pat ? UTF8SKIP(STRINGs(p)) : 1;
                 while (hardcount < max
                         && foldEQ_utf8_flags(scan, &tmpeol, 0, utf8_target,
-                                             STRING(p), NULL, pat_len,
+                                             STRINGs(p), NULL, pat_len,
                                              reginfo->is_utf8_pat, utf8_flags))
                 {
                     scan = tmpeol;
index a1929b8..9b51665 100644 (file)
@@ -6,8 +6,8 @@
 
 /* Regops and State definitions */
 
-#define REGNODE_MAX            103
-#define REGMATCH_STATE_MAX     143
+#define REGNODE_MAX            104
+#define REGMATCH_STATE_MAX     144
 
 #define        END                     0       /* 0000 End of program. */
 #define        SUCCEED                 1       /* 0x01 Return from a subroutine, basically. */
 #define        CLUMP                   35      /* 0x23 Match any extended grapheme cluster sequence */
 #define        BRANCH                  36      /* 0x24 Match this alternative, or the next... */
 #define        EXACT                   37      /* 0x25 Match this string (flags field is the length). */
-#define        EXACTL                  38      /* 0x26 Like EXACT, but /l is in effect (used so locale-related warnings can be checked for). */
-#define        EXACTF                  39      /* 0x27 Like EXACT, but match using /id rules; (string not UTF-8, not guaranteed to be folded). */
-#define        EXACTFL                 40      /* 0x28 Like EXACT, but match using /il rules; (string not likely to be folded). */
-#define        EXACTFU                 41      /* 0x29 Like EXACT, but match using /iu rules; (string folded). */
-#define        EXACTFAA                42      /* 0x2a Like EXACT, but match using /iaa rules; (string folded iff pattern is UTF8; folded length <= unfolded). */
-#define        EXACTFUP                43      /* 0x2b Like EXACT, but match using /iu rules; (string not UTF-8, not guaranteed to be folded; and it is Problematic). */
-#define        EXACTFLU8               44      /* 0x2c Like EXACTFU, but use /il, UTF-8, (string is folded, and everything in it is above 255. */
-#define        EXACTFAA_NO_TRIE        45      /* 0x2d Like EXACT, but match using /iaa rules (string not UTF-8, not guaranteed to be folded, not currently trie-able). */
-#define        EXACT_ONLY8             46      /* 0x2e Like EXACT, but only UTF-8 encoded targets can match */
-#define        EXACTFU_ONLY8           47      /* 0x2f Like EXACTFU, but only UTF-8 encoded targets can match */
-#define        EXACTFU_S_EDGE          48      /* 0x30 /di rules, but nothing in it precludes /ui, except begins and/or ends with [Ss]; (string not UTF-8; compile-time only). */
-#define        NOTHING                 49      /* 0x31 Match empty string. */
-#define        TAIL                    50      /* 0x32 Match empty string. Can jump here from outside. */
-#define        STAR                    51      /* 0x33 Match this (simple) thing 0 or more times. */
-#define        PLUS                    52      /* 0x34 Match this (simple) thing 1 or more times. */
-#define        CURLY                   53      /* 0x35 Match this simple thing {n,m} times. */
-#define        CURLYN                  54      /* 0x36 Capture next-after-this simple thing */
-#define        CURLYM                  55      /* 0x37 Capture this medium-complex thing {n,m} times. */
-#define        CURLYX                  56      /* 0x38 Match this complex thing {n,m} times. */
-#define        WHILEM                  57      /* 0x39 Do curly processing and see if rest matches. */
-#define        OPEN                    58      /* 0x3a Mark this point in input as start of #n. */
-#define        CLOSE                   59      /* 0x3b Close corresponding OPEN of #n. */
-#define        SROPEN                  60      /* 0x3c Same as OPEN, but for script run */
-#define        SRCLOSE                 61      /* 0x3d Close preceding SROPEN */
-#define        REF                     62      /* 0x3e Match some already matched string */
-#define        REFF                    63      /* 0x3f Match already matched string, using /di rules. */
-#define        REFFL                   64      /* 0x40 Match already matched string, using /li rules. */
-#define        REFFU                   65      /* 0x41 Match already matched string, usng /ui. */
-#define        REFFA                   66      /* 0x42 Match already matched string, using /aai rules. */
-#define        REFN                    67      /* 0x43 Match some already matched string */
-#define        REFFN                   68      /* 0x44 Match already matched string, using /di rules. */
-#define        REFFLN                  69      /* 0x45 Match already matched string, using /li rules. */
-#define        REFFUN                  70      /* 0x46 Match already matched string, using /ui rules. */
-#define        REFFAN                  71      /* 0x47 Match already matched string, using /aai rules. */
-#define        LONGJMP                 72      /* 0x48 Jump far away. */
-#define        BRANCHJ                 73      /* 0x49 BRANCH with long offset. */
-#define        IFMATCH                 74      /* 0x4a Succeeds if the following matches; non-zero flags "f", next_off "o" means lookbehind assertion starting "f..(f-o)" characters before current */
-#define        UNLESSM                 75      /* 0x4b Fails if the following matches; non-zero flags "f", next_off "o" means lookbehind assertion starting "f..(f-o)" characters before current */
-#define        SUSPEND                 76      /* 0x4c "Independent" sub-RE. */
-#define        IFTHEN                  77      /* 0x4d Switch, should be preceded by switcher. */
-#define        GROUPP                  78      /* 0x4e Whether the group matched. */
-#define        EVAL                    79      /* 0x4f Execute some Perl code. */
-#define        MINMOD                  80      /* 0x50 Next operator is not greedy. */
-#define        LOGICAL                 81      /* 0x51 Next opcode should set the flag only. */
-#define        RENUM                   82      /* 0x52 Group with independently numbered parens. */
-#define        TRIE                    83      /* 0x53 Match many EXACT(F[ALU]?)? at once. flags==type */
-#define        TRIEC                   84      /* 0x54 Same as TRIE, but with embedded charclass data */
-#define        AHOCORASICK             85      /* 0x55 Aho Corasick stclass. flags==type */
-#define        AHOCORASICKC            86      /* 0x56 Same as AHOCORASICK, but with embedded charclass data */
-#define        GOSUB                   87      /* 0x57 recurse to paren arg1 at (signed) ofs arg2 */
-#define        GROUPPN                 88      /* 0x58 Whether the group matched. */
-#define        INSUBP                  89      /* 0x59 Whether we are in a specific recurse. */
-#define        DEFINEP                 90      /* 0x5a Never execute directly. */
-#define        ENDLIKE                 91      /* 0x5b Used only for the type field of verbs */
-#define        OPFAIL                  92      /* 0x5c Same as (?!), but with verb arg */
-#define        ACCEPT                  93      /* 0x5d Accepts the current matched string, with verbar */
-#define        VERB                    94      /* 0x5e Used only for the type field of verbs */
-#define        PRUNE                   95      /* 0x5f Pattern fails at this startpoint if no-backtracking through this */
-#define        MARKPOINT               96      /* 0x60 Push the current location for rollback by cut. */
-#define        SKIP                    97      /* 0x61 On failure skip forward (to the mark) before retrying */
-#define        COMMIT                  98      /* 0x62 Pattern fails outright if backtracking through this */
-#define        CUTGROUP                99      /* 0x63 On failure go to the next alternation in the group */
-#define        KEEPS                   100     /* 0x64 $& begins here. */
-#define        LNBREAK                 101     /* 0x65 generic newline pattern */
-#define        OPTIMIZED               102     /* 0x66 Placeholder for dump. */
-#define        PSEUDO                  103     /* 0x67 Pseudo opcode for internal use. */
+#define        LEXACT                  38      /* 0x26 Match this long string (preceded by length; flags unused). */
+#define        EXACTL                  39      /* 0x27 Like EXACT, but /l is in effect (used so locale-related warnings can be checked for). */
+#define        EXACTF                  40      /* 0x28 Like EXACT, but match using /id rules; (string not UTF-8, not guaranteed to be folded). */
+#define        EXACTFL                 41      /* 0x29 Like EXACT, but match using /il rules; (string not likely to be folded). */
+#define        EXACTFU                 42      /* 0x2a Like EXACT, but match using /iu rules; (string folded). */
+#define        EXACTFAA                43      /* 0x2b Like EXACT, but match using /iaa rules; (string folded iff pattern is UTF8; folded length <= unfolded). */
+#define        EXACTFUP                44      /* 0x2c Like EXACT, but match using /iu rules; (string not UTF-8, not guaranteed to be folded; and it is Problematic). */
+#define        EXACTFLU8               45      /* 0x2d Like EXACTFU, but use /il, UTF-8, (string is folded, and everything in it is above 255. */
+#define        EXACTFAA_NO_TRIE        46      /* 0x2e Like EXACT, but match using /iaa rules (string not UTF-8, not guaranteed to be folded, not currently trie-able). */
+#define        EXACT_ONLY8             47      /* 0x2f Like EXACT, but only UTF-8 encoded targets can match */
+#define        EXACTFU_ONLY8           48      /* 0x30 Like EXACTFU, but only UTF-8 encoded targets can match */
+#define        EXACTFU_S_EDGE          49      /* 0x31 /di rules, but nothing in it precludes /ui, except begins and/or ends with [Ss]; (string not UTF-8; compile-time only). */
+#define        NOTHING                 50      /* 0x32 Match empty string. */
+#define        TAIL                    51      /* 0x33 Match empty string. Can jump here from outside. */
+#define        STAR                    52      /* 0x34 Match this (simple) thing 0 or more times. */
+#define        PLUS                    53      /* 0x35 Match this (simple) thing 1 or more times. */
+#define        CURLY                   54      /* 0x36 Match this simple thing {n,m} times. */
+#define        CURLYN                  55      /* 0x37 Capture next-after-this simple thing */
+#define        CURLYM                  56      /* 0x38 Capture this medium-complex thing {n,m} times. */
+#define        CURLYX                  57      /* 0x39 Match this complex thing {n,m} times. */
+#define        WHILEM                  58      /* 0x3a Do curly processing and see if rest matches. */
+#define        OPEN                    59      /* 0x3b Mark this point in input as start of #n. */
+#define        CLOSE                   60      /* 0x3c Close corresponding OPEN of #n. */
+#define        SROPEN                  61      /* 0x3d Same as OPEN, but for script run */
+#define        SRCLOSE                 62      /* 0x3e Close preceding SROPEN */
+#define        REF                     63      /* 0x3f Match some already matched string */
+#define        REFF                    64      /* 0x40 Match already matched string, using /di rules. */
+#define        REFFL                   65      /* 0x41 Match already matched string, using /li rules. */
+#define        REFFU                   66      /* 0x42 Match already matched string, usng /ui. */
+#define        REFFA                   67      /* 0x43 Match already matched string, using /aai rules. */
+#define        REFN                    68      /* 0x44 Match some already matched string */
+#define        REFFN                   69      /* 0x45 Match already matched string, using /di rules. */
+#define        REFFLN                  70      /* 0x46 Match already matched string, using /li rules. */
+#define        REFFUN                  71      /* 0x47 Match already matched string, using /ui rules. */
+#define        REFFAN                  72      /* 0x48 Match already matched string, using /aai rules. */
+#define        LONGJMP                 73      /* 0x49 Jump far away. */
+#define        BRANCHJ                 74      /* 0x4a BRANCH with long offset. */
+#define        IFMATCH                 75      /* 0x4b Succeeds if the following matches; non-zero flags "f", next_off "o" means lookbehind assertion starting "f..(f-o)" characters before current */
+#define        UNLESSM                 76      /* 0x4c Fails if the following matches; non-zero flags "f", next_off "o" means lookbehind assertion starting "f..(f-o)" characters before current */
+#define        SUSPEND                 77      /* 0x4d "Independent" sub-RE. */
+#define        IFTHEN                  78      /* 0x4e Switch, should be preceded by switcher. */
+#define        GROUPP                  79      /* 0x4f Whether the group matched. */
+#define        EVAL                    80      /* 0x50 Execute some Perl code. */
+#define        MINMOD                  81      /* 0x51 Next operator is not greedy. */
+#define        LOGICAL                 82      /* 0x52 Next opcode should set the flag only. */
+#define        RENUM                   83      /* 0x53 Group with independently numbered parens. */
+#define        TRIE                    84      /* 0x54 Match many EXACT(F[ALU]?)? at once. flags==type */
+#define        TRIEC                   85      /* 0x55 Same as TRIE, but with embedded charclass data */
+#define        AHOCORASICK             86      /* 0x56 Aho Corasick stclass. flags==type */
+#define        AHOCORASICKC            87      /* 0x57 Same as AHOCORASICK, but with embedded charclass data */
+#define        GOSUB                   88      /* 0x58 recurse to paren arg1 at (signed) ofs arg2 */
+#define        GROUPPN                 89      /* 0x59 Whether the group matched. */
+#define        INSUBP                  90      /* 0x5a Whether we are in a specific recurse. */
+#define        DEFINEP                 91      /* 0x5b Never execute directly. */
+#define        ENDLIKE                 92      /* 0x5c Used only for the type field of verbs */
+#define        OPFAIL                  93      /* 0x5d Same as (?!), but with verb arg */
+#define        ACCEPT                  94      /* 0x5e Accepts the current matched string, with verbar */
+#define        VERB                    95      /* 0x5f Used only for the type field of verbs */
+#define        PRUNE                   96      /* 0x60 Pattern fails at this startpoint if no-backtracking through this */
+#define        MARKPOINT               97      /* 0x61 Push the current location for rollback by cut. */
+#define        SKIP                    98      /* 0x62 On failure skip forward (to the mark) before retrying */
+#define        COMMIT                  99      /* 0x63 Pattern fails outright if backtracking through this */
+#define        CUTGROUP                100     /* 0x64 On failure go to the next alternation in the group */
+#define        KEEPS                   101     /* 0x65 $& begins here. */
+#define        LNBREAK                 102     /* 0x66 generic newline pattern */
+#define        OPTIMIZED               103     /* 0x67 Placeholder for dump. */
+#define        PSEUDO                  104     /* 0x68 Pseudo opcode for internal use. */
        /* ------------ States ------------- */
 #define        TRIE_next               (REGNODE_MAX + 1)       /* state for TRIE */
 #define        TRIE_next_fail          (REGNODE_MAX + 2)       /* state for TRIE */
@@ -201,6 +202,7 @@ EXTCONST U8 PL_regkind[] = {
        CLUMP,          /* CLUMP                  */
        BRANCH,         /* BRANCH                 */
        EXACT,          /* EXACT                  */
+       EXACT,          /* LEXACT                 */
        EXACT,          /* EXACTL                 */
        EXACT,          /* EXACTF                 */
        EXACT,          /* EXACTFL                */
@@ -354,6 +356,7 @@ static const U8 regarglen[] = {
        0,                                      /* CLUMP        */
        0,                                      /* BRANCH       */
        0,                                      /* EXACT        */
+       EXTRA_SIZE(struct regnode_1),           /* LEXACT       */
        0,                                      /* EXACTL       */
        0,                                      /* EXACTF       */
        0,                                      /* EXACTFL      */
@@ -463,6 +466,7 @@ static const char reg_off_by_arg[] = {
        0,      /* CLUMP        */
        0,      /* BRANCH       */
        0,      /* EXACT        */
+       0,      /* LEXACT       */
        0,      /* EXACTL       */
        0,      /* EXACTF       */
        0,      /* EXACTFL      */
@@ -578,72 +582,73 @@ EXTCONST char * const PL_reg_name[] = {
        "CLUMP",                        /* 0x23 */
        "BRANCH",                       /* 0x24 */
        "EXACT",                        /* 0x25 */
-       "EXACTL",                       /* 0x26 */
-       "EXACTF",                       /* 0x27 */
-       "EXACTFL",                      /* 0x28 */
-       "EXACTFU",                      /* 0x29 */
-       "EXACTFAA",                     /* 0x2a */
-       "EXACTFUP",                     /* 0x2b */
-       "EXACTFLU8",                    /* 0x2c */
-       "EXACTFAA_NO_TRIE",             /* 0x2d */
-       "EXACT_ONLY8",                  /* 0x2e */
-       "EXACTFU_ONLY8",                /* 0x2f */
-       "EXACTFU_S_EDGE",               /* 0x30 */
-       "NOTHING",                      /* 0x31 */
-       "TAIL",                         /* 0x32 */
-       "STAR",                         /* 0x33 */
-       "PLUS",                         /* 0x34 */
-       "CURLY",                        /* 0x35 */
-       "CURLYN",                       /* 0x36 */
-       "CURLYM",                       /* 0x37 */
-       "CURLYX",                       /* 0x38 */
-       "WHILEM",                       /* 0x39 */
-       "OPEN",                         /* 0x3a */
-       "CLOSE",                        /* 0x3b */
-       "SROPEN",                       /* 0x3c */
-       "SRCLOSE",                      /* 0x3d */
-       "REF",                          /* 0x3e */
-       "REFF",                         /* 0x3f */
-       "REFFL",                        /* 0x40 */
-       "REFFU",                        /* 0x41 */
-       "REFFA",                        /* 0x42 */
-       "REFN",                         /* 0x43 */
-       "REFFN",                        /* 0x44 */
-       "REFFLN",                       /* 0x45 */
-       "REFFUN",                       /* 0x46 */
-       "REFFAN",                       /* 0x47 */
-       "LONGJMP",                      /* 0x48 */
-       "BRANCHJ",                      /* 0x49 */
-       "IFMATCH",                      /* 0x4a */
-       "UNLESSM",                      /* 0x4b */
-       "SUSPEND",                      /* 0x4c */
-       "IFTHEN",                       /* 0x4d */
-       "GROUPP",                       /* 0x4e */
-       "EVAL",                         /* 0x4f */
-       "MINMOD",                       /* 0x50 */
-       "LOGICAL",                      /* 0x51 */
-       "RENUM",                        /* 0x52 */
-       "TRIE",                         /* 0x53 */
-       "TRIEC",                        /* 0x54 */
-       "AHOCORASICK",                  /* 0x55 */
-       "AHOCORASICKC",                 /* 0x56 */
-       "GOSUB",                        /* 0x57 */
-       "GROUPPN",                      /* 0x58 */
-       "INSUBP",                       /* 0x59 */
-       "DEFINEP",                      /* 0x5a */
-       "ENDLIKE",                      /* 0x5b */
-       "OPFAIL",                       /* 0x5c */
-       "ACCEPT",                       /* 0x5d */
-       "VERB",                         /* 0x5e */
-       "PRUNE",                        /* 0x5f */
-       "MARKPOINT",                    /* 0x60 */
-       "SKIP",                         /* 0x61 */
-       "COMMIT",                       /* 0x62 */
-       "CUTGROUP",                     /* 0x63 */
-       "KEEPS",                        /* 0x64 */
-       "LNBREAK",                      /* 0x65 */
-       "OPTIMIZED",                    /* 0x66 */
-       "PSEUDO",                       /* 0x67 */
+       "LEXACT",                       /* 0x26 */
+       "EXACTL",                       /* 0x27 */
+       "EXACTF",                       /* 0x28 */
+       "EXACTFL",                      /* 0x29 */
+       "EXACTFU",                      /* 0x2a */
+       "EXACTFAA",                     /* 0x2b */
+       "EXACTFUP",                     /* 0x2c */
+       "EXACTFLU8",                    /* 0x2d */
+       "EXACTFAA_NO_TRIE",             /* 0x2e */
+       "EXACT_ONLY8",                  /* 0x2f */
+       "EXACTFU_ONLY8",                /* 0x30 */
+       "EXACTFU_S_EDGE",               /* 0x31 */
+       "NOTHING",                      /* 0x32 */
+       "TAIL",                         /* 0x33 */
+       "STAR",                         /* 0x34 */
+       "PLUS",                         /* 0x35 */
+       "CURLY",                        /* 0x36 */
+       "CURLYN",                       /* 0x37 */
+       "CURLYM",                       /* 0x38 */
+       "CURLYX",                       /* 0x39 */
+       "WHILEM",                       /* 0x3a */
+       "OPEN",                         /* 0x3b */
+       "CLOSE",                        /* 0x3c */
+       "SROPEN",                       /* 0x3d */
+       "SRCLOSE",                      /* 0x3e */
+       "REF",                          /* 0x3f */
+       "REFF",                         /* 0x40 */
+       "REFFL",                        /* 0x41 */
+       "REFFU",                        /* 0x42 */
+       "REFFA",                        /* 0x43 */
+       "REFN",                         /* 0x44 */
+       "REFFN",                        /* 0x45 */
+       "REFFLN",                       /* 0x46 */
+       "REFFUN",                       /* 0x47 */
+       "REFFAN",                       /* 0x48 */
+       "LONGJMP",                      /* 0x49 */
+       "BRANCHJ",                      /* 0x4a */
+       "IFMATCH",                      /* 0x4b */
+       "UNLESSM",                      /* 0x4c */
+       "SUSPEND",                      /* 0x4d */
+       "IFTHEN",                       /* 0x4e */
+       "GROUPP",                       /* 0x4f */
+       "EVAL",                         /* 0x50 */
+       "MINMOD",                       /* 0x51 */
+       "LOGICAL",                      /* 0x52 */
+       "RENUM",                        /* 0x53 */
+       "TRIE",                         /* 0x54 */
+       "TRIEC",                        /* 0x55 */
+       "AHOCORASICK",                  /* 0x56 */
+       "AHOCORASICKC",                 /* 0x57 */
+       "GOSUB",                        /* 0x58 */
+       "GROUPPN",                      /* 0x59 */
+       "INSUBP",                       /* 0x5a */
+       "DEFINEP",                      /* 0x5b */
+       "ENDLIKE",                      /* 0x5c */
+       "OPFAIL",                       /* 0x5d */
+       "ACCEPT",                       /* 0x5e */
+       "VERB",                         /* 0x5f */
+       "PRUNE",                        /* 0x60 */
+       "MARKPOINT",                    /* 0x61 */
+       "SKIP",                         /* 0x62 */
+       "COMMIT",                       /* 0x63 */
+       "CUTGROUP",                     /* 0x64 */
+       "KEEPS",                        /* 0x65 */
+       "LNBREAK",                      /* 0x66 */
+       "OPTIMIZED",                    /* 0x67 */
+       "PSEUDO",                       /* 0x68 */
        /* ------------ States ------------- */
        "TRIE_next",                    /* REGNODE_MAX +0x01 */
        "TRIE_next_fail",               /* REGNODE_MAX +0x02 */
@@ -778,7 +783,7 @@ EXTCONST U8 PL_varies[] __attribute__deprecated__ = {
 EXTCONST U8 PL_varies_bitmask[];
 #else
 EXTCONST U8 PL_varies_bitmask[] = {
-    0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xF8, 0xC3, 0xFF, 0x32, 0x00, 0x00, 0x00
+    0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xF0, 0x87, 0xFF, 0x65, 0x00, 0x00, 0x00, 0x00
 };
 #endif /* DOINIT */
 
@@ -801,7 +806,7 @@ EXTCONST U8 PL_simple[] __attribute__deprecated__ = {
 EXTCONST U8 PL_simple_bitmask[];
 #else
 EXTCONST U8 PL_simple_bitmask[] = {
-    0x00, 0x00, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+    0x00, 0x00, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 #endif /* DOINIT */