]> git.vpit.fr Git - perl/modules/Variable-Magic.git/blobdiff - Magic.xs
Decorate the magic callbacks section
[perl/modules/Variable-Magic.git] / Magic.xs
index 3c4cd3347faa74ceab8869d267110c38e91823d5..8aee17be7e46024b90eb9536699486fbe3091d15 100644 (file)
--- a/Magic.xs
+++ b/Magic.xs
 # define VMG_UVAR 0
 #endif
 
+#if VMG_HAS_PERL_MAINT(5, 11, 0, 32969) || VMG_HAS_PERL(5, 12, 0)
+# define VMG_COMPAT_SCALAR_LENGTH_NOLEN 1
+#else
+# define VMG_COMPAT_SCALAR_LENGTH_NOLEN 0
+#endif
+
 /* Applied to dev-5.9 as 25854, integrated to maint-5.8 as 28160, partially
  * reverted to dev-5.11 as 9cdcb38b */
 #if VMG_HAS_PERL_MAINT(5, 8, 9, 28160) || VMG_HAS_PERL_MAINT(5, 9, 3, 25854) || VMG_HAS_PERL(5, 10, 0)
 # define VMG_COMPAT_ARRAY_UNDEF_CLEAR 0
 #endif
 
-#if VMG_HAS_PERL_MAINT(5, 11, 0, 32969) || VMG_HAS_PERL(5, 12, 0)
-# define VMG_COMPAT_SCALAR_LENGTH_NOLEN 1
+#if VMG_HAS_PERL(5, 11, 0)
+# define VMG_COMPAT_HASH_DELETE_NOUVAR_VOID 1
 #else
-# define VMG_COMPAT_SCALAR_LENGTH_NOLEN 0
+# define VMG_COMPAT_HASH_DELETE_NOUVAR_VOID 0
 #endif
 
 #if VMG_HAS_PERL(5, 13, 2)
@@ -406,11 +412,6 @@ typedef struct {
 
 START_MY_CXT
 
-/* --- Signatures ---------------------------------------------------------- */
-
-#define SIG_WZO ((U16) (0x3891))
-#define SIG_WIZ ((U16) (0x3892))
-
 /* --- <vmg_vtable> structure ---------------------------------------------- */
 
 #if VMG_THREADSAFE
@@ -434,9 +435,7 @@ STATIC vmg_vtable *vmg_vtable_alloc(pTHX) {
 
 #define vmg_vtable_vtbl(T) (T)->vtbl
 
-#if VMG_THREADSAFE
 STATIC perl_mutex vmg_vtable_refcount_mutex;
-#endif
 
 STATIC vmg_vtable *vmg_vtable_dup(pTHX_ vmg_vtable *t) {
 #define vmg_vtable_dup(T) vmg_vtable_dup(aTHX_ (T))
@@ -644,7 +643,7 @@ STATIC SV *vmg_wizard_sv_new(pTHX_ const vmg_wizard *w) {
  if (w) {
   MAGIC *mg = sv_magicext(wiz, NULL, PERL_MAGIC_ext, &vmg_wizard_sv_vtbl,
                                      (const char *) w, 0);
-  mg->mg_private = SIG_WZO;
+  mg->mg_private = 0;
 #if VMG_THREADSAFE
   mg->mg_flags  |= MGf_DUP;
 #endif
@@ -775,9 +774,10 @@ STATIC void vmg_uvar_del(SV *sv, MAGIC *prevmagic, MAGIC *mg, MAGIC *moremagic)
 
 STATIC UV vmg_cast(pTHX_ SV *sv, const vmg_wizard *w, const SV *wiz, SV **args, I32 items) {
 #define vmg_cast(S, W, WIZ, A, I) vmg_cast(aTHX_ (S), (W), (WIZ), (A), (I))
- MAGIC *mg;
- SV    *data;
- U32    oldgmg;
+ MAGIC  *mg;
+ MGVTBL *t;
+ SV     *data;
+ U32     oldgmg;
 
  if (vmg_find(sv, w))
   return 1;
@@ -785,19 +785,22 @@ STATIC UV vmg_cast(pTHX_ SV *sv, const vmg_wizard *w, const SV *wiz, SV **args,
  oldgmg = SvGMAGICAL(sv);
 
  data = (w->cb_data) ? vmg_data_new(w->cb_data, sv, args, items) : NULL;
+
+ t  = vmg_vtable_vtbl(w->vtable);
+ mg = sv_magicext(sv, data, PERL_MAGIC_ext, t, (const char *) wiz, HEf_SVKEY);
+ mg->mg_private = 0;
+
  /* sv_magicext() calls mg_magical and increments data's refcount */
- mg   = sv_magicext(sv, data, PERL_MAGIC_ext, vmg_vtable_vtbl(w->vtable),
-                              (const char *) wiz, HEf_SVKEY);
  SvREFCNT_dec(data);
- mg->mg_private = SIG_WIZ;
- if (w->cb_copy)
+
+ if (t->svt_copy)
   mg->mg_flags |= MGf_COPY;
 #if 0
- if (w->cb_dup)
+ if (t->svt_dup)
   mg->mg_flags |= MGf_DUP;
 #endif
 #if MGf_LOCAL
- if (w->cb_local)
+ if (t->svt_local)
   mg->mg_flags |= MGf_LOCAL;
 #endif /* MGf_LOCAL */
 
@@ -1011,7 +1014,7 @@ STATIC SV *vmg_op_info(pTHX_ unsigned int opinfo) {
  return &PL_sv_undef;
 }
 
-/* ... svt callbacks ....................................................... */
+/* --- svt callbacks ------------------------------------------------------- */
 
 #define VMG_CB_CALL_ARGS_MASK  15
 #define VMG_CB_CALL_ARGS_SHIFT 4
@@ -1069,18 +1072,44 @@ STATIC int vmg_cb_call(pTHX_ SV *cb, unsigned int flags, SV *sv, ...) {
 #define vmg_cb_call3(I, OI, S, A1, A2, A3) \
         vmg_cb_call(aTHX_ (I), VMG_CB_FLAGS((OI), 3), (S), (A1), (A2), (A3))
 
+STATIC int vmg_svt_default_noop(pTHX_ SV *sv, MAGIC *mg) {
+ return 0;
+}
+
+/* ... get magic ........................................................... */
+
 STATIC int vmg_svt_get(pTHX_ SV *sv, MAGIC *mg) {
  const vmg_wizard *w = vmg_wizard_from_mg_nocheck(mg);
 
  return vmg_cb_call1(w->cb_get, w->opinfo, sv, mg->mg_obj);
 }
 
+#define vmg_svt_get_noop vmg_svt_default_noop
+
+/* ... set magic ........................................................... */
+
 STATIC int vmg_svt_set(pTHX_ SV *sv, MAGIC *mg) {
  const vmg_wizard *w = vmg_wizard_from_mg_nocheck(mg);
 
  return vmg_cb_call1(w->cb_set, w->opinfo, sv, mg->mg_obj);
 }
 
+#define vmg_svt_set_noop vmg_svt_default_noop
+
+/* ... len magic ........................................................... */
+
+STATIC U32 vmg_sv_len(pTHX_ SV *sv) {
+#define vmg_sv_len(S) vmg_sv_len(aTHX_ (S))
+ STRLEN len;
+#if VMG_HAS_PERL(5, 9, 3)
+ const U8 *s = VOID2(const U8 *, VOID2(const void *, SvPV_const(sv, len)));
+#else
+ U8 *s = SvPV(sv, len);
+#endif
+
+ return DO_UTF8(sv) ? utf8_length(s, s + len) : len;
+}
+
 STATIC U32 vmg_svt_len(pTHX_ SV *sv, MAGIC *mg) {
  const vmg_wizard *w = vmg_wizard_from_mg_nocheck(mg);
  unsigned int opinfo = w->opinfo;
@@ -1098,16 +1127,7 @@ STATIC U32 vmg_svt_len(pTHX_ SV *sv, MAGIC *mg) {
  PUSHs(sv_2mortal(newRV_inc(sv)));
  PUSHs(mg->mg_obj ? mg->mg_obj : &PL_sv_undef);
  if (t < SVt_PVAV) {
-  STRLEN l;
-#if VMG_HAS_PERL(5, 9, 3)
-  const U8 *s = VOID2(const U8 *, VOID2(const void *, SvPV_const(sv, l)));
-#else
-  U8 *s = SvPV(sv, l);
-#endif
-  if (DO_UTF8(sv))
-   len = utf8_length(s, s + l);
-  else
-   len = l;
+  len = vmg_sv_len(sv);
   mPUSHu(len);
  } else if (t == SVt_PVAV) {
   len = av_len((AV *) sv) + 1;
@@ -1135,12 +1155,31 @@ STATIC U32 vmg_svt_len(pTHX_ SV *sv, MAGIC *mg) {
  return ret;
 }
 
+STATIC U32 vmg_svt_len_noop(pTHX_ SV *sv, MAGIC *mg) {
+ U32    len = 0;
+ svtype t   = SvTYPE(sv);
+
+ if (t < SVt_PVAV) {
+  len = vmg_sv_len(sv);
+ } else if (t == SVt_PVAV) {
+  len = (U32) av_len((AV *) sv);
+ }
+
+ return len;
+}
+
+/* ... clear magic ......................................................... */
+
 STATIC int vmg_svt_clear(pTHX_ SV *sv, MAGIC *mg) {
  const vmg_wizard *w = vmg_wizard_from_mg_nocheck(mg);
 
  return vmg_cb_call1(w->cb_clear, w->opinfo, sv, mg->mg_obj);
 }
 
+#define vmg_svt_clear_noop vmg_svt_default_noop
+
+/* ... free magic .......................................................... */
+
 STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) {
  const vmg_wizard *w;
  int ret = 0;
@@ -1196,13 +1235,17 @@ STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) {
  return ret;
 }
 
-STATIC int vmg_svt_copy(pTHX_ SV *sv, MAGIC *mg, SV *nsv, const char *key,
-# if VMG_HAS_PERL_MAINT(5, 11, 0, 33256) || VMG_HAS_PERL(5, 12, 0)
-  I32 keylen
-# else
-  int keylen
-# endif
- ) {
+#define vmg_svt_free_noop vmg_svt_default_noop
+
+#if VMG_HAS_PERL_MAINT(5, 11, 0, 33256) || VMG_HAS_PERL(5, 12, 0)
+# define VMG_SVT_COPY_KEYLEN_TYPE I32
+#else
+# define VMG_SVT_COPY_KEYLEN_TYPE int
+#endif
+
+/* ... copy magic .......................................................... */
+
+STATIC int vmg_svt_copy(pTHX_ SV *sv, MAGIC *mg, SV *nsv, const char *key, VMG_SVT_COPY_KEYLEN_TYPE keylen) {
  const vmg_wizard *w = vmg_wizard_from_mg_nocheck(mg);
  SV *keysv;
  int ret;
@@ -1222,20 +1265,35 @@ STATIC int vmg_svt_copy(pTHX_ SV *sv, MAGIC *mg, SV *nsv, const char *key,
  return ret;
 }
 
+STATIC int vmg_svt_copy_noop(pTHX_ SV *sv, MAGIC *mg, SV *nsv, const char *key, VMG_SVT_COPY_KEYLEN_TYPE keylen) {
+ return 0;
+}
+
+/* ... dup magic ........................................................... */
+
 #if 0
 STATIC int vmg_svt_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *param) {
  return 0;
 }
+#define vmg_svt_dup_noop vmg_svt_dup
 #endif
 
+/* ... local magic ......................................................... */
+
 #if MGf_LOCAL
+
 STATIC int vmg_svt_local(pTHX_ SV *nsv, MAGIC *mg) {
  const vmg_wizard *w = vmg_wizard_from_mg_nocheck(mg);
 
  return vmg_cb_call1(w->cb_local, w->opinfo, nsv, mg->mg_obj);
 }
+
+#define vmg_svt_local_noop vmg_svt_default_noop
+
 #endif /* MGf_LOCAL */
 
+/* ... uvar magic .......................................................... */
+
 #if VMG_UVAR
 STATIC OP *vmg_pp_resetuvar(pTHX) {
  SvRMAGICAL_on(cSVOP_sv);
@@ -1258,9 +1316,9 @@ STATIC I32 vmg_svt_val(pTHX_ IV action, SV *sv) {
  if (uf[1].uf_set)
   uf[1].uf_set(aTHX_ action, sv);
 
- action &= HV_FETCH_ISSTORE | HV_FETCH_ISEXISTS | HV_FETCH_LVALUE | HV_DELETE;
  for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
   const vmg_wizard *w;
+
   switch (mg->mg_type) {
    case PERL_MAGIC_ext:
     break;
@@ -1270,8 +1328,11 @@ STATIC I32 vmg_svt_val(pTHX_ IV action, SV *sv) {
    default:
     continue;
   }
+
   w = vmg_wizard_from_mg(mg);
-  if (!w) continue;
+  if (!w)
+   continue;
+
   switch (w->uvar) {
    case 0:
     continue;
@@ -1279,7 +1340,9 @@ STATIC I32 vmg_svt_val(pTHX_ IV action, SV *sv) {
     if (!newkey)
      newkey = key = umg->mg_obj = sv_mortalcopy(umg->mg_obj);
   }
-  switch (action) {
+
+  switch (action
+             & (HV_FETCH_ISSTORE|HV_FETCH_ISEXISTS|HV_FETCH_LVALUE|HV_DELETE)) {
    case 0:
     if (w->cb_fetch)
      vmg_cb_call2(w->cb_fetch, w->opinfo, sv, mg->mg_obj, key);
@@ -1301,21 +1364,21 @@ STATIC I32 vmg_svt_val(pTHX_ IV action, SV *sv) {
   }
  }
 
- if (SvRMAGICAL(sv) && !tied) {
+ if (SvRMAGICAL(sv) && !tied && !(action & (HV_FETCH_ISSTORE|HV_DELETE))) {
   /* Temporarily hide the RMAGICAL flag of the hash so it isn't wrongly
    * mistaken for a tied hash by the rest of hv_common. It will be reset by
    * the op_ppaddr of a new fake op injected between the current and the next
    * one. */
-  OP *o = PL_op;
-  if (!o->op_next || o->op_next->op_ppaddr != vmg_pp_resetuvar) {
+  OP *nop = PL_op->op_next;
+  if (!nop || nop->op_ppaddr != vmg_pp_resetuvar) {
    SVOP *svop;
    NewOp(1101, svop, 1, SVOP);
    svop->op_type   = OP_STUB;
    svop->op_ppaddr = vmg_pp_resetuvar;
-   svop->op_next   = o->op_next;
+   svop->op_next   = nop;
    svop->op_flags  = 0;
    svop->op_sv     = sv;
-   o->op_next      = (OP *) svop;
+   PL_op->op_next  = (OP *) svop;
   }
   SvRMAGICAL_off(sv);
  }
@@ -1326,19 +1389,46 @@ STATIC I32 vmg_svt_val(pTHX_ IV action, SV *sv) {
 
 /* --- Macros for the XS section ------------------------------------------- */
 
-#define VMG_SET_CB(S, N)              \
- cb = (S);                            \
- w->cb_ ## N = (SvOK(cb) && SvROK(cb)) ? SvREFCNT_inc(SvRV(cb)) : NULL;
-
-#define VMG_SET_SVT_CB(S, N)          \
- cb = (S);                            \
- if (SvOK(cb) && SvROK(cb)) {         \
-  t->svt_ ## N = vmg_svt_ ## N;       \
-  w->cb_  ## N = SvREFCNT_inc(SvRV(cb)); \
- } else {                             \
-  t->svt_ ## N = NULL;                \
-  w->cb_  ## N = NULL;                \
- }
+#ifdef CvISXSUB
+# define VMG_CVOK(C) \
+   ((CvISXSUB(C) ? (void *) CvXSUB(C) : (void *) CvROOT(C)) ? 1 : 0)
+#else
+# define VMG_CVOK(C) (CvROOT(C) || CvXSUB(C))
+#endif
+
+#define VMG_CBOK(S) ((SvTYPE(S) == SVt_PVCV) ? VMG_CVOK(S) : SvOK(S))
+
+#define VMG_SET_CB(S, N) {       \
+ SV *cb = (S);                   \
+ if (SvOK(cb) && SvROK(cb)) {    \
+  cb = SvRV(cb);                 \
+  if (VMG_CBOK(cb))              \
+   SvREFCNT_inc_simple_void(cb); \
+  else                           \
+   cb = NULL;                    \
+ } else {                        \
+  cb = NULL;                     \
+ }                               \
+ w->cb_ ## N = cb;               \
+}
+
+#define VMG_SET_SVT_CB(S, N) {   \
+ SV *cb = (S);                   \
+ if (SvOK(cb) && SvROK(cb)) {    \
+  cb = SvRV(cb);                 \
+  if (VMG_CBOK(cb)) {            \
+   t->svt_ ## N = vmg_svt_ ## N; \
+   SvREFCNT_inc_simple_void(cb); \
+  } else {                       \
+   t->svt_ ## N = vmg_svt_ ## N ## _noop; \
+   cb           = NULL;          \
+  }                              \
+ } else {                        \
+  t->svt_ ## N = NULL;           \
+  cb           = NULL;           \
+ }                               \
+ w->cb_ ## N = cb;               \
+}
 
 /* --- XS ------------------------------------------------------------------ */
 
@@ -1362,6 +1452,8 @@ BOOT:
  newCONSTSUB(stash, "MGf_DUP",   newSVuv(MGf_DUP));
  newCONSTSUB(stash, "MGf_LOCAL", newSVuv(MGf_LOCAL));
  newCONSTSUB(stash, "VMG_UVAR",  newSVuv(VMG_UVAR));
+ newCONSTSUB(stash, "VMG_COMPAT_SCALAR_LENGTH_NOLEN",
+                    newSVuv(VMG_COMPAT_SCALAR_LENGTH_NOLEN));
  newCONSTSUB(stash, "VMG_COMPAT_ARRAY_PUSH_NOLEN",
                     newSVuv(VMG_COMPAT_ARRAY_PUSH_NOLEN));
  newCONSTSUB(stash, "VMG_COMPAT_ARRAY_PUSH_NOLEN_VOID",
@@ -1370,8 +1462,8 @@ BOOT:
                     newSVuv(VMG_COMPAT_ARRAY_UNSHIFT_NOLEN_VOID));
  newCONSTSUB(stash, "VMG_COMPAT_ARRAY_UNDEF_CLEAR",
                     newSVuv(VMG_COMPAT_ARRAY_UNDEF_CLEAR));
- newCONSTSUB(stash, "VMG_COMPAT_SCALAR_LENGTH_NOLEN",
-                    newSVuv(VMG_COMPAT_SCALAR_LENGTH_NOLEN));
+ newCONSTSUB(stash, "VMG_COMPAT_HASH_DELETE_NOUVAR_VOID",
+                    newSVuv(VMG_COMPAT_HASH_DELETE_NOUVAR_VOID));
  newCONSTSUB(stash, "VMG_COMPAT_GLOB_GET", newSVuv(VMG_COMPAT_GLOB_GET));
  newCONSTSUB(stash, "VMG_PERL_PATCHLEVEL", newSVuv(VMG_PERL_PATCHLEVEL));
  newCONSTSUB(stash, "VMG_THREADSAFE",      newSVuv(VMG_THREADSAFE));
@@ -1412,7 +1504,7 @@ PROTOTYPE: DISABLE
 PREINIT:
  vmg_wizard *w;
  MGVTBL *t;
- SV *cb, *op_info, *copy_key;
+ SV *op_info, *copy_key;
  I32 i = 0;
 CODE:
  if (items != 9