This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Automate processing of op_private flags
authorDavid Mitchell <davem@iabyn.com>
Tue, 2 Sep 2014 16:11:42 +0000 (17:11 +0100)
committerDavid Mitchell <davem@iabyn.com>
Wed, 10 Sep 2014 13:25:05 +0000 (14:25 +0100)
Add a new config file, regen/op_private, which contains all the
information about the flags and descriptions for the OP op_private field.

Previously, the flags themselves were defined in op.h, accompanied by
textual descriptions (sometimes inaccurate or incomplete).

For display purposes, there were short labels for each flag found in
Concise.pm, and another set of labels for Perl_do_op_dump() in dump.c.
These two sets of labels differed from each other in spelling (e.g.
REFC verses REFCOUNT), and differed in completeness and accuracy.

With this commit, all the data to generate the defines and the labels is
derived from a single source, and are generated automatically by 'make
regen'. It also contains complete data on which bits are used for what by
each op. So any attempt to add a new flag for a particular op where that
bit is already in use, will raise an error in make regen.  This compares
to the previous practice of reading the descriptions in op.h and hoping
for the best.

It also makes use of data in regen/opcodes: for example, regen/op_private
specifies that all ops flagged as 'T' get the OPpTARGET_MY flag.

Since the set of labels used by Concise and Perl_do_op_dump() differed,
I've standardised on the Concise version. Thus this commit changes the
output produced by Concise only marginally, while Perl_do_op_dump() is
considerably different. As well as the change in labels (and missing
labels), Perl_do_op_dump() formerly had a bug whereby any unrecognised
bits would not be shown if there was at least one recognised bit.
So while Concise displayed (and still does) "LVINTRO,2", Perl_do_op_dump()
has changed:

    - PRIVATE = (INTRO)
    + PRIVATE = (LVINTRO,0x2)

Concise has mainly changed in that a few op/bit combinations weren't being
shown symbolically, and now are. I've avoiding fixing the ones that would
break tests; they'll be fixed up in the next few commits.

A few new OPp* flags have been added:

    OPpARG1_MASK
    OPpARG2_MASK
    OPpARG3_MASK
    OPpARG4_MASK
    OPpHINT_M_VMSISH_STATUS
    OPpHINT_M_VMSISH_TIME
    OPpHINT_STRICT_REFS

The last three are analogues for existing HINT_* flags. The former four
reflect that many ops some of the lower few bits of op_private to indicate
how many args the op expects. While (for now) this is still displayed as,
e.g. "LVINTRO,2", the definitions in regen/op_private now fully account
for which ops use which bits for the arg count.

There is a new module, B::Op_private, which allows this new data to be
accessed from Perl. For example,

    use B::Op_private;
    my $name  = $B::Op_private::bits{aelem}{7}; # OPpLVAL_INTRO
    my $value = $B::Op_private::defines{$name}; # 128
    my $label = $B::Op_private::labels{$name};  # LVINTRO

There are several new constant PL_* tables. PL_op_private_valid[]
specifies for each op number, which bits are valid for that op. In a
couple of commits' time, op_free() will use this on debugging builds to
assert that no ops gained any private flags which we don't know about.
In fact it was by using such a temporary assert repeatedly against the
test suite, that I tracked down most of the inconsistencies and errors in
the current flag data.

The other PL_op_private_* tables contain a compact representation of all
the ops/bits/labels in a format suitable for Perl_do_op_dump() to decode
Op_private. Overall, the perl binary is about 500 bytes smaller on my
system.

15 files changed:
MANIFEST
Porting/Maintainers.pl
dump.c
ext/B/B/Concise.pm
ext/B/Makefile.PL
ext/Devel-Peek/t/Peek.t
globvar.sym
lib/B/Op_private.pm [new file with mode: 0644]
op.h
opcode.h
pp.h
pp_sys.c
regen/op_private [new file with mode: 0644]
regen/opcode.pl
t/porting/regen.t

index 0b122e3..e9b57fd 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -4008,6 +4008,7 @@ lib/Benchmark.pm          Measure execution time
 lib/Benchmark.t                        See if Benchmark works
 lib/blib.pm                    For "use blib"
 lib/blib.t                     blib.pm test
+lib/B/Op_private.pm            Definitions of OP op_private flags
 lib/bytes_heavy.pl             Support routines for byte pragma
 lib/bytes.pm                   Pragma to enable byte operations
 lib/bytes.t                    bytes.pm test
@@ -4696,6 +4697,7 @@ regen/mk_invlists.pl              Generates charclass_invlists.h
 regen/mk_PL_charclass.pl       Populate the PL_charclass table
 regen/opcode.pl                        Opcode header generator
 regen/opcodes                  Opcode data
+regen/op_private               Definitions of bits in an OP's op_private field
 regen/overload.pl              generate overload.h
 regen_perly.pl                 generate perly.{act,h,tab} from perly.y
 regen.pl                       Run all scripts that (re)generate files
index 2015edd..6e494f2 100755 (executable)
@@ -1351,6 +1351,7 @@ use File::Glob qw(:case);
                 lib/AnyDBM_File.{pm,t}
                 lib/Benchmark.{pm,t}
                 lib/B/Deparse{.pm,.t,-core.t}
+                lib/B/Op_private.pm
                 lib/CORE.pod
                 lib/Class/Struct.{pm,t}
                 lib/Config.t
diff --git a/dump.c b/dump.c
index 99ff6c1..471b104 100644 (file)
--- a/dump.c
+++ b/dump.c
@@ -751,6 +751,10 @@ S_sequence_num(pTHX_ const OP *o)
     return PL_op_seq;
 }
 
+
+
+
+
 const struct flag_to_name op_flags_names[] = {
     {OPf_KIDS, ",KIDS"},
     {OPf_PARENS, ",PARENS"},
@@ -760,125 +764,6 @@ const struct flag_to_name op_flags_names[] = {
     {OPf_SPECIAL, ",SPECIAL"}
 };
 
-const struct flag_to_name op_trans_names[] = {
-    {OPpTRANS_FROM_UTF, ",FROM_UTF"},
-    {OPpTRANS_TO_UTF, ",TO_UTF"},
-    {OPpTRANS_IDENTICAL, ",IDENTICAL"},
-    {OPpTRANS_SQUASH, ",SQUASH"},
-    {OPpTRANS_COMPLEMENT, ",COMPLEMENT"},
-    {OPpTRANS_GROWS, ",GROWS"},
-    {OPpTRANS_DELETE, ",DELETE"}
-};
-
-const struct flag_to_name op_entersub_names[] = {
-    {OPpENTERSUB_DB, ",DB"},
-    {OPpENTERSUB_HASTARG, ",HASTARG"},
-    {OPpENTERSUB_AMPER, ",AMPER"},
-    {OPpENTERSUB_NOPAREN, ",NOPAREN"},
-    {OPpENTERSUB_INARGS, ",INARGS"}
-};
-
-const struct flag_to_name op_const_names[] = {
-    {OPpCONST_NOVER, ",NOVER"},
-    {OPpCONST_SHORTCIRCUIT, ",SHORTCIRCUIT"},
-    {OPpCONST_STRICT, ",STRICT"},
-    {OPpCONST_ENTERED, ",ENTERED"},
-    {OPpCONST_BARE, ",BARE"}
-};
-
-const struct flag_to_name op_sort_names[] = {
-    {OPpSORT_NUMERIC, ",NUMERIC"},
-    {OPpSORT_INTEGER, ",INTEGER"},
-    {OPpSORT_REVERSE, ",REVERSE"},
-    {OPpSORT_INPLACE, ",INPLACE"},
-    {OPpSORT_DESCEND, ",DESCEND"},
-    {OPpSORT_QSORT, ",QSORT"},
-    {OPpSORT_STABLE, ",STABLE"}
-};
-
-const struct flag_to_name op_open_names[] = {
-    {OPpOPEN_IN_RAW, ",IN_RAW"},
-    {OPpOPEN_IN_CRLF, ",IN_CRLF"},
-    {OPpOPEN_OUT_RAW, ",OUT_RAW"},
-    {OPpOPEN_OUT_CRLF, ",OUT_CRLF"}
-};
-
-const struct flag_to_name op_sassign_names[] = {
-    {OPpASSIGN_BACKWARDS, ",BACKWARDS"},
-    {OPpASSIGN_CV_TO_GV,  ",CV2GV"}
-};
-
-const struct flag_to_name op_leave_names[] = {
-    {OPpREFCOUNTED, ",REFCOUNTED"},
-    {OPpLVALUE,            ",LVALUE"}
-};
-
-#define OP_PRIVATE_ONCE(op, flag, name) \
-    const struct flag_to_name CAT2(op, _names)[] = {   \
-       {(flag), (name)} \
-    }
-
-OP_PRIVATE_ONCE(op_leavesub, OPpREFCOUNTED, ",REFCOUNTED");
-OP_PRIVATE_ONCE(op_repeat, OPpREPEAT_DOLIST, ",DOLIST");
-OP_PRIVATE_ONCE(op_reverse, OPpREVERSE_INPLACE, ",INPLACE");
-OP_PRIVATE_ONCE(op_rv2cv, OPpLVAL_INTRO, ",INTRO");
-OP_PRIVATE_ONCE(op_flip, OPpFLIP_LINENUM, ",LINENUM");
-OP_PRIVATE_ONCE(op_gv, OPpEARLY_CV, ",EARLY_CV");
-OP_PRIVATE_ONCE(op_list, OPpLIST_GUESSED, ",GUESSED");
-OP_PRIVATE_ONCE(op_delete, OPpSLICE, ",SLICE");
-OP_PRIVATE_ONCE(op_exists, OPpEXISTS_SUB, ",EXISTS_SUB");
-OP_PRIVATE_ONCE(op_die, OPpHUSH_VMSISH, ",HUSH_VMSISH");
-OP_PRIVATE_ONCE(op_split, OPpSPLIT_IMPLIM, ",IMPLIM");
-OP_PRIVATE_ONCE(op_dbstate, OPpHUSH_VMSISH, ",HUSH_VMSISH");
-
-struct op_private_by_op {
-    U16 op_type;
-    U16 len;
-    const struct flag_to_name *start;
-};
-
-const struct op_private_by_op op_private_names[] = {
-    {OP_LEAVESUB, C_ARRAY_LENGTH(op_leavesub_names), op_leavesub_names },
-    {OP_LEAVE, C_ARRAY_LENGTH(op_leave_names), op_leave_names },
-    {OP_LEAVESUBLV, C_ARRAY_LENGTH(op_leavesub_names), op_leavesub_names },
-    {OP_LEAVEWRITE, C_ARRAY_LENGTH(op_leavesub_names), op_leavesub_names },
-    {OP_DIE, C_ARRAY_LENGTH(op_die_names), op_die_names },
-    {OP_DELETE, C_ARRAY_LENGTH(op_delete_names), op_delete_names },
-    {OP_EXISTS, C_ARRAY_LENGTH(op_exists_names), op_exists_names },
-    {OP_FLIP, C_ARRAY_LENGTH(op_flip_names), op_flip_names },
-    {OP_FLOP, C_ARRAY_LENGTH(op_flip_names), op_flip_names },
-    {OP_GV, C_ARRAY_LENGTH(op_gv_names), op_gv_names },
-    {OP_LIST, C_ARRAY_LENGTH(op_list_names), op_list_names },
-    {OP_SASSIGN, C_ARRAY_LENGTH(op_sassign_names), op_sassign_names },
-    {OP_REPEAT, C_ARRAY_LENGTH(op_repeat_names), op_repeat_names },
-    {OP_RV2CV, C_ARRAY_LENGTH(op_rv2cv_names), op_rv2cv_names },
-    {OP_TRANS, C_ARRAY_LENGTH(op_trans_names), op_trans_names },
-    {OP_CONST, C_ARRAY_LENGTH(op_const_names), op_const_names },
-    {OP_SORT, C_ARRAY_LENGTH(op_sort_names), op_sort_names },
-    {OP_OPEN, C_ARRAY_LENGTH(op_open_names), op_open_names },
-    {OP_SPLIT, C_ARRAY_LENGTH(op_split_names), op_split_names },
-    {OP_DBSTATE, C_ARRAY_LENGTH(op_dbstate_names), op_dbstate_names },
-    {OP_NEXTSTATE, C_ARRAY_LENGTH(op_dbstate_names), op_dbstate_names },
-    {OP_BACKTICK, C_ARRAY_LENGTH(op_open_names), op_open_names }
-};
-
-static bool
-S_op_private_to_names(pTHX_ SV *tmpsv, U32 optype, U32 op_private) {
-    const struct op_private_by_op *start = op_private_names;
-    const struct op_private_by_op *const end = C_ARRAY_END(op_private_names);
-
-    /* This is a linear search, but no worse than the code that it replaced.
-       It's debugging code - size is more important than speed.  */
-    do {
-       if (optype == start->op_type) {
-           S_append_flags(aTHX_ tmpsv, op_private, start->start,
-                          start->start + start->len);
-           return TRUE;
-       }
-    } while (++start < end);
-    return FALSE;
-}
-
 
 void
 Perl_do_op_dump(pTHX_ I32 level, PerlIO *file, const OP *o)
@@ -966,95 +851,88 @@ Perl_do_op_dump(pTHX_ I32 level, PerlIO *file, const OP *o)
     }
 
     if (o->op_private) {
-        U32 optype = o->op_type;
-        U32 oppriv = o->op_private;
-        SV * const tmpsv = newSVpvs("");
-       if (PL_opargs[optype] & OA_TARGLEX) {
-           if (oppriv & OPpTARGET_MY)
-               sv_catpv(tmpsv, ",TARGET_MY");
-       }
-       else if (optype == OP_ENTERSUB ||
-                 optype == OP_RV2SV ||
-                 optype == OP_GVSV ||
-                 optype == OP_RV2AV ||
-                 optype == OP_RV2HV ||
-                 optype == OP_RV2GV ||
-                 optype == OP_AELEM ||
-                 optype == OP_HELEM )
-        {
-            if (optype == OP_ENTERSUB) {
-                append_flags(tmpsv, oppriv, op_entersub_names);
-            }
-            else {
-                switch (oppriv & OPpDEREF) {
-                case OPpDEREF_SV:
-                    sv_catpv(tmpsv, ",SV");
-                    break;
-                case OPpDEREF_AV:
-                    sv_catpv(tmpsv, ",AV");
-                    break;
-                case OPpDEREF_HV:
-                    sv_catpv(tmpsv, ",HV");
-                    break;
+        U16 oppriv = o->op_private;
+        I16 op_ix = PL_op_private_bitdef_ix[o->op_type];
+        SV * tmpsv = NULL;
+
+        if (op_ix != -1) {
+            U16 stop = 0;
+            tmpsv = newSVpvs("");
+            for (; !stop; op_ix++) {
+                U16 entry = PL_op_private_bitdefs[op_ix];
+                U16 bit = (entry >> 2) & 7;
+                U16 ix = entry >> 5;
+
+                stop = (entry & 1);
+
+                if (entry & 2) {
+                    /* bitfield */
+                    I16 const *p = &PL_op_private_bitfields[ix];
+                    U16 bitmin = (U16) *p++;
+                    I16 label = *p++;
+                    I16 enum_label;
+                    U16 mask = 0;
+                    U16 i;
+                    U16 val;
+
+                    for (i = bitmin; i<= bit; i++)
+                        mask |= (1<<i);
+                    bit = bitmin;
+                    val = (oppriv & mask);
+
+                    if (   label != -1
+                        && PL_op_private_labels[label] == '-'
+                        && PL_op_private_labels[label+1] == '\0'
+                    )
+                        /* display as raw number */
+                        continue;
+
+                    oppriv -= val;
+                    val >>= bit;
+                    enum_label = -1;
+                    while (*p != -1) {
+                        if (val == *p++) {
+                            enum_label = *p;
+                            break;
+                        }
+                        p++;
+                    }
+                    if (val == 0 && enum_label == -1)
+                        /* don't display anonymous zero values */
+                        continue;
+
+                    sv_catpv(tmpsv, ",");
+                    if (label != -1) {
+                        sv_catpv(tmpsv, &PL_op_private_labels[label]);
+                        sv_catpv(tmpsv, "=");
+                    }
+                    sv_catpv(tmpsv, &PL_op_private_labels[enum_label]);
+
+                }
+                else {
+                    /* bit flag */
+                    if (   oppriv & (1<<bit)
+                        && !(PL_op_private_labels[ix] == '-'
+                             && PL_op_private_labels[ix+1] == '\0'))
+                    {
+                        oppriv -= (1<<bit);
+                        sv_catpv(tmpsv, ",");
+                        sv_catpv(tmpsv, &PL_op_private_labels[ix]);
+                    }
                 }
-                if (oppriv & OPpMAYBE_LVSUB)
-                    sv_catpv(tmpsv, ",MAYBE_LVSUB");
-            }
-            if (optype == OP_AELEM || optype == OP_HELEM) {
-                if (oppriv & OPpLVAL_DEFER)
-                    sv_catpv(tmpsv, ",LVAL_DEFER");
-            }
-            else if (optype == OP_RV2HV || optype == OP_PADHV) {
-                if (oppriv & OPpMAYBE_TRUEBOOL)
-                    sv_catpvs(tmpsv, ",OPpMAYBE_TRUEBOOL");
-                if (oppriv & OPpTRUEBOOL)
-                    sv_catpvs(tmpsv, ",OPpTRUEBOOL");
             }
-            else {
-                if (oppriv & HINT_STRICT_REFS)
-                    sv_catpv(tmpsv, ",STRICT_REFS");
-                if (oppriv & OPpOUR_INTRO)
-                    sv_catpv(tmpsv, ",OUR_INTRO");
+            if (oppriv) {
+                sv_catpv(tmpsv, ",");
+                Perl_sv_catpvf(aTHX_ tmpsv, "0x%"UVxf, (UV)oppriv);
             }
         }
-       else if (S_op_private_to_names(aTHX_ tmpsv, optype, oppriv)) {
-       }
-       else if (OP_IS_FILETEST(o->op_type)) {
-            if (oppriv & OPpFT_ACCESS)
-                sv_catpv(tmpsv, ",FT_ACCESS");
-            if (oppriv & OPpFT_STACKED)
-                sv_catpv(tmpsv, ",FT_STACKED");
-            if (oppriv & OPpFT_STACKING)
-                sv_catpv(tmpsv, ",FT_STACKING");
-            if (oppriv & OPpFT_AFTER_t)
-                sv_catpv(tmpsv, ",AFTER_t");
-       }
-       else if (o->op_type == OP_AASSIGN) {
-           if (oppriv & OPpASSIGN_COMMON)
-               sv_catpvs(tmpsv, ",COMMON");
-           if (oppriv & OPpMAYBE_LVSUB)
-               sv_catpvs(tmpsv, ",MAYBE_LVSUB");
-       }
-       if (o->op_flags & OPf_MOD && oppriv & OPpLVAL_INTRO)
-           sv_catpv(tmpsv, ",INTRO");
-       if (o->op_type == OP_PADRANGE)
-           Perl_sv_catpvf(aTHX_ tmpsv, ",COUNT=%"UVuf,
-                           (UV)(oppriv & OPpPADRANGE_COUNTMASK));
-        if (  (o->op_type == OP_RV2HV || o->op_type == OP_RV2AV ||
-               o->op_type == OP_PADAV || o->op_type == OP_PADHV ||
-               o->op_type == OP_ASLICE || o->op_type == OP_HSLICE)
-           && oppriv & OPpSLICEWARNING  )
-            sv_catpvs(tmpsv, ",SLICEWARNING");
-       if (SvCUR(tmpsv)) {
+       if (tmpsv && SvCUR(tmpsv)) {
             Perl_dump_indent(aTHX_ level, file, "PRIVATE = (%s)\n", SvPVX_const(tmpsv) + 1);
        } else
             Perl_dump_indent(aTHX_ level, file, "PRIVATE = (0x%"UVxf")\n",
                              (UV)oppriv);
     }
 
-
-
-
     switch (optype) {
     case OP_AELEMFAST:
     case OP_GVSV:
index 53790db..b531ce8 100644 (file)
@@ -592,73 +592,13 @@ sub fmt_line {    # generate text-line for op.
     return $text; # suppress empty lines
 }
 
-our %priv; # used to display each opcode's BASEOP.op_private values
-
-$priv{$_}{128} = "LVINTRO"
-  for qw(pos substr vec threadsv gvsv rv2sv rv2hv rv2gv rv2av rv2arylen
-         aelem helem aslice hslice padsv padav padhv enteriter entersub
-         padrange pushmark);
-$priv{$_}{64} = "REFC" for qw(leave leavesub leavesublv leavewrite);
-$priv{$_}{128} = "LV" for qw(leave leaveloop);
-@{$priv{aassign}}{32,64} = qw(STATE COMMON);
-@{$priv{sassign}}{32,64,128} = qw(STATE BKWARD CV2GV);
-$priv{$_}{64} = "RTIME" for qw(match subst substcont qr);
-@{$priv{$_}}{1,2,4,8,16,64} = qw(<UTF >UTF IDENT SQUASH DEL COMPL GROWS)
-  for qw(trans transr);
-$priv{repeat}{64} = "DOLIST";
-$priv{leaveloop}{64} = "CONT";
-@{$priv{$_}}{32,64,96} = qw(DREFAV DREFHV DREFSV)
-  for qw(rv2gv rv2sv padsv aelem helem);
-$priv{$_}{16} = "STATE" for qw(padav padhv padsv);
-@{$priv{rv2gv}}{4,16} = qw(NOINIT FAKE);
-@{$priv{entersub}}{1,4,16,32,64} = qw(INARGS TARG DBG DEREF);
-@{$priv{rv2cv}}{64,8,128} = qw(CONST AMPER NO());
-$priv{gv}{32} = "EARLYCV";
-$priv{$_}{16} = "LVDEFER" for qw(aelem helem);
-$priv{$_}{16} = "OURINTR" for qw(gvsv rv2sv rv2av rv2hv r2gv enteriter);
-$priv{$_}{8} = "LVSUB"
-  for qw(rv2av rv2gv rv2hv padav padhv aelem helem aslice hslice
-         av2arylen keys rkeys substr pos vec);
-$priv{$_}{4} = "SLICEWARN"
-  for qw(rv2hv rv2av padav padhv hslice aslice);
-@{$priv{$_}}{32,64} = qw(BOOL BOOL?) for qw(rv2hv padhv);
-$priv{substr}{16} = "REPL1ST";
-$priv{$_}{16} = "TARGMY"
-  for map(($_,"s$_"), qw(chop chomp)),
-      map(($_,"i_$_"), qw(postinc postdec multiply divide modulo add
-                          subtract negate)),
-      qw(pow concat stringify left_shift right_shift bit_and bit_xor
-         bit_or complement atan2 sin cos rand exp log sqrt int hex oct
-         abs length index rindex sprintf ord chr crypt quotemeta join
-         push unshift flock chdir chown chroot unlink chmod utime rename
-         link symlink mkdir rmdir wait waitpid system exec kill getppid
-         getpgrp setpgrp getpriority setpriority time sleep);
-$priv{$_}{4} = "REVERSED" for qw(enteriter iter);
-@{$priv{const}}{2,4,8,16,64} = qw(NOVER SHORT STRICT ENTERED BARE);
-$priv{$_}{64} = "LINENUM" for qw(flip flop);
-$priv{list}{64} = "GUESSED";
-$priv{delete}{64} = "SLICE";
-$priv{exists}{64} = "SUB";
-@{$priv{sort}}{1,2,4,8,16,32,64} = qw(NUM INT REV INPLACE DESC QSORT STABLE);
-$priv{reverse}{8} = "INPLACE";
-$priv{threadsv}{64} = "SVREFd";
-@{$priv{$_}}{16,32,64,128} = qw(INBIN INCR OUTBIN OUTCR)
-  for qw(open backtick);
-$priv{$_}{32} = "HUSH" for qw(nextstate dbstate);
-$priv{$_}{2} = "FTACCESS"
-  for qw(ftrread ftrwrite ftrexec fteread ftewrite fteexec);
-@{$priv{entereval}}{2,4,8,16} = qw(HAS_HH UNI BYTES COPHH);
-@{$priv{$_}}{4,8,16} = qw(FTSTACKED FTSTACKING FTAFTERt)
-  for qw(ftrread ftrwrite ftrexec fteread ftewrite fteexec ftis fteowned
-         ftrowned ftzero ftsize ftmtime ftatime ftctime ftsock ftchr
-         ftblk ftfile ftdir ftpipe ftlink ftsuid ftsgid ftsvtx fttty
-         fttext ftbinary);
-$priv{$_}{2} = "GREPLEX"
-  for qw(mapwhile mapstart grepwhile grepstart);
-$priv{$_}{128} = "+1" for qw(caller wantarray runcv);
-@{$priv{coreargs}}{1,2,64,128} = qw(DREF1 DREF2 $MOD MARK);
-$priv{$_}{128} = "UTF" for qw(last redo next goto dump);
-$priv{split}{128} = "IMPLIM";
+
+
+# use require rather than use here to avoid disturbing tests that dump
+# BEGIN blocks
+require B::Op_private;
+
+
 
 our %hints; # used to display each COP's op_hints values
 
@@ -688,9 +628,61 @@ sub _flags {
     return join(",", @s);
 }
 
+# return a string like 'LVINTRO,1' for the op $name with op_private
+# value $x
+
 sub private_flags {
     my($name, $x) = @_;
-    _flags($priv{$name}, $x);
+    my $entry = $B::Op_private::bits{$name};
+    return $x ? "$x" : '' unless $entry;
+
+    my @flags;
+    my $bit;
+    for ($bit = 7; $bit >= 0; $bit--) {
+        next unless exists $entry->{$bit};
+        my $e = $entry->{$bit};
+        if (ref($e) eq 'HASH') {
+            # bit field
+
+            my ($bitmin, $bitmax, $bitmask, $enum, $label) =
+                    @{$e}{qw(bitmin bitmax bitmask enum label)};
+            $bit = $bitmin;
+            next if defined $label && $label eq '-'; # display as raw number
+
+            my $val = $x & $bitmask;
+            $x &= ~$bitmask;
+            $val >>= $bitmin;
+
+            if (defined $enum) {
+                # try to convert numeric $val into symbolic
+                my @enum = @$enum;
+                while (@enum) {
+                    my $ix    = shift @enum;
+                    my $name  = shift @enum;
+                    my $label = shift @enum;
+                    if ($val == $ix) {
+                        $val = $label;
+                        last;
+                    }
+                }
+            }
+            next if $val eq '0'; # don't display anonymous zero values
+            push @flags, defined $label ? "$label=$val" : $val;
+
+        }
+        else {
+            # flag bit
+            my $label = $B::Op_private::labels{$e};
+            next if defined $label && $label eq '-'; # display as raw number
+            if ($x & (1<<$bit)) {
+                $x -= (1<<$bit);
+                push @flags, $label;
+            }
+        }
+    }
+
+    push @flags, $x if $x; # display unknown bits numerically
+    return join ",", @flags;
 }
 
 sub hints_flags {
@@ -779,18 +771,25 @@ sub concise_op {
     $h{class} = class($op);
     $h{extarg} = $h{targ} = $op->targ;
     $h{extarg} = "" unless $h{extarg};
+    $h{privval} = $op->private;
+    $h{private} = private_flags($h{name}, $op->private);
+    if ($op->folded) {
+      $h{private} &&= "$h{private},";
+      $h{private} .= "FOLD";
+    }
+
     if ($h{name} eq "null" and $h{targ}) {
        # targ holds the old type
        $h{exname} = "ex-" . substr(ppname($h{targ}), 3);
        $h{extarg} = "";
-    } elsif ($op->name =~ /^leave(sub(lv)?|write)?$/) {
-       # targ potentially holds a reference count
-       if ($op->private & 64) {
-           my $refs = "ref" . ($h{targ} != 1 ? "s" : "");
-           $h{targarglife} = $h{targarg} = "$h{targ} $refs";
-       }
+    } elsif ($h{private} =~ /\bREFC\b/) {
+       # targ holds a reference count
+        my $refs = "ref" . ($h{targ} != 1 ? "s" : "");
+        $h{targarglife} = $h{targarg} = "$h{targ} $refs";
     } elsif ($h{targ}) {
-       my $count = $h{name} eq 'padrange' ? ($op->private & 127) : 1;
+       my $count = $h{name} eq 'padrange'
+            ? ($op->private & $B::Op_private::defines{'OPpPADRANGE_COUNTMASK'})
+            : 1;
        my (@targarg, @targarglife);
        for my $i (0..$count-1) {
            my ($targarg, $targarglife);
@@ -916,12 +915,6 @@ sub concise_op {
     $h{classsym} = $opclass{$h{class}};
     $h{flagval} = $op->flags;
     $h{flags} = op_flags($op->flags);
-    $h{privval} = $op->private;
-    $h{private} = private_flags($h{name}, $op->private);
-    if ($op->folded) {
-      $h{private} &&= "$h{private},";
-      $h{private} .= "FOLD";
-    }
     if ($op->can("hints")) {
       $h{hintsval} = $op->hints;
       $h{hints} = hints_flags($h{hintsval});
@@ -1413,10 +1406,7 @@ Private flags, if any are set for an opcode, are displayed after a '/'
 
 They're opcode specific, and occur less often than the public ones, so
 they're represented by short mnemonics instead of single-chars; see
-F<op.h> for gory details, or try this quick 2-liner:
-
-  $> perl -MB::Concise -de 1
-  DB<1> |x \%B::Concise::priv
+B::Op_private and F<regen/op_private> for more details.
 
 =head1 FORMATTING SPECIFICATIONS
 
index 8767b5e..308b015 100644 (file)
@@ -32,6 +32,7 @@ foreach my $tuple (['cop.h'],
                    ['cv.h', 'CVf'],
                    ['gv.h', 'GVf'],
                    ['op.h'],
+                   ['opcode.h', 'OPp'],
                    ['op_reg_common.h','(?:(?:RXf_)?PMf_)'],
                    ['regexp.h','RXf_'],
                    ['sv.h', 'SV(?:[fps]|pad)_'],
index 52dc175..ce777da 100644 (file)
@@ -1529,7 +1529,7 @@ dumpindent is 4 at - line 1.
 1   TYPE = leave  ===> NULL
     TARG = 1
     FLAGS = (VOID,KIDS,PARENS,SLABBED,LASTSIB)
-    PRIVATE = (REFCOUNTED)
+    PRIVATE = (REFC)
     REFCNT = 1
     {
 2       TYPE = enter  ===> 3
@@ -1545,7 +1545,7 @@ dumpindent is 4 at - line 1.
 5       TYPE = entersub  ===> 1
         TARG = 1
         FLAGS = (VOID,KIDS,STACKED,SLABBED,LASTSIB)
-        PRIVATE = (HASTARG)
+        PRIVATE = (TARG)
         {
 6           TYPE = null  ===> (5)
               (was list)
index 3cab4bf..3e66db9 100644 (file)
@@ -39,6 +39,11 @@ no_usym
 no_wrongref
 op_desc
 op_name
+op_private_bitdef_ix
+op_private_bitdefs
+op_private_bitfields
+op_private_labels
+op_private_valid
 opargs
 phase_names
 ppaddr
diff --git a/lib/B/Op_private.pm b/lib/B/Op_private.pm
new file mode 100644 (file)
index 0000000..08ab0f4
--- /dev/null
@@ -0,0 +1,695 @@
+# -*- buffer-read-only: t -*-
+#
+#    lib/B/Op_private.pm
+#
+#    Copyright (C) 2014 by Larry Wall and others
+#
+#    You may distribute under the terms of either the GNU General Public
+#    License or the Artistic License, as specified in the README file.
+#
+# !!!!!!!   DO NOT EDIT THIS FILE   !!!!!!!
+# This file is built by regen/opcode.pl from data in regen/op_private.
+# Any changes made here will be lost!
+
+=head1 NAME
+
+B::Op_private -  OP op_private flag definitions
+
+=head1 SYNOPSIS
+
+    use B::Op_private;
+
+    # flag details for bit 7 of OP_AELEM's op_private:
+    my $name  = $B::Op_private::bits{aelem}{7}; # OPpLVAL_INTRO
+    my $value = $B::Op_private::defines{$name}; # 128
+    my $label = $B::Op_private::labels{$name};  # LVINTRO
+
+    # the bit field at bits 5..6 of OP_AELEM's op_private:
+    my $bf  = $B::Op_private::bits{aelem}{6};
+    my $mask = $bf->{bitmask}; # etc
+
+=head1 DESCRIPTION
+
+This module provides three global hashes:
+
+    %B::Op_private::bits
+    %B::Op_private::defines
+    %B::Op_private::labels
+
+which contain information about the per-op meanings of the bits in the
+op_private field.
+
+=head2 C<%bits>
+
+This is indexed by op name and then bit number (0..7). For single bit flags,
+it returns the name of the define (if any) for that bit:
+
+   $B::Op_private::bits{aelem}{7} eq 'OPpLVAL_INTRO';
+
+For bit fields, it returns a hash ref containing details about the field.
+The same reference will be returned for all bit positions that make
+up the bit field; so for example these both return the same hash ref:
+
+    $bitfield = $B::Op_private::bits{aelem}{5};
+    $bitfield = $B::Op_private::bits{aelem}{6};
+
+The general format of this hash ref is
+
+    {
+        # The bit range and mask; these are always present.
+        bitmin        => 5,
+        bitmax        => 6,
+        bitmask       => 0x60,
+
+        # (The remaining keys are optional)
+
+        # The names of any defines that were requested:
+        mask_def      => 'OPpFOO_MASK',
+        baseshift_def => 'OPpFOO_SHIFT',
+        bitcount_def  => 'OPpFOO_BITS',
+
+        # If present, Concise etc will display the value with a 'FOO='
+        # prefix. If it equals '-', then Concise will treat the bit field
+        # as raw bits and not try to interpret it.
+        label         => 'FOO',
+
+        # If present, specifies the names of some defines and the display
+        # labels that are used to assign meaning to particular integer
+        # values within the bit field; e.g. 3 is displayed as 'C'.
+        enum          => [ qw(
+                             1   OPpFOO_A  A
+                             2   OPpFOO_B  B
+                             3   OPpFOO_C  C
+                         )],
+
+    };
+
+
+=head2 C<%defines>
+
+This gives the value of every C<OPp> define, e.g.
+
+    $B::Op_private::defines{OPpLVAL_INTRO} == 128;
+
+=head2 C<%labels>
+
+This gives the short display label for each define, as used by C<B::Concise>
+and C<perl -Dx>, e.g.
+
+    $B::Op_private::labels{OPpLVAL_INTRO} eq 'LVINTRO';
+
+If the label equals '-', then Concise will treat the bit as a raw bit and
+not try to display it symbolically.
+
+=cut
+
+package B::Op_private;
+
+our %bits;
+
+$bits{$_}{3} = 'OPpENTERSUB_AMPER' for qw(entersub rv2cv);
+$bits{$_}{4} = 'OPpENTERSUB_DB' for qw(entersub rv2cv);
+$bits{$_}{2} = 'OPpENTERSUB_HASTARG' for qw(entersub rv2cv);
+$bits{$_}{6} = 'OPpFLIP_LINENUM' for qw(flip flop);
+$bits{$_}{1} = 'OPpFT_ACCESS' for qw(fteexec fteread ftewrite ftrexec ftrread ftrwrite);
+$bits{$_}{4} = 'OPpFT_AFTER_t' for qw(ftatime ftbinary ftblk ftchr ftctime ftdir fteexec fteowned fteread ftewrite ftfile ftis ftlink ftmtime ftpipe ftrexec ftrowned ftrread ftrwrite ftsgid ftsize ftsock ftsuid ftsvtx fttext fttty ftzero);
+$bits{$_}{2} = 'OPpFT_STACKED' for qw(ftatime ftbinary ftblk ftchr ftctime ftdir fteexec fteowned fteread ftewrite ftfile ftis ftlink ftmtime ftpipe ftrexec ftrowned ftrread ftrwrite ftsgid ftsize ftsock ftsuid ftsvtx fttext fttty ftzero);
+$bits{$_}{3} = 'OPpFT_STACKING' for qw(ftatime ftbinary ftblk ftchr ftctime ftdir fteexec fteowned fteread ftewrite ftfile ftis ftlink ftmtime ftpipe ftrexec ftrowned ftrread ftrwrite ftsgid ftsize ftsock ftsuid ftsvtx fttext fttty ftzero);
+$bits{$_}{1} = 'OPpGREP_LEX' for qw(grepstart grepwhile mapstart mapwhile);
+$bits{$_}{6} = 'OPpHINT_M_VMSISH_STATUS' for qw(dbstate nextstate);
+$bits{$_}{7} = 'OPpHINT_M_VMSISH_TIME' for qw(dbstate nextstate);
+$bits{$_}{1} = 'OPpHINT_STRICT_REFS' for qw(entersub rv2av rv2cv rv2gv rv2hv rv2sv);
+$bits{$_}{5} = 'OPpHUSH_VMSISH' for qw(dbstate nextstate);
+$bits{$_}{2} = 'OPpITER_REVERSED' for qw(enteriter iter);
+$bits{$_}{7} = 'OPpLVALUE' for qw(leave leaveloop);
+$bits{$_}{4} = 'OPpLVAL_DEFER' for qw(aelem helem);
+$bits{$_}{7} = 'OPpLVAL_INTRO' for qw(aelem aslice cond_expr delete enteriter entersub gvsv helem hslice list padav padhv padrange padsv pos pushmark rv2av rv2gv rv2hv rv2sv substr vec);
+$bits{$_}{3} = 'OPpMAYBE_LVSUB' for qw(aassign aelem aslice av2arylen helem hslice keys kvaslice kvhslice padav padhv pos rkeys rv2av rv2gv rv2hv substr vec);
+$bits{$_}{6} = 'OPpMAYBE_TRUEBOOL' for qw(padhv rv2hv);
+$bits{$_}{7} = 'OPpOFFBYONE' for qw(caller runcv wantarray);
+$bits{$_}{5} = 'OPpOPEN_IN_CRLF' for qw(backtick open);
+$bits{$_}{4} = 'OPpOPEN_IN_RAW' for qw(backtick open);
+$bits{$_}{7} = 'OPpOPEN_OUT_CRLF' for qw(backtick open);
+$bits{$_}{6} = 'OPpOPEN_OUT_RAW' for qw(backtick open);
+$bits{$_}{4} = 'OPpOUR_INTRO' for qw(enteriter gvsv rv2av rv2hv rv2sv);
+$bits{$_}{4} = 'OPpPAD_STATE' for qw(padav padhv padsv pushmark);
+$bits{$_}{7} = 'OPpPV_IS_UTF8' for qw(dump goto last next redo);
+$bits{$_}{6} = 'OPpREFCOUNTED' for qw(leave leaveeval leavesub leavesublv leavewrite);
+$bits{$_}{6} = 'OPpRUNTIME' for qw(match pushre qr subst substcont);
+$bits{$_}{2} = 'OPpSLICEWARNING' for qw(aslice hslice padav padhv rv2av rv2hv);
+$bits{$_}{4} = 'OPpTARGET_MY' for qw(abs add atan2 chdir chmod chomp chown chr chroot concat cos crypt divide exec exp flock getpgrp getppid getpriority hex i_add i_divide i_modulo i_multiply i_negate i_postdec i_postinc i_subtract index int kill left_shift length link log match mkdir modulo multiply oct ord pow push rand rename right_shift rindex rmdir schomp setpgrp setpriority sin sleep sqrt srand stringify subst subtract symlink system time trans transr unlink unshift utime wait waitpid);
+$bits{$_}{5} = 'OPpTRANS_COMPLEMENT' for qw(trans transr);
+$bits{$_}{7} = 'OPpTRANS_DELETE' for qw(trans transr);
+$bits{$_}{0} = 'OPpTRANS_FROM_UTF' for qw(trans transr);
+$bits{$_}{6} = 'OPpTRANS_GROWS' for qw(trans transr);
+$bits{$_}{2} = 'OPpTRANS_IDENTICAL' for qw(trans transr);
+$bits{$_}{3} = 'OPpTRANS_SQUASH' for qw(trans transr);
+$bits{$_}{1} = 'OPpTRANS_TO_UTF' for qw(trans transr);
+$bits{$_}{5} = 'OPpTRUEBOOL' for qw(padhv rv2hv);
+
+my @bf = (
+    {
+        label     => '-',
+        mask_def  => 'OPpARG1_MASK',
+        bitmin    => 0,
+        bitmax    => 0,
+        bitmask   => 1,
+    },
+    {
+        label     => '-',
+        mask_def  => 'OPpARG2_MASK',
+        bitmin    => 0,
+        bitmax    => 1,
+        bitmask   => 3,
+    },
+    {
+        label     => '-',
+        mask_def  => 'OPpARG3_MASK',
+        bitmin    => 0,
+        bitmax    => 2,
+        bitmask   => 7,
+    },
+    {
+        label     => '-',
+        mask_def  => 'OPpARG4_MASK',
+        bitmin    => 0,
+        bitmax    => 3,
+        bitmask   => 15,
+    },
+    {
+        label     => '-',
+        mask_def  => 'OPpPADRANGE_COUNTMASK',
+        bitcount_def => 'OPpPADRANGE_COUNTSHIFT',
+        bitmin    => 0,
+        bitmax    => 6,
+        bitmask   => 127,
+    },
+    {
+        label     => '-',
+        bitmin    => 0,
+        bitmax    => 7,
+        bitmask   => 255,
+    },
+    {
+        mask_def  => 'OPpDEREF',
+        bitmin    => 5,
+        bitmax    => 6,
+        bitmask   => 96,
+        enum      => [
+            1, 'OPpDEREF_AV', 'DREFAV',
+            2, 'OPpDEREF_HV', 'DREFHV',
+            3, 'OPpDEREF_SV', 'DREFSV',
+        ],
+    },
+);
+
+@{$bits{aassign}}{6,1,0} = ('OPpASSIGN_COMMON', $bf[1], $bf[1]);
+$bits{abs}{0} = $bf[0];
+@{$bits{accept}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{add}}{1,0} = ($bf[1], $bf[1]);
+$bits{aeach}{0} = $bf[0];
+@{$bits{aelem}}{6,5,1,0} = ($bf[6], $bf[6], $bf[1], $bf[1]);
+@{$bits{aelemfast}}{7,6,5,4,3,2,1,0} = ($bf[5], $bf[5], $bf[5], $bf[5], $bf[5], $bf[5], $bf[5], $bf[5]);
+@{$bits{aelemfast_lex}}{7,6,5,4,3,2,1,0} = ($bf[5], $bf[5], $bf[5], $bf[5], $bf[5], $bf[5], $bf[5], $bf[5]);
+$bits{akeys}{0} = $bf[0];
+$bits{alarm}{0} = $bf[0];
+$bits{and}{0} = $bf[0];
+$bits{andassign}{0} = $bf[0];
+@{$bits{anonhash}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{anonlist}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{atan2}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{av2arylen}{0} = $bf[0];
+$bits{avalues}{0} = $bf[0];
+$bits{backtick}{0} = $bf[0];
+@{$bits{bind}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{binmode}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{bit_and}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{bit_or}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{bit_xor}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{bless}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{caller}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{chdir}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{chmod}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{chomp}{0} = $bf[0];
+$bits{chop}{0} = $bf[0];
+@{$bits{chown}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{chr}{0} = $bf[0];
+$bits{chroot}{0} = $bf[0];
+@{$bits{close}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{closedir}{0} = $bf[0];
+$bits{complement}{0} = $bf[0];
+@{$bits{concat}}{1,0} = ($bf[1], $bf[1]);
+$bits{cond_expr}{0} = $bf[0];
+@{$bits{connect}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{const}}{6,4,3,2,1} = ('OPpCONST_BARE', 'OPpCONST_ENTERED', 'OPpCONST_STRICT', 'OPpCONST_SHORTCIRCUIT', 'OPpCONST_NOVER');
+@{$bits{coreargs}}{7,6,1,0} = ('OPpCOREARGS_PUSHMARK', 'OPpCOREARGS_SCALARMOD', 'OPpCOREARGS_DEREF2', 'OPpCOREARGS_DEREF1');
+$bits{cos}{0} = $bf[0];
+@{$bits{crypt}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{dbmclose}{0} = $bf[0];
+@{$bits{dbmopen}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{defined}{0} = $bf[0];
+@{$bits{delete}}{6,0} = ('OPpSLICE', $bf[0]);
+@{$bits{die}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{divide}}{1,0} = ($bf[1], $bf[1]);
+$bits{dofile}{0} = $bf[0];
+$bits{dor}{0} = $bf[0];
+$bits{dorassign}{0} = $bf[0];
+$bits{dump}{0} = $bf[0];
+$bits{each}{0} = $bf[0];
+@{$bits{entereval}}{5,4,3,2,1,0} = ('OPpEVAL_RE_REPARSING', 'OPpEVAL_COPHH', 'OPpEVAL_BYTES', 'OPpEVAL_UNICODE', 'OPpEVAL_HAS_HH', $bf[0]);
+$bits{entergiven}{0} = $bf[0];
+$bits{enteriter}{3} = 'OPpITER_DEF';
+@{$bits{entersub}}{6,5,0} = ($bf[6], $bf[6], 'OPpENTERSUB_INARGS');
+$bits{entertry}{0} = $bf[0];
+$bits{enterwhen}{0} = $bf[0];
+@{$bits{enterwrite}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{eof}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{eq}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{exec}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{exists}}{6,0} = ('OPpEXISTS_SUB', $bf[0]);
+@{$bits{exit}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{exp}{0} = $bf[0];
+$bits{fc}{0} = $bf[0];
+@{$bits{fcntl}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{fileno}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{flip}{0} = $bf[0];
+@{$bits{flock}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{flop}{0} = $bf[0];
+@{$bits{formline}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{ftatime}{0} = $bf[0];
+$bits{ftbinary}{0} = $bf[0];
+$bits{ftblk}{0} = $bf[0];
+$bits{ftchr}{0} = $bf[0];
+$bits{ftctime}{0} = $bf[0];
+$bits{ftdir}{0} = $bf[0];
+$bits{fteexec}{0} = $bf[0];
+$bits{fteowned}{0} = $bf[0];
+$bits{fteread}{0} = $bf[0];
+$bits{ftewrite}{0} = $bf[0];
+$bits{ftfile}{0} = $bf[0];
+$bits{ftis}{0} = $bf[0];
+$bits{ftlink}{0} = $bf[0];
+$bits{ftmtime}{0} = $bf[0];
+$bits{ftpipe}{0} = $bf[0];
+$bits{ftrexec}{0} = $bf[0];
+$bits{ftrowned}{0} = $bf[0];
+$bits{ftrread}{0} = $bf[0];
+$bits{ftrwrite}{0} = $bf[0];
+$bits{ftsgid}{0} = $bf[0];
+$bits{ftsize}{0} = $bf[0];
+$bits{ftsock}{0} = $bf[0];
+$bits{ftsuid}{0} = $bf[0];
+$bits{ftsvtx}{0} = $bf[0];
+$bits{fttext}{0} = $bf[0];
+$bits{fttty}{0} = $bf[0];
+$bits{ftzero}{0} = $bf[0];
+@{$bits{ge}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{gelem}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{getc}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{getpeername}{0} = $bf[0];
+@{$bits{getpgrp}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{getpriority}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{getsockname}{0} = $bf[0];
+$bits{ggrgid}{0} = $bf[0];
+$bits{ggrnam}{0} = $bf[0];
+@{$bits{ghbyaddr}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{ghbyname}{0} = $bf[0];
+@{$bits{glob}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{gmtime}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{gnbyaddr}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{gnbyname}{0} = $bf[0];
+$bits{goto}{0} = $bf[0];
+$bits{gpbyname}{0} = $bf[0];
+@{$bits{gpbynumber}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{gpwnam}{0} = $bf[0];
+$bits{gpwuid}{0} = $bf[0];
+$bits{grepwhile}{0} = $bf[0];
+@{$bits{gsbyname}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{gsbyport}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{gsockopt}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{gt}}{1,0} = ($bf[1], $bf[1]);
+$bits{gv}{5} = 'OPpEARLY_CV';
+@{$bits{helem}}{6,5,1,0} = ($bf[6], $bf[6], $bf[1], $bf[1]);
+$bits{hex}{0} = $bf[0];
+@{$bits{i_add}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{i_divide}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{i_eq}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{i_ge}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{i_gt}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{i_le}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{i_lt}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{i_modulo}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{i_multiply}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{i_ncmp}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{i_ne}}{1,0} = ($bf[1], $bf[1]);
+$bits{i_negate}{0} = $bf[0];
+$bits{i_postdec}{0} = $bf[0];
+$bits{i_postinc}{0} = $bf[0];
+$bits{i_predec}{0} = $bf[0];
+$bits{i_preinc}{0} = $bf[0];
+@{$bits{i_subtract}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{index}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{int}{0} = $bf[0];
+@{$bits{ioctl}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{join}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{keys}{0} = $bf[0];
+@{$bits{kill}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{last}{0} = $bf[0];
+$bits{lc}{0} = $bf[0];
+$bits{lcfirst}{0} = $bf[0];
+@{$bits{le}}{1,0} = ($bf[1], $bf[1]);
+$bits{leaveeval}{0} = $bf[0];
+$bits{leavegiven}{0} = $bf[0];
+@{$bits{leaveloop}}{1,0} = ($bf[1], $bf[1]);
+$bits{leavesub}{0} = $bf[0];
+$bits{leavesublv}{0} = $bf[0];
+$bits{leavewhen}{0} = $bf[0];
+$bits{leavewrite}{0} = $bf[0];
+@{$bits{left_shift}}{1,0} = ($bf[1], $bf[1]);
+$bits{length}{0} = $bf[0];
+@{$bits{link}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{list}{6} = 'OPpLIST_GUESSED';
+@{$bits{listen}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{localtime}{0} = $bf[0];
+$bits{lock}{0} = $bf[0];
+$bits{log}{0} = $bf[0];
+@{$bits{lslice}}{1,0} = ($bf[1], $bf[1]);
+$bits{lstat}{0} = $bf[0];
+@{$bits{lt}}{1,0} = ($bf[1], $bf[1]);
+$bits{mapwhile}{0} = $bf[0];
+$bits{method}{0} = $bf[0];
+@{$bits{mkdir}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{modulo}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{msgctl}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{msgget}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{msgrcv}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{msgsnd}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{multiply}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{ncmp}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{ne}}{1,0} = ($bf[1], $bf[1]);
+$bits{negate}{0} = $bf[0];
+$bits{next}{0} = $bf[0];
+$bits{not}{0} = $bf[0];
+$bits{oct}{0} = $bf[0];
+$bits{once}{0} = $bf[0];
+@{$bits{open}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{open_dir}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{or}{0} = $bf[0];
+$bits{orassign}{0} = $bf[0];
+$bits{ord}{0} = $bf[0];
+@{$bits{pack}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{padrange}}{6,5,4,3,2,1,0} = ($bf[4], $bf[4], $bf[4], $bf[4], $bf[4], $bf[4], $bf[4]);
+@{$bits{padsv}}{6,5} = ($bf[6], $bf[6]);
+@{$bits{pipe_op}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{pop}{0} = $bf[0];
+$bits{pos}{0} = $bf[0];
+$bits{postdec}{0} = $bf[0];
+$bits{postinc}{0} = $bf[0];
+@{$bits{pow}}{1,0} = ($bf[1], $bf[1]);
+$bits{predec}{0} = $bf[0];
+$bits{preinc}{0} = $bf[0];
+$bits{prototype}{0} = $bf[0];
+@{$bits{push}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{quotemeta}{0} = $bf[0];
+@{$bits{rand}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{range}{0} = $bf[0];
+$bits{reach}{0} = $bf[0];
+@{$bits{read}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{readdir}{0} = $bf[0];
+$bits{readline}{0} = $bf[0];
+$bits{readlink}{0} = $bf[0];
+@{$bits{recv}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{redo}{0} = $bf[0];
+$bits{ref}{0} = $bf[0];
+$bits{refgen}{0} = $bf[0];
+$bits{regcmaybe}{0} = $bf[0];
+$bits{regcomp}{0} = $bf[0];
+$bits{regcreset}{0} = $bf[0];
+@{$bits{rename}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{repeat}}{6,1,0} = ('OPpREPEAT_DOLIST', $bf[1], $bf[1]);
+$bits{require}{0} = $bf[0];
+@{$bits{reset}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{reverse}}{3,0} = ('OPpREVERSE_INPLACE', $bf[0]);
+$bits{rewinddir}{0} = $bf[0];
+@{$bits{right_shift}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{rindex}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{rkeys}{0} = $bf[0];
+$bits{rmdir}{0} = $bf[0];
+$bits{rv2av}{0} = $bf[0];
+@{$bits{rv2cv}}{7,6,0} = ('OPpENTERSUB_NOPAREN', 'OPpMAY_RETURN_CONSTANT', $bf[0]);
+@{$bits{rv2gv}}{6,5,4,2,0} = ($bf[6], $bf[6], 'OPpALLOW_FAKE', 'OPpDONT_INIT_GV', $bf[0]);
+$bits{rv2hv}{0} = $bf[0];
+@{$bits{rv2sv}}{6,5,0} = ($bf[6], $bf[6], $bf[0]);
+$bits{rvalues}{0} = $bf[0];
+@{$bits{sassign}}{7,6,1,0} = ('OPpASSIGN_CV_TO_GV', 'OPpASSIGN_BACKWARDS', $bf[1], $bf[1]);
+$bits{scalar}{0} = $bf[0];
+$bits{schomp}{0} = $bf[0];
+$bits{schop}{0} = $bf[0];
+@{$bits{scmp}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{seek}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{seekdir}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{select}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{semctl}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{semget}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{semop}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{send}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{seq}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{setpgrp}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{setpriority}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{sge}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{sgt}}{1,0} = ($bf[1], $bf[1]);
+$bits{shift}{0} = $bf[0];
+@{$bits{shmctl}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{shmget}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{shmread}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{shmwrite}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{shostent}{0} = $bf[0];
+@{$bits{shutdown}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{sin}{0} = $bf[0];
+@{$bits{sle}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{sleep}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{slt}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{smartmatch}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{sne}}{1,0} = ($bf[1], $bf[1]);
+$bits{snetent}{0} = $bf[0];
+@{$bits{socket}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{sockpair}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{sort}}{6,5,4,3,2,1,0} = ('OPpSORT_STABLE', 'OPpSORT_QSORT', 'OPpSORT_DESCEND', 'OPpSORT_INPLACE', 'OPpSORT_REVERSE', 'OPpSORT_INTEGER', 'OPpSORT_NUMERIC');
+@{$bits{splice}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{split}{7} = 'OPpSPLIT_IMPLIM';
+@{$bits{sprintf}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{sprotoent}{0} = $bf[0];
+$bits{sqrt}{0} = $bf[0];
+@{$bits{srand}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{srefgen}{0} = $bf[0];
+@{$bits{sselect}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{sservent}{0} = $bf[0];
+@{$bits{ssockopt}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{stat}{0} = $bf[0];
+@{$bits{stringify}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{study}{0} = $bf[0];
+$bits{substcont}{0} = $bf[0];
+@{$bits{substr}}{4,2,1,0} = ('OPpSUBSTR_REPL_FIRST', $bf[2], $bf[2], $bf[2]);
+@{$bits{subtract}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{symlink}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{syscall}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{sysopen}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{sysread}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{sysseek}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{system}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{syswrite}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{tell}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{telldir}{0} = $bf[0];
+@{$bits{tie}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{tied}{0} = $bf[0];
+@{$bits{truncate}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{uc}{0} = $bf[0];
+$bits{ucfirst}{0} = $bf[0];
+@{$bits{umask}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{undef}{0} = $bf[0];
+@{$bits{unlink}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{unpack}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{unshift}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{untie}{0} = $bf[0];
+@{$bits{utime}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+$bits{values}{0} = $bf[0];
+@{$bits{vec}}{1,0} = ($bf[1], $bf[1]);
+@{$bits{waitpid}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{warn}}{3,2,1,0} = ($bf[3], $bf[3], $bf[3], $bf[3]);
+@{$bits{xor}}{1,0} = ($bf[1], $bf[1]);
+
+
+our %defines = (
+    OPpALLOW_FAKE            =>  16,
+    OPpARG1_MASK             =>   1,
+    OPpARG2_MASK             =>   3,
+    OPpARG3_MASK             =>   7,
+    OPpARG4_MASK             =>  15,
+    OPpASSIGN_BACKWARDS      =>  64,
+    OPpASSIGN_COMMON         =>  64,
+    OPpASSIGN_CV_TO_GV       => 128,
+    OPpCONST_BARE            =>  64,
+    OPpCONST_ENTERED         =>  16,
+    OPpCONST_NOVER           =>   2,
+    OPpCONST_SHORTCIRCUIT    =>   4,
+    OPpCONST_STRICT          =>   8,
+    OPpCOREARGS_DEREF1       =>   1,
+    OPpCOREARGS_DEREF2       =>   2,
+    OPpCOREARGS_PUSHMARK     => 128,
+    OPpCOREARGS_SCALARMOD    =>  64,
+    OPpDEREF                 =>  96,
+    OPpDEREF_AV              =>  32,
+    OPpDEREF_HV              =>  64,
+    OPpDEREF_SV              =>  96,
+    OPpDONT_INIT_GV          =>   4,
+    OPpEARLY_CV              =>  32,
+    OPpENTERSUB_AMPER        =>   8,
+    OPpENTERSUB_DB           =>  16,
+    OPpENTERSUB_HASTARG      =>   4,
+    OPpENTERSUB_INARGS       =>   1,
+    OPpENTERSUB_NOPAREN      => 128,
+    OPpEVAL_BYTES            =>   8,
+    OPpEVAL_COPHH            =>  16,
+    OPpEVAL_HAS_HH           =>   2,
+    OPpEVAL_RE_REPARSING     =>  32,
+    OPpEVAL_UNICODE          =>   4,
+    OPpEXISTS_SUB            =>  64,
+    OPpFLIP_LINENUM          =>  64,
+    OPpFT_ACCESS             =>   2,
+    OPpFT_AFTER_t            =>  16,
+    OPpFT_STACKED            =>   4,
+    OPpFT_STACKING           =>   8,
+    OPpGREP_LEX              =>   2,
+    OPpHINT_M_VMSISH_STATUS  =>  64,
+    OPpHINT_M_VMSISH_TIME    => 128,
+    OPpHINT_STRICT_REFS      =>   2,
+    OPpHUSH_VMSISH           =>  32,
+    OPpITER_DEF              =>   8,
+    OPpITER_REVERSED         =>   4,
+    OPpLIST_GUESSED          =>  64,
+    OPpLVALUE                => 128,
+    OPpLVAL_DEFER            =>  16,
+    OPpLVAL_INTRO            => 128,
+    OPpMAYBE_LVSUB           =>   8,
+    OPpMAYBE_TRUEBOOL        =>  64,
+    OPpMAY_RETURN_CONSTANT   =>  64,
+    OPpOFFBYONE              => 128,
+    OPpOPEN_IN_CRLF          =>  32,
+    OPpOPEN_IN_RAW           =>  16,
+    OPpOPEN_OUT_CRLF         => 128,
+    OPpOPEN_OUT_RAW          =>  64,
+    OPpOUR_INTRO             =>  16,
+    OPpPADRANGE_COUNTMASK    => 127,
+    OPpPADRANGE_COUNTSHIFT   =>   7,
+    OPpPAD_STATE             =>  16,
+    OPpPV_IS_UTF8            => 128,
+    OPpREFCOUNTED            =>  64,
+    OPpREPEAT_DOLIST         =>  64,
+    OPpREVERSE_INPLACE       =>   8,
+    OPpRUNTIME               =>  64,
+    OPpSLICE                 =>  64,
+    OPpSLICEWARNING          =>   4,
+    OPpSORT_DESCEND          =>  16,
+    OPpSORT_INPLACE          =>   8,
+    OPpSORT_INTEGER          =>   2,
+    OPpSORT_NUMERIC          =>   1,
+    OPpSORT_QSORT            =>  32,
+    OPpSORT_REVERSE          =>   4,
+    OPpSORT_STABLE           =>  64,
+    OPpSPLIT_IMPLIM          => 128,
+    OPpSUBSTR_REPL_FIRST     =>  16,
+    OPpTARGET_MY             =>  16,
+    OPpTRANS_COMPLEMENT      =>  32,
+    OPpTRANS_DELETE          => 128,
+    OPpTRANS_FROM_UTF        =>   1,
+    OPpTRANS_GROWS           =>  64,
+    OPpTRANS_IDENTICAL       =>   4,
+    OPpTRANS_SQUASH          =>   8,
+    OPpTRANS_TO_UTF          =>   2,
+    OPpTRUEBOOL              =>  32,
+);
+
+our %labels = (
+    OPpALLOW_FAKE            => 'FAKE',
+    OPpASSIGN_BACKWARDS      => 'BKWARD',
+    OPpASSIGN_COMMON         => 'COMMON',
+    OPpASSIGN_CV_TO_GV       => 'CV2GV',
+    OPpCONST_BARE            => 'BARE',
+    OPpCONST_ENTERED         => 'ENTERED',
+    OPpCONST_NOVER           => 'NOVER',
+    OPpCONST_SHORTCIRCUIT    => 'SHORT',
+    OPpCONST_STRICT          => 'STRICT',
+    OPpCOREARGS_DEREF1       => 'DEREF1',
+    OPpCOREARGS_DEREF2       => 'DEREF2',
+    OPpCOREARGS_PUSHMARK     => 'MARK',
+    OPpCOREARGS_SCALARMOD    => '$MOD',
+    OPpDEREF_AV              => 'DREFAV',
+    OPpDEREF_HV              => 'DREFHV',
+    OPpDEREF_SV              => 'DREFSV',
+    OPpDONT_INIT_GV          => 'NOINIT',
+    OPpEARLY_CV              => 'EARLYCV',
+    OPpENTERSUB_AMPER        => 'AMPER',
+    OPpENTERSUB_DB           => 'DBG',
+    OPpENTERSUB_HASTARG      => 'TARG',
+    OPpENTERSUB_INARGS       => 'INARGS',
+    OPpENTERSUB_NOPAREN      => 'NO()',
+    OPpEVAL_BYTES            => 'BYTES',
+    OPpEVAL_COPHH            => 'COPHH',
+    OPpEVAL_HAS_HH           => 'HAS_HH',
+    OPpEVAL_RE_REPARSING     => '-',
+    OPpEVAL_UNICODE          => 'UNI',
+    OPpEXISTS_SUB            => 'SUB',
+    OPpFLIP_LINENUM          => 'LINENUM',
+    OPpFT_ACCESS             => 'FTACCESS',
+    OPpFT_AFTER_t            => 'FTAFTERt',
+    OPpFT_STACKED            => 'FTSTACKED',
+    OPpFT_STACKING           => 'FTSTACKING',
+    OPpGREP_LEX              => 'GREPLEX',
+    OPpHINT_M_VMSISH_STATUS  => 'VMSISH_STATUS',
+    OPpHINT_M_VMSISH_TIME    => 'VMSISH_TIME',
+    OPpHINT_STRICT_REFS      => '-',
+    OPpHUSH_VMSISH           => 'HUSH',
+    OPpITER_DEF              => '-',
+    OPpITER_REVERSED         => 'REVERSED',
+    OPpLIST_GUESSED          => 'GUESSED',
+    OPpLVALUE                => 'LV',
+    OPpLVAL_DEFER            => 'LVDEFER',
+    OPpLVAL_INTRO            => 'LVINTRO',
+    OPpMAYBE_LVSUB           => 'LVSUB',
+    OPpMAYBE_TRUEBOOL        => 'BOOL?',
+    OPpMAY_RETURN_CONSTANT   => 'CONST',
+    OPpOFFBYONE              => '+1',
+    OPpOPEN_IN_CRLF          => 'INCR',
+    OPpOPEN_IN_RAW           => 'INBIN',
+    OPpOPEN_OUT_CRLF         => 'OUTCR',
+    OPpOPEN_OUT_RAW          => 'OUTBIN',
+    OPpOUR_INTRO             => 'OURINTR',
+    OPpPAD_STATE             => 'STATE',
+    OPpPV_IS_UTF8            => 'UTF',
+    OPpREFCOUNTED            => 'REFC',
+    OPpREPEAT_DOLIST         => 'DOLIST',
+    OPpREVERSE_INPLACE       => 'INPLACE',
+    OPpRUNTIME               => 'RTIME',
+    OPpSLICE                 => 'SLICE',
+    OPpSLICEWARNING          => 'SLICEWARN',
+    OPpSORT_DESCEND          => 'DESC',
+    OPpSORT_INPLACE          => 'INPLACE',
+    OPpSORT_INTEGER          => 'INT',
+    OPpSORT_NUMERIC          => 'NUM',
+    OPpSORT_QSORT            => 'QSORT',
+    OPpSORT_REVERSE          => 'REV',
+    OPpSORT_STABLE           => 'STABLE',
+    OPpSPLIT_IMPLIM          => 'IMPLIM',
+    OPpSUBSTR_REPL_FIRST     => 'REPL1ST',
+    OPpTARGET_MY             => 'TARGMY',
+    OPpTRANS_COMPLEMENT      => 'COMPL',
+    OPpTRANS_DELETE          => 'DEL',
+    OPpTRANS_FROM_UTF        => '<UTF',
+    OPpTRANS_GROWS           => 'GROWS',
+    OPpTRANS_IDENTICAL       => 'IDENT',
+    OPpTRANS_SQUASH          => 'SQUASH',
+    OPpTRANS_TO_UTF          => '>UTF',
+    OPpTRUEBOOL              => 'BOOL',
+);
+
+# ex: set ro:
diff --git a/op.h b/op.h
index 0486548..9593744 100644 (file)
--- a/op.h
+++ b/op.h
@@ -150,213 +150,22 @@ Deprecated.  Use C<GIMME_V> instead.
              : G_SCALAR)                                               \
           : dowantarray())
 
-/* Lower bits of op_private often carry the number of arguments, as
- * set by newBINOP, newUNOP and ck_fun */
 
-/* NOTE: OP_NEXTSTATE and OP_DBSTATE (i.e. COPs) carry NATIVE_HINTS
- * in op_private */
+/* NOTE: OPp* flags are now auto-generated and defined in opcode.h,
+ *       from data in regen/op_private */
 
-/* Private for lvalues */
-#define OPpLVAL_INTRO  128     /* Lvalue must be localized or lvalue sub */
 
-/* Private for OPs with TARGLEX */
-  /* (lower bits may carry MAXARG) */
-#define OPpTARGET_MY           16      /* Target is PADMY. */
-
-/* Private for OP_LEAVE, OP_LEAVESUB, OP_LEAVESUBLV and OP_LEAVEWRITE */
-#define OPpREFCOUNTED          64      /* op_targ carries a refcount */
-
-/* Private for OP_LEAVE and OP_LEAVELOOP */
-#define OPpLVALUE              128     /* Do not copy return value */
-
-/* Private for OP_AASSIGN */
-#define OPpASSIGN_COMMON       64      /* Left & right have syms in common. */
-
-/* Private for OP_SASSIGN */
-#define OPpASSIGN_BACKWARDS    64      /* Left & right switched. */
-#define OPpASSIGN_CV_TO_GV     128     /* Possible optimisation for constants. */
-
-/* Private for OP_MATCH and OP_SUBST{,CONT} */
-#define OPpRUNTIME             64      /* Pattern coming in on the stack */
-
-/* Private for OP_TRANS */
-#define OPpTRANS_FROM_UTF      1
-#define OPpTRANS_TO_UTF                2
-#define OPpTRANS_IDENTICAL     4       /* right side is same as left */
-#define OPpTRANS_SQUASH                8
-    /* 16 is used for OPpTARGET_MY */
-#define OPpTRANS_COMPLEMENT    32
-#define OPpTRANS_GROWS         64
-#define OPpTRANS_DELETE                128
 #define OPpTRANS_ALL   (OPpTRANS_FROM_UTF|OPpTRANS_TO_UTF|OPpTRANS_IDENTICAL|OPpTRANS_SQUASH|OPpTRANS_COMPLEMENT|OPpTRANS_GROWS|OPpTRANS_DELETE)
 
-/* Private for OP_REPEAT */
-#define OPpREPEAT_DOLIST       64      /* List replication. */
-
-/* Private for OP_RV2GV, OP_RV2SV, OP_AELEM, OP_HELEM, OP_PADSV */
-#define OPpDEREF               (32|64) /* autovivify: Want ref to something: */
-#define OPpDEREF_AV            32      /*   Want ref to AV. */
-#define OPpDEREF_HV            64      /*   Want ref to HV. */
-#define OPpDEREF_SV            (32|64) /*   Want ref to SV. */
-
-/* OP_ENTERSUB and OP_RV2CV flags
-
-Flags are set on entersub and rv2cv in three phases:
-  parser  - the parser passes the flag to the op constructor
-  check   - the check routine called by the op constructor sets the flag
-  context - application of scalar/ref/lvalue context applies the flag
-
-In the third stage, an entersub op might turn into an rv2cv op (undef &foo,
-\&foo, lock &foo, exists &foo, defined &foo).  The two places where that
-happens (op_lvalue_flags and doref in op.c) need to make sure the flags do
-not conflict.  Flags applied in the context phase are only set when there
-is no conversion of op type.
-
-  bit  entersub flag       phase   rv2cv flag             phase
-  ---  -------------       -----   ----------             -----
-    1  OPpENTERSUB_INARGS  context
-    2  HINT_STRICT_REFS    check   HINT_STRICT_REFS       check
-    4  OPpENTERSUB_HASTARG check
-    8                              OPpENTERSUB_AMPER      parser
-   16  OPpENTERSUB_DB      check
-   32  OPpDEREF_AV         context
-   64  OPpDEREF_HV         context OPpMAY_RETURN_CONSTANT context
-  128  OPpLVAL_INTRO       context OPpENTERSUB_NOPAREN    parser
 
-*/
 
-  /* OP_ENTERSUB only */
-#define OPpENTERSUB_DB         16      /* Debug subroutine. */
-#define OPpENTERSUB_HASTARG    4       /* Called from OP tree. */
-#define OPpENTERSUB_INARGS     1       /* Lval used as arg to a sub. */
-/* used by OPpDEREF             (32|64) */
-/* used by HINT_STRICT_REFS     2          */
-  /* Mask for OP_ENTERSUB flags, the absence of which must be propagated
-     in dynamic context */
+/* Mask for OP_ENTERSUB flags, the absence of which must be propagated
+ in dynamic context */
 #define OPpENTERSUB_LVAL_MASK (OPpLVAL_INTRO|OPpENTERSUB_INARGS)
 
-  /* OP_RV2CV only */
-#define OPpENTERSUB_AMPER      8       /* Used & form to call. */
-#define OPpENTERSUB_NOPAREN    128     /* bare sub call (without parens) */
-#define OPpMAY_RETURN_CONSTANT 64      /* If a constant sub, return the constant */
-
-  /* OP_GV only */
-#define OPpEARLY_CV            32      /* foo() called before sub foo was parsed */
-  /* OP_?ELEM only */
-#define OPpLVAL_DEFER          16      /* Defer creation of array/hash elem */
-  /* OP_RV2[AH]V OP_[AH]SLICE */
-#define OPpSLICEWARNING                4       /* warn about @hash{$scalar} */
-  /* OP_RV2[SAH]V, OP_GVSV, OP_ENTERITER only */
-#define OPpOUR_INTRO           16      /* Variable was in an our() */
-  /* OP_RV2[AGH]V, OP_PAD[AH]V, OP_[AH]ELEM, OP_[AH]SLICE OP_AV2ARYLEN,
-     OP_R?KEYS, OP_SUBSTR, OP_POS, OP_VEC */
-#define OPpMAYBE_LVSUB         8       /* We might be an lvalue to return */
-  /* OP_RV2HV and OP_PADHV */
-#define OPpTRUEBOOL            32      /* %hash in (%hash || $foo) in
-                                          void context */
-#define OPpMAYBE_TRUEBOOL      64      /* %hash in (%hash || $foo) where
-                                          cx is not known till run time */
-
-  /* OP_SUBSTR only */
-#define OPpSUBSTR_REPL_FIRST   16      /* 1st arg is replacement string */
-
-  /* OP_PADSV only */
-#define OPpPAD_STATE           16      /* is a "state" pad */
-  /* for OP_RV2?V, lower bits carry hints (currently only HINT_STRICT_REFS) */
-
-  /* OP_PADRANGE only */
-  /* bit 7 is OPpLVAL_INTRO */
-#define OPpPADRANGE_COUNTMASK  127     /* bits 6..0 hold target range, */
-#define OPpPADRANGE_COUNTSHIFT 7       /* 7 bits in total */
-
-  /* OP_RV2GV only */
-#define OPpDONT_INIT_GV                4       /* Call gv_fetchpv with GV_NOINIT */
-/* (Therefore will return whatever is currently in the symbol table, not
-   guaranteed to be a PVGV)  */
-#define OPpALLOW_FAKE          16      /* OK to return fake glob */
-
-/* Private for OP_ENTERITER and OP_ITER */
-#define OPpITER_REVERSED       4       /* for (reverse ...) */
-#define OPpITER_DEF            8       /* for $_ or for my $_ */
-
-/* Private for OP_CONST */
-#define        OPpCONST_NOVER          2       /* no 6; */
-#define        OPpCONST_SHORTCIRCUIT   4       /* eg the constant 5 in (5 || foo) */
-#define        OPpCONST_STRICT         8       /* bareword subject to strict 'subs' */
-#define OPpCONST_ENTERED       16      /* Has been entered as symbol. */
-#define OPpCONST_BARE          64      /* Was a bare word (filehandle?). */
-
-/* Private for OP_FLIP/FLOP */
-#define OPpFLIP_LINENUM                64      /* Range arg potentially a line num. */
-
-/* Private for OP_LIST */
-#define OPpLIST_GUESSED                64      /* Guessed that pushmark was needed. */
-
-/* Private for OP_DELETE */
-#define OPpSLICE               64      /* Operating on a list of keys */
-/* Also OPpLVAL_INTRO (128) */
-
-/* Private for OP_EXISTS */
-#define OPpEXISTS_SUB          64      /* Checking for &sub, not {} or [].  */
-
-/* Private for OP_SORT */
-#define OPpSORT_NUMERIC                1       /* Optimized away { $a <=> $b } */
-#define OPpSORT_INTEGER                2       /* Ditto while under "use integer" */
-#define OPpSORT_REVERSE                4       /* Reversed sort */
-#define OPpSORT_INPLACE                8       /* sort in-place; eg @a = sort @a */
-#define OPpSORT_DESCEND                16      /* Descending sort */
-#define OPpSORT_QSORT          32      /* Use quicksort (not mergesort) */
-#define OPpSORT_STABLE         64      /* Use a stable algorithm */
-
-/* Private for OP_REVERSE */
-#define OPpREVERSE_INPLACE     8       /* reverse in-place (@a = reverse @a) */
-
-/* Private for OP_OPEN and OP_BACKTICK */
-#define OPpOPEN_IN_RAW         16      /* binmode(F,":raw") on input fh */
-#define OPpOPEN_IN_CRLF                32      /* binmode(F,":crlf") on input fh */
-#define OPpOPEN_OUT_RAW                64      /* binmode(F,":raw") on output fh */
-#define OPpOPEN_OUT_CRLF       128     /* binmode(F,":crlf") on output fh */
-
-/* Private for COPs */
-#define OPpHUSH_VMSISH         32      /* hush DCL exit msg vmsish mode*/
-/* Note: Used for NATIVE_HINTS (shifted from the values in PL_hints),
-        currently defined by vms/vmsish.h:
-                               64
-                               128
- */
 
-/* Private for OP_FTXXX */
-#define OPpFT_ACCESS           2       /* use filetest 'access' */
-#define OPpFT_STACKED          4       /* stacked filetest, as "-f" in "-f -x $f" */
-#define OPpFT_STACKING         8       /* stacking filetest, as "-x" in "-f -x $f" */
-#define OPpFT_AFTER_t          16      /* previous op was -t */
-
-/* Private for OP_(MAP|GREP)(WHILE|START) */
-#define OPpGREP_LEX            2       /* iterate over lexical $_ */
-    
-/* Private for OP_ENTEREVAL */
-#define OPpEVAL_HAS_HH         2       /* Does it have a copy of %^H */
-#define OPpEVAL_UNICODE                4
-#define OPpEVAL_BYTES          8
-#define OPpEVAL_COPHH          16      /* Construct %^H from cop hints */
-#define OPpEVAL_RE_REPARSING   32      /* eval_sv(..., G_RE_REPARSING) */
-    
-/* Private for OP_CALLER, OP_WANTARRAY and OP_RUNCV */
-#define OPpOFFBYONE            128     /* Treat caller(1) as caller(2) */
-
-/* Private for OP_COREARGS */
-/* These must not conflict with OPpDONT_INIT_GV or OPpALLOW_FAKE.
-   See pp.c:S_rv2gv. */
-#define OPpCOREARGS_DEREF1     1       /* Arg 1 is a handle constructor */
-#define OPpCOREARGS_DEREF2     2       /* Arg 2 is a handle constructor */
-#define OPpCOREARGS_SCALARMOD  64      /* \$ rather than \[$@%*] */
-#define OPpCOREARGS_PUSHMARK   128     /* Call pp_pushmark */
-
-/* Private for OP_(LAST|REDO|NEXT|GOTO|DUMP) */
-#define OPpPV_IS_UTF8          128     /* label is in UTF8 */
-
-/* Private for OP_SPLIT */
-#define OPpSPLIT_IMPLIM                128     /* implicit limit */
+
+
 
 struct op {
     BASEOP
index fbc3fe1..ea6ae85 100644 (file)
--- a/opcode.h
+++ b/opcode.h
@@ -2110,4 +2110,1356 @@ EXTCONST U32 PL_opargs[] = {
 
 END_EXTERN_C
 
+
+#define OPpARG1_MASK            0x01
+#define OPpCOREARGS_DEREF1      0x01
+#define OPpENTERSUB_INARGS      0x01
+#define OPpSORT_NUMERIC         0x01
+#define OPpTRANS_FROM_UTF       0x01
+#define OPpCONST_NOVER          0x02
+#define OPpCOREARGS_DEREF2      0x02
+#define OPpEVAL_HAS_HH          0x02
+#define OPpFT_ACCESS            0x02
+#define OPpGREP_LEX             0x02
+#define OPpHINT_STRICT_REFS     0x02
+#define OPpSORT_INTEGER         0x02
+#define OPpTRANS_TO_UTF         0x02
+#define OPpARG2_MASK            0x03
+#define OPpCONST_SHORTCIRCUIT   0x04
+#define OPpDONT_INIT_GV         0x04
+#define OPpENTERSUB_HASTARG     0x04
+#define OPpEVAL_UNICODE         0x04
+#define OPpFT_STACKED           0x04
+#define OPpITER_REVERSED        0x04
+#define OPpSLICEWARNING         0x04
+#define OPpSORT_REVERSE         0x04
+#define OPpTRANS_IDENTICAL      0x04
+#define OPpARG3_MASK            0x07
+#define OPpPADRANGE_COUNTSHIFT  0x07
+#define OPpCONST_STRICT         0x08
+#define OPpENTERSUB_AMPER       0x08
+#define OPpEVAL_BYTES           0x08
+#define OPpFT_STACKING          0x08
+#define OPpITER_DEF             0x08
+#define OPpMAYBE_LVSUB          0x08
+#define OPpREVERSE_INPLACE      0x08
+#define OPpSORT_INPLACE         0x08
+#define OPpTRANS_SQUASH         0x08
+#define OPpARG4_MASK            0x0f
+#define OPpALLOW_FAKE           0x10
+#define OPpCONST_ENTERED        0x10
+#define OPpENTERSUB_DB          0x10
+#define OPpEVAL_COPHH           0x10
+#define OPpFT_AFTER_t           0x10
+#define OPpLVAL_DEFER           0x10
+#define OPpOPEN_IN_RAW          0x10
+#define OPpOUR_INTRO            0x10
+#define OPpPAD_STATE            0x10
+#define OPpSORT_DESCEND         0x10
+#define OPpSUBSTR_REPL_FIRST    0x10
+#define OPpTARGET_MY            0x10
+#define OPpDEREF_AV             0x20
+#define OPpEARLY_CV             0x20
+#define OPpEVAL_RE_REPARSING    0x20
+#define OPpHUSH_VMSISH          0x20
+#define OPpOPEN_IN_CRLF         0x20
+#define OPpSORT_QSORT           0x20
+#define OPpTRANS_COMPLEMENT     0x20
+#define OPpTRUEBOOL             0x20
+#define OPpASSIGN_BACKWARDS     0x40
+#define OPpASSIGN_COMMON        0x40
+#define OPpCONST_BARE           0x40
+#define OPpCOREARGS_SCALARMOD   0x40
+#define OPpDEREF_HV             0x40
+#define OPpEXISTS_SUB           0x40
+#define OPpFLIP_LINENUM         0x40
+#define OPpHINT_M_VMSISH_STATUS 0x40
+#define OPpLIST_GUESSED         0x40
+#define OPpMAYBE_TRUEBOOL       0x40
+#define OPpMAY_RETURN_CONSTANT  0x40
+#define OPpOPEN_OUT_RAW         0x40
+#define OPpREFCOUNTED           0x40
+#define OPpREPEAT_DOLIST        0x40
+#define OPpRUNTIME              0x40
+#define OPpSLICE                0x40
+#define OPpSORT_STABLE          0x40
+#define OPpTRANS_GROWS          0x40
+#define OPpDEREF                0x60
+#define OPpDEREF_SV             0x60
+#define OPpPADRANGE_COUNTMASK   0x7f
+#define OPpASSIGN_CV_TO_GV      0x80
+#define OPpCOREARGS_PUSHMARK    0x80
+#define OPpENTERSUB_NOPAREN     0x80
+#define OPpHINT_M_VMSISH_TIME   0x80
+#define OPpLVALUE               0x80
+#define OPpLVAL_INTRO           0x80
+#define OPpOFFBYONE             0x80
+#define OPpOPEN_OUT_CRLF        0x80
+#define OPpPV_IS_UTF8           0x80
+#define OPpSPLIT_IMPLIM         0x80
+#define OPpTRANS_DELETE         0x80
+START_EXTERN_C
+
+#ifndef PERL_GLOBAL_STRUCT_INIT
+
+#  ifndef DOINIT
+
+/* data about the flags in op_private */
+
+EXTCONST I16  PL_op_private_bitdef_ix[];
+EXTCONST U16  PL_op_private_bitdefs[];
+EXTCONST char PL_op_private_labels[];
+EXTCONST I16  PL_op_private_bitfields[];
+EXTCONST U8   PL_op_private_valid[];
+
+#  else
+
+
+/* PL_op_private_labels[]: the short descriptions of private flags.
+ * All labels are concatenated into a single char array
+ * (separated by \0's) for compactness.
+ */
+
+EXTCONST char PL_op_private_labels[] = {
+    '$','M','O','D','\0',
+    '+','1','\0',
+    '-','\0',
+    '<','U','T','F','\0',
+    '>','U','T','F','\0',
+    'A','M','P','E','R','\0',
+    'B','A','R','E','\0',
+    'B','K','W','A','R','D','\0',
+    'B','O','O','L','\0',
+    'B','O','O','L','?','\0',
+    'B','Y','T','E','S','\0',
+    'C','O','M','M','O','N','\0',
+    'C','O','M','P','L','\0',
+    'C','O','N','S','T','\0',
+    'C','O','P','H','H','\0',
+    'C','V','2','G','V','\0',
+    'D','B','G','\0',
+    'D','E','L','\0',
+    'D','E','R','E','F','1','\0',
+    'D','E','R','E','F','2','\0',
+    'D','E','S','C','\0',
+    'D','O','L','I','S','T','\0',
+    'D','R','E','F','A','V','\0',
+    'D','R','E','F','H','V','\0',
+    'D','R','E','F','S','V','\0',
+    'E','A','R','L','Y','C','V','\0',
+    'E','N','T','E','R','E','D','\0',
+    'F','A','K','E','\0',
+    'F','T','A','C','C','E','S','S','\0',
+    'F','T','A','F','T','E','R','t','\0',
+    'F','T','S','T','A','C','K','E','D','\0',
+    'F','T','S','T','A','C','K','I','N','G','\0',
+    'G','R','E','P','L','E','X','\0',
+    'G','R','O','W','S','\0',
+    'G','U','E','S','S','E','D','\0',
+    'H','A','S','_','H','H','\0',
+    'H','U','S','H','\0',
+    'I','D','E','N','T','\0',
+    'I','M','P','L','I','M','\0',
+    'I','N','A','R','G','S','\0',
+    'I','N','B','I','N','\0',
+    'I','N','C','R','\0',
+    'I','N','P','L','A','C','E','\0',
+    'I','N','T','\0',
+    'L','I','N','E','N','U','M','\0',
+    'L','V','\0',
+    'L','V','D','E','F','E','R','\0',
+    'L','V','I','N','T','R','O','\0',
+    'L','V','S','U','B','\0',
+    'M','A','R','K','\0',
+    'N','O','(',')','\0',
+    'N','O','I','N','I','T','\0',
+    'N','O','V','E','R','\0',
+    'N','U','M','\0',
+    'O','U','R','I','N','T','R','\0',
+    'O','U','T','B','I','N','\0',
+    'O','U','T','C','R','\0',
+    'Q','S','O','R','T','\0',
+    'R','E','F','C','\0',
+    'R','E','P','L','1','S','T','\0',
+    'R','E','V','\0',
+    'R','E','V','E','R','S','E','D','\0',
+    'R','T','I','M','E','\0',
+    'S','H','O','R','T','\0',
+    'S','L','I','C','E','\0',
+    'S','L','I','C','E','W','A','R','N','\0',
+    'S','Q','U','A','S','H','\0',
+    'S','T','A','B','L','E','\0',
+    'S','T','A','T','E','\0',
+    'S','T','R','I','C','T','\0',
+    'S','U','B','\0',
+    'T','A','R','G','\0',
+    'T','A','R','G','M','Y','\0',
+    'U','N','I','\0',
+    'U','T','F','\0',
+    'V','M','S','I','S','H','_','S','T','A','T','U','S','\0',
+    'V','M','S','I','S','H','_','T','I','M','E','\0',
+
+};
+
+
+
+/* PL_op_private_bitfields[]: details about each bit field type.
+ * Each defintition consists of the following list of words:
+ *    bitmin
+ *    label (index into PL_op_private_labels[]; -1 if no label)
+ *    repeat for each enum entry (if any):
+ *       enum value
+ *       enum label (index into PL_op_private_labels[])
+ *    -1
+ */
+
+EXTCONST I16 PL_op_private_bitfields[] = {
+    0, 8, -1,
+    0, 8, -1,
+    0, 8, -1,
+    0, 8, -1,
+    0, 8, -1,
+    0, 8, -1,
+    5, -1, 1, 120, 2, 127, 3, 134, -1,
+
+};
+
+
+/* PL_op_private_bitdef_ix[]: map an op number to a starting position
+ * in PL_op_private_bitdefs.  If -1, the op has no bits defined */
+
+EXTCONST I16  PL_op_private_bitdef_ix[] = {
+      -1, /* null */
+      -1, /* stub */
+       0, /* scalar */
+       1, /* pushmark */
+       3, /* wantarray */
+       4, /* const */
+       9, /* gvsv */
+      11, /* gv */
+      12, /* gelem */
+      13, /* padsv */
+      16, /* padav */
+      20, /* padhv */
+      -1, /* padany */
+      26, /* pushre */
+      27, /* rv2gv */
+      34, /* rv2sv */
+      39, /* av2arylen */
+      41, /* rv2cv */
+      -1, /* anoncode */
+      48, /* prototype */
+      49, /* refgen */
+      50, /* srefgen */
+      51, /* ref */
+      52, /* bless */
+      53, /* backtick */
+      58, /* glob */
+      59, /* readline */
+      -1, /* rcatline */
+      60, /* regcmaybe */
+      61, /* regcreset */
+      62, /* regcomp */
+      63, /* match */
+      65, /* qr */
+      66, /* subst */
+      68, /* substcont */
+      70, /* trans */
+      78, /* transr */
+      86, /* sassign */
+      89, /* aassign */
+      92, /* chop */
+      93, /* schop */
+      94, /* chomp */
+      96, /* schomp */
+      98, /* defined */
+      99, /* undef */
+     100, /* study */
+     101, /* pos */
+     104, /* preinc */
+     105, /* i_preinc */
+     106, /* predec */
+     107, /* i_predec */
+     108, /* postinc */
+     109, /* i_postinc */
+     111, /* postdec */
+     112, /* i_postdec */
+     114, /* pow */
+     116, /* multiply */
+     118, /* i_multiply */
+     120, /* divide */
+     122, /* i_divide */
+     124, /* modulo */
+     126, /* i_modulo */
+     128, /* repeat */
+     130, /* add */
+     132, /* i_add */
+     134, /* subtract */
+     136, /* i_subtract */
+     138, /* concat */
+     140, /* stringify */
+     142, /* left_shift */
+     144, /* right_shift */
+     146, /* lt */
+     147, /* i_lt */
+     148, /* gt */
+     149, /* i_gt */
+     150, /* le */
+     151, /* i_le */
+     152, /* ge */
+     153, /* i_ge */
+     154, /* eq */
+     155, /* i_eq */
+     156, /* ne */
+     157, /* i_ne */
+     158, /* ncmp */
+     159, /* i_ncmp */
+     160, /* slt */
+     161, /* sgt */
+     162, /* sle */
+     163, /* sge */
+     164, /* seq */
+     165, /* sne */
+     166, /* scmp */
+     167, /* bit_and */
+     168, /* bit_xor */
+     169, /* bit_or */
+     170, /* negate */
+     171, /* i_negate */
+     173, /* not */
+     174, /* complement */
+     175, /* smartmatch */
+     176, /* atan2 */
+     178, /* sin */
+     180, /* cos */
+     182, /* rand */
+     184, /* srand */
+     186, /* exp */
+     188, /* log */
+     190, /* sqrt */
+     192, /* int */
+     194, /* hex */
+     196, /* oct */
+     198, /* abs */
+     200, /* length */
+     202, /* substr */
+     206, /* vec */
+     209, /* index */
+     211, /* rindex */
+     213, /* sprintf */
+     214, /* formline */
+     215, /* ord */
+     217, /* chr */
+     219, /* crypt */
+     221, /* ucfirst */
+     222, /* lcfirst */
+     223, /* uc */
+     224, /* lc */
+     225, /* quotemeta */
+     226, /* rv2av */
+     232, /* aelemfast */
+     233, /* aelemfast_lex */
+     234, /* aelem */
+     239, /* aslice */
+     242, /* kvaslice */
+     243, /* aeach */
+     244, /* akeys */
+     245, /* avalues */
+     246, /* each */
+     247, /* values */
+     248, /* keys */
+     250, /* delete */
+     253, /* exists */
+     255, /* rv2hv */
+     263, /* helem */
+     268, /* hslice */
+     271, /* kvhslice */
+     272, /* unpack */
+     273, /* pack */
+     274, /* split */
+     275, /* join */
+     276, /* list */
+     278, /* lslice */
+     279, /* anonlist */
+     280, /* anonhash */
+     281, /* splice */
+     282, /* push */
+     284, /* pop */
+     285, /* shift */
+     286, /* unshift */
+     288, /* sort */
+     295, /* reverse */
+     297, /* grepstart */
+     298, /* grepwhile */
+     300, /* mapstart */
+     301, /* mapwhile */
+     303, /* range */
+     304, /* flip */
+     306, /* flop */
+     308, /* and */
+     309, /* or */
+     310, /* xor */
+     311, /* dor */
+     312, /* cond_expr */
+     314, /* andassign */
+     315, /* orassign */
+     316, /* dorassign */
+     317, /* method */
+     318, /* entersub */
+     325, /* leavesub */
+     327, /* leavesublv */
+     329, /* caller */
+     331, /* warn */
+     332, /* die */
+     333, /* reset */
+      -1, /* lineseq */
+     334, /* nextstate */
+     337, /* dbstate */
+      -1, /* unstack */
+      -1, /* enter */
+     340, /* leave */
+      -1, /* scope */
+     342, /* enteriter */
+     346, /* iter */
+      -1, /* enterloop */
+     347, /* leaveloop */
+      -1, /* return */
+     349, /* last */
+     351, /* next */
+     353, /* redo */
+     355, /* dump */
+     357, /* goto */
+     359, /* exit */
+      -1, /* method_named */
+     360, /* entergiven */
+     361, /* leavegiven */
+     362, /* enterwhen */
+     363, /* leavewhen */
+      -1, /* break */
+      -1, /* continue */
+     364, /* open */
+     369, /* close */
+     370, /* pipe_op */
+     371, /* fileno */
+     372, /* umask */
+     373, /* binmode */
+     374, /* tie */
+     375, /* untie */
+     376, /* tied */
+     377, /* dbmopen */
+     378, /* dbmclose */
+     379, /* sselect */
+     380, /* select */
+     381, /* getc */
+     382, /* read */
+     383, /* enterwrite */
+     384, /* leavewrite */
+      -1, /* prtf */
+      -1, /* print */
+      -1, /* say */
+     386, /* sysopen */
+     387, /* sysseek */
+     388, /* sysread */
+     389, /* syswrite */
+     390, /* eof */
+     391, /* tell */
+     392, /* seek */
+     393, /* truncate */
+     394, /* fcntl */
+     395, /* ioctl */
+     396, /* flock */
+     398, /* send */
+     399, /* recv */
+     400, /* socket */
+     401, /* sockpair */
+     402, /* bind */
+     403, /* connect */
+     404, /* listen */
+     405, /* accept */
+     406, /* shutdown */
+     407, /* gsockopt */
+     408, /* ssockopt */
+     409, /* getsockname */
+     410, /* getpeername */
+     411, /* lstat */
+     412, /* stat */
+     413, /* ftrread */
+     418, /* ftrwrite */
+     423, /* ftrexec */
+     428, /* fteread */
+     433, /* ftewrite */
+     438, /* fteexec */
+     443, /* ftis */
+     447, /* ftsize */
+     451, /* ftmtime */
+     455, /* ftatime */
+     459, /* ftctime */
+     463, /* ftrowned */
+     467, /* fteowned */
+     471, /* ftzero */
+     475, /* ftsock */
+     479, /* ftchr */
+     483, /* ftblk */
+     487, /* ftfile */
+     491, /* ftdir */
+     495, /* ftpipe */
+     499, /* ftsuid */
+     503, /* ftsgid */
+     507, /* ftsvtx */
+     511, /* ftlink */
+     515, /* fttty */
+     519, /* fttext */
+     523, /* ftbinary */
+     527, /* chdir */
+     529, /* chown */
+     531, /* chroot */
+     533, /* unlink */
+     535, /* chmod */
+     537, /* utime */
+     539, /* rename */
+     541, /* link */
+     543, /* symlink */
+     545, /* readlink */
+     546, /* mkdir */
+     548, /* rmdir */
+     550, /* open_dir */
+     551, /* readdir */
+     552, /* telldir */
+     553, /* seekdir */
+     554, /* rewinddir */
+     555, /* closedir */
+      -1, /* fork */
+     556, /* wait */
+     557, /* waitpid */
+     559, /* system */
+     561, /* exec */
+     563, /* kill */
+     565, /* getppid */
+     566, /* getpgrp */
+     568, /* setpgrp */
+     570, /* getpriority */
+     572, /* setpriority */
+     574, /* time */
+      -1, /* tms */
+     575, /* localtime */
+     576, /* gmtime */
+     577, /* alarm */
+     578, /* sleep */
+     580, /* shmget */
+     581, /* shmctl */
+     582, /* shmread */
+     583, /* shmwrite */
+     584, /* msgget */
+     585, /* msgctl */
+     586, /* msgsnd */
+     587, /* msgrcv */
+     588, /* semop */
+     589, /* semget */
+     590, /* semctl */
+     591, /* require */
+     592, /* dofile */
+      -1, /* hintseval */
+     593, /* entereval */
+     599, /* leaveeval */
+     601, /* entertry */
+      -1, /* leavetry */
+     602, /* ghbyname */
+     603, /* ghbyaddr */
+      -1, /* ghostent */
+     604, /* gnbyname */
+     605, /* gnbyaddr */
+      -1, /* gnetent */
+     606, /* gpbyname */
+     607, /* gpbynumber */
+      -1, /* gprotoent */
+     608, /* gsbyname */
+     609, /* gsbyport */
+      -1, /* gservent */
+     610, /* shostent */
+     611, /* snetent */
+     612, /* sprotoent */
+     613, /* sservent */
+      -1, /* ehostent */
+      -1, /* enetent */
+      -1, /* eprotoent */
+      -1, /* eservent */
+     614, /* gpwnam */
+     615, /* gpwuid */
+      -1, /* gpwent */
+      -1, /* spwent */
+      -1, /* epwent */
+     616, /* ggrnam */
+     617, /* ggrgid */
+      -1, /* ggrent */
+      -1, /* sgrent */
+      -1, /* egrent */
+      -1, /* getlogin */
+     618, /* syscall */
+     619, /* lock */
+     620, /* once */
+      -1, /* custom */
+     621, /* reach */
+     622, /* rkeys */
+     624, /* rvalues */
+     625, /* coreargs */
+     629, /* runcv */
+     630, /* fc */
+      -1, /* padcv */
+      -1, /* introcv */
+      -1, /* clonecv */
+     631, /* padrange */
+
+};
+
+
+
+/* PL_op_private_bitdefs[]: given a starting position in this array (as
+ * supplied by PL_op_private_bitdef_ix[]), each word (until a stop bit is
+ * seen) defines the meaning of a particular op_private bit for a
+ * particular op. Each word consists of:
+ *  bit  0:     stop bit: this is the last bit def for the current op
+ *  bit  1:     bitfield: if set, this defines a bit field rather than a flag
+ *  bits 2..4:  unsigned number in the range 0..7 which is the bit number
+ *  bits 5..15: unsigned number in the range 0..2047 which is an index
+ *              into PL_op_private_labels[]    (for a flag), or
+ *              into PL_op_private_bitfields[] (for a bit field)
+ */
+
+EXTCONST U16  PL_op_private_bitdefs[] = {
+    /* scalar        */ 0x0003,
+    /* pushmark      */ 0x253c, 0x3631,
+    /* wantarray     */ 0x00bd,
+    /* const         */ 0x0358, 0x12b0, 0x36ec, 0x31a8, 0x2905,
+    /* gvsv          */ 0x253c, 0x2a51,
+    /* gv            */ 0x11b5,
+    /* gelem         */ 0x0067,
+    /* padsv         */ 0x253c, 0x025a, 0x3631,
+    /* padav         */ 0x253c, 0x3630, 0x262c, 0x3329,
+    /* padhv         */ 0x253c, 0x0578, 0x04d4, 0x3630, 0x262c, 0x3329,
+    /* pushre        */ 0x30f9,
+    /* rv2gv         */ 0x253c, 0x025a, 0x13b0, 0x262c, 0x2828, 0x0104, 0x0003,
+    /* rv2sv         */ 0x253c, 0x025a, 0x2a50, 0x0104, 0x0003,
+    /* av2arylen     */ 0x262c, 0x0003,
+    /* rv2cv         */ 0x279c, 0x0898, 0x0ad0, 0x028c, 0x3848, 0x0104, 0x0003,
+    /* prototype     */ 0x0003,
+    /* refgen        */ 0x0003,
+    /* srefgen       */ 0x0003,
+    /* ref           */ 0x0003,
+    /* bless         */ 0x012f,
+    /* backtick      */ 0x2c3c, 0x2b58, 0x20b4, 0x1ff0, 0x0003,
+    /* glob          */ 0x012f,
+    /* readline      */ 0x0003,
+    /* regcmaybe     */ 0x0003,
+    /* regcreset     */ 0x0003,
+    /* regcomp       */ 0x0003,
+    /* match         */ 0x30f8, 0x38f1,
+    /* qr            */ 0x30f9,
+    /* subst         */ 0x30f8, 0x38f1,
+    /* substcont     */ 0x30f8, 0x0003,
+    /* trans         */ 0x0b5c, 0x1a38, 0x07d4, 0x38f0, 0x346c, 0x1d68, 0x01e4, 0x0141,
+    /* transr        */ 0x0b5c, 0x1a38, 0x07d4, 0x38f0, 0x346c, 0x1d68, 0x01e4, 0x0141,
+    /* sassign       */ 0x0a1c, 0x03f8, 0x0067,
+    /* aassign       */ 0x06f8, 0x262c, 0x0067,
+    /* chop          */ 0x0003,
+    /* schop         */ 0x0003,
+    /* chomp         */ 0x38f0, 0x0003,
+    /* schomp        */ 0x38f0, 0x0003,
+    /* defined       */ 0x0003,
+    /* undef         */ 0x0003,
+    /* study         */ 0x0003,
+    /* pos           */ 0x253c, 0x262c, 0x0003,
+    /* preinc        */ 0x0003,
+    /* i_preinc      */ 0x0003,
+    /* predec        */ 0x0003,
+    /* i_predec      */ 0x0003,
+    /* postinc       */ 0x0003,
+    /* i_postinc     */ 0x38f0, 0x0003,
+    /* postdec       */ 0x0003,
+    /* i_postdec     */ 0x38f0, 0x0003,
+    /* pow           */ 0x38f0, 0x0067,
+    /* multiply      */ 0x38f0, 0x0067,
+    /* i_multiply    */ 0x38f0, 0x0067,
+    /* divide        */ 0x38f0, 0x0067,
+    /* i_divide      */ 0x38f0, 0x0067,
+    /* modulo        */ 0x38f0, 0x0067,
+    /* i_modulo      */ 0x38f0, 0x0067,
+    /* repeat        */ 0x0e38, 0x0067,
+    /* add           */ 0x38f0, 0x0067,
+    /* i_add         */ 0x38f0, 0x0067,
+    /* subtract      */ 0x38f0, 0x0067,
+    /* i_subtract    */ 0x38f0, 0x0067,
+    /* concat        */ 0x38f0, 0x0067,
+    /* stringify     */ 0x38f0, 0x012f,
+    /* left_shift    */ 0x38f0, 0x0067,
+    /* right_shift   */ 0x38f0, 0x0067,
+    /* lt            */ 0x0067,
+    /* i_lt          */ 0x0067,
+    /* gt            */ 0x0067,
+    /* i_gt          */ 0x0067,
+    /* le            */ 0x0067,
+    /* i_le          */ 0x0067,
+    /* ge            */ 0x0067,
+    /* i_ge          */ 0x0067,
+    /* eq            */ 0x0067,
+    /* i_eq          */ 0x0067,
+    /* ne            */ 0x0067,
+    /* i_ne          */ 0x0067,
+    /* ncmp          */ 0x0067,
+    /* i_ncmp        */ 0x0067,
+    /* slt           */ 0x0067,
+    /* sgt           */ 0x0067,
+    /* sle           */ 0x0067,
+    /* sge           */ 0x0067,
+    /* seq           */ 0x0067,
+    /* sne           */ 0x0067,
+    /* scmp          */ 0x0067,
+    /* bit_and       */ 0x0067,
+    /* bit_xor       */ 0x0067,
+    /* bit_or        */ 0x0067,
+    /* negate        */ 0x0003,
+    /* i_negate      */ 0x38f0, 0x0003,
+    /* not           */ 0x0003,
+    /* complement    */ 0x0003,
+    /* smartmatch    */ 0x0067,
+    /* atan2         */ 0x38f0, 0x012f,
+    /* sin           */ 0x38f0, 0x0003,
+    /* cos           */ 0x38f0, 0x0003,
+    /* rand          */ 0x38f0, 0x012f,
+    /* srand         */ 0x38f0, 0x012f,
+    /* exp           */ 0x38f0, 0x0003,
+    /* log           */ 0x38f0, 0x0003,
+    /* sqrt          */ 0x38f0, 0x0003,
+    /* int           */ 0x38f0, 0x0003,
+    /* hex           */ 0x38f0, 0x0003,
+    /* oct           */ 0x38f0, 0x0003,
+    /* abs           */ 0x38f0, 0x0003,
+    /* length        */ 0x38f0, 0x0003,
+    /* substr        */ 0x253c, 0x2e50, 0x262c, 0x00cb,
+    /* vec           */ 0x253c, 0x262c, 0x0067,
+    /* index         */ 0x38f0, 0x012f,
+    /* rindex        */ 0x38f0, 0x012f,
+    /* sprintf       */ 0x012f,
+    /* formline      */ 0x012f,
+    /* ord           */ 0x38f0, 0x0003,
+    /* chr           */ 0x38f0, 0x0003,
+    /* crypt         */ 0x38f0, 0x012f,
+    /* ucfirst       */ 0x0003,
+    /* lcfirst       */ 0x0003,
+    /* uc            */ 0x0003,
+    /* lc            */ 0x0003,
+    /* quotemeta     */ 0x0003,
+    /* rv2av         */ 0x253c, 0x2a50, 0x262c, 0x3328, 0x0104, 0x0003,
+    /* aelemfast     */ 0x01ff,
+    /* aelemfast_lex */ 0x01ff,
+    /* aelem         */ 0x253c, 0x025a, 0x2430, 0x262c, 0x0067,
+    /* aslice        */ 0x253c, 0x262c, 0x3329,
+    /* kvaslice      */ 0x262d,
+    /* aeach         */ 0x0003,
+    /* akeys         */ 0x0003,
+    /* avalues       */ 0x0003,
+    /* each          */ 0x0003,
+    /* values        */ 0x0003,
+    /* keys          */ 0x262c, 0x0003,
+    /* delete        */ 0x253c, 0x3278, 0x0003,
+    /* exists        */ 0x37d8, 0x0003,
+    /* rv2hv         */ 0x253c, 0x0578, 0x04d4, 0x2a50, 0x262c, 0x3328, 0x0104, 0x0003,
+    /* helem         */ 0x253c, 0x025a, 0x2430, 0x262c, 0x0067,
+    /* hslice        */ 0x253c, 0x262c, 0x3329,
+    /* kvhslice      */ 0x262d,
+    /* unpack        */ 0x012f,
+    /* pack          */ 0x012f,
+    /* split         */ 0x1e3d,
+    /* join          */ 0x012f,
+    /* list          */ 0x253c, 0x1af9,
+    /* lslice        */ 0x0067,
+    /* anonlist      */ 0x012f,
+    /* anonhash      */ 0x012f,
+    /* splice        */ 0x012f,
+    /* push          */ 0x38f0, 0x012f,
+    /* pop           */ 0x0003,
+    /* shift         */ 0x0003,
+    /* unshift       */ 0x38f0, 0x012f,
+    /* sort          */ 0x3558, 0x2cf4, 0x0d90, 0x214c, 0x2f48, 0x2244, 0x29c1,
+    /* reverse       */ 0x214c, 0x0003,
+    /* grepstart     */ 0x1925,
+    /* grepwhile     */ 0x1924, 0x0003,
+    /* mapstart      */ 0x1925,
+    /* mapwhile      */ 0x1924, 0x0003,
+    /* range         */ 0x0003,
+    /* flip          */ 0x22d8, 0x0003,
+    /* flop          */ 0x22d8, 0x0003,
+    /* and           */ 0x0003,
+    /* or            */ 0x0003,
+    /* xor           */ 0x0067,
+    /* dor           */ 0x0003,
+    /* cond_expr     */ 0x253c, 0x0003,
+    /* andassign     */ 0x0003,
+    /* orassign      */ 0x0003,
+    /* dorassign     */ 0x0003,
+    /* method        */ 0x0003,
+    /* entersub      */ 0x253c, 0x025a, 0x0ad0, 0x028c, 0x3848, 0x0104, 0x1f01,
+    /* leavesub      */ 0x2db8, 0x0003,
+    /* leavesublv    */ 0x2db8, 0x0003,
+    /* caller        */ 0x00bc, 0x012f,
+    /* warn          */ 0x012f,
+    /* die           */ 0x012f,
+    /* reset         */ 0x012f,
+    /* nextstate     */ 0x3c9c, 0x3ad8, 0x1cd5,
+    /* dbstate       */ 0x3c9c, 0x3ad8, 0x1cd5,
+    /* leave         */ 0x23dc, 0x2db9,
+    /* enteriter     */ 0x253c, 0x2a50, 0x010c, 0x2fc9,
+    /* iter          */ 0x2fc9,
+    /* leaveloop     */ 0x23dc, 0x0067,
+    /* last          */ 0x3a5c, 0x0003,
+    /* next          */ 0x3a5c, 0x0003,
+    /* redo          */ 0x3a5c, 0x0003,
+    /* dump          */ 0x3a5c, 0x0003,
+    /* goto          */ 0x3a5c, 0x0003,
+    /* exit          */ 0x012f,
+    /* entergiven    */ 0x0003,
+    /* leavegiven    */ 0x0003,
+    /* enterwhen     */ 0x0003,
+    /* leavewhen     */ 0x0003,
+    /* open          */ 0x2c3c, 0x2b58, 0x20b4, 0x1ff0, 0x012f,
+    /* close         */ 0x012f,
+    /* pipe_op       */ 0x012f,
+    /* fileno        */ 0x012f,
+    /* umask         */ 0x012f,
+    /* binmode       */ 0x012f,
+    /* tie           */ 0x012f,
+    /* untie         */ 0x0003,
+    /* tied          */ 0x0003,
+    /* dbmopen       */ 0x012f,
+    /* dbmclose      */ 0x0003,
+    /* sselect       */ 0x012f,
+    /* select        */ 0x012f,
+    /* getc          */ 0x012f,
+    /* read          */ 0x012f,
+    /* enterwrite    */ 0x012f,
+    /* leavewrite    */ 0x2db8, 0x0003,
+    /* sysopen       */ 0x012f,
+    /* sysseek       */ 0x012f,
+    /* sysread       */ 0x012f,
+    /* syswrite      */ 0x012f,
+    /* eof           */ 0x012f,
+    /* tell          */ 0x012f,
+    /* seek          */ 0x012f,
+    /* truncate      */ 0x012f,
+    /* fcntl         */ 0x012f,
+    /* ioctl         */ 0x012f,
+    /* flock         */ 0x38f0, 0x012f,
+    /* send          */ 0x012f,
+    /* recv          */ 0x012f,
+    /* socket        */ 0x012f,
+    /* sockpair      */ 0x012f,
+    /* bind          */ 0x012f,
+    /* connect       */ 0x012f,
+    /* listen        */ 0x012f,
+    /* accept        */ 0x012f,
+    /* shutdown      */ 0x012f,
+    /* gsockopt      */ 0x012f,
+    /* ssockopt      */ 0x012f,
+    /* getsockname   */ 0x0003,
+    /* getpeername   */ 0x0003,
+    /* lstat         */ 0x0003,
+    /* stat          */ 0x0003,
+    /* ftrread       */ 0x1570, 0x17cc, 0x1688, 0x1444, 0x0003,
+    /* ftrwrite      */ 0x1570, 0x17cc, 0x1688, 0x1444, 0x0003,
+    /* ftrexec       */ 0x1570, 0x17cc, 0x1688, 0x1444, 0x0003,
+    /* fteread       */ 0x1570, 0x17cc, 0x1688, 0x1444, 0x0003,
+    /* ftewrite      */ 0x1570, 0x17cc, 0x1688, 0x1444, 0x0003,
+    /* fteexec       */ 0x1570, 0x17cc, 0x1688, 0x1444, 0x0003,
+    /* ftis          */ 0x1570, 0x17cc, 0x1688, 0x0003,
+    /* ftsize        */ 0x1570, 0x17cc, 0x1688, 0x0003,
+    /* ftmtime       */ 0x1570, 0x17cc, 0x1688, 0x0003,
+    /* ftatime       */ 0x1570, 0x17cc, 0x1688, 0x0003,
+    /* ftctime       */ 0x1570, 0x17cc, 0x1688, 0x0003,
+    /* ftrowned      */ 0x1570, 0x17cc, 0x1688, 0x0003,
+    /* fteowned      */ 0x1570, 0x17cc, 0x1688, 0x0003,
+    /* ftzero        */ 0x1570, 0x17cc, 0x1688, 0x0003,
+    /* ftsock        */ 0x1570, 0x17cc, 0x1688, 0x0003,
+    /* ftchr         */ 0x1570, 0x17cc, 0x1688, 0x0003,
+    /* ftblk         */ 0x1570, 0x17cc, 0x1688, 0x0003,
+    /* ftfile        */ 0x1570, 0x17cc, 0x1688, 0x0003,
+    /* ftdir         */ 0x1570, 0x17cc, 0x1688, 0x0003,
+    /* ftpipe        */ 0x1570, 0x17cc, 0x1688, 0x0003,
+    /* ftsuid        */ 0x1570, 0x17cc, 0x1688, 0x0003,
+    /* ftsgid        */ 0x1570, 0x17cc, 0x1688, 0x0003,
+    /* ftsvtx        */ 0x1570, 0x17cc, 0x1688, 0x0003,
+    /* ftlink        */ 0x1570, 0x17cc, 0x1688, 0x0003,
+    /* fttty         */ 0x1570, 0x17cc, 0x1688, 0x0003,
+    /* fttext        */ 0x1570, 0x17cc, 0x1688, 0x0003,
+    /* ftbinary      */ 0x1570, 0x17cc, 0x1688, 0x0003,
+    /* chdir         */ 0x38f0, 0x012f,
+    /* chown         */ 0x38f0, 0x012f,
+    /* chroot        */ 0x38f0, 0x0003,
+    /* unlink        */ 0x38f0, 0x012f,
+    /* chmod         */ 0x38f0, 0x012f,
+    /* utime         */ 0x38f0, 0x012f,
+    /* rename        */ 0x38f0, 0x012f,
+    /* link          */ 0x38f0, 0x012f,
+    /* symlink       */ 0x38f0, 0x012f,
+    /* readlink      */ 0x0003,
+    /* mkdir         */ 0x38f0, 0x012f,
+    /* rmdir         */ 0x38f0, 0x0003,
+    /* open_dir      */ 0x012f,
+    /* readdir       */ 0x0003,
+    /* telldir       */ 0x0003,
+    /* seekdir       */ 0x012f,
+    /* rewinddir     */ 0x0003,
+    /* closedir      */ 0x0003,
+    /* wait          */ 0x38f1,
+    /* waitpid       */ 0x38f0, 0x012f,
+    /* system        */ 0x38f0, 0x012f,
+    /* exec          */ 0x38f0, 0x012f,
+    /* kill          */ 0x38f0, 0x012f,
+    /* getppid       */ 0x38f1,
+    /* getpgrp       */ 0x38f0, 0x012f,
+    /* setpgrp       */ 0x38f0, 0x012f,
+    /* getpriority   */ 0x38f0, 0x012f,
+    /* setpriority   */ 0x38f0, 0x012f,
+    /* time          */ 0x38f1,
+    /* localtime     */ 0x0003,
+    /* gmtime        */ 0x012f,
+    /* alarm         */ 0x0003,
+    /* sleep         */ 0x38f0, 0x012f,
+    /* shmget        */ 0x012f,
+    /* shmctl        */ 0x012f,
+    /* shmread       */ 0x012f,
+    /* shmwrite      */ 0x012f,
+    /* msgget        */ 0x012f,
+    /* msgctl        */ 0x012f,
+    /* msgsnd        */ 0x012f,
+    /* msgrcv        */ 0x012f,
+    /* semop         */ 0x012f,
+    /* semget        */ 0x012f,
+    /* semctl        */ 0x012f,
+    /* require       */ 0x0003,
+    /* dofile        */ 0x0003,
+    /* entereval     */ 0x0114, 0x0950, 0x062c, 0x39c8, 0x1be4, 0x0003,
+    /* leaveeval     */ 0x2db8, 0x0003,
+    /* entertry      */ 0x0003,
+    /* ghbyname      */ 0x0003,
+    /* ghbyaddr      */ 0x012f,
+    /* gnbyname      */ 0x0003,
+    /* gnbyaddr      */ 0x012f,
+    /* gpbyname      */ 0x0003,
+    /* gpbynumber    */ 0x012f,
+    /* gsbyname      */ 0x012f,
+    /* gsbyport      */ 0x012f,
+    /* shostent      */ 0x0003,
+    /* snetent       */ 0x0003,
+    /* sprotoent     */ 0x0003,
+    /* sservent      */ 0x0003,
+    /* gpwnam        */ 0x0003,
+    /* gpwuid        */ 0x0003,
+    /* ggrnam        */ 0x0003,
+    /* ggrgid        */ 0x0003,
+    /* syscall       */ 0x012f,
+    /* lock          */ 0x0003,
+    /* once          */ 0x0003,
+    /* reach         */ 0x0003,
+    /* rkeys         */ 0x262c, 0x0003,
+    /* rvalues       */ 0x0003,
+    /* coreargs      */ 0x26fc, 0x0018, 0x0ca4, 0x0bc1,
+    /* runcv         */ 0x00bd,
+    /* fc            */ 0x0003,
+    /* padrange      */ 0x253c, 0x019b,
+
+};
+
+
+/* PL_op_private_valid: for each op, indexed by op_type, indicate which
+ * flags bits in op_private are legal */
+
+EXTCONST U8 PL_op_private_valid[] = {
+    /* NULL       */ (0xff),
+    /* STUB       */ (0),
+    /* SCALAR     */ (OPpARG1_MASK),
+    /* PUSHMARK   */ (OPpPAD_STATE|OPpLVAL_INTRO),
+    /* WANTARRAY  */ (OPpOFFBYONE),
+    /* CONST      */ (OPpCONST_NOVER|OPpCONST_SHORTCIRCUIT|OPpCONST_STRICT|OPpCONST_ENTERED|OPpCONST_BARE),
+    /* GVSV       */ (OPpOUR_INTRO|OPpLVAL_INTRO),
+    /* GV         */ (OPpEARLY_CV),
+    /* GELEM      */ (OPpARG2_MASK),
+    /* PADSV      */ (OPpPAD_STATE|OPpDEREF|OPpLVAL_INTRO),
+    /* PADAV      */ (OPpSLICEWARNING|OPpMAYBE_LVSUB|OPpPAD_STATE|OPpLVAL_INTRO),
+    /* PADHV      */ (OPpSLICEWARNING|OPpMAYBE_LVSUB|OPpPAD_STATE|OPpTRUEBOOL|OPpMAYBE_TRUEBOOL|OPpLVAL_INTRO),
+    /* PADANY     */ (0),
+    /* PUSHRE     */ (OPpRUNTIME),
+    /* RV2GV      */ (OPpARG1_MASK|OPpHINT_STRICT_REFS|OPpDONT_INIT_GV|OPpMAYBE_LVSUB|OPpALLOW_FAKE|OPpDEREF|OPpLVAL_INTRO),
+    /* RV2SV      */ (OPpARG1_MASK|OPpHINT_STRICT_REFS|OPpOUR_INTRO|OPpDEREF|OPpLVAL_INTRO),
+    /* AV2ARYLEN  */ (OPpARG1_MASK|OPpMAYBE_LVSUB),
+    /* RV2CV      */ (OPpARG1_MASK|OPpHINT_STRICT_REFS|OPpENTERSUB_HASTARG|OPpENTERSUB_AMPER|OPpENTERSUB_DB|OPpMAY_RETURN_CONSTANT|OPpENTERSUB_NOPAREN),
+    /* ANONCODE   */ (0),
+    /* PROTOTYPE  */ (OPpARG1_MASK),
+    /* REFGEN     */ (OPpARG1_MASK),
+    /* SREFGEN    */ (OPpARG1_MASK),
+    /* REF        */ (OPpARG1_MASK),
+    /* BLESS      */ (OPpARG4_MASK),
+    /* BACKTICK   */ (OPpARG1_MASK|OPpOPEN_IN_RAW|OPpOPEN_IN_CRLF|OPpOPEN_OUT_RAW|OPpOPEN_OUT_CRLF),
+    /* GLOB       */ (OPpARG4_MASK),
+    /* READLINE   */ (OPpARG1_MASK),
+    /* RCATLINE   */ (0),
+    /* REGCMAYBE  */ (OPpARG1_MASK),
+    /* REGCRESET  */ (OPpARG1_MASK),
+    /* REGCOMP    */ (OPpARG1_MASK),
+    /* MATCH      */ (OPpTARGET_MY|OPpRUNTIME),
+    /* QR         */ (OPpRUNTIME),
+    /* SUBST      */ (OPpTARGET_MY|OPpRUNTIME),
+    /* SUBSTCONT  */ (OPpARG1_MASK|OPpRUNTIME),
+    /* TRANS      */ (OPpTRANS_FROM_UTF|OPpTRANS_TO_UTF|OPpTRANS_IDENTICAL|OPpTRANS_SQUASH|OPpTARGET_MY|OPpTRANS_COMPLEMENT|OPpTRANS_GROWS|OPpTRANS_DELETE),
+    /* TRANSR     */ (OPpTRANS_FROM_UTF|OPpTRANS_TO_UTF|OPpTRANS_IDENTICAL|OPpTRANS_SQUASH|OPpTARGET_MY|OPpTRANS_COMPLEMENT|OPpTRANS_GROWS|OPpTRANS_DELETE),
+    /* SASSIGN    */ (OPpARG2_MASK|OPpASSIGN_BACKWARDS|OPpASSIGN_CV_TO_GV),
+    /* AASSIGN    */ (OPpARG2_MASK|OPpMAYBE_LVSUB|OPpASSIGN_COMMON),
+    /* CHOP       */ (OPpARG1_MASK),
+    /* SCHOP      */ (OPpARG1_MASK),
+    /* CHOMP      */ (OPpARG1_MASK|OPpTARGET_MY),
+    /* SCHOMP     */ (OPpARG1_MASK|OPpTARGET_MY),
+    /* DEFINED    */ (OPpARG1_MASK),
+    /* UNDEF      */ (OPpARG1_MASK),
+    /* STUDY      */ (OPpARG1_MASK),
+    /* POS        */ (OPpARG1_MASK|OPpMAYBE_LVSUB|OPpLVAL_INTRO),
+    /* PREINC     */ (OPpARG1_MASK),
+    /* I_PREINC   */ (OPpARG1_MASK),
+    /* PREDEC     */ (OPpARG1_MASK),
+    /* I_PREDEC   */ (OPpARG1_MASK),
+    /* POSTINC    */ (OPpARG1_MASK),
+    /* I_POSTINC  */ (OPpARG1_MASK|OPpTARGET_MY),
+    /* POSTDEC    */ (OPpARG1_MASK),
+    /* I_POSTDEC  */ (OPpARG1_MASK|OPpTARGET_MY),
+    /* POW        */ (OPpARG2_MASK|OPpTARGET_MY),
+    /* MULTIPLY   */ (OPpARG2_MASK|OPpTARGET_MY),
+    /* I_MULTIPLY */ (OPpARG2_MASK|OPpTARGET_MY),
+    /* DIVIDE     */ (OPpARG2_MASK|OPpTARGET_MY),
+    /* I_DIVIDE   */ (OPpARG2_MASK|OPpTARGET_MY),
+    /* MODULO     */ (OPpARG2_MASK|OPpTARGET_MY),
+    /* I_MODULO   */ (OPpARG2_MASK|OPpTARGET_MY),
+    /* REPEAT     */ (OPpARG2_MASK|OPpREPEAT_DOLIST),
+    /* ADD        */ (OPpARG2_MASK|OPpTARGET_MY),
+    /* I_ADD      */ (OPpARG2_MASK|OPpTARGET_MY),
+    /* SUBTRACT   */ (OPpARG2_MASK|OPpTARGET_MY),
+    /* I_SUBTRACT */ (OPpARG2_MASK|OPpTARGET_MY),
+    /* CONCAT     */ (OPpARG2_MASK|OPpTARGET_MY),
+    /* STRINGIFY  */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* LEFT_SHIFT */ (OPpARG2_MASK|OPpTARGET_MY),
+    /* RIGHT_SHIFT */ (OPpARG2_MASK|OPpTARGET_MY),
+    /* LT         */ (OPpARG2_MASK),
+    /* I_LT       */ (OPpARG2_MASK),
+    /* GT         */ (OPpARG2_MASK),
+    /* I_GT       */ (OPpARG2_MASK),
+    /* LE         */ (OPpARG2_MASK),
+    /* I_LE       */ (OPpARG2_MASK),
+    /* GE         */ (OPpARG2_MASK),
+    /* I_GE       */ (OPpARG2_MASK),
+    /* EQ         */ (OPpARG2_MASK),
+    /* I_EQ       */ (OPpARG2_MASK),
+    /* NE         */ (OPpARG2_MASK),
+    /* I_NE       */ (OPpARG2_MASK),
+    /* NCMP       */ (OPpARG2_MASK),
+    /* I_NCMP     */ (OPpARG2_MASK),
+    /* SLT        */ (OPpARG2_MASK),
+    /* SGT        */ (OPpARG2_MASK),
+    /* SLE        */ (OPpARG2_MASK),
+    /* SGE        */ (OPpARG2_MASK),
+    /* SEQ        */ (OPpARG2_MASK),
+    /* SNE        */ (OPpARG2_MASK),
+    /* SCMP       */ (OPpARG2_MASK),
+    /* BIT_AND    */ (OPpARG2_MASK),
+    /* BIT_XOR    */ (OPpARG2_MASK),
+    /* BIT_OR     */ (OPpARG2_MASK),
+    /* NEGATE     */ (OPpARG1_MASK),
+    /* I_NEGATE   */ (OPpARG1_MASK|OPpTARGET_MY),
+    /* NOT        */ (OPpARG1_MASK),
+    /* COMPLEMENT */ (OPpARG1_MASK),
+    /* SMARTMATCH */ (OPpARG2_MASK),
+    /* ATAN2      */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* SIN        */ (OPpARG1_MASK|OPpTARGET_MY),
+    /* COS        */ (OPpARG1_MASK|OPpTARGET_MY),
+    /* RAND       */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* SRAND      */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* EXP        */ (OPpARG1_MASK|OPpTARGET_MY),
+    /* LOG        */ (OPpARG1_MASK|OPpTARGET_MY),
+    /* SQRT       */ (OPpARG1_MASK|OPpTARGET_MY),
+    /* INT        */ (OPpARG1_MASK|OPpTARGET_MY),
+    /* HEX        */ (OPpARG1_MASK|OPpTARGET_MY),
+    /* OCT        */ (OPpARG1_MASK|OPpTARGET_MY),
+    /* ABS        */ (OPpARG1_MASK|OPpTARGET_MY),
+    /* LENGTH     */ (OPpARG1_MASK|OPpTARGET_MY),
+    /* SUBSTR     */ (OPpARG3_MASK|OPpMAYBE_LVSUB|OPpSUBSTR_REPL_FIRST|OPpLVAL_INTRO),
+    /* VEC        */ (OPpARG2_MASK|OPpMAYBE_LVSUB|OPpLVAL_INTRO),
+    /* INDEX      */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* RINDEX     */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* SPRINTF    */ (OPpARG4_MASK),
+    /* FORMLINE   */ (OPpARG4_MASK),
+    /* ORD        */ (OPpARG1_MASK|OPpTARGET_MY),
+    /* CHR        */ (OPpARG1_MASK|OPpTARGET_MY),
+    /* CRYPT      */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* UCFIRST    */ (OPpARG1_MASK),
+    /* LCFIRST    */ (OPpARG1_MASK),
+    /* UC         */ (OPpARG1_MASK),
+    /* LC         */ (OPpARG1_MASK),
+    /* QUOTEMETA  */ (OPpARG1_MASK),
+    /* RV2AV      */ (OPpARG1_MASK|OPpHINT_STRICT_REFS|OPpSLICEWARNING|OPpMAYBE_LVSUB|OPpOUR_INTRO|OPpLVAL_INTRO),
+    /* AELEMFAST  */ (255),
+    /* AELEMFAST_LEX */ (255),
+    /* AELEM      */ (OPpARG2_MASK|OPpMAYBE_LVSUB|OPpLVAL_DEFER|OPpDEREF|OPpLVAL_INTRO),
+    /* ASLICE     */ (OPpSLICEWARNING|OPpMAYBE_LVSUB|OPpLVAL_INTRO),
+    /* KVASLICE   */ (OPpMAYBE_LVSUB),
+    /* AEACH      */ (OPpARG1_MASK),
+    /* AKEYS      */ (OPpARG1_MASK),
+    /* AVALUES    */ (OPpARG1_MASK),
+    /* EACH       */ (OPpARG1_MASK),
+    /* VALUES     */ (OPpARG1_MASK),
+    /* KEYS       */ (OPpARG1_MASK|OPpMAYBE_LVSUB),
+    /* DELETE     */ (OPpARG1_MASK|OPpSLICE|OPpLVAL_INTRO),
+    /* EXISTS     */ (OPpARG1_MASK|OPpEXISTS_SUB),
+    /* RV2HV      */ (OPpARG1_MASK|OPpHINT_STRICT_REFS|OPpSLICEWARNING|OPpMAYBE_LVSUB|OPpOUR_INTRO|OPpTRUEBOOL|OPpMAYBE_TRUEBOOL|OPpLVAL_INTRO),
+    /* HELEM      */ (OPpARG2_MASK|OPpMAYBE_LVSUB|OPpLVAL_DEFER|OPpDEREF|OPpLVAL_INTRO),
+    /* HSLICE     */ (OPpSLICEWARNING|OPpMAYBE_LVSUB|OPpLVAL_INTRO),
+    /* KVHSLICE   */ (OPpMAYBE_LVSUB),
+    /* UNPACK     */ (OPpARG4_MASK),
+    /* PACK       */ (OPpARG4_MASK),
+    /* SPLIT      */ (OPpSPLIT_IMPLIM),
+    /* JOIN       */ (OPpARG4_MASK),
+    /* LIST       */ (OPpLIST_GUESSED|OPpLVAL_INTRO),
+    /* LSLICE     */ (OPpARG2_MASK),
+    /* ANONLIST   */ (OPpARG4_MASK),
+    /* ANONHASH   */ (OPpARG4_MASK),
+    /* SPLICE     */ (OPpARG4_MASK),
+    /* PUSH       */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* POP        */ (OPpARG1_MASK),
+    /* SHIFT      */ (OPpARG1_MASK),
+    /* UNSHIFT    */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* SORT       */ (OPpSORT_NUMERIC|OPpSORT_INTEGER|OPpSORT_REVERSE|OPpSORT_INPLACE|OPpSORT_DESCEND|OPpSORT_QSORT|OPpSORT_STABLE),
+    /* REVERSE    */ (OPpARG1_MASK|OPpREVERSE_INPLACE),
+    /* GREPSTART  */ (OPpGREP_LEX),
+    /* GREPWHILE  */ (OPpARG1_MASK|OPpGREP_LEX),
+    /* MAPSTART   */ (OPpGREP_LEX),
+    /* MAPWHILE   */ (OPpARG1_MASK|OPpGREP_LEX),
+    /* RANGE      */ (OPpARG1_MASK),
+    /* FLIP       */ (OPpARG1_MASK|OPpFLIP_LINENUM),
+    /* FLOP       */ (OPpARG1_MASK|OPpFLIP_LINENUM),
+    /* AND        */ (OPpARG1_MASK),
+    /* OR         */ (OPpARG1_MASK),
+    /* XOR        */ (OPpARG2_MASK),
+    /* DOR        */ (OPpARG1_MASK),
+    /* COND_EXPR  */ (OPpARG1_MASK|OPpLVAL_INTRO),
+    /* ANDASSIGN  */ (OPpARG1_MASK),
+    /* ORASSIGN   */ (OPpARG1_MASK),
+    /* DORASSIGN  */ (OPpARG1_MASK),
+    /* METHOD     */ (OPpARG1_MASK),
+    /* ENTERSUB   */ (OPpENTERSUB_INARGS|OPpHINT_STRICT_REFS|OPpENTERSUB_HASTARG|OPpENTERSUB_AMPER|OPpENTERSUB_DB|OPpDEREF|OPpLVAL_INTRO),
+    /* LEAVESUB   */ (OPpARG1_MASK|OPpREFCOUNTED),
+    /* LEAVESUBLV */ (OPpARG1_MASK|OPpREFCOUNTED),
+    /* CALLER     */ (OPpARG4_MASK|OPpOFFBYONE),
+    /* WARN       */ (OPpARG4_MASK),
+    /* DIE        */ (OPpARG4_MASK),
+    /* RESET      */ (OPpARG4_MASK),
+    /* LINESEQ    */ (0),
+    /* NEXTSTATE  */ (OPpHUSH_VMSISH|OPpHINT_M_VMSISH_STATUS|OPpHINT_M_VMSISH_TIME),
+    /* DBSTATE    */ (OPpHUSH_VMSISH|OPpHINT_M_VMSISH_STATUS|OPpHINT_M_VMSISH_TIME),
+    /* UNSTACK    */ (0),
+    /* ENTER      */ (0),
+    /* LEAVE      */ (OPpREFCOUNTED|OPpLVALUE),
+    /* SCOPE      */ (0),
+    /* ENTERITER  */ (OPpITER_REVERSED|OPpITER_DEF|OPpOUR_INTRO|OPpLVAL_INTRO),
+    /* ITER       */ (OPpITER_REVERSED),
+    /* ENTERLOOP  */ (0),
+    /* LEAVELOOP  */ (OPpARG2_MASK|OPpLVALUE),
+    /* RETURN     */ (0),
+    /* LAST       */ (OPpARG1_MASK|OPpPV_IS_UTF8),
+    /* NEXT       */ (OPpARG1_MASK|OPpPV_IS_UTF8),
+    /* REDO       */ (OPpARG1_MASK|OPpPV_IS_UTF8),
+    /* DUMP       */ (OPpARG1_MASK|OPpPV_IS_UTF8),
+    /* GOTO       */ (OPpARG1_MASK|OPpPV_IS_UTF8),
+    /* EXIT       */ (OPpARG4_MASK),
+    /* METHOD_NAMED */ (0),
+    /* ENTERGIVEN */ (OPpARG1_MASK),
+    /* LEAVEGIVEN */ (OPpARG1_MASK),
+    /* ENTERWHEN  */ (OPpARG1_MASK),
+    /* LEAVEWHEN  */ (OPpARG1_MASK),
+    /* BREAK      */ (0),
+    /* CONTINUE   */ (0),
+    /* OPEN       */ (OPpARG4_MASK|OPpOPEN_IN_RAW|OPpOPEN_IN_CRLF|OPpOPEN_OUT_RAW|OPpOPEN_OUT_CRLF),
+    /* CLOSE      */ (OPpARG4_MASK),
+    /* PIPE_OP    */ (OPpARG4_MASK),
+    /* FILENO     */ (OPpARG4_MASK),
+    /* UMASK      */ (OPpARG4_MASK),
+    /* BINMODE    */ (OPpARG4_MASK),
+    /* TIE        */ (OPpARG4_MASK),
+    /* UNTIE      */ (OPpARG1_MASK),
+    /* TIED       */ (OPpARG1_MASK),
+    /* DBMOPEN    */ (OPpARG4_MASK),
+    /* DBMCLOSE   */ (OPpARG1_MASK),
+    /* SSELECT    */ (OPpARG4_MASK),
+    /* SELECT     */ (OPpARG4_MASK),
+    /* GETC       */ (OPpARG4_MASK),
+    /* READ       */ (OPpARG4_MASK),
+    /* ENTERWRITE */ (OPpARG4_MASK),
+    /* LEAVEWRITE */ (OPpARG1_MASK|OPpREFCOUNTED),
+    /* PRTF       */ (0),
+    /* PRINT      */ (0),
+    /* SAY        */ (0),
+    /* SYSOPEN    */ (OPpARG4_MASK),
+    /* SYSSEEK    */ (OPpARG4_MASK),
+    /* SYSREAD    */ (OPpARG4_MASK),
+    /* SYSWRITE   */ (OPpARG4_MASK),
+    /* EOF        */ (OPpARG4_MASK),
+    /* TELL       */ (OPpARG4_MASK),
+    /* SEEK       */ (OPpARG4_MASK),
+    /* TRUNCATE   */ (OPpARG4_MASK),
+    /* FCNTL      */ (OPpARG4_MASK),
+    /* IOCTL      */ (OPpARG4_MASK),
+    /* FLOCK      */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* SEND       */ (OPpARG4_MASK),
+    /* RECV       */ (OPpARG4_MASK),
+    /* SOCKET     */ (OPpARG4_MASK),
+    /* SOCKPAIR   */ (OPpARG4_MASK),
+    /* BIND       */ (OPpARG4_MASK),
+    /* CONNECT    */ (OPpARG4_MASK),
+    /* LISTEN     */ (OPpARG4_MASK),
+    /* ACCEPT     */ (OPpARG4_MASK),
+    /* SHUTDOWN   */ (OPpARG4_MASK),
+    /* GSOCKOPT   */ (OPpARG4_MASK),
+    /* SSOCKOPT   */ (OPpARG4_MASK),
+    /* GETSOCKNAME */ (OPpARG1_MASK),
+    /* GETPEERNAME */ (OPpARG1_MASK),
+    /* LSTAT      */ (OPpARG1_MASK),
+    /* STAT       */ (OPpARG1_MASK),
+    /* FTRREAD    */ (OPpARG1_MASK|OPpFT_ACCESS|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTRWRITE   */ (OPpARG1_MASK|OPpFT_ACCESS|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTREXEC    */ (OPpARG1_MASK|OPpFT_ACCESS|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTEREAD    */ (OPpARG1_MASK|OPpFT_ACCESS|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTEWRITE   */ (OPpARG1_MASK|OPpFT_ACCESS|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTEEXEC    */ (OPpARG1_MASK|OPpFT_ACCESS|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTIS       */ (OPpARG1_MASK|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTSIZE     */ (OPpARG1_MASK|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTMTIME    */ (OPpARG1_MASK|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTATIME    */ (OPpARG1_MASK|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTCTIME    */ (OPpARG1_MASK|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTROWNED   */ (OPpARG1_MASK|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTEOWNED   */ (OPpARG1_MASK|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTZERO     */ (OPpARG1_MASK|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTSOCK     */ (OPpARG1_MASK|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTCHR      */ (OPpARG1_MASK|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTBLK      */ (OPpARG1_MASK|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTFILE     */ (OPpARG1_MASK|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTDIR      */ (OPpARG1_MASK|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTPIPE     */ (OPpARG1_MASK|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTSUID     */ (OPpARG1_MASK|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTSGID     */ (OPpARG1_MASK|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTSVTX     */ (OPpARG1_MASK|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTLINK     */ (OPpARG1_MASK|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTTTY      */ (OPpARG1_MASK|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTTEXT     */ (OPpARG1_MASK|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* FTBINARY   */ (OPpARG1_MASK|OPpFT_STACKED|OPpFT_STACKING|OPpFT_AFTER_t),
+    /* CHDIR      */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* CHOWN      */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* CHROOT     */ (OPpARG1_MASK|OPpTARGET_MY),
+    /* UNLINK     */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* CHMOD      */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* UTIME      */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* RENAME     */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* LINK       */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* SYMLINK    */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* READLINK   */ (OPpARG1_MASK),
+    /* MKDIR      */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* RMDIR      */ (OPpARG1_MASK|OPpTARGET_MY),
+    /* OPEN_DIR   */ (OPpARG4_MASK),
+    /* READDIR    */ (OPpARG1_MASK),
+    /* TELLDIR    */ (OPpARG1_MASK),
+    /* SEEKDIR    */ (OPpARG4_MASK),
+    /* REWINDDIR  */ (OPpARG1_MASK),
+    /* CLOSEDIR   */ (OPpARG1_MASK),
+    /* FORK       */ (0),
+    /* WAIT       */ (OPpTARGET_MY),
+    /* WAITPID    */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* SYSTEM     */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* EXEC       */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* KILL       */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* GETPPID    */ (OPpTARGET_MY),
+    /* GETPGRP    */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* SETPGRP    */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* GETPRIORITY */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* SETPRIORITY */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* TIME       */ (OPpTARGET_MY),
+    /* TMS        */ (0),
+    /* LOCALTIME  */ (OPpARG1_MASK),
+    /* GMTIME     */ (OPpARG4_MASK),
+    /* ALARM      */ (OPpARG1_MASK),
+    /* SLEEP      */ (OPpARG4_MASK|OPpTARGET_MY),
+    /* SHMGET     */ (OPpARG4_MASK),
+    /* SHMCTL     */ (OPpARG4_MASK),
+    /* SHMREAD    */ (OPpARG4_MASK),
+    /* SHMWRITE   */ (OPpARG4_MASK),
+    /* MSGGET     */ (OPpARG4_MASK),
+    /* MSGCTL     */ (OPpARG4_MASK),
+    /* MSGSND     */ (OPpARG4_MASK),
+    /* MSGRCV     */ (OPpARG4_MASK),
+    /* SEMOP      */ (OPpARG4_MASK),
+    /* SEMGET     */ (OPpARG4_MASK),
+    /* SEMCTL     */ (OPpARG4_MASK),
+    /* REQUIRE    */ (OPpARG1_MASK),
+    /* DOFILE     */ (OPpARG1_MASK),
+    /* HINTSEVAL  */ (0),
+    /* ENTEREVAL  */ (OPpARG1_MASK|OPpEVAL_HAS_HH|OPpEVAL_UNICODE|OPpEVAL_BYTES|OPpEVAL_COPHH|OPpEVAL_RE_REPARSING),
+    /* LEAVEEVAL  */ (OPpARG1_MASK|OPpREFCOUNTED),
+    /* ENTERTRY   */ (OPpARG1_MASK),
+    /* LEAVETRY   */ (0),
+    /* GHBYNAME   */ (OPpARG1_MASK),
+    /* GHBYADDR   */ (OPpARG4_MASK),
+    /* GHOSTENT   */ (0),
+    /* GNBYNAME   */ (OPpARG1_MASK),
+    /* GNBYADDR   */ (OPpARG4_MASK),
+    /* GNETENT    */ (0),
+    /* GPBYNAME   */ (OPpARG1_MASK),
+    /* GPBYNUMBER */ (OPpARG4_MASK),
+    /* GPROTOENT  */ (0),
+    /* GSBYNAME   */ (OPpARG4_MASK),
+    /* GSBYPORT   */ (OPpARG4_MASK),
+    /* GSERVENT   */ (0),
+    /* SHOSTENT   */ (OPpARG1_MASK),
+    /* SNETENT    */ (OPpARG1_MASK),
+    /* SPROTOENT  */ (OPpARG1_MASK),
+    /* SSERVENT   */ (OPpARG1_MASK),
+    /* EHOSTENT   */ (0),
+    /* ENETENT    */ (0),
+    /* EPROTOENT  */ (0),
+    /* ESERVENT   */ (0),
+    /* GPWNAM     */ (OPpARG1_MASK),
+    /* GPWUID     */ (OPpARG1_MASK),
+    /* GPWENT     */ (0),
+    /* SPWENT     */ (0),
+    /* EPWENT     */ (0),
+    /* GGRNAM     */ (OPpARG1_MASK),
+    /* GGRGID     */ (OPpARG1_MASK),
+    /* GGRENT     */ (0),
+    /* SGRENT     */ (0),
+    /* EGRENT     */ (0),
+    /* GETLOGIN   */ (0),
+    /* SYSCALL    */ (OPpARG4_MASK),
+    /* LOCK       */ (OPpARG1_MASK),
+    /* ONCE       */ (OPpARG1_MASK),
+    /* CUSTOM     */ (0xff),
+    /* REACH      */ (OPpARG1_MASK),
+    /* RKEYS      */ (OPpARG1_MASK|OPpMAYBE_LVSUB),
+    /* RVALUES    */ (OPpARG1_MASK),
+    /* COREARGS   */ (OPpCOREARGS_DEREF1|OPpCOREARGS_DEREF2|OPpCOREARGS_SCALARMOD|OPpCOREARGS_PUSHMARK),
+    /* RUNCV      */ (OPpOFFBYONE),
+    /* FC         */ (OPpARG1_MASK),
+    /* PADCV      */ (0),
+    /* INTROCV    */ (0),
+    /* CLONECV    */ (0),
+    /* PADRANGE   */ (OPpPADRANGE_COUNTMASK|OPpLVAL_INTRO),
+
+};
+
+#  endif /* !DOINIT */
+#endif /* !PERL_GLOBAL_STRUCT_INIT */
+
+END_EXTERN_C
+
+
+
 /* ex: set ro: */
diff --git a/pp.h b/pp.h
index a7e936c..58a0a5c 100644 (file)
--- a/pp.h
+++ b/pp.h
@@ -380,7 +380,7 @@ Does not use C<TARG>.  See also C<XPUSHu>, C<mPUSHu> and C<PUSHu>.
 #define ARGTARG                PL_op->op_targ
 
     /* See OPpTARGET_MY: */
-#define MAXARG         (PL_op->op_private & 15)
+#define MAXARG         (PL_op->op_private & OPpARG4_MASK)
 
 #define SWITCHSTACK(f,t) \
     STMT_START {                                                       \
index 642214e..def63b8 100644 (file)
--- a/pp_sys.c
+++ b/pp_sys.c
@@ -2994,7 +2994,7 @@ PP(pp_ftrread)
 {
     I32 result;
     /* Not const, because things tweak this below. Not bool, because there's
-       no guarantee that OPp_FT_ACCESS is <= CHAR_MAX  */
+       no guarantee that OPpFT_ACCESS is <= CHAR_MAX  */
 #if defined(HAS_ACCESS) || defined (PERL_EFF_ACCESS)
     I32 use_access = PL_op->op_private & OPpFT_ACCESS;
     /* Giving some sort of initial value silences compilers.  */
diff --git a/regen/op_private b/regen/op_private
new file mode 100644 (file)
index 0000000..3a1e9dc
--- /dev/null
@@ -0,0 +1,668 @@
+#!perl
+
+=head1 F<regen/op_private>
+
+This file contains all the definitions of the meanings of the flags in the
+op_private field of an OP.
+
+After editing this file, run C<make regen>. This will generate/update data
+in:
+
+    opcode.h
+    lib/B/Op_private.pm
+
+C<B::Op_private> holds three global hashes, C<%bits>, C<%defines>,
+C<%labels>, which hold roughly the same information as found in this file
+(after processing).
+
+F<opcode.h> gains a series of C<OPp*> defines, and a few static data
+structures:
+
+C<PL_op_private_valid> defines, per-op, which op_private bits are legally,
+allowed to be set. This is a first good place to look to see if an op has
+any spare private bits.
+
+C<PL_op_private_bitdef_ix>, C<PL_op_private_bitdefs>,
+C<PL_op_private_labels>, C<PL_op_private_bitfields>,
+C<PL_op_private_valid> contain (in a compact form) the data needed by
+Perl_do_op_dump() to dump the op_private field of an op.
+
+This file actually contains perl code which is run by F<regen/opcode.pl>.
+The basic idea is that you keep calling addbits() to add definitions of
+what a particular bit or range of bits in op_private means for a
+particular op. This can be specified either as a 1-bit flag or a 1-or-more
+bit bit field. Here's a general example:
+
+    addbits('aelem',
+            7 => qw(OPpLVAL_INTRO LVINTRO),
+       '5..6' =>  {
+                       mask_def  => 'OPpDEREF',
+                       enum => [ qw(
+                                   1   OPpDEREF_AV   DREFAV
+                                   2   OPpDEREF_HV   DREFHV
+                                   3   OPpDEREF_SV   DREFSV
+                               )],
+                   },
+            4 => qw(OPpLVAL_DEFER LVDEFER),
+    );
+
+Here for the op C<aelem>, bits 4 and 7 (bits are numbered 0..7) are
+defined as single-bit flags. The first string following the bit number is
+the define name that gets emitted in F<opcode.h>, and the second string is
+the label, which will be displayed by F<Concise.pm> and Perl_do_op_dump()
+(as used by C<perl -Dx>).
+
+If the bit number is actually two numbers connected with '..', then this
+defines a bit field, which is 1 or more bits taken to hold a small
+unsigned integer. Instead of two string arguments, it just has a single
+hash ref argument. A bit field allows you to generate extra defines, such
+as a mask, and optionally allows you to define an enumeration, where a
+subset of the possible values of the bit field are given their own defines
+and labels. The full syntax of this hash is explained further below.
+
+Note that not all bits for a particular op need to be added in a single
+addbits() call; they accumulate. In particular, this file is arranged in
+two halves; first, generic flags shared by multiple ops are added, then
+in the second half, specific per-op flags are added, e.g.
+
+   addbits($_, 7 => qw(OPpLVAL_INTRO LVINTRO)) for qw(pos substr vec  ...);
+
+   ....
+   
+   addbits('substr',
+               4 => qw(OPpSUBSTR_REPL_FIRST REPL1ST),
+               3 => ...
+           );
+
+(although the diving line between these two halves is somewhat subjective,
+and is based on whether "OPp" is followed by the op name or something
+generic).
+
+There are some utility functions for generating a list of ops from
+F<regen/opcodes> based on various criteria. These are:
+
+    ops_with_check('ck_foo')
+    ops_with_flag('X')
+    ops_with_arg(N, 'XYZ')
+
+which return a list of op names where:
+
+    field 3 of regen/opcodes specifies 'ck_foo' as the check function;
+    field 4 of of regen/opcodes has flag or type 'X' set;
+    argument field N of of regen/opcodes matches 'XYZ';
+
+For example
+
+    addbits($_, 4 => qw(OPpTARGET_MY TARGMY)) for ops_with_flag('T');
+
+If a label is specified as '-', then the flag or bit field is not
+displayed symbolically by Concise/-Dx; instead the bits are treated as
+unrecognised and included in the final residual integer value after all
+recognised bits have been processed (this doesn't apply to individual
+enum labels).
+
+Here is a full example of a bit field hash:
+
+    '5..6' =>  {
+        mask_def      => 'OPpFOO_MASK',
+        baseshift_def => 'OPpFOO_SHIFT',
+        bitcount_def  => 'OPpFOO_BITS',
+        label         => 'FOO',
+        enum          => [ qw(
+                             1   OPpFOO_A  A
+                             2   OPpFOO_B  B
+                             3   OPpFOO_C  C
+                         )],
+    };
+
+The optional C<*_def> keys cause defines to be emitted that specify
+useful values based on the bit range (5 to 6 in this case):
+
+    mask_def:      a mask that will extract the bit field
+    baseshift_def: how much to shift to make the bit field reach bit 0
+    bitcount_def:  how many bits make up the bit field
+
+The example above will generate
+
+    #define OPpFOO_MASK 0x60
+    #define OPpFOO_SHIFT   5
+    #define OPpFOO_BITS    2
+
+The optional enum list specifies a set of defines and labels for (possibly
+a subset of) the possible values of the bit field (which in this example
+are 0,1,2,3). If a particular value matches an enum, then it will be
+displayed symbolically (e.g. 'C'), otherwise as a small integer. The
+defines are suitably shifted. The example above will generate
+
+    #define OPpFOO_A 0x20
+    #define OPpFOO_B 0x40
+    #define OPpFOO_C 0x60
+
+So you can write code like
+
+    if ((o->op_private & OPpFOO_MASK) == OPpFOO_C) ...
+
+The optional 'label' key causes Concise/-Dx output to prefix the value
+with C<LABEL=>; so in this case it might display C<FOO=C>.  If the field
+value is zero, and if no label is present, and if no enum matches, then
+the field isn't displayed.
+
+=cut
+
+
+use warnings;
+use strict;
+
+
+
+
+# ====================================================================
+#
+# GENERIC OPpFOO flags
+#
+# Flags where FOO is a generic term (like LVAL), and the flag is
+# shared between multiple (possibly unrelated) ops.
+
+
+
+
+{
+    # The lower few bits of op_private often indicate the number of
+    # arguments. This is usually set by newUNOP() and newLOGOP (to 1),
+    # by newBINOP() (to 1 or 2), and by ck_fun() (to 1..15).
+    #
+    # These values are sometimes used at runtime: in particular,
+    # the MAXARG macro extracts out the lower 4 bits.
+    #
+    # Some ops encroach upon these bits; for example, entersub is a unop,
+    # but uses bit 0 for something else. Bit 0 is initially set to 1 in
+    # newUNOP(), but is later cleared (in ck_rvconst()), when the code
+    # notices that this op is an entersub.
+    #
+    # The important thing below is that any ops which use MAXARG at
+    # runtime must have all 4 bits allocated; if bit 3 were used for a new
+    # flag say, then things could break.  The information on the other
+    # types of op is for completeness (so we can account for every bit
+    # used in every op)
+
+    my (%maxarg, %args0, %args1, %args2, %args3, %args4);
+
+    # these are the functions which currently use MAXARG at runtime
+    # (i.e. in the pp() functions). Thus they must always have 4 bits
+    # allocated
+    $maxarg{$_} = 1 for qw(
+        binmode bless caller chdir close enterwrite eof exit fileno getc
+        getpgrp gmtime index mkdir rand reset setpgrp sleep srand sysopen
+        tell umask
+    );
+
+    # find which ops use 0,1,2,3 or 4 bits of op_private for arg count info
+
+    $args0{$_} = 1 for qw(entersub); # UNOPs that usurp bit 0
+
+    $args1{$_} = 1 for (
+                        qw(reverse), # ck_fun(), but most bits stolen
+                        grep !$maxarg{$_} && !$args0{$_},
+                            ops_with_flag('1'), # UNOP
+                            ops_with_flag('%'), # BASEOP/UNOP
+                            ops_with_flag('|'), # LOGOP
+                            ops_with_flag('-'), # FILESTATOP
+                            ops_with_flag('}'), # LOOPEXOP
+                    );
+
+    $args2{$_} = 1 for (
+                        qw(vec),
+                        grep !$maxarg{$_} && !$args0{$_} && !$args1{$_},
+                            ops_with_flag('2'), # BINOP
+                            # this is a binop, but special-cased as a
+                            # baseop in regen/opcodes
+                            'sassign',
+                    );
+
+    $args3{$_} = 1 for grep !$maxarg{$_} && !$args0{$_}
+                                            && !$args1{$_} && !$args2{$_},
+                            # substr starts off with 4 bits set in
+                            # ck_fun(), but since it never has more than 7
+                            # args, bit 3 is later stolen
+                            qw(substr);
+
+    $args4{$_} = 1 for  keys %maxarg,
+                        grep !$args0{$_} && !$args1{$_}
+                                                && !$args2{$_} && !$args3{$_},
+                            ops_with_check('ck_fun'),
+                            # these other ck_*() functions call ck_fun()
+                            ops_with_check('ck_exec'),
+                            ops_with_check('ck_glob'),
+                            ops_with_check('ck_index'),
+                            ops_with_check('ck_join'),
+                            ops_with_check('ck_lfun'),
+                            ops_with_check('ck_open'),
+                            ops_with_check('ck_select'),
+                            ops_with_check('ck_tell'),
+                            ops_with_check('ck_trunc'),
+                            ;
+
+
+    for (sort keys %args1) {
+        addbits($_, '0..0' => {
+                mask_def  => 'OPpARG1_MASK',
+                label     => '-',
+            }
+        );
+    }
+
+    for (sort keys %args2) {
+        addbits($_, '0..1' => {
+                mask_def  => 'OPpARG2_MASK',
+                label     => '-',
+            }
+        );
+    }
+
+    for (sort keys %args3) {
+        addbits($_, '0..2' => {
+                mask_def  => 'OPpARG3_MASK',
+                label     => '-',
+            }
+        );
+    }
+
+    for (sort keys %args4) {
+        addbits($_, '0..3' => {
+                mask_def  => 'OPpARG4_MASK',
+                label     => '-',
+            }
+        );
+    }
+}
+
+
+
+# if NATIVE_HINTS is defined, op_private on cops holds the top 8 bits
+# of PL_hints, although only bits 6 & 7 are officially used for that
+# purpose (the rest ought to be masked off). Bit 5 is set separately
+
+for (qw(nextstate dbstate)) {
+    addbits($_,
+        5 => qw(OPpHUSH_VMSISH          HUSH),
+        # should match HINT_M_VMSISH_STATUS, HINT_M_VMSISH_TIME
+        6 => qw(OPpHINT_M_VMSISH_STATUS VMSISH_STATUS),
+        7 => qw(OPpHINT_M_VMSISH_TIME   VMSISH_TIME),
+
+    );
+}
+
+
+
+addbits($_, 7 => qw(OPpLVAL_INTRO LVINTRO))
+    for qw(pos substr vec gvsv rv2sv rv2hv rv2gv rv2av aelem helem aslice
+           hslice delete padsv padav padhv enteriter entersub padrange
+           pushmark cond_expr),
+           'list', # this gets set in my_attrs() for some reason
+           ;
+
+
+
+# TARGLEX
+#
+# in constructs like my $x; ...; $x = $a + $b,
+# the sassign is optimised away and OPpTARGET_MY is set on the add op
+
+# XXX the old Concise.pm disagreed with regen/opcodes as to which ops have
+# this flag: in Concise, but not T:
+#       bit_and bit_or bit_xor chop complement join negate postdec postinc
+#       quotemeta schop sprintf
+# in T but not Concise:
+#       srand
+
+addbits($_, 4 => qw(OPpTARGET_MY TARGMY))
+    for ops_with_flag('T'),
+    # This flag is also used to indicate matches against implicit $_,
+    # where $_ is lexical; e.g. my $_; ....; /foo/
+    qw(match subst trans transr);
+;
+
+
+
+
+
+# op_targ carries a refcount
+addbits($_, 6 => qw(OPpREFCOUNTED REFC))
+    for qw(leave leavesub leavesublv leavewrite leaveeval);
+
+
+
+# Do not copy return value
+addbits($_, 7 => qw(OPpLVALUE LV)) for qw(leave leaveloop);
+
+
+
+# Pattern coming in on the stack
+addbits($_, 6 => qw(OPpRUNTIME RTIME))
+    for qw(match subst substcont qr pushre);
+
+
+
+# autovivify: Want ref to something
+for (qw(rv2gv rv2sv padsv aelem helem entersub)) {
+    addbits($_, '5..6' => {
+                mask_def  => 'OPpDEREF',
+                enum => [ qw(
+                            1   OPpDEREF_AV   DREFAV
+                            2   OPpDEREF_HV   DREFHV
+                            3   OPpDEREF_SV   DREFSV
+                        )],
+            }
+    );
+}
+
+
+
+# Defer creation of array/hash elem
+addbits($_, 4 => qw(OPpLVAL_DEFER LVDEFER)) for qw(aelem helem);
+
+
+
+addbits($_, 2 => qw(OPpSLICEWARNING SLICEWARN)) # warn about @hash{$scalar}
+    for qw(rv2hv rv2av padav padhv hslice aslice);
+
+
+
+# XXX Concise seemed to think that OPpOUR_INTRO is used in rv2gv too,
+# but I can't see it - DAPM
+addbits($_, 4 => qw(OPpOUR_INTRO OURINTR)) # Variable was in an our()
+    for qw(gvsv rv2sv rv2av rv2hv enteriter);
+
+
+
+# We might be an lvalue to return
+addbits($_, 3 => qw(OPpMAYBE_LVSUB LVSUB))
+    for qw(aassign rv2av rv2gv rv2hv padav padhv aelem helem aslice hslice
+           av2arylen keys rkeys kvaslice kvhslice substr pos vec);
+
+
+
+for (qw(rv2hv padhv)) {
+    addbits($_,                           # e.g. %hash in (%hash || $foo) ...
+        5 => qw(OPpTRUEBOOL       BOOL),  # ... in void cxt
+        6 => qw(OPpMAYBE_TRUEBOOL BOOL?), # ... cx not known till run time
+    );
+}
+
+
+
+addbits($_, 1 => qw(OPpHINT_STRICT_REFS -)) for qw(rv2sv rv2av rv2hv rv2gv);
+
+
+
+# Treat caller(1) as caller(2)
+addbits($_, 7 => qw(OPpOFFBYONE  +1)) for qw(caller wantarray runcv);
+
+
+
+# label is in UTF8 */
+addbits($_, 7 => qw(OPpPV_IS_UTF8 UTF)) for qw(last redo next goto dump);
+
+
+
+# ====================================================================
+#
+# OP-SPECIFIC OPpFOO_* flags:
+#
+# where FOO is typically the name of an op, and the flag is used by a
+# single op (or maybe by a few closely related ops).
+
+
+
+addbits($_, 4 => qw(OPpPAD_STATE STATE))  for qw(padav padhv padsv pushmark);
+
+
+
+addbits('aassign', 6 => qw(OPpASSIGN_COMMON COMMON));
+
+
+
+addbits('sassign',
+    6 => qw(OPpASSIGN_BACKWARDS BKWARD), # Left & right switched
+    7 => qw(OPpASSIGN_CV_TO_GV  CV2GV),  # Possible optimisation for constants
+);
+
+
+
+for (qw(trans transr)) {
+    addbits($_,
+        0 => qw(OPpTRANS_FROM_UTF   <UTF),
+        1 => qw(OPpTRANS_TO_UTF     >UTF),
+        2 => qw(OPpTRANS_IDENTICAL  IDENT),   # right side is same as left
+        3 => qw(OPpTRANS_SQUASH     SQUASH),
+        # 4 is used for OPpTARGET_MY
+        5 => qw(OPpTRANS_COMPLEMENT COMPL),
+        6 => qw(OPpTRANS_GROWS      GROWS),
+        7 => qw(OPpTRANS_DELETE     DEL),
+    );
+}
+
+
+
+addbits('repeat', 6 => qw(OPpREPEAT_DOLIST DOLIST)); # List replication
+
+
+
+# OP_ENTERSUB and OP_RV2CV flags
+#
+# Flags are set on entersub and rv2cv in three phases:
+#   parser  - the parser passes the flag to the op constructor
+#   check   - the check routine called by the op constructor sets the flag
+#   context - application of scalar/ref/lvalue context applies the flag
+#
+# In the third stage, an entersub op might turn into an rv2cv op (undef &foo,
+# \&foo, lock &foo, exists &foo, defined &foo).  The two places where that
+# happens (op_lvalue_flags and doref in op.c) need to make sure the flags do
+# not conflict, since some flags with different meanings overlap between
+# the two ops.  Flags applied in the context phase are only set when there
+# is no conversion of op type.
+#
+#   bit  entersub flag       phase   rv2cv flag             phase
+#   ---  -------------       -----   ----------             -----
+#     0  OPpENTERSUB_INARGS  context
+#     1  HINT_STRICT_REFS    check   HINT_STRICT_REFS       check
+#     2  OPpENTERSUB_HASTARG check
+#     3  OPpENTERSUB_AMPER   check   OPpENTERSUB_AMPER      parser
+#     4  OPpENTERSUB_DB      check
+#     5  OPpDEREF_AV         context
+#     6  OPpDEREF_HV         context OPpMAY_RETURN_CONSTANT context
+#     7  OPpLVAL_INTRO       context OPpENTERSUB_NOPAREN    parser
+
+# NB: OPpHINT_STRICT_REFS must equal HINT_STRICT_REFS
+
+addbits('entersub',
+    0      => qw(OPpENTERSUB_INARGS   INARGS), # Lval used as arg to a sub
+    1      => qw(OPpHINT_STRICT_REFS  -     ), # 'use strict' in scope
+    2      => qw(OPpENTERSUB_HASTARG  TARG  ), # Called from OP tree
+    3      => qw(OPpENTERSUB_AMPER    AMPER),  # Used & form to call
+    4      => qw(OPpENTERSUB_DB       DBG   ), # Debug subroutine
+    # 5..6 => OPpDEREF,      already defined above
+    # 7    => OPpLVAL_INTRO, already defined above
+);
+addbits('rv2cv',
+    # If a constant sub, return the constant
+    1 => qw(OPpHINT_STRICT_REFS    -    ),  # 'use strict' in scope
+
+    3 => qw(OPpENTERSUB_AMPER      AMPER),  # Used & form to call
+
+    6 => qw(OPpMAY_RETURN_CONSTANT CONST),
+    7 => qw(OPpENTERSUB_NOPAREN    NO() ),  # bare sub call (without parens)
+);
+
+# XXX perhaps ought the clear these flags in Perl_doref when converting
+# and entersub into an rv2cv???? Failing that, update the comments above
+# and add them as part of the main addbits('rv2cv'.
+
+addbits('rv2cv',
+              # If a constant sub, return the constant
+    2 => qw(OPpENTERSUB_HASTARG TARG),
+    4 => qw(OPpENTERSUB_DB       DBG   ), # Debug subroutine
+);
+
+
+
+#foo() called before sub foo was parsed */
+addbits('gv', 5 => qw(OPpEARLY_CV EARLYCV));
+
+
+
+# 1st arg is replacement string */
+addbits('substr', 4 => qw(OPpSUBSTR_REPL_FIRST REPL1ST));
+
+
+
+addbits('padrange',
+    # bits 0..6 hold target range
+    '0..6' =>  {
+            label         => '-',
+            mask_def      => 'OPpPADRANGE_COUNTMASK',
+            bitcount_def  => 'OPpPADRANGE_COUNTSHIFT',
+          }
+     # 7    => OPpLVAL_INTRO, already defined above
+);
+
+
+
+for (qw(aelemfast aelemfast_lex)) {
+    addbits($_,
+        '0..7' =>  {
+                label     => '-',
+              }
+    );
+}
+
+
+
+addbits('rv2gv',
+    2 => qw(OPpDONT_INIT_GV NOINIT), # Call gv_fetchpv with GV_NOINIT
+                            # (Therefore will return whatever is currently in
+                            # the symbol table, not guaranteed to be a PVGV)
+    4 => qw(OPpALLOW_FAKE   FAKE),   # OK to return fake glob
+);
+
+
+
+addbits('enteriter',
+                    2 => qw(OPpITER_REVERSED REVERSED),# for (reverse ...)
+                    3 => qw(OPpITER_DEF      -),       # 'for $_' or 'for my $_'
+);
+addbits('iter',     2 => qw(OPpITER_REVERSED REVERSED));
+
+
+
+addbits('const',
+    1 => qw(OPpCONST_NOVER        NOVER),   # no 6;
+    2 => qw(OPpCONST_SHORTCIRCUIT SHORT),   # e.g. the constant 5 in (5 || foo)
+    3 => qw(OPpCONST_STRICT       STRICT),  # bareword subject to strict 'subs'
+    4 => qw(OPpCONST_ENTERED      ENTERED), # Has been entered as symbol
+    6 => qw(OPpCONST_BARE         BARE),    # Was a bare word (filehandle?)
+);
+
+
+
+# Range arg potentially a line num. */
+addbits($_, 6 => qw(OPpFLIP_LINENUM LINENUM)) for qw(flip flop);
+
+
+
+# Guessed that pushmark was needed. */
+addbits('list', 6 => qw(OPpLIST_GUESSED GUESSED));
+
+
+
+# Operating on a list of keys
+addbits('delete', 6 => qw(OPpSLICE SLICE));
+# also 7 => OPpLVAL_INTRO, already defined above
+
+
+
+# Checking for &sub, not {} or [].
+addbits('exists', 6 => qw(OPpEXISTS_SUB SUB));
+
+
+
+addbits('sort',
+    0 => qw(OPpSORT_NUMERIC  NUM    ), # Optimized away { $a <=> $b }
+    1 => qw(OPpSORT_INTEGER  INT    ), # Ditto while under "use integer"
+    2 => qw(OPpSORT_REVERSE  REV    ), # Reversed sort
+    3 => qw(OPpSORT_INPLACE  INPLACE), # sort in-place; eg @a = sort @a
+    4 => qw(OPpSORT_DESCEND  DESC   ), # Descending sort
+    5 => qw(OPpSORT_QSORT    QSORT  ), # Use quicksort (not mergesort)
+    6 => qw(OPpSORT_STABLE   STABLE ), # Use a stable algorithm
+);
+
+
+
+# reverse in-place (@a = reverse @a) */
+addbits('reverse', 3 => qw(OPpREVERSE_INPLACE  INPLACE));
+
+
+
+for (qw(open backtick)) {
+    addbits($_,
+        4 => qw(OPpOPEN_IN_RAW    INBIN ), # binmode(F,":raw")  on input  fh
+        5 => qw(OPpOPEN_IN_CRLF   INCR  ), # binmode(F,":crlf") on input  fh
+        6 => qw(OPpOPEN_OUT_RAW   OUTBIN), # binmode(F,":raw")  on output fh
+        7 => qw(OPpOPEN_OUT_CRLF  OUTCR ), # binmode(F,":crlf") on output fh
+    );
+}
+
+
+
+# The various OPpFT* filetest ops
+
+# "use filetest 'access'" is in scope:
+# this flag is set only on a subset of the FT* ops
+addbits($_, 1 => qw(OPpFT_ACCESS FTACCESS)) for ops_with_arg(0, 'F-+');
+
+# all OPpFT* ops except stat and lstat
+for (grep { $_ !~ /^l?stat$/ } ops_with_flag('-')) {
+    addbits($_,
+        2 => qw(OPpFT_STACKED  FTSTACKED ),  # stacked filetest,
+                                             #    e.g. "-f" in "-f -x $foo"
+        3 => qw(OPpFT_STACKING FTSTACKING),  # stacking filetest.
+                                             #    e.g. "-x" in "-f -x $foo"
+        4 => qw(OPpFT_AFTER_t  FTAFTERt  ),  # previous op was -t
+    );
+}
+
+
+
+addbits($_, 1 => qw(OPpGREP_LEX GREPLEX)) # iterate over lexical $_
+    for qw(mapwhile mapstart grepwhile grepstart);
+
+
+
+addbits('entereval',
+    1 => qw(OPpEVAL_HAS_HH       HAS_HH ), # Does it have a copy of %^H ?
+    2 => qw(OPpEVAL_UNICODE      UNI    ),
+    3 => qw(OPpEVAL_BYTES        BYTES  ),
+    4 => qw(OPpEVAL_COPHH        COPHH  ), # Construct %^H from COP hints
+    5 => qw(OPpEVAL_RE_REPARSING -      ), # eval_sv(..., G_RE_REPARSING)
+);
+
+
+
+# These must not conflict with OPpDONT_INIT_GV or OPpALLOW_FAKE.
+# See pp.c:S_rv2gv. */
+addbits('coreargs',
+    0 => qw(OPpCOREARGS_DEREF1    DEREF1), # Arg 1 is a handle constructor
+    1 => qw(OPpCOREARGS_DEREF2    DEREF2), # Arg 2 is a handle constructor
+   #2 reserved for OPpDONT_INIT_GV in rv2gv
+   #4 reserved for OPpALLOW_FAKE   in rv2gv
+    6 => qw(OPpCOREARGS_SCALARMOD $MOD  ), # \$ rather than \[$@%*]
+    7 => qw(OPpCOREARGS_PUSHMARK  MARK  ), # Call pp_pushmark
+);
+
+
+
+addbits('split', 7 => qw(OPpSPLIT_IMPLIM IMPLIM)); # implicit limit
+
+1;
+
+# ex: set ts=8 sts=4 sw=4 et:
index a081c64..34f9d4b 100755 (executable)
@@ -5,9 +5,12 @@
 #    opcode.h
 #    opnames.h
 #    pp_proto.h
+#    lib/B/Op_private.pm
 #
-# from information stored in regen/opcodes, plus the
-# values hardcoded into this script in @raw_alias.
+# from:
+#  * information stored in regen/opcodes;
+#  * information stored in regen/op_private (which is actually perl code);
+#  * the values hardcoded into this script in @raw_alias.
 #
 # Accepts the standard regen_lib -q and -v args.
 #
@@ -29,7 +32,14 @@ my $on = open_new('opnames.h', '>',
                  { by => 'regen/opcode.pl', from => 'its data', style => '*',
                    file => 'opnames.h', copyright => [1999 .. 2008] });
 
-# Read data.
+my $oprivpm = open_new('lib/B/Op_private.pm', '>',
+                 { by => 'regen/opcode.pl',
+                    from => 'data in regen/op_private',
+                    style => '#',
+                   file => 'lib/B/Op_private.pm',
+                    copyright => [2014 .. 2014] });
+
+# Read 'opcodes' data.
 
 my %seen;
 my (@ops, %desc, %check, %ckname, %flags, %args, %opnum);
@@ -143,6 +153,725 @@ foreach my $sock_func (qw(socket bind listen accept shutdown
     $alias{$sock_func} = ["Perl_pp_$sock_func", '#ifdef HAS_SOCKET'],
 }
 
+
+
+# =================================================================
+#
+# Functions for processing regen/op_private data.
+#
+# Put them in a separate package so that croak() does the right thing
+
+package OP_PRIVATE;
+
+use Carp;
+
+
+# the vars holding the global state built up by all the calls to addbits()
+
+
+# map OPpLVAL_INTRO => LVINTRO
+my %LABELS;
+
+
+# the numeric values of flags - what will get output as a #define
+my %DEFINES;
+
+# %BITFIELDS: the various bit field types. The key is the concatenation of
+# all the field values that make up a bit field hash; the values are bit
+# field hash refs.  This allows us to de-dup identical bit field defs
+# across different ops, and thus make the output tables more compact (esp
+# important for the C version)
+my %BITFIELDS;
+
+# %FLAGS: the main data structure. Indexed by op name, then bit index:
+# single bit flag:
+#   $FLAGS{rv2av}{2} = 'OPpSLICEWARNING';
+# bit field (bits 5 and 6):
+#   $FLAGS{rv2av}{5} = $FLAGS{rv2av}{6} = { .... };
+my %FLAGS;
+
+
+# do, with checking, $LABELS{$name} = $label
+
+sub add_label {
+    my ($name, $label) = @_;
+    if (exists $LABELS{$name} and $LABELS{$name} ne $label) {
+        croak "addbits(): label for flag '$name' redefined:\n"
+        .  "  was '$LABELS{$name}', now '$label'";
+    }
+    $LABELS{$name} = $label;
+}
+
+#
+# do, with checking, $DEFINES{$name} = $val
+
+sub add_define {
+    my ($name, $val) = @_;
+    if (exists $DEFINES{$name} && $DEFINES{$name} != $val) {
+        croak "addbits(): value for flag '$name' redefined:\n"
+        .  "  was $DEFINES{$name}, now $val";
+    }
+    $DEFINES{$name} = $val;
+}
+
+
+# intended to be called from regen/op_private; see that file for details
+
+sub ::addbits {
+    my @args = @_;
+
+    croak "too few arguments for addbits()" unless @args >= 3;
+    my $op = shift @args;
+    croak "invalid op name: '$op'" unless exists $opnum{$op};
+
+    while (@args) {
+        my $bits = shift @args;
+        if ($bits =~ /^[0-7]$/) {
+            # single bit
+            croak "addbits(): too few arguments for single bit flag"
+                unless @args >= 2;
+            my $flag_name   = shift @args;
+            my $flag_label  = shift @args;
+            add_label($flag_name, $flag_label);
+            croak "addbits(): bit $bits of $op already specified"
+                if defined $FLAGS{$op}{$bits};
+            $FLAGS{$op}{$bits} = $flag_name;
+            add_define($flag_name, (1 << $bits));
+        }
+        elsif ($bits =~ /^([0-7])\.\.([0-7])$/) {
+            # bit range
+            my ($bitmin, $bitmax) = ($1,$2);
+
+            croak "addbits(): min bit > max bit in bit range '$bits'"
+                unless $bitmin <= $bitmax;
+            croak "addbits(): bit field argument missing"
+                unless @args >= 1;
+
+            my $arg_hash = shift @args;
+            croak "addbits(): arg to $bits must be a hash ref"
+                unless defined $arg_hash and ref($arg_hash) =~ /HASH/;
+
+            my %valid_keys;
+            @valid_keys{qw(baseshift_def bitcount_def mask_def label enum)} = ();
+            for (keys %$arg_hash) {
+                croak "addbits(): unrecognised bifield key: '$_'"
+                    unless exists $valid_keys{$_};
+            }
+
+            my $bitmask = 0;
+            $bitmask += (1 << $_) for $bitmin..$bitmax;
+
+            my $enum_id ='';
+
+            if (defined $arg_hash->{enum}) {
+                my $enum = $arg_hash->{enum};
+                croak "addbits(): arg to enum must be an array ref"
+                    unless defined $enum and ref($enum) =~ /ARRAY/;
+                croak "addbits(): enum list must be in triplets"
+                    unless @$enum % 3 == 0;
+
+                my $max_id = (1 << ($bitmax - $bitmin + 1)) - 1;
+
+                my @e = @$enum;
+                while (@e) {
+                    my $enum_ix     = shift @e;
+                    my $enum_name   = shift @e;
+                    my $enum_label  = shift @e;
+                    croak "addbits(): enum index must be a number: '$enum_ix'"
+                        unless $enum_ix =~ /^\d+$/;
+                    croak "addbits(): enum index too big: '$enum_ix'"
+                        unless $enum_ix  <= $max_id;
+                    add_label($enum_name, $enum_label);
+                    add_define($enum_name, $enum_ix << $bitmin);
+                    $enum_id .= "($enum_ix:$enum_name:$enum_label)";
+                }
+            }
+
+            # id is a fingerprint of all the content of the bit field hash
+            my $id = join ':', map defined() ? $_ : "-undef-",
+                $bitmin, $bitmax,
+                $arg_hash->{label},
+                $arg_hash->{mask_def},
+                $arg_hash->{baseshift_def},
+                $arg_hash->{bitcount_def},
+                $enum_id;
+
+            unless (defined $BITFIELDS{$id}) {
+
+                if (defined $arg_hash->{mask_def}) {
+                    add_define($arg_hash->{mask_def}, $bitmask);
+                }
+
+                if (defined $arg_hash->{baseshift_def}) {
+                    add_define($arg_hash->{baseshift_def}, $bitmin);
+                }
+
+                if (defined $arg_hash->{bitcount_def}) {
+                    add_define($arg_hash->{bitcount_def}, $bitmax-$bitmin+1);
+                }
+
+                # create deep copy
+
+                my $copy = {};
+                for (qw(baseshift_def  bitcount_def mask_def label)) {
+                    $copy->{$_} = $arg_hash->{$_} if defined $arg_hash->{$_};
+                }
+                if (defined $arg_hash->{enum}) {
+                    $copy->{enum} = [ @{$arg_hash->{enum}} ];
+                }
+
+                # and add some extra fields
+
+                $copy->{bitmask} = $bitmask;
+                $copy->{bitmin} = $bitmin;
+                $copy->{bitmax} = $bitmax;
+
+                $BITFIELDS{$id} = $copy;
+            }
+
+            for my $bit ($bitmin..$bitmax) {
+                croak "addbits(): bit $bit of $op already specified"
+                    if defined $FLAGS{$op}{$bit};
+                $FLAGS{$op}{$bit} = $BITFIELDS{$id};
+            }
+        }
+        else {
+            croak "addbits(): invalid bit specifier '$bits'";
+        }
+    }
+}
+
+
+# intended to be called from regen/op_private; see that file for details
+
+sub ::ops_with_flag {
+    my $flag = shift;
+    return grep $flags{$_} =~ /\Q$flag/, sort keys %flags;
+}
+
+
+# intended to be called from regen/op_private; see that file for details
+
+sub ::ops_with_check {
+    my $c = shift;
+    return grep $check{$_} eq $c, sort keys %check;
+}
+
+
+# intended to be called from regen/op_private; see that file for details
+
+sub ::ops_with_arg {
+    my ($i, $arg_type) = @_;
+    my @ops;
+    for my $op (sort keys %args) {
+        my @args = split(' ',$args{$op});
+        push @ops, $op if defined $args[$i] and $args[$i] eq $arg_type;
+    }
+    @ops;
+}
+
+
+# output '#define OPpLVAL_INTRO 0x80' etc
+
+sub print_defines {
+    my $fh = shift;
+
+    for (sort { $DEFINES{$a} <=> $DEFINES{$b} || $a cmp $b } keys %DEFINES) {
+        printf $fh "#define %-23s 0x%02x\n", $_, $DEFINES{$_};
+    }
+}
+
+
+# Generate the content of B::Op_private
+
+sub print_B_Op_private {
+    my $fh = shift;
+
+    my $header = <<'EOF';
+@=head1 NAME
+@
+@B::Op_private -  OP op_private flag definitions
+@
+@=head1 SYNOPSIS
+@
+@    use B::Op_private;
+@
+@    # flag details for bit 7 of OP_AELEM's op_private:
+@    my $name  = $B::Op_private::bits{aelem}{7}; # OPpLVAL_INTRO
+@    my $value = $B::Op_private::defines{$name}; # 128
+@    my $label = $B::Op_private::labels{$name};  # LVINTRO
+@
+@    # the bit field at bits 5..6 of OP_AELEM's op_private:
+@    my $bf  = $B::Op_private::bits{aelem}{6};
+@    my $mask = $bf->{bitmask}; # etc
+@
+@=head1 DESCRIPTION
+@
+@This module provides three global hashes:
+@
+@    %B::Op_private::bits
+@    %B::Op_private::defines
+@    %B::Op_private::labels
+@
+@which contain information about the per-op meanings of the bits in the
+@op_private field.
+@
+@=head2 C<%bits>
+@
+@This is indexed by op name and then bit number (0..7). For single bit flags,
+@it returns the name of the define (if any) for that bit:
+@
+@   $B::Op_private::bits{aelem}{7} eq 'OPpLVAL_INTRO';
+@
+@For bit fields, it returns a hash ref containing details about the field.
+@The same reference will be returned for all bit positions that make
+@up the bit field; so for example these both return the same hash ref:
+@
+@    $bitfield = $B::Op_private::bits{aelem}{5};
+@    $bitfield = $B::Op_private::bits{aelem}{6};
+@
+@The general format of this hash ref is
+@
+@    {
+@        # The bit range and mask; these are always present.
+@        bitmin        => 5,
+@        bitmax        => 6,
+@        bitmask       => 0x60,
+@
+@        # (The remaining keys are optional)
+@
+@        # The names of any defines that were requested:
+@        mask_def      => 'OPpFOO_MASK',
+@        baseshift_def => 'OPpFOO_SHIFT',
+@        bitcount_def  => 'OPpFOO_BITS',
+@
+@        # If present, Concise etc will display the value with a 'FOO='
+@        # prefix. If it equals '-', then Concise will treat the bit field
+@        # as raw bits and not try to interpret it.
+@        label         => 'FOO',
+@
+@        # If present, specifies the names of some defines and the display
+@        # labels that are used to assign meaning to particular integer
+@        # values within the bit field; e.g. 3 is displayed as 'C'.
+@        enum          => [ qw(
+@                             1   OPpFOO_A  A
+@                             2   OPpFOO_B  B
+@                             3   OPpFOO_C  C
+@                         )],
+@
+@    };
+@
+@
+@=head2 C<%defines>
+@
+@This gives the value of every C<OPp> define, e.g.
+@
+@    $B::Op_private::defines{OPpLVAL_INTRO} == 128;
+@
+@=head2 C<%labels>
+@
+@This gives the short display label for each define, as used by C<B::Concise>
+@and C<perl -Dx>, e.g.
+@
+@    $B::Op_private::labels{OPpLVAL_INTRO} eq 'LVINTRO';
+@
+@If the label equals '-', then Concise will treat the bit as a raw bit and
+@not try to display it symbolically.
+@
+@=cut
+
+package B::Op_private;
+
+our %bits;
+
+EOF
+    # remove podcheck.t-defeating leading char
+    $header =~ s/^\@//gm;
+    print $fh $header;
+
+    # for each flag/bit combination, find the ops which use it
+    my %combos;
+    for my $op (sort keys %FLAGS) {
+        my $entry = $FLAGS{$op};
+        for my $bit (0..7) {
+            my $e = $entry->{$bit};
+            next unless defined $e;
+            next if ref $e; # bit field, not flag
+            push @{$combos{$e}{$bit}}, $op;
+        }
+    }
+
+    # dump flags used by multiple ops
+    for my $flag (sort keys %combos) {
+        for my $bit (sort keys %{$combos{$flag}}) {
+            my $ops = $combos{$flag}{$bit};
+            next unless @$ops > 1;
+            my @o = sort @$ops;
+            print $fh "\$bits{\$_}{$bit} = '$flag' for qw(@o);\n";
+        }
+    }
+
+    # dump bit field definitions
+
+    my %bitfield_ix;
+    {
+        my %bitfields;
+        # stringified-ref to ref mapping
+        $bitfields{$_} = $_ for values %BITFIELDS;
+        my $ix = -1;
+        my $s = "\nmy \@bf = (\n";
+        for my $bitfield_key (sort keys %BITFIELDS) {
+            my $bitfield = $BITFIELDS{$bitfield_key};
+            $ix++;
+            $bitfield_ix{$bitfield} = $ix;
+
+            $s .= "    {\n";
+            for (qw(label mask_def baseshift_def bitcount_def)) {
+                next unless defined $bitfield->{$_};
+                $s .= sprintf "        %-9s => '%s',\n",
+                            $_,  $bitfield->{$_};
+            }
+            for (qw(bitmin bitmax bitmask)) {
+                croak "panic" unless defined $bitfield->{$_};
+                $s .= sprintf "        %-9s => %d,\n",
+                            $_,  $bitfield->{$_};
+            }
+            if (defined $bitfield->{enum}) {
+                $s .= "        enum      => [\n";
+                my @enum = @{$bitfield->{enum}};
+                while (@enum) {
+                    my $i     = shift @enum;
+                    my $name  = shift @enum;
+                    my $label = shift @enum;
+                    $s .= sprintf "            %d, %-10s, %s,\n",
+                            $i, "'$name'", "'$label'";
+                }
+                $s .= "        ],\n";
+            }
+            $s .= "    },\n";
+
+        }
+        $s .= ");\n";
+        print $fh "$s\n";
+    }
+
+    # dump bitfields and remaining labels
+
+    for my $op (sort keys %FLAGS) {
+        my @indices;
+        my @vals;
+        my $entry = $FLAGS{$op};
+        my $bit;
+
+        for ($bit = 7; $bit >= 0; $bit--) {
+            next unless defined $entry->{$bit};
+            my $e = $entry->{$bit};
+            if (ref $e) {
+                my $ix = $bitfield_ix{$e};
+                for (reverse $e->{bitmin}..$e->{bitmax}) {
+                    push @indices,  $_;
+                    push @vals, "\$bf[$ix]";
+                }
+                $bit = $e->{bitmin};
+            }
+            else {
+                next if @{$combos{$e}{$bit}} > 1;  # already output
+                push @indices, $bit;
+                push @vals, "'$e'";
+            }
+        }
+        if (@indices) {
+            my $s = '';
+            $s = '@{' if @indices > 1;
+            $s .= "\$bits{$op}";
+            $s .= '}' if @indices > 1;
+            $s .= '{' . join(',', @indices) . '} = ';
+            $s .= '(' if @indices > 1;
+            $s .= join ', ', @vals;
+            $s .= ')' if @indices > 1;
+            print $fh "$s;\n";
+        }
+    }
+
+    # populate %defines and %labels
+
+    print  $fh "\n\nour %defines = (\n";
+    printf $fh "    %-23s  => %3d,\n", $_ , $DEFINES{$_} for sort keys %DEFINES;
+    print  $fh ");\n\nour %labels = (\n";
+    printf $fh "    %-23s  => '%s',\n", $_ , $LABELS{$_}  for sort keys %LABELS;
+    print  $fh ");\n";
+
+}
+
+
+
+# output the contents of the assorted PL_op_private_*[] tables
+
+sub print_PL_op_private_tables {
+    my $fh = shift;
+
+    my $PL_op_private_labels     = '';
+    my $PL_op_private_valid      = '';
+    my $PL_op_private_bitdef_ix  = '';
+    my $PL_op_private_bitdefs    = '';
+    my $PL_op_private_bitfields  = '';
+
+    my %label_ix;
+    my %bitfield_ix;
+
+    # generate $PL_op_private_labels
+
+    {
+        my %labs;
+        $labs{$_} = 1 for values %LABELS; # de-duplicate labels
+        # add in bit field labels
+        for (values %BITFIELDS) {
+            next unless defined $_->{label};
+            $labs{$_->{label}} = 1;
+        }
+
+        my $labels = '';
+        for my $lab (sort keys %labs) {
+            $label_ix{$lab} = length $labels;
+            $labels .= "$lab\0";
+            $PL_op_private_labels .=
+                  "    "
+                . join(',', map("'$_'", split //, $lab))
+                . ",'\\0',\n";
+        }
+    }
+
+
+    # generate PL_op_private_bitfields
+
+    {
+        my %bitfields;
+        # stringified-ref to ref mapping
+        $bitfields{$_} = $_ for values %BITFIELDS;
+
+        my $ix = 0;
+        for my $bitfield_key (sort keys %BITFIELDS) {
+            my $bf = $BITFIELDS{$bitfield_key};
+            $bitfield_ix{$bf} = $ix;
+
+            my @b;
+            push @b, $bf->{bitmin},
+                defined $bf->{label} ? $label_ix{$bf->{label}} : -1;
+            my $enum = $bf->{enum};
+            if (defined $enum) {
+                my @enum = @$enum;
+                while (@enum) {
+                    my $i     = shift @enum;
+                    my $name  = shift @enum;
+                    my $label = shift @enum;
+                    push @b, $i, $label_ix{$label};
+                }
+            }
+            push @b, -1; # terminate enum list
+
+            $PL_op_private_bitfields .= "    " .  join(', ', @b) .",\n";
+            $ix += @b;
+        }
+    }
+
+
+    # generate PL_op_private_bitdefs, PL_op_private_bitdef_ix
+
+    {
+        my $bitdef_count = 0;
+
+        my %not_seen = %FLAGS;
+
+        my $opnum = -1;
+        for my $op (sort { $opnum{$a} <=> $opnum{$b} } keys %opnum) {
+            $opnum++;
+            die "panic: opnum misorder: opnum=$opnum opnum{op}=$opnum{$op}"
+                unless $opnum == $opnum{$op};
+            delete $not_seen{$op};
+
+            my @bitdefs;
+            my $entry = $FLAGS{$op};
+            my $bit;
+            my $index;
+
+            for ($bit = 7; $bit >= 0; $bit--) {
+                my $e = $entry->{$bit};
+                next unless defined $e;
+
+                my $ix;
+                if (ref $e) {
+                    $ix = $bitfield_ix{$e};
+                    die "panic: \$bit =\= $e->{bitmax}"
+                        unless $bit == $e->{bitmax};
+
+                    push @bitdefs, ( ($ix << 5) | ($bit << 2) | 2 );
+                    $bit = $e->{bitmin};
+                }
+                else {
+                    $ix = $label_ix{$LABELS{$e}};
+                    die "panic: no label ix for '$e'" unless defined $ix;
+                    push @bitdefs, ( ($ix << 5) | ($bit << 2));
+                }
+                if ($ix > 2047) {
+                    die "Too many labels or bitfields (ix=$ix): "
+                    . "maybe the type of PL_op_private_bitdefs needs "
+                    . "expanding from U16 to U32???";
+                }
+            }
+            if (@bitdefs) {
+                $bitdefs[-1] |= 1; # stop bit
+                $index = $bitdef_count;
+                $bitdef_count += @bitdefs;
+                $PL_op_private_bitdefs .= sprintf "    /* %-13s */ %s,\n",
+                        $op,
+                        join(', ', map(sprintf("0x%04x", $_), @bitdefs));
+            }
+            else {
+                $index = -1;
+            }
+            $PL_op_private_bitdef_ix .= sprintf "    %4d, /* %s */\n", $index, $op;
+        }
+        if (%not_seen) {
+            die "panic: unprocessed ops: ". join(',', keys %not_seen);
+        }
+    }
+
+
+    # generate PL_op_private_valid
+
+    for my $op (@ops) {
+        my $last;
+        my @flags;
+        for my $bit (0..7) {
+            next unless exists $FLAGS{$op};
+            my $entry = $FLAGS{$op}{$bit};
+            next unless defined $entry;
+            if (ref $entry) {
+                # skip later entries for the same bit field
+                next if defined $last and $last == $entry;
+                $last = $entry;
+                push @flags,
+                    defined $entry->{mask_def}
+                        ? $entry->{mask_def}
+                        : $entry->{bitmask};
+            }
+            else {
+                push @flags, $entry;
+            }
+        }
+
+        # all bets are off
+        @flags = '0xff' if $op eq 'null' or $op eq 'custom';
+
+        $PL_op_private_valid .= sprintf "    /* %-10s */ (%s),\n", uc($op),
+                                    @flags ? join('|', @flags): '0';
+    }
+
+    print $fh <<EOF;
+START_EXTERN_C
+
+#ifndef PERL_GLOBAL_STRUCT_INIT
+
+#  ifndef DOINIT
+
+/* data about the flags in op_private */
+
+EXTCONST I16  PL_op_private_bitdef_ix[];
+EXTCONST U16  PL_op_private_bitdefs[];
+EXTCONST char PL_op_private_labels[];
+EXTCONST I16  PL_op_private_bitfields[];
+EXTCONST U8   PL_op_private_valid[];
+
+#  else
+
+
+/* PL_op_private_labels[]: the short descriptions of private flags.
+ * All labels are concatenated into a single char array
+ * (separated by \\0's) for compactness.
+ */
+
+EXTCONST char PL_op_private_labels[] = {
+$PL_op_private_labels
+};
+
+
+
+/* PL_op_private_bitfields[]: details about each bit field type.
+ * Each defintition consists of the following list of words:
+ *    bitmin
+ *    label (index into PL_op_private_labels[]; -1 if no label)
+ *    repeat for each enum entry (if any):
+ *       enum value
+ *       enum label (index into PL_op_private_labels[])
+ *    -1
+ */
+
+EXTCONST I16 PL_op_private_bitfields[] = {
+$PL_op_private_bitfields
+};
+
+
+/* PL_op_private_bitdef_ix[]: map an op number to a starting position
+ * in PL_op_private_bitdefs.  If -1, the op has no bits defined */
+
+EXTCONST I16  PL_op_private_bitdef_ix[] = {
+$PL_op_private_bitdef_ix
+};
+
+
+
+/* PL_op_private_bitdefs[]: given a starting position in this array (as
+ * supplied by PL_op_private_bitdef_ix[]), each word (until a stop bit is
+ * seen) defines the meaning of a particular op_private bit for a
+ * particular op. Each word consists of:
+ *  bit  0:     stop bit: this is the last bit def for the current op
+ *  bit  1:     bitfield: if set, this defines a bit field rather than a flag
+ *  bits 2..4:  unsigned number in the range 0..7 which is the bit number
+ *  bits 5..15: unsigned number in the range 0..2047 which is an index
+ *              into PL_op_private_labels[]    (for a flag), or
+ *              into PL_op_private_bitfields[] (for a bit field)
+ */
+
+EXTCONST U16  PL_op_private_bitdefs[] = {
+$PL_op_private_bitdefs
+};
+
+
+/* PL_op_private_valid: for each op, indexed by op_type, indicate which
+ * flags bits in op_private are legal */
+
+EXTCONST U8 PL_op_private_valid[] = {
+$PL_op_private_valid
+};
+
+#  endif /* !DOINIT */
+#endif /* !PERL_GLOBAL_STRUCT_INIT */
+
+END_EXTERN_C
+
+
+EOF
+
+}
+
+
+# =================================================================
+
+
+package main;
+
+# read regen/op_private data
+#
+# This file contains Perl code that builds up some data structures
+# which define what bits in op_private have what meanings for each op.
+# It populates %LABELS, %DEFINES, %FLAGS, %BITFIELDS.
+
+require 'regen/op_private';
+
+#use Data::Dumper;
+#print Dumper \%LABELS, \%DEFINES, \%FLAGS, \%BITFIELDS;
+
+
 # Emit defines.
 
 print $oc    "#ifndef PERL_GLOBAL_STRUCT_INIT\n\n";
@@ -469,7 +1198,14 @@ my $pp = open_new('pp_proto.h', '>',
     }
     print $pp "PERL_CALLCONV OP *$_(pTHX);\n" foreach sort keys %funcs;
 }
-foreach ($oc, $on, $pp) {
+
+print $oc "\n\n";
+OP_PRIVATE::print_defines($oc);
+OP_PRIVATE::print_PL_op_private_tables($oc);
+
+OP_PRIVATE::print_B_Op_private($oprivpm);
+
+foreach ($oc, $on, $pp, $oprivpm) {
     read_only_bottom_close_and_rename($_);
 }
 
index 3198183..0c378cd 100644 (file)
@@ -20,7 +20,7 @@ if ( $Config{usecrosscompile} ) {
   skip_all( "Not all files are available during cross-compilation" );
 }
 
-my $tests = 25; # I can't see a clean way to calculate this automatically.
+my $tests = 26; # I can't see a clean way to calculate this automatically.
 
 my %skip = ("regen_perly.pl"    => [qw(perly.act perly.h perly.tab)],
             "regen/keywords.pl" => [qw(keywords.c keywords.h)],