Skip to content

Commit

Permalink
Implement an optimization for private method calls. If possible, it r…
Browse files Browse the repository at this point in the history
…educes them to sub calls. Can also detect and complain about missing private method calls at CHECK time (since they're non-virtual). Requires --optimize=3.
  • Loading branch information
jnthn committed Nov 26, 2011
1 parent da4426a commit de3e8e7
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 1 deletion.
6 changes: 5 additions & 1 deletion src/Perl6/Actions.pm
Expand Up @@ -232,8 +232,10 @@ class Perl6::Actions is HLL::Actions {
$outer.unshift(PAST::Op.new(:inline(".annotate 'file', '" ~ $file ~ "'")));
}

$outer<UNIT> := $unit;
# Pass some extra bits along to the optimizer.
$outer<UNIT> := $unit;
$outer<GLOBALish> := $*GLOBALish;
$outer<ST> := $*ST;
make $outer;
}

Expand Down Expand Up @@ -2505,13 +2507,15 @@ class Perl6::Actions is HLL::Actions {
$methpkg.HOW.name($methpkg) ~ " because it does not trust " ~
$*PACKAGE.HOW.name($*PACKAGE));
}
$past[1].type($methpkg);
}
else {
unless pir::can($*PACKAGE.HOW, 'find_private_method') {
$/.CURSOR.panic("Private method call to '$name' must be fully " ~
"qualified with the package containing the method");
}
$past.unshift($*ST.get_object_sc_ref_past($*PACKAGE));
$past[0].type($*PACKAGE);
$past.unshift($*ST.add_string_constant($name));
}
$past.name('dispatch:<!>');
Expand Down
25 changes: 25 additions & 0 deletions src/Perl6/Optimizer.pm
Expand Up @@ -39,6 +39,7 @@ class Perl6::Optimizer {
# over OUTER since we don't walk loadinits).
my $unit := $past<UNIT>;
my $*GLOBALish := $past<GLOBALish>;
my $*ST := $past<ST>;
unless $unit.isa(PAST::Block) {
pir::die("Optimizer could not find UNIT");
}
Expand Down Expand Up @@ -200,6 +201,30 @@ class Perl6::Optimizer {
}
}

# If it's a private method call, we can sometimes resolve it at
# compile time. If so, we can reduce it to a sub call in some cases.
elsif $*LEVEL >= 3 && $op.pasttype eq 'callmethod' && $op.name eq 'dispatch:<!>' {
if $op[1]<has_compile_time_value> && $op[1]<boxable_native> == 3 {
my $name := $op[1][2]; # get raw string name
my $pkg := $op[2].type; # actions always sets this
my $meth := $pkg.HOW.find_private_method($pkg, $name);
if $meth {
try {
my $call := $*ST.get_object_sc_ref_past($meth); # may fail, thus the try
my $inv := $op.shift;
$op.shift; $op.shift; # name, package (both pre-resolved now)
$op.unshift($inv);
$op.unshift($call);
$op.pasttype('call');
$op.name(nqp::null());
}
}
else {
self.add_deadly($op, "Undefined private method '" ~ $name ~ "' called");
}
}
}

# If we end up here, just leave op as is.
if $op.pasttype eq 'chain' {
$!chain_depth := $!chain_depth - 1;
Expand Down

0 comments on commit de3e8e7

Please sign in to comment.