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