From 727c831467302dd8b1d8a0aad05b715fbaa22fed Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Tue, 3 Jan 2017 23:39:43 +0300 Subject: [PATCH] Use new null checker in optimizer. Fix multiple bugs in optimizer and IR --- .../teavm/model/analysis/NullnessChecker.java | 289 ------------------ .../model/analysis/NullnessInformation.java | 2 + .../optimization/GlobalValueNumbering.java | 61 +++- .../teavm/model/optimization/Inlining.java | 2 + .../optimization/LoopInvariantAnalyzer.java | 13 +- .../optimization/LoopInvariantMotion.java | 173 +++-------- .../model/optimization/LoopInversion.java | 2 +- .../model/optimization/LoopInversionImpl.java | 17 +- .../UnusedVariableElimination.java | 93 +++--- .../model/text/InstructionStringifier.java | 4 +- .../org/teavm/model/text/ListingBuilder.java | 5 +- .../model/util/AsyncProgramSplitter.java | 1 + .../java/org/teavm/model/util/PhiUpdater.java | 22 ++ .../org/teavm/model/util/ProgramUtils.java | 1 + .../main/java/org/teavm/parsing/Parser.java | 4 +- .../org/teavm/jso/impl/JSClassProcessor.java | 5 +- 16 files changed, 196 insertions(+), 498 deletions(-) delete mode 100644 core/src/main/java/org/teavm/model/analysis/NullnessChecker.java diff --git a/core/src/main/java/org/teavm/model/analysis/NullnessChecker.java b/core/src/main/java/org/teavm/model/analysis/NullnessChecker.java deleted file mode 100644 index 152c2ef29..000000000 --- a/core/src/main/java/org/teavm/model/analysis/NullnessChecker.java +++ /dev/null @@ -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 notNullIncomings; - List> 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 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 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 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 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; - } - } -} diff --git a/core/src/main/java/org/teavm/model/analysis/NullnessInformation.java b/core/src/main/java/org/teavm/model/analysis/NullnessInformation.java index ed921a0d8..1769b52f1 100644 --- a/core/src/main/java/org/teavm/model/analysis/NullnessInformation.java +++ b/core/src/main/java/org/teavm/model/analysis/NullnessInformation.java @@ -77,6 +77,8 @@ public class NullnessInformation { insn.acceptVisitor(variableMapper); } } + variableMapper.applyToPhis(block); + variableMapper.applyToTryCatchBlocks(block); } } diff --git a/core/src/main/java/org/teavm/model/optimization/GlobalValueNumbering.java b/core/src/main/java/org/teavm/model/optimization/GlobalValueNumbering.java index 39ce9c41b..029106f26 100644 --- a/core/src/main/java/org/teavm/model/optimization/GlobalValueNumbering.java +++ b/core/src/main/java/org/teavm/model/optimization/GlobalValueNumbering.java @@ -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; } diff --git a/core/src/main/java/org/teavm/model/optimization/Inlining.java b/core/src/main/java/org/teavm/model/optimization/Inlining.java index 30c40af10..4153db5be 100644 --- a/core/src/main/java/org/teavm/model/optimization/Inlining.java +++ b/core/src/main/java/org/teavm/model/optimization/Inlining.java @@ -109,6 +109,8 @@ public class Inlining { List tryCatches = new ArrayList<>(blockToInline.getTryCatchBlocks()); blockToInline.getTryCatchBlocks().clear(); inlineBlock.getTryCatchBlocks().addAll(tryCatches); + + inlineBlock.setExceptionVariable(blockToInline.getExceptionVariable()); } BasicBlockMapper blockMapper = new BasicBlockMapper((BasicBlock b) -> diff --git a/core/src/main/java/org/teavm/model/optimization/LoopInvariantAnalyzer.java b/core/src/main/java/org/teavm/model/optimization/LoopInvariantAnalyzer.java index 2b757b8cb..3754bb448 100644 --- a/core/src/main/java/org/teavm/model/optimization/LoopInvariantAnalyzer.java +++ b/core/src/main/java/org/teavm/model/optimization/LoopInvariantAnalyzer.java @@ -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; } } diff --git a/core/src/main/java/org/teavm/model/optimization/LoopInvariantMotion.java b/core/src/main/java/org/teavm/model/optimization/LoopInvariantMotion.java index fd489ba17..98a7dfc72 100644 --- a/core/src/main/java/org/teavm/model/optimization/LoopInvariantMotion.java +++ b/core/src/main/java/org/teavm/model/optimization/LoopInvariantMotion.java @@ -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 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) { - } } } diff --git a/core/src/main/java/org/teavm/model/optimization/LoopInversion.java b/core/src/main/java/org/teavm/model/optimization/LoopInversion.java index 20f70e304..c950ecc57 100644 --- a/core/src/main/java/org/teavm/model/optimization/LoopInversion.java +++ b/core/src/main/java/org/teavm/model/optimization/LoopInversion.java @@ -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(); } } diff --git a/core/src/main/java/org/teavm/model/optimization/LoopInversionImpl.java b/core/src/main/java/org/teavm/model/optimization/LoopInversionImpl.java index 0c430b874..7947e2e0a 100644 --- a/core/src/main/java/org/teavm/model/optimization/LoopInversionImpl.java +++ b/core/src/main/java/org/teavm/model/optimization/LoopInversionImpl.java @@ -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; diff --git a/core/src/main/java/org/teavm/model/optimization/UnusedVariableElimination.java b/core/src/main/java/org/teavm/model/optimization/UnusedVariableElimination.java index 77972d278..34e82f5e9 100644 --- a/core/src/main/java/org/teavm/model/optimization/UnusedVariableElimination.java +++ b/core/src/main/java/org/teavm/model/optimization/UnusedVariableElimination.java @@ -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) { - } } } diff --git a/core/src/main/java/org/teavm/model/text/InstructionStringifier.java b/core/src/main/java/org/teavm/model/text/InstructionStringifier.java index 28d85a4ec..fd7502420 100644 --- a/core/src/main/java/org/teavm/model/text/InstructionStringifier.java +++ b/core/src/main/java/org/teavm/model/text/InstructionStringifier.java @@ -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 diff --git a/core/src/main/java/org/teavm/model/text/ListingBuilder.java b/core/src/main/java/org/teavm/model/text/ListingBuilder.java index 6131a7598..7ee31b1c5 100644 --- a/core/src/main/java/org/teavm/model/text/ListingBuilder.java +++ b/core/src/main/java/org/teavm/model/text/ListingBuilder.java @@ -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()) { diff --git a/core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java b/core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java index eb63f02d9..ea6e47622 100644 --- a/core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java +++ b/core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java @@ -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; } diff --git a/core/src/main/java/org/teavm/model/util/PhiUpdater.java b/core/src/main/java/org/teavm/model/util/PhiUpdater.java index b58804719..a73f2b05e 100644 --- a/core/src/main/java/org/teavm/model/util/PhiUpdater.java +++ b/core/src/main/java/org/teavm/model/util/PhiUpdater.java @@ -102,6 +102,9 @@ public class PhiUpdater { private List 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> phiOutputs = ProgramUtils.getPhiOutputs(program); + List> 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> getInputJoints(Program program) { + List> 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) { diff --git a/core/src/main/java/org/teavm/model/util/ProgramUtils.java b/core/src/main/java/org/teavm/model/util/ProgramUtils.java index b86de0c9e..8e54a0c2d 100644 --- a/core/src/main/java/org/teavm/model/util/ProgramUtils.java +++ b/core/src/main/java/org/teavm/model/util/ProgramUtils.java @@ -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(); diff --git a/core/src/main/java/org/teavm/parsing/Parser.java b/core/src/main/java/org/teavm/parsing/Parser.java index 5cf0a7fec..04c7f48e5 100644 --- a/core/src/main/java/org/teavm/parsing/Parser.java +++ b/core/src/main/java/org/teavm/parsing/Parser.java @@ -129,7 +129,9 @@ public class Parser { for (Map.Entry 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()); } } } diff --git a/jso/impl/src/main/java/org/teavm/jso/impl/JSClassProcessor.java b/jso/impl/src/main/java/org/teavm/jso/impl/JSClassProcessor.java index 21051d473..28a4cc62b 100644 --- a/jso/impl/src/main/java/org/teavm/jso/impl/JSClassProcessor.java +++ b/jso/impl/src/main/java/org/teavm/jso/impl/JSClassProcessor.java @@ -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);