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