]> git.vpit.fr Git - perl/modules/Variable-Magic.git/blobdiff - Magic.xs
Port the svt_free-specific part of vmg_call_sv() to a customizable hook
[perl/modules/Variable-Magic.git] / Magic.xs
index ccb4685953e2f119e6a1c32566c42d19762f3863..8799958baade4e9af507b0bcd10c0ab7d6439431 100644 (file)
--- a/Magic.xs
+++ b/Magic.xs
@@ -222,14 +222,10 @@ STATIC void vmg_mg_magical(SV *sv) {
 
 /* ... Safe version of call_sv() ........................................... */
 
-#define VMG_SAVE_LAST_CX (!VMG_HAS_PERL(5, 8, 4) || VMG_HAS_PERL(5, 9, 5))
-
-STATIC I32 vmg_call_sv(pTHX_ SV *sv, I32 flags, SV *dsv) {
-#define vmg_call_sv(S, F, D) vmg_call_sv(aTHX_ (S), (F), (D))
- I32 ret, cxix = 0, in_eval = 0;
-#if VMG_SAVE_LAST_CX
+STATIC I32 vmg_call_sv(pTHX_ SV *sv, I32 flags, int (*cleanup)(pTHX_ void *), void *ud) {
+#define vmg_call_sv(S, F, C, U) vmg_call_sv(aTHX_ (S), (F), (C), (U))
+ I32 ret, cxix, in_eval = 0;
  PERL_CONTEXT saved_cx;
-#endif
  SV *old_err = NULL;
 
  if (SvTRUE(ERRSV)) {
@@ -238,22 +234,18 @@ STATIC I32 vmg_call_sv(pTHX_ SV *sv, I32 flags, SV *dsv) {
  }
 
  if (cxstack_ix < cxstack_max) {
-  cxix = cxstack_ix + 1;
-  if (dsv && CxTYPE(cxstack + cxix) == CXt_EVAL)
-   in_eval = 1;
+  cxix    = cxstack_ix + 1;
+  in_eval = CxTYPE(cxstack + cxix) == CXt_EVAL;
+ } else {
+  cxix    = Perl_cxinc(aTHX);
  }
-
-#if VMG_SAVE_LAST_CX
  /* The last popped context will be reused by call_sv(), but our callers may
   * still need its previous value. Back it up so that it isn't clobbered. */
  saved_cx = cxstack[cxix];
-#endif
 
  ret = call_sv(sv, flags | G_EVAL);
 
-#if VMG_SAVE_LAST_CX
  cxstack[cxix] = saved_cx;
-#endif
 
  if (SvTRUE(ERRSV)) {
   if (old_err) {
@@ -278,21 +270,8 @@ STATIC I32 vmg_call_sv(pTHX_ SV *sv, I32 flags, SV *dsv) {
    ++PL_Ierror_count;
 #endif
    } else if (!in_eval) {
-    if (dsv) {
-     /* We are about to croak() while dsv is being destroyed. Try to clean up
-      * things a bit. */
-     MAGIC *mg = SvMAGIC(dsv);
-     SvREFCNT_dec((SV *) mg->mg_ptr);
-     /* mg->mg_obj may not be refcounted if the data constructor returned the
-      * variable itself. */
-     if (mg->mg_flags & MGf_REFCOUNTED)
-      SvREFCNT_dec(mg->mg_obj);
-     SvMAGIC_set(dsv, mg->mg_moremagic);
-     Safefree(mg);
-     mg_magical(dsv);
-     SvREFCNT_dec(dsv);
-    }
-    croak(NULL);
+    if (!cleanup || cleanup(aTHX_ ud))
+     croak(NULL);
    }
  } else {
   if (old_err) {
@@ -749,7 +728,7 @@ STATIC SV *vmg_data_new(pTHX_ SV *ctor, SV *sv, SV **args, I32 items) {
   PUSHs(args[i]);
  PUTBACK;
 
- vmg_call_sv(ctor, G_SCALAR, NULL);
+ vmg_call_sv(ctor, G_SCALAR, 0, NULL);
 
  SPAGAIN;
  nsv = POPs;
@@ -778,6 +757,11 @@ STATIC SV *vmg_data_get(pTHX_ SV *sv, const vmg_wizard *w) {
 #if VMG_UVAR
 STATIC I32 vmg_svt_val(pTHX_ IV, SV *);
 
+typedef struct {
+ struct ufuncs new_uf;
+ struct ufuncs old_uf;
+} vmg_uvar_ud;
+
 STATIC void vmg_uvar_del(SV *sv, MAGIC *prevmagic, MAGIC *mg, MAGIC *moremagic) {
  if (prevmagic) {
   prevmagic->mg_moremagic = moremagic;
@@ -837,14 +821,14 @@ STATIC UV vmg_cast(pTHX_ SV *sv, const vmg_wizard *w, const SV *wiz, SV **args,
 #if VMG_UVAR
  if (w->uvar) {
   MAGIC *prevmagic, *moremagic = NULL;
-  struct ufuncs uf[2];
+  vmg_uvar_ud ud;
 
-  uf[0].uf_val   = vmg_svt_val;
-  uf[0].uf_set   = NULL;
-  uf[0].uf_index = 0;
-  uf[1].uf_val   = NULL;
-  uf[1].uf_set   = NULL;
-  uf[1].uf_index = 0;
+  ud.new_uf.uf_val   = vmg_svt_val;
+  ud.new_uf.uf_set   = NULL;
+  ud.new_uf.uf_index = 0;
+  ud.old_uf.uf_val   = NULL;
+  ud.old_uf.uf_set   = NULL;
+  ud.old_uf.uf_index = 0;
 
   /* One uvar magic in the chain is enough. */
   for (prevmagic = NULL, mg = SvMAGIC(sv); mg; prevmagic = mg, mg = moremagic) {
@@ -854,18 +838,18 @@ STATIC UV vmg_cast(pTHX_ SV *sv, const vmg_wizard *w, const SV *wiz, SV **args,
   }
 
   if (mg) { /* Found another uvar magic. */
-   struct ufuncs *olduf = (struct ufuncs *) mg->mg_ptr;
-   if (olduf->uf_val == vmg_svt_val) {
+   struct ufuncs *uf = (struct ufuncs *) mg->mg_ptr;
+   if (uf->uf_val == vmg_svt_val) {
     /* It's our uvar magic, nothing to do. oldgmg was true. */
     goto done;
    } else {
     /* It's another uvar magic, backup it and replace it by ours. */
-    uf[1] = *olduf;
+    ud.old_uf = *uf;
     vmg_uvar_del(sv, prevmagic, mg, moremagic);
    }
   }
 
-  sv_magic(sv, NULL, PERL_MAGIC_uvar, (const char *) &uf, sizeof(uf));
+  sv_magic(sv, NULL, PERL_MAGIC_uvar, (const char *) &ud, sizeof(ud));
   vmg_mg_magical(sv);
   /* Our hash now carries uvar magic. The uvar/clear shortcoming has to be
    * handled by our uvar callback. */
@@ -942,19 +926,23 @@ STATIC UV vmg_dispell(pTHX_ SV *sv, const vmg_wizard *w) {
   }
 
   if (uvars == 1) {
-   struct ufuncs *uf;
+   vmg_uvar_ud *ud;
+
    for (prevmagic = NULL, mg = SvMAGIC(sv); mg; prevmagic = mg, mg = moremagic){
     moremagic = mg->mg_moremagic;
     if (mg->mg_type == PERL_MAGIC_uvar)
      break;
    }
-   uf = (struct ufuncs *) mg->mg_ptr;
-   if (uf[1].uf_val || uf[1].uf_set) {
+
+   ud = (vmg_uvar_ud *) mg->mg_ptr;
+   if (ud->old_uf.uf_val || ud->old_uf.uf_set) {
     /* Revert the original uvar magic. */
-    uf[0] = uf[1];
-    Renew(uf, 1, struct ufuncs);
+    struct ufuncs *uf;
+    Newx(uf, 1, struct ufuncs);
+    *uf = ud->old_uf;
+    Safefree(ud);
     mg->mg_ptr = (char *) uf;
-    mg->mg_len = sizeof(struct ufuncs);
+    mg->mg_len = sizeof(*uf);
    } else {
     /* Remove the uvar magic. */
     vmg_uvar_del(sv, prevmagic, mg, moremagic);
@@ -1064,7 +1052,7 @@ STATIC int vmg_cb_call(pTHX_ SV *cb, unsigned int flags, SV *sv, ...) {
   XPUSHs(vmg_op_info(opinfo));
  PUTBACK;
 
- vmg_call_sv(cb, G_SCALAR, NULL);
+ vmg_call_sv(cb, G_SCALAR, 0, NULL);
 
  SPAGAIN;
  svr = POPs;
@@ -1156,7 +1144,7 @@ STATIC U32 vmg_svt_len(pTHX_ SV *sv, MAGIC *mg) {
   XPUSHs(vmg_op_info(opinfo));
  PUTBACK;
 
- vmg_call_sv(w->cb_len, G_SCALAR, NULL);
+ vmg_call_sv(w->cb_len, G_SCALAR, 0, NULL);
 
  SPAGAIN;
  svr = POPs;
@@ -1196,6 +1184,27 @@ STATIC int vmg_svt_clear(pTHX_ SV *sv, MAGIC *mg) {
 
 /* ... free magic .......................................................... */
 
+STATIC int vmg_svt_free_cleanup(pTHX_ void *ud) {
+ SV    *sv = VOID2(SV *, ud);
+ MAGIC *mg;
+
+ /* We are about to croak() while sv is being destroyed. Try to clean up
+  * things a bit. */
+ mg = SvMAGIC(sv);
+ SvREFCNT_dec((SV *) mg->mg_ptr);
+ /* mg->mg_obj may not be refcounted if the data constructor returned the
+  * variable itself. */
+ if (mg->mg_flags & MGf_REFCOUNTED)
+  SvREFCNT_dec(mg->mg_obj);
+ SvMAGIC_set(sv, mg->mg_moremagic);
+ Safefree(mg);
+ mg_magical(sv);
+ SvREFCNT_dec(sv);
+
+ /* After that, propagate the error upwards. */
+ return 1;
+}
+
 STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) {
  const vmg_wizard *w;
  int ret = 0;
@@ -1231,7 +1240,7 @@ STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) {
   XPUSHs(vmg_op_info(w->opinfo));
  PUTBACK;
 
- vmg_call_sv(w->cb_free, G_SCALAR, sv);
+ vmg_call_sv(w->cb_free, G_SCALAR, vmg_svt_free_cleanup, sv);
 
  SPAGAIN;
  svr = POPs;
@@ -1317,7 +1326,7 @@ STATIC OP *vmg_pp_resetuvar(pTHX) {
 }
 
 STATIC I32 vmg_svt_val(pTHX_ IV action, SV *sv) {
struct ufuncs *uf;
vmg_uvar_ud *ud;
  MAGIC *mg, *umg;
  SV *key = NULL, *newkey = NULL;
  int tied = 0;
@@ -1325,12 +1334,12 @@ STATIC I32 vmg_svt_val(pTHX_ IV action, SV *sv) {
  umg = mg_find(sv, PERL_MAGIC_uvar);
  /* umg can't be NULL or we wouldn't be there. */
  key = umg->mg_obj;
- uf  = (struct ufuncs *) umg->mg_ptr;
+ ud  = (vmg_uvar_ud *) umg->mg_ptr;
 
- if (uf[1].uf_val)
-  uf[1].uf_val(aTHX_ action, sv);
- if (uf[1].uf_set)
-  uf[1].uf_set(aTHX_ action, sv);
+ if (ud->old_uf.uf_val)
+  ud->old_uf.uf_val(aTHX_ action, sv);
+ if (ud->old_uf.uf_set)
+  ud->old_uf.uf_set(aTHX_ action, sv);
 
  for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
   const vmg_wizard *w;