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