In perl.git, the branch smoke-me/davem/op_signature2 has been created
<http://perl5.git.perl.org/perl.git/commitdiff/d42bc4dff263d04925cbdff92f63dbc7776dad05?hp=0000000000000000000000000000000000000000>
at d42bc4dff263d04925cbdff92f63dbc7776dad05 (commit)
- Log -----------------------------------------------------------------
commit d42bc4dff263d04925cbdff92f63dbc7776dad05
Author: David Mitchell <[email protected]>
Date: Mon Feb 16 17:32:45 2015 +0000
make my(...)=@_ use OP_SIGNATURE
This isn't yet enabled by default: it requires perl to be built with
PERL_FAKE_SIGNATURE defined.
Where the first statement in a function is a simple
my (....) = @_;
with the my elements being any mixture of scalars or undefs, with an
optional final array or hash, then convert that subtree of ops into
a single OP_SIGNATURE op, which will be faster.
The op will have the OPpSIGNATURE_FAKE private flag set, to distinguish
it from real signatured subs.
M ext/B/t/optree_misc.t
M lib/B/Deparse.pm
M lib/B/Deparse.t
M lib/B/Op_private.pm
M op.c
M opcode.h
M pp_hot.c
M regen/op_private
M t/op/sub.t
M t/perf/opcount.t
commit 7e653df572dec1d0fa3b6114d4c08e1a9f49e654
Author: David Mitchell <[email protected]>
Date: Mon Feb 16 13:51:14 2015 +0000
add Perl_prefinalize_optree()
this is a top-down optree function like Perl_finalize_optree,
but is called before peep(), so allows you to do stuff to the
optree before its been optimised.
M embed.fnc
M embed.h
M op.c
M proto.h
commit e874c8071d5fdb28280eef2b432f88078fefd773
Author: David Mitchell <[email protected]>
Date: Mon Feb 16 12:50:35 2015 +0000
add S_postprocess_optree() to op.c
Collect several of the common steps in finishing off an optree
into a single sub (e.g. setting refcount on the root op, calling peep,
etc).
M op.c
commit c122830401fd72093e19a18a87f081cad50c46cf
Author: David Mitchell <[email protected]>
Date: Tue Jan 20 17:45:55 2015 +0000
add OP_SIGNATURE
In the current (experimental) subroutine signatures implementation, the
checking for sufficient numbers of args, the introduction of lexical vars,
and the assignment of @_ and/or default values to them, is done by placing
lots of individual perl ops at the start of the function body.
For example, this:
sub f ($a, $b = 0, $c = "foo") {};
deparses as:
sub f {
die sprintf("Too many arguments for subroutine at %s line %d.\n",
(calle
r)[1, 2]) unless @_ <= 3;
die sprintf("Too few arguments for subroutine at %s line %d.\n",
(caller
)[1, 2]) unless @_ >= 1;
my $a = $_[0];
my $b = @_ >= 2 ? $_[1] : 0;
my $c = @_ >= 3 ? $_[2] : 'foo';
();
}
which is of course *very* slow.
This commit adds a new op, OP_SIGNATURE, of type UNOP_AUX, which handles
most of this work in a single op. It's inspired by my OP_MULTIDEREF work,
where 'simple' indices and keys (integers, consts, simple lex and package
vars) were handled directly by the op using values and pointers stored in
the op_aux array. For OP_SIGNATURE, simple default args (ints, consts, and
sometimes lexicals and package vars) are stored in the op_aux struct,
while more complex expressions are compiled as assign statements following
the OP_SIGNATURE op. For example:
sub f ($a, $b = 0, $c = "foo", $d = $c+1) {};
now gives
$ ./perl -Ilib -MO=Concise,f,-exec /tmp/signatures.t
main::f:
1 <;> nextstate(main 78 p:6) v:%,469762048
2 <+> signature($a, $b=0, $c="foo", $d=<expr>) v
3 <;> nextstate(main 81 p:6) v:%,469762048
4 <0> padsv[$c:80,82] s
5 <$> const[IV 1] s
6 <2> add[$d:81,82] sK/TARGMY,2
7 <;> nextstate(main 82 p:6) :%,469762048
8 <1> leavesub[1 ref] K/REFC,1
The performance is impressive, with a simple
sub f($a, $b, $c) {}
now being typically faster than
sub { my ($a, $b, $c) = @_; }
and signatured subs being typically twice as fast to call as they were
before.
As well as benefiting from doing nearly all the work in a single op,
the fact that it is the first op in the function allows some fairly
aggressive optimisations. In particular we know that newly introduced
lexicals will always be undef and non-magical, unlike for example:
f();
my $x; # $x not undef here!
sub f { $x = 1 }
Also, it is likely that subs are always called with a particular arg being
always the same type; for example, methods will always pass a ref as arg
1. Given the fact that at end of scope, lexical vars with a ref count of 1
are simply cleared in place, then in this case, by the time of the second
call, the lexical var $self in
sub f($self, ...) {...}
is likely to be a !SvOK SV with a body of type SVt_IV (already suitable
for holding an int or RV). If OP_SIGNATURE sees that the passed arg is
SvROK, it checks whether the lexical is of type SVt_IV, and if so just
directly does
SvRV_set(...);
SvROK_on(...)
rather than calling sv_setsv(). A similar short-cut is performed for
SvIOK values.
Default values of 0 and 1 are special-cased with their own action, so
no extra data needs storing in the op_aux array. Other integer-valued
constant defaults are stored as an IV in op_aux. More general constants
are stored as an SV pointer (or pad offset for threaded builds) in op_aux.
Default values that are simple lexicals or package vars, such as
sub f ($a, $b = $a, $c = $::Foo)
are usually stored as a pad index or GV pointer in the op_aux array.
There is a complication here in that more complex defaults are stored as
ops that get executed *after* OP_SIGNATURE, which means that default arg
processing can get re-ordered. For example,
sub f ($a, $b = $a++, $c = $a) {}
might get executed as the equivalent of
# happens within OP_SIGNATURE:
$a = $_[0];
$b = $_[1];
$c = $_[2] // $a;
# delayed: happens afterwards
$b //= $a++;
since the '$a' default is handled directly by OP_SIGNATURE, while '$a++'
is postponed. Clearly in this case this would be wrong, so the '$a'
default is in fact handled outside the OP_SIGNATURE too in cases like
this, leading to correct execution roughly like:
# happens within OP_SIGNATURE:
$a = $_[0];
$b = $_[1];
$c = $_[2];
# happens afterwards
$b //= $a++;
$c //= $a
This commit also makes signatured subs deparse correctly for the first
time, and also makes t/op/signature.t pass under TEST -deparse.
Note that this commit introduces a hard limit of 32767 parameters for any
signature sub, but I can't conceive of that being an issue.
M Porting/deparse-skips.txt
M cv.h
M dump.c
M embed.fnc
M embed.h
M ext/B/B.pm
M ext/B/B.xs
M ext/Devel-Peek/t/Peek.t
M ext/Opcode/Opcode.pm
M lib/B/Deparse.pm
M lib/B/Deparse.t
M lib/B/Op_private.pm
M op.c
M op.h
M opcode.h
M opnames.h
M perly.act
M perly.h
M perly.tab
M perly.y
M pod/perldiag.pod
M pp_hot.c
M pp_proto.h
M proto.h
M regen/opcodes
M sv.c
M t/lib/warnings/9uninit
M t/op/signatures.t
M t/op/svleak.t
M t/op/taint.t
M t/perf/benchmarks
M t/perf/opcount.t
M toke.c
commit 8f883c82c6d3eeb9b9ee1fe8b3012e072a04b005
Author: David Mitchell <[email protected]>
Date: Fri Jan 30 23:26:23 2015 +0000
make S_op_relocate_sv() non-static
This function will shortly need to be accessed from toke.c as well
as op.c, so make it global but non-public. Also, stop it being an
inlinable function - it's only used during compilation and isn't
performance-critical, and is not small.
M embed.fnc
M embed.h
M op.c
M proto.h
-----------------------------------------------------------------------
--
Perl5 Master Repository