mirror of
https://github.com/konsoletyper/teavm.git
synced 2024-11-27 01:30:35 +08:00
Remove unnecessary arrays if possible after generating methods via metaprogramming API. Arrays are unnecessary if they are only indexed by constants and never escape method.
This commit is contained in:
parent
c6d4265f8b
commit
d654896833
@ -93,7 +93,7 @@ public class MetaprogrammingDependencyListener extends AbstractDependencyListene
|
||||
result.returnValue();
|
||||
}
|
||||
|
||||
agent.submitMethod(model.getMethod(), new Optimizations().apply(pe.getProgram()));
|
||||
agent.submitMethod(model.getMethod(), new Optimizations().apply(pe.getProgram(), model.getMethod()));
|
||||
}
|
||||
|
||||
private void emitMultipleUsage(MethodModel model, ProgramEmitter pe, DependencyAgent agent,
|
||||
@ -132,6 +132,6 @@ public class MetaprogrammingDependencyListener extends AbstractDependencyListene
|
||||
}
|
||||
});
|
||||
|
||||
agent.submitMethod(model.getMethod(), new Optimizations().apply(pe.getProgram()));
|
||||
agent.submitMethod(model.getMethod(), new Optimizations().apply(pe.getProgram(), model.getMethod()));
|
||||
}
|
||||
}
|
||||
|
@ -304,7 +304,7 @@ public final class MetaprogrammingImpl {
|
||||
jumpToStart.setTarget(program.basicBlockAt(startBlock.getIndex() + 1));
|
||||
startBlock.add(jumpToStart);
|
||||
|
||||
new Optimizations().apply(program);
|
||||
new Optimizations().apply(program, new MethodReference(cls.getName(), methodHolder.getDescriptor()));
|
||||
cls.addMethod(methodHolder);
|
||||
} finally {
|
||||
returnType = returnTypeBackup;
|
||||
|
@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright 2017 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.metaprogramming.impl.optimization;
|
||||
|
||||
import org.teavm.common.DisjointSet;
|
||||
import org.teavm.model.BasicBlock;
|
||||
import org.teavm.model.Incoming;
|
||||
import org.teavm.model.Instruction;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.Phi;
|
||||
import org.teavm.model.Program;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.Variable;
|
||||
import org.teavm.model.instructions.AssignInstruction;
|
||||
import org.teavm.model.instructions.ConstructArrayInstruction;
|
||||
import org.teavm.model.instructions.DoubleConstantInstruction;
|
||||
import org.teavm.model.instructions.FloatConstantInstruction;
|
||||
import org.teavm.model.instructions.GetElementInstruction;
|
||||
import org.teavm.model.instructions.IntegerConstantInstruction;
|
||||
import org.teavm.model.instructions.LongConstantInstruction;
|
||||
import org.teavm.model.instructions.NullConstantInstruction;
|
||||
import org.teavm.model.instructions.PutElementInstruction;
|
||||
import org.teavm.model.instructions.UnwrapArrayInstruction;
|
||||
import org.teavm.model.util.DefinitionExtractor;
|
||||
import org.teavm.model.util.PhiUpdater;
|
||||
import org.teavm.model.util.UsageExtractor;
|
||||
|
||||
public class ArrayElimination {
|
||||
private Program program;
|
||||
private int[] varClasses;
|
||||
private int[] constantValues;
|
||||
private boolean[] constants;
|
||||
private boolean[] unsafeArrays;
|
||||
private int[] arraySizes;
|
||||
private boolean hasModifications;
|
||||
|
||||
public void apply(Program program, MethodReference methodReference) {
|
||||
this.program = program;
|
||||
findVarClasses();
|
||||
findConstantVariables();
|
||||
findSafeArrays();
|
||||
removeSafeArrays();
|
||||
if (hasModifications) {
|
||||
Variable[] parameters = new Variable[methodReference.parameterCount() + 1];
|
||||
for (int i = 0; i < parameters.length; ++i) {
|
||||
parameters[i] = program.variableAt(i);
|
||||
}
|
||||
new PhiUpdater().updatePhis(program, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
private void findVarClasses() {
|
||||
DisjointSet varClasses = new DisjointSet();
|
||||
for (int i = 0; i < program.variableCount(); ++i) {
|
||||
varClasses.create();
|
||||
}
|
||||
for (BasicBlock block : program.getBasicBlocks()) {
|
||||
for (Instruction instruction : block) {
|
||||
int receiver;
|
||||
int assignee;
|
||||
if (instruction instanceof AssignInstruction) {
|
||||
AssignInstruction assign = (AssignInstruction) instruction;
|
||||
receiver = assign.getReceiver().getIndex();
|
||||
assignee = assign.getAssignee().getIndex();
|
||||
} else if (instruction instanceof UnwrapArrayInstruction) {
|
||||
UnwrapArrayInstruction unwrap = (UnwrapArrayInstruction) instruction;
|
||||
receiver = unwrap.getReceiver().getIndex();
|
||||
assignee = unwrap.getArray().getIndex();
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
varClasses.union(receiver, assignee);
|
||||
}
|
||||
}
|
||||
this.varClasses = varClasses.pack(program.variableCount());
|
||||
}
|
||||
|
||||
private void findConstantVariables() {
|
||||
int[] constantValuesByClasses = new int[program.variableCount()];
|
||||
boolean[] constantsByClasses = new boolean[program.variableCount()];
|
||||
for (BasicBlock block : program.getBasicBlocks()) {
|
||||
for (Instruction instruction : block) {
|
||||
if (instruction instanceof IntegerConstantInstruction) {
|
||||
IntegerConstantInstruction constant = (IntegerConstantInstruction) instruction;
|
||||
int receiver = varClasses[constant.getReceiver().getIndex()];
|
||||
constantsByClasses[receiver] = true;
|
||||
constantValuesByClasses[receiver] = constant.getConstant();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constantValues = new int[program.variableCount()];
|
||||
constants = new boolean[program.variableCount()];
|
||||
for (int i = 0; i < program.variableCount(); ++i) {
|
||||
constantValues[i] = constantValuesByClasses[varClasses[i]];
|
||||
constants[i] = constantsByClasses[varClasses[i]];
|
||||
}
|
||||
}
|
||||
|
||||
private void findSafeArrays() {
|
||||
boolean[] unsafeArraysByClasses = new boolean[program.variableCount()];
|
||||
int[] arraySizesByClasses = new int[program.variableCount()];
|
||||
|
||||
DefinitionExtractor defExtractor = new DefinitionExtractor();
|
||||
UsageExtractor useExtractor = new UsageExtractor();
|
||||
for (BasicBlock block : program.getBasicBlocks()) {
|
||||
for (Phi phi : block.getPhis()) {
|
||||
unsafeArraysByClasses[varClasses[phi.getReceiver().getIndex()]] = true;
|
||||
for (Incoming incoming : phi.getIncomings()) {
|
||||
unsafeArraysByClasses[varClasses[incoming.getValue().getIndex()]] = true;
|
||||
}
|
||||
}
|
||||
for (Instruction instruction : block) {
|
||||
if (instruction instanceof GetElementInstruction) {
|
||||
GetElementInstruction getElement = (GetElementInstruction) instruction;
|
||||
unsafeArraysByClasses[varClasses[getElement.getReceiver().getIndex()]] = true;
|
||||
} else if (instruction instanceof PutElementInstruction) {
|
||||
PutElementInstruction putElement = (PutElementInstruction) instruction;
|
||||
unsafeArraysByClasses[varClasses[putElement.getValue().getIndex()]] = true;
|
||||
if (!constants[putElement.getIndex().getIndex()]) {
|
||||
unsafeArraysByClasses[varClasses[putElement.getIndex().getIndex()]] = true;
|
||||
}
|
||||
} else if (instruction instanceof ConstructArrayInstruction) {
|
||||
ConstructArrayInstruction construct = (ConstructArrayInstruction) instruction;
|
||||
int receiver = varClasses[construct.getReceiver().getIndex()];
|
||||
if (!constants[construct.getSize().getIndex()]) {
|
||||
unsafeArraysByClasses[receiver] = true;
|
||||
} else {
|
||||
arraySizesByClasses[receiver] = constantValues[construct.getSize().getIndex()];
|
||||
}
|
||||
} else {
|
||||
if (instruction instanceof AssignInstruction || instruction instanceof UnwrapArrayInstruction) {
|
||||
continue;
|
||||
}
|
||||
instruction.acceptVisitor(defExtractor);
|
||||
instruction.acceptVisitor(useExtractor);
|
||||
for (Variable var : defExtractor.getDefinedVariables()) {
|
||||
unsafeArraysByClasses[varClasses[var.getIndex()]] = true;
|
||||
}
|
||||
for (Variable var : useExtractor.getUsedVariables()) {
|
||||
unsafeArraysByClasses[varClasses[var.getIndex()]] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafeArrays = new boolean[program.variableCount()];
|
||||
arraySizes = new int[program.variableCount()];
|
||||
for (int i = 0; i < program.variableCount(); ++i) {
|
||||
unsafeArrays[i] = unsafeArraysByClasses[varClasses[i]];
|
||||
arraySizes[i] = arraySizesByClasses[varClasses[i]];
|
||||
}
|
||||
}
|
||||
|
||||
private void removeSafeArrays() {
|
||||
int[][] arrayItemsAsVariablesByClass = new int[program.variableCount()][];
|
||||
for (int i = 0; i < arrayItemsAsVariablesByClass.length; ++i) {
|
||||
int varClass = varClasses[i];
|
||||
if (arrayItemsAsVariablesByClass[varClass] != null || unsafeArrays[i]) {
|
||||
continue;
|
||||
}
|
||||
int size = arraySizes[i];
|
||||
arrayItemsAsVariablesByClass[varClass] = new int[size];
|
||||
for (int j = 0; j < size; ++j) {
|
||||
arrayItemsAsVariablesByClass[varClass][j] = program.createVariable().getIndex();
|
||||
}
|
||||
}
|
||||
|
||||
int[][] arrayItemsAsVariables = new int[arrayItemsAsVariablesByClass.length][];
|
||||
for (int i = 0; i < arrayItemsAsVariables.length; ++i) {
|
||||
arrayItemsAsVariables[i] = arrayItemsAsVariablesByClass[varClasses[i]];
|
||||
}
|
||||
|
||||
for (BasicBlock block : program.getBasicBlocks()) {
|
||||
for (Instruction instruction : block) {
|
||||
if (instruction instanceof GetElementInstruction) {
|
||||
GetElementInstruction getElement = (GetElementInstruction) instruction;
|
||||
int array = getElement.getArray().getIndex();
|
||||
if (!unsafeArrays[array]) {
|
||||
int index = constantValues[getElement.getIndex().getIndex()];
|
||||
Variable var = program.variableAt(arrayItemsAsVariables[array][index]);
|
||||
AssignInstruction assign = new AssignInstruction();
|
||||
assign.setReceiver(getElement.getReceiver());
|
||||
assign.setAssignee(var);
|
||||
assign.setLocation(getElement.getLocation());
|
||||
getElement.replace(assign);
|
||||
hasModifications = true;
|
||||
}
|
||||
} else if (instruction instanceof PutElementInstruction) {
|
||||
PutElementInstruction putElement = (PutElementInstruction) instruction;
|
||||
int array = putElement.getArray().getIndex();
|
||||
if (!unsafeArrays[array]) {
|
||||
int index = constantValues[putElement.getIndex().getIndex()];
|
||||
Variable var = program.variableAt(arrayItemsAsVariables[array][index]);
|
||||
AssignInstruction assign = new AssignInstruction();
|
||||
assign.setReceiver(var);
|
||||
assign.setAssignee(putElement.getValue());
|
||||
assign.setLocation(putElement.getLocation());
|
||||
putElement.replace(assign);
|
||||
hasModifications = true;
|
||||
}
|
||||
} else if (instruction instanceof ConstructArrayInstruction) {
|
||||
ConstructArrayInstruction construct = (ConstructArrayInstruction) instruction;
|
||||
if (!unsafeArrays[construct.getReceiver().getIndex()]) {
|
||||
int[] vars = arrayItemsAsVariables[construct.getReceiver().getIndex()];
|
||||
for (int i = 0; i < vars.length; ++i) {
|
||||
Instruction constantInsn = createDefaultConstantInstruction(construct.getItemType(),
|
||||
program.variableAt(vars[i]));
|
||||
constantInsn.setLocation(construct.getLocation());
|
||||
construct.insertPrevious(constantInsn);
|
||||
}
|
||||
construct.delete();
|
||||
hasModifications = true;
|
||||
}
|
||||
} else if (instruction instanceof UnwrapArrayInstruction) {
|
||||
UnwrapArrayInstruction unwrap = (UnwrapArrayInstruction) instruction;
|
||||
if (!unsafeArrays[unwrap.getArray().getIndex()]) {
|
||||
unwrap.delete();
|
||||
hasModifications = true;
|
||||
}
|
||||
} else if (instruction instanceof AssignInstruction) {
|
||||
AssignInstruction assign = (AssignInstruction) instruction;
|
||||
if (!unsafeArrays[assign.getAssignee().getIndex()]) {
|
||||
assign.delete();
|
||||
hasModifications = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Instruction createDefaultConstantInstruction(ValueType valueType, Variable receiver) {
|
||||
if (valueType instanceof ValueType.Primitive) {
|
||||
switch (((ValueType.Primitive) valueType).getKind()) {
|
||||
case BOOLEAN:
|
||||
case CHARACTER:
|
||||
case BYTE:
|
||||
case SHORT:
|
||||
case INTEGER: {
|
||||
IntegerConstantInstruction result = new IntegerConstantInstruction();
|
||||
result.setReceiver(receiver);
|
||||
return result;
|
||||
}
|
||||
case LONG: {
|
||||
LongConstantInstruction result = new LongConstantInstruction();
|
||||
result.setReceiver(receiver);
|
||||
return result;
|
||||
}
|
||||
case FLOAT: {
|
||||
FloatConstantInstruction result = new FloatConstantInstruction();
|
||||
result.setReceiver(receiver);
|
||||
return result;
|
||||
}
|
||||
case DOUBLE: {
|
||||
DoubleConstantInstruction result = new DoubleConstantInstruction();
|
||||
result.setReceiver(receiver);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
NullConstantInstruction result = new NullConstantInstruction();
|
||||
result.setReceiver(receiver);
|
||||
return result;
|
||||
}
|
||||
}
|
@ -15,13 +15,16 @@
|
||||
*/
|
||||
package org.teavm.metaprogramming.impl.optimization;
|
||||
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.Program;
|
||||
|
||||
public class Optimizations {
|
||||
private BoxingElimination boxingElimination = new BoxingElimination();
|
||||
private ArrayElimination arrayElimination = new ArrayElimination();
|
||||
|
||||
public Program apply(Program program) {
|
||||
public Program apply(Program program, MethodReference methodReference) {
|
||||
boxingElimination.optimize(program);
|
||||
arrayElimination.apply(program, methodReference);
|
||||
return program;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user