+
+/*
+ * The per-CV op slabs consist of a header (the opslab struct) and a bunch
+ * of space for allocating op slots, each of which consists of two pointers
+ * followed by an op. The first pointer points to the next op slot. The
+ * second points to the slab. At the end of the slab is a null pointer,
+ * so that slot->opslot_next - slot can be used to determine the size
+ * of the op.
+ *
+ * Each CV can have multiple slabs; opslab_next points to the next slab, to
+ * form a chain. All bookkeeping is done on the first slab, which is where
+ * all the op slots point.
+ *
+ * Freed ops are marked as freed and attached to the freed chain
+ * via op_next pointers.
+ *
+ * When there is more than one slab, the second slab in the slab chain is
+ * assumed to be the one with free space available. It is used when allo-
+ * cating an op if there are no freed ops available or big enough.
+ */
+
+#ifdef PERL_CORE
+struct opslot {
+ /* keep opslot_next first */
+ OPSLOT * opslot_next; /* next slot */
+ OPSLAB * opslot_slab; /* owner */
+ OP opslot_op; /* the op itself */
+};
+
+struct opslab {
+ OPSLOT * opslab_first; /* first op in this slab */
+ OPSLAB * opslab_next; /* next slab */
+ OP * opslab_freed; /* chain of freed ops */
+ size_t opslab_refcnt; /* number of ops */
+# ifdef PERL_DEBUG_READONLY_OPS
+ U16 opslab_size; /* size of slab in pointers */
+ bool opslab_readonly;
+# endif
+ OPSLOT opslab_slots; /* slots begin here */
+};
+
+# define OPSLOT_HEADER STRUCT_OFFSET(OPSLOT, opslot_op)
+# define OPSLOT_HEADER_P (OPSLOT_HEADER/sizeof(I32 *))
+# define OpSLOT(o) (assert_(o->op_slabbed) \
+ (OPSLOT *)(((char *)o)-OPSLOT_HEADER))
+# define OpSLAB(o) OpSLOT(o)->opslot_slab
+# define OpslabREFCNT_dec(slab) \
+ (((slab)->opslab_refcnt == 1) \
+ ? opslab_free_nopad(slab) \
+ : (void)--(slab)->opslab_refcnt)
+ /* Variant that does not null out the pads */
+# define OpslabREFCNT_dec_padok(slab) \
+ (((slab)->opslab_refcnt == 1) \
+ ? opslab_free(slab) \
+ : (void)--(slab)->opslab_refcnt)
+#endif
+
+struct block_hooks {
+ U32 bhk_flags;
+ void (*bhk_start) (pTHX_ int full);
+ void (*bhk_pre_end) (pTHX_ OP **seq);
+ void (*bhk_post_end) (pTHX_ OP **seq);
+ void (*bhk_eval) (pTHX_ OP *const saveop);
+};
+
+/*
+=head1 Compile-time scope hooks
+
+=for apidoc mx|U32|BhkFLAGS|BHK *hk
+Return the BHK's flags.
+
+=for apidoc mx|void *|BhkENTRY|BHK *hk|which
+Return an entry from the BHK structure. I<which> is a preprocessor token
+indicating which entry to return. If the appropriate flag is not set
+this will return NULL. The type of the return value depends on which
+entry you ask for.
+
+=for apidoc Amx|void|BhkENTRY_set|BHK *hk|which|void *ptr
+Set an entry in the BHK structure, and set the flags to indicate it is
+valid. I<which> is a preprocessing token indicating which entry to set.
+The type of I<ptr> depends on the entry.
+
+=for apidoc Amx|void|BhkDISABLE|BHK *hk|which
+Temporarily disable an entry in this BHK structure, by clearing the
+appropriate flag. I<which> is a preprocessor token indicating which
+entry to disable.
+
+=for apidoc Amx|void|BhkENABLE|BHK *hk|which
+Re-enable an entry in this BHK structure, by setting the appropriate
+flag. I<which> is a preprocessor token indicating which entry to enable.
+This will assert (under -DDEBUGGING) if the entry doesn't contain a valid
+pointer.
+
+=for apidoc mx|void|CALL_BLOCK_HOOKS|which|arg
+Call all the registered block hooks for type I<which>. I<which> is a
+preprocessing token; the type of I<arg> depends on I<which>.
+
+=cut
+*/
+
+#define BhkFLAGS(hk) ((hk)->bhk_flags)
+
+#define BHKf_bhk_start 0x01
+#define BHKf_bhk_pre_end 0x02
+#define BHKf_bhk_post_end 0x04
+#define BHKf_bhk_eval 0x08
+
+#define BhkENTRY(hk, which) \
+ ((BhkFLAGS(hk) & BHKf_ ## which) ? ((hk)->which) : NULL)
+
+#define BhkENABLE(hk, which) \
+ STMT_START { \
+ BhkFLAGS(hk) |= BHKf_ ## which; \
+ assert(BhkENTRY(hk, which)); \
+ } STMT_END
+
+#define BhkDISABLE(hk, which) \
+ STMT_START { \
+ BhkFLAGS(hk) &= ~(BHKf_ ## which); \
+ } STMT_END
+
+#define BhkENTRY_set(hk, which, ptr) \
+ STMT_START { \
+ (hk)->which = ptr; \
+ BhkENABLE(hk, which); \
+ } STMT_END
+
+#define CALL_BLOCK_HOOKS(which, arg) \
+ STMT_START { \
+ if (PL_blockhooks) { \
+ I32 i; \
+ for (i = av_len(PL_blockhooks); i >= 0; i--) { \
+ SV *sv = AvARRAY(PL_blockhooks)[i]; \
+ BHK *hk; \
+ \
+ assert(SvIOK(sv)); \
+ if (SvUOK(sv)) \
+ hk = INT2PTR(BHK *, SvUVX(sv)); \
+ else \
+ hk = INT2PTR(BHK *, SvIVX(sv)); \
+ \
+ if (BhkENTRY(hk, which)) \
+ BhkENTRY(hk, which)(aTHX_ arg); \
+ } \
+ } \
+ } STMT_END
+
+/* flags for rv2cv_op_cv */
+
+#define RV2CVOPCV_MARK_EARLY 0x00000001
+#define RV2CVOPCV_RETURN_NAME_GV 0x00000002
+
+#define op_lvalue(op,t) Perl_op_lvalue_flags(aTHX_ op,t,0)
+
+/* flags for op_lvalue_flags */
+
+#define OP_LVALUE_NO_CROAK 1
+
+/*
+=head1 Custom Operators
+
+=for apidoc Am|U32|XopFLAGS|XOP *xop
+Return the XOP's flags.
+
+=for apidoc Am||XopENTRY|XOP *xop|which
+Return a member of the XOP structure. I<which> is a cpp token indicating
+which entry to return. If the member is not set this will return a
+default value. The return type depends on I<which>.
+
+=for apidoc Am|void|XopENTRY_set|XOP *xop|which|value
+Set a member of the XOP structure. I<which> is a cpp token indicating
+which entry to set. See L<perlguts/"Custom Operators"> for details about
+the available members and how they are used.
+
+=for apidoc Am|void|XopDISABLE|XOP *xop|which
+Temporarily disable a member of the XOP, by clearing the appropriate flag.
+
+=for apidoc Am|void|XopENABLE|XOP *xop|which
+Reenable a member of the XOP which has been disabled.
+
+=cut
+*/
+
+struct custom_op {
+ U32 xop_flags;
+ const char *xop_name;
+ const char *xop_desc;
+ U32 xop_class;
+ void (*xop_peep)(pTHX_ OP *o, OP *oldop);
+};
+
+#define XopFLAGS(xop) ((xop)->xop_flags)
+
+#define XOPf_xop_name 0x01
+#define XOPf_xop_desc 0x02
+#define XOPf_xop_class 0x04
+#define XOPf_xop_peep 0x08
+
+#define XOPd_xop_name PL_op_name[OP_CUSTOM]
+#define XOPd_xop_desc PL_op_desc[OP_CUSTOM]
+#define XOPd_xop_class OA_BASEOP
+#define XOPd_xop_peep ((Perl_cpeep_t)0)
+
+#define XopENTRY_set(xop, which, to) \
+ STMT_START { \
+ (xop)->which = (to); \
+ (xop)->xop_flags |= XOPf_ ## which; \
+ } STMT_END
+
+#define XopENTRY(xop, which) \
+ ((XopFLAGS(xop) & XOPf_ ## which) ? (xop)->which : XOPd_ ## which)
+
+#define XopDISABLE(xop, which) ((xop)->xop_flags &= ~XOPf_ ## which)
+#define XopENABLE(xop, which) \
+ STMT_START { \
+ (xop)->xop_flags |= XOPf_ ## which; \
+ assert(XopENTRY(xop, which)); \
+ } STMT_END
+
+/*
+=head1 Optree Manipulation Functions
+
+=for apidoc Am|const char *|OP_NAME|OP *o
+Return the name of the provided OP. For core ops this looks up the name
+from the op_type; for custom ops from the op_ppaddr.
+
+=for apidoc Am|const char *|OP_DESC|OP *o
+Return a short description of the provided OP.
+
+=for apidoc Am|U32|OP_CLASS|OP *o
+Return the class of the provided OP: that is, which of the *OP
+structures it uses. For core ops this currently gets the information out
+of PL_opargs, which does not always accurately reflect the type used.
+For custom ops the type is returned from the registration, and it is up
+to the registree to ensure it is accurate. The value returned will be
+one of the OA_* constants from op.h.
+
+=cut
+*/
+
+#define OP_NAME(o) ((o)->op_type == OP_CUSTOM \
+ ? XopENTRY(Perl_custom_op_xop(aTHX_ o), xop_name) \
+ : PL_op_name[(o)->op_type])
+#define OP_DESC(o) ((o)->op_type == OP_CUSTOM \
+ ? XopENTRY(Perl_custom_op_xop(aTHX_ o), xop_desc) \
+ : PL_op_desc[(o)->op_type])
+#define OP_CLASS(o) ((o)->op_type == OP_CUSTOM \
+ ? XopENTRY(Perl_custom_op_xop(aTHX_ o), xop_class) \
+ : (PL_opargs[(o)->op_type] & OA_CLASS_MASK))
+
+#define newSUB(f, o, p, b) Perl_newATTRSUB(aTHX_ (f), (o), (p), NULL, (b))
+
+#ifdef PERL_MAD
+# define MAD_NULL 1
+# define MAD_PV 2
+# define MAD_OP 3
+# define MAD_SV 4
+
+struct madprop {
+ MADPROP* mad_next;
+ void *mad_val;
+ U32 mad_vlen;
+/* short mad_count; */
+ char mad_key;
+ char mad_type;
+};
+
+struct token {
+ I32 tk_type;
+ YYSTYPE tk_lval;
+ MADPROP* tk_mad;
+};
+#endif
+
+/*
+ * Values that can be held by mad_key :
+ * ^ unfilled head spot
+ * , literal ,
+ * ; literal ; (blank if implicit ; at end of block)
+ * : literal : from ?: or attr list
+ * + unary +
+ * ? literal ? from ?:
+ * ( literal (
+ * ) literal )
+ * [ literal [
+ * ] literal ]
+ * { literal {
+ * } literal }
+ * @ literal @ sigil
+ * $ literal $ sigil
+ * * literal * sigil
+ * ! use is source filtered
+ * & & or sub
+ * # whitespace/comment following ; or }
+ * # $# sigil
+ * 1 1st ; from for(;;)
+ * 1 retired protasis
+ * 2 2nd ; from for(;;)
+ * 2 retired apodosis
+ * 3 C-style for list
+ * a sub or var attributes
+ * a non-method arrow operator
+ * A method arrow operator
+ * A use import args
+ * b format block
+ * B retired stub block
+ * C constant conditional op
+ * d declarator
+ * D do block
+ * e unreached "else" (see C)
+ * e expression producing E
+ * E tr/E/R/, /E/
+ * f folded constant op
+ * F peg op for format
+ * g op was forced to be a word
+ * i if/unless modifier
+ * I if/elsif/unless statement
+ * k local declarator
+ * K retired kid op
+ * l last index of array ($#foo)
+ * L label
+ * m modifier on regex
+ * n sub or format name
+ * o current operator/declarator name
+ * o else/continue
+ * O generic optimized op
+ * p peg to hold extra whitespace at statement level
+ * P peg op for package declaration
+ * q opening quote
+ * = quoted material
+ * Q closing quote
+ * Q optimized qw//
+ * r expression producing R
+ * R tr/E/R/ s/E/R/
+ * s sub signature
+ * S use import stub (no import)
+ * S retired sort block
+ * t unreached "then" (see C)
+ * U use import op
+ * v private sv of for loop
+ * V use version
+ * w while/until modifier
+ * W while/for statement
+ * x optimized qw
+ * X random thing
+ * _ whitespace/comments preceding anything else
+ * ~ =~ operator
+ */
+
+/*
+=head1 Hook manipulation
+*/
+
+#ifdef USE_ITHREADS
+# define OP_CHECK_MUTEX_INIT MUTEX_INIT(&PL_check_mutex)
+# define OP_CHECK_MUTEX_LOCK MUTEX_LOCK(&PL_check_mutex)
+# define OP_CHECK_MUTEX_UNLOCK MUTEX_UNLOCK(&PL_check_mutex)
+# define OP_CHECK_MUTEX_TERM MUTEX_DESTROY(&PL_check_mutex)