# define MY_CXT_CLONE NOOP
#endif
+/* --- Error messages ------------------------------------------------------ */
+
+static const char su_stack_smash[] = "Cannot target a scope outside of the current stack";
+static const char su_no_such_target[] = "No targetable %s scope in the current stack";
+
/* --- Unique context ID global storage ------------------------------------ */
/* ... Sequence ID counter ................................................. */
/* --- Actions ------------------------------------------------------------- */
typedef struct {
- I32 depth;
- I32 pad;
+ U8 type;
+ U8 private;
+ U8 pad;
+ /* spare */
+ I32 depth;
I32 *origin;
- void (*handler)(pTHX_ void *);
} su_ud_common;
-#define SU_UD_DEPTH(U) (((su_ud_common *) (U))->depth)
+#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)
-#define SU_UD_HANDLER(U) (((su_ud_common *) (U))->handler)
+
+#define SU_UD_TYPE_REAP 0
+#define SU_UD_TYPE_LOCALIZE 1
+#define SU_UD_TYPE_UID 2
#define SU_UD_FREE(U) STMT_START { \
if (SU_UD_ORIGIN(U)) Safefree(SU_UD_ORIGIN(U)); \
typedef struct {
su_ud_common ci;
- SV *cb;
+ SV *cb;
} su_ud_reap;
-static void su_call(pTHX_ void *ud_) {
- su_ud_reap *ud = (su_ud_reap *) ud_;
+#define SU_UD_REAP_CB(U) (((su_ud_reap *) (U))->cb)
+
+static void su_call(pTHX_ SV *cb) {
#if SU_SAVE_LAST_CX
I32 cxix;
PERL_CONTEXT saved_cx;
SU_D({
PerlIO_printf(Perl_debug_log,
- "%p: @@@ call\n%p: depth=%2d scope_ix=%2d save_ix=%2d\n",
- ud, ud, SU_UD_DEPTH(ud), PL_scopestack_ix, PL_savestack_ix);
+ "@@@ call scope_ix=%2d save_ix=%2d\n",
+ PL_scopestack_ix, PL_savestack_ix);
});
ENTER;
saved_cx = cxstack[cxix];
#endif /* SU_SAVE_LAST_CX */
- call_sv(ud->cb, G_VOID);
+ call_sv(cb, G_VOID);
#if SU_SAVE_LAST_CX
cxstack[cxix] = saved_cx;
FREETMPS;
LEAVE;
- SvREFCNT_dec(ud->cb);
- SU_UD_FREE(ud);
-}
+ SvREFCNT_dec(cb);
-static void su_reap(pTHX_ void *ud) {
-#define su_reap(U) su_reap(aTHX_ (U))
- SU_D({
- PerlIO_printf(Perl_debug_log,
- "%p: === reap\n%p: depth=%2d scope_ix=%2d save_ix=%2d\n",
- ud, ud, SU_UD_DEPTH(ud), PL_scopestack_ix, PL_savestack_ix);
- });
-
- SAVEDESTRUCTOR_X(su_call, ud);
+ return;
}
/* ... Localize & localize array/hash element .............................. */
typedef struct {
su_ud_common ci;
- SV *sv;
- SV *val;
- SV *elem;
- svtype type;
+ SV *sv;
+ SV *val;
+ SV *elem;
} su_ud_localize;
+#define SU_UD_LOCALIZE_SV(U) (((su_ud_localize *) (U))->sv)
+#define SU_UD_LOCALIZE_VAL(U) (((su_ud_localize *) (U))->val)
+#define SU_UD_LOCALIZE_ELEM(U) (((su_ud_localize *) (U))->elem)
+
#define SU_UD_LOCALIZE_FREE(U) STMT_START { \
- SvREFCNT_dec((U)->elem); \
- SvREFCNT_dec((U)->val); \
- SvREFCNT_dec((U)->sv); \
- SU_UD_FREE(U); \
+ SvREFCNT_dec(SU_UD_LOCALIZE_ELEM(U)); \
+ SvREFCNT_dec(SU_UD_LOCALIZE_VAL(U)); \
+ SvREFCNT_dec(SU_UD_LOCALIZE_SV(U)); \
+ SU_UD_FREE(U); \
} STMT_END
static I32 su_ud_localize_init(pTHX_ su_ud_localize *ud, SV *sv, SV *val, SV *elem) {
}
/* When deref is set, val isn't NULL */
+ SU_UD_PRIVATE(ud) = t;
+
ud->sv = sv;
ud->val = val ? newSVsv(deref ? SvRV(val) : val) : NULL;
ud->elem = SvREFCNT_inc(elem);
- ud->type = t;
return size;
}
SV *sv = ud->sv;
SV *val = ud->val;
SV *elem = ud->elem;
- svtype t = ud->type;
+ svtype t = SU_UD_PRIVATE(ud);
GV *gv;
if (SvTYPE(sv) >= SVt_PVGV) {
case SVt_PVAV:
if (elem) {
su_save_aelem(GvAV(gv), elem, val);
- goto done;
+ return;
} else
save_ary(gv);
break;
case SVt_PVHV:
if (elem) {
su_save_helem(GvHV(gv), elem, val);
- goto done;
+ return;
} else
save_hash(gv);
break;
if (val)
SvSetMagicSV((SV *) gv, val);
-done:
- SU_UD_LOCALIZE_FREE(ud);
+ return;
+}
+
+/* ... Unique context ID ................................................... */
+
+typedef struct {
+ su_ud_common ci;
+ su_uid *uid;
+} su_ud_uid;
+
+#define SU_UD_UID_UID(U) (((su_ud_uid *) (U))->uid)
+
+static void su_uid_drop(pTHX_ void *ud_) {
+ su_uid *uid = ud_;
+
+ uid->flags &= ~SU_UID_ACTIVE;
+
+ return;
}
/* --- Pop a context back -------------------------------------------------- */
SU_UD_DEPTH(ud) = --depth;
if (depth > 0) {
- I32 pad;
+ U8 pad;
- if ((pad = SU_UD_PAD(ud))) {
+ if ((pad = SU_UD_PAD(ud)) > 0) {
dMY_CXT;
do {
SU_D(PerlIO_printf(Perl_debug_log,
ud, depth, PL_scopestack_ix, PL_savestack_ix));
SAVEDESTRUCTOR_X(su_pop, ud);
} else {
- SU_UD_HANDLER(ud)(aTHX_ ud);
+ switch (SU_UD_TYPE(ud)) {
+ case SU_UD_TYPE_REAP: {
+ SU_D({
+ PerlIO_printf(Perl_debug_log,
+ "%p: === reap\n%p: depth=%2d scope_ix=%2d save_ix=%2d\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);
+ break;
+ }
+ case SU_UD_TYPE_LOCALIZE:
+ su_localize(ud);
+ SU_UD_LOCALIZE_FREE(ud);
+ break;
+ case SU_UD_TYPE_UID:
+ SAVEDESTRUCTOR_X(su_uid_drop, SU_UD_UID_UID(ud));
+ SU_UD_FREE(ud);
+ break;
+ }
}
SU_D(PerlIO_printf(Perl_debug_log,
static I32 su_init(pTHX_ void *ud, I32 cxix, I32 size) {
#define su_init(U, C, S) su_init(aTHX_ (U), (C), (S))
- I32 i, depth, pad, offset, base, *origin;
+ I32 i, depth, offset, base, *origin;
+ U8 pad;
SU_D(PerlIO_printf(Perl_debug_log, "%p: ### init for cx %d\n", ud, cxix));
}
origin[depth] = PL_savestack_ix;
- SU_UD_ORIGIN(ud) = origin;
- SU_UD_DEPTH(ud) = depth;
SU_UD_PAD(ud) = pad;
+ SU_UD_DEPTH(ud) = depth;
+ SU_UD_ORIGIN(ud) = origin;
/* Make sure the first destructor fires by pushing enough fake slots on the
* stack. */
return uid && (uid->seq == seq) && (uid->flags & SU_UID_ACTIVE);
}
-static void su_uid_drop(pTHX_ void *ud_) {
- su_uid *uid = ud_;
-
- uid->flags &= ~SU_UID_ACTIVE;
-}
-
-static void su_uid_bump(pTHX_ void *ud_) {
- su_ud_reap *ud = ud_;
-
- SAVEDESTRUCTOR_X(su_uid_drop, ud->cb);
-
- SU_UD_FREE(ud);
-}
-
static SV *su_uid_get(pTHX_ I32 cxix) {
#define su_uid_get(I) su_uid_get(aTHX_ (I))
su_uid *uid;
uid = su_uid_storage_fetch(depth);
if (!(uid->flags & SU_UID_ACTIVE)) {
- su_ud_reap *ud;
+ su_ud_uid *ud;
- uid->seq = su_uid_seq_next(depth);
+ uid->seq = su_uid_seq_next(depth);
uid->flags |= SU_UID_ACTIVE;
- Newx(ud, 1, su_ud_reap);
- SU_UD_ORIGIN(ud) = NULL;
- SU_UD_HANDLER(ud) = su_uid_bump;
- ud->cb = (SV *) uid;
+ Newx(ud, 1, su_ud_uid);
+ SU_UD_TYPE(ud) = SU_UD_TYPE_UID;
+ ud->uid = uid;
su_init(ud, cxix, SU_SAVE_DESTRUCTOR_SIZE);
}
--cxix;
cxix = su_context_skip_db(cxix);
cxix = su_context_normalize_up(cxix);
+ } else {
+ warn(su_stack_smash);
}
EXTEND(SP, 1);
mPUSHi(cxix);
XSRETURN(1);
}
}
+ warn(su_no_such_target, "subroutine");
XSRETURN_UNDEF;
void
XSRETURN(1);
}
}
+ warn(su_no_such_target, "eval");
XSRETURN_UNDEF;
void
SU_GET_LEVEL(0, 0);
cxix = su_context_here();
while (--level >= 0) {
- if (cxix <= 0)
+ if (cxix <= 0) {
+ warn(su_stack_smash);
break;
+ }
--cxix;
cxix = su_context_skip_db(cxix);
cxix = su_context_normalize_up(cxix);
}
}
done:
+ if (level >= 0)
+ warn(su_stack_smash);
EXTEND(SP, 1);
mPUSHi(cxix);
XSRETURN(1);
SU_GET_CONTEXT(1, 1, su_context_skip_db(cxstack_ix));
cxix = su_context_normalize_down(cxix);
Newx(ud, 1, su_ud_reap);
- SU_UD_ORIGIN(ud) = NULL;
- SU_UD_HANDLER(ud) = su_reap;
- ud->cb = newSVsv(hook);
+ SU_UD_TYPE(ud) = SU_UD_TYPE_REAP;
+ ud->cb = (SvROK(hook) && SvTYPE(SvRV(hook)) >= SVt_PVCV)
+ ? SvRV(hook) : hook;
+ SvREFCNT_inc_simple_void(ud->cb);
su_init(ud, cxix, SU_SAVE_DESTRUCTOR_SIZE);
void
SU_GET_CONTEXT(2, 2, su_context_skip_db(cxstack_ix));
cxix = su_context_normalize_down(cxix);
Newx(ud, 1, su_ud_localize);
- SU_UD_ORIGIN(ud) = NULL;
- SU_UD_HANDLER(ud) = su_localize;
+ SU_UD_TYPE(ud) = SU_UD_TYPE_LOCALIZE;
size = su_ud_localize_init(ud, sv, val, NULL);
su_init(ud, cxix, size);
SU_GET_CONTEXT(3, 3, su_context_skip_db(cxstack_ix));
cxix = su_context_normalize_down(cxix);
Newx(ud, 1, su_ud_localize);
- SU_UD_ORIGIN(ud) = NULL;
- SU_UD_HANDLER(ud) = su_localize;
+ /* Initialize SU_UD_ORIGIN(ud) in case SU_UD_LOCALIZE_FREE(ud) needs it */
+ SU_UD_ORIGIN(ud) = NULL;
+ SU_UD_TYPE(ud) = SU_UD_TYPE_LOCALIZE;
size = su_ud_localize_init(ud, sv, val, elem);
- if (ud->type != SVt_PVAV && ud->type != SVt_PVHV) {
+ if (SU_UD_PRIVATE(ud) != SVt_PVAV && SU_UD_PRIVATE(ud) != SVt_PVHV) {
SU_UD_LOCALIZE_FREE(ud);
croak("Can't localize an element of something that isn't an array or a hash");
}
SU_GET_CONTEXT(2, 2, su_context_skip_db(cxstack_ix));
cxix = su_context_normalize_down(cxix);
Newx(ud, 1, su_ud_localize);
- SU_UD_ORIGIN(ud) = NULL;
- SU_UD_HANDLER(ud) = su_localize;
+ SU_UD_TYPE(ud) = SU_UD_TYPE_LOCALIZE;
size = su_ud_localize_init(ud, sv, NULL, elem);
su_init(ud, cxix, size);