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