mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -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);
|
||||
}
|
||||
}
|
||||
variableMapper.applyToPhis(block);
|
||||
variableMapper.applyToTryCatchBlocks(block);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) ->
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue
Block a user