]> git.vpit.fr Git - perl/modules/autovivification.git/blobdiff - autovivification.xs
Delete exists/delete ops from the map when the pragma isn't in use
[perl/modules/autovivification.git] / autovivification.xs
index de413b4c54c4c8269d783b0fc170190ae731d291..9e10bb5a9f00dd089321c6646f5c54580dd35f88 100644 (file)
@@ -189,6 +189,19 @@ STATIC const a_op_info *a_map_fetch(const OP *o, a_op_info *oi) {
  return val;
 }
 
+STATIC void a_map_delete(pTHX_ const OP *o) {
+#define a_map_delete(O) a_map_delete(aTHX_ (O))
+#ifdef USE_ITHREADS
+ MUTEX_LOCK(&a_op_map_mutex);
+#endif
+
+ ptable_map_store(a_op_map, o, NULL);
+
+#ifdef USE_ITHREADS
+ MUTEX_UNLOCK(&a_op_map_mutex);
+#endif
+}
+
 STATIC void a_map_set_root(const OP *root, UV flags) {
  a_op_info *oi;
  const OP *o = root;
@@ -204,12 +217,28 @@ STATIC void a_map_set_root(const OP *root, UV flags) {
   }
   if (!(o->op_flags & OPf_KIDS))
    break;
-  o = cUNOPo->op_first;
+  switch (PL_opargs[o->op_type] & OA_CLASS_MASK) {
+   case OA_BASEOP:
+   case OA_UNOP:
+   case OA_BINOP:
+   case OA_BASEOP_OR_UNOP:
+    o = cUNOPo->op_first;
+    break;
+   case OA_LIST:
+   case OA_LISTOP:
+    o = cLISTOPo->op_last;
+    break;
+   default:
+    goto done;
+  }
  }
 
+done:
 #ifdef USE_ITHREADS
  MUTEX_UNLOCK(&a_op_map_mutex);
 #endif
+
+ return;
 }
 
 /* ... Lightweight pp_defined() ............................................ */
@@ -246,6 +275,8 @@ STATIC OP *a_pp_rv2av(pTHX) {
  dSP;
 
  if (!SvOK(TOPs)) {
+  /* We always need to push an empty array to fool the pp_aelem() that comes
+   * later. */
   SV *av;
   POPs;
   av = sv_2mortal((SV *) newAV());
@@ -265,11 +296,18 @@ STATIC OP *a_pp_rv2hv(pTHX) {
  UV hint;
  dSP;
 
- if (!SvOK(TOPs))
-  RETURN;
-
  a_map_fetch(PL_op, &oi);
 
+ if (!SvOK(TOPs)) {
+  if (oi.root->op_flags & OPf_MOD) {
+   SV *hv;
+   POPs;
+   hv = sv_2mortal((SV *) newHV());
+   PUSHs(hv);
+  }
+  RETURN;
+ }
+
  return CALL_FPTR(oi.old_pp)(aTHX);
 }
 
@@ -291,9 +329,8 @@ STATIC OP *a_pp_deref(pTHX) {
   U8 old_private;
 
 deref:
-  old_private = PL_op->op_private;
-  PL_op->op_private &= ~OPpDEREF;
-  PL_op->op_private |= OPpLVAL_DEFER;
+  old_private       = PL_op->op_private;
+  PL_op->op_private = ((old_private & ~OPpDEREF) | OPpLVAL_DEFER);
   o = CALL_FPTR(oi.old_pp)(aTHX);
   PL_op->op_private = old_private;
 
@@ -313,11 +350,11 @@ deref:
  } else if (flags && (PL_op->op_private & OPpDEREF || PL_op == oi.root)) {
   oi.flags = flags & A_HINT_NOTIFY;
 
-  if (oi.root->op_flags & OPf_MOD) {
-   if (flags & A_HINT_STORE)
+  if ((oi.root->op_flags & (OPf_MOD|OPf_REF)) != (OPf_MOD|OPf_REF)) {
+   if (flags & A_HINT_FETCH)
+    oi.flags |= (A_HINT_FETCH|A_HINT_DEREF);
+  } else if (flags & A_HINT_STORE)
     oi.flags |= (A_HINT_STORE|A_HINT_DEREF);
-  } else if (flags & A_HINT_FETCH)
-   oi.flags |= (A_HINT_FETCH|A_HINT_DEREF);
 
   if (PL_op == oi.root)
    oi.flags &= ~A_HINT_DEREF;
@@ -408,7 +445,7 @@ STATIC OP *a_ck_padany(pTHX_ OP *o) {
   a_pp_padsv_save();
   a_map_store(o, a_pp_padsv_saved, hint);
  } else
-  a_map_store(o, 0, 0);
+  a_map_delete(o);
 
  return o;
 }
@@ -427,7 +464,7 @@ STATIC OP *a_ck_padsv(pTHX_ OP *o) {
   a_map_store(o, o->op_ppaddr, hint);
   o->op_ppaddr = a_pp_deref;
  } else
-  a_map_store(o, 0, 0);
+  a_map_delete(o);
 
  return o;
 }
@@ -451,24 +488,40 @@ STATIC OP *a_ck_deref(pTHX_ OP *o) {
 
  hint = a_hint();
  if (hint & A_HINT_DO) {
-  if (!(hint & A_HINT_STRICT) && o->op_flags & OPf_KIDS) {
-   OP *kid = cUNOPo->op_first;
-   switch (kid->op_type) {
-    case OP_RV2AV:
-     a_map_store(kid, kid->op_ppaddr, hint);
-     kid->op_ppaddr = a_pp_rv2av;
-     break;
-    case OP_RV2HV:
-     a_map_store(kid, kid->op_ppaddr, hint);
-     kid->op_ppaddr = a_pp_rv2hv;
-     break;
-   }
-  }
   a_map_store(o, o->op_ppaddr, hint);
   o->op_ppaddr = a_pp_deref;
   a_map_set_root(o, hint);
  } else
-  a_map_store(o, 0, 0);
+  a_map_delete(o);
+
+ return o;
+}
+
+/* ... ck_rv2xv (rv2av,rv2hv) .............................................. */
+
+STATIC OP *(*a_old_ck_rv2av)(pTHX_ OP *) = 0;
+STATIC OP *(*a_old_ck_rv2hv)(pTHX_ OP *) = 0;
+
+STATIC OP *a_ck_rv2xv(pTHX_ OP *o) {
+ OP * (*old_ck)(pTHX_ OP *o) = 0;
+ OP * (*new_pp)(pTHX)        = 0;
+ UV hint;
+
+ switch (o->op_type) {
+  case OP_RV2AV: old_ck = a_old_ck_rv2av; new_pp = a_pp_rv2av; break;
+  case OP_RV2HV: old_ck = a_old_ck_rv2hv; new_pp = a_pp_rv2hv; break;
+ }
+ o = CALL_FPTR(old_ck)(aTHX_ o);
+
+ hint = a_hint();
+ if (hint & A_HINT_DO) {
+  if (!(hint & A_HINT_STRICT)) {
+   a_map_store(o, o->op_ppaddr, hint);
+   o->op_ppaddr = new_pp;
+  }
+  a_map_set_root(o, hint);
+ } else
+  a_map_delete(o);
 
  return o;
 }
@@ -495,13 +548,16 @@ STATIC OP *a_ck_root(pTHX_ OP *o) {
  }
  o = CALL_FPTR(old_ck)(aTHX_ o);
 
- if (enabled) {
-  a_map_set_root(o, hint | A_HINT_DEREF);
-  a_map_store(o, o->op_ppaddr, hint);
-  o->op_ppaddr = a_pp_root;
- } else {
-  a_map_set_root(o, 0);
- }
+ if (hint & A_HINT_DO) {
+  if (enabled) {
+   a_map_set_root(o, hint | A_HINT_DEREF);
+   a_map_store(o, o->op_ppaddr, hint);
+   o->op_ppaddr = a_pp_root;
+  } else {
+   a_map_set_root(o, 0);
+  }
+ } else
+  a_map_delete(o);
 
  return o;
 }
@@ -536,6 +592,10 @@ BOOT:
   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_exists     = PL_check[OP_EXISTS];
   PL_check[OP_EXISTS] = MEMBER_TO_FPTR(a_ck_root);
   a_old_ck_delete     = PL_check[OP_DELETE];