summaryrefslogtreecommitdiff
path: root/op.c
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2012-11-02 16:18:20 +0000
committerDavid Mitchell <davem@iabyn.com>2012-11-10 13:39:33 +0000
commitfd3cc9e5282b97a033e0685520257cf98b326562 (patch)
treef2a22654c32282912ed7152c62c1b216c2b3c042 /op.c
parent4774ee0a8f9bc16a2ee4d1603401c927d02c41bc (diff)
downloadperl-fd3cc9e5282b97a033e0685520257cf98b326562.tar.gz
Consolidate any single pad ops after a padrange
Given something like my ($a,$b); my $c; my $d; then after having detected that we can create a padrange op for $a,$b, extend it to include $c,$d too. Together with the previous commit that consolidates adjacent padrange ops, this means that any contiguous sequence of void 'my' declarations that starts with a list (i.e. my ($x,..) rather than my $x) will all be compressed into a single padrange op. For example my ($a,$b); my @c; my %d; my ($e,@f); becomes the two ops padrange[$a;$b;@c;%d;$e;@f] nextstate The restriction on the first 'my' being a list is that we only ever convert pushmarks into padranges, to keep things manageable (both for compiling and for Deparse). This simply means that my $x; my ($a,$b); my @c; my %d; my ($e,@f) becomes padsv[$x] nextstate padrange[$a;$b;@c;%d;$e;@f] nextstate
Diffstat (limited to 'op.c')
-rw-r--r--op.c65
1 files changed, 52 insertions, 13 deletions
diff --git a/op.c b/op.c
index fdb509420b..b4a845e7b2 100644
--- a/op.c
+++ b/op.c
@@ -10945,6 +10945,7 @@ Perl_rpeep(pTHX_ register OP *o)
PADOFFSET base = 0; /* init only to stop compiler whining */
U8 gimme = 0; /* init only to stop compiler whining */
bool defav = 0; /* seen (...) = @_ */
+ bool reuse = 0; /* reuse an existing padrange op */
/* look for a pushmark -> gv[_] -> rv2av */
@@ -11077,10 +11078,12 @@ Perl_rpeep(pTHX_ register OP *o)
followop = followop->op_next; /* skip OP_LIST */
/* consolidate two successive my(...);'s */
+
if ( oldoldop
&& oldoldop->op_type == OP_PADRANGE
&& (oldoldop->op_flags & OPf_WANT) == OPf_WANT_VOID
&& (oldoldop->op_private & OPpLVAL_INTRO) == intro
+ && !(oldoldop->op_flags & OPf_SPECIAL)
) {
U8 old_count;
assert(oldoldop->op_next == oldop);
@@ -11093,26 +11096,62 @@ Perl_rpeep(pTHX_ register OP *o)
assert(oldoldop->op_targ + old_count == base);
if (old_count < OPpPADRANGE_COUNTMASK - count) {
- oldoldop->op_private = (intro | (old_count+count));
- oldoldop->op_next = followop;
- break;
+ base = oldoldop->op_targ;
+ count += old_count;
+ reuse = 1;
}
}
+
+ /* if there's any immediately following singleton
+ * my var's; then swallow them and the associated
+ * nextstates; i.e.
+ * my ($a,$b); my $c; my $d;
+ * is treated as
+ * my ($a,$b,$c,$d);
+ */
+
+ while ( ((p = followop->op_next))
+ && ( p->op_type == OP_PADSV
+ || p->op_type == OP_PADAV
+ || p->op_type == OP_PADHV)
+ && (p->op_flags & OPf_WANT) == OPf_WANT_VOID
+ && (p->op_private & OPpLVAL_INTRO) == intro
+ && p->op_next
+ && ( p->op_next->op_type == OP_NEXTSTATE
+ || p->op_next->op_type == OP_DBSTATE)
+ && count < OPpPADRANGE_COUNTMASK
+ ) {
+ assert(base + count == p->op_targ);
+ count++;
+ followop = p->op_next;
+ }
}
else
break;
}
- /* Convert the pushmark into a padrange */
- o->op_next = followop;
- o->op_type = OP_PADRANGE;
- o->op_ppaddr = PL_ppaddr[OP_PADRANGE];
- o->op_targ = base;
- /* bit 7: INTRO; bit 6..0: count */
- o->op_private = (intro | count);
- o->op_flags = ((o->op_flags & ~(OPf_WANT|OPf_SPECIAL))
- | gimme | (defav ? OPf_SPECIAL : 0));
-
+ if (reuse) {
+ assert(oldoldop->op_type == OP_PADRANGE);
+ oldoldop->op_next = followop;
+ oldoldop->op_private = (intro | count);
+ o = oldoldop;
+ oldop = NULL;
+ oldoldop = NULL;
+ }
+ else {
+ /* Convert the pushmark into a padrange.
+ * To make Deparse easier, we guarantee that a padrange was
+ * *always* formerly a pushmark */
+ assert(o->op_type == OP_PUSHMARK);
+ o->op_next = followop;
+ o->op_type = OP_PADRANGE;
+ o->op_ppaddr = PL_ppaddr[OP_PADRANGE];
+ o->op_targ = base;
+ /* bit 7: INTRO; bit 6..0: count */
+ o->op_private = (intro | count);
+ o->op_flags = ((o->op_flags & ~(OPf_WANT|OPf_SPECIAL))
+ | gimme | (defav ? OPf_SPECIAL : 0));
+ }
break;
}