]> git.vpit.fr Git - perl/modules/indirect.git/blob - indirect.xs
Get rid of the linestr check
[perl/modules/indirect.git] / indirect.xs
1 /* This file is part of the indirect Perl module.
2  * See http://search.cpan.org/dist/indirect/ */
3
4 #define PERL_NO_GET_CONTEXT
5 #include "EXTERN.h"
6 #include "perl.h"
7 #include "XSUB.h"
8
9 #define __PACKAGE__     "indirect"
10 #define __PACKAGE_LEN__ (sizeof(__PACKAGE__)-1)
11
12 /* --- Compatibility wrappers ---------------------------------------------- */
13
14 #ifndef NOOP
15 # define NOOP
16 #endif
17
18 #ifndef dNOOP
19 # define dNOOP
20 #endif
21
22 #ifndef Newx
23 # define Newx(v, n, c) New(0, v, n, c)
24 #endif
25
26 #ifndef SvPV_const
27 # define SvPV_const SvPV
28 #endif
29
30 #ifndef SvPV_nolen_const
31 # define SvPV_nolen_const SvPV_nolen
32 #endif
33
34 #ifndef SvPVX_const
35 # define SvPVX_const SvPVX
36 #endif
37
38 #ifndef SvREFCNT_inc_simple_NN
39 # define SvREFCNT_inc_simple_NN SvREFCNT_inc
40 #endif
41
42 #ifndef sv_catpvn_nomg
43 # define sv_catpvn_nomg sv_catpvn
44 #endif
45
46 #ifndef mPUSHp
47 # define mPUSHp(P, L) PUSHs(sv_2mortal(newSVpvn((P), (L))))
48 #endif
49
50 #ifndef mPUSHu
51 # define mPUSHu(U) PUSHs(sv_2mortal(newSVuv(U)))
52 #endif
53
54 #ifndef HvNAME_get
55 # define HvNAME_get(H) HvNAME(H)
56 #endif
57
58 #ifndef HvNAMELEN_get
59 # define HvNAMELEN_get(H) strlen(HvNAME_get(H))
60 #endif
61
62 #define I_HAS_PERL(R, V, S) (PERL_REVISION > (R) || (PERL_REVISION == (R) && (PERL_VERSION > (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION >= (S))))))
63
64 #if I_HAS_PERL(5, 10, 0) || defined(PL_parser)
65 # ifndef PL_bufptr
66 #  define PL_bufptr PL_parser->bufptr
67 # endif
68 # ifndef PL_oldbufptr
69 #  define PL_oldbufptr PL_parser->oldbufptr
70 # endif
71 #else
72 # ifndef PL_bufptr
73 #  define PL_bufptr PL_Ibufptr
74 # endif
75 # ifndef PL_oldbufptr
76 #  define PL_oldbufptr PL_Ioldbufptr
77 # endif
78 #endif
79
80 #ifndef I_WORKAROUND_REQUIRE_PROPAGATION
81 # define I_WORKAROUND_REQUIRE_PROPAGATION !I_HAS_PERL(5, 10, 1)
82 #endif
83
84 /* ... Thread safety and multiplicity ...................................... */
85
86 /* Safe unless stated otherwise in Makefile.PL */
87 #ifndef I_FORKSAFE
88 # define I_FORKSAFE 1
89 #endif
90
91 #ifndef I_MULTIPLICITY
92 # if defined(MULTIPLICITY) || defined(PERL_IMPLICIT_CONTEXT)
93 #  define I_MULTIPLICITY 1
94 # else
95 #  define I_MULTIPLICITY 0
96 # endif
97 #endif
98 #if I_MULTIPLICITY && !defined(tTHX)
99 # define tTHX PerlInterpreter*
100 #endif
101
102 #if I_MULTIPLICITY && defined(USE_ITHREADS) && defined(dMY_CXT) && defined(MY_CXT) && defined(START_MY_CXT) && defined(MY_CXT_INIT) && (defined(MY_CXT_CLONE) || defined(dMY_CXT_SV))
103 # define I_THREADSAFE 1
104 # ifndef MY_CXT_CLONE
105 #  define MY_CXT_CLONE \
106     dMY_CXT_SV;                                                      \
107     my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1)); \
108     Copy(INT2PTR(my_cxt_t*, SvUV(my_cxt_sv)), my_cxtp, 1, my_cxt_t); \
109     sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
110 # endif
111 #else
112 # define I_THREADSAFE 0
113 # undef  dMY_CXT
114 # define dMY_CXT      dNOOP
115 # undef  MY_CXT
116 # define MY_CXT       indirect_globaldata
117 # undef  START_MY_CXT
118 # define START_MY_CXT STATIC my_cxt_t MY_CXT;
119 # undef  MY_CXT_INIT
120 # define MY_CXT_INIT  NOOP
121 # undef  MY_CXT_CLONE
122 # define MY_CXT_CLONE NOOP
123 #endif
124
125 /* --- Helpers ------------------------------------------------------------- */
126
127 /* ... Thread-safe hints ................................................... */
128
129 #if I_WORKAROUND_REQUIRE_PROPAGATION
130
131 typedef struct {
132  SV *code;
133  IV  require_tag;
134 } indirect_hint_t;
135
136 #define I_HINT_STRUCT 1
137
138 #define I_HINT_CODE(H) ((H)->code)
139
140 #define I_HINT_FREE(H) {   \
141  indirect_hint_t *h = (H); \
142  SvREFCNT_dec(h->code);    \
143  PerlMemShared_free(h);    \
144 }
145
146 #else  /*  I_WORKAROUND_REQUIRE_PROPAGATION */
147
148 typedef SV indirect_hint_t;
149
150 #define I_HINT_STRUCT 0
151
152 #define I_HINT_CODE(H) (H)
153
154 #define I_HINT_FREE(H) SvREFCNT_dec(H);
155
156 #endif /* !I_WORKAROUND_REQUIRE_PROPAGATION */
157
158 #if I_THREADSAFE
159
160 #define PTABLE_NAME        ptable_hints
161 #define PTABLE_VAL_FREE(V) I_HINT_FREE(V)
162
163 #define pPTBL  pTHX
164 #define pPTBL_ pTHX_
165 #define aPTBL  aTHX
166 #define aPTBL_ aTHX_
167
168 #include "ptable.h"
169
170 #define ptable_hints_store(T, K, V) ptable_hints_store(aTHX_ (T), (K), (V))
171 #define ptable_hints_free(T)        ptable_hints_free(aTHX_ (T))
172
173 #endif /* I_THREADSAFE */
174
175 /* Define the op->str ptable here because we need to be able to clean it during
176  * thread cleanup. */
177
178 typedef struct {
179  const char *pos;
180  char       *buf;
181  STRLEN      len, size;
182  line_t      line;
183 } indirect_op_info_t;
184
185 #define PTABLE_NAME        ptable
186 #define PTABLE_VAL_FREE(V) if (V) { Safefree(((indirect_op_info_t *) (V))->buf); Safefree(V); }
187
188 #define pPTBL  pTHX
189 #define pPTBL_ pTHX_
190 #define aPTBL  aTHX
191 #define aPTBL_ aTHX_
192
193 #include "ptable.h"
194
195 #define ptable_store(T, K, V) ptable_store(aTHX_ (T), (K), (V))
196 #define ptable_clear(T)       ptable_clear(aTHX_ (T))
197 #define ptable_free(T)        ptable_free(aTHX_ (T))
198
199 #define MY_CXT_KEY __PACKAGE__ "::_guts" XS_VERSION
200
201 typedef struct {
202 #if I_THREADSAFE
203  ptable *tbl; /* It really is a ptable_hints */
204  tTHX    owner;
205 #endif
206  ptable *map;
207 } my_cxt_t;
208
209 START_MY_CXT
210
211 #if I_THREADSAFE
212
213 STATIC SV *indirect_clone(pTHX_ SV *sv, tTHX owner) {
214 #define indirect_clone(S, O) indirect_clone(aTHX_ (S), (O))
215  CLONE_PARAMS  param;
216  AV           *stashes = NULL;
217  SV           *dupsv;
218
219  if (SvTYPE(sv) == SVt_PVHV && HvNAME_get(sv))
220   stashes = newAV();
221
222  param.stashes    = stashes;
223  param.flags      = 0;
224  param.proto_perl = owner;
225
226  dupsv = sv_dup(sv, &param);
227
228  if (stashes) {
229   av_undef(stashes);
230   SvREFCNT_dec(stashes);
231  }
232
233  return SvREFCNT_inc(dupsv);
234 }
235
236 STATIC void indirect_ptable_clone(pTHX_ ptable_ent *ent, void *ud_) {
237  my_cxt_t        *ud = ud_;
238  indirect_hint_t *h1 = ent->val;
239  indirect_hint_t *h2;
240
241  if (ud->owner == aTHX)
242   return;
243
244 #if I_HINT_STRUCT
245
246  h2       = PerlMemShared_malloc(sizeof *h2);
247  h2->code = indirect_clone(h1->code, ud->owner);
248  SvREFCNT_inc(h2->code);
249 #if I_WORKAROUND_REQUIRE_PROPAGATION
250  h2->require_tag = PTR2IV(indirect_clone(INT2PTR(SV *, h1->require_tag),
251                                          ud->owner));
252 #endif
253
254 #else  /*  I_HINT_STRUCT */
255
256  h2 = indirect_clone(h1, ud->owner);
257  SvREFCNT_inc(h2);
258
259 #endif /* !I_HINT_STRUCT */
260
261  ptable_hints_store(ud->tbl, ent->key, h2);
262 }
263
264 #include "reap.h"
265
266 STATIC void indirect_thread_cleanup(pTHX_ void *ud) {
267  dMY_CXT;
268
269  ptable_free(MY_CXT.map);
270  ptable_hints_free(MY_CXT.tbl);
271 }
272
273 #endif /* I_THREADSAFE */
274
275 #if I_WORKAROUND_REQUIRE_PROPAGATION
276 STATIC IV indirect_require_tag(pTHX) {
277 #define indirect_require_tag() indirect_require_tag(aTHX)
278  const CV *cv, *outside;
279
280  cv = PL_compcv;
281
282  if (!cv) {
283   /* If for some reason the pragma is operational at run-time, try to discover
284    * the current cv in use. */
285   const PERL_SI *si;
286
287   for (si = PL_curstackinfo; si; si = si->si_prev) {
288    I32 cxix;
289
290    for (cxix = si->si_cxix; cxix >= 0; --cxix) {
291     const PERL_CONTEXT *cx = si->si_cxstack + cxix;
292
293     switch (CxTYPE(cx)) {
294      case CXt_SUB:
295      case CXt_FORMAT:
296       /* The propagation workaround is only needed up to 5.10.0 and at that
297        * time format and sub contexts were still identical. And even later the
298        * cv members offsets should have been kept the same. */
299       cv = cx->blk_sub.cv;
300       goto get_enclosing_cv;
301      case CXt_EVAL:
302       cv = cx->blk_eval.cv;
303       goto get_enclosing_cv;
304      default:
305       break;
306     }
307    }
308   }
309
310   cv = PL_main_cv;
311  }
312
313 get_enclosing_cv:
314  for (outside = CvOUTSIDE(cv); outside; outside = CvOUTSIDE(cv))
315   cv = outside;
316
317  return PTR2IV(cv);
318 }
319 #endif /* I_WORKAROUND_REQUIRE_PROPAGATION */
320
321 STATIC SV *indirect_tag(pTHX_ SV *value) {
322 #define indirect_tag(V) indirect_tag(aTHX_ (V))
323  indirect_hint_t *h;
324  SV *code = NULL;
325  dMY_CXT;
326
327  if (SvROK(value)) {
328   value = SvRV(value);
329   if (SvTYPE(value) >= SVt_PVCV) {
330    code = value;
331    SvREFCNT_inc_simple_NN(code);
332   }
333  }
334
335 #if I_HINT_STRUCT
336  h = PerlMemShared_malloc(sizeof *h);
337  h->code        = code;
338 # if I_WORKAROUND_REQUIRE_PROPAGATION
339  h->require_tag = indirect_require_tag();
340 # endif /* I_WORKAROUND_REQUIRE_PROPAGATION */
341 #else  /*  I_HINT_STRUCT */
342  h = code;
343 #endif /* !I_HINT_STRUCT */
344
345 #if I_THREADSAFE
346  /* We only need for the key to be an unique tag for looking up the value later.
347   * Allocated memory provides convenient unique identifiers, so that's why we
348   * use the hint as the key itself. */
349  ptable_hints_store(MY_CXT.tbl, h, h);
350 #endif /* I_THREADSAFE */
351
352  return newSViv(PTR2IV(h));
353 }
354
355 STATIC SV *indirect_detag(pTHX_ const SV *hint) {
356 #define indirect_detag(H) indirect_detag(aTHX_ (H))
357  indirect_hint_t *h;
358  dMY_CXT;
359
360  if (!(hint && SvIOK(hint)))
361   return NULL;
362
363  h = INT2PTR(indirect_hint_t *, SvIVX(hint));
364 #if I_THREADSAFE
365  h = ptable_fetch(MY_CXT.tbl, h);
366 #endif /* I_THREADSAFE */
367
368 #if I_WORKAROUND_REQUIRE_PROPAGATION
369  if (indirect_require_tag() != h->require_tag)
370   return NULL;
371 #endif /* I_WORKAROUND_REQUIRE_PROPAGATION */
372
373  return I_HINT_CODE(h);
374 }
375
376 STATIC U32 indirect_hash = 0;
377
378 STATIC SV *indirect_hint(pTHX) {
379 #define indirect_hint() indirect_hint(aTHX)
380  SV *hint;
381
382  if (IN_PERL_RUNTIME)
383   return NULL;
384
385 #if I_HAS_PERL(5, 9, 5)
386  hint = Perl_refcounted_he_fetch(aTHX_ PL_curcop->cop_hints_hash,
387                                        NULL,
388                                        __PACKAGE__, __PACKAGE_LEN__,
389                                        0,
390                                        indirect_hash);
391 #else
392  {
393   SV **val = hv_fetch(GvHV(PL_hintgv), __PACKAGE__, __PACKAGE_LEN__,
394                                                                  indirect_hash);
395   if (!val)
396    return 0;
397   hint = *val;
398  }
399 #endif
400  return indirect_detag(hint);
401 }
402
403 /* ... op -> source position ............................................... */
404
405 STATIC void indirect_map_store(pTHX_ const OP *o, const char *src, SV *sv, line_t line) {
406 #define indirect_map_store(O, S, N, L) indirect_map_store(aTHX_ (O), (S), (N), (L))
407  indirect_op_info_t *oi;
408  const char *s;
409  STRLEN len;
410  dMY_CXT;
411
412  if (!(oi = ptable_fetch(MY_CXT.map, o))) {
413   Newx(oi, 1, indirect_op_info_t);
414   ptable_store(MY_CXT.map, o, oi);
415   oi->buf  = NULL;
416   oi->size = 0;
417  }
418
419  if (sv) {
420   s = SvPV_const(sv, len);
421  } else {
422   s   = "{";
423   len = 1;
424  }
425
426  if (len > oi->size) {
427   Safefree(oi->buf);
428   Newx(oi->buf, len, char);
429   oi->size = len;
430  }
431  Copy(s, oi->buf, len, char);
432
433  oi->len  = len;
434  oi->pos  = src;
435  oi->line = line;
436 }
437
438 STATIC const indirect_op_info_t *indirect_map_fetch(pTHX_ const OP *o) {
439 #define indirect_map_fetch(O) indirect_map_fetch(aTHX_ (O))
440  dMY_CXT;
441
442  return ptable_fetch(MY_CXT.map, o);
443 }
444
445 STATIC void indirect_map_delete(pTHX_ const OP *o) {
446 #define indirect_map_delete(O) indirect_map_delete(aTHX_ (O))
447  dMY_CXT;
448
449  ptable_store(MY_CXT.map, o, NULL);
450 }
451
452 /* --- Check functions ----------------------------------------------------- */
453
454 STATIC const char *indirect_find(pTHX_ SV *sv, const char *s) {
455 #define indirect_find(N, S) indirect_find(aTHX_ (N), (S))
456  STRLEN len;
457  const char *p = NULL, *r = SvPV_const(sv, len);
458
459  if (len >= 1 && *r == '$') {
460   ++r;
461   --len;
462   s = strchr(s, '$');
463   if (!s)
464    return NULL;
465  }
466
467  p = strstr(s, r);
468  while (p) {
469   p += len;
470   if (!isALNUM(*p))
471    break;
472   p = strstr(p + 1, r);
473  }
474
475  return p;
476 }
477
478 /* ... ck_const ............................................................ */
479
480 STATIC OP *(*indirect_old_ck_const)(pTHX_ OP *) = 0;
481
482 STATIC OP *indirect_ck_const(pTHX_ OP *o) {
483  o = CALL_FPTR(indirect_old_ck_const)(aTHX_ o);
484
485  if (indirect_hint()) {
486   SV *sv = cSVOPo_sv;
487   if (SvPOK(sv) && (SvTYPE(sv) >= SVt_PV)) {
488    const char *s = indirect_find(sv, PL_oldbufptr);
489    indirect_map_store(o, s, sv, CopLINE(&PL_compiling));
490    return o;
491   }
492  }
493
494  indirect_map_delete(o);
495  return o;
496 }
497
498 /* ... ck_rv2sv ............................................................ */
499
500 STATIC OP *(*indirect_old_ck_rv2sv)(pTHX_ OP *) = 0;
501
502 STATIC OP *indirect_ck_rv2sv(pTHX_ OP *o) {
503  if (indirect_hint()) {
504   OP *op = cUNOPo->op_first;
505   SV *sv;
506   const char *name = NULL, *s;
507   STRLEN len;
508   OPCODE type = (OPCODE) op->op_type;
509
510   switch (type) {
511    case OP_GV:
512    case OP_GVSV: {
513     GV *gv = cGVOPx_gv(op);
514     name = GvNAME(gv);
515     len  = GvNAMELEN(gv);
516     break;
517    }
518    default:
519     if ((PL_opargs[type] & OA_CLASS_MASK) == OA_SVOP) {
520      SV *nsv = cSVOPx_sv(op);
521      if (SvPOK(nsv) && (SvTYPE(nsv) >= SVt_PV))
522       name = SvPV_const(nsv, len);
523     }
524   }
525   if (!name)
526    goto done;
527
528   sv = sv_2mortal(newSVpvn("$", 1));
529   sv_catpvn_nomg(sv, name, len);
530   s = indirect_find(sv, PL_oldbufptr);
531   if (!s) { /* If it failed, retry without the current stash */
532    const char *stash = HvNAME_get(PL_curstash);
533    STRLEN stashlen = HvNAMELEN_get(PL_curstash);
534
535    if ((len < stashlen + 2) || strnNE(name, stash, stashlen)
536        || name[stashlen] != ':' || name[stashlen+1] != ':') {
537     /* Failed again ? Try to remove main */
538     stash = "main";
539     stashlen = 4;
540     if ((len < stashlen + 2) || strnNE(name, stash, stashlen)
541         || name[stashlen] != ':' || name[stashlen+1] != ':')
542      goto done;
543    }
544
545    sv_setpvn(sv, "$", 1);
546    stashlen += 2;
547    sv_catpvn_nomg(sv, name + stashlen, len - stashlen);
548    s = indirect_find(sv, PL_oldbufptr);
549    if (!s)
550     goto done;
551   }
552
553   o = CALL_FPTR(indirect_old_ck_rv2sv)(aTHX_ o);
554   indirect_map_store(o, s, sv, CopLINE(&PL_compiling));
555   return o;
556  }
557
558 done:
559  o = CALL_FPTR(indirect_old_ck_rv2sv)(aTHX_ o);
560
561  indirect_map_delete(o);
562  return o;
563 }
564
565 /* ... ck_padany ........................................................... */
566
567 STATIC OP *(*indirect_old_ck_padany)(pTHX_ OP *) = 0;
568
569 STATIC OP *indirect_ck_padany(pTHX_ OP *o) {
570  o = CALL_FPTR(indirect_old_ck_padany)(aTHX_ o);
571
572  if (indirect_hint()) {
573   SV *sv;
574   const char *s = PL_oldbufptr, *t = PL_bufptr - 1;
575
576   while (s < t && isSPACE(*s)) ++s;
577   if (*s == '$' && ++s <= t) {
578    while (s < t && isSPACE(*s)) ++s;
579    while (s < t && isSPACE(*t)) --t;
580    sv = sv_2mortal(newSVpvn("$", 1));
581    sv_catpvn_nomg(sv, s, t - s + 1);
582    indirect_map_store(o, s, sv, CopLINE(&PL_compiling));
583    return o;
584   }
585  }
586
587  indirect_map_delete(o);
588  return o;
589 }
590
591 /* ... ck_scope ............................................................ */
592
593 STATIC OP *(*indirect_old_ck_scope)  (pTHX_ OP *) = 0;
594 STATIC OP *(*indirect_old_ck_lineseq)(pTHX_ OP *) = 0;
595
596 STATIC OP *indirect_ck_scope(pTHX_ OP *o) {
597  OP *(*old_ck)(pTHX_ OP *) = 0;
598
599  switch (o->op_type) {
600   case OP_SCOPE:   old_ck = indirect_old_ck_scope;   break;
601   case OP_LINESEQ: old_ck = indirect_old_ck_lineseq; break;
602  }
603  o = CALL_FPTR(old_ck)(aTHX_ o);
604
605  if (indirect_hint()) {
606   indirect_map_store(o, PL_oldbufptr, NULL, CopLINE(&PL_compiling));
607   return o;
608  }
609
610  indirect_map_delete(o);
611  return o;
612 }
613
614 /* We don't need to clean the map entries for leave ops because they can only
615  * be created by mutating from a lineseq. */
616
617 /* ... ck_method ........................................................... */
618
619 STATIC OP *(*indirect_old_ck_method)(pTHX_ OP *) = 0;
620
621 STATIC OP *indirect_ck_method(pTHX_ OP *o) {
622  if (indirect_hint()) {
623   OP *op = cUNOPo->op_first;
624
625   /* Indirect method call is only possible when the method is a bareword, so
626    * don't trip up on $obj->$meth. */
627   if (op && op->op_type == OP_CONST) {
628    const indirect_op_info_t *oi = indirect_map_fetch(op);
629    const char *s = NULL;
630    line_t line;
631    SV *sv;
632
633    if (oi && (s = oi->pos)) {
634     sv   = sv_2mortal(newSVpvn(oi->buf, oi->len));
635     /* Keep the old line so that we really point to the first line of the
636      * expression. */
637     line = oi->line;
638    } else {
639     sv = cSVOPx_sv(op);
640     if (!SvPOK(sv) || (SvTYPE(sv) < SVt_PV))
641      goto done;
642     sv   = sv_mortalcopy(sv);
643     s    = indirect_find(sv, PL_oldbufptr);
644     line = CopLINE(&PL_compiling);
645    }
646
647    o = CALL_FPTR(indirect_old_ck_method)(aTHX_ o);
648    /* o may now be a method_named */
649
650    indirect_map_store(o, s, sv, line);
651    return o;
652   }
653  }
654
655 done:
656  o = CALL_FPTR(indirect_old_ck_method)(aTHX_ o);
657
658  indirect_map_delete(o);
659  return o;
660 }
661
662 /* ... ck_entersub ......................................................... */
663
664 STATIC int indirect_is_indirect(const indirect_op_info_t *moi, const indirect_op_info_t *ooi) {
665  if (moi->pos > ooi->pos)
666   return 0;
667
668  if (moi->pos == ooi->pos)
669   return moi->len == ooi->len && !memcmp(moi->buf, ooi->buf, moi->len);
670
671  return 1;
672 }
673
674 STATIC OP *(*indirect_old_ck_entersub)(pTHX_ OP *) = 0;
675
676 STATIC OP *indirect_ck_entersub(pTHX_ OP *o) {
677  SV *code = indirect_hint();
678
679  o = CALL_FPTR(indirect_old_ck_entersub)(aTHX_ o);
680
681  if (code) {
682   const indirect_op_info_t *moi, *ooi;
683   OP     *mop, *oop;
684   LISTOP *lop;
685
686   oop = o;
687   do {
688    lop = (LISTOP *) oop;
689    if (!(lop->op_flags & OPf_KIDS))
690     goto done;
691    oop = lop->op_first;
692   } while (oop->op_type != OP_PUSHMARK);
693   oop = oop->op_sibling;
694   mop = lop->op_last;
695
696   if (!oop)
697    goto done;
698
699   switch (oop->op_type) {
700    case OP_CONST:
701    case OP_RV2SV:
702    case OP_PADSV:
703    case OP_SCOPE:
704    case OP_LEAVE:
705     break;
706    default:
707     goto done;
708   }
709
710   if (mop->op_type == OP_METHOD)
711    mop = cUNOPx(mop)->op_first;
712   else if (mop->op_type != OP_METHOD_NAMED)
713    goto done;
714
715   moi = indirect_map_fetch(mop);
716   if (!(moi && moi->pos))
717    goto done;
718
719   ooi = indirect_map_fetch(oop);
720   if (!(ooi && ooi->pos))
721    goto done;
722
723   if (indirect_is_indirect(moi, ooi)) {
724    SV *file;
725    dSP;
726
727    ENTER;
728    SAVETMPS;
729
730 #ifdef USE_ITHREADS
731    file = sv_2mortal(newSVpv(CopFILE(&PL_compiling), 0));
732 #else
733    file = sv_mortalcopy(CopFILESV(&PL_compiling));
734 #endif
735
736    PUSHMARK(SP);
737    EXTEND(SP, 4);
738    mPUSHp(ooi->buf, ooi->len);
739    mPUSHp(moi->buf, moi->len);
740    PUSHs(file);
741    mPUSHu(moi->line);
742    PUTBACK;
743
744    call_sv(code, G_VOID);
745
746    PUTBACK;
747
748    FREETMPS;
749    LEAVE;
750   }
751  }
752
753 done:
754  return o;
755 }
756
757 STATIC U32 indirect_initialized = 0;
758
759 STATIC void indirect_teardown(pTHX_ void *root) {
760  dMY_CXT;
761
762  if (!indirect_initialized)
763   return;
764
765 #if I_MULTIPLICITY
766  if (aTHX != root)
767   return;
768 #endif
769
770  ptable_free(MY_CXT.map);
771 #if I_THREADSAFE
772  ptable_hints_free(MY_CXT.tbl);
773 #endif
774
775  PL_check[OP_CONST]       = MEMBER_TO_FPTR(indirect_old_ck_const);
776  indirect_old_ck_const    = 0;
777  PL_check[OP_RV2SV]       = MEMBER_TO_FPTR(indirect_old_ck_rv2sv);
778  indirect_old_ck_rv2sv    = 0;
779  PL_check[OP_PADANY]      = MEMBER_TO_FPTR(indirect_old_ck_padany);
780  indirect_old_ck_padany   = 0;
781  PL_check[OP_SCOPE]       = MEMBER_TO_FPTR(indirect_old_ck_scope);
782  indirect_old_ck_scope    = 0;
783  PL_check[OP_LINESEQ]     = MEMBER_TO_FPTR(indirect_old_ck_lineseq);
784  indirect_old_ck_lineseq  = 0;
785
786  PL_check[OP_METHOD]      = MEMBER_TO_FPTR(indirect_old_ck_method);
787  indirect_old_ck_method   = 0;
788  PL_check[OP_ENTERSUB]    = MEMBER_TO_FPTR(indirect_old_ck_entersub);
789  indirect_old_ck_entersub = 0;
790
791  indirect_initialized = 0;
792 }
793
794 STATIC void indirect_setup(pTHX) {
795 #define indirect_setup() indirect_setup(aTHX)
796  if (indirect_initialized)
797   return;
798
799  {
800   MY_CXT_INIT;
801 #if I_THREADSAFE
802   MY_CXT.tbl   = ptable_new();
803   MY_CXT.owner = aTHX;
804 #endif
805   MY_CXT.map   = ptable_new();
806  }
807
808  indirect_old_ck_const    = PL_check[OP_CONST];
809  PL_check[OP_CONST]       = MEMBER_TO_FPTR(indirect_ck_const);
810  indirect_old_ck_rv2sv    = PL_check[OP_RV2SV];
811  PL_check[OP_RV2SV]       = MEMBER_TO_FPTR(indirect_ck_rv2sv);
812  indirect_old_ck_padany   = PL_check[OP_PADANY];
813  PL_check[OP_PADANY]      = MEMBER_TO_FPTR(indirect_ck_padany);
814  indirect_old_ck_scope    = PL_check[OP_SCOPE];
815  PL_check[OP_SCOPE]       = MEMBER_TO_FPTR(indirect_ck_scope);
816  indirect_old_ck_lineseq  = PL_check[OP_LINESEQ];
817  PL_check[OP_LINESEQ]     = MEMBER_TO_FPTR(indirect_ck_scope);
818
819  indirect_old_ck_method   = PL_check[OP_METHOD];
820  PL_check[OP_METHOD]      = MEMBER_TO_FPTR(indirect_ck_method);
821  indirect_old_ck_entersub = PL_check[OP_ENTERSUB];
822  PL_check[OP_ENTERSUB]    = MEMBER_TO_FPTR(indirect_ck_entersub);
823
824 #if I_MULTIPLICITY
825  call_atexit(indirect_teardown, aTHX);
826 #else
827  call_atexit(indirect_teardown, NULL);
828 #endif
829
830  indirect_initialized = 1;
831 }
832
833 STATIC U32 indirect_booted = 0;
834
835 /* --- XS ------------------------------------------------------------------ */
836
837 MODULE = indirect      PACKAGE = indirect
838
839 PROTOTYPES: ENABLE
840
841 BOOT:
842 {
843  if (!indirect_booted++) {
844   HV *stash;
845
846   PERL_HASH(indirect_hash, __PACKAGE__, __PACKAGE_LEN__);
847
848   stash = gv_stashpvn(__PACKAGE__, __PACKAGE_LEN__, 1);
849   newCONSTSUB(stash, "I_THREADSAFE", newSVuv(I_THREADSAFE));
850   newCONSTSUB(stash, "I_FORKSAFE",   newSVuv(I_FORKSAFE));
851  }
852
853  indirect_setup();
854 }
855
856 #if I_THREADSAFE
857
858 void
859 CLONE(...)
860 PROTOTYPE: DISABLE
861 PREINIT:
862  ptable *t;
863 PPCODE:
864  {
865   my_cxt_t ud;
866   dMY_CXT;
867   ud.tbl   = t = ptable_new();
868   ud.owner = MY_CXT.owner;
869   ptable_walk(MY_CXT.tbl, indirect_ptable_clone, &ud);
870  }
871  {
872   MY_CXT_CLONE;
873   MY_CXT.map   = ptable_new();
874   MY_CXT.tbl   = t;
875   MY_CXT.owner = aTHX;
876  }
877  reap(3, indirect_thread_cleanup, NULL);
878  XSRETURN(0);
879
880 #endif
881
882 SV *
883 _tag(SV *value)
884 PROTOTYPE: $
885 CODE:
886  RETVAL = indirect_tag(value);
887 OUTPUT:
888  RETVAL