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.

Reply via email to