getting the invocation syntax right was kind of tricky since my first thought,
which was that writing to $_[0] would overwrite the symtab entry for a
subroutine when the optimizer was invoked tr_optimize(\&function) turned
out to be incorrect -- it will work with globs though -- no support for
anonsubs or other alternate invocations although I'm leaving the name-based
invocation in below for your inspection.
There is obviously a lot of room for improvement especially in complex
return arguments -- I'm not sure how to do a match for balanced parentheses,
for instance, and sometimes Deparse terminates the return with a semicolon
and sometimes it doesn't.
Here's what I have just gotten working,
it does deep deep deep recursion with no stack size increase:
package Acme::TailRecursionOptimizer;
use Exporter; @EXPORT = qw/tr_optimize/;
use B::Deparse;
our $dp = B::Deparse->new(qw/ -P -q -x7/);
use Carp;
use constant DEBUG => 0;
=pod
invoke tr_optimize with a glob reference to an existing subroutine.
tr_optimize will replace the subroutine with a tail-recursive version
that clobbers @_ so shift everything out of @_ before returning
anything within your routine. complex return expressions will
probably break it at this time as the code filter is not very smart.
=cut
sub tr_optimize($){
# my $subroutine_name = shift;
# my $cp = caller();
# exists &{"$cp\::$subroutine_name"} or
# croak "arg must be function name in current package";
ref($_[0]) eq 'GLOB' or croak "arg must be glob ref, like \\*func";
my $sub_in = \&{$_[0]}; # don't shift, we're going to
# write back to $_[0]
# my $sub_in = \&{"$cp\::$subroutine_name"};
my $p = prototype($sub_in);
$p = (defined($p)? "($p)" : '');
my $deparsed = $dp->coderef2text($sub_in);
DEBUG and print "DEPARSED TO:\n$deparsed\n";
# explicitize implied return on final statement
# FIXME
# rewrite return calls as goto-sub calls
# the matching part of this could obviously be improved
$deparsed =~ s/\breturn\s+(\w+)([^;\n]*)/do{ [EMAIL PROTECTED]($2); goto
\&$1}/g;
DEBUG and print "REWROTE TO:\n$deparsed\n";
my $sub_out = eval "sub$p$deparsed";
$sub_out or die "eval: [EMAIL PROTECTED]";
DEBUG and print "EVALLED TO:\n", $dp->coderef2text($sub_out),"\n";
*{$_[0]} = $sub_out;
# *{"$cp\::$subroutine_name"} = $sub_out
};
1;
__END__
use Acme::TailRecursionOptimizer
use constant DEBUG=>1;
sub recursor2 { $x = shift; return recursor2(1+$x) if$x<21;$x };
sub recursor3 {
# print "args: @_\n";
$x = shift;
$x % 1000 or print "$x\n";
if($x < 21) {
return recursor3(1+$x+recursor2(20));
};$x
};
# tr_optimize('recursor2'); # this one could be made to work
# tr_optimize(\&recursor2); does not work as expected
# tr_optimize(*recursor2); nor this
DEBUG and print "BEFORE:\n", # ...
$Acme::TailRecursionOptimizer::dp->coderef2text(\&recursor2),"\n";
tr_optimize(\*recursor2); # this one works
DEBUG and print "AFTER:\n", $dp->coderef2text(\&recursor2),"\n";
DEBUG and print "BEFORE:\n", $dp->coderef2text(\&recursor3),"\n";
tr_optimize(\*recursor3);
DEBUG and print "AFTER:\n", $dp->coderef2text(\&recursor3),"\n";
print "Expect a return w/o OOM -- we're counting up from -100000\n";
print recursor2(-100000);
print "Expect a return w/o OOM -- we're counting up from -100000\n";
print recursor3(-100000);
--
Although efforts are under way to mitigate the problem, this message
may contain flippancy, hyperbole and/or confusing assertions. Please
reply directly to [EMAIL PROTECTED] for clarification of any points
appearing unclear, vague, cruel, frustrating, threatening, negative,
dilletantish or otherwise unprofessional before taking action based on
misintepretation or misconstruction of such points.