In perl.git, the branch smoke-me/davem/op_signature3 has been created
<http://perl5.git.perl.org/perl.git/commitdiff/710ddd120e1631b12a599b7683917539c927a15d?hp=0000000000000000000000000000000000000000>
at 710ddd120e1631b12a599b7683917539c927a15d (commit)
- Log -----------------------------------------------------------------
commit 710ddd120e1631b12a599b7683917539c927a15d
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 34b8ef89ea031e6d025248ddbeea2321f536ce60
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 e2f0970fbae115d09688dc05f8f5834ae6ac9a3e
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 6cceb1891207f86be05075d2c7b77d2c0790c3a4
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 14f63bdde15a544bddab14aca8d8e322907dcbce
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 makedef.pl
M op.c
M proto.h
-----------------------------------------------------------------------
--
Perl5 Master Repository