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