mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-03 05:44:10 -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();
|
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,
|
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));
|
jumpToStart.setTarget(program.basicBlockAt(startBlock.getIndex() + 1));
|
||||||
startBlock.add(jumpToStart);
|
startBlock.add(jumpToStart);
|
||||||
|
|
||||||
new Optimizations().apply(program);
|
new Optimizations().apply(program, new MethodReference(cls.getName(), methodHolder.getDescriptor()));
|
||||||
cls.addMethod(methodHolder);
|
cls.addMethod(methodHolder);
|
||||||
} finally {
|
} finally {
|
||||||
returnType = returnTypeBackup;
|
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;
|
package org.teavm.metaprogramming.impl.optimization;
|
||||||
|
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.Program;
|
import org.teavm.model.Program;
|
||||||
|
|
||||||
public class Optimizations {
|
public class Optimizations {
|
||||||
private BoxingElimination boxingElimination = new BoxingElimination();
|
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);
|
boxingElimination.optimize(program);
|
||||||
|
arrayElimination.apply(program, methodReference);
|
||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user