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 make regen
. This will generate/update data in:
opcode.h
lib/B/Op_private.pm
B::Op_private
holds three global hashes, %bits
, %defines
, %labels
, which hold roughly the same information as found in this file (after processing).
opcode.h gains a series of OPp*
defines, and a few static data structures:
PL_op_private_valid
defines, per-op, which op_private bits are legally allowed to be set. This is a good first place to look to see if an op has any spare private bits.
PL_op_private_bitdef_ix
, PL_op_private_bitdefs
, PL_op_private_labels
, PL_op_private_bitfields
, 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 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),
6 => qw(OPpLVAL_DEFER LVDEFER),
'4..5' => {
mask_def => 'OPpDEREF',
enum => [ qw(
1 OPpDEREF_AV DREFAV
2 OPpDEREF_HV DREFHV
3 OPpDEREF_SV DREFSV
)],
},
);
Here for the op aelem
, bits 6 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 opcode.h, and the second string is the label, which will be displayed by Concise.pm and Perl_do_op_dump() (as used by 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 dividing 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 regen/opcodes based on various criteria. These are:
ops_with_check('ck_foo')
ops_with_flag('X')
ops_with_arg(N, 'XYZ')
which respectively 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 are 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 *_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 LABEL=
; so in this case it might display 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.