summaryrefslogtreecommitdiff
path: root/peep.c
diff options
context:
space:
mode:
Diffstat (limited to 'peep.c')
-rw-r--r--peep.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/peep.c b/peep.c
index 1319745b9a..0e3a81f019 100644
--- a/peep.c
+++ b/peep.c
@@ -3147,6 +3147,62 @@ Perl_rpeep(pTHX_ OP *o)
}
}
+ /* If the pushmark is associated with an empty anonhash
+ * or anonlist, null out the pushmark and swap in a
+ * specialised op for the parent.
+ * 4 <@> anonhash sK* ->5
+ * 3 <0> pushmark s ->4
+ * becomes:
+ * 3 <@> emptyavhv sK* ->4
+ * - <0> pushmark s ->3
+ */
+ if (!OpHAS_SIBLING(o) && (o->op_next == o->op_sibparent) && (
+ (o->op_next->op_type == OP_ANONHASH) ||
+ (o->op_next->op_type == OP_ANONLIST) ) &&
+ (o->op_next->op_flags & OPf_SPECIAL) ) {
+
+ OP* anon = o->op_next;
+ /* These next two are _potentially_ a padsv and an sassign */
+ OP* padsv = anon->op_next;
+ OP* sassign = (padsv) ? padsv->op_next: NULL;
+
+ anon->op_private = (anon->op_type == OP_ANONLIST) ?
+ 0 : OPpEMPTYAVHV_IS_HV;
+ OpTYPE_set(anon, OP_EMPTYAVHV);
+ op_null(o);
+ o = anon;
+ if (oldop) /* A previous optimization may have NULLED it */
+ oldop->op_next = anon;
+
+ /* Further optimise scalar assignment of an empty anonhash
+ * or anonlist by subsuming the padsv & sassign OPs. */
+ if ((padsv->op_type == OP_PADSV) &&
+ !(padsv->op_private & OPpDEREF) &&
+ sassign && (sassign->op_type == OP_SASSIGN) ){
+
+ /* Take some public flags from the sassign */
+ anon->op_flags = OPf_KIDS | OPf_SPECIAL |
+ (anon->op_flags & OPf_PARENS) |
+ (sassign->op_flags & (OPf_WANT|OPf_PARENS));
+
+ /* Take some private flags from the padsv */
+ anon->op_private |= OPpTARGET_MY |
+ (padsv->op_private & (OPpLVAL_INTRO|OPpPAD_STATE));
+
+ /* Take the targ slot from the padsv*/
+ anon->op_targ = padsv->op_targ;
+ padsv->op_targ = 0;
+
+ /* Clean up */
+ anon->op_next = sassign->op_next;
+ op_null(padsv);
+ op_null(sassign);
+ }
+ break;
+
+ }
+
+
/* Convert a series of PAD ops for my vars plus support into a
* single padrange op. Basically
*