summaryrefslogtreecommitdiff
path: root/pp_hot.c
diff options
context:
space:
mode:
authorVincent Pit <perl@profvince.com>2008-12-28 15:08:05 +0100
committerVincent Pit <perl@profvince.com>2008-12-28 15:46:41 +0100
commit4ad10a0b60fb728d1be0a9eeb1970166a3846d38 (patch)
tree1d837e46785bb215c2744c7becf85e3c71bcc8e3 /pp_hot.c
parentc68ec7a9f950f968bb39608a47e0228e03511a18 (diff)
downloadperl-4ad10a0b60fb728d1be0a9eeb1970166a3846d38.tar.gz
On scope end, delete localized array elements that should not exist anymore, so that the array recovers its previous length. Honour EXISTS and DELETE for tied arrays.
Diffstat (limited to 'pp_hot.c')
-rw-r--r--pp_hot.c23
1 files changed, 21 insertions, 2 deletions
diff --git a/pp_hot.c b/pp_hot.c
index 88fe83814e..66c36cbcf6 100644
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -2913,6 +2913,8 @@ PP(pp_aelem)
AV *const av = MUTABLE_AV(POPs);
const U32 lval = PL_op->op_flags & OPf_MOD || LVRET;
const U32 defer = (PL_op->op_private & OPpLVAL_DEFER) && (elem > av_len(av));
+ const bool localizing = PL_op->op_private & OPpLVAL_INTRO;
+ bool preeminent = TRUE;
SV *sv;
if (SvROK(elemsv) && !SvGAMAGIC(elemsv) && ckWARN(WARN_MISC))
@@ -2923,6 +2925,19 @@ PP(pp_aelem)
elem -= CopARYBASE_get(PL_curcop);
if (SvTYPE(av) != SVt_PVAV)
RETPUSHUNDEF;
+
+ if (localizing) {
+ MAGIC *mg;
+ HV *stash;
+
+ /* If we can determine whether the element exist,
+ * Try to preserve the existenceness of a tied array
+ * element by using EXISTS and DELETE if possible.
+ * Fallback to FETCH and STORE otherwise. */
+ if (SvCANEXISTDELETE(av))
+ preeminent = av_exists(av, elem);
+ }
+
svp = av_fetch(av, elem, lval && !defer);
if (lval) {
#ifdef PERL_MALLOC_WRAP
@@ -2952,8 +2967,12 @@ PP(pp_aelem)
PUSHs(lv);
RETURN;
}
- if (PL_op->op_private & OPpLVAL_INTRO)
- save_aelem(av, elem, svp);
+ if (localizing) {
+ if (preeminent)
+ save_aelem(av, elem, svp);
+ else
+ SAVEADELETE(av, elem);
+ }
else if (PL_op->op_private & OPpDEREF)
vivify_ref(*svp, PL_op->op_private & OPpDEREF);
}