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