Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 4 Jun 2016 20:58:50 +0000 (UTC)
From:      Kurt Jaeger <pi@FreeBSD.org>
To:        ports-committers@freebsd.org, svn-ports-all@freebsd.org, svn-ports-head@freebsd.org
Subject:   svn commit: r416377 - in head/devel/p5-Scope-Upper: . files
Message-ID:  <201606042058.u54Kwo8W038682@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: pi
Date: Sat Jun  4 20:58:49 2016
New Revision: 416377
URL: https://svnweb.freebsd.org/changeset/ports/416377

Log:
  devel/p5-Scope-Upper: fix build with perl 5.24
  
  Source of patch see
  https://rt.cpan.org/Public/Bug/Display.html?id=112246
  and there:
  http://www.nntp.perl.org/group/perl.perl5.porters/2016/05/msg236847.html,
  the patches from Dave Mitchell
  
  PR:		210036

Added:
  head/devel/p5-Scope-Upper/files/
  head/devel/p5-Scope-Upper/files/patch-MANIFEST   (contents, props changed)
  head/devel/p5-Scope-Upper/files/patch-Makefile.PL   (contents, props changed)
  head/devel/p5-Scope-Upper/files/patch-Upper.xs   (contents, props changed)
  head/devel/p5-Scope-Upper/files/patch-t_13-reap-ctl.t   (contents, props changed)
  head/devel/p5-Scope-Upper/files/patch-t_91-pod.t   (contents, props changed)
  head/devel/p5-Scope-Upper/files/patch-t_92-pod-coverage.t   (contents, props changed)
  head/devel/p5-Scope-Upper/files/patch-t_93-pod-spelling.t   (contents, props changed)
  head/devel/p5-Scope-Upper/files/patch-t_95-portability-files.t   (contents, props changed)
  head/devel/p5-Scope-Upper/files/patch-xsh_caps.h   (contents, props changed)
  head/devel/p5-Scope-Upper/files/patch-xsh_debug.h   (contents, props changed)
  head/devel/p5-Scope-Upper/files/patch-xsh_threads.h   (contents, props changed)
  head/devel/p5-Scope-Upper/files/patch-xsh_util.h   (contents, props changed)
Modified:
  head/devel/p5-Scope-Upper/Makefile

Modified: head/devel/p5-Scope-Upper/Makefile
==============================================================================
--- head/devel/p5-Scope-Upper/Makefile	Sat Jun  4 20:42:47 2016	(r416376)
+++ head/devel/p5-Scope-Upper/Makefile	Sat Jun  4 20:58:49 2016	(r416377)
@@ -3,6 +3,7 @@
 
 PORTNAME=	Scope-Upper
 PORTVERSION=	0.28
+PORTREVISION=	1
 CATEGORIES=	devel perl5
 MASTER_SITES=	CPAN
 MASTER_SITE_SUBDIR=	CPAN:VPIT

Added: head/devel/p5-Scope-Upper/files/patch-MANIFEST
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/devel/p5-Scope-Upper/files/patch-MANIFEST	Sat Jun  4 20:58:49 2016	(r416377)
@@ -0,0 +1,10 @@
+--- MANIFEST.orig	2015-03-23 19:15:17 UTC
++++ MANIFEST
+@@ -66,3 +66,7 @@ t/87-stress-uid.t
+ t/lib/Scope/Upper/TestGenerator.pm
+ t/lib/Test/Leaner.pm
+ t/lib/VPIT/TestHelpers.pm
++xsh/caps.h
++xsh/debug.h
++xsh/threads.h
++xsh/util.h

Added: head/devel/p5-Scope-Upper/files/patch-Makefile.PL
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/devel/p5-Scope-Upper/files/patch-Makefile.PL	Sat Jun  4 20:58:49 2016	(r416377)
@@ -0,0 +1,11 @@
+--- Makefile.PL.orig	2015-03-27 19:07:42 UTC
++++ Makefile.PL
+@@ -51,7 +51,7 @@ print $is_gcc_34 ? "yes\n" : "no\n";
+ 
+ # Threads, Windows and 5.8.x don't seem to be best friends
+ if ($^O eq 'MSWin32' && "$]" < 5.009) {
+- push @DEFINES, '-DSU_MULTIPLICITY=0';
++ push @DEFINES, '-DXSH_MULTIPLICITY=0';
+ }
+ 
+ @DEFINES = (DEFINE => join ' ', @DEFINES) if @DEFINES;

Added: head/devel/p5-Scope-Upper/files/patch-Upper.xs
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/devel/p5-Scope-Upper/files/patch-Upper.xs	Sat Jun  4 20:58:49 2016	(r416377)
@@ -0,0 +1,2099 @@
+--- Upper.xs.orig	2015-08-18 13:52:04 UTC
++++ Upper.xs
+@@ -6,21 +6,21 @@
+ #include "perl.h"
+ #include "XSUB.h"
+ 
+-#define __PACKAGE__ "Scope::Upper"
++/* --- XS helpers ---------------------------------------------------------- */
+ 
+-#ifndef SU_DEBUG
+-# define SU_DEBUG 0
+-#endif
++#define XSH_PACKAGE "Scope::Upper"
++
++#include "xsh/caps.h"
++#include "xsh/util.h"
++#include "xsh/debug.h"
+ 
+ /* --- Compatibility ------------------------------------------------------- */
+ 
+-#ifndef NOOP
+-# define NOOP
++/* perl 5.23.8 onwards has a revamped context system */
++#if XSH_HAS_PERL(5, 23, 8)
++# define SU_HAS_NEW_CXT
+ #endif
+ 
+-#ifndef dNOOP
+-# define dNOOP
+-#endif
+ 
+ #ifndef dVAR
+ # define dVAR dNOOP
+@@ -42,31 +42,6 @@
+ # define PERL_UNUSED_VAR(V)
+ #endif
+ 
+-#ifndef STMT_START
+-# define STMT_START do
+-#endif
+-
+-#ifndef STMT_END
+-# define STMT_END while (0)
+-#endif
+-
+-#if SU_DEBUG
+-# define SU_D(X) STMT_START X STMT_END
+-static void su_debug_log(const char *fmt, ...) {
+- va_list va;
+- SV *sv;
+- dTHX;
+- va_start(va, fmt);
+- sv = get_sv(__PACKAGE__ "::DEBUG", 0);
+- if (sv && SvTRUE(sv))
+-  PerlIO_vprintf(Perl_debug_log, fmt, va);
+- va_end(va);
+- return;
+-}
+-#else
+-# define SU_D(X)
+-#endif
+-
+ #ifndef Newx
+ # define Newx(v, n, c) New(0, v, n, c)
+ #endif
+@@ -228,45 +203,6 @@ static U8 su_op_gimme_reverse(U8 gimme) 
+ # define NEGATIVE_INDICES_VAR "NEGATIVE_INDICES"
+ #endif
+ 
+-#define SU_HAS_PERL(R, V, S) (PERL_REVISION > (R) || (PERL_REVISION == (R) && (PERL_VERSION > (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION >= (S))))))
+-#define SU_HAS_PERL_EXACT(R, V, S) ((PERL_REVISION == (R)) && (PERL_VERSION == (V)) && (PERL_SUBVERSION == (S)))
+-
+-/* --- Threads and multiplicity -------------------------------------------- */
+-
+-#ifndef SU_MULTIPLICITY
+-# if defined(MULTIPLICITY) || defined(PERL_IMPLICIT_CONTEXT)
+-#  define SU_MULTIPLICITY 1
+-# else
+-#  define SU_MULTIPLICITY 0
+-# endif
+-#endif
+-#if SU_MULTIPLICITY && !defined(tTHX)
+-# define tTHX PerlInterpreter*
+-#endif
+-
+-#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))
+-# define SU_THREADSAFE 1
+-# ifndef MY_CXT_CLONE
+-#  define MY_CXT_CLONE \
+-    dMY_CXT_SV;                                                      \
+-    my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1)); \
+-    Copy(INT2PTR(my_cxt_t*, SvUV(my_cxt_sv)), my_cxtp, 1, my_cxt_t); \
+-    sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
+-# endif
+-#else
+-# define SU_THREADSAFE 0
+-# undef  dMY_CXT
+-# define dMY_CXT      dNOOP
+-# undef  MY_CXT
+-# define MY_CXT       su_globaldata
+-# undef  START_MY_CXT
+-# define START_MY_CXT static my_cxt_t MY_CXT;
+-# undef  MY_CXT_INIT
+-# define MY_CXT_INIT  NOOP
+-# undef  MY_CXT_CLONE
+-# define MY_CXT_CLONE NOOP
+-#endif
+-
+ /* --- Error messages ------------------------------------------------------ */
+ 
+ static const char su_stack_smash[]    = "Cannot target a scope outside of the current stack";
+@@ -287,22 +223,14 @@ static su_uv_array su_uid_seq_counter;
+ 
+ static perl_mutex su_uid_seq_counter_mutex;
+ 
+-#define SU_LOCK(M)   MUTEX_LOCK(M)
+-#define SU_UNLOCK(M) MUTEX_UNLOCK(M)
+-
+-#else /* USE_ITHREADS */
+-
+-#define SU_LOCK(M)
+-#define SU_UNLOCK(M)
+-
+-#endif /* !USE_ITHREADS */
++#endif /* USE_ITHREADS */
+ 
+ static UV su_uid_seq_next(pTHX_ UV depth) {
+ #define su_uid_seq_next(D) su_uid_seq_next(aTHX_ (D))
+  UV seq;
+  UV *seqs;
+ 
+- SU_LOCK(&su_uid_seq_counter_mutex);
++ XSH_LOCK(&su_uid_seq_counter_mutex);
+ 
+  seqs = su_uid_seq_counter.seqs;
+ 
+@@ -319,7 +247,7 @@ static UV su_uid_seq_next(pTHX_ UV depth
+ 
+  seq = ++seqs[depth];
+ 
+- SU_UNLOCK(&su_uid_seq_counter_mutex);
++ XSH_UNLOCK(&su_uid_seq_counter_mutex);
+ 
+  return seq;
+ }
+@@ -415,7 +343,7 @@ typedef struct {
+ 
+ /* --- uplevel() data tokens and global storage ---------------------------- */
+ 
+-#define SU_UPLEVEL_HIJACKS_RUNOPS SU_HAS_PERL(5, 8, 0)
++#define SU_UPLEVEL_HIJACKS_RUNOPS XSH_HAS_PERL(5, 8, 0)
+ 
+ typedef struct {
+  void          *next;
+@@ -425,27 +353,39 @@ typedef struct {
+ 
+  I32            cxix;
+ 
+- I32            target_depth;
+- CV            *target;
+-
+  CV            *callback;
+  CV            *renamed;
+ 
++#ifdef SU_HAS_NEW_CXT
++ U8            *cxtypes; /* array of saved context types */
++ I32           gap;      /* how many contexts have temporarily CXt_NULLed out */
++ AV*           argarray; /* the PL_curpad[0] of the uplevel sub */
++#else
++ I32            target_depth;
++ CV            *target;
+  PERL_SI       *si;
+  PERL_SI       *old_curstackinfo;
+  AV            *old_mainstack;
++ OP            *old_op;
++ bool           old_catch;
++ bool           died;
++#endif
+ 
+  COP           *old_curcop;
+ 
+- OP            *old_op;
+ #if SU_UPLEVEL_HIJACKS_RUNOPS
+  runops_proc_t  old_runops;
+ #endif
+- bool           old_catch;
+-
+- bool           died;
+ } su_uplevel_ud;
+ 
++#ifdef SU_HAS_NEW_CXT
++/* used to flag a context stack entry whose type has been temporarily
++ * set to CXt_NULL. It relies on perl not using this value for real
++ * CXt_NULL entries.
++ */
++# define CXp_SU_UPLEVEL_NULLED 0x20
++#endif
++
+ static su_uplevel_ud *su_uplevel_ud_new(pTHX) {
+ #define su_uplevel_ud_new() su_uplevel_ud_new(aTHX)
+  su_uplevel_ud *sud;
+@@ -458,24 +398,29 @@ static su_uplevel_ud *su_uplevel_ud_new(
+  sud->tmp_uid_storage.used  = 0;
+  sud->tmp_uid_storage.alloc = 0;
+ 
++ #ifndef SU_HAS_NEW_CXT
+  Newx(si, 1, PERL_SI);
+  si->si_stack   = newAV();
+  AvREAL_off(si->si_stack);
+  si->si_cxstack = NULL;
+- si->si_cxmax   = 0;
++ si->si_cxmax   = -1;
+ 
+  sud->si = si;
++#endif
+ 
+  return sud;
+ }
+ 
+ static void su_uplevel_ud_delete(pTHX_ su_uplevel_ud *sud) {
+ #define su_uplevel_ud_delete(S) su_uplevel_ud_delete(aTHX_ (S))
++
++#ifndef SU_HAS_NEW_CXT
+  PERL_SI *si = sud->si;
+ 
+  Safefree(si->si_cxstack);
+  SvREFCNT_dec(si->si_stack);
+  Safefree(si);
++#endif
+ 
+  Safefree(sud->tmp_uid_storage.map);
+ 
+@@ -496,60 +441,97 @@ typedef struct {
+ 
+ /* --- Global data --------------------------------------------------------- */
+ 
+-#define MY_CXT_KEY __PACKAGE__ "::_guts" XS_VERSION
+-
+ typedef struct {
+- char               *stack_placeholder;
+  su_unwind_storage   unwind_storage;
+  su_yield_storage    yield_storage;
+  su_uplevel_storage  uplevel_storage;
+  su_uid_storage      uid_storage;
+-} my_cxt_t;
++} xsh_user_cxt_t;
+ 
+-START_MY_CXT
++#define XSH_THREADS_USER_CONTEXT            1
++#define XSH_THREADS_USER_CLONE_NEEDS_DUP    0
++#define XSH_THREADS_COMPILE_TIME_PROTECTION 0
++
++#if XSH_THREADSAFE
++
++static void xsh_user_clone(pTHX_ const xsh_user_cxt_t *old_cxt, xsh_user_cxt_t *new_cxt) {
++ new_cxt->uplevel_storage.top   = NULL;
++ new_cxt->uplevel_storage.root  = NULL;
++ new_cxt->uplevel_storage.count = 0;
++ new_cxt->uid_storage.map   = NULL;
++ new_cxt->uid_storage.used  = 0;
++ new_cxt->uid_storage.alloc = 0;
++
++ su_uid_storage_dup(&new_cxt->uid_storage, &old_cxt->uid_storage,
++                    old_cxt->uid_storage.used);
++
++ return;
++}
++
++#endif /* XSH_THREADSAFE */
++
++#include "xsh/threads.h"
+ 
+ /* --- Stack manipulations ------------------------------------------------- */
+ 
+-#define SU_SAVE_PLACEHOLDER() save_pptr(&MY_CXT.stack_placeholder)
++/* how many slots on the save stack various save types take up */
+ 
+-#define SU_SAVE_DESTRUCTOR_SIZE  3
+-#define SU_SAVE_PLACEHOLDER_SIZE 3
++#define SU_SAVE_DESTRUCTOR_SIZE 3 /* SAVEt_DESTRUCTOR_X */
++#define SU_SAVE_SCALAR_SIZE     3 /* SAVEt_SV */
++#define SU_SAVE_ARY_SIZE        3 /* SAVEt_AV */
++#define SU_SAVE_AELEM_SIZE      4 /* SAVEt_AELEM */
++#define SU_SAVE_HASH_SIZE       3 /* SAVEt_HV */
++#define SU_SAVE_HELEM_SIZE      4 /* SAVEt_HELEM */
++#define SU_SAVE_HDELETE_SIZE    4 /* SAVEt_DELETE */
+ 
+-#define SU_SAVE_SCALAR_SIZE 3
++#define SU_SAVE_GVCV_SIZE       SU_SAVE_DESTRUCTOR_SIZE
++
++/* the overhead of save_alloc() but not including any elements,
++ * of which there must be at least 1 */
++#if XSH_HAS_PERL(5, 14, 0)
++# define SU_SAVE_ALLOC_SIZE      1 /* SAVEt_ALLOC */
++#else
++# define SU_SAVE_ALLOC_SIZE      2 /* SAVEt_ALLOC */
++#endif
+ 
+-#define SU_SAVE_ARY_SIZE      3
+-#define SU_SAVE_AELEM_SIZE    4
+ #ifdef SAVEADELETE
+-# define SU_SAVE_ADELETE_SIZE 3
++# define SU_SAVE_ADELETE_SIZE   3 /* SAVEt_ADELETE */
+ #else
+-# define SU_SAVE_ADELETE_SIZE SU_SAVE_DESTRUCTOR_SIZE
++# define SU_SAVE_ADELETE_SIZE   SU_SAVE_DESTRUCTOR_SIZE
++#endif
++
++/* (NB: it was 4 between 5.13.1 and 5.13.7) */
++#if XSH_HAS_PERL(5, 8, 9)
++# define SU_SAVE_GP_SIZE        3 /* SAVEt_GP */
++# else
++# define SU_SAVE_GP_SIZE        6 /* SAVEt_GP */
+ #endif
++
++/* sometimes we don't know in advance whether we're saving or deleting
++ * an array/hash element. So include enough room for a variable-sized
++ * save_alloc() to pad it to a fixed size.
++ */
++
+ #if SU_SAVE_AELEM_SIZE < SU_SAVE_ADELETE_SIZE
+-# define SU_SAVE_AELEM_OR_ADELETE_SIZE SU_SAVE_ADELETE_SIZE
++# define SU_SAVE_AELEM_OR_ADELETE_SIZE \
++    (SU_SAVE_ADELETE_SIZE + SU_SAVE_ALLOC_SIZE + 1)
++#elif SU_SAVE_AELEM_SIZE > SU_SAVE_ADELETE_SIZE
++# define SU_SAVE_AELEM_OR_ADELETE_SIZE \
++    (SU_SAVE_AELEM_SIZE + SU_SAVE_ALLOC_SIZE + 1)
+ #else
+ # define SU_SAVE_AELEM_OR_ADELETE_SIZE SU_SAVE_AELEM_SIZE
+ #endif
+ 
+-#define SU_SAVE_HASH_SIZE    3
+-#define SU_SAVE_HELEM_SIZE   4
+-#define SU_SAVE_HDELETE_SIZE 4
+ #if SU_SAVE_HELEM_SIZE < SU_SAVE_HDELETE_SIZE
+-# define SU_SAVE_HELEM_OR_HDELETE_SIZE SU_SAVE_HDELETE_SIZE
++# define SU_SAVE_HELEM_OR_HDELETE_SIZE \
++    (SU_SAVE_HDELETE_SIZE + SU_SAVE_ALLOC_SIZE + 1)
++#elif SU_SAVE_HELEM_SIZE > SU_SAVE_HDELETE_SIZE
++# define SU_SAVE_HELEM_OR_HDELETE_SIZE \
++    (SU_SAVE_HELEM_SIZE + SU_SAVE_ALLOC_SIZE + 1)
+ #else
+ # define SU_SAVE_HELEM_OR_HDELETE_SIZE SU_SAVE_HELEM_SIZE
+ #endif
+ 
+-#define SU_SAVE_GVCV_SIZE SU_SAVE_DESTRUCTOR_SIZE
+-
+-#if !SU_HAS_PERL(5, 8, 9)
+-# define SU_SAVE_GP_SIZE 6
+-#elif !SU_HAS_PERL(5, 13, 0) || (SU_RELEASE && SU_HAS_PERL_EXACT(5, 13, 0))
+-# define SU_SAVE_GP_SIZE 3
+-#elif !SU_HAS_PERL(5, 13, 8)
+-# define SU_SAVE_GP_SIZE 4
+-#else
+-# define SU_SAVE_GP_SIZE 3
+-#endif
+ 
+ #ifndef SvCANEXISTDELETE
+ # define SvCANEXISTDELETE(sv) \
+@@ -572,7 +554,7 @@ static I32 su_av_key2idx(pTHX_ AV *av, I
+   return key;
+ 
+ /* Added by MJD in perl-5.8.1 with 6f12eb6d2a1dfaf441504d869b27d2e40ef4966a */
+-#if SU_HAS_PERL(5, 8, 1)
++#if XSH_HAS_PERL(5, 8, 1)
+  if (SvRMAGICAL(av)) {
+   const MAGIC * const tied_magic = mg_find((SV *) av, PERL_MAGIC_tied);
+   if (tied_magic) {
+@@ -693,7 +675,7 @@ static void su_save_helem(pTHX_ HV *hv, 
+ 
+ /* ... Saving code slots from a glob ....................................... */
+ 
+-#if !SU_HAS_PERL(5, 10, 0) && !defined(mro_method_changed_in)
++#if !XSH_HAS_PERL(5, 10, 0) && !defined(mro_method_changed_in)
+ # define mro_method_changed_in(G) PL_sub_generation++
+ #endif
+ 
+@@ -731,17 +713,21 @@ static void su_save_gvcv(pTHX_ GV *gv) {
+ /* --- Actions ------------------------------------------------------------- */
+ 
+ typedef struct {
++ I32  orig_ix; /* original savestack_ix */
++ I32  offset;  /* how much we bumped this savestack index */
++} su_ud_origin_elem;
++
++typedef struct {
+  U8   type;
+  U8   private;
+- U8   pad;
+  /* spare */
+  I32  depth;
+- I32 *origin;
++ su_ud_origin_elem *origin;
+ } su_ud_common;
+ 
++
+ #define SU_UD_TYPE(U)    (((su_ud_common *) (U))->type)
+ #define SU_UD_PRIVATE(U) (((su_ud_common *) (U))->private)
+-#define SU_UD_PAD(U)     (((su_ud_common *) (U))->pad)
+ #define SU_UD_DEPTH(U)   (((su_ud_common *) (U))->depth)
+ #define SU_UD_ORIGIN(U)  (((su_ud_common *) (U))->origin)
+ 
+@@ -756,7 +742,7 @@ typedef struct {
+ 
+ /* ... Reap ................................................................ */
+ 
+-#define SU_SAVE_LAST_CX (!SU_HAS_PERL(5, 8, 4) || (SU_HAS_PERL(5, 9, 5) && !SU_HAS_PERL(5, 14, 0)) || SU_HAS_PERL(5, 15, 0))
++#define SU_SAVE_LAST_CX (!XSH_HAS_PERL(5, 8, 4) || (XSH_HAS_PERL(5, 9, 5) && !XSH_HAS_PERL(5, 14, 0)) || XSH_HAS_PERL(5, 15, 0))
+ 
+ typedef struct {
+  su_ud_common ci;
+@@ -773,8 +759,8 @@ static void su_call(pTHX_ SV *cb) {
+ 
+  dSP;
+ 
+- SU_D(su_debug_log("@@@ call scope_ix=%2d save_ix=%2d\n",
+-                         PL_scopestack_ix, PL_savestack_ix));
++ XSH_D(su_debug_log("@@@ call scope_ix=%2d save_ix=%2d\n",
++                          PL_scopestack_ix, PL_savestack_ix));
+ 
+  ENTER;
+  SAVETMPS;
+@@ -919,6 +905,15 @@ static void su_localize(pTHX_ void *ud_)
+  if (SvTYPE(sv) >= SVt_PVGV) {
+   gv = (GV *) sv;
+  } else {
++
++/* new perl context implementation frees savestack *before* restoring
++ * PL_curcop. Temporarily restore it prematurely to make gv_fetch*
++ * looks up unqualified var names in the caller's package */
++#ifdef SU_HAS_NEW_CXT
++  COP *old_cop = PL_curcop;
++  PL_curcop = CX_CUR()->blk_oldcop;
++#endif
++
+ #ifdef gv_fetchsv
+   gv = gv_fetchsv(sv, GV_ADDMULTI, t);
+ #else
+@@ -926,13 +921,16 @@ static void su_localize(pTHX_ void *ud_)
+   const char *name = SvPV_const(sv, len);
+   gv = gv_fetchpvn_flags(name, len, GV_ADDMULTI, t);
+ #endif
++#ifdef SU_HAS_NEW_CXT
++  CX_CUR()->blk_oldcop = PL_curcop;
++#endif
+  }
+ 
+- SU_D({
++ XSH_D({
+   SV *z = newSV(0);
+   SvUPGRADE(z, t);
+-  su_debug_log("%p: === localize a %s\n",ud, sv_reftype(z, 0));
+-  su_debug_log("%p: depth=%2d scope_ix=%2d save_ix=%2d\n",
++  su_debug_log("%p:     === localize a %s\n",ud, sv_reftype(z, 0));
++  su_debug_log("%p:         depth=%2d scope_ix=%2d save_ix=%2d\n",
+                 ud, SU_UD_DEPTH(ud), PL_scopestack_ix, PL_savestack_ix);
+   SvREFCNT_dec(z);
+  });
+@@ -972,7 +970,7 @@ static void su_localize(pTHX_ void *ud_)
+ 
+ /* ... Unique context ID ................................................... */
+ 
+-/* We must pass the index because MY_CXT.uid_storage might be reallocated
++/* We must pass the index because XSH_CXT.uid_storage might be reallocated
+  * between the UID fetch and the invalidation at the end of scope. */
+ 
+ typedef struct {
+@@ -982,9 +980,9 @@ typedef struct {
+ 
+ static void su_uid_drop(pTHX_ void *ud_) {
+  su_ud_uid *ud = ud_;
+- dMY_CXT;
++ dXSH_CXT;
+ 
+- MY_CXT.uid_storage.map[ud->idx].flags &= ~SU_UID_ACTIVE;
++ XSH_CXT.uid_storage.map[ud->idx].flags &= ~SU_UID_ACTIVE;
+ 
+  SU_UD_FREE(ud);
+ 
+@@ -994,37 +992,50 @@ static void su_uid_drop(pTHX_ void *ud_)
+ /* --- Pop a context back -------------------------------------------------- */
+ 
+ #ifdef DEBUGGING
+-# define SU_CXNAME(C) PL_block_type[CxTYPE(C)]
++# define SU_CX_TYPENAME(T) PL_block_type[(T)]
+ #else
+-# if SU_HAS_PERL(5, 11, 0)
++# if XSH_HAS_PERL(5, 23, 8)
+ static const char *su_block_type[] = {
+  "NULL",
+  "WHEN",
+  "BLOCK",
+  "GIVEN",
+- "LOOP_FOR",
+- "LOOP_PLAIN",
++ "LOOP_ARY",
+  "LOOP_LAZYSV",
+  "LOOP_LAZYIV",
++ "LOOP_LIST",
++ "LOOP_PLAIN",
+  "SUB",
+  "FORMAT",
+  "EVAL",
+  "SUBST"
+ };
+-# elif SU_HAS_PERL(5, 9, 3)
++# elif XSH_HAS_PERL(5, 11, 0)
+ static const char *su_block_type[] = {
+  "NULL",
+- "SUB",
+- "EVAL",
+  "WHEN",
+- "SUBST",
+  "BLOCK",
+- "FORMAT",
+  "GIVEN",
+  "LOOP_FOR",
+  "LOOP_PLAIN",
+  "LOOP_LAZYSV",
+- "LOOP_LAZYIV"
++ "LOOP_LAZYIV",
++ "SUB",
++ "FORMAT",
++ "EVAL",
++ "SUBST"
++};
++# elif XSH_HAS_PERL(5, 10, 0)
++static const char *su_block_type[] = {
++ "NULL",
++ "SUB",
++ "EVAL",
++ "LOOP",
++ "SUBST",
++ "BLOCK",
++ "FORMAT"
++ "WHEN",
++ "GIVEN"
+ };
+ # else
+ static const char *su_block_type[] = {
+@@ -1033,78 +1044,107 @@ static const char *su_block_type[] = {
+  "EVAL",
+  "LOOP",
+  "SUBST",
+- "BLOCK"
++ "BLOCK",
++ "FORMAT"
+ };
+ # endif
+-# define SU_CXNAME(C) su_block_type[CxTYPE(C)]
++# define SU_CX_TYPENAME(T) su_block_type[(T)]
+ #endif
+ 
++#define SU_CXNAME(C) SU_CX_TYPENAME(CxTYPE(C))
++
++/* for debugging. These indicate how many ENTERs each context type
++ * does before the PUSHBLOCK */
++
++static const int su_cxt_enter_count[] = {
++# if XSH_HAS_PERL(5, 23, 8)
++  0 /* context pushes no longer do ENTERs */
++# elif XSH_HAS_PERL(5, 11, 0)
++ /* NULL WHEN BLOCK GIVEN LOOP_FOR LOOP_PLAIN LOOP_LAZYSV
++  * LOOP_LAZYIV SUB FORMAT EVAL SUBST */
++ 0, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 0
++# elif XSH_HAS_PERL(5, 10, 0)
++ /* NULL SUB EVAL LOOP SUBST BLOCK FORMAT WHEN GIVEN */
++ 0, 1, 1, 2, 0, 1, 1, 1, 1
++# else
++ /* NULL SUB EVAL LOOP SUBST BLOCK FORMAT */
++ 0, 1, 1, 2, 0, 1, 1
++# endif
++};
++
++
++
++/* push at least 'size' slots worth of padding onto the savestack */
++
++static void su_ss_push_padding(pTHX_ void *ud, I32 size) {
++ if (size <= 0)
++  return;
++ if (size < SU_SAVE_ALLOC_SIZE + 1) /* minimum possible SAVEt_ALLOC */
++  size = SU_SAVE_ALLOC_SIZE + 1;
++ XSH_D(su_debug_log(
++        "%p:     push %2d padding at save_ix=%d\n",
++         ud, size, PL_savestack_ix));
++ save_alloc((size - SU_SAVE_ALLOC_SIZE)*sizeof(*PL_savestack), 0);
++}
++
++
++static void su_pop(pTHX_ void *ud);
++
++
++
++/* push an su_pop destructor onto the savestack with suitable padding.
++ * first indicates that this is the first push of a destructor */
++
++static void su_ss_push_destructor(pTHX_ void *ud, I32 depth, bool first) {
++ su_ud_origin_elem *origin = SU_UD_ORIGIN(ud);
++ I32 pad;
++
++ assert(first || origin[depth+1].orig_ix == PL_savestack_ix);
++ su_ss_push_padding(aTHX_ ud,
++    (origin[depth].orig_ix + origin[depth].offset) - PL_savestack_ix);
++ XSH_D(su_debug_log(
++        "%p:     push destructor at save_ix=%d depth=%d scope_ix=%d\n",
++         ud, PL_savestack_ix, depth, PL_scopestack_ix));
++ SAVEDESTRUCTOR_X(su_pop, ud);
++ assert(first ||
++        PL_savestack_ix <= origin[depth+1].orig_ix +  origin[depth+1].offset);
++}
++
++
++/* this is called during each leave_scope() via SAVEDESTRUCTOR_X */
++
+ static void su_pop(pTHX_ void *ud) {
+ #define su_pop(U) su_pop(aTHX_ (U))
+- I32 depth, base, mark, *origin;
+- depth = SU_UD_DEPTH(ud);
+-
+- SU_D(su_debug_log(
+-  "%p: --- pop a %s\n"
+-  "%p: leave scope     at depth=%2d scope_ix=%2d cur_top=%2d cur_base=%2d\n",
+-   ud, SU_CXNAME(cxstack + cxstack_ix),
+-   ud, depth, PL_scopestack_ix,PL_savestack_ix,PL_scopestack[PL_scopestack_ix]
+- ));
++ I32 depth, base, mark;
++ su_ud_origin_elem *origin;
+ 
++ depth  = SU_UD_DEPTH(ud);
+  origin = SU_UD_ORIGIN(ud);
+- mark   = origin[depth];
+- base   = origin[depth - 1];
+ 
+- SU_D(su_debug_log("%p: original scope was %*c top=%2d     base=%2d\n",
+-                    ud,                24, ' ',    mark,        base));
+-
+- if (base < mark) {
+-#if SU_HAS_PERL(5, 19, 4)
+-  I32 save = -1;
+-  PERL_CONTEXT *cx;
+-#endif
++ XSH_D(su_debug_log( "%p: ### su_pop: depth=%d\n", ud, depth));
+ 
+-  SU_D(su_debug_log("%p: clear leftovers\n", ud));
++ depth--;
++ mark = PL_savestack_ix;
++ base = origin[depth].orig_ix;
+ 
+-#if SU_HAS_PERL(5, 19, 4)
+-  cx = cxstack + cxstack_ix;
+-  if (CxTYPE(cx) == CXt_SUB || CxTYPE(cx) == CXt_FORMAT)
+-   save = PL_scopestack[cx->blk_oldscopesp - 1];
+-#endif
++ XSH_D(su_debug_log("%p:     residual savestack frame is %d(+%d)..%d\n",
++                     ud, base, origin[depth].offset, mark));
+ 
+-  PL_savestack_ix = mark;
++ if (base < mark) {
++  XSH_D(su_debug_log("%p:     clear leftovers at %d..%d\n", ud, base, mark));
+   leave_scope(base);
+-
+-#if SU_HAS_PERL(5, 19, 4)
+-  if (CxTYPE(cx) == CXt_SUB || CxTYPE(cx) == CXt_FORMAT)
+-   PL_scopestack[cx->blk_oldscopesp - 1] = save;
+-#endif
+  }
+- PL_savestack_ix = base;
++ assert(PL_savestack_ix == base);
+ 
+- SU_UD_DEPTH(ud) = --depth;
++ SU_UD_DEPTH(ud) = depth;
+ 
+  if (depth > 0) {
+-  U8 pad;
+-
+-  if ((pad = SU_UD_PAD(ud)) > 0) {
+-   dMY_CXT;
+-   do {
+-    SU_D(su_debug_log(
+-          "%p: push a pad slot at depth=%2d scope_ix=%2d save_ix=%2d\n",
+-           ud,                       depth, PL_scopestack_ix, PL_savestack_ix));
+-    SU_SAVE_PLACEHOLDER();
+-   } while (--pad);
+-  }
+-
+-  SU_D(su_debug_log(
+-         "%p: push destructor at depth=%2d scope_ix=%2d save_ix=%2d\n",
+-          ud,                        depth, PL_scopestack_ix, PL_savestack_ix));
+-  SAVEDESTRUCTOR_X(su_pop, ud);
++  su_ss_push_destructor(aTHX_ ud, depth-1, 0);
+  } else {
++  I32 offset = origin[0].offset; /* grab value before origin is freed */
+   switch (SU_UD_TYPE(ud)) {
+    case SU_UD_TYPE_REAP: {
+-    SU_D(su_debug_log("%p: === reap\n%p: depth=%2d scope_ix=%2d save_ix=%2d\n",
++    XSH_D(su_debug_log("%p:     === reap\n%p: depth=%d scope_ix=%d save_ix=%d\n",
+                    ud, ud, SU_UD_DEPTH(ud), PL_scopestack_ix, PL_savestack_ix));
+     SAVEDESTRUCTOR_X(su_call, SU_UD_REAP_CB(ud));
+     SU_UD_FREE(ud);
+@@ -1118,112 +1158,193 @@ static void su_pop(pTHX_ void *ud) {
+     SAVEDESTRUCTOR_X(su_uid_drop, ud);
+     break;
+   }
++  /* perl 5.23.8 onwards is very fussy about the return from leave_scope()
++   * leaving PL_savestack_ix where it expects it to be */
++  if (PL_savestack_ix < base + offset) {
++   I32 gap = (base + offset) - PL_savestack_ix;
++   assert(gap >= SU_SAVE_ALLOC_SIZE + 1);
++   su_ss_push_padding(aTHX_ ud, gap);
++  }
++  assert(PL_savestack_ix == base + offset);
+  }
+ 
+- SU_D(su_debug_log("%p: --- end pop: cur_top=%2d == cur_base=%2d\n",
+-                    ud, PL_savestack_ix, PL_scopestack[PL_scopestack_ix]));
++ XSH_D(su_debug_log("%p:     end pop: ss_ix=%d\n", ud, PL_savestack_ix));
+ }
+ 
++
+ /* --- Initialize the stack and the action userdata ------------------------ */
+ 
+-static I32 su_init(pTHX_ void *ud, I32 cxix, I32 size) {
++static void su_init(pTHX_ void *ud, I32 cxix, I32 size) {
+ #define su_init(U, C, S) su_init(aTHX_ (U), (C), (S))
+- I32 i, depth, offset, base, *origin;
+- U8 pad;
++ I32 i, depth, base;
++ su_ud_origin_elem *origin;
++ I32 cur_cx_ix;
++ I32 cur_scope_ix;
+ 
+- SU_D(su_debug_log("%p: ### init for cx %d\n", ud, cxix));
++ XSH_D(su_debug_log("%p: ### su_init(cxix=%d, size=%d)\n", ud, cxix, size));
+ 
+- /* su_pop() is going to be called from leave_scope(), so before pushing the
+-  * next callback, we'll want to flush the current scope stack slice first.
+-  * However, if we want the next callback not to be processed immediately by
+-  * the current leave_scope(), we'll need to hide it by artificially
+-  * incrementing the scope stack marker before. For the intermediate bumps,
+-  * we will only need a bump of SU_SAVE_DESTRUCTOR_SIZE items, but for the
+-  * last one we will need a bump of size items. However, in order to preserve
+-  * the natural ordering between scope stack markers, we cannot bump lower
+-  * markers more than higher ones. This is why we bump the intermediate markers
+-  * by the smallest multiple of SU_SAVE_PLACEHOLDER_SIZE greater or equal to
+-  * max(SU_SAVE_DESTRUCTOR_SIZE, size). */
++ depth = PL_scopestack_ix - cxstack[cxix].blk_oldscopesp;
++#ifdef SU_HAS_NEW_CXT
++ depth += (cxstack_ix - cxix); /* each context frame holds 1 scope */
++#endif
++ XSH_D(su_debug_log(
++   "%p:     going down by depth=%d with scope_ix=%d save_ix=%d\n",
++    ud, depth, PL_scopestack_ix, PL_savestack_ix));
+ 
+- if (size <= SU_SAVE_DESTRUCTOR_SIZE) {
+-  pad = 0;
+- } else {
+-  I32 extra = size - SU_SAVE_DESTRUCTOR_SIZE;
+-  pad = extra / SU_SAVE_PLACEHOLDER_SIZE;
+-  if (extra % SU_SAVE_PLACEHOLDER_SIZE)
+-   ++pad;
+- }
+- offset = SU_SAVE_DESTRUCTOR_SIZE + SU_SAVE_PLACEHOLDER_SIZE * pad;
+- SU_D(su_debug_log("%p: size=%d pad=%d offset=%d\n", ud, size, pad, offset));
++ /* Artificially increase the position of each savestack frame boundary
++  * to make space to squeeze in a 'size' sized entry (first one) or a
++  * SU_SAVE_DESTRUCTOR_SIZE sized entry (higher ones). In addition, make
++  * sure that each boundary is higher than the previous, so that *every*
++  * scope exit triggers a call to leave_scope(). Each scope exit will call
++  * the su_pop() destructor, which is responsible for: freeing any
++  * savestack entries below the artificially raised floor; then pushing a
++  * new destructor in that space. On the final pop, the "real" savestack
++  * action is pushed rather than another destructor.
++  *
++  * On older perls, savestack frame boundaries are specified by a range of
++  * scopestack entries (one per ENTER). Each scope entry typically does
++  * one or two ENTERs followed by a PUSHBLOCK. Thus the
++  * cx->blku_oldscopesp field set by the PUSHBLOCK points to the next free
++  * slot, which is one above the last of the ENTERs. In the debugging
++  * output we indicate that by bracketing the ENTERs directly preceding
++  * that context push with dashes, e.g.:
++  *
++  *   13b98d8:     ------------------
++  *   13b98d8:                 ENTER origin[0] scope[3] savestack=3+3
++  *   13b98d8:                 ENTER origin[1] scope[4] savestack=9+3
++  *   13b98d8:     cx=1  LOOP_LAZYIV
++  *   13b98d8:     ------------------
++  *
++  * In addition to context stack pushes, other activities can push ENTERs
++  * too, such as grep expr and XS sub calls.
++  *
++  * For newer perls (SU_HAS_NEW_CXT), a context push no longer does any
++  * ENTERs; instead the old savestack position is stored in the new
++  * cx->blk_oldsaveix field; thus this field specifies an additional
++  * savestack frame boundary point in addition to the scopestack entries,
++  * and will also need adjusting.
++  *
++  * We record the original and modified position of each boundary in the
++  * origin array.
++  *
++  * The passed cxix argument represents the scope we wish to inject into;
++  * we have to adjust all the savestack frame boundaries above (but not
++  * including) that context. 
++  */
+ 
+- depth = PL_scopestack_ix - cxstack[cxix].blk_oldscopesp;
+- SU_D(su_debug_log("%p: going down to depth %d\n", ud, depth));
++ Newx(origin, depth, su_ud_origin_elem);
+ 
+- /* We need to bump all the intermediary stack markers just in case an
+-  * exception is thrown before the target scope is reached. Indeed, in this
+-  * case there might be arbitrary many scope frames flushed at the same time,
+-  * and since we cannot know in advance whether this will happen or not, we
+-  * have to make sure the final frame is protected for the actual action. But
+-  * of course, in order to do that, we also need to bump all the previous stack
+-  * markers. If not for this, it should have been possible to just bump the two
+-  * next frames in su_pop(). */
++ cur_cx_ix  = cxix;
++ cur_scope_ix = cxstack[cxix].blk_oldscopesp;
++#ifdef SU_HAS_NEW_CXT
++ XSH_D(su_debug_log("%p:     cx=%-2d %-11s\n",
++      ud, cur_cx_ix, SU_CXNAME(cxstack+cur_cx_ix)));
++ cur_cx_ix++;
++#endif
+ 
+- Newx(origin, depth + 1, I32);
+- base = PL_scopestack_ix - depth;
+- origin[0] = PL_scopestack[base];
+- PL_scopestack[base] += size;
+- for (i = 1; i < depth; ++i) {
+-  I32 j = i + base;
+-  /* origin[depth - i] == PL_scopestack[PL_scopestack_ix - i] */
+-  origin[i] = PL_scopestack[j];
+-  PL_scopestack[j] += offset;
+- }
+- origin[depth] = PL_savestack_ix;
++ for (i = 0; cur_scope_ix < PL_scopestack_ix; i++) {
++  I32 *ixp;
++  I32 offset;
+ 
+- SU_UD_PAD(ud)    = pad;
+- SU_UD_DEPTH(ud)  = depth;
+- SU_UD_ORIGIN(ud) = origin;
++#ifdef SU_HAS_NEW_CXT
+ 
+- /* Make sure the first destructor fires by pushing enough fake slots on the
+-  * stack. */
+- if (PL_savestack_ix + SU_SAVE_DESTRUCTOR_SIZE
+-                                       <= PL_scopestack[PL_scopestack_ix - 1]) {
+-  dMY_CXT;
+-  do {
+-   SU_D(su_debug_log("%p: push a fake slot      at scope_ix=%2d  save_ix=%2d\n",
+-                      ud,                   PL_scopestack_ix, PL_savestack_ix));
+-   SU_SAVE_PLACEHOLDER();
+-  } while (PL_savestack_ix + SU_SAVE_DESTRUCTOR_SIZE
+-                                        <= PL_scopestack[PL_scopestack_ix - 1]);
+- }
+- SU_D(su_debug_log("%p: push first destructor at scope_ix=%2d  save_ix=%2d\n",
+-                    ud,                     PL_scopestack_ix, PL_savestack_ix));
+- SAVEDESTRUCTOR_X(su_pop, ud);
++  if (   cur_cx_ix <= cxstack_ix
++      && cur_scope_ix == cxstack[cur_cx_ix].blk_oldscopesp
++  )
++   ixp = &(cxstack[cur_cx_ix++].blk_oldsaveix);
++  else
++   ixp = &PL_scopestack[cur_scope_ix++]; /* an ENTER pushed after cur context */
+ 
+- SU_D({
+-  for (i = 0; i <= depth; ++i) {
+-   I32 j = PL_scopestack_ix  - i;
+-   su_debug_log("%p: depth=%2d scope_ix=%2d saved_floor=%2d new_floor=%2d\n",
+-                 ud,         i,           j, origin[depth - i],
+-                                   i == 0 ? PL_savestack_ix : PL_scopestack[j]);
++#else
++
++  XSH_D({
++   if (cur_cx_ix <= cxstack_ix) {
++    if (cur_scope_ix == cxstack[cur_cx_ix].blk_oldscopesp) {
++     su_debug_log(
++       "%p:     cx=%-2d %s\n%p:     ------------------\n",
++       ud, cur_cx_ix, SU_CXNAME(cxstack+cur_cx_ix), ud);
++     cur_cx_ix++;
++    }
++    else if (cur_scope_ix + su_cxt_enter_count[CxTYPE(cxstack+cur_cx_ix)]
++             == cxstack[cur_cx_ix].blk_oldscopesp)
++     su_debug_log("%p:     ------------------\n", ud);
++   }
++  });
++  ixp = &PL_scopestack[cur_scope_ix++];
++
++#endif
++
++  if (i == 0)
++   offset = size;
++  else {
++   /* we have three constraints to satisfy:
++    * 1) Each adjusted offset must be at least SU_SAVE_DESTRUCTOR_SIZE
++    *    above its unadjusted boundary, so that there is space to inject a
++    *    destructor into the outer scope.
++    * 2) Each adjusted boundary must be at least SU_SAVE_DESTRUCTOR_SIZE
++    *    higher than the previous adjusted boundary, so that a new
++    *    destructor can be added below the Nth adjusted frame boundary,
++    *    but be within the (N-1)th adjusted frame and so be triggered on
++    *    the next scope exit;
++    * 3) If the adjustment needs to be greater than SU_SAVE_DESTRUCTOR_SIZE,
++    *    then it should be greater by an amount of at least the minimum
++    *    pad side, so a destructor and padding can be pushed.
++    */
++   I32 pad;
++   offset = SU_SAVE_DESTRUCTOR_SIZE; /* rule 1 */
++   pad = (origin[i-1].orig_ix + origin[i-1].offset) + offset - (*ixp + offset);
++   if (pad > 0) { /* rule 2 */
++    if (pad < SU_SAVE_ALLOC_SIZE + 1) /* rule 3 */
++     pad = SU_SAVE_ALLOC_SIZE + 1;
++    offset += pad;
++   }
+   }
+- });
+ 
+- return depth;
++  origin[i].offset = offset;
++  origin[i].orig_ix = *ixp;
++  *ixp += offset;
++
++#ifdef SU_HAS_NEW_CXT
++  XSH_D({
++   if (ixp == &PL_scopestack[cur_scope_ix-1])
++    su_debug_log(
++     "%p:           ENTER       origin[%d] scope[%d] savestack=%d+%d\n",
++      ud, i, cur_scope_ix, origin[i].orig_ix, origin[i].offset);
++   else
++    su_debug_log(
++     "%p:     cx=%-2d %-11s origin[%d] scope[%d] savestack=%d+%d\n",
++      ud, cur_cx_ix-1, SU_CXNAME(cxstack+cur_cx_ix-1),
++      i, cur_scope_ix, origin[i].orig_ix, origin[i].offset);
++  });
++#else
++  XSH_D(su_debug_log(
++    "%p:                 ENTER origin[%d] scope[%d] savestack=%d+%d\n",
++     ud, i, cur_scope_ix, origin[i].orig_ix, origin[i].offset));
++#endif
++
++ }
++
++ assert(i == depth);
++
++ SU_UD_DEPTH(ud)  = depth;
++ SU_UD_ORIGIN(ud) = origin;
++
++ su_ss_push_destructor(aTHX_ ud, depth-1, 1);
+ }
+ 
++
+ /* --- Unwind stack -------------------------------------------------------- */
+ 
+ static void su_unwind(pTHX_ void *ud_) {
+- dMY_CXT;
+- I32 cxix  = MY_CXT.unwind_storage.cxix;
+- I32 items = MY_CXT.unwind_storage.items;
++ dXSH_CXT;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201606042058.u54Kwo8W038682>