summaryrefslogtreecommitdiff
path: root/pp_hot.c
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2017-07-23 16:31:38 +0100
committerDavid Mitchell <davem@iabyn.com>2017-07-27 11:30:25 +0100
commit6f2dc9a6b978e866e22c46235932d018da8262ba (patch)
treeaaea4ac92d8aa676e597ecbf13aff28c3a58f65d /pp_hot.c
parent8dc9003ff3914e78971f561eaece965e9ceeb49e (diff)
downloadperl-6f2dc9a6b978e866e22c46235932d018da8262ba.tar.gz
make scalar(keys(%lexical)) less slow.
A recent commit in this branch made OP_PADHV / OP_RV2HV in void/scalar context, followed by OP_KEYS, optimise away the OP_KEYS op and set the OPpPADHV_ISKEYS or OPpRV2HV_ISKEYS flag on the OP_PADHV / OP_RV2HV op. However, in scalar but non-boolean context with OP_PADHV, this actually makes it slower, because the OP_KEYS op has a target, while the OP_PADHV op doesn't, thus it has to create a new mortal each time to return the integer value. This commit fixes that by, in the case of scalar padhv, retaining the OP_KEYS node (although still not keeping it in the execution path), then at runtime using that op's otherwise unused target. This only works on PERL_OP_PARENT builds (now the default) as the OP_KEYS is the parent of the OP_PADHV, so would be hard to find at runtime otherwise. This commit also fixes pp_padhv/pp_rv2hv in void context - formerly it was needlessly pushing a scalar-valued count like scalar context.
Diffstat (limited to 'pp_hot.c')
-rw-r--r--pp_hot.c18
1 files changed, 18 insertions, 0 deletions
diff --git a/pp_hot.c b/pp_hot.c
index e1e151bc6e..528817fed9 100644
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -991,6 +991,9 @@ S_padhv_rv2hv_common(pTHX_ HV *hv, U8 gimme, bool is_keys, bool has_targ)
/* 'keys %h' masquerading as '%h': reset iterator */
(void)hv_iterinit(hv);
+ if (gimme == G_VOID)
+ return NORMAL;
+
is_bool = ( PL_op->op_private & OPpTRUEBOOL
|| ( PL_op->op_private & OPpMAYBE_TRUEBOOL
&& block_gimme() == G_VOID));
@@ -1022,6 +1025,21 @@ S_padhv_rv2hv_common(pTHX_ HV *hv, U8 gimme, bool is_keys, bool has_targ)
PUSHi(i);
}
else
+#ifdef PERL_OP_PARENT
+ if (is_keys) {
+ /* parent op should be an unused OP_KEYS whose targ we can
+ * use */
+ dTARG;
+ OP *k;
+
+ assert(!OpHAS_SIBLING(PL_op));
+ k = PL_op->op_sibparent;
+ assert(k->op_type == OP_KEYS);
+ TARG = PAD_SV(k->op_targ);
+ PUSHi(i);
+ }
+ else
+#endif
mPUSHi(i);
}
}