Use new null checker in optimizer. Fix multiple bugs in optimizer and IR

This commit is contained in:
Alexey Andreev 2017-01-03 23:39:43 +03:00
parent aef1e2e206
commit 727c831467
16 changed files with 196 additions and 498 deletions

View File

@ -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;
}
}
}

View File

@ -77,6 +77,8 @@ public class NullnessInformation {
insn.acceptVisitor(variableMapper);
}
}
variableMapper.applyToPhis(block);
variableMapper.applyToTryCatchBlocks(block);
}
}

View File

@ -15,13 +15,61 @@
*/
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 org.teavm.common.DominatorTree;
import org.teavm.common.Graph;
import org.teavm.common.GraphUtils;
import org.teavm.model.*;
import org.teavm.model.instructions.*;
import org.teavm.model.BasicBlock;
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;
public class GlobalValueNumbering implements MethodOptimization {
@ -86,9 +134,7 @@ public class GlobalValueNumbering implements MethodOptimization {
currentInsn.acceptVisitor(optimizer);
if (eliminate) {
affected = true;
EmptyInstruction empty = new EmptyInstruction();
empty.setLocation(currentInsn.getLocation());
currentInsn.replace(empty);
currentInsn.delete();
eliminate = false;
} else if (evaluatedConstant != null) {
if (evaluatedConstant instanceof Integer) {
@ -501,6 +547,9 @@ public class GlobalValueNumbering implements MethodOptimization {
if (insn.getReceiver().getDebugName() != null) {
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()];
eliminate = true;
}

View File

@ -109,6 +109,8 @@ public class Inlining {
List<TryCatchBlock> tryCatches = new ArrayList<>(blockToInline.getTryCatchBlocks());
blockToInline.getTryCatchBlocks().clear();
inlineBlock.getTryCatchBlocks().addAll(tryCatches);
inlineBlock.setExceptionVariable(blockToInline.getExceptionVariable());
}
BasicBlockMapper blockMapper = new BasicBlockMapper((BasicBlock b) ->

View File

@ -16,6 +16,7 @@
package org.teavm.model.optimization;
import org.teavm.model.InvokeDynamicInstruction;
import org.teavm.model.analysis.NullnessInformation;
import org.teavm.model.instructions.ArrayLengthInstruction;
import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.BinaryBranchingInstruction;
@ -57,13 +58,13 @@ import org.teavm.model.instructions.SwitchInstruction;
import org.teavm.model.instructions.UnwrapArrayInstruction;
public class LoopInvariantAnalyzer implements InstructionVisitor {
private boolean[] notNull;
private NullnessInformation nullness;
public boolean canMove;
public boolean constant;
public boolean sideEffect;
public LoopInvariantAnalyzer(boolean[] notNull) {
this.notNull = notNull;
public LoopInvariantAnalyzer(NullnessInformation nullness) {
this.nullness = nullness;
}
public void reset() {
@ -192,7 +193,7 @@ public class LoopInvariantAnalyzer implements InstructionVisitor {
@Override
public void visit(ArrayLengthInstruction insn) {
canMove = true;
if (!notNull[insn.getArray().getIndex()]) {
if (!nullness.isNotNull(insn.getArray())) {
sideEffect = true;
}
}
@ -204,7 +205,7 @@ public class LoopInvariantAnalyzer implements InstructionVisitor {
@Override
public void visit(UnwrapArrayInstruction insn) {
canMove = true;
if (!notNull[insn.getArray().getIndex()]) {
if (!nullness.isNotNull(insn.getArray())) {
sideEffect = true;
}
}
@ -237,7 +238,7 @@ public class LoopInvariantAnalyzer implements InstructionVisitor {
@Override
public void visit(NullCheckInstruction insn) {
canMove = true;
if (!notNull[insn.getValue().getIndex()]) {
if (!nullness.isNotNull(insn.getValue())) {
sideEffect = true;
}
}

View File

@ -18,11 +18,34 @@ package org.teavm.model.optimization;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.teavm.common.*;
import org.teavm.model.*;
import org.teavm.model.analysis.NullnessChecker;
import org.teavm.model.instructions.*;
import org.teavm.model.util.*;
import org.teavm.common.DominatorTree;
import org.teavm.common.Graph;
import org.teavm.common.GraphUtils;
import org.teavm.common.IntegerStack;
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 {
private int[] preheaders;
@ -32,6 +55,8 @@ public class LoopInvariantMotion implements MethodOptimization {
@Override
public boolean optimize(MethodOptimizationContext context, Program program) {
NullnessInformation nullness = NullnessInformation.build(program, context.getMethod().getDescriptor());
boolean affected = false;
this.program = program;
graph = new LoopGraph(ProgramUtils.buildControlFlowGraph(program));
@ -54,7 +79,7 @@ public class LoopInvariantMotion implements MethodOptimization {
DefinitionExtractor defExtractor = new DefinitionExtractor();
UsageExtractor useExtractor = new UsageExtractor();
LoopInvariantAnalyzer analyzer = new LoopInvariantAnalyzer(new NullnessChecker().check(program));
LoopInvariantAnalyzer analyzer = new LoopInvariantAnalyzer(nullness);
CopyConstantVisitor constantCopier = new CopyConstantVisitor();
int[][] loopExits = ControlFlowUtils.findLoopExits(graph);
@ -112,9 +137,7 @@ public class LoopInvariantMotion implements MethodOptimization {
}
}
EmptyInstruction empty = new EmptyInstruction();
empty.setLocation(insn.getLocation());
insn.replace(empty);
insn.delete();
BasicBlock preheader = program.basicBlockAt(getPreheader(defLoop.getHead()));
List<Instruction> newInstructions = new ArrayList<>();
Variable[] variableMap = null;
@ -146,6 +169,7 @@ public class LoopInvariantMotion implements MethodOptimization {
}
}
nullness.dispose();
return affected;
}
@ -191,6 +215,8 @@ public class LoopInvariantMotion implements MethodOptimization {
if (preheaderPhi == null) {
preheaderPhi = new Phi();
preheaderPhi.setReceiver(program.createVariable());
preheaderPhi.getReceiver().setLabel(phi.getReceiver().getLabel());
preheaderPhi.getReceiver().setDebugName(phi.getReceiver().getDebugName());
preheader.getPhis().add(preheaderPhi);
}
preheaderPhi.getIncomings().add(incoming);
@ -215,18 +241,15 @@ public class LoopInvariantMotion implements MethodOptimization {
return preheader.getIndex();
}
private class CopyConstantVisitor implements InstructionVisitor {
private class CopyConstantVisitor extends AbstractInstructionVisitor {
Instruction copy;
Variable var;
@Override
public void visit(EmptyInstruction insn) {
}
@Override
public void visit(ClassConstantInstruction insn) {
var = program.createVariable();
var.setDebugName(insn.getReceiver().getDebugName());
var.setLabel(insn.getReceiver().getLabel());
ClassConstantInstruction copy = new ClassConstantInstruction();
copy.setConstant(insn.getConstant());
copy.setReceiver(var);
@ -237,6 +260,7 @@ public class LoopInvariantMotion implements MethodOptimization {
public void visit(NullConstantInstruction insn) {
var = program.createVariable();
var.setDebugName(insn.getReceiver().getDebugName());
var.setLabel(insn.getReceiver().getLabel());
NullConstantInstruction copy = new NullConstantInstruction();
copy.setReceiver(var);
this.copy = copy;
@ -246,6 +270,7 @@ public class LoopInvariantMotion implements MethodOptimization {
public void visit(IntegerConstantInstruction insn) {
var = program.createVariable();
var.setDebugName(insn.getReceiver().getDebugName());
var.setLabel(insn.getReceiver().getLabel());
IntegerConstantInstruction copy = new IntegerConstantInstruction();
copy.setConstant(insn.getConstant());
copy.setReceiver(var);
@ -256,6 +281,7 @@ public class LoopInvariantMotion implements MethodOptimization {
public void visit(LongConstantInstruction insn) {
var = program.createVariable();
var.setDebugName(insn.getReceiver().getDebugName());
var.setLabel(insn.getReceiver().getLabel());
LongConstantInstruction copy = new LongConstantInstruction();
copy.setConstant(insn.getConstant());
copy.setReceiver(var);
@ -266,6 +292,7 @@ public class LoopInvariantMotion implements MethodOptimization {
public void visit(FloatConstantInstruction insn) {
var = program.createVariable();
var.setDebugName(insn.getReceiver().getDebugName());
var.setLabel(insn.getReceiver().getLabel());
FloatConstantInstruction copy = new FloatConstantInstruction();
copy.setConstant(insn.getConstant());
copy.setReceiver(var);
@ -276,6 +303,7 @@ public class LoopInvariantMotion implements MethodOptimization {
public void visit(DoubleConstantInstruction insn) {
var = program.createVariable();
var.setDebugName(insn.getReceiver().getDebugName());
var.setLabel(insn.getReceiver().getLabel());
DoubleConstantInstruction copy = new DoubleConstantInstruction();
copy.setConstant(insn.getConstant());
copy.setReceiver(var);
@ -286,126 +314,11 @@ public class LoopInvariantMotion implements MethodOptimization {
public void visit(StringConstantInstruction insn) {
var = program.createVariable();
var.setDebugName(insn.getReceiver().getDebugName());
var.setLabel(insn.getReceiver().getLabel());
StringConstantInstruction copy = new StringConstantInstruction();
copy.setConstant(insn.getConstant());
copy.setReceiver(var);
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) {
}
}
}

View File

@ -22,6 +22,6 @@ public class LoopInversion implements MethodOptimization {
@Override
public boolean optimize(MethodOptimizationContext context, Program program) {
MethodReader method = context.getMethod();
return new LoopInversionImpl(program, method.parameterCount() + 1).apply();
return new LoopInversionImpl(program, method.getReference(), method.parameterCount() + 1).apply();
}
}

View File

@ -35,12 +35,13 @@ import org.teavm.common.LoopGraph;
import org.teavm.model.BasicBlock;
import org.teavm.model.Incoming;
import org.teavm.model.Instruction;
import org.teavm.model.MethodReference;
import org.teavm.model.Phi;
import org.teavm.model.Program;
import org.teavm.model.TryCatchBlock;
import org.teavm.model.TryCatchJoint;
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.DefinitionExtractor;
import org.teavm.model.util.InstructionCopyReader;
@ -80,6 +81,7 @@ import org.teavm.model.util.UsageExtractor;
*/
class LoopInversionImpl {
private final Program program;
private final MethodReference method;
private final int parameterCount;
private Graph cfg;
private DominatorTree dom;
@ -88,8 +90,9 @@ class LoopInversionImpl {
private BasicBlock[] definitionPlaces;
private boolean affected;
LoopInversionImpl(Program program, int parameterCount) {
LoopInversionImpl(Program program, MethodReference method, int parameterCount) {
this.program = program;
this.method = method;
this.parameterCount = parameterCount;
definitionPlaces = ProgramUtils.getVariableDefinitionPlaces(program);
}
@ -202,7 +205,10 @@ class LoopInversionImpl {
}
IntSet nodesToCopy = nodesToCopy();
if (!isInversionProfitable(nodesToCopy)) {
NullnessInformation nullness = NullnessInformation.build(program, method.getDescriptor());
boolean profitable = isInversionProfitable(nodesToCopy, nullness);
nullness.dispose();
if (!profitable) {
return false;
}
copyBasicBlocks(nodesToCopy);
@ -216,11 +222,10 @@ class LoopInversionImpl {
return true;
}
private boolean isInversionProfitable(IntSet nodesToCopy) {
private boolean isInversionProfitable(IntSet nodesToCopy, NullnessInformation nullness) {
UsageExtractor useExtractor = new UsageExtractor();
DefinitionExtractor defExtractor = new DefinitionExtractor();
boolean[] notNull = new NullnessChecker().check(program);
LoopInvariantAnalyzer invariantAnalyzer = new LoopInvariantAnalyzer(notNull);
LoopInvariantAnalyzer invariantAnalyzer = new LoopInvariantAnalyzer(nullness);
for (int node : nodes.toArray()) {
if (nodesToCopy.contains(node)) {
continue;

View File

@ -16,8 +16,40 @@
package org.teavm.model.optimization;
import org.teavm.common.Graph;
import org.teavm.model.*;
import org.teavm.model.instructions.*;
import org.teavm.model.BasicBlock;
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 {
@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;
}
private static class InstructionOptimizer implements InstructionVisitor {
private static class InstructionOptimizer extends AbstractInstructionVisitor {
private boolean[] used;
boolean eliminate;
@ -107,10 +146,6 @@ public class UnusedVariableElimination implements MethodOptimization {
}
}
@Override
public void visit(EmptyInstruction insn) {
}
@Override
public void visit(ClassConstantInstruction insn) {
requestUsage(insn.getReceiver());
@ -176,30 +211,6 @@ public class UnusedVariableElimination implements MethodOptimization {
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
public void visit(ConstructArrayInstruction insn) {
requestUsage(insn.getReceiver());
@ -220,10 +231,6 @@ public class UnusedVariableElimination implements MethodOptimization {
requestUsage(insn.getReceiver());
}
@Override
public void visit(PutFieldInstruction insn) {
}
@Override
public void visit(ArrayLengthInstruction insn) {
requestUsage(insn.getReceiver());
@ -244,10 +251,6 @@ public class UnusedVariableElimination implements MethodOptimization {
requestUsage(insn.getReceiver());
}
@Override
public void visit(PutElementInstruction insn) {
}
@Override
public void visit(InvokeInstruction insn) {
if (insn.getReceiver() != null && !used[insn.getReceiver().getIndex()]) {
@ -267,21 +270,9 @@ public class UnusedVariableElimination implements MethodOptimization {
requestUsage(insn.getReceiver());
}
@Override
public void visit(InitClassInstruction insn) {
}
@Override
public void visit(NullCheckInstruction insn) {
requestUsage(insn.getReceiver());
}
@Override
public void visit(MonitorEnterInstruction insn) {
}
@Override
public void visit(MonitorExitInstruction insn) {
}
}
}

View File

@ -348,7 +348,7 @@ class InstructionStringifier implements InstructionReader {
@Override
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(']');
}
@ -368,7 +368,7 @@ class InstructionStringifier implements InstructionReader {
@Override
public void create(VariableReader receiver, String type) {
appendLocalVar(receiver).append(" := newArray ").escapeIdentifierIfNeeded(type);
appendLocalVar(receiver).append(" := new ").escapeIdentifierIfNeeded(type);
}
@Override

View File

@ -31,6 +31,7 @@ public class ListingBuilder {
continue;
}
sb.append(prefix).append("var @").append(stringifier.getVariableLabel(i));
sb.append(" as ").append(var.getDebugName());
sb.append('\n');
}
for (int i = 0; i < program.basicBlockCount(); ++i) {
@ -41,8 +42,8 @@ public class ListingBuilder {
}
if (block.getExceptionVariable() != null) {
sb.append(" ").append(stringifier.getVariableLabel(block.getExceptionVariable().getIndex()))
.append(" = exception\n");
sb.append(" @").append(stringifier.getVariableLabel(block.getExceptionVariable().getIndex()))
.append(" := exception\n");
}
for (PhiReader phi : block.readPhis()) {

View File

@ -222,6 +222,7 @@ public class AsyncProgramSplitter {
Variable varCopy = copy.variableAt(i);
varCopy.setRegister(var.getRegister());
varCopy.setDebugName(var.getDebugName());
varCopy.setLabel(var.getLabel());
}
return copy;
}

View File

@ -102,6 +102,9 @@ public class PhiUpdater {
private List<TryCatchJoint> synthesizedJoints = new ArrayList<>();
public int getSourceVariable(int var) {
if (var >= variableToSourceMap.size()) {
return -1;
}
return variableToSourceMap.get(var);
}
@ -217,6 +220,7 @@ public class PhiUpdater {
}
List<List<Incoming>> phiOutputs = ProgramUtils.getPhiOutputs(program);
List<List<TryCatchJoint>> inputJoints = getInputJoints(program);
while (head > 0) {
Task task = stack[--head];
@ -240,6 +244,9 @@ public class PhiUpdater {
for (Phi phi : currentBlock.getPhis()) {
phi.setReceiver(define(phi.getReceiver()));
}
for (TryCatchJoint joint : inputJoints.get(index)) {
joint.setReceiver(define(joint.getReceiver()));
}
for (Instruction insn : currentBlock) {
insn.acceptVisitor(consumer);
@ -494,6 +501,21 @@ public class PhiUpdater {
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() {
@Override
public void visit(EmptyInstruction insn) {

View File

@ -75,6 +75,7 @@ public final class ProgramUtils {
for (int i = 0; i < program.variableCount(); ++i) {
Variable var = copy.createVariable();
var.setDebugName(program.variableAt(i).getDebugName());
var.setLabel(program.variableAt(i).getLabel());
}
for (int i = 0; i < program.basicBlockCount(); ++i) {
copy.createBasicBlock();

View File

@ -129,7 +129,9 @@ public class Parser {
for (Map.Entry<Integer, String> debugName : debugNames.entrySet()) {
int receiver = varMap.getOrDefault(debugName.getKey(), -1);
if (receiver >= 0) {
program.variableAt(receiver).setDebugName(debugName.getValue());
Variable receiverVar = program.variableAt(receiver);
receiverVar.setDebugName(debugName.getValue());
receiverVar.setLabel(debugName.getValue());
}
}
}

View File

@ -74,10 +74,6 @@ import org.teavm.model.util.InstructionVariableMapper;
import org.teavm.model.util.ModelUtils;
import org.teavm.model.util.ProgramUtils;
/**
*
* @author Alexey Andreev
*/
class JSClassProcessor {
private final ClassReaderSource classSource;
private final JSBodyRepository repository;
@ -171,6 +167,7 @@ class JSClassProcessor {
program.variableAt(var.getIndex() + 1));
for (int i = program.variableCount() - 1; i > 0; --i) {
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) {
BasicBlock block = program.basicBlockAt(i);