+/* ... OP info ............................................................. */
+
+#define VMG_OP_INFO_NAME 1
+#define VMG_OP_INFO_OBJECT 2
+
+STATIC U32 vmg_op_name_refcnt = 0;
+STATIC STRLEN *vmg_op_name_len = NULL;
+
+STATIC HV *vmg_b__op_stash = NULL;
+
+STATIC void vmg_op_info_init(pTHX_ unsigned int opinfo) {
+#define vmg_op_info_init(W) vmg_op_info_init(aTHX_ (W))
+ switch (opinfo) {
+ case VMG_OP_INFO_NAME:
+ if (!vmg_op_name_len) {
+ OPCODE t;
+ Newx(vmg_op_name_len, MAXO, STRLEN);
+ for (t = 0; t < OP_max; ++t)
+ vmg_op_name_len[t] = strlen(PL_op_name[t]);
+ }
+ ++vmg_op_name_refcnt;
+ break;
+ case VMG_OP_INFO_OBJECT:
+ if (!vmg_b__op_stash) {
+ require_pv("B.pm");
+ vmg_b__op_stash = gv_stashpv("B::OP", 1);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+STATIC void vmg_op_info_deinit(unsigned int opinfo) {
+ switch (opinfo) {
+ case VMG_OP_INFO_NAME:
+ if (vmg_op_name_refcnt > 0)
+ --vmg_op_name_refcnt;
+ if (!vmg_op_name_refcnt && vmg_op_name_len) {
+ Safefree(vmg_op_name_len);
+ vmg_op_name_len = NULL;
+ }
+ break;
+ case VMG_OP_INFO_OBJECT:
+ default:
+ break;
+ }
+}
+
+STATIC SV *vmg_op_info(pTHX_ unsigned int opinfo) {
+#define vmg_op_info(W) vmg_op_info(aTHX_ (W))
+ if (!PL_op)
+ return &PL_sv_undef;
+
+ switch (opinfo) {
+ case VMG_OP_INFO_NAME: {
+ OPCODE t = PL_op->op_type;
+ return sv_2mortal(newSVpvn(PL_op_name[t], vmg_op_name_len[t]));
+ }
+ case VMG_OP_INFO_OBJECT:
+ return sv_bless(sv_2mortal(newRV_noinc(newSViv(PTR2IV(PL_op)))),
+ vmg_b__op_stash);
+ default:
+ break;
+ }
+
+ return &PL_sv_undef;
+}
+