- LISTOP *op;
- OP *om, *oo;
- UV hint = indirect_hint();
-
- if (hint) {
- const char *pm, *po;
- SV *svm, *svo;
- op = (LISTOP *) o;
- while (op->op_type != OP_PUSHMARK)
- op = (LISTOP *) op->op_first;
- oo = op->op_sibling;
- om = oo;
- while (om->op_sibling)
- om = om->op_sibling;
- if (om->op_type == OP_METHOD)
- om = cUNOPx(om)->op_first;
- pm = indirect_map_fetch(om, &svm);
- po = indirect_map_fetch(oo, &svo);
- if (pm && po && pm < po && indirect_intuit(pm, po))
- ((hint == 2) ? croak : warn)(indirect_msg, SvPV_nolen(svm), SvPV_nolen(svo));
- }
-
- return CALL_FPTR(indirect_old_ck_entersub)(aTHX_ o);
+ SV *code = indirect_hint();
+
+ o = CALL_FPTR(indirect_old_ck_entersub)(aTHX_ o);
+
+ if (code) {
+ const indirect_op_info_t *moi, *ooi;
+ OP *mop, *oop;
+ LISTOP *lop;
+
+ oop = o;
+ do {
+ lop = (LISTOP *) oop;
+ if (!(lop->op_flags & OPf_KIDS))
+ goto done;
+ oop = lop->op_first;
+ } while (oop->op_type != OP_PUSHMARK);
+ oop = oop->op_sibling;
+ mop = lop->op_last;
+
+ if (!oop)
+ goto done;
+
+ switch (oop->op_type) {
+ case OP_CONST:
+ case OP_RV2SV:
+ case OP_PADSV:
+ case OP_SCOPE:
+ case OP_LEAVE:
+ break;
+ default:
+ goto done;
+ }
+
+ if (mop->op_type == OP_METHOD)
+ mop = cUNOPx(mop)->op_first;
+ else if (mop->op_type != OP_METHOD_NAMED)
+ goto done;
+
+ moi = indirect_map_fetch(mop);
+ if (!(moi && moi->pos))
+ goto done;
+
+ ooi = indirect_map_fetch(oop);
+ if (!(ooi && ooi->pos))
+ goto done;
+
+ if (indirect_is_indirect(moi, ooi)) {
+ SV *file;
+ dSP;
+
+ ENTER;
+ SAVETMPS;
+
+#ifdef USE_ITHREADS
+ file = sv_2mortal(newSVpv(CopFILE(&PL_compiling), 0));
+#else
+ file = sv_mortalcopy(CopFILESV(&PL_compiling));
+#endif
+
+ PUSHMARK(SP);
+ EXTEND(SP, 4);
+ mPUSHp(ooi->buf, ooi->len);
+ mPUSHp(moi->buf, moi->len);
+ PUSHs(file);
+ mPUSHu(moi->line);
+ PUTBACK;
+
+ call_sv(code, G_VOID);
+
+ PUTBACK;
+
+ FREETMPS;
+ LEAVE;
+ }
+ }
+
+done:
+ return o;
+}
+
+STATIC U32 indirect_initialized = 0;
+
+STATIC void indirect_teardown(pTHX_ void *root) {
+ dMY_CXT;
+
+ if (!indirect_initialized)
+ return;
+
+#if I_MULTIPLICITY
+ if (aTHX != root)
+ return;
+#endif
+
+ ptable_free(MY_CXT.map);
+#if I_THREADSAFE
+ ptable_hints_free(MY_CXT.tbl);
+#endif
+
+ PL_check[OP_CONST] = MEMBER_TO_FPTR(indirect_old_ck_const);
+ indirect_old_ck_const = 0;
+ PL_check[OP_RV2SV] = MEMBER_TO_FPTR(indirect_old_ck_rv2sv);
+ indirect_old_ck_rv2sv = 0;
+ PL_check[OP_PADANY] = MEMBER_TO_FPTR(indirect_old_ck_padany);
+ indirect_old_ck_padany = 0;
+ PL_check[OP_SCOPE] = MEMBER_TO_FPTR(indirect_old_ck_scope);
+ indirect_old_ck_scope = 0;
+ PL_check[OP_LINESEQ] = MEMBER_TO_FPTR(indirect_old_ck_lineseq);
+ indirect_old_ck_lineseq = 0;
+
+ PL_check[OP_METHOD] = MEMBER_TO_FPTR(indirect_old_ck_method);
+ indirect_old_ck_method = 0;
+ PL_check[OP_ENTERSUB] = MEMBER_TO_FPTR(indirect_old_ck_entersub);
+ indirect_old_ck_entersub = 0;
+
+ indirect_initialized = 0;
+}
+
+STATIC void indirect_setup(pTHX) {
+#define indirect_setup() indirect_setup(aTHX)
+ if (indirect_initialized)
+ return;
+
+ {
+ MY_CXT_INIT;
+#if I_THREADSAFE
+ MY_CXT.tbl = ptable_new();
+ MY_CXT.owner = aTHX;
+#endif
+ MY_CXT.map = ptable_new();
+ MY_CXT.linestr = NULL;
+ }
+
+ indirect_old_ck_const = PL_check[OP_CONST];
+ PL_check[OP_CONST] = MEMBER_TO_FPTR(indirect_ck_const);
+ indirect_old_ck_rv2sv = PL_check[OP_RV2SV];
+ PL_check[OP_RV2SV] = MEMBER_TO_FPTR(indirect_ck_rv2sv);
+ indirect_old_ck_padany = PL_check[OP_PADANY];
+ PL_check[OP_PADANY] = MEMBER_TO_FPTR(indirect_ck_padany);
+ indirect_old_ck_scope = PL_check[OP_SCOPE];
+ PL_check[OP_SCOPE] = MEMBER_TO_FPTR(indirect_ck_scope);
+ indirect_old_ck_lineseq = PL_check[OP_LINESEQ];
+ PL_check[OP_LINESEQ] = MEMBER_TO_FPTR(indirect_ck_scope);
+
+ indirect_old_ck_method = PL_check[OP_METHOD];
+ PL_check[OP_METHOD] = MEMBER_TO_FPTR(indirect_ck_method);
+ indirect_old_ck_entersub = PL_check[OP_ENTERSUB];
+ PL_check[OP_ENTERSUB] = MEMBER_TO_FPTR(indirect_ck_entersub);
+
+#if I_MULTIPLICITY
+ call_atexit(indirect_teardown, aTHX);
+#else
+ call_atexit(indirect_teardown, NULL);
+#endif
+
+ indirect_initialized = 1;