Implementing loop inversion

This commit is contained in:
Alexey Andreev 2016-05-07 17:36:38 +03:00
parent eb3558cb1a
commit a57be365b4
9 changed files with 964 additions and 455 deletions

View File

@ -29,4 +29,16 @@ public interface DominatorTree {
int immediateDominatorOf(int a);
int levelOf(int a);
default int commonDominatorOf(int[] nodes) {
if (nodes.length == 0) {
return -1;
}
int result = nodes[0];
for (int i = 1; i < nodes.length; ++i) {
result = commonDominatorOf(result, nodes[i]);
}
return result;
}
}

View File

@ -252,4 +252,14 @@ public final class GraphUtils {
}
return set;
}
public static Graph invert(Graph graph) {
GraphBuilder graphBuilder = new GraphBuilder(graph.size());
for (int node = 0; node < graph.size(); ++node) {
for (int pred : graph.incomingEdges(node)) {
graphBuilder.addEdge(node, pred);
}
}
return graphBuilder.build();
}
}

View File

@ -608,6 +608,9 @@ class StatementGenerator implements InstructionVisitor {
return null;
}
Decompiler.Block block = blockMap[target.getIndex()];
if (block == null) {
throw new IllegalStateException("Could not find block for basic block $" + target.getIndex());
}
if (target.getIndex() == indexer.nodeAt(block.end)) {
BreakStatement breakStmt = new BreakStatement();
breakStmt.setLocation(currentLocation);

View File

@ -0,0 +1,482 @@
/*
* Copyright 2016 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.model.util;
import java.util.List;
import java.util.stream.Collectors;
import org.teavm.model.BasicBlock;
import org.teavm.model.BasicBlockReader;
import org.teavm.model.FieldReference;
import org.teavm.model.Instruction;
import org.teavm.model.InstructionLocation;
import org.teavm.model.InvokeDynamicInstruction;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodHandle;
import org.teavm.model.MethodReference;
import org.teavm.model.Program;
import org.teavm.model.RuntimeConstant;
import org.teavm.model.ValueType;
import org.teavm.model.Variable;
import org.teavm.model.VariableReader;
import org.teavm.model.instructions.ArrayElementType;
import org.teavm.model.instructions.ArrayLengthInstruction;
import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.BinaryBranchingCondition;
import org.teavm.model.instructions.BinaryBranchingInstruction;
import org.teavm.model.instructions.BinaryInstruction;
import org.teavm.model.instructions.BinaryOperation;
import org.teavm.model.instructions.BranchingCondition;
import org.teavm.model.instructions.BranchingInstruction;
import org.teavm.model.instructions.CastInstruction;
import org.teavm.model.instructions.CastIntegerDirection;
import org.teavm.model.instructions.CastIntegerInstruction;
import org.teavm.model.instructions.CastNumberInstruction;
import org.teavm.model.instructions.ClassConstantInstruction;
import org.teavm.model.instructions.CloneArrayInstruction;
import org.teavm.model.instructions.ConstructArrayInstruction;
import org.teavm.model.instructions.ConstructInstruction;
import org.teavm.model.instructions.ConstructMultiArrayInstruction;
import org.teavm.model.instructions.DoubleConstantInstruction;
import org.teavm.model.instructions.EmptyInstruction;
import org.teavm.model.instructions.ExitInstruction;
import org.teavm.model.instructions.FloatConstantInstruction;
import org.teavm.model.instructions.GetElementInstruction;
import org.teavm.model.instructions.GetFieldInstruction;
import org.teavm.model.instructions.InitClassInstruction;
import org.teavm.model.instructions.InstructionReader;
import org.teavm.model.instructions.IntegerConstantInstruction;
import org.teavm.model.instructions.IntegerSubtype;
import org.teavm.model.instructions.InvocationType;
import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.instructions.IsInstanceInstruction;
import org.teavm.model.instructions.JumpInstruction;
import org.teavm.model.instructions.LongConstantInstruction;
import org.teavm.model.instructions.MonitorEnterInstruction;
import org.teavm.model.instructions.MonitorExitInstruction;
import org.teavm.model.instructions.NegateInstruction;
import org.teavm.model.instructions.NullCheckInstruction;
import org.teavm.model.instructions.NullConstantInstruction;
import org.teavm.model.instructions.NumericOperandType;
import org.teavm.model.instructions.PutElementInstruction;
import org.teavm.model.instructions.PutFieldInstruction;
import org.teavm.model.instructions.RaiseInstruction;
import org.teavm.model.instructions.StringConstantInstruction;
import org.teavm.model.instructions.SwitchInstruction;
import org.teavm.model.instructions.SwitchTableEntry;
import org.teavm.model.instructions.SwitchTableEntryReader;
import org.teavm.model.instructions.UnwrapArrayInstruction;
public class InstructionCopyReader implements InstructionReader {
private Instruction copy;
private Program programCopy;
private InstructionLocation location;
public InstructionCopyReader(Program programCopy) {
this.programCopy = programCopy;
}
public Instruction getCopy() {
return copy;
}
public void resetLocation() {
location = null;
}
@Override
public void location(InstructionLocation location) {
this.location = location;
}
private Variable copyVar(VariableReader var) {
if (var == null) {
throw new NullPointerException();
}
return programCopy.variableAt(var.getIndex());
}
private BasicBlock copyBlock(BasicBlockReader block) {
return programCopy.basicBlockAt(block.getIndex());
}
@Override
public void nop() {
copy = new EmptyInstruction();
copy.setLocation(location);
}
@Override
public void classConstant(VariableReader receiver, ValueType cst) {
ClassConstantInstruction insnCopy = new ClassConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void nullConstant(VariableReader receiver) {
NullConstantInstruction insnCopy = new NullConstantInstruction();
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void integerConstant(VariableReader receiver, int cst) {
IntegerConstantInstruction insnCopy = new IntegerConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void longConstant(VariableReader receiver, long cst) {
LongConstantInstruction insnCopy = new LongConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void floatConstant(VariableReader receiver, float cst) {
FloatConstantInstruction insnCopy = new FloatConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void doubleConstant(VariableReader receiver, double cst) {
DoubleConstantInstruction insnCopy = new DoubleConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void stringConstant(VariableReader receiver, String cst) {
StringConstantInstruction insnCopy = new StringConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void binary(BinaryOperation op, VariableReader receiver, VariableReader first, VariableReader second,
NumericOperandType type) {
BinaryInstruction insnCopy = new BinaryInstruction(op, type);
insnCopy.setFirstOperand(copyVar(first));
insnCopy.setSecondOperand(copyVar(second));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void negate(VariableReader receiver, VariableReader operand, NumericOperandType type) {
NegateInstruction insnCopy = new NegateInstruction(type);
insnCopy.setOperand(copyVar(operand));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void assign(VariableReader receiver, VariableReader assignee) {
AssignInstruction insnCopy = new AssignInstruction();
insnCopy.setAssignee(copyVar(assignee));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
CastInstruction insnCopy = new CastInstruction();
insnCopy.setValue(copyVar(value));
insnCopy.setReceiver(copyVar(receiver));
insnCopy.setTargetType(targetType);
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void cast(VariableReader receiver, VariableReader value, NumericOperandType sourceType,
NumericOperandType targetType) {
CastNumberInstruction insnCopy = new CastNumberInstruction(sourceType, targetType);
insnCopy.setValue(copyVar(value));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void cast(VariableReader receiver, VariableReader value, IntegerSubtype type,
CastIntegerDirection dir) {
CastIntegerInstruction insnCopy = new CastIntegerInstruction(type, dir);
insnCopy.setValue(copyVar(value));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void jumpIf(BranchingCondition cond, VariableReader operand, BasicBlockReader consequent,
BasicBlockReader alternative) {
BranchingInstruction insnCopy = new BranchingInstruction(cond);
insnCopy.setOperand(copyVar(operand));
insnCopy.setConsequent(copyBlock(consequent));
insnCopy.setAlternative(copyBlock(alternative));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void jumpIf(BinaryBranchingCondition cond, VariableReader first, VariableReader second,
BasicBlockReader consequent, BasicBlockReader alternative) {
BinaryBranchingInstruction insnCopy = new BinaryBranchingInstruction(cond);
insnCopy.setFirstOperand(copyVar(first));
insnCopy.setSecondOperand(copyVar(second));
insnCopy.setConsequent(copyBlock(consequent));
insnCopy.setAlternative(copyBlock(alternative));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void jump(BasicBlockReader target) {
JumpInstruction insnCopy = new JumpInstruction();
insnCopy.setTarget(copyBlock(target));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void choose(VariableReader condition, List<? extends SwitchTableEntryReader> table,
BasicBlockReader defaultTarget) {
SwitchInstruction insnCopy = new SwitchInstruction();
insnCopy.setCondition(copyVar(condition));
insnCopy.setDefaultTarget(copyBlock(defaultTarget));
for (SwitchTableEntryReader entry : table) {
SwitchTableEntry entryCopy = new SwitchTableEntry();
entryCopy.setCondition(entry.getCondition());
entryCopy.setTarget(copyBlock(entry.getTarget()));
insnCopy.getEntries().add(entryCopy);
}
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void exit(VariableReader valueToReturn) {
ExitInstruction insnCopy = new ExitInstruction();
insnCopy.setValueToReturn(valueToReturn != null ? copyVar(valueToReturn) : null);
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void raise(VariableReader exception) {
RaiseInstruction insnCopy = new RaiseInstruction();
insnCopy.setException(copyVar(exception));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
ConstructArrayInstruction insnCopy = new ConstructArrayInstruction();
insnCopy.setItemType(itemType);
insnCopy.setSize(copyVar(size));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void createArray(VariableReader receiver, ValueType itemType,
List<? extends VariableReader> dimensions) {
ConstructMultiArrayInstruction insnCopy = new ConstructMultiArrayInstruction();
insnCopy.setItemType(itemType);
insnCopy.setReceiver(copyVar(receiver));
for (VariableReader dim : dimensions) {
insnCopy.getDimensions().add(copyVar(dim));
}
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void create(VariableReader receiver, String type) {
ConstructInstruction insnCopy = new ConstructInstruction();
insnCopy.setType(type);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void getField(VariableReader receiver, VariableReader instance, FieldReference field,
ValueType fieldType) {
GetFieldInstruction insnCopy = new GetFieldInstruction();
insnCopy.setField(field);
insnCopy.setFieldType(fieldType);
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void putField(VariableReader instance, FieldReference field, VariableReader value,
ValueType fieldType) {
PutFieldInstruction insnCopy = new PutFieldInstruction();
insnCopy.setField(field);
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
insnCopy.setValue(copyVar(value));
insnCopy.setFieldType(fieldType);
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void arrayLength(VariableReader receiver, VariableReader array) {
ArrayLengthInstruction insnCopy = new ArrayLengthInstruction();
insnCopy.setArray(copyVar(array));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void cloneArray(VariableReader receiver, VariableReader array) {
CloneArrayInstruction insnCopy = new CloneArrayInstruction();
insnCopy.setArray(copyVar(array));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) {
UnwrapArrayInstruction insnCopy = new UnwrapArrayInstruction(elementType);
insnCopy.setArray(copyVar(array));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void getElement(VariableReader receiver, VariableReader array, VariableReader index) {
GetElementInstruction insnCopy = new GetElementInstruction();
insnCopy.setArray(copyVar(array));
insnCopy.setReceiver(copyVar(receiver));
insnCopy.setIndex(copyVar(index));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void putElement(VariableReader array, VariableReader index, VariableReader value) {
PutElementInstruction insnCopy = new PutElementInstruction();
insnCopy.setArray(copyVar(array));
insnCopy.setValue(copyVar(value));
insnCopy.setIndex(copyVar(index));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
List<? extends VariableReader> arguments, InvocationType type) {
InvokeInstruction insnCopy = new InvokeInstruction();
insnCopy.setMethod(method);
insnCopy.setType(type);
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
insnCopy.setReceiver(receiver != null ? copyVar(receiver) : null);
for (VariableReader arg : arguments) {
insnCopy.getArguments().add(copyVar(arg));
}
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void invokeDynamic(VariableReader receiver, VariableReader instance, MethodDescriptor method,
List<? extends VariableReader> arguments, MethodHandle bootstrapMethod,
List<RuntimeConstant> bootstrapArguments) {
InvokeDynamicInstruction insnCopy = new InvokeDynamicInstruction();
insnCopy.setMethod(method);
insnCopy.setBootstrapMethod(bootstrapMethod);
insnCopy.getBootstrapArguments().addAll(bootstrapArguments);
if (instance != null) {
insnCopy.setInstance(copyVar(instance));
}
insnCopy.getArguments().addAll(arguments.stream().map(this::copyVar).collect(Collectors.toList()));
insnCopy.setReceiver(receiver != null ? copyVar(receiver) : null);
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void isInstance(VariableReader receiver, VariableReader value, ValueType type) {
IsInstanceInstruction insnCopy = new IsInstanceInstruction();
insnCopy.setValue(copyVar(value));
insnCopy.setReceiver(copyVar(receiver));
insnCopy.setType(type);
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void initClass(String className) {
InitClassInstruction insnCopy = new InitClassInstruction();
insnCopy.setClassName(className);
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void nullCheck(VariableReader receiver, VariableReader value) {
NullCheckInstruction insnCopy = new NullCheckInstruction();
insnCopy.setReceiver(copyVar(receiver));
insnCopy.setValue(copyVar(value));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void monitorEnter(VariableReader objectRef) {
MonitorEnterInstruction insnCopy = new MonitorEnterInstruction();
insnCopy.setObjectRef(copyVar(objectRef));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void monitorExit(VariableReader objectRef) {
MonitorExitInstruction insnCopy = new MonitorExitInstruction();
insnCopy.setObjectRef(copyVar(objectRef));
copy = insnCopy;
copy.setLocation(location);
}
}

View File

@ -15,17 +15,25 @@
*/
package org.teavm.model.util;
import java.util.*;
import java.util.stream.Collectors;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.teavm.common.Graph;
import org.teavm.common.GraphBuilder;
import org.teavm.model.*;
import org.teavm.model.instructions.*;
import org.teavm.model.BasicBlock;
import org.teavm.model.BasicBlockReader;
import org.teavm.model.Incoming;
import org.teavm.model.IncomingReader;
import org.teavm.model.Instruction;
import org.teavm.model.InstructionLocation;
import org.teavm.model.Phi;
import org.teavm.model.PhiReader;
import org.teavm.model.Program;
import org.teavm.model.ProgramReader;
import org.teavm.model.TryCatchBlock;
import org.teavm.model.TryCatchBlockReader;
import org.teavm.model.Variable;
/**
*
* @author Alexey Andreev
*/
public final class ProgramUtils {
private ProgramUtils() {
}
@ -81,8 +89,6 @@ public final class ProgramUtils {
public static Program copy(ProgramReader program) {
Program copy = new Program();
InstructionCopyReader insnCopier = new InstructionCopyReader();
insnCopier.programCopy = copy;
for (int i = 0; i < program.variableCount(); ++i) {
Variable var = copy.createVariable();
var.getDebugNames().addAll(program.variableAt(i).readDebugNames());
@ -108,12 +114,10 @@ public final class ProgramUtils {
public static List<Instruction> copyInstructions(BasicBlockReader block, int from, int to, Program target) {
List<Instruction> result = new ArrayList<>();
InstructionCopyReader copyReader = new InstructionCopyReader();
copyReader.programCopy = target;
InstructionCopyReader copyReader = new InstructionCopyReader(target);
for (int i = from; i < to; ++i) {
block.readInstruction(i, copyReader);
copyReader.copy.setLocation(copyReader.location);
result.add(copyReader.copy);
result.add(copyReader.getCopy());
}
return result;
}
@ -145,394 +149,4 @@ public final class ProgramUtils {
}
return result;
}
private static class InstructionCopyReader implements InstructionReader {
Instruction copy;
Program programCopy;
InstructionLocation location;
@Override
public void location(InstructionLocation location) {
this.location = location;
}
private Variable copyVar(VariableReader var) {
if (var == null) {
throw new NullPointerException();
}
return programCopy.variableAt(var.getIndex());
}
private BasicBlock copyBlock(BasicBlockReader block) {
return programCopy.basicBlockAt(block.getIndex());
}
@Override
public void nop() {
copy = new EmptyInstruction();
copy.setLocation(location);
}
@Override
public void classConstant(VariableReader receiver, ValueType cst) {
ClassConstantInstruction insnCopy = new ClassConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void nullConstant(VariableReader receiver) {
NullConstantInstruction insnCopy = new NullConstantInstruction();
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void integerConstant(VariableReader receiver, int cst) {
IntegerConstantInstruction insnCopy = new IntegerConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void longConstant(VariableReader receiver, long cst) {
LongConstantInstruction insnCopy = new LongConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void floatConstant(VariableReader receiver, float cst) {
FloatConstantInstruction insnCopy = new FloatConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void doubleConstant(VariableReader receiver, double cst) {
DoubleConstantInstruction insnCopy = new DoubleConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void stringConstant(VariableReader receiver, String cst) {
StringConstantInstruction insnCopy = new StringConstantInstruction();
insnCopy.setConstant(cst);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void binary(BinaryOperation op, VariableReader receiver, VariableReader first, VariableReader second,
NumericOperandType type) {
BinaryInstruction insnCopy = new BinaryInstruction(op, type);
insnCopy.setFirstOperand(copyVar(first));
insnCopy.setSecondOperand(copyVar(second));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void negate(VariableReader receiver, VariableReader operand, NumericOperandType type) {
NegateInstruction insnCopy = new NegateInstruction(type);
insnCopy.setOperand(copyVar(operand));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void assign(VariableReader receiver, VariableReader assignee) {
AssignInstruction insnCopy = new AssignInstruction();
insnCopy.setAssignee(copyVar(assignee));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
CastInstruction insnCopy = new CastInstruction();
insnCopy.setValue(copyVar(value));
insnCopy.setReceiver(copyVar(receiver));
insnCopy.setTargetType(targetType);
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void cast(VariableReader receiver, VariableReader value, NumericOperandType sourceType,
NumericOperandType targetType) {
CastNumberInstruction insnCopy = new CastNumberInstruction(sourceType, targetType);
insnCopy.setValue(copyVar(value));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void cast(VariableReader receiver, VariableReader value, IntegerSubtype type,
CastIntegerDirection dir) {
CastIntegerInstruction insnCopy = new CastIntegerInstruction(type, dir);
insnCopy.setValue(copyVar(value));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void jumpIf(BranchingCondition cond, VariableReader operand, BasicBlockReader consequent,
BasicBlockReader alternative) {
BranchingInstruction insnCopy = new BranchingInstruction(cond);
insnCopy.setOperand(copyVar(operand));
insnCopy.setConsequent(copyBlock(consequent));
insnCopy.setAlternative(copyBlock(alternative));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void jumpIf(BinaryBranchingCondition cond, VariableReader first, VariableReader second,
BasicBlockReader consequent, BasicBlockReader alternative) {
BinaryBranchingInstruction insnCopy = new BinaryBranchingInstruction(cond);
insnCopy.setFirstOperand(copyVar(first));
insnCopy.setSecondOperand(copyVar(second));
insnCopy.setConsequent(copyBlock(consequent));
insnCopy.setAlternative(copyBlock(alternative));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void jump(BasicBlockReader target) {
JumpInstruction insnCopy = new JumpInstruction();
insnCopy.setTarget(copyBlock(target));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void choose(VariableReader condition, List<? extends SwitchTableEntryReader> table,
BasicBlockReader defaultTarget) {
SwitchInstruction insnCopy = new SwitchInstruction();
insnCopy.setCondition(copyVar(condition));
insnCopy.setDefaultTarget(copyBlock(defaultTarget));
for (SwitchTableEntryReader entry : table) {
SwitchTableEntry entryCopy = new SwitchTableEntry();
entryCopy.setCondition(entry.getCondition());
entryCopy.setTarget(copyBlock(entry.getTarget()));
insnCopy.getEntries().add(entryCopy);
}
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void exit(VariableReader valueToReturn) {
ExitInstruction insnCopy = new ExitInstruction();
insnCopy.setValueToReturn(valueToReturn != null ? copyVar(valueToReturn) : null);
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void raise(VariableReader exception) {
RaiseInstruction insnCopy = new RaiseInstruction();
insnCopy.setException(copyVar(exception));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
ConstructArrayInstruction insnCopy = new ConstructArrayInstruction();
insnCopy.setItemType(itemType);
insnCopy.setSize(copyVar(size));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void createArray(VariableReader receiver, ValueType itemType,
List<? extends VariableReader> dimensions) {
ConstructMultiArrayInstruction insnCopy = new ConstructMultiArrayInstruction();
insnCopy.setItemType(itemType);
insnCopy.setReceiver(copyVar(receiver));
for (VariableReader dim : dimensions) {
insnCopy.getDimensions().add(copyVar(dim));
}
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void create(VariableReader receiver, String type) {
ConstructInstruction insnCopy = new ConstructInstruction();
insnCopy.setType(type);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void getField(VariableReader receiver, VariableReader instance, FieldReference field,
ValueType fieldType) {
GetFieldInstruction insnCopy = new GetFieldInstruction();
insnCopy.setField(field);
insnCopy.setFieldType(fieldType);
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void putField(VariableReader instance, FieldReference field, VariableReader value,
ValueType fieldType) {
PutFieldInstruction insnCopy = new PutFieldInstruction();
insnCopy.setField(field);
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
insnCopy.setValue(copyVar(value));
insnCopy.setFieldType(fieldType);
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void arrayLength(VariableReader receiver, VariableReader array) {
ArrayLengthInstruction insnCopy = new ArrayLengthInstruction();
insnCopy.setArray(copyVar(array));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void cloneArray(VariableReader receiver, VariableReader array) {
CloneArrayInstruction insnCopy = new CloneArrayInstruction();
insnCopy.setArray(copyVar(array));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) {
UnwrapArrayInstruction insnCopy = new UnwrapArrayInstruction(elementType);
insnCopy.setArray(copyVar(array));
insnCopy.setReceiver(copyVar(receiver));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void getElement(VariableReader receiver, VariableReader array, VariableReader index) {
GetElementInstruction insnCopy = new GetElementInstruction();
insnCopy.setArray(copyVar(array));
insnCopy.setReceiver(copyVar(receiver));
insnCopy.setIndex(copyVar(index));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void putElement(VariableReader array, VariableReader index, VariableReader value) {
PutElementInstruction insnCopy = new PutElementInstruction();
insnCopy.setArray(copyVar(array));
insnCopy.setValue(copyVar(value));
insnCopy.setIndex(copyVar(index));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
List<? extends VariableReader> arguments, InvocationType type) {
InvokeInstruction insnCopy = new InvokeInstruction();
insnCopy.setMethod(method);
insnCopy.setType(type);
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
insnCopy.setReceiver(receiver != null ? copyVar(receiver) : null);
for (VariableReader arg : arguments) {
insnCopy.getArguments().add(copyVar(arg));
}
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void invokeDynamic(VariableReader receiver, VariableReader instance, MethodDescriptor method,
List<? extends VariableReader> arguments, MethodHandle bootstrapMethod,
List<RuntimeConstant> bootstrapArguments) {
InvokeDynamicInstruction insnCopy = new InvokeDynamicInstruction();
insnCopy.setMethod(method);
insnCopy.setBootstrapMethod(bootstrapMethod);
insnCopy.getBootstrapArguments().addAll(bootstrapArguments);
if (instance != null) {
insnCopy.setInstance(copyVar(instance));
}
insnCopy.getArguments().addAll(arguments.stream().map(this::copyVar).collect(Collectors.toList()));
insnCopy.setReceiver(receiver != null ? copyVar(receiver) : null);
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void isInstance(VariableReader receiver, VariableReader value, ValueType type) {
IsInstanceInstruction insnCopy = new IsInstanceInstruction();
insnCopy.setValue(copyVar(value));
insnCopy.setReceiver(copyVar(receiver));
insnCopy.setType(type);
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void initClass(String className) {
InitClassInstruction insnCopy = new InitClassInstruction();
insnCopy.setClassName(className);
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void nullCheck(VariableReader receiver, VariableReader value) {
NullCheckInstruction insnCopy = new NullCheckInstruction();
insnCopy.setReceiver(copyVar(receiver));
insnCopy.setValue(copyVar(value));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void monitorEnter(VariableReader objectRef) {
MonitorEnterInstruction insnCopy = new MonitorEnterInstruction();
insnCopy.setObjectRef(copyVar(objectRef));
copy = insnCopy;
copy.setLocation(location);
}
@Override
public void monitorExit(VariableReader objectRef) {
MonitorExitInstruction insnCopy = new MonitorExitInstruction();
insnCopy.setObjectRef(copyVar(objectRef));
copy = insnCopy;
copy.setLocation(location);
}
}
}

View File

@ -1,50 +0,0 @@
/*
* Copyright 2013 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.optimization;
import java.util.Arrays;
import java.util.List;
import org.teavm.model.ClassHolder;
import org.teavm.model.ListableClassHolderSource;
import org.teavm.model.MethodHolder;
import org.teavm.model.Program;
import org.teavm.model.util.ProgramUtils;
/**
*
* @author Alexey Andreev
*/
public class ClassSetOptimizer {
private List<MethodOptimization> getOptimizations() {
return Arrays.asList(new ArrayUnwrapMotion(), new LoopInvariantMotion(),
new GlobalValueNumbering(), new UnusedVariableElimination());
}
public void optimizeAll(ListableClassHolderSource classSource) {
for (String className : classSource.getClassNames()) {
ClassHolder cls = classSource.get(className);
for (MethodHolder method : cls.getMethods()) {
if (method.getProgram() != null && method.getProgram().basicBlockCount() > 0) {
Program program = ProgramUtils.copy(method.getProgram());
for (MethodOptimization optimization : getOptimizations()) {
optimization.optimize(method, program);
}
method.setProgram(program);
}
}
}
}
}

View File

@ -0,0 +1,26 @@
/*
* Copyright 2016 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.optimization;
import org.teavm.model.MethodReader;
import org.teavm.model.Program;
public class LoopInversion implements MethodOptimization {
@Override
public void optimize(MethodReader method, Program program) {
new LoopInversionImpl(program).apply();
}
}

View File

@ -0,0 +1,412 @@
/*
* Copyright 2016 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.optimization;
import com.carrotsearch.hppc.IntIntMap;
import com.carrotsearch.hppc.IntIntOpenHashMap;
import com.carrotsearch.hppc.IntOpenHashSet;
import com.carrotsearch.hppc.IntSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.teavm.common.DominatorTree;
import org.teavm.common.Graph;
import org.teavm.common.GraphUtils;
import org.teavm.common.Loop;
import org.teavm.common.LoopGraph;
import org.teavm.model.BasicBlock;
import org.teavm.model.Incoming;
import org.teavm.model.Instruction;
import org.teavm.model.Phi;
import org.teavm.model.Program;
import org.teavm.model.TryCatchBlock;
import org.teavm.model.Variable;
import org.teavm.model.util.BasicBlockMapper;
import org.teavm.model.util.DefinitionExtractor;
import org.teavm.model.util.InstructionCopyReader;
import org.teavm.model.util.InstructionVariableMapper;
import org.teavm.model.util.ProgramUtils;
/**
* Transforms loop in form:
*
* ```
* while (true) {
* condition;
* body;
* }
* ```
*
* to form:
*
* ```
* if (condition) {
* while (true) {
* body;
* condition; // copy
* }
* }
* ```
*
* where `condition` is a part of loop that has exits and `body` has no exits.
* More formally, we define *condition end* as a node that postdominates all loop exits.
* Therefore, *condition* is a set of nodes of the loop that are postdominated by condition end and
* all remaining nodes are *body*.
*/
class LoopInversionImpl {
private Program program;
private Graph cfg;
private DominatorTree pdom;
private boolean postponed;
LoopInversionImpl(Program program) {
this.program = program;
}
void apply() {
do {
cfg = ProgramUtils.buildControlFlowGraph(program);
LoopGraph loopGraph = new LoopGraph(cfg);
pdom = GraphUtils.buildDominatorTree(GraphUtils.invert(cfg));
List<LoopWithExits> loops = getLoopsWithExits(loopGraph);
postponed = false;
for (LoopWithExits loop : loops) {
loop.invert();
}
} while (postponed);
}
private List<LoopWithExits> getLoopsWithExits(LoopGraph cfg) {
Map<Loop, LoopWithExits> loops = new HashMap<>();
for (int node = 0; node < cfg.size(); ++node) {
Loop loop = cfg.loopAt(node);
while (loop != null) {
LoopWithExits loopWithExits = getLoopWithExits(loops, loop);
loopWithExits.nodes.add(node);
for (int successor : cfg.outgoingEdges(node)) {
Loop successorLoop = cfg.loopAt(successor);
if (successorLoop == null || !successorLoop.isChildOf(loop)) {
loopWithExits.exits.add(node);
break;
}
}
loop = loop.getParent();
}
}
List<LoopWithExits> resultList = new ArrayList<>();
Set<LoopWithExits> visited = new HashSet<>();
for (LoopWithExits loop : loops.values()) {
sortLoops(loop, visited, resultList);
}
Collections.reverse(resultList);
return resultList;
}
private LoopWithExits getLoopWithExits(Map<Loop, LoopWithExits> cache, Loop loop) {
return cache.computeIfAbsent(loop, key ->
new LoopWithExits(key.getHead(), key.getParent() != null
? getLoopWithExits(cache, key.getParent())
: null));
}
private void sortLoops(LoopWithExits loop, Set<LoopWithExits> visited, List<LoopWithExits> target) {
if (!visited.add(loop)) {
return;
}
if (loop.parent != null) {
sortLoops(loop.parent, visited, target);
}
target.add(loop);
}
private class LoopWithExits {
final int head;
final LoopWithExits parent;
final IntSet nodes = new IntOpenHashSet();
final IntSet nodesAndCopies = new IntOpenHashSet();
final IntSet exits = new IntOpenHashSet();
int conditionEnd;
int copyStart;
int headCopy;
final IntIntMap copiedVars = new IntIntOpenHashMap();
final IntIntMap copiedNodes = new IntIntOpenHashMap();
boolean shouldSkip;
LoopWithExits(int head, LoopWithExits parent) {
this.head = head;
this.parent = parent;
}
void invert() {
if (tryInvert()) {
LoopWithExits ancestor = parent;
while (ancestor != null) {
ancestor.shouldSkip = true;
ancestor = ancestor.parent;
}
}
}
private boolean tryInvert() {
if (shouldSkip) {
postponed = true;
return false;
}
findCondition();
if (conditionEnd < 0 || !canInvert()) {
return false;
}
collectNodesToCopy();
collectVariablesToCopy();
copyCondition();
moveBackEdges();
removeInternalPhiInputsFromCondition();
removeExternalPhiInputsFromConditionCopy();
putNewPhis();
return true;
}
private void findCondition() {
IntSet endNodes = new IntOpenHashSet(program.basicBlockCount());
for (int exit : exits.toArray()) {
for (int successor : cfg.outgoingEdges(exit)) {
if (nodes.contains(successor) && successor != head) {
endNodes.add(successor);
}
}
}
conditionEnd = pdom.commonDominatorOf(endNodes.toArray());
}
/**
* We can't invert loop if condition has back edges. Indeed, back edges from `if` statement
* must point inside loop, which makes CFG irreducible.
*/
private boolean canInvert() {
for (int node : nodes.toArray()) {
if (pdom.dominates(conditionEnd, node)) {
for (int successor : cfg.outgoingEdges(node)) {
if (successor == head) {
return false;
}
}
}
}
return true;
}
private void collectNodesToCopy() {
int[] nodes = this.nodes.toArray();
Arrays.sort(nodes);
for (int node : nodes) {
nodesAndCopies.add(node);
if (pdom.dominates(conditionEnd, node)) {
int copy = program.createBasicBlock().getIndex();
if (head == node) {
headCopy = copy;
}
copiedNodes.put(node, copy);
nodesAndCopies.add(copy);
}
}
}
private void collectVariablesToCopy() {
DefinitionExtractor definitionExtractor = new DefinitionExtractor();
IntSet varsToCopy = new IntOpenHashSet();
for (int node : copiedNodes.keys().toArray()) {
BasicBlock block = program.basicBlockAt(node);
for (Instruction insn : block.getInstructions()) {
insn.acceptVisitor(definitionExtractor);
for (Variable var : definitionExtractor.getDefinedVariables()) {
varsToCopy.add(var.getIndex());
}
}
for (Phi phi : block.getPhis()) {
varsToCopy.add(phi.getReceiver().getIndex());
}
}
int[] orderedVarsToCopy = varsToCopy.toArray();
Arrays.sort(orderedVarsToCopy);
for (int var : orderedVarsToCopy) {
copiedVars.put(var, program.createVariable().getIndex());
}
}
private void copyCondition() {
InstructionVariableMapper variableMapper = new InstructionVariableMapper() {
@Override
protected Variable map(Variable var) {
return program.variableAt(copiedVars.getOrDefault(var.getIndex(), var.getIndex()));
}
};
BasicBlockMapper blockMapper = new BasicBlockMapper() {
@Override
protected BasicBlock map(BasicBlock block) {
return program.basicBlockAt(copiedNodes.getOrDefault(block.getIndex(), block.getIndex()));
}
};
InstructionCopyReader copier = new InstructionCopyReader(program);
for (int node : copiedNodes.keys().toArray()) {
BasicBlock sourceBlock = program.basicBlockAt(node);
BasicBlock targetBlock = program.basicBlockAt(copiedNodes.get(node));
copier.resetLocation();
for (int i = 0; i < sourceBlock.instructionCount(); ++i) {
sourceBlock.readInstruction(i, copier);
Instruction insn = copier.getCopy();
insn.acceptVisitor(variableMapper);
insn.acceptVisitor(blockMapper);
targetBlock.getInstructions().add(insn);
}
for (Phi phi : sourceBlock.getPhis()) {
Phi phiCopy = new Phi();
int receiver = phi.getReceiver().getIndex();
phiCopy.setReceiver(program.variableAt(copiedVars.getOrDefault(receiver, receiver)));
for (Incoming incoming : phi.getIncomings()) {
Incoming incomingCopy = new Incoming();
int source = incoming.getSource().getIndex();
int value = incoming.getValue().getIndex();
incomingCopy.setSource(program.basicBlockAt(copiedNodes.getOrDefault(source, source)));
incomingCopy.setValue(program.variableAt(copiedVars.getOrDefault(value, value)));
phiCopy.getIncomings().add(incomingCopy);
}
targetBlock.getPhis().add(phi);
}
for (TryCatchBlock tryCatch : sourceBlock.getTryCatchBlocks()) {
TryCatchBlock tryCatchCopy = new TryCatchBlock();
int var = tryCatch.getExceptionVariable().getIndex();
int handler = tryCatch.getHandler().getIndex();
tryCatchCopy.setExceptionType(tryCatch.getExceptionType());
tryCatchCopy.setExceptionVariable(program.variableAt(copiedVars.getOrDefault(var, var)));
tryCatchCopy.setHandler(program.basicBlockAt(copiedNodes.getOrDefault(handler, handler)));
targetBlock.getTryCatchBlocks().add(tryCatchCopy);
}
}
}
/**
* Back edges from body are not back edges anymore, instead they point to a copied condition.
*/
private void moveBackEdges() {
BasicBlockMapper mapper = new BasicBlockMapper() {
@Override
protected BasicBlock map(BasicBlock block) {
return block.getIndex() == head ? program.basicBlockAt(headCopy) : block;
}
};
for (int node : nodes.toArray()) {
BasicBlock block = program.basicBlockAt(node);
Instruction last = block.getLastInstruction();
if (last != null) {
last.acceptVisitor(mapper);
}
}
}
/**
* Original head becomes start of `if (condition)`, it's not loop head anymore.
* Hence we don't need phi inputs that come from back edges.
*/
private void removeInternalPhiInputsFromCondition() {
BasicBlock block = program.basicBlockAt(head);
for (Phi phi : block.getPhis()) {
List<Incoming> incomings = phi.getIncomings();
for (int i = 0; i < incomings.size(); ++i) {
Incoming incoming = incomings.get(i);
if (nodes.contains(incoming.getSource().getIndex())) {
incomings.remove(i--);
}
}
}
}
/**
* Head copy is not a loop head anymore and there aren't transition from outside of former loop,
* therefore delete all external phi inputs.
*/
private void removeExternalPhiInputsFromConditionCopy() {
BasicBlock block = program.basicBlockAt(headCopy);
for (Phi phi : block.getPhis()) {
List<Incoming> incomings = phi.getIncomings();
for (int i = 0; i < incomings.size(); ++i) {
Incoming incoming = incomings.get(i);
if (!nodesAndCopies.contains(incoming.getSource().getIndex())) {
incomings.remove(i--);
}
}
}
}
/**
* Variables defined in condition should be converted to phis in a new loop head (i.e. condition end).
* Every reference to variable from old condition must be replaced by reference to corresponding phi.
*/
private void putNewPhis() {
BasicBlock head = program.basicBlockAt(conditionEnd);
IntIntMap phiMap = new IntIntOpenHashMap();
int[] vars = copiedVars.keys().toArray();
Arrays.sort(vars);
for (int var : vars) {
Phi phi = new Phi();
phi.setReceiver(program.createVariable());
phiMap.put(var, phi.getReceiver().getIndex());
head.getPhis().add(phi);
for (int source : cfg.incomingEdges(conditionEnd)) {
int inputVar = copiedNodes.containsKey(source) ? var : copiedVars.get(var);
Incoming incoming = new Incoming();
incoming.setValue(program.variableAt(inputVar));
incoming.setSource(program.basicBlockAt(source));
phi.getIncomings().add(incoming);
}
}
InstructionVariableMapper mapper = new InstructionVariableMapper() {
@Override
protected Variable map(Variable var) {
int index = var.getIndex();
return program.variableAt(phiMap.getOrDefault(index, index));
}
};
for (int node : nodes.toArray()) {
if (copiedNodes.containsKey(node)) {
BasicBlock block = program.basicBlockAt(node);
for (Instruction instruction : block.getInstructions()) {
instruction.acceptVisitor(mapper);
}
}
}
}
}
}

View File

@ -649,7 +649,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
}
private List<MethodOptimization> getOptimizations() {
return Arrays.asList(new ArrayUnwrapMotion(), new LoopInvariantMotion(),
return Arrays.asList(new ArrayUnwrapMotion(), new LoopInversion(), new LoopInvariantMotion(),
new GlobalValueNumbering(), new UnusedVariableElimination());
}