summaryrefslogtreecommitdiff
path: root/pp_hot.c
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2011-03-12 22:01:26 +0000
committerDavid Mitchell <davem@iabyn.com>2011-03-12 22:54:28 +0000
commitacdea6f0600816151724f1e3525a3e41433e2646 (patch)
tree14beee47ca5d8594c82f860994601220de9ff1e4 /pp_hot.c
parentfaa5b915472fb587460f0f9249bf16fecdf6f103 (diff)
downloadperl-acdea6f0600816151724f1e3525a3e41433e2646.tar.gz
[perl #82111] de-pessimise some my @array = ...
Due to obscure closure and goto tricks, it's sometimes possible for the array or hash in the LHS of 'my @a = ...' and 'my %h = ...' to be non-empty. At compile-time, these conditions are detected and the assign op is compiled with the OPpASSIGN_COMMON, making the assignment slower. This commit speeds it up again by adding a run-time check to pp_aassign to only do the OPpASSIGN_COMMON code-branch if the LHS isn't an empty array or hash. See also #70171.
Diffstat (limited to 'pp_hot.c')
-rw-r--r--pp_hot.c13
1 files changed, 12 insertions, 1 deletions
diff --git a/pp_hot.c b/pp_hot.c
index 852ff80d43..f8a61cbdb2 100644
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -989,8 +989,19 @@ PP(pp_aassign)
/* If there's a common identifier on both sides we have to take
* special care that assigning the identifier on the left doesn't
* clobber a value on the right that's used later in the list.
+ * Don't bother if LHS is just an empty hash or array.
*/
- if (PL_op->op_private & (OPpASSIGN_COMMON)) {
+
+ if ( (PL_op->op_private & OPpASSIGN_COMMON)
+ && (
+ firstlelem != lastlelem
+ || ! ((sv = *firstlelem))
+ || SvMAGICAL(sv)
+ || ! (SvTYPE(sv) == SVt_PVAV || SvTYPE(sv) == SVt_PVHV)
+ || (SvTYPE(sv) == SVt_PVAV && AvFILL((AV*)sv) != -1)
+ || (SvTYPE(sv) == SVt_PVHV && HvKEYS((HV*)sv) != 0)
+ )
+ ) {
EXTEND_MORTAL(lastrelem - firstrelem + 1);
for (relem = firstrelem; relem <= lastrelem; relem++) {
if ((sv = *relem)) {