in src/main/java/net/hydromatic/linq4j/expressions/BlockBuilder.java [316:424]
private boolean optimize(Visitor optimizer, boolean performInline) {
int optimizeCount = 0;
final UseCounter useCounter = new UseCounter();
for (Statement statement : statements) {
if (statement instanceof DeclarationStatement && performInline) {
DeclarationStatement decl = (DeclarationStatement) statement;
useCounter.map.put(decl.parameter, new Slot());
}
// We are added only counters up to current statement.
// It is fine to count usages as the latter declarations cannot be used
// in more recent statements.
if (!useCounter.map.isEmpty()) {
statement.accept(useCounter);
}
}
final Map<ParameterExpression, Expression> subMap =
new IdentityHashMap<ParameterExpression, Expression>(
useCounter.map.size());
final SubstituteVariableVisitor visitor = new SubstituteVariableVisitor(
subMap);
final ArrayList<Statement> oldStatements = new ArrayList<Statement>(
statements);
statements.clear();
for (Statement oldStatement : oldStatements) {
if (oldStatement instanceof DeclarationStatement) {
DeclarationStatement statement = (DeclarationStatement) oldStatement;
final Slot slot = useCounter.map.get(statement.parameter);
int count = slot == null ? Integer.MAX_VALUE - 10 : slot.count;
if (count > 1 && isSimpleExpression(statement.initializer)) {
// Inline simple final constants
count = 1;
}
if (!isSafeForReuse(statement)) {
// Don't inline variables that are not final. They might be assigned
// more than once.
count = 100;
}
if (statement.parameter.name.startsWith("_")) {
// Don't inline variables whose name begins with "_". This
// is a hacky way to prevent inlining. E.g.
// final int _count = collection.size();
// foo(collection);
// return collection.size() - _count;
count = Integer.MAX_VALUE;
}
if (statement.initializer instanceof NewExpression
&& ((NewExpression) statement.initializer).memberDeclarations
!= null) {
// Don't inline anonymous inner classes. Janino gets
// confused referencing variables from deeply nested
// anonymous classes.
count = Integer.MAX_VALUE;
}
Expression normalized = normalizeDeclaration(statement);
expressionForReuse.remove(normalized);
switch (count) {
case 0:
// Only declared, never used. Throw away declaration.
break;
case 1:
// declared, used once. inline it.
subMap.put(statement.parameter, normalized);
break;
default:
Statement beforeOptimize = oldStatement;
if (!subMap.isEmpty()) {
oldStatement = oldStatement.accept(visitor); // remap
}
oldStatement = oldStatement.accept(optimizer);
if (beforeOptimize != oldStatement) {
++optimizeCount;
if (count != Integer.MAX_VALUE
&& oldStatement instanceof DeclarationStatement
&& isSafeForReuse((DeclarationStatement) oldStatement)
&& isSimpleExpression(
((DeclarationStatement) oldStatement).initializer)) {
// Allow to inline the expression that became simple after
// optimizations.
DeclarationStatement newDecl =
(DeclarationStatement) oldStatement;
subMap.put(newDecl.parameter, normalizeDeclaration(newDecl));
oldStatement = OptimizeVisitor.EMPTY_STATEMENT;
}
}
if (oldStatement != OptimizeVisitor.EMPTY_STATEMENT) {
if (oldStatement instanceof DeclarationStatement) {
addExpressionForReuse((DeclarationStatement) oldStatement);
}
statements.add(oldStatement);
}
break;
}
} else {
Statement beforeOptimize = oldStatement;
if (!subMap.isEmpty()) {
oldStatement = oldStatement.accept(visitor); // remap
}
oldStatement = oldStatement.accept(optimizer);
if (beforeOptimize != oldStatement) {
++optimizeCount;
}
if (oldStatement != OptimizeVisitor.EMPTY_STATEMENT) {
statements.add(oldStatement);
}
}
}
return optimizeCount > 0;
}