Skip to content

Commit 215ac4c

Browse files
committed
try to turn lexicals into locals.
1 parent 6de1913 commit 215ac4c

File tree

1 file changed

+106
-4
lines changed

1 file changed

+106
-4
lines changed

src/NQP/Optimizer.nqp

Lines changed: 106 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,103 @@
11
class NQP::Optimizer {
22
has @!block_stack;
3+
has @!local_var_stack;
34

45
method optimize($ast, *%adverbs) {
56
@!block_stack := [$ast[0]];
7+
@!local_var_stack := nqp::list();
68
self.visit_children($ast);
79
$ast;
810
}
911

1012
method visit_block($block) {
1113
@!block_stack.push($block);
14+
my %*shallow_var_usages := nqp::hash();
15+
@!local_var_stack.push(%*shallow_var_usages);
16+
17+
# Push all the lexically declared variables into our shallow vars hash.
18+
# Currently we limit ourselves to natives, because they are guaranteed
19+
# not to have some weird setup that we have to be careful about.
20+
if nqp::istype($block[0], QAST::Stmts) {
21+
my int $idx := 0;
22+
# before the $_ come the arguments. we must not turn these into locals,
23+
# otherwise our signature binding will explode.
24+
#say("THE BLOCK:::::::::::::::::::::::::::::::::::::::::::::::");
25+
#say($block.dump);
26+
#say(":::::::::::::::::::::::::::::::::::::::::::::::THE BLOCK");
27+
while $idx < +@($block[0]) {
28+
my $var := $block[0][$idx];
29+
if nqp::istype($var, QAST::Op) && $var.op eq 'bind' {
30+
# variables are initialised on the spot in nqp.
31+
$var := $var[0]
32+
}
33+
if nqp::istype($var, QAST::Var) && $var.scope eq 'lexical' && $var.decl eq 'var' {
34+
# also make sure we don't turn dynamic vars into locals
35+
my $twigil := nqp::substr($var.name, 1, 1);
36+
my $sigil := nqp::substr($var.name, 0, 1);
37+
if $sigil eq '$' && $twigil ne '*'
38+
&& $var.name ne '$_' && $var.name ne '$/' && $var.name ne '$!' && $var.name ne '' {
39+
%*shallow_var_usages{$var.name} := nqp::list($var);
40+
}
41+
} elsif nqp::istype($var, QAST::Op) && $var.op eq 'bind' {
42+
if nqp::existskey(%*shallow_var_usages, $var[0].name) {
43+
nqp::push(%*shallow_var_usages{$var[0].name}, $var[0]);
44+
}
45+
}
46+
$idx := $idx + 1;
47+
}
48+
}
1249

1350
self.visit_children($block);
1451

52+
my $succ;
53+
for %*shallow_var_usages {
54+
my $name := $_.key;
55+
my $newname := $block.unique('lex_to_loc_' ~ +@!block_stack);
56+
my @usages := $_.value;
57+
say("found " ~ +@usages ~ " usages for $name");
58+
for @usages -> $var {
59+
say($var.scope ~ ": " ~ $var.name ~ " <- old");
60+
$var.scope('local');
61+
$var.name($newname);
62+
#if $var.decl eq 'var' {
63+
#$var.decl('static');
64+
#}
65+
$succ := 1;
66+
}
67+
say("turned $name into a local ($newname), yippie");
68+
}
69+
if $succ {
70+
say($block.dump);
71+
}
72+
1573
@!block_stack.pop();
74+
@!local_var_stack.pop();
1675

1776
$block;
1877
}
1978

20-
method find_lex($name) {
79+
method lexical_depth($name) {
2180
my int $i := +@!block_stack;
2281
while $i > 0 {
2382
$i := $i - 1;
24-
my %sym := @!block_stack[$i].symbol($name);
83+
my $block := @!block_stack[$i];
84+
my %sym := $block.symbol($name);
2585
if +%sym {
26-
return %sym;
86+
return $i;
2787
}
2888
}
29-
NQPMu;
89+
-1
90+
}
91+
92+
method find_lex($name) {
93+
my int $d := self.lexical_depth($name);
94+
if $d >= 0 {
95+
my $block := @!block_stack[$d];
96+
my %sym := $block.symbol($name);
97+
return %sym;
98+
} else {
99+
nqp::hash();
100+
}
30101
}
31102

32103
method find_sym($name) {
@@ -39,6 +110,34 @@ class NQP::Optimizer {
39110
}
40111
}
41112

113+
method visit_var($var) {
114+
if $var.scope eq 'lexical' {
115+
my int $lexdepth := self.lexical_depth($var.name);
116+
my int $vardepth := +@!block_stack - 1 - $lexdepth;
117+
if $lexdepth != -1 {
118+
if $vardepth == 0 {
119+
if nqp::existskey(%*shallow_var_usages, $var.name) {
120+
say("found a usage for " ~ $var.name);
121+
nqp::push(%*shallow_var_usages{$var.name}, $var);
122+
}
123+
} else {
124+
say("poisoned " ~ $var.name);
125+
say("my local var stack is " ~ +@!local_var_stack ~ " deep, my lexdepth is $lexdepth");
126+
say(nqp::existskey(@!local_var_stack[$lexdepth-1], $var.name));
127+
try {
128+
nqp::deletekey(@!local_var_stack[$lexdepth-1], $var.name);
129+
}
130+
}
131+
}
132+
}
133+
134+
if nqp::istype($var, QAST::VarWithFallback) {
135+
self.visit_children($var);
136+
}
137+
138+
$var;
139+
}
140+
42141
method visit_op($op) {
43142
sub returns_int($node) {
44143
if nqp::objprimspec($node.returns) == 1 {
@@ -63,6 +162,7 @@ class NQP::Optimizer {
63162
}
64163
return 0;
65164
}
165+
66166
self.visit_children($op);
67167

68168
my $typeinfo := nqp::chars($op.op) >= 2
@@ -118,6 +218,8 @@ class NQP::Optimizer {
118218
$node[$i] := self.visit_op($visit)
119219
} elsif nqp::istype($visit, QAST::Block) {
120220
$node[$i] := self.visit_block($visit)
221+
} elsif nqp::istype($visit, QAST::Var) {
222+
$node[$i] := self.visit_var($visit);
121223
} elsif nqp::istype($visit, QAST::Want) {
122224
self.visit_children($visit, :skip_selectors)
123225
} else {

0 commit comments

Comments
 (0)