diff --git a/core/src/main/java/org/teavm/model/BasicBlock.java b/core/src/main/java/org/teavm/model/BasicBlock.java index 4716fbf07..e4195847b 100644 --- a/core/src/main/java/org/teavm/model/BasicBlock.java +++ b/core/src/main/java/org/teavm/model/BasicBlock.java @@ -316,8 +316,8 @@ public class BasicBlock implements BasicBlockReader, Iterable { } public void removeIncomingsFrom(BasicBlock predecessor) { - for (Phi phi : getPhis()) { - List incomings = phi.getIncomings(); + for (var phi : getPhis()) { + var incomings = phi.getIncomings(); for (int i = 0; i < incomings.size(); ++i) { if (incomings.get(i).getSource() == predecessor) { incomings.remove(i--); diff --git a/core/src/main/java/org/teavm/model/instructions/AbstractInstructionVisitor.java b/core/src/main/java/org/teavm/model/instructions/AbstractInstructionVisitor.java index 966ef01f8..afc1de01e 100644 --- a/core/src/main/java/org/teavm/model/instructions/AbstractInstructionVisitor.java +++ b/core/src/main/java/org/teavm/model/instructions/AbstractInstructionVisitor.java @@ -15,158 +15,200 @@ */ package org.teavm.model.instructions; +import org.teavm.model.Instruction; import org.teavm.model.InvokeDynamicInstruction; public abstract class AbstractInstructionVisitor implements InstructionVisitor { @Override public void visit(EmptyInstruction insn) { + visitDefault(insn); } @Override public void visit(ClassConstantInstruction insn) { + visitDefault(insn); } @Override public void visit(NullConstantInstruction insn) { + visitDefault(insn); } @Override public void visit(IntegerConstantInstruction insn) { + visitDefault(insn); } @Override public void visit(LongConstantInstruction insn) { + visitDefault(insn); } @Override public void visit(FloatConstantInstruction insn) { + visitDefault(insn); } @Override public void visit(DoubleConstantInstruction insn) { + visitDefault(insn); } @Override public void visit(StringConstantInstruction insn) { + visitDefault(insn); } @Override public void visit(BinaryInstruction insn) { + visitDefault(insn); } @Override public void visit(NegateInstruction insn) { + visitDefault(insn); } @Override public void visit(AssignInstruction insn) { + visitDefault(insn); } @Override public void visit(CastInstruction insn) { + visitDefault(insn); } @Override public void visit(CastNumberInstruction insn) { + visitDefault(insn); } @Override public void visit(CastIntegerInstruction insn) { + visitDefault(insn); } @Override public void visit(BranchingInstruction insn) { + visitDefault(insn); } @Override public void visit(BinaryBranchingInstruction insn) { + visitDefault(insn); } @Override public void visit(JumpInstruction insn) { + visitDefault(insn); } @Override public void visit(SwitchInstruction insn) { + visitDefault(insn); } @Override public void visit(ExitInstruction insn) { + visitDefault(insn); } @Override public void visit(RaiseInstruction insn) { + visitDefault(insn); } @Override public void visit(ConstructArrayInstruction insn) { + visitDefault(insn); } @Override public void visit(ConstructInstruction insn) { + visitDefault(insn); } @Override public void visit(ConstructMultiArrayInstruction insn) { + visitDefault(insn); } @Override public void visit(GetFieldInstruction insn) { + visitDefault(insn); } @Override public void visit(PutFieldInstruction insn) { + visitDefault(insn); } @Override public void visit(ArrayLengthInstruction insn) { + visitDefault(insn); } @Override public void visit(CloneArrayInstruction insn) { + visitDefault(insn); } @Override public void visit(UnwrapArrayInstruction insn) { + visitDefault(insn); } @Override public void visit(GetElementInstruction insn) { + visitDefault(insn); } @Override public void visit(PutElementInstruction insn) { + visitDefault(insn); } @Override public void visit(InvokeInstruction insn) { + visitDefault(insn); } @Override public void visit(InvokeDynamicInstruction insn) { + visitDefault(insn); } @Override public void visit(IsInstanceInstruction insn) { + visitDefault(insn); } @Override public void visit(InitClassInstruction insn) { + visitDefault(insn); } @Override public void visit(NullCheckInstruction insn) { + visitDefault(insn); } @Override public void visit(MonitorEnterInstruction insn) { + visitDefault(insn); } @Override public void visit(MonitorExitInstruction insn) { + visitDefault(insn); } @Override public void visit(BoundCheckInstruction insn) { + visitDefault(insn); + } + + public void visitDefault(Instruction insn) { } } diff --git a/core/src/main/java/org/teavm/model/util/AssignmentExtractor.java b/core/src/main/java/org/teavm/model/util/AssignmentExtractor.java new file mode 100644 index 000000000..d39fce971 --- /dev/null +++ b/core/src/main/java/org/teavm/model/util/AssignmentExtractor.java @@ -0,0 +1,183 @@ +/* + * Copyright 2023 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.model.util; + +import org.teavm.model.Instruction; +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.BoundCheckInstruction; +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 AssignmentExtractor extends AbstractInstructionVisitor { + private Variable result; + + public Variable getResult() { + return result; + } + + @Override + public void visit(IntegerConstantInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(LongConstantInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(FloatConstantInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(DoubleConstantInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(StringConstantInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(ClassConstantInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(NullConstantInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(CastInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(CastIntegerInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(IsInstanceInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(AssignInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(BinaryInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(InvokeInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(NegateInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(CastNumberInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(NullCheckInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(BoundCheckInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(GetFieldInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(GetElementInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(UnwrapArrayInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(ArrayLengthInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(CloneArrayInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(ConstructInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(ConstructArrayInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visit(ConstructMultiArrayInstruction insn) { + result = insn.getReceiver(); + } + + @Override + public void visitDefault(Instruction insn) { + result = null; + } +} diff --git a/core/src/main/java/org/teavm/model/util/MissingItemsProcessor.java b/core/src/main/java/org/teavm/model/util/MissingItemsProcessor.java index 2d6840b8b..8ff7001ce 100644 --- a/core/src/main/java/org/teavm/model/util/MissingItemsProcessor.java +++ b/core/src/main/java/org/teavm/model/util/MissingItemsProcessor.java @@ -19,6 +19,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import org.teavm.dependency.DependencyInfo; @@ -54,9 +55,9 @@ public class MissingItemsProcessor { } public void processClass(ClassHolder cls) { - for (MethodHolder method : cls.getMethods()) { + for (var method : cls.getMethods()) { if (reachableMethods.contains(method.getReference()) && method.getProgram() != null) { - MethodDependencyInfo methodDep = dependencyInfo.getMethod(method.getReference()); + var methodDep = dependencyInfo.getMethod(method.getReference()); if (methodDep != null && methodDep.isUsed()) { processMethod(method); } @@ -76,7 +77,7 @@ public class MissingItemsProcessor { BasicBlock block = program.basicBlockAt(i); instructionsToAdd.clear(); boolean missing = false; - for (Instruction insn : block) { + for (var insn : block) { insn.acceptVisitor(instructionProcessor); if (!instructionsToAdd.isEmpty()) { wasModified = true; @@ -86,7 +87,7 @@ public class MissingItemsProcessor { } } if (!missing) { - for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) { + for (var tryCatch : block.getTryCatchBlocks()) { checkClass(null, tryCatch.getExceptionType()); } } @@ -97,14 +98,42 @@ public class MissingItemsProcessor { } private void truncateBlock(Instruction instruction) { - TransitionExtractor transitionExtractor = new TransitionExtractor(); - BasicBlock block = instruction.getBasicBlock(); + var transitionExtractor = new TransitionExtractor(); + var block = instruction.getBasicBlock(); if (block.getLastInstruction() != null) { block.getLastInstruction().acceptVisitor(transitionExtractor); } - for (BasicBlock successor : transitionExtractor.getTargets()) { + for (var successor : transitionExtractor.getTargets()) { successor.removeIncomingsFrom(block); } + + if (!block.getTryCatchBlocks().isEmpty()) { + var handlers = new LinkedHashSet(); + for (var tryCatch : block.getTryCatchBlocks()) { + handlers.add(tryCatch.getHandler()); + } + + var next = instruction; + var assignExtractor = new AssignmentExtractor(); + while (next != null) { + next.acceptVisitor(assignExtractor); + var definition = assignExtractor.getResult(); + if (definition != null) { + for (var handler : handlers) { + for (var phi : handler.getPhis()) { + for (var iter = phi.getIncomings().iterator(); iter.hasNext();) { + var incoming = iter.next(); + if (incoming.getSource() == block && incoming.getValue() == definition) { + iter.remove(); + } + } + } + } + } + next = next.getNext(); + } + } + while (instruction.getNext() != null) { instruction.getNext().delete(); }