]> git.vpit.fr Git - perl/modules/Scope-Upper.git/blob - Upper.xs
Compatibility fix for perl 5.13.10
[perl/modules/Scope-Upper.git] / Upper.xs
1 /* This file is part of the Scope::Upper Perl module.
2  * See http://search.cpan.org/dist/Scope-Upper/ */
3
4 #define PERL_NO_GET_CONTEXT
5 #include "EXTERN.h"
6 #include "perl.h" 
7 #include "XSUB.h"
8
9 #define __PACKAGE__ "Scope::Upper"
10
11 #ifndef SU_DEBUG
12 # define SU_DEBUG 0
13 #endif
14
15 /* --- Compatibility ------------------------------------------------------- */
16
17 #ifndef PERL_UNUSED_VAR
18 # define PERL_UNUSED_VAR(V)
19 #endif
20
21 #ifndef STMT_START
22 # define STMT_START do
23 #endif
24
25 #ifndef STMT_END
26 # define STMT_END while (0)
27 #endif
28
29 #if SU_DEBUG
30 # define SU_D(X) STMT_START X STMT_END
31 #else
32 # define SU_D(X)
33 #endif
34
35 #ifndef Newx
36 # define Newx(v, n, c) New(0, v, n, c)
37 #endif
38
39 #ifndef SvPV_const
40 # define SvPV_const(S, L) SvPV(S, L)
41 #endif
42
43 #ifndef SvPV_nolen_const
44 # define SvPV_nolen_const(S) SvPV_nolen(S)
45 #endif
46
47 #ifndef SvREFCNT_inc_simple_void
48 # define SvREFCNT_inc_simple_void(sv) SvREFCNT_inc(sv)
49 #endif
50
51 #ifndef GvCV_set
52 # define GvCV_set(G, C) (GvCV(G) = (C))
53 #endif
54
55 #ifndef HvNAME_get
56 # define HvNAME_get(H) HvNAME(H)
57 #endif
58
59 #ifndef gv_fetchpvn_flags
60 # define gv_fetchpvn_flags(A, B, C, D) gv_fetchpv((A), (C), (D))
61 #endif
62
63 #ifndef PERL_MAGIC_tied
64 # define PERL_MAGIC_tied 'P'
65 #endif
66
67 #ifndef PERL_MAGIC_env
68 # define PERL_MAGIC_env 'E'
69 #endif
70
71 #ifndef NEGATIVE_INDICES_VAR
72 # define NEGATIVE_INDICES_VAR "NEGATIVE_INDICES"
73 #endif
74
75 #define SU_HAS_PERL(R, V, S) (PERL_REVISION > (R) || (PERL_REVISION == (R) && (PERL_VERSION > (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION >= (S))))))
76 #define SU_HAS_PERL_EXACT(R, V, S) ((PERL_REVISION == (R)) && (PERL_VERSION == (V)) && (PERL_SUBVERSION == (S)))
77
78 /* --- Threads and multiplicity -------------------------------------------- */
79
80 #ifndef NOOP
81 # define NOOP
82 #endif
83
84 #ifndef dNOOP
85 # define dNOOP
86 #endif
87
88 #ifndef SU_MULTIPLICITY
89 # if defined(MULTIPLICITY) || defined(PERL_IMPLICIT_CONTEXT)
90 #  define SU_MULTIPLICITY 1
91 # else
92 #  define SU_MULTIPLICITY 0
93 # endif
94 #endif
95 #if SU_MULTIPLICITY && !defined(tTHX)
96 # define tTHX PerlInterpreter*
97 #endif
98
99 #if SU_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))
100 # define SU_THREADSAFE 1
101 # ifndef MY_CXT_CLONE
102 #  define MY_CXT_CLONE \
103     dMY_CXT_SV;                                                      \
104     my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1)); \
105     Copy(INT2PTR(my_cxt_t*, SvUV(my_cxt_sv)), my_cxtp, 1, my_cxt_t); \
106     sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
107 # endif
108 #else
109 # define SU_THREADSAFE 0
110 # undef  dMY_CXT
111 # define dMY_CXT      dNOOP
112 # undef  MY_CXT
113 # define MY_CXT       su_globaldata
114 # undef  START_MY_CXT
115 # define START_MY_CXT STATIC my_cxt_t MY_CXT;
116 # undef  MY_CXT_INIT
117 # define MY_CXT_INIT  NOOP
118 # undef  MY_CXT_CLONE
119 # define MY_CXT_CLONE NOOP
120 #endif
121
122 /* --- Global data --------------------------------------------------------- */
123
124 #define MY_CXT_KEY __PACKAGE__ "::_guts" XS_VERSION
125
126 typedef struct {
127  char    *stack_placeholder;
128  I32      cxix;
129  I32      items;
130  SV     **savesp;
131  LISTOP   return_op;
132  OP       proxy_op;
133 } my_cxt_t;
134
135 START_MY_CXT
136
137 /* --- Stack manipulations ------------------------------------------------- */
138
139 #define SU_SAVE_PLACEHOLDER() save_pptr(&MY_CXT.stack_placeholder)
140
141 #define SU_SAVE_DESTRUCTOR_SIZE  3
142 #define SU_SAVE_PLACEHOLDER_SIZE 3
143
144 #define SU_SAVE_SCALAR_SIZE 3
145
146 #define SU_SAVE_ARY_SIZE      3
147 #define SU_SAVE_AELEM_SIZE    4
148 #ifdef SAVEADELETE
149 # define SU_SAVE_ADELETE_SIZE 3
150 #else
151 # define SU_SAVE_ADELETE_SIZE SU_SAVE_DESTRUCTOR_SIZE
152 #endif
153 #if SU_SAVE_AELEM_SIZE < SU_SAVE_ADELETE_SIZE
154 # define SU_SAVE_AELEM_OR_ADELETE_SIZE SU_SAVE_ADELETE_SIZE
155 #else
156 # define SU_SAVE_AELEM_OR_ADELETE_SIZE SU_SAVE_AELEM_SIZE
157 #endif
158
159 #define SU_SAVE_HASH_SIZE    3
160 #define SU_SAVE_HELEM_SIZE   4
161 #define SU_SAVE_HDELETE_SIZE 4
162 #if SU_SAVE_HELEM_SIZE < SU_SAVE_HDELETE_SIZE
163 # define SU_SAVE_HELEM_OR_HDELETE_SIZE SU_SAVE_HDELETE_SIZE
164 #else
165 # define SU_SAVE_HELEM_OR_HDELETE_SIZE SU_SAVE_HELEM_SIZE
166 #endif
167
168 #define SU_SAVE_SPTR_SIZE 3
169
170 #if !SU_HAS_PERL(5, 8, 9)
171 # define SU_SAVE_GP_SIZE 6
172 #elif !SU_HAS_PERL(5, 13, 0) || (SU_RELEASE && SU_HAS_PERL_EXACT(5, 13, 0))
173 # define SU_SAVE_GP_SIZE 3
174 #elif !SU_HAS_PERL(5, 13, 8)
175 # define SU_SAVE_GP_SIZE 4
176 #else
177 # define SU_SAVE_GP_SIZE 3
178 #endif
179
180 #ifndef SvCANEXISTDELETE
181 # define SvCANEXISTDELETE(sv) \
182   (!SvRMAGICAL(sv)            \
183    || ((mg = mg_find((SV *) sv, PERL_MAGIC_tied))            \
184        && (stash = SvSTASH(SvRV(SvTIED_obj((SV *) sv, mg)))) \
185        && gv_fetchmethod_autoload(stash, "EXISTS", TRUE)     \
186        && gv_fetchmethod_autoload(stash, "DELETE", TRUE)     \
187       )                       \
188    )
189 #endif
190
191 /* ... Saving array elements ............................................... */
192
193 STATIC I32 su_av_key2idx(pTHX_ AV *av, I32 key) {
194 #define su_av_key2idx(A, K) su_av_key2idx(aTHX_ (A), (K))
195  I32 idx;
196
197  if (key >= 0)
198   return key;
199
200 /* Added by MJD in perl-5.8.1 with 6f12eb6d2a1dfaf441504d869b27d2e40ef4966a */
201 #if SU_HAS_PERL(5, 8, 1)
202  if (SvRMAGICAL(av)) {
203   const MAGIC * const tied_magic = mg_find((SV *) av, PERL_MAGIC_tied);
204   if (tied_magic) {
205    SV * const * const negative_indices_glob =
206                     hv_fetch(SvSTASH(SvRV(SvTIED_obj((SV *) (av), tied_magic))),
207                              NEGATIVE_INDICES_VAR, 16, 0);
208    if (negative_indices_glob && SvTRUE(GvSV(*negative_indices_glob)))
209     return key;
210   }
211  }
212 #endif
213
214  idx = key + av_len(av) + 1;
215  if (idx < 0)
216   return key;
217
218  return idx;
219 }
220
221 #ifndef SAVEADELETE
222
223 typedef struct {
224  AV *av;
225  I32 idx;
226 } su_ud_adelete;
227
228 STATIC void su_adelete(pTHX_ void *ud_) {
229  su_ud_adelete *ud = (su_ud_adelete *) ud_;
230
231  av_delete(ud->av, ud->idx, G_DISCARD);
232  SvREFCNT_dec(ud->av);
233
234  Safefree(ud);
235 }
236
237 STATIC void su_save_adelete(pTHX_ AV *av, I32 idx) {
238 #define su_save_adelete(A, K) su_save_adelete(aTHX_ (A), (K))
239  su_ud_adelete *ud;
240
241  Newx(ud, 1, su_ud_adelete);
242  ud->av  = av;
243  ud->idx = idx;
244  SvREFCNT_inc_simple_void(av);
245
246  SAVEDESTRUCTOR_X(su_adelete, ud);
247 }
248
249 #define SAVEADELETE(A, K) su_save_adelete((A), (K))
250
251 #endif /* SAVEADELETE */
252
253 STATIC void su_save_aelem(pTHX_ AV *av, SV *key, SV *val) {
254 #define su_save_aelem(A, K, V) su_save_aelem(aTHX_ (A), (K), (V))
255  I32 idx;
256  I32 preeminent = 1;
257  SV **svp;
258  HV *stash;
259  MAGIC *mg;
260
261  idx = su_av_key2idx(av, SvIV(key));
262
263  if (SvCANEXISTDELETE(av))
264   preeminent = av_exists(av, idx);
265
266  svp = av_fetch(av, idx, 1);
267  if (!svp || *svp == &PL_sv_undef) croak(PL_no_aelem, idx);
268
269  if (preeminent)
270   save_aelem(av, idx, svp);
271  else
272   SAVEADELETE(av, idx);
273
274  if (val) { /* local $x[$idx] = $val; */
275   SvSetMagicSV(*svp, val);
276  } else {   /* local $x[$idx]; delete $x[$idx]; */
277   av_delete(av, idx, G_DISCARD);
278  }
279 }
280
281 /* ... Saving hash elements ................................................ */
282
283 STATIC void su_save_helem(pTHX_ HV *hv, SV *keysv, SV *val) {
284 #define su_save_helem(H, K, V) su_save_helem(aTHX_ (H), (K), (V))
285  I32 preeminent = 1;
286  HE *he;
287  SV **svp;
288  HV *stash;
289  MAGIC *mg;
290
291  if (SvCANEXISTDELETE(hv) || mg_find((SV *) hv, PERL_MAGIC_env))
292   preeminent = hv_exists_ent(hv, keysv, 0);
293
294  he  = hv_fetch_ent(hv, keysv, 1, 0);
295  svp = he ? &HeVAL(he) : NULL;
296  if (!svp || *svp == &PL_sv_undef) croak("Modification of non-creatable hash value attempted, subscript \"%s\"", SvPV_nolen_const(*svp));
297
298  if (HvNAME_get(hv) && isGV(*svp)) {
299   save_gp((GV *) *svp, 0);
300   return;
301  }
302
303  if (preeminent)
304   save_helem(hv, keysv, svp);
305  else {
306   STRLEN keylen;
307   const char * const key = SvPV_const(keysv, keylen);
308   SAVEDELETE(hv, savepvn(key, keylen),
309                  SvUTF8(keysv) ? -(I32)keylen : (I32)keylen);
310  }
311
312  if (val) { /* local $x{$keysv} = $val; */
313   SvSetMagicSV(*svp, val);
314  } else {   /* local $x{$keysv}; delete $x{$keysv}; */
315   (void)hv_delete_ent(hv, keysv, G_DISCARD, HeHASH(he));
316  }
317 }
318
319 /* ... Saving code slots from a glob ....................................... */
320
321 #if SU_HAS_PERL(5, 13, 10)
322
323 /* Since perl 5.13.10, GvCV() is only a rvalue so we no longer can store a
324  * pointer to the gvcv member of the gv. */
325
326 typedef struct {
327  GV *gv;
328  CV *old_cv;
329 } su_save_gvcv_ud;
330
331 STATIC void su_restore_gvcv(pTHX_ void *ud_) {
332  su_save_gvcv_ud *ud = ud_;
333
334  GvCV_set(ud->gv, ud->old_cv);
335
336  Safefree(ud);
337 }
338
339 STATIC void su_save_gvcv(pTHX_ GV *gv) {
340 #define su_save_gvcv(gv) su_save_gvcv(aTHX_ (gv))
341  su_save_gvcv_ud *ud;
342
343  Newx(ud, 1, su_save_gvcv_ud);
344  ud->gv     = gv;
345  ud->old_cv = GvCV(gv);
346
347  GvCV_set(gv, NULL);
348
349  SAVEDESTRUCTOR_X(su_restore_gvcv, ud);
350 }
351
352 #else
353
354 #define su_save_gvcv(gv) SAVESPTR(GvCV(gv)), GvCV_set((gv), NULL)
355
356 #endif
357
358 /* --- Actions ------------------------------------------------------------- */
359
360 typedef struct {
361  I32 depth;
362  I32 pad;
363  I32 *origin;
364  void (*handler)(pTHX_ void *);
365 } su_ud_common;
366
367 #define SU_UD_DEPTH(U)   (((su_ud_common *) (U))->depth)
368 #define SU_UD_PAD(U)     (((su_ud_common *) (U))->pad)
369 #define SU_UD_ORIGIN(U)  (((su_ud_common *) (U))->origin)
370 #define SU_UD_HANDLER(U) (((su_ud_common *) (U))->handler)
371
372 #define SU_UD_FREE(U) STMT_START { \
373  if (SU_UD_ORIGIN(U)) Safefree(SU_UD_ORIGIN(U)); \
374  Safefree(U); \
375 } STMT_END
376
377 /* ... Reap ................................................................ */
378
379 typedef struct {
380  su_ud_common ci;
381  SV *cb;
382 } su_ud_reap;
383
384 STATIC void su_call(pTHX_ void *ud_) {
385  su_ud_reap *ud = (su_ud_reap *) ud_;
386 #if SU_HAS_PERL(5, 9, 5)
387  PERL_CONTEXT saved_cx;
388  I32 cxix;
389 #endif
390
391  dSP;
392
393  SU_D({
394   PerlIO_printf(Perl_debug_log,
395                 "%p: @@@ call\n%p: depth=%2d scope_ix=%2d save_ix=%2d\n",
396                  ud, ud, SU_UD_DEPTH(ud), PL_scopestack_ix, PL_savestack_ix);
397  });
398
399  ENTER;
400  SAVETMPS;
401
402  PUSHMARK(SP);
403  PUTBACK;
404
405  /* If the recently popped context isn't saved there, it will be overwritten by
406   * the sub scope from call_sv, although it's still needed in our caller. */
407
408 #if SU_HAS_PERL(5, 9, 5)
409  if (cxstack_ix < cxstack_max)
410   cxix = cxstack_ix + 1;
411  else
412   cxix = Perl_cxinc(aTHX);
413  saved_cx = cxstack[cxix];
414 #endif
415
416  call_sv(ud->cb, G_VOID);
417
418 #if SU_HAS_PERL(5, 9, 5)
419  cxstack[cxix] = saved_cx;
420 #endif
421
422  PUTBACK;
423
424  FREETMPS;
425  LEAVE;
426
427  SvREFCNT_dec(ud->cb);
428  SU_UD_FREE(ud);
429 }
430
431 STATIC void su_reap(pTHX_ void *ud) {
432 #define su_reap(U) su_reap(aTHX_ (U))
433  SU_D({
434   PerlIO_printf(Perl_debug_log,
435                 "%p: === reap\n%p: depth=%2d scope_ix=%2d save_ix=%2d\n",
436                  ud, ud, SU_UD_DEPTH(ud), PL_scopestack_ix, PL_savestack_ix);
437  });
438
439  SAVEDESTRUCTOR_X(su_call, ud);
440 }
441
442 /* ... Localize & localize array/hash element .............................. */
443
444 typedef struct {
445  su_ud_common ci;
446  SV    *sv;
447  SV    *val;
448  SV    *elem;
449  svtype type;
450 } su_ud_localize;
451
452 #define SU_UD_LOCALIZE_FREE(U) STMT_START { \
453  SvREFCNT_dec((U)->elem); \
454  SvREFCNT_dec((U)->val);  \
455  SvREFCNT_dec((U)->sv);   \
456  SU_UD_FREE(U);           \
457 } STMT_END
458
459 STATIC I32 su_ud_localize_init(pTHX_ su_ud_localize *ud, SV *sv, SV *val, SV *elem) {
460 #define su_ud_localize_init(UD, S, V, E) su_ud_localize_init(aTHX_ (UD), (S), (V), (E))
461  UV deref = 0;
462  svtype t = SVt_NULL;
463  I32 size;
464
465  SvREFCNT_inc_simple_void(sv);
466
467  if (SvTYPE(sv) >= SVt_PVGV) {
468   if (!val || !SvROK(val)) { /* local *x; or local *x = $val; */
469    t = SVt_PVGV;
470   } else {                   /* local *x = \$val; */
471    t = SvTYPE(SvRV(val));
472    deref = 1;
473   }
474  } else if (SvROK(sv)) {
475   croak("Invalid %s reference as the localization target",
476                  sv_reftype(SvRV(sv), 0));
477  } else {
478   STRLEN len, l;
479   const char *p = SvPV_const(sv, len), *s;
480   for (s = p, l = len; l > 0 && isSPACE(*s); ++s, --l) { }
481   if (!l) {
482    l = len;
483    s = p;
484   }
485   switch (*s) {
486    case '$': t = SVt_PV;   break;
487    case '@': t = SVt_PVAV; break;
488    case '%': t = SVt_PVHV; break;
489    case '&': t = SVt_PVCV; break;
490    case '*': t = SVt_PVGV; break;
491   }
492   if (t != SVt_NULL) {
493    ++s;
494    --l;
495   } else if (val) { /* t == SVt_NULL, type can't be inferred from the sigil */
496    if (SvROK(val) && !sv_isobject(val)) {
497     t = SvTYPE(SvRV(val));
498     deref = 1;
499    } else {
500     t = SvTYPE(val);
501    }
502   }
503   SvREFCNT_dec(sv);
504   sv = newSVpvn(s, l);
505  }
506
507  switch (t) {
508   case SVt_PVAV:
509    size  = elem ? SU_SAVE_AELEM_OR_ADELETE_SIZE
510                 : SU_SAVE_ARY_SIZE;
511    deref = 0;
512    break;
513   case SVt_PVHV:
514    size  = elem ? SU_SAVE_HELEM_OR_HDELETE_SIZE
515                 : SU_SAVE_HASH_SIZE;
516    deref = 0;
517    break;
518   case SVt_PVGV:
519    size  = SU_SAVE_GP_SIZE;
520    deref = 0;
521    break;
522   case SVt_PVCV:
523    size  = SU_SAVE_SPTR_SIZE;
524    deref = 0;
525    break;
526   default:
527    size = SU_SAVE_SCALAR_SIZE;
528    break;
529  }
530  /* When deref is set, val isn't NULL */
531
532  ud->sv   = sv;
533  ud->val  = val ? newSVsv(deref ? SvRV(val) : val) : NULL;
534  ud->elem = SvREFCNT_inc(elem);
535  ud->type = t;
536
537  return size;
538 }
539
540 STATIC void su_localize(pTHX_ void *ud_) {
541 #define su_localize(U) su_localize(aTHX_ (U))
542  su_ud_localize *ud = (su_ud_localize *) ud_;
543  SV *sv   = ud->sv;
544  SV *val  = ud->val;
545  SV *elem = ud->elem;
546  svtype t = ud->type;
547  GV *gv;
548
549  if (SvTYPE(sv) >= SVt_PVGV) {
550   gv = (GV *) sv;
551  } else {
552 #ifdef gv_fetchsv
553   gv = gv_fetchsv(sv, GV_ADDMULTI, t);
554 #else
555   STRLEN len;
556   const char *name = SvPV_const(sv, len);
557   gv = gv_fetchpvn_flags(name, len, GV_ADDMULTI, t);
558 #endif
559  }
560
561  SU_D({
562   SV *z = newSV(0);
563   SvUPGRADE(z, t);
564   PerlIO_printf(Perl_debug_log, "%p: === localize a %s\n",ud, sv_reftype(z, 0));
565   PerlIO_printf(Perl_debug_log,
566                 "%p: depth=%2d scope_ix=%2d save_ix=%2d\n",
567                  ud, SU_UD_DEPTH(ud), PL_scopestack_ix, PL_savestack_ix);
568   SvREFCNT_dec(z);
569  });
570
571  /* Inspired from Alias.pm */
572  switch (t) {
573   case SVt_PVAV:
574    if (elem) {
575     su_save_aelem(GvAV(gv), elem, val);
576     goto done;
577    } else
578     save_ary(gv);
579    break;
580   case SVt_PVHV:
581    if (elem) {
582     su_save_helem(GvHV(gv), elem, val);
583     goto done;
584    } else
585     save_hash(gv);
586    break;
587   case SVt_PVGV:
588    save_gp(gv, 1); /* hide previous entry in symtab */
589    break;
590   case SVt_PVCV:
591    su_save_gvcv(gv);
592    break;
593   default:
594    gv = (GV *) save_scalar(gv);
595    break;
596  }
597
598  if (val)
599   SvSetMagicSV((SV *) gv, val);
600
601 done:
602  SU_UD_LOCALIZE_FREE(ud);
603 }
604
605 /* --- Pop a context back -------------------------------------------------- */
606
607 #if SU_DEBUG
608 # ifdef DEBUGGING
609 #  define SU_CXNAME PL_block_type[CxTYPE(&cxstack[cxstack_ix])]
610 # else
611 #  define SU_CXNAME "XXX"
612 # endif
613 #endif
614
615 STATIC void su_pop(pTHX_ void *ud) {
616 #define su_pop(U) su_pop(aTHX_ (U))
617  I32 depth, base, mark, *origin;
618  depth = SU_UD_DEPTH(ud);
619
620  SU_D(
621   PerlIO_printf(Perl_debug_log,
622    "%p: --- pop a %s\n"
623    "%p: leave scope     at depth=%2d scope_ix=%2d cur_top=%2d cur_base=%2d\n",
624     ud, SU_CXNAME,
625     ud, depth, PL_scopestack_ix,PL_savestack_ix,PL_scopestack[PL_scopestack_ix])
626  );
627
628  origin = SU_UD_ORIGIN(ud);
629  mark   = origin[depth];
630  base   = origin[depth - 1];
631
632  SU_D(PerlIO_printf(Perl_debug_log,
633                     "%p: original scope was %*c top=%2d     base=%2d\n",
634                      ud,                24, ' ',    mark,        base));
635
636  if (base < mark) {
637   SU_D(PerlIO_printf(Perl_debug_log, "%p: clear leftovers\n", ud));
638   PL_savestack_ix = mark;
639   leave_scope(base);
640  }
641  PL_savestack_ix = base;
642
643  SU_UD_DEPTH(ud) = --depth;
644
645  if (depth > 0) {
646   I32 pad;
647
648   if ((pad = SU_UD_PAD(ud))) {
649    dMY_CXT;
650    do {
651     SU_D(PerlIO_printf(Perl_debug_log,
652           "%p: push a pad slot at depth=%2d scope_ix=%2d save_ix=%2d\n",
653            ud,                       depth, PL_scopestack_ix, PL_savestack_ix));
654     SU_SAVE_PLACEHOLDER();
655    } while (--pad);
656   }
657
658   SU_D(PerlIO_printf(Perl_debug_log,
659           "%p: push destructor at depth=%2d scope_ix=%2d save_ix=%2d\n",
660            ud,                       depth, PL_scopestack_ix, PL_savestack_ix));
661   SAVEDESTRUCTOR_X(su_pop, ud);
662  } else {
663   SU_UD_HANDLER(ud)(aTHX_ ud);
664  }
665
666  SU_D(PerlIO_printf(Perl_debug_log,
667                     "%p: --- end pop: cur_top=%2d == cur_base=%2d\n",
668                      ud, PL_savestack_ix, PL_scopestack[PL_scopestack_ix]));
669 }
670
671 /* --- Initialize the stack and the action userdata ------------------------ */
672
673 STATIC I32 su_init(pTHX_ void *ud, I32 cxix, I32 size) {
674 #define su_init(U, C, S) su_init(aTHX_ (U), (C), (S))
675  I32 i, depth = 1, pad, offset, *origin;
676
677  SU_D(PerlIO_printf(Perl_debug_log, "%p: ### init for cx %d\n", ud, cxix));
678
679  if (size <= SU_SAVE_DESTRUCTOR_SIZE)
680   pad = 0;
681  else {
682   I32 extra = size - SU_SAVE_DESTRUCTOR_SIZE;
683   pad = extra / SU_SAVE_PLACEHOLDER_SIZE;
684   if (extra % SU_SAVE_PLACEHOLDER_SIZE)
685    ++pad;
686  }
687  offset = SU_SAVE_DESTRUCTOR_SIZE + SU_SAVE_PLACEHOLDER_SIZE * pad;
688
689  SU_D(PerlIO_printf(Perl_debug_log, "%p: size=%d pad=%d offset=%d\n",
690                                      ud,    size,   pad,   offset));
691
692  for (i = cxstack_ix; i > cxix; --i) {
693   PERL_CONTEXT *cx = cxstack + i;
694   switch (CxTYPE(cx)) {
695 #if SU_HAS_PERL(5, 10, 0)
696    case CXt_BLOCK:
697     SU_D(PerlIO_printf(Perl_debug_log, "%p: cx %d is block\n", ud, i));
698     /* Given and when blocks are actually followed by a simple block, so skip
699      * it if needed. */
700     if (cxix > 0) { /* Implies i > 0 */
701      PERL_CONTEXT *next = cx - 1;
702      if (CxTYPE(next) == CXt_GIVEN || CxTYPE(next) == CXt_WHEN)
703       --cxix;
704     }
705     depth++;
706     break;
707 #endif
708 #if SU_HAS_PERL(5, 11, 0)
709    case CXt_LOOP_FOR:
710    case CXt_LOOP_PLAIN:
711    case CXt_LOOP_LAZYSV:
712    case CXt_LOOP_LAZYIV:
713 #else
714    case CXt_LOOP:
715 #endif
716     SU_D(PerlIO_printf(Perl_debug_log, "%p: cx %d is loop\n", ud, i));
717     depth += 2;
718     break;
719    default:
720     SU_D(PerlIO_printf(Perl_debug_log, "%p: cx %d is other\n", ud, i));
721     depth++;
722     break;
723   }
724  }
725  SU_D(PerlIO_printf(Perl_debug_log, "%p: going down to depth %d\n", ud, depth));
726
727  Newx(origin, depth + 1, I32);
728  origin[0] = PL_scopestack[PL_scopestack_ix - depth];
729  PL_scopestack[PL_scopestack_ix - depth] += size;
730  for (i = depth - 1; i >= 1; --i) {
731   I32 j = PL_scopestack_ix - i;
732   origin[depth - i] = PL_scopestack[j];
733   PL_scopestack[j] += offset;
734  }
735  origin[depth] = PL_savestack_ix;
736
737  SU_UD_ORIGIN(ud) = origin;
738  SU_UD_DEPTH(ud)  = depth;
739  SU_UD_PAD(ud)    = pad;
740
741  /* Make sure the first destructor fires by pushing enough fake slots on the
742   * stack. */
743  if (PL_savestack_ix + SU_SAVE_DESTRUCTOR_SIZE
744                                        <= PL_scopestack[PL_scopestack_ix - 1]) {
745   dMY_CXT;
746   do {
747    SU_D(PerlIO_printf(Perl_debug_log,
748                   "%p: push a fake slot      at scope_ix=%2d  save_ix=%2d\n",
749                    ud,                      PL_scopestack_ix, PL_savestack_ix));
750    SU_SAVE_PLACEHOLDER();
751   } while (PL_savestack_ix + SU_SAVE_DESTRUCTOR_SIZE
752                                         <= PL_scopestack[PL_scopestack_ix - 1]);
753  }
754  SU_D(PerlIO_printf(Perl_debug_log,
755                   "%p: push first destructor at scope_ix=%2d  save_ix=%2d\n",
756                    ud,                      PL_scopestack_ix, PL_savestack_ix));
757  SAVEDESTRUCTOR_X(su_pop, ud);
758
759  SU_D({
760   for (i = 0; i <= depth; ++i) {
761    I32 j = PL_scopestack_ix  - i;
762    PerlIO_printf(Perl_debug_log,
763                  "%p: depth=%2d scope_ix=%2d saved_floor=%2d new_floor=%2d\n",
764                   ud,        i, j, origin[depth - i],
765                                    i == 0 ? PL_savestack_ix : PL_scopestack[j]);
766   }
767  });
768
769  return depth;
770 }
771
772 /* --- Unwind stack -------------------------------------------------------- */
773
774 STATIC void su_unwind(pTHX_ void *ud_) {
775  dMY_CXT;
776  I32 cxix    = MY_CXT.cxix;
777  I32 items   = MY_CXT.items - 1;
778  SV **savesp = MY_CXT.savesp;
779  I32 mark;
780
781  PERL_UNUSED_VAR(ud_);
782
783  if (savesp)
784   PL_stack_sp = savesp;
785
786  if (cxstack_ix > cxix)
787   dounwind(cxix);
788
789  /* Hide the level */
790  if (items >= 0)
791   PL_stack_sp--;
792
793  mark = PL_markstack[cxstack[cxix].blk_oldmarksp];
794  *PL_markstack_ptr = PL_stack_sp - PL_stack_base - items;
795
796  SU_D({
797   I32 gimme = GIMME_V;
798   PerlIO_printf(Perl_debug_log,
799                 "%p: cx=%d gimme=%s items=%d sp=%d oldmark=%d mark=%d\n",
800                 &MY_CXT, cxix,
801                 gimme == G_VOID ? "void" : gimme == G_ARRAY ? "list" : "scalar",
802                 items, PL_stack_sp - PL_stack_base, *PL_markstack_ptr, mark);
803  });
804
805  PL_op = (OP *) &(MY_CXT.return_op);
806  PL_op = PL_op->op_ppaddr(aTHX);
807
808  *PL_markstack_ptr = mark;
809
810  MY_CXT.proxy_op.op_next = PL_op;
811  PL_op = &(MY_CXT.proxy_op);
812 }
813
814 /* --- XS ------------------------------------------------------------------ */
815
816 #if SU_HAS_PERL(5, 8, 9)
817 # define SU_SKIP_DB_MAX 2
818 #else
819 # define SU_SKIP_DB_MAX 3
820 #endif
821
822 /* Skip context sequences of 1 to SU_SKIP_DB_MAX (included) block contexts
823  * followed by a DB sub */
824
825 #define SU_SKIP_DB(C) \
826  STMT_START {         \
827   I32 skipped = 0;    \
828   PERL_CONTEXT *base = cxstack;      \
829   PERL_CONTEXT *cx   = base + (C);   \
830   while (cx >= base && (C) > skipped && CxTYPE(cx) == CXt_BLOCK) \
831    --cx, ++skipped;                  \
832   if (cx >= base && (C) > skipped) { \
833    switch (CxTYPE(cx)) {  \
834     case CXt_SUB:         \
835      if (skipped <= SU_SKIP_DB_MAX && cx->blk_sub.cv == GvCV(PL_DBsub)) \
836       (C) -= skipped + 1; \
837       break;              \
838     default:              \
839      break;               \
840    }                      \
841   }                       \
842  } STMT_END
843
844 #define SU_GET_CONTEXT(A, B)   \
845  STMT_START {                  \
846   if (items > A) {             \
847    SV *csv = ST(B);            \
848    if (!SvOK(csv))             \
849     goto default_cx;           \
850    cxix = SvIV(csv);           \
851    if (cxix < 0)               \
852     cxix = 0;                  \
853    else if (cxix > cxstack_ix) \
854     cxix = cxstack_ix;         \
855   } else {                     \
856 default_cx:                    \
857    cxix = cxstack_ix;          \
858    if (PL_DBsub)               \
859     SU_SKIP_DB(cxix);          \
860   }                            \
861  } STMT_END
862
863 #define SU_GET_LEVEL(A, B) \
864  STMT_START {              \
865   level = 0;               \
866   if (items > 0) {         \
867    SV *lsv = ST(B);        \
868    if (SvOK(lsv)) {        \
869     level = SvIV(lsv);     \
870     if (level < 0)         \
871      level = 0;            \
872    }                       \
873   }                        \
874  } STMT_END
875
876 XS(XS_Scope__Upper_unwind); /* prototype to pass -Wmissing-prototypes */
877
878 XS(XS_Scope__Upper_unwind) {
879 #ifdef dVAR
880  dVAR; dXSARGS;
881 #else
882  dXSARGS;
883 #endif
884  dMY_CXT;
885  I32 cxix;
886
887  PERL_UNUSED_VAR(cv); /* -W */
888  PERL_UNUSED_VAR(ax); /* -Wall */
889
890  SU_GET_CONTEXT(0, items - 1);
891  do {
892   PERL_CONTEXT *cx = cxstack + cxix;
893   switch (CxTYPE(cx)) {
894    case CXt_SUB:
895     if (PL_DBsub && cx->blk_sub.cv == GvCV(PL_DBsub))
896      continue;
897    case CXt_EVAL:
898    case CXt_FORMAT:
899     MY_CXT.cxix  = cxix;
900     MY_CXT.items = items;
901     /* pp_entersub will want to sanitize the stack after returning from there
902      * Screw that, we're insane */
903     if (GIMME_V == G_SCALAR) {
904      MY_CXT.savesp = PL_stack_sp;
905      /* dXSARGS calls POPMARK, so we need to match PL_markstack_ptr[1] */
906      PL_stack_sp = PL_stack_base + PL_markstack_ptr[1] + 1;
907     } else {
908      MY_CXT.savesp = NULL;
909     }
910     SAVEDESTRUCTOR_X(su_unwind, NULL);
911     return;
912    default:
913     break;
914   }
915  } while (--cxix >= 0);
916  croak("Can't return outside a subroutine");
917 }
918
919 MODULE = Scope::Upper            PACKAGE = Scope::Upper
920
921 PROTOTYPES: ENABLE
922
923 BOOT:
924 {
925  HV *stash;
926
927  MY_CXT_INIT;
928
929  MY_CXT.stack_placeholder = NULL;
930
931  /* NewOp() calls calloc() which just zeroes the memory with memset(). */
932  Zero(&(MY_CXT.return_op), 1, sizeof(MY_CXT.return_op));
933  MY_CXT.return_op.op_type   = OP_RETURN;
934  MY_CXT.return_op.op_ppaddr = PL_ppaddr[OP_RETURN];
935
936  Zero(&(MY_CXT.proxy_op), 1, sizeof(MY_CXT.proxy_op));
937  MY_CXT.proxy_op.op_type   = OP_STUB;
938  MY_CXT.proxy_op.op_ppaddr = NULL;
939
940  stash = gv_stashpv(__PACKAGE__, 1);
941  newCONSTSUB(stash, "TOP",           newSViv(0));
942  newCONSTSUB(stash, "SU_THREADSAFE", newSVuv(SU_THREADSAFE));
943
944  newXSproto("Scope::Upper::unwind", XS_Scope__Upper_unwind, file, NULL);
945 }
946
947 #if SU_THREADSAFE
948
949 void
950 CLONE(...)
951 PROTOTYPE: DISABLE
952 PPCODE:
953  {
954   MY_CXT_CLONE;
955  }
956  XSRETURN(0);
957
958 #endif /* SU_THREADSAFE */
959
960 SV *
961 HERE()
962 PROTOTYPE:
963 PREINIT:
964  I32 cxix = cxstack_ix;
965 CODE:
966  if (PL_DBsub)
967   SU_SKIP_DB(cxix);
968  RETVAL = newSViv(cxix);
969 OUTPUT:
970  RETVAL
971
972 SV *
973 UP(...)
974 PROTOTYPE: ;$
975 PREINIT:
976  I32 cxix;
977 CODE:
978  SU_GET_CONTEXT(0, 0);
979  if (--cxix < 0)
980   cxix = 0;
981  if (PL_DBsub)
982   SU_SKIP_DB(cxix);
983  RETVAL = newSViv(cxix);
984 OUTPUT:
985  RETVAL
986
987 void
988 SUB(...)
989 PROTOTYPE: ;$
990 PREINIT:
991  I32 cxix;
992 PPCODE:
993  SU_GET_CONTEXT(0, 0);
994  for (; cxix >= 0; --cxix) {
995   PERL_CONTEXT *cx = cxstack + cxix;
996   switch (CxTYPE(cx)) {
997    default:
998     continue;
999    case CXt_SUB:
1000     if (PL_DBsub && cx->blk_sub.cv == GvCV(PL_DBsub))
1001      continue;
1002     ST(0) = sv_2mortal(newSViv(cxix));
1003     XSRETURN(1);
1004   }
1005  }
1006  XSRETURN_UNDEF;
1007
1008 void
1009 EVAL(...)
1010 PROTOTYPE: ;$
1011 PREINIT:
1012  I32 cxix;
1013 PPCODE:
1014  SU_GET_CONTEXT(0, 0);
1015  for (; cxix >= 0; --cxix) {
1016   PERL_CONTEXT *cx = cxstack + cxix;
1017   switch (CxTYPE(cx)) {
1018    default:
1019     continue;
1020    case CXt_EVAL:
1021     ST(0) = sv_2mortal(newSViv(cxix));
1022     XSRETURN(1);
1023   }
1024  }
1025  XSRETURN_UNDEF;
1026
1027 void
1028 SCOPE(...)
1029 PROTOTYPE: ;$
1030 PREINIT:
1031  I32 cxix, level;
1032 PPCODE:
1033  SU_GET_LEVEL(0, 0);
1034  cxix = cxstack_ix;
1035  if (PL_DBsub) {
1036   SU_SKIP_DB(cxix);
1037   while (cxix > 0) {
1038    if (--level < 0)
1039     break;
1040    --cxix;
1041    SU_SKIP_DB(cxix);
1042   }
1043  } else {
1044   cxix -= level;
1045   if (cxix < 0)
1046    cxix = 0;
1047  }
1048  ST(0) = sv_2mortal(newSViv(cxix));
1049  XSRETURN(1);
1050
1051 void
1052 CALLER(...)
1053 PROTOTYPE: ;$
1054 PREINIT:
1055  I32 cxix, level;
1056 PPCODE:
1057  SU_GET_LEVEL(0, 0);
1058  for (cxix = cxstack_ix; cxix > 0; --cxix) {
1059   PERL_CONTEXT *cx = cxstack + cxix;
1060   switch (CxTYPE(cx)) {
1061    case CXt_SUB:
1062     if (PL_DBsub && cx->blk_sub.cv == GvCV(PL_DBsub))
1063      continue;
1064    case CXt_EVAL:
1065    case CXt_FORMAT:
1066     if (--level < 0)
1067      goto done;
1068     break;
1069   }
1070  }
1071 done:
1072  ST(0) = sv_2mortal(newSViv(cxix));
1073  XSRETURN(1);
1074
1075 void
1076 want_at(...)
1077 PROTOTYPE: ;$
1078 PREINIT:
1079  I32 cxix;
1080 PPCODE:
1081  SU_GET_CONTEXT(0, 0);
1082  while (cxix > 0) {
1083   PERL_CONTEXT *cx = cxstack + cxix--;
1084   switch (CxTYPE(cx)) {
1085    case CXt_SUB:
1086    case CXt_EVAL:
1087    case CXt_FORMAT: {
1088     I32 gimme = cx->blk_gimme;
1089     switch (gimme) {
1090      case G_VOID:   XSRETURN_UNDEF; break;
1091      case G_SCALAR: XSRETURN_NO;    break;
1092      case G_ARRAY:  XSRETURN_YES;   break;
1093     }
1094     break;
1095    }
1096   }
1097  }
1098  XSRETURN_UNDEF;
1099
1100 void
1101 reap(SV *hook, ...)
1102 PROTOTYPE: &;$
1103 PREINIT:
1104  I32 cxix;
1105  su_ud_reap *ud;
1106 CODE:
1107  SU_GET_CONTEXT(1, 1);
1108  Newx(ud, 1, su_ud_reap);
1109  SU_UD_ORIGIN(ud)  = NULL;
1110  SU_UD_HANDLER(ud) = su_reap;
1111  ud->cb = newSVsv(hook);
1112  su_init(ud, cxix, SU_SAVE_DESTRUCTOR_SIZE);
1113
1114 void
1115 localize(SV *sv, SV *val, ...)
1116 PROTOTYPE: $$;$
1117 PREINIT:
1118  I32 cxix;
1119  I32 size;
1120  su_ud_localize *ud;
1121 CODE:
1122  SU_GET_CONTEXT(2, 2);
1123  Newx(ud, 1, su_ud_localize);
1124  SU_UD_ORIGIN(ud)  = NULL;
1125  SU_UD_HANDLER(ud) = su_localize;
1126  size = su_ud_localize_init(ud, sv, val, NULL);
1127  su_init(ud, cxix, size);
1128
1129 void
1130 localize_elem(SV *sv, SV *elem, SV *val, ...)
1131 PROTOTYPE: $$$;$
1132 PREINIT:
1133  I32 cxix;
1134  I32 size;
1135  su_ud_localize *ud;
1136 CODE:
1137  if (SvTYPE(sv) >= SVt_PVGV)
1138   croak("Can't infer the element localization type from a glob and the value");
1139  SU_GET_CONTEXT(3, 3);
1140  Newx(ud, 1, su_ud_localize);
1141  SU_UD_ORIGIN(ud)  = NULL;
1142  SU_UD_HANDLER(ud) = su_localize;
1143  size = su_ud_localize_init(ud, sv, val, elem);
1144  if (ud->type != SVt_PVAV && ud->type != SVt_PVHV) {
1145   SU_UD_LOCALIZE_FREE(ud);
1146   croak("Can't localize an element of something that isn't an array or a hash");
1147  }
1148  su_init(ud, cxix, size);
1149
1150 void
1151 localize_delete(SV *sv, SV *elem, ...)
1152 PROTOTYPE: $$;$
1153 PREINIT:
1154  I32 cxix;
1155  I32 size;
1156  su_ud_localize *ud;
1157 CODE:
1158  SU_GET_CONTEXT(2, 2);
1159  Newx(ud, 1, su_ud_localize);
1160  SU_UD_ORIGIN(ud)  = NULL;
1161  SU_UD_HANDLER(ud) = su_localize;
1162  size = su_ud_localize_init(ud, sv, NULL, elem);
1163  su_init(ud, cxix, size);