mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-03 05:44:10 -08:00
Use new null checker in optimizer. Fix multiple bugs in optimizer and IR
This commit is contained in:
parent
aef1e2e206
commit
727c831467
|
@ -1,289 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.analysis;
|
|
||||||
|
|
||||||
import java.util.ArrayDeque;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Queue;
|
|
||||||
import java.util.Set;
|
|
||||||
import org.teavm.common.DominatorTree;
|
|
||||||
import org.teavm.common.Graph;
|
|
||||||
import org.teavm.common.GraphBuilder;
|
|
||||||
import org.teavm.common.GraphUtils;
|
|
||||||
import org.teavm.model.BasicBlock;
|
|
||||||
import org.teavm.model.BasicBlockReader;
|
|
||||||
import org.teavm.model.FieldReference;
|
|
||||||
import org.teavm.model.Incoming;
|
|
||||||
import org.teavm.model.MethodReference;
|
|
||||||
import org.teavm.model.Phi;
|
|
||||||
import org.teavm.model.Program;
|
|
||||||
import org.teavm.model.ValueType;
|
|
||||||
import org.teavm.model.VariableReader;
|
|
||||||
import org.teavm.model.instructions.AbstractInstructionReader;
|
|
||||||
import org.teavm.model.instructions.ArrayElementType;
|
|
||||||
import org.teavm.model.instructions.BinaryBranchingCondition;
|
|
||||||
import org.teavm.model.instructions.BranchingCondition;
|
|
||||||
import org.teavm.model.instructions.InvocationType;
|
|
||||||
import org.teavm.model.util.ProgramUtils;
|
|
||||||
|
|
||||||
public class NullnessChecker {
|
|
||||||
Set<Incoming> notNullIncomings;
|
|
||||||
List<List<Incoming>> phiOutputs;
|
|
||||||
boolean[] notNull;
|
|
||||||
boolean[] nullLiteral;
|
|
||||||
GraphBuilder graphBuilder;
|
|
||||||
|
|
||||||
public boolean[] check(Program program) {
|
|
||||||
notNullIncomings = new HashSet<>();
|
|
||||||
notNull = new boolean[program.variableCount()];
|
|
||||||
nullLiteral = new boolean[program.variableCount()];
|
|
||||||
phiOutputs = ProgramUtils.getPhiOutputsByVariable(program);
|
|
||||||
graphBuilder = new GraphBuilder(program.variableCount());
|
|
||||||
|
|
||||||
Graph cfg = ProgramUtils.buildControlFlowGraph(program);
|
|
||||||
DominatorTree dom = GraphUtils.buildDominatorTree(cfg);
|
|
||||||
Graph domGraph = GraphUtils.buildDominatorGraph(dom, cfg.size());
|
|
||||||
|
|
||||||
Step[] stack = new Step[cfg.size() * 2];
|
|
||||||
int head = 0;
|
|
||||||
stack[head++] = new Step(0, notNull.clone());
|
|
||||||
|
|
||||||
while (head > 0) {
|
|
||||||
Step step = stack[--head];
|
|
||||||
int node = step.node;
|
|
||||||
|
|
||||||
BasicBlock block = program.basicBlockAt(node);
|
|
||||||
InstructionReaderImpl reader = new InstructionReaderImpl(step.nonNull);
|
|
||||||
block.readAllInstructions(reader);
|
|
||||||
|
|
||||||
for (Phi phi : block.getPhis()) {
|
|
||||||
for (Incoming incoming : phi.getIncomings()) {
|
|
||||||
graphBuilder.addEdge(incoming.getValue().getIndex(), phi.getReceiver().getIndex());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int successor : domGraph.outgoingEdges(node)) {
|
|
||||||
boolean[] nextNonNull = step.nonNull.clone();
|
|
||||||
if (successor == reader.notNullTarget && reader.notNullVariable >= 0) {
|
|
||||||
nextNonNull[reader.notNullVariable] = true;
|
|
||||||
}
|
|
||||||
stack[head++] = new Step(successor, nextNonNull);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
propagateNullness(graphBuilder.build());
|
|
||||||
|
|
||||||
boolean[] result = notNull;
|
|
||||||
|
|
||||||
notNullIncomings = null;
|
|
||||||
notNull = null;
|
|
||||||
nullLiteral = null;
|
|
||||||
phiOutputs = null;
|
|
||||||
graphBuilder = null;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void propagateNullness(Graph graph) {
|
|
||||||
Queue<Integer> worklist = new ArrayDeque<>();
|
|
||||||
for (int i = 0; i < notNull.length; ++i) {
|
|
||||||
if (notNull[i] && graph.outgoingEdgesCount(i) > 0) {
|
|
||||||
for (int j : graph.outgoingEdges(i)) {
|
|
||||||
if (!notNull[j]) {
|
|
||||||
worklist.add(j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!worklist.isEmpty()) {
|
|
||||||
int node = worklist.remove();
|
|
||||||
if (notNull[node]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
notNull[node] = true;
|
|
||||||
for (int next : graph.outgoingEdges(node)) {
|
|
||||||
if (!notNull[next]) {
|
|
||||||
worklist.add(next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class InstructionReaderImpl extends AbstractInstructionReader {
|
|
||||||
boolean[] currentNotNull;
|
|
||||||
int notNullTarget;
|
|
||||||
int notNullVariable = -1;
|
|
||||||
|
|
||||||
public InstructionReaderImpl(boolean[] currentNotNull) {
|
|
||||||
this.currentNotNull = currentNotNull;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void nullConstant(VariableReader receiver) {
|
|
||||||
nullLiteral[receiver.getIndex()] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void classConstant(VariableReader receiver, ValueType cst) {
|
|
||||||
notNull[receiver.getIndex()] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stringConstant(VariableReader receiver, String cst) {
|
|
||||||
notNull[receiver.getIndex()] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void assign(VariableReader receiver, VariableReader assignee) {
|
|
||||||
if (currentNotNull[assignee.getIndex()]) {
|
|
||||||
notNull[receiver.getIndex()] = true;
|
|
||||||
}
|
|
||||||
graphBuilder.addEdge(assignee.getIndex(), receiver.getIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invoke(VariableReader receiver, VariableReader instance, MethodReference method,
|
|
||||||
List<? extends VariableReader> arguments, InvocationType type) {
|
|
||||||
if (instance != null) {
|
|
||||||
markAsCurrentNotNull(instance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getField(VariableReader receiver, VariableReader instance, FieldReference field,
|
|
||||||
ValueType fieldType) {
|
|
||||||
if (instance != null) {
|
|
||||||
markAsCurrentNotNull(instance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void putField(VariableReader instance, FieldReference field, VariableReader value, ValueType fieldType) {
|
|
||||||
if (instance != null) {
|
|
||||||
markAsCurrentNotNull(instance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getElement(VariableReader receiver, VariableReader array, VariableReader index,
|
|
||||||
ArrayElementType elementType) {
|
|
||||||
markAsCurrentNotNull(array);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void putElement(VariableReader array, VariableReader index, VariableReader value,
|
|
||||||
ArrayElementType elementType) {
|
|
||||||
markAsCurrentNotNull(array);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void create(VariableReader receiver, String type) {
|
|
||||||
notNull[receiver.getIndex()] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void createArray(VariableReader receiver, ValueType itemType,
|
|
||||||
List<? extends VariableReader> dimensions) {
|
|
||||||
notNull[receiver.getIndex()] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
|
|
||||||
notNull[receiver.getIndex()] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void arrayLength(VariableReader receiver, VariableReader array) {
|
|
||||||
markAsCurrentNotNull(array);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) {
|
|
||||||
notNull[receiver.getIndex()] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void nullCheck(VariableReader receiver, VariableReader value) {
|
|
||||||
notNull[receiver.getIndex()] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void jumpIf(BranchingCondition cond, VariableReader operand, BasicBlockReader consequent,
|
|
||||||
BasicBlockReader alternative) {
|
|
||||||
switch (cond) {
|
|
||||||
case NULL:
|
|
||||||
notNullVariable = operand.getIndex();
|
|
||||||
notNullTarget = alternative.getIndex();
|
|
||||||
break;
|
|
||||||
case NOT_NULL:
|
|
||||||
notNullVariable = operand.getIndex();
|
|
||||||
notNullTarget = consequent.getIndex();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void jumpIf(BinaryBranchingCondition cond, VariableReader first, VariableReader second,
|
|
||||||
BasicBlockReader consequent, BasicBlockReader alternative) {
|
|
||||||
switch (cond) {
|
|
||||||
case REFERENCE_EQUAL:
|
|
||||||
if (nullLiteral[first.getIndex()]) {
|
|
||||||
notNullVariable = second.getIndex();
|
|
||||||
} else if (nullLiteral[second.getIndex()]) {
|
|
||||||
notNullVariable = first.getIndex();
|
|
||||||
}
|
|
||||||
notNullTarget = alternative.getIndex();
|
|
||||||
break;
|
|
||||||
case REFERENCE_NOT_EQUAL:
|
|
||||||
if (nullLiteral[first.getIndex()]) {
|
|
||||||
notNullVariable = second.getIndex();
|
|
||||||
} else if (nullLiteral[second.getIndex()]) {
|
|
||||||
notNullVariable = first.getIndex();
|
|
||||||
}
|
|
||||||
notNullTarget = consequent.getIndex();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void markAsCurrentNotNull(VariableReader variable) {
|
|
||||||
if (!currentNotNull[variable.getIndex()]) {
|
|
||||||
currentNotNull[variable.getIndex()] = true;
|
|
||||||
List<Incoming> outputs = phiOutputs.get(variable.getIndex());
|
|
||||||
if (outputs != null) {
|
|
||||||
for (Incoming output : outputs) {
|
|
||||||
notNullIncomings.add(output);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class Step {
|
|
||||||
int node;
|
|
||||||
boolean[] nonNull;
|
|
||||||
|
|
||||||
public Step(int node, boolean[] nonNull) {
|
|
||||||
this.node = node;
|
|
||||||
this.nonNull = nonNull;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -77,6 +77,8 @@ public class NullnessInformation {
|
||||||
insn.acceptVisitor(variableMapper);
|
insn.acceptVisitor(variableMapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
variableMapper.applyToPhis(block);
|
||||||
|
variableMapper.applyToTryCatchBlocks(block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,13 +15,61 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.model.optimization;
|
package org.teavm.model.optimization;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.function.UnaryOperator;
|
import java.util.function.UnaryOperator;
|
||||||
import org.teavm.common.DominatorTree;
|
import org.teavm.common.DominatorTree;
|
||||||
import org.teavm.common.Graph;
|
import org.teavm.common.Graph;
|
||||||
import org.teavm.common.GraphUtils;
|
import org.teavm.common.GraphUtils;
|
||||||
import org.teavm.model.*;
|
import org.teavm.model.BasicBlock;
|
||||||
import org.teavm.model.instructions.*;
|
import org.teavm.model.Incoming;
|
||||||
|
import org.teavm.model.Instruction;
|
||||||
|
import org.teavm.model.InvokeDynamicInstruction;
|
||||||
|
import org.teavm.model.Program;
|
||||||
|
import org.teavm.model.TryCatchBlock;
|
||||||
|
import org.teavm.model.TryCatchJoint;
|
||||||
|
import org.teavm.model.Variable;
|
||||||
|
import org.teavm.model.instructions.ArrayLengthInstruction;
|
||||||
|
import org.teavm.model.instructions.AssignInstruction;
|
||||||
|
import org.teavm.model.instructions.BinaryBranchingInstruction;
|
||||||
|
import org.teavm.model.instructions.BinaryInstruction;
|
||||||
|
import org.teavm.model.instructions.BinaryOperation;
|
||||||
|
import org.teavm.model.instructions.BranchingInstruction;
|
||||||
|
import org.teavm.model.instructions.CastInstruction;
|
||||||
|
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.InstructionVisitor;
|
||||||
|
import org.teavm.model.instructions.IntegerConstantInstruction;
|
||||||
|
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.UnwrapArrayInstruction;
|
||||||
import org.teavm.model.util.ProgramUtils;
|
import org.teavm.model.util.ProgramUtils;
|
||||||
|
|
||||||
public class GlobalValueNumbering implements MethodOptimization {
|
public class GlobalValueNumbering implements MethodOptimization {
|
||||||
|
@ -86,9 +134,7 @@ public class GlobalValueNumbering implements MethodOptimization {
|
||||||
currentInsn.acceptVisitor(optimizer);
|
currentInsn.acceptVisitor(optimizer);
|
||||||
if (eliminate) {
|
if (eliminate) {
|
||||||
affected = true;
|
affected = true;
|
||||||
EmptyInstruction empty = new EmptyInstruction();
|
currentInsn.delete();
|
||||||
empty.setLocation(currentInsn.getLocation());
|
|
||||||
currentInsn.replace(empty);
|
|
||||||
eliminate = false;
|
eliminate = false;
|
||||||
} else if (evaluatedConstant != null) {
|
} else if (evaluatedConstant != null) {
|
||||||
if (evaluatedConstant instanceof Integer) {
|
if (evaluatedConstant instanceof Integer) {
|
||||||
|
@ -501,6 +547,9 @@ public class GlobalValueNumbering implements MethodOptimization {
|
||||||
if (insn.getReceiver().getDebugName() != null) {
|
if (insn.getReceiver().getDebugName() != null) {
|
||||||
insn.getAssignee().setDebugName(insn.getReceiver().getDebugName());
|
insn.getAssignee().setDebugName(insn.getReceiver().getDebugName());
|
||||||
}
|
}
|
||||||
|
if (insn.getReceiver().getLabel() != null) {
|
||||||
|
insn.getAssignee().setLabel(insn.getReceiver().getLabel());
|
||||||
|
}
|
||||||
map[insn.getReceiver().getIndex()] = map[insn.getAssignee().getIndex()];
|
map[insn.getReceiver().getIndex()] = map[insn.getAssignee().getIndex()];
|
||||||
eliminate = true;
|
eliminate = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,6 +109,8 @@ public class Inlining {
|
||||||
List<TryCatchBlock> tryCatches = new ArrayList<>(blockToInline.getTryCatchBlocks());
|
List<TryCatchBlock> tryCatches = new ArrayList<>(blockToInline.getTryCatchBlocks());
|
||||||
blockToInline.getTryCatchBlocks().clear();
|
blockToInline.getTryCatchBlocks().clear();
|
||||||
inlineBlock.getTryCatchBlocks().addAll(tryCatches);
|
inlineBlock.getTryCatchBlocks().addAll(tryCatches);
|
||||||
|
|
||||||
|
inlineBlock.setExceptionVariable(blockToInline.getExceptionVariable());
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicBlockMapper blockMapper = new BasicBlockMapper((BasicBlock b) ->
|
BasicBlockMapper blockMapper = new BasicBlockMapper((BasicBlock b) ->
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package org.teavm.model.optimization;
|
package org.teavm.model.optimization;
|
||||||
|
|
||||||
import org.teavm.model.InvokeDynamicInstruction;
|
import org.teavm.model.InvokeDynamicInstruction;
|
||||||
|
import org.teavm.model.analysis.NullnessInformation;
|
||||||
import org.teavm.model.instructions.ArrayLengthInstruction;
|
import org.teavm.model.instructions.ArrayLengthInstruction;
|
||||||
import org.teavm.model.instructions.AssignInstruction;
|
import org.teavm.model.instructions.AssignInstruction;
|
||||||
import org.teavm.model.instructions.BinaryBranchingInstruction;
|
import org.teavm.model.instructions.BinaryBranchingInstruction;
|
||||||
|
@ -57,13 +58,13 @@ import org.teavm.model.instructions.SwitchInstruction;
|
||||||
import org.teavm.model.instructions.UnwrapArrayInstruction;
|
import org.teavm.model.instructions.UnwrapArrayInstruction;
|
||||||
|
|
||||||
public class LoopInvariantAnalyzer implements InstructionVisitor {
|
public class LoopInvariantAnalyzer implements InstructionVisitor {
|
||||||
private boolean[] notNull;
|
private NullnessInformation nullness;
|
||||||
public boolean canMove;
|
public boolean canMove;
|
||||||
public boolean constant;
|
public boolean constant;
|
||||||
public boolean sideEffect;
|
public boolean sideEffect;
|
||||||
|
|
||||||
public LoopInvariantAnalyzer(boolean[] notNull) {
|
public LoopInvariantAnalyzer(NullnessInformation nullness) {
|
||||||
this.notNull = notNull;
|
this.nullness = nullness;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
|
@ -192,7 +193,7 @@ public class LoopInvariantAnalyzer implements InstructionVisitor {
|
||||||
@Override
|
@Override
|
||||||
public void visit(ArrayLengthInstruction insn) {
|
public void visit(ArrayLengthInstruction insn) {
|
||||||
canMove = true;
|
canMove = true;
|
||||||
if (!notNull[insn.getArray().getIndex()]) {
|
if (!nullness.isNotNull(insn.getArray())) {
|
||||||
sideEffect = true;
|
sideEffect = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,7 +205,7 @@ public class LoopInvariantAnalyzer implements InstructionVisitor {
|
||||||
@Override
|
@Override
|
||||||
public void visit(UnwrapArrayInstruction insn) {
|
public void visit(UnwrapArrayInstruction insn) {
|
||||||
canMove = true;
|
canMove = true;
|
||||||
if (!notNull[insn.getArray().getIndex()]) {
|
if (!nullness.isNotNull(insn.getArray())) {
|
||||||
sideEffect = true;
|
sideEffect = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,7 +238,7 @@ public class LoopInvariantAnalyzer implements InstructionVisitor {
|
||||||
@Override
|
@Override
|
||||||
public void visit(NullCheckInstruction insn) {
|
public void visit(NullCheckInstruction insn) {
|
||||||
canMove = true;
|
canMove = true;
|
||||||
if (!notNull[insn.getValue().getIndex()]) {
|
if (!nullness.isNotNull(insn.getValue())) {
|
||||||
sideEffect = true;
|
sideEffect = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,11 +18,34 @@ package org.teavm.model.optimization;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.teavm.common.*;
|
import org.teavm.common.DominatorTree;
|
||||||
import org.teavm.model.*;
|
import org.teavm.common.Graph;
|
||||||
import org.teavm.model.analysis.NullnessChecker;
|
import org.teavm.common.GraphUtils;
|
||||||
import org.teavm.model.instructions.*;
|
import org.teavm.common.IntegerStack;
|
||||||
import org.teavm.model.util.*;
|
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.Variable;
|
||||||
|
import org.teavm.model.analysis.NullnessInformation;
|
||||||
|
import org.teavm.model.instructions.AbstractInstructionVisitor;
|
||||||
|
import org.teavm.model.instructions.ClassConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.DoubleConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.FloatConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.IntegerConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.JumpInstruction;
|
||||||
|
import org.teavm.model.instructions.LongConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.NullConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.StringConstantInstruction;
|
||||||
|
import org.teavm.model.util.BasicBlockMapper;
|
||||||
|
import org.teavm.model.util.ControlFlowUtils;
|
||||||
|
import org.teavm.model.util.DefinitionExtractor;
|
||||||
|
import org.teavm.model.util.InstructionVariableMapper;
|
||||||
|
import org.teavm.model.util.ProgramUtils;
|
||||||
|
import org.teavm.model.util.UsageExtractor;
|
||||||
|
|
||||||
public class LoopInvariantMotion implements MethodOptimization {
|
public class LoopInvariantMotion implements MethodOptimization {
|
||||||
private int[] preheaders;
|
private int[] preheaders;
|
||||||
|
@ -32,6 +55,8 @@ public class LoopInvariantMotion implements MethodOptimization {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean optimize(MethodOptimizationContext context, Program program) {
|
public boolean optimize(MethodOptimizationContext context, Program program) {
|
||||||
|
NullnessInformation nullness = NullnessInformation.build(program, context.getMethod().getDescriptor());
|
||||||
|
|
||||||
boolean affected = false;
|
boolean affected = false;
|
||||||
this.program = program;
|
this.program = program;
|
||||||
graph = new LoopGraph(ProgramUtils.buildControlFlowGraph(program));
|
graph = new LoopGraph(ProgramUtils.buildControlFlowGraph(program));
|
||||||
|
@ -54,7 +79,7 @@ public class LoopInvariantMotion implements MethodOptimization {
|
||||||
|
|
||||||
DefinitionExtractor defExtractor = new DefinitionExtractor();
|
DefinitionExtractor defExtractor = new DefinitionExtractor();
|
||||||
UsageExtractor useExtractor = new UsageExtractor();
|
UsageExtractor useExtractor = new UsageExtractor();
|
||||||
LoopInvariantAnalyzer analyzer = new LoopInvariantAnalyzer(new NullnessChecker().check(program));
|
LoopInvariantAnalyzer analyzer = new LoopInvariantAnalyzer(nullness);
|
||||||
CopyConstantVisitor constantCopier = new CopyConstantVisitor();
|
CopyConstantVisitor constantCopier = new CopyConstantVisitor();
|
||||||
int[][] loopExits = ControlFlowUtils.findLoopExits(graph);
|
int[][] loopExits = ControlFlowUtils.findLoopExits(graph);
|
||||||
|
|
||||||
|
@ -112,9 +137,7 @@ public class LoopInvariantMotion implements MethodOptimization {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EmptyInstruction empty = new EmptyInstruction();
|
insn.delete();
|
||||||
empty.setLocation(insn.getLocation());
|
|
||||||
insn.replace(empty);
|
|
||||||
BasicBlock preheader = program.basicBlockAt(getPreheader(defLoop.getHead()));
|
BasicBlock preheader = program.basicBlockAt(getPreheader(defLoop.getHead()));
|
||||||
List<Instruction> newInstructions = new ArrayList<>();
|
List<Instruction> newInstructions = new ArrayList<>();
|
||||||
Variable[] variableMap = null;
|
Variable[] variableMap = null;
|
||||||
|
@ -146,6 +169,7 @@ public class LoopInvariantMotion implements MethodOptimization {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nullness.dispose();
|
||||||
return affected;
|
return affected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,6 +215,8 @@ public class LoopInvariantMotion implements MethodOptimization {
|
||||||
if (preheaderPhi == null) {
|
if (preheaderPhi == null) {
|
||||||
preheaderPhi = new Phi();
|
preheaderPhi = new Phi();
|
||||||
preheaderPhi.setReceiver(program.createVariable());
|
preheaderPhi.setReceiver(program.createVariable());
|
||||||
|
preheaderPhi.getReceiver().setLabel(phi.getReceiver().getLabel());
|
||||||
|
preheaderPhi.getReceiver().setDebugName(phi.getReceiver().getDebugName());
|
||||||
preheader.getPhis().add(preheaderPhi);
|
preheader.getPhis().add(preheaderPhi);
|
||||||
}
|
}
|
||||||
preheaderPhi.getIncomings().add(incoming);
|
preheaderPhi.getIncomings().add(incoming);
|
||||||
|
@ -215,18 +241,15 @@ public class LoopInvariantMotion implements MethodOptimization {
|
||||||
return preheader.getIndex();
|
return preheader.getIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CopyConstantVisitor implements InstructionVisitor {
|
private class CopyConstantVisitor extends AbstractInstructionVisitor {
|
||||||
Instruction copy;
|
Instruction copy;
|
||||||
Variable var;
|
Variable var;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(EmptyInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ClassConstantInstruction insn) {
|
public void visit(ClassConstantInstruction insn) {
|
||||||
var = program.createVariable();
|
var = program.createVariable();
|
||||||
var.setDebugName(insn.getReceiver().getDebugName());
|
var.setDebugName(insn.getReceiver().getDebugName());
|
||||||
|
var.setLabel(insn.getReceiver().getLabel());
|
||||||
ClassConstantInstruction copy = new ClassConstantInstruction();
|
ClassConstantInstruction copy = new ClassConstantInstruction();
|
||||||
copy.setConstant(insn.getConstant());
|
copy.setConstant(insn.getConstant());
|
||||||
copy.setReceiver(var);
|
copy.setReceiver(var);
|
||||||
|
@ -237,6 +260,7 @@ public class LoopInvariantMotion implements MethodOptimization {
|
||||||
public void visit(NullConstantInstruction insn) {
|
public void visit(NullConstantInstruction insn) {
|
||||||
var = program.createVariable();
|
var = program.createVariable();
|
||||||
var.setDebugName(insn.getReceiver().getDebugName());
|
var.setDebugName(insn.getReceiver().getDebugName());
|
||||||
|
var.setLabel(insn.getReceiver().getLabel());
|
||||||
NullConstantInstruction copy = new NullConstantInstruction();
|
NullConstantInstruction copy = new NullConstantInstruction();
|
||||||
copy.setReceiver(var);
|
copy.setReceiver(var);
|
||||||
this.copy = copy;
|
this.copy = copy;
|
||||||
|
@ -246,6 +270,7 @@ public class LoopInvariantMotion implements MethodOptimization {
|
||||||
public void visit(IntegerConstantInstruction insn) {
|
public void visit(IntegerConstantInstruction insn) {
|
||||||
var = program.createVariable();
|
var = program.createVariable();
|
||||||
var.setDebugName(insn.getReceiver().getDebugName());
|
var.setDebugName(insn.getReceiver().getDebugName());
|
||||||
|
var.setLabel(insn.getReceiver().getLabel());
|
||||||
IntegerConstantInstruction copy = new IntegerConstantInstruction();
|
IntegerConstantInstruction copy = new IntegerConstantInstruction();
|
||||||
copy.setConstant(insn.getConstant());
|
copy.setConstant(insn.getConstant());
|
||||||
copy.setReceiver(var);
|
copy.setReceiver(var);
|
||||||
|
@ -256,6 +281,7 @@ public class LoopInvariantMotion implements MethodOptimization {
|
||||||
public void visit(LongConstantInstruction insn) {
|
public void visit(LongConstantInstruction insn) {
|
||||||
var = program.createVariable();
|
var = program.createVariable();
|
||||||
var.setDebugName(insn.getReceiver().getDebugName());
|
var.setDebugName(insn.getReceiver().getDebugName());
|
||||||
|
var.setLabel(insn.getReceiver().getLabel());
|
||||||
LongConstantInstruction copy = new LongConstantInstruction();
|
LongConstantInstruction copy = new LongConstantInstruction();
|
||||||
copy.setConstant(insn.getConstant());
|
copy.setConstant(insn.getConstant());
|
||||||
copy.setReceiver(var);
|
copy.setReceiver(var);
|
||||||
|
@ -266,6 +292,7 @@ public class LoopInvariantMotion implements MethodOptimization {
|
||||||
public void visit(FloatConstantInstruction insn) {
|
public void visit(FloatConstantInstruction insn) {
|
||||||
var = program.createVariable();
|
var = program.createVariable();
|
||||||
var.setDebugName(insn.getReceiver().getDebugName());
|
var.setDebugName(insn.getReceiver().getDebugName());
|
||||||
|
var.setLabel(insn.getReceiver().getLabel());
|
||||||
FloatConstantInstruction copy = new FloatConstantInstruction();
|
FloatConstantInstruction copy = new FloatConstantInstruction();
|
||||||
copy.setConstant(insn.getConstant());
|
copy.setConstant(insn.getConstant());
|
||||||
copy.setReceiver(var);
|
copy.setReceiver(var);
|
||||||
|
@ -276,6 +303,7 @@ public class LoopInvariantMotion implements MethodOptimization {
|
||||||
public void visit(DoubleConstantInstruction insn) {
|
public void visit(DoubleConstantInstruction insn) {
|
||||||
var = program.createVariable();
|
var = program.createVariable();
|
||||||
var.setDebugName(insn.getReceiver().getDebugName());
|
var.setDebugName(insn.getReceiver().getDebugName());
|
||||||
|
var.setLabel(insn.getReceiver().getLabel());
|
||||||
DoubleConstantInstruction copy = new DoubleConstantInstruction();
|
DoubleConstantInstruction copy = new DoubleConstantInstruction();
|
||||||
copy.setConstant(insn.getConstant());
|
copy.setConstant(insn.getConstant());
|
||||||
copy.setReceiver(var);
|
copy.setReceiver(var);
|
||||||
|
@ -286,126 +314,11 @@ public class LoopInvariantMotion implements MethodOptimization {
|
||||||
public void visit(StringConstantInstruction insn) {
|
public void visit(StringConstantInstruction insn) {
|
||||||
var = program.createVariable();
|
var = program.createVariable();
|
||||||
var.setDebugName(insn.getReceiver().getDebugName());
|
var.setDebugName(insn.getReceiver().getDebugName());
|
||||||
|
var.setLabel(insn.getReceiver().getLabel());
|
||||||
StringConstantInstruction copy = new StringConstantInstruction();
|
StringConstantInstruction copy = new StringConstantInstruction();
|
||||||
copy.setConstant(insn.getConstant());
|
copy.setConstant(insn.getConstant());
|
||||||
copy.setReceiver(var);
|
copy.setReceiver(var);
|
||||||
this.copy = copy;
|
this.copy = copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(BinaryInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(NegateInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(AssignInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(CastInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(CastNumberInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(CastIntegerInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(BranchingInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(BinaryBranchingInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(JumpInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(SwitchInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(ExitInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(RaiseInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(ConstructArrayInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(ConstructInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(ConstructMultiArrayInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(GetFieldInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(PutFieldInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(ArrayLengthInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(CloneArrayInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(UnwrapArrayInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(GetElementInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(PutElementInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(InvokeInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(InvokeDynamicInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(IsInstanceInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(InitClassInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(NullCheckInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(MonitorEnterInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(MonitorExitInstruction insn) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,6 @@ public class LoopInversion implements MethodOptimization {
|
||||||
@Override
|
@Override
|
||||||
public boolean optimize(MethodOptimizationContext context, Program program) {
|
public boolean optimize(MethodOptimizationContext context, Program program) {
|
||||||
MethodReader method = context.getMethod();
|
MethodReader method = context.getMethod();
|
||||||
return new LoopInversionImpl(program, method.parameterCount() + 1).apply();
|
return new LoopInversionImpl(program, method.getReference(), method.parameterCount() + 1).apply();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,12 +35,13 @@ import org.teavm.common.LoopGraph;
|
||||||
import org.teavm.model.BasicBlock;
|
import org.teavm.model.BasicBlock;
|
||||||
import org.teavm.model.Incoming;
|
import org.teavm.model.Incoming;
|
||||||
import org.teavm.model.Instruction;
|
import org.teavm.model.Instruction;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.Phi;
|
import org.teavm.model.Phi;
|
||||||
import org.teavm.model.Program;
|
import org.teavm.model.Program;
|
||||||
import org.teavm.model.TryCatchBlock;
|
import org.teavm.model.TryCatchBlock;
|
||||||
import org.teavm.model.TryCatchJoint;
|
import org.teavm.model.TryCatchJoint;
|
||||||
import org.teavm.model.Variable;
|
import org.teavm.model.Variable;
|
||||||
import org.teavm.model.analysis.NullnessChecker;
|
import org.teavm.model.analysis.NullnessInformation;
|
||||||
import org.teavm.model.util.BasicBlockMapper;
|
import org.teavm.model.util.BasicBlockMapper;
|
||||||
import org.teavm.model.util.DefinitionExtractor;
|
import org.teavm.model.util.DefinitionExtractor;
|
||||||
import org.teavm.model.util.InstructionCopyReader;
|
import org.teavm.model.util.InstructionCopyReader;
|
||||||
|
@ -80,6 +81,7 @@ import org.teavm.model.util.UsageExtractor;
|
||||||
*/
|
*/
|
||||||
class LoopInversionImpl {
|
class LoopInversionImpl {
|
||||||
private final Program program;
|
private final Program program;
|
||||||
|
private final MethodReference method;
|
||||||
private final int parameterCount;
|
private final int parameterCount;
|
||||||
private Graph cfg;
|
private Graph cfg;
|
||||||
private DominatorTree dom;
|
private DominatorTree dom;
|
||||||
|
@ -88,8 +90,9 @@ class LoopInversionImpl {
|
||||||
private BasicBlock[] definitionPlaces;
|
private BasicBlock[] definitionPlaces;
|
||||||
private boolean affected;
|
private boolean affected;
|
||||||
|
|
||||||
LoopInversionImpl(Program program, int parameterCount) {
|
LoopInversionImpl(Program program, MethodReference method, int parameterCount) {
|
||||||
this.program = program;
|
this.program = program;
|
||||||
|
this.method = method;
|
||||||
this.parameterCount = parameterCount;
|
this.parameterCount = parameterCount;
|
||||||
definitionPlaces = ProgramUtils.getVariableDefinitionPlaces(program);
|
definitionPlaces = ProgramUtils.getVariableDefinitionPlaces(program);
|
||||||
}
|
}
|
||||||
|
@ -202,7 +205,10 @@ class LoopInversionImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
IntSet nodesToCopy = nodesToCopy();
|
IntSet nodesToCopy = nodesToCopy();
|
||||||
if (!isInversionProfitable(nodesToCopy)) {
|
NullnessInformation nullness = NullnessInformation.build(program, method.getDescriptor());
|
||||||
|
boolean profitable = isInversionProfitable(nodesToCopy, nullness);
|
||||||
|
nullness.dispose();
|
||||||
|
if (!profitable) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
copyBasicBlocks(nodesToCopy);
|
copyBasicBlocks(nodesToCopy);
|
||||||
|
@ -216,11 +222,10 @@ class LoopInversionImpl {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isInversionProfitable(IntSet nodesToCopy) {
|
private boolean isInversionProfitable(IntSet nodesToCopy, NullnessInformation nullness) {
|
||||||
UsageExtractor useExtractor = new UsageExtractor();
|
UsageExtractor useExtractor = new UsageExtractor();
|
||||||
DefinitionExtractor defExtractor = new DefinitionExtractor();
|
DefinitionExtractor defExtractor = new DefinitionExtractor();
|
||||||
boolean[] notNull = new NullnessChecker().check(program);
|
LoopInvariantAnalyzer invariantAnalyzer = new LoopInvariantAnalyzer(nullness);
|
||||||
LoopInvariantAnalyzer invariantAnalyzer = new LoopInvariantAnalyzer(notNull);
|
|
||||||
for (int node : nodes.toArray()) {
|
for (int node : nodes.toArray()) {
|
||||||
if (nodesToCopy.contains(node)) {
|
if (nodesToCopy.contains(node)) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -16,8 +16,40 @@
|
||||||
package org.teavm.model.optimization;
|
package org.teavm.model.optimization;
|
||||||
|
|
||||||
import org.teavm.common.Graph;
|
import org.teavm.common.Graph;
|
||||||
import org.teavm.model.*;
|
import org.teavm.model.BasicBlock;
|
||||||
import org.teavm.model.instructions.*;
|
import org.teavm.model.Instruction;
|
||||||
|
import org.teavm.model.InvokeDynamicInstruction;
|
||||||
|
import org.teavm.model.MethodReader;
|
||||||
|
import org.teavm.model.Phi;
|
||||||
|
import org.teavm.model.Program;
|
||||||
|
import org.teavm.model.TryCatchBlock;
|
||||||
|
import org.teavm.model.TryCatchJoint;
|
||||||
|
import org.teavm.model.Variable;
|
||||||
|
import org.teavm.model.instructions.AbstractInstructionVisitor;
|
||||||
|
import org.teavm.model.instructions.ArrayLengthInstruction;
|
||||||
|
import org.teavm.model.instructions.AssignInstruction;
|
||||||
|
import org.teavm.model.instructions.BinaryInstruction;
|
||||||
|
import org.teavm.model.instructions.CastInstruction;
|
||||||
|
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.FloatConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.GetElementInstruction;
|
||||||
|
import org.teavm.model.instructions.GetFieldInstruction;
|
||||||
|
import org.teavm.model.instructions.IntegerConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.InvokeInstruction;
|
||||||
|
import org.teavm.model.instructions.IsInstanceInstruction;
|
||||||
|
import org.teavm.model.instructions.LongConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.NegateInstruction;
|
||||||
|
import org.teavm.model.instructions.NullCheckInstruction;
|
||||||
|
import org.teavm.model.instructions.NullConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.StringConstantInstruction;
|
||||||
|
import org.teavm.model.instructions.UnwrapArrayInstruction;
|
||||||
|
|
||||||
public class UnusedVariableElimination implements MethodOptimization {
|
public class UnusedVariableElimination implements MethodOptimization {
|
||||||
@Override
|
@Override
|
||||||
|
@ -90,10 +122,17 @@ public class UnusedVariableElimination implements MethodOptimization {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < program.variableCount(); ++i) {
|
||||||
|
if (!used[i]) {
|
||||||
|
program.deleteVariable(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
program.pack();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class InstructionOptimizer implements InstructionVisitor {
|
private static class InstructionOptimizer extends AbstractInstructionVisitor {
|
||||||
private boolean[] used;
|
private boolean[] used;
|
||||||
boolean eliminate;
|
boolean eliminate;
|
||||||
|
|
||||||
|
@ -107,10 +146,6 @@ public class UnusedVariableElimination implements MethodOptimization {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(EmptyInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ClassConstantInstruction insn) {
|
public void visit(ClassConstantInstruction insn) {
|
||||||
requestUsage(insn.getReceiver());
|
requestUsage(insn.getReceiver());
|
||||||
|
@ -176,30 +211,6 @@ public class UnusedVariableElimination implements MethodOptimization {
|
||||||
requestUsage(insn.getReceiver());
|
requestUsage(insn.getReceiver());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(BranchingInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(BinaryBranchingInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(JumpInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(SwitchInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(ExitInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(RaiseInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ConstructArrayInstruction insn) {
|
public void visit(ConstructArrayInstruction insn) {
|
||||||
requestUsage(insn.getReceiver());
|
requestUsage(insn.getReceiver());
|
||||||
|
@ -220,10 +231,6 @@ public class UnusedVariableElimination implements MethodOptimization {
|
||||||
requestUsage(insn.getReceiver());
|
requestUsage(insn.getReceiver());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(PutFieldInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ArrayLengthInstruction insn) {
|
public void visit(ArrayLengthInstruction insn) {
|
||||||
requestUsage(insn.getReceiver());
|
requestUsage(insn.getReceiver());
|
||||||
|
@ -244,10 +251,6 @@ public class UnusedVariableElimination implements MethodOptimization {
|
||||||
requestUsage(insn.getReceiver());
|
requestUsage(insn.getReceiver());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(PutElementInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(InvokeInstruction insn) {
|
public void visit(InvokeInstruction insn) {
|
||||||
if (insn.getReceiver() != null && !used[insn.getReceiver().getIndex()]) {
|
if (insn.getReceiver() != null && !used[insn.getReceiver().getIndex()]) {
|
||||||
|
@ -267,21 +270,9 @@ public class UnusedVariableElimination implements MethodOptimization {
|
||||||
requestUsage(insn.getReceiver());
|
requestUsage(insn.getReceiver());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(InitClassInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(NullCheckInstruction insn) {
|
public void visit(NullCheckInstruction insn) {
|
||||||
requestUsage(insn.getReceiver());
|
requestUsage(insn.getReceiver());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(MonitorEnterInstruction insn) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(MonitorExitInstruction insn) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -348,7 +348,7 @@ class InstructionStringifier implements InstructionReader {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
|
public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) {
|
||||||
appendLocalVar(receiver).append(" := new ").escapeIdentifierIfNeeded(itemType.toString())
|
appendLocalVar(receiver).append(" := newArray ").escapeIdentifierIfNeeded(itemType.toString())
|
||||||
.append("[").appendLocalVar(size).append(']');
|
.append("[").appendLocalVar(size).append(']');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,7 +368,7 @@ class InstructionStringifier implements InstructionReader {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void create(VariableReader receiver, String type) {
|
public void create(VariableReader receiver, String type) {
|
||||||
appendLocalVar(receiver).append(" := newArray ").escapeIdentifierIfNeeded(type);
|
appendLocalVar(receiver).append(" := new ").escapeIdentifierIfNeeded(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -31,6 +31,7 @@ public class ListingBuilder {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
sb.append(prefix).append("var @").append(stringifier.getVariableLabel(i));
|
sb.append(prefix).append("var @").append(stringifier.getVariableLabel(i));
|
||||||
|
sb.append(" as ").append(var.getDebugName());
|
||||||
sb.append('\n');
|
sb.append('\n');
|
||||||
}
|
}
|
||||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||||
|
@ -41,8 +42,8 @@ public class ListingBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block.getExceptionVariable() != null) {
|
if (block.getExceptionVariable() != null) {
|
||||||
sb.append(" ").append(stringifier.getVariableLabel(block.getExceptionVariable().getIndex()))
|
sb.append(" @").append(stringifier.getVariableLabel(block.getExceptionVariable().getIndex()))
|
||||||
.append(" = exception\n");
|
.append(" := exception\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (PhiReader phi : block.readPhis()) {
|
for (PhiReader phi : block.readPhis()) {
|
||||||
|
|
|
@ -222,6 +222,7 @@ public class AsyncProgramSplitter {
|
||||||
Variable varCopy = copy.variableAt(i);
|
Variable varCopy = copy.variableAt(i);
|
||||||
varCopy.setRegister(var.getRegister());
|
varCopy.setRegister(var.getRegister());
|
||||||
varCopy.setDebugName(var.getDebugName());
|
varCopy.setDebugName(var.getDebugName());
|
||||||
|
varCopy.setLabel(var.getLabel());
|
||||||
}
|
}
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,6 +102,9 @@ public class PhiUpdater {
|
||||||
private List<TryCatchJoint> synthesizedJoints = new ArrayList<>();
|
private List<TryCatchJoint> synthesizedJoints = new ArrayList<>();
|
||||||
|
|
||||||
public int getSourceVariable(int var) {
|
public int getSourceVariable(int var) {
|
||||||
|
if (var >= variableToSourceMap.size()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
return variableToSourceMap.get(var);
|
return variableToSourceMap.get(var);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,6 +220,7 @@ public class PhiUpdater {
|
||||||
}
|
}
|
||||||
|
|
||||||
List<List<Incoming>> phiOutputs = ProgramUtils.getPhiOutputs(program);
|
List<List<Incoming>> phiOutputs = ProgramUtils.getPhiOutputs(program);
|
||||||
|
List<List<TryCatchJoint>> inputJoints = getInputJoints(program);
|
||||||
|
|
||||||
while (head > 0) {
|
while (head > 0) {
|
||||||
Task task = stack[--head];
|
Task task = stack[--head];
|
||||||
|
@ -240,6 +244,9 @@ public class PhiUpdater {
|
||||||
for (Phi phi : currentBlock.getPhis()) {
|
for (Phi phi : currentBlock.getPhis()) {
|
||||||
phi.setReceiver(define(phi.getReceiver()));
|
phi.setReceiver(define(phi.getReceiver()));
|
||||||
}
|
}
|
||||||
|
for (TryCatchJoint joint : inputJoints.get(index)) {
|
||||||
|
joint.setReceiver(define(joint.getReceiver()));
|
||||||
|
}
|
||||||
|
|
||||||
for (Instruction insn : currentBlock) {
|
for (Instruction insn : currentBlock) {
|
||||||
insn.acceptVisitor(consumer);
|
insn.acceptVisitor(consumer);
|
||||||
|
@ -494,6 +501,21 @@ public class PhiUpdater {
|
||||||
return mappedVar;
|
return mappedVar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static List<List<TryCatchJoint>> getInputJoints(Program program) {
|
||||||
|
List<List<TryCatchJoint>> inputJoints = new ArrayList<>();
|
||||||
|
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||||
|
inputJoints.add(new ArrayList<>());
|
||||||
|
}
|
||||||
|
for (BasicBlock block : program.getBasicBlocks()) {
|
||||||
|
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
|
||||||
|
for (TryCatchJoint joint : tryCatch.getJoints()) {
|
||||||
|
inputJoints.get(tryCatch.getHandler().getIndex()).add(joint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return inputJoints;
|
||||||
|
}
|
||||||
|
|
||||||
private InstructionVisitor consumer = new InstructionVisitor() {
|
private InstructionVisitor consumer = new InstructionVisitor() {
|
||||||
@Override
|
@Override
|
||||||
public void visit(EmptyInstruction insn) {
|
public void visit(EmptyInstruction insn) {
|
||||||
|
|
|
@ -75,6 +75,7 @@ public final class ProgramUtils {
|
||||||
for (int i = 0; i < program.variableCount(); ++i) {
|
for (int i = 0; i < program.variableCount(); ++i) {
|
||||||
Variable var = copy.createVariable();
|
Variable var = copy.createVariable();
|
||||||
var.setDebugName(program.variableAt(i).getDebugName());
|
var.setDebugName(program.variableAt(i).getDebugName());
|
||||||
|
var.setLabel(program.variableAt(i).getLabel());
|
||||||
}
|
}
|
||||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||||
copy.createBasicBlock();
|
copy.createBasicBlock();
|
||||||
|
|
|
@ -129,7 +129,9 @@ public class Parser {
|
||||||
for (Map.Entry<Integer, String> debugName : debugNames.entrySet()) {
|
for (Map.Entry<Integer, String> debugName : debugNames.entrySet()) {
|
||||||
int receiver = varMap.getOrDefault(debugName.getKey(), -1);
|
int receiver = varMap.getOrDefault(debugName.getKey(), -1);
|
||||||
if (receiver >= 0) {
|
if (receiver >= 0) {
|
||||||
program.variableAt(receiver).setDebugName(debugName.getValue());
|
Variable receiverVar = program.variableAt(receiver);
|
||||||
|
receiverVar.setDebugName(debugName.getValue());
|
||||||
|
receiverVar.setLabel(debugName.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,10 +74,6 @@ import org.teavm.model.util.InstructionVariableMapper;
|
||||||
import org.teavm.model.util.ModelUtils;
|
import org.teavm.model.util.ModelUtils;
|
||||||
import org.teavm.model.util.ProgramUtils;
|
import org.teavm.model.util.ProgramUtils;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
class JSClassProcessor {
|
class JSClassProcessor {
|
||||||
private final ClassReaderSource classSource;
|
private final ClassReaderSource classSource;
|
||||||
private final JSBodyRepository repository;
|
private final JSBodyRepository repository;
|
||||||
|
@ -171,6 +167,7 @@ class JSClassProcessor {
|
||||||
program.variableAt(var.getIndex() + 1));
|
program.variableAt(var.getIndex() + 1));
|
||||||
for (int i = program.variableCount() - 1; i > 0; --i) {
|
for (int i = program.variableCount() - 1; i > 0; --i) {
|
||||||
program.variableAt(i).setDebugName(program.variableAt(i - 1).getDebugName());
|
program.variableAt(i).setDebugName(program.variableAt(i - 1).getDebugName());
|
||||||
|
program.variableAt(i).setLabel(program.variableAt(i - 1).getLabel());
|
||||||
}
|
}
|
||||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||||
BasicBlock block = program.basicBlockAt(i);
|
BasicBlock block = program.basicBlockAt(i);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user