Don't crash when reporting some cases of missing standard APIs

This commit is contained in:
Alexey Andreev 2023-07-17 18:41:28 +02:00
parent 9fd7b9c4e2
commit b1ddf163d7
4 changed files with 263 additions and 9 deletions

View File

@ -316,8 +316,8 @@ public class BasicBlock implements BasicBlockReader, Iterable<Instruction> {
} }
public void removeIncomingsFrom(BasicBlock predecessor) { public void removeIncomingsFrom(BasicBlock predecessor) {
for (Phi phi : getPhis()) { for (var phi : getPhis()) {
List<Incoming> incomings = phi.getIncomings(); var incomings = phi.getIncomings();
for (int i = 0; i < incomings.size(); ++i) { for (int i = 0; i < incomings.size(); ++i) {
if (incomings.get(i).getSource() == predecessor) { if (incomings.get(i).getSource() == predecessor) {
incomings.remove(i--); incomings.remove(i--);

View File

@ -15,158 +15,200 @@
*/ */
package org.teavm.model.instructions; package org.teavm.model.instructions;
import org.teavm.model.Instruction;
import org.teavm.model.InvokeDynamicInstruction; import org.teavm.model.InvokeDynamicInstruction;
public abstract class AbstractInstructionVisitor implements InstructionVisitor { public abstract class AbstractInstructionVisitor implements InstructionVisitor {
@Override @Override
public void visit(EmptyInstruction insn) { public void visit(EmptyInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(ClassConstantInstruction insn) { public void visit(ClassConstantInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(NullConstantInstruction insn) { public void visit(NullConstantInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(IntegerConstantInstruction insn) { public void visit(IntegerConstantInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(LongConstantInstruction insn) { public void visit(LongConstantInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(FloatConstantInstruction insn) { public void visit(FloatConstantInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(DoubleConstantInstruction insn) { public void visit(DoubleConstantInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(StringConstantInstruction insn) { public void visit(StringConstantInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(BinaryInstruction insn) { public void visit(BinaryInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(NegateInstruction insn) { public void visit(NegateInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(AssignInstruction insn) { public void visit(AssignInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(CastInstruction insn) { public void visit(CastInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(CastNumberInstruction insn) { public void visit(CastNumberInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(CastIntegerInstruction insn) { public void visit(CastIntegerInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(BranchingInstruction insn) { public void visit(BranchingInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(BinaryBranchingInstruction insn) { public void visit(BinaryBranchingInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(JumpInstruction insn) { public void visit(JumpInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(SwitchInstruction insn) { public void visit(SwitchInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(ExitInstruction insn) { public void visit(ExitInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(RaiseInstruction insn) { public void visit(RaiseInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(ConstructArrayInstruction insn) { public void visit(ConstructArrayInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(ConstructInstruction insn) { public void visit(ConstructInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(ConstructMultiArrayInstruction insn) { public void visit(ConstructMultiArrayInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(GetFieldInstruction insn) { public void visit(GetFieldInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(PutFieldInstruction insn) { public void visit(PutFieldInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(ArrayLengthInstruction insn) { public void visit(ArrayLengthInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(CloneArrayInstruction insn) { public void visit(CloneArrayInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(UnwrapArrayInstruction insn) { public void visit(UnwrapArrayInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(GetElementInstruction insn) { public void visit(GetElementInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(PutElementInstruction insn) { public void visit(PutElementInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(InvokeInstruction insn) { public void visit(InvokeInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(InvokeDynamicInstruction insn) { public void visit(InvokeDynamicInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(IsInstanceInstruction insn) { public void visit(IsInstanceInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(InitClassInstruction insn) { public void visit(InitClassInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(NullCheckInstruction insn) { public void visit(NullCheckInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(MonitorEnterInstruction insn) { public void visit(MonitorEnterInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(MonitorExitInstruction insn) { public void visit(MonitorExitInstruction insn) {
visitDefault(insn);
} }
@Override @Override
public void visit(BoundCheckInstruction insn) { public void visit(BoundCheckInstruction insn) {
visitDefault(insn);
}
public void visitDefault(Instruction insn) {
} }
} }

View File

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

View File

@ -19,6 +19,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.teavm.dependency.DependencyInfo; import org.teavm.dependency.DependencyInfo;
@ -54,9 +55,9 @@ public class MissingItemsProcessor {
} }
public void processClass(ClassHolder cls) { public void processClass(ClassHolder cls) {
for (MethodHolder method : cls.getMethods()) { for (var method : cls.getMethods()) {
if (reachableMethods.contains(method.getReference()) && method.getProgram() != null) { 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()) { if (methodDep != null && methodDep.isUsed()) {
processMethod(method); processMethod(method);
} }
@ -76,7 +77,7 @@ public class MissingItemsProcessor {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
instructionsToAdd.clear(); instructionsToAdd.clear();
boolean missing = false; boolean missing = false;
for (Instruction insn : block) { for (var insn : block) {
insn.acceptVisitor(instructionProcessor); insn.acceptVisitor(instructionProcessor);
if (!instructionsToAdd.isEmpty()) { if (!instructionsToAdd.isEmpty()) {
wasModified = true; wasModified = true;
@ -86,7 +87,7 @@ public class MissingItemsProcessor {
} }
} }
if (!missing) { if (!missing) {
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) { for (var tryCatch : block.getTryCatchBlocks()) {
checkClass(null, tryCatch.getExceptionType()); checkClass(null, tryCatch.getExceptionType());
} }
} }
@ -97,14 +98,42 @@ public class MissingItemsProcessor {
} }
private void truncateBlock(Instruction instruction) { private void truncateBlock(Instruction instruction) {
TransitionExtractor transitionExtractor = new TransitionExtractor(); var transitionExtractor = new TransitionExtractor();
BasicBlock block = instruction.getBasicBlock(); var block = instruction.getBasicBlock();
if (block.getLastInstruction() != null) { if (block.getLastInstruction() != null) {
block.getLastInstruction().acceptVisitor(transitionExtractor); block.getLastInstruction().acceptVisitor(transitionExtractor);
} }
for (BasicBlock successor : transitionExtractor.getTargets()) { for (var successor : transitionExtractor.getTargets()) {
successor.removeIncomingsFrom(block); successor.removeIncomingsFrom(block);
} }
if (!block.getTryCatchBlocks().isEmpty()) {
var handlers = new LinkedHashSet<BasicBlock>();
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) { while (instruction.getNext() != null) {
instruction.getNext().delete(); instruction.getNext().delete();
} }