]> git.vpit.fr Git - perl/modules/Scope-Upper.git/blob - Upper.xs
Preemptively remove uses of lvalue GvCV
[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 /* --- Actions ------------------------------------------------------------- */
320
321 typedef struct {
322  I32 depth;
323  I32 pad;
324  I32 *origin;
325  void (*handler)(pTHX_ void *);
326 } su_ud_common;
327
328 #define SU_UD_DEPTH(U)   (((su_ud_common *) (U))->depth)
329 #define SU_UD_PAD(U)     (((su_ud_common *) (U))->pad)
330 #define SU_UD_ORIGIN(U)  (((su_ud_common *) (U))->origin)
331 #define SU_UD_HANDLER(U) (((su_ud_common *) (U))->handler)
332
333 #define SU_UD_FREE(U) STMT_START { \
334  if (SU_UD_ORIGIN(U)) Safefree(SU_UD_ORIGIN(U)); \
335  Safefree(U); \
336 } STMT_END
337
338 /* ... Reap ................................................................ */
339
340 typedef struct {
341  su_ud_common ci;
342  SV *cb;
343 } su_ud_reap;
344
345 STATIC void su_call(pTHX_ void *ud_) {
346  su_ud_reap *ud = (su_ud_reap *) ud_;
347 #if SU_HAS_PERL(5, 9, 5)
348  PERL_CONTEXT saved_cx;
349  I32 cxix;
350 #endif
351
352  dSP;
353
354  SU_D({
355   PerlIO_printf(Perl_debug_log,
356                 "%p: @@@ call\n%p: depth=%2d scope_ix=%2d save_ix=%2d\n",
357                  ud, ud, SU_UD_DEPTH(ud), PL_scopestack_ix, PL_savestack_ix);
358  });
359
360  ENTER;
361  SAVETMPS;
362
363  PUSHMARK(SP);
364  PUTBACK;
365
366  /* If the recently popped context isn't saved there, it will be overwritten by
367   * the sub scope from call_sv, although it's still needed in our caller. */
368
369 #if SU_HAS_PERL(5, 9, 5)
370  if (cxstack_ix < cxstack_max)
371   cxix = cxstack_ix + 1;
372  else
373   cxix = Perl_cxinc(aTHX);
374  saved_cx = cxstack[cxix];
375 #endif
376
377  call_sv(ud->cb, G_VOID);
378
379 #if SU_HAS_PERL(5, 9, 5)
380  cxstack[cxix] = saved_cx;
381 #endif
382
383  PUTBACK;
384
385  FREETMPS;
386  LEAVE;
387
388  SvREFCNT_dec(ud->cb);
389  SU_UD_FREE(ud);
390 }
391
392 STATIC void su_reap(pTHX_ void *ud) {
393 #define su_reap(U) su_reap(aTHX_ (U))
394  SU_D({
395   PerlIO_printf(Perl_debug_log,
396                 "%p: === reap\n%p: depth=%2d scope_ix=%2d save_ix=%2d\n",
397                  ud, ud, SU_UD_DEPTH(ud), PL_scopestack_ix, PL_savestack_ix);
398  });
399
400  SAVEDESTRUCTOR_X(su_call, ud);
401 }
402
403 /* ... Localize & localize array/hash element .............................. */
404
405 typedef struct {
406  su_ud_common ci;
407  SV    *sv;
408  SV    *val;
409  SV    *elem;
410  svtype type;
411 } su_ud_localize;
412
413 #define SU_UD_LOCALIZE_FREE(U) STMT_START { \
414  SvREFCNT_dec((U)->elem); \
415  SvREFCNT_dec((U)->val);  \
416  SvREFCNT_dec((U)->sv);   \
417  SU_UD_FREE(U);           \
418 } STMT_END
419
420 STATIC I32 su_ud_localize_init(pTHX_ su_ud_localize *ud, SV *sv, SV *val, SV *elem) {
421 #define su_ud_localize_init(UD, S, V, E) su_ud_localize_init(aTHX_ (UD), (S), (V), (E))
422  UV deref = 0;
423  svtype t = SVt_NULL;
424  I32 size;
425
426  SvREFCNT_inc_simple_void(sv);
427
428  if (SvTYPE(sv) >= SVt_PVGV) {
429   if (!val || !SvROK(val)) { /* local *x; or local *x = $val; */
430    t = SVt_PVGV;
431   } else {                   /* local *x = \$val; */
432    t = SvTYPE(SvRV(val));
433    deref = 1;
434   }
435  } else if (SvROK(sv)) {
436   croak("Invalid %s reference as the localization target",
437                  sv_reftype(SvRV(sv), 0));
438  } else {
439   STRLEN len, l;
440   const char *p = SvPV_const(sv, len), *s;
441   for (s = p, l = len; l > 0 && isSPACE(*s); ++s, --l) { }
442   if (!l) {
443    l = len;
444    s = p;
445   }
446   switch (*s) {
447    case '$': t = SVt_PV;   break;
448    case '@': t = SVt_PVAV; break;
449    case '%': t = SVt_PVHV; break;
450    case '&': t = SVt_PVCV; break;
451    case '*': t = SVt_PVGV; break;
452   }
453   if (t != SVt_NULL) {
454    ++s;
455    --l;
456   } else if (val) { /* t == SVt_NULL, type can't be inferred from the sigil */
457    if (SvROK(val) && !sv_isobject(val)) {
458     t = SvTYPE(SvRV(val));
459     deref = 1;
460    } else {
461     t = SvTYPE(val);
462    }
463   }
464   SvREFCNT_dec(sv);
465   sv = newSVpvn(s, l);
466  }
467
468  switch (t) {
469   case SVt_PVAV:
470    size  = elem ? SU_SAVE_AELEM_OR_ADELETE_SIZE
471                 : SU_SAVE_ARY_SIZE;
472    deref = 0;
473    break;
474   case SVt_PVHV:
475    size  = elem ? SU_SAVE_HELEM_OR_HDELETE_SIZE
476                 : SU_SAVE_HASH_SIZE;
477    deref = 0;
478    break;
479   case SVt_PVGV:
480    size  = SU_SAVE_GP_SIZE;
481    deref = 0;
482    break;
483   case SVt_PVCV:
484    size  = SU_SAVE_SPTR_SIZE;
485    deref = 0;
486    break;
487   default:
488    size = SU_SAVE_SCALAR_SIZE;
489    break;
490  }
491  /* When deref is set, val isn't NULL */
492
493  ud->sv   = sv;
494  ud->val  = val ? newSVsv(deref ? SvRV(val) : val) : NULL;
495  ud->elem = SvREFCNT_inc(elem);
496  ud->type = t;
497
498  return size;
499 }
500
501 STATIC void su_localize(pTHX_ void *ud_) {
502 #define su_localize(U) su_localize(aTHX_ (U))
503  su_ud_localize *ud = (su_ud_localize *) ud_;
504  SV *sv   = ud->sv;
505  SV *val  = ud->val;
506  SV *elem = ud->elem;
507  svtype t = ud->type;
508  GV *gv;
509
510  if (SvTYPE(sv) >= SVt_PVGV) {
511   gv = (GV *) sv;
512  } else {
513 #ifdef gv_fetchsv
514   gv = gv_fetchsv(sv, GV_ADDMULTI, t);
515 #else
516   STRLEN len;
517   const char *name = SvPV_const(sv, len);
518   gv = gv_fetchpvn_flags(name, len, GV_ADDMULTI, t);
519 #endif
520  }
521
522  SU_D({
523   SV *z = newSV(0);
524   SvUPGRADE(z, t);
525   PerlIO_printf(Perl_debug_log, "%p: === localize a %s\n",ud, sv_reftype(z, 0));
526   PerlIO_printf(Perl_debug_log,
527                 "%p: depth=%2d scope_ix=%2d save_ix=%2d\n",
528                  ud, SU_UD_DEPTH(ud), PL_scopestack_ix, PL_savestack_ix);
529   SvREFCNT_dec(z);
530  });
531
532  /* Inspired from Alias.pm */
533  switch (t) {
534   case SVt_PVAV:
535    if (elem) {
536     su_save_aelem(GvAV(gv), elem, val);
537     goto done;
538    } else
539     save_ary(gv);
540    break;
541   case SVt_PVHV:
542    if (elem) {
543     su_save_helem(GvHV(gv), elem, val);
544     goto done;
545    } else
546     save_hash(gv);
547    break;
548   case SVt_PVGV:
549    save_gp(gv, 1); /* hide previous entry in symtab */
550    break;
551   case SVt_PVCV:
552    SAVESPTR(GvCV(gv));
553    GvCV_set(gv, NULL);
554    break;
555   default:
556    gv = (GV *) save_scalar(gv);
557    break;
558  }
559
560  if (val)
561   SvSetMagicSV((SV *) gv, val);
562
563 done:
564  SU_UD_LOCALIZE_FREE(ud);
565 }
566
567 /* --- Pop a context back -------------------------------------------------- */
568
569 #if SU_DEBUG
570 # ifdef DEBUGGING
571 #  define SU_CXNAME PL_block_type[CxTYPE(&cxstack[cxstack_ix])]
572 # else
573 #  define SU_CXNAME "XXX"
574 # endif
575 #endif
576
577 STATIC void su_pop(pTHX_ void *ud) {
578 #define su_pop(U) su_pop(aTHX_ (U))
579  I32 depth, base, mark, *origin;
580  depth = SU_UD_DEPTH(ud);
581
582  SU_D(
583   PerlIO_printf(Perl_debug_log,
584    "%p: --- pop a %s\n"
585    "%p: leave scope     at depth=%2d scope_ix=%2d cur_top=%2d cur_base=%2d\n",
586     ud, SU_CXNAME,
587     ud, depth, PL_scopestack_ix,PL_savestack_ix,PL_scopestack[PL_scopestack_ix])
588  );
589
590  origin = SU_UD_ORIGIN(ud);
591  mark   = origin[depth];
592  base   = origin[depth - 1];
593
594  SU_D(PerlIO_printf(Perl_debug_log,
595                     "%p: original scope was %*c top=%2d     base=%2d\n",
596                      ud,                24, ' ',    mark,        base));
597
598  if (base < mark) {
599   SU_D(PerlIO_printf(Perl_debug_log, "%p: clear leftovers\n", ud));
600   PL_savestack_ix = mark;
601   leave_scope(base);
602  }
603  PL_savestack_ix = base;
604
605  SU_UD_DEPTH(ud) = --depth;
606
607  if (depth > 0) {
608   I32 pad;
609
610   if ((pad = SU_UD_PAD(ud))) {
611    dMY_CXT;
612    do {
613     SU_D(PerlIO_printf(Perl_debug_log,
614           "%p: push a pad slot at depth=%2d scope_ix=%2d save_ix=%2d\n",
615            ud,                       depth, PL_scopestack_ix, PL_savestack_ix));
616     SU_SAVE_PLACEHOLDER();
617    } while (--pad);
618   }
619
620   SU_D(PerlIO_printf(Perl_debug_log,
621           "%p: push destructor at depth=%2d scope_ix=%2d save_ix=%2d\n",
622            ud,                       depth, PL_scopestack_ix, PL_savestack_ix));
623   SAVEDESTRUCTOR_X(su_pop, ud);
624  } else {
625   SU_UD_HANDLER(ud)(aTHX_ ud);
626  }
627
628  SU_D(PerlIO_printf(Perl_debug_log,
629                     "%p: --- end pop: cur_top=%2d == cur_base=%2d\n",
630                      ud, PL_savestack_ix, PL_scopestack[PL_scopestack_ix]));
631 }
632
633 /* --- Initialize the stack and the action userdata ------------------------ */
634
635 STATIC I32 su_init(pTHX_ void *ud, I32 cxix, I32 size) {
636 #define su_init(U, C, S) su_init(aTHX_ (U), (C), (S))
637  I32 i, depth = 1, pad, offset, *origin;
638
639  SU_D(PerlIO_printf(Perl_debug_log, "%p: ### init for cx %d\n", ud, cxix));
640
641  if (size <= SU_SAVE_DESTRUCTOR_SIZE)
642   pad = 0;
643  else {
644   I32 extra = size - SU_SAVE_DESTRUCTOR_SIZE;
645   pad = extra / SU_SAVE_PLACEHOLDER_SIZE;
646   if (extra % SU_SAVE_PLACEHOLDER_SIZE)
647    ++pad;
648  }
649  offset = SU_SAVE_DESTRUCTOR_SIZE + SU_SAVE_PLACEHOLDER_SIZE * pad;
650
651  SU_D(PerlIO_printf(Perl_debug_log, "%p: size=%d pad=%d offset=%d\n",
652                                      ud,    size,   pad,   offset));
653
654  for (i = cxstack_ix; i > cxix; --i) {
655   PERL_CONTEXT *cx = cxstack + i;
656   switch (CxTYPE(cx)) {
657 #if SU_HAS_PERL(5, 10, 0)
658    case CXt_BLOCK:
659     SU_D(PerlIO_printf(Perl_debug_log, "%p: cx %d is block\n", ud, i));
660     /* Given and when blocks are actually followed by a simple block, so skip
661      * it if needed. */
662     if (cxix > 0) { /* Implies i > 0 */
663      PERL_CONTEXT *next = cx - 1;
664      if (CxTYPE(next) == CXt_GIVEN || CxTYPE(next) == CXt_WHEN)
665       --cxix;
666     }
667     depth++;
668     break;
669 #endif
670 #if SU_HAS_PERL(5, 11, 0)
671    case CXt_LOOP_FOR:
672    case CXt_LOOP_PLAIN:
673    case CXt_LOOP_LAZYSV:
674    case CXt_LOOP_LAZYIV:
675 #else
676    case CXt_LOOP:
677 #endif
678     SU_D(PerlIO_printf(Perl_debug_log, "%p: cx %d is loop\n", ud, i));
679     depth += 2;
680     break;
681    default:
682     SU_D(PerlIO_printf(Perl_debug_log, "%p: cx %d is other\n", ud, i));
683     depth++;
684     break;
685   }
686  }
687  SU_D(PerlIO_printf(Perl_debug_log, "%p: going down to depth %d\n", ud, depth));
688
689  Newx(origin, depth + 1, I32);
690  origin[0] = PL_scopestack[PL_scopestack_ix - depth];
691  PL_scopestack[PL_scopestack_ix - depth] += size;
692  for (i = depth - 1; i >= 1; --i) {
693   I32 j = PL_scopestack_ix - i;
694   origin[depth - i] = PL_scopestack[j];
695   PL_scopestack[j] += offset;
696  }
697  origin[depth] = PL_savestack_ix;
698
699  SU_UD_ORIGIN(ud) = origin;
700  SU_UD_DEPTH(ud)  = depth;
701  SU_UD_PAD(ud)    = pad;
702
703  /* Make sure the first destructor fires by pushing enough fake slots on the
704   * stack. */
705  if (PL_savestack_ix + SU_SAVE_DESTRUCTOR_SIZE
706                                        <= PL_scopestack[PL_scopestack_ix - 1]) {
707   dMY_CXT;
708   do {
709    SU_D(PerlIO_printf(Perl_debug_log,
710                   "%p: push a fake slot      at scope_ix=%2d  save_ix=%2d\n",
711                    ud,                      PL_scopestack_ix, PL_savestack_ix));
712    SU_SAVE_PLACEHOLDER();
713   } while (PL_savestack_ix + SU_SAVE_DESTRUCTOR_SIZE
714                                         <= PL_scopestack[PL_scopestack_ix - 1]);
715  }
716  SU_D(PerlIO_printf(Perl_debug_log,
717                   "%p: push first destructor at scope_ix=%2d  save_ix=%2d\n",
718                    ud,                      PL_scopestack_ix, PL_savestack_ix));
719  SAVEDESTRUCTOR_X(su_pop, ud);
720
721  SU_D({
722   for (i = 0; i <= depth; ++i) {
723    I32 j = PL_scopestack_ix  - i;
724    PerlIO_printf(Perl_debug_log,
725                  "%p: depth=%2d scope_ix=%2d saved_floor=%2d new_floor=%2d\n",
726                   ud,        i, j, origin[depth - i],
727                                    i == 0 ? PL_savestack_ix : PL_scopestack[j]);
728   }
729  });
730
731  return depth;
732 }
733
734 /* --- Unwind stack -------------------------------------------------------- */
735
736 STATIC void su_unwind(pTHX_ void *ud_) {
737  dMY_CXT;
738  I32 cxix    = MY_CXT.cxix;
739  I32 items   = MY_CXT.items - 1;
740  SV **savesp = MY_CXT.savesp;
741  I32 mark;
742
743  PERL_UNUSED_VAR(ud_);
744
745  if (savesp)
746   PL_stack_sp = savesp;
747
748  if (cxstack_ix > cxix)
749   dounwind(cxix);
750
751  /* Hide the level */
752  if (items >= 0)
753   PL_stack_sp--;
754
755  mark = PL_markstack[cxstack[cxix].blk_oldmarksp];
756  *PL_markstack_ptr = PL_stack_sp - PL_stack_base - items;
757
758  SU_D({
759   I32 gimme = GIMME_V;
760   PerlIO_printf(Perl_debug_log,
761                 "%p: cx=%d gimme=%s items=%d sp=%d oldmark=%d mark=%d\n",
762                 &MY_CXT, cxix,
763                 gimme == G_VOID ? "void" : gimme == G_ARRAY ? "list" : "scalar",
764                 items, PL_stack_sp - PL_stack_base, *PL_markstack_ptr, mark);
765  });
766
767  PL_op = (OP *) &(MY_CXT.return_op);
768  PL_op = PL_op->op_ppaddr(aTHX);
769
770  *PL_markstack_ptr = mark;
771
772  MY_CXT.proxy_op.op_next = PL_op;
773  PL_op = &(MY_CXT.proxy_op);
774 }
775
776 /* --- XS ------------------------------------------------------------------ */
777
778 #if SU_HAS_PERL(5, 8, 9)
779 # define SU_SKIP_DB_MAX 2
780 #else
781 # define SU_SKIP_DB_MAX 3
782 #endif
783
784 /* Skip context sequences of 1 to SU_SKIP_DB_MAX (included) block contexts
785  * followed by a DB sub */
786
787 #define SU_SKIP_DB(C) \
788  STMT_START {         \
789   I32 skipped = 0;    \
790   PERL_CONTEXT *base = cxstack;      \
791   PERL_CONTEXT *cx   = base + (C);   \
792   while (cx >= base && (C) > skipped && CxTYPE(cx) == CXt_BLOCK) \
793    --cx, ++skipped;                  \
794   if (cx >= base && (C) > skipped) { \
795    switch (CxTYPE(cx)) {  \
796     case CXt_SUB:         \
797      if (skipped <= SU_SKIP_DB_MAX && cx->blk_sub.cv == GvCV(PL_DBsub)) \
798       (C) -= skipped + 1; \
799       break;              \
800     default:              \
801      break;               \
802    }                      \
803   }                       \
804  } STMT_END
805
806 #define SU_GET_CONTEXT(A, B)   \
807  STMT_START {                  \
808   if (items > A) {             \
809    SV *csv = ST(B);            \
810    if (!SvOK(csv))             \
811     goto default_cx;           \
812    cxix = SvIV(csv);           \
813    if (cxix < 0)               \
814     cxix = 0;                  \
815    else if (cxix > cxstack_ix) \
816     cxix = cxstack_ix;         \
817   } else {                     \
818 default_cx:                    \
819    cxix = cxstack_ix;          \
820    if (PL_DBsub)               \
821     SU_SKIP_DB(cxix);          \
822   }                            \
823  } STMT_END
824
825 #define SU_GET_LEVEL(A, B) \
826  STMT_START {              \
827   level = 0;               \
828   if (items > 0) {         \
829    SV *lsv = ST(B);        \
830    if (SvOK(lsv)) {        \
831     level = SvIV(lsv);     \
832     if (level < 0)         \
833      level = 0;            \
834    }                       \
835   }                        \
836  } STMT_END
837
838 XS(XS_Scope__Upper_unwind); /* prototype to pass -Wmissing-prototypes */
839
840 XS(XS_Scope__Upper_unwind) {
841 #ifdef dVAR
842  dVAR; dXSARGS;
843 #else
844  dXSARGS;
845 #endif
846  dMY_CXT;
847  I32 cxix;
848
849  PERL_UNUSED_VAR(cv); /* -W */
850  PERL_UNUSED_VAR(ax); /* -Wall */
851
852  SU_GET_CONTEXT(0, items - 1);
853  do {
854   PERL_CONTEXT *cx = cxstack + cxix;
855   switch (CxTYPE(cx)) {
856    case CXt_SUB:
857     if (PL_DBsub && cx->blk_sub.cv == GvCV(PL_DBsub))
858      continue;
859    case CXt_EVAL:
860    case CXt_FORMAT:
861     MY_CXT.cxix  = cxix;
862     MY_CXT.items = items;
863     /* pp_entersub will want to sanitize the stack after returning from there
864      * Screw that, we're insane */
865     if (GIMME_V == G_SCALAR) {
866      MY_CXT.savesp = PL_stack_sp;
867      /* dXSARGS calls POPMARK, so we need to match PL_markstack_ptr[1] */
868      PL_stack_sp = PL_stack_base + PL_markstack_ptr[1] + 1;
869     } else {
870      MY_CXT.savesp = NULL;
871     }
872     SAVEDESTRUCTOR_X(su_unwind, NULL);
873     return;
874    default:
875     break;
876   }
877  } while (--cxix >= 0);
878  croak("Can't return outside a subroutine");
879 }
880
881 MODULE = Scope::Upper            PACKAGE = Scope::Upper
882
883 PROTOTYPES: ENABLE
884
885 BOOT:
886 {
887  HV *stash;
888
889  MY_CXT_INIT;
890
891  MY_CXT.stack_placeholder = NULL;
892
893  /* NewOp() calls calloc() which just zeroes the memory with memset(). */
894  Zero(&(MY_CXT.return_op), 1, sizeof(MY_CXT.return_op));
895  MY_CXT.return_op.op_type   = OP_RETURN;
896  MY_CXT.return_op.op_ppaddr = PL_ppaddr[OP_RETURN];
897
898  Zero(&(MY_CXT.proxy_op), 1, sizeof(MY_CXT.proxy_op));
899  MY_CXT.proxy_op.op_type   = OP_STUB;
900  MY_CXT.proxy_op.op_ppaddr = NULL;
901
902  stash = gv_stashpv(__PACKAGE__, 1);
903  newCONSTSUB(stash, "TOP",           newSViv(0));
904  newCONSTSUB(stash, "SU_THREADSAFE", newSVuv(SU_THREADSAFE));
905
906  newXSproto("Scope::Upper::unwind", XS_Scope__Upper_unwind, file, NULL);
907 }
908
909 #if SU_THREADSAFE
910
911 void
912 CLONE(...)
913 PROTOTYPE: DISABLE
914 PPCODE:
915  {
916   MY_CXT_CLONE;
917  }
918  XSRETURN(0);
919
920 #endif /* SU_THREADSAFE */
921
922 SV *
923 HERE()
924 PROTOTYPE:
925 PREINIT:
926  I32 cxix = cxstack_ix;
927 CODE:
928  if (PL_DBsub)
929   SU_SKIP_DB(cxix);
930  RETVAL = newSViv(cxix);
931 OUTPUT:
932  RETVAL
933
934 SV *
935 UP(...)
936 PROTOTYPE: ;$
937 PREINIT:
938  I32 cxix;
939 CODE:
940  SU_GET_CONTEXT(0, 0);
941  if (--cxix < 0)
942   cxix = 0;
943  if (PL_DBsub)
944   SU_SKIP_DB(cxix);
945  RETVAL = newSViv(cxix);
946 OUTPUT:
947  RETVAL
948
949 void
950 SUB(...)
951 PROTOTYPE: ;$
952 PREINIT:
953  I32 cxix;
954 PPCODE:
955  SU_GET_CONTEXT(0, 0);
956  for (; cxix >= 0; --cxix) {
957   PERL_CONTEXT *cx = cxstack + cxix;
958   switch (CxTYPE(cx)) {
959    default:
960     continue;
961    case CXt_SUB:
962     if (PL_DBsub && cx->blk_sub.cv == GvCV(PL_DBsub))
963      continue;
964     ST(0) = sv_2mortal(newSViv(cxix));
965     XSRETURN(1);
966   }
967  }
968  XSRETURN_UNDEF;
969
970 void
971 EVAL(...)
972 PROTOTYPE: ;$
973 PREINIT:
974  I32 cxix;
975 PPCODE:
976  SU_GET_CONTEXT(0, 0);
977  for (; cxix >= 0; --cxix) {
978   PERL_CONTEXT *cx = cxstack + cxix;
979   switch (CxTYPE(cx)) {
980    default:
981     continue;
982    case CXt_EVAL:
983     ST(0) = sv_2mortal(newSViv(cxix));
984     XSRETURN(1);
985   }
986  }
987  XSRETURN_UNDEF;
988
989 void
990 SCOPE(...)
991 PROTOTYPE: ;$
992 PREINIT:
993  I32 cxix, level;
994 PPCODE:
995  SU_GET_LEVEL(0, 0);
996  cxix = cxstack_ix;
997  if (PL_DBsub) {
998   SU_SKIP_DB(cxix);
999   while (cxix > 0) {
1000    if (--level < 0)
1001     break;
1002    --cxix;
1003    SU_SKIP_DB(cxix);
1004   }
1005  } else {
1006   cxix -= level;
1007   if (cxix < 0)
1008    cxix = 0;
1009  }
1010  ST(0) = sv_2mortal(newSViv(cxix));
1011  XSRETURN(1);
1012
1013 void
1014 CALLER(...)
1015 PROTOTYPE: ;$
1016 PREINIT:
1017  I32 cxix, level;
1018 PPCODE:
1019  SU_GET_LEVEL(0, 0);
1020  for (cxix = cxstack_ix; cxix > 0; --cxix) {
1021   PERL_CONTEXT *cx = cxstack + cxix;
1022   switch (CxTYPE(cx)) {
1023    case CXt_SUB:
1024     if (PL_DBsub && cx->blk_sub.cv == GvCV(PL_DBsub))
1025      continue;
1026    case CXt_EVAL:
1027    case CXt_FORMAT:
1028     if (--level < 0)
1029      goto done;
1030     break;
1031   }
1032  }
1033 done:
1034  ST(0) = sv_2mortal(newSViv(cxix));
1035  XSRETURN(1);
1036
1037 void
1038 want_at(...)
1039 PROTOTYPE: ;$
1040 PREINIT:
1041  I32 cxix;
1042 PPCODE:
1043  SU_GET_CONTEXT(0, 0);
1044  while (cxix > 0) {
1045   PERL_CONTEXT *cx = cxstack + cxix--;
1046   switch (CxTYPE(cx)) {
1047    case CXt_SUB:
1048    case CXt_EVAL:
1049    case CXt_FORMAT: {
1050     I32 gimme = cx->blk_gimme;
1051     switch (gimme) {
1052      case G_VOID:   XSRETURN_UNDEF; break;
1053      case G_SCALAR: XSRETURN_NO;    break;
1054      case G_ARRAY:  XSRETURN_YES;   break;
1055     }
1056     break;
1057    }
1058   }
1059  }
1060  XSRETURN_UNDEF;
1061
1062 void
1063 reap(SV *hook, ...)
1064 PROTOTYPE: &;$
1065 PREINIT:
1066  I32 cxix;
1067  su_ud_reap *ud;
1068 CODE:
1069  SU_GET_CONTEXT(1, 1);
1070  Newx(ud, 1, su_ud_reap);
1071  SU_UD_ORIGIN(ud)  = NULL;
1072  SU_UD_HANDLER(ud) = su_reap;
1073  ud->cb = newSVsv(hook);
1074  su_init(ud, cxix, SU_SAVE_DESTRUCTOR_SIZE);
1075
1076 void
1077 localize(SV *sv, SV *val, ...)
1078 PROTOTYPE: $$;$
1079 PREINIT:
1080  I32 cxix;
1081  I32 size;
1082  su_ud_localize *ud;
1083 CODE:
1084  SU_GET_CONTEXT(2, 2);
1085  Newx(ud, 1, su_ud_localize);
1086  SU_UD_ORIGIN(ud)  = NULL;
1087  SU_UD_HANDLER(ud) = su_localize;
1088  size = su_ud_localize_init(ud, sv, val, NULL);
1089  su_init(ud, cxix, size);
1090
1091 void
1092 localize_elem(SV *sv, SV *elem, SV *val, ...)
1093 PROTOTYPE: $$$;$
1094 PREINIT:
1095  I32 cxix;
1096  I32 size;
1097  su_ud_localize *ud;
1098 CODE:
1099  if (SvTYPE(sv) >= SVt_PVGV)
1100   croak("Can't infer the element localization type from a glob and the value");
1101  SU_GET_CONTEXT(3, 3);
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, val, elem);
1106  if (ud->type != SVt_PVAV && ud->type != SVt_PVHV) {
1107   SU_UD_LOCALIZE_FREE(ud);
1108   croak("Can't localize an element of something that isn't an array or a hash");
1109  }
1110  su_init(ud, cxix, size);
1111
1112 void
1113 localize_delete(SV *sv, SV *elem, ...)
1114 PROTOTYPE: $$;$
1115 PREINIT:
1116  I32 cxix;
1117  I32 size;
1118  su_ud_localize *ud;
1119 CODE:
1120  SU_GET_CONTEXT(2, 2);
1121  Newx(ud, 1, su_ud_localize);
1122  SU_UD_ORIGIN(ud)  = NULL;
1123  SU_UD_HANDLER(ud) = su_localize;
1124  size = su_ud_localize_init(ud, sv, NULL, elem);
1125  su_init(ud, cxix, size);