]> git.vpit.fr Git - perl/modules/autovivification.git/blobdiff - autovivification.xs
Use the op free hook to clean up pointer table entries when available
[perl/modules/autovivification.git] / autovivification.xs
index e36b8f50dfc6f1ed7bdfec6f3c6d3a0b1df5a339..27f44c7ae74cbe41a260d648ff0b205aead3d468 100644 (file)
 # define A_HAS_RPEEP A_HAS_PERL(5, 13, 5)
 #endif
 
+#ifndef A_HAS_OPFREEHOOK
+# define A_HAS_OPFREEHOOK A_HAS_PERL(5, 12, 0)
+#endif
+
 /* ... Thread safety and multiplicity ...................................... */
 
 /* Always safe when the workaround isn't needed */
 # define MY_CXT_CLONE NOOP
 #endif
 
+#if defined(OP_CHECK_MUTEX_LOCK) && defined(OP_CHECK_MUTEX_UNLOCK)
+# define A_CHECK_MUTEX_LOCK   OP_CHECK_MUTEX_LOCK
+# define A_CHECK_MUTEX_UNLOCK OP_CHECK_MUTEX_UNLOCK
+#else
+# define A_CHECK_MUTEX_LOCK   OP_REFCNT_LOCK
+# define A_CHECK_MUTEX_UNLOCK OP_REFCNT_UNLOCK
+#endif
+
+typedef OP *(*a_ck_t)(pTHX_ OP *);
+
+#ifdef wrap_op_checker
+
+# define a_ck_replace(T, NC, OCP) wrap_op_checker((T), (NC), (OCP))
+
+#else
+
+STATIC void a_ck_replace(pTHX_ OPCODE type, a_ck_t new_ck, a_ck_t *old_ck_p) {
+#define a_ck_replace(T, NC, OCP) a_ck_replace(aTHX_ (T), (NC), (OCP))
+ A_CHECK_MUTEX_LOCK;
+ if (!*old_ck_p) {
+  *old_ck_p      = PL_check[type];
+  PL_check[type] = new_ck;
+ }
+ A_CHECK_MUTEX_UNLOCK;
+}
+
+#endif
+
+STATIC void a_ck_restore(pTHX_ OPCODE type, a_ck_t *old_ck_p) {
+#define a_ck_restore(T, OCP) a_ck_restore(aTHX_ (T), (OCP))
+ A_CHECK_MUTEX_LOCK;
+ if (*old_ck_p) {
+  PL_check[type] = *old_ck_p;
+  *old_ck_p      = 0;
+ }
+ A_CHECK_MUTEX_UNLOCK;
+}
+
 /* --- Helpers ------------------------------------------------------------- */
 
 /* ... Thread-safe hints ................................................... */
@@ -586,7 +628,7 @@ STATIC OP *a_pp_rv2av(pTHX) {
    /* We always need to push an empty array to fool the pp_aelem() that comes
     * later. */
    SV *av;
-   POPs;
+   (void) POPs;
    av = sv_2mortal((SV *) newAV());
    PUSHs(av);
    RETURN;
@@ -623,7 +665,7 @@ STATIC OP *a_pp_rv2hv(pTHX) {
  if (oi->flags & A_HINT_DEREF) {
   if (a_undef(TOPs)) {
    SV *hv;
-   POPs;
+   (void) POPs;
    hv = sv_2mortal((SV *) newHV());
    PUSHs(hv);
    RETURN;
@@ -673,7 +715,7 @@ STATIC OP *a_pp_root_unop(pTHX) {
  dSP;
 
  if (a_undef(TOPs)) {
-  POPs;
+  (void) POPs;
   /* Can only be reached by keys or values */
   if (GIMME_V == G_SCALAR) {
    dTARGET;
@@ -693,8 +735,8 @@ STATIC OP *a_pp_root_binop(pTHX) {
  dSP;
 
  if (a_undef(TOPm1s)) {
-  POPs;
-  POPs;
+  (void) POPs;
+  (void) POPs;
   if (PL_op->op_type == OP_EXISTS)
    RETPUSHNO;
   else
@@ -741,10 +783,13 @@ STATIC OP *a_ck_padany(pTHX_ OP *o) {
  o = a_old_ck_padany(aTHX_ o);
 
  hint = a_hint();
- if (hint & A_HINT_DO)
+ if (hint & A_HINT_DO) {
   a_map_store_root(o, o->op_ppaddr, hint);
- else
+#if !A_HAS_OPFREEHOOK
+ } else {
   a_map_delete(o);
+#endif
+ }
 
  return o;
 }
@@ -760,8 +805,11 @@ STATIC OP *a_ck_padsv(pTHX_ OP *o) {
  if (hint & A_HINT_DO) {
   a_map_store_root(o, o->op_ppaddr, hint);
   o->op_ppaddr = a_pp_deref;
- } else
+#if !A_HAS_OPFREEHOOK
+ } else {
   a_map_delete(o);
+#endif
+ }
 
  return o;
 }
@@ -801,8 +849,11 @@ STATIC OP *a_ck_deref(pTHX_ OP *o) {
  if (hint & A_HINT_DO) {
   a_map_store_root(o, o->op_ppaddr, hint);
   o->op_ppaddr = a_pp_deref;
- } else
+#if !A_HAS_OPFREEHOOK
+ } else {
   a_map_delete(o);
+#endif
+ }
 
  return o;
 }
@@ -835,8 +886,11 @@ STATIC OP *a_ck_rv2xv(pTHX_ OP *o) {
  if (hint & A_HINT_DO && !(hint & A_HINT_STRICT)) {
   a_map_store_root(o, o->op_ppaddr, hint);
   o->op_ppaddr = new_pp;
- } else
+#if !A_HAS_OPFREEHOOK
+ } else {
   a_map_delete(o);
+#endif
+ }
 
  return o;
 }
@@ -869,8 +923,11 @@ STATIC OP *a_ck_xslice(pTHX_ OP *o) {
 
  if (hint & A_HINT_DO) {
   a_map_store_root(o, 0, hint);
- } else
+#if !A_HAS_OPFREEHOOK
+ } else {
   a_map_delete(o);
+#endif
+ }
 
  return o;
 }
@@ -923,8 +980,11 @@ STATIC OP *a_ck_root(pTHX_ OP *o) {
   } else {
    a_map_cancel(o);
   }
- } else
+#if !A_HAS_OPFREEHOOK
+ } else {
   a_map_delete(o);
+#endif
+ }
 
  return o;
 }
@@ -1040,6 +1100,21 @@ STATIC void a_peep(pTHX_ OP *o) {
  ptable_seen_clear(seen);
 }
 
+/* ... Our op free hook (when available) ................................... */
+
+#if A_HAS_OPFREEHOOK
+
+STATIC void (*a_old_opfreehook)(pTHX_ OP *) = 0;
+
+STATIC void a_opfreehook(pTHX_ OP *o) {
+ a_map_delete(o);
+
+ if (a_old_opfreehook)
+  a_old_opfreehook(aTHX_ o);
+}
+
+#endif
+
 /* --- Interpreter setup/teardown ------------------------------------------ */
 
 STATIC U32 a_initialized = 0;
@@ -1062,36 +1137,23 @@ STATIC void a_teardown(pTHX_ void *root) {
   ptable_seen_free(MY_CXT.seen);
  }
 
- PL_check[OP_PADANY] = MEMBER_TO_FPTR(a_old_ck_padany);
- a_old_ck_padany     = 0;
- PL_check[OP_PADSV]  = MEMBER_TO_FPTR(a_old_ck_padsv);
- a_old_ck_padsv      = 0;
-
- PL_check[OP_AELEM]  = MEMBER_TO_FPTR(a_old_ck_aelem);
- a_old_ck_aelem      = 0;
- PL_check[OP_HELEM]  = MEMBER_TO_FPTR(a_old_ck_helem);
- a_old_ck_helem      = 0;
- PL_check[OP_RV2SV]  = MEMBER_TO_FPTR(a_old_ck_rv2sv);
- a_old_ck_rv2sv      = 0;
-
- PL_check[OP_RV2AV]  = MEMBER_TO_FPTR(a_old_ck_rv2av);
- a_old_ck_rv2av      = 0;
- PL_check[OP_RV2HV]  = MEMBER_TO_FPTR(a_old_ck_rv2hv);
- a_old_ck_rv2hv      = 0;
-
- PL_check[OP_ASLICE] = MEMBER_TO_FPTR(a_old_ck_aslice);
- a_old_ck_aslice     = 0;
- PL_check[OP_HSLICE] = MEMBER_TO_FPTR(a_old_ck_hslice);
- a_old_ck_hslice     = 0;
-
- PL_check[OP_EXISTS] = MEMBER_TO_FPTR(a_old_ck_exists);
- a_old_ck_exists     = 0;
- PL_check[OP_DELETE] = MEMBER_TO_FPTR(a_old_ck_delete);
- a_old_ck_delete     = 0;
- PL_check[OP_KEYS]   = MEMBER_TO_FPTR(a_old_ck_keys);
- a_old_ck_keys       = 0;
- PL_check[OP_VALUES] = MEMBER_TO_FPTR(a_old_ck_values);
- a_old_ck_values     = 0;
+ a_ck_restore(OP_PADANY, &a_old_ck_padany);
+ a_ck_restore(OP_PADSV,  &a_old_ck_padsv);
+
+ a_ck_restore(OP_AELEM,  &a_old_ck_aelem);
+ a_ck_restore(OP_HELEM,  &a_old_ck_helem);
+ a_ck_restore(OP_RV2SV,  &a_old_ck_rv2sv);
+
+ a_ck_restore(OP_RV2AV,  &a_old_ck_rv2av);
+ a_ck_restore(OP_RV2HV,  &a_old_ck_rv2hv);
+
+ a_ck_restore(OP_ASLICE, &a_old_ck_aslice);
+ a_ck_restore(OP_HSLICE, &a_old_ck_hslice);
+
+ a_ck_restore(OP_EXISTS, &a_old_ck_exists);
+ a_ck_restore(OP_DELETE, &a_old_ck_delete);
+ a_ck_restore(OP_KEYS,   &a_old_ck_keys);
+ a_ck_restore(OP_VALUES, &a_old_ck_values);
 
 #if A_HAS_RPEEP
  PL_rpeepp  = a_old_peep;
@@ -1100,6 +1162,11 @@ STATIC void a_teardown(pTHX_ void *root) {
 #endif
  a_old_peep = 0;
 
+#if A_HAS_OPFREEHOOK
+ PL_opfreehook    = a_old_opfreehook;
+ a_old_opfreehook = 0;
+#endif
+
  a_initialized = 0;
 }
 
@@ -1117,36 +1184,23 @@ STATIC void a_setup(pTHX) {
   MY_CXT.seen  = ptable_new();
  }
 
- a_old_ck_padany     = PL_check[OP_PADANY];
- PL_check[OP_PADANY] = MEMBER_TO_FPTR(a_ck_padany);
- a_old_ck_padsv      = PL_check[OP_PADSV];
- PL_check[OP_PADSV]  = MEMBER_TO_FPTR(a_ck_padsv);
-
- a_old_ck_aelem      = PL_check[OP_AELEM];
- PL_check[OP_AELEM]  = MEMBER_TO_FPTR(a_ck_deref);
- a_old_ck_helem      = PL_check[OP_HELEM];
- PL_check[OP_HELEM]  = MEMBER_TO_FPTR(a_ck_deref);
- a_old_ck_rv2sv      = PL_check[OP_RV2SV];
- PL_check[OP_RV2SV]  = MEMBER_TO_FPTR(a_ck_deref);
-
- a_old_ck_rv2av      = PL_check[OP_RV2AV];
- PL_check[OP_RV2AV]  = MEMBER_TO_FPTR(a_ck_rv2xv);
- a_old_ck_rv2hv      = PL_check[OP_RV2HV];
- PL_check[OP_RV2HV]  = MEMBER_TO_FPTR(a_ck_rv2xv);
-
- a_old_ck_aslice     = PL_check[OP_ASLICE];
- PL_check[OP_ASLICE] = MEMBER_TO_FPTR(a_ck_xslice);
- a_old_ck_hslice     = PL_check[OP_HSLICE];
- PL_check[OP_HSLICE] = MEMBER_TO_FPTR(a_ck_xslice);
-
- a_old_ck_exists     = PL_check[OP_EXISTS];
- PL_check[OP_EXISTS] = MEMBER_TO_FPTR(a_ck_root);
- a_old_ck_delete     = PL_check[OP_DELETE];
- PL_check[OP_DELETE] = MEMBER_TO_FPTR(a_ck_root);
- a_old_ck_keys       = PL_check[OP_KEYS];
- PL_check[OP_KEYS]   = MEMBER_TO_FPTR(a_ck_root);
- a_old_ck_values     = PL_check[OP_VALUES];
- PL_check[OP_VALUES] = MEMBER_TO_FPTR(a_ck_root);
+ a_ck_replace(OP_PADANY, a_ck_padany, &a_old_ck_padany);
+ a_ck_replace(OP_PADSV,  a_ck_padsv,  &a_old_ck_padsv);
+
+ a_ck_replace(OP_AELEM,  a_ck_deref,  &a_old_ck_aelem);
+ a_ck_replace(OP_HELEM,  a_ck_deref,  &a_old_ck_helem);
+ a_ck_replace(OP_RV2SV,  a_ck_deref,  &a_old_ck_rv2sv);
+
+ a_ck_replace(OP_RV2AV,  a_ck_rv2xv,  &a_old_ck_rv2av);
+ a_ck_replace(OP_RV2HV,  a_ck_rv2xv,  &a_old_ck_rv2hv);
+
+ a_ck_replace(OP_ASLICE, a_ck_xslice, &a_old_ck_aslice);
+ a_ck_replace(OP_HSLICE, a_ck_xslice, &a_old_ck_hslice);
+
+ a_ck_replace(OP_EXISTS, a_ck_root,   &a_old_ck_exists);
+ a_ck_replace(OP_DELETE, a_ck_root,   &a_old_ck_delete);
+ a_ck_replace(OP_KEYS,   a_ck_root,   &a_old_ck_keys);
+ a_ck_replace(OP_VALUES, a_ck_root,   &a_old_ck_values);
 
 #if A_HAS_RPEEP
  a_old_peep = PL_rpeepp;
@@ -1156,6 +1210,11 @@ STATIC void a_setup(pTHX) {
  PL_peepp   = a_peep;
 #endif
 
+#if A_HAS_OPFREEHOOK
+ a_old_opfreehook = PL_opfreehook;
+ PL_opfreehook    = a_opfreehook;
+#endif
+
 #if A_MULTIPLICITY
  call_atexit(a_teardown, aTHX);
 #else